docs(theming): la auditoría de alcance de tema, componente a componente, con su propuesta
El censo medía el eje y no lo explicaba: 5.205 knobs en dos tablas del plan no
dicen QUÉ knob de QUÉ línea no alcanza un tema, ni qué token habría que crear.
Ahora `theming-census.ts --report` escribe la auditoría entera bajo
`docs/audit/theming/`: un README con la vista de conjunto y 170 fichas — 162
recetas con CSS + 8 componentes sin receta, el árbol completo de
`eidos/components/`.
Cada ficha de receta: knobs fuera de alcance con fichero:línea Y selector
(agrupados por clase), sistema transversal aparte, los privados con la columna
que decide («¿deriva de un público?»), y una PROPUESTA de corrección — el token
a declarar en `base.ts` con su valor VERBATIM y su scope TSC. La propuesta
deriva los nombres de recipe-contract §1 y theming §6.7; donde la doctrina no
decide, marca `⚠ decisión` en vez de inventar. Y no propone acuñar lo que la
doctrina prohíbe: lo que posee una capa compartida, el foco, la capa de estado,
un token prestado de otra receta, un shorthand o un eje físico.
Las 8 fichas sin receta dicen —medido, no supuesto— dónde vive su visual: el
componente que componen (icon-button → button), la capa que consumen (affix →
viewport-placement) o la receta ajena que pinta sus attrs (svg → badge/button).
Defectos del instrumento corregidos en el mismo pase, todos encontrados
mirando la salida: un `@import` pegado al primer selector se comía 2 knobs de
color-picker (el suelo del censo no puede moverse); `:not(:disabled)` se leía
como estado y producía `hover-disabled-*`; un knob que lee un privado se
proponía a sí mismo en vez de resolverse por talla; `--icon-size-sm` se
reportaba como préstamo del componente `icon` (ahora el préstamo se verifica
contra las claves del dueño en `base.ts`); y el default de talla salía sin
nombrar en vez de `-md`.
Verificación: censo global idéntico al suelo publicado (5205 · 1621/33% · 856 ·
1880 · 614 · 234) y COMPONENTE A COMPONENTE contra la tabla §9 del plan — 0
diferencias en 162 · regenerar dos veces da el árbol idéntico · el bloque de
veredicto escrito a mano sobrevive · docs:check 0 errores sobre 813 docs ·
prettier limpio (el árbol generado entra en .prettierignore junto a
eidos/generated).
Las 10 primeras fichas llevan ya su veredicto de revisión: análisis correcto en
las 10, propuesta apta en 2 (gradient-builder como piloto, combobox con cinco
correcciones — dos de ellas evitaban romper el default), y 5 que no se
tokenizan en solitario porque son alias de --calendar-*/--field-* y esperan la
decisión de familia. Cuatro destaparon privados con prefijo ajeno o abreviado
declarados en su propio CSS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
# palabras — alcance de tema: análisis y propuesta
> Generado por `node --import tsx/esm scripts/theming-census.ts --report`.
> Lo **medido** y la **propuesta** se regeneran; el **Veredicto** (§5) se conserva.
> Vista de conjunto: [README](./README.md) · método y protocolo:
> [`PLAN-theming.md`](../../process/PLAN-theming.md) §1, §2, §7.
docs(theming): 164 fichas regeneradas — dos perdían prosa medida, y el generador es el culpable
Una sesión regeneró todas las fichas de docs/audit/theming con el --report del
censo y las dejó sucias en el árbol. Antes de commitearlas las clasifiqué una a
una en vez de mirar la cifra:
- 155 sólo cambiaban la FECHA de medida. Inocuo, y correcto: el censo corrió
hoy.
- 7 traían cifras nuevas y buenas (collapsible y toolbar, que acaban de cerrar)
o retiraban una propuesta §4 ya cumplida. Mejora.
- 2 —chat-log y chat-composer— BORRABAN prosa medida: donde un humano escribió
«_Ninguno_ — los cuatro que había (el padding-block del divisor, el radio de
foco de la fila de evento…) están cosidos», la plantilla dejaba «_Ninguno._»,
y en chat-composer se llevaba además el bloque de las cuatro declaraciones
retiradas por muertas.
Esas dos van cosidas: el cuerpo de HEAD con la línea de cabecera regenerada.
El resto entra tal cual.
Que la regeneración sea mayoritariamente buena y ocasionalmente destructiva es
el peor reparto posible, porque nadie la mira. Registrado en §13 con su
arreglo: extender los marcadores tipo veredicto:end a cualquier bloque que un
humano haya ampliado, o que el generador respete una línea que no empiece por
su propia plantilla. Mientras tanto, regenerar fichas y commitear sin leer el
diff es una pérdida de datos silenciosa.
Y con él, la hermana que reportó una sesión de la tanda: snapshot-y-restaura
sobre un directorio COMPARTIDO pisa a quien escriba en medio. Dos sesiones
hicieron cp -r de docs/audit/theming y la segunda restauró desde un snapshot
anterior al trabajo de la primera, devolviéndole sus veredictos a «pendiente» a
media faena. El árbol de trabajo también es compartido: respalda por FICHERO
tocado, nunca por directorio.
Quedan fuera a propósito las fichas de chat-message y tags-input: sus sesiones
siguen trabajando.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- **Medido**: 2026-08-24 · **Alcance** : **22%** — 103 de 463 knobs por token público
tooling(theming): el censo aprende a leer la válvula del canon — clase `exception`
Global 58 % → **59 %** sin tocar una línea de CSS: 54 knobs que eran deuda
resultan ser desviaciones que el canon ya había firmado.
`recipe-contract` §3 dice que una desviación anotada `/* literal: <razón> */`
EN SU PROPIA DECLARACIÓN es válida, y `component-audit` la honra desde siempre
(`declarationWindow` + `/literal:/i` en R-2.1, R-2.6 y R-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 literales
sin excusa. Dos instrumentos, un canon, dos respuestas — y la que mandaba era la
del que no sabía leerlo.
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, que
su README documenta como decisión — «No 5× duplicated scale»), `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.
Detalles que costaron medición:
- **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. Se comprueban
todas las líneas que abarca la declaración.
- **`strip()` blanquea en el sitio** (sustituye por espacios, conserva los
saltos), así que el cuerpo despojado y el crudo quedan alineados línea a línea
y basta con guardar el crudo al lado.
- Muta-prueba: retirar una anotación de `prose` mueve el knob de `exception` a
`literal` (21 → 20) y el conteo vuelve al restaurarla.
Efecto colateral bueno: cada ficha gana una **§1.4 «Excepciones firmadas»** que
las LISTA con su razón. Estaban escritas en el CSS y no se leían desde ninguna
parte; ahora la ficha del componente las enseña, que es donde se decide si una
sigue siendo cierta.
Las 163 fichas cambian porque la plantilla cambia (sección nueva + la línea de
reparto); el README de la auditoría gana la fila de la clase y la nota de que
`system` y `exception` quedan fuera del denominador.
Guards: `--names` 4.105 claves, DESVIADAS 0 · component-audit PASS · docs:check
0 · `check` con 72 errores globales y 0 en los ficheros tocados.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- **Knobs de apariencia**: 468 — público 103 · privado 1 · global 272 · literal 87 · sistema 5 · excepción 3 _(los dos últimos, fuera del ratio)_
docs(theming): la auditoría de alcance de tema, componente a componente, con su propuesta
El censo medía el eje y no lo explicaba: 5.205 knobs en dos tablas del plan no
dicen QUÉ knob de QUÉ línea no alcanza un tema, ni qué token habría que crear.
Ahora `theming-census.ts --report` escribe la auditoría entera bajo
`docs/audit/theming/`: un README con la vista de conjunto y 170 fichas — 162
recetas con CSS + 8 componentes sin receta, el árbol completo de
`eidos/components/`.
Cada ficha de receta: knobs fuera de alcance con fichero:línea Y selector
(agrupados por clase), sistema transversal aparte, los privados con la columna
que decide («¿deriva de un público?»), y una PROPUESTA de corrección — el token
a declarar en `base.ts` con su valor VERBATIM y su scope TSC. La propuesta
deriva los nombres de recipe-contract §1 y theming §6.7; donde la doctrina no
decide, marca `⚠ decisión` en vez de inventar. Y no propone acuñar lo que la
doctrina prohíbe: lo que posee una capa compartida, el foco, la capa de estado,
un token prestado de otra receta, un shorthand o un eje físico.
Las 8 fichas sin receta dicen —medido, no supuesto— dónde vive su visual: el
componente que componen (icon-button → button), la capa que consumen (affix →
viewport-placement) o la receta ajena que pinta sus attrs (svg → badge/button).
Defectos del instrumento corregidos en el mismo pase, todos encontrados
mirando la salida: un `@import` pegado al primer selector se comía 2 knobs de
color-picker (el suelo del censo no puede moverse); `:not(:disabled)` se leía
como estado y producía `hover-disabled-*`; un knob que lee un privado se
proponía a sí mismo en vez de resolverse por talla; `--icon-size-sm` se
reportaba como préstamo del componente `icon` (ahora el préstamo se verifica
contra las claves del dueño en `base.ts`); y el default de talla salía sin
nombrar en vez de `-md`.
Verificación: censo global idéntico al suelo publicado (5205 · 1621/33% · 856 ·
1880 · 614 · 234) y COMPONENTE A COMPONENTE contra la tabla §9 del plan — 0
diferencias en 162 · regenerar dos veces da el árbol idéntico · el bloque de
veredicto escrito a mano sobrevive · docs:check 0 errores sobre 813 docs ·
prettier limpio (el árbol generado entra en .prettierignore junto a
eidos/generated).
Las 10 primeras fichas llevan ya su veredicto de revisión: análisis correcto en
las 10, propuesta apta en 2 (gradient-builder como piloto, combobox con cinco
correcciones — dos de ellas evitaban romper el default), y 5 que no se
tokenizan en solitario porque son alias de --calendar-*/--field-* y esperan la
decisión de familia. Cuatro destaparon privados con prefijo ajeno o abreviado
declarados en su propio CSS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- **Contrato hoy** (`lib/recipes/base.ts`): **sin entrada en `base.ts`**
- **Eje `size` **: no · **ficheros** : `palabras-chrome.css` , `palabras.css`
## 1. Knobs fuera de alcance
### 1.1 Directo a primitivo global (272)
| # | fichero:línea | selector | propiedad | valor |
| ---: | --- | --- | --- | --- |
| 1 | `palabras-chrome.css:77` | `[data-palabras-doc] [data-palabras-handle], [data-palabras-canvas] [data-palabras-column-inserter] [data-palabras-column-inserter-button]` | `background` | `var(--color-surface-default)` |
| 2 | `palabras-chrome.css:78` | `[data-palabras-doc] [data-palabras-handle], [data-palabras-canvas] [data-palabras-column-inserter] [data-palabras-column-inserter-button]` | `border` | `1px solid var(--color-border-default)` |
| 3 | `palabras-chrome.css:79` | `[data-palabras-doc] [data-palabras-handle], [data-palabras-canvas] [data-palabras-column-inserter] [data-palabras-column-inserter-button]` | `border-radius` | `var(--radius-full)` |
| 4 | `palabras-chrome.css:80` | `[data-palabras-doc] [data-palabras-handle], [data-palabras-canvas] [data-palabras-column-inserter] [data-palabras-column-inserter-button]` | `box-shadow` | `var(--shadow-2)` |
| 5 | `palabras-chrome.css:81` | `[data-palabras-doc] [data-palabras-handle], [data-palabras-canvas] [data-palabras-column-inserter] [data-palabras-column-inserter-button]` | `color` | `var(--color-content-muted)` |
| 6 | `palabras-chrome.css:87` | `[data-palabras-doc] [data-button][data-palabras-handle]:hover:not([data-disabled]), [data-palabras-canvas] [data-palabras-column-inserter] [data-button][data-palabras-column-inserter-button]:hover:not([data-disabled])` | `background` | `var(--color-surface-default)` |
| 7 | `palabras-chrome.css:88` | `[data-palabras-doc] [data-button][data-palabras-handle]:hover:not([data-disabled]), [data-palabras-canvas] [data-palabras-column-inserter] [data-button][data-palabras-column-inserter-button]:hover:not([data-disabled])` | `border-color` | `var(--color-primary-border)` |
| 8 | `palabras-chrome.css:89` | `[data-palabras-doc] [data-button][data-palabras-handle]:hover:not([data-disabled]), [data-palabras-canvas] [data-palabras-column-inserter] [data-button][data-palabras-column-inserter-button]:hover:not([data-disabled])` | `color` | `var(--color-primary-text)` |
| 9 | `palabras-chrome.css:108` | `[data-palabras-menubar]` | `gap` | `var(--space-1)` |
feat(color)!: una palabra, un significado - primary/secondary son SIEMPRE jerarquia
La homonimia muere: `primary`/`secondary` significan JERARQUIA DE MARCA en el
catalogo ENTERO, tambien dentro de los seis primitivos de tinta (text, heading,
display, code, label, s-text). El paso de tinta del 82 % se llama `subtle` -
PROP y TOKEN, sin excepcion: el nombre es el contrato en el artefacto (la misma
ley que la FIRMA B' y la 12.9; se rechazo por escrito la via "solo el prop con
tabla de traduccion" - las excepciones legitimas son las FIRMADAS con razon,
no las inventadas al decidir para abaratar).
- Los seis CONTENT_INK, IDENTICOS: {subtle, muted, disabled, on-solid}; el
nivel-1 es el DEFAULT sin prop. `label` gana `on-solid` (cierra la
divergencia de familia registrada en e4fa616e5).
- Renombre completo: --color-content-secondary -> --color-content-subtle y la
clave de config content.secondary -> content.subtle (RUPTURA de API de
tema). 355 referencias por patrones acotados; la raiz SIN prefijo
(cssVar('color-content-secondary'), render-css.ts) incluida; en grafito.ts
conviven tres claves `subtle` (content/border/shadow) y solo cambio content.
El generado, reproducido BYTE A BYTE aplicando solo el renombre al anterior.
- Codemod value-preserving: 11 call sites (6 secondary->subtle incl.
expresiones y ternarias; 5 primary->fuera, incl. TRES defaults de prop) con
la condicion ROJA caracterizada (--style-caption-color es el UNICO estilo
cuya tinta default no es primary; los 5 sitios caen en ramas body). alpha/
(untracked, TERMINATED) fuera.
- Las 6 demos migradas al vocabulario nuevo (s-text: CERO cambios, no tiene
lista de tinta); label arranca en el default y pinta IDENTICO (contrafactual
medido: el estado viejo habria pintado el morado de marca).
- Neutra en pixel, MEDIDO: nivel 1 ESTRICTO CERO en 71.200 valores (blocks
enteros, s-text entero, subarboles data-*); nivel 2: 31 diffs, todos
trazados a las ediciones firmadas del harness (anchos de chips, reindexado
de la lista de label con las tintas supervivientes byte a byte). Total
171.712 valores + 59.072 de re-corridas a 0 de ruido.
- Guards: CONTENT_INK identicos entre los seis y sin nombres de rol (mutacion:
muerde), y el generado sin rastro del token viejo con las 6 definiciones del
nuevo. Dos cronicas fechadas en docs/old-deprecated, intactas a proposito.
- Docs: changelog 54 - reference (eje de tinta) - next-features 13 (divergencia
de label RESUELTA).
Supervision: verificador independiente pre-firma (dos claims MURIERON en
verificacion antes de tocar codigo), tres agentes en fases (censo+baseline ->
implementacion+codemod -> demos -> verificacion de dos niveles -> docs).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
| 10 | `palabras-chrome.css:117` | `[data-palabras-delete]` | `color` | `var(--color-content-subtle)` |
docs(theming): la auditoría de alcance de tema, componente a componente, con su propuesta
El censo medía el eje y no lo explicaba: 5.205 knobs en dos tablas del plan no
dicen QUÉ knob de QUÉ línea no alcanza un tema, ni qué token habría que crear.
Ahora `theming-census.ts --report` escribe la auditoría entera bajo
`docs/audit/theming/`: un README con la vista de conjunto y 170 fichas — 162
recetas con CSS + 8 componentes sin receta, el árbol completo de
`eidos/components/`.
Cada ficha de receta: knobs fuera de alcance con fichero:línea Y selector
(agrupados por clase), sistema transversal aparte, los privados con la columna
que decide («¿deriva de un público?»), y una PROPUESTA de corrección — el token
a declarar en `base.ts` con su valor VERBATIM y su scope TSC. La propuesta
deriva los nombres de recipe-contract §1 y theming §6.7; donde la doctrina no
decide, marca `⚠ decisión` en vez de inventar. Y no propone acuñar lo que la
doctrina prohíbe: lo que posee una capa compartida, el foco, la capa de estado,
un token prestado de otra receta, un shorthand o un eje físico.
Las 8 fichas sin receta dicen —medido, no supuesto— dónde vive su visual: el
componente que componen (icon-button → button), la capa que consumen (affix →
viewport-placement) o la receta ajena que pinta sus attrs (svg → badge/button).
Defectos del instrumento corregidos en el mismo pase, todos encontrados
mirando la salida: un `@import` pegado al primer selector se comía 2 knobs de
color-picker (el suelo del censo no puede moverse); `:not(:disabled)` se leía
como estado y producía `hover-disabled-*`; un knob que lee un privado se
proponía a sí mismo en vez de resolverse por talla; `--icon-size-sm` se
reportaba como préstamo del componente `icon` (ahora el préstamo se verifica
contra las claves del dueño en `base.ts`); y el default de talla salía sin
nombrar en vez de `-md`.
Verificación: censo global idéntico al suelo publicado (5205 · 1621/33% · 856 ·
1880 · 614 · 234) y COMPONENTE A COMPONENTE contra la tabla §9 del plan — 0
diferencias en 162 · regenerar dos veces da el árbol idéntico · el bloque de
veredicto escrito a mano sobrevive · docs:check 0 errores sobre 813 docs ·
prettier limpio (el árbol generado entra en .prettierignore junto a
eidos/generated).
Las 10 primeras fichas llevan ya su veredicto de revisión: análisis correcto en
las 10, propuesta apta en 2 (gradient-builder como piloto, combobox con cinco
correcciones — dos de ellas evitaban romper el default), y 5 que no se
tokenizan en solitario porque son alias de --calendar-*/--field-* y esperan la
decisión de familia. Cuatro destaparon privados con prefijo ajeno o abreviado
declarados en su propio CSS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| 11 | `palabras-chrome.css:120` | `[data-palabras-delete]:hover:not(:disabled)` | `color` | `var(--color-threat-solid, crimson)` |
| 12 | `palabras-chrome.css:126` | `[data-palabras-menubar-crumbs]` | `padding-inline` | `var(--space-2)` |
| 13 | `palabras-chrome.css:130` | `[data-palabras-menubar-crumbs] [data-breadcrumb-link]` | `font-size` | `var(--font-size-sm)` |
| 14 | `palabras-chrome.css:175` | `[data-palabras-inspector]` | `inline-size` | `min(calc(8rem + var(--pcols) * 9rem), calc(100vw - var(--space-8)))` |
| 15 | `palabras-chrome.css:178` | `[data-palabras-inspector]` | `padding` | `var(--space-3-5) var(--space-4) var(--space-4)` |
| 16 | `palabras-chrome.css:179` | `[data-palabras-inspector]` | `font-family` | `var(--style-label-font-family)` |
| 17 | `palabras-chrome.css:182` | `[data-palabras-inspector] *` | `font-family` | `var(--style-label-font-family)` |
| 18 | `palabras-chrome.css:191` | `[data-palabras-inspector-fields]` | `gap` | `var(--space-3)` |
| 19 | `palabras-chrome.css:223` | `[data-palabras-inspector] [data-palabras-typography]` | `gap` | `var(--space-2-5) var(--space-3)` |
| 20 | `palabras-chrome.css:245` | `[data-palabras-inspector] [data-palabras-adjustments]` | `column-gap` | `var(--space-5)` |
| 21 | `palabras-chrome.css:246` | `[data-palabras-inspector] [data-palabras-adjustments]` | `row-gap` | `var(--space-3)` |
| 22 | `palabras-chrome.css:259` | `[data-palabras-inspector] :is([data-field-control], [data-css-field], [data-textarea-input]), [data-palabras-inspector] [data-select-trigger]` | `background` | `var(--color-surface-muted)` |
| 23 | `palabras-chrome.css:261` | `[data-palabras-inspector] :is([data-field-control], [data-css-field], [data-textarea-input]), [data-palabras-inspector] [data-select-trigger]` | `border-radius` | `var(--radius-md)` |
| 24 | `palabras-chrome.css:267` | `[data-palabras-inspector] [data-field-control]:focus-within, [data-palabras-inspector] [data-css-field]:focus-within, [data-palabras-inspector] [data-textarea][data-focused] [data-textarea-input], [data-palabras-inspector] [data-select-trigger]:focus-visible` | `background` | `var(--color-surface-default)` |
| 25 | `palabras-chrome.css:280` | `[data-palabras-inspector] :is([data-textarea-input], [data-field] input)` | `font-size` | `var(--font-size-sm)` |
| 26 | `palabras-chrome.css:297` | `[data-palabras-handle-menu] [role='menuitem']` | `gap` | `var(--space-2)` |
| 27 | `palabras-chrome.css:335` | `[data-palabras-canvas] [data-palabras-block-drop-line]` | `background` | `var(--color-primary-solid)` |
| 28 | `palabras-chrome.css:342` | `[data-palabras-help]` | `font-size` | `var(--font-size-sm)` |
| 29 | `palabras-chrome.css:343` | `[data-palabras-help]` | `color` | `var(--color-content-muted)` |
| 30 | `palabras-chrome.css:347` | `[data-palabras-help] kbd` | `padding-inline` | `var(--space-1)` |
| 31 | `palabras-chrome.css:348` | `[data-palabras-help] kbd` | `border` | `1px solid var(--color-border-default)` |
| 32 | `palabras-chrome.css:349` | `[data-palabras-help] kbd` | `border-radius` | `var(--radius-sm)` |
| 33 | `palabras-chrome.css:350` | `[data-palabras-help] kbd` | `background` | `var(--color-surface-muted)` |
| 34 | `palabras-chrome.css:358` | `[data-palabras-status]` | `gap` | `var(--space-3)` |
| 35 | `palabras-chrome.css:359` | `[data-palabras-status]` | `padding-block` | `var(--space-1)` |
| 36 | `palabras-chrome.css:360` | `[data-palabras-status]` | `font-size` | `var(--font-size-xs)` |
feat(color)!: una palabra, un significado - primary/secondary son SIEMPRE jerarquia
La homonimia muere: `primary`/`secondary` significan JERARQUIA DE MARCA en el
catalogo ENTERO, tambien dentro de los seis primitivos de tinta (text, heading,
display, code, label, s-text). El paso de tinta del 82 % se llama `subtle` -
PROP y TOKEN, sin excepcion: el nombre es el contrato en el artefacto (la misma
ley que la FIRMA B' y la 12.9; se rechazo por escrito la via "solo el prop con
tabla de traduccion" - las excepciones legitimas son las FIRMADAS con razon,
no las inventadas al decidir para abaratar).
- Los seis CONTENT_INK, IDENTICOS: {subtle, muted, disabled, on-solid}; el
nivel-1 es el DEFAULT sin prop. `label` gana `on-solid` (cierra la
divergencia de familia registrada en e4fa616e5).
- Renombre completo: --color-content-secondary -> --color-content-subtle y la
clave de config content.secondary -> content.subtle (RUPTURA de API de
tema). 355 referencias por patrones acotados; la raiz SIN prefijo
(cssVar('color-content-secondary'), render-css.ts) incluida; en grafito.ts
conviven tres claves `subtle` (content/border/shadow) y solo cambio content.
El generado, reproducido BYTE A BYTE aplicando solo el renombre al anterior.
- Codemod value-preserving: 11 call sites (6 secondary->subtle incl.
expresiones y ternarias; 5 primary->fuera, incl. TRES defaults de prop) con
la condicion ROJA caracterizada (--style-caption-color es el UNICO estilo
cuya tinta default no es primary; los 5 sitios caen en ramas body). alpha/
(untracked, TERMINATED) fuera.
- Las 6 demos migradas al vocabulario nuevo (s-text: CERO cambios, no tiene
lista de tinta); label arranca en el default y pinta IDENTICO (contrafactual
medido: el estado viejo habria pintado el morado de marca).
- Neutra en pixel, MEDIDO: nivel 1 ESTRICTO CERO en 71.200 valores (blocks
enteros, s-text entero, subarboles data-*); nivel 2: 31 diffs, todos
trazados a las ediciones firmadas del harness (anchos de chips, reindexado
de la lista de label con las tintas supervivientes byte a byte). Total
171.712 valores + 59.072 de re-corridas a 0 de ruido.
- Guards: CONTENT_INK identicos entre los seis y sin nombres de rol (mutacion:
muerde), y el generado sin rastro del token viejo con las 6 definiciones del
nuevo. Dos cronicas fechadas en docs/old-deprecated, intactas a proposito.
- Docs: changelog 54 - reference (eje de tinta) - next-features 13 (divergencia
de label RESUELTA).
Supervision: verificador independiente pre-firma (dos claims MURIERON en
verificacion antes de tocar codigo), tres agentes en fases (censo+baseline ->
implementacion+codemod -> demos -> verificacion de dos niveles -> docs).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
| 37 | `palabras-chrome.css:361` | `[data-palabras-status]` | `color` | `var(--color-content-subtle)` |
docs(theming): la auditoría de alcance de tema, componente a componente, con su propuesta
El censo medía el eje y no lo explicaba: 5.205 knobs en dos tablas del plan no
dicen QUÉ knob de QUÉ línea no alcanza un tema, ni qué token habría que crear.
Ahora `theming-census.ts --report` escribe la auditoría entera bajo
`docs/audit/theming/`: un README con la vista de conjunto y 170 fichas — 162
recetas con CSS + 8 componentes sin receta, el árbol completo de
`eidos/components/`.
Cada ficha de receta: knobs fuera de alcance con fichero:línea Y selector
(agrupados por clase), sistema transversal aparte, los privados con la columna
que decide («¿deriva de un público?»), y una PROPUESTA de corrección — el token
a declarar en `base.ts` con su valor VERBATIM y su scope TSC. La propuesta
deriva los nombres de recipe-contract §1 y theming §6.7; donde la doctrina no
decide, marca `⚠ decisión` en vez de inventar. Y no propone acuñar lo que la
doctrina prohíbe: lo que posee una capa compartida, el foco, la capa de estado,
un token prestado de otra receta, un shorthand o un eje físico.
Las 8 fichas sin receta dicen —medido, no supuesto— dónde vive su visual: el
componente que componen (icon-button → button), la capa que consumen (affix →
viewport-placement) o la receta ajena que pinta sus attrs (svg → badge/button).
Defectos del instrumento corregidos en el mismo pase, todos encontrados
mirando la salida: un `@import` pegado al primer selector se comía 2 knobs de
color-picker (el suelo del censo no puede moverse); `:not(:disabled)` se leía
como estado y producía `hover-disabled-*`; un knob que lee un privado se
proponía a sí mismo en vez de resolverse por talla; `--icon-size-sm` se
reportaba como préstamo del componente `icon` (ahora el préstamo se verifica
contra las claves del dueño en `base.ts`); y el default de talla salía sin
nombrar en vez de `-md`.
Verificación: censo global idéntico al suelo publicado (5205 · 1621/33% · 856 ·
1880 · 614 · 234) y COMPONENTE A COMPONENTE contra la tabla §9 del plan — 0
diferencias en 162 · regenerar dos veces da el árbol idéntico · el bloque de
veredicto escrito a mano sobrevive · docs:check 0 errores sobre 813 docs ·
prettier limpio (el árbol generado entra en .prettierignore junto a
eidos/generated).
Las 10 primeras fichas llevan ya su veredicto de revisión: análisis correcto en
las 10, propuesta apta en 2 (gradient-builder como piloto, combobox con cinco
correcciones — dos de ellas evitaban romper el default), y 5 que no se
tokenizan en solitario porque son alias de --calendar-*/--field-* y esperan la
decisión de familia. Cuatro destaparon privados con prefijo ajeno o abreviado
declarados en su propio CSS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| 38 | `palabras-chrome.css:366` | `[data-palabras-outline-trigger]` | `gap` | `var(--space-1)` |
| 39 | `palabras-chrome.css:367` | `[data-palabras-outline-trigger]` | `padding` | `var(--space-1) var(--space-2)` |
| 40 | `palabras-chrome.css:368` | `[data-palabras-outline-trigger]` | `border-radius` | `var(--radius-sm)` |
feat(color)!: una palabra, un significado - primary/secondary son SIEMPRE jerarquia
La homonimia muere: `primary`/`secondary` significan JERARQUIA DE MARCA en el
catalogo ENTERO, tambien dentro de los seis primitivos de tinta (text, heading,
display, code, label, s-text). El paso de tinta del 82 % se llama `subtle` -
PROP y TOKEN, sin excepcion: el nombre es el contrato en el artefacto (la misma
ley que la FIRMA B' y la 12.9; se rechazo por escrito la via "solo el prop con
tabla de traduccion" - las excepciones legitimas son las FIRMADAS con razon,
no las inventadas al decidir para abaratar).
- Los seis CONTENT_INK, IDENTICOS: {subtle, muted, disabled, on-solid}; el
nivel-1 es el DEFAULT sin prop. `label` gana `on-solid` (cierra la
divergencia de familia registrada en e4fa616e5).
- Renombre completo: --color-content-secondary -> --color-content-subtle y la
clave de config content.secondary -> content.subtle (RUPTURA de API de
tema). 355 referencias por patrones acotados; la raiz SIN prefijo
(cssVar('color-content-secondary'), render-css.ts) incluida; en grafito.ts
conviven tres claves `subtle` (content/border/shadow) y solo cambio content.
El generado, reproducido BYTE A BYTE aplicando solo el renombre al anterior.
- Codemod value-preserving: 11 call sites (6 secondary->subtle incl.
expresiones y ternarias; 5 primary->fuera, incl. TRES defaults de prop) con
la condicion ROJA caracterizada (--style-caption-color es el UNICO estilo
cuya tinta default no es primary; los 5 sitios caen en ramas body). alpha/
(untracked, TERMINATED) fuera.
- Las 6 demos migradas al vocabulario nuevo (s-text: CERO cambios, no tiene
lista de tinta); label arranca en el default y pinta IDENTICO (contrafactual
medido: el estado viejo habria pintado el morado de marca).
- Neutra en pixel, MEDIDO: nivel 1 ESTRICTO CERO en 71.200 valores (blocks
enteros, s-text entero, subarboles data-*); nivel 2: 31 diffs, todos
trazados a las ediciones firmadas del harness (anchos de chips, reindexado
de la lista de label con las tintas supervivientes byte a byte). Total
171.712 valores + 59.072 de re-corridas a 0 de ruido.
- Guards: CONTENT_INK identicos entre los seis y sin nombres de rol (mutacion:
muerde), y el generado sin rastro del token viejo con las 6 definiciones del
nuevo. Dos cronicas fechadas en docs/old-deprecated, intactas a proposito.
- Docs: changelog 54 - reference (eje de tinta) - next-features 13 (divergencia
de label RESUELTA).
Supervision: verificador independiente pre-firma (dos claims MURIERON en
verificacion antes de tocar codigo), tres agentes en fases (censo+baseline ->
implementacion+codemod -> demos -> verificacion de dos niveles -> docs).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
| 41 | `palabras-chrome.css:369` | `[data-palabras-outline-trigger]` | `color` | `var(--color-content-subtle)` |
docs(theming): la auditoría de alcance de tema, componente a componente, con su propuesta
El censo medía el eje y no lo explicaba: 5.205 knobs en dos tablas del plan no
dicen QUÉ knob de QUÉ línea no alcanza un tema, ni qué token habría que crear.
Ahora `theming-census.ts --report` escribe la auditoría entera bajo
`docs/audit/theming/`: un README con la vista de conjunto y 170 fichas — 162
recetas con CSS + 8 componentes sin receta, el árbol completo de
`eidos/components/`.
Cada ficha de receta: knobs fuera de alcance con fichero:línea Y selector
(agrupados por clase), sistema transversal aparte, los privados con la columna
que decide («¿deriva de un público?»), y una PROPUESTA de corrección — el token
a declarar en `base.ts` con su valor VERBATIM y su scope TSC. La propuesta
deriva los nombres de recipe-contract §1 y theming §6.7; donde la doctrina no
decide, marca `⚠ decisión` en vez de inventar. Y no propone acuñar lo que la
doctrina prohíbe: lo que posee una capa compartida, el foco, la capa de estado,
un token prestado de otra receta, un shorthand o un eje físico.
Las 8 fichas sin receta dicen —medido, no supuesto— dónde vive su visual: el
componente que componen (icon-button → button), la capa que consumen (affix →
viewport-placement) o la receta ajena que pinta sus attrs (svg → badge/button).
Defectos del instrumento corregidos en el mismo pase, todos encontrados
mirando la salida: un `@import` pegado al primer selector se comía 2 knobs de
color-picker (el suelo del censo no puede moverse); `:not(:disabled)` se leía
como estado y producía `hover-disabled-*`; un knob que lee un privado se
proponía a sí mismo en vez de resolverse por talla; `--icon-size-sm` se
reportaba como préstamo del componente `icon` (ahora el préstamo se verifica
contra las claves del dueño en `base.ts`); y el default de talla salía sin
nombrar en vez de `-md`.
Verificación: censo global idéntico al suelo publicado (5205 · 1621/33% · 856 ·
1880 · 614 · 234) y COMPONENTE A COMPONENTE contra la tabla §9 del plan — 0
diferencias en 162 · regenerar dos veces da el árbol idéntico · el bloque de
veredicto escrito a mano sobrevive · docs:check 0 errores sobre 813 docs ·
prettier limpio (el árbol generado entra en .prettierignore junto a
eidos/generated).
Las 10 primeras fichas llevan ya su veredicto de revisión: análisis correcto en
las 10, propuesta apta en 2 (gradient-builder como piloto, combobox con cinco
correcciones — dos de ellas evitaban romper el default), y 5 que no se
tokenizan en solitario porque son alias de --calendar-*/--field-* y esperan la
decisión de familia. Cuatro destaparon privados con prefijo ajeno o abreviado
declarados en su propio CSS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| 42 | `palabras-chrome.css:370` | `[data-palabras-outline-trigger]` | `font-size` | `var(--font-size-xs)` |
| 43 | `palabras-chrome.css:374` | `[data-palabras-outline-trigger]:hover:not(:disabled)` | `background` | `var(--color-surface-muted)` |
| 44 | `palabras-chrome.css:401` | `[data-palabras-outline-item]` | `padding` | `var(--space-1) var(--space-2)` |
| 45 | `palabras-chrome.css:402` | `[data-palabras-outline-item]` | `border-radius` | `var(--radius-sm)` |
feat(color)!: una palabra, un significado - primary/secondary son SIEMPRE jerarquia
La homonimia muere: `primary`/`secondary` significan JERARQUIA DE MARCA en el
catalogo ENTERO, tambien dentro de los seis primitivos de tinta (text, heading,
display, code, label, s-text). El paso de tinta del 82 % se llama `subtle` -
PROP y TOKEN, sin excepcion: el nombre es el contrato en el artefacto (la misma
ley que la FIRMA B' y la 12.9; se rechazo por escrito la via "solo el prop con
tabla de traduccion" - las excepciones legitimas son las FIRMADAS con razon,
no las inventadas al decidir para abaratar).
- Los seis CONTENT_INK, IDENTICOS: {subtle, muted, disabled, on-solid}; el
nivel-1 es el DEFAULT sin prop. `label` gana `on-solid` (cierra la
divergencia de familia registrada en e4fa616e5).
- Renombre completo: --color-content-secondary -> --color-content-subtle y la
clave de config content.secondary -> content.subtle (RUPTURA de API de
tema). 355 referencias por patrones acotados; la raiz SIN prefijo
(cssVar('color-content-secondary'), render-css.ts) incluida; en grafito.ts
conviven tres claves `subtle` (content/border/shadow) y solo cambio content.
El generado, reproducido BYTE A BYTE aplicando solo el renombre al anterior.
- Codemod value-preserving: 11 call sites (6 secondary->subtle incl.
expresiones y ternarias; 5 primary->fuera, incl. TRES defaults de prop) con
la condicion ROJA caracterizada (--style-caption-color es el UNICO estilo
cuya tinta default no es primary; los 5 sitios caen en ramas body). alpha/
(untracked, TERMINATED) fuera.
- Las 6 demos migradas al vocabulario nuevo (s-text: CERO cambios, no tiene
lista de tinta); label arranca en el default y pinta IDENTICO (contrafactual
medido: el estado viejo habria pintado el morado de marca).
- Neutra en pixel, MEDIDO: nivel 1 ESTRICTO CERO en 71.200 valores (blocks
enteros, s-text entero, subarboles data-*); nivel 2: 31 diffs, todos
trazados a las ediciones firmadas del harness (anchos de chips, reindexado
de la lista de label con las tintas supervivientes byte a byte). Total
171.712 valores + 59.072 de re-corridas a 0 de ruido.
- Guards: CONTENT_INK identicos entre los seis y sin nombres de rol (mutacion:
muerde), y el generado sin rastro del token viejo con las 6 definiciones del
nuevo. Dos cronicas fechadas en docs/old-deprecated, intactas a proposito.
- Docs: changelog 54 - reference (eje de tinta) - next-features 13 (divergencia
de label RESUELTA).
Supervision: verificador independiente pre-firma (dos claims MURIERON en
verificacion antes de tocar codigo), tres agentes en fases (censo+baseline ->
implementacion+codemod -> demos -> verificacion de dos niveles -> docs).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
| 46 | `palabras-chrome.css:403` | `[data-palabras-outline-item]` | `color` | `var(--color-content-subtle)` |
docs(theming): la auditoría de alcance de tema, componente a componente, con su propuesta
El censo medía el eje y no lo explicaba: 5.205 knobs en dos tablas del plan no
dicen QUÉ knob de QUÉ línea no alcanza un tema, ni qué token habría que crear.
Ahora `theming-census.ts --report` escribe la auditoría entera bajo
`docs/audit/theming/`: un README con la vista de conjunto y 170 fichas — 162
recetas con CSS + 8 componentes sin receta, el árbol completo de
`eidos/components/`.
Cada ficha de receta: knobs fuera de alcance con fichero:línea Y selector
(agrupados por clase), sistema transversal aparte, los privados con la columna
que decide («¿deriva de un público?»), y una PROPUESTA de corrección — el token
a declarar en `base.ts` con su valor VERBATIM y su scope TSC. La propuesta
deriva los nombres de recipe-contract §1 y theming §6.7; donde la doctrina no
decide, marca `⚠ decisión` en vez de inventar. Y no propone acuñar lo que la
doctrina prohíbe: lo que posee una capa compartida, el foco, la capa de estado,
un token prestado de otra receta, un shorthand o un eje físico.
Las 8 fichas sin receta dicen —medido, no supuesto— dónde vive su visual: el
componente que componen (icon-button → button), la capa que consumen (affix →
viewport-placement) o la receta ajena que pinta sus attrs (svg → badge/button).
Defectos del instrumento corregidos en el mismo pase, todos encontrados
mirando la salida: un `@import` pegado al primer selector se comía 2 knobs de
color-picker (el suelo del censo no puede moverse); `:not(:disabled)` se leía
como estado y producía `hover-disabled-*`; un knob que lee un privado se
proponía a sí mismo en vez de resolverse por talla; `--icon-size-sm` se
reportaba como préstamo del componente `icon` (ahora el préstamo se verifica
contra las claves del dueño en `base.ts`); y el default de talla salía sin
nombrar en vez de `-md`.
Verificación: censo global idéntico al suelo publicado (5205 · 1621/33% · 856 ·
1880 · 614 · 234) y COMPONENTE A COMPONENTE contra la tabla §9 del plan — 0
diferencias en 162 · regenerar dos veces da el árbol idéntico · el bloque de
veredicto escrito a mano sobrevive · docs:check 0 errores sobre 813 docs ·
prettier limpio (el árbol generado entra en .prettierignore junto a
eidos/generated).
Las 10 primeras fichas llevan ya su veredicto de revisión: análisis correcto en
las 10, propuesta apta en 2 (gradient-builder como piloto, combobox con cinco
correcciones — dos de ellas evitaban romper el default), y 5 que no se
tokenizan en solitario porque son alias de --calendar-*/--field-* y esperan la
decisión de familia. Cuatro destaparon privados con prefijo ajeno o abreviado
declarados en su propio CSS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| 47 | `palabras-chrome.css:404` | `[data-palabras-outline-item]` | `font-size` | `var(--font-size-sm)` |
| 48 | `palabras-chrome.css:411` | `[data-palabras-outline-item]:hover` | `background` | `var(--color-surface-muted)` |
| 49 | `palabras-chrome.css:414` | `[data-palabras-outline-item][data-level='2']` | `padding-inline-start` | `var(--space-3)` |
| 50 | `palabras-chrome.css:417` | `[data-palabras-outline-item][data-level='3']` | `padding-inline-start` | `var(--space-5)` |
| 51 | `palabras-chrome.css:422` | `[data-palabras-outline-item][data-level='4'], [data-palabras-outline-item][data-level='5'], [data-palabras-outline-item][data-level='6']` | `padding-inline-start` | `var(--space-8)` |
| 52 | `palabras-chrome.css:454` | `[data-palabras-col-resize]::before` | `border-radius` | `var(--radius-full)` |
| 53 | `palabras-chrome.css:455` | `[data-palabras-col-resize]::before` | `background` | `var(--color-border-default)` |
| 54 | `palabras-chrome.css:463` | `[data-palabras-col-resize]:hover::before, [data-palabras-col-resize][data-dragging]::before` | `background` | `var(--color-primary-border)` |
| 55 | `palabras-chrome.css:486` | `[data-palabras-panel][data-palabras-panel], [data-palabras-panel][data-palabras-panel] *` | `font-family` | `var(--style-label-font-family)` |
| 56 | `palabras-chrome.css:495` | `[data-palabras-panel][data-palabras-panel]:not([data-palabras-docked]):not([data-menubar-panel])` | `background` | `var(--color-surface-default)` |
| 57 | `palabras-chrome.css:496` | `[data-palabras-panel][data-palabras-panel]:not([data-palabras-docked]):not([data-menubar-panel])` | `border` | `var(--border-width) solid var(--color-border-subtle)` |
| 58 | `palabras-chrome.css:497` | `[data-palabras-panel][data-palabras-panel]:not([data-palabras-docked]):not([data-menubar-panel])` | `border-radius` | `var(--radius-xl)` |
| 59 | `palabras-chrome.css:498` | `[data-palabras-panel][data-palabras-panel]:not([data-palabras-docked]):not([data-menubar-panel])` | `box-shadow` | `var(--shadow-4)` |
| 60 | `palabras-chrome.css:521` | `[data-palabras-panel] [data-float-panel-header], [data-palabras-panel] [data-palabras-dock-header]` | `padding` | `var(--space-3-5) var(--space-4) var(--space-1)` |
| 61 | `palabras-chrome.css:537` | `[data-palabras-panel][data-palabras-docked][data-drawer-content]` | `background` | `var(--color-surface-default)` |
| 62 | `palabras-chrome.css:555` | `[data-palabras-panel][data-palabras-docked][data-side='right']` | `border-inline-start` | `var(--border-width) solid var(--color-border-subtle)` |
| 63 | `palabras-chrome.css:558` | `[data-palabras-panel][data-palabras-docked][data-side='left']` | `border-inline-end` | `var(--border-width) solid var(--color-border-subtle)` |
| 64 | `palabras-chrome.css:579` | `[data-palabras-panel] [data-palabras-dock-controls]` | `gap` | `var(--space-1)` |
| 65 | `palabras-chrome.css:585` | `[data-palabras-panel-head-main]` | `gap` | `var(--space-2-5, 10px)` |
| 66 | `palabras-chrome.css:593` | `[data-palabras-panel-icon]` | `inline-size` | `var(--space-8)` |
| 67 | `palabras-chrome.css:594` | `[data-palabras-panel-icon]` | `block-size` | `var(--space-8)` |
| 68 | `palabras-chrome.css:595` | `[data-palabras-panel-icon]` | `border-radius` | `var(--radius-md)` |
| 69 | `palabras-chrome.css:596` | `[data-palabras-panel-icon]` | `background` | `var(--color-primary-surface)` |
| 70 | `palabras-chrome.css:597` | `[data-palabras-panel-icon]` | `color` | `var(--color-primary-text) !important` |
| 71 | `palabras-chrome.css:606` | `[data-palabras-panel] [data-float-panel-title], [data-palabras-panel] [data-drawer-title], [data-palabras-panel] [data-palabras-menu-title]` | `font-size` | `var(--font-size-md)` |
| 72 | `palabras-chrome.css:607` | `[data-palabras-panel] [data-float-panel-title], [data-palabras-panel] [data-drawer-title], [data-palabras-panel] [data-palabras-menu-title]` | `font-weight` | `var(--font-weight-semibold)` |
| 73 | `palabras-chrome.css:609` | `[data-palabras-panel] [data-float-panel-title], [data-palabras-panel] [data-drawer-title], [data-palabras-panel] [data-palabras-menu-title]` | `color` | `var(--color-content-primary)` |
| 74 | `palabras-chrome.css:618` | `[data-palabras-panel-crumbs]` | `column-gap` | `var(--space-1)` |
| 75 | `palabras-chrome.css:619` | `[data-palabras-panel-crumbs]` | `padding` | `0 var(--space-4) var(--space-1)` |
| 76 | `palabras-chrome.css:620` | `[data-palabras-panel-crumbs]` | `font-size` | `var(--font-size-sm)` |
| 77 | `palabras-chrome.css:621` | `[data-palabras-panel-crumbs]` | `color` | `var(--color-content-muted)` |
| 78 | `palabras-chrome.css:634` | `button[data-palabras-panel-crumb]:hover` | `color` | `var(--color-primary-text)` |
| 79 | `palabras-chrome.css:639` | `[data-palabras-panel-crumb][data-current]` | `color` | `var(--color-content-primary)` |
| 80 | `palabras-chrome.css:640` | `[data-palabras-panel-crumb][data-current]` | `font-weight` | `var(--font-weight-medium)` |
| 81 | `palabras-chrome.css:643` | `[data-palabras-panel-crumb-sep]` | `color` | `var(--color-border-strong)` |
| 82 | `palabras-chrome.css:657` | `[data-palabras-tabs]` | `padding-inline` | `var(--space-4)` |
| 83 | `palabras-chrome.css:679` | `[data-palabras-tabs] [data-tabs-content]` | `border-block-start` | `var(--border-width) solid var(--color-border-subtle)` |
| 84 | `palabras-chrome.css:693` | `[data-palabras-panel] [data-palabras-doc-body]` | `padding-inline` | `var(--space-4)` |
| 85 | `palabras-chrome.css:694` | `[data-palabras-panel] [data-palabras-doc-body]` | `padding-block` | `var(--space-1) var(--space-4)` |
| 86 | `palabras-chrome.css:695` | `[data-palabras-panel] [data-palabras-doc-body]` | `border-block-start` | `var(--border-width) solid var(--color-border-subtle)` |
| 87 | `palabras-chrome.css:725` | `[data-palabras-tabs] [data-tabs-content] > [data-scroll-area] > [data-scroll-area-viewport]` | `padding-block` | `var(--space-1) var(--space-4)` |
| 88 | `palabras-chrome.css:729` | `[data-palabras-tab-empty]` | `padding` | `var(--space-2) 0` |
| 89 | `palabras-chrome.css:730` | `[data-palabras-tab-empty]` | `font-size` | `var(--font-size-sm)` |
| 90 | `palabras-chrome.css:731` | `[data-palabras-tab-empty]` | `color` | `var(--color-content-muted)` |
| 91 | `palabras-chrome.css:751` | `[data-palabras-field]` | `column-gap` | `var(--space-3)` |
| 92 | `palabras-chrome.css:752` | `[data-palabras-field]` | `row-gap` | `var(--space-2)` |
| 93 | `palabras-chrome.css:790` | `[data-palabras-field-label]` | `font-size` | `var(--font-size-sm)` |
feat(color)!: una palabra, un significado - primary/secondary son SIEMPRE jerarquia
La homonimia muere: `primary`/`secondary` significan JERARQUIA DE MARCA en el
catalogo ENTERO, tambien dentro de los seis primitivos de tinta (text, heading,
display, code, label, s-text). El paso de tinta del 82 % se llama `subtle` -
PROP y TOKEN, sin excepcion: el nombre es el contrato en el artefacto (la misma
ley que la FIRMA B' y la 12.9; se rechazo por escrito la via "solo el prop con
tabla de traduccion" - las excepciones legitimas son las FIRMADAS con razon,
no las inventadas al decidir para abaratar).
- Los seis CONTENT_INK, IDENTICOS: {subtle, muted, disabled, on-solid}; el
nivel-1 es el DEFAULT sin prop. `label` gana `on-solid` (cierra la
divergencia de familia registrada en e4fa616e5).
- Renombre completo: --color-content-secondary -> --color-content-subtle y la
clave de config content.secondary -> content.subtle (RUPTURA de API de
tema). 355 referencias por patrones acotados; la raiz SIN prefijo
(cssVar('color-content-secondary'), render-css.ts) incluida; en grafito.ts
conviven tres claves `subtle` (content/border/shadow) y solo cambio content.
El generado, reproducido BYTE A BYTE aplicando solo el renombre al anterior.
- Codemod value-preserving: 11 call sites (6 secondary->subtle incl.
expresiones y ternarias; 5 primary->fuera, incl. TRES defaults de prop) con
la condicion ROJA caracterizada (--style-caption-color es el UNICO estilo
cuya tinta default no es primary; los 5 sitios caen en ramas body). alpha/
(untracked, TERMINATED) fuera.
- Las 6 demos migradas al vocabulario nuevo (s-text: CERO cambios, no tiene
lista de tinta); label arranca en el default y pinta IDENTICO (contrafactual
medido: el estado viejo habria pintado el morado de marca).
- Neutra en pixel, MEDIDO: nivel 1 ESTRICTO CERO en 71.200 valores (blocks
enteros, s-text entero, subarboles data-*); nivel 2: 31 diffs, todos
trazados a las ediciones firmadas del harness (anchos de chips, reindexado
de la lista de label con las tintas supervivientes byte a byte). Total
171.712 valores + 59.072 de re-corridas a 0 de ruido.
- Guards: CONTENT_INK identicos entre los seis y sin nombres de rol (mutacion:
muerde), y el generado sin rastro del token viejo con las 6 definiciones del
nuevo. Dos cronicas fechadas en docs/old-deprecated, intactas a proposito.
- Docs: changelog 54 - reference (eje de tinta) - next-features 13 (divergencia
de label RESUELTA).
Supervision: verificador independiente pre-firma (dos claims MURIERON en
verificacion antes de tocar codigo), tres agentes en fases (censo+baseline ->
implementacion+codemod -> demos -> verificacion de dos niveles -> docs).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
| 94 | `palabras-chrome.css:791` | `[data-palabras-field-label]` | `color` | `var(--color-content-subtle)` |
docs(theming): la auditoría de alcance de tema, componente a componente, con su propuesta
El censo medía el eje y no lo explicaba: 5.205 knobs en dos tablas del plan no
dicen QUÉ knob de QUÉ línea no alcanza un tema, ni qué token habría que crear.
Ahora `theming-census.ts --report` escribe la auditoría entera bajo
`docs/audit/theming/`: un README con la vista de conjunto y 170 fichas — 162
recetas con CSS + 8 componentes sin receta, el árbol completo de
`eidos/components/`.
Cada ficha de receta: knobs fuera de alcance con fichero:línea Y selector
(agrupados por clase), sistema transversal aparte, los privados con la columna
que decide («¿deriva de un público?»), y una PROPUESTA de corrección — el token
a declarar en `base.ts` con su valor VERBATIM y su scope TSC. La propuesta
deriva los nombres de recipe-contract §1 y theming §6.7; donde la doctrina no
decide, marca `⚠ decisión` en vez de inventar. Y no propone acuñar lo que la
doctrina prohíbe: lo que posee una capa compartida, el foco, la capa de estado,
un token prestado de otra receta, un shorthand o un eje físico.
Las 8 fichas sin receta dicen —medido, no supuesto— dónde vive su visual: el
componente que componen (icon-button → button), la capa que consumen (affix →
viewport-placement) o la receta ajena que pinta sus attrs (svg → badge/button).
Defectos del instrumento corregidos en el mismo pase, todos encontrados
mirando la salida: un `@import` pegado al primer selector se comía 2 knobs de
color-picker (el suelo del censo no puede moverse); `:not(:disabled)` se leía
como estado y producía `hover-disabled-*`; un knob que lee un privado se
proponía a sí mismo en vez de resolverse por talla; `--icon-size-sm` se
reportaba como préstamo del componente `icon` (ahora el préstamo se verifica
contra las claves del dueño en `base.ts`); y el default de talla salía sin
nombrar en vez de `-md`.
Verificación: censo global idéntico al suelo publicado (5205 · 1621/33% · 856 ·
1880 · 614 · 234) y COMPONENTE A COMPONENTE contra la tabla §9 del plan — 0
diferencias en 162 · regenerar dos veces da el árbol idéntico · el bloque de
veredicto escrito a mano sobrevive · docs:check 0 errores sobre 813 docs ·
prettier limpio (el árbol generado entra en .prettierignore junto a
eidos/generated).
Las 10 primeras fichas llevan ya su veredicto de revisión: análisis correcto en
las 10, propuesta apta en 2 (gradient-builder como piloto, combobox con cinco
correcciones — dos de ellas evitaban romper el default), y 5 que no se
tokenizan en solitario porque son alias de --calendar-*/--field-* y esperan la
decisión de familia. Cuatro destaparon privados con prefijo ajeno o abreviado
declarados en su propio CSS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| 95 | `palabras-chrome.css:792` | `[data-palabras-field-label]` | `line-height` | `var(--leading-ui)` |
| 96 | `palabras-chrome.css:805` | `[data-palabras-panel] :is([data-field-control], [data-css-field], [data-textarea-input]), [data-palabras-panel] [data-select-trigger], [data-palabras-text], [data-palabras-spacing-cell]` | `background` | `var(--color-surface-muted)` |
| 97 | `palabras-chrome.css:807` | `[data-palabras-panel] :is([data-field-control], [data-css-field], [data-textarea-input]), [data-palabras-panel] [data-select-trigger], [data-palabras-text], [data-palabras-spacing-cell]` | `border-radius` | `var(--radius-md)` |
| 98 | `palabras-chrome.css:815` | `[data-palabras-panel] [data-field-control]:focus-within, [data-palabras-panel] [data-css-field]:focus-within, [data-palabras-panel] [data-textarea][data-focused] [data-textarea-input], [data-palabras-panel] [data-select-trigger]:focus-visible, [data-palabras-text]:focus-visible, [data-palabras-spacing-cell]:focus-visible` | `background` | `var(--color-surface-default)` |
| 99 | `palabras-chrome.css:830` | `[data-palabras-panel] :is([data-textarea-input], [data-field] input)` | `font-size` | `var(--font-size-sm)` |
| 100 | `palabras-chrome.css:836` | `[data-palabras-text]` | `padding` | `var(--space-1-5) var(--space-2)` |
| 101 | `palabras-chrome.css:838` | `[data-palabras-text]` | `color` | `var(--color-content-primary)` |
| 102 | `palabras-chrome.css:840` | `[data-palabras-text]` | `font-size` | `var(--font-size-sm)` |
| 103 | `palabras-chrome.css:841` | `[data-palabras-text]` | `font-family` | `var(--font-family-mono)` |
| 104 | `palabras-chrome.css:848` | `[data-palabras-text][data-invalid]` | `border-color` | `var(--color-threat-border, crimson)` |
| 105 | `palabras-chrome.css:854` | `[data-toggle-group][data-palabras-segmented]` | `background` | `var(--color-surface-muted)` |
| 106 | `palabras-chrome.css:855` | `[data-toggle-group][data-palabras-segmented]` | `border-radius` | `var(--radius-lg)` |
| 107 | `palabras-chrome.css:856` | `[data-toggle-group][data-palabras-segmented]` | `padding` | `var(--space-0-5)` |
| 108 | `palabras-chrome.css:857` | `[data-toggle-group][data-palabras-segmented]` | `gap` | `var(--space-0-5)` |
| 109 | `palabras-chrome.css:863` | `[data-toggle-group][data-palabras-segmented] [data-toggle-group-item]` | `border-radius` | `calc(var(--radius-lg) - var(--space-0-5))` |
feat(color)!: una palabra, un significado - primary/secondary son SIEMPRE jerarquia
La homonimia muere: `primary`/`secondary` significan JERARQUIA DE MARCA en el
catalogo ENTERO, tambien dentro de los seis primitivos de tinta (text, heading,
display, code, label, s-text). El paso de tinta del 82 % se llama `subtle` -
PROP y TOKEN, sin excepcion: el nombre es el contrato en el artefacto (la misma
ley que la FIRMA B' y la 12.9; se rechazo por escrito la via "solo el prop con
tabla de traduccion" - las excepciones legitimas son las FIRMADAS con razon,
no las inventadas al decidir para abaratar).
- Los seis CONTENT_INK, IDENTICOS: {subtle, muted, disabled, on-solid}; el
nivel-1 es el DEFAULT sin prop. `label` gana `on-solid` (cierra la
divergencia de familia registrada en e4fa616e5).
- Renombre completo: --color-content-secondary -> --color-content-subtle y la
clave de config content.secondary -> content.subtle (RUPTURA de API de
tema). 355 referencias por patrones acotados; la raiz SIN prefijo
(cssVar('color-content-secondary'), render-css.ts) incluida; en grafito.ts
conviven tres claves `subtle` (content/border/shadow) y solo cambio content.
El generado, reproducido BYTE A BYTE aplicando solo el renombre al anterior.
- Codemod value-preserving: 11 call sites (6 secondary->subtle incl.
expresiones y ternarias; 5 primary->fuera, incl. TRES defaults de prop) con
la condicion ROJA caracterizada (--style-caption-color es el UNICO estilo
cuya tinta default no es primary; los 5 sitios caen en ramas body). alpha/
(untracked, TERMINATED) fuera.
- Las 6 demos migradas al vocabulario nuevo (s-text: CERO cambios, no tiene
lista de tinta); label arranca en el default y pinta IDENTICO (contrafactual
medido: el estado viejo habria pintado el morado de marca).
- Neutra en pixel, MEDIDO: nivel 1 ESTRICTO CERO en 71.200 valores (blocks
enteros, s-text entero, subarboles data-*); nivel 2: 31 diffs, todos
trazados a las ediciones firmadas del harness (anchos de chips, reindexado
de la lista de label con las tintas supervivientes byte a byte). Total
171.712 valores + 59.072 de re-corridas a 0 de ruido.
- Guards: CONTENT_INK identicos entre los seis y sin nombres de rol (mutacion:
muerde), y el generado sin rastro del token viejo con las 6 definiciones del
nuevo. Dos cronicas fechadas en docs/old-deprecated, intactas a proposito.
- Docs: changelog 54 - reference (eje de tinta) - next-features 13 (divergencia
de label RESUELTA).
Supervision: verificador independiente pre-firma (dos claims MURIERON en
verificacion antes de tocar codigo), tres agentes en fases (censo+baseline ->
implementacion+codemod -> demos -> verificacion de dos niveles -> docs).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
| 110 | `palabras-chrome.css:864` | `[data-toggle-group][data-palabras-segmented] [data-toggle-group-item]` | `color` | `var(--color-content-subtle)` |
docs(theming): la auditoría de alcance de tema, componente a componente, con su propuesta
El censo medía el eje y no lo explicaba: 5.205 knobs en dos tablas del plan no
dicen QUÉ knob de QUÉ línea no alcanza un tema, ni qué token habría que crear.
Ahora `theming-census.ts --report` escribe la auditoría entera bajo
`docs/audit/theming/`: un README con la vista de conjunto y 170 fichas — 162
recetas con CSS + 8 componentes sin receta, el árbol completo de
`eidos/components/`.
Cada ficha de receta: knobs fuera de alcance con fichero:línea Y selector
(agrupados por clase), sistema transversal aparte, los privados con la columna
que decide («¿deriva de un público?»), y una PROPUESTA de corrección — el token
a declarar en `base.ts` con su valor VERBATIM y su scope TSC. La propuesta
deriva los nombres de recipe-contract §1 y theming §6.7; donde la doctrina no
decide, marca `⚠ decisión` en vez de inventar. Y no propone acuñar lo que la
doctrina prohíbe: lo que posee una capa compartida, el foco, la capa de estado,
un token prestado de otra receta, un shorthand o un eje físico.
Las 8 fichas sin receta dicen —medido, no supuesto— dónde vive su visual: el
componente que componen (icon-button → button), la capa que consumen (affix →
viewport-placement) o la receta ajena que pinta sus attrs (svg → badge/button).
Defectos del instrumento corregidos en el mismo pase, todos encontrados
mirando la salida: un `@import` pegado al primer selector se comía 2 knobs de
color-picker (el suelo del censo no puede moverse); `:not(:disabled)` se leía
como estado y producía `hover-disabled-*`; un knob que lee un privado se
proponía a sí mismo en vez de resolverse por talla; `--icon-size-sm` se
reportaba como préstamo del componente `icon` (ahora el préstamo se verifica
contra las claves del dueño en `base.ts`); y el default de talla salía sin
nombrar en vez de `-md`.
Verificación: censo global idéntico al suelo publicado (5205 · 1621/33% · 856 ·
1880 · 614 · 234) y COMPONENTE A COMPONENTE contra la tabla §9 del plan — 0
diferencias en 162 · regenerar dos veces da el árbol idéntico · el bloque de
veredicto escrito a mano sobrevive · docs:check 0 errores sobre 813 docs ·
prettier limpio (el árbol generado entra en .prettierignore junto a
eidos/generated).
Las 10 primeras fichas llevan ya su veredicto de revisión: análisis correcto en
las 10, propuesta apta en 2 (gradient-builder como piloto, combobox con cinco
correcciones — dos de ellas evitaban romper el default), y 5 que no se
tokenizan en solitario porque son alias de --calendar-*/--field-* y esperan la
decisión de familia. Cuatro destaparon privados con prefijo ajeno o abreviado
declarados en su propio CSS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| 111 | `palabras-chrome.css:868` | `[data-toggle-group][data-palabras-segmented] [data-toggle-group-item]:hover` | `color` | `var(--color-content-primary)` |
| 112 | `palabras-chrome.css:874` | `[data-toggle-group][data-palabras-segmented] [data-toggle-group-item][data-state='on']` | `background` | `var(--color-primary-solid)` |
| 113 | `palabras-chrome.css:875` | `[data-toggle-group][data-palabras-segmented] [data-toggle-group-item][data-state='on']` | `color` | `var(--color-content-on-solid)` |
| 114 | `palabras-chrome.css:876` | `[data-toggle-group][data-palabras-segmented] [data-toggle-group-item][data-state='on']` | `box-shadow` | `var(--shadow-1)` |
| 115 | `palabras-chrome.css:882` | `[data-palabras-type-style]` | `gap` | `var(--space-1)` |
| 116 | `palabras-chrome.css:890` | `[data-palabras-spacing]` | `column-gap` | `var(--space-2)` |
| 117 | `palabras-chrome.css:891` | `[data-palabras-spacing]` | `row-gap` | `var(--space-1)` |
| 118 | `palabras-chrome.css:899` | `[data-palabras-spacing-head]` | `gap` | `var(--space-2)` |
| 119 | `palabras-chrome.css:900` | `[data-palabras-spacing-head]` | `min-block-size` | `var(--space-6)` |
| 120 | `palabras-chrome.css:920` | `[data-palabras-spacing-cell] :is(input, [data-field-input])` | `padding` | `var(--space-2) var(--space-1)` |
| 121 | `palabras-chrome.css:921` | `[data-palabras-spacing-cell] :is(input, [data-field-input])` | `font-size` | `var(--font-size-sm)` |
| 122 | `palabras-chrome.css:926` | `[data-palabras-spacing-side]` | `font-size` | `var(--font-size-xs)` |
| 123 | `palabras-chrome.css:927` | `[data-palabras-spacing-side]` | `color` | `var(--color-content-muted)` |
| 124 | `palabras-chrome.css:932` | `[data-palabras-spacing-link]` | `color` | `var(--color-content-muted)` |
| 125 | `palabras-chrome.css:939` | `[data-palabras-border]` | `gap` | `var(--space-2-5)` |
| 126 | `palabras-chrome.css:946` | `[data-palabras-border-row]` | `column-gap` | `var(--space-2)` |
| 127 | `palabras-chrome.css:957` | `[data-palabras-border-field]` | `column-gap` | `var(--space-2)` |
| 128 | `palabras-chrome.css:962` | `[data-palabras-border-field][data-stack]` | `row-gap` | `var(--space-1)` |
| 129 | `palabras-chrome.css:965` | `[data-palabras-border-caption]` | `font-size` | `var(--font-size-sm)` |
feat(color)!: una palabra, un significado - primary/secondary son SIEMPRE jerarquia
La homonimia muere: `primary`/`secondary` significan JERARQUIA DE MARCA en el
catalogo ENTERO, tambien dentro de los seis primitivos de tinta (text, heading,
display, code, label, s-text). El paso de tinta del 82 % se llama `subtle` -
PROP y TOKEN, sin excepcion: el nombre es el contrato en el artefacto (la misma
ley que la FIRMA B' y la 12.9; se rechazo por escrito la via "solo el prop con
tabla de traduccion" - las excepciones legitimas son las FIRMADAS con razon,
no las inventadas al decidir para abaratar).
- Los seis CONTENT_INK, IDENTICOS: {subtle, muted, disabled, on-solid}; el
nivel-1 es el DEFAULT sin prop. `label` gana `on-solid` (cierra la
divergencia de familia registrada en e4fa616e5).
- Renombre completo: --color-content-secondary -> --color-content-subtle y la
clave de config content.secondary -> content.subtle (RUPTURA de API de
tema). 355 referencias por patrones acotados; la raiz SIN prefijo
(cssVar('color-content-secondary'), render-css.ts) incluida; en grafito.ts
conviven tres claves `subtle` (content/border/shadow) y solo cambio content.
El generado, reproducido BYTE A BYTE aplicando solo el renombre al anterior.
- Codemod value-preserving: 11 call sites (6 secondary->subtle incl.
expresiones y ternarias; 5 primary->fuera, incl. TRES defaults de prop) con
la condicion ROJA caracterizada (--style-caption-color es el UNICO estilo
cuya tinta default no es primary; los 5 sitios caen en ramas body). alpha/
(untracked, TERMINATED) fuera.
- Las 6 demos migradas al vocabulario nuevo (s-text: CERO cambios, no tiene
lista de tinta); label arranca en el default y pinta IDENTICO (contrafactual
medido: el estado viejo habria pintado el morado de marca).
- Neutra en pixel, MEDIDO: nivel 1 ESTRICTO CERO en 71.200 valores (blocks
enteros, s-text entero, subarboles data-*); nivel 2: 31 diffs, todos
trazados a las ediciones firmadas del harness (anchos de chips, reindexado
de la lista de label con las tintas supervivientes byte a byte). Total
171.712 valores + 59.072 de re-corridas a 0 de ruido.
- Guards: CONTENT_INK identicos entre los seis y sin nombres de rol (mutacion:
muerde), y el generado sin rastro del token viejo con las 6 definiciones del
nuevo. Dos cronicas fechadas en docs/old-deprecated, intactas a proposito.
- Docs: changelog 54 - reference (eje de tinta) - next-features 13 (divergencia
de label RESUELTA).
Supervision: verificador independiente pre-firma (dos claims MURIERON en
verificacion antes de tocar codigo), tres agentes en fases (censo+baseline ->
implementacion+codemod -> demos -> verificacion de dos niveles -> docs).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
| 130 | `palabras-chrome.css:966` | `[data-palabras-border-caption]` | `color` | `var(--color-content-subtle)` |
docs(theming): la auditoría de alcance de tema, componente a componente, con su propuesta
El censo medía el eje y no lo explicaba: 5.205 knobs en dos tablas del plan no
dicen QUÉ knob de QUÉ línea no alcanza un tema, ni qué token habría que crear.
Ahora `theming-census.ts --report` escribe la auditoría entera bajo
`docs/audit/theming/`: un README con la vista de conjunto y 170 fichas — 162
recetas con CSS + 8 componentes sin receta, el árbol completo de
`eidos/components/`.
Cada ficha de receta: knobs fuera de alcance con fichero:línea Y selector
(agrupados por clase), sistema transversal aparte, los privados con la columna
que decide («¿deriva de un público?»), y una PROPUESTA de corrección — el token
a declarar en `base.ts` con su valor VERBATIM y su scope TSC. La propuesta
deriva los nombres de recipe-contract §1 y theming §6.7; donde la doctrina no
decide, marca `⚠ decisión` en vez de inventar. Y no propone acuñar lo que la
doctrina prohíbe: lo que posee una capa compartida, el foco, la capa de estado,
un token prestado de otra receta, un shorthand o un eje físico.
Las 8 fichas sin receta dicen —medido, no supuesto— dónde vive su visual: el
componente que componen (icon-button → button), la capa que consumen (affix →
viewport-placement) o la receta ajena que pinta sus attrs (svg → badge/button).
Defectos del instrumento corregidos en el mismo pase, todos encontrados
mirando la salida: un `@import` pegado al primer selector se comía 2 knobs de
color-picker (el suelo del censo no puede moverse); `:not(:disabled)` se leía
como estado y producía `hover-disabled-*`; un knob que lee un privado se
proponía a sí mismo en vez de resolverse por talla; `--icon-size-sm` se
reportaba como préstamo del componente `icon` (ahora el préstamo se verifica
contra las claves del dueño en `base.ts`); y el default de talla salía sin
nombrar en vez de `-md`.
Verificación: censo global idéntico al suelo publicado (5205 · 1621/33% · 856 ·
1880 · 614 · 234) y COMPONENTE A COMPONENTE contra la tabla §9 del plan — 0
diferencias en 162 · regenerar dos veces da el árbol idéntico · el bloque de
veredicto escrito a mano sobrevive · docs:check 0 errores sobre 813 docs ·
prettier limpio (el árbol generado entra en .prettierignore junto a
eidos/generated).
Las 10 primeras fichas llevan ya su veredicto de revisión: análisis correcto en
las 10, propuesta apta en 2 (gradient-builder como piloto, combobox con cinco
correcciones — dos de ellas evitaban romper el default), y 5 que no se
tokenizan en solitario porque son alias de --calendar-*/--field-* y esperan la
decisión de familia. Cuatro destaparon privados con prefijo ajeno o abreviado
declarados en su propio CSS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| 131 | `palabras-chrome.css:972` | `[data-palabras-border-pair]` | `column-gap` | `var(--space-2)` |
| 132 | `palabras-chrome.css:984` | `[data-palabras-typography]` | `gap` | `var(--space-3)` |
| 133 | `palabras-chrome.css:993` | `[data-palabras-type-pair]` | `column-gap` | `var(--space-1)` |
| 134 | `palabras-chrome.css:1008` | `[data-palabras-select-text][data-empty]` | `color` | `var(--color-content-muted)` |
| 135 | `palabras-chrome.css:1029` | `[data-palabras-panel] [data-palabras-design] [data-accordion-item] + [data-accordion-item]` | `border-block-start` | `1px solid var(--color-border-subtle)` |
| 136 | `palabras-chrome.css:1066` | `[data-palabras-panel] [data-scroll-area]:has([data-scroll-area-scrollbar]) [data-scroll-area-viewport]` | `padding-inline-end` | `calc(var(--scroll-area-scrollbar-size, var(--space-2-5)) + var(--space-1-5))` ⤴ prestado de `scroll-area` |
| 137 | `palabras-chrome.css:1070` | `[data-palabras-panel] [data-palabras-design] [data-accordion-trigger]` | `padding-block` | `var(--space-3-5)` |
| 138 | `palabras-chrome.css:1071` | `[data-palabras-panel] [data-palabras-design] [data-accordion-trigger]` | `font-size` | `var(--font-size-sm)` |
| 139 | `palabras-chrome.css:1072` | `[data-palabras-panel] [data-palabras-design] [data-accordion-trigger]` | `font-weight` | `var(--font-weight-semibold)` |
| 140 | `palabras-chrome.css:1073` | `[data-palabras-panel] [data-palabras-design] [data-accordion-trigger]` | `color` | `var(--color-content-primary)` |
| 141 | `palabras-chrome.css:1080` | `[data-palabras-panel] [data-palabras-design] [data-accordion-trigger]:hover, [data-palabras-panel] [data-palabras-design] [data-accordion-trigger][data-state='open'], [data-palabras-panel] [data-palabras-design] [data-accordion-trigger][aria-expanded='true']` | `color` | `var(--color-content-primary)` |
| 142 | `palabras-chrome.css:1092` | `[data-palabras-panel] [data-palabras-design] [data-accordion-content]` | `padding` | `var(--space-1) 0 var(--space-4)` |
| 143 | `palabras-chrome.css:1115` | `[data-palabras-section-reset]` | `color` | `var(--color-content-muted)` |
| 144 | `palabras-chrome.css:1124` | `[data-palabras-field][data-slider]` | `row-gap` | `var(--space-0-5, 2px)` |
| 145 | `palabras-chrome.css:1130` | `[data-palabras-field][data-slider] [data-palabras-slider-head]` | `gap` | `var(--space-2)` |
| 146 | `palabras-chrome.css:1133` | `[data-palabras-field][data-slider] [data-palabras-slider-value]` | `font-size` | `var(--font-size-sm)` |
| 147 | `palabras-chrome.css:1134` | `[data-palabras-field][data-slider] [data-palabras-slider-value]` | `color` | `var(--color-primary-text)` |
| 148 | `palabras-chrome.css:1141` | `[data-palabras-src-group]` | `gap` | `var(--space-1)` |
| 149 | `palabras-chrome.css:1153` | `[data-palabras-panel-foot]` | `gap` | `var(--space-1)` |
| 150 | `palabras-chrome.css:1154` | `[data-palabras-panel-foot]` | `padding` | `var(--space-2-5, 10px) var(--space-4)` |
| 151 | `palabras-chrome.css:1155` | `[data-palabras-panel-foot]` | `border-block-start` | `1px solid var(--color-border-subtle)` |
| 152 | `palabras-chrome.css:1158` | `[data-palabras-panel-foot]` | `background` | `var(--color-surface-default)` |
| 153 | `palabras-chrome.css:1159` | `[data-palabras-panel-foot]` | `font-size` | `var(--font-size-sm)` |
| 154 | `palabras-chrome.css:1160` | `[data-palabras-panel-foot]` | `color` | `var(--color-content-muted)` |
| 155 | `palabras-chrome.css:1169` | `[data-palabras-panel-empty]` | `padding` | `var(--space-5) var(--space-4)` |
| 156 | `palabras-chrome.css:1170` | `[data-palabras-panel-empty]` | `font-size` | `var(--font-size-sm)` |
| 157 | `palabras-chrome.css:1171` | `[data-palabras-panel-empty]` | `color` | `var(--color-content-muted)` |
| 158 | `palabras-chrome.css:1177` | `[data-palabras-appearance][data-palabras-appearance], [data-palabras-appearance][data-palabras-appearance] *` | `font-family` | `var(--style-label-font-family)` |
| 159 | `palabras-chrome.css:1204` | `[data-palabras-bubble]` | `gap` | `var(--space-0-5)` |
| 160 | `palabras-chrome.css:1205` | `[data-palabras-bubble]` | `padding` | `var(--space-1)` |
| 161 | `palabras-chrome.css:1206` | `[data-palabras-bubble]` | `background` | `var(--color-surface-overlay)` |
| 162 | `palabras-chrome.css:1207` | `[data-palabras-bubble]` | `border` | `var(--border-width) solid var(--color-border-default)` |
| 163 | `palabras-chrome.css:1208` | `[data-palabras-bubble]` | `border-radius` | `var(--radius-lg)` |
| 164 | `palabras-chrome.css:1209` | `[data-palabras-bubble]` | `box-shadow` | `var(--shadow-overlay)` |
| 165 | `palabras-chrome.css:1210` | `[data-palabras-bubble]` | `font-family` | `var(--style-label-font-family)` |
| 166 | `palabras-chrome.css:1214` | `[data-palabras-bubble] [data-active]` | `background` | `var(--color-primary-element)` |
| 167 | `palabras-chrome.css:1215` | `[data-palabras-bubble] [data-active]` | `color` | `var(--color-content-primary)` |
| 168 | `palabras-chrome.css:1222` | `[data-palabras-bubble-divider]` | `background` | `var(--color-border-subtle)` |
| 169 | `palabras-chrome.css:1228` | `[data-palabras-bubble-link]` | `gap` | `var(--space-1)` |
| 170 | `palabras-chrome.css:1232` | `[data-palabras-bubble-link] input` | `padding` | `var(--space-1) var(--space-2)` |
| 171 | `palabras-chrome.css:1233` | `[data-palabras-bubble-link] input` | `border` | `var(--border-width) solid transparent` |
| 172 | `palabras-chrome.css:1234` | `[data-palabras-bubble-link] input` | `border-radius` | `var(--radius-md)` |
| 173 | `palabras-chrome.css:1235` | `[data-palabras-bubble-link] input` | `background` | `var(--color-surface-muted)` |
| 174 | `palabras-chrome.css:1236` | `[data-palabras-bubble-link] input` | `color` | `var(--color-content-default)` |
| 175 | `palabras-chrome.css:1237` | `[data-palabras-bubble-link] input` | `font-size` | `var(--font-size-sm)` |
| 176 | `palabras-chrome.css:1241` | `[data-palabras-bubble-link] input:focus` | `background` | `var(--color-surface-default)` |
| 177 | `palabras-chrome.css:1248` | `[data-palabras-bubble-typo]` | `gap` | `var(--space-0-5)` |
| 178 | `palabras-chrome.css:1281` | `[data-palabras-slash]` | `padding` | `var(--space-1)` |
| 179 | `palabras-chrome.css:1282` | `[data-palabras-slash]` | `background` | `var(--color-surface-overlay)` |
| 180 | `palabras-chrome.css:1283` | `[data-palabras-slash]` | `border` | `var(--border-width) solid var(--color-border-default)` |
| 181 | `palabras-chrome.css:1284` | `[data-palabras-slash]` | `border-radius` | `var(--radius-lg)` |
| 182 | `palabras-chrome.css:1285` | `[data-palabras-slash]` | `box-shadow` | `var(--shadow-overlay)` |
| 183 | `palabras-chrome.css:1286` | `[data-palabras-slash]` | `font-family` | `var(--style-label-font-family)` |
| 184 | `palabras-chrome.css:1291` | `[data-palabras-slash-item]` | `gap` | `var(--space-2)` |
| 185 | `palabras-chrome.css:1293` | `[data-palabras-slash-item]` | `padding` | `var(--space-1-5) var(--space-2)` |
| 186 | `palabras-chrome.css:1296` | `[data-palabras-slash-item]` | `border-radius` | `var(--radius-md)` |
| 187 | `palabras-chrome.css:1297` | `[data-palabras-slash-item]` | `color` | `var(--color-content-default)` |
| 188 | `palabras-chrome.css:1299` | `[data-palabras-slash-item]` | `font-size` | `var(--font-size-sm)` |
| 189 | `palabras-chrome.css:1304` | `[data-palabras-slash-item][data-active]` | `background` | `var(--color-surface-muted)` |
| 190 | `palabras-chrome.css:1309` | `[data-palabras-slash-icon]` | `color` | `var(--color-content-muted)` |
| 191 | `palabras-chrome.css:1312` | `[data-palabras-slash-label]` | `font-weight` | `var(--font-weight-medium)` |
| 192 | `palabras-chrome.css:1316` | `[data-palabras-slash-desc]` | `padding-inline-start` | `var(--space-2)` |
| 193 | `palabras-chrome.css:1317` | `[data-palabras-slash-desc]` | `color` | `var(--color-content-muted)` |
| 194 | `palabras-chrome.css:1318` | `[data-palabras-slash-desc]` | `font-size` | `var(--font-size-xs)` |
| 195 | `palabras-chrome.css:1332` | `[data-palabras-find]` | `gap` | `var(--space-1)` |
| 196 | `palabras-chrome.css:1333` | `[data-palabras-find]` | `padding` | `var(--space-2)` |
| 197 | `palabras-chrome.css:1334` | `[data-palabras-find]` | `background` | `var(--color-surface-overlay)` |
| 198 | `palabras-chrome.css:1335` | `[data-palabras-find]` | `border` | `var(--border-width) solid var(--color-border-default)` |
| 199 | `palabras-chrome.css:1336` | `[data-palabras-find]` | `border-radius` | `var(--radius-lg)` |
| 200 | `palabras-chrome.css:1337` | `[data-palabras-find]` | `box-shadow` | `var(--shadow-overlay)` |
| 201 | `palabras-chrome.css:1338` | `[data-palabras-find]` | `font-family` | `var(--style-label-font-family)` |
| 202 | `palabras-chrome.css:1343` | `[data-palabras-find-row]` | `gap` | `var(--space-1)` |
| 203 | `palabras-chrome.css:1348` | `[data-palabras-find-icon]` | `padding-inline` | `var(--space-1)` |
| 204 | `palabras-chrome.css:1349` | `[data-palabras-find-icon]` | `color` | `var(--color-content-muted)` |
| 205 | `palabras-chrome.css:1354` | `[data-palabras-find-input]` | `padding` | `var(--space-1) var(--space-2)` |
| 206 | `palabras-chrome.css:1355` | `[data-palabras-find-input]` | `border` | `var(--border-width) solid transparent` |
| 207 | `palabras-chrome.css:1356` | `[data-palabras-find-input]` | `border-radius` | `var(--radius-md)` |
| 208 | `palabras-chrome.css:1357` | `[data-palabras-find-input]` | `background` | `var(--color-surface-muted)` |
| 209 | `palabras-chrome.css:1358` | `[data-palabras-find-input]` | `color` | `var(--color-content-default)` |
| 210 | `palabras-chrome.css:1359` | `[data-palabras-find-input]` | `font-size` | `var(--font-size-sm)` |
| 211 | `palabras-chrome.css:1363` | `[data-palabras-find-input]:focus` | `background` | `var(--color-surface-default)` |
| 212 | `palabras-chrome.css:1367` | `[data-palabras-find][data-invalid] [data-palabras-find-row]:first-child [data-palabras-find-input]` | `border-color` | `var(--color-threat-solid)` |
| 213 | `palabras-chrome.css:1373` | `[data-palabras-find-count]` | `font-size` | `var(--font-size-xs)` |
| 214 | `palabras-chrome.css:1374` | `[data-palabras-find-count]` | `color` | `var(--color-content-muted)` |
| 215 | `palabras-chrome.css:1382` | `[data-palabras-find-sep]` | `background` | `var(--color-border-subtle)` |
| 216 | `palabras-chrome.css:1385` | `[data-palabras-find] [data-active]` | `background` | `var(--color-primary-element)` |
| 217 | `palabras-chrome.css:1386` | `[data-palabras-find] [data-active]` | `color` | `var(--color-content-primary)` |
| 218 | `palabras-chrome.css:1394` | `[data-palabras-export-foot]` | `gap` | `var(--space-2)` |
| 219 | `palabras-chrome.css:1395` | `[data-palabras-export-foot]` | `padding` | `var(--space-2-5) var(--space-4)` |
| 220 | `palabras-chrome.css:1396` | `[data-palabras-export-foot]` | `border-block-start` | `var(--border-width) solid var(--color-border-subtle)` |
| 221 | `palabras-chrome.css:1401` | `[data-palabras-export-label]` | `gap` | `var(--space-1-5)` |
| 222 | `palabras-chrome.css:1402` | `[data-palabras-export-label]` | `font-size` | `var(--font-size-sm)` |
| 223 | `palabras-chrome.css:1403` | `[data-palabras-export-label]` | `color` | `var(--color-content-muted)` |
| 224 | `palabras-chrome.css:1407` | `[data-palabras-export-actions]` | `gap` | `var(--space-1)` |
| 225 | `palabras-chrome.css:1418` | `[data-palabras-lang-switcher][data-mode='segmented']` | `gap` | `var(--space-0-5)` |
| 226 | `palabras-chrome.css:1419` | `[data-palabras-lang-switcher][data-mode='segmented']` | `padding` | `var(--space-0-5)` |
| 227 | `palabras-chrome.css:1420` | `[data-palabras-lang-switcher][data-mode='segmented']` | `border-radius` | `var(--radius-md)` |
| 228 | `palabras-chrome.css:1421` | `[data-palabras-lang-switcher][data-mode='segmented']` | `background` | `var(--color-surface-muted)` |
| 229 | `palabras-chrome.css:1426` | `[data-palabras-lang-option]` | `gap` | `var(--space-1)` |
| 230 | `palabras-chrome.css:1427` | `[data-palabras-lang-option]` | `padding-inline` | `var(--space-2)` |
| 231 | `palabras-chrome.css:1428` | `[data-palabras-lang-option]` | `min-block-size` | `var(--space-5)` |
| 232 | `palabras-chrome.css:1430` | `[data-palabras-lang-option]` | `border-radius` | `var(--radius-sm)` |
feat(color)!: una palabra, un significado - primary/secondary son SIEMPRE jerarquia
La homonimia muere: `primary`/`secondary` significan JERARQUIA DE MARCA en el
catalogo ENTERO, tambien dentro de los seis primitivos de tinta (text, heading,
display, code, label, s-text). El paso de tinta del 82 % se llama `subtle` -
PROP y TOKEN, sin excepcion: el nombre es el contrato en el artefacto (la misma
ley que la FIRMA B' y la 12.9; se rechazo por escrito la via "solo el prop con
tabla de traduccion" - las excepciones legitimas son las FIRMADAS con razon,
no las inventadas al decidir para abaratar).
- Los seis CONTENT_INK, IDENTICOS: {subtle, muted, disabled, on-solid}; el
nivel-1 es el DEFAULT sin prop. `label` gana `on-solid` (cierra la
divergencia de familia registrada en e4fa616e5).
- Renombre completo: --color-content-secondary -> --color-content-subtle y la
clave de config content.secondary -> content.subtle (RUPTURA de API de
tema). 355 referencias por patrones acotados; la raiz SIN prefijo
(cssVar('color-content-secondary'), render-css.ts) incluida; en grafito.ts
conviven tres claves `subtle` (content/border/shadow) y solo cambio content.
El generado, reproducido BYTE A BYTE aplicando solo el renombre al anterior.
- Codemod value-preserving: 11 call sites (6 secondary->subtle incl.
expresiones y ternarias; 5 primary->fuera, incl. TRES defaults de prop) con
la condicion ROJA caracterizada (--style-caption-color es el UNICO estilo
cuya tinta default no es primary; los 5 sitios caen en ramas body). alpha/
(untracked, TERMINATED) fuera.
- Las 6 demos migradas al vocabulario nuevo (s-text: CERO cambios, no tiene
lista de tinta); label arranca en el default y pinta IDENTICO (contrafactual
medido: el estado viejo habria pintado el morado de marca).
- Neutra en pixel, MEDIDO: nivel 1 ESTRICTO CERO en 71.200 valores (blocks
enteros, s-text entero, subarboles data-*); nivel 2: 31 diffs, todos
trazados a las ediciones firmadas del harness (anchos de chips, reindexado
de la lista de label con las tintas supervivientes byte a byte). Total
171.712 valores + 59.072 de re-corridas a 0 de ruido.
- Guards: CONTENT_INK identicos entre los seis y sin nombres de rol (mutacion:
muerde), y el generado sin rastro del token viejo con las 6 definiciones del
nuevo. Dos cronicas fechadas en docs/old-deprecated, intactas a proposito.
- Docs: changelog 54 - reference (eje de tinta) - next-features 13 (divergencia
de label RESUELTA).
Supervision: verificador independiente pre-firma (dos claims MURIERON en
verificacion antes de tocar codigo), tres agentes en fases (censo+baseline ->
implementacion+codemod -> demos -> verificacion de dos niveles -> docs).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
| 233 | `palabras-chrome.css:1432` | `[data-palabras-lang-option]` | `color` | `var(--color-content-subtle)` |
docs(theming): la auditoría de alcance de tema, componente a componente, con su propuesta
El censo medía el eje y no lo explicaba: 5.205 knobs en dos tablas del plan no
dicen QUÉ knob de QUÉ línea no alcanza un tema, ni qué token habría que crear.
Ahora `theming-census.ts --report` escribe la auditoría entera bajo
`docs/audit/theming/`: un README con la vista de conjunto y 170 fichas — 162
recetas con CSS + 8 componentes sin receta, el árbol completo de
`eidos/components/`.
Cada ficha de receta: knobs fuera de alcance con fichero:línea Y selector
(agrupados por clase), sistema transversal aparte, los privados con la columna
que decide («¿deriva de un público?»), y una PROPUESTA de corrección — el token
a declarar en `base.ts` con su valor VERBATIM y su scope TSC. La propuesta
deriva los nombres de recipe-contract §1 y theming §6.7; donde la doctrina no
decide, marca `⚠ decisión` en vez de inventar. Y no propone acuñar lo que la
doctrina prohíbe: lo que posee una capa compartida, el foco, la capa de estado,
un token prestado de otra receta, un shorthand o un eje físico.
Las 8 fichas sin receta dicen —medido, no supuesto— dónde vive su visual: el
componente que componen (icon-button → button), la capa que consumen (affix →
viewport-placement) o la receta ajena que pinta sus attrs (svg → badge/button).
Defectos del instrumento corregidos en el mismo pase, todos encontrados
mirando la salida: un `@import` pegado al primer selector se comía 2 knobs de
color-picker (el suelo del censo no puede moverse); `:not(:disabled)` se leía
como estado y producía `hover-disabled-*`; un knob que lee un privado se
proponía a sí mismo en vez de resolverse por talla; `--icon-size-sm` se
reportaba como préstamo del componente `icon` (ahora el préstamo se verifica
contra las claves del dueño en `base.ts`); y el default de talla salía sin
nombrar en vez de `-md`.
Verificación: censo global idéntico al suelo publicado (5205 · 1621/33% · 856 ·
1880 · 614 · 234) y COMPONENTE A COMPONENTE contra la tabla §9 del plan — 0
diferencias en 162 · regenerar dos veces da el árbol idéntico · el bloque de
veredicto escrito a mano sobrevive · docs:check 0 errores sobre 813 docs ·
prettier limpio (el árbol generado entra en .prettierignore junto a
eidos/generated).
Las 10 primeras fichas llevan ya su veredicto de revisión: análisis correcto en
las 10, propuesta apta en 2 (gradient-builder como piloto, combobox con cinco
correcciones — dos de ellas evitaban romper el default), y 5 que no se
tokenizan en solitario porque son alias de --calendar-*/--field-* y esperan la
decisión de familia. Cuatro destaparon privados con prefijo ajeno o abreviado
declarados en su propio CSS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| 234 | `palabras-chrome.css:1433` | `[data-palabras-lang-option]` | `font-size` | `var(--font-size-xs)` |
| 235 | `palabras-chrome.css:1438` | `[data-palabras-lang-option]:hover:not([data-active])` | `color` | `var(--color-content-primary)` |
| 236 | `palabras-chrome.css:1441` | `[data-palabras-lang-switcher][data-mode='segmented'] [data-palabras-lang-option][data-active]` | `background` | `var(--color-surface-default)` |
| 237 | `palabras-chrome.css:1442` | `[data-palabras-lang-switcher][data-mode='segmented'] [data-palabras-lang-option][data-active]` | `color` | `var(--color-content-primary)` |
| 238 | `palabras-chrome.css:1450` | `[data-palabras-lang-option]::before` | `border-radius` | `var(--radius-full)` |
| 239 | `palabras-chrome.css:1451` | `[data-palabras-lang-option]::before` | `border` | `1px solid var(--color-border-default)` |
| 240 | `palabras-chrome.css:1455` | `[data-palabras-lang-option][data-complete]::before` | `background` | `var(--color-primary-solid)` |
| 241 | `palabras-chrome.css:1456` | `[data-palabras-lang-option][data-complete]::before` | `border-color` | `var(--color-primary-solid)` |
| 242 | `palabras-chrome.css:1462` | `[data-palabras-lang-trigger]` | `gap` | `var(--space-1)` |
| 243 | `palabras-chrome.css:1463` | `[data-palabras-lang-trigger]` | `padding-inline` | `var(--space-2)` |
| 244 | `palabras-chrome.css:1464` | `[data-palabras-lang-trigger]` | `min-block-size` | `var(--space-6)` |
| 245 | `palabras-chrome.css:1465` | `[data-palabras-lang-trigger]` | `border` | `1px solid var(--color-border-default)` |
| 246 | `palabras-chrome.css:1466` | `[data-palabras-lang-trigger]` | `border-radius` | `var(--radius-md)` |
| 247 | `palabras-chrome.css:1467` | `[data-palabras-lang-trigger]` | `background` | `var(--color-surface-default)` |
| 248 | `palabras-chrome.css:1468` | `[data-palabras-lang-trigger]` | `color` | `var(--color-content-primary)` |
| 249 | `palabras-chrome.css:1469` | `[data-palabras-lang-trigger]` | `font-size` | `var(--font-size-xs)` |
| 250 | `palabras-chrome.css:1473` | `[data-palabras-lang-menu-content]` | `padding` | `var(--space-1)` |
| 251 | `palabras-chrome.css:1478` | `[data-palabras-lang-menu]` | `gap` | `var(--space-0-5)` |
| 252 | `palabras-chrome.css:1484` | `[data-palabras-lang-menu] [data-palabras-lang-option]` | `min-block-size` | `var(--space-6)` |
| 253 | `palabras.css:296` | `[data-palabras-doc] [data-palabras-content] pre[data-palabras-code-language]::before` | `font-family` | `var(--font-family-sans, sans-serif)` |
| 254 | `palabras.css:297` | `[data-palabras-doc] [data-palabras-content] pre[data-palabras-code-language]::before` | `font-size` | `var(--font-size-xs)` |
| 255 | `palabras.css:391` | `[data-palabras-doc] [data-palabras-active]` | `outline` | `1.5px dashed var(--color-primary-border)` |
| 256 | `palabras.css:393` | `[data-palabras-doc] [data-palabras-active]` | `border-radius` | `var(--radius-sm)` |
| 257 | `palabras.css:418` | `[data-palabras-doc] [data-palabras-block='columns'] [data-palabras-column]` | `padding` | `var(--space-2)` |
| 258 | `palabras.css:419` | `[data-palabras-doc] [data-palabras-block='columns'] [data-palabras-column]` | `border` | `1px dashed var(--color-neutral-border)` |
| 259 | `palabras.css:420` | `[data-palabras-doc] [data-palabras-block='columns'] [data-palabras-column]` | `border-radius` | `var(--radius-sm)` |
| 260 | `palabras.css:425` | `[data-palabras-doc] [data-palabras-block='columns'] [data-palabras-column]:hover, [data-palabras-doc] [data-palabras-block='columns'] [data-palabras-column]:focus-within` | `border-color` | `var(--color-content-primary)` |
| 261 | `palabras.css:446` | `[data-palabras-doc] figure[data-palabras-block='image'] img` | `border-radius` | `var(--radius-sm)` |
| 262 | `palabras.css:463` | `[data-palabras-doc] figure[data-palabras-block='image'] figcaption` | `font-size` | `var(--font-size-sm)` |
| 263 | `palabras.css:464` | `[data-palabras-doc] figure[data-palabras-block='image'] figcaption` | `color` | `var(--color-content-muted)` |
| 264 | `palabras.css:481` | `[data-palabras-doc] figure[data-palabras-block='image'][data-palabras-image-fit] :where(img, [data-palabras-image-tile])` | `border-radius` | `var(--radius-sm)` |
| 265 | `palabras.css:482` | `[data-palabras-doc] figure[data-palabras-block='image'][data-palabras-image-fit] :where(img, [data-palabras-image-tile])` | `background` | `var(--color-surface-muted)` |
| 266 | `palabras.css:501` | `[data-palabras-doc] [data-palabras-image-placeholder]` | `padding` | `var(--space-6) var(--space-4)` |
| 267 | `palabras.css:502` | `[data-palabras-doc] [data-palabras-image-placeholder]` | `border` | `1.5px dashed var(--color-neutral-border)` |
| 268 | `palabras.css:503` | `[data-palabras-doc] [data-palabras-image-placeholder]` | `border-radius` | `var(--radius-md)` |
| 269 | `palabras.css:504` | `[data-palabras-doc] [data-palabras-image-placeholder]` | `background` | `var(--color-surface-muted)` |
| 270 | `palabras.css:505` | `[data-palabras-doc] [data-palabras-image-placeholder]` | `color` | `var(--color-content-muted)` |
| 271 | `palabras.css:567` | `[data-palabras-doc] [data-palabras-untranslated]` | `outline` | `1.5px dashed var(--color-risk-border, var(--color-risk-solid))` |
| 272 | `palabras.css:569` | `[data-palabras-doc] [data-palabras-untranslated]` | `border-radius` | `var(--radius-sm, 4px)` |
### 1.2 A través de un privado (1)
| # | fichero:línea | selector | propiedad | valor |
| ---: | --- | --- | --- | --- |
| 1 | `palabras-chrome.css:452` | `[data-palabras-col-resize]::before` | `inline-size` | `var(--_palabras-col-resize-w)` |
tooling(theming): el censo aprende a leer la válvula del canon — clase `exception`
Global 58 % → **59 %** sin tocar una línea de CSS: 54 knobs que eran deuda
resultan ser desviaciones que el canon ya había firmado.
`recipe-contract` §3 dice que una desviación anotada `/* literal: <razón> */`
EN SU PROPIA DECLARACIÓN es válida, y `component-audit` la honra desde siempre
(`declarationWindow` + `/literal:/i` en R-2.1, R-2.6 y R-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 literales
sin excusa. Dos instrumentos, un canon, dos respuestas — y la que mandaba era la
del que no sabía leerlo.
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, que
su README documenta como decisión — «No 5× duplicated scale»), `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.
Detalles que costaron medición:
- **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. Se comprueban
todas las líneas que abarca la declaración.
- **`strip()` blanquea en el sitio** (sustituye por espacios, conserva los
saltos), así que el cuerpo despojado y el crudo quedan alineados línea a línea
y basta con guardar el crudo al lado.
- Muta-prueba: retirar una anotación de `prose` mueve el knob de `exception` a
`literal` (21 → 20) y el conteo vuelve al restaurarla.
Efecto colateral bueno: cada ficha gana una **§1.4 «Excepciones firmadas»** que
las LISTA con su razón. Estaban escritas en el CSS y no se leían desde ninguna
parte; ahora la ficha del componente las enseña, que es donde se decide si una
sigue siendo cierta.
Las 163 fichas cambian porque la plantilla cambia (sección nueva + la línea de
reparto); el README de la auditoría gana la fila de la clase y la nota de que
`system` y `exception` quedan fuera del denominador.
Guards: `--names` 4.105 claves, DESVIADAS 0 · component-audit PASS · docs:check
0 · `check` con 72 errores globales y 0 en los ficheros tocados.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
### 1.3 Literales (87)
docs(theming): la auditoría de alcance de tema, componente a componente, con su propuesta
El censo medía el eje y no lo explicaba: 5.205 knobs en dos tablas del plan no
dicen QUÉ knob de QUÉ línea no alcanza un tema, ni qué token habría que crear.
Ahora `theming-census.ts --report` escribe la auditoría entera bajo
`docs/audit/theming/`: un README con la vista de conjunto y 170 fichas — 162
recetas con CSS + 8 componentes sin receta, el árbol completo de
`eidos/components/`.
Cada ficha de receta: knobs fuera de alcance con fichero:línea Y selector
(agrupados por clase), sistema transversal aparte, los privados con la columna
que decide («¿deriva de un público?»), y una PROPUESTA de corrección — el token
a declarar en `base.ts` con su valor VERBATIM y su scope TSC. La propuesta
deriva los nombres de recipe-contract §1 y theming §6.7; donde la doctrina no
decide, marca `⚠ decisión` en vez de inventar. Y no propone acuñar lo que la
doctrina prohíbe: lo que posee una capa compartida, el foco, la capa de estado,
un token prestado de otra receta, un shorthand o un eje físico.
Las 8 fichas sin receta dicen —medido, no supuesto— dónde vive su visual: el
componente que componen (icon-button → button), la capa que consumen (affix →
viewport-placement) o la receta ajena que pinta sus attrs (svg → badge/button).
Defectos del instrumento corregidos en el mismo pase, todos encontrados
mirando la salida: un `@import` pegado al primer selector se comía 2 knobs de
color-picker (el suelo del censo no puede moverse); `:not(:disabled)` se leía
como estado y producía `hover-disabled-*`; un knob que lee un privado se
proponía a sí mismo en vez de resolverse por talla; `--icon-size-sm` se
reportaba como préstamo del componente `icon` (ahora el préstamo se verifica
contra las claves del dueño en `base.ts`); y el default de talla salía sin
nombrar en vez de `-md`.
Verificación: censo global idéntico al suelo publicado (5205 · 1621/33% · 856 ·
1880 · 614 · 234) y COMPONENTE A COMPONENTE contra la tabla §9 del plan — 0
diferencias en 162 · regenerar dos veces da el árbol idéntico · el bloque de
veredicto escrito a mano sobrevive · docs:check 0 errores sobre 813 docs ·
prettier limpio (el árbol generado entra en .prettierignore junto a
eidos/generated).
Las 10 primeras fichas llevan ya su veredicto de revisión: análisis correcto en
las 10, propuesta apta en 2 (gradient-builder como piloto, combobox con cinco
correcciones — dos de ellas evitaban romper el default), y 5 que no se
tokenizan en solitario porque son alias de --calendar-*/--field-* y esperan la
decisión de familia. Cuatro destaparon privados con prefijo ajeno o abreviado
declarados en su propio CSS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| # | fichero:línea | selector | propiedad | valor |
| ---: | --- | --- | --- | --- |
| 1 | `palabras-chrome.css:22` | `[data-palabras-shell]` | `inline-size` | `100%` |
| 2 | `palabras-chrome.css:29` | `[data-palabras-doc-card]` | `min-block-size` | `20rem` |
| 3 | `palabras-chrome.css:105` | `[data-palabras-menubar]` | `inline-size` | `100%` |
| 4 | `palabras-chrome.css:139` | `[data-palabras-panel][data-menubar-panel]` | `inline-size` | `328px` |
| 5 | `palabras-chrome.css:155` | `[data-menubar-panel][data-palabras-inspector-surface]` | `inline-size` | `fit-content` |
| 6 | `palabras-chrome.css:274` | `[data-palabras-inspector] [data-css-field], [data-palabras-inspector] [data-select-trigger]` | `inline-size` | `100%` |
| 7 | `palabras-chrome.css:304` | `[data-palabras-handle-menu] [role='menuitem'] svg` | `inline-size` | `1rem` |
| 8 | `palabras-chrome.css:305` | `[data-palabras-handle-menu] [role='menuitem'] svg` | `block-size` | `1rem` |
| 9 | `palabras-chrome.css:306` | `[data-palabras-handle-menu] [role='menuitem'] svg` | `opacity` | `0.85` |
| 10 | `palabras-chrome.css:313` | `[data-palabras-insert-grid]` | `gap` | `2px` |
| 11 | `palabras-chrome.css:325` | `[data-palabras-canvas] [data-palabras-column-inserter][data-visible]` | `opacity` | `1` |
| 12 | `palabras-chrome.css:332` | `[data-palabras-canvas] [data-palabras-block-drop-line]` | `block-size` | `2px` |
| 13 | `palabras-chrome.css:334` | `[data-palabras-canvas] [data-palabras-block-drop-line]` | `border-radius` | `1px` |
| 14 | `palabras-chrome.css:377` | `[data-palabras-outline-trigger]:disabled` | `opacity` | `0.5` |
| 15 | `palabras-chrome.css:381` | `[data-palabras-outline-trigger] svg` | `inline-size` | `1em` |
| 16 | `palabras-chrome.css:382` | `[data-palabras-outline-trigger] svg` | `block-size` | `1em` |
| 17 | `palabras-chrome.css:385` | `[data-palabras-outline]` | `min-inline-size` | `14rem` |
| 18 | `palabras-chrome.css:399` | `[data-palabras-outline-item]` | `inline-size` | `100%` |
| 19 | `palabras-chrome.css:431` | `[data-palabras-col-resize]` | `inline-size` | `11px` |
| 20 | `palabras-chrome.css:469` | `[data-palabras-live]` | `inline-size` | `1px` |
| 21 | `palabras-chrome.css:470` | `[data-palabras-live]` | `block-size` | `1px` |
| 22 | `palabras-chrome.css:493` | `[data-palabras-panel][data-palabras-panel]:not([data-palabras-docked]):not([data-menubar-panel])` | `height` | `auto !important` |
| 23 | `palabras-chrome.css:546` | `[data-palabras-panel][data-palabras-mobile][data-drawer-content]` | `inline-size` | `100%` |
| 24 | `palabras-chrome.css:600` | `[data-palabras-panel-icon] svg` | `inline-size` | `1.05rem` |
| 25 | `palabras-chrome.css:601` | `[data-palabras-panel-icon] svg` | `block-size` | `1.05rem` |
| 26 | `palabras-chrome.css:608` | `[data-palabras-panel] [data-float-panel-title], [data-palabras-panel] [data-drawer-title], [data-palabras-panel] [data-palabras-menu-title]` | `letter-spacing` | `-0.01em` |
| 27 | `palabras-chrome.css:649` | `[data-palabras-tabs]` | `inline-size` | `100%` |
| 28 | `palabras-chrome.css:715` | `[data-palabras-tabs] [data-tabs-content] > [data-scroll-area]` | `inline-size` | `100%` |
| 29 | `palabras-chrome.css:784` | `[data-palabras-field][data-stack] > [data-toggle-group][data-palabras-segmented] [data-toggle-group-item]` | `min-inline-size` | `max-content` |
| 30 | `palabras-chrome.css:795` | `[data-palabras-field][data-disabled]` | `opacity` | `0.45` |
| 31 | `palabras-chrome.css:821` | `[data-palabras-field] [data-css-field]` | `inline-size` | `100%` |
| 32 | `palabras-chrome.css:824` | `[data-palabras-panel] [data-select-trigger]` | `inline-size` | `100%` |
| 33 | `palabras-chrome.css:835` | `[data-palabras-text]` | `inline-size` | `100%` |
| 34 | `palabras-chrome.css:837` | `[data-palabras-text]` | `border` | `1px solid transparent` |
| 35 | `palabras-chrome.css:893` | `[data-palabras-spacing]` | `inline-size` | `100%` |
| 36 | `palabras-chrome.css:910` | `[data-palabras-panel] [data-palabras-spacing-scale]` | `inline-size` | `6.5rem` |
| 37 | `palabras-chrome.css:911` | `[data-palabras-panel] [data-palabras-spacing-scale]` | `min-inline-size` | `6.5rem` |
| 38 | `palabras-chrome.css:916` | `[data-palabras-spacing-cell]` | `inline-size` | `100%` |
| 39 | `palabras-chrome.css:940` | `[data-palabras-border]` | `inline-size` | `100%` |
| 40 | `palabras-chrome.css:950` | `[data-palabras-panel] [data-palabras-border-style]` | `inline-size` | `100%` |
| 41 | `palabras-chrome.css:976` | `[data-palabras-panel] [data-palabras-border-radius-scale]` | `inline-size` | `100%` |
| 42 | `palabras-chrome.css:985` | `[data-palabras-typography]` | `inline-size` | `100%` |
| 43 | `palabras-chrome.css:1024` | `[data-palabras-panel] [data-palabras-design]` | `inline-size` | `100%` |
| 44 | `palabras-chrome.css:1048` | `[data-palabras-panel] [data-palabras-design] [data-accordion-content] [data-scroll-area]` | `inline-size` | `100%` |
| 45 | `palabras-chrome.css:1142` | `[data-palabras-src-group]` | `inline-size` | `100%` |
| 46 | `palabras-chrome.css:1180` | `[data-palabras-appearance] [data-number-field]` | `inline-size` | `6rem` |
| 47 | `palabras-chrome.css:1219` | `[data-palabras-bubble-divider]` | `inline-size` | `1px` |
| 48 | `palabras-chrome.css:1220` | `[data-palabras-bubble-divider]` | `block-size` | `1.15rem` |
| 49 | `palabras-chrome.css:1231` | `[data-palabras-bubble-link] input` | `inline-size` | `15rem` |
| 50 | `palabras-chrome.css:1251` | `[data-palabras-bubble-size]` | `inline-size` | `7rem` |
| 51 | `palabras-chrome.css:1254` | `[data-palabras-bubble-family]` | `inline-size` | `12rem` |
| 52 | `palabras-chrome.css:1258` | `[data-palabras-bubble-size] [data-number-field], [data-palabras-bubble-family] [data-select-trigger]` | `inline-size` | `100%` |
| 53 | `palabras-chrome.css:1277` | `[data-palabras-slash]` | `gap` | `1px` |
| 54 | `palabras-chrome.css:1278` | `[data-palabras-slash]` | `min-inline-size` | `15rem` |
| 55 | `palabras-chrome.css:1292` | `[data-palabras-slash-item]` | `inline-size` | `100%` |
| 56 | `palabras-chrome.css:1352` | `[data-palabras-find-input]` | `inline-size` | `13rem` |
| 57 | `palabras-chrome.css:1371` | `[data-palabras-find-count]` | `min-inline-size` | `3rem` |
| 58 | `palabras-chrome.css:1379` | `[data-palabras-find-sep]` | `inline-size` | `1px` |
| 59 | `palabras-chrome.css:1380` | `[data-palabras-find-sep]` | `block-size` | `1.15rem` |
| 60 | `palabras-chrome.css:1434` | `[data-palabras-lang-option]` | `font-weight` | `500` |
| 61 | `palabras-chrome.css:1443` | `[data-palabras-lang-switcher][data-mode='segmented'] [data-palabras-lang-option][data-active]` | `font-weight` | `600` |
| 62 | `palabras-chrome.css:1448` | `[data-palabras-lang-option]::before` | `inline-size` | `6px` |
| 63 | `palabras-chrome.css:1449` | `[data-palabras-lang-option]::before` | `block-size` | `6px` |
| 64 | `palabras-chrome.css:1479` | `[data-palabras-lang-menu]` | `min-inline-size` | `8rem` |
| 65 | `palabras-chrome.css:1483` | `[data-palabras-lang-menu] [data-palabras-lang-option]` | `inline-size` | `100%` |
| 66 | `palabras.css:150` | `[data-palabras-doc] [data-palabras-content] blockquote[data-palabras-quote-marks]::before` | `font-size` | `2.5em` |
| 67 | `palabras.css:151` | `[data-palabras-doc] [data-palabras-content] blockquote[data-palabras-quote-marks]::before` | `line-height` | `0.6` |
| 68 | `palabras.css:153` | `[data-palabras-doc] [data-palabras-content] blockquote[data-palabras-quote-marks]::before` | `opacity` | `0.3` |
| 69 | `palabras.css:168` | `[data-palabras-doc] [data-palabras-content] [data-palabras-block='callout'][data-palabras-callout-icon]::before` | `font-size` | `1.1em` |
| 70 | `palabras.css:169` | `[data-palabras-doc] [data-palabras-content] [data-palabras-block='callout'][data-palabras-callout-icon]::before` | `line-height` | `1` |
| 71 | `palabras.css:170` | `[data-palabras-doc] [data-palabras-content] [data-palabras-block='callout'][data-palabras-callout-icon]::before` | `opacity` | `0.9` |
| 72 | `palabras.css:206` | `[data-palabras-doc] [data-palabras-content] table` | `inline-size` | `100%` |
| 73 | `palabras.css:227` | `[data-palabras-doc] [data-palabras-content] table[data-palabras-table-zebra] tbody tr:nth-child(even) td` | `background` | `var( --palabras-scheme-table-zebra-bg, color-mix(in srgb, currentColor 4%, transparent) )` |
| 74 | `palabras.css:298` | `[data-palabras-doc] [data-palabras-content] pre[data-palabras-code-language]::before` | `font-weight` | `600` |
| 75 | `palabras.css:299` | `[data-palabras-doc] [data-palabras-content] pre[data-palabras-code-language]::before` | `line-height` | `1` |
| 76 | `palabras.css:301` | `[data-palabras-doc] [data-palabras-content] pre[data-palabras-code-language]::before` | `letter-spacing` | `0.06em` |
| 77 | `palabras.css:416` | `[data-palabras-doc] [data-palabras-block='columns'] [data-palabras-column]` | `min-block-size` | `3em` |
| 78 | `palabras.css:456` | `[data-palabras-doc] figure[data-palabras-block='image'][data-palabras-image-full-width]` | `inline-size` | `100%` |
| 79 | `palabras.css:459` | `[data-palabras-doc] figure[data-palabras-block='image'][data-palabras-image-full-width] img` | `inline-size` | `100%` |
| 80 | `palabras.css:472` | `[data-palabras-doc] figure[data-palabras-block='image'][data-palabras-image-fit]` | `inline-size` | `100%` |
| 81 | `palabras.css:477` | `[data-palabras-doc] figure[data-palabras-block='image'][data-palabras-image-fit] :where(img, [data-palabras-image-tile])` | `inline-size` | `100%` |
| 82 | `palabras.css:498` | `[data-palabras-doc] [data-palabras-image-placeholder]` | `inline-size` | `100%` |
| 83 | `palabras.css:500` | `[data-palabras-doc] [data-palabras-image-placeholder]` | `min-block-size` | `11rem` |
| 84 | `palabras.css:510` | `[data-palabras-doc] [data-palabras-image-placeholder]::before` | `inline-size` | `4.5rem` |
| 85 | `palabras.css:511` | `[data-palabras-doc] [data-palabras-image-placeholder]::before` | `block-size` | `4.5rem` |
| 86 | `palabras.css:512` | `[data-palabras-doc] [data-palabras-image-placeholder]::before` | `background` | `url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%239aa0aa'%20stroke-width='1.75'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Crect%20width='18'%20height='18'%20x='3'%20y='3'%20rx='2'%20ry='2'/%3E%3Ccircle%20cx='9'%20cy='9'%20r='2'/%3E%3Cpath%20d='m21%2015-3.086-3.086a2%202%200%200%200-2.828%200L6%2021'/%3E%3C/svg%3E") center / contain no-repeat` |
tooling(theming): el censo aprende a leer la válvula del canon — clase `exception`
Global 58 % → **59 %** sin tocar una línea de CSS: 54 knobs que eran deuda
resultan ser desviaciones que el canon ya había firmado.
`recipe-contract` §3 dice que una desviación anotada `/* literal: <razón> */`
EN SU PROPIA DECLARACIÓN es válida, y `component-audit` la honra desde siempre
(`declarationWindow` + `/literal:/i` en R-2.1, R-2.6 y R-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 literales
sin excusa. Dos instrumentos, un canon, dos respuestas — y la que mandaba era la
del que no sabía leerlo.
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, que
su README documenta como decisión — «No 5× duplicated scale»), `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.
Detalles que costaron medición:
- **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. Se comprueban
todas las líneas que abarca la declaración.
- **`strip()` blanquea en el sitio** (sustituye por espacios, conserva los
saltos), así que el cuerpo despojado y el crudo quedan alineados línea a línea
y basta con guardar el crudo al lado.
- Muta-prueba: retirar una anotación de `prose` mueve el knob de `exception` a
`literal` (21 → 20) y el conteo vuelve al restaurarla.
Efecto colateral bueno: cada ficha gana una **§1.4 «Excepciones firmadas»** que
las LISTA con su razón. Estaban escritas en el CSS y no se leían desde ninguna
parte; ahora la ficha del componente las enseña, que es donde se decide si una
sigue siendo cierta.
Las 163 fichas cambian porque la plantilla cambia (sección nueva + la línea de
reparto); el README de la auditoría gana la fila de la clase y la nota de que
`system` y `exception` quedan fuera del denominador.
Guards: `--names` 4.105 claves, DESVIADAS 0 · component-audit PASS · docs:check
0 · `check` con 72 errores globales y 0 en los ficheros tocados.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| 87 | `palabras.css:560` | `[data-palabras-doc] [data-palabras-i18n-fallback]::before` | `opacity` | `0.6` |
docs(theming): la auditoría de alcance de tema, componente a componente, con su propuesta
El censo medía el eje y no lo explicaba: 5.205 knobs en dos tablas del plan no
dicen QUÉ knob de QUÉ línea no alcanza un tema, ni qué token habría que crear.
Ahora `theming-census.ts --report` escribe la auditoría entera bajo
`docs/audit/theming/`: un README con la vista de conjunto y 170 fichas — 162
recetas con CSS + 8 componentes sin receta, el árbol completo de
`eidos/components/`.
Cada ficha de receta: knobs fuera de alcance con fichero:línea Y selector
(agrupados por clase), sistema transversal aparte, los privados con la columna
que decide («¿deriva de un público?»), y una PROPUESTA de corrección — el token
a declarar en `base.ts` con su valor VERBATIM y su scope TSC. La propuesta
deriva los nombres de recipe-contract §1 y theming §6.7; donde la doctrina no
decide, marca `⚠ decisión` en vez de inventar. Y no propone acuñar lo que la
doctrina prohíbe: lo que posee una capa compartida, el foco, la capa de estado,
un token prestado de otra receta, un shorthand o un eje físico.
Las 8 fichas sin receta dicen —medido, no supuesto— dónde vive su visual: el
componente que componen (icon-button → button), la capa que consumen (affix →
viewport-placement) o la receta ajena que pinta sus attrs (svg → badge/button).
Defectos del instrumento corregidos en el mismo pase, todos encontrados
mirando la salida: un `@import` pegado al primer selector se comía 2 knobs de
color-picker (el suelo del censo no puede moverse); `:not(:disabled)` se leía
como estado y producía `hover-disabled-*`; un knob que lee un privado se
proponía a sí mismo en vez de resolverse por talla; `--icon-size-sm` se
reportaba como préstamo del componente `icon` (ahora el préstamo se verifica
contra las claves del dueño en `base.ts`); y el default de talla salía sin
nombrar en vez de `-md`.
Verificación: censo global idéntico al suelo publicado (5205 · 1621/33% · 856 ·
1880 · 614 · 234) y COMPONENTE A COMPONENTE contra la tabla §9 del plan — 0
diferencias en 162 · regenerar dos veces da el árbol idéntico · el bloque de
veredicto escrito a mano sobrevive · docs:check 0 errores sobre 813 docs ·
prettier limpio (el árbol generado entra en .prettierignore junto a
eidos/generated).
Las 10 primeras fichas llevan ya su veredicto de revisión: análisis correcto en
las 10, propuesta apta en 2 (gradient-builder como piloto, combobox con cinco
correcciones — dos de ellas evitaban romper el default), y 5 que no se
tokenizan en solitario porque son alias de --calendar-*/--field-* y esperan la
decisión de familia. Cuatro destaparon privados con prefijo ajeno o abreviado
declarados en su propio CSS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
tooling(theming): el censo aprende a leer la válvula del canon — clase `exception`
Global 58 % → **59 %** sin tocar una línea de CSS: 54 knobs que eran deuda
resultan ser desviaciones que el canon ya había firmado.
`recipe-contract` §3 dice que una desviación anotada `/* literal: <razón> */`
EN SU PROPIA DECLARACIÓN es válida, y `component-audit` la honra desde siempre
(`declarationWindow` + `/literal:/i` en R-2.1, R-2.6 y R-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 literales
sin excusa. Dos instrumentos, un canon, dos respuestas — y la que mandaba era la
del que no sabía leerlo.
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, que
su README documenta como decisión — «No 5× duplicated scale»), `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.
Detalles que costaron medición:
- **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. Se comprueban
todas las líneas que abarca la declaración.
- **`strip()` blanquea en el sitio** (sustituye por espacios, conserva los
saltos), así que el cuerpo despojado y el crudo quedan alineados línea a línea
y basta con guardar el crudo al lado.
- Muta-prueba: retirar una anotación de `prose` mueve el knob de `exception` a
`literal` (21 → 20) y el conteo vuelve al restaurarla.
Efecto colateral bueno: cada ficha gana una **§1.4 «Excepciones firmadas»** que
las LISTA con su razón. Estaban escritas en el CSS y no se leían desde ninguna
parte; ahora la ficha del componente las enseña, que es donde se decide si una
sigue siendo cierta.
Las 163 fichas cambian porque la plantilla cambia (sección nueva + la línea de
reparto); el README de la auditoría gana la fila de la clase y la nota de que
`system` y `exception` quedan fuera del denominador.
Guards: `--names` 4.105 claves, DESVIADAS 0 · component-audit PASS · docs:check
0 · `check` con 72 errores globales y 0 en los ficheros tocados.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
### 1.4 Excepciones firmadas (3) — fuera del ratio
Literales que llevan su anotación `/* literal: <razón> */` en la propia
declaración: la válvula de recipe-contract §3, la misma que honra
`component-audit` . **Una desviación firmada no es deuda** — se listan para que la
razón se lea, no para acuñarlas.
| # | fichero:línea | selector | propiedad | valor |
| ---: | --- | --- | --- | --- |
| 1 | `palabras.css:538` | `[data-palabras-doc] [data-palabras-marks~='code']` | `font-size` | `0.9em` |
| 2 | `palabras.css:546` | `[data-palabras-doc] [data-palabras-marks~='sub']` | `font-size` | `0.75em` |
| 3 | `palabras.css:550` | `[data-palabras-doc] [data-palabras-marks~='sup']` | `font-size` | `0.75em` |
docs(theming): la auditoría de alcance de tema, componente a componente, con su propuesta
El censo medía el eje y no lo explicaba: 5.205 knobs en dos tablas del plan no
dicen QUÉ knob de QUÉ línea no alcanza un tema, ni qué token habría que crear.
Ahora `theming-census.ts --report` escribe la auditoría entera bajo
`docs/audit/theming/`: un README con la vista de conjunto y 170 fichas — 162
recetas con CSS + 8 componentes sin receta, el árbol completo de
`eidos/components/`.
Cada ficha de receta: knobs fuera de alcance con fichero:línea Y selector
(agrupados por clase), sistema transversal aparte, los privados con la columna
que decide («¿deriva de un público?»), y una PROPUESTA de corrección — el token
a declarar en `base.ts` con su valor VERBATIM y su scope TSC. La propuesta
deriva los nombres de recipe-contract §1 y theming §6.7; donde la doctrina no
decide, marca `⚠ decisión` en vez de inventar. Y no propone acuñar lo que la
doctrina prohíbe: lo que posee una capa compartida, el foco, la capa de estado,
un token prestado de otra receta, un shorthand o un eje físico.
Las 8 fichas sin receta dicen —medido, no supuesto— dónde vive su visual: el
componente que componen (icon-button → button), la capa que consumen (affix →
viewport-placement) o la receta ajena que pinta sus attrs (svg → badge/button).
Defectos del instrumento corregidos en el mismo pase, todos encontrados
mirando la salida: un `@import` pegado al primer selector se comía 2 knobs de
color-picker (el suelo del censo no puede moverse); `:not(:disabled)` se leía
como estado y producía `hover-disabled-*`; un knob que lee un privado se
proponía a sí mismo en vez de resolverse por talla; `--icon-size-sm` se
reportaba como préstamo del componente `icon` (ahora el préstamo se verifica
contra las claves del dueño en `base.ts`); y el default de talla salía sin
nombrar en vez de `-md`.
Verificación: censo global idéntico al suelo publicado (5205 · 1621/33% · 856 ·
1880 · 614 · 234) y COMPONENTE A COMPONENTE contra la tabla §9 del plan — 0
diferencias en 162 · regenerar dos veces da el árbol idéntico · el bloque de
veredicto escrito a mano sobrevive · docs:check 0 errores sobre 813 docs ·
prettier limpio (el árbol generado entra en .prettierignore junto a
eidos/generated).
Las 10 primeras fichas llevan ya su veredicto de revisión: análisis correcto en
las 10, propuesta apta en 2 (gradient-builder como piloto, combobox con cinco
correcciones — dos de ellas evitaban romper el default), y 5 que no se
tokenizan en solitario porque son alias de --calendar-*/--field-* y esperan la
decisión de familia. Cuatro destaparon privados con prefijo ajeno o abreviado
declarados en su propio CSS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## 2. Sistema transversal (5) — informativo, fuera del ratio
Un tema los alcanza **a nivel de sistema** , por diseño (recipe-contract §2).
| # | fichero:línea | selector | propiedad | valor |
| ---: | --- | --- | --- | --- |
| 1 | `palabras-chrome.css:268` | `[data-palabras-inspector] [data-field-control]:focus-within, [data-palabras-inspector] [data-css-field]:focus-within, [data-palabras-inspector] [data-textarea][data-focused] [data-textarea-input], [data-palabras-inspector] [data-select-trigger]:focus-visible` | `border-color` | `var(--focus-ring-color)` |
| 2 | `palabras-chrome.css:286` | `[data-palabras-inspector] [data-field] input[data-dirty]` | `box-shadow` | `inset 0 0 0 1px var(--focus-ring-color)` |
| 3 | `palabras-chrome.css:816` | `[data-palabras-panel] [data-field-control]:focus-within, [data-palabras-panel] [data-css-field]:focus-within, [data-palabras-panel] [data-textarea][data-focused] [data-textarea-input], [data-palabras-panel] [data-select-trigger]:focus-visible, [data-palabras-text]:focus-visible, [data-palabras-spacing-cell]:focus-visible` | `border-color` | `var(--focus-ring-color)` |
| 4 | `palabras-chrome.css:1242` | `[data-palabras-bubble-link] input:focus` | `border-color` | `var(--focus-ring-color)` |
| 5 | `palabras-chrome.css:1364` | `[data-palabras-find-input]:focus` | `border-color` | `var(--focus-ring-color)` |
## 3. Privados de la receta — ¿de dónde sale su valor?
| privado | declaraciones | valor(es) | origen | ¿deriva de un público? |
| --- | ---: | --- | --- | :-: |
| `--_palabras-content-padding-inline` | 1 | `var(--space-8)` | global | no |
| `--_palabras-col-resize-w` | 2 | `2px` , `3px` | literal | no |
| `--_palabras-label-col` | 1 | `7rem` | literal | no |
| `--_palabras-section-reserve` | 1 | `26rem` | literal | no |
| `--_palabras-callout-glyph` | 6 | `'\2139\FE0E'` , `'\2713'` , `'\2605'` , `'\26A0\FE0E'` , `'\2691'` , `'\2715'` | literal | no |
Consumidos y **no declarados en el CSS** (vienen de `base.ts` o de un estilo inline del wrapper): `--_palabras-bubble-x` , `--_palabras-bubble-y` , `--_palabras-slash-x` , `--_palabras-slash-y` .
## 4. Propuesta de corrección
- **Consume la capa compartida `picker-shell` .** Un eje que la capa posee se consume como `var(--_x, var(--x))` ; el consumidor **no acuña** `--palabras-{eje}` para él — sería un vocabulario paralelo (README de `eidos/components` , «Capas compartidas» regla 2).
- **Consume tokens públicos de `scroll-area` .** Un token prestado importa la semántica de su dueño: la corrección no es duplicarlo con prefijo propio, sino la decisión de familia que la auditoría de fase 1 dejó registrada (`theming-audit.md` §B, familia calendar).
### 4.1 Tokens a declarar en `lib/recipes/base.ts` (233)
Valor **verbatim** del CSS de hoy: el default no se mueve, sólo cambia quién
puede moverlo. Nombres derivados de recipe-contract §1 (ejes lógicos, talla
al final) y theming §6.7 (slots de color, modificador delante). Un token con
DOS valores distintos es una colisión de nombre: son dos knobs, o el nombre
no distingue lo que debería — se marca `⚠` .
| token (`--palabras-…`) | scope TSC | valor propuesto | usos |
| --- | --- | --- | ---: |
| `doc-radius` | `root` | ⚠ `var(--radius-full)` / `var(--radius-sm)` / `var(--radius-md)` / `var(--radius-sm, 4px)` | 7 |
| `doc-font-size` | `root` | ⚠ `2.5em` / `1.1em` / `var(--font-size-xs)` / `var(--font-size-sm)` / `0.9em` / `0.75em` | 7 |
| `doc-bg` | `root` | ⚠ `var(--color-surface-default)` / `var( --palabras-scheme-table-zebra-bg, color-mix(in srgb, currentColor 4%, transparent) )` / `var(--color-surface-muted)` / `url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%239aa0aa'%20stroke-width='1.75'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Crect%20width='18'%20height='18'%20x='3'%20y='3'%20rx='2'%20ry='2'/%3E%3Ccircle%20cx='9'%20cy='9'%20r='2'/%3E%3Cpath%20d='m21%2015-3.086-3.086a2%202%200%200%200-2.828%200L6%2021'/%3E%3C/svg%3E") center / contain no-repeat` | 5 |
| `panel-bg` | `root` | ⚠ `var(--color-surface-default)` / `var(--color-surface-muted)` | 4 |
| `doc-fg` | `root` | `var(--color-content-muted)` | 3 |
| `panel-width` | `root` | ⚠ `328px` / `6.5rem` | 3 |
| `outline-item-padding-inline` | `root` | ⚠ `var(--space-3)` / `var(--space-5)` / `var(--space-8)` | 3 |
| `col-resize-width` | `root` | ⚠ `11px` / `2px` / `3px` | 3 |
| `panel-font-size` | `root` | ⚠ `var(--font-size-md)` / `var(--font-size-sm)` | 3 |
| `doc-opacity` | `root` | ⚠ `0.3` / `0.9` / `0.6` | 3 |
| `doc-height` | `root` | ⚠ `3em` / `11rem` / `4.5rem` | 3 |
| `hover-doc-border` | `root` | ⚠ `var(--color-primary-border)` / `var(--color-content-primary)` | 2 |
| `inspector-font-family` | `root` | `var(--style-label-font-family)` | 2 |
| `inspector-bg` | `root` | ⚠ `var(--color-surface-muted)` / `var(--color-surface-default)` | 2 |
| `panel-radius` | `root` | ⚠ `var(--radius-xl)` / `var(--radius-md)` | 2 |
| `panel-icon-width` | `root` | ⚠ `var(--space-8)` / `1.05rem` | 2 |
| `panel-icon-height` | `root` | ⚠ `var(--space-8)` / `1.05rem` | 2 |
| `panel-font-weight` | `root` | `var(--font-weight-semibold)` | 2 |
| `panel-fg` | `root` | `var(--color-content-primary)` | 2 |
| `panel-padding-inline` | `root` | ⚠ `var(--space-4)` / `calc(var(--scroll-area-scrollbar-size, var(--space-2-5)) + var(--space-1-5))` | 2 |
| `panel-padding-block` | `root` | ⚠ `var(--space-1) var(--space-4)` / `var(--space-3-5)` | 2 |
| `field-row-gap` | `root` | ⚠ `var(--space-2)` / `var(--space-0-5, 2px)` | 2 |
| `segmented-bg` | `root` | ⚠ `var(--color-surface-muted)` / `var(--color-primary-solid)` | 2 |
| `segmented-radius` | `root` | ⚠ `var(--radius-lg)` / `calc(var(--radius-lg) - var(--space-0-5))` | 2 |
feat(color)!: una palabra, un significado - primary/secondary son SIEMPRE jerarquia
La homonimia muere: `primary`/`secondary` significan JERARQUIA DE MARCA en el
catalogo ENTERO, tambien dentro de los seis primitivos de tinta (text, heading,
display, code, label, s-text). El paso de tinta del 82 % se llama `subtle` -
PROP y TOKEN, sin excepcion: el nombre es el contrato en el artefacto (la misma
ley que la FIRMA B' y la 12.9; se rechazo por escrito la via "solo el prop con
tabla de traduccion" - las excepciones legitimas son las FIRMADAS con razon,
no las inventadas al decidir para abaratar).
- Los seis CONTENT_INK, IDENTICOS: {subtle, muted, disabled, on-solid}; el
nivel-1 es el DEFAULT sin prop. `label` gana `on-solid` (cierra la
divergencia de familia registrada en e4fa616e5).
- Renombre completo: --color-content-secondary -> --color-content-subtle y la
clave de config content.secondary -> content.subtle (RUPTURA de API de
tema). 355 referencias por patrones acotados; la raiz SIN prefijo
(cssVar('color-content-secondary'), render-css.ts) incluida; en grafito.ts
conviven tres claves `subtle` (content/border/shadow) y solo cambio content.
El generado, reproducido BYTE A BYTE aplicando solo el renombre al anterior.
- Codemod value-preserving: 11 call sites (6 secondary->subtle incl.
expresiones y ternarias; 5 primary->fuera, incl. TRES defaults de prop) con
la condicion ROJA caracterizada (--style-caption-color es el UNICO estilo
cuya tinta default no es primary; los 5 sitios caen en ramas body). alpha/
(untracked, TERMINATED) fuera.
- Las 6 demos migradas al vocabulario nuevo (s-text: CERO cambios, no tiene
lista de tinta); label arranca en el default y pinta IDENTICO (contrafactual
medido: el estado viejo habria pintado el morado de marca).
- Neutra en pixel, MEDIDO: nivel 1 ESTRICTO CERO en 71.200 valores (blocks
enteros, s-text entero, subarboles data-*); nivel 2: 31 diffs, todos
trazados a las ediciones firmadas del harness (anchos de chips, reindexado
de la lista de label con las tintas supervivientes byte a byte). Total
171.712 valores + 59.072 de re-corridas a 0 de ruido.
- Guards: CONTENT_INK identicos entre los seis y sin nombres de rol (mutacion:
muerde), y el generado sin rastro del token viejo con las 6 definiciones del
nuevo. Dos cronicas fechadas en docs/old-deprecated, intactas a proposito.
- Docs: changelog 54 - reference (eje de tinta) - next-features 13 (divergencia
de label RESUELTA).
Supervision: verificador independiente pre-firma (dos claims MURIERON en
verificacion antes de tocar codigo), tres agentes en fases (censo+baseline ->
implementacion+codemod -> demos -> verificacion de dos niveles -> docs).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
| `segmented-fg` | `root` | ⚠ `var(--color-content-subtle)` / `var(--color-content-on-solid)` | 2 |
docs(theming): la auditoría de alcance de tema, componente a componente, con su propuesta
El censo medía el eje y no lo explicaba: 5.205 knobs en dos tablas del plan no
dicen QUÉ knob de QUÉ línea no alcanza un tema, ni qué token habría que crear.
Ahora `theming-census.ts --report` escribe la auditoría entera bajo
`docs/audit/theming/`: un README con la vista de conjunto y 170 fichas — 162
recetas con CSS + 8 componentes sin receta, el árbol completo de
`eidos/components/`.
Cada ficha de receta: knobs fuera de alcance con fichero:línea Y selector
(agrupados por clase), sistema transversal aparte, los privados con la columna
que decide («¿deriva de un público?»), y una PROPUESTA de corrección — el token
a declarar en `base.ts` con su valor VERBATIM y su scope TSC. La propuesta
deriva los nombres de recipe-contract §1 y theming §6.7; donde la doctrina no
decide, marca `⚠ decisión` en vez de inventar. Y no propone acuñar lo que la
doctrina prohíbe: lo que posee una capa compartida, el foco, la capa de estado,
un token prestado de otra receta, un shorthand o un eje físico.
Las 8 fichas sin receta dicen —medido, no supuesto— dónde vive su visual: el
componente que componen (icon-button → button), la capa que consumen (affix →
viewport-placement) o la receta ajena que pinta sus attrs (svg → badge/button).
Defectos del instrumento corregidos en el mismo pase, todos encontrados
mirando la salida: un `@import` pegado al primer selector se comía 2 knobs de
color-picker (el suelo del censo no puede moverse); `:not(:disabled)` se leía
como estado y producía `hover-disabled-*`; un knob que lee un privado se
proponía a sí mismo en vez de resolverse por talla; `--icon-size-sm` se
reportaba como préstamo del componente `icon` (ahora el préstamo se verifica
contra las claves del dueño en `base.ts`); y el default de talla salía sin
nombrar en vez de `-md`.
Verificación: censo global idéntico al suelo publicado (5205 · 1621/33% · 856 ·
1880 · 614 · 234) y COMPONENTE A COMPONENTE contra la tabla §9 del plan — 0
diferencias en 162 · regenerar dos veces da el árbol idéntico · el bloque de
veredicto escrito a mano sobrevive · docs:check 0 errores sobre 813 docs ·
prettier limpio (el árbol generado entra en .prettierignore junto a
eidos/generated).
Las 10 primeras fichas llevan ya su veredicto de revisión: análisis correcto en
las 10, propuesta apta en 2 (gradient-builder como piloto, combobox con cinco
correcciones — dos de ellas evitaban romper el default), y 5 que no se
tokenizan en solitario porque son alias de --calendar-*/--field-* y esperan la
decisión de familia. Cuatro destaparon privados con prefijo ajeno o abreviado
declarados en su propio CSS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| `bubble-bg` | `root` | ⚠ `var(--color-surface-overlay)` / `var(--color-primary-element)` | 2 |
| `bubble-link-bg` | `root` | ⚠ `var(--color-surface-muted)` / `var(--color-surface-default)` | 2 |
| `find-bg` | `root` | ⚠ `var(--color-surface-overlay)` / `var(--color-primary-element)` | 2 |
| `find-input-bg` | `root` | ⚠ `var(--color-surface-muted)` / `var(--color-surface-default)` | 2 |
| `lang-switcher-bg` | `root` | ⚠ `var(--color-surface-muted)` / `var(--color-surface-default)` | 2 |
| `lang-option-height` | `root` | ⚠ `var(--space-5)` / `6px` | 2 |
| `lang-option-radius` | `root` | ⚠ `var(--radius-sm)` / `var(--radius-full)` | 2 |
| `doc-card-height` | `root` | `20rem` | 1 |
| `doc-shadow` | `root` | `var(--shadow-2)` | 1 |
| `hover-doc-bg` | `root` | `var(--color-surface-default)` | 1 |
| `hover-doc-fg` | `root` | `var(--color-primary-text)` | 1 |
| `menubar-gap` | `root` | `var(--space-1)` | 1 |
feat(color)!: una palabra, un significado - primary/secondary son SIEMPRE jerarquia
La homonimia muere: `primary`/`secondary` significan JERARQUIA DE MARCA en el
catalogo ENTERO, tambien dentro de los seis primitivos de tinta (text, heading,
display, code, label, s-text). El paso de tinta del 82 % se llama `subtle` -
PROP y TOKEN, sin excepcion: el nombre es el contrato en el artefacto (la misma
ley que la FIRMA B' y la 12.9; se rechazo por escrito la via "solo el prop con
tabla de traduccion" - las excepciones legitimas son las FIRMADAS con razon,
no las inventadas al decidir para abaratar).
- Los seis CONTENT_INK, IDENTICOS: {subtle, muted, disabled, on-solid}; el
nivel-1 es el DEFAULT sin prop. `label` gana `on-solid` (cierra la
divergencia de familia registrada en e4fa616e5).
- Renombre completo: --color-content-secondary -> --color-content-subtle y la
clave de config content.secondary -> content.subtle (RUPTURA de API de
tema). 355 referencias por patrones acotados; la raiz SIN prefijo
(cssVar('color-content-secondary'), render-css.ts) incluida; en grafito.ts
conviven tres claves `subtle` (content/border/shadow) y solo cambio content.
El generado, reproducido BYTE A BYTE aplicando solo el renombre al anterior.
- Codemod value-preserving: 11 call sites (6 secondary->subtle incl.
expresiones y ternarias; 5 primary->fuera, incl. TRES defaults de prop) con
la condicion ROJA caracterizada (--style-caption-color es el UNICO estilo
cuya tinta default no es primary; los 5 sitios caen en ramas body). alpha/
(untracked, TERMINATED) fuera.
- Las 6 demos migradas al vocabulario nuevo (s-text: CERO cambios, no tiene
lista de tinta); label arranca en el default y pinta IDENTICO (contrafactual
medido: el estado viejo habria pintado el morado de marca).
- Neutra en pixel, MEDIDO: nivel 1 ESTRICTO CERO en 71.200 valores (blocks
enteros, s-text entero, subarboles data-*); nivel 2: 31 diffs, todos
trazados a las ediciones firmadas del harness (anchos de chips, reindexado
de la lista de label con las tintas supervivientes byte a byte). Total
171.712 valores + 59.072 de re-corridas a 0 de ruido.
- Guards: CONTENT_INK identicos entre los seis y sin nombres de rol (mutacion:
muerde), y el generado sin rastro del token viejo con las 6 definiciones del
nuevo. Dos cronicas fechadas en docs/old-deprecated, intactas a proposito.
- Docs: changelog 54 - reference (eje de tinta) - next-features 13 (divergencia
de label RESUELTA).
Supervision: verificador independiente pre-firma (dos claims MURIERON en
verificacion antes de tocar codigo), tres agentes en fases (censo+baseline ->
implementacion+codemod -> demos -> verificacion de dos niveles -> docs).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
| `delete-fg` | `root` | `var(--color-content-subtle)` | 1 |
docs(theming): la auditoría de alcance de tema, componente a componente, con su propuesta
El censo medía el eje y no lo explicaba: 5.205 knobs en dos tablas del plan no
dicen QUÉ knob de QUÉ línea no alcanza un tema, ni qué token habría que crear.
Ahora `theming-census.ts --report` escribe la auditoría entera bajo
`docs/audit/theming/`: un README con la vista de conjunto y 170 fichas — 162
recetas con CSS + 8 componentes sin receta, el árbol completo de
`eidos/components/`.
Cada ficha de receta: knobs fuera de alcance con fichero:línea Y selector
(agrupados por clase), sistema transversal aparte, los privados con la columna
que decide («¿deriva de un público?»), y una PROPUESTA de corrección — el token
a declarar en `base.ts` con su valor VERBATIM y su scope TSC. La propuesta
deriva los nombres de recipe-contract §1 y theming §6.7; donde la doctrina no
decide, marca `⚠ decisión` en vez de inventar. Y no propone acuñar lo que la
doctrina prohíbe: lo que posee una capa compartida, el foco, la capa de estado,
un token prestado de otra receta, un shorthand o un eje físico.
Las 8 fichas sin receta dicen —medido, no supuesto— dónde vive su visual: el
componente que componen (icon-button → button), la capa que consumen (affix →
viewport-placement) o la receta ajena que pinta sus attrs (svg → badge/button).
Defectos del instrumento corregidos en el mismo pase, todos encontrados
mirando la salida: un `@import` pegado al primer selector se comía 2 knobs de
color-picker (el suelo del censo no puede moverse); `:not(:disabled)` se leía
como estado y producía `hover-disabled-*`; un knob que lee un privado se
proponía a sí mismo en vez de resolverse por talla; `--icon-size-sm` se
reportaba como préstamo del componente `icon` (ahora el préstamo se verifica
contra las claves del dueño en `base.ts`); y el default de talla salía sin
nombrar en vez de `-md`.
Verificación: censo global idéntico al suelo publicado (5205 · 1621/33% · 856 ·
1880 · 614 · 234) y COMPONENTE A COMPONENTE contra la tabla §9 del plan — 0
diferencias en 162 · regenerar dos veces da el árbol idéntico · el bloque de
veredicto escrito a mano sobrevive · docs:check 0 errores sobre 813 docs ·
prettier limpio (el árbol generado entra en .prettierignore junto a
eidos/generated).
Las 10 primeras fichas llevan ya su veredicto de revisión: análisis correcto en
las 10, propuesta apta en 2 (gradient-builder como piloto, combobox con cinco
correcciones — dos de ellas evitaban romper el default), y 5 que no se
tokenizan en solitario porque son alias de --calendar-*/--field-* y esperan la
decisión de familia. Cuatro destaparon privados con prefijo ajeno o abreviado
declarados en su propio CSS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| `hover-delete-fg` | `root` | `var(--color-threat-solid, crimson)` | 1 |
| `menubar-crumbs-padding-inline` | `root` | `var(--space-2)` | 1 |
| `menubar-crumbs-font-size` | `root` | `var(--font-size-sm)` | 1 |
| `inspector-surface-width` | `root` | `fit-content` | 1 |
| `inspector-width` | `root` | `min(calc(8rem + var(--pcols) * 9rem), calc(100vw - var(--space-8)))` | 1 |
| `inspector-fields-gap` | `root` | `var(--space-3)` | 1 |
| `inspector-gap` | `root` | `var(--space-2-5) var(--space-3)` | 1 |
| `inspector-column-gap` | `root` | `var(--space-5)` | 1 |
| `inspector-row-gap` | `root` | `var(--space-3)` | 1 |
| `inspector-radius` | `root` | `var(--radius-md)` | 1 |
| `inspector-font-size` | `root` | `var(--font-size-sm)` | 1 |
| `handle-menu-gap` | `root` | `var(--space-2)` | 1 |
| `handle-menu-width` | `root` | `1rem` | 1 |
| `handle-menu-height` | `root` | `1rem` | 1 |
| `handle-menu-opacity` | `root` | `0.85` | 1 |
| `insert-grid-gap` | `root` | `2px` | 1 |
| `canvas-height` | `root` | `2px` | 1 |
| `canvas-radius` | `root` | `1px` | 1 |
| `canvas-bg` | `root` | `var(--color-primary-solid)` | 1 |
| `help-font-size` | `root` | `var(--font-size-sm)` | 1 |
| `help-fg` | `root` | `var(--color-content-muted)` | 1 |
| `help-padding-inline` | `root` | `var(--space-1)` | 1 |
| `help-radius` | `root` | `var(--radius-sm)` | 1 |
| `help-bg` | `root` | `var(--color-surface-muted)` | 1 |
| `status-gap` | `root` | `var(--space-3)` | 1 |
| `status-padding-block` | `root` | `var(--space-1)` | 1 |
| `status-font-size` | `root` | `var(--font-size-xs)` | 1 |
feat(color)!: una palabra, un significado - primary/secondary son SIEMPRE jerarquia
La homonimia muere: `primary`/`secondary` significan JERARQUIA DE MARCA en el
catalogo ENTERO, tambien dentro de los seis primitivos de tinta (text, heading,
display, code, label, s-text). El paso de tinta del 82 % se llama `subtle` -
PROP y TOKEN, sin excepcion: el nombre es el contrato en el artefacto (la misma
ley que la FIRMA B' y la 12.9; se rechazo por escrito la via "solo el prop con
tabla de traduccion" - las excepciones legitimas son las FIRMADAS con razon,
no las inventadas al decidir para abaratar).
- Los seis CONTENT_INK, IDENTICOS: {subtle, muted, disabled, on-solid}; el
nivel-1 es el DEFAULT sin prop. `label` gana `on-solid` (cierra la
divergencia de familia registrada en e4fa616e5).
- Renombre completo: --color-content-secondary -> --color-content-subtle y la
clave de config content.secondary -> content.subtle (RUPTURA de API de
tema). 355 referencias por patrones acotados; la raiz SIN prefijo
(cssVar('color-content-secondary'), render-css.ts) incluida; en grafito.ts
conviven tres claves `subtle` (content/border/shadow) y solo cambio content.
El generado, reproducido BYTE A BYTE aplicando solo el renombre al anterior.
- Codemod value-preserving: 11 call sites (6 secondary->subtle incl.
expresiones y ternarias; 5 primary->fuera, incl. TRES defaults de prop) con
la condicion ROJA caracterizada (--style-caption-color es el UNICO estilo
cuya tinta default no es primary; los 5 sitios caen en ramas body). alpha/
(untracked, TERMINATED) fuera.
- Las 6 demos migradas al vocabulario nuevo (s-text: CERO cambios, no tiene
lista de tinta); label arranca en el default y pinta IDENTICO (contrafactual
medido: el estado viejo habria pintado el morado de marca).
- Neutra en pixel, MEDIDO: nivel 1 ESTRICTO CERO en 71.200 valores (blocks
enteros, s-text entero, subarboles data-*); nivel 2: 31 diffs, todos
trazados a las ediciones firmadas del harness (anchos de chips, reindexado
de la lista de label con las tintas supervivientes byte a byte). Total
171.712 valores + 59.072 de re-corridas a 0 de ruido.
- Guards: CONTENT_INK identicos entre los seis y sin nombres de rol (mutacion:
muerde), y el generado sin rastro del token viejo con las 6 definiciones del
nuevo. Dos cronicas fechadas en docs/old-deprecated, intactas a proposito.
- Docs: changelog 54 - reference (eje de tinta) - next-features 13 (divergencia
de label RESUELTA).
Supervision: verificador independiente pre-firma (dos claims MURIERON en
verificacion antes de tocar codigo), tres agentes en fases (censo+baseline ->
implementacion+codemod -> demos -> verificacion de dos niveles -> docs).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
| `status-fg` | `root` | `var(--color-content-subtle)` | 1 |
docs(theming): la auditoría de alcance de tema, componente a componente, con su propuesta
El censo medía el eje y no lo explicaba: 5.205 knobs en dos tablas del plan no
dicen QUÉ knob de QUÉ línea no alcanza un tema, ni qué token habría que crear.
Ahora `theming-census.ts --report` escribe la auditoría entera bajo
`docs/audit/theming/`: un README con la vista de conjunto y 170 fichas — 162
recetas con CSS + 8 componentes sin receta, el árbol completo de
`eidos/components/`.
Cada ficha de receta: knobs fuera de alcance con fichero:línea Y selector
(agrupados por clase), sistema transversal aparte, los privados con la columna
que decide («¿deriva de un público?»), y una PROPUESTA de corrección — el token
a declarar en `base.ts` con su valor VERBATIM y su scope TSC. La propuesta
deriva los nombres de recipe-contract §1 y theming §6.7; donde la doctrina no
decide, marca `⚠ decisión` en vez de inventar. Y no propone acuñar lo que la
doctrina prohíbe: lo que posee una capa compartida, el foco, la capa de estado,
un token prestado de otra receta, un shorthand o un eje físico.
Las 8 fichas sin receta dicen —medido, no supuesto— dónde vive su visual: el
componente que componen (icon-button → button), la capa que consumen (affix →
viewport-placement) o la receta ajena que pinta sus attrs (svg → badge/button).
Defectos del instrumento corregidos en el mismo pase, todos encontrados
mirando la salida: un `@import` pegado al primer selector se comía 2 knobs de
color-picker (el suelo del censo no puede moverse); `:not(:disabled)` se leía
como estado y producía `hover-disabled-*`; un knob que lee un privado se
proponía a sí mismo en vez de resolverse por talla; `--icon-size-sm` se
reportaba como préstamo del componente `icon` (ahora el préstamo se verifica
contra las claves del dueño en `base.ts`); y el default de talla salía sin
nombrar en vez de `-md`.
Verificación: censo global idéntico al suelo publicado (5205 · 1621/33% · 856 ·
1880 · 614 · 234) y COMPONENTE A COMPONENTE contra la tabla §9 del plan — 0
diferencias en 162 · regenerar dos veces da el árbol idéntico · el bloque de
veredicto escrito a mano sobrevive · docs:check 0 errores sobre 813 docs ·
prettier limpio (el árbol generado entra en .prettierignore junto a
eidos/generated).
Las 10 primeras fichas llevan ya su veredicto de revisión: análisis correcto en
las 10, propuesta apta en 2 (gradient-builder como piloto, combobox con cinco
correcciones — dos de ellas evitaban romper el default), y 5 que no se
tokenizan en solitario porque son alias de --calendar-*/--field-* y esperan la
decisión de familia. Cuatro destaparon privados con prefijo ajeno o abreviado
declarados en su propio CSS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| `outline-trigger-gap` | `root` | `var(--space-1)` | 1 |
| `outline-trigger-radius` | `root` | `var(--radius-sm)` | 1 |
feat(color)!: una palabra, un significado - primary/secondary son SIEMPRE jerarquia
La homonimia muere: `primary`/`secondary` significan JERARQUIA DE MARCA en el
catalogo ENTERO, tambien dentro de los seis primitivos de tinta (text, heading,
display, code, label, s-text). El paso de tinta del 82 % se llama `subtle` -
PROP y TOKEN, sin excepcion: el nombre es el contrato en el artefacto (la misma
ley que la FIRMA B' y la 12.9; se rechazo por escrito la via "solo el prop con
tabla de traduccion" - las excepciones legitimas son las FIRMADAS con razon,
no las inventadas al decidir para abaratar).
- Los seis CONTENT_INK, IDENTICOS: {subtle, muted, disabled, on-solid}; el
nivel-1 es el DEFAULT sin prop. `label` gana `on-solid` (cierra la
divergencia de familia registrada en e4fa616e5).
- Renombre completo: --color-content-secondary -> --color-content-subtle y la
clave de config content.secondary -> content.subtle (RUPTURA de API de
tema). 355 referencias por patrones acotados; la raiz SIN prefijo
(cssVar('color-content-secondary'), render-css.ts) incluida; en grafito.ts
conviven tres claves `subtle` (content/border/shadow) y solo cambio content.
El generado, reproducido BYTE A BYTE aplicando solo el renombre al anterior.
- Codemod value-preserving: 11 call sites (6 secondary->subtle incl.
expresiones y ternarias; 5 primary->fuera, incl. TRES defaults de prop) con
la condicion ROJA caracterizada (--style-caption-color es el UNICO estilo
cuya tinta default no es primary; los 5 sitios caen en ramas body). alpha/
(untracked, TERMINATED) fuera.
- Las 6 demos migradas al vocabulario nuevo (s-text: CERO cambios, no tiene
lista de tinta); label arranca en el default y pinta IDENTICO (contrafactual
medido: el estado viejo habria pintado el morado de marca).
- Neutra en pixel, MEDIDO: nivel 1 ESTRICTO CERO en 71.200 valores (blocks
enteros, s-text entero, subarboles data-*); nivel 2: 31 diffs, todos
trazados a las ediciones firmadas del harness (anchos de chips, reindexado
de la lista de label con las tintas supervivientes byte a byte). Total
171.712 valores + 59.072 de re-corridas a 0 de ruido.
- Guards: CONTENT_INK identicos entre los seis y sin nombres de rol (mutacion:
muerde), y el generado sin rastro del token viejo con las 6 definiciones del
nuevo. Dos cronicas fechadas en docs/old-deprecated, intactas a proposito.
- Docs: changelog 54 - reference (eje de tinta) - next-features 13 (divergencia
de label RESUELTA).
Supervision: verificador independiente pre-firma (dos claims MURIERON en
verificacion antes de tocar codigo), tres agentes en fases (censo+baseline ->
implementacion+codemod -> demos -> verificacion de dos niveles -> docs).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
| `outline-trigger-fg` | `root` | `var(--color-content-subtle)` | 1 |
docs(theming): la auditoría de alcance de tema, componente a componente, con su propuesta
El censo medía el eje y no lo explicaba: 5.205 knobs en dos tablas del plan no
dicen QUÉ knob de QUÉ línea no alcanza un tema, ni qué token habría que crear.
Ahora `theming-census.ts --report` escribe la auditoría entera bajo
`docs/audit/theming/`: un README con la vista de conjunto y 170 fichas — 162
recetas con CSS + 8 componentes sin receta, el árbol completo de
`eidos/components/`.
Cada ficha de receta: knobs fuera de alcance con fichero:línea Y selector
(agrupados por clase), sistema transversal aparte, los privados con la columna
que decide («¿deriva de un público?»), y una PROPUESTA de corrección — el token
a declarar en `base.ts` con su valor VERBATIM y su scope TSC. La propuesta
deriva los nombres de recipe-contract §1 y theming §6.7; donde la doctrina no
decide, marca `⚠ decisión` en vez de inventar. Y no propone acuñar lo que la
doctrina prohíbe: lo que posee una capa compartida, el foco, la capa de estado,
un token prestado de otra receta, un shorthand o un eje físico.
Las 8 fichas sin receta dicen —medido, no supuesto— dónde vive su visual: el
componente que componen (icon-button → button), la capa que consumen (affix →
viewport-placement) o la receta ajena que pinta sus attrs (svg → badge/button).
Defectos del instrumento corregidos en el mismo pase, todos encontrados
mirando la salida: un `@import` pegado al primer selector se comía 2 knobs de
color-picker (el suelo del censo no puede moverse); `:not(:disabled)` se leía
como estado y producía `hover-disabled-*`; un knob que lee un privado se
proponía a sí mismo en vez de resolverse por talla; `--icon-size-sm` se
reportaba como préstamo del componente `icon` (ahora el préstamo se verifica
contra las claves del dueño en `base.ts`); y el default de talla salía sin
nombrar en vez de `-md`.
Verificación: censo global idéntico al suelo publicado (5205 · 1621/33% · 856 ·
1880 · 614 · 234) y COMPONENTE A COMPONENTE contra la tabla §9 del plan — 0
diferencias en 162 · regenerar dos veces da el árbol idéntico · el bloque de
veredicto escrito a mano sobrevive · docs:check 0 errores sobre 813 docs ·
prettier limpio (el árbol generado entra en .prettierignore junto a
eidos/generated).
Las 10 primeras fichas llevan ya su veredicto de revisión: análisis correcto en
las 10, propuesta apta en 2 (gradient-builder como piloto, combobox con cinco
correcciones — dos de ellas evitaban romper el default), y 5 que no se
tokenizan en solitario porque son alias de --calendar-*/--field-* y esperan la
decisión de familia. Cuatro destaparon privados con prefijo ajeno o abreviado
declarados en su propio CSS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| `outline-trigger-font-size` | `root` | `var(--font-size-xs)` | 1 |
| `hover-outline-trigger-bg` | `root` | `var(--color-surface-muted)` | 1 |
| `disabled-outline-trigger-opacity` | `root` | `0.5` | 1 |
| `outline-trigger-width` | `root` | `1em` | 1 |
| `outline-trigger-height` | `root` | `1em` | 1 |
| `outline-width` | `root` | `14rem` | 1 |
| `outline-item-radius` | `root` | `var(--radius-sm)` | 1 |
feat(color)!: una palabra, un significado - primary/secondary son SIEMPRE jerarquia
La homonimia muere: `primary`/`secondary` significan JERARQUIA DE MARCA en el
catalogo ENTERO, tambien dentro de los seis primitivos de tinta (text, heading,
display, code, label, s-text). El paso de tinta del 82 % se llama `subtle` -
PROP y TOKEN, sin excepcion: el nombre es el contrato en el artefacto (la misma
ley que la FIRMA B' y la 12.9; se rechazo por escrito la via "solo el prop con
tabla de traduccion" - las excepciones legitimas son las FIRMADAS con razon,
no las inventadas al decidir para abaratar).
- Los seis CONTENT_INK, IDENTICOS: {subtle, muted, disabled, on-solid}; el
nivel-1 es el DEFAULT sin prop. `label` gana `on-solid` (cierra la
divergencia de familia registrada en e4fa616e5).
- Renombre completo: --color-content-secondary -> --color-content-subtle y la
clave de config content.secondary -> content.subtle (RUPTURA de API de
tema). 355 referencias por patrones acotados; la raiz SIN prefijo
(cssVar('color-content-secondary'), render-css.ts) incluida; en grafito.ts
conviven tres claves `subtle` (content/border/shadow) y solo cambio content.
El generado, reproducido BYTE A BYTE aplicando solo el renombre al anterior.
- Codemod value-preserving: 11 call sites (6 secondary->subtle incl.
expresiones y ternarias; 5 primary->fuera, incl. TRES defaults de prop) con
la condicion ROJA caracterizada (--style-caption-color es el UNICO estilo
cuya tinta default no es primary; los 5 sitios caen en ramas body). alpha/
(untracked, TERMINATED) fuera.
- Las 6 demos migradas al vocabulario nuevo (s-text: CERO cambios, no tiene
lista de tinta); label arranca en el default y pinta IDENTICO (contrafactual
medido: el estado viejo habria pintado el morado de marca).
- Neutra en pixel, MEDIDO: nivel 1 ESTRICTO CERO en 71.200 valores (blocks
enteros, s-text entero, subarboles data-*); nivel 2: 31 diffs, todos
trazados a las ediciones firmadas del harness (anchos de chips, reindexado
de la lista de label con las tintas supervivientes byte a byte). Total
171.712 valores + 59.072 de re-corridas a 0 de ruido.
- Guards: CONTENT_INK identicos entre los seis y sin nombres de rol (mutacion:
muerde), y el generado sin rastro del token viejo con las 6 definiciones del
nuevo. Dos cronicas fechadas en docs/old-deprecated, intactas a proposito.
- Docs: changelog 54 - reference (eje de tinta) - next-features 13 (divergencia
de label RESUELTA).
Supervision: verificador independiente pre-firma (dos claims MURIERON en
verificacion antes de tocar codigo), tres agentes en fases (censo+baseline ->
implementacion+codemod -> demos -> verificacion de dos niveles -> docs).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
| `outline-item-fg` | `root` | `var(--color-content-subtle)` | 1 |
docs(theming): la auditoría de alcance de tema, componente a componente, con su propuesta
El censo medía el eje y no lo explicaba: 5.205 knobs en dos tablas del plan no
dicen QUÉ knob de QUÉ línea no alcanza un tema, ni qué token habría que crear.
Ahora `theming-census.ts --report` escribe la auditoría entera bajo
`docs/audit/theming/`: un README con la vista de conjunto y 170 fichas — 162
recetas con CSS + 8 componentes sin receta, el árbol completo de
`eidos/components/`.
Cada ficha de receta: knobs fuera de alcance con fichero:línea Y selector
(agrupados por clase), sistema transversal aparte, los privados con la columna
que decide («¿deriva de un público?»), y una PROPUESTA de corrección — el token
a declarar en `base.ts` con su valor VERBATIM y su scope TSC. La propuesta
deriva los nombres de recipe-contract §1 y theming §6.7; donde la doctrina no
decide, marca `⚠ decisión` en vez de inventar. Y no propone acuñar lo que la
doctrina prohíbe: lo que posee una capa compartida, el foco, la capa de estado,
un token prestado de otra receta, un shorthand o un eje físico.
Las 8 fichas sin receta dicen —medido, no supuesto— dónde vive su visual: el
componente que componen (icon-button → button), la capa que consumen (affix →
viewport-placement) o la receta ajena que pinta sus attrs (svg → badge/button).
Defectos del instrumento corregidos en el mismo pase, todos encontrados
mirando la salida: un `@import` pegado al primer selector se comía 2 knobs de
color-picker (el suelo del censo no puede moverse); `:not(:disabled)` se leía
como estado y producía `hover-disabled-*`; un knob que lee un privado se
proponía a sí mismo en vez de resolverse por talla; `--icon-size-sm` se
reportaba como préstamo del componente `icon` (ahora el préstamo se verifica
contra las claves del dueño en `base.ts`); y el default de talla salía sin
nombrar en vez de `-md`.
Verificación: censo global idéntico al suelo publicado (5205 · 1621/33% · 856 ·
1880 · 614 · 234) y COMPONENTE A COMPONENTE contra la tabla §9 del plan — 0
diferencias en 162 · regenerar dos veces da el árbol idéntico · el bloque de
veredicto escrito a mano sobrevive · docs:check 0 errores sobre 813 docs ·
prettier limpio (el árbol generado entra en .prettierignore junto a
eidos/generated).
Las 10 primeras fichas llevan ya su veredicto de revisión: análisis correcto en
las 10, propuesta apta en 2 (gradient-builder como piloto, combobox con cinco
correcciones — dos de ellas evitaban romper el default), y 5 que no se
tokenizan en solitario porque son alias de --calendar-*/--field-* y esperan la
decisión de familia. Cuatro destaparon privados con prefijo ajeno o abreviado
declarados en su propio CSS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| `outline-item-font-size` | `root` | `var(--font-size-sm)` | 1 |
| `hover-outline-item-bg` | `root` | `var(--color-surface-muted)` | 1 |
| `col-resize-radius` | `root` | `var(--radius-full)` | 1 |
| `col-resize-bg` | `root` | `var(--color-border-default)` | 1 |
| `hover-col-resize-bg` | `root` | `var(--color-primary-border)` | 1 |
| `live-width` | `root` | `1px` | 1 |
| `live-height` | `root` | `1px` | 1 |
| `panel-font-family` | `root` | `var(--style-label-font-family)` | 1 |
| `panel-shadow` | `root` | `var(--shadow-4)` | 1 |
| `panel-gap` | `root` | `var(--space-1)` | 1 |
| `panel-head-main-gap` | `root` | `var(--space-2-5, 10px)` | 1 |
| `panel-icon-radius` | `root` | `var(--radius-md)` | 1 |
| `panel-icon-bg` | `root` | `var(--color-primary-surface)` | 1 |
| `panel-icon-fg` | `root` | `var(--color-primary-text) !important` | 1 |
| `panel-letter-spacing` | `root` | `-0.01em` | 1 |
| `panel-crumbs-column-gap` | `root` | `var(--space-1)` | 1 |
| `panel-crumbs-font-size` | `root` | `var(--font-size-sm)` | 1 |
| `panel-crumbs-fg` | `root` | `var(--color-content-muted)` | 1 |
| `hover-panel-crumb-fg` | `root` | `var(--color-primary-text)` | 1 |
| `panel-crumb-fg` | `root` | `var(--color-content-primary)` | 1 |
| `panel-crumb-font-weight` | `root` | `var(--font-weight-medium)` | 1 |
| `panel-crumb-sep-fg` | `root` | `var(--color-border-strong)` | 1 |
| `tabs-padding-inline` | `root` | `var(--space-4)` | 1 |
| `tabs-padding-block` | `root` | `var(--space-1) var(--space-4)` | 1 |
| `tab-empty-font-size` | `root` | `var(--font-size-sm)` | 1 |
| `tab-empty-fg` | `root` | `var(--color-content-muted)` | 1 |
| `field-column-gap` | `root` | `var(--space-3)` | 1 |
| `field-width` | `root` | `max-content` | 1 |
| `field-label-font-size` | `root` | `var(--font-size-sm)` | 1 |
feat(color)!: una palabra, un significado - primary/secondary son SIEMPRE jerarquia
La homonimia muere: `primary`/`secondary` significan JERARQUIA DE MARCA en el
catalogo ENTERO, tambien dentro de los seis primitivos de tinta (text, heading,
display, code, label, s-text). El paso de tinta del 82 % se llama `subtle` -
PROP y TOKEN, sin excepcion: el nombre es el contrato en el artefacto (la misma
ley que la FIRMA B' y la 12.9; se rechazo por escrito la via "solo el prop con
tabla de traduccion" - las excepciones legitimas son las FIRMADAS con razon,
no las inventadas al decidir para abaratar).
- Los seis CONTENT_INK, IDENTICOS: {subtle, muted, disabled, on-solid}; el
nivel-1 es el DEFAULT sin prop. `label` gana `on-solid` (cierra la
divergencia de familia registrada en e4fa616e5).
- Renombre completo: --color-content-secondary -> --color-content-subtle y la
clave de config content.secondary -> content.subtle (RUPTURA de API de
tema). 355 referencias por patrones acotados; la raiz SIN prefijo
(cssVar('color-content-secondary'), render-css.ts) incluida; en grafito.ts
conviven tres claves `subtle` (content/border/shadow) y solo cambio content.
El generado, reproducido BYTE A BYTE aplicando solo el renombre al anterior.
- Codemod value-preserving: 11 call sites (6 secondary->subtle incl.
expresiones y ternarias; 5 primary->fuera, incl. TRES defaults de prop) con
la condicion ROJA caracterizada (--style-caption-color es el UNICO estilo
cuya tinta default no es primary; los 5 sitios caen en ramas body). alpha/
(untracked, TERMINATED) fuera.
- Las 6 demos migradas al vocabulario nuevo (s-text: CERO cambios, no tiene
lista de tinta); label arranca en el default y pinta IDENTICO (contrafactual
medido: el estado viejo habria pintado el morado de marca).
- Neutra en pixel, MEDIDO: nivel 1 ESTRICTO CERO en 71.200 valores (blocks
enteros, s-text entero, subarboles data-*); nivel 2: 31 diffs, todos
trazados a las ediciones firmadas del harness (anchos de chips, reindexado
de la lista de label con las tintas supervivientes byte a byte). Total
171.712 valores + 59.072 de re-corridas a 0 de ruido.
- Guards: CONTENT_INK identicos entre los seis y sin nombres de rol (mutacion:
muerde), y el generado sin rastro del token viejo con las 6 definiciones del
nuevo. Dos cronicas fechadas en docs/old-deprecated, intactas a proposito.
- Docs: changelog 54 - reference (eje de tinta) - next-features 13 (divergencia
de label RESUELTA).
Supervision: verificador independiente pre-firma (dos claims MURIERON en
verificacion antes de tocar codigo), tres agentes en fases (censo+baseline ->
implementacion+codemod -> demos -> verificacion de dos niveles -> docs).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
| `field-label-fg` | `root` | `var(--color-content-subtle)` | 1 |
docs(theming): la auditoría de alcance de tema, componente a componente, con su propuesta
El censo medía el eje y no lo explicaba: 5.205 knobs en dos tablas del plan no
dicen QUÉ knob de QUÉ línea no alcanza un tema, ni qué token habría que crear.
Ahora `theming-census.ts --report` escribe la auditoría entera bajo
`docs/audit/theming/`: un README con la vista de conjunto y 170 fichas — 162
recetas con CSS + 8 componentes sin receta, el árbol completo de
`eidos/components/`.
Cada ficha de receta: knobs fuera de alcance con fichero:línea Y selector
(agrupados por clase), sistema transversal aparte, los privados con la columna
que decide («¿deriva de un público?»), y una PROPUESTA de corrección — el token
a declarar en `base.ts` con su valor VERBATIM y su scope TSC. La propuesta
deriva los nombres de recipe-contract §1 y theming §6.7; donde la doctrina no
decide, marca `⚠ decisión` en vez de inventar. Y no propone acuñar lo que la
doctrina prohíbe: lo que posee una capa compartida, el foco, la capa de estado,
un token prestado de otra receta, un shorthand o un eje físico.
Las 8 fichas sin receta dicen —medido, no supuesto— dónde vive su visual: el
componente que componen (icon-button → button), la capa que consumen (affix →
viewport-placement) o la receta ajena que pinta sus attrs (svg → badge/button).
Defectos del instrumento corregidos en el mismo pase, todos encontrados
mirando la salida: un `@import` pegado al primer selector se comía 2 knobs de
color-picker (el suelo del censo no puede moverse); `:not(:disabled)` se leía
como estado y producía `hover-disabled-*`; un knob que lee un privado se
proponía a sí mismo en vez de resolverse por talla; `--icon-size-sm` se
reportaba como préstamo del componente `icon` (ahora el préstamo se verifica
contra las claves del dueño en `base.ts`); y el default de talla salía sin
nombrar en vez de `-md`.
Verificación: censo global idéntico al suelo publicado (5205 · 1621/33% · 856 ·
1880 · 614 · 234) y COMPONENTE A COMPONENTE contra la tabla §9 del plan — 0
diferencias en 162 · regenerar dos veces da el árbol idéntico · el bloque de
veredicto escrito a mano sobrevive · docs:check 0 errores sobre 813 docs ·
prettier limpio (el árbol generado entra en .prettierignore junto a
eidos/generated).
Las 10 primeras fichas llevan ya su veredicto de revisión: análisis correcto en
las 10, propuesta apta en 2 (gradient-builder como piloto, combobox con cinco
correcciones — dos de ellas evitaban romper el default), y 5 que no se
tokenizan en solitario porque son alias de --calendar-*/--field-* y esperan la
decisión de familia. Cuatro destaparon privados con prefijo ajeno o abreviado
declarados en su propio CSS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| `field-label-line-height` | `root` | `var(--leading-ui)` | 1 |
| `disabled-field-opacity` | `root` | `0.45` | 1 |
| `text-fg` | `root` | `var(--color-content-primary)` | 1 |
| `text-font-size` | `root` | `var(--font-size-sm)` | 1 |
| `text-font-family` | `root` | `var(--font-family-mono)` | 1 |
| `invalid-text-border` | `root` | `var(--color-threat-border, crimson)` | 1 |
| `segmented-gap` | `root` | `var(--space-0-5)` | 1 |
| `hover-segmented-fg` | `root` | `var(--color-content-primary)` | 1 |
| `segmented-shadow` | `root` | `var(--shadow-1)` | 1 |
| `type-style-gap` | `root` | `var(--space-1)` | 1 |
| `spacing-column-gap` | `root` | `var(--space-2)` | 1 |
| `spacing-row-gap` | `root` | `var(--space-1)` | 1 |
| `spacing-head-gap` | `root` | `var(--space-2)` | 1 |
| `spacing-head-height` | `root` | `var(--space-6)` | 1 |
| `spacing-cell-font-size` | `root` | `var(--font-size-sm)` | 1 |
| `spacing-side-font-size` | `root` | `var(--font-size-xs)` | 1 |
| `spacing-side-fg` | `root` | `var(--color-content-muted)` | 1 |
| `spacing-link-fg` | `root` | `var(--color-content-muted)` | 1 |
| `border-gap` | `root` | `var(--space-2-5)` | 1 |
| `border-row-column-gap` | `root` | `var(--space-2)` | 1 |
| `border-field-column-gap` | `root` | `var(--space-2)` | 1 |
| `border-field-row-gap` | `root` | `var(--space-1)` | 1 |
| `border-caption-font-size` | `root` | `var(--font-size-sm)` | 1 |
feat(color)!: una palabra, un significado - primary/secondary son SIEMPRE jerarquia
La homonimia muere: `primary`/`secondary` significan JERARQUIA DE MARCA en el
catalogo ENTERO, tambien dentro de los seis primitivos de tinta (text, heading,
display, code, label, s-text). El paso de tinta del 82 % se llama `subtle` -
PROP y TOKEN, sin excepcion: el nombre es el contrato en el artefacto (la misma
ley que la FIRMA B' y la 12.9; se rechazo por escrito la via "solo el prop con
tabla de traduccion" - las excepciones legitimas son las FIRMADAS con razon,
no las inventadas al decidir para abaratar).
- Los seis CONTENT_INK, IDENTICOS: {subtle, muted, disabled, on-solid}; el
nivel-1 es el DEFAULT sin prop. `label` gana `on-solid` (cierra la
divergencia de familia registrada en e4fa616e5).
- Renombre completo: --color-content-secondary -> --color-content-subtle y la
clave de config content.secondary -> content.subtle (RUPTURA de API de
tema). 355 referencias por patrones acotados; la raiz SIN prefijo
(cssVar('color-content-secondary'), render-css.ts) incluida; en grafito.ts
conviven tres claves `subtle` (content/border/shadow) y solo cambio content.
El generado, reproducido BYTE A BYTE aplicando solo el renombre al anterior.
- Codemod value-preserving: 11 call sites (6 secondary->subtle incl.
expresiones y ternarias; 5 primary->fuera, incl. TRES defaults de prop) con
la condicion ROJA caracterizada (--style-caption-color es el UNICO estilo
cuya tinta default no es primary; los 5 sitios caen en ramas body). alpha/
(untracked, TERMINATED) fuera.
- Las 6 demos migradas al vocabulario nuevo (s-text: CERO cambios, no tiene
lista de tinta); label arranca en el default y pinta IDENTICO (contrafactual
medido: el estado viejo habria pintado el morado de marca).
- Neutra en pixel, MEDIDO: nivel 1 ESTRICTO CERO en 71.200 valores (blocks
enteros, s-text entero, subarboles data-*); nivel 2: 31 diffs, todos
trazados a las ediciones firmadas del harness (anchos de chips, reindexado
de la lista de label con las tintas supervivientes byte a byte). Total
171.712 valores + 59.072 de re-corridas a 0 de ruido.
- Guards: CONTENT_INK identicos entre los seis y sin nombres de rol (mutacion:
muerde), y el generado sin rastro del token viejo con las 6 definiciones del
nuevo. Dos cronicas fechadas en docs/old-deprecated, intactas a proposito.
- Docs: changelog 54 - reference (eje de tinta) - next-features 13 (divergencia
de label RESUELTA).
Supervision: verificador independiente pre-firma (dos claims MURIERON en
verificacion antes de tocar codigo), tres agentes en fases (censo+baseline ->
implementacion+codemod -> demos -> verificacion de dos niveles -> docs).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
| `border-caption-fg` | `root` | `var(--color-content-subtle)` | 1 |
docs(theming): la auditoría de alcance de tema, componente a componente, con su propuesta
El censo medía el eje y no lo explicaba: 5.205 knobs en dos tablas del plan no
dicen QUÉ knob de QUÉ línea no alcanza un tema, ni qué token habría que crear.
Ahora `theming-census.ts --report` escribe la auditoría entera bajo
`docs/audit/theming/`: un README con la vista de conjunto y 170 fichas — 162
recetas con CSS + 8 componentes sin receta, el árbol completo de
`eidos/components/`.
Cada ficha de receta: knobs fuera de alcance con fichero:línea Y selector
(agrupados por clase), sistema transversal aparte, los privados con la columna
que decide («¿deriva de un público?»), y una PROPUESTA de corrección — el token
a declarar en `base.ts` con su valor VERBATIM y su scope TSC. La propuesta
deriva los nombres de recipe-contract §1 y theming §6.7; donde la doctrina no
decide, marca `⚠ decisión` en vez de inventar. Y no propone acuñar lo que la
doctrina prohíbe: lo que posee una capa compartida, el foco, la capa de estado,
un token prestado de otra receta, un shorthand o un eje físico.
Las 8 fichas sin receta dicen —medido, no supuesto— dónde vive su visual: el
componente que componen (icon-button → button), la capa que consumen (affix →
viewport-placement) o la receta ajena que pinta sus attrs (svg → badge/button).
Defectos del instrumento corregidos en el mismo pase, todos encontrados
mirando la salida: un `@import` pegado al primer selector se comía 2 knobs de
color-picker (el suelo del censo no puede moverse); `:not(:disabled)` se leía
como estado y producía `hover-disabled-*`; un knob que lee un privado se
proponía a sí mismo en vez de resolverse por talla; `--icon-size-sm` se
reportaba como préstamo del componente `icon` (ahora el préstamo se verifica
contra las claves del dueño en `base.ts`); y el default de talla salía sin
nombrar en vez de `-md`.
Verificación: censo global idéntico al suelo publicado (5205 · 1621/33% · 856 ·
1880 · 614 · 234) y COMPONENTE A COMPONENTE contra la tabla §9 del plan — 0
diferencias en 162 · regenerar dos veces da el árbol idéntico · el bloque de
veredicto escrito a mano sobrevive · docs:check 0 errores sobre 813 docs ·
prettier limpio (el árbol generado entra en .prettierignore junto a
eidos/generated).
Las 10 primeras fichas llevan ya su veredicto de revisión: análisis correcto en
las 10, propuesta apta en 2 (gradient-builder como piloto, combobox con cinco
correcciones — dos de ellas evitaban romper el default), y 5 que no se
tokenizan en solitario porque son alias de --calendar-*/--field-* y esperan la
decisión de familia. Cuatro destaparon privados con prefijo ajeno o abreviado
declarados en su propio CSS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| `border-pair-column-gap` | `root` | `var(--space-2)` | 1 |
| `typography-gap` | `root` | `var(--space-3)` | 1 |
| `type-pair-column-gap` | `root` | `var(--space-1)` | 1 |
| `select-text-fg` | `root` | `var(--color-content-muted)` | 1 |
| `hover-open-panel-fg` | `root` | `var(--color-content-primary)` | 1 |
| `section-reset-fg` | `root` | `var(--color-content-muted)` | 1 |
| `field-gap` | `root` | `var(--space-2)` | 1 |
| `field-font-size` | `root` | `var(--font-size-sm)` | 1 |
| `field-fg` | `root` | `var(--color-primary-text)` | 1 |
| `src-group-gap` | `root` | `var(--space-1)` | 1 |
| `panel-foot-gap` | `root` | `var(--space-1)` | 1 |
| `panel-foot-bg` | `root` | `var(--color-surface-default)` | 1 |
| `panel-foot-font-size` | `root` | `var(--font-size-sm)` | 1 |
| `panel-foot-fg` | `root` | `var(--color-content-muted)` | 1 |
| `panel-empty-font-size` | `root` | `var(--font-size-sm)` | 1 |
| `panel-empty-fg` | `root` | `var(--color-content-muted)` | 1 |
| `appearance-font-family` | `root` | `var(--style-label-font-family)` | 1 |
| `appearance-width` | `root` | `6rem` | 1 |
| `bubble-gap` | `root` | `var(--space-0-5)` | 1 |
| `bubble-radius` | `root` | `var(--radius-lg)` | 1 |
| `bubble-shadow` | `root` | `var(--shadow-overlay)` | 1 |
| `bubble-font-family` | `root` | `var(--style-label-font-family)` | 1 |
| `bubble-fg` | `root` | `var(--color-content-primary)` | 1 |
| `bubble-divider-width` | `root` | `1px` | 1 |
| `bubble-divider-height` | `root` | `1.15rem` | 1 |
| `bubble-divider-bg` | `root` | `var(--color-border-subtle)` | 1 |
| `bubble-link-gap` | `root` | `var(--space-1)` | 1 |
| `bubble-link-width` | `root` | `15rem` | 1 |
| `bubble-link-radius` | `root` | `var(--radius-md)` | 1 |
| `bubble-link-fg` | `root` | `var(--color-content-default)` | 1 |
| `bubble-link-font-size` | `root` | `var(--font-size-sm)` | 1 |
| `bubble-typo-gap` | `root` | `var(--space-0-5)` | 1 |
| `bubble-size-width` | `root` | `7rem` | 1 |
| `bubble-family-width` | `root` | `12rem` | 1 |
| `slash-gap` | `root` | `1px` | 1 |
| `slash-width` | `root` | `15rem` | 1 |
| `slash-bg` | `root` | `var(--color-surface-overlay)` | 1 |
| `slash-radius` | `root` | `var(--radius-lg)` | 1 |
| `slash-shadow` | `root` | `var(--shadow-overlay)` | 1 |
| `slash-font-family` | `root` | `var(--style-label-font-family)` | 1 |
| `slash-item-gap` | `root` | `var(--space-2)` | 1 |
| `slash-item-radius` | `root` | `var(--radius-md)` | 1 |
| `slash-item-fg` | `root` | `var(--color-content-default)` | 1 |
| `slash-item-font-size` | `root` | `var(--font-size-sm)` | 1 |
| `slash-item-bg` | `root` | `var(--color-surface-muted)` | 1 |
| `slash-icon-fg` | `root` | `var(--color-content-muted)` | 1 |
| `slash-label-font-weight` | `root` | `var(--font-weight-medium)` | 1 |
| `slash-desc-padding-inline` | `root` | `var(--space-2)` | 1 |
| `slash-desc-fg` | `root` | `var(--color-content-muted)` | 1 |
| `slash-desc-font-size` | `root` | `var(--font-size-xs)` | 1 |
| `find-gap` | `root` | `var(--space-1)` | 1 |
| `find-radius` | `root` | `var(--radius-lg)` | 1 |
| `find-shadow` | `root` | `var(--shadow-overlay)` | 1 |
| `find-font-family` | `root` | `var(--style-label-font-family)` | 1 |
| `find-row-gap` | `root` | `var(--space-1)` | 1 |
| `find-icon-padding-inline` | `root` | `var(--space-1)` | 1 |
| `find-icon-fg` | `root` | `var(--color-content-muted)` | 1 |
| `find-input-width` | `root` | `13rem` | 1 |
| `find-input-radius` | `root` | `var(--radius-md)` | 1 |
| `find-input-fg` | `root` | `var(--color-content-default)` | 1 |
| `find-input-font-size` | `root` | `var(--font-size-sm)` | 1 |
| `invalid-find-border` | `root` | `var(--color-threat-solid)` | 1 |
| `find-count-width` | `root` | `3rem` | 1 |
| `find-count-font-size` | `root` | `var(--font-size-xs)` | 1 |
| `find-count-fg` | `root` | `var(--color-content-muted)` | 1 |
| `find-sep-width` | `root` | `1px` | 1 |
| `find-sep-height` | `root` | `1.15rem` | 1 |
| `find-sep-bg` | `root` | `var(--color-border-subtle)` | 1 |
| `find-fg` | `root` | `var(--color-content-primary)` | 1 |
| `export-foot-gap` | `root` | `var(--space-2)` | 1 |
| `export-label-gap` | `root` | `var(--space-1-5)` | 1 |
| `export-label-font-size` | `root` | `var(--font-size-sm)` | 1 |
| `export-label-fg` | `root` | `var(--color-content-muted)` | 1 |
| `export-actions-gap` | `root` | `var(--space-1)` | 1 |
| `lang-switcher-gap` | `root` | `var(--space-0-5)` | 1 |
| `lang-switcher-radius` | `root` | `var(--radius-md)` | 1 |
| `lang-option-gap` | `root` | `var(--space-1)` | 1 |
| `lang-option-padding-inline` | `root` | `var(--space-2)` | 1 |
feat(color)!: una palabra, un significado - primary/secondary son SIEMPRE jerarquia
La homonimia muere: `primary`/`secondary` significan JERARQUIA DE MARCA en el
catalogo ENTERO, tambien dentro de los seis primitivos de tinta (text, heading,
display, code, label, s-text). El paso de tinta del 82 % se llama `subtle` -
PROP y TOKEN, sin excepcion: el nombre es el contrato en el artefacto (la misma
ley que la FIRMA B' y la 12.9; se rechazo por escrito la via "solo el prop con
tabla de traduccion" - las excepciones legitimas son las FIRMADAS con razon,
no las inventadas al decidir para abaratar).
- Los seis CONTENT_INK, IDENTICOS: {subtle, muted, disabled, on-solid}; el
nivel-1 es el DEFAULT sin prop. `label` gana `on-solid` (cierra la
divergencia de familia registrada en e4fa616e5).
- Renombre completo: --color-content-secondary -> --color-content-subtle y la
clave de config content.secondary -> content.subtle (RUPTURA de API de
tema). 355 referencias por patrones acotados; la raiz SIN prefijo
(cssVar('color-content-secondary'), render-css.ts) incluida; en grafito.ts
conviven tres claves `subtle` (content/border/shadow) y solo cambio content.
El generado, reproducido BYTE A BYTE aplicando solo el renombre al anterior.
- Codemod value-preserving: 11 call sites (6 secondary->subtle incl.
expresiones y ternarias; 5 primary->fuera, incl. TRES defaults de prop) con
la condicion ROJA caracterizada (--style-caption-color es el UNICO estilo
cuya tinta default no es primary; los 5 sitios caen en ramas body). alpha/
(untracked, TERMINATED) fuera.
- Las 6 demos migradas al vocabulario nuevo (s-text: CERO cambios, no tiene
lista de tinta); label arranca en el default y pinta IDENTICO (contrafactual
medido: el estado viejo habria pintado el morado de marca).
- Neutra en pixel, MEDIDO: nivel 1 ESTRICTO CERO en 71.200 valores (blocks
enteros, s-text entero, subarboles data-*); nivel 2: 31 diffs, todos
trazados a las ediciones firmadas del harness (anchos de chips, reindexado
de la lista de label con las tintas supervivientes byte a byte). Total
171.712 valores + 59.072 de re-corridas a 0 de ruido.
- Guards: CONTENT_INK identicos entre los seis y sin nombres de rol (mutacion:
muerde), y el generado sin rastro del token viejo con las 6 definiciones del
nuevo. Dos cronicas fechadas en docs/old-deprecated, intactas a proposito.
- Docs: changelog 54 - reference (eje de tinta) - next-features 13 (divergencia
de label RESUELTA).
Supervision: verificador independiente pre-firma (dos claims MURIERON en
verificacion antes de tocar codigo), tres agentes en fases (censo+baseline ->
implementacion+codemod -> demos -> verificacion de dos niveles -> docs).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
| `lang-option-fg` | `root` | `var(--color-content-subtle)` | 1 |
docs(theming): la auditoría de alcance de tema, componente a componente, con su propuesta
El censo medía el eje y no lo explicaba: 5.205 knobs en dos tablas del plan no
dicen QUÉ knob de QUÉ línea no alcanza un tema, ni qué token habría que crear.
Ahora `theming-census.ts --report` escribe la auditoría entera bajo
`docs/audit/theming/`: un README con la vista de conjunto y 170 fichas — 162
recetas con CSS + 8 componentes sin receta, el árbol completo de
`eidos/components/`.
Cada ficha de receta: knobs fuera de alcance con fichero:línea Y selector
(agrupados por clase), sistema transversal aparte, los privados con la columna
que decide («¿deriva de un público?»), y una PROPUESTA de corrección — el token
a declarar en `base.ts` con su valor VERBATIM y su scope TSC. La propuesta
deriva los nombres de recipe-contract §1 y theming §6.7; donde la doctrina no
decide, marca `⚠ decisión` en vez de inventar. Y no propone acuñar lo que la
doctrina prohíbe: lo que posee una capa compartida, el foco, la capa de estado,
un token prestado de otra receta, un shorthand o un eje físico.
Las 8 fichas sin receta dicen —medido, no supuesto— dónde vive su visual: el
componente que componen (icon-button → button), la capa que consumen (affix →
viewport-placement) o la receta ajena que pinta sus attrs (svg → badge/button).
Defectos del instrumento corregidos en el mismo pase, todos encontrados
mirando la salida: un `@import` pegado al primer selector se comía 2 knobs de
color-picker (el suelo del censo no puede moverse); `:not(:disabled)` se leía
como estado y producía `hover-disabled-*`; un knob que lee un privado se
proponía a sí mismo en vez de resolverse por talla; `--icon-size-sm` se
reportaba como préstamo del componente `icon` (ahora el préstamo se verifica
contra las claves del dueño en `base.ts`); y el default de talla salía sin
nombrar en vez de `-md`.
Verificación: censo global idéntico al suelo publicado (5205 · 1621/33% · 856 ·
1880 · 614 · 234) y COMPONENTE A COMPONENTE contra la tabla §9 del plan — 0
diferencias en 162 · regenerar dos veces da el árbol idéntico · el bloque de
veredicto escrito a mano sobrevive · docs:check 0 errores sobre 813 docs ·
prettier limpio (el árbol generado entra en .prettierignore junto a
eidos/generated).
Las 10 primeras fichas llevan ya su veredicto de revisión: análisis correcto en
las 10, propuesta apta en 2 (gradient-builder como piloto, combobox con cinco
correcciones — dos de ellas evitaban romper el default), y 5 que no se
tokenizan en solitario porque son alias de --calendar-*/--field-* y esperan la
decisión de familia. Cuatro destaparon privados con prefijo ajeno o abreviado
declarados en su propio CSS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| `lang-option-font-size` | `root` | `var(--font-size-xs)` | 1 |
| `lang-option-font-weight` | `root` | `500` | 1 |
| `hover-lang-option-fg` | `root` | `var(--color-content-primary)` | 1 |
| `lang-switcher-fg` | `root` | `var(--color-content-primary)` | 1 |
| `lang-switcher-font-weight` | `root` | `600` | 1 |
| `lang-option-width` | `root` | `6px` | 1 |
| `lang-option-bg` | `root` | `var(--color-primary-solid)` | 1 |
| `lang-option-border` | `root` | `var(--color-primary-solid)` | 1 |
| `lang-trigger-gap` | `root` | `var(--space-1)` | 1 |
| `lang-trigger-padding-inline` | `root` | `var(--space-2)` | 1 |
| `lang-trigger-height` | `root` | `var(--space-6)` | 1 |
| `lang-trigger-radius` | `root` | `var(--radius-md)` | 1 |
| `lang-trigger-bg` | `root` | `var(--color-surface-default)` | 1 |
| `lang-trigger-fg` | `root` | `var(--color-content-primary)` | 1 |
| `lang-trigger-font-size` | `root` | `var(--font-size-xs)` | 1 |
| `lang-menu-gap` | `root` | `var(--space-0-5)` | 1 |
| `lang-menu-width` | `root` | `8rem` | 1 |
| `lang-menu-height` | `root` | `var(--space-6)` | 1 |
| `doc-line-height` | `root` | `0.6` | 1 |
| `doc-font-family` | `root` | `var(--font-family-sans, sans-serif)` | 1 |
| `doc-font-weight` | `root` | `600` | 1 |
| `doc-letter-spacing` | `root` | `0.06em` | 1 |
| `doc-width` | `root` | `4.5rem` | 1 |
### 4.2 Sin nombre mecánico (77)
- **⚠ decisión: `100%` es un valor identidad o geometría de layout, no un knob de tema — el perímetro de «knob» es D-TH.2, sin firmar** — 28: `inline-size` .
- **⚠ decisión: `border` es shorthand o eje físico — hay que partirlo en ejes lógicos antes de nombrarlo (recipe-contract §1, R-4.4)** — 13: `border` .
- **⚠ decisión: `padding` es shorthand o eje físico — hay que partirlo en ejes lógicos antes de nombrarlo (recipe-contract §1, R-4.4)** — 23: `padding` .
- **⚠ decisión: `1` es un valor identidad o geometría de layout, no un knob de tema — el perímetro de «knob» es D-TH.2, sin firmar** — 3: `opacity` , `line-height` .
- **⚠ decisión: `height` es shorthand o eje físico — hay que partirlo en ejes lógicos antes de nombrarlo (recipe-contract §1, R-4.4)** — 1: `height` .
- **⚠ decisión: `border-inline-start` es shorthand o eje físico — hay que partirlo en ejes lógicos antes de nombrarlo (recipe-contract §1, R-4.4)** — 1: `border-inline-start` .
- **⚠ decisión: `border-inline-end` es shorthand o eje físico — hay que partirlo en ejes lógicos antes de nombrarlo (recipe-contract §1, R-4.4)** — 1: `border-inline-end` .
- **⚠ decisión: `border-block-start` es shorthand o eje físico — hay que partirlo en ejes lógicos antes de nombrarlo (recipe-contract §1, R-4.4)** — 5: `border-block-start` .
- **foco: lo posee el sistema (`--focus-ring-*`, theming §32) — no acuñar token propio** — 2: `outline` .
### 4.3 Avisos sobre los tokens propuestos (2)
- **⚠ decisión: el valor es una expresión — el token puede llevar la expresión entera o sólo su término variable** — `--palabras-inspector-width` , `--palabras-segmented-radius` , `--palabras-panel-padding-inline`
- **el privado `--_palabras-col-resize-w` debe pasar a leer este público (o desaparecer)** — `--palabras-col-resize-width`
### 4.4 Lo que hay que comprobar a mano (PLAN-theming §1.3 · §7.4)
- [ ] **Privado que no deriva de un público** — §3 lo marca; el privado debe leer el público o desaparecer.
- [ ] **Velo o acento en el nodo equivocado** (`archetype: 'item'` en un envoltorio, un `background` en shorthand que mata la capa de estado) — se mide desde el píxel hacia arriba.
- [ ] **Doble animación** al mover un sello a una superficie con animación propia — registro de `animationstart` /`animationend`.
- [ ] **Diff de computed = 0** en reposo · hover · abierto · disabled · foco, por talla, antes y después.
- [ ] **Centinela por token nuevo** : valor imposible en el root → el nodo lo sigue. Si no, el token miente.
## 5. Veredicto
<!-- veredicto:start -->
_(pendiente — lo escribe el autor; se conserva al regenerar)_
<!-- veredicto:end -->