uix(banner): temable — 30 % → 100 %, y el guard pasa de 4/42 a 53/53

11 claves nuevas (42 → 53). Su contrato ya era grande —40 claves de intención—
pero su CROMO estaba a pelo: la densidad por talla, la interlínea y el trazo del
anillo de `outline`, que era la última fila que impedía al privado del borde
derivar de un público.

Dos ausencias firmadas: los `transparent` de `outline` y `ghost` y los tres
`border-width: 0`. La variante ES la ausencia de cromo — mismo criterio que
button, y por la misma razón: diez claves de `transparent` no son un contrato,
son ruido.

EL INSTRUMENTO NO VEÍA 38 DE SUS 42 CLAVES, Y NINGUNA ESTABA MUERTA. Dos
cegueras a la vez:

1. Su paleta resuelve por `data-intent`, NO por `data-color`. El barrido de tono
   del guard —añadido esta mañana para button— estampaba sólo `data-color`. Ahora
   estampa los DOS nombres: un componente selecciona por uno y el otro queda
   inerte.
2. Y luego por VARIANTE: las ranuras `solid`/`contrast` sólo pintan en `solid`,
   la de borde sólo en `outline`, y la demo monta una de cada. Con `sweepAttr`
   sobre `data-variant`, el guard las recorre.

Con las dos, 4/42 → 53/53. Es la diferencia entre «38 tokens que mienten» y «38
tokens que nadie había mirado con el atributo puesto»: exactamente lo que R-5.4
existe para distinguir.

Gates: sonda 0 diffs en 192 valores × 7 estados (la demo monta UNA franja) ·
centinela 53/53 sin una sola adjudicación · censo 100 % · `component:audit` PASS
· suite eidos con el rojo conocido ajeno · `rtl:check` 0 · `docs:check` 0 ·
captura de las cuatro variantes con cuatro intenciones.

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

@ -10,9 +10,9 @@
- **Medido**: 2026-08-23 · **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**: **64%** — 2974 de 4622 knobs pasan por un token público del componente
- **Reparto**: público 2974 · privado 326 · global 870 · literal 452 · sistema transversal 509 · excepción firmada 90 _(los dos últimos, fuera del ratio)_
- **Sin token público propio**: 24 · **alcance < 20 %**: 14 · **alcance 100 %**: 19 · **con eje `size`**: 58
- **Alcance global**: **64%** — 2980 de 4621 knobs pasan por un token público del componente
- **Reparto**: público 2980 · privado 321 · global 869 · literal 451 · sistema transversal 509 · excepción firmada 91 _(los dos últimos, fuera del ratio)_
- **Sin token público propio**: 24 · **alcance < 20 %**: 14 · **alcance 100 %**: 20 · **con eje `size`**: 58
## Cómo se lee
@ -127,7 +127,6 @@ La columna «contrato» cuenta las claves **públicas** del bloque del component
| [surface](./surface.md) | 25% | 4 | 1 | 3 | 0 | 0 | 0 | 25 | – |
| [date-range-field](./date-range-field.md) | 29% | 8 | 2 | 0 | 4 | 1 | 1 | 3 | – |
| [time-range-field](./time-range-field.md) | 29% | 8 | 2 | 0 | 4 | 1 | 1 | 3 | – |
| [banner](./banner.md) | 30% | 10 | 3 | 5 | 1 | 1 | 0 | 42 | y |
| [scroll-frames](./scroll-frames.md) | 33% | 9 | 3 | 1 | 1 | 4 | 0 | 4 | – |
| [toggle-group](./toggle-group.md) | 33% | 3 | 1 | 0 | 1 | 1 | 0 | 1 | – |
| [link](./link.md) | 36% | 14 | 4 | 4 | 1 | 2 | 3 | 5 | – |
@ -249,6 +248,7 @@ La columna «contrato» cuenta las claves **públicas** del bloque del component
| [date-field](./date-field.md) | 100% | 11 | 11 | 0 | 0 | 0 | 0 | 21 | y |
| [time-field](./time-field.md) | 100% | 11 | 11 | 0 | 0 | 0 | 0 | 21 | y |
| [text-gradient](./text-gradient.md) | 100% | 10 | 10 | 0 | 0 | 0 | 0 | 7 | – |
| [banner](./banner.md) | 100% | 9 | 9 | 0 | 0 | 0 | 0 | 53 | y |
| [box](./box.md) | 100% | 9 | 9 | 0 | 0 | 0 | 0 | 43 | – |
| [label](./label.md) | 100% | 8 | 2 | 0 | 0 | 0 | 6 | 2 | – |
| [text-focus](./text-focus.md) | 100% | 8 | 8 | 0 | 0 | 0 | 0 | 8 | – |

@ -5,43 +5,35 @@
> Vista de conjunto: [README](./README.md) · método y protocolo:
> [`PLAN-theming.md`](../../process/PLAN-theming.md) §1, §2, §7.
- **Medido**: 2026-08-23 · **Alcance**: **30%** — 3 de 10 knobs por token público
- **Knobs de apariencia**: 10 — público 3 · privado 5 · global 1 · literal 1 · sistema 0 · excepción 0 _(los dos últimos, fuera del ratio)_
- **Contrato hoy** (`lib/recipes/base.ts`): 42 pública(s) — `gap`, `radius`, `primary-solid`, `primary-contrast`, `primary-track`, `primary-border`, `primary-text`, `secondary-solid`, `secondary-contrast`, `secondary-track`, `secondary-border`, `secondary-text`, `neutral-solid`, `neutral-contrast`, `neutral-track`, `neutral-border`, `neutral-text`, `affirm-solid`, `affirm-contrast`, `affirm-track`, `affirm-border`, `affirm-text`, `fulfill-solid`, `fulfill-contrast`, `fulfill-track`, `fulfill-border`, `fulfill-text`, `risk-solid`, `risk-contrast`, `risk-track`, `risk-border`, `risk-text`, `threat-solid`, `threat-contrast`, `threat-track`, `threat-border`, `threat-text`, `loss-solid`, `loss-contrast`, `loss-track`, `loss-border`, `loss-text`
- **Medido**: 2026-08-23 · **Alcance**: **100%** — 9 de 9 knobs por token público
- **Knobs de apariencia**: 9 — público 9 · privado 0 · global 0 · literal 0 · sistema 0 · excepción 1 _(los dos últimos, fuera del ratio)_
- **Contrato hoy** (`lib/recipes/base.ts`): 53 pública(s) — `gap`, `radius`, `padding-block-sm`, `padding-block-md`, `padding-block-lg`, `padding-inline-sm`, `padding-inline-md`, `padding-inline-lg`, `font-size-sm`, `font-size-md`, `font-size-lg`, `line-height`, `border-width`, `primary-solid`, `primary-contrast`, `primary-track`, `primary-border`, `primary-text`, `secondary-solid`, `secondary-contrast`, `secondary-track`, `secondary-border`, `secondary-text`, `neutral-solid`, `neutral-contrast`, `neutral-track`, `neutral-border`, `neutral-text`, `affirm-solid`, `affirm-contrast`, `affirm-track`, `affirm-border`, `affirm-text`, `fulfill-solid`, `fulfill-contrast`, `fulfill-track`, `fulfill-border`, `fulfill-text`, `risk-solid`, `risk-contrast`, `risk-track`, `risk-border`, `risk-text`, `threat-solid`, `threat-contrast`, `threat-track`, `threat-border`, `threat-text`, `loss-solid`, `loss-contrast`, `loss-track`, `loss-border`, `loss-text`
- **Eje `size`**: sí · **ficheros**: `banner.css`
## 1. Knobs fuera de alcance
### 1.1 Directo a primitivo global (1)
### 1.1 Directo a primitivo global (0)
| # | fichero:línea | selector | propiedad | valor |
| ---: | --- | --- | --- | --- |
| 1 | `banner.css:29` | `[data-banner]` | `line-height` | `var(--font-line-height-sm, 1.4)` |
_Ninguno._
### 1.2 A través de un privado (5)
### 1.2 A través de un privado (0)
| # | fichero:línea | selector | propiedad | valor |
| ---: | --- | --- | --- | --- |
| 1 | `banner.css:23` | `[data-banner]` | `padding-block` | `var(--_banner-padding-block)` |
| 2 | `banner.css:24` | `[data-banner]` | `padding-inline` | `var(--_banner-padding-inline)` |
| 3 | `banner.css:28` | `[data-banner]` | `font-size` | `var(--_banner-font-size)` |
| 4 | `banner.css:30` | `[data-banner]` | `background` | `var(--_banner-bg, transparent)` |
| 5 | `banner.css:32` | `[data-banner]` | `border` | `var(--_banner-border-width, 0) solid var(--_banner-border-color, transparent)` |
_Ninguno._
### 1.3 Literales (1)
### 1.3 Literales (0)
| # | fichero:línea | selector | propiedad | valor |
| ---: | --- | --- | --- | --- |
| 1 | `banner.css:25` | `[data-banner]` | `inline-size` | `100%` |
_Ninguno._
### 1.4 Excepciones firmadas (0) — fuera del ratio
### 1.4 Excepciones firmadas (1) — 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.
_Ninguno._
| # | fichero:línea | selector | propiedad | valor |
| ---: | --- | --- | --- | --- |
| 1 | `banner.css:25` | `[data-banner]` | `inline-size` | `100%` |
## 2. Sistema transversal (0) — informativo, fuera del ratio
Un tema los alcanza **a nivel de sistema**, por diseño (recipe-contract §2).
@ -52,24 +44,24 @@ _Ninguno._
| privado | declaraciones | valor(es) | origen | ¿deriva de un público? |
| --- | ---: | --- | --- | :-: |
| `--_banner-padding-block` | 3 | `var(--space-2)`, `var(--space-3)`, `var(--space-4)` | global | no |
| `--_banner-padding-inline` | 3 | `var(--space-3)`, `var(--space-4)`, `var(--space-5)` | global | no |
| `--_banner-font-size` | 3 | `var(--font-size-sm)`, `var(--font-size-md)`, `var(--font-size-lg)` | global | no |
| `--_banner-padding-block` | 3 | `var(--banner-padding-block-sm)`, `var(--banner-padding-block-md)`, `var(--banner-padding-block-lg)` | public | **sí** |
| `--_banner-padding-inline` | 3 | `var(--banner-padding-inline-sm)`, `var(--banner-padding-inline-md)`, `var(--banner-padding-inline-lg)` | public | **sí** |
| `--_banner-font-size` | 3 | `var(--banner-font-size-sm)`, `var(--banner-font-size-md)`, `var(--banner-font-size-lg)` | public | **sí** |
| `--_banner-solid` | 8 | `var(--banner-primary-solid)`, `var(--banner-secondary-solid)`, `var(--banner-neutral-solid)`, `var(--banner-affirm-solid)`, `var(--banner-fulfill-solid)`, `var(--banner-risk-solid)` …(+2) | public | **sí** |
| `--_banner-solid-contrast` | 8 | `var(--banner-primary-contrast)`, `var(--banner-secondary-contrast)`, `var(--banner-neutral-contrast)`, `var(--banner-affirm-contrast)`, `var(--banner-fulfill-contrast)`, `var(--banner-risk-contrast)` …(+2) | public | **sí** |
| `--_banner-track` | 8 | `var(--banner-primary-track)`, `var(--banner-secondary-track)`, `var(--banner-neutral-track)`, `var(--banner-affirm-track)`, `var(--banner-fulfill-track)`, `var(--banner-risk-track)` …(+2) | public | **sí** |
| `--_banner-border` | 8 | `var(--banner-primary-border)`, `var(--banner-secondary-border)`, `var(--banner-neutral-border)`, `var(--banner-affirm-border)`, `var(--banner-fulfill-border)`, `var(--banner-risk-border)` …(+2) | public | **sí** |
| `--_banner-text` | 8 | `var(--banner-primary-text)`, `var(--banner-secondary-text)`, `var(--banner-neutral-text)`, `var(--banner-affirm-text)`, `var(--banner-fulfill-text)`, `var(--banner-risk-text)` …(+2) | public | **sí** |
| `--_banner-bg` | 4 | `var(--_banner-track)`, `var(--_banner-solid)`, `transparent` | literal, private | no |
| `--_banner-bg` | 4 | `var(--_banner-track)`, `var(--_banner-solid)`, `transparent` | exception, private | no |
| `--_banner-fg` | 4 | `var(--_banner-text)`, `var(--_banner-solid-contrast)` | private | no |
| `--_banner-border-width` | 4 | `0`, `var(--border-width)` | global, literal | no |
| `--_banner-border-width` | 4 | `0`, `var(--banner-border-width)` | exception, public | no |
| `--_banner-border-color` | 1 | `var(--_banner-border)` | private | no |
## 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 guard `recipe-css-contract` prohíbe el primitivo).
### 4.1 Tokens a declarar en `lib/recipes/base.ts` (11)
### 4.1 Tokens a declarar en `lib/recipes/base.ts` (0)
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
@ -79,29 +71,10 @@ no distingue lo que debería — se marca `⚠`.
| token (`--banner-…`) | scope TSC | valor propuesto | usos |
| --- | --- | --- | ---: |
| `bg` | `root` | ⚠ `var(--_banner-track)` / `var(--_banner-solid)` / `transparent` | 4 |
| `padding-block-sm` | `size:sm` | `var(--space-2)` | 1 |
| `padding-block-md` | `size:md` | `var(--space-3)` | 1 |
| `padding-block-lg` | `size:lg` | `var(--space-4)` | 1 |
| `padding-inline-sm` | `size:sm` | `var(--space-3)` | 1 |
| `padding-inline-md` | `size:md` | `var(--space-4)` | 1 |
| `padding-inline-lg` | `size:lg` | `var(--space-5)` | 1 |
| `font-size-sm` | `size:sm` | `var(--font-size-sm)` | 1 |
| `font-size-md` | `size:md` | `var(--font-size-md)` | 1 |
| `font-size-lg` | `size:lg` | `var(--font-size-lg)` | 1 |
| `line-height` | `root` | `var(--font-line-height-sm, 1.4)` | 1 |
### 4.2 Sin nombre mecánico (2)
- **⚠ 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** — 1: `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)** — 1: `border`.
### 4.3 Avisos sobre los tokens propuestos (4)
### 4.2 Sin nombre mecánico (1)
- **el privado `--_banner-padding-block` debe pasar a leer este público (o desaparecer)** — `--banner-padding-block-sm`, `--banner-padding-block-md`, `--banner-padding-block-lg`
- **el privado `--_banner-padding-inline` debe pasar a leer este público (o desaparecer)** — `--banner-padding-inline-sm`, `--banner-padding-inline-md`, `--banner-padding-inline-lg`
- **el privado `--_banner-font-size` debe pasar a leer este público (o desaparecer)** — `--banner-font-size-sm`, `--banner-font-size-md`, `--banner-font-size-lg`
- **el privado `--_banner-bg` debe pasar a leer este público (o desaparecer)** — `--banner-bg`
- **⚠ 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** — 1: `inline-size`.
### 4.4 Lo que hay que comprobar a mano (PLAN-theming §1.3 · §7.4)
@ -115,6 +88,37 @@ no distingue lo que debería — se marca `⚠`.
<!-- veredicto:start -->
_(pendiente — lo escribe el autor; se conserva al regenerar)_
**EJECUTADO 2026-08-23 — 30 % → 100 %**, 11 claves nuevas (42 → 53), y el
centinela pasa **53/53 sin una sola adjudicación**. Su contrato ya era grande
—40 claves de intención— pero su CROMO estaba a pelo.
Cosida la densidad por talla (relleno de bloque y de línea, y la escala, que lee
el bundle), la interlínea y **el trazo del anillo de `outline`**, que era la
última fila que impedía al privado del borde derivar de un público.
**Dos ausencias firmadas**: los `transparent` de `outline` y `ghost` y los tres
`border-width: 0`. La variante ES la ausencia de cromo — el mismo criterio que
button, y por la misma razón: diez claves de `transparent` no son un contrato,
son ruido.
**El instrumento no veía 38 de sus 42 claves, y ninguna estaba muerta.** Dos
cegueras a la vez:
1. **Su paleta resuelve por `data-intent`, no por `data-color`.** El barrido de
tono del guard —añadido esta mañana para button— estampaba sólo
`data-color`. Ahora estampa los DOS nombres: un componente selecciona por uno
y el otro queda inerte.
2. **Y luego por VARIANTE**: las ranuras `solid`/`contrast` sólo pintan en
`solid`, la de borde sólo en `outline`, y la demo monta una de cada. Con
`sweepAttr` sobre `data-variant`, el guard las recorre.
Con las dos, **4/42 → 53/53**. Es la diferencia entre «38 tokens que mienten» y
«38 tokens que nadie había mirado con el atributo puesto»: exactamente lo que
R-5.4 existe para distinguir.
Verificación: **diff de computed = 0** sobre 192 valores en 7 estados (la demo
monta UNA franja) · centinela **53/53** · censo 100 % · `component:audit` PASS ·
suite eidos con el rojo conocido ajeno · `rtl:check` 0 · `docs:check` 0 ·
captura de las cuatro variantes con cuatro intenciones.
<!-- veredicto:end -->

@ -455,6 +455,25 @@ de commit. Sin artefacto, el paso no se ha hecho.
## 8. Registro
- 2026-08-23 — **`banner` 30 % → 100 %** (11 claves) **y el guard pasa de 4/42 a
53/53**: sus 38 «muertos» estaban vivos, sólo que nadie los había mirado con
el atributo puesto. Global 64 %.
Cosida la densidad por talla, la interlínea y el trazo del anillo de
`outline` —la última fila que impedía al privado del borde derivar—. Dos
ausencias firmadas: los `transparent` de `outline`/`ghost` y los
`border-width: 0`, con el criterio de button.
**Dos cegueras del instrumento, arregladas**: (1) su paleta resuelve por
`data-intent`, no por `data-color`, y el barrido de tono estampaba sólo el
segundo — ahora estampa los dos nombres; (2) y luego por VARIANTE, así que el
guard recorre `data-variant` con `sweepAttr`. Es la diferencia entre «38
tokens que mienten» y «38 que nadie había mirado con el atributo puesto».
Gates: sonda 0 diffs en 192 valores × 7 estados · centinela 53/53 · censo
100 % · audit PASS · suite con el rojo conocido ajeno · rtl 0 · docs 0 ·
captura de cuatro variantes × cuatro intenciones.
- 2026-08-23 — **`anchor-nav` 20 % → 100 %** (11 claves) **y el censo aprende los
bordes POR LADO**. Global 64 %.

@ -182,6 +182,11 @@ const COMPONENT_OVERRIDES: Record<
// no attribute of its own: without this the guard measures ONE node (the root)
// and 27 of its 37 tokens read dead. Measured 2026-08-22.
prose: { extraNodes: '[data-prose] *' },
// Its palette resolves per INTENT and then per VARIANT: the solid/contrast
// slots only paint under `solid`, the border slot only under `outline`, and
// the demo mounts one of each. 38 of its 42 tokens read dead without the
// sweep (2026-08-23).
banner: { sweepAttr: { attr: 'data-variant', values: ['soft', 'solid', 'outline', 'ghost'] } },
// Same class-hook blindness as prose, inside an SVG: sectors, labels, icons
// and the trigger glyph carry no `data-onion-*`.
'onion-menu': { openMarker: '.onion-menu-sector', extraNodes: '.onion-menu-sector, .onion-menu-label, .onion-menu-icon, .onion-menu-icon svg, .onion-menu-trigger, .onion-menu-trigger-glyph' },
@ -453,7 +458,15 @@ async function main() {
const tone = TONES.find((t) => (token as string).startsWith(t + '-'));
const toned = tone ? all() : [];
const toneWas = toned.map((n) => n.getAttribute('data-color'));
if (tone) for (const n of toned) n.setAttribute('data-color', tone);
// Two attribute names for the same vocabulary: most recipes read
// `data-color`, banner reads `data-intent`. Stamp both — a component
// only selects on one, so the other is inert.
const toneIntentWas = toned.map((n) => n.getAttribute('data-intent'));
if (tone)
for (const n of toned) {
n.setAttribute('data-color', tone);
n.setAttribute('data-intent', tone);
}
const sized = all().filter((n) => n.hasAttribute('data-size'));
const original = sized.map((n) => n.getAttribute('data-size'));
const snap = () =>
@ -494,9 +507,12 @@ async function main() {
swept.forEach((n, i2) =>
sweptWas[i2] ? n.setAttribute(sweepAttr as string, sweptWas[i2]!) : n.removeAttribute(sweepAttr as string)
);
toned.forEach((n, i2) =>
toneWas[i2] ? n.setAttribute('data-color', toneWas[i2]!) : n.removeAttribute('data-color')
);
toned.forEach((n, i2) => {
toneWas[i2] ? n.setAttribute('data-color', toneWas[i2]!) : n.removeAttribute('data-color');
toneIntentWas[i2]
? n.setAttribute('data-intent', toneIntentWas[i2]!)
: n.removeAttribute('data-intent');
});
return moved;
},
[

@ -19,38 +19,38 @@
/* Shared structural surface. */
display: flex;
align-items: center;
gap: var(--banner-gap, var(--space-3));
gap: var(--banner-gap);
padding-block: var(--_banner-padding-block);
padding-inline: var(--_banner-padding-inline);
inline-size: 100%;
inline-size: 100%; /* literal: a banner IS full width — identity, not a knob */
min-inline-size: 0;
box-sizing: border-box;
font-size: var(--_banner-font-size);
line-height: var(--font-line-height-sm, 1.4);
line-height: var(--banner-line-height);
background: var(--_banner-bg, transparent);
color: var(--_banner-fg, inherit);
border: var(--_banner-border-width, 0) solid var(--_banner-border-color, transparent);
border-radius: var(--banner-radius, 0);
border-radius: var(--banner-radius);
}
/* ── Size ──────────────────────────────────────────────────────────── */
[data-banner][data-size='sm'] {
--_banner-padding-block: var(--space-2);
--_banner-padding-inline: var(--space-3);
--_banner-font-size: var(--font-size-sm);
--_banner-padding-block: var(--banner-padding-block-sm);
--_banner-padding-inline: var(--banner-padding-inline-sm);
--_banner-font-size: var(--banner-font-size-sm);
}
[data-banner][data-size='md'] {
--_banner-padding-block: var(--space-3);
--_banner-padding-inline: var(--space-4);
--_banner-font-size: var(--font-size-md);
--_banner-padding-block: var(--banner-padding-block-md);
--_banner-padding-inline: var(--banner-padding-inline-md);
--_banner-font-size: var(--banner-font-size-md);
}
[data-banner][data-size='lg'] {
--_banner-padding-block: var(--space-4);
--_banner-padding-inline: var(--space-5);
--_banner-font-size: var(--font-size-lg);
--_banner-padding-block: var(--banner-padding-block-lg);
--_banner-padding-inline: var(--banner-padding-inline-lg);
--_banner-font-size: var(--banner-font-size-lg);
}
/* ── Intent palette resolution ─────────────────────────────────────── */
@ -117,26 +117,26 @@
[data-banner][data-variant='soft'] {
--_banner-bg: var(--_banner-track);
--_banner-fg: var(--_banner-text);
--_banner-border-width: 0;
--_banner-border-width: 0; /* literal: this variant IS the absence of chrome */
}
[data-banner][data-variant='solid'] {
--_banner-bg: var(--_banner-solid);
--_banner-fg: var(--_banner-solid-contrast);
--_banner-border-width: 0;
--_banner-border-width: 0; /* literal: this variant IS the absence of chrome */
}
[data-banner][data-variant='outline'] {
--_banner-bg: transparent;
--_banner-bg: transparent; /* literal: this variant IS the absence of chrome */
--_banner-fg: var(--_banner-text);
--_banner-border-width: var(--border-width);
--_banner-border-width: var(--banner-border-width);
--_banner-border-color: var(--_banner-border);
}
[data-banner][data-variant='ghost'] {
--_banner-bg: transparent;
--_banner-bg: transparent; /* literal: this variant IS the absence of chrome */
--_banner-fg: var(--_banner-text);
--_banner-border-width: 0;
--_banner-border-width: 0; /* literal: this variant IS the absence of chrome */
}
/* ── Close button (eidos-only part) ────────────────────────────────── */

@ -3967,6 +3967,17 @@
--group-attached-overlap: 1px;
--banner-gap: var(--space-3);
--banner-radius: 0;
--banner-padding-block-sm: var(--space-2);
--banner-padding-block-md: var(--space-3);
--banner-padding-block-lg: var(--space-4);
--banner-padding-inline-sm: var(--space-3);
--banner-padding-inline-md: var(--space-4);
--banner-padding-inline-lg: var(--space-5);
--banner-font-size-sm: var(--size-sm-font-size);
--banner-font-size-md: var(--size-md-font-size);
--banner-font-size-lg: var(--size-lg-font-size);
--banner-line-height: var(--size-sm-font-line-height);
--banner-border-width: var(--border-width);
--banner-primary-solid: var(--color-primary-solid);
--banner-primary-contrast: var(--color-primary-contrast);
--banner-primary-track: var(--color-primary-track);

@ -6245,6 +6245,20 @@ export const THEME_BASE_RECIPE_TOKENS = defineRecipes({
banner: {
gap: 'var(--space-3)',
radius: '0',
// Densidad por talla: la franja es un anuncio a todo el ancho, y su respiro
// es lo primero que un tema toca.
'padding-block-sm': 'var(--space-2)',
'padding-block-md': 'var(--space-3)',
'padding-block-lg': 'var(--space-4)',
'padding-inline-sm': 'var(--space-3)',
'padding-inline-md': 'var(--space-4)',
'padding-inline-lg': 'var(--space-5)',
'font-size-sm': 'var(--size-sm-font-size)',
'font-size-md': 'var(--size-md-font-size)',
'font-size-lg': 'var(--size-lg-font-size)',
'line-height': 'var(--size-sm-font-line-height)',
// El trazo del anillo de la variante `outline` — la única que dibuja borde.
'border-width': 'var(--border-width)',
// Per-intent palette forwarders → Banner is retintable via
// `recipes.banner.{intent}-{slot}` like every other color component
// (button/badge/toggle). banner.css reads these instead of the raw

Loading…
Cancel
Save

Powered by TurnKey Linux.