La revisión de hoy (`REVIEW-theming-2026-08-23.md`, punto P4) destapó que
NINGUNO de los commits de tokenización de la mañana del 23 hizo los pasos 8 y 9
del protocolo: `git show --stat` de los diecisiete sólo tocaba CSS, base.ts, el
ledger y las fichas. Veintidós componentes tokenizados sin la tabla de tokens en
su README y veintiuno sin la pestaña que la enseña viva.
QUÉ ENTRA
- **README «Talla y tema»** en 22 (los 21 con demo + `surface`, que no tiene
ruta). La tabla NO está escrita a mano: se DERIVA de `lib/recipes/base.ts` y
de `theming-sentinel-exceptions.ts`, así que lo que el lector ve es lo que el
contrato dice. Hasta 30 claves va la tabla completa clave → valor por defecto;
por encima, agrupada por parte (con la paleta en su propio grupo, que si no se
come la tabla: button tiene 70 claves de tono de 106). Debajo, lo que el guard
da por silencioso con su razón medida, y la excepción POR PATRÓN cuando la
razón es la cascada de paleta.
- **Pestaña `Tokens`** en los 21 con demo, con el conteo real de claves.
VERIFICADO EN EL NAVEGADOR, LOS 21
Cada pestaña abre y lista exactamente sus claves: menubar 35 · field 68 ·
onion-menu 19 · button 106 · callout 34 · empty-state 26 · dropdown-menu 28 ·
context-menu 28 · checkbox 47 · image 23 · anchor-nav 12 · banner 53 ·
date-range-field 7 · time-range-field 7 · tooltip 23 · section 4 · sticky 1 ·
button-group 1 · qr-code 10 · toggle-group 1 · split-button 1.
⚠ Y el verificador mintió DOS veces antes de acertar: primero buscaba el rótulo
de la cabecera del panel en `innerText` (no lo encontraba aunque la tabla estaba
ahí), y después clicaba con `element.click()` tras `waitUntil: 'load'` — la
página aún NO ha hidratado, así que el `onclick` de Svelte no está enganchado y
el clic no hace nada. Con `networkidle` + el clic de Playwright (que espera a
que el nodo sea accionable), los 21 en verde. Es la ley de siempre: el
instrumento miente primero.
`audio-player` queda fuera: no tiene README propio — hueco aparte, anotado.
Verificación: `npm run check` sin errores nuevos en las 21 demos (los 72
globales son ajenos y preexistentes) · `docs:check` 0 · cada README conserva su
estructura de encabezados y **ninguno gana un hunk de prettier** (mi sección se
formateó dentro de su propio recorte, sin tocar lo ajeno).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- `transition-duration` — the guard freezes transitions to measure and this token IS the transition; measured unfrozen -> reaches (0.12s -> 11.5s, five properties)
- `disabled-opacity` — no disabled button in the demo; forced data-disabled -> reaches (0.4 -> 0.137)
- `primary-track` — the FALLBACK of the palette forward: it acts only on an instance with NO data-color, and the demo stamps data-color=primary. Removed the attribute -> reaches. See the pattern entry below for…
- `primary-element` — same fallback, same condition
- `primary-border` — same fallback, same condition
- `primary-solid` — same fallback: without data-color it repaints (oklch(0.5556 0.1829 305.86) -> rgb(1,2,3)); with data-color=primary the generic forward rule supersedes it
- `primary-solid-hover` — same fallback, same condition
- `primary-text` — same fallback, same condition
- `primary-contrast` — same fallback, same condition
- `palette-track` — a RESOLVED name, declared on [data-button] by the forward, so a :root write loses BY DESIGN - a theme moves the tone or the scale. Measured on a soft button: from :root nothing, from the nod…
- `palette-element` — same resolved name; the theme moves its coordinate
- `palette-border` — same resolved name; the theme moves its coordinate
- **Por patrón**`/^(secondary|neutral|affirm|fulfill|risk|threat|loss)-(track|element|border|solid|solid-hover|text|contrast)$/` — la cascada de paleta: el bloque genérico `[data-button][data-color]` se emite el ÚLTIMO y gana por orden, así que la pintura sale del `--palette-*` global (§13, pendiente de firma).
**Lo que el guard R-5.4 da por silencioso, con su razón medida**
(`scripts/theming-sentinel-exceptions.ts`):
- **Por patrón**`/^(primary|secondary|neutral|affirm|fulfill|risk|threat|loss)-(track|text|solid)$/` — la cascada de paleta: el bloque genérico `[data-callout][data-color]` se emite el ÚLTIMO y gana por orden, así que la pintura sale del `--palette-*` global (§13, pendiente de firma).
**Lo que el guard R-5.4 da por silencioso, con su razón medida**
(`scripts/theming-sentinel-exceptions.ts`):
- `size-xs-indicator-stroke` — the glyph exists only inside a CHECKED box and the first checkbox of the demo is empty; measured on a checked one with data-size forced -> reaches (2px -> 7px)
- `invalid-border` — only under [data-invalid]; forced -> reaches (oklch(0.9555 0.0207 13.86) -> rgb(1,2,3))
- `invalid-ring` — the invalid focus ring: needs [data-invalid] AND :focus-visible, which the guard blurs on purpose; focused by hand -> reaches (the 4px ring turns rgb(1,2,3))
- `invalid-ring-gap` — same double ring; forced -> reaches (the 2px gap turns rgb(4,5,6))
- `disabled-bg` — only under [data-disabled]; forced -> reaches
- `disabled-border` — only under [data-disabled]; forced -> reaches
- `disabled-opacity` — only under [data-disabled]; forced -> reaches (0.4 -> 0.137)
- `disabled-indicator-fg` — needs [data-disabled] AND a checked box (the glyph); forced on a checked one -> reaches
- `disabled-group-label-fg` — the label carries its OWN [data-disabled] - it is not inherited from the group, so forcing the group does nothing; set on the label -> reaches (oklch(0.5032 0 0) -> rgb(1,2,3))
- `transition-duration` — the guard freezes transitions and this token IS the transition; measured unfrozen -> reaches (0.12s -> 11.5s)
- `transition-ease` — same instrument limit; measured unfrozen -> reaches
- `stroke-duration` — same, on the check path dash animation; measured unfrozen -> reaches (0.12s -> 11.5s)
- **Por patrón**`/^(primary|secondary|neutral|affirm)-(solid|solid-hover)$/` — la cascada de paleta: el bloque genérico `[data-checkbox][data-color]` se emite el ÚLTIMO y gana por orden, así que la pintura sale del `--palette-*` global (§13, pendiente de firma).
**Lo que el guard R-5.4 da por silencioso, con su razón medida**
(`scripts/theming-sentinel-exceptions.ts`):
- `invalid-label-fg` — only under [data-invalid] and the demo boots valid; forced -> reaches (oklch(0.5855 0.1743 42.74) -> rgb(1,2,3))
- `disabled-label-fg` — only under [data-disabled]; forced -> reaches (oklch(0.7921 0 0) -> rgb(1,2,3))
- `invalid-control-border` — only under [data-invalid]; forced -> reaches (oklch(0.8059 0.1123 59.96) -> rgb(1,2,3))
- `disabled-control-bg` — only under [data-disabled]; forced -> reaches (oklch(0.9551 0 0) -> rgb(1,2,3))
- `control-bg-readonly` — only under [data-readonly]; forced -> reaches (oklch(0.9551 0 0) -> rgb(1,2,3))
- `disabled-opacity` — it lives on the CONTROL, not on the field root, so the guard read the wrong node; forced data-disabled and read on the control -> reaches (0.4 -> 0.137)
- `control-ghost-border` — the ghost variant and the demo boots surface; forced data-variant=ghost -> reaches (transparent -> rgb(1,2,3))
- `layout-column-gap` — only in the horizontal orientation; forced data-orientation=horizontal -> reaches (16px -> 1234px)
- `focus-control-border` — only under :focus-within, and the guard blurs ON PURPOSE (the click-focus poisoning fix); focused from the keyboard -> reaches (the focus ring colour -> rgb(1,2,3))
- `focus-control-trigger-fg` — only under :focus-visible on the picker trigger, which the guard blurs; focused from the keyboard on /date-picker -> reaches (oklch(0.2435 0 0) -> rgb(1,2,3))
- `floating-label-top` — floatingLabel is a demo switch that boots OFF, and the label must also be floated (focused or filled); switch on + focus -> reaches (0px -> 1234px)
- `floating-label-padding-inline` — same switch; turned on -> reaches (4px -> 1234px)
- `error-fg` — the error text only RENDERS when the field is invalid, and it is the demo switch that mounts it - forcing the data-invalid attribute does not make Svelte render the node; switch on -> reache…
- `control-placeholder-fg` — the ::placeholder box exists only when the input HAS a placeholder attribute, and the demo input has none: getComputedStyle then returns the ELEMENT style and the token reads dead. With a pl…
- `segment-active-bg` — the ACTIVE segment being edited: no segment on the field route and none focused; measured on /date-field with the segment clicked -> reaches (the 40% mix -> rgb(1,2,3))
- `segment-active-text` — same segment; measured on /date-field -> reaches (oklch(0.5168 0.1733 305.88) -> rgb(1,2,3))
- `segment-height` — a FAMILY token that field OWNS and the pickers CONSUME - nothing on the field routes reads it - and it is RESOLVED (declared per [data-field][data-size]), so a :root write loses BY DESIGN: a…
- `transition-duration` — the guard freezes transitions to measure and this token IS the transition; measured unfrozen -> reaches (0.12s -> 11.5s)
**Lo que el guard R-5.4 da por silencioso, con su razón medida**
(`scripts/theming-sentinel-exceptions.ts`):
- `trigger-lift` — the lift TRANSITIONS, so an immediate read after the write returns the old value; hovered with transitions frozen -> reaches (translate 0 -2px -> 0 -123px)
- `rim-width` — the luminous look is not rendered by the component demo; measured on /active/docs/agnt -> reaches (2px -> 17px)
- `rim-glow-width` — same look, same route -> reaches (9px -> 17px)
- `rim-glow-blur` — same look, same route -> reaches (blur(4px) -> blur(13px))
No Air baseline — new component (2026-06-12). Nothing in the legacy layers
rendered QR codes; the encoder itself is also new (`$libs/qr`, zero-dep).
## Talla y tema
**10 clave(s) pública(s)** en `lib/recipes/base.ts` (bloque `qr-code`), con sus pasos por talla y el nombre RESUELTO que consume la receta.
Es el contrato vivo: la pestaña **Tokens** de su demo lista estas mismas
claves y las resuelve sobre el escenario.
| Token (`--qr-code-…`) | Valor por defecto |
| --------------------- | ------------------ |
| `fg` | `#18181b` |
| `bg` | `#ffffff` |
| `size-xs` | `96px` |
| `size-sm` | `128px` |
| `size-md` | `160px` |
| `size-lg` | `200px` |
| `size-xl` | `256px` |
| `radius` | `var(--radius-md)` |
| `overlay-bg` | `#ffffff` |
| `overlay-radius` | `var(--radius-sm)` |
**Lo que el guard R-5.4 da por silencioso, con su razón medida**
(`scripts/theming-sentinel-exceptions.ts`):
- `size-xs` — one step per instance: the wrapper writes var(--qr-code-size-{k}) inline from the size prop and the demo runs lg. Forced -> reaches (96px -> 123px)
- `size-sm` — same, one step per instance
- `size-md` — same, one step per instance
- `size-xl` — same, one step per instance
- `fg` — painted as the SVG fill of the module path, not as color on the root; read on the path -> reaches (rgb(24,24,27) -> rgb(1,2,3))
## Comparativa — why a new one (vs the references)
**Lo que el guard R-5.4 da por silencioso, con su razón medida**
(`scripts/theming-sentinel-exceptions.ts`):
- **Por patrón**`/^(primary|secondary|neutral|affirm|fulfill|risk|threat|loss)-(track|solid|contrast)$/` — la cascada de paleta: el bloque genérico `[data-surface][data-color]` se emite el ÚLTIMO y gana por orden, así que la pintura sale del `--palette-*` global (§13, pendiente de firma).
**Lo que el guard R-5.4 da por silencioso, con su razón medida**
(`scripts/theming-sentinel-exceptions.ts`):
- `content-z` — it lands on the floating WRAPPER, which carries no data-tooltip-\* attr and so is outside the measured set; read on the wrapper -> reaches (90 -> 4321)
- `bg` — SUPERSEDED by the overlay plane: [data-depth=overlay] declares background at the same specificity and later in the cascade, so the recipe loses. Measured: --tooltip-bg moves nothing, --depth…
- `border` — same supersession: --depth-overlay-border repaints it, --tooltip-border does not
- `shadow` — same supersession: --depth-overlay-shadow repaints it, --tooltip-shadow does not
- `font-family` — same plane, the typography half of it (PLAN 12.9, unsigned)
- `line-height` — same plane, same open decision
- `outline-arrow-bg` — the arrow is painted through a SIBLING selector that needs the content carrying data-variant=outline AND the panel open; measured with the demo switch -> reaches (oklch(0.9911 0 0) -> rgb(1,…
## Comparativa
| Referencia | Superficie relevante | Estado Eidos |