18 KiB
proof-of-human — 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 · método y protocolo:PLAN-theming.md§1, §2, §7.
- Medido: 2026-08-20 · Alcance: 0% — 0 de 91 knobs por token público
- Knobs de apariencia: 95 — público 0 · privado 18 · global 36 · literal 37 · sistema 4 (fuera del ratio)
- Contrato hoy (
lib/recipes/base.ts): 0 pública(s) · 2 privada(s) forward —_palette-solid,_palette-element - Eje
size: sí · ficheros:clock.css,proof-of-human.css,rotate-align.css
1. Knobs fuera de alcance
1.1 Directo a primitivo global (36)
| # | fichero:línea | selector | propiedad | valor |
|---|---|---|---|---|
| 1 | clock.css:29 |
.ck-ring |
fill |
var(--color-surface-raised) |
| 2 | clock.css:30 |
.ck-ring |
stroke |
var(--color-border-default) |
| 3 | clock.css:34 |
.ck-tick |
stroke |
var(--color-border-strong, var(--color-border-default)) |
| 4 | clock.css:39 |
.ck-num |
fill |
var(--color-content-secondary) |
| 5 | clock.css:60 |
.ck-badge-num |
fill |
var(--color-content-on-solid) |
| 6 | clock.css:68 |
.ck-house-frame |
stroke |
var(--color-border-default) |
| 7 | clock.css:87 |
.ck-sill |
fill |
var(--color-content-tertiary, var(--color-content-secondary)) |
| 8 | clock.css:145 |
.ck-hand-main, .ck-hand-tail |
fill |
var(--color-content-primary, var(--color-content-secondary)) |
| 9 | clock.css:148 |
.ck-hub |
fill |
var(--color-content-primary, var(--color-content-secondary)) |
| 10 | clock.css:178 |
[data-proof-of-human][data-state='verified'] .ck-roof |
fill |
var(--color-fulfill-solid) |
| 11 | clock.css:181 |
[data-proof-of-human][data-state='verified'] .ck-badge-dot |
fill |
var(--color-fulfill-solid) |
| 12 | proof-of-human.css:53 |
[data-proof-of-human] |
border-radius |
var(--radius-md) |
| 13 | proof-of-human.css:54 |
[data-proof-of-human] |
background |
var(--color-surface-raised) |
| 14 | proof-of-human.css:55 |
[data-proof-of-human] |
border |
var(--border-width) solid var(--color-border-default) |
| 15 | proof-of-human.css:63 |
[data-proof-of-human][data-state='verified'] |
border-color |
var(--color-fulfill-solid) |
| 16 | proof-of-human.css:66 |
[data-proof-of-human][data-state='failed'] |
border-color |
var(--color-risk-solid) |
| 17 | proof-of-human.css:156 |
[data-path-trace-token]:focus-visible |
border-radius |
var(--radius-full) |
| 18 | proof-of-human.css:164 |
.poh-trace-dot |
border-radius |
var(--radius-full) |
| 19 | proof-of-human.css:174 |
.poh-trace-dot[data-off-path] |
background |
var(--color-risk-solid) |
| 20 | proof-of-human.css:175 |
.poh-trace-dot[data-off-path] |
box-shadow |
0 0 0 4px color-mix(in srgb, var(--color-risk-solid) 24%, transparent), var(--shadow-2) |
| 21 | proof-of-human.css:187 |
[data-path-trace-token]::before |
min-inline-size |
var(--touch-target) |
| 22 | proof-of-human.css:188 |
[data-path-trace-token]::before |
min-block-size |
var(--touch-target) |
| 23 | rotate-align.css:59 |
[data-rotate-align-needle]:focus-visible |
border-radius |
var(--radius-full) |
| 24 | rotate-align.css:67 |
[data-rotate-align-needle]::before |
min-inline-size |
var(--touch-target) |
| 25 | rotate-align.css:68 |
[data-rotate-align-needle]::before |
min-block-size |
var(--touch-target) |
| 26 | rotate-align.css:83 |
.ra-ring |
fill |
var(--color-surface-raised) |
| 27 | rotate-align.css:84 |
.ra-ring |
stroke |
var(--color-border-default) |
| 28 | rotate-align.css:88 |
.ra-tick |
stroke |
var(--color-border-strong, var(--color-border-default)) |
| 29 | rotate-align.css:93 |
.ra-card |
fill |
var(--color-content-secondary) |
| 30 | rotate-align.css:114 |
.ra-post |
fill |
var(--color-content-tertiary, var(--color-content-secondary)) |
| 31 | rotate-align.css:123 |
.ra-flag |
fill |
var(--color-risk-solid) |
| 32 | rotate-align.css:128 |
[data-proof-of-human][data-state='verified'] .ra-box |
fill |
var(--color-fulfill-solid) |
| 33 | rotate-align.css:131 |
[data-proof-of-human][data-state='verified'] .ra-flag |
fill |
var(--color-fulfill-solid) |
| 34 | rotate-align.css:136 |
.ra-n |
fill |
var(--color-risk-solid) |
| 35 | rotate-align.css:139 |
.ra-s |
fill |
var(--color-content-secondary) |
| 36 | rotate-align.css:142 |
.ra-hub |
fill |
var(--color-content-primary, var(--color-content-secondary)) |
1.2 A través de un privado (18)
| # | fichero:línea | selector | propiedad | valor |
|---|---|---|---|---|
| 1 | clock.css:57 |
.ck-badge-dot |
fill |
var(--_proof-of-human-accent) |
| 2 | clock.css:67 |
.ck-house-frame |
fill |
var(--_proof-of-human-accent-soft) |
| 3 | clock.css:72 |
.ck-doorway |
fill |
color-mix(in srgb, var(--_proof-of-human-accent) 22%, black) |
| 4 | clock.css:75 |
.ck-door |
fill |
var(--_proof-of-human-accent-soft) |
| 5 | clock.css:76 |
.ck-door |
stroke |
var(--_proof-of-human-accent) |
| 6 | clock.css:90 |
.ck-roof |
fill |
var(--_proof-of-human-accent) |
| 7 | clock.css:151 |
.ck-hub-dot |
fill |
var(--_proof-of-human-accent-soft) |
| 8 | proof-of-human.css:52 |
[data-proof-of-human] |
min-block-size |
var(--_proof-of-human-min-h) |
| 9 | proof-of-human.css:103 |
.poh-trace-corridor |
stroke |
var(--_proof-of-human-accent-soft) |
| 10 | proof-of-human.css:111 |
.poh-trace-line |
stroke |
var(--_proof-of-human-accent) |
| 11 | proof-of-human.css:121 |
.poh-trace-trail |
stroke |
var(--_proof-of-human-accent) |
| 12 | proof-of-human.css:129 |
.poh-trace-start |
fill |
var(--_proof-of-human-accent) |
| 13 | proof-of-human.css:133 |
.poh-trace-goal |
stroke |
var(--_proof-of-human-accent) |
| 14 | proof-of-human.css:165 |
.poh-trace-dot |
background |
var(--_proof-of-human-accent) |
| 15 | proof-of-human.css:166 |
.poh-trace-dot |
box-shadow |
0 0 0 4px color-mix(in srgb, var(--_proof-of-human-accent) 22%, transparent), var(--shadow-2) |
| 16 | rotate-align.css:98 |
.ra-card.n |
fill |
var(--_proof-of-human-accent) |
| 17 | rotate-align.css:117 |
.ra-box |
fill |
var(--_proof-of-human-accent) |
| 18 | rotate-align.css:120 |
.ra-slot |
fill |
color-mix(in srgb, var(--_proof-of-human-accent) 55%, black) |
1.3 Literales (37)
| # | fichero:línea | selector | propiedad | valor |
|---|---|---|---|---|
| 1 | clock.css:21 |
.ck-face, .ck-hand |
inline-size |
100% |
| 2 | clock.css:22 |
.ck-face, .ck-hand |
block-size |
100% |
| 3 | clock.css:40 |
.ck-num |
font-size |
13px |
| 4 | clock.css:41 |
.ck-num |
font-weight |
600 |
| 5 | clock.css:61 |
.ck-badge-num |
font-size |
11px |
| 6 | clock.css:62 |
.ck-badge-num |
font-weight |
700 |
| 7 | clock.css:103 |
.ck-wing |
fill |
#9ca3af |
| 8 | clock.css:112 |
.ck-bird-body |
fill |
#d1d5db |
| 9 | clock.css:115 |
.ck-bird-head |
fill |
#e5e7eb |
| 10 | clock.css:118 |
.ck-eye |
fill |
#111827 |
| 11 | clock.css:121 |
.ck-glint |
fill |
#ffffff |
| 12 | clock.css:124 |
.ck-letter-paper |
fill |
#fefcf8 |
| 13 | clock.css:125 |
.ck-letter-paper |
stroke |
#cbb892 |
| 14 | clock.css:130 |
.ck-letter-flap |
stroke |
#cbb892 |
| 15 | clock.css:134 |
.ck-stamp |
fill |
#3b82f6 |
| 16 | clock.css:137 |
.ck-beak |
fill |
#fbbf24 |
| 17 | clock.css:138 |
.ck-beak |
stroke |
#d97706 |
| 18 | clock.css:203 |
0%, 13% |
opacity |
1 |
| 19 | clock.css:209 |
26%, 62% |
opacity |
1 |
| 20 | clock.css:220 |
to |
opacity |
1 |
| 21 | proof-of-human.css:82 |
[data-proof-of-human][data-state='verifying'] [data-path-trace], [data-proof-of-human][data-state='verified'] [data-path-trace] |
opacity |
0.55 |
| 22 | proof-of-human.css:94 |
.poh-trace-svg |
inline-size |
100% |
| 23 | proof-of-human.css:95 |
.poh-trace-svg |
block-size |
100% |
| 24 | proof-of-human.css:106 |
.poh-trace-corridor |
opacity |
0.5 |
| 25 | proof-of-human.css:116 |
.poh-trace-line |
opacity |
0.65 |
| 26 | proof-of-human.css:135 |
.poh-trace-goal |
opacity |
0.8 |
| 27 | proof-of-human.css:162 |
.poh-trace-dot |
inline-size |
1.25rem |
| 28 | proof-of-human.css:163 |
.poh-trace-dot |
block-size |
1.25rem |
| 29 | proof-of-human.css:189 |
[data-path-trace-token]::before |
inline-size |
100% |
| 30 | proof-of-human.css:190 |
[data-path-trace-token]::before |
block-size |
100% |
| 31 | rotate-align.css:23 |
[data-rotate-align-skin] |
inline-size |
min(230px, 72%) |
| 32 | rotate-align.css:36 |
[data-rotate-align-dial], [data-rotate-align-needle] |
inline-size |
100% |
| 33 | rotate-align.css:37 |
[data-rotate-align-dial], [data-rotate-align-needle] |
block-size |
100% |
| 34 | rotate-align.css:77 |
.ra-dial, .ra-needle |
inline-size |
100% |
| 35 | rotate-align.css:78 |
.ra-dial, .ra-needle |
block-size |
100% |
| 36 | rotate-align.css:94 |
.ra-card |
font-size |
13px |
| 37 | rotate-align.css:95 |
.ra-card |
font-weight |
600 |
2. Sistema transversal (4) — 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 | proof-of-human.css:151 |
[data-path-trace-token][data-disabled] |
opacity |
var(--opacity-disabled) |
| 2 | proof-of-human.css:154 |
[data-path-trace-token]:focus-visible |
outline |
var(--focus-ring-width) solid var(--focus-ring-color) |
| 3 | rotate-align.css:54 |
[data-rotate-align-needle][data-disabled] |
opacity |
var(--opacity-disabled) |
| 4 | rotate-align.css:57 |
[data-rotate-align-needle]:focus-visible |
outline |
var(--focus-ring-width) solid 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? |
|---|---|---|---|---|
--_proof-of-human-accent |
2 | var(--color-primary-solid), var(--_proof-of-human-palette-solid) |
global, private | no |
--_proof-of-human-accent-soft |
2 | var(--color-primary-element), var(--_proof-of-human-palette-element) |
global, private | no |
--_proof-of-human-min-h |
3 | calc(var(--size-md-control-height) * 3), calc(var(--size-sm-control-height) * 3), calc(var(--size-lg-control-height) * 3) |
global | no |
Consumidos y no declarados en el CSS (vienen de base.ts o de un estilo inline del wrapper): --_proof-of-human-palette-element, --_proof-of-human-palette-solid.
4. Propuesta de corrección
- Tiene eje
size: los tokens dimensionales van por talla ({part}-{eje}-{k}) apuntando al bundle--size-{k}-*, nunca al primitivo crudo (theming §5; el guardrecipe-css-contractprohíbe el primitivo).
4.1 Tokens a declarar en lib/recipes/base.ts (14)
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 (--proof-of-human-…) |
scope TSC | valor propuesto | usos |
|---|---|---|---|
fill |
root |
⚠ var(--color-surface-raised) / var(--color-content-secondary) / var(--color-primary-solid) / var(--_proof-of-human-palette-solid) / var(--color-content-on-solid) / var(--color-primary-element) / var(--_proof-of-human-palette-element) / var(--color-content-tertiary, var(--color-content-secondary)) / #9ca3af / #d1d5db / #e5e7eb / #111827 / #ffffff / #fefcf8 / #3b82f6 / #fbbf24 / var(--color-content-primary, var(--color-content-secondary)) / var(--color-fulfill-solid) / var(--color-risk-solid) |
45 |
stroke |
root |
⚠ var(--color-border-default) / var(--color-border-strong, var(--color-border-default)) / var(--color-primary-solid) / var(--_proof-of-human-palette-solid) / #cbb892 / #d97706 / var(--color-primary-element) / var(--_proof-of-human-palette-element) |
18 |
radius |
root |
⚠ var(--radius-md) / var(--radius-full) |
4 |
bg |
root |
⚠ var(--color-surface-raised) / var(--color-primary-solid) / var(--_proof-of-human-palette-solid) / var(--color-risk-solid) |
4 |
opacity |
root |
⚠ 0.55 / 0.5 / 0.65 / 0.8 |
4 |
width |
root |
⚠ 1.25rem / var(--touch-target) / min(230px, 72%) |
4 |
font-size |
root |
⚠ 13px / 11px |
3 |
font-weight |
root |
⚠ 600 / 700 |
3 |
height |
root |
⚠ 1.25rem / var(--touch-target) |
3 |
shadow |
root |
⚠ var(--color-primary-solid) / var(--_proof-of-human-palette-solid) / 0 0 0 4px color-mix(in srgb, var(--color-risk-solid) 24%, transparent), var(--shadow-2) |
3 |
border |
root |
⚠ var(--color-fulfill-solid) / var(--color-risk-solid) |
2 |
height-md |
size:md |
calc(var(--size-md-control-height) * 3) |
1 |
height-sm |
size:sm |
calc(var(--size-sm-control-height) * 3) |
1 |
height-lg |
size:lg |
calc(var(--size-lg-control-height) * 3) |
1 |
4.2 Sin nombre mecánico (14)
- ⚠ 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 — 10:inline-size,block-size. - ⚠ decisión:
1es 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. - ⚠ decisión:
borderes shorthand o eje físico — hay que partirlo en ejes lógicos antes de nombrarlo (recipe-contract §1, R-4.4) — 1:border.
4.3 Avisos sobre los tokens propuestos (4)
- el privado
--_proof-of-human-accentdebe pasar a leer este público (o desaparecer) —--proof-of-human-fill,--proof-of-human-stroke,--proof-of-human-bg,--proof-of-human-shadow - el privado
--_proof-of-human-accent-softdebe pasar a leer este público (o desaparecer) —--proof-of-human-fill,--proof-of-human-stroke - ⚠ decisión: el valor es una expresión — el token puede llevar la expresión entera o sólo su término variable · el privado
--_proof-of-human-min-hdebe pasar a leer este público (o desaparecer) —--proof-of-human-height-md,--proof-of-human-height-sm,--proof-of-human-height-lg - ⚠ decisión: el valor es una expresión — el token puede llevar la expresión entera o sólo su término variable —
--proof-of-human-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, unbackgrounden 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
Revisión 2026-08-20 — verificación previa a implementación (Opus).
Análisis (§1–§3): CORRECTO en cifras (95 · 0 · 18 · 36 · 37 · 4,
reproducido), con un matiz que cambia la lectura de los literales: de los
37, al menos 20 ya llevan anotación /* literal: … */ (el papel de la
carta #fefcf8, el sello #3b82f6, la paloma #fbbf24, los cielos del
reloj…) — son los colores físicamente fijos que recipe-contract §3 bendice
(«the natural clock's skies»). El censo no ve comentarios, así que los cuenta
como deuda; para R-5 son excepciones por válvula, no tokens.
Propuesta (§4.1): NO IMPLEMENTAR tal cual. La tabla colapsa en nombres
inservibles (fill con 45 usos y 19 valores; stroke 18/8) porque el CSS de
la escena no usa data-attrs sino clases (.ra-card, .ra-needle,
.poh-trace-dot, .ra-tick…) y la derivación no puede leer la parte. Eso
destapa además una deuda propia: hooks de clase en una receta eidos violan
la convención (los ganchos del recipe son data-*; memoria
eidos-lint-no-class-hooks) — el linter no puede clasificarlos.
Disposición (diseño a mano, no mecánico):
- Separar CROMO de ESCENA. Cromo (la tarjeta
.ra-card/root: bg, radius, border, sombra, tipografía del HUD,--_proof-of-human-min-h) → tokens públicos normales; ahí sí valen las filasheight-{sm,md,lg}de §4.1 (expresión enteracalc(var(--size-{k}-control-height) * 3), patrón Sidebar con resueltohost+size:{k}; el root estampadata-size✓). - La escena NO se tokeniza por knob: sus colores son identidad del desafío (anti-bot) y ya están anotados físicamente fijos → excepciones R-5 con razón («escena del captcha, identidad fija»); completar la anotación en los ~17 literales que aún no la lleven.
- El acento SÍ:
--_proof-of-human-accent/-accent-soft(hoyvar(--color-primary-*)con forward de paleta THM-2) es el único eje de color que un tema debe alcanzar — promover a públicoaccent/accent-softy que los privados lo lean. - Deuda aparte (no de este eje): migrar los hooks
.ra-*/.poh-*adata-*del morfo — sin eso,eidos-lintseguirá ciego aquí. Anotarla, no ejecutarla de oficio (no-cascade).
Bloqueos de firma: el perímetro escena-vs-cromo (qué literales son
excepción y cuáles knobs) lo firma el autor con la lista delante · la deuda de
hooks de clase (eje aparte) · D-TH.2 (los 100%/opacity:1).