docs(theming): ratifica la doctrina de contraste tonal — Stage 1 (paridad)

Cierra Stage 1 de la iniciativa next-features §1 con los veredictos del usuario:
- reference.md §40 (doctrina standing): contrato de contraste por pares de
  slots. Texto = dos tiers (text·11 secundario ≈APCA 60 / text-strong·12 AA
  garantizado). Bordes = dos tiers WCAG 1.4.11 (decorativo exento: accent·7,
  subtle·4/default·6, reposo-sobre-fondo · portador 3:1: solid·9 lo cumple, el
  resto con señal redundante). Foco = eje de config (primitives.focusRing +
  color.focus, un solo `outline` por §32); default suave, endurecer = valores
  por config, no código.
- changelog.md §44: el chronicle datado (drift medido + veredictos + la
  herramienta scripts/contrast-audit.ts).
- next-features.md §1: Stage 1 marcado DONE; Stage 2 (generador
  by-construction) sigue abierto, gated en la migración base→seeds.

Sin cambios de código (el hallazgo del foco es una decisión de valores-por-
defecto vía config; defaults mantenidos por decisión del usuario). El script
de auditoría (commiteado antes) queda como herramienta de medición.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
alpha-0.1-sec-dom
dev 3 months ago
parent 3f3658da96
commit b2f0a7f2bf

@ -14,7 +14,17 @@ audit/session raised it), its scope in one paragraph, and its dependencies.
Entries are **registered, not started** — starting one is a session decision.
Detail lives in the linked doc, never copied here.
## 1. Tonal-ramp contrast parity (measure, then construct) — 2026-07-06
## 1. Tonal-ramp contrast parity (measure, then construct) — 2026-07-06 · Stage 1 DONE 2026-07-19
> **Stage 1 SHIPPED (2026-07-19).** Measured with `scripts/contrast-audit.ts`
> (33 scales × 2 modes); drift + user verdicts ratified as doctrine in
> [`theming/reference.md §40`](./theming/reference.md) + [`changelog.md §44`](./theming/changelog.md).
> Outcome: `text·11` = secondary tier, `text-strong` = AA-guaranteed; the border
> vocabulary is Radix-subtle by design (only `solid·9` clears 3:1 by
> construction) with a decorative-vs-load-bearing split; the focus ring is a
> config axis (`primitives.focusRing` + `color.focus`, single `outline` per §32)
> whose shipped default is soft — hardening is a config-value choice, kept as-is.
> **Stage 2 (below) remains open**, gated on the base→seeds migration.
**Origin**: A.7 follow-up (theming audit F). The on-solid pair is now computed
at generation with a single criterion ([`rfcs/rfc-color-engine.md`](./rfcs/rfc-color-engine.md)

@ -1709,6 +1709,47 @@ cascada CSS exige navegador** (el workflow lo dio por bueno leyendo solo código
---
**Última revisión**: 2026-07-19 (§43 jaula del color abierta — cierre
definitivo). Si algo en este doc no coincide con el código, el código gana —
pero abre un issue para que actualicemos el doc.
## 44. Paridad de contraste del tonal-ramp — Stage 1 (medir) (2026-07-19)
Ejecución de la iniciativa [`next-features.md §1`](../next-features.md). Se
generalizó el criterio on-solid de UN par (§8 del RFC color-engine, `lib/on-solid.ts`)
a una TABLA de pares de slots, y se midió si las promesas de contraste declaradas
se cumplen en las 33 escalas × 2 modos. Herramienta reutilizable:
`scripts/contrast-audit.ts` (WCAG 2 = gate normativo; APCA Lc reportado al lado;
reutiliza la matemática de `$color`).
**Drift medido + veredictos del usuario:**
- **Texto sobre fondos**: `text·11` (Radix "low-contrast text") queda marginal
sub-4.5:1 en ~11 escalas turbias en modo claro (bronze/orange/teal/gold/…,
peor sobre `element·3`); `textStrong·12` pasa 4.5 en TODAS. **Veredicto:
`text·11` es el tier SECUNDARIO (contrato Radix, ≈APCA 60), `textStrong·12`
(`text-strong`) es el texto AA garantizado. Para texto AA-crítico se usa
`text-strong`.** Cero cambio de color.
- **Bordes**: TODO el vocabulario de border vive en el rango sutil (steps 4-8,
contrato Radix); el único que cruza 3:1 es el `solid·9` (checked/selected). Se
ratifica el modelo de DOS tiers: **decorativo** (acento `border·7` por-escala
§28, semantic `subtle·4`/`default·6`, border en reposo sobre superficie con
fondo) = indicador NO único → WCAG 1.4.11 EXENTO, sutil por diseño; **portador**
(checked/selected `solid·9`, error, foco) = 3:1 objetivo. El error (`risk·7`)
y el hover/ghost (`neutral·8`) miden sub-3:1 pero van acompañados de señal
redundante (texto de error / fondo) → exentos donde la hay.
- **Foco**: es el único indicador SIEMPRE único. El anillo por defecto
(`color.focus.ring` = `primary·8 @ ~50%` translúcido, `innerWidth: 0`) mide
sub-3:1 (1.4–1.9:1 vs superficies; ~1.1 sobre un control solid del mismo hue).
PERO es un **eje de config** (`primitives.focusRing` {offset,width,innerWidth}
+ `color.focus.ring`, emitido una vez, §32): endurecerlo (color opaco,
`innerWidth>0`, offset) es una decisión de valores-por-defecto por config, NO
código. El modelo sigue siendo UN `outline` (§32 lo canonizó; el box-shadow
doble-anillo se retiró — sobrevive a HCM, sin flicker de segment-fields). Se
mantienen los defaults por decisión del usuario; queda registrado.
Stage 2 (generador by-construction que resuelve la luminancia de cada step para
satisfacer la tabla) sigue registrado en `next-features.md §1`, gated en la
migración base→seeds (`rfc-color-engine §9`). Doctrina standing:
[`reference.md §40`](./reference.md).
---
**Última revisión**: 2026-07-19 (§44 paridad de contraste — Stage 1). Si algo en
este doc no coincide con el código, el código gana — pero abre un issue para que
actualicemos el doc.

@ -1760,8 +1760,50 @@ The NAMED gradients (`--gradient-{name}`, the open cage) remain a separate
axis: scenography material (v2 queue: named finishes with authored ink +
the `Surface` primitive for aurora/mesh). Live lab: `web/routes/temas/gradientes`.
## 40. Tonal-ramp contrast contract — the slot-pair floors (Stage 1, 2026-07-19)
Chronicle + the measured drift in [`changelog.md §44`](./changelog.md);
initiative registry [`next-features.md §1`](../next-features.md). Standing
doctrine — which slot pairs the framework promises to clear, and which are
intentionally subtle. Measured by `scripts/contrast-audit.ts` (WCAG 2 gate +
APCA Lc, over the 33 scales × 2 modes), reusing the on-solid math (§8 of
`rfc-color-engine.md`, `lib/on-solid.ts`).
**Text.** Two tiers, by the inherited Radix contract:
- `text·11` is the **secondary / low-contrast** ink (≈APCA 60) — marginal
sub-4.5:1 on the muddy light-mode scales (bronze/orange/teal/gold…), by design.
- `text·12` (`text-strong`) is the **AA-guaranteed body ink** (≥4.5:1 on every
scale × mode). **For AA-critical text, consume `text-strong`, not `text`.**
**Borders — two tiers (WCAG 1.4.11).** The whole border vocabulary lives in the
subtle 4–8 range (Radix's border steps); only `solid·9` clears 3:1 by
construction.
- **Decorative (EXEMPT — not a sole indicator):** the per-scale accent
`border·7` (§28), the semantic `subtle·4` / `default·6`, and any resting
border on a control that also carries a fill. Subtle on purpose; the fill +
content carry the boundary. Do NOT hold these to 3:1.
- **Load-bearing (3:1 target):** checked/selected (`solid·9` — clears it), the
error border and hover/ghost border (measure sub-3:1 but ride a redundant cue
— error text, background — so they're exempt where that cue exists), and the
focus ring (below).
**Focus — a config axis, single `outline` (§32).** The focus ring is the one
always-sole indicator. Its appearance is parameterised, NOT hardcoded:
`primitives.focusRing` (`{ offset, width, innerWidth }`, `primitives/static.ts`)
+ `color.focus.{ring,ringError}` (the theme), emitted ONCE as `--focus-ring-*`
tokens (`render-css.ts`). `innerWidth: 0` = single ring (default); a theme raises
it for a second inset line. The shipped default (`primary·8 @ ~50%` translucent)
measures sub-3:1 as a raw ratio; hardening it (opaque color, `innerWidth > 0`,
offset) is a **default-VALUE decision via config, never a per-component CSS
change** — and it stays a single `outline` (§32 canonized outline over
box-shadow: it survives forced-colors/HCM, avoids segment-field flicker).
**Stage 2 (deferred).** A by-construction generator that solves each step's
luminance to satisfy this pair table for ANY seed — registered in
`next-features.md §1`, gated on the base→seeds migration (`rfc-color-engine §9`).
---
**Last revision**: 2026-07-15 (gradient finish §39). If anything
**Last revision**: 2026-07-19 (contrast contract §40). If anything
in this doc disagrees with the code, the code wins — but open an issue so we
update the doc.

Loading…
Cancel
Save

Powered by TurnKey Linux.