fix(theming): el slot de tinta es `fg` — R-5.3 me cazó tres claves, y el handoff de mañana

Los guards globales, corridos antes de cerrar la sesión, encontraron una
regresión MÍA: `--names` daba **3 desviadas en 2 componentes** y
`component:audit` había pasado de 4 a **6 NEEDS-WORK**.

La causa: en `text-circular` y `text-focus` nombré tres claves con el slot
`color` (`color`, `border-color`, `glow-color`) cuando la gramática firmada el
2026-08-20 dice que **el slot de tinta es `fg` y `color` como slot MUERE**.
R-5.3 existe justamente para eso y funcionó — pero después de que yo lo
escribiera, porque el guard es de catálogo y yo verificaba `--only`.

Renombradas a `fg`, `border-fg` y `glow-fg`, con los destinos que el propio
censo indica en su salida `--names`. Value-preserving verificado: **0 diffs**
en text-circular (5.916 valores) y en text-focus (1.769), guards 5/6 y 8/8,
`--names` **DESVIADAS 0**, audit de vuelta a **162 PASS / 4 NEEDS-WORK** (los
cuatro preexistentes y ajenos al eje).

La lección para el protocolo, y va al handoff: **la propuesta §4 generada usa
el slot `color`**, así que es la cuarta manera en que falla — y como el paso 7
corre los guards con `--only`, la desviación de gramática sólo aparece al
correr `--names` GLOBAL. Ese comando ya estaba en el paso 1 del handoff; ahora
también se explica por qué no basta con el audit.

Y el HANDOFF para mañana: cifras nuevas (56 %, sin contrato 25, al 100 % 16),
la lista de los 24 componentes de F2-B con su alcance, las tres cosas que el
bloque enseñó y hay que tener delante al seguir (las cuatro maneras en que
falla la propuesta · declarar un público «de facto» puede MATAR una escala si
detrás hay un privado por talla · cuenta los nodos que ve la sonda antes de
creerte un gate verde), y la cola actualizada — con `mockup` marcado como SIN
DEMO (404) y `text-scramble` como «0 % estructural, escribe el veredicto, no
tokens».

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
alpha-0.1-background
dev 2 months ago
parent 9c9c0c8652
commit e7219bb909

@ -7,7 +7,7 @@
- **Medido**: 2026-08-22 · **Alcance**: **100%** — 6 de 6 knobs por token público
- **Knobs de apariencia**: 6 — público 6 · privado 0 · global 0 · literal 0 · sistema 0 _(fuera del ratio)_
- **Contrato hoy** (`lib/recipes/base.ts`): 6 pública(s) — `size`, `radius`, `weight`, `color`, `font-size`, `char-transition`
- **Contrato hoy** (`lib/recipes/base.ts`): 6 pública(s) — `size`, `radius`, `weight`, `fg`, `font-size`, `char-transition`
- **Eje `size`**: no · **ficheros**: `text-circular.css`
## 1. Knobs fuera de alcance
@ -61,7 +61,7 @@ knob que faltaba.
fallback simplemente deja de usarse y el valor por defecto pasa al contrato,
que es donde un tema lo busca.
2. **El que faltaba es el `radius`** (`var(--radius-full, 9999px)`): el círculo.
3. **`color` con valor `currentColor` es correcto como token**: una custom
3. **`fg` con valor `currentColor` es correcto como token**: una custom
property no resuelve `currentColor` hasta el punto de uso, así que sigue
tomando la tinta del nodo y no la del `:root` — verificado con el diff.
4. **`char-transition` guarda una transición COMPLETA**

@ -7,7 +7,7 @@
- **Medido**: 2026-08-22 · **Alcance**: **100%** — 8 de 8 knobs por token público
- **Knobs de apariencia**: 8 — público 8 · privado 0 · global 0 · literal 0 · sistema 0 _(fuera del ratio)_
- **Contrato hoy** (`lib/recipes/base.ts`): 8 pública(s) — `gap`, `word-weight`, `word-size`, `corner-size`, `corner-width`, `corner-radius`, `border-color`, `glow-color`
- **Contrato hoy** (`lib/recipes/base.ts`): 8 pública(s) — `gap`, `word-weight`, `word-size`, `corner-size`, `corner-width`, `corner-radius`, `border-fg`, `glow-fg`
- **Eje `size`**: no · **ficheros**: `text-focus.css`
## 1. Knobs fuera de alcance
@ -61,7 +61,7 @@ faltaban, todos en la ESQUINA del marco de foco.
2. **Los desplazamientos `-0.625rem` de cada esquina NO son knobs**: colocan la
escuadra justo fuera del marco y su valor se deriva del tamaño y el trazo —
son construcción de la forma, como las proporciones del spinner.
3. **`border-color` y `glow-color` son el mismo acento en dos capas** (el trazo
3. **`border-fg` y `glow-fg` son el mismo acento en dos capas** (el trazo
y su resplandor via `drop-shadow`), y los dos ya leen el mismo default. Se
declaran por separado a propósito: un tema puede querer el halo de otro tono
que el borde.

@ -3,14 +3,14 @@
**Estado: EN EJECUCIÓN — F0 y F1 CERRADAS · F2 en curso, bloque F2-B CERRADO
con su revisión adversarial pasada (2026-08-22).** Alcance global **56 %** (33 % al abrir el eje, 45 % tras F2-A, 50 % tras F2-B,
y **+6 puntos al arreglar la MEDICIÓN**, no el código: ver abajo). Sin contrato
**29**; al 100 % **14**; alcance <20 % **20**.
**25**; al 100 % **16**; alcance <20 % **19**.
## LO PRIMERO AL ENTRAR (cinco minutos, en este orden)
1. **Comprueba que el suelo no se ha movido**:
```bash
node --import tsx/esm scripts/theming-census.ts # 162 · 5.187 · 2.617 (56 %) · 29 sin contrato
node --import tsx/esm scripts/theming-census.ts # 162 · 5.187 · 2.634 (56 %) · 25 sin contrato
node --import tsx/esm scripts/theming-census.ts --names # DESVIADAS 0 — la gramática se mantiene
```
@ -64,17 +64,52 @@ tocar una línea de su código**.
Consecuencia: **cualquier cifra anterior al 2026-08-22 no es comparable con las
de ahora.** Las de este handoff ya son las nuevas.
### 3. La cola que queda, por alcance
### 3. Lo que dejó la sesión del 22 (24 componentes en F2-B, todos con 0 diffs)
`grid-list` 85 · `textarea` 80 · `tree-view` 92 · `code-block` 81 ·
`card-group` 90 · `spinner` 70 · `picker-shell` 95 · `link-preview` 100 ·
`drag-drop` 89 · `kbd` 86 · `link` 36 · `code` 100 · `virtual-list` 67 ·
`virtual-grid` 73 · `skeleton` 45 · `label` 100 · `announce` 88 ·
`clipboard` 63 · `scroll-frames` 33 · `mark` 60 · `menu-dial` 38 · `knob` 75 ·
`skin-media-player` 22 · `text-circular` 100 · `text-focus` 100. Más cinco
adjudicados como **0 % estructural** (`aspect-ratio`, `text-blur`, `cascade`,
`motion`, `date-picker`), la revisión adversarial §7.7, el arreglo del censo y
el test del suelo.
**Tres cosas que enseñó y conviene tener delante al seguir:**
1. **La propuesta §4 generada falla de cuatro maneras.** Hereda el
incumplimiento del CSS de partida (si ya violaba `recipe-css-contract`, lo
repite); infla hasta 4× (71 tokens para 23 knobs en `spinner`); nombra por
el primer selector de la regla y no por el nodo pintado (llamaba `root-bg` a
una guía de indentación); y **usa el slot `color` donde la gramática firmada
exige `fg`** — R-5.3 lo caza, pero después de escribirlo.
2. **Declarar un público «de facto» puede MATAR una escala.** Varios
componentes consumen `var(--c-x, <default>)` sin declarar `--c-x`. Si detrás
del fallback hay un privado por talla (`knob`), declarar el público lo mata:
el público va primero y gana siempre. Hay que subir la escala al TSC. Si no
lo hay (`text-circular`, `text-focus`), declarar es seguro.
3. **Cuenta los nodos que ve la sonda antes de creerte un gate verde.** Cuatro
componentes miden UN nodo, `picker-shell` medía CERO. Y el centinela tiene
tres puntos ciegos ya medidos: congela transiciones, su valor grande se capa
contra `min()`, y no ve lo que la demo no monta.
### 4. La cola que queda, por alcance
| componente | knobs | nota |
| --- | ---: | --- |
| `palabras` | 471 (22 %) | **el mayor del catálogo**, sin tocar; D-TH.3 decide si entra |
| `palabras` | 471 (22 %) | **el mayor del catálogo con diferencia**, sin tocar; D-TH.3 decide si entra |
| `field-langs` | 41 | espera el **mandato Field** (firma 2), que NO es tokenización: manda que los x-field incorporen el wrapper Field — cambia composición y mueve píxel |
| `avatar` | 36 (36 %) | |
| `mockup` | 29 (14 %) | además sale NEEDS-WORK en `component:audit`, preexistente |
| `knob` | 27 (29 %) | |
| `skin-media-player` | 11 | el del rojo conocido de la suite eidos |
| `text-*` varios | 4-9 | `text-scramble` 50 %, `text-focus` 63 %, `text-gradient` 67 %, `text-circular` 83 % |
| `mockup` | 29 (38 %) | ⚠ **sin ruta de demo (404)**, como `picker-shell`: sin sonda ni guard. Y sale NEEDS-WORK en el audit, preexistente |
| `text-gradient` | 9 (67 %) | el siguiente ejecutable sin decisión: mismo patrón que `text-focus`/`text-circular` |
| `text-scramble` | 4 (50 %) | sus dos knobs son el `1px` de sr-only — **0 % estructural**, como `text-blur`: escribir el veredicto, no tokens |
| `chronos` | 245 (1 %) | el segundo mayor; sin abrir |
| `result` · `banner` · … | varios | ver el censo, `reach < 20 %` = 19 |
`avatar` ya está al **75 %** y `knob` al 75 % (ambos hechos). `heading` /
`text` / `display` son primitivos tipográficos: su superficie es `--style-*` y
el censo los saca del ratio. `range-calendar` / `month-grid` / `year-grid`
están a 0 % **honesto** (consumen `calendar-surface`).
`heading` / `text` / `display` son primitivos tipográficos: su superficie es
`--style-*` y el censo ya los saca del ratio. `range-calendar` / `month-grid` /
@ -82,7 +117,7 @@ de ahora.** Las de este handoff ya son las nuevas.
`alert-dialog`, `css-field`, `mask-field`, `number-field`, `highlight`, `stack`,
`wrap`, `auto-grid` tienen **cero knobs**: no hay nada que tokenizar.
### 4. Lo que espera TU FIRMA (todo medido, nada bloquea la cola)
### 5. Lo que espera TU FIRMA (todo medido, nada bloquea la cola)
1. **El plano `overlay` impone tipografía a VEINTE componentes**
(`font-family` + `line-height` junto a superficie/borde/sombra). ¿Un plano

@ -90,7 +90,7 @@ todo DECLARAR lo que ya se consumía, más el `radius` que faltaba.
**Aquí declarar es seguro, a diferencia de `knob`**: no hay privado por talla
detrás del fallback, así que el público no puede matar una escala.
`color: currentColor` es correcto como token — una custom property no resuelve
`fg: currentColor` es correcto como token — una custom property no resuelve
`currentColor` hasta el punto de uso, así que sigue tomando la tinta del nodo y
no la del `:root` (verificado con el diff). Y `char-transition` guarda una
transición COMPLETA (`all 0.5s cubic-bezier(0, 0, 0, 1)`): es el gesto del

@ -16,7 +16,7 @@
height: var(--text-circular-size);
border-radius: var(--text-circular-radius);
font-weight: var(--text-circular-weight);
color: var(--text-circular-color);
color: var(--text-circular-fg);
text-align: center;
cursor: pointer;
transform-origin: center;

@ -92,7 +92,7 @@ un knob, el grosor del trazo otro y el radio el tercero. Los desplazamientos
`-0.625rem` **no** son knobs: colocan la escuadra justo fuera del marco y se
derivan del tamaño y el trazo.
`border-color` y `glow-color` son el mismo acento en dos capas —el trazo y su
`border-fg` y `glow-fg` son el mismo acento en dos capas —el trazo y su
resplandor vía `drop-shadow`— y se declaran por separado a propósito: un tema
puede querer el halo de otro tono que el borde.

@ -38,9 +38,9 @@
position: absolute;
width: var(--text-focus-corner-size);
height: var(--text-focus-corner-size);
border: var(--text-focus-corner-width) solid var(--text-focus-border-color);
border: var(--text-focus-corner-width) solid var(--text-focus-border-fg);
border-radius: var(--text-focus-corner-radius);
filter: drop-shadow(0 0 4px var(--text-focus-glow-color));
filter: drop-shadow(0 0 4px var(--text-focus-glow-fg));
}
[data-text-focus-corner='tl'] {
top: -0.625rem;

@ -4100,12 +4100,12 @@
--text-focus-corner-size: 1rem;
--text-focus-corner-width: 3px;
--text-focus-corner-radius: 3px;
--text-focus-border-color: var(--color-primary-solid);
--text-focus-glow-color: var(--color-primary-solid);
--text-focus-border-fg: var(--color-primary-solid);
--text-focus-glow-fg: var(--color-primary-solid);
--text-circular-size: 12.5rem;
--text-circular-radius: var(--radius-full);
--text-circular-weight: 900;
--text-circular-color: currentColor;
--text-circular-fg: currentColor;
--text-circular-font-size: 1.5rem;
--text-circular-char-transition: all 0.5s cubic-bezier(0, 0, 0, 1);
--knob-gap-sm: var(--size-sm-gap);

@ -6661,14 +6661,14 @@ export const THEME_BASE_RECIPE_TOKENS = defineRecipes({
'corner-radius': '3px',
// The stroke and its halo: same accent, two layers, declared apart so a
// theme can tint the glow differently from the border.
'border-color': 'var(--color-primary-solid)',
'glow-color': 'var(--color-primary-solid)'
'border-fg': 'var(--color-primary-solid)',
'glow-fg': 'var(--color-primary-solid)'
},
'text-circular': {
size: '12.5rem',
radius: 'var(--radius-full)',
weight: '900',
color: 'currentColor',
fg: 'currentColor',
'font-size': '1.5rem',
// The character's turn, kept verbatim: it is a gesture, not four axes.
'char-transition': 'all 0.5s cubic-bezier(0, 0, 0, 1)'

Loading…
Cancel
Save

Powered by TurnKey Linux.