THE CASCADE CONSTITUTION (hard laws)
- Layers decide the cascade. Within a layer, specificity is ZERO. Every selector is wrapped in :where(...), and :not() guards go INSIDE the :where(). No ID selectors, no !important outside the media and skin layers (config switches that must out-cascade), no specificity battles. A specificity conflict is a SYSTEM FAILURE requiring root-cause review — never patch it with a more-specific selector.
- Do not touch engine internals when the public API suffices. Internal vars are --_-prefixed (--_bg, --_sem-ink). Author with the public knobs above. If you find yourself reaching for --_sem-ink, stop — you almost certainly want --hue-lock + --fg instead.
- The right LAYER owns the change. Region surfaces (pg-* --bg) ship in the
skin layer; an app recipe that has settled graduates into the engine's
own components layer (the project layer RETIRED 2026-09-01, gf-133 —
ProjectStyles is gone); a public page's one-off look lives in that
page's own
@scopeblock (the landing's idiom). A rule in the wrong layer is silently out-cascaded — that is a layer-placement bug, never a specificity problem to fight. - NO NEW CSS CLASSES (gf-185, per Mike, at maximum emphasis). The engine's whole point is explicit declarative HTML composed from the EXISTING composition classes + the style API (--type/--bg/--fg/ --hue-shift/--hue-lock/--lift/--gap) — never a new class per feature. A vertical stepper, a card variant, a layout arrangement: composition (.row/.column + knobs + the ARIA-state idioms + native elements like
Enforcement is Go now (the cowork-era conformance.py is long gone):
go test ./... runs view/ratchet_test.go — the INLINE-GEOMETRY ratchet
(style= is sanctioned only for --knobs, anchor-name/position-anchor, and
commented one-offs; per-.templ counts may only go DOWN), the icon 24px-box
ratchet, and the anatomy-reach ratchet (project CSS may not restyle engine
anatomy). The cssaudit package charts lines-per-layer complexity on the
admin Metrics page. Keep them all green.