|
|
# Theming coherence — consolidated (E-bis roll-up)
|
|
|
|
|
|
updated-at: 2026-06-26
|
|
|
batches-complete: 1
|
|
|
canon refs: THEMING §4 (9 roles), §5 (sizes + 1:1 font), §6 (naming/slots), §16 (anti-patterns A–H),
|
|
|
§19 (EIDOS_VARIANTS), §35 (scales — z/opacity/border)
|
|
|
|
|
|
## (a) Hardcoded-where-canonical values (the consolidation)
|
|
|
|
|
|
| Value (literal) | Canonical token it should be | Components hardcoding it | Severity |
|
|
|
| --- | --- | --- | --- |
|
|
|
| `content-z` / `overlay-z` integers (`80`/`75`/`70`/`60`) | `--z-index-{overlay-ladder}` (THEMING §35-C) | select(80), dialog(70), popover(75/60), combobox(80), dropdown-menu(80) — **5/5** | **SYSTEMIC** |
|
|
|
| `item-disabled-opacity: '0.55'` | `var(--opacity-disabled)` | dropdown-menu | MEDIUM |
|
|
|
| `item-description-font-size: '0.85em'` | `var(--font-size-*)` (escapes the px/rem guard) | select | MEDIUM |
|
|
|
| `group-heading-letter-spacing: '0.04em'` | `var(--tracking-caps)` | select | LOW |
|
|
|
| `item-description-mt: '0.125rem'` | `var(--space-0-5)` | select | LOW |
|
|
|
| `item-height: '2rem'` | `--list-item-height-*` / `--control-height-*` (list-surface layer) | dropdown-menu | LOW |
|
|
|
|
|
|
> `dialog.overlay-opacity: '62%'` is left as recipe-legitimate (scrim opacity is a recipe knob, not on the
|
|
|
> `--opacity-*` step scale) — noted, not flagged.
|
|
|
|
|
|
## (b) Near-duplicate tokens (same resolved value, different name)
|
|
|
- `content-z: '80'` appears identically in **select**, **combobox**, **dropdown-menu** — three names, one
|
|
|
value, no shared source. Folds into SYS-2 (MAGIC-Z).
|
|
|
- No other near-duplicate token pairs surfaced in Batch 1 (the recipes alias `--color-*`/`--space-*`/`--radius-*`
|
|
|
consistently).
|
|
|
|
|
|
## (c) Non-canonical role / variant / size / slot names found
|
|
|
- **Roles:** NONE. All 5 use only the 9 canonical roles (`primary/secondary/tertiary/neutral` +
|
|
|
`affirm/fulfill/risk/threat/loss`). No `success`/`warning`/`danger`/`info`. ✓ (THEMING §16-C clean.)
|
|
|
- **Variants:** NONE invented. `SelectVariant = ControlVariant`, dialog uses position/size data-attrs (visual,
|
|
|
eidos-owned, not "variants"). ✓
|
|
|
- **Sizes:** NONE invented (`xs..xl` subsets). One raw-rem size (`dropdown-menu.item-height: 2rem`) that should
|
|
|
bridge the list-surface scale — drift, not an invented name.
|
|
|
- **Slots:** NONE invented; recipes use `track/border/text/bg/hover/...` from the fixed vocabulary. ✓
|
|
|
|
|
|
## (d) Per-component canon-conformance
|
|
|
|
|
|
| Component | roles | sizes | variants | naming | no-overlap |
|
|
|
| --- | --- | --- | --- | --- | --- |
|
|
|
| select | ✓ | ✓ | ✓ | ✓ | ✗ (em-font literal escapes guard; magic-z; subset type=all-9 vs 8 accents) |
|
|
|
| dialog | ✓ | ✓ | ✓ | ✓ | ✗ (dead `[data-dialog-trigger]` envelope overlaps composed Button; magic-z) |
|
|
|
| popover | ✓ | ✓ | ✓ | ✓ | ⚠ (magic-z only) |
|
|
|
| combobox | ✓ | ✓ | ✓ | ✓ | ⚠ (magic-z only) |
|
|
|
| dropdown-menu | ✓ | ⚠ (item-height 2rem) | ✓ | ✓ | ⚠ (magic-z + magic opacity) |
|
|
|
|
|
|
Legend: ✓ clean · ⚠ minor drift · ✗ real overlap/violation.
|
|
|
|
|
|
## (e) Systemic theming finding (≥3 components → one structural fix)
|
|
|
|
|
|
### THEME-SYS-1 · Overlay z-index is an ad-hoc parallel scale; a canonical `--z-index-*` ladder already exists <!-- id: THEME-SYS-001 -->
|
|
|
- recurs in (B1+B2): select 80 · dialog overlay 70 · popover content 75 / overlay 60 · combobox 80 ·
|
|
|
dropdown-menu 80 · **tooltip 76** · **drawer overlay 72 / inline 64** · **link-preview preview-z 99** ·
|
|
|
navigation-menu content-z (token, value hardcoded) · toast toaster-z 1200. **~10 overlay recipes.**
|
|
|
- **lead-verified ground truth:** the canonical scale `STATIC_Z_INDEX` (`lib/primitives/static.ts:291`) EXISTS:
|
|
|
`base 0 · raised 1 · sticky 100 · dropdown 300 · popover 400 · tooltip 500 · modal 700 · toast 900`, exposed as
|
|
|
`--z-index-{key}` and consumed by the depth planes (`overlay → var(--z-index-popover)`, `modal → var(--z-index-
|
|
|
modal)`) AND by **menu-dial** (`var(--z-index-sticky, 1100)`). So the overlay recipes hardcode an ad-hoc 60–99/
|
|
|
1200 scale that (a) duplicates a scale that already exists and (b) doesn't even match its ordering — e.g. ad-hoc
|
|
|
tooltip 76 < dropdown 80, but canonical tooltip 500 > dropdown 300.
|
|
|
- precise fix mapping (one sweep): dropdown-menu/context-menu → `--z-index-dropdown`; select/combobox/popover/
|
|
|
link-preview content → `--z-index-popover`; tooltip → `--z-index-tooltip`; dialog/drawer overlay → `--z-index-
|
|
|
modal` (content = +1 or a `--z-index-modal-content`); toast → `--z-index-toast`. menu-dial already does it right.
|
|
|
- fix-status: open
|
|
|
|
|
|
### THEME-SYS-2 · Recipe opacity decimals where a numeric `--opacity-*` scale exists <!-- id: THEME-SYS-002 -->
|
|
|
- recurs in: dropdown-menu `item-disabled-opacity 0.55`, context-menu `item-disabled-opacity 0.55`, onion-menu
|
|
|
`muted-opacity 0.85`/`hover-ring-opacity 0.65`, **calendar `day-outside-opacity 0.62`** (B3). The `--opacity-*`
|
|
|
scale is a 0.05 step (static.ts:255-275: `--opacity-60=0.6`, `--opacity-65=0.65`) — `0.62` maps to NO step, and
|
|
|
the same off-scale `0.62`/`62%` recurs as overlay-opacity in dialog (base.ts:729) + drawer (:895): an unnamed
|
|
|
brand value. Dialog uses `var(--opacity-disabled)` for disabled — the positive model.
|
|
|
- one fix: map disabled opacities to `var(--opacity-disabled)`, snap decimals to the nearest `--opacity-*` step,
|
|
|
and give the recurring `0.62` scrim value ONE named token (`--opacity-scrim`?) instead of three literals.
|
|
|
- fix-status: open
|
|
|
|
|
|
### B3 theming note — calendar `8ch` select-min-width is LEGIT (not drift)
|
|
|
- The verify correctly ruled `'select-min-width': '8ch'` (calendar recipe) a non-violation: `ch` is the right unit
|
|
|
for a text-box min-width (tracks glyph width of the month/year label), there is no canonical `ch`-scale to
|
|
|
reference, and it's already a named component token. Token-naming nit at most (LOW). Recorded so the next sweep
|
|
|
doesn't re-flag it.
|
|
|
|
|
|
## Batch-8 closing — eidos primitives (44) are theming-clean
|
|
|
|
|
|
The final batch swept all eidos-only primitives (layout · typography · visual · composite+service · infra) for E-bis.
|
|
|
Result: **the eidos theming layer is in excellent shape.**
|
|
|
|
|
|
- **(c) NON-CANONICAL ROLES — CLEAN across all 124 components (authoritative).** Lead grep + the B8 category sweep +
|
|
|
verify agree: NO recipe / type union / `data-color` enum / token name anywhere uses `success`/`warning`/`danger`/
|
|
|
`info`/`error`/`brand`. The only occurrences are COMMENTS that correctly *document the mapping* (badge/types.ts:22:
|
|
|
"success → affirm, warning → risk, error → threat"). The B8 agents' "TextColor/HeadingColor must use ColorRole"
|
|
|
flags were all REFUTED: typography color uses the **content-color** slots (`content-primary/secondary/muted/disabled/
|
|
|
on-solid`), which are valid content roles, NOT the 9 hierarchy/intent roles. THEMING §16-C is fully satisfied.
|
|
|
- **VARIANTS / SIZES / NAMING — CLEAN.** No invented `data-variant`, no invented size, no `--eidos-/--soma-/--air-`
|
|
|
prefix, no redundant `color-` segment found in any primitive.
|
|
|
- **RAW HEX — only the physically-fixed ones.** qr-code's `#fff`/`#000` (scanability) is the sole raw-hex, correctly
|
|
|
ruled legitimate (refuted).
|
|
|
- **The residual literals are minor (3 MEDIUM, 12 LOW), no systemic class:**
|
|
|
- `code`/`kbd`/`mark` inline-pill padding in `em` (0.1–0.4em) — there is NO canonical em-padding scale, so this is
|
|
|
borderline-acceptable LOW (a candidate for a future `--inline-pad-*` token if it ever recurs more).
|
|
|
- `scroll-frames` layout + opacity literals (2 MEDIUM) — should reference `--space-*` / `--opacity-*`.
|
|
|
- `radio-cards` one-off easing literal (MEDIUM) — should reference `--ease-*`.
|
|
|
- `section` `calc(--space-16 * 1.5)` (LOW) — composes the canonical token for an off-scale xl=96px (no `--space-24`).
|
|
|
- `container` `80rem` defensive fallback, `group` `1px` border-collapse — physically-fixed/defensive (LOW, accept).
|
|
|
- **No new systemic theming finding from B8.** The two systemic theming issues remain THEME-SYS-1 (overlay z-ladder,
|
|
|
~10 overlay recipes — the only structural theming fix worth a sweep) and THEME-SYS-2 (magic opacity decimals).
|
|
|
|
|
|
## Notes for the full sweep
|
|
|
- The biggest theming wins are E-bis structural (tokenize z-ladder), not per-recipe. Batch 8 (eidos-only
|
|
|
primitives) will add the most distinct hardcoded-value data — re-run this roll-up after each batch and
|
|
|
promote any value hardcoded in ≥3 components to a systemic entry here.
|
|
|
- The px/rem font-size coherence guard has an `em`/`%` hole (select-008) — tracked in VALIDATOR_GAPS.
|