Los cinco knobs fuera de alcance se clasificaron UNO A UNO antes de tocar una
línea, que es la mitad del trabajo:
- **uno era la COSTURA**: `[data-tags-input-control][data-invalid]` leía
`var(--color-risk-border)` A PELO. Entra como
`--tags-input-invalid-control-border`, valor verbatim, con el nombre Y el
default de `field.invalid-control-border` — la misma parte del mismo chasis.
NO se reusó el `risk-border` de la paleta: la cascada `[data-color]` lo
re-enruta por instancia y se llevaría con él el estado inválido, que no es
una elección de tono. `global` a CERO.
- **los otros cuatro son el MISMO puente THM-2**: el borde del control
enfocado y los tres slots de la etiqueta activa leen
`--_tags-input-palette-{border,track,text}`. Ni conmutador ni escala por
talla. No se acuñan (CONTINUE §3.pre): un público encima dejaría que un tema
los fijara y matara en silencio el `color=` por instancia.
**Así que 90 % ES el techo, y es doctrina bien aplicada, no deuda.** Los siete
privados dimensionales ya derivan de públicos; sus bloques `[data-size]` del
CSS SE QUEDAN porque aquí no los emite el TSC (las claves de talla son planas,
sin `scope: 'size:{k}'`) — retirarlos rompería el eje. Migrar esa escala al TSC
es cambio de mecanismo, no de alcance, y queda fuera.
Censo: 46 knobs · público 37 → 38 · global 1 → 0 · privado 4 (el puente) ·
sistema 4 (fuera del ratio) · 88 % → 90 %. Contrato 90 → 91 claves.
`--names`: 0 desviadas (67 conformes + 24 role-slot canónicas).
Diff de computed: VACÍO en las dos superficies. 2.496 valores × 8 estados en el
escenario por defecto (válido, sonda estándar, 10 nodos) y 459 valores × 5
tallas + 3 variantes + hover en el estado INVÁLIDO, con una sonda de un solo
uso porque la demo arranca válida. Captura 2× antes/después byte a byte
idéntica. No se tocó ninguna regla `:hover`, así que el paso 12 no aplica.
Centinela R-5.4: **63/91**, 28 adjudicadas, cuatro razones y todas MEDIDAS:
1. **Las 24 claves de tono — la cascada de paleta** (excepción por PATRÓN). El
wrapper resuelve `color` y estampa `data-color` en TODA instancia, incluida
la del default, así que gana el bloque genérico
`[data-tags-input][data-color], [data-tags-input][data-color-custom]`, que
se emite el ÚLTIMO a la misma (0,2,0) que los ocho por tono. Medido sobre la
etiqueta real forzada a `data-state=active`: `--tags-input-primary-border`
no mueve nada (el borde sigue en `oklch(0.8043 0.0918 309.69)`) mientras
`--palette-border` en el mismo nodo lo repinta (`rgb(4, 5, 6)`); quita
`data-color` y `--tags-input-primary-border` vuelve a pintar
(`rgb(1, 2, 3)`).
2. **`transition-duration` / `transition-ease`** SON la transición que el guard
congela. Medidos sin congelar: 0.12s → 4.321s y
`cubic-bezier(0.4, 0, 0.2, 1)` → `steps(3)`.
3. **`placeholder-fg`**: soma sólo pone el atributo `placeholder` mientras el
input está VACÍO (`isEmpty ? opts.placeholder : undefined`) y el escenario
arranca con dos etiquetas — y `::placeholder` sobre un input SIN placeholder
devuelve el estilo del ELEMENTO (la trampa ya medida en `field`). Vaciar el
escenario no vale para esa corrida: borra los nodos de etiqueta, donde pinta
un tercio del contrato. Medido de las dos formas: pulsando el propio `Clear`
de la demo el input queda con `placeholder="Add tag"`, y forzando el
atributo sobre el input real el token alcanza (`rgb(1, 2, 3)`; default
`oklch(0.61 0 0)` = `--color-content-muted`).
4. **`item-fg` — y ésta NO es del instrumento, es del COMPONENTE.** El morfo
sella `aria-selected='true'` como LITERAL en CADA etiqueta, así que la regla
de `archetypes.css`
`[data-archetype='item'][aria-selected='true']:not([data-state='checked']):not([data-state='on'])`
**(0,4,0)** gana siempre a `[data-tags-input-item]` **(0,1,0)**: la tinta de
la etiqueta es la del arquetipo y su velo de estado se pinta en TODAS las
etiquetas en reposo. Medido: con el atributo tal como se envía el token no
mueve nada (`oklch(0.2435 0 0)`, la del arquetipo); con `aria-selected=false`
sobre la etiqueta real, la misma escritura alcanza (`rgb(1, 2, 3)`). Los
tres slots `*-text` del tono llevan esta SEGUNDA causa encima de la primera.
Es la clase de `table.selected-row-fg` y la tinta de `listbox`. Toca morfo Y
mueve píxel ⇒ se mide, se REGISTRA (next-features §12, con su cara de a11y:
un lector anuncia todas las etiquetas como seleccionadas) y se sigue.
Lo que el instrumento aprendió: **el guard ABRE haciendo clic en el control**,
lo que 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`, un token perfectamente vivo,
leía muerto. Es la clase de `command.input-border`, otra vez, y la cura es
barrer la AUSENCIA (`null`) de `data-focus`, `data-invalid` y `data-disabled`:
**60/91 → 63/91 sin adjudicar una clave de más**, y de paso reviven
`invalid-control-border` y `disabled-opacity`. Es una entrada por componente:
no toca a nadie más. `fab` re-verificado tras el cambio del guard: 11/12, sin
regresión ni STALE.
Guards: censo `--only tags-input` 90 % (global 68 %, no baja) · `--names` 0
desviadas · `component-audit --only tags-input` PASS · `eidos-lint tags-input`
0 invalid (22 morfo-backed, 6 eidos-only) · `vitest run src/uix/eidos` 35/36
ficheros, el único rojo es el conocido `skin-media-player` en `lint.test.ts` ·
`rtl:check` 0 · `docs:check` 0 · `npm run check` COMPLETED, cero errores en los
ficheros tocados (los 72 globales son de otras sesiones) · prettier limpio
sobre el contenido normalizado a LF.
README con su sección «Talla y tema», pestaña `Tokens` en la demo verificada en
navegador (91 claves, cero errores de página) y veredicto §5 escrito en la
ficha.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>