uix(password-field): temable — 41 % → 62 %, y el guard queda EN VERDE

7 claves (23 → 30). Censo password-field 41 % → **62 %**; el centinela pasa a
verde con **las siete adjudicaciones medidas**, incluidas las tres que este
componente arrastraba sin medir.

Cosido: el tracking del input enmascarado —los puntos leen mejor algo sueltos—,
el chip de bloq-mayús (radio y peso; su peso llevaba un `500` muerto detrás de un
token que ya vale 500) y **los cuatro peldaños del medidor de fuerza**.

LOS CUATRO PELDAÑOS SON UNA ESCALA DE INTENCIÓN, no cuatro colores sueltos: cada
uno lee su rol —pérdida, riesgo, cumplimiento, afirmación— y ahora un tema puede
recorrer la escala entera sin tocar los roles del sistema. De paso muere otra
referencia con respaldo: el primer peldaño leía
`var(--color-loss-solid, var(--color-threat-solid))` y el primitivo SÍ existe, así
que el respaldo era ruido.

LO QUE NO SE ACUÑA, Y ES COMPOSICIÓN: el `padding-inline` del medidor y el
`font-size` de su rótulo leen privados de FIELD (`--_field-control-*`), porque
este componente monta un Field. Se teman en la ficha del dueño — mandato de
composición, `theming-audit` §5.3-3.

Siete adjudicaciones, todas medidas: los cuatro peldaños sólo pintan bajo su
`data-strength` y la demo arranca con el campo vacío (fuerza 0, ningún segmento
activo); las dos de transición las congela el guard; y la opacidad deshabilitada
vive en el disparador de visibilidad, no en la raíz — por eso mi primera medición
dio «sin efecto» y hubo que buscar el nodo que la regla señala.

Gates: sonda antes/después **0 diffs en 3.060 valores** (14 nodos × 8 estados) ·
centinela 23/30 con las siete adjudicadas, exit 0 · censo --only 62 % · `--names`
sin desviadas · component-audit PASS · eidos-lint 0 invalid · suite eidos con el
único rojo conocido · rtl:check 0 · docs:check 0 · captura mirada (campo,
medidor de cuatro segmentos y rótulo en su sitio).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
alpha-0.1-background
dev 2 months ago
parent ab96ae783b
commit 608e7d5507

@ -10,8 +10,8 @@
- **Medido**: 2026-08-22 · **162 recetas** con CSS + **8 componentes sin receta** = 170 fichas, el árbol entero de `eidos/components/`
- **La pregunta**: ¿cuánto de la apariencia de cada componente puede cambiar un tema **sin tocar el sistema ni la receta**?
- **Alcance global**: **62%** — 2870 de 4628 knobs pasan por un token público del componente
- **Reparto**: público 2870 · privado 344 · global 919 · literal 495 · sistema transversal 509 · excepción firmada 54 _(los dos últimos, fuera del ratio)_
- **Alcance global**: **62%** — 2877 de 4628 knobs pasan por un token público del componente
- **Reparto**: público 2877 · privado 344 · global 912 · literal 495 · sistema transversal 509 · excepción firmada 54 _(los dos últimos, fuera del ratio)_
- **Sin token público propio**: 24 · **alcance < 20 %**: 15 · **alcance 100 %**: 17 · **con eje `size`**: 58
## Cómo se lee
@ -84,15 +84,15 @@ theming §6.7 lo pone delante (`hover-bg`). Las fichas proponen la forma
| 9 | [natural-time-picker](./natural-time-picker.md) | 25 | 67% | 77 | 62 |
| 10 | [menubar](./menubar.md) | 22 | 15% | 27 | 5 |
| 11 | [color-picker](./color-picker.md) | 20 | 75% | 82 | 71 |
| 12 | [password-field](./password-field.md) | 20 | 41% | 35 | 23 |
| 13 | [navigation-menu](./navigation-menu.md) | 19 | 44% | 38 | 26 |
| 14 | [sidebar](./sidebar.md) | 19 | 55% | 45 | 50 |
| 15 | [field](./field.md) | 18 | 73% | 72 | 60 |
| 16 | [mockup](./mockup.md) | 18 | 38% | 29 | 0 |
| 17 | [drawer](./drawer.md) | 17 | 72% | 62 | 54 |
| 18 | [onion-menu](./onion-menu.md) | 17 | 29% | 27 | 12 |
| 19 | [radio-group](./radio-group.md) | 17 | 77% | 75 | 61 |
| 20 | [popover](./popover.md) | 16 | 67% | 51 | 46 |
| 12 | [navigation-menu](./navigation-menu.md) | 19 | 44% | 38 | 26 |
| 13 | [sidebar](./sidebar.md) | 19 | 55% | 45 | 50 |
| 14 | [field](./field.md) | 18 | 73% | 72 | 60 |
| 15 | [mockup](./mockup.md) | 18 | 38% | 29 | 0 |
| 16 | [drawer](./drawer.md) | 17 | 72% | 62 | 54 |
| 17 | [onion-menu](./onion-menu.md) | 17 | 29% | 27 | 12 |
| 18 | [radio-group](./radio-group.md) | 17 | 77% | 75 | 61 |
| 19 | [popover](./popover.md) | 16 | 67% | 51 | 46 |
| 20 | [form](./form.md) | 15 | 71% | 52 | 54 |
## Sin ningún token público propio (24)
@ -141,7 +141,6 @@ La columna «contrato» cuenta las claves **públicas** del bloque del component
| [mockup](./mockup.md) | 38% | 29 | 11 | 0 | 13 | 5 | 0 | 0 | – |
| [date-range-picker](./date-range-picker.md) | 40% | 53 | 20 | 9 | 19 | 2 | 3 | 22 | y |
| [button-group](./button-group.md) | 40% | 5 | 2 | 0 | 0 | 3 | 0 | 1 | – |
| [password-field](./password-field.md) | 41% | 35 | 14 | 2 | 9 | 9 | 1 | 23 | y |
| [qr-code](./qr-code.md) | 43% | 7 | 3 | 0 | 0 | 4 | 0 | 10 | – |
| [navigation-menu](./navigation-menu.md) | 44% | 38 | 15 | 1 | 13 | 5 | 4 | 26 | y |
| [skeleton](./skeleton.md) | 45% | 11 | 5 | 5 | 0 | 1 | 0 | 9 | – |
@ -162,6 +161,7 @@ La columna «contrato» cuenta las claves **públicas** del bloque del component
| [mark](./mark.md) | 60% | 5 | 3 | 2 | 0 | 0 | 0 | 3 | – |
| [emoji-picker](./emoji-picker.md) | 61% | 32 | 17 | 0 | 8 | 3 | 4 | 17 | – |
| [radio-cards](./radio-cards.md) | 61% | 72 | 43 | 0 | 23 | 4 | 2 | 40 | y |
| [password-field](./password-field.md) | 62% | 35 | 21 | 2 | 2 | 9 | 1 | 30 | y |
| [clipboard](./clipboard.md) | 63% | 8 | 5 | 2 | 1 | 0 | 0 | 6 | – |
| [spin-field](./spin-field.md) | 64% | 27 | 16 | 0 | 8 | 1 | 2 | 20 | – |
| [meter](./meter.md) | 64% | 14 | 9 | 1 | 2 | 2 | 0 | 28 | y |

@ -5,26 +5,19 @@
> Vista de conjunto: [README](./README.md) · método y protocolo:
> [`PLAN-theming.md`](../../process/PLAN-theming.md) §1, §2, §7.
- **Medido**: 2026-08-22 · **Alcance**: **41%** — 14 de 34 knobs por token público
- **Knobs de apariencia**: 35 — público 14 · privado 2 · global 9 · literal 9 · sistema 1 · excepción 1 _(los dos últimos, fuera del ratio)_
- **Contrato hoy** (`lib/recipes/base.ts`): 23 pública(s) — `placeholder-fg`, `trigger-radius`, `trigger-bg`, `trigger-fg`, `icon-size-xs`, `icon-size-sm`, `icon-size-md`, `icon-size-lg`, `icon-size-xl`, `caps-fg`, `caps-bg`, `caps-font-size-xs`, `caps-font-size-sm`, `caps-font-size-md`, `caps-font-size-lg`, `caps-font-size-xl`, `strength-segment-bg`, `strength-segment-gap`, `strength-segment-height`, `strength-radius`, `transition-duration`, `transition-ease`, `disabled-opacity`
- **Medido**: 2026-08-22 · **Alcance**: **62%** — 21 de 34 knobs por token público
- **Knobs de apariencia**: 35 — público 21 · privado 2 · global 2 · literal 9 · sistema 1 · excepción 1 _(los dos últimos, fuera del ratio)_
- **Contrato hoy** (`lib/recipes/base.ts`): 30 pública(s) — `input-letter-spacing`, `caps-radius`, `caps-font-weight`, `strength-1-bg`, `strength-2-bg`, `strength-3-bg`, `strength-4-bg`, `placeholder-fg`, `trigger-radius`, `trigger-bg`, `trigger-fg`, `icon-size-xs`, `icon-size-sm`, `icon-size-md`, `icon-size-lg`, `icon-size-xl`, `caps-fg`, `caps-bg`, `caps-font-size-xs`, `caps-font-size-sm`, `caps-font-size-md`, `caps-font-size-lg`, `caps-font-size-xl`, `strength-segment-bg`, `strength-segment-gap`, `strength-segment-height`, `strength-radius`, `transition-duration`, `transition-ease`, `disabled-opacity`
- **Eje `size`**: sí · **ficheros**: `password-field.css`
## 1. Knobs fuera de alcance
### 1.1 Directo a primitivo global (9)
### 1.1 Directo a primitivo global (2)
| # | fichero:línea | selector | propiedad | valor |
| ---: | --- | --- | --- | --- |
| 1 | `password-field.css:76` | `[data-password-field-input]` | `letter-spacing` | `var(--tracking-wide)` |
| 2 | `password-field.css:130` | `[data-password-field-caps-lock-indicator]` | `border-radius` | `var(--radius-sm)` |
| 3 | `password-field.css:132` | `[data-password-field-caps-lock-indicator]` | `font-weight` | `var(--font-weight-medium, 500)` |
| 4 | `password-field.css:161` | `[data-password-field-strength-meter]` | `padding-inline` | `var(--_field-control-padding-inline)` |
| 5 | `password-field.css:179` | `[data-password-field-strength-meter][data-strength='1'] [data-password-field-strength-meter-segment][data-active]` | `background` | `var(--color-loss-solid, var(--color-threat-solid))` |
| 6 | `password-field.css:183` | `[data-password-field-strength-meter][data-strength='2'] [data-password-field-strength-meter-segment][data-active]` | `background` | `var(--color-risk-solid)` |
| 7 | `password-field.css:187` | `[data-password-field-strength-meter][data-strength='3'] [data-password-field-strength-meter-segment][data-active]` | `background` | `var(--color-fulfill-solid)` |
| 8 | `password-field.css:191` | `[data-password-field-strength-meter][data-strength='4'] [data-password-field-strength-meter-segment][data-active]` | `background` | `var(--color-affirm-solid)` |
| 9 | `password-field.css:195` | `[data-password-field-strength-meter-label]` | `font-size` | `calc(var(--_field-control-font-size) * 0.85)` |
| 1 | `password-field.css:161` | `[data-password-field-strength-meter]` | `padding-inline` | `var(--_field-control-padding-inline)` |
| 2 | `password-field.css:195` | `[data-password-field-strength-meter-label]` | `font-size` | `calc(var(--_field-control-font-size) * 0.85)` |
### 1.2 A través de un privado (2)
@ -78,7 +71,7 @@ Un tema los alcanza **a nivel de sistema**, por diseño (recipe-contract §2).
- **Tiene eje `size`**: los tokens dimensionales van por talla (`{part}-{eje}-{k}`) apuntando al bundle `--size-{k}-*`, nunca al primitivo crudo (theming §5; el guard `recipe-css-contract` prohíbe el primitivo).
### 4.1 Tokens a declarar en `lib/recipes/base.ts` (17)
### 4.1 Tokens a declarar en `lib/recipes/base.ts` (13)
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
@ -90,15 +83,11 @@ no distingue lo que debería — se marca `⚠`.
| --- | --- | --- | ---: |
| `hover-visibility-trigger-bg` | `root` | ⚠ `var(--color-secondary-track)` / `var(--color-neutral-track)` / `var(--color-affirm-track)` / `var(--color-fulfill-track)` / `var(--color-risk-track)` / `var(--color-threat-track)` / `var(--color-loss-track)` / `var(--color-primary-track)` | 8 |
| `hover-visibility-trigger-fg` | `root` | ⚠ `var(--color-secondary-text)` / `var(--color-neutral-text)` / `var(--color-affirm-text)` / `var(--color-fulfill-text)` / `var(--color-risk-text)` / `var(--color-threat-text)` / `var(--color-loss-text)` / `var(--color-primary-text)` | 8 |
| `strength-meter-bg` | `root` | ⚠ `var(--color-loss-solid, var(--color-threat-solid))` / `var(--color-risk-solid)` / `var(--color-fulfill-solid)` / `var(--color-affirm-solid)` | 4 |
| `input-letter-spacing` | `root` | `var(--tracking-wide)` | 1 |
| `visibility-trigger-width` | `root` | `65%` | 1 |
| `visibility-trigger-height` | `root` | `65%` | 1 |
| `caps-lock-indicator-gap` | `root` | `0.25em` | 1 |
| `caps-lock-indicator-padding-inline` | `root` | `0.4em` | 1 |
| `caps-lock-indicator-padding-block` | `root` | `0.2em` | 1 |
| `caps-lock-indicator-radius` | `root` | `var(--radius-sm)` | 1 |
| `caps-lock-indicator-font-weight` | `root` | `var(--font-weight-medium, 500)` | 1 |
| `caps-lock-glyph-font-size` | `root` | `1em` | 1 |
| `caps-lock-glyph-width` | `root` | `1em` | 1 |
| `caps-lock-glyph-height` | `root` | `1em` | 1 |
@ -128,6 +117,26 @@ no distingue lo que debería — se marca `⚠`.
<!-- veredicto:start -->
_(pendiente — lo escribe el autor; se conserva al regenerar)_
**EJECUTADO 2026-08-22 — 41 % → 62 %**, 7 claves, y el guard queda **en verde
con las siete adjudicaciones medidas** (antes arrastraba tres sin medir).
Cosido: el tracking del input enmascarado —los puntos leen mejor algo
sueltos—, el chip de bloq-mayús (radio y peso; su peso llevaba un `500` muerto
detrás de un token que ya vale 500) y **los cuatro peldaños del medidor de
fuerza**. Éstos son una ESCALA DE INTENCIÓN, no cuatro colores sueltos: cada
uno lee su rol —pérdida, riesgo, cumplimiento, afirmación— y ahora un tema
puede recorrer la escala entera sin tocar los roles del sistema.
**Lo que NO se acuña, y es composición**: el `padding-inline` del medidor y el
`font-size` de su rótulo leen privados de FIELD (`--_field-control-*`), porque
este componente monta un Field. Se teman en la ficha del dueño — mandato de
composición, `theming-audit` §5.3-3.
**Siete adjudicaciones, todas medidas**: los cuatro peldaños sólo pintan bajo
su `data-strength` y la demo arranca con el campo vacío (fuerza 0, ningún
segmento activo); las dos de transición las congela el guard, y la opacidad
deshabilitada vive en el disparador de visibilidad. Forzadas una a una.
Sonda antes/después: **0 diffs en 3.060 valores** (14 nodos × 8 estados).
<!-- veredicto:end -->

@ -455,6 +455,19 @@ de commit. Sin artefacto, el paso no se ha hecho.
## 8. Registro
- 2026-08-22 — **`password-field` 41 % → 62 %** (7 claves) **y el guard en
VERDE**: sus siete silencios quedan medidos, incluidos los tres que arrastraba
de antes.
Los cuatro peldaños del medidor de fuerza son una ESCALA DE INTENCIÓN —cada
uno lee su rol: pérdida, riesgo, cumplimiento, afirmación—, así que un tema
puede recorrerla entera sin tocar los roles del sistema. Fuera, por
composición: el padding del medidor y el tamaño de su rótulo leen privados de
FIELD (§5.3-3, se teman en la ficha del dueño).
Gates: sonda 0 diffs en 3.060 valores · censo 62 % · audit PASS · lint 0 ·
suite con el rojo conocido · rtl 0 · docs 0 · captura mirada.
- 2026-08-22 — **`context-menu` 53 % → 90 %** (11 claves, `global` a cero), y
**el instrumento aprende a abrir un menú contextual**: se abre con clic
DERECHO y con nada más, así que sonda y guard medían UN nodo. Con

@ -314,6 +314,20 @@ export const SENTINEL_EXCEPTIONS: Record<string, Record<string, string>> = {
'disabled-row-fg':
'no disabled row in the demo (0 mounted, counted); forced data-disabled → reaches (oklch(0.61 0 0) → rgb(1,2,3))'
},
'password-field': {
// The demo boots with an empty field: data-strength=0, so no segment is
// active and none of the four steps paints. Forced level by level
// 2026-08-22, transitions frozen.
'strength-1-bg': 'the meter sits at strength 0 (empty field); forced -> reaches (oklch(0.5787 0.1877 322.11) -> rgb(1,2,3))',
'strength-2-bg': 'same; forced -> reaches (oklch(0.6908 0.1909 45.02) -> rgb(1,2,3))',
'strength-3-bg': 'same; forced -> reaches (oklch(0.6406 0.1329 157.68) -> rgb(1,2,3))',
'strength-4-bg': 'same; forced -> reaches (oklch(0.6491 0.1136 181.96) -> rgb(1,2,3))',
// The visibility trigger owns both: the guard freezes transitions, and the
// demo boots enabled. Measured on it 2026-08-22.
'transition-duration': 'the guard freezes transitions; measured without the freeze on the visibility trigger -> reaches (0.12s -> 11.5s)',
'transition-ease': 'same freeze, same node -> reaches (cubic-bezier(0.4, 0, 0.2, 1) -> steps(4))',
'disabled-opacity': 'only under [data-disabled] on the visibility trigger; forced -> reaches (0.4 -> 0.123)'
},
'context-menu': {
// Third measurement of the same finding: the overlay DEPTH PLANE imposes the
// panel font and beats the recipe (section 12.9, pending signature, 20

@ -73,7 +73,7 @@
/* ── Input — reset owned by field.css `[data-field-input]`; keep only the mask
readability tweak (· glyphs read better with a touch of tracking). */
[data-password-field-input] {
letter-spacing: var(--tracking-wide);
letter-spacing: var(--password-field-input-letter-spacing);
}
[data-password-field-input]::placeholder {
letter-spacing: 0;
@ -127,9 +127,9 @@
gap: 0.25em;
padding-inline: 0.4em;
padding-block: 0.2em;
border-radius: var(--radius-sm);
border-radius: var(--password-field-caps-radius);
font-size: var(--_password-field-caps-font-size);
font-weight: var(--font-weight-medium, 500);
font-weight: var(--password-field-caps-font-weight);
color: var(--password-field-caps-fg);
background: var(--password-field-caps-bg);
pointer-events: none;
@ -176,19 +176,19 @@
[data-password-field-strength-meter][data-strength='1']
[data-password-field-strength-meter-segment][data-active] {
background: var(--color-loss-solid, var(--color-threat-solid));
background: var(--password-field-strength-1-bg);
}
[data-password-field-strength-meter][data-strength='2']
[data-password-field-strength-meter-segment][data-active] {
background: var(--color-risk-solid);
background: var(--password-field-strength-2-bg);
}
[data-password-field-strength-meter][data-strength='3']
[data-password-field-strength-meter-segment][data-active] {
background: var(--color-fulfill-solid);
background: var(--password-field-strength-3-bg);
}
[data-password-field-strength-meter][data-strength='4']
[data-password-field-strength-meter-segment][data-active] {
background: var(--color-affirm-solid);
background: var(--password-field-strength-4-bg);
}
[data-password-field-strength-meter-label] {

@ -2668,6 +2668,13 @@
--search-field-loading-indicator-track: var(--color-border-subtle);
--search-field-loading-indicator-thickness: 2px;
--search-field-loading-indicator-duration: 900ms;
--password-field-input-letter-spacing: var(--tracking-wide);
--password-field-caps-radius: var(--radius-sm);
--password-field-caps-font-weight: var(--font-weight-medium);
--password-field-strength-1-bg: var(--color-loss-solid);
--password-field-strength-2-bg: var(--color-risk-solid);
--password-field-strength-3-bg: var(--color-fulfill-solid);
--password-field-strength-4-bg: var(--color-affirm-solid);
--password-field-placeholder-fg: var(--color-content-muted);
--password-field-trigger-radius: var(--radius-sm);
--password-field-trigger-bg: transparent;

@ -4026,6 +4026,18 @@ export const THEME_BASE_RECIPE_TOKENS = defineRecipes({
'loading-indicator-duration': '900ms'
},
'password-field': {
// El tracking del input enmascarado (los puntos leen mejor algo sueltos) y el
// chip de bloq-mayús. Su peso llevaba un `500` muerto detrás del token.
'input-letter-spacing': 'var(--tracking-wide)',
'caps-radius': 'var(--radius-sm)',
'caps-font-weight': 'var(--font-weight-medium)',
// Los CUATRO peldaños del medidor de fuerza. Son una escala de intención,
// no cuatro colores sueltos: cada uno lee su rol —pérdida, riesgo,
// cumplimiento, afirmación— y un tema puede recorrer la escala entera.
'strength-1-bg': 'var(--color-loss-solid)',
'strength-2-bg': 'var(--color-risk-solid)',
'strength-3-bg': 'var(--color-fulfill-solid)',
'strength-4-bg': 'var(--color-affirm-solid)',
'placeholder-fg': 'var(--color-content-muted)',
'trigger-radius': 'var(--radius-sm)',
'trigger-bg': 'transparent',

Loading…
Cancel
Save

Powered by TurnKey Linux.