fix(theming): el velo del sistema no muere por un atajo - y el pin de chronos sobra

Dos hechos de cascada, hermanos de la firma 55:

1. Las reglas del suelo de popover usaban el ATAJO `background:` - expande a
   `background-image: none` y MATA el velo de hover del sistema
   (archetypes) cuando el orden de carga cae del otro lado. La regla dura lo
   prohibe por escrito ("hover is the system's"). Partido a
   `background-color:`: 0 px sobre las 14 identidades del catalogo (68
   lecturas reposo + 68 hover, todas a cero; `rules split=2` en las catorce
   como anti-vacio; control negativo 5/4), y el velo SOBREVIVE al orden
   invertido - verificado con experimento de cascada aislado.
2. El pin de `chronos.css:417` RETIRADO: sus cinco declaraciones eran copias
   textuales de `[data-button]` - 20 combinaciones variant x size identicas
   con y sin el (control negativo 0/20). La adjudicacion de 13 era FALSA:
   al `+N more` el velo se lo mata `button.css:69`/`:88`, con pin o sin el.
   `calendar-select.css:14` NO es pin (vivo en 3 de 4 tallas) - se queda.

- Guarda extendida (active-eidos-config.test.ts): el suelo declara
  `background-color` y NUNCA el atajo - validada por 4 mutaciones (las dos
  ultimas prueban la mitad NEGATIVA, anadidas porque 1-2 solas la dejaban
  sin morder).
- Sondas popover 0/448 y chronos 0/36.832 - eidos 443+1 ajeno - check
  identico byte a byte antes/despues - docs-check 0/0 x2 - lint 0 invalid.
- Registro: changelog 56 (la prueba citable es el barrido de catalogo) -
  13: `background-image` RESUELTO y `transition` como RESIDUO VIVO con su
  numero (suelo `background,border-color` vs arquetipo
  `opacity,background-color`: hoy el border-color del hover SALTA en vez de
  animarse) - fichas de chronos (7 filas stale corregidas, recuentos
  contados contra fichero: 202->198, 50->47), calendar (su HALLAZGO ya
  resuelto por 55, cerrado) y emoji-picker - 5 textos stale ANOTADOS sin
  reescribir (cada medida fue correcta con la cascada de su dia), con dos
  matices: en gradient-picker solo caduco la mitad base, y open-trigger-fg
  gana ahora por ESPECIFICIDAD, no por orden.
- Fuera del registro del eje, por regla dura del autor: el material de
  sitio/demo (la inversion de imports de /alpha) - ademas desactivado por
  esta misma firma en la capa que importa.

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

@ -144,6 +144,15 @@ identidad, que es lo que son.
`next-features` §13.
**Regla que confirma**: ante un diff inesperado, corre la sonda dos veces
sobre el mismo código ANTES de sospechar de tu cambio.
**CERRADO 2026-08-25 por la firma §55 «el sobre de trigger de popover es el
SUELO»** (changelog §55). El empate ya no existe: el sobre de `popover.css`
se emite desde `:where(...)`, (0,0,0), así que
`[data-calendar-month-select][data-button]` (0,2,0) le gana de forma
DETERMINISTA y la letra deja de depender de qué chunk inyecte Vite el último.
Medido después por talla con la regla desactivada en vivo: xs 12px, sm 14px,
md 16px, lg 20px con la regla, 16px en las cuatro sin ella — retirarla
rompería el tipo en 3 de 4 tallas, así que **no es un pin y no se toca**. Ya
no apunta a `next-features` §13.
4. **`select-min-width` no tiene nodo en NINGUNA página del repo**: su único
consumidor es `[data-range-calendar-month-select]` / `-year-select`, y ninguna
demo monta esas partes (la de range-calendar renderiza un heading de texto; el

@ -12,6 +12,22 @@
## 1. Knobs fuera de alcance
<!-- mano:start -->
> **NOTA 2026-08-25 — las filas 68-71 de §1.1 citan una regla RETIRADA.** El pin
> `[data-popover-trigger][data-chronos-more-link]:not(…)` (`chronos.css:417-423`,
> propiedades `padding-inline` · `border` · `border-radius` · `background`) se
> retiró con la firma «el velo del sistema no muere por un atajo». Existía sólo
> para ganarle al sobre de trigger de `popover.css` cuando estaba a (0,2,0); §55
> bajó ese sobre al SUELO (0,0,0), donde `[data-button]` (0,1,0) ya le gana, y
> cuatro de las cinco declaraciones del pin eran copias literales de
> `[data-button]`. Medido con la regla desactivada en vivo: **0 diffs en 20
> combinaciones `variant` × `size`**, reposo y hover. **El censo baja de 202 a
> 198** (verificado: `--only chronos` → knobs 240 · global 198); las cuatro filas
> desaparecen al regenerar la ficha.
<!-- mano:end -->
### 1.1 Directo a primitivo global (202)
| # | fichero:línea | selector | propiedad | valor |
@ -302,6 +318,19 @@ Consumidos y **no declarados en el CSS** (vienen de `base.ts` o de un estilo inl
## 4. Propuesta de corrección
<!-- mano:start -->
> **NOTA 2026-08-25 — `more-link-{padding-inline,radius,bg}` se quedan SIN
> CONSUMIDOR.** Los tres tokens propuestos en §4.1 tienen `usos: 1`, y ese uso
> era el pin de `chronos.css:417`, retirado por la firma «el velo del sistema no
> muere por un atajo». **La propuesta baja de 50 a 47.** Y no es sólo una
> limpieza: los tres proponían un token PÚBLICO de `chronos` cuyo valor es un
> PRIVADO de `button` (`--_button-*`), justo lo que el preámbulo de este §4
> prohíbe — «un token prestado importa la semántica de su dueño: la corrección
> no es duplicarlo con prefijo propio». Retirar el pin las borra gratis.
<!-- mano:end -->
- **Consume la capa compartida `picker-shell`.** Un eje que la capa posee se consume como `var(--_x, var(--x))`; el consumidor **no acuña** `--chronos-{eje}` para él — sería un vocabulario paralelo (README de `eidos/components`, «Capas compartidas» regla 2).
- **Consume tokens públicos de `button`, `popover`.** 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).
- **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).

@ -106,6 +106,15 @@ de que estaban muertas. Es el defecto que `gradient-picker` documentó (36 de su
orden. **`trigger-fg` no llegó a existir**: se acuñó y se midió muerta en el
mismo pase.
> **NOTA 2026-08-25 — la PREMISA de ese párrafo caducó; la retirada sigue
> siendo correcta.** El sobre de trigger ya no es **(0,2,0)**: la firma §55 «el
> sobre de trigger de popover es el SUELO» lo emite desde `:where(...)`,
> **(0,0,0)**, así que hoy PIERDE contra el (0,1,0) de esta receta. Las tres
> claves siguen retiradas y no hay defecto visual —la receta calla y el suelo
> pinta, que es su trabajo—, pero si volvieran **ganarían**: la razón por la que
> estaban muertas ya no es la que dice arriba. Se anota en vez de reescribirse
> porque la medida de entonces fue correcta con la cascada de entonces.
**Cinco adjudicaciones, todas medidas forzando sobre nodos reales**: las tres
del marcador de tono (la demo monta **cero** celdas `data-tone-capable`; forzado
el atributo sobre una celda real, el `::after` alcanza — 4px → 37px, 9999px →

@ -558,16 +558,30 @@ existiera. Se anotan porque el eje entero se apoya en esas mediciones.
selector propio ENCIMA para recuperar su cromo. Con el sobre en el suelo, esos
pines ya no defienden de nada — pero siguen pesando, y ahora ganan a reglas que
quizá deberían ganarles:
- `chronos.css:417` — `[data-popover-trigger][data-chronos-more-link]:not(…)`
a **(0,3,0)**, con su comentario diciendo por qué existe. Medido hoy: su
`background: var(--_button-bg)` (shorthand) le gana al velo de hover de
`archetypes.css` (0,0,0), así que el `+N more` NO recibe la capa de estado
del sistema; su afordancia de hover es el `text-decoration: underline` de su
propia receta, que es correcta para un enlace pero NO es lo que el pin
pretendía. **Retirarlo es un cambio de píxel: firma aparte.**
- ~~`chronos.css:417`~~ — **RETIRADO 2026-08-25** (firma «el velo del sistema
no muere por un atajo»), y **§13 lo había adjudicado MAL**. Decía que su
`background: var(--_button-bg)` le ganaba al velo de hover de
`archetypes.css` y que retirarlo era un cambio de píxel. El HECHO es cierto
—el `+N more` no recibe el velo, su afordancia es el `underline` de su
receta— pero la ATRIBUCIÓN era falsa: al velo lo mata `button.css:69`
(`[data-button]`, (0,1,0)) y `button.css:88` (`:hover`, (0,2,0)), con el pin
puesto **o quitado**; medido, el único autor de `background-image` que casa
es `archetypes` y pierde en las dos pasadas. El pin era
**REDUNDANTE-TOTAL**: cuatro de sus cinco declaraciones eran copias
literales de `[data-button]` y la quinta (`height: auto`) es el gemelo
lógico de su `block-size: fit-content`. **0 diffs en 20 combinaciones
`variant` × `size`**, reposo y hover, con el sucesor NOMBRADO y control
negativo 20/20. No necesitó firma de producto: fue una limpieza. Ficha
`docs/audit/theming/chronos.md` anotada (censo 202→198, propuesta 50→47:
los tres `more-link-*` se quedaron sin consumidor, y proponían un público de
`chronos` con valor privado de `button` — lo que su propio §4 prohíbe).
- `calendar` — sus selectores de mes/año NO llevan pin propio; el que empataba
era `[data-calendar-month-select][data-button]` (0,2,0), que hoy gana solo.
Nada que revisar.
Nada que revisar. **Medido 2026-08-25** con la declaración desactivada en
vivo: retirarla rompería el tipo en **3 de 4 tallas** (xs 12→16, sm 14→16,
lg 20→16 px), así que ni es un pin ni se toca. El ⚠ HALLAZGO «no
determinista» de `docs/audit/theming/calendar.md` que apuntaba a este §13
queda CERRADO allí con nota fechada.
- `chat-message.css:462` — `[data-chat-message-actions] [data-chat-message-reaction-add]`
(0,2,0) **era una trampa armada** (empataba con el sobre y ninguna superficie
del repo monta ese anidamiento). Hoy gana de forma determinista: medido
@ -585,18 +599,38 @@ existiera. Se anotan porque el eje entero se apoya en esas mediciones.
ninguna de las dos es una petición explícita por elemento como el `frost`, y
`archetypes.css:19-21` ya declara que el anillo de foco «must lose to any
component rule». **Decisión pendiente, con su número.**
- **El suelo de `popover.css` COMPARTE peldaño con `archetypes.css`**
(2026-08-25, medido, sin defecto observado). Al bajar a (0,0,0), las dos reglas
del sobre empatan con `:where([data-archetype='trigger'])` y su gemela de
hover, que declaran `transition` y el velo de estado. El orden lo decide el
documento. **Medido 16 cargas limpias en 4 rutas: archetypes SIEMPRE cae
después** (los índices de hoja varían de `sheet0` a `sheet19` y el resultado no
cambia), así que hoy el sistema gana su `transition` y su velo — que es lo que
la firma quería. Pero es un empate de verdad, y **no se ha verificado en
producción** (bundle de Vite en vez de dev), donde el orden de emisión es otro.
Si alguna vez se invierte, un trigger desnudo perdería el velo de hover.
El arreglo limpio sería que `popover.css` dejara de declarar hover propio y se
apoyara en la capa del sistema — otra firma.
- **El suelo de `popover.css` COMPARTE peldaño con `archetypes.css`** — y lo
único que queda del empate es `transition` (2026-08-25, medido). Al bajar a
(0,0,0), las dos reglas del sobre empatan con `:where([data-archetype='trigger'])`
y su gemela de hover: las CUATRO a (0,0,0), así que el orden de documento
decide. Se disputaban DOS propiedades y la firma «el velo del sistema no muere
por un atajo» sacó una del empate:
- **`background-image` — RESUELTO.** El suelo declaraba `background:`, un
ATAJO que expande a los ocho longhands y entre ellos `background-image: none`
— que es EXACTAMENTE donde `archetypes.css` pinta el velo de estado. Y no
era sólo la regla de hover: el `:where()` deja también la de REPOSO empatada
con la de hover del arquetipo, y ésa sola bastaba para matarlo. Partido en
`background-color:` (`popover.css:60` y `:75`), el velo **compone encima
gane quien gane el orden** — medido idéntico en los DOS órdenes, donde antes
daba `none`. Coste **0 px** sobre el barrido de **14 identidades del
catálogo, 68 lecturas × 2 estados**, con control negativo (diff 5 y 4). Es
lo que `feedback_hover_is_the_systems_never_a_per_component_invention` ya
mandaba: el acento de estado va en `background-color` para que la capa
COMPONGA encima.
- **`transition` — RESIDUO VIVO, con su número.** El suelo declara
`background, border-color`; el arquetipo, `opacity, background-color`.
Siguen empatados a (0,0,0) y sigue decidiéndolo el orden: hoy gana el del
arquetipo, así que **el cambio de `border-color` del hover de popover no se
anima — salta**. Defecto pequeño y sin efecto sobre el velo, pero es la
misma clase que §12.9 y §53 se firmaron para prohibir («no rung ties
another»): la doctrina no adjudica un ganador del empate, lo PROHÍBE.
- **Decisión de producto, aparte**: que `popover.css` deje de declarar hover
propio y se apoye entera en la capa del sistema — lo doctrinalmente puro, y
lo que §13 proponía. **NO es de coste cero**: hoy el hover de un trigger
desnudo mueve `background-color` 0.9821 → 0.931 **y además** recibe el velo;
sin la regla propia queda sólo el velo. Cambio visible en los triggers
desnudos del catálogo — firma aparte, con censo. Cerraría de paso el residuo
`transition`.
- ~~**El centinela da falsos negativos sobre una propiedad transicionada.**~~
**CAUSA ENCONTRADA Y ARREGLADA 2026-08-21** (revisión adversarial): no era la
@ -667,6 +701,13 @@ existiera. Se anotan porque el eje entero se apoya en esas mediciones.
Nació con la segunda ocurrencia de la clase: el `item-gap` de `carousel`
contra un estilo INLINE de soma, invisible para todo análisis estático.
Los ocho componentes de F2-A pasan con su adjudicación escrita.
> **NOTA 2026-08-25** — la premisa «(0,2,0 contra 0,1,0)» de este punto
> CADUCÓ: la firma §55 emite el sobre de trigger de `popover.css` desde
> `:where(...)`, **(0,0,0)**, así que hoy PIERDE contra la receta del huésped.
> El hallazgo sigue en pie como historia y la retirada sigue siendo correcta
> —la receta calla y el suelo pinta, que es su trabajo—, pero si aquellas
> declaraciones volvieran hoy **ganarían**. Se anota en vez de reescribirse:
> la medida de entonces fue correcta con la cascada de entonces.
- **`--gp-current-gradient` es un nombre ABREVIADO en SOMA.** Lo estampa
`gradient-picker-provider.svelte.ts` (no el wrapper de eidos, como decía la
ficha), y viola theming §6 r5. No es knob de tema —es un canal de valor— pero
@ -722,6 +763,12 @@ Lo que la capa `calendar-surface` añadió (2026-08-21):
Arreglarlo es subir el peso del pin de forma determinista — decisión, porque
fija el píxel en un lado. Segunda ocurrencia de la clase §12.3 (empate por
orden de carga) y segunda víctima de la misma regla de popover.
> **CERRADO 2026-08-25 por §55.** No hizo falta subir el peso del pin: bajó el
> del rival. El sobre de `popover.css` se emite desde `:where(...)`, (0,0,0),
> así que `[data-calendar-month-select][data-button]` (0,2,0) gana de forma
> DETERMINISTA y la letra deja de depender de qué chunk inyecte Vite el
> último. Re-medido 2026-08-25 por talla: 12 / 14 / 16 / 20 px con la regla,
> 16 px en las cuatro sin ella — **no es un pin y no se toca**.
- **Los tres consumidores de la capa siguen leyendo 0 % de alcance**, ahora por
los forwards de paleta THM-2 — ver el punto del censo más arriba.

@ -1,4 +1,4 @@
# CONTINUE — eje Theming «theme-reach» (handoff, act. 2026-08-24 noche)
# CONTINUE — eje Theming «theme-reach» (handoff, act. 2026-08-25)
## EMPIEZA AQUÍ
@ -10,6 +10,47 @@ pendientes. Global **68 %**, **45 componentes al 100 %**.
Lo que queda NO es ejecución: son **cinco firmas** y una lista de deuda acotada.
No abras nada nuevo sin leer §«Lo que espera TU FIRMA» de aquí abajo.
### FIRMA EJECUTADA (2026-08-25) — el velo del sistema no muere por un ATAJO
**Qué se firmó** (changelog §56, reverso de §55 el mismo día): al bajar el sobre
de trigger de `popover.css` al suelo, §55 lo dejó a **(0,0,0) — el mismo peldaño
que `archetypes.css`**, que es quien pinta el velo de estado del sistema. Y el
suelo declaraba su superficie con el ATAJO `background:`, que expande a
`background-image: none` — **la propiedad exacta donde vive ese velo**. Resultado:
el velo de hover de todo trigger desnudo dependía de qué hoja cayera después.
No sólo por la regla de hover: el `:where()` deja también la de REPOSO empatada
con la de hover del arquetipo, y ésa sola bastaba. La corrección son DOS
PALABRAS — `background-color:` en `popover.css:60` y `:75`.
**Los números**: **0 px** en el barrido de las **14 identidades del catálogo**
que montan un `[data-popover-trigger]` (68 lecturas en reposo → 0 movidas, 68 en
hover → 0 movidas, `rules split=2` en las 14) con control negativo diff 5 / 4;
las dos sondas del eje a **0 diffs** (`popover` 448 valores / 8 estados, `chronos`
36 832 / 7); y **el velo sobrevive al orden invertido**, donde con el atajo moría
(`linear-gradient(…8 %…)` → `none`). Cae con la firma el pin `chronos.css:417`
(cinco declaraciones a (0,3,0) que ya no defendían nada): **0 diffs en 20
combinaciones `variant` × `size`**, control negativo 20/20 — §13 lo había
adjudicado mal, al velo del `+N more` lo mata `button.css:69`/`:88`. Guarda §55
apartado **(f)** en `active-eidos-config.test.ts`, **4 mutaciones / 4 mordidas**
(las dos primeras muerden la mitad positiva, las dos segundas —el atajo AÑADIDO
junto al longhand— la negativa).
**Lo que quedó fuera, con su número en `next-features.md` §13**: el residuo
`transition` del MISMO empate (suelo `background, border-color` vs arquetipo
`opacity, background-color`, las dos a (0,0,0) — hoy el `border-color` del hover
de popover salta en vez de animarse), la decisión de producto «popover deja de
declarar hover propio» (no es coste cero: 0.9821 → 0.931 **más** el velo hoy,
sólo el velo después) y `calendar-select.css:14`, que **no es un pin** — retirarlo
rompe el tipo en 3 de 4 tallas (12 / 14 / 20 → 16 px).
**Fichas y prosa saneadas**: `chronos.md` (censo 202→198, propuesta 50→47, en
bloques `<!-- mano:… -->` para que sobrevivan a `--report`), `calendar.md` (su
⚠ HALLAZGO «no determinista» lo cerró §55 y ya no apunta a §13), `emoji-picker.md`
y los tres comentarios de código que seguían afirmando **(0,2,0)** del sobre
(`emoji-picker.css`, `gradient-picker.css` —sólo su mitad base, la de estados
sigue viva— y `lib/recipes/base.ts`). Se ANOTAN, no se reescriben: cada medida
fue correcta con la cascada de su día.
### FIRMA B′ EJECUTADA (2026-08-24) — la cascada de paleta es una ESCALERA
**Qué se firmó**: los tres escritores de `--{c}-palette-*` pasan a tres peldaños

@ -2307,8 +2307,83 @@ Guarda por **mutación** en `active-eidos-config.test.ts` (§55, 6 mutaciones,
del `:where()` · suelo vaciado · una QUINTA regla de trigger fuera del suelo ·
y las dos reglas de estado bajadas en silencio.
## 56. El velo del sistema no muere por un ATAJO — `background-color`, nunca el shorthand `background` (2026-08-25)
**FIRMA — el reverso de §55, el mismo día.** Al bajar el sobre de trigger al
suelo, §55 lo dejó a (0,0,0): **el mismo peldaño que ocupa `archetypes.css`**,
que es quien pinta el velo de estado del sistema. Empate nuevo. Y el suelo
declaraba su superficie con el ATAJO `background:`, que expande a los OCHO
longhands y entre ellos **`background-image: none`** — que es EXACTAMENTE la
propiedad donde ese velo se pinta. El empate no era cosmético: **el velo de hover
de todo trigger desnudo dependía de qué hoja cayera después**.
**Y no era sólo la regla de hover.** El `:where()` anula la contribución de
especificidad de todo lo que lleva dentro, pseudo-clases incluidas, así que deja
la regla de **REPOSO** del suelo empatada también con la de **HOVER** del
arquetipo — y la de reposo ya declaraba `background-image: none` por el atajo.
Bastaba ella sola para matar el velo.
**La corrección son dos palabras**: `background:` → `background-color:` en
`popover.css:60` (reposo) y `:75` (hover). Deja de declararse `background-image`,
así que **el velo SALE del empate**: el sistema pinta su capa y la superficie de
popover compone debajo, gane quien gane el orden. Es lo que
`feedback_hover_is_the_systems_never_a_per_component_invention` ya mandaba —
«nunca un `background:` a mano, nunca `background-image: none` para "limpiar" el
velo; el acento de estado va en `background-color` para que la capa COMPONGA
encima»—. La causa no era el empate: era un shorthand donde la doctrina exige un
longhand.
**Los números** (transiciones congeladas en toda medida):
- **0 px sobre el barrido de las 14 identidades del catálogo** que montan un
`[data-popover-trigger]` — `popover` · `chronos` · `calendar` ·
`emoji-picker` · `natural-time-picker` · `chat-message` · `gradient-picker` ·
`palabras` · `date-picker` · `time-picker` · `color-picker` · `field-langs` ·
`toolbar` · `select`: **68 lecturas en reposo → 0 movidas, 68 en hover →
0 movidas**, con las DOS reglas del suelo intervenidas en las catorce
(`rules split=2` en todas, que es el anti-vacío del barrido). **Control
negativo** con centinela: diff **5** y diff **4** — el arnés muerde.
- **Las dos sondas del eje, 0 diffs**: `popover` 448 valores computados en
8 estados; `chronos` **36 832** en 7.
- **El velo sobrevive al ORDEN INVERTIDO.** Aislado el empate —las dos reglas del
suelo sacadas de su hoja y re-anexadas al final del `<head>`, misma
especificidad, sólo cambia el orden de documento— el `background-image` del
hover leía `linear-gradient(…8 %…)` **→ `none`** con el atajo, y
`linear-gradient(…8 %…)` **en los DOS órdenes** con el longhand.
**Y cae con ella un pin que ya no defendía nada**: `chronos.css:417`, cinco
declaraciones a (0,3,0) que existían sólo para ganarle al sobre viejo a (0,2,0).
Con el sobre en el suelo, `[data-button]` (0,1,0) le gana solo — y cuatro de las
cinco eran copias **literales** de `[data-button]`; la quinta, `height: auto`, es
el gemelo lógico de su `block-size: fit-content`. Retirado con **0 diffs en 20
combinaciones `variant` × `size`**, reposo y hover, control negativo **20/20**.
`next-features.md` §13 lo había adjudicado como «cambio de píxel, firma aparte»
por una atribución FALSA: al velo del `+N more` lo mata `button.css:69`
(`[data-button]`, (0,1,0)) y `button.css:88` (`:hover`, (0,2,0)), con el pin
puesto **o quitado**. Corregido allí, y la ficha de `chronos` anotada
(censo **202→198**, propuesta **50→47**: los tres `more-link-*` se quedaron sin
consumidor, y proponían un público de `chronos` con valor privado de `button` —
lo que su propio §4 prohíbe).
**Lo que NO se tocó, y es decisión**: `calendar-select.css:14`, que **no es un
pin** —retirarlo rompe el tipo en 3 de 4 tallas (12 / 14 / 20 → 16 px)—; el
**residuo `transition`** del mismo empate (el suelo declara `background,
border-color`, el arquetipo `opacity, background-color`, las dos a (0,0,0): hoy
gana el arquetipo, así que el cambio de `border-color` del hover de popover
SALTA en vez de animarse); y la decisión de producto de que `popover.css` deje de
declarar hover propio, que **no es de coste cero** (hoy el trigger desnudo mueve
`background-color` 0.9821 → 0.931 **y además** recibe el velo; sin ella, sólo el
velo). Los tres en `next-features.md` §13.
Guarda por **mutación** en `active-eidos-config.test.ts` (§55, apartado **(f)**,
4 mutaciones, **4 mordidas**): el longhand devuelto al atajo en reposo y en hover
—que muerden la mitad POSITIVA, el anti-vacío— y el atajo **AÑADIDO junto** al
longhand en las dos, que muerden la mitad negativa, la que vigila el shorthand.
Control de falso positivo: el `transition: background …` de la misma regla sigue
ahí y el verde pasa.
---
**Última revisión**: 2026-08-25 (§55 el sobre de trigger de popover es el
suelo). Si algo en este doc no coincide con el código, el código gana — pero
abre un issue para que actualicemos el doc.
**Última revisión**: 2026-08-25 (§56 el velo del sistema no muere por un atajo).
Si algo en este doc no coincide con el código, el código gana — pero abre un
issue para que actualicemos el doc.

@ -670,6 +670,34 @@ describe('ActiveEidos config', () => {
// A guard that inspected NOTHING passes green: the census is the other half
// of the assertion. Four trigger rules — two on the floor, two above it.
expect(triggerRules).toHaveLength(4);
// (f) …and the floor paints its surface with the LONGHAND (signed
// 2026-08-25). `background:` is a SHORTHAND: it expands to all eight
// longhands, `background-image: none` among them — and `background-image`
// is exactly where `archetypes.css` paints the system's hover veil, at
// (0,0,0), i.e. TIED with this floor. While the shorthand was here the veil
// died on every bare trigger wherever popover.css happened to load LAST
// (measured live on the inverted order: `linear-gradient(…8 %…)` → `none`),
// a coin flip decided by two `import` lines of a layout. The longhand takes
// the surface out of the tie — 0 px over 68 triggers × 2 states — and is
// what `feedback: hover is the system's, never a per-component invention`
// already mandates. The positive half is the anti-void: a `not.toMatch` on
// an empty body passes green.
const SHORTHAND = /(?:^|[;\s])background\s*:/;
expect(rest!.body, 'the rest floor stopped painting a surface at all').toContain(
'background-color: var(--popover-trigger-bg);'
);
expect(
rest!.body,
'the rest floor is back on the `background` SHORTHAND — it expands to `background-image: none` and kills the system hover veil it ties with'
).not.toMatch(SHORTHAND);
expect(hover!.body, 'the hover floor stopped painting a surface at all').toContain(
'background-color: var(--popover-hover-trigger-bg);'
);
expect(
hover!.body,
'the hover floor is back on the `background` SHORTHAND — it expands to `background-image: none` and kills the system hover veil it ties with'
).not.toMatch(SHORTHAND);
});
it('emits the Fase 4 frost atmosphere (opt-in [data-frost] + blur tokens)', () => {

@ -410,17 +410,15 @@
align-self: start;
justify-self: start;
}
/* It's a composed <Button variant="plain">, but as a popover trigger it also
inherits the popover's default surface envelope (bg + border + fixed control
height, specificity 0-2-0). Hand styling back to the Button so `plain` reads
plain — same private vars the Button recipe consumes, no literals. */
[data-popover-trigger][data-chronos-more-link]:not([data-archetype='field-trigger']) {
height: auto;
padding-inline: var(--_button-padding-inline);
border: var(--button-border-width) solid var(--_button-border);
border-radius: var(--_button-radius);
background: var(--_button-bg);
}
/* The `+N more` PIN was RETIRED 2026-08-25. It re-declared five properties at
(0,3,0) on `[data-popover-trigger][data-chronos-more-link]:not(…)` for ONE
reason: popover's trigger envelope shipped at (0,2,0) and beat the composed
<Button variant="plain">. §55 moved that envelope to the FLOOR (0,0,0), so
`[data-button]` at (0,1,0) wins on its own — and four of the five declarations
were literal copies of it (`--_button-padding-inline`, `--_button-border`,
`--_button-radius`, `--_button-bg`); the fifth, `height: auto`, is the twin of
its `block-size: fit-content`. Measured with the rule disabled live: 0 diffs
over 20 variant × size combinations, rest and hover. */
/* ── Legend ──────────────────────────────────────────────────────────────── */

@ -28,7 +28,15 @@
`data-popover-trigger`, whose rule is (0,2,0) against this one's (0,1,0)
and paints all three. The declarations that lived here moved NOTHING
(measured 2026-08-23) — the same defect `gradient-picker` documented. The
OPEN ink below does win: its selector adds `[data-state='open']`. */
OPEN ink below does win: its selector adds `[data-state='open']`.
⚠ 2026-08-25 — THAT PREMISE EXPIRED. §55 emits popover's trigger envelope
from `:where(...)`, (0,0,0), so it now LOSES to this recipe's (0,1,0). The
retiral still stands and there is no visual defect — the recipe stays
silent and the floor paints, which is a floor's job — but those three
declarations would WIN if they came back, so the reason they were dead is
no longer the reason written above. Annotated rather than rewritten: the
2026-08-23 measurement was right for the cascade of that day. */
background: transparent;
cursor: pointer;
transition: background var(--duration-fast) var(--ease-default);

@ -26,6 +26,15 @@
* which outweighs anything this file can say about `[data-gradient-picker-trigger]`
* (0,2,0 vs 0,1,0; 0,3,0 vs 0,2,0 on the states).
*
* ⚠ 2026-08-25 — HALF of that parenthesis expired. §55 emits popover's REST
* envelope and its `:hover` from `:where(...)`, (0,0,0), so the base pair is no
* longer 0,2,0 vs 0,1,0: this recipe would WIN there today. The two STATE rules
* (`[data-state='open']`, `:focus-visible`) keep their (0,3,0) and the second
* half still holds. The retiral stands either way — the chrome genuinely is the
* popover contract's — but the cascade rule quoted above is not the one in
* force. Annotated, not rewritten: the 2026-08-20 measurement was right for the
* cascade of that day.
*
* This recipe used to re-declare all of it. Measured 2026-08-20 with a
* sentinel on every knob: NONE of it painted — height, padding, font-size and
* radius all came from popover, and the values differed (12px vs the recipe's

@ -38,6 +38,16 @@
* (0,5,0) and killed the system's hover layer on every host that paints its
* own surface. `[data-state='open']` and `:focus-visible` keep their
* specificity: not part of this signature, registered in `next-features.md`.
*
* ── `background-color`, NEVER the `background` SHORTHAND (signed 2026-08-25) ──
* The shorthand expands to all eight longhands, `background-image: none` among
* them — and `background-image` is EXACTLY where the system paints its hover
* layer. On the floor this envelope TIES with `archetypes.css` (also (0,0,0)),
* so the shorthand erased that veil wherever popover.css happened to load LAST:
* a coin flip decided by two `import` lines of a layout. The longhand takes the
* surface out of the tie — the system's layer composes over it in ANY order. It
* is also what `feedback: hover is the system's, never a per-component
* invention` already mandates. Measured: 0 px over 68 triggers × 2 states.
*/
:where([data-popover-trigger]:not([data-archetype='field-trigger'])) {
display: inline-flex;
@ -47,7 +57,7 @@
padding-inline: var(--popover-trigger-padding-inline);
border: var(--popover-trigger-border-width) solid var(--popover-trigger-border);
border-radius: var(--popover-trigger-radius);
background: var(--popover-trigger-bg);
background-color: var(--popover-trigger-bg);
color: var(--popover-trigger-fg);
font: inherit;
font-size: var(--popover-trigger-font-size);
@ -62,7 +72,7 @@
[data-disabled]
)
) {
background: var(--popover-hover-trigger-bg);
background-color: var(--popover-hover-trigger-bg);
border-color: var(--popover-hover-trigger-border);
}

@ -1060,6 +1060,14 @@ export const THEME_BASE_RECIPE_TOKENS = defineRecipes({
// `[…-trigger][data-state='open']`, (0,2,0), and wins by order; and
// `trigger-size` survives because popover sizes with `height`, not with the
// logical pair.
// ⚠ 2026-08-25 — the (0,2,0) premise above EXPIRED. §55 emits popover's
// rest envelope and its `:hover` from `:where(...)`, (0,0,0), so today they
// LOSE to this recipe's (0,1,0): the three retired declarations would win
// if they came back, and `open-trigger-fg` wins by SPECIFICITY now, not by
// order. No visual defect — the recipe is silent and the floor paints —
// but the cascade rule written above is no longer the one in force.
// Annotated, not rewritten: the 2026-08-23 measurement was right for the
// cascade of that day.
'open-trigger-fg': 'var(--color-content-primary)',
// ── Panel (portaled; Popover provides surface + depth). The picker owns
// its width as a component token (color-picker precedent: a concrete rem

Loading…
Cancel
Save

Powered by TurnKey Linux.