|
|
# PLAN — Theming: que TODO componente sea personalizable por un tema (eje `theme-reach`)
|
|
|
|
|
|
> **Estado (act. 2026-08-23): EN EJECUCIÓN — alcance global 65 %, 25
|
|
|
> componentes al 100 %, 24 sin contrato, 12 por debajo del 20 %. Vocabulario
|
|
|
> CERRADO (codemod + R-5.3 + muro de tipos), bloques F2-A y F2-B CERRADOS y la
|
|
|
> cola avanzando: dieciséis componentes el 2026-08-23. Las D-TH.1…8 de §4
|
|
|
> FIRMADAS TODAS el 2026-08-20** (más las
|
|
|
> tres decisiones hermanas del mismo día: familia calendar = capa compartida,
|
|
|
> mandato Field ejecutable, hover→capa de estado — ver «Firmas del 2026-08-20»
|
|
|
> del CONTINUE). El registro con cifras y commits está en §8, y el punto
|
|
|
> de entrada diario es [`CONTINUE-theming.md`](./CONTINUE-theming.md). Toda
|
|
|
> decisión NUEVA que surja se sigue presentando una por mensaje, con las
|
|
|
> cinco preguntas.
|
|
|
>
|
|
|
> **Origen (conversación 2026-08-19)**: al arreglar `navigation-menu` salió que
|
|
|
> el radio de su trigger vivía en un privado clavado a `--radius-default` y que
|
|
|
> el contrato del componente sólo publicaba tres knobs: ningún tema podía decir
|
|
|
> «píldora» sin mover el radio del sistema entero. El autor, textual: **«esto
|
|
|
> ha abierto una duda importante, y es si los componentes creados son
|
|
|
> themables; si no lo son, es un error como framework. Necesitaríamos
|
|
|
> desarrollar un plan para auditar todos los componentes, verificar qué grado
|
|
|
> de personalización soportan y desarrollar una corrección a cada uno de ellos
|
|
|
> para que sean totalmente personalizables.»** Y sobre la ejecución: **«lo
|
|
|
> ejecutará Opus, y Opus falla mucho, por lo que tienes que establecer procesos
|
|
|
> de verificación en todo el plan.»** Este documento obedece a las dos frases:
|
|
|
> §1 es la auditoría MEDIDA (reproducible por script, no por memoria), §5 son
|
|
|
> las fases, y §7 es el protocolo de verificación que cada sesión ejecuta sin
|
|
|
> excepción.
|
|
|
>
|
|
|
> **Kickoff para sesión nueva**: _«Lee `docs/process/PLAN-theming.md` ENTERO y
|
|
|
> después `CONTINUE-theming.md`; si las D-TH de §4 están firmadas, ejecuta el
|
|
|
> siguiente bloque de §5 con el protocolo de §7, un componente por commit; si
|
|
|
> no, PARA y preséntalas una a una.»_
|
|
|
>
|
|
|
> Fuentes de doctrina que este plan cita y NO copia:
|
|
|
> [`docs/theming/reference.md`](../theming/reference.md) §1bis, §3, §5, §6,
|
|
|
> §7, §12, §16 · [`docs/canon/tsc.md`](../canon/tsc.md) ·
|
|
|
> [`docs/canon/recipe-contract.md`](../canon/recipe-contract.md) §1–§5 ·
|
|
|
> [`docs/theming/motion.md`](../theming/motion.md) §"When both write
|
|
|
> `animation` on ONE node" · [`docs/guides/component-guide.md`](../guides/component-guide.md)
|
|
|
> §Build contract · [`src/uix/eidos/components/README.md`](../../src/uix/eidos/components/README.md)
|
|
|
> · el precedente ejecutado y firmado: [`PLAN-sidebar.md`](./PLAN-sidebar.md)
|
|
|
> §3 + F3 (el eje `size` de la fila, 2026-08-19) y `navigation-menu`
|
|
|
> (`ae9e277fa` · `a82794845`, el cromo del trigger en tokens públicos).
|
|
|
|
|
|
---
|
|
|
|
|
|
## 0. Veredicto corto
|
|
|
|
|
|
1. **La doctrina ya lo exige; los guards no lo comprueban.** recipe-contract §1:
|
|
|
«Every recipe declares its knobs in `lib/recipes/base.ts`»; theming §6: el
|
|
|
token público de componente es `--{c}-{slot}`; la TSC decide dónde se emite.
|
|
|
Pero R-1…R-4 comprueban que **no haya literales** (y que lo que haya sea un
|
|
|
`var(`), no que cada knob sea **alcanzable por un tema**. Una receta con
|
|
|
todo en `var(--radius-md)` y en privados `--_{c}-*` pasa `component:audit`
|
|
|
en PASS y la dimensión 10 «Adopción theming» de la ficha en ✓ — y sólo se
|
|
|
puede temar moviendo el planeta. Es un error de framework porque rompe la
|
|
|
promesa que el framework hace por escrito.
|
|
|
2. **Medido, no opinado** (§1, `scripts/theming-census.ts`): de 5.205 knobs
|
|
|
de apariencia en 162 recetas, **1.621 (33 %) pasan por un token público del
|
|
|
componente**; 1.880 atan directo a un primitivo global; 856 a privados;
|
|
|
614 son literales. **62 componentes no tienen una sola entrada en el
|
|
|
contrato**; 59 tienen alcance < 20 %; 6 están al 100 %. `navigation-menu`,
|
|
|
tras el trabajo de hoy, está en 44 %: el eje no se cierra arreglando un
|
|
|
componente.
|
|
|
3. **La corrección es mecánica y ya tiene forma firmada**: la de la fila del
|
|
|
`Sidebar` (D-SB.5/D-SB.6, `PLAN-sidebar.md` §3) y la del trigger del nav
|
|
|
(`ae9e277fa`): tokens públicos por talla que apuntan al bundle
|
|
|
`--size-{k}-*`, nombre RESUELTO por `data-size`, acentos de estado en
|
|
|
`background-color`, y **el default queda idéntico** — sólo cambia quién
|
|
|
puede moverlo. Lo que NO hay que hacer: rediseñar nada por el camino.
|
|
|
4. **Sin guard no hay cierre**: el censo de hoy se repetirá en seis meses si
|
|
|
R-5 no existe. F0 crea el guard en `warn` con la cifra de hoy como suelo; F3
|
|
|
lo gradúa a `error` cuando el backfill termina. Igual que hizo R-4.x el
|
|
|
2026-07-02.
|
|
|
|
|
|
---
|
|
|
|
|
|
## 1. Inventario medido (2026-08-19)
|
|
|
|
|
|
**Instrumento**: `node --import tsx/esm scripts/theming-census.ts` (añadido
|
|
|
con este plan; `--json` para máquina; `--only {c}` por componente). Cuenta, por
|
|
|
receta CSS, cada declaración de APARIENCIA (lista `KNOB_PROPS` en el script:
|
|
|
fondo, tinta, borde, radio, sombra, padding, gap, tipografía, tamaño, opacidad,
|
|
|
fill/stroke, filtros) y la clasifica por el ORIGEN de su valor:
|
|
|
|
|
|
| Clase | Qué es | ¿La alcanza un tema de componente? |
|
|
|
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
|
|
|
| `public` | `var(--{c}-…)` — token del contrato del componente | **Sí** |
|
|
|
| `private` | `var(--_{c}-…)` — nombre interno | No (salvo que el privado DERIVE de un público — el script no lo distingue, cuenta como no) |
|
|
|
| `global` | cualquier otro `var(--…)`: `--space-*`, `--radius-*`, `--color-*`, `--font-size-*`, `--size-*`… | Sólo moviendo el sistema |
|
|
|
| `literal` | sin `var(`: `8px`, `1.25`, `#fff` | No, y además viola R-4/R-2 |
|
|
|
| `system` | sistemas transversales que una receta CONSUME: capa de estado, anillo de foco, planos de depth, motion, bandas z, opacidad, shape, `floating-gap` | Sí, **a nivel de sistema**, por diseño (recipe-contract §2) — fuera del ratio |
|
|
|
|
|
|
**Alcance** = `public / (public + private + global + literal)`.
|
|
|
|
|
|
### 1.1 Totales
|
|
|
|
|
|
| Medida | Valor |
|
|
|
| -------------------------------------- | ---------------- |
|
|
|
| Componentes con receta CSS | 162 |
|
|
|
| Knobs de apariencia | 5.205 |
|
|
|
| Por token público del componente | **1.621 (33 %)** |
|
|
|
| Por privado | 856 |
|
|
|
| Directo a primitivo global | 1.880 |
|
|
|
| Literales | 614 |
|
|
|
| Sistema transversal (fuera del ratio) | 234 |
|
|
|
| **Sin ninguna entrada en el contrato** | **62** |
|
|
|
| Alcance < 20 % | 59 |
|
|
|
| Alcance = 100 % | 6 |
|
|
|
| Con eje `data-size` en la receta | 82 |
|
|
|
|
|
|
### 1.2 Por familia (propuesta de familias en D-TH.4 — el autor la firma o la cambia)
|
|
|
|
|
|
| Familia | Comp. | Knobs | Alcance | Sin contrato | Fuera del contrato |
|
|
|
| ----------------------------------- | ----: | ----: | ------: | -----------: | -----------------: |
|
|
|
| Tiempo (chronos · fecha/hora) | 15 | 879 | 9 % | 9 | 774 |
|
|
|
| Campos | 24 | 905 | 38 % | 9 | 526 |
|
|
|
| Controles · marcas | 33 | 867 | 39 % | 9 | 502 |
|
|
|
| Menús · listas · navegación | 24 | 735 | 37 % | 10 | 432 |
|
|
|
| Superficies · overlays · estado | 34 | 807 | 45 % | 10 | 429 |
|
|
|
| WIP (`palabras`) | 1 | 471 | 22 % | 1 | 363 |
|
|
|
| Texto · tipografía | 12 | 238 | 9 % | 10 | 217 |
|
|
|
| Media · chat | 9 | 283 | 61 % | 1 | 104 |
|
|
|
| Layout (primitivos) | 9 | 14 | 93 % | 3 | 1 |
|
|
|
| (`separator`, sin familia asignada) | 1 | 6 | 67 % | 0 | 2 |
|
|
|
|
|
|
### 1.3 Los tres defectos que el censo NO ve y la ejecución sí tiene que mirar
|
|
|
|
|
|
El script es un regex sobre texto: sobre-reporta, nunca infra-reporta. Tres
|
|
|
clases de defecto de theming que un alcance del 100 % no garantiza:
|
|
|
|
|
|
- **Privado que no deriva de un público** (`--_c-radius: var(--radius-default)`):
|
|
|
cuenta como `private`; la corrección es que el privado lea el público o
|
|
|
desaparezca.
|
|
|
- **Velo o acento en el nodo equivocado**: `archetype: 'item'` en un `<li>`
|
|
|
envoltorio (`navigation-menu`, `822b78cf2`), o el shorthand `background`
|
|
|
matando la capa de estado (`Sidebar` F3, `navigation-menu` `ae9e277fa`). No
|
|
|
es un knob: es un nodo. Se detecta midiendo desde el píxel hacia arriba (§7.3).
|
|
|
- **Doble animación al mover un sello** a una superficie con animación propia
|
|
|
(`navigation-menu` `822b78cf2`: `present-rise` + la entrada de receta). Se
|
|
|
detecta con un registro de `animationstart/end`, no con `getComputedStyle`.
|
|
|
|
|
|
### 1.4 Tabla completa por componente
|
|
|
|
|
|
Al final del documento (§9), ordenada por alcance. Se REGENERA con el script
|
|
|
en cada bloque; no se edita a mano.
|
|
|
|
|
|
---
|
|
|
|
|
|
## 2. Contrato objetivo — qué significa «totalmente personalizable» (los cuatro ejes)
|
|
|
|
|
|
Un componente es personalizable cuando un tema puede moverlo **sin tocar el
|
|
|
sistema ni la receta**, en estos ejes:
|
|
|
|
|
|
| Eje | Mecanismo canónico | Cómo se comprueba |
|
|
|
| -------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
|
| **A · Tokens** (forma, color, espacio, tipografía) | todo knob de apariencia lee `--{c}-{slot}` del contrato (`recipes/base.ts`), nombre RESUELTO por talla/estado; los privados sólo derivan de públicos | censo al 100 % **+** prueba de centinela (§7.4) |
|
|
|
| **B · Talla** | `size` → `data-size` en el wrapper; tokens `{part}-{eje}-{k}` apuntando al bundle `--size-{k}-*` (theming §5; recipe-contract §1) | computed por talla = bundle; `md` idéntico al default anterior |
|
|
|
| **C · Color / variante** | `data-color` / `data-variant` vía paleta (`--{c}-{role}-{slot}`, `--{c}-palette-*`), los 9 roles (theming §4) | cada variante lee tokens, ninguna un `--scale-*` (R-4.6) |
|
|
|
| **D · Estados** | hover/press/selected neutros = la capa del sistema en el nodo CON forma; acentos de estado (`on-bg`…) en `background-color` para que la capa componga | `background-image` presente en hover, `<li>`/envoltorios sin velo, abierto + hover = acento + capa |
|
|
|
|
|
|
**Regla de oro del eje**: **el default no cambia.** Cada componente se mide
|
|
|
antes y después en sus estados (reposo · hover · activo/abierto · disabled ·
|
|
|
foco) y tallas, y el diff de computed styles es **cero** salvo donde una
|
|
|
decisión firmada diga lo contrario. Este eje mueve QUIÉN puede cambiar cada
|
|
|
cosa, no QUÉ se ve.
|
|
|
|
|
|
---
|
|
|
|
|
|
## 3. Contrato objetivo — la regla R-5 «alcance de tema»
|
|
|
|
|
|
Nueva regla de `component-audit` (familia R-5), misma mecánica que R-4.x:
|
|
|
|
|
|
- **R-5.1** — Toda declaración de apariencia (`KNOB_PROPS`) en una receta lee
|
|
|
(a) un público `var(--{c}-…)`, (b) un privado `--_{c}-*` cuya definición en
|
|
|
la misma receta lee un público, o (c) un token de sistema transversal (la
|
|
|
lista `SYSTEM` del censo). Otra cosa es fallo.
|
|
|
- **R-5.2** — Todo componente con receta tiene entrada en `recipes/base.ts`.
|
|
|
- **R-5.3** — Los nombres de los tokens siguen recipe-contract §1 (ejes
|
|
|
lógicos, `{part}-{eje}-{k}`) y theming §6 regla 7 (slots de color: `bg, fg,
|
|
|
border, on-bg, on-fg, on-border, hover-bg, on-hover-bg`). **Hoy no se
|
|
|
cumple** ni en recetas viejas (`tabs`: `trigger-color-*`) ni en las de hoy
|
|
|
(`navigation-menu`: `trigger-bg-active`, `trigger-color-active`) — ver
|
|
|
D-TH.6.
|
|
|
- **Válvula** (recipe-contract §3): `R-5.1 exception: <razón>` en el README
|
|
|
del componente, greppable, UNA por knob o grupo de knobs con la razón (p. ej.
|
|
|
«glifo ∝ diámetro, excepción canónica avatar/marker»). Sin razón escrita no
|
|
|
hay excepción.
|
|
|
- **Severidad**: `warn` desde F0 con el suelo del censo; `error` en F3 (D-TH.7
|
|
|
— firmada con enmienda: **R-5.3 gradúa a `error` directo tras el codemod**,
|
|
|
su deuda muere en el mismo pass; R-5.1/5.2 esperan F3).
|
|
|
|
|
|
---
|
|
|
|
|
|
## 4. Decisiones que firma el autor (una por mensaje, con sus cinco preguntas)
|
|
|
|
|
|
| Id | Decisión | Propuesta | Estado |
|
|
|
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
|
| **D-TH.1** | ¿R-5 es regla DURA? («todo knob público salvo sistema transversal o excepción firmada») | Sí. Es lo que recipe-contract §1 ya dice sin guard. | **FIRMADA 2026-08-20** tal cual. Ancla: la medición 2026-07-01 (canon sin guard deriva 30-85 %) y el mandato origen del eje. |
|
|
|
| **D-TH.2** | Perímetro de «knob» | La lista `KNOB_PROPS` del script (apariencia; layout fuera). Cambios a la lista = cambio del guard, firmados aquí. | **FIRMADA 2026-08-20** con la opción (b) de la ficha `heading`: la familia tipográfica B5 mide su superficie por `--style-*` como sistema transversal (verdad estructural — la vertebración tipográfica RECHAZA acoplar componentes a la capa semántica; acuñar `--heading-*` = 36 alias de una capa ya pública, la clase que §39 mató). No se acuñan `--{c}-*` para los primitivos tipográficos. |
|
|
|
| **D-TH.3** | Tracks WIP (`palabras`, `words`, `chronos` y su familia de fecha/hora) | En el CENSO siempre; en R-5 `error` sólo cuando salgan de su carril (coherente con R-4.x, que los excluye). | **FIRMADA 2026-08-20** tal cual. |
|
|
|
| **D-TH.4** | Familias y ORDEN del backfill | El de §5 F2: menús/navegación → campos → controles → superficies → texto → media/chat → tiempo (el último por ser el más grande y estar en carril propio). Dentro de cada familia, sin contrato primero, luego por knobs fuera del contrato. | **FIRMADA 2026-08-20** con enmienda: la cola REVISADA del CONTINUE (fichas con veredicto §5 verificado) tiene prioridad sobre el orden de familias — trabajo revisado no se deja enfriar. |
|
|
|
| **D-TH.5** | El default NO cambia en este eje | Sí. Toda mejora visual que aparezca se anota como deuda y se firma aparte (como hoy con `navigation-menu`). | **FIRMADA 2026-08-20** sin matices — es lo que hace verificable el eje (diff de computed = 0 como gate). Única excepción viva: la migración hover→capa de estado, firmada aparte el mismo día (ver «Firmas del 2026-08-20» del CONTINUE), que mueve píxel con captura y diff explicado. |
|
|
|
| **D-TH.6** | Vocabulario de slots (R-5.3): ¿se NORMALIZAN los nombres que ya se desvían (`trigger-color-*` de `tabs`, `*-bg-active`/`*-color-active` del nav de hoy, …) con un codemod value-preserving como el de px/py del 2026-07-06? | Sí, en F1, ANTES del backfill — si no, el backfill escribirá más nombres fuera de vocabulario. Inventario exacto de desviaciones sale en F0 (el censo añade `--names`). | **FIRMADA COMPLETA 2026-08-20**, en dos actos. (1) El slot de tinta es **`fg`**; `color` como slot MUERE (196 claves cola). Razón: el principio de plataforma del 2026-07-06 gobierna los ejes DIMENSIONALES, no la pareja `bg`/`fg` (si gobernara, `bg` sería `background-color`); `color` colisiona con `--color-*`, `data-color` y los 9 roles; `on-fg` compone. (2) Modificador recipe-level DELANTE — regla: **delante lo interactivo, detrás lo dimensional y contextual** (`hover-bg` pero `control-height-md`, `scrim-fg-over-dark`); rol/paleta conserva su gramática propia (detrás, `COLOR_ROLE_SLOTS` — las 47 `{rol}-{slot-de-rol}` son canónicas). Modificador válido ∈ vocabulario universal (+`current`, aria) ∪ valores `data-state`/ejes del MORFO del componente (así `partial` de rating-group y `read/failed` de chat-message validan contra el compilado, igual que la parte). `waveform.played/buffered` = pseudo-partes eidos-only (`played-fg`). Los hovers neutros se EXCLUYEN del codemod: migran a la capa de estado (firma aparte, mismo día). Detalle operativo: CONTINUE §«Mañana». |
|
|
|
| **D-TH.7** | Cuándo gradúa R-5 a `error` | Cuando el censo global dé 100 % o excepción documentada (F3), nunca antes de terminar F2 — un `error` a medio backfill rompe el `component:audit` de todo el parque. | **FIRMADA 2026-08-20** con enmienda: **R-5.3 (gramática de nombres) gradúa a `error` DIRECTO tras el codemod** — su deuda muere en el mismo pass (precedente R-4.4, «sin allowlist»). R-5.1/R-5.2 esperan F3 como propone la fila. |
|
|
|
| **D-TH.8** | ¿Entra la exposición en la demo de temas (`/temas`: un panel que liste los tokens públicos por componente y permita moverlos)? | Sí pero DESPUÉS (F4, opcional): es la prueba viva de A; sin el backfill no hay nada que exponer. | **FIRMADA 2026-08-20** tal cual — el instrumental existe (`listRecipes()` / `getRecipeTokens()`; la ruta `/temas` existe). |
|
|
|
|
|
|
---
|
|
|
|
|
|
## 5. Fases y gates
|
|
|
|
|
|
Cada fase: **qué leer ANTES** (entero), **qué producir**, **guard**. Ninguna
|
|
|
arranca sin la anterior en verde. Todo bloque de F2 ejecuta el protocolo de §7
|
|
|
**por componente**, sin atajos: es la parte del plan que existe porque «Opus
|
|
|
falla mucho».
|
|
|
|
|
|
### F0 — Instrumento + guard en `warn` (una sesión)
|
|
|
|
|
|
- Leer: theming §1bis, §3, §5, §6, §7, §12, §16 · tsc.md entero ·
|
|
|
recipe-contract §1–§5 · `scripts/component-audit.ts` (cómo se declara una
|
|
|
regla R-x, `readmeException`, severidades) · `src/uix/eidos/recipe-css-contract.test.ts`
|
|
|
(qué ya guarda) · `PLAN-sidebar.md` §3 y F3 · este plan entero.
|
|
|
- Producir: (a) `scripts/theming-census.ts` endurecido: `--names` (inventario
|
|
|
de nombres de token fuera del vocabulario §1/§6.7), detección «privado que
|
|
|
deriva de público» (leer `--_c-x: var(--c-y)` en la misma receta y
|
|
|
reclasificar), salida `--json` estable; (b) **R-5.1/5.2/5.3 en
|
|
|
`component-audit`** con severidad `warn` y la válvula `R-5.x exception:`;
|
|
|
(c) `docs/theming/reference.md` §12 (tabla de tooling) gana la fila del censo;
|
|
|
(d) **HECHO 2026-08-22** — `src/uix/eidos/theming-reach-floor.test.ts`, que
|
|
|
**fija el suelo**: alcance global ≥ el de hoy (33 %) y literales ≤ 614 — el
|
|
|
número SUBE o el test falla (muta-prueba: meter un literal en una receta y ver
|
|
|
el rojo antes de dar el test por bueno — memoria `a-guard-that-inspects-nothing-passes`.
|
|
|
Ya pasó una vez HOY: la primera versión del censo no contaba una regla de una
|
|
|
sola línea, y la mutación `padding-inline: 8px` no movió la cifra; se endureció
|
|
|
el regex y la mutación pasó a 6→7→8).
|
|
|
- Guard: `node --import tsx/esm scripts/theming-census.ts` reproduce §1.1 a
|
|
|
la cifra · `npm run component:audit` NO añade ningún `error` (sólo `warn`) ·
|
|
|
`npx vitest run src/uix/eidos` sin nuevos rojos (el rojo conocido es
|
|
|
`skin-media-player`, ajeno) · `npm run check` con cero errores en los
|
|
|
ficheros tocados (§7.6).
|
|
|
|
|
|
### F1 — Doctrina + vocabulario (una sesión)
|
|
|
|
|
|
- Leer: F0 + theming §6 (reglas estrictas) + el codemod del 2026-07-06
|
|
|
(recipe-contract §1, bloque «Normalización ejecutada») como molde.
|
|
|
- Producir: recipe-contract §1 gana la regla R-5 (y §2 una fila «Alcance de
|
|
|
tema»), §4 la tabla de enforcement, §5 el checklist (punto 12: «censo del
|
|
|
componente al 100 % o excepción»); theming §6 referencia cruzada; el
|
|
|
checklist de cierre (`docs/guides/completion-checklist.md`) y el
|
|
|
`COMPONENT_AUDIT_GUIDE` endurecen las dimensiones 5 y 10 («usa tokens» ≠
|
|
|
«es temable»: la ficha exige el % del censo). **D-TH.6**: codemod
|
|
|
value-preserving de los nombres fuera de vocabulario (lista de F0), con
|
|
|
`generated/base.css` regenerado y diff = renombres 1:1, computed idéntico en
|
|
|
navegador (mismo triple muro que px/py).
|
|
|
- Guard: `docs:check` 0 · el diff de `generated/base.css` son SOLO renombres ·
|
|
|
censo idéntico antes/después del codemod (un rename no cambia el alcance) ·
|
|
|
sonda de computed en 3 componentes renombrados = idéntico.
|
|
|
- **Repaso de lo ya ejecutado (2026-08-20)**: firmar una gramática obliga a
|
|
|
releer lo corregido ANTES de ella. Auditados los 7 de §8 contra `fg` +
|
|
|
familias (`scripts/__names-audit7.ts`): 6 limpios, y una sola corrección —
|
|
|
`gradient-builder.checker-color` → `checker-fg` (slot, no sustantivo; 4
|
|
|
consumos en `gradient-builder.css`). Las 4 claves `stop-color-*` del mismo
|
|
|
componente son falso amigo verificado (`stop-color` es la PARTE) y NO se
|
|
|
tocan. La corrección entra DENTRO del codemod. Detalle y tabla:
|
|
|
[`CONTINUE-theming.md`](./CONTINUE-theming.md) §«Primera posición».
|
|
|
|
|
|
### F2 — Backfill por familias (6–8 bloques de sesión; **un componente = un commit**)
|
|
|
|
|
|
Orden propuesto (D-TH.4). Dentro de cada bloque: sin contrato primero, luego
|
|
|
por knobs fuera del contrato. Cada componente sigue §7 entero.
|
|
|
|
|
|
| Bloque | Familia | Comp. | Knobs fuera | Entran primero (sin contrato) |
|
|
|
| ------ | ----------------------------------------------------- | ----: | ----------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
|
| B1 | Menús · listas · navegación | 24 | 432 | `command`, `listbox`, `table`, `tree-grid`, `tree-view`, `grid-list`, `virtual-list`, `virtual-grid`, `menu-dial`, `feed` — y `navigation-menu` (44 %) hasta el 100 % |
|
|
|
| B2 | Campos | 24 | 526 | `combobox` (1), `textarea`, `css-field`, `mask-field`, `number-field`, `field-langs`, `gradient-builder`, `gradient-picker`, `label` |
|
|
|
| B3 | Controles · marcas | 33 | 502 | `knob`, `avatar`, `kbd`, `link`, `mark`, `highlight`, `clipboard`, `proof-of-human`, `aspect-ratio` |
|
|
|
| B4 | Superficies · overlays · estado | 34 | 429 | `alert-dialog`, `announce`, `carousel`, `link-preview`, `skeleton`, `spinner`, `scroll-frames`, `motion`, `mockup`, `cascade`, `card-group` |
|
|
|
| B5 | Texto · tipografía | 12 | 217 | `heading`, `text`, `s-text`, `display`, `code`, `code-block`, `text-*` (los que no tienen contrato) |
|
|
|
| B6 | Media · chat | 9 | 104 | `skin-media-player` |
|
|
|
| B7 | Tiempo (chronos · fecha/hora) — **si D-TH.3 lo mete** | 15 | 774 | `range-calendar`, `month-grid`, `year-grid`, `date-picker`, `date-range-picker`, `time-picker`, `time-range-picker`, `natural-time-picker`, `picker-shell` |
|
|
|
| B8 | `palabras` — **si D-TH.3 lo mete** | 1 | 363 | — |
|
|
|
|
|
|
Por componente se produce: entrada (o ampliación) en `recipes/base.ts` con los
|
|
|
nombres de §1/§6.7 — dimensionales por talla si el componente tiene `size`
|
|
|
(patrón `Sidebar`: `{part}-{eje}-{k}` + nombre resuelto con `declarations` por
|
|
|
`scope: 'size:{k}'`), colores por rol/slot, acentos de estado; la receta
|
|
|
consume SOLO nombres resueltos (nunca un primitivo crudo, nunca un literal);
|
|
|
privados sólo si derivan de públicos; `generated/base.css` regenerado por el
|
|
|
script (**jamás a mano**, theming §16 F); README de eidos con la tabla de
|
|
|
tokens («Talla y tema», molde: `navigation-menu`); registro en §8.
|
|
|
|
|
|
- Guard por componente: §7 entero, y el censo `--only {c}` al **100 %** (o
|
|
|
`R-5.x exception:` con razón) — si no llega, el commit NO se hace.
|
|
|
- Guard por bloque: **revisión adversarial** (§7.7) antes de dar el bloque por
|
|
|
cerrado: un pase escéptico por componente que intente REFUTAR «el default es
|
|
|
idéntico» y «cada token alcanza» con medición propia, no con la del autor
|
|
|
del commit.
|
|
|
|
|
|
### F3 — R-5 a `error` + cierre (una sesión)
|
|
|
|
|
|
- Producir: severidad `error` en R-5.1/5.2/5.3 (D-TH.7); el test del suelo
|
|
|
pasa a exigir 100 % global (o excepciones listadas); theming §12 y
|
|
|
recipe-contract §4 lo reflejan; `CONTINUE-theming.md` cerrado.
|
|
|
- Guard: `component:audit` PASS en los 162 · censo 100 % · `docs:check` 0.
|
|
|
|
|
|
### F4 — Exposición en la demo de temas (opcional, D-TH.8)
|
|
|
|
|
|
- Producir: en `/temas` (o en cada demo) un panel que lista los públicos del
|
|
|
componente desde `recipes/base.ts` y los mueve en vivo — la prueba viva del
|
|
|
eje A, y el detector de tokens que no alcanzan (mover y que nada cambie).
|
|
|
- Guard: mover cada token del componente en la demo y ver cambiar el computed
|
|
|
(automatizable con el centinela de §7.4).
|
|
|
|
|
|
---
|
|
|
|
|
|
## 6. Deuda transversal que este plan destapa — NO se ejecuta aquí
|
|
|
|
|
|
| Id | Dónde | Qué |
|
|
|
| ---------- | ----------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
|
| **T-TH.1** | `component-audit` dims 5 y 10 | Dan ✓ a «usa tokens»; el criterio se endurece en F1. Las fichas ya escritas (`docs/audit/components/*.md`) quedan con el ✓ viejo: se corrigen al pasar cada componente por F2, no en masa. |
|
|
|
| **T-TH.2** | Vocabulario de slots (theming §6.7) | Existe y no se guarda: `tabs` (`trigger-color-*`), `navigation-menu` (`-bg-active`, `-color-active`) y más lo incumplen. D-TH.6. |
|
|
|
| **T-TH.3** | `menubar` | Misma clase que el nav: cromo de barra en privados («the bar itself styles via foundation privates», `recipes/base.ts`) + `commit-select` en el trigger al DESPLEGAR (otra sesión, sema). |
|
|
|
| **T-TH.4** | `archetype: 'item'` en envoltorios | Hay que censar qué otras partes `<li>`/wrapper lo declaran (memoria `archetype-item-pulls-interactive-styling`: Timeline, Breadcrumb, NavigationMenu ya corregidos). Un guard de morfo («un `item` no envuelve a un `trigger`») es candidato. |
|
|
|
| **T-TH.5** | `--control-height-*` en `:root` (T-6 del sidebar) | La densidad/zoom por SUBÁRBOL no re-deriva; afecta a la promesa de theming «por ámbito». Eje de theming aparte. |
|
|
|
| **T-TH.6** | 25 knobs visuales fuera del morfo (`component-visual-attrs`, eje Affix) | Filas sin firmar `image/skeleton/qr-code/s-text`. El eje C (variantes) depende de ellas. |
|
|
|
|
|
|
---
|
|
|
|
|
|
## 7. PROTOCOLO DE VERIFICACIÓN — por componente, sin excepciones
|
|
|
|
|
|
Existe porque el que ejecuta falla, y porque en un solo día (2026-08-19,
|
|
|
`navigation-menu`) cuatro de estos pasos ausentes costaron cuatro commits de
|
|
|
corrección: se dio por arreglado un hover leyendo el nodo equivocado; se
|
|
|
resolvió un doble de animación en la dirección contraria a la doctrina; se
|
|
|
inventó un hover por componente; y se declaró «idéntico» sin captura. Cada paso
|
|
|
tiene un **artefacto** (número, captura, salida de comando) que va al mensaje
|
|
|
de commit. Sin artefacto, el paso no se ha hecho.
|
|
|
|
|
|
### 7.1 Antes de tocar el componente (las cinco preguntas + lectura)
|
|
|
|
|
|
1. Las cinco preguntas del autor, UN componente por mensaje cuando haya
|
|
|
decisión (nombres fuera de vocabulario, una excepción, un default que
|
|
|
parece defecto): qué soluciona · leído todo o presupuesto · qué afecta ·
|
|
|
qué doctrina · qué modificaciones. Si no hay decisión nueva (el componente
|
|
|
sólo necesita tokens con nombres canónicos), se ejecuta sin preguntar y se
|
|
|
reporta.
|
|
|
2. Leer ENTEROS: la receta del componente, su entrada en `recipes/base.ts`,
|
|
|
su README de eidos y de soma, su morfo (¿qué partes llevan arquetipo?), su
|
|
|
ficha en `docs/audit/components/`. Y la doctrina de §0 (fuentes) si la
|
|
|
sesión no la ha leído hoy.
|
|
|
3. `git status` + `git log -1`: ¿hay otra sesión con el árbol sucio?
|
|
|
**Nunca `git stash`** para medir una base (le arranca el trabajo a otro).
|
|
|
|
|
|
### 7.2 Medir ANTES (el suelo del «idéntico»)
|
|
|
|
|
|
4. `node --import tsx/esm scripts/theming-census.ts --only {c}` → guardar la
|
|
|
línea.
|
|
|
5. Sonda Playwright **headless desde la raíz del repo** (la pantalla oculta
|
|
|
congela rAF; `playwright` no resuelve desde el scratchpad) contra la demo
|
|
|
del componente: para cada parte visible y cada talla, computed de los
|
|
|
knobs (`backgroundColor`, `backgroundImage`, `color`, `borderRadius`,
|
|
|
`padding*`, `fontSize`, `lineHeight`, `blockSize`/`inlineSize`,
|
|
|
`boxShadow`, `borderColor`) en reposo · hover · activo/abierto ·
|
|
|
disabled · `:focus-visible`. Muestrear FUERA de callbacks de
|
|
|
`MutationObserver` (miden el instante anterior al flush). Guardar JSON.
|
|
|
6. Captura 2× de la demo en reposo y en hover (sirve de «antes» para la
|
|
|
comparación a ojo).
|
|
|
|
|
|
**6.bis — CUENTA LOS NODOS ANTES DE CREER NADA.** La sonda imprime cuántos mide;
|
|
|
el guard, cuántos tokens mueven. Un recuento de 0–2 nodos, o un 0/N del guard, NO
|
|
|
es un resultado: es el instrumento ciego. Las siete causas medidas hasta el
|
|
|
2026-08-23, con el interruptor que las arregla (todos en `COMPONENT_OVERRIDES`
|
|
|
del guard y en `EXTRA_NODES`/`DEMO_VARIANTS` de la sonda):
|
|
|
|
|
|
| síntoma | causa | interruptor |
|
|
|
| --- | --- | --- |
|
|
|
| 0 nodos, ruta 404 | el componente **no tiene demo** (picker-shell, mockup, surface, audio-player) | `urls: ['/ruta/donde/sí/vive']` |
|
|
|
| 0–2 nodos con la página llena | sus partes **no llevan `data-{c}-*`**: hooks de clase (onion-menu, prose) o partes de OTRO chasis (audio-player) | `extraNodes` / `EXTRA_NODES` |
|
|
|
| la superficie no está en el DOM | abre por **hover**, no por clic (tooltip, link-preview) | `openBy: 'hover'` |
|
|
|
| la superficie se CIERRA sola | nace abierta y el guard la pulsa (onion-menu) | `openMarker` |
|
|
|
| media docena de tokens muertos por variante | el panel/skin sólo existe tras un **chip de la demo** | `openWith` + `DEMO_VARIANTS` |
|
|
|
| todos los tonos muertos | la paleta resuelve por `data-color` **o `data-intent`**, y por VARIANTE | barrido de tono (automático) + `sweepAttr` |
|
|
|
| `TimeoutError` antes de medir | la página **nunca alcanza `networkidle`** (image reintenta un `src` roto) | caída a `load` (automática) |
|
|
|
|
|
|
**Y tres lecturas que mienten aunque el nodo esté bien**: una propiedad EN
|
|
|
TRANSICIÓN devuelve el valor viejo (congela antes de leer, salvo que el token SEA
|
|
|
la transición); un nodo ANIMADO devuelve el valor de la animación (congela
|
|
|
también `animation`, a mano); y `::placeholder` sobre un input sin `placeholder`
|
|
|
devuelve el estilo del ELEMENTO.
|
|
|
|
|
|
### 7.3 Editar (la forma firmada — nada más)
|
|
|
|
|
|
7. Tokens con los nombres de recipe-contract §1 / theming §6.7. Por talla si
|
|
|
hay `size`. Acentos de estado en `background-color`. Hover/press/selected
|
|
|
neutros = la capa del sistema (nunca `background:` a mano, nunca
|
|
|
`background-image: none` para «limpiar», nunca una escalera de color
|
|
|
propia). Privados sólo derivando de públicos. Literales: cero.
|
|
|
8. `npm run generate:eidos-css` y `git diff --stat src/uix/eidos/generated/`:
|
|
|
el diff son SOLO los tokens del componente. Si toca otra cosa, parar.
|
|
|
9. Si un envoltorio lleva `archetype: 'item'`/`'option'`/`'trigger'` sin ser
|
|
|
el interactivo, es una DECISIÓN (morfo): se presenta, no se toca de oficio.
|
|
|
|
|
|
### 7.4 Medir DESPUÉS (los tres artefactos)
|
|
|
|
|
|
10. **Idéntico**: repetir la sonda de 7.2 → diff de computed por parte/estado/talla
|
|
|
= **vacío**. Un solo valor distinto = parar y explicar (o es defecto
|
|
|
previo que se firma, o es error del commit).
|
|
|
11. **Alcanza**: la **prueba de centinela**, que desde 2026-08-21 es el guard
|
|
|
**R-5.4** (`npm run theming:sentinel -- {c} <url>`, doctrina en
|
|
|
recipe-contract §4) — por cada token público, un valor imposible de
|
|
|
confundir (`1234px`, `rgb(1, 2, 3)`, `0.123`) y algún computed tiene que
|
|
|
seguirlo. Si un token no mueve nada, es un token que miente (fantasma,
|
|
|
nombre equivocado, o una cascada que jamás gana) — o su silencio tiene una
|
|
|
razón MEDIDA escrita en el ledger
|
|
|
(`scripts/theming-sentinel-exceptions.ts`): el guard falla con un muerto
|
|
|
sin adjudicar y avisa de excepciones STALE.
|
|
|
12. **Desde el píxel hacia arriba** en los estados de hover: `elementsFromPoint`
|
|
|
en el centro del control y la pila de ancestros con `backgroundImage` /
|
|
|
`backgroundColor` — el velo cae en el nodo CON forma y en ningún
|
|
|
envoltorio (memoria `measure-the-node-the-user-points-at`). Si hay
|
|
|
animación propia y un sello de sema en el mismo nodo, registro de
|
|
|
`animationstart/end` (no `getAnimations` en un solo instante): UNA
|
|
|
entrada por ocurrencia (memoria motion.md §"when both write `animation`").
|
|
|
13. Captura 2× después, al lado de la de antes. Mirarla.
|
|
|
|
|
|
**Nota 2026-08-23 (revisión `REVIEW-theming-2026-08-23.md`, D3)**: los pasos 6 y
|
|
|
13 —las capturas— **no se hicieron en ninguno de los 33 componentes** de los
|
|
|
bloques del 22 y el 23. No se recuperan retroactivamente: para esos, el artefacto
|
|
|
es el diff de computed en vacío más el centinela. **Se exigen desde el siguiente
|
|
|
componente**, y el paso 12 (píxel hacia arriba) es OBLIGATORIO en cuanto el
|
|
|
commit toque una regla `:hover` — que es donde el 2026-08-19 costó cuatro
|
|
|
commits de corrección.
|
|
|
|
|
|
### 7.5 Guards mecánicos (todos, cada componente)
|
|
|
|
|
|
14. `node --import tsx/esm scripts/theming-census.ts --only {c}` → **100 %** o
|
|
|
excepción escrita. Y el global NO baja.
|
|
|
15. `node --import tsx/esm scripts/component-audit.ts --only {c}` → PASS, sin
|
|
|
R-5 nuevos (en `warn` durante F2, pero se listan y se resuelven).
|
|
|
16. `node --import tsx/esm scripts/eidos-lint.ts {c}` → 0 invalid.
|
|
|
17. `npx vitest run src/uix/eidos` → sin rojos nuevos (comparar **por
|
|
|
fichero de test**, no por cifra: el rojo conocido es `skin-media-player`).
|
|
|
18. `npm run rtl:check` 0 · `npm run docs:check` 0 · `npx prettier --check`
|
|
|
en los ficheros tocados (ojo: `autocrlf=true` hace que prettier se queje
|
|
|
del CRLF del checkout — comprobar el contenido normalizado a LF, no el
|
|
|
fichero; git guarda LF).
|
|
|
19. `npm run check`: atribuir errores **por fichero** (`grep ERROR | grep {c}`),
|
|
|
nunca por cifra global; la rama tiene sesiones concurrentes y el total
|
|
|
se mueve solo. Si el log no llega a `COMPLETED`, es `tmp/lexical/`:
|
|
|
relanzar.
|
|
|
|
|
|
### 7.6 Commit (uno por componente)
|
|
|
|
|
|
20. `git add` con rutas EXPLÍCITAS (sólo lo del componente + `recipes/base.ts`
|
|
|
- `generated/base.css` + su README + este plan §8); `git diff --cached --stat`
|
|
|
y `git show :ruta` para verificar el ÁRBOL INDEXADO, no el de trabajo;
|
|
|
`git status` para ver que no entra nada de otra sesión. Mensaje con
|
|
|
`git commit -F fichero` (backticks en `-m` se ejecutan en bash), en
|
|
|
castellano, con: qué knobs entran, la cifra del censo antes → después,
|
|
|
el diff de computed (vacío), el centinela (n tokens probados), los
|
|
|
guards. **Nunca `--amend`** en la rama compartida.
|
|
|
21. Registro en §8 de este plan (componente · commit · censo antes→después ·
|
|
|
excepciones) y, si el bloque cierra, en `CONTINUE-theming.md`.
|
|
|
|
|
|
### 7.7 Revisión adversarial por bloque
|
|
|
|
|
|
22. Al cerrar un bloque, una pasada escéptica (otra sesión o un pase separado)
|
|
|
que por componente intente REFUTAR con medición propia: «el default es
|
|
|
idéntico» (sonda 7.2 vs 7.4 rehecha, no leída del commit), «cada token
|
|
|
alcanza» (centinela rehecho), «el velo cae donde debe» (píxel arriba),
|
|
|
«no hay doble animación». Hallazgos reales se arreglan en el bloque; los
|
|
|
refutados se anotan. El molde es la revisión del `Sidebar` (21
|
|
|
hallazgos · 17 refutados · 4 reales, `bae03e55c`).
|
|
|
|
|
|
### 7.8 Lo que NO se hace en este eje (y se anota como deuda si aparece)
|
|
|
|
|
|
- Rediseñar un default (radio, color, altura…): deuda firmable, no cambio.
|
|
|
- Tocar sema/morfo salvo un arquetipo en un envoltorio (decisión aparte).
|
|
|
- Cascadear a otro componente «ya que estamos» (memoria `no-cascade-changes`).
|
|
|
- Inventar nombres de token fuera de §1/§6.7, o un hover/estado por componente.
|
|
|
- Editar `generated/base.css` a mano.
|
|
|
- Dar un paso por hecho sin su artefacto.
|
|
|
|
|
|
**Excepción FIRMADA 2026-08-24 — completar una demo que no monta su propio
|
|
|
componente ES instrumento, no diseño.** La regla «las demos quedan FUERA de
|
|
|
este eje» sigue en pie para lo que fue escrita: **un hallazgo de demo o de
|
|
|
harness no se registra ni se mide**, y no se rediseña una demo «ya que
|
|
|
estamos». Pero una demo que sólo menciona en prosa partes que la receta VISTE
|
|
|
y el morfo DECLARA no es un testbed: es una página, y deja tokens vivos sin un
|
|
|
nodo donde probarse (`chat-log`, 2026-08-23: tres de sus seis partes sin
|
|
|
montar, **once claves sin nodo que pintar**). Montarlas está permitido con las
|
|
|
CUATRO condiciones, todas verificables:
|
|
|
|
|
|
1. Sólo partes o estados **del propio componente**, declarados en su morfo.
|
|
|
Nada de otro componente, nada que el morfo no nombre.
|
|
|
2. **Contenido mínimo canónico**: el ejemplo más corto que hace existir la
|
|
|
parte. Cero diseño nuevo, cero variantes decorativas.
|
|
|
3. **El diff de computed sobre lo que YA estaba montado sigue siendo CERO** —
|
|
|
se mide igual que el resto: la demo crece, lo que ya se veía no se mueve.
|
|
|
4. **Declarado en el mensaje de commit**, con las claves que pasan de «sin
|
|
|
nodo» a medibles.
|
|
|
|
|
|
Fuera de esas cuatro, la demo no se toca desde este eje. Y lo que se aprenda
|
|
|
mirando la demo sigue **sin** entrar en el ratio ni en el registro: la
|
|
|
excepción abre la mano para MEDIR, no para contabilizar.
|
|
|
|
|
|
---
|
|
|
|
|
|
## 8. Registro
|
|
|
|
|
|
- 2026-08-24 — **`tags-input` 88 % → 90 % CERRADO** (`92180c390`), contrato 90 →
|
|
|
**91** claves, centinela **63/91** con 28 adjudicadas. Sus **cinco** knobs
|
|
|
fuera de alcance se clasificaron uno a uno ANTES de tocar nada: **uno** era la
|
|
|
COSTURA (`[data-invalid]` leía `var(--color-risk-border)` a pelo → entra como
|
|
|
`invalid-control-border`, con el nombre Y el default de
|
|
|
`field.invalid-control-border`, que tinta la misma parte del mismo chasis; NO
|
|
|
el `risk-border` de la paleta, que la cascada `[data-color]` re-enruta por
|
|
|
instancia y se llevaría con él el estado inválido). Los otros **cuatro son el
|
|
|
mismo puente THM-2** (`--_tags-input-palette-{border,track,text}` en el borde
|
|
|
del control enfocado y en los tres slots de la etiqueta activa): no se
|
|
|
acuñan, así que **90 % es su techo y es doctrina, no deuda**. Sus bloques
|
|
|
`[data-size]` del CSS **se quedan**: aquí NO los emite el TSC (claves de talla
|
|
|
planas, sin `scope: 'size:{k}'`), y retirarlos rompería el eje. **Lo que
|
|
|
enseñó**: (1) **su tinta de etiqueta no ha pintado NUNCA** — el morfo sella
|
|
|
`aria-selected='true'` como LITERAL en cada etiqueta, así que la regla de
|
|
|
`archetypes.css` (0,4,0) gana siempre a `[data-tags-input-item]` (0,1,0) y le
|
|
|
fija `color` y el velo de estado EN REPOSO; medido con `aria-selected=false`
|
|
|
sobre el nodo real, donde `item-fg` alcanza al instante. Tercera ocurrencia de
|
|
|
§12.5 y con cara de a11y (un lector anuncia todas las etiquetas como
|
|
|
seleccionadas) — registrado en next-features §12, no se toca desde este eje;
|
|
|
(2) **el guard se poisona a sí mismo abriendo**: clicar el control estampa
|
|
|
`data-focus` y la regla de foco re-tinta el borde a la misma (0,2,0) pero más
|
|
|
tarde, así que `control-border` —vivísimo— leía muerto (la clase de
|
|
|
`command.input-border`, otra vez). Barrer la AUSENCIA (`null`) de
|
|
|
`data-focus` / `data-invalid` / `data-disabled` lo devuelve: **60/91 → 63/91
|
|
|
sin adjudicar una clave de más**. Diff de computed vacío (2.496 valores × 8
|
|
|
estados en el escenario válido + 459 × 5 tallas × 3 variantes + hover en el
|
|
|
INVÁLIDO, con sonda de un solo uso), captura 2× byte a byte idéntica.
|
|
|
- 2026-08-24 — **`fab` 88 % → 100 %** (`5fd2fcdd8`), contrato 10 → **12** claves,
|
|
|
centinela **11/12** con 1 adjudicada. Dos knobs, y los dos del **pill
|
|
|
extendido**: el FAB circular no declara `padding-inline` ni `gap`, pero la
|
|
|
regla `[data-extended]` sí, y leía `var(--space-5)` / `var(--space-2)` a pelo
|
|
|
— la COSTURA de §2-A, con `global` a CERO. **El nombre lleva el cualificador
|
|
|
DETRÁS** (`padding-inline-extended`, `gap-extended`): `extended` es un MODO,
|
|
|
no un estado interactivo, así que cae en la otra mitad de la frase de D-TH.6,
|
|
|
como `sidebar.width-icon`; un `padding-inline` a secas habría prometido a TODO
|
|
|
FAB un padding que sólo tiene el pill. **Lo que enseñó**: (1) **la composición
|
|
|
no le quita nada, y valía la pena medirlo** — el mismo `<button>` lleva
|
|
|
`data-button` y `data-fab`, que es la forma del hallazgo de `gradient-picker`,
|
|
|
pero las reglas del FAB casan (0,3,0) contra los (0,2,0) del Button y ganan
|
|
|
sea cual sea el orden de carga (padding computado 20px = `--space-5`); (2)
|
|
|
**`lift` es la laguna del guard sobre `translate`** —hermana de la de
|
|
|
`transform` en background / rating-group / card— y trae una trampa nueva: **el
|
|
|
centinela se auto-cancela**, porque un lift de 1234px se lleva el nodo de
|
|
|
debajo del cursor (`:hover` cierto en t+50 ms, falso en t+300, `none` en
|
|
|
t+900), así que ni añadiéndole una pasada de hover se mediría; medido a mano
|
|
|
escribiendo el token ANTES de entrar, `translate: 0px -1234px`; (3) el
|
|
|
instrumento: un FAB es **UN nodo**, su segunda superficie es el hueco de icono
|
|
|
del Button compuesto (`EXTRA_NODES`), y su eje de talla es `data-fab-size`,
|
|
|
**no** `data-size` — con el barrido cartesiano `data-fab-size` ×
|
|
|
`data-extended` el guard pasa de **3/12 a 11/12** sin adjudicar nada de más.
|
|
|
Diff de computed vacío (416 valores × 7 estados en el circular + 188 × 4
|
|
|
tallas + hover en el pill), capturas 2× byte a byte idénticas en las dos
|
|
|
formas.
|
|
|
- 2026-08-24 — **`chat-typing` 89 % → 100 %** (`d39147c11`), contrato 7 → **8**
|
|
|
claves, centinela **8/8** con **cero adjudicadas**. Entra **una** clave y es
|
|
|
la COSTURA: `dot-radius` (`var(--radius-full)`), el único knob que leía el
|
|
|
sistema a pelo. El catálogo corrigió el nombre de la §4 generada —proponía
|
|
|
`indicator-radius`, que nombra por el primer selector de la regla
|
|
|
(`[data-chat-typing-indicator] > span`) cuando el nodo que PINTA es el punto y
|
|
|
el contrato ya habla `dot-size` / `dot-gap` / `dot-fg`: el defecto de
|
|
|
`tree-view` en pequeño. **Lo que enseñó**: (1) **el instrumento veía 3 nodos
|
|
|
de 8** por dos causas sumadas —los tres puntos son `> span` DESNUDOS del
|
|
|
indicador (la clase de la pastilla del separador de `chat-log`) y la demo
|
|
|
arranca con NADIE escribiendo, así que `data-state='idle'` esconde a todos los
|
|
|
hijos (presencia = visibilidad, N-7)—; con el selector extra y un typer
|
|
|
encendido por `prepareWith`, el centinela daba **7/7 antes de tocar el
|
|
|
código**; (2) **un componente cuyo loop de sistema anima `opacity` no puede
|
|
|
cerrar el diff en cero leyendo esa propiedad**: 18 diffs, los 18 de `opacity`
|
|
|
y los 18 en los tres `span[data-animation-style=pulse]`, **reproducidos
|
|
|
corriendo la sonda dos veces sobre el MISMO código** (control `after` vs
|
|
|
`after2`) — la sonda congela `transition`, nunca `animation`. Ninguna otra
|
|
|
propiedad se mueve, la clave tocada es `border-radius`, y las capturas 2×
|
|
|
antes/después son idénticas **byte a byte** (1.568 valores × 7 estados × 8
|
|
|
nodos).
|
|
|
- 2026-08-24 — **`chat-message` 84 % → 100 %** (`f882e1b9d`), el mayor de la
|
|
|
familia chat: contrato 75 → **81** claves, centinela **77/81** con 4
|
|
|
adjudicadas. Diff de computed **vacío** (4.192 valores × 8 estados × 16 nodos)
|
|
|
y capturas 2× idénticas **byte a byte**, en reposo y con la barra tapback
|
|
|
abierta. Entran seis, todas la COSTURA de los seis globales: `focus-radius`,
|
|
|
`mentioned-fg`, `reply-fg`, `reaction-fg`, `reaction-inner-gap` y
|
|
|
`quick-react-radius`. **Lo que enseñó**: (1) **el guard leía 45/75 y las
|
|
|
treinta muertas eran ejes que la demo no enciende** — una fila de chat es una
|
|
|
PILA de superficies opt-in (reply, read-by, entrega, mención) y de ejes de
|
|
|
PRESENTACIÓN (`run`, `direction`, `emphasized`) que la demo arranca en su
|
|
|
posición más pobre; con las cuatro superficies por `prepareWith` y los cinco
|
|
|
ejes barridos como PRODUCTO, **71/75 antes de acuñar nada** (12 → 16 nodos en
|
|
|
reposo, 24 con el panel abierto); (2) **un nombre que YA existe con otro
|
|
|
sentido no se reusa**: `reaction-gap` es el hueco ENTRE chips (se pinta en la
|
|
|
fila `reactions`) y el knob nuevo es el ritmo INTERNO del chip — mismo valor,
|
|
|
dos papeles, así que entra como `reaction-inner-gap`; el resto del bloque
|
|
|
`{parte}-gap` de esta receta significa «dentro de la parte», la anómala es la
|
|
|
vieja y renombrarla es churn con riesgo; (3) **tercera regla `> svg` muerta de
|
|
|
la familia**, retirada con 0 diffs: el `Icon` compuesto escribe
|
|
|
`style="width: var(--icon-size-sm)"` EN LÍNEA y el glifo mide 16 px, no los
|
|
|
15,4 px que `1.1em` prometía (la otra mitad del selector ni siquiera tiene
|
|
|
nodo: los chips llevan emoji de TEXTO); (4) **las cuatro adjudicaciones son
|
|
|
cuatro límites distintos del instrumento** — el guard fotografía UNA esquina
|
|
|
(`borderTopLeftRadius`) y la cola de la burbuja es la de ABAJO; congela la
|
|
|
transición que `emphasize-duration` ES; no hay `:focus-visible` porque la fila
|
|
|
sólo es tabulable compuesta DENTRO de un Feed (medida en la demo de
|
|
|
`chat-log`, donde sí lo es); y `transform` sigue fuera de su lista. **Y un
|
|
|
defecto real medido y NO corregido** (mueve píxel, D-TH.5): el chip de añadir
|
|
|
reacción lleva también `data-popover-trigger`, y
|
|
|
`[data-popover-trigger]:not([data-archetype='field-trigger'])` pesa (0,2,0)
|
|
|
contra los (0,1,0) de la receta, así que su cromo entero lo pinta
|
|
|
`popover.css` — se ve en la captura, los dos chips de reacción son píldoras
|
|
|
redondas y el de añadir un cuadrado gris. Clase `gradient-picker` /
|
|
|
`emoji-picker`; los `reaction-*` no mienten (alcanzan sobre los chips
|
|
|
normales), así que no hay nada que retirar: es una decisión de diseño.
|
|
|
- 2026-08-24 — **`separator` 67 % → 100 %** (`acf9c3a23`), contrato **3** claves
|
|
|
intacto (**cero acuñadas**), centinela **3/3** con **cero adjudicadas**. Su
|
|
|
alcance no subía por falta de tokens: subía **firmando lo que nunca fue un
|
|
|
knob**. Los dos que quedaban fuera eran `inline-size: 100%` en el horizontal y
|
|
|
`block-size: 100%` en el vertical — la IDENTIDAD del primitivo: una regla
|
|
|
ocupa su contenedor, y uno que no lo hiciera sería otro componente (su propio
|
|
|
README ya lo decía en sus Gaps, «Horizontal already fills 100%»). Llevan su
|
|
|
`/* literal: … */` y salen del ratio. Acuñar un `--separator-length` habría
|
|
|
sido inventar un eje que nadie pidió. **Lo que enseñó**: (1) **el techo puede
|
|
|
estar en el contrato que YA existe** — `thickness` (el mismo token alimenta
|
|
|
`block-size` en horizontal e `inline-size` en vertical), `fg` y `min-length`
|
|
|
son toda su apariencia, y el `border: 0` / `flex-shrink: 0` no son apariencia
|
|
|
sino puesta a cero y defensa contra el colapso en un padre flex; (2)
|
|
|
**`min-length` leía MUERTO y no mentía** — la demo arranca en el ejemplo
|
|
|
`stacked`, que monta sólo reglas horizontales, y media receta cuelga de
|
|
|
`[data-orientation='vertical']`; se arregla MIDIENDO, con un `sweepAttr` sobre
|
|
|
`data-orientation` que recorre las dos orientaciones **sobre los mismos
|
|
|
nodos**, no cambiando el chip de la demo al ejemplo `toolbar`, que **cambia
|
|
|
una orientación por la otra en vez de sumarlas** («montar MÁS puede medir
|
|
|
MENOS», otra vez). Diff de computed vacío (448 valores × 7 estados),
|
|
|
capturas 2× antes/después.
|
|
|
- 2026-08-24 — **`image-adjustments` 67 % → 100 %** (`e76d2db2b`), contrato
|
|
|
12 → **16** claves, centinela **15/16** con 1 adjudicada. Las cuatro que
|
|
|
entran son **LA COSTURA** (§2-A) y ninguna un diseño nuevo: `head-gap`
|
|
|
(`--space-2`) y `label-line-height` (`--leading-ui`), que la receta leía a
|
|
|
pelo; `hover-reset-fg` (`--color-content-primary`), que **no es un hover
|
|
|
inventado por componente** sino TINTA —el velo del sistema es
|
|
|
`background-image`, y un control sin superficie no puede recibirlo—; y
|
|
|
`focus-reset-radius` (`--radius-sm`), con el precedente exacto
|
|
|
`rating-group.focus-radius`. El catálogo corrigió DOS nombres de la §4
|
|
|
generada: `item-label-line-height` cuando el bloque ya habla `label-*` para
|
|
|
esa parte, y `reset-radius` cuando el radio sólo existe bajo `:focus-visible`.
|
|
|
Su único literal queda FIRMADO (`outline-color: Highlight` bajo
|
|
|
`@media (forced-colors: active)`: la paleta del SO manda ahí). **Lo que
|
|
|
enseñó**: (1) **medir de MÁS midió menos, y por un tope numérico** — el pase
|
|
|
de hover del guard recorre como mucho **30 nodos**, así que ampliar
|
|
|
`extraNodes` de la fila `hue` a las seis filas llevó el conjunto a 32 nodos y
|
|
|
convirtió al reset en el nº 32: `hover-reset-fg` leía muerto por una razón
|
|
|
ajena al token, y acotar el selector a la fila que la receta realmente
|
|
|
re-tinta lo revivió; (2) `hue-track` leía muerto (11/12) y estaba vivísimo —
|
|
|
pinta en el `::before` del `<Slider>` **compuesto**, cuyo nodo lleva
|
|
|
`data-slider*` y no `data-image-adjustments-*` (la clase de `waveform`); (3)
|
|
|
**el canal de VALOR de un panel de ajustes no toca el CSS** — su salida es la
|
|
|
cadena `filter` que soma entrega por `onFilterChange`, así que aquí no había
|
|
|
nada que confundir con un knob. Píxel hacia arriba sobre la regla `:hover`
|
|
|
tocada: el hover mueve `color` y sólo `color` en el propio `<button>`, sin
|
|
|
`background-image` en él ni en un solo ancestro. Diff de computed vacío
|
|
|
(5.440 valores × 7 estados × 26 nodos), capturas 2× antes/después.
|
|
|
- 2026-08-24 — **`toolbar` 91 % → 94 % CERRADO** (`26713f288`), contrato **54**
|
|
|
claves intacto (cero acuñadas), centinela **52/54** con 2 adjudicadas. **No
|
|
|
había nada que acuñar, y ése es el resultado**: el censo daba `global 0` —la
|
|
|
receta ya lee su contrato en cada declaración, con el eje `size` resuelto por
|
|
|
el TSC a través de siete privados que sólo reapuntan claves públicas por
|
|
|
talla— así que el trabajo fue CLASIFICAR lo que quedaba fuera. Sus dos
|
|
|
privados son **conmutadores por variante**, medidos uno a uno en el nodo real
|
|
|
(`--_toolbar-bg` = `var(--toolbar-bg)` en `surface`, `transparent` en
|
|
|
`outline` y `ghost`; `--_toolbar-shadow` igual con `none`): esa segunda rama
|
|
|
es la **identidad de la variante**, no un knob — una barra `ghost` ES la que
|
|
|
no tiene relleno ni sombra, y un público encima dejaría que un tema la
|
|
|
rellenara. Y su único literal (`inline-size: 100%` del separador horizontal,
|
|
|
el mismo trabajo que `align-self: stretch` en el gemelo vertical, medido 112
|
|
|
px sobre 126) queda FIRMADO y sale del ratio. **Lo que enseñó**: (1) **ceder
|
|
|
el cromo al componente compuesto sale GRATIS** — `Toolbar.Button` compone el
|
|
|
`<Button>` canónico y sus nodos llevan `data-button` Y `data-toolbar-button`,
|
|
|
con `[data-button]` casando a la misma especificidad (0,1,0) pero emitiéndose
|
|
|
DESPUÉS; la diferencia con `form`, que conserva 24 declaraciones que Button
|
|
|
anula, es que esta receta **no escribe ni una regla `[data-toolbar-button]`**
|
|
|
(A-112), así que la cascada del compuesto no le mata una sola clave —medido
|
|
|
ANTES de tocar nada: 51/54, y ninguna de las tres silenciosas era del botón;
|
|
|
(2) el interruptor que revive `disabled-opacity` hay que elegirlo MIRANDO la
|
|
|
regla de hover: encender «group disabled» no tapa nada porque el hover del
|
|
|
bar es `[data-toolbar-link]:hover, [data-toolbar-group-item]:hover:not([data-disabled])`
|
|
|
y el Link no pertenece al grupo — comprobado corriendo el guard antes y
|
|
|
después (51/54 → 52/54, el conjunto muerto encoge en uno y no gana ninguno).
|
|
|
Diff de computed vacío (2.464 valores × 7 estados × 11 nodos), capturas 2×
|
|
|
antes/después.
|
|
|
- 2026-08-24 — **`collapsible` 90 % → 100 %** (`1621de93c`), contrato 11 → **12**
|
|
|
claves, centinela **10/12** con 2 adjudicadas. Una sola clave, y es **la
|
|
|
COSTURA** (§2-A): el `gap` del encabezado leía `var(--space-2)` A PELO, así
|
|
|
que el valor era del sistema y el knob no era de nadie. El nombre lo decidió
|
|
|
el **catálogo**, no la propuesta de la ficha: `trigger-gap` ya existía ocho
|
|
|
veces en `base.ts`, cinco con exactamente ese paso. **Lo que enseñó**: (1) **el
|
|
|
componente que ANIMA su apertura no tiene un solo knob de motion** — su firma
|
|
|
es el par de eventos `emerge-expand` / `emerge-collapse` que materializa
|
|
|
`EidosConfig.motion.signatures`, y la receta no declara un `@keyframes`
|
|
|
(recipe-contract §2, R-4.5), de modo que lo único suyo es el par
|
|
|
`transition-*` que ya estaba en el contrato: el aviso «nunca `@keyframes` en
|
|
|
una receta» aquí no tenía nada que prohibir; (2) **una silenciosa se ARREGLA
|
|
|
antes que adjudicarse, pero eligiendo el interruptor** — encender el
|
|
|
`disabled` de la demo para toda la corrida se habría llevado el tinte de hover
|
|
|
por delante (`pointer-events: none` en el provider, «montar más mide menos»),
|
|
|
así que el estado entra como **superficie extra** por la URL
|
|
|
(`?perm.disabled=true`, precedente `radio-group`) en vez de como línea de
|
|
|
ledger. Las dos que sí se adjudican son `transition-duration` /
|
|
|
`transition-ease`, que SON la transición que el guard congela — medidas sin
|
|
|
congelar sobre el encabezado real (`0.18s ×2 → 4.321s ×2`). Diff de computed
|
|
|
vacío (736 valores × 8 estados × 3 nodos, las tres partes del morfo en cerrado
|
|
|
y en abierto), capturas 2× antes/después.
|
|
|
- 2026-08-23 — **`card` 78 % → 78 %** (`f3189a05a`), contrato 97 → **98** claves,
|
|
|
centinela **49/98** con 49 adjudicadas. **Cerrado en su número, y ése es el
|
|
|
resultado**: sus ocho privados son TODOS, transitivamente, el puente THM-2 —
|
|
|
cuatro leen `--_card-palette-*` directo y cuatro leen el conmutador por
|
|
|
VARIANTE (`--_card-bg` / `--_card-fg`), cuyas ramas son ese mismo puente. Un
|
|
|
público encima mataría el `color=` por instancia. Lo único que faltaba era
|
|
|
**la costura**: la rama `outline` del conmutador leía
|
|
|
`var(--color-surface-default)` a pelo → `--card-outline-bg`. **Lo que
|
|
|
enseñó**: (1) el trío `emerge-*` no pinta en la demo porque el montaje CEDE
|
|
|
al sistema de motion (`:not([data-animation-style])`) y el escenario arranca
|
|
|
con un preset — y `emerge-distance` tiene además una segunda causa, que
|
|
|
alimenta `--motion-distance-md` y la animación acaba en `translate 0` con
|
|
|
`fill-mode: both`, así que `transform` en reposo no puede enseñarlo nunca;
|
|
|
(2) **una receta que COMPONE gana a la compuesta**: dentro de un `CardGroup`
|
|
|
el eje `radius` de la card está muerto (`[data-card-group] [data-card]` es
|
|
|
(0,2,0) contra (0,1,0)) — medido, deliberado (anidación concéntrica §30) y
|
|
|
registrado. Diff de computed vacío (1.216 valores × 7 estados + 2.484 × 18
|
|
|
celdas), capturas 2× antes/después.
|
|
|
- 2026-08-23 — **`toggle` 81 % → 100 %** (`edc019515` + `007c2af52`), contrato 119 → **126**
|
|
|
claves, centinela **70/126** con 56 adjudicadas. Tres knobs y una firma: el
|
|
|
**radio** (`radius` + los cinco pasos de `rounded`) leía `--radius-default` y
|
|
|
la escala global A PELO —el agujero de `navigation-menu`, y el único de los
|
|
|
CINCO componentes con escala `rounded` que no tenía la suya (`button`,
|
|
|
`badge`, `image`, `color-swatch` la declaran)—; el **tinte inválido** iba a
|
|
|
`--color-threat-element` a pelo (la costura §2-A); y los tres literales
|
|
|
quedan FIRMADOS (identidad del `block`, técnica `sr-only`). El desacople de
|
|
|
`size` se conserva: son pasos de `rounded`, no de talla. **Lo que enseñó**:
|
|
|
el centinela empezó en 36/126 y llegó a 70 **sin adjudicar nada** — las
|
|
|
claves `{variante}-*` y `{variante}-on-*` son las mismas tres variantes en
|
|
|
dos ESTADOS, y forzar el estado con `prepareWith` cambiaba una mitad por la
|
|
|
otra (36 → 46). El guard aprende a barrer el **producto cartesiano** de
|
|
|
varios ejes, a QUITAR un atributo con `null` (sellar `data-invalid` toda la
|
|
|
corrida hacía que el borde inválido ganase a los otros seis) y a aplicar el
|
|
|
barrido también en el **pase de hover**, que no barría nada — que es
|
|
|
literalmente la razón escrita en el ledger de
|
|
|
`radio-group.hover-segmented-segment-fg`. Los 12 componentes con `sweepAttr`
|
|
|
re-verificados uno a uno: **cero regresiones, cero STALE** (y tres de ellos
|
|
|
dieron exit=1 falso corriendo doce seguidos: a solas, verdes). Diff de
|
|
|
computed vacío (416 valores × 7 estados + 1.150 × 25 celdas de barrido
|
|
|
dirigido), capturas 2× antes/después. **Anotado y FUERA por D-TH.5**: el
|
|
|
`:hover` tapa el borde inválido (mismo peso, declarado antes) — mueve píxel
|
|
|
en los cuatro controles de formulario.
|
|
|
- 2026-08-23 — **`rating-group` 80 % → 100 %** (`f6a618328`), contrato 25 → **29**
|
|
|
claves, centinela **23/29** con 6 adjudicadas. Tres RESUELTAS por talla
|
|
|
(`gap`, `item-size`, `font-size`) jubilan sus tres privados y los cuatro
|
|
|
bloques `[data-size]` que los conmutaban: eran «privado con fuentes por
|
|
|
TALLA», o sea una ESCALA, que sube al contrato. Más `invalid-item-fg` (la
|
|
|
costura: leía `--color-threat-element` a pelo) y los dos `100%` del glifo
|
|
|
FIRMADOS como identidad, que salen del ratio. Diff **0** sobre 5.624 valores.
|
|
|
Lo que enseñó: **el centinela no fotografía `transform`**, así que
|
|
|
`item-hover-offset` —el único knob de la receta que mueve uno— leía muerto
|
|
|
estando vivo (§13).
|
|
|
- 2026-08-23 — **`radio-group` 77 % → 81 %, y su TECHO es ése** (`f5d252443`),
|
|
|
contrato 61 → **69** claves, centinela **46/69** con 23 adjudicadas. Ocho
|
|
|
claves: tres RESUELTAS por talla (`item-size`, `dot-size`, `font-size`) que
|
|
|
retiran **diecisiete bloques `[data-size]`** y jubilan `--_radio-item-size`
|
|
|
(privado con el nombre ABREVIADO, clase `--_mp-*`/`--gp-*`), cuatro de
|
|
|
validación que iban a `--color-threat-*` a pelo (el trío del anillo con el
|
|
|
vocabulario del gemelo `checkbox`) y `segmented-segment-padding-block`. Diff
|
|
|
**0** sobre 25.263 valores en 47 estados. Los diez knobs que quedan son el
|
|
|
puente THM-2 de paleta: **el techo no es el 100 %**.
|
|
|
**`row-min-height-touch` se acuñó y hubo que RETIRARLO**: `--touch-target` no
|
|
|
lo emite ningún generador (constante ergonómica escrita a mano en
|
|
|
`archetypes.css`) y `recipe-css-contract` lo cazó como referencia FANTASMA en
|
|
|
el acto — recipe-contract §2 ya lo lista entre los sistemas transversales que
|
|
|
una receta consume y nunca acuña. **Y salieron TRES declaraciones que no
|
|
|
pintan** (§13, las tres mueven píxel ⇒ firma): la escala del punto no ha
|
|
|
pintado nunca (`<SvgDot>` escribe `width:1em` INLINE — 13,3281px en las cinco
|
|
|
tallas), `[data-radio-group-label][data-disabled]` no casa jamás (soma no
|
|
|
estampa el atributo en la parte `Label`), y el fondo de un radio marcado Y
|
|
|
deshabilitado pierde (0,3,0) contra la regla de variante (0,4,0).
|
|
|
- 2026-08-23 — **`chat-composer` 79 % → 100 %** (`71a097ddc`), contrato 31 → **33**
|
|
|
claves, centinela **29/33** con 4 adjudicadas. **La mitad de su contrato no
|
|
|
la montaba la demo**: 14 muertas de 31, y once eran la barra de contexto
|
|
|
(opt-in tras un chip) más la bandeja de adjuntos (opt-in tras un botón); con
|
|
|
las dos encendidas por `prepareWith`, 29/33 antes de tocar el código. Lo
|
|
|
acuñado son **DOS** claves donde el generador pedía cuatro:
|
|
|
`context-close-size` —el chip de descarte es un control CUADRADO, una clave
|
|
|
para los dos ejes como `send-size` en la misma receta; el ⚠ del generador
|
|
|
fundía la caja (26 px) con su glifo (`1em`)— y `context-close-radius`.
|
|
|
**CUATRO declaraciones retiradas por muertas**: los dos `> svg` (`1em` del
|
|
|
cierre, `1.1em` del envío) no pueden ganar al `style="width:
|
|
|
var(--icon-size-{k})"` que el `Icon` compuesto escribe INLINE — medido 14 px
|
|
|
contra 13,3 y 16 px contra 14,7; retirarlas da 0 diffs. Misma lección que
|
|
|
`chat-log` la misma tarde. **Y una colisión ENTRE RECETAS**:
|
|
|
`--chat-composer-disabled-opacity` no alcanza porque `file-upload` barre
|
|
|
DESCENDIENTES (`[data-file-upload] [data-disabled]`, (0,2,0), el mismo peso
|
|
|
que `[data-chat-composer-send][data-disabled]`) y su receta se emite MÁS
|
|
|
TARDE — y el composer vive dentro de un FileUpload en su composición
|
|
|
DOCUMENTADA. Fuera del envoltorio alcanza (0.4 → 0.123); los dos defaults son
|
|
|
`--opacity-disabled`, así que es invisible hasta que un tema mueva uno. No se
|
|
|
arregla aquí (sería cascadear): adjudicada. Las otras tres son hábitos del
|
|
|
guard (`focus-border` bajo `:focus-within`, y el par que ES la transición que
|
|
|
congela). **El diff no salió limpio del todo y la causa está medida**: 2-4
|
|
|
valores de `[data-chat-composer-attach]` `blockSize` flotando 30 ↔ 36 px, que
|
|
|
flota IGUAL corriendo dos veces el mismo código — una recarga de cada ocho, el
|
|
|
`Button size="sm" variant="ghost"` que la demo compone ahí computa 36 px y
|
|
|
fondo sólido primario con sus `data-size`/`data-variant` puestos: las reglas
|
|
|
de talla y variante de `button` llegan tarde en el dev server. Los 2.204
|
|
|
valores restantes, idénticos.
|
|
|
|
|
|
- 2026-08-24 — **`calendar` 84 % → 89 %** (`509d1144f`), contrato **74 claves sin
|
|
|
tocar**, centinela **45/74 → 68/74** con 6 adjudicadas. **CERO claves
|
|
|
acuñadas: el censo no tenía nada que coser** (`global` ya era 0 desde la capa
|
|
|
`calendar-surface`), así que lo único fuera de alcance eran cuatro literales
|
|
|
de IDENTIDAD (`max-content` ×3 + `100%`), ahora firmados con su razón. **Todo
|
|
|
el trabajo fue MEDIR**, y enseñó la ley del bloque: **una entrada de receta de
|
|
|
FAMILIA no se juzga en la ruta de UN componente** — 23 de sus 29 «muertos»
|
|
|
eran el cromo que `month-grid` y `range-calendar` pintan con sus propios
|
|
|
atributos, invisible al filtro `data-calendar`; y la propia demo pone
|
|
|
SELECTORES de mes/año donde iría el `heading`, así que tres claves más no
|
|
|
tenían nodo aquí. Con `urls` a las tres rutas de la familia + `extraNodes` +
|
|
|
barrido de `variant`, sin tocar a los tres consumidores (siguen a 0 % honesto).
|
|
|
**Hallazgo de píxel**: el tamaño de letra de los selectores de mes / año es NO
|
|
|
DETERMINISTA — `[data-calendar-month-select][data-button]` y
|
|
|
`[data-popover-trigger]:not([data-archetype='field-trigger'])` empatan a
|
|
|
(0,2,0) y gana el módulo que Vite inyecte el último (cuatro cargas:
|
|
|
14/16/14/14 px). Lo destapó la sonda dando **24 diffs corriendo dos veces el
|
|
|
MISMO código**; es la clase de `tree-grid` y va a §13. Sonda 22.656 valores ×
|
|
|
7 estados: **0 diffs fuera de esos dos nodos**; capturas 2× idénticas byte a
|
|
|
byte. Guards: censo `--only` 89 % (global 68 %, no baja) · audit PASS ·
|
|
|
eidos-lint 0 invalid · rtl 0 · docs 0.
|
|
|
- 2026-08-24 — **`select` 83 % → 92 %** (`cc010f79a`), contrato 101 → **103** claves,
|
|
|
centinela **69/103** con 34 adjudicadas. Dos claves de COSTURA:
|
|
|
**`invalid-border`** (las TRES declaraciones del estado inválido leían
|
|
|
`--color-risk-border` a pelo — y son UNA clave, no las dos que proponía la §4:
|
|
|
las filas se agrupan por VALOR) y **`group-gap`** (nombre contado en el
|
|
|
catálogo: `toolbar.group-gap`). Tres literales de identidad firmados. Lo que
|
|
|
queda son los 5 forwards de paleta THM-2: **CERRADO en 92 %**. Lo que enseñó,
|
|
|
todo del PORTAL: (1) el guard tiene que mantener el panel ABIERTO para medir
|
|
|
30 tokens y **el estado abierto tapa los de reposo** —`trigger-border` y
|
|
|
`trigger-indicator-fg` miden bien con el panel cerrado—; (2) tres knobs viven
|
|
|
en nodos SIN `data-select-*` (la `z` en el `[data-floating-wrapper]`, el ritmo
|
|
|
del viewport en el `ScrollArea` compuesto): con `extraNodes`, 65/101 → 69/103;
|
|
|
(3) la cascada de paleta anula sus 24 tonos en su forma MULTI-PARTE (trigger +
|
|
|
content, porque el panel se porta fuera); (4) **⚠ `separator-size` alcanza y
|
|
|
aun así no pinta**: `flex-shrink` 1 en un panel que desborda aplasta su 1px a
|
|
|
**0px** (con `flex-shrink: 0`, 1px → 9px) — defecto de píxel a §13. §12.9
|
|
|
respetado: nada de `font-family` / `line-height` para la superficie `overlay`.
|
|
|
Sonda 2.176 valores × 8 estados = **0 diffs**; capturas 2× (cerrado y abierto)
|
|
|
idénticas byte a byte. Guards: censo 92 % · audit PASS · eidos-lint 0 invalid ·
|
|
|
rtl 0 · docs 0.
|
|
|
- 2026-08-23 — **`chat-log` 77 % → 100 %** (`fd8f01bac`), contrato 31 → **35**
|
|
|
claves, centinela **34/35** con 1 adjudicada. **El instrumento daba 15/31
|
|
|
antes de tocar el código, y las dieciséis «muertas» estaban VIVAS las
|
|
|
dieciséis.** Tres cegueras, ninguna del componente: (1) el viewport que
|
|
|
scrollea es del VirtualList compuesto (`data-virtual-list-viewport`, cero
|
|
|
`data-chat-log-*`), donde el log pinta sus dos paddings — la cuarta forma del
|
|
|
punto ciego de prose / navigation-menu / waveform; (2) la demo no montaba
|
|
|
TRES de las seis partes (separador de día y divisor de no-leídos no existían;
|
|
|
la fila de evento vivía en el índice 0 de una lista virtualizada anclada al
|
|
|
final, o sea fuera de la ventana) — once claves sin nodo; (3) la pastilla del
|
|
|
separador es un `> span` sin atributo, seis claves más. Con las tres
|
|
|
arregladas: **31/31 antes de acuñar nada**. Lo acuñado es la COSTURA de los
|
|
|
cuatro globales: `divider-padding-block`, `event-radius`, `pill-gap`,
|
|
|
`to-latest-radius` — con los nombres del CATÁLOGO (`divider-*` / `pill-*`),
|
|
|
no los del generador (`divider-unread-*` / `pill-new-*`), que nombra por el
|
|
|
atributo de la parte. **Y una regla RETIRADA por muerta**:
|
|
|
`[data-chat-log-to-latest] svg { block-size: 1em }` nunca ha pintado porque
|
|
|
el `Icon` compuesto escribe `style="width: var(--icon-size-sm)"` EN LÍNEA —
|
|
|
el glifo mide 16 px, no los 14 px de `1em`; retirarla da 0 diffs, la prueba.
|
|
|
Es la clase `carousel.item-gap`, pero el inline lo pone un COMPONENTE
|
|
|
COMPUESTO, no soma. Tres identidades firmadas (`block-size: 100%` ×2,
|
|
|
`inline-size: fit-content`). Adjudicada: `event-radius`, que sólo pinta bajo
|
|
|
`:focus-visible` (medido con teclado sobre la fila real: 0 → 4 → 1234 px).
|
|
|
Diff de computed VACÍO (1.920 valores · 7 estados · 9 nodos).
|
|
|
|
|
|
- 2026-08-23 — **`editable` 75 % → 82 %** (`2117d7422`), contrato 56 claves,
|
|
|
centinela **42/56** con 14 adjudicadas. **Su apertura es frágil AL REVÉS**:
|
|
|
salir del modo edición es lo que hace un `blur` —da igual lo que diga
|
|
|
`submitMode`, esa opción sólo decide si el valor se compromete— y el guard
|
|
|
blurea justo después de abrir, así que abrir con clic medía una superficie ya
|
|
|
cerrada (`submit-fg` leía muerto y mueve perfectamente abierta). Se abre por
|
|
|
FOCO, con la demo en `activationMode=focus`. Además tiene **DOS superficies
|
|
|
excluyentes** (preview/input comparten celda; Edit contra Save+Cancel), así
|
|
|
que todo se midió dos veces: diff 0 en modo preview (1.696 valores) y en modo
|
|
|
edición (2.528). Entra **`disabled-fg`** —la tinta apagada de TODO el
|
|
|
componente, una sola regla; era el único knob a primitivo crudo y traía un
|
|
|
respaldo `, var(--color-content-muted)` MUERTO— y sale **`control-border`**,
|
|
|
clave pública que no consumía ninguna regla (deuda inversa). Dos literales de
|
|
|
identidad firmados. Los 7 privados son el puente de paleta THM-2: **82 % es su
|
|
|
techo**. ⚠ **`risk-border` NO cae en el patrón de paleta**: las tres reglas de
|
|
|
inválido la leen directamente, así que su silencio tiene otra causa y su
|
|
|
propia adjudicación —forzado `data-invalid` alcanza en input y control—; una
|
|
|
excepción por patrón que engulle una clave con vida propia es una adjudicación
|
|
|
falsa. **Defecto anotado**: el tinte inválido ES la clave de tono, o sea dos
|
|
|
knobs con una sola llave; el arreglo es `invalid-{parte}-border` (la forma que
|
|
|
`switch` acuñó el mismo día) y es contrato.
|
|
|
|
|
|
- 2026-08-23 — **`avatar` 75 % → 90 %** (`f68bac4a6`), contrato 84 → 88 claves,
|
|
|
centinela **83/88** con 5 adjudicadas. **Su contrato existía y NINGÚN
|
|
|
instrumento lo veía**: es la única entrada de `base.ts` construida por una
|
|
|
IIFE (un helper local genera sus 24 ámbitos compuestos), así que su mapa vive
|
|
|
en el `return {`, un tabulador más adentro — el censo la daba «sin entrada» y
|
|
|
**el centinela moría** (`no recipe block for avatar`). Los dos lectores leen
|
|
|
ya la IIFE. Lo demás: **`group-overlap-{xs..xxl}`**, porque la clave única
|
|
|
`--avatar-group-overlap` la RE-DECLARABA la receta en seis bloques
|
|
|
`[data-size]` —sentada en el elemento, ganaba al `:root` de un tema: medido,
|
|
|
no movía nada desde el asiento del tema, y **el centinela lo daba por vivo
|
|
|
porque escribe el token también sobre el nodo** (falso positivo nuevo, §13)—;
|
|
|
**`group-max` RETIRADO** de la receta y del envoltorio (el tope lo aplica
|
|
|
`data-has-max` + `:nth-child(n + M)`, y la variable inline no la leía nadie);
|
|
|
el respaldo `, white` de `--_avatar-badge-fg`, muerto contra su propio token;
|
|
|
y **seis literales de identidad firmados**. Los 3 privados que quedan son el
|
|
|
CONMUTADOR de variante sobre el forward de paleta THM-2: 90 % es su techo.
|
|
|
Artefactos: diff de computed 0 en tres bases (576 + 384 + 3.072 valores),
|
|
|
capturas 2× idénticas al byte, `rtl:check` 0, `docs:check` 0, `check` sin un
|
|
|
solo error en `avatar`. **Queda R-5.3 preexistente**: cuatro claves
|
|
|
`*-color-custom*` donde la gramática exige `fg` — renombrarlas cambia tres
|
|
|
escotillas públicas, así que se lista.
|
|
|
|
|
|
- 2026-08-23 — **REVISIÓN DE LOS 26 COMMITS SIN REVISAR (§7.7 incluida)**:
|
|
|
`REVIEW-theming-2026-08-23.md`. 33 componentes, los de los bloques del 22 y el
|
|
|
23. **5 errores reales, 5 desviaciones de protocolo, y la §7.7 con 5 hipótesis
|
|
|
y 5 refutaciones.** Todo arreglado el mismo día:
|
|
|
|
|
|
- **E5 — `float-panel` tenía DOCE rojos sin adjudicar y el guard fallaba en
|
|
|
él** (`233ef989b`). Su commit del 22 los dejó escritos como «lo rojo que
|
|
|
queda» y el handoff dio por cerrado el bloque viejo: la frase era FALSA.
|
|
|
Seis son el plano `overlay` (§12.9), tres estados que la demo no monta, uno
|
|
|
el puente de paleta y dos la ley del congelado. **Sólo se ve corriendo el
|
|
|
guard sobre el ledger ENTERO, no sobre lo que tocas.**
|
|
|
- **E1 — `badge` acuñó la clave con el nombre de la PROPIEDAD**
|
|
|
(`min-block-size-{k}`) donde la ranura es `height` (`bfe7727b0`). 24
|
|
|
componentes dimensionan por `…-height-{k}`; era el único. **R-5.3 no guarda
|
|
|
el vocabulario dimensional** — §13.
|
|
|
- **E2 — una adjudicación mal clasificada**: `background.parallax-travel` no
|
|
|
era «estructural», es que **el guard no fotografía `translate`** — §13.
|
|
|
- **D1 — la sesión de la mañana se saltó los pasos 8 y 9 en los 22
|
|
|
componentes**: ni README «Talla y tema» ni pestaña `Tokens` (`e522e04e6`,
|
|
|
tabla DERIVADA del contrato y del ledger, 21 pestañas verificadas en el
|
|
|
navegador).
|
|
|
- **§7.7**: base en worktree con `server.fs.allow` (sin él no hidrata y se
|
|
|
compara contra una base muerta), **31 de 33 con 0 diffs sobre ~48.000
|
|
|
valores**; los dos con diffs (`image`, `audio-player`) son ruido
|
|
|
reproducible del instrumento —dos corridas del MISMO código dan 1 y 11—;
|
|
|
píxel-arriba verde en los cuatro que tocaron `:hover`; sin dobles
|
|
|
animaciones (ningún commit toca `animation`); contrato sin duplicados ni
|
|
|
huérfanos.
|
|
|
|
|
|
- 2026-08-23 — **`file-upload` 76 % → 83 %** (`0c06d42aa`), 1 clave acuñada y **1
|
|
|
RETIRADA**. `invalid-dropzone-border` (con la PARTE en el nombre: tres partes
|
|
|
con borde) era el único knob a un primitivo a pelo. **`button-bg` no pintaba**:
|
|
|
la regla compartida de los tres botones la declaraba y los tres la pisan
|
|
|
después (el trigger con el sólido de la paleta, `ItemRemove` y `ClearTrigger`
|
|
|
con `transparent`) — medido sobre los tres nodos, cero movimiento, así que se
|
|
|
retira la declaración Y la clave, y el diff 0 lo prueba. **Cuatro literales de
|
|
|
identidad firmados** (el ancho del campo, los dos de la miniatura, el de la
|
|
|
barra). **CUARENTA claves de tono** (8 × 5 ranuras) adjudicadas por patrón: la
|
|
|
cascada de paleta, medida sobre el trigger y el dropzone en hover para los
|
|
|
ocho tonos. Los 9 privados son 8 puentes THM-2 + **el canal de valor**
|
|
|
(`--_file-upload-progress-value`, inline por fila), así que **su techo honesto
|
|
|
no es el 100 %**. R-5.4 54/98, exit 0. Diff 0 sobre **11.448 valores en 17
|
|
|
estados** y capturas 2× idénticas byte a byte. ⚠ **Truco de medición nuevo**:
|
|
|
el barrido de estados que la demo no arranca (variante × talla × invalid ×
|
|
|
disabled × dragging) reconstruye el «antes» **inyectando el CSS de HEAD en la
|
|
|
página** —gana por orden a igual especificidad—, sin tocar el árbol que otras
|
|
|
tres sesiones están usando; con su muta-prueba (19 diffs al alterar el control,
|
|
|
1 al alterar sólo el borde inválido).
|
|
|
|
|
|
- 2026-08-23 — **`switch` 76 % → 81 %** (`bbdc77c07`), 1 clave. `invalid-track-border`
|
|
|
era el ÚNICO knob que iba a un primitivo a pelo (`--color-threat-element`).
|
|
|
**El nombre NO es el `invalid-border` del catálogo** (6 recetas lo usan):
|
|
|
esta tiene DOS partes con borde y las nombra —`disabled-track-border` es su
|
|
|
hermana de estado, `thumb-border` es la del pulgar—, así que el nombre desnudo
|
|
|
no diría cuál tiñe; la forma modificador+parte+ranura ya existe
|
|
|
(`invalid-input-border`, `invalid-control-border`). **Las DOCE claves de tono
|
|
|
no pintan y aquí cae también `neutral`**: la cascada de paleta ya conocida,
|
|
|
más que **soma estampa `data-color` SIEMPRE** (color resuelto, `neutral` por
|
|
|
defecto), así que el bloque genérico casa en toda instancia y el fallback que
|
|
|
salva al tono por defecto en otras recetas tampoco llega — medido en checked
|
|
|
(`--switch-neutral-solid` no mueve nada, `--palette-solid` repinta).
|
|
|
Adjudicadas por PATRÓN. Otras trece adjudicaciones son estado que la demo no
|
|
|
monta (5 `disabled-*`, `invalid-track-border`) y dos huecos del instrumento
|
|
|
(los 5 `size-*-thumb-translate` pintan sobre `transform`, que el guard no lee,
|
|
|
y valen 0 hasta checked; el par de transición ES la transición que congela).
|
|
|
Los 4 `private` que quedan son 2 CONMUTADORES + 2 lecturas del puente THM-2:
|
|
|
**su techo honesto no es el 100 %**. R-5.4 27/52, exit 0. Diff 0 sobre
|
|
|
**1.344 valores en 36 estados** (416 de la sonda estándar + 928 de una sonda
|
|
|
de estados propia: checked / invalid / readonly / disabled / RTL / 5 tallas,
|
|
|
cada uno con hover y foco) y capturas 2× idénticas. ⚠ **Defecto anotado, no
|
|
|
arreglado**: el tinte inválido es el paso `element` de la escala
|
|
|
(`oklch(0.9555 …)`, casi blanco) y el `:hover` (0,4,0) lo tapa — mismo valor
|
|
|
en checkbox / radio-group / toggle, así que es escala del sistema y mueve
|
|
|
píxel en cuatro sitios.
|
|
|
|
|
|
- 2026-08-23 — **`search-field` 71 % → 100 %** (`f24abdb60`), contrato **17
|
|
|
claves sin tocar**, centinela **7/17 → 17/17** sin una sola adjudicación.
|
|
|
**CERO claves acuñadas: su 29 % de deuda eran CUATRO literales que son
|
|
|
IDENTIDAD**, ahora firmados con `/* literal: … */` (la válvula de
|
|
|
recipe-contract §3): el `line-height: 1` del icono —un glifo solo no tiene
|
|
|
interlineado, la misma anotación que su hermana `field.css`—, el `100%`
|
|
|
doble del `::before` —el anillo ES la caja del indicador, que ya mide por
|
|
|
`--_search-field-loading-size`— y el `border-radius: 50%`, que la §4 pedía
|
|
|
acuñar como `loading-indicator-radius`: **sería un knob que SÓLO puede
|
|
|
romper el componente**, porque el arco es un BORDE que gira y con cualquier
|
|
|
otro valor la ruleta deja de leerse como una — la clase 4 de F2-B, «el 50 %
|
|
|
de un círculo», al pie de la letra. Censo 15 knobs → 11 (público 10, literal
|
|
|
4 → 0, excepción firmada 0 → 4; el `--opacity-muted` del indicador bajo
|
|
|
`prefers-reduced-motion` es capa de sistema, fuera del ratio). **Lo que
|
|
|
enseñó**: (1) **diez de sus diecisiete tokens no se habían medido NUNCA** —
|
|
|
la demo no monta dos estados: el indicador de carga sólo existe con
|
|
|
`loading` y son **NUEVE** claves suyas (el commit y el comentario del guard
|
|
|
dicen «ocho»; `base.ts` le da nueve, y 7 del icono + 9 + 1 = 17), y la X
|
|
|
sólo se desvanece con el campo VACÍO, y el escenario arranca con valor
|
|
|
(`clear-hidden-opacity`); con los dos interruptores en `prepareWith` **EL
|
|
|
ORDEN IMPORTA**: el clic en la X va PRIMERO, porque la propia regla que
|
|
|
enciende le quita después el `pointer-events` al botón que la disparó; la
|
|
|
sonda necesita el de `loading` por lo mismo, 4 → **5 nodos**, sin perder
|
|
|
ninguno; (2) **los dos privados NO son deuda** — `--_search-field-icon-size`
|
|
|
y `--_search-field-loading-size` son el conmutador por talla y sus cinco
|
|
|
fuentes son, cada una, una clave pública: **58 de las 162 recetas** (cifra
|
|
|
del commit; el censo confirma las 162, pero ningún guard reproduce el 58)
|
|
|
resuelven así su eje `size` —incluidas `empty-state` y `banner`, cerradas
|
|
|
al 100 % este mes—, y pasarlas al ámbito `size:` del TSC cambiaría la
|
|
|
especificidad de la emisión sin ganar un punto de alcance. ⚠ **Un default
|
|
|
medido, ANOTADO, no cambiado**: las dos escalas del mismo renglón divergen
|
|
|
en los dos últimos peldaños — medido en Chrome con transiciones y animación
|
|
|
congeladas, forzando `data-size` sobre el nodo real, icono → indicador: xs
|
|
|
14→14, sm 16→16, md 18→18, **lg 20→18**, **xl 32→20**; el contrato lo
|
|
|
declara de frente (`loading-indicator-size-lg` apunta a
|
|
|
`--size-md-icon-size` y `-xl` a `--size-lg-icon-size`), así que en `xl` la
|
|
|
ruleta es DOCE píxeles menor que la lupa que tiene al lado. No es deuda de
|
|
|
alcance —las diez claves alcanzan—, es diseño que huele a copia a medias:
|
|
|
mueve píxel, D-TH.5 lo saca de este eje (anotado en el veredicto §5 y en el
|
|
|
README). Diff de computed vacío (1.216 valores · 8 estados · 5 nodos),
|
|
|
capturas 2× antes/después idénticas byte a byte. Guards: audit PASS ·
|
|
|
eidos-lint 0 invalid (9 morfo-backed, 4 eidos-only) · vitest
|
|
|
`src/uix/eidos` 35/36 (el rojo `skin-media-player`, preexistente) · rtl 0 ·
|
|
|
docs 0. README con su sección «Talla y tema» y pestaña Tokens en la demo
|
|
|
(17 claves).
|
|
|
- 2026-08-23 — **`image-picker` 71 % → 100 %** (`1a41312b6`), contrato 13 →
|
|
|
**14** claves, centinela **14/14** con 0 adjudicadas — de 13/13 a 14/14 SIN
|
|
|
una sola adjudicación. **Una sola clave: `hover-button-bg`**, el único knob
|
|
|
que iba a un primitivo global a pelo (`--color-surface-default`), y **no es
|
|
|
el velo del sistema, por eso se acuña**: los dos botones flotan SOBRE la
|
|
|
foto, su relleno de reposo es translúcido (`color-mix(… 88%, transparent)`)
|
|
|
y el hover lo vuelve OPACO — un cambio de RELLENO, no una capa encima.
|
|
|
Medido desde el píxel hacia arriba con las transiciones congeladas: el
|
|
|
cambio cae en el `<button>` (el nodo con forma, radio 6 px, `srgb .988/.88`
|
|
|
→ `oklch(.9911 0 0)`) y NINGÚN ancestro recibe `background-image`, porque el
|
|
|
arquetipo `action` no trae velo — `archetypes.css` sólo vela `trigger`,
|
|
|
`item` y `option`; no se bendice un duplicado, que es lo que paró el
|
|
|
`highlighted` de `listbox`. **El nombre lo decidió el catálogo**: la §4 lo
|
|
|
llamaba `hover-rotate-bg` por el PRIMER selector de la regla y miente dos
|
|
|
veces (pinta rotate **y** remove, y el contrato ya llama `button-*` a ese
|
|
|
par desde que nació); `hover-{parte}-{slot}` es la forma de las 77 claves
|
|
|
`hover-*` de `base.ts` (52 nombres distintos). Los **cuatro literales se
|
|
|
firman, no se acuñan** (válvula de recipe-contract §3): el `100%` doble del
|
|
|
hijo del canvas es identidad (la `<Image>` ES la caja del canvas, ya con
|
|
|
`inset: 0`), el `line-height: 1` es un botón de un solo glifo y el
|
|
|
`Highlight` de `forced-colors` es la paleta del SO, que el UA sustituiría.
|
|
|
Censo 20 knobs → 16 (público 12 → 13, global 1 → 0, literal 4 → 0,
|
|
|
excepción firmada 0 → 4; sistema 3, fuera del ratio). **Lo que enseñó**: el
|
|
|
instrumento medía **UN nodo** — el picker arranca VACÍO y todo lo que la
|
|
|
receta pinta (preview, canvas, toolbar y los dos botones de icono) sólo
|
|
|
existe en el estado `ready`, al que no llega ningún trigger: hay que cargar
|
|
|
un fichero. Con el chip «Load sample image» de la demo la sonda pasa de 1 a
|
|
|
**6 nodos** (`DEMO_VARIANTS` en la sonda, `prepareWith` en el centinela), y
|
|
|
éste necesita además `openMarker` porque su re-apertura por token volvería
|
|
|
a pulsar el chip y remontaría la vista previa a mitad de corrida. **Anotado
|
|
|
y FUERA por D-TH.5**: ese hover neutro es una invención por componente (§38
|
|
|
/ R-4.3 mandan la capa `--state-*`), pero migrarlo cambia el default y no
|
|
|
basta con tocar la receta — el arquetipo del par es `action`, que HOY no
|
|
|
recibe velo, así que o `action` gana velo en `archetypes.css` (mueve píxel
|
|
|
en todo el catálogo) o el par cambia de arquetipo, que es morfo. Diff de
|
|
|
computed vacío (1.344 valores en 7 estados × 6 nodos), capturas 2×
|
|
|
antes/después idénticas.
|
|
|
- 2026-08-23 — **`form` 71 % → 86 %** (`9c3f17fa6`), contrato 54 → **64**
|
|
|
claves, centinela **22/64** con 42 adjudicadas (19 nominales + 23 por un
|
|
|
patrón). Diez claves que iban a los primitivos A PELO: el resumen de errores
|
|
|
(`error-summary-{bg,fg,border}` — es el señalizador de nivel de página, y su
|
|
|
superficie, su tinta y su borde SON el tono risk), el acento de formulario
|
|
|
inválido (`invalid-accent`, un privado con UNA sola fuente, no un
|
|
|
conmutador), las tres superficies del árbol de AutoFields, las dos del
|
|
|
widget y el subrayado a media tinta de los enlaces del resumen
|
|
|
(`link-underline-fg`, el par del `-offset` que ya existía); más un literal
|
|
|
de identidad firmado. **R-5.3 cazó el nombre en el acto**: lo acuñé
|
|
|
`link-underline-color` y la tinta es `fg` (theming §6.7 r7, firmado el 20),
|
|
|
renombrado antes de commitear — el guard de nombres funciona; es el
|
|
|
vocabulario DIMENSIONAL el que no cubre (ver `badge`, el mismo día). **Lo
|
|
|
que enseñó**: ⚠⚠ **23 claves del contrato NO PINTAN, y no es deuda de valor:
|
|
|
es una cascada.** `[data-form-submit]`, `[data-form-reset]` y los dos
|
|
|
botones del array llevan también `data-button` porque COMPONEN el `Button`
|
|
|
canónico, y `[data-button]` casa con la MISMA especificidad (0,1,0) pero
|
|
|
carga DESPUÉS: gana `button.css`. Medido propiedad a propiedad sobre el nodo
|
|
|
real —altura, `padding-inline`, tamaño y peso de letra, interlineado, hueco,
|
|
|
radio, grosor de borde, el par de transición y la opacidad deshabilitada—:
|
|
|
**ninguna se mueve**. Es el defecto que `gradient-picker` documentó (36 de
|
|
|
sus 45 claves) y que `emoji-picker` encontró hoy en su trigger; allí la
|
|
|
respuesta fue RETIRAR las declaraciones muertas, y aquí son 23 claves
|
|
|
PÚBLICAS: decisión del autor, no del que ejecuta. Quedan adjudicadas POR
|
|
|
PATRÓN (`^(action-|transition-|disabled-opacity$)`, una razón arquitectónica
|
|
|
escrita una vez) y anotadas en §13 con la pregunta de fondo, que es la de
|
|
|
§12.9 con el plano overlay: qué manda, el componente compuesto o la receta
|
|
|
que lo compone — si mandan las recetas se sube la especificidad y no se
|
|
|
retira nada; si mandan los compuestos, hay ~62 claves públicas que retirar
|
|
|
en tres componentes. ⚠ el commit, su título y la nota de §13 dicen **24** y
|
|
|
«las 20 + el patrón»: el guard adjudica 19 nominales + 23 por patrón = 42,
|
|
|
que es lo que exige el 22/64 — off-by-one del autor, a corregir en
|
|
|
`next-features.md`. Las demás adjudicaciones son ramas que la demo no monta:
|
|
|
el layout `grid` (forzado alcanza — y su `grid-template-columns` sólo CAMBIA
|
|
|
si el valor altera el número de columnas: con 90px pasa de una columna de
|
|
|
502px a cuatro de 110,5), el resumen de errores VACÍO (sin `<ul>` que
|
|
|
indentar ni `<a>` que subrayar) y toda la rama de ARRAY de AutoFields — el
|
|
|
modo `auto` de la demo monta `group` y `field`, nunca `array`, `item` ni
|
|
|
`widget`. Fuera por doctrina: los tres privados del panel son un CONMUTADOR
|
|
|
(`plain` contra `panel`) y los cuatro `--_form-action-*` leen el forward de
|
|
|
paleta THM-2. Diff de computed vacío (832 valores · 7 estados), capturas 2×
|
|
|
antes/después. Guards: censo `--only` 86 % · audit PASS · `--names` 0
|
|
|
desviadas · eidos-lint 36 morfo-backed / 0 invalid / 0 class-hooks · rtl 0 ·
|
|
|
docs 0 · suite eidos 439/440 (el rojo conocido).
|
|
|
- 2026-08-23 — **`skip-link` 71 % → 100 %** (`ebe3fe6ed`), contrato **8 claves
|
|
|
sin tocar**, centinela **0/8 → 8/8** con **cero adjudicaciones**. **Ninguna
|
|
|
clave nueva**: su 29 % de deuda eran DOS literales que son la TÉCNICA:
|
|
|
`inline-size: 1px` / `block-size: 1px`, la mitad del sr-only canónico —la
|
|
|
otra mitad es el par `clip` / `clip-path`—, ahora firmados con
|
|
|
`/* literal: */`, la válvula de recipe-contract §3: salen del ratio como
|
|
|
ausencia ESCRITA, no como deuda, y el censo baja de 8 knobs a 6. No se
|
|
|
acuñan porque un tema que los mueva no cambia una apariencia, ROMPE el
|
|
|
mecanismo — y a `0 × 0` algunos motores sacan el enlace del árbol de
|
|
|
accesibilidad, que es lo único que este componente no puede permitirse;
|
|
|
misma clase que `text-blur` y `text-scramble`. Los otros 5 knobs ya pasaban
|
|
|
por token público, y las dos ausencias que quedan son doctrina aplicada: la
|
|
|
tipografía se HEREDA (no hay `font-*` declarado; acuñarla fijaría el
|
|
|
default, D-TH.5) y el anillo de foco es del SISTEMA (`--focus-ring-*`,
|
|
|
recipe-contract §2). El `background:` en shorthand no mata ninguna capa de
|
|
|
estado: su parte lleva `archetype: 'provider'`, que no recibe velo. **Lo que
|
|
|
enseñó**: la OCTAVA clase de punto ciego del instrumento — toda su
|
|
|
superficie existe SÓLO bajo `:focus` (sr-only mientras no lo tiene, píldora
|
|
|
cuando sí), así que el guard leía 0 de 8: no lo enfocaba nunca, el `blur`
|
|
|
que hace tras abrir lo habría deshecho igual, y clicarlo tampoco vale porque
|
|
|
su handler manda el foco a la región de destino y la píldora se va por el
|
|
|
camino de entrada. Nace `openBy: 'focus'`, y con él `openingIsFragile` — el
|
|
|
conjunto de aperturas que el blur y el aparcado del puntero NO deben
|
|
|
deshacer, hasta hoy sólo `hover`. Es aditivo: las cuatro condiciones que
|
|
|
decían `openBy !== 'hover'` pasan a consultarlo y ninguna configuración
|
|
|
existente cambia de rama. Re-verificados tres del ledger: `dialog` 37/44 (la
|
|
|
cifra exacta de su commit), `tooltip` 15/23, `context-menu` 27/28 — cero
|
|
|
regresiones. Diff de computed vacío (192 valores en 7 estados, más los 52
|
|
|
del estado ENFOCADO —el único que se ve— medidos aparte con un script
|
|
|
propio: la sonda estándar mide reposo, tallas, abierto y hover, nunca foco),
|
|
|
capturas 2× antes/después idénticas byte a byte.
|
|
|
- 2026-08-23 — **`dialog` 67 % → 89 %** (`bb89174a8`), contrato 37 → **44**
|
|
|
claves, centinela **37/44** con 7 adjudicadas. Las siete son las dos tintas
|
|
|
SEMÁNTICAS que le faltaban. Cuatro para los tonos EVALUATIVOS
|
|
|
(`risk-border`, `risk-title-fg`, `threat-border`, `threat-title-fg`): dialog
|
|
|
no tiene forward de paleta THM-2 y su trato de tono es deliberadamente
|
|
|
estrecho —el borde y la tinta del TÍTULO, nunca la superficie del cuerpo,
|
|
|
para que el texto largo no compita con la señal—, pero iban a
|
|
|
`--color-risk-*` a pelo. Y tres para el tinte de SALIDA (`saved-border`,
|
|
|
`failed-border`, `dismissed-border`): el morfo escribe `data-last-action`
|
|
|
antes de que `data-state` pase a `closed`, así que el borde superior dice
|
|
|
CÓMO se cerró mientras se va; el tercero cubre `cancelled` / `dismissed` /
|
|
|
`dismissed-outside`, que comparten valor — todo cierre sin resultado.
|
|
|
`{tono}-border` es el nombre del catálogo (48 claves) y `failed-border` el
|
|
|
de `proof-of-human`. **El 11 % que queda son los cuatro
|
|
|
`--_dialog-content-*-override`, y no es deuda**: escotillas POR INSTANCIA
|
|
|
que el wrapper escribe INLINE desde las props `width` / `minWidth` /
|
|
|
`maxWidth` / `height` / `minHeight` — un público encima lo pisaría el inline
|
|
|
y mentiría, la clase de `--_background-gradient-image` y del triple de
|
|
|
`s-text-virtual-list`. Más el `width: 100%` de la hoja inferior, firmado
|
|
|
como identidad. ⚠ **Nada de tipografía de superficie, por §12.9**: el
|
|
|
contenido lleva `data-depth='modal'` y un plano declara `font-family` /
|
|
|
`line-height` a la misma especificidad y más tarde en la cascada; las claves
|
|
|
de título y descripción que ya existían son de PARTES internas, no de la
|
|
|
superficie del plano. **Lo que enseñó**: ⚠⚠ **`overlay-opacity` es un FALSO
|
|
|
POSITIVO del guard** — `dialog-overlay.svelte` escribe
|
|
|
`--dialog-overlay-opacity` en el `style` INLINE del velo y el guard escribe
|
|
|
su centinela en el `style` de cada nodo, así que se pisa a sí mismo y ve un
|
|
|
cambio. Medido como lo haría un TEMA (sólo desde `:root`, animaciones
|
|
|
congeladas) el fondo del velo **no se mueve**
|
|
|
(`color(srgb 0.1098 0.098 0.0902 / 0.2518)` antes y después): la clave está
|
|
|
en el contrato y ningún tema la alcanza. Cara opuesta de
|
|
|
`drag-drop.preview-z`, misma familia que el velo de `drawer` que no pinta; a
|
|
|
§13 con el arreglo del guard, y retirar o rescatar la clave es decisión
|
|
|
aparte, porque cambia quién controla la opacidad del velo. Y dos de las
|
|
|
siete adjudicaciones costaron una segunda pasada **por el VALOR del
|
|
|
atributo**: la rejilla de posición usa `top-left` / `top-right` (físicos),
|
|
|
no `top-start`, y el botón de cierre NO lleva `data-position` en esta demo
|
|
|
aunque todas las reglas que leen `close-inset` lo exigen. Diff de computed
|
|
|
vacío (480 valores · 8 estados · 8 nodos con el diálogo abierto), capturas
|
|
|
2× antes/después. Guards: censo `--only` 89 % · audit PASS · eidos-lint 15
|
|
|
morfo-backed / 0 invalid / 0 class-hooks · rtl 0 · docs 0 · suite eidos
|
|
|
439/440 (el rojo conocido).
|
|
|
- 2026-08-23 — **`pin-input` 65 % → 100 %** (`4b9354bba`), contrato 20 → **22**
|
|
|
claves, centinela **16/22** con seis adjudicadas. Su 35 % de deuda eran TRES
|
|
|
defectos, ninguno de diseño: un prefijo ABREVIADO —los privados se llamaban
|
|
|
`--_pin-cell-*` dentro de un componente llamado `pin-input`, así que el
|
|
|
censo no los reconocía como suyos y los cuatro knobs que los leen contaban
|
|
|
como deuda aunque DERIVAN de públicos; cuarto caso de la clase tras
|
|
|
`color-picker`, `metrics` y `time-picker`—, un respaldo A SÍ MISMO
|
|
|
(`font-family` leía `var(--style-label-font-family,
|
|
|
var(--style-label-font-family))`, un no-op con forma de defecto) y la tinta
|
|
|
del dígito a `--color-content-primary` a pelo. Las dos claves nuevas son
|
|
|
esas dos costuras (§2-A): `font-family` y `cell-fg`. **Lo que enseñó**: los
|
|
|
**veintidós respaldos escritos a mano** duplicaban lo que el contrato ya
|
|
|
declara en `:root` —código muerto, y retirarlos dio 0 diffs, que es la
|
|
|
prueba— pero UNO MENTÍA: `disabled-opacity` respaldaba `0.55` cuando
|
|
|
`--opacity-disabled` vale **0.4**. Es la ley de los `, 1.4` contra un
|
|
|
`--font-line-height-sm` de 1.45 que este mes ya salió en dos componentes,
|
|
|
aquí con más deriva: **un respaldo no es una red de seguridad, es una
|
|
|
segunda fuente que nadie actualiza**. Y las seis adjudicaciones enseñaron
|
|
|
DÓNDE vive cada estado: `filled` y `active` son atributos de la CELDA, pero
|
|
|
`invalid` y `readonly` se estampan en el CONTENEDOR y cascadean (soma los
|
|
|
OR-fusiona con el Field que las envuelve), así que forzarlos en la celda no
|
|
|
hace nada. Diff de computed vacío (1.856 valores · 8 estados · 8 nodos),
|
|
|
capturas 2× antes/después.
|
|
|
- 2026-08-23 — **`spin-field` ADJUDICADO: 67 % es su techo** (`2ebeb9b16`),
|
|
|
64 % → 67 % por UN literal firmado, contrato 20 → **20** claves, centinela
|
|
|
**13/20** con siete adjudicadas. **Cero claves nuevas: el techo estaba
|
|
|
escrito en la cabecera de su propio CSS.** Ocho de sus knobs leen los
|
|
|
privados RESUELTOS del Field (`--_field-control-height`,
|
|
|
`--_field-control-padding-inline`, `--_field-control-gap`) porque los
|
|
|
steppers y el scrubber IGUALAN la fila del input a cualquier talla —«never a
|
|
|
parallel `--spin-field-*` chrome that would alias the Field base», dice la
|
|
|
cabecera—, así que acuñar ahí sería el antipatrón que el fichero prohíbe por
|
|
|
su nombre ([S6] no-token-aliases). Préstamo con dueño: se tema en la ficha
|
|
|
de `field`, y el censo lo puntúa como deuda porque no sabe distinguirlo — el
|
|
|
mismo artefacto que `listbox` (68 %) y `radio-cards` (61 %) ya registraron.
|
|
|
Los dos factores del apilado (`* 0.62` el ancho del botón, `* 0.34` el
|
|
|
glifo) viven dentro de un `calc()` sobre ese mismo privado de Field, así que
|
|
|
un token propio no cambiaría quién manda; y el `line-height: 1` de la celda
|
|
|
de glifo es identidad, FIRMADO — lo único que mueve la cifra (16/25 → 16/24
|
|
|
knobs en ratio). **Lo que enseñó**: (1) los tres `active-control-*` no
|
|
|
responden a `:active` NI forzando el pseudo por CDP — su estado es el
|
|
|
`[data-scrubbing]` que soma pone en el SCRUBBER mientras se arrastra, y
|
|
|
forzado el atributo sobre el nodo real los tres alcanzan; (2) es una CAPA,
|
|
|
no un componente: sin wrapper ni ruta propia, el guard lo mide dentro de
|
|
|
`number-field`, declarado ahora en `urls` para que nadie tenga que saberlo;
|
|
|
(3) una corrida de sonda dio 5 «nodos ausentes» que no eran nada —una
|
|
|
recarga que no montó la talla `xl`—: repetida, 0 diffs y 0 ausentes contra
|
|
|
el mismo ANTES, y un «missing node» tampoco se cree a la primera. Las otras
|
|
|
cuatro adjudicadas: `focus-control-bg` (pseudo forzado por CDP),
|
|
|
`control-disabled-opacity` (0.48 → 0.137) y el par de transición medido sin
|
|
|
congelar (0,12s → 11,5s). Diff de computed vacío (2.400 valores · 8 estados
|
|
|
· 5 nodos), `component:audit` sin hallazgos, `docs:check` 0, el ledger en
|
|
|
sus 63 hunks previos, captura del anfitrión `number-field`.
|
|
|
- 2026-08-23 — **`emoji-picker` 61 % → 100 %** (`863c6993c`), contrato 17 →
|
|
|
**21** claves, centinela **17/21** con 5 adjudicadas. Siete acuñadas, **tres
|
|
|
retiradas por muertas** y tres literales de identidad firmados. Los nombres
|
|
|
los dio el catálogo: `open-trigger-fg` (`accordion` lo nombra igual),
|
|
|
`grid-padding-inline` + `grid-padding-block-end` (el eje lógico completo,
|
|
|
como `card-group` / `combobox` / `command`) y las tres del marcador de tono,
|
|
|
la familia `timeline.marker-{size-*,radius,bg}` — se llama `tone-marker-*` y
|
|
|
no `marker-*` porque el pie lleva además un selector de TONO, y `marker` a
|
|
|
secas sería ambiguo dentro del propio componente. Las cinco adjudicaciones,
|
|
|
todas forzadas sobre nodos reales: las tres del marcador (la demo monta CERO
|
|
|
celdas `data-tone-capable`; con el atributo puesto el `::after` alcanza —
|
|
|
4px → 37px, 9999px → 37px, y el fondo), `preview-name-fg` (los hijos de la
|
|
|
vista previa son `<span>` desnudos, sin atributo del componente, fuera del
|
|
|
conjunto medido) y `open-trigger-fg`. **Lo que enseñó**: (1) **el cromo de
|
|
|
reposo del trigger NO es suyo** — el nodo lleva también
|
|
|
`data-popover-trigger`, y
|
|
|
`[data-popover-trigger]:not([data-archetype='field-trigger'])` es
|
|
|
**(0,2,0)** contra el (0,1,0) de esta receta: el radio, la tinta y el tamaño
|
|
|
de letra los pinta `popover.css`. Retiradas las tres declaraciones, **0
|
|
|
diffs**, la prueba de que estaban muertas (`trigger-fg` no llegó a existir:
|
|
|
se acuñó y se midió muerta en el mismo pase). Es el defecto que
|
|
|
`gradient-picker` documentó (36 de sus 45 tokens) y la misma respuesta;
|
|
|
sobreviven dos, `trigger-size` porque popover dimensiona con `height` y no
|
|
|
con el par lógico, y `open-trigger-fg` porque su selector añade
|
|
|
`[data-state='open']` y gana por orden. (2) ⚠ **`open-trigger-fg` OSCILA
|
|
|
entre corridas** — 17/21, 16/21, 16/21 con el mismo código, medido vivo
|
|
|
CUATRO veces (la última replicando paso a paso el `staticPass` del guard):
|
|
|
el panel se cierra en algún punto de la pasada y, durante la animación de
|
|
|
SALIDA, el content sigue en el DOM mientras el trigger ya perdió
|
|
|
`data-state='open'`, que es lo que la regla selecciona, así que `reopen()`
|
|
|
mira el CONTENT, cree que está abierto y no reabre. Un `openMarker` sobre
|
|
|
el trigger NO basta (el clic de reapertura cae en esa misma ventana) y se
|
|
|
retiró; el arreglo real es que `reopen()` espere a la CONDICIÓN en vez de
|
|
|
dormir un número fijo — §13. Su entrada de ledger saldrá **STALE** en las
|
|
|
corridas donde alcanza, y está escrito en la razón para que nadie la borre
|
|
|
por eso. (3) **el instrumento de captura estaba roto desde siempre**:
|
|
|
`__shot.ts` tenía el puerto 5173 CABLEADO, así que cualquier sesión en otro
|
|
|
puerto moría con `ERR_EMPTY_RESPONSE` — probablemente por lo que los pasos
|
|
|
6 y 13 del protocolo se saltaron en 33 componentes sin que nadie lo notara.
|
|
|
Ahora toma la URL como argumento, con un `--open` para los componentes cuya
|
|
|
superficie sólo existe abierta. Diff de computed vacío (6.080 valores · 8
|
|
|
estados · 176 nodos con el panel abierto), capturas 2× antes/después,
|
|
|
estrenando el instrumento arreglado.
|
|
|
- 2026-08-23 — **`progress` 69 % → 87 %** (`2e708adae`), 2 claves. `row-gap` +
|
|
|
`column-gap`: el `gap` en atajo tenía DOS valores distintos, así que es un knob
|
|
|
por eje (molde `chart.legend-row-gap`). **Seis literales de identidad
|
|
|
firmados** (cuatro `100%`, dos `max-content`: llena la fila que le dan o se
|
|
|
encoge a su propio grosor). **Rechazadas dos de las tres filas de la §4**: el
|
|
|
`--radius-full` del anillo es lo que HACE circular a `shape='circular'` — su
|
|
|
gemelo `meter` ya lo dejó escrito en el CSS, y se copia el comentario. Los dos
|
|
|
`private` que quedan son el CANAL DE VALOR (`--_progress-value-pct`, inline de
|
|
|
soma), así que **su techo honesto es 87 %**. R-5.4 40/43 con `sweepAttr:
|
|
|
data-shape` + los controles `indeterminate` y `vertical` de la demo (22/41 sin
|
|
|
ellos); tres adjudicados. Diff 0 sobre **60 configuraciones** (2 formas × 2
|
|
|
orientaciones × 3 estados × 5 tallas, 17.280 valores) y capturas 2×
|
|
|
**idénticas byte a byte**. ⚠ **una sonda que CACHEA los nodos da 8.352 falsos
|
|
|
diffs si el HMR reemplaza el subárbol**: `getComputedStyle` de un nodo
|
|
|
desacoplado devuelve la cadena vacía en TODAS las propiedades.
|
|
|
|
|
|
- 2026-08-23 — **`cropper` 60 % → 94 %** (`f03ee5af4`), 2 claves. El cromo del
|
|
|
botón de zoom (radio + `font-size`, costura). **Siete literales de IDENTIDAD**
|
|
|
firmados: cuatro `100%`, dos `50%` (lo que HACE redonda una selección y un
|
|
|
tirador) y un `line-height: 1`. El 6 % restante es el `:hover` neutro de ese
|
|
|
botón — no se acuña (§38 / R-4.3 lo deprecan) y no se puede migrar aquí
|
|
|
porque `[data-cropper-zoom-btn]` es hook EIDOS-ONLY sin arquetipo: cola de la
|
|
|
firma 3. De paso, hueco de composición: ese botón debería componer
|
|
|
`IconButton`. R-5.4 17/17.
|
|
|
|
|
|
- 2026-08-23 — **`badge` 59 % → 75 %** (`271fcd4df`), 6 claves. La ALTURA del
|
|
|
chip vivía en un privado con cuatro fuentes por talla leyendo
|
|
|
`--control-height-*` a pelo: es una ESCALA y sube al TSC. Más `dot-radius`, el
|
|
|
par que a `dot-size` le faltaba. **Y la suite corrigió el valor al entrar en el
|
|
|
contrato** (el bundle, no el primitivo): `recipe-css-contract` no se aplicaba a
|
|
|
la declaración mientras vivía en el CSS. Las 40 claves de tono no mueven nada
|
|
|
por la CASCADA DE PALETA — entran como excepción POR PATRÓN. Su sonda medía 2
|
|
|
nodos (dot / icon / remove son opt-in). `component:audit` NEEDS-WORK
|
|
|
PREEXISTENTE (R-1.5, sin foco).
|
|
|
|
|
|
- 2026-08-23 — **`s-text-virtual-list` 58 % → 70 %** (`1f785b6f2`), CERO claves.
|
|
|
Su techo es ése: el triple tipográfico lo escribe el componente INLINE en cada
|
|
|
render desde props resueltas, así que un público mentiría — y hay una razón
|
|
|
dura, el canvas que mide el texto lee `getComputedStyle` del contenedor y la
|
|
|
fuente pintada tiene que ser la MISMA que la medida. R-5.4 9/9 a la primera.
|
|
|
|
|
|
- 2026-08-23 — **`background` 57 % → 95 %** (`9bdc5a5d5`), 6 claves — la misma
|
|
|
costura dos veces (el mesh leía `--gradient-aurora`, los cinco pasos de
|
|
|
escarcha leían `--blur-*`). El grano del ruido NO se acuña: la textura ES la
|
|
|
técnica y re-escapar su data-URI cambiaría el valor serializado. Nace
|
|
|
`prepareWith` en el guard (3/37 → 18/37) **y la lección al revés: montar MÁS
|
|
|
capas midió MENOS** (17 → 9), porque el foco puntual y el paralaje repintan la
|
|
|
capa donde se miden los patrones. 19 adjudicaciones medidas.
|
|
|
|
|
|
- 2026-08-23 — **`color-field` 56 % → 93 %** (`3c6742b9c`), 4 claves (el divisor
|
|
|
de canal y el ancho fijo por caracteres). **13 tokens preexistentes medidos uno
|
|
|
a uno** — nunca había pasado por R-5.4. Las dos de transición costaron dos
|
|
|
diagnósticos falsos: el conocido (el guard congela) y uno mío, sospechar del
|
|
|
`prefers-reduced-motion` cuando la causa era medir el PRIMER segmento, que es
|
|
|
un `literal` con `transition: none` propio.
|
|
|
|
|
|
- 2026-08-23 — **`waveform` 55 % → 86 %** (`11b92ded6`), 1 clave: `playhead-bg`,
|
|
|
la única línea del re-tinte del Slider embebido que pasaba un primitivo CRUDO.
|
|
|
El censo no la veía (una custom property reenviada a un compuesto no está en
|
|
|
`KNOB_PROPS`). El 14 % restante es préstamo con dueño: apagarse es decisión del
|
|
|
Slider. Tercera cara del punto ciego del instrumento: las partes de un
|
|
|
componente COMPUESTO.
|
|
|
|
|
|
- 2026-08-23 — **`navigation-menu` 44 % → 100 %** (`85988785d`), bloque B1.
|
|
|
Contrato 26 → 44 claves: **19 nuevas y UNA retirada**. Diff 0 sobre 2.752
|
|
|
valores en 8 estados; R-5.4 43/44 con una adjudicación.
|
|
|
|
|
|
**Los nombres los dio el catálogo**: los gemelos cerrados el mismo día
|
|
|
(`dropdown-menu`, `context-menu`) para `content-{min-width,padding,radius,fg}`
|
|
|
y `chevron-{size,stroke}`; `accordion` para `trigger-font-family` y
|
|
|
`disabled-trigger-fg`. Las CUATRO recetas que declaran un chevron lo
|
|
|
dimensionan con un literal — un glifo no es un paso de la escala de espacio —,
|
|
|
y al revés el subrayado: su `2px` ES `--border-width-medium`.
|
|
|
|
|
|
**La §4 generada falla de CINCO maneras, una nueva**: llamaba `trigger-width`
|
|
|
/ `trigger-height` al CHEVRON (colisionando con la altura del control, que ya
|
|
|
existe), fundía dos nodos en `content-radius`, cruzaba `content-padding-*`
|
|
|
(era de la FILA) y llamaba `content-width` a un `min-inline-size` — y abría
|
|
|
exigiendo consumir la capa `menu-indicator`, que es **homonimia**: esa capa es
|
|
|
el check de los CheckboxItem, no el subrayado de esta barra.
|
|
|
|
|
|
**Las filas del panel no son `item-` ni `link-`**: aquí `item` es el `<li>` de
|
|
|
la barra y el `Link` de barra viste el cromo del trigger, así que esos nombres
|
|
|
prometerían un nodo que no alcanzan. `content-link-*` nombra el nodo por donde
|
|
|
vive. **El privado era una ESCALA** (tres fuentes por talla), y sube al TSC.
|
|
|
**`indicator-x` era declaración muerta** — soma escribe el rect inline y la
|
|
|
receta lee sólo `-w`/`-h`; retirada, 0 diffs.
|
|
|
|
|
|
**El instrumento, dos cegueras y una trampa** (§13): sonda y centinela no
|
|
|
veían el panel ni sus filas (los `<a>` desnudos del consumidor: 10 nodos y
|
|
|
ninguno era el panel — 9 de 19 knobs fuera del diff); **el guard cerraba el
|
|
|
panel que medía** (abre por `pointerenter`, y el aparcado del puntero en (0,0)
|
|
|
dispara el cierre) dando falso negativo Y falso positivo a la vez; y `color`
|
|
|
está EN TRANSICIÓN en esta parte, así que forzar `data-disabled` y leer en el
|
|
|
acto devuelve el valor viejo — la trampa del cuentagotas, en otro componente.
|
|
|
|
|
|
- 2026-08-23 — **`audio-player` 37 % → 56 %** (3 claves) **y el instrumento
|
|
|
medía CERO nodos**. El 44 % restante es préstamo con dueño (ocho filas
|
|
|
`--media-player-*`): es la piel de audio de ese chasis y se tema en su ficha.
|
|
|
|
|
|
Acuñado lo único que añade sobre el chasis: el peso del título y la insignia
|
|
|
LIVE (peso + tracking); los dos `600` pasan a `var(--font-weight-semibold)`.
|
|
|
|
|
|
**Tres cegueras encadenadas**: `/uix/components/audio-player` es un **404** —el
|
|
|
CUARTO canónico sin ruta—; sus partes son `data-media-player-*`, no
|
|
|
`data-audio-player-*` (con `extraNodes`, la sonda pasa de **0 a 48 nodos**); y
|
|
|
sólo existe tras el chip `media: audio` de la demo del chasis (sonda y guard lo
|
|
|
pulsan ahora, y el guard barre las cuatro variantes). Con eso, 0/8 → 6/8.
|
|
|
|
|
|
- 2026-08-23 — **COLA PEQUEÑA: seis componentes, cero claves nuevas.** `section`
|
|
|
(— · cuatro claves RESUCITADAS), `sticky` 0 → **100 %**, `button-group` 40 →
|
|
|
**100 %**, `qr-code` 43 → **100 %**, `toggle-group` 33 → **50 %** (su techo) y
|
|
|
`split-button` ADJUDICADO en 50 % (su techo). Global 65 %; **25 componentes al
|
|
|
100 %** y los de alcance <20 % bajan de 14 a 12.
|
|
|
|
|
|
**El hallazgo está en `section`: la receta TAPABA sus propias claves públicas.**
|
|
|
Declaraba los cuatro pasos de relleno en el host
|
|
|
(`[data-box][data-section] { --section-padding-block-sm: … }`), y esa
|
|
|
declaración gana a la que el contrato emite en `:root`: un tema que escribiera
|
|
|
`--section-padding-block-lg` perdía contra la receta. Borrado el bloque —mismos
|
|
|
valores, una sola fuente—, computado idéntico (48px antes y después), y las
|
|
|
cuatro claves alcanzan.
|
|
|
|
|
|
Lo demás es **identidad**: once `100 %` entre las seis recetas y el centinela
|
|
|
de 2px del sticky —el hilo invisible que el observador vigila—, todos con su
|
|
|
razón escrita. Más un respaldo muerto retirado en `toggle-group`, sobre un
|
|
|
token PRESTADO de `toggle` (el velo de un grupo deshabilitado es el del
|
|
|
toggle, y se tema en su ficha).
|
|
|
|
|
|
**Y una clase de adjudicación nueva, que se repetirá: UN PASO POR INSTANCIA.**
|
|
|
`section` y `qr-code` mapean su prop de talla a `var(--{c}-{eje}-{k})` y la
|
|
|
escriben INLINE, así que sólo el paso ACTIVO alcanza; los otros cuatro leen
|
|
|
muertos hasta que la prop cambia. No es deuda ni ceguera del instrumento: es
|
|
|
cómo funciona una escala resuelta por prop.
|
|
|
|
|
|
Gates: seis guards en verde · censo · audit PASS · suite con el rojo conocido
|
|
|
ajeno · rtl 0 · docs 0.
|
|
|
|
|
|
- 2026-08-23 — **`tooltip` 52 % → 75 %** (3 claves, 4 literales anotados) **y el
|
|
|
plano `overlay` ANULA SUS TRES VARIANTES**. Global 65 %.
|
|
|
|
|
|
Acuñados el desenfoque del velo `ghost` y las dos tintas de la flecha
|
|
|
`outline`. **No se acuñó `ghost-bg`**: lo intenté, el centinela lo delató y se
|
|
|
retiró antes de commitear.
|
|
|
|
|
|
**⚠⚠ El plano no sólo se queda la tipografía: se queda el fondo, el borde y la
|
|
|
sombra.** Medido: `--tooltip-bg`/`-border`/`-shadow` no mueven nada,
|
|
|
`--depth-overlay-*` repinta. Y la consecuencia visual es peor que la contable:
|
|
|
`solid`, `outline` y `ghost` computan lo MISMO — `outline` es indistinguible
|
|
|
de `solid`. → §13. Las cinco claves quedan adjudicadas, no retiradas: son la
|
|
|
fuente de la máquina de variantes.
|
|
|
|
|
|
Instrumento: el tooltip abre por HOVER (`openBy: 'hover'`, como link-preview) —
|
|
|
0/24 → 14/24—, y el resto se midió con el interruptor `open` de la demo, porque
|
|
|
un panel abierto por puntero exige el ratón quieto toda la pasada.
|
|
|
|
|
|
- 2026-08-23 — **`time-range-field` 29 % → 100 %** (4 claves), gemelo exacto de
|
|
|
`date-range-field` **defecto incluido**: la misma clave `row-gap` alimentando
|
|
|
el `column-gap`. Global **64 % → 65 %**.
|
|
|
|
|
|
Que los dos gemelos tuvieran el MISMO nombre equivocado dice algo: el error no
|
|
|
se coló al escribir, se copió al duplicar. **Donde hay un par, el defecto viene
|
|
|
en par** — mirar al gemelo es parte de la pasada.
|
|
|
|
|
|
- 2026-08-23 — **`date-range-field` 29 % → 100 %** (4 claves, una RENOMBRADA
|
|
|
porque mentía). Centinela 7/7.
|
|
|
|
|
|
**`row-gap` alimentaba el `column-gap`**: la clave pública movía el hueco entre
|
|
|
los dos campos, y el de fila —etiqueta ↔ campos— leía `--space-1-5` a pelo.
|
|
|
Dos claves ahora, cada una con el nombre de lo que alimenta, y **ningún
|
|
|
computado se mueve**. Un nombre equivocado es una perilla que gira otra cosa.
|
|
|
|
|
|
**La etiqueta se acuña con fecha de caducidad**: la raíz del rango NO es un
|
|
|
`[data-field]` —lo dice la propia receta— así que no puede heredar la etiqueta
|
|
|
de field.css y repetía los valores de la fundación. Nombrados aquí, y escrito
|
|
|
en el contrato que el mandato §5.3-3 los borra cuando la raíz sea un campo.
|
|
|
|
|
|
- 2026-08-23 — **`surface` ADJUDICADO: el 25 % es su techo**, cero claves nuevas.
|
|
|
Es la cara de PINTURA de Box y lo que pinta no es suyo: `bg` y `fg` salen del
|
|
|
puente de paleta (THM-2) y el acabado es canal de valor del generador (§39).
|
|
|
La rama `inherit` del `fg` suave es intencionada y está escrita en la receta.
|
|
|
|
|
|
**Pero no tiene ruta**: `/uix/components/surface` es un 404 y el guard medía
|
|
|
una página VACÍA — 0/25, incluido un `radius` vivísimo. Apuntado a
|
|
|
`/temas/gradientes` + `/blocks/cta`: 1/25, y el que mueve es el radio. Ya son
|
|
|
TRES los canónicos sin demo (picker-shell, mockup, surface) → §13.
|
|
|
|
|
|
Sus 24 claves de tono son la supersesión de paleta de hoy: patrón compartido.
|
|
|
|
|
|
- 2026-08-23 — **`banner` 30 % → 100 %** (11 claves) **y el guard pasa de 4/42 a
|
|
|
53/53**: sus 38 «muertos» estaban vivos, sólo que nadie los había mirado con
|
|
|
el atributo puesto. Global 64 %.
|
|
|
|
|
|
Cosida la densidad por talla, la interlínea y el trazo del anillo de
|
|
|
`outline` —la última fila que impedía al privado del borde derivar—. Dos
|
|
|
ausencias firmadas: los `transparent` de `outline`/`ghost` y los
|
|
|
`border-width: 0`, con el criterio de button.
|
|
|
|
|
|
**Dos cegueras del instrumento, arregladas**: (1) su paleta resuelve por
|
|
|
`data-intent`, no por `data-color`, y el barrido de tono estampaba sólo el
|
|
|
segundo — ahora estampa los dos nombres; (2) y luego por VARIANTE, así que el
|
|
|
guard recorre `data-variant` con `sweepAttr`. Es la diferencia entre «38
|
|
|
tokens que mienten» y «38 que nadie había mirado con el atributo puesto».
|
|
|
|
|
|
Gates: sonda 0 diffs en 192 valores × 7 estados · centinela 53/53 · censo
|
|
|
100 % · audit PASS · suite con el rojo conocido ajeno · rtl 0 · docs 0 ·
|
|
|
captura de cuatro variantes × cuatro intenciones.
|
|
|
|
|
|
- 2026-08-23 — **`anchor-nav` 20 % → 100 %** (11 claves) **y el censo aprende los
|
|
|
bordes POR LADO**. Global 64 %.
|
|
|
|
|
|
Tenía dos knobs y todo lo demás a pelo: la escala (que ahora lee el bundle),
|
|
|
el relleno y el radio del enlace, sus tres tintas, el peso del activo y las dos
|
|
|
tintas del RAÍL, que es lo que da nombre al componente.
|
|
|
|
|
|
**El raíl activo era INVISIBLE para la medida**: su color vive en un
|
|
|
`border-inline-start-color` y `KNOB_PROPS` sólo conocía `border-color` y los
|
|
|
shorthands. El centinela mira esos longhands desde el 2026-08-22 (los añadió
|
|
|
cuando prose y nav-tree leyeron muertos); el censo no. Añadidos los ocho por
|
|
|
lado, color y grosor: **+30 filas en el catálogo** (5.101 → 5.131) y esta ficha
|
|
|
baja a 18 % antes de coserse — el censo promete sobre-reportar, NUNCA
|
|
|
infra-reportar.
|
|
|
|
|
|
La tinta de reposo del raíl estaba escondida de otra manera: dentro de un
|
|
|
shorthand que el censo clasifica por el PRIMER token que casa (el trazo, ya
|
|
|
público). No hizo falta partirlo: basta nombrar el color dentro.
|
|
|
|
|
|
**Un susto útil**: una coma que faltaba en el contrato rompió el build de
|
|
|
tokens y lo delató la SONDA midiendo 0 nodos — la página no renderizaba. El
|
|
|
recuento de nodos es el canario.
|
|
|
|
|
|
Gates: sonda 0 diffs en 1.760 valores × 7 estados · centinela 11/12 · censo
|
|
|
100 % · audit PASS · suite con el rojo conocido ajeno · rtl 0 · docs 0.
|
|
|
|
|
|
- 2026-08-23 — **`image` 60 % → 96 %** (1 clave, 12 literales anotados) **y dos
|
|
|
instrumentos que morían en esta página**. Global 64 %.
|
|
|
|
|
|
Su deuda era casi toda IDENTIDAD: once `100 %` (la imagen, el fallback, el
|
|
|
error y sus dos `<img>` llenan su caja) y un `opacity: 1` (una imagen cargada
|
|
|
es opaca). Lo acuñado es la barra del esqueleto, que leía `--gradient-shimmer`
|
|
|
a pelo.
|
|
|
|
|
|
**La página NO alcanza `networkidle` NUNCA** —monta un `src` roto a propósito
|
|
|
para su estado de error— y sonda y guard morían con `TimeoutError` antes de
|
|
|
medir un nodo. Las dos caen ahora al evento `load` si la espera se agota.
|
|
|
|
|
|
**Un token bajo `@media (prefers-reduced-motion: reduce)` lee muerto**:
|
|
|
`placeholder-base` sólo existe ahí. Emulando la preferencia, alcanza — y vale
|
|
|
para cualquier token detrás de una media query de preferencia.
|
|
|
|
|
|
**Lectura fantasma cazada por repetición**: el primer diff acusó
|
|
|
`opacity: 0.925793 → 1` en la imagen cargada; era el fade EN VUELO, como el rim
|
|
|
animado de `onion-menu`. Repetida la medida, 0 diffs.
|
|
|
|
|
|
Gates: sonda 0 diffs en 544 valores × 7 estados (repetida) · centinela 20/23 ·
|
|
|
censo 96 % · audit PASS · suite con el rojo conocido ajeno · rtl 0 · docs 0.
|
|
|
|
|
|
- 2026-08-23 — **`checkbox` 59 % → 72 %** (3 claves, 3 literales anotados) **y un
|
|
|
HUÉRFANO cableado**. El 28 % restante es el puente de paleta (8 filas, THM-2).
|
|
|
|
|
|
**`indicator-fg` era un huérfano que el test de huérfanos no puede ver**: la
|
|
|
clave estaba en el contrato, pero la receta pintaba la tinta de la casilla
|
|
|
marcada leyendo `--color-content-on-solid` DIRECTAMENTE, sin nombrarla — y el
|
|
|
test busca el NOMBRE en los ficheros del componente. Cableada al privado de
|
|
|
paleta (computado idéntico), el propio guard lo confirmó marcando su
|
|
|
adjudicación como STALE: ahora mueve. Misma clase que el `--popover-bg` que
|
|
|
vivía de un COMENTARIO, al revés.
|
|
|
|
|
|
Acuñado el estado INVALID: el borde y el doble anillo de foco (hueco +
|
|
|
anillo), que era una sombra con dos colores cableados; la geometría 2px/4px se
|
|
|
queda dentro de la declaración, que es la forma del anillo.
|
|
|
|
|
|
**Dos trampas de ALCANCE del instrumento**, anotadas: el glifo sólo existe
|
|
|
dentro de una casilla MARCADA (medir «el primer indicador del documento» mide
|
|
|
otro nodo) y la etiqueta de grupo lleva su PROPIO `[data-disabled]`, no lo
|
|
|
hereda.
|
|
|
|
|
|
Gates: sonda 0 diffs en 2.688 valores × 7 estados · centinela 22/47 con todo
|
|
|
adjudicado · censo 72 % · audit PASS · suite con el rojo conocido ajeno · rtl 0
|
|
|
· docs 0 · captura de cinco estados.
|
|
|
|
|
|
- 2026-08-23 — **`dropdown-menu` 57 % → 96 %** (9 claves, 18 respaldos muertos
|
|
|
retirados) **y la tipografía del gemelo, RETIRADA**: `context-menu` 90 % →
|
|
|
87 %, a la baja y a propósito. Global 64 %.
|
|
|
|
|
|
Cosidos la tinta del panel y de la fila, su interlínea, el encabezado entero y
|
|
|
el galón del submenú (trazo + caja). **El filo del separador deja de ser un
|
|
|
`1px` suelto** y pasa a `--border-width`. Las dos limpiezas del gemelo se
|
|
|
repiten aquí: `font-family` era respaldo de SÍ MISMO y el peso del encabezado
|
|
|
llevaba un `500` muerto.
|
|
|
|
|
|
**Los 18 respaldos**: cada `var(--dropdown-menu-x, …)` llevaba detrás un valor
|
|
|
que no puede ocurrir —las claves están en el contrato— y sólo servía para
|
|
|
envejecer contra él; dos ya discrepaban en la FUENTE.
|
|
|
|
|
|
**⚠ `content-font-family` no se acuña, y la de `context-menu` se RETIRA.** El
|
|
|
panel lleva `data-depth='overlay'` y el plano gana (quinta prueba de §12.9).
|
|
|
Tenerla acuñada con una adjudicación escrita —como quedó ayer en el gemelo—
|
|
|
era media doctrina: **un público que no alcanza es un token que miente**
|
|
|
(R-5.4). Las dos recetas vuelven a la fuente literal con la razón encima.
|
|
|
`combobox` tiene la misma clave sobre el mismo plano: medido, registrado en
|
|
|
§13, no tocado aquí.
|
|
|
|
|
|
Gates: sonda 0 diffs en 928 valores × 8 estados · centinela 27/28 · censo
|
|
|
96 % · audit PASS · suite con el rojo conocido ajeno · rtl 0 · docs 0 ·
|
|
|
captura del panel.
|
|
|
|
|
|
- 2026-08-23 — **`empty-state` 29 % → 100 %** (20 claves, 6 → 26) **y el
|
|
|
centinela 26/26 sin una sola adjudicación**. Global 64 %.
|
|
|
|
|
|
Su deuda era de una clase: **la escala de talla vivía entera en privados** que
|
|
|
leían el bundle a pelo. Cada paso tiene ya su público (relleno, título, cuerpo
|
|
|
y glifo en `sm`/`md`/`lg`) y los privados los derivan; con eso el resto —peso,
|
|
|
interlínea y tinta del título, interlínea y tinta de la descripción— sale
|
|
|
solo. La caja del glifo se sigue derivando (2×) de su tamaño, ahora público.
|
|
|
|
|
|
**Siete respaldos muertos retirados**, dos de ellos MENTIROSOS: el `, 1.4` de
|
|
|
`--font-line-height-sm` (vale 1.45) y el `, 1.5` de `--font-line-height-md`.
|
|
|
Mismo defecto que `callout` hoy: **un respaldo escrito a mano envejece contra
|
|
|
el token**.
|
|
|
|
|
|
Gates: sonda 0 diffs en 1.056 valores × 7 estados · centinela 26/26 · censo
|
|
|
100 % · audit PASS · suite con el rojo conocido ajeno · rtl 0 · docs 0 ·
|
|
|
captura de las tres tallas.
|
|
|
|
|
|
- 2026-08-23 — **`callout` 27 % → 79 %** (7 claves, un literal anotado). Global
|
|
|
**63 % → 64 %**. El 21 % restante es el PUENTE DE PALETA (THM-2), que no es
|
|
|
deuda.
|
|
|
|
|
|
Cosidos el hueco de fila, la tipografía del cuerpo, la tinta, el tamaño del
|
|
|
icono y el peso del título, todos leyendo el BUNDLE. **La línea base óptica
|
|
|
del icono deja de repetir las métricas del sistema**: la misma derivación,
|
|
|
ahora sobre los tokens del propio callout, así que un tema que agrande la
|
|
|
copia mueve la caja del glifo con ella.
|
|
|
|
|
|
**Cinco respaldos muertos retirados** (`var(--callout-gap, var(--space-3))` y
|
|
|
compañía: las claves están en el contrato) incluido el `, 1.5` de
|
|
|
`--font-line-height-md`, que además mentía — el token existe y vale 1.45.
|
|
|
|
|
|
Los 24 rojos del guard son los TONOS: la supersesión que `button` destapó el
|
|
|
mismo día, adjudicada con el patrón compartido.
|
|
|
|
|
|
Gates: sonda 0 diffs en 896 valores × 7 estados · centinela 10/34 · censo
|
|
|
79 % · audit PASS · suite con el rojo conocido ajeno · rtl 0 · docs 0 ·
|
|
|
captura de cuatro tonos.
|
|
|
|
|
|
- 2026-08-23 — **`button` 55 % → 91 %** (1 clave, 17 declaraciones anotadas) **y
|
|
|
el hallazgo más gordo del eje: la cascada de paleta ANULA los tonos del
|
|
|
componente — 419 claves en el catálogo.** Global 63 %.
|
|
|
|
|
|
Acuñado lo único que faltaba: **el paso `full` de la escala de radio**
|
|
|
(`[data-rounded='full']` leía el primitivo global a pelo). Anotadas 7
|
|
|
identidades (`fit-content` × 2, el `100 %` de `[data-block]`, los cuatro
|
|
|
`1px` de las cajas sr-only) y **10 ausencias**: los `transparent` de `soft`,
|
|
|
`outline`, `ghost` y `plain` — la variante ES la ausencia de cromo, y diez
|
|
|
claves de `transparent` habrían sido el antipatrón que la doctrina avisa.
|
|
|
|
|
|
Para que la ausencia cuente, **el censo aprende la válvula de recipe-contract
|
|
|
§3 un piso más abajo**: un PRIVADO cuyo valor es un literal CON su razón
|
|
|
escrita es una ausencia firmada, no deuda (`derivesFromPublic` la acepta).
|
|
|
Sin eso, cuatro privados marcaban «no deriva» y seis knobs leían
|
|
|
inalcanzables mientras todas las demás ramas del mismo privado leen un
|
|
|
público. El censo global sube 5 knobs por esto, no por retoque de ratio.
|
|
|
|
|
|
**⚠⚠ EL HALLAZGO.** El último bloque del forward, `[data-button][data-color]`,
|
|
|
resuelve `--button-palette-*` desde el `--palette-*` GLOBAL —que
|
|
|
`[data-color='{tono}']` llena desde `--color-{tono}-*`— y **gana a las reglas
|
|
|
por tono por ORDEN**, con la misma especificidad (0,2,0). Medido sobre
|
|
|
`data-color='risk'`: `--button-risk-solid` no mueve nada, ni en `:root` ni en
|
|
|
el nodo; `--palette-solid` y `--color-risk-solid` en el nodo repintan. Las
|
|
|
siete `primary-*` son el RESPALDO de esa regla y sólo actúan SIN
|
|
|
`data-color`. **49 recetas emiten ese mismo forward y el catálogo tiene 419
|
|
|
claves de tono**; medido igual en `badge` y `callout`. → §13, con el arreglo
|
|
|
propuesto (orden de emisión) y su contrapartida (la jaula del color).
|
|
|
|
|
|
El techo restante son dos filas de canal de valor (`--_button-fill-finish`,
|
|
|
el acabado que el generador deriva por instancia; su dial es del sistema).
|
|
|
|
|
|
**Un error de método que casi cuela**: anclé la clave nueva en la primera
|
|
|
línea `'radius-xl'` del fichero y aterrizó en **`meter`**. Lo delató el
|
|
|
navegador (`--button-radius-full` sin definir ⇒ radio 0). Una inserción se
|
|
|
ancla en el BLOQUE del componente, nunca en una línea de clave.
|
|
|
|
|
|
Instrumento: el guard aprende **`sweepAttr`** (barrer una variante mientras
|
|
|
mide) y a estampar **el tono que la clave nombra**; y el fichero de
|
|
|
excepciones gana **patrones** (`SENTINEL_PATTERN_EXCEPTIONS`), para que una
|
|
|
razón arquitectónica se escriba UNA vez y no 56.
|
|
|
|
|
|
Gates: sonda 0 diffs (416 valores; la demo monta UN botón) · equivalencia del
|
|
|
paso `full` comprobada aparte · centinela 34/106 con el resto adjudicado ·
|
|
|
censo 91 % · audit PASS · suite con el rojo conocido ajeno · rtl 0 · docs 0 ·
|
|
|
captura de las seis variantes + píldora + tono `risk`.
|
|
|
|
|
|
- 2026-08-23 — **`onion-menu` 29 % → 84 %** (7 claves + 5 literales anotados), y
|
|
|
**una regla del recipe que el navegador DESCARTA**. Global 63 %.
|
|
|
|
|
|
Acuñados el color del anillo del sector —UNO para los dos estados: el propio
|
|
|
CSS dice que el hover usa «el mismo color que el anillo de selección, más
|
|
|
claro», y lo que los separa es la opacidad que ya tenía token—, la tipografía
|
|
|
de la etiqueta, el radio y la tinta del disparador y las dos piezas del glifo
|
|
|
`+`→`×`. Dos limpiezas de paso: un `var(--style-label-font-family, var(--style-label-font-family))`
|
|
|
—respaldo de sí mismo, el defecto de context-menu— y dos `var(--radius-full, …)`
|
|
|
con respaldo imposible.
|
|
|
|
|
|
**⚠ `.onion-menu-icon :global(svg)` NO EXISTE**: `:global()` es un envoltorio
|
|
|
de Svelte y esto es un CSS plano, así que el selector es inválido y la regla
|
|
|
entera se descarta. Medido: el glifo computa 14px (el tamaño propio del Icon)
|
|
|
y el `70 %` que el fichero cree pintar no pinta. Acuñé `icon-glyph-size`, el
|
|
|
centinela lo delató y lo RETIRÉ: arreglar el selector mueve píxel. Mismo bug
|
|
|
en `timeline.css:331`; `image-picker.css` ya documentaba la trampa. → §13.
|
|
|
|
|
|
**Tres cegueras del instrumento, dos nuevas y genéricas**:
|
|
|
|
|
|
1. **El guard CERRABA la superficie.** Este menú nace ABIERTO y el clic de
|
|
|
«abrir» lo cerraba — 12 de 20 tokens muertos. Ahora, si hay `openMarker` y
|
|
|
ya casa, no se pulsa nada (8 → 14 de golpe).
|
|
|
2. Sus tripas cuelgan de CLASES, no de `data-onion-*`: sonda y guard las miden
|
|
|
con `extraNodes` (37 nodos en reposo contra 5).
|
|
|
3. **Congelar las transiciones no basta cuando el nodo está ANIMADO**:
|
|
|
`rim-glow-opacity` leía 0,482956 —el valor animado— y parecía muerto;
|
|
|
congelando también la animación computa 0,45 y sigue al token.
|
|
|
|
|
|
Los cuatro tokens del rim son del look `luminous`, **que la demo del
|
|
|
componente no renderiza** (prop de Svelte que emite otro marcado, no hay
|
|
|
atributo que forzar): medidos en `/active/docs/agnt`.
|
|
|
|
|
|
Gates: sonda **0 diffs** en 7.328 valores × 8 estados · centinela 14/19 con
|
|
|
las cinco adjudicadas · censo 84 % · audit PASS · suite con el rojo conocido
|
|
|
ajeno · rtl 0 · docs 0 · `check` sin errores propios · capturas.
|
|
|
|
|
|
- 2026-08-23 — **`field` 73 % → 98 %** (8 claves + 8 literales ANOTADOS) **y sus
|
|
|
18 rojos, medidos**. Global **63 %**. El 2 % que falta es el puente de paleta
|
|
|
(THM-2), que no es deuda.
|
|
|
|
|
|
Es el componente más COMPUESTO del sistema: lo que otras fichas llaman
|
|
|
«préstamo con dueño» se cobra aquí, así que su techo pesa más que el de nadie.
|
|
|
|
|
|
Acuñados el **disparador de control** —el icono que abre el calendario, el
|
|
|
reloj o la muestra, y revela la contraseña: `size`, `radius`, `fg` y sus dos
|
|
|
estados—, el indicador `optional` (gemelo del `required`, que ya tenía token)
|
|
|
y el **lateral de la etiqueta flotante**, que es lo que CORTA el borde bajo el
|
|
|
texto. La caja del disparador se mide en `em` a propósito, así que el token
|
|
|
guarda la RAZÓN (`1.75em`), no un píxel por talla.
|
|
|
|
|
|
**Ocho literales pasan a excepción firmada por IDENTIDAD, no por inflar el
|
|
|
ratio**: cuatro `inline-size: 100%`, dos `line-height: 1` de un glifo suelto y
|
|
|
dos `1em` del icono dentro del disparador (el glifo ES el tamaño del texto).
|
|
|
|
|
|
**Los 20 rojos del guard estaban VIVOS**, y tres enseñan algo:
|
|
|
`disabled-opacity` vive en el CONTROL y el guard leía la raíz;
|
|
|
**`control-placeholder-fg` no leía porque el input de la demo NO TIENE
|
|
|
`placeholder`** —sin atributo no hay caja `::placeholder` y
|
|
|
`getComputedStyle(nd, '::placeholder')` devuelve el estilo del ELEMENTO—; y
|
|
|
`segment-height` es un token de FAMILIA que field posee y los pickers
|
|
|
consumen, además de RESUELTO: desde `:root` no se mueve por diseño (medido en
|
|
|
`/time-picker`: desde el host 28px → 1234px, moviendo la coordenada
|
|
|
`--field-control-height-md` 28px → 992px).
|
|
|
|
|
|
**Instrumento**: el disparador de control no lo monta NINGUNA demo de field,
|
|
|
así que el guard mide ahora `field` sobre DOS rutas (`/field` + `/date-picker`).
|
|
|
|
|
|
Gates: sonda **0 diffs** en 2.280 valores × 8 estados · equivalencia del
|
|
|
disparador comprobada aparte · centinela 48/68 con las 20 adjudicadas · censo
|
|
|
98 % · `--names` 0 · audit PASS · rtl 0 · docs 0 · suite eidos con el rojo
|
|
|
conocido ajeno · `check` sin errores propios · capturas de reposo, invalid,
|
|
|
disabled, etiqueta flotante y disparador.
|
|
|
|
|
|
- 2026-08-23 — **`menubar` 15 % → 88 %** (30 claves, 5 → 35). Global **62 % →
|
|
|
63 %**. Las tres filas que quedan fuera NO son deuda de este eje.
|
|
|
|
|
|
Cosidas la barra (superficie, marco, radio desacoplado de la talla, y las
|
|
|
tres escalas `gap`/`padding`/`height`), el disparador (tinta, tipografía,
|
|
|
escala de `font-size` y de `padding-inline`, el par de la entrada ABIERTA y
|
|
|
la tinta deshabilitada) y el Panel `role=dialog` (tinta + escala). Los pasos
|
|
|
leen el BUNDLE (`--size-{k}-control-height` / `--size-{k}-font-size`), no el
|
|
|
primitivo crudo que el CSS venía consumiendo, y el `calc(var(--space-1) * 0.5)`
|
|
|
del paso `sm` pasa a `var(--space-0-5)` (mismo computado).
|
|
|
|
|
|
**El hueco del panel deja de repetir el valor del padding**: las tres reglas
|
|
|
de `--floating-gap` compensaban el sangrado del disparador con una COPIA del
|
|
|
padding de la barra; ahora leen `--menubar-padding-{k}`, su fuente. No pueden
|
|
|
leer el privado: esas superficies viajan por PORTAL, y un privado de la raíz
|
|
|
no cruza esa frontera (la ley de ayer, aplicada al derecho).
|
|
|
|
|
|
**⚠ El plano `overlay` GANA a la receta — cuarta prueba de §12.9, y la
|
|
|
primera con MECANISMO.** Acuñé `panel-font-family` y `panel-line-height`; el
|
|
|
centinela las dio muertas. Medido: `[data-depth='overlay']` declara las dos
|
|
|
con la MISMA especificidad (0,1,0) y más tarde en la cascada, así que gana,
|
|
|
mientras `panel-fg` y `panel-font-size-*` —del mismo bloque— sí alcanzan.
|
|
|
Retiradas del contrato, devueltas a su fuente literal con la razón en el CSS.
|
|
|
**Mientras §12.9 no se firme, un token de tipografía en cualquier superficie
|
|
|
`overlay` miente**, y eso vale para los veinte componentes del empate.
|
|
|
|
|
|
**El hover no se acuña: es del eje navigation-menu.** `background:
|
|
|
var(--color-surface-overlay)` sobre el disparador mata la capa del sistema
|
|
|
—medido: `background-image` computa `none` en hover con `--state-hover`
|
|
|
vivo—, por las dos razones que `navigation-menu.css` ya documenta al haber
|
|
|
retirado esa misma regla: el shorthand resetea `background-image`, y la regla
|
|
|
del arquetipo va en `:where()` (especificidad CERO). Acuñar `hover-trigger-bg`
|
|
|
habría fosilizado la invención. → §13.
|
|
|
|
|
|
**Instrumento**: la barra suelta DOS superficies y el Panel —el que lleva sus
|
|
|
knobs— cuelga de la entrada «Format», no de la primera; sonda (`OPEN_TRIGGER`)
|
|
|
y guard (`openWith`) aprenden a abrir la que toca. Y el guard necesitó
|
|
|
`openMarker`: su comprobación de «ya está abierto» busca `[data-{c}-content]`,
|
|
|
que aquí no existe, así que volvía a pulsar el disparador antes de cada token
|
|
|
y CERRABA el panel.
|
|
|
|
|
|
Gates: sonda **0 diffs** en 1.470 valores × 8 estados · centinela 34/35 (la
|
|
|
deshabilitada adjudicada) · censo 88 % · `--names` 0 · audit PASS · rtl 0 ·
|
|
|
docs 0 · suite eidos con el rojo conocido ajeno · `check` sin errores propios
|
|
|
· capturas de barra, tallas, menú y panel.
|
|
|
|
|
|
- 2026-08-23 — **Los dos rojos que quedaban del bloque viejo, medidos: `metrics`
|
|
|
(18) y `color-picker` (25). Los dos guards en verde; sin cambios de código.**
|
|
|
|
|
|
**`metrics`: los 18 están VIVOS, uno por uno.** Ninguno miente — lo que
|
|
|
faltaba era el escenario: seis piden el paso `xxl` (la demo llega a `xl`),
|
|
|
dos el icono SIN `data-color` (el defecto que sólo pinta cuando no hay
|
|
|
color, y todos los iconos de la demo llevan uno), dos las formas `circle` /
|
|
|
`square` (la demo monta `rounded`), cuatro la fila de acciones (no montada),
|
|
|
uno el gráfico en `end` (la demo los coloca `full`), uno el borde de la
|
|
|
variante `outline`, y **dos el sello de sema durante el hold**
|
|
|
(`data-event-family=signal` + `phase=active`): el destello del valor se mide
|
|
|
estampando el sello a mano, porque cuando el guard lee ya se ha ido.
|
|
|
|
|
|
**`color-picker`: 23 de 25 vivos, y los otros dos son un DEFECTO REAL —
|
|
|
el eje `size` muere en el portal.** `--_color-picker-content-width` se
|
|
|
declara TRES veces y no lo consume NADIE: la anchura del panel la fija
|
|
|
`--_popover-content-width-override` cableada al paso `md`, así que un picker
|
|
|
`sm` y uno `lg` abren el mismo panel de 344 px. Lo mismo con las muestras
|
|
|
dentro del panel (`--_color-picker-swatch-size` clavado a `md`): fuera del
|
|
|
portal los tres pasos alcanzan (20 / 24 / 28 px), dentro sólo el `md`. La
|
|
|
causa es una sola y vale como ley: **el portal es una frontera de cascada —
|
|
|
un privado declarado en la raíz del componente no la cruza.** → §13, porque
|
|
|
arreglarlo mueve píxel en `sm` y `lg`.
|
|
|
|
|
|
Tres cegueras del instrumento, medidas y anotadas: **el guard congela las
|
|
|
transiciones y `transition-duration` / `transition-ease` SON la transición**
|
|
|
(sin congelar: 0.12s → 11.5s) — es genérico, cualquier componente con esos
|
|
|
dos públicos los reportará muertos; **una lectura inmediata de una propiedad
|
|
|
en transición devuelve el valor VIEJO**, que es lo que hacía ilegible el
|
|
|
fondo del cuentagotas; y **la demo pisa el cuentagotas con su propia regla
|
|
|
de ámbito** (`.cp-tools-row` le pone `inline-size:auto` y `background`), así
|
|
|
que sus dos tokens sólo se pueden medir devolviéndole el consumo.
|
|
|
|
|
|
- 2026-08-22 — **`drawer`: los 24 rojos que arrastraba, medidos uno a uno — y
|
|
|
uno era un DEFECTO REAL.** El guard queda en verde; sin cambios de código.
|
|
|
|
|
|
**EL VELO DEL CAJÓN NO PINTA.** Su regla es
|
|
|
`color-mix(in srgb, var(--drawer-overlay-bg) var(--drawer-overlay-opacity), transparent)`
|
|
|
y **soma escribe `--drawer-overlay-opacity: 1` INLINE** —su progreso de
|
|
|
arrastre, un número sin unidad—. `color-mix` exige ahí un PORCENTAJE: con
|
|
|
`1` la función entera es inválida y el fondo cae a `transparent`. Medido
|
|
|
(`rgba(0, 0, 0, 0)` en el velo abierto; con `80%` en el nodo, pinta) y VISTO
|
|
|
en captura: el fondo tras el cajón sale desenfocado pero sin atenuar. Mueve
|
|
|
píxel y toca soma, así que va a §13 con su lección: **un valor que soma
|
|
|
escribe inline y una receta consume tiene que compartir UNIDAD**, o el fallo
|
|
|
es silencioso.
|
|
|
|
|
|
El segundo hallazgo: **las tallas son canal de valor en el eje que manda** —
|
|
|
soma escribe `width`/`height` inline según el lado, así que
|
|
|
`content-width-*` no gana desde `:root` en un cajón izquierda/derecha (el
|
|
|
eje cruzado sí: `height-sm` 260px → 976px). Misma clase que el `item-gap`
|
|
|
de carousel, pero aquí el token sigue siendo la fuente del valor que soma
|
|
|
resuelve: retirar o no es firma.
|
|
|
|
|
|
Los otros 22 son lo esperable y quedan medidos: el asa (no montada, y su
|
|
|
tamaño INTERCAMBIA ejes según el lado), el anillo de arrastre, el padding
|
|
|
`full`, la cabecera y el pie opcionales, la z de la variante inline.
|
|
|
|
|
|
- 2026-08-22 — **REVISIÓN ADVERSARIAL DEL BLOQUE (§7.7): 5 hipótesis, 1
|
|
|
hallazgo real, 4 refutadas.** Bloque de CATORCE componentes; global 56 % →
|
|
|
**62 %**.
|
|
|
|
|
|
**HALLAZGO REAL — la anomalía de `float-panel` tenía causa, y era del guard.**
|
|
|
`resize-grip-fg` movía aislado y leía muerto en una corrida completa. La
|
|
|
causa: **la pasada de HOVER deja el puntero sobre el último nodo que tocó**, y
|
|
|
una regla `:hover` gana a la de reposo con la que comparte nodo (el asa
|
|
|
re-apunta su color al acento). Es decir: **cualquier token de reposo probado
|
|
|
después de un token `hover-*` podía leer muerto** — misma clase que el
|
|
|
envenenamiento por clic-foco que F2-A arregló, una pasada más tarde.
|
|
|
Arreglado aparcando el puntero tras la pasada de hover. El propio guard
|
|
|
delató entonces DOS excepciones STALE —`float-panel.resize-grip-fg` y
|
|
|
`media-player.track`—, retiradas: dos tokens que se daban por muertos están
|
|
|
vivos. Se confirma la regla de F2-A: **un falso negativo siempre tiene causa**;
|
|
|
registrarlo como «sin causa» era el paso previo, no el final.
|
|
|
|
|
|
**REFUTADA «hay tokens huérfanos»**: comprobación ESTRICTA (comentarios
|
|
|
despojados —el hueco que dejó vivo el `popover.bg`— sobre todo el CSS del
|
|
|
árbol) de las **553 claves** de los catorce bloques: ninguna declarada sin que
|
|
|
una regla la lea.
|
|
|
|
|
|
**REFUTADA «el cambio de instrumento rompió algo»**: los **27 componentes con
|
|
|
ledger re-verificados** tras aparcar el puntero — cero regresiones. Los tres
|
|
|
rojos que quedan (`drawer` 24, `metrics` 16, `color-picker` 23) son
|
|
|
ANTERIORES al bloque y están anotados.
|
|
|
|
|
|
**REFUTADA «quedan fantasmas del barrido en lo tocado»**: el barrido pasa de
|
|
|
9 a **8** — el `--color-content-tertiary` de float-panel murió con su costura.
|
|
|
Los ocho restantes son de componentes que este bloque no tocó.
|
|
|
|
|
|
**CONFIRMADO, y ya estaba escrito: hay gates FINOS.** `popover` mide 1 nodo en
|
|
|
reposo (7 en abierto), `drawer` 1, `context-menu` 1 + 14 en abierto,
|
|
|
`color-picker` 5 + 12. Cada veredicto lo dice; el forzado a mano de sus
|
|
|
estados es lo que sostiene esas cifras, no la sonda.
|
|
|
|
|
|
- 2026-08-22 — **`password-field` 41 % → 62 %** (7 claves) **y el guard en
|
|
|
VERDE**: sus siete silencios quedan medidos, incluidos los tres que arrastraba
|
|
|
de antes.
|
|
|
|
|
|
Los cuatro peldaños del medidor de fuerza son una ESCALA DE INTENCIÓN —cada
|
|
|
uno lee su rol: pérdida, riesgo, cumplimiento, afirmación—, así que un tema
|
|
|
puede recorrerla entera sin tocar los roles del sistema. Fuera, por
|
|
|
composición: el padding del medidor y el tamaño de su rótulo leen privados de
|
|
|
FIELD (§5.3-3, se teman en la ficha del dueño).
|
|
|
|
|
|
Gates: sonda 0 diffs en 3.060 valores · censo 62 % · audit PASS · lint 0 ·
|
|
|
suite con el rojo conocido · rtl 0 · docs 0 · captura mirada.
|
|
|
|
|
|
- 2026-08-22 — **`context-menu` 53 % → 90 %** (11 claves, `global` a cero), y
|
|
|
**el instrumento aprende a abrir un menú contextual**: se abre con clic
|
|
|
DERECHO y con nada más, así que sonda y guard medían UN nodo. Con
|
|
|
`openBy: 'contextmenu'` y el clic derecho en la sonda: 14 nodos en abierto y
|
|
|
el guard en **27/29**.
|
|
|
|
|
|
Dos limpiezas: el `font-family` era respaldo de sí mismo y el peso del
|
|
|
encabezado llevaba un `500` muerto. Dos adjudicaciones, y una es la TERCERA
|
|
|
ocurrencia de §12.9 (el plano `overlay` impone la tipografía del panel).
|
|
|
|
|
|
Gates: sonda 0 diffs en 600 valores · censo 90 % · audit PASS · lint 0 · suite
|
|
|
con el rojo conocido · rtl 0 · docs 0 · captura del panel mirada.
|
|
|
|
|
|
- 2026-08-22 — **`metrics` 74 % → 82 %** (4 claves + prefijo abreviado fuera,
|
|
|
`global` a cero). **`--_mi-*` violaba theming §6 r5** —segundo caso del día
|
|
|
tras `--cp-*`—: 16 ocurrencias renombradas a `--_metrics-icon-*`. Son el
|
|
|
conmutador del icono por variante y ya derivaban de públicos, así que el censo
|
|
|
los reclasifica solo. Cosido: el ritmo del trend y las TRES formas del icono
|
|
|
(una clave por valor de `data-shape`; el radio es lo único que las distingue).
|
|
|
Dos adjudicaciones forzando las formas que la demo no monta. Sonda 0 diffs en
|
|
|
1.590 valores · censo 82 % · audit PASS · lint 0 · captura mirada.
|
|
|
|
|
|
- 2026-08-22 — **`float-panel` 59 % → 84 %** (12 claves, `global` a cero).
|
|
|
|
|
|
Las dos variantes que ajustan desde el default elevado, los botones de la
|
|
|
barra y el asa. **Muere uno de los nueve fantasmas del barrido**: el asa leía
|
|
|
`var(--color-content-tertiary, …)` y ese primitivo no existe — el contrato
|
|
|
guarda lo que de verdad pintaba.
|
|
|
|
|
|
Once adjudicaciones medidas (la demo monta la variante por defecto y no tiene
|
|
|
botón de acción genérico) **y una ANOMALÍA registrada**: `resize-grip-fg`
|
|
|
mueve bajo una réplica a mano de la secuencia del propio guard y aun así lo da
|
|
|
por muerto; causa no encontrada, descartadas cuatro. El token está vivo; la
|
|
|
lectura es lo que está en duda → §13, primer sitio por donde empezar la
|
|
|
revisión adversarial de este bloque.
|
|
|
|
|
|
Los 12 rojos que quedan son anteriores, y seis son el mismo conjunto que en
|
|
|
`popover`: el plano de profundidad gana sobre el panel (§12.9).
|
|
|
|
|
|
Gates: sonda 0 diffs en 1.890 valores · censo 84 % · `--names` sin desviadas ·
|
|
|
audit PASS · lint 0 · suite con el rojo conocido · rtl 0 · docs 0 · captura
|
|
|
mirada (cabecera, cierre y asa en su sitio).
|
|
|
|
|
|
- 2026-08-22 — **`nav-tree` 4 % → 96 %** (17 claves; tenía UNA). Global 61 %.
|
|
|
|
|
|
**La FILA es link + trigger a la vez** —mismo padding, tinta, radio y hover—,
|
|
|
así que el knob es de la fila (pseudo-parte, molde de `waveform`), con el
|
|
|
modificador DELANTE en lo interactivo (`hover-`/`active-`/`disabled-row-fg`)
|
|
|
y DETRÁS en lo contextual (`trail-row-fg`). El galón es una escuadra de dos
|
|
|
bordes: lado y trazo, como la esquina de `text-focus`.
|
|
|
|
|
|
**La suite cazó un incumplimiento heredado**, tercera vez en el eje: el
|
|
|
contrato copió `var(--font-size-sm)` verbatim del CSS y ésa es la coordenada
|
|
|
CRUDA que `recipe-css-contract` prohíbe. Al bundle, computa idéntico.
|
|
|
|
|
|
**Dos cegueras más del guard**: la fila es un `<div>` pelado sin atributo (su
|
|
|
`gap` leía muerto) y no leía el ANCHO de un borde que no fuera el de arriba.
|
|
|
Con las dos: **18/18 sin una sola excepción**. Los nueve componentes con
|
|
|
ledger re-verificados tras tocar las PROPS: sin regresiones ni STALE.
|
|
|
|
|
|
Gates: sonda **0 diffs en 22.140 valores** (102 nodos × 8 estados) · censo
|
|
|
96 % · `--names` sin desviadas · audit PASS · lint 0 · suite con el rojo
|
|
|
conocido · rtl 0 · docs 0 · captura del escenario mirada.
|
|
|
|
|
|
- 2026-08-22 — **`drawer` 57 % → 72 %** (10 claves: el disparador, gemelo del
|
|
|
de popover, con `min-block-size` al bundle). Global 61 %.
|
|
|
|
|
|
Lo que queda fuera es la FIRMA DE SALIDA (los cuatro bordes base que
|
|
|
`data-last-action` tiñe al cerrar) → §13, y ocho privados que son canales de
|
|
|
valor del wrapper.
|
|
|
|
|
|
**Una adjudicación de clase nueva**: el guard ABRE el cajón antes de probar y
|
|
|
el velo tapa el disparador, así que la pasada de hover no puede posarse en él.
|
|
|
Con el cajón cerrado y hover a mano, `hover-trigger-bg` alcanza. Los otros 24
|
|
|
rojos son anteriores (asa, anillo de arrastre, tallas del panel).
|
|
|
|
|
|
Gates: sonda 0 diffs en 390 valores · censo 72 % · `--names` sin desviadas ·
|
|
|
audit PASS · lint 0 · suite con el rojo conocido · rtl 0 · docs 0.
|
|
|
|
|
|
- 2026-08-22 — **`aura` 43 % → 80 %** (13 claves). Global 61 %.
|
|
|
|
|
|
Su texto de estado baja un paso del bundle por talla y las TRES coordenadas
|
|
|
viajan juntas: doce declaraciones, doce valores, doce claves (1:1, sin
|
|
|
inflación). Más `idle-opacity`. Identidad fuera: el radio del anillo, los
|
|
|
cuatro `100%` y el `1px` de la región sr-only.
|
|
|
|
|
|
**Doce adjudicaciones medidas**: las seis tintas de estado y el halo pintan el
|
|
|
fondo del INDICADOR y la demo corre con el canvas WebGL montado —
|
|
|
`:has(canvas)` pone `background: none` a propósito—; quitando el canvas en
|
|
|
vivo, el gradiente vuelve y las siete siguen. El arco y el halo son SLOTS que
|
|
|
sólo existen en los estados de trabajo: montados como `<circle>` en el SVG
|
|
|
real, alcanzan. Y el guard no veía ese SVG (sus `<circle>` no llevan
|
|
|
`data-aura*`): tercera vez que `extraNodes` salva tokens vivos.
|
|
|
|
|
|
Gates: sonda 0 diffs en 1.710 valores · centinela 25/37 con las doce
|
|
|
adjudicadas · censo 80 % · `--names` sin desviadas · audit PASS · lint 0 ·
|
|
|
suite con el rojo conocido · rtl 0 · docs 0.
|
|
|
|
|
|
- 2026-08-22 — **`color-picker` 51 % → 75 %** (20 costuras + un prefijo
|
|
|
abreviado retirado). Global **60 % → 61 %**.
|
|
|
|
|
|
**`--cp-*` violaba theming §6 r5** (no abreviar el nombre del componente):
|
|
|
cinco nombres, **45 ocurrencias en 8 ficheros**, tres de SOMA —el provider los
|
|
|
estampa inline, su test los lee, sus tipos los declaran—. Renombrados a
|
|
|
`--_color-picker-*` con `git ls-files` y 0 diffs; dos ya derivaban de un
|
|
|
público, así que el censo los reclasifica solo. Precedente: los `--gb-*` de
|
|
|
F2-A.
|
|
|
|
|
|
Cosido el ritmo, la tinta de la etiqueta, la tipografía del disparador y la
|
|
|
del VALOR (metadato: mono/regular/tinta propia), el borde de la muestra, el
|
|
|
raíl de canal y su pulgar, el hueco del anillo y el borde del cuentagotas.
|
|
|
**El pulgar lleva DOS sombras que hacen una cosa** (contorno + elevación):
|
|
|
un token, y la regla de foco lo compone con su tercer anillo.
|
|
|
|
|
|
**El instrumento no veía dos familias de nodo**: las muestras del picker SON
|
|
|
`<ColorSwatch>` (`data-color-swatch`) y sus sliders SON sliders
|
|
|
(`data-slider-*`); cuatro tokens vivos leían muertos. Con `extraNodes` para
|
|
|
las dos, 46/71.
|
|
|
|
|
|
**Lo rojo que queda es anterior**: 23 sin adjudicar (eran 24), del bloque
|
|
|
viejo — su pase propio queda en §13, con dos causas ya descartadas (el panel
|
|
|
SÍ abre y sobrevive al forzado de talla; el guard ya ve sus nodos).
|
|
|
|
|
|
Gates: sonda 0 diffs en 1.350 valores, medida DOS veces (tras el renombrado y
|
|
|
tras la costura) · tests de soma del color-picker 7/7 · censo 75 % ·
|
|
|
`--names` sin desviadas · audit PASS · lint 0 · suite con el rojo conocido ·
|
|
|
rtl 0 · docs 0 · `check` sin errores propios.
|
|
|
|
|
|
- 2026-08-22 — **`popover` 46 % → 67 %** (11 claves para el disparador + una
|
|
|
RETIRADA). Global 60 %.
|
|
|
|
|
|
El disparador genérico —el que no lleva el arquetipo `field-trigger`— montaba
|
|
|
su cromo sobre primitivos crudos: once costuras, con `trigger-height` leyendo
|
|
|
el BUNDLE y no el primitivo, y hover/abierto con su par cada uno (mismo valor
|
|
|
hoy, dos estados distintos).
|
|
|
|
|
|
**`bg` retirado: era un huérfano que el test de huérfanos no veía.** Ninguna
|
|
|
regla lo consumía; lo único que lo nombraba era un COMENTARIO de
|
|
|
`popover-arrow.svelte`, y ese test busca el nombre como texto en los ficheros
|
|
|
del componente. La superficie la pinta el plano de profundidad. → §13.
|
|
|
|
|
|
**Los doce que quedan son la FIRMA DE SALIDA y no se cosen aquí**: la misma
|
|
|
matriz `data-last-action` × 3 intents × 4 lados está repetida en drawer (22)
|
|
|
y dialog (9), y ya ha derivado (dialog tiñe sólo el color; popover y drawer
|
|
|
también el grosor). La tabla morfo→eidos la sitúa como mapeo transversal, así
|
|
|
que la salida es una regla sobre el arquetipo, no tres copias. → §13.
|
|
|
|
|
|
**Dos cegueras del instrumento**: la página tiene CINCO disparadores y el
|
|
|
guard abría el primero del documento en vez del del escenario; y `content-z`
|
|
|
se consume sobre el ENVOLTORIO FLOTANTE, un nodo sin atributo `data-popover*`,
|
|
|
así que leía muerto moviendo 80 → 4321. Las dos arregladas en
|
|
|
`COMPONENT_OVERRIDES`.
|
|
|
|
|
|
Gates: sonda 0 diffs en 420 valores (8 estados) · centinela 33/46 con trece
|
|
|
adjudicaciones medidas —nueve de partes que la demo no monta, dos del overlay
|
|
|
opcional y **dos que el plano `overlay` gana** (§12.9, pendiente de firma)— ·
|
|
|
censo 67 % · `--names` sin desviadas · audit PASS · lint 0 · suite con el rojo
|
|
|
conocido · rtl 0 · docs 0.
|
|
|
|
|
|
- 2026-08-22 — **`radio-cards` 60 % → 61 %: una sola clave, y ése es su techo.**
|
|
|
21 de sus 23 knobs fuera de alcance **no son suyos**: es un SKIN sobre
|
|
|
RadioGroup —renderiza `<RadioGroup.Provider>` y su indicador ES un radio—, así
|
|
|
que lee `--radio-group-*` y el puente de paleta del anfitrión. Mandato de
|
|
|
composición (`theming-audit` §5.3-3): se teman en la ficha del dueño. Lo suyo
|
|
|
es la TARJETA: `invalid-border`. Los dos `--radius-full` del indicador son
|
|
|
identidad (un radio es redondo por definición).
|
|
|
|
|
|
**La lección de la medición**: la primera lectura de `invalid-border` dio «sin
|
|
|
efecto» porque la tarjeta transiciona `border-color` y leer justo después de
|
|
|
escribir devuelve el valor de PARTIDA. Con las transiciones congeladas —lo que
|
|
|
el guard hace por defecto y mi sonda a mano no— alcanza. **Una medición
|
|
|
forzada tiene que congelar también.**
|
|
|
|
|
|
Gates: sonda 0 diffs en 3.540 valores · centinela 35/40 con las cinco
|
|
|
adjudicadas y medidas · censo 61 % · `--names` sin desviadas · audit PASS ·
|
|
|
lint 0.
|
|
|
|
|
|
- 2026-08-22 — **`prose` 1 % → 83 %** (35 claves de costura, 2 → 37).
|
|
|
Global **59 % → 60 %**; `global` del catálogo 1.064 → 1.021.
|
|
|
|
|
|
Estiliza HTML CRUDO por `:where([data-prose] el)`, así que sus partes son
|
|
|
ELEMENTOS y la costura va por parte, como en `result`. Su escala editorial
|
|
|
`em`-relativa no entra: es decisión de diseño de su README («No 5×
|
|
|
duplicated scale») y va anotada `/* literal: */` — las 21 excepciones que el
|
|
|
censo aprendió a leer esta misma sesión. Dos literales se cambiaron por su
|
|
|
paso de escala con idéntico valor (`3px` → `--border-width-thick`, los `1px`
|
|
|
→ `--border-width`).
|
|
|
|
|
|
**El instrumento estaba ciego de dos maneras**, las dos arregladas antes de
|
|
|
medir: sonda y centinela filtran por `data-{c}-*` y aquí NINGUNA parte lo
|
|
|
lleva —la sonda medía **1 nodo** y el guard daba 27 de 37 por muertos—, así
|
|
|
que ambos ganan un selector de nodos extra (63 nodos con él); y el centinela
|
|
|
no leía el color de un borde que no fuera el de arriba, con lo que el
|
|
|
blockquote (`border-inline-start`) y la tabla (bordes de bloque) leían
|
|
|
muertos estando vivos.
|
|
|
|
|
|
Ocho adjudicaciones medidas: cinco las tapa el harness de la documentación
|
|
|
(`[data-uix-docs] code|pre` (0,2,0) gana a `:where(…)` (0,0,0) — la
|
|
|
incidencia ya escrita para `code-block`) y tres son elementos que el HTML de
|
|
|
ejemplo no usa, montados dentro del contenedor real.
|
|
|
|
|
|
Gates: sonda **0 diffs en 11.910 valores** (63 nodos × 7 estados) · centinela
|
|
|
29/37 · censo 83 % · `--names` 37/37 · audit PASS · lint 0 · suite con el
|
|
|
rojo conocido · rtl 0 · docs 0 · `check` sin errores propios. Los del ledger
|
|
|
re-verificados tras tocar el guard: sin regresiones.
|
|
|
|
|
|
- 2026-08-22 — **`listbox` ADJUDICADO: 68 % es su techo, y coserlo habría
|
|
|
mentido.** Sin cambios de código: su veredicto §5.
|
|
|
|
|
|
Cinco de sus nueve privados adoptan la capa `list-surface` (el ritmo de fila
|
|
|
compartido con select, combobox, command y los tres menús), dos son el puente
|
|
|
de paleta y el noveno sí deriva de un público. La cola decía «cose como sus
|
|
|
hermanos» —`dropdown-menu` y `context-menu` sí acuñan el puente—, y la
|
|
|
medición lo desmontó: **ninguno de los dos nombres alcanza desde `:root`**
|
|
|
(fila a 36 px, `--dropdown-menu-item-height` y `--list-item-height` a
|
|
|
`1234px` en `:root` → 36 px). La capa declara sobre
|
|
|
`[data-list-surface][data-size]` y el puente sobre `[data-{c}-content]`: las
|
|
|
dos ganan a `:root`. Copiar el puente habría subido la cifra sin dar alcance
|
|
|
— un token que miente, la clase que R-5.4 existe para cazar.
|
|
|
|
|
|
Se arregla EN LA CAPA (entrada de receta, como `calendar-surface`), toca diez
|
|
|
componentes y es su propio eje → §13. **Y avisa sobre el instrumento**: el
|
|
|
centinela da por vivos estos tokens porque escribe inline en el nodo; para un
|
|
|
token que un tema sólo puede escribir en `:root`, «mueve un computed» no
|
|
|
equivale a «un tema lo alcanza».
|
|
|
|
|
|
- 2026-08-22 — **El censo aprende a leer la válvula del canon: clase
|
|
|
`exception`.** Global **58 % → 59 %**, sin tocar una línea de CSS.
|
|
|
|
|
|
`recipe-contract` §3 dice que una desviación anotada
|
|
|
`/* literal: <razón> */` **en su propia declaración** es válida, y
|
|
|
`component-audit` ya la honra desde siempre (`declarationWindow` +
|
|
|
`/literal:/i` en R-2.1/2.6/2.7). El censo era el único instrumento que no:
|
|
|
su `strip()` blanquea los comentarios ANTES de clasificar, así que las
|
|
|
**81 anotaciones del catálogo** contaban como deuda. Dos instrumentos, un
|
|
|
canon, dos respuestas.
|
|
|
|
|
|
Ahora un literal anotado cae en la clase `exception`, **fuera del ratio**
|
|
|
como `system` — y por la misma razón: no es que un tema no lo alcance, es que
|
|
|
el canon ya aceptó por escrito que ahí no va un token. **54 knobs** en 12
|
|
|
componentes: `prose` 21 (su escala editorial `em`-relativa, decisión de
|
|
|
diseño firmada en su README), `proof-of-human` 16 (la escena de tono fijo),
|
|
|
`palabras` 3, `timeline` 2 (73 % → **77 %**), `result` 1 (86 % → **90 %**),
|
|
|
y siete más con una cada uno.
|
|
|
|
|
|
**La anotación vale para la DECLARACIÓN entera**, no sólo para su primera
|
|
|
línea: un valor partido en varias líneas lleva la nota al final, y así se
|
|
|
mide. Muta-prueba: retirar una anotación de `prose` mueve el knob de
|
|
|
`exception` a `literal` (21 → 20) y devuelve el conteo al restaurarla.
|
|
|
|
|
|
Efecto colateral bueno: las fichas ganan una **§1.4** que LISTA las
|
|
|
excepciones con su razón. Antes estaban escritas en el CSS y no se leían
|
|
|
desde ninguna parte.
|
|
|
|
|
|
- 2026-08-22 — **Tres techos adjudicados: el PUENTE DE PALETA no es deuda.**
|
|
|
`tag-group` 65 %, `stepper` 79 %, `timeline` 73 % — sin cambios de código,
|
|
|
sus tres veredictos §5.
|
|
|
|
|
|
Los tres tienen `global` a cero: lo único fuera de alcance son sus privados
|
|
|
`--_{c}-palette-*`, el puente THM-2 que la capa compartida alimenta por
|
|
|
instancia desde `[data-color]`. **Un público encima del puente dejaría que un
|
|
|
tema lo fijara y matara en silencio el `color=` de cada instancia** — la misma
|
|
|
clase de daño que «declarar un público de facto mata una escala». Ya exponen
|
|
|
sus nueve roles × variante en claves públicas (91 en `tag-group`): ésa ES su
|
|
|
superficie de color. `timeline` suma la segunda razón firmada: sus
|
|
|
`--_timeline-hue-*` son un CONMUTADOR por `data-intent` (doctrina F2-B, cinco
|
|
|
precedentes) cuya rama por defecto es el puente.
|
|
|
|
|
|
Medido para no adjudicar de oído: de las **687** declaraciones del catálogo
|
|
|
que leen un privado, **130 leen un `--_{c}-palette-*`**, y son las que dominan
|
|
|
la columna `private` de todo componente con paleta (tag-group 14/14, stepper
|
|
|
11/11, radio-group 10, checkbox 8, file-upload 8, calendar / editable / los
|
|
|
tres grids 7). **El techo de un componente con paleta no es el 100 %** y su
|
|
|
cifra no compara con la de uno sin ella — registrado en §13, junto con la
|
|
|
única salida si algún día se quiere comparabilidad: una clase `bridge` en el
|
|
|
censo, no acuñar los tokens.
|
|
|
|
|
|
- 2026-08-22 — **LA COSTURA: `chart` 49 % → 89 % y `result` 23 % → 86 %**
|
|
|
(6 + 15 claves). Global **57 % → 58 %**; `global` del catálogo 1.113 → 1.064.
|
|
|
|
|
|
**Corrige una lectura mía de las dos horas anteriores.** Al tokenizar `chart`
|
|
|
y `result` di por doctrina que «el texto no recibe tokens del componente»
|
|
|
porque su valor viene del canon —la capa de estilos con nombre, las ranuras de
|
|
|
contenido, el bundle de talla— y lo dejé leyendo el canon A PELO desde el CSS.
|
|
|
Eso es media doctrina: **el valor es del sistema, pero el knob tiene que ser
|
|
|
del componente** (PLAN §2-A: todo knob de apariencia lee `--{c}-{slot}`). Sin
|
|
|
la costura, un tema no puede aclarar las anotaciones de un gráfico denso sin
|
|
|
mover `caption` en toda la app, y `getRecipeTokens()` / `/temas` no ven esa
|
|
|
superficie. El molde ya estaba escrito en la vertebración tipográfica
|
|
|
(`--accordion-trigger-font-family: var(--style-label-font-family)`) y D-TH.2
|
|
|
aclara que **sólo los seis PRIMITIVOS** quedan fuera («un componente que sólo
|
|
|
LEE un named style para un eje no es un primitivo»).
|
|
|
|
|
|
**Dos formas, porque los componentes son distintos** — y ésa es la parte que
|
|
|
se firmó:
|
|
|
|
|
|
- `chart`, **por ROL**: dos roles del canon (`caption` para las anotaciones,
|
|
|
`label` para el cromo) × tres ejes = 6 claves para 19 nodos de texto.
|
|
|
Nombrar por parte habría dado ~30 claves con dos valores. Tamaño y tinta
|
|
|
son ORTOGONALES a propósito (`empty` y `bar-list-value` son tamaño `label`
|
|
|
con tinta `caption`). El readout del gauge no tiene rol en el canon y su
|
|
|
costura toma el bundle.
|
|
|
- `result`, **por PARTE**: cinco partes con tipografía distinta y ningún rol
|
|
|
que las cubra → 15 claves `title-*`, `description-*`, `extra-*`, `code-*`,
|
|
|
`media-*`. Es la forma dominante del catálogo.
|
|
|
|
|
|
**Nombres**: los tres que propuse primero no aguantaron la revisión
|
|
|
(`label-font-size` chocando con las seis partes `*-label`, `emphasis-*`
|
|
|
inventando vocabulario, `fg-muted` apoyado en un solo precedente). Se nombra
|
|
|
por el ROL DEL CANON que el texto adopta, y la tinta lee el color DEL ROL
|
|
|
(`var(--style-caption-color)`), no la ranura a pelo.
|
|
|
|
|
|
Con esto **`global` cae a CERO en los dos**: lo que queda fuera son los diez
|
|
|
literales de identidad de chart (nueve `100%` + `max-content`) y tres de
|
|
|
result.
|
|
|
|
|
|
Gates: sonda **0 diffs en 161.850 valores** (chart, 16 rutas × 7 estados) y
|
|
|
**990** (result) · centinela chart **43/45** y result **15/27**, y las doce
|
|
|
que callan están medidas SOBRE NODOS REALES con los controles de la demo
|
|
|
(chip `not-found` para el código HTTP, casilla del `extra`, quitar
|
|
|
`data-status` para la tinta por defecto del glifo) · censo 89 % / 86 % ·
|
|
|
`--names` 45/45 y 27/27 · audit PASS · lint 0 · suite con el rojo conocido ·
|
|
|
rtl 0 · docs 0 · `check` sin errores propios.
|
|
|
|
|
|
**Y retira una nota equivocada de §13**: escribí que el censo penalizaba
|
|
|
consumir la capa tipográfica. El censo medía bien; faltaba la costura. La
|
|
|
lección queda escrita ahí: cuando la métrica y la doctrina discrepan,
|
|
|
sospecha de la lectura antes que del instrumento. `listbox` (68 %, ritmo de
|
|
|
fila prestado de `list-surface`) es la misma pregunta un piso más arriba y
|
|
|
queda pendiente de revisar con este molde.
|
|
|
|
|
|
- 2026-08-22 — **`result` 14 % → 23 %** (4 claves, 8 → 12). Global 57 %,
|
|
|
<20 % 18 → 17. Aplicación directa de la doctrina que cerró `chart`: **la
|
|
|
receta posee su CAJA** —inset de página, ritmo entre bloques— y nada más. Su
|
|
|
tipo ya leía el BUNDLE DE TALLA (`--size-{k}-font-size`), que es lo que
|
|
|
recipe-contract §1 prescribe, y su tinta las ranuras de contenido: acuñar
|
|
|
`--result-title-font-size` habría sido tipografía por componente. Las trece
|
|
|
lecturas de canon siguen contando `global` — §13, tercera ocurrencia.
|
|
|
|
|
|
Higiene de paso: el privado `--_result-media-color` → `--_result-media-fg`
|
|
|
(D-TH.6 dice `fg`; R-5.3 no mira privados).
|
|
|
|
|
|
Gates: sonda **0 diffs en 990 valores** · centinela 7/12 con **cinco
|
|
|
adjudicaciones medidas sobre nodos REALES** —los tres acentos pulsando su
|
|
|
chip de estado, el bloque `extra` marcando su casilla— y no sobre nodos
|
|
|
fabricados (la lección de `drag-drop`) · censo --only 23 % · --names 12/12 ·
|
|
|
audit PASS · lint 0 · suite con el rojo conocido · rtl 0 · docs 0 · `check`
|
|
|
sin errores propios.
|
|
|
|
|
|
- 2026-08-22 — **`chart` 9 % → 49 %** (22 claves nuevas fusionadas en su bloque,
|
|
|
17 → 39). El mayor de los de alcance <20 % que no estaba bloqueado.
|
|
|
|
|
|
**La ficha pedía 71 claves y ~20 habrían llevado el mismo valor.** Lo decidió
|
|
|
la medición: las 84 filas fuera de alcance colapsan a **26 valores distintos**
|
|
|
(9× `content-secondary`, 9× `content-primary`, 9× `100%`, 6× `font-size-sm`,
|
|
|
6× `font-size-xs`, 6× `font-weight-medium`, 5× `surface-default`). La
|
|
|
inflación de `spinner` con otra forma: nombrar por parte lo que es un
|
|
|
concepto.
|
|
|
|
|
|
**El texto no recibe tokens de chart**: toma su ROL DE TAMAÑO de los estilos
|
|
|
con nombre (`caption` para anotaciones, `label` para el cromo) y su tinta y
|
|
|
peso de las ranuras del sistema. Acuñarlos sería tipografía por componente,
|
|
|
lo que el autor prohibió el mismo día. Precedente de consumir la capa:
|
|
|
`code-block`, `kbd`, `announce`. **La receta sólo posee la tinta de lo que no
|
|
|
es texto** — `axis-fg`, `grid-fg`, `separator-fg` (el pelo de superficie que
|
|
|
separa marcas contiguas: cinco partes, una idea), `smith-boundary-fg`,
|
|
|
`track-bg` — más 17 de geometría de cromo. Identidad fuera de contrato: los
|
|
|
nueve `100%` y el `max-content` del tooltip.
|
|
|
|
|
|
**Incumplimiento heredado corregido**: el CSS leía la coordenada CRUDA
|
|
|
`var(--control-height-sm, var(--space-7))` (respaldo muerto); el contrato
|
|
|
guarda el bundle `var(--size-sm-control-height)`, 1:1.
|
|
|
|
|
|
**El instrumento estaba ciego de TRES maneras, arregladas antes de medir:**
|
|
|
|
|
|
1. **La superficie de chart vive en 16 rutas de demo**, una por tipo:
|
|
|
`/chart` monta 58 nodos de los 302 de la página y el resto vive en rutas
|
|
|
hermanas. El guard gana `urls`: un token está VIVO si ALGUNA superficie del
|
|
|
componente lo sigue, y cada URL sólo re-prueba lo que sigue pendiente.
|
|
|
De paso `picker-shell` recibe la suya (su ruta propia es un 404, se mide
|
|
|
dentro del date-picker: 0/31 → 6/31 sin pasar la URL a mano).
|
|
|
2. **El guard no leía NINGUNA propiedad SVG** — sin `fill`/`stroke`/
|
|
|
`strokeWidth`/`fillOpacity`/`r`/`rx`, doce claves de un componente que
|
|
|
dibuja en SVG leían muertas estando vivas. Misma clase que el hueco de
|
|
|
`filter` del día anterior.
|
|
|
3. **El valor centinela se elegía por SUBCADENA**: `slice-stroke-width`
|
|
|
recibía `rgb(1, 2, 3)` por contener «stroke» — inválido para una longitud,
|
|
|
así que leía muerta. Ahora la dimensión se decide por el final del nombre.
|
|
|
|
|
|
Gates: sonda **0 diffs en 161.850 valores** (16 rutas × 7 estados, 892 nodos
|
|
|
en reposo) · centinela **37/39** con dos adjudicaciones medidas sin la
|
|
|
congelación (`transition-duration` 0.12s → 11.5s, `-ease` → steps(4)) ·
|
|
|
censo `--only` 49 % y global **56 % → 57 %** (2.638 → 2.675 públicos,
|
|
|
<20 % 19 → 18) · `--names` 39/39 conformes · audit PASS · eidos-lint 0
|
|
|
invalid · suite eidos con el único rojo conocido · rtl 0 · docs 0 · `check`
|
|
|
sin errores en los ficheros tocados. **Los 28 componentes con ledger
|
|
|
re-verificados tras los tres cambios de instrumento: cero regresiones, cero
|
|
|
STALE.**
|
|
|
|
|
|
Abre (→ §13): el censo **penaliza consumir la capa tipográfica** si no eres
|
|
|
un primitivo (las doce declaraciones correctas siguen contando `global`) — la
|
|
|
nota de `listbox` con una segunda ocurrencia; y el número del gauge no tiene
|
|
|
estilo con nombre que lo represente (un readout de dato no es un `h2`).
|
|
|
|
|
|
- 2026-08-22 — **`text-scramble` ADJUDICADO: sin contrato que escribir** (y el
|
|
|
barrido de fantasmas, hecho). Sin cambios de código: su veredicto §5.
|
|
|
|
|
|
Su 50 % no es ni deuda ni logro. **Dos literales son la técnica sr-only**
|
|
|
(`width`/`height: 1px`), idéntica a `text-blur`. **Los dos «públicos» son
|
|
|
tipografía que el componente no debería acuñar** —`font` y `size`,
|
|
|
consumidos con fallback y sin declarar—, o sea la firma **1.bis**:
|
|
|
escribirles contrato ahora sería acuñar exactamente lo que esa firma propone
|
|
|
retirar. Con `text-scramble` la cuenta de esa firma sube a **7 claves en 4 de
|
|
|
los 5** componentes de la familia (`text-blur` es el único limpio: hereda).
|
|
|
|
|
|
Y su `font` apunta a un fantasma: `var(--font-mono, …)` no existe —el
|
|
|
canónico es `--font-family-mono`— así que pinta `ui-monospace` e **ignora la
|
|
|
mono del tema** (`Azeret Mono`). Medido en navegador.
|
|
|
|
|
|
**El barrido mecánico que `--radius-xs` y `--font-size-4xl` pedían está
|
|
|
HECHO**: 5.793 nombres declarados en `src/uix/eidos` contra los
|
|
|
`var(--x, fallback)` de las recetas → **9 referencias fantasma**, tabla en
|
|
|
next-features §13. La más grave no es de esta familia:
|
|
|
`--color-content-tertiary` sigue vivo en TRES recetas (el caso histórico que
|
|
|
`recipe-contract` §1 cita como origen de su regla) y los cuatro
|
|
|
`--style-*-font-variation-settings` de `text.css` significan que el eje de
|
|
|
fuente variable **no llega nunca al primitivo `Text`**. Ninguna se arregla
|
|
|
aquí; el barrido debería ser un guard (misma lógica que el test de fantasmas
|
|
|
sin fallback, con el filtro de vocabulario de sistema encima).
|
|
|
|
|
|
- 2026-08-22 — **`text-gradient` 67 % → 100 %** (7 claves, entrada nueva).
|
|
|
Tercero de la familia text-* con la forma de `text-circular` / `text-focus`
|
|
|
(públicos «de facto» con fallback y sin declarar), pero la propuesta §4
|
|
|
generada fallaba en las tres decisiones y las tres se resolvieron midiendo
|
|
|
contra el CATÁLOGO, no contra el CSS de partida:
|
|
|
|
|
|
- **`weight` → `font-weight`**: 77 claves `font-weight` en el catálogo
|
|
|
contra 4 `weight` a secas, dos de ellas escritas el mismo 22 en esta
|
|
|
familia. Y `500` **es** `var(--font-weight-medium)`.
|
|
|
- **`calc(100% - 2px)` no son dos knobs de eje físico** (que es lo que la
|
|
|
ficha marcaba con ⚠) sino UNO: los 2 px son el trazo del marco asomando a
|
|
|
cada lado. Knob = `border-width` con `var(--border-width)` (el paso
|
|
|
`thin`, no un literal igual a un paso), y el hueco DERIVA de él.
|
|
|
- **`blur(4px)` → `var(--blur-sm)`**: `blur` es familia MÉTRICA del eje
|
|
|
`scaling` (theming §23) y un literal es ciego al zoom global.
|
|
|
|
|
|
Fuera del contrato por naturaleza: `duration` y `play-direction`, que el
|
|
|
wrapper escribe INLINE desde `animationSpeed`/`yoyo` — misma clase que el
|
|
|
`item-gap` de `carousel` y el `preview-z` de `drag-drop`.
|
|
|
|
|
|
**Dos puntos ciegos del instrumento, arreglados ANTES de medir** (la lección
|
|
|
de F2-B aplicada por adelantado): la demo arranca con `showBorder=false`, así
|
|
|
que sonda y centinela veían 2 nodos y NINGUNO de los tres tokens del marco;
|
|
|
y la sonda no leía `backdropFilter`, que el censo sí cuenta como knob. La
|
|
|
sonda gana un mapa `DEMO_VARIANTS` (chips de variante que se re-pulsan tras
|
|
|
cada recarga) y el centinela una entrada `openWith` que no abre un panel sino
|
|
|
que ENCIENDE UNA VARIANTE — un uso nuevo del mismo gancho.
|
|
|
|
|
|
Gates: 4 nodos · 720 valores × 7 estados · **0 diffs** · centinela **7/7 sin
|
|
|
excepciones** · censo `--only` 100 % y global 2.634 → 2.638 públicos ·
|
|
|
`--names` 7/7 conformes · audit PASS · eidos-lint 0 invalid · suite eidos con
|
|
|
el único rojo conocido (`skin-media-player`) · rtl 0 · docs 0 · `check` sin
|
|
|
errores en los ficheros tocados. Demo con pestaña **Tokens** (y fuera la
|
|
|
tabla de tokens escrita a mano, que este mismo renombrado dejaba obsoleta).
|
|
|
|
|
|
Abre (→ next-features §13, **pendiente de firma, apuntado para después**):
|
|
|
**la familia text-effects ACUÑA tipografía propia contra el canon** — cinco
|
|
|
claves (`text-focus.word-size` vía el fantasma `--font-size-4xl` y
|
|
|
`word-weight` · `text-circular.weight` y `font-size` ·
|
|
|
`text-gradient.font-weight`, ésta subida aquí), opiniones del seed que el
|
|
|
«valor verbatim» hizo contrato. Doctrina F2-B regla 2: se CONSUME la capa
|
|
|
(`--style-*`) o se HEREDA (`link`); un efecto de pintura sobre texto real no
|
|
|
tiene tipografía propia. Resolución propuesta: retirar las cinco y heredar
|
|
|
(mueve defaults → firma). El módulo de tipografía es canon y no se toca. Las
|
|
|
demos NO forman parte del eje (autor, 2026-08-22).
|
|
|
|
|
|
- 2026-08-22 — **Bloque F2-B: 21 componentes tokenizados + 5 adjudicados como
|
|
|
«0 % estructural».** Global **45 % → 50 %**; sin contrato 49 → 29; al 100 %
|
|
|
7 → 10; alcance <20 % 43 → 22. Uno por commit, protocolo §7 entero, sonda
|
|
|
antes/después = 0 diffs en todos.
|
|
|
|
|
|
| componente | alcance | commit |
|
|
|
| --- | ---: | --- |
|
|
|
| `grid-list` | 0 → 85 % | `60b5b9896` |
|
|
|
| `textarea` | 0 → 80 % | `893aeaf81` |
|
|
|
| `tree-view` | 0 → 92 % | `dd188f125` |
|
|
|
| `code-block` | 0 → 81 % | `354d166df` |
|
|
|
| `card-group` | 0 → 90 % | `c56d6544e` |
|
|
|
| `spinner` | 0 → 70 % | `42a3e7413` |
|
|
|
| `picker-shell` | 0 → 76 % | `67b4c810c` |
|
|
|
| `link-preview` | 0 → 100 % | `7a0fc2ead` |
|
|
|
| `drag-drop` | 0 → 89 % | `650d76aa0` |
|
|
|
| `kbd` | 0 → 86 % | `adb77863c` |
|
|
|
| `link` | 0 → 36 % | `d3089e880` |
|
|
|
| `code` | 0 → 100 % | `e4bcd505d` |
|
|
|
| `virtual-list` | 0 → 67 % | `070145786` |
|
|
|
| `virtual-grid` | 0 → 73 % | `e3f39ce28` |
|
|
|
| `skeleton` | 0 → 45 % | `a6d4d4f5a` |
|
|
|
| `label` | 0 → 100 % | `7565eff47` |
|
|
|
| `announce` | 0 → 88 % | `d568577eb` |
|
|
|
| `clipboard` | 0 → 63 % | `151e5159b` |
|
|
|
| `scroll-frames` | 0 → 33 % | `1f692629e` |
|
|
|
| `mark` | 0 → 60 % | `9f24a31eb` |
|
|
|
| `menu-dial` | 0 → 25 % | `471ba96d2` |
|
|
|
| 5 estructurales (fichas) | 0 % FINAL | `ed2e3cd7c` |
|
|
|
|
|
|
**Lo que el bloque enseñó, y no estaba en el plan:**
|
|
|
|
|
|
1. **Un alcance bajo puede ser doctrina bien aplicada.** `menu-dial` 25 %
|
|
|
porque sus ejes de colocación son de la capa `viewport-placement` y la
|
|
|
receta escribe en sus RANURAS DE OVERRIDE; `link` 36 % porque sus
|
|
|
escotillas caen en `inherit`, que es semántico; `scroll-frames` 33 %
|
|
|
porque es layout puro. El % no es la métrica de calidad.
|
|
|
2. **Un privado con DOS fuentes es un conmutador, no deuda** — cinco casos
|
|
|
con el mismo veredicto (`textarea`, `spinner`, `skeleton`, `code`,
|
|
|
`label`): aplanarlo obligaría a duplicar cada regla por color.
|
|
|
3. **Lo que la capa tipográfica posee no se acuña** — cinco casos
|
|
|
(`code-block`, `kbd`, `announce`, `code`, `label`).
|
|
|
4. **Cinco componentes tienen 0 % POR NATURALEZA** y ninguna deuda:
|
|
|
`aspect-ratio` (faceta de Box, knob prestado), `text-blur` (sr-only),
|
|
|
`cascade` y `motion` (gate antiparpadeo del canal), `date-picker`
|
|
|
(corrección `max-content` de composición). El censo no los distingue de
|
|
|
la deuda real, **así que el gate de F3 «censo 100 %» es inalcanzable por
|
|
|
construcción** hasta que exista una clase `structural` — §13.
|
|
|
5. **La propuesta §4 generada hereda el incumplimiento del CSS de partida**:
|
|
|
copia el valor verbatim, y si ese valor ya violaba `recipe-css-contract`
|
|
|
(primitivo crudo en vez del bundle), la propuesta lo repite. Lo cazó la
|
|
|
suite en `code-block`.
|
|
|
6. **La inflación del generador puede ser 4×**: en `spinner` proponía 71
|
|
|
tokens para 23 knobs, multiplicando UNA coordenada de talla por
|
|
|
variante × parte × dimensión.
|
|
|
|
|
|
**El guard R-5.4 ganó SEIS capacidades**, todas nacidas de una medición y
|
|
|
con los componentes del ledger re-verificados sin regresión tras cada una:
|
|
|
puntero parqueado tras el blur (`reopen()` corre antes de cada token),
|
|
|
`::placeholder` en el snapshot (la nota de §13 que decía que no se lee era
|
|
|
falsa), `COMPONENT_OVERRIDES` de prefijo y selector de apertura, apertura
|
|
|
por `hover` para hover-cards, y `text-decoration-thickness` /
|
|
|
`-underline-offset` en la lista de propiedades.
|
|
|
|
|
|
**Revisión adversarial §7.7 — HECHA 2026-08-22.** Molde F2-A: worktree en la
|
|
|
base del bloque (`8400e5bdd`) con su propio dev server, medición
|
|
|
independiente. **4 hipótesis · 3 refutadas · 1 hallazgo real.**
|
|
|
|
|
|
- **REFUTADA «el default cambió en algún sitio que la demo no mira»**: 77
|
|
|
casos FORZADOS (variantes, formas, tallas y estados que las demos NO
|
|
|
montan, en los 21 componentes) comparados base vs HEAD → **0 diferencias**.
|
|
|
- **REFUTADA «hay tokens huérfanos»**: 339 públicos de los 21 bloques, 0 sin
|
|
|
consumo. Con muta-prueba: un token falso inyectado sale detectado, y el
|
|
|
árbol se restaura.
|
|
|
- **REFUTADA «el gate de 0 diffs pasó sobre casi nada»**: se contaron los
|
|
|
nodos que ve cada sonda. Cuatro componentes miden 1 nodo (`link`, `code`,
|
|
|
`skeleton`, `link-preview`), y por eso se forzaron sus variantes en el
|
|
|
punto anterior — ahí es donde viven sus tokens, y salieron idénticos.
|
|
|
- **HALLAZGO REAL: `drag-drop.preview-z` mentía.** El ledger lo daba por vivo
|
|
|
con «forzado → alcanza», pero el nodo se había creado a mano; el preview
|
|
|
REAL que soma monta durante un arrastre lleva `z-index: 9999` INLINE, así
|
|
|
que ninguna cascada puede ganarle. Retirado con 0 diffs. Misma clase que el
|
|
|
`item-gap*` de carousel en F2-A. **La lección: una adjudicación «forzado →
|
|
|
alcanza» vale lo que valga el nodo que se forzó.** Re-verificado el resto de
|
|
|
la clase contra nodos reales (`clipboard`, `picker-shell`): correctos.
|
|
|
|
|
|
Dos hallazgos de INSTRUMENTO en la propia revisión, ambos registrados en §13:
|
|
|
el orden de carga **no es el mismo en dev que en producción** (medido con
|
|
|
build + CDP; el ganador coincide por casualidad), y un **worktree cuyo
|
|
|
`node_modules` es una junction fuera del root no hidrata** — Vite responde 403
|
|
|
a `@fs/…` y la primera pasada de esta revisión comparó contra una base
|
|
|
muerta sin que nada lo delatara.
|
|
|
|
|
|
- 2026-08-21 — **La capa `calendar-surface`** (firma 1 del acta, diseño
|
|
|
presentado y firmado el mismo día). La medición desmontó el encargo: la capa
|
|
|
ya existía de hecho — `--calendar-*` en `:root`, y `range-calendar` /
|
|
|
`month-grid` / `year-grid` con 114 / 77 / 77 referencias prestadas y CERO
|
|
|
tokens propios. Se le dio nombre y casa (`lib/calendar-surface.css`, hook
|
|
|
`data-calendar-surface`, cuatro coordenadas xs..lg sin xl, celda dos pasos
|
|
|
bajo el bundle) y se cerró el defecto que la justificaba: las dos sombras del
|
|
|
anillo se emitían con ámbito `[data-calendar]` y los otros tres las leían
|
|
|
vacías, así que el anillo sema **no pintaba** en tres componentes. Capa
|
|
|
HÍBRIDA: el vocabulario se queda en la entrada de receta (76 claves
|
|
|
semánticas alcanzables por config), la capa posee la resolución por talla y
|
|
|
la forma del anillo. **Siete wrappers estampan**, no cuatro — los pickers
|
|
|
renderizan la superficie soma por los suyos y un panel portalado no hereda.
|
|
|
Censo: `LAYER_VOCABULARY` deja de penalizar consumir una capa; global 43 % →
|
|
|
**45 %**, `calendar` 75 % → **84 %**.
|
|
|
|
|
|
- 2026-08-21 — **Revisión adversarial de F2-A (§7.7) + nace R-5.4.** Molde
|
|
|
Sidebar sobre worktree con solo el CSS revertido a la base: 34 hipótesis ·
|
|
|
26 refutadas · 8 reales, todas las de código arregladas con diff de computed
|
|
|
VACÍO (command 8.091 · carousel 2.842 valores). Retiradas: el re-point
|
|
|
muerto de `--command-radius` en el Dialog (su comentario mentía: el input
|
|
|
nunca lo leyó) y el trío `item-gap*` de carousel (el `gap` INLINE de soma
|
|
|
gana siempre — canal de valor, no knob). Tokenizado: el `2.25` vertical del
|
|
|
indicador activo. El instrumento viejo cargaba 22 falsos negativos de 26
|
|
|
«no effect» (clic-foco · override solo en `[data-{c}]` · pseudos) y la
|
|
|
no-determinación de `feed` era la demo cargando — cuatro causas arregladas.
|
|
|
**R-5.4**: `theming-sentinel.ts` + ledger de adjudicaciones, los ocho
|
|
|
componentes en verde con 46 excepciones medidas. El `striped` inerte se
|
|
|
firmó y ejecutó el mismo día: `:nth-child(even of [data-table-row])` +
|
|
|
`:where(:not([data-selected]))` al mismo (0,6,0) — 12 diffs exactos, hover
|
|
|
y selected verificados, la excepción del ledger retirada (table 42/45).
|
|
|
Pendiente de firma: el `item` en fila Y celda, y el gap de soma.
|
|
|
Detalle en [`CONTINUE-theming.md`](./CONTINUE-theming.md) §«Registro».
|
|
|
|
|
|
- 2026-08-20/21 — **Las 14 firmas, el vocabulario y el bloque F2-A.** El día se
|
|
|
abrió presentando D-TH.6 y acabó con las catorce decisiones pendientes
|
|
|
firmadas en bloque, el vocabulario normalizado con guard, y ocho componentes
|
|
|
tokenizados. Detalle en [`CONTINUE-theming.md`](./CONTINUE-theming.md)
|
|
|
§«Registro de la sesión».
|
|
|
|
|
|
**El vocabulario** (`f09e04fab` acta · `bd916ef3f` codemod · `93017975c`
|
|
|
segunda pasada · `7781d6e4c` guard + doctrina · `476da2dd2` muro de tipos):
|
|
|
307 claves al idioma firmado —tinta `fg`, modificador interactivo delante—
|
|
|
con censo de alcance IDÉNTICO y 0 diffs de computed. R-5.3 entra en `error`
|
|
|
directo; el tipo de `defineRecipes` impide la regresión sin ejecutar nada.
|
|
|
La medición corrigió el inventario heredado: 370 «desviadas» eran 301, porque
|
|
|
47 claves `{rol}-{slot-de-rol}` son canónicas por construcción y un codemod
|
|
|
sobre ellas habría roto `button` entero.
|
|
|
|
|
|
**El bloque F2-A** (pieza 0 `bd032534b` + ocho componentes): global
|
|
|
**37 % → 43 %**, sin contrato **56 → 49**, al 100 % **6 → 7**. `command` 98 %
|
|
|
· `table` 86 % · `media-player` 88 % · `tree-grid` 95 % · `gradient-picker`
|
|
|
88 % · `listbox` 68 % (techo deliberado: su ritmo es de `list-surface`) ·
|
|
|
`carousel` 77 % · `feed` 94 %. Protocolo §7 entero en los ocho; diff de
|
|
|
computed vacío en todos.
|
|
|
|
|
|
**Lo que el bloque destapó y NO se arregló aquí** está en
|
|
|
[`next-features.md`](../next-features.md) §12 y §13: el contrato de cascada
|
|
|
del velo de estado (131 declaraciones-atajo en 45 componentes, la prop
|
|
|
`hoverable` que no suprime nada, un empate de especificidad resuelto por orden
|
|
|
de carga) y los huecos de instrumento y demo. La regla que el eje adoptó: si
|
|
|
una incidencia mueve píxel o toca morfo, se mide, se anota y se sigue.
|
|
|
|
|
|
**Tres veredictos de ocho tenían un error de lectura** que sólo apareció
|
|
|
midiendo, y esa es la lección de método del bloque: el veredicto orienta, la
|
|
|
medición decide.
|
|
|
|
|
|
Además: la demo enseña ahora el contrato de tokens (`90aa6dc5f`,
|
|
|
`TokensPanel` leyendo `getRecipeTokens()` en vivo) — hasta ese día ninguna
|
|
|
demo mostraba la superficie que este eje construye.
|
|
|
|
|
|
- 2026-08-19 — Censo medido (§1) con `scripts/theming-census.ts` (añadido en
|
|
|
este commit como instrumento, sin guard). Plan entregado. **Nada firmado,
|
|
|
nada construido.** Precedente ejecutado hoy que fija la forma:
|
|
|
`navigation-menu` (`ae9e277fa`: tokens del trigger por talla, default
|
|
|
idéntico; `a82794845`: el hover es el del sistema; `822b78cf2`: el `<li>`
|
|
|
sin arquetipo) — y aun así el componente queda en 44 %, prueba de que hace
|
|
|
falta el guard.
|
|
|
|
|
|
- 2026-08-20 — **Informe + primeros siete componentes** (`2591ec2f0` el informe
|
|
|
y el instrumento; `3bfe0d413` la revisión de las fichas 11-20). El censo pasa
|
|
|
a `--report`: `docs/audit/theming/` con un README de conjunto y **170 fichas**
|
|
|
(162 recetas + 8 sin receta), cada una con análisis, propuesta derivada de la
|
|
|
doctrina y un bloque de **veredicto** que se conserva al regenerar.
|
|
|
|
|
|
| Componente | Censo antes → después | Commit | Excepciones / lo que queda fuera |
|
|
|
| --------------------------- | --------------------: | ----------- | ------------------------------------------------------------------------------------------------------------------------ |
|
|
|
| `gradient-builder` (piloto) | 0 % → 80 % | `3cdb5b5f0` | foco (sistema) + 3 literales de layout; damero tapado por el `background` inline del wrapper (anotado) |
|
|
|
| `combobox` | 0 % → 76 % | `cef2d32f1` | 3 hovers bespoke (esperan firma) + 6 literales; `content-font-family/-line-height` inertes bajo `[data-depth='overlay']` |
|
|
|
| `natural-time-picker` | 0 % → 61 % | `e774ca7e8` | cielos = excepción de tono fijo ya firmada; panel presta `--popover-*` por composición |
|
|
|
| `date-range-picker` | 0 % → 42 % | `07778b597` | mitad calendario (§B) + mitad campo (§5.3-3) |
|
|
|
| `time-range-picker` | 0 % → 19 % | `68eb8af26` | préstamos de Field/Slider/Toggle |
|
|
|
| `time-picker` | 0 % → 18 % | `e4fcdd62e` | préstamos de Field |
|
|
|
| `proof-of-human` | 0 % → 14 % | `ae91573c3` | escena = `FIXED_TONE_COMPONENTS`; hooks de clase (eje aparte) |
|
|
|
|
|
|
**Global: 33 % → 37 %** (1.621 → 1.841 públicos; 62 → 56 sin contrato).
|
|
|
Protocolo §7 aplicado entero en los siete: diff de computed **vacío** en todos
|
|
|
(6.612 · 1.566 · 6.438 · 493 · 725 · 580 · 406 valores, 7-8 estados cada uno),
|
|
|
centinela por token, `component:audit` PASS, `eidos-lint` 0 invalid,
|
|
|
`rtl:check` 0, `docs:check` 0, suite eidos con el único rojo conocido
|
|
|
(`skin-media-player`).
|
|
|
|
|
|
Cuatro defectos del método que la verificación destapó y que el handoff
|
|
|
recoge: **clave duplicada** en `recipes/base.ts` descarta el bloque en
|
|
|
silencio · dejar vivos los bloques `[data-size]` del CSS hace que el diff dé
|
|
|
0 por la ruta vieja · la sonda debe congelar `transition` pero **no**
|
|
|
`animation` (Presence no monta) · un token RESUELTO no se mueve desde `:root`
|
|
|
por diseño.
|
|
|
|
|
|
Prefijos abreviados o ajenos corregidos de paso (el censo los contaba como
|
|
|
`global` y se cruzarían al anidar): `--gb-*`, `--_ntp-*`, `--_time-field-*` en
|
|
|
los dos time-pickers, `--_date-field-*` y `--_calendar-font-size` en el
|
|
|
date-range-picker.
|
|
|
|
|
|
---
|
|
|
|
|
|
## 9. Tabla completa por componente (2026-08-19 — regenerar con el script, no editar)
|
|
|
|
|
|
| Componente | Familia | Alcance | Knobs | Público | Privado | Global | Literal | Sistema | Contrato | size |
|
|
|
| --------------------- | ------------------------------- | ------: | ----: | ------: | ------: | -----: | ------: | ------: | -------: | :--: |
|
|
|
| `range-calendar` | Tiempo (chronos · fecha/hora) | 0% | 98 | 0 | 7 | 84 | 4 | 3 | 0 | y |
|
|
|
| `combobox` | Campos | 0% | 96 | 0 | 15 | 67 | 6 | 8 | 1 | y |
|
|
|
| `proof-of-human` | Controles · marcas | 0% | 95 | 0 | 18 | 36 | 37 | 4 | 0 | y |
|
|
|
| `time-range-picker` | Tiempo (chronos · fecha/hora) | 0% | 88 | 0 | 6 | 61 | 17 | 4 | 0 | y |
|
|
|
| `natural-time-picker` | Tiempo (chronos · fecha/hora) | 0% | 78 | 0 | 0 | 69 | 7 | 2 | 0 | y |
|
|
|
| `gradient-builder` | Campos | 0% | 62 | 0 | 8 | 46 | 3 | 5 | 0 | y |
|
|
|
| `month-grid` | Tiempo (chronos · fecha/hora) | 0% | 61 | 0 | 13 | 40 | 5 | 3 | 0 | y |
|
|
|
| `year-grid` | Tiempo (chronos · fecha/hora) | 0% | 61 | 0 | 13 | 40 | 5 | 3 | 0 | y |
|
|
|
| `time-picker` | Tiempo (chronos · fecha/hora) | 0% | 59 | 0 | 3 | 42 | 12 | 2 | 0 | y |
|
|
|
| `date-range-picker` | Tiempo (chronos · fecha/hora) | 0% | 55 | 0 | 0 | 49 | 3 | 3 | 0 | y |
|
|
|
| `command` | Menús · listas · navegación | 0% | 52 | 0 | 9 | 35 | 6 | 2 | 0 | y |
|
|
|
| `table` | Menús · listas · navegación | 0% | 46 | 0 | 23 | 14 | 5 | 4 | 0 | y |
|
|
|
| `media-player` | Media · chat | 0% | 45 | 0 | 0 | 37 | 8 | 0 | 2 | y |
|
|
|
| `tree-grid` | Menús · listas · navegación | 0% | 42 | 0 | 29 | 8 | 2 | 3 | 0 | y |
|
|
|
| `field-langs` | Campos | 0% | 41 | 0 | 0 | 31 | 8 | 2 | 0 | – |
|
|
|
| `gradient-picker` | Campos | 0% | 38 | 0 | 7 | 23 | 5 | 3 | 0 | y |
|
|
|
| `listbox` | Campos | 0% | 38 | 0 | 9 | 23 | 3 | 3 | 0 | – |
|
|
|
| `carousel` | Superficies · overlays · estado | 0% | 36 | 0 | 14 | 12 | 5 | 5 | 0 | y |
|
|
|
| `heading` | Texto · tipografía | 0% | 36 | 0 | 36 | 0 | 0 | 0 | 0 | – |
|
|
|
| `feed` | Menús · listas · navegación | 0% | 33 | 0 | 13 | 16 | 3 | 1 | 0 | y |
|
|
|
| `grid-list` | Menús · listas · navegación | 0% | 32 | 0 | 8 | 17 | 2 | 5 | 0 | y |
|
|
|
| `textarea` | Campos | 0% | 28 | 0 | 16 | 5 | 4 | 3 | 0 | y |
|
|
|
| `tree-view` | Menús · listas · navegación | 0% | 28 | 0 | 8 | 14 | 4 | 2 | 0 | y |
|
|
|
| `code-block` | Texto · tipografía | 0% | 26 | 0 | 2 | 24 | 0 | 0 | 0 | – |
|
|
|
| `card-group` | Superficies · overlays · estado | 0% | 24 | 0 | 0 | 18 | 4 | 2 | 0 | y |
|
|
|
| `text` | Texto · tipografía | 0% | 24 | 0 | 24 | 0 | 0 | 0 | 0 | – |
|
|
|
| `spinner` | Superficies · overlays · estado | 0% | 23 | 0 | 15 | 4 | 4 | 0 | 0 | y |
|
|
|
| `picker-shell` | Tiempo (chronos · fecha/hora) | 0% | 21 | 0 | 4 | 17 | 0 | 0 | 0 | y |
|
|
|
| `link-preview` | Superficies · overlays · estado | 0% | 17 | 0 | 4 | 9 | 1 | 3 | 0 | y |
|
|
|
| `drag-drop` | Controles · marcas | 0% | 16 | 0 | 3 | 6 | 0 | 7 | 1 | – |
|
|
|
| `kbd` | Controles · marcas | 0% | 14 | 0 | 1 | 9 | 4 | 0 | 0 | – |
|
|
|
| `link` | Controles · marcas | 0% | 14 | 0 | 4 | 2 | 5 | 3 | 0 | – |
|
|
|
| `code` | Texto · tipografía | 0% | 13 | 0 | 6 | 3 | 4 | 0 | 0 | – |
|
|
|
| `virtual-list` | Menús · listas · navegación | 0% | 13 | 0 | 2 | 6 | 4 | 1 | 0 | y |
|
|
|
| `virtual-grid` | Menús · listas · navegación | 0% | 12 | 0 | 2 | 6 | 3 | 1 | 0 | y |
|
|
|
| `skeleton` | Superficies · overlays · estado | 0% | 11 | 0 | 9 | 1 | 1 | 0 | 0 | y |
|
|
|
| `skin-media-player` | Media · chat | 0% | 11 | 0 | 0 | 2 | 7 | 2 | 0 | y |
|
|
|
| `scroll-frames` | Superficies · overlays · estado | 0% | 9 | 0 | 1 | 4 | 4 | 0 | 0 | – |
|
|
|
| `announce` | Superficies · overlays · estado | 0% | 8 | 0 | 0 | 8 | 0 | 0 | 0 | – |
|
|
|
| `clipboard` | Controles · marcas | 0% | 8 | 0 | 2 | 5 | 1 | 0 | 0 | – |
|
|
|
| `label` | Campos | 0% | 8 | 0 | 6 | 2 | 0 | 0 | 0 | – |
|
|
|
| `menu-dial` | Menús · listas · navegación | 0% | 8 | 0 | 3 | 1 | 4 | 0 | 0 | y |
|
|
|
| `display` | Texto · tipografía | 0% | 6 | 0 | 6 | 0 | 0 | 0 | 0 | – |
|
|
|
| `mark` | Controles · marcas | 0% | 5 | 0 | 2 | 1 | 2 | 0 | 0 | – |
|
|
|
| `aspect-ratio` | Controles · marcas | 0% | 3 | 0 | 0 | 1 | 2 | 0 | 0 | – |
|
|
|
| `date-picker` | Tiempo (chronos · fecha/hora) | 0% | 2 | 0 | 0 | 0 | 2 | 0 | 0 | – |
|
|
|
| `sticky` | Superficies · overlays · estado | 0% | 2 | 0 | 1 | 0 | 1 | 0 | 1 | – |
|
|
|
| `text-blur` | Texto · tipografía | 0% | 2 | 0 | 0 | 0 | 2 | 0 | 0 | – |
|
|
|
| `cascade` | Menús · listas · navegación | 0% | 1 | 0 | 0 | 0 | 1 | 0 | 0 | – |
|
|
|
| `motion` | Superficies · overlays · estado | 0% | 1 | 0 | 0 | 0 | 1 | 0 | 0 | – |
|
|
|
| `section` | Layout (primitivos) | 0% | 1 | 0 | 0 | 0 | 1 | 0 | 4 | – |
|
|
|
| `chronos` | Tiempo (chronos · fecha/hora) | 1% | 245 | 2 | 22 | 202 | 12 | 7 | 9 | y |
|
|
|
| `prose` | Texto · tipografía | 1% | 74 | 1 | 0 | 43 | 30 | 0 | 2 | y |
|
|
|
| `nav-tree` | Menús · listas · navegación | 4% | 25 | 1 | 0 | 17 | 6 | 1 | 1 | – |
|
|
|
| `s-text` | Texto · tipografía | 7% | 30 | 2 | 28 | 0 | 0 | 0 | 3 | – |
|
|
|
| `chart` | Controles · marcas | 9% | 92 | 8 | 0 | 66 | 14 | 4 | 17 | – |
|
|
|
| `result` | Superficies · overlays · estado | 9% | 22 | 2 | 1 | 15 | 4 | 0 | 8 | – |
|
|
|
| `mockup` | Superficies · overlays · estado | 14% | 29 | 4 | 7 | 13 | 5 | 0 | 0 | – |
|
|
|
| `menubar` | Menús · listas · navegación | 15% | 27 | 4 | 6 | 16 | 0 | 1 | 5 | y |
|
|
|
| `anchor-nav` | Menús · listas · navegación | 20% | 11 | 2 | 0 | 8 | 0 | 1 | 2 | – |
|
|
|
| `banner` | Superficies · overlays · estado | 20% | 10 | 2 | 6 | 1 | 1 | 0 | 42 | y |
|
|
|
| `button` | Controles · marcas | 21% | 30 | 6 | 16 | 0 | 7 | 1 | 105 | y |
|
|
|
| `palabras` | WIP (tracks paralelos) | 22% | 471 | 103 | 1 | 272 | 90 | 5 | 0 | – |
|
|
|
| `toggle` | Controles · marcas | 22% | 28 | 6 | 17 | 1 | 3 | 1 | 119 | y |
|
|
|
| `date-range-field` | Tiempo (chronos · fecha/hora) | 25% | 9 | 2 | 0 | 4 | 2 | 1 | 3 | – |
|
|
|
| `time-range-field` | Tiempo (chronos · fecha/hora) | 25% | 9 | 2 | 0 | 4 | 2 | 1 | 3 | – |
|
|
|
| `surface` | Superficies · overlays · estado | 25% | 4 | 1 | 3 | 0 | 0 | 0 | 25 | – |
|
|
|
| `callout` | Superficies · overlays · estado | 27% | 15 | 4 | 3 | 7 | 1 | 0 | 28 | – |
|
|
|
| `meter` | Superficies · overlays · estado | 29% | 14 | 4 | 6 | 2 | 2 | 0 | 28 | y |
|
|
|
| `knob` | Controles · marcas | 29% | 27 | 7 | 4 | 9 | 4 | 3 | 0 | y |
|
|
|
| `onion-menu` | Menús · listas · navegación | 29% | 27 | 7 | 0 | 8 | 9 | 3 | 12 | – |
|
|
|
| `empty-state` | Superficies · overlays · estado | 29% | 17 | 5 | 7 | 5 | 0 | 0 | 6 | y |
|
|
|
| `search-field` | Campos | 31% | 14 | 4 | 5 | 0 | 4 | 1 | 17 | y |
|
|
|
| `password-field` | Campos | 31% | 36 | 11 | 5 | 9 | 10 | 1 | 23 | y |
|
|
|
| `aura` | Superficies · overlays · estado | 31% | 35 | 11 | 4 | 14 | 6 | 0 | 24 | y |
|
|
|
| `toggle-group` | Controles · marcas | 33% | 3 | 1 | 0 | 1 | 1 | 0 | 1 | – |
|
|
|
| `background` | Superficies · overlays · estado | 35% | 26 | 8 | 6 | 6 | 3 | 3 | 31 | – |
|
|
|
| `avatar` | Controles · marcas | 36% | 36 | 13 | 17 | 0 | 6 | 0 | 0 | y |
|
|
|
| `audio-player` | Media · chat | 37% | 19 | 7 | 0 | 8 | 4 | 0 | 5 | – |
|
|
|
| `tooltip` | Superficies · overlays · estado | 38% | 22 | 8 | 9 | 3 | 1 | 1 | 20 | y |
|
|
|
| `button-group` | Controles · marcas | 40% | 5 | 2 | 0 | 0 | 3 | 0 | 1 | – |
|
|
|
| `badge` | Controles · marcas | 41% | 22 | 9 | 10 | 1 | 2 | 0 | 65 | y |
|
|
|
| `popover` | Superficies · overlays · estado | 42% | 51 | 20 | 6 | 22 | 0 | 3 | 36 | y |
|
|
|
| `qr-code` | Controles · marcas | 43% | 7 | 3 | 0 | 0 | 4 | 0 | 10 | – |
|
|
|
| `navigation-menu` | Menús · listas · navegación | 44% | 38 | 15 | 1 | 13 | 5 | 4 | 26 | y |
|
|
|
| `waveform` | Media · chat | 45% | 11 | 5 | 1 | 1 | 4 | 0 | 10 | y |
|
|
|
| `color-picker` | Campos | 46% | 82 | 36 | 10 | 22 | 11 | 3 | 54 | y |
|
|
|
| `checkbox` | Controles · marcas | 48% | 34 | 16 | 12 | 2 | 3 | 1 | 45 | y |
|
|
|
| `progress` | Superficies · overlays · estado | 49% | 35 | 17 | 9 | 3 | 6 | 0 | 41 | y |
|
|
|
| `tag-group` | Controles · marcas | 49% | 46 | 21 | 21 | 0 | 1 | 3 | 91 | y |
|
|
|
| `color-swatch` | Controles · marcas | 50% | 10 | 5 | 2 | 3 | 0 | 0 | 12 | y |
|
|
|
| `text-scramble` | Texto · tipografía | 50% | 4 | 2 | 0 | 0 | 2 | 0 | 0 | – |
|
|
|
| `split-button` | Controles · marcas | 50% | 2 | 1 | 0 | 1 | 0 | 0 | 1 | y |
|
|
|
| `timeline` | Superficies · overlays · estado | 51% | 49 | 25 | 21 | 0 | 3 | 0 | 45 | y |
|
|
|
| `field` | Campos | 51% | 73 | 35 | 15 | 7 | 11 | 5 | 60 | y |
|
|
|
| `context-menu` | Menús · listas · navegación | 53% | 33 | 16 | 0 | 11 | 3 | 3 | 18 | – |
|
|
|
| `rating-group` | Controles · marcas | 53% | 16 | 8 | 4 | 1 | 2 | 1 | 25 | y |
|
|
|
| `metrics` | Controles · marcas | 54% | 50 | 27 | 10 | 9 | 4 | 0 | 68 | y |
|
|
|
| `sidebar` | Menús · listas · navegación | 55% | 45 | 23 | 0 | 14 | 5 | 3 | 50 | – |
|
|
|
| `drawer` | Superficies · overlays · estado | 55% | 62 | 33 | 9 | 13 | 5 | 2 | 44 | y |
|
|
|
| `color-field` | Campos | 56% | 16 | 9 | 0 | 2 | 5 | 0 | 22 | y |
|
|
|
| `image` | Controles · marcas | 57% | 35 | 20 | 2 | 1 | 12 | 0 | 22 | y |
|
|
|
| `dropdown-menu` | Menús · listas · navegación | 57% | 30 | 16 | 0 | 9 | 3 | 2 | 19 | – |
|
|
|
| `switch` | Controles · marcas | 57% | 22 | 12 | 8 | 1 | 0 | 1 | 52 | y |
|
|
|
| `s-text-virtual-list` | Menús · listas · navegación | 58% | 12 | 7 | 0 | 3 | 2 | 0 | 9 | – |
|
|
|
| `form` | Campos | 59% | 52 | 30 | 14 | 5 | 2 | 1 | 54 | y |
|
|
|
| `float-panel` | Superficies · overlays · estado | 59% | 53 | 29 | 3 | 12 | 5 | 4 | 28 | – |
|
|
|
| `slider` | Controles · marcas | 59% | 33 | 19 | 12 | 0 | 1 | 1 | 39 | y |
|
|
|
| `radio-cards` | Controles · marcas | 60% | 72 | 42 | 0 | 24 | 4 | 2 | 39 | y |
|
|
|
| `card` | Superficies · overlays · estado | 60% | 36 | 21 | 14 | 0 | 0 | 1 | 97 | y |
|
|
|
| `cropper` | Controles · marcas | 60% | 27 | 15 | 0 | 3 | 7 | 2 | 15 | – |
|
|
|
| `emoji-picker` | Campos | 61% | 32 | 17 | 0 | 8 | 3 | 4 | 17 | – |
|
|
|
| `pin-input` | Campos | 61% | 19 | 11 | 0 | 6 | 1 | 1 | 20 | y |
|
|
|
| `editable` | Campos | 63% | 44 | 25 | 12 | 1 | 2 | 4 | 56 | y |
|
|
|
| `text-focus` | Texto · tipografía | 63% | 8 | 5 | 0 | 1 | 2 | 0 | 0 | – |
|
|
|
| `spin-field` | Campos | 64% | 27 | 16 | 0 | 8 | 1 | 2 | 20 | – |
|
|
|
| `file-upload` | Campos | 64% | 61 | 38 | 16 | 1 | 4 | 2 | 98 | y |
|
|
|
| `tags-input` | Campos | 67% | 46 | 28 | 13 | 1 | 0 | 4 | 90 | y |
|
|
|
| `toolbar` | Menús · listas · navegación | 67% | 35 | 22 | 10 | 0 | 1 | 2 | 54 | y |
|
|
|
| `image-adjustments` | Controles · marcas | 67% | 18 | 10 | 0 | 4 | 1 | 3 | 12 | – |
|
|
|
| `text-gradient` | Texto · tipografía | 67% | 9 | 6 | 0 | 0 | 3 | 0 | 0 | – |
|
|
|
| `separator` | SIN FAMILIA | 67% | 6 | 4 | 0 | 0 | 2 | 0 | 3 | – |
|
|
|
| `select` | Campos | 69% | 72 | 45 | 14 | 3 | 3 | 7 | 101 | y |
|
|
|
| `dialog` | Superficies · overlays · estado | 70% | 33 | 23 | 5 | 4 | 1 | 0 | 37 | y |
|
|
|
| `image-picker` | Campos | 71% | 20 | 12 | 0 | 1 | 4 | 3 | 13 | – |
|
|
|
| `pagination` | Menús · listas · navegación | 71% | 26 | 17 | 7 | 0 | 0 | 2 | 34 | y |
|
|
|
| `stepper` | Menús · listas · navegación | 71% | 60 | 40 | 15 | 0 | 1 | 4 | 69 | y |
|
|
|
| `skip-link` | Superficies · overlays · estado | 71% | 8 | 5 | 0 | 0 | 2 | 1 | 8 | – |
|
|
|
| `date-field` | Tiempo (chronos · fecha/hora) | 73% | 11 | 8 | 3 | 0 | 0 | 0 | 21 | y |
|
|
|
| `time-field` | Tiempo (chronos · fecha/hora) | 73% | 11 | 8 | 3 | 0 | 0 | 0 | 21 | y |
|
|
|
| `calendar` | Tiempo (chronos · fecha/hora) | 75% | 71 | 51 | 13 | 0 | 4 | 3 | 76 | y |
|
|
|
| `accordion` | Superficies · overlays · estado | 77% | 65 | 49 | 10 | 0 | 5 | 1 | 76 | y |
|
|
|
| `radio-group` | Controles · marcas | 77% | 75 | 56 | 10 | 7 | 0 | 2 | 61 | y |
|
|
|
| `chat-log` | Media · chat | 77% | 42 | 30 | 0 | 4 | 5 | 3 | 31 | – |
|
|
|
| `chat-composer` | Media · chat | 79% | 44 | 31 | 0 | 3 | 5 | 5 | 31 | – |
|
|
|
| `chat-message` | Media · chat | 82% | 84 | 63 | 2 | 6 | 6 | 7 | 75 | y |
|
|
|
| `fab` | Controles · marcas | 82% | 17 | 14 | 0 | 2 | 1 | 0 | 10 | – |
|
|
|
| `toast` | Superficies · overlays · estado | 83% | 42 | 35 | 6 | 0 | 1 | 0 | 85 | – |
|
|
|
| `text-circular` | Texto · tipografía | 83% | 6 | 5 | 0 | 1 | 0 | 0 | 0 | – |
|
|
|
| `tabs` | Menús · listas · navegación | 88% | 76 | 66 | 6 | 2 | 1 | 1 | 79 | y |
|
|
|
| `chat-typing` | Media · chat | 89% | 9 | 8 | 0 | 1 | 0 | 0 | 7 | – |
|
|
|
| `breadcrumb` | Menús · listas · navegación | 90% | 23 | 18 | 2 | 0 | 0 | 3 | 28 | y |
|
|
|
| `collapsible` | Superficies · overlays · estado | 90% | 12 | 9 | 0 | 1 | 0 | 2 | 11 | – |
|
|
|
| `scroll-area` | Superficies · overlays · estado | 94% | 17 | 15 | 0 | 0 | 1 | 1 | 13 | – |
|
|
|
| `splitter` | Superficies · overlays · estado | 100% | 19 | 18 | 0 | 0 | 0 | 1 | 16 | – |
|
|
|
| `chat-list` | Media · chat | 100% | 18 | 18 | 0 | 0 | 0 | 0 | 18 | – |
|
|
|
| `box` | Layout (primitivos) | 100% | 9 | 9 | 0 | 0 | 0 | 0 | 43 | – |
|
|
|
| `barcode` | Controles · marcas | 100% | 5 | 5 | 0 | 0 | 0 | 0 | 7 | – |
|
|
|
| `flex` | Layout (primitivos) | 100% | 2 | 2 | 0 | 0 | 0 | 0 | 7 | – |
|
|
|
| `grid` | Layout (primitivos) | 100% | 2 | 2 | 0 | 0 | 0 | 0 | 13 | – |
|
|
|
| `alert-dialog` | Superficies · overlays · estado | — | 0 | 0 | 0 | 0 | 0 | 0 | 0 | – |
|
|
|
| `auto-grid` | Layout (primitivos) | — | 0 | 0 | 0 | 0 | 0 | 0 | 0 | – |
|
|
|
| `container` | Layout (primitivos) | — | 0 | 0 | 0 | 0 | 0 | 0 | 1 | – |
|
|
|
| `css-field` | Campos | — | 0 | 0 | 0 | 0 | 0 | 0 | 0 | – |
|
|
|
| `float` | Superficies · overlays · estado | — | 0 | 0 | 0 | 0 | 0 | 0 | 1 | – |
|
|
|
| `group` | Layout (primitivos) | — | 0 | 0 | 0 | 0 | 0 | 0 | 1 | – |
|
|
|
| `highlight` | Controles · marcas | — | 0 | 0 | 0 | 0 | 0 | 0 | 0 | – |
|
|
|
| `icon` | Controles · marcas | — | 0 | 0 | 0 | 0 | 0 | 0 | 2 | – |
|
|
|
| `mask-field` | Campos | — | 0 | 0 | 0 | 0 | 0 | 0 | 0 | – |
|
|
|
| `number-field` | Campos | — | 0 | 0 | 0 | 0 | 0 | 0 | 0 | – |
|
|
|
| `stack` | Layout (primitivos) | — | 0 | 0 | 0 | 0 | 0 | 0 | 0 | – |
|
|
|
| `wrap` | Layout (primitivos) | — | 0 | 0 | 0 | 0 | 0 | 0 | 0 | – |
|