@orkestrel/scaffold 0.0.64 → 0.0.66

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,20 +1,25 @@
1
1
  # Instruments
2
2
 
3
- Reach for an instrument here where a capture cannot settle the claim. Run every one with its negative
4
- control, in the same conditions, on the real compiled cascade the page loads. Treat an instrument
5
- whose negative control passes as broken and refuse its reading as evidence;
6
- `.claude/rules/quality.md` owns that law where it is present.
7
-
8
- Take each entry's property, population, reading, negative control, and coverage as written, and hold
9
- every entry to these rules.
10
-
11
- - **Report the population.** A reading carries the population it walked. An empty population fails
12
- the run, because an extractor that quietly matched nothing satisfies every other assertion.
13
- - **Draw every negative control from outside the population.** Name the membership rule first, then
14
- pick a negative control the rule excludes. Reject a negative control that rule admits.
15
- - **Enter a negative control through the same door the surface enters.** A negative control handed
16
- straight to the reading tests the reading alone, so pair it with one appended to the tree, the stylesheet,
17
- or the registry the instrument walks wherever the instrument has an extraction step.
3
+ Reach for an instrument where a capture cannot settle the claim. Run it against the compiled
4
+ cascade the page loads, with its negative controls under the same conditions. Treat a missed
5
+ negative control as a broken instrument and refuse its reading as evidence;
6
+ `.claude/rules/quality.md` owns that law where present.
7
+
8
+ Keep mechanical results separate from visual judgments. Take each entry's property, population,
9
+ reading, negative control, and coverage as its contract. Report failures and untested coverage, not
10
+ a pass label alone.
11
+
12
+ - **Report the population.** Name the membership rule and count what the extractor walked. An
13
+ expected but empty population fails. Mark a genuinely absent feature not applicable with its
14
+ reason; do not count it as passing.
15
+ - **Keep controls independent.** Construct known-invalid fixtures in the harness, outside the
16
+ production population and the accepted set. Include them in the test run through the same
17
+ extraction path, and exclude them from production counts. Do not filter the defect out before
18
+ the reader can see it.
19
+ - **Test extraction as well as reading.** Pair a directly fed fixture with one appended to the
20
+ tree, stylesheet, or registry wherever extraction exists. Remove harness mutations afterward.
21
+ - **Bound the claim.** Name files, routes, themes, viewports, states, and exclusions actually read.
22
+ Unsupported input and unavailable tooling remain open, never passed by assumption.
18
23
 
19
24
  ## Contents
20
25
 
@@ -22,146 +27,264 @@ every entry to these rules.
22
27
  - [Declared class combinations](#declared-class-combinations)
23
28
  - [Style escapes](#style-escapes)
24
29
  - [Token discipline](#token-discipline)
30
+ - [Declared design scales](#declared-design-scales)
25
31
  - [Custom rule doing a utility's job](#custom-rule-doing-a-utilitys-job)
26
- - [Composited contrast in both themes](#composited-contrast-in-both-themes)
32
+ - [Color-mode inheritance](#color-mode-inheritance)
33
+ - [Composited contrast in every declared theme](#composited-contrast-in-every-declared-theme)
27
34
  - [One glyph, one meaning](#one-glyph-one-meaning)
35
+ - [Fixed and adaptive pairing](#fixed-and-adaptive-pairing)
36
+ - [Responsive task and reflow](#responsive-task-and-reflow)
37
+ - [Responsive interaction continuity](#responsive-interaction-continuity)
38
+ - [Rendered design review](#rendered-design-review)
28
39
  - [When an authored rule is already earned](#when-an-authored-rule-is-already-earned)
29
40
 
30
41
  ## Authored class in the shipped cascade
31
42
 
32
- - **Property.** Every class token the surface's own templates and components author has a rule in
33
- the compiled CSS the page loads.
34
- - **Population.** The class tokens the authored markup carries, read against every stylesheet the
35
- page loads: the vendor build, each skin, and the project's own.
36
- - **Reading.** Subtract the tokens the loaded stylesheets define from the tokens the markup carries.
37
- A remainder fails the run and names each token with the file that authored it. Report the token
38
- population walked, and fail a run that walked none.
39
- - **Negative control.** A fed control and an appended control, each of which the reading must report.
40
- Feed the first — a token no stylesheet defines — straight to the reading. Append the second through
41
- the extraction door: an element built in the harness carrying that undefined token on an SVG
42
- `class` attribute, added to the tree the reading walks. Each sits outside the population, which is
43
- authored tokens the cascade resolves.
44
- - **Coverage.** The fed negative control covers the subtraction. The appended negative control covers the extractor,
45
- and it is what fails a reading that never leaves the root or that drops SVG tokens by reaching for
46
- `className`, where the value is an `SVGAnimatedString` rather than a string. Together they prove
47
- authored tokens are a subset of the cascade. The instrument says nothing about a cascade rule
48
- nobody authored, a token a build step or a script adds after the read, or whether a resolved rule
49
- paints what the author intended.
43
+ - **Property.** Every styling class the surface authors resolves in the loaded CSS. Separately name
44
+ legitimate behavior/test hooks that require no CSS; never excuse an intended utility as a hook.
45
+ - **Population.** Authored class tokens, including SVG and conditional states, against vendor,
46
+ skin, dependency, generated-utility, and project stylesheets actually loaded.
47
+ - **Reading.** Parse selectors, subtract the defined styling tokens from the authored set, and
48
+ report each unresolved token with its source. Enumerate declared conditional classes not reached
49
+ in the mounted tree separately; an unreachable stylesheet is an open dependency, not an empty one.
50
+ - **Negative control.** Feed an undefined styling token to the reader, then append a harness SVG
51
+ carrying that token through the same tree extractor. Both must be reported.
52
+ - **Coverage.** The controls cover set comparison and extraction, including SVG's non-string
53
+ `className`. Use `getAttribute('class')` or an equivalent safe reader. Resolution does not prove
54
+ the rule wins the cascade, paints the intended result, or covers a state never enumerated.
50
55
 
51
56
  ## Declared class combinations
52
57
 
53
- - **Property.** Every multi-utility chrome string the surface reuses is declared once by name with
54
- the invariant it holds, and the markup carries no undeclared combination.
55
- - **Population.** The declared combinations, each with its name and its invariant, and every
56
- multi-utility string the authored markup carries.
57
- - **Reading.** Match each string in the markup against the declared set. An undeclared combination
58
- fails and names the element that carries it.
59
- - **Negative control.** A fed control and an appended control, each of which the reading must refuse.
60
- Feed the first — a string one utility away from a declared combination — straight to the reading.
61
- Append the second through the extraction door: an element built in the harness carrying that same
62
- undeclared string on an SVG `class` attribute, added to the tree the reading walks. Each sits
63
- outside the declared set.
64
- - **Coverage.** The fed negative control covers the match against the declared set. The appended negative
65
- control covers the extractor, and it is what fails a reading that never leaves the root or that drops SVG
66
- tokens by reaching for `className`. Together they prove reused chrome is declared. The instrument
67
- does not prove a declared invariant is true, and it does not read a single utility used alone.
68
- - **Never substitute a cancellation heuristic.** A rule that flags a string for its utility count, or
69
- for mixing categories, refuses the legitimate transparent read chrome that keeps a read view and an
70
- edit view from reflowing.
58
+ - **Property.** Reused multi-utility chrome has one named declaration and a stated invariant.
59
+ - **Population.** Declared combinations and the authored instances of those reusable patterns.
60
+ Declare the pattern scope; do not require a registry entry for every one-off layout string.
61
+ - **Reading.** Compare token sets within that scope to the named contracts. Report an undeclared
62
+ or divergent instance. Keep utility order irrelevant unless the host's class merger makes it
63
+ meaningful; record that merger when it applies.
64
+ - **Negative control.** Feed a combination one utility away from its contract, then append an
65
+ instance carrying that mutation through the same extractor, including an SVG fixture. Report both.
66
+ - **Coverage.** This proves instances match declarations, not that an invariant renders correctly.
67
+ Pair geometry or contrast invariants with their own measurements. Never substitute utility-count
68
+ or mixed-category heuristics; a valid transparent read-only treatment can use several utilities.
71
69
 
72
70
  ## Style escapes
73
71
 
74
- - **Property.** The surface's own markup carries no `style` attribute and no `<style>` element.
75
- - **Population.** The elements of a freshly mounted, undriven tree — the surface as authored, before
76
- any interaction drives it.
77
- - **Reading.** Collect every element carrying an inline declaration or an embedded style element and
78
- report it with its markup. Any hit fails.
79
- - **Exemptions, declared by name.** Exempt the framework's own runtime styles and name each exemption
80
- in the instrument: a Bootstrap Modal, Offcanvas, Collapse, or Dropdown writes inline styles as it
81
- runs, and a conditional-visibility directive such as `v-show` emits `style="display: none"` at
82
- mount. Run the reading on an undriven tree, because a reading taken after a journey drives the
83
- surface reports on the framework rather than on the author.
84
- - **Negative control.** An element carrying an inline declaration, built in the harness rather
85
- than taken from the surface, fed to the reading. It sits outside the surface's own markup and the
86
- reading must report it.
87
- - **Coverage.** The instrument reads authored markup at mount. It does not see a style a component
88
- writes after the person interacts, a rule authored in a stylesheet, or an escape inside a
89
- third-party component's own markup.
72
+ - **Property.** Authored markup carries no `style` attribute, and the surface's only `<style>`
73
+ element is the standalone-HTML project stylesheet in `<head>` that
74
+ [SKILL.md](../SKILL.md) → The styling ladder permits. A component-scoped `<style>` block fails.
75
+ - **Population.** Authored templates and the freshly mounted, undriven tree. Keep source and mounted
76
+ readings distinct so generated framework styles are not mistaken for authored declarations.
77
+ - **Reading.** Report inline declarations and non-permitted style elements with their source or
78
+ element. Record each runtime exemption by producer, element, and the property it writes — never a
79
+ blanket component exemption, and never a producer that writes a property outside its purpose.
80
+ Bootstrap overlay positioning and conditional-visibility directives write runtime styles. The host
81
+ script for progress owns the `width` declaration on the elements specified in
82
+ [components.md](components.md) → Progress.
83
+ - **Negative control.** Feed an element with an inline declaration, then append an inline-styled
84
+ element and a component-scoped `<style>` element to the harness tree. Every non-exempt fixture
85
+ must be reported. Add a permitted fixture the reader must leave alone — the project stylesheet's
86
+ own `<head>` block, and a recorded runtime producer writing only its declared property — so the
87
+ reader cannot pass by rejecting every style element.
88
+ - **Coverage.** This covers authored and mount-time escapes, not later interactions or third-party
89
+ internals outside the declared scope. Drive later states separately when making claims about them.
90
90
 
91
91
  ## Token discipline
92
92
 
93
- - **Property.** No authored rule carries a literal color, and every custom paint resolves through a
94
- token in each color mode the product ships.
95
- - **Population.** The project's own authored stylesheet rules, and the resolved value of each
96
- custom-painted property in each color mode.
97
- - **Reading.** A literal color in an authored declaration fails. For each custom paint, read the
98
- resolved value once per mode; a mode that leaves it unresolved fails, and so does a pair of modes
99
- that resolve it identically where the design says the modes differ.
100
- - **Negative control.** A rule carrying a literal color, and a paint whose token the cascade does
101
- not define, both fed to the reading rather than authored into the surface. Each sits outside the
102
- population of authored rules that pass, and the reading must report both.
103
- - **Coverage.** The instrument covers authored rules and the paints it was given. It does not judge
104
- whether the chosen token is the right one, and it reads no vendor rule and no inline declaration —
105
- [Style escapes](#style-escapes) covers those.
93
+ - **Property.** Literal colors live only in declared primitive definitions. Semantic and component
94
+ paint resolve through the declared token layers in each shipped color mode.
95
+ - **Population.** Project-authored color declarations and token references, the named primitive
96
+ definition locations, and custom-painted properties reached in each theme and state.
97
+ - **Reading.** Parse declarations, not color-looking text in comments or strings. Permit raw colors
98
+ only in the named primitive definitions; reject literals in component paint, unresolved or cyclic
99
+ references, and a component bypassing semantic tokens. Check RGB partners where consumed. A theme
100
+ pair may resolve identically unless the design contract requires it to differ.
101
+ - **Negative control.** Accept a valid primitive definition as a positive fixture. Feed a literal
102
+ component fill and an undefined token reference; append both to a harness stylesheet through the
103
+ same extractor. The valid definition must survive and every invalid fixture must fail.
104
+ - **Coverage.** This proves declared paint follows the token boundary in the read scope. It does not
105
+ prove mode adaptation, foreground ownership, legibility, or visual quality. Use Color-mode inheritance for the cascade contract. Vendor literals are not authored violations;
106
+ rendered contrast still measures their effect. Inline paint belongs to Style escapes.
107
+
108
+ ## Declared design scales
109
+
110
+ - **Property.** Authored type, spacing, width, radius, and elevation treatments use declared roles,
111
+ shipped scale steps, or documented extensions rather than untracked one-off values.
112
+ - **Population.** The project's scale/role definitions and authored declarations consuming them.
113
+ Include breakpoint rules, component variants, and any declared fluid sizing formulas.
114
+ - **Reading.** Resolve each treatment to its role or accepted step. Report undeclared values,
115
+ missing generated selectors, `em` font sizes, and `.small` nested inside `.small`. Validate fluid formulas against their declared bounds; do not reject
116
+ legitimate intermediate computed values as off-scale. Confirm required grouping relationships in
117
+ the rendered review rather than inferring them from token names.
118
+ - **Negative control.** Feed an undeclared spacing value and append an off-scale type declaration
119
+ through the stylesheet extractor. Report both. Accept a declared fluid value inside its bounds.
120
+ - **Coverage.** This checks consistency with a system, not whether the system suits the task. A
121
+ perfectly on-scale layout can still have ambiguous grouping, poor line breaks, or the wrong density.
106
122
 
107
123
  ## Custom rule doing a utility's job
108
124
 
109
- - **Property.** Every authored selector expresses something no shipped utility expresses, or records
110
- the reason the utility does not fit.
111
- - **Population.** The selectors in the project's own stylesheets.
112
- - **Reading.** For each selector, name the utility that would carry the same declarations. A selector
113
- a shipped utility already expresses fails unless it carries the recorded reason.
114
- - **Negative control.** A rule restating a shipped utility exactly — a padding declaration matching
115
- a spacing step — fed to the reading rather than authored into the stylesheet. It sits outside the
116
- set of authored selectors that pass, and the reading must report it.
117
- - **Coverage.** The instrument reads declarations, not intent. A rule that does a utility's job
118
- alongside something else passes it, so a person still reads the authored stylesheet.
119
-
120
- ## Composited contrast in both themes
121
-
122
- - **Property.** Every pairing the surface paints meets its bar in every theme: 4.5:1 for anything
123
- information-bearing, 3:1 for textless marks and the chrome that carries state.
124
- - **Population.** The pairings the surface renders, read per theme on the compiled cascade, with
125
- every translucent layer composited. Exempt disabled controls, per [SKILL.md](../SKILL.md) →
126
- Surfaces, color, contrast.
127
- - **Reading.** Composite the painted layers, read the ratio, and fail anything under its bar with the
128
- pairing named. Take the mechanics from [bootstrap-reference.md](bootstrap-reference.md) → Measuring
129
- the bars.
130
- - **Negative control.** An opaque pairing and a translucent stack, each of which the reading must
131
- fail. Compose the opaque pairing in the harness at a ratio known to sit under the bar. Compose the
132
- stack with a translucent layer over a floor, so its composited ratio sits under the bar while its
133
- top layer read alone sits above it. Each is composed in the harness rather than taken from the
134
- surface, so each sits outside the rendered population.
135
- - **Coverage.** The opaque pairing covers the ratio arithmetic. The translucent stack covers the
136
- compositing step, and it is what fails a reader that takes the top layer's declared color and skips
137
- the layers under it. Together they measure what rendered, in the themes and viewports the run
138
- entered. A pairing that appears only in a state the run never reached is unmeasured, so name the
139
- states the run covered beside the result.
125
+ - **Property.** Each authored selector expresses a need no shipped utility expresses, or records
126
+ why the utility does not fit. Declared component-variable overrides and generated utilities stay
127
+ on their extension rung; they are not automatically bespoke styling violations.
128
+ - **Population.** Project-authored selectors, their declarations, and the loaded utility rules.
129
+ - **Reading.** Compare declarations and name the equivalent utility when one exists. Report a
130
+ duplicate without a recorded reason. Read mixed-purpose rules too; adding an unrelated declaration
131
+ does not excuse the duplicated part.
132
+ - **Negative control.** Feed a rule that exactly repeats a shipped padding utility, then append it
133
+ through the stylesheet extractor. Report it in both runs.
134
+ - **Coverage.** This checks expressible equivalence, not the intent or merit of an exception. Review
135
+ the reason and styling-rung authorization separately; specificity and state scope can matter.
136
+
137
+ ## Color-mode inheritance
138
+
139
+ - **Property.** Ordinary content inherits its body or component foreground. Quiet adaptive fills
140
+ add no arbitrary text color. Intentional solid and local-mode boundaries own a measured pair;
141
+ native component states retain their foreground behavior. Take the contract from
142
+ [color-modes.md](color-modes.md).
143
+ - **Population.** Rendered text, status marks, badges, tags, links, fields, selected controls, table
144
+ cells, and overlays in the actual loaded build. Include supported nested modes, skin overrides,
145
+ and portal mount points; name the boundaries that own an explicit foreground.
146
+ - **Reading.** Drive the existing mounted tree through every declared mode and back. Read computed text,
147
+ painted backgrounds, relevant custom properties, and winning declarations after each transition.
148
+ Confirm quiet ordinary text matches its intended inherited foreground; identify the owner when
149
+ a component legitimately differs. Check supported system preference and reload behavior when the
150
+ mode controller is in scope. A class-name match or a changing variable alone does not pass.
151
+ - **Negative control.** Add fixed `text-dark` on a dark body surface, a stock `.badge` with a subtle
152
+ fill but no inheritance reset in light mode, and an opposite-mode plain region without its owned
153
+ foreground/background pair. Require the reader to detect each violated contract. For projects
154
+ using aliases, add a root-resolved foreground alias inherited into an opposite-mode scope.
155
+ Verify each control is invalid in that build; a class name alone does not establish the defect.
156
+ - **Coverage.** Pair the cascade reading with Composited contrast in every declared theme; correct inheritance can still
157
+ produce insufficient contrast on a changed surface. An isolated stock fixture establishes only
158
+ that fixture's behavior, not the host skin or application. Unreached states and mounts stay open.
159
+
160
+ ## Composited contrast in every declared theme
161
+
162
+ - **Property.** Every measured pairing meets the bars in [SKILL.md](../SKILL.md) → Surfaces, color,
163
+ contrast, in each declared theme and reached state. That section owns the bars; read them there
164
+ rather than from a copy here.
165
+ - **Population.** Rendered text and meaningful graphics, their actual surfaces, and all paint layers
166
+ affecting contrast. Name exemptions for disabled controls; do not exempt readable metadata.
167
+ - **Reading.** Composite translucent backgrounds onto the opaque base and translucent foregrounds
168
+ onto that result before calculating contrast. Include ancestor opacity where relevant. Report the
169
+ pairing, ratio, bar, theme, and state for each failure. Take the mechanics from
170
+ [bootstrap-reference.md](bootstrap-reference.md) → Measuring the bars.
171
+ - **Negative control.** Feed an opaque pair known to fail and a translucent stack whose composited
172
+ ratio fails although a flat read would pass. Append both through the rendered-pair extractor and
173
+ require all failures. Include the same theme scopes and paint mechanism as the production run.
174
+ - **Coverage.** Flat computed colors cannot settle text over images, gradients, masks, blend modes,
175
+ or unsupported compositing. Read the actual background under the text with an appropriate method,
176
+ or mark the pairing open. Never average an image into a passing color. Name unvisited states;
177
+ measurements from one surface, theme, or crop do not establish another.
140
178
 
141
179
  ## One glyph, one meaning
142
180
 
143
- - **Property.** Each status meaning takes one glyph, each glyph serves one meaning, and every
144
- registered glyph resolves in the icon set the product actually ships.
145
- - **Population.** The registry of meanings and glyphs the surface uses, and the shipped icon set.
146
- - **Reading.** A meaning registered twice, a glyph registered against two meanings, or a glyph the
147
- shipped set does not resolve fails, each named.
148
- - **Negative control.** A registry entry binding a second meaning to a glyph already registered,
149
- plus a glyph name the shipped set lacks. Both sit outside the registered set, and the reading must
150
- report both.
151
- - **Coverage.** The instrument proves the registry is consistent and resolvable. It does not prove
152
- the markup draws the registered glyph for the meaning it carries, so pair it with a capture of the
153
- states that use marks.
181
+ - **Property.** Each registered status meaning takes one glyph; each registered glyph serves one
182
+ status meaning and resolves in the icon set the product ships.
183
+ - **Population.** The surface's status registry and the shipped icon set. Keep generic action icons
184
+ outside this status-only contract unless the project explicitly includes them.
185
+ - **Reading.** Report duplicate meanings, a status glyph bound to two meanings, and missing glyphs.
186
+ - **Negative control.** Feed a second meaning for a registered glyph and an unavailable glyph name;
187
+ append equivalent invalid entries through the registry extractor. Report both kinds of failure.
188
+ - **Coverage.** This proves registry consistency, not that the markup uses the correct glyph or that
189
+ its optical size and contrast work. Capture the states that use the marks and inspect their names.
190
+
191
+ ## Fixed and adaptive pairing
192
+
193
+ - **Property.** Every text, icon, and border color resolves against the surface it sits on with
194
+ tokens of the same kind: adaptive on adaptive, or fixed on a fixed fill that names its own
195
+ foreground or carries a `data-bs-theme` scope.
196
+ - **Population.** Every element with a color class, and every component with a fixed foreground
197
+ or fill (`btn-outline-*`, `table-*`, `badge`, `progress-bar`), including template branches,
198
+ portals, and inline SVG with literal fills.
199
+ - **Reading.** For each element, resolve the nearest ancestor that paints a background — class,
200
+ component, or scope — and classify both sides from
201
+ [color-modes.md](color-modes.md#fixed-and-adaptive-classes). Report mixed pairs, fixed fills
202
+ with inherited text — including a `data-bs-theme` scope on a fixed fill that does not carry
203
+ `text-body` on the same element — fixed neutrals on adaptive surfaces (`bg-light`, `bg-white`,
204
+ `text-dark`), `text-dark-emphasis` inside a dark scope, and outline buttons outside a measured
205
+ scope. Report `text-muted`, `navbar-light`, `navbar-dark`, and `btn-close-white` under a separate
206
+ deprecation finding: they are 5.3 deprecations rather than pairing defects, and `text-muted` pairs
207
+ correctly. The scan predicts a pairing failure; the contrast instrument in each declared theme
208
+ establishes it.
209
+ - **Negative control.** Append `bg-light` with inherited text, `text-white` on `bg-body`,
210
+ `text-primary` inside a `data-bs-theme="dark"` region, and a `bg-dark` region with
211
+ `data-bs-theme="dark"` and plain text but no `text-body`, in a harness; each must be reported by
212
+ the same reader.
213
+ - **Coverage.** Mechanical class analysis only; it does not see custom CSS, `currentColor`
214
+ resolution, image content, or composited opacity. Measure those in the render.
215
+
216
+ ## Responsive task and reflow
217
+
218
+ - **Property.** The declared task remains readable and operable without unintended page overflow,
219
+ concealed content, or clipped controls at the widths in [responsive-layout.md](responsive-layout.md).
220
+ - **Population.** Changed routes, responsive regions, required task fields/actions, local scrollers,
221
+ and their reached data states. Include conditional content and loaded fonts/assets. Name the
222
+ Bootstrap build and every environment substitution; a missing dependency is not a passing page.
223
+ - **Reading.** Record viewport and container bounds, document width, local client/scroll dimensions,
224
+ critical text bounds, effective target sizes, and required content/action visibility. Check both
225
+ sides of each actual transition. Use a small declared rounding tolerance. Keep intentional data
226
+ scrolling separate from document overflow; identify the owner and prove reach to its final item.
227
+ Read task regions as well as `documentElement.scrollWidth`; hidden overflow is not a repair.
228
+ - **Negative control.** Feed a too-wide region to the bounds reader; append an oversized child,
229
+ conceal it behind a clipping parent, and hide a required primary action in separate harness runs.
230
+ Each defect must be reported by the same production extraction path. Include a positive local
231
+ table scroller so the reader cannot pass by banning all overflow.
232
+ - **Coverage.** Test 320/390 CSS px, a wide view, each used boundary, long content, and short height.
233
+ Record enlarged-text and real browser-zoom tests separately. Reducing the viewport is a reflow
234
+ proxy, not execution of 400% browser zoom. Geometry does not establish aesthetics, full text
235
+ contrast, real-device keyboard behavior, or an exhaustive accessibility result.
236
+
237
+ ## Responsive interaction continuity
238
+
239
+ - **Property.** Narrow/wide changes preserve access, state, and meaningful focus; responsive chrome
240
+ does not leave a stale overlay, scroll lock, or trap.
241
+ - **Population.** Navigation triggers/panels, forms, selections, filters, sort/pagination, disclosures,
242
+ and overlays changed by a breakpoint. Record which controls are functional and which are fixtures.
243
+ - **Reading.** Complete the narrow primary flow. Open/close navigation with pointer and keyboard,
244
+ test Escape/focus return, resize while open, and return below the threshold. Carry selected IDs,
245
+ filters, sort, field values, and active detail context through both directions. Check reachable
246
+ dialog actions in a short viewport and with enlarged text. Confirm actual row/filter changes,
247
+ not merely `aria-sort`, labels, or a success message.
248
+ - **Negative control.** Remove the required narrow trigger, break its target, and erase a selected
249
+ record during a harness resize. Drive the same interaction assertions; each must fail. Mark an
250
+ absent component not applicable rather than treating an empty locator set as success.
251
+ - **Coverage.** Desktop mouse, keyboard, and emulated touch are separate runs. Keep real-device
252
+ browser chrome/soft keyboard, unsupported engines, persistence, and server actions open unless
253
+ exercised. For dual presentations, inspect IDs and the accessibility tree: only the active view
254
+ may expose its controls. Attribute presence alone does not establish any interaction result.
255
+
256
+ ## Rendered design review
257
+
258
+ Use captures for these judgments, not synthetic negative controls. Record the criterion, capture,
259
+ viewport/theme/state, finding, and disposition. A missing capture leaves the judgment open. For a
260
+ requested review round or campaign, use `orkestrel-polish-surface` rather than creating one here.
261
+
262
+ - **Task and hierarchy:** the main information and action lead; supporting content remains readable;
263
+ labels, semantics, and destructive rank match the work. Check a grayscale view as a hierarchy aid.
264
+ - **Grouping and density:** inter-group gaps exceed internal gaps; labels/help/errors stay with the
265
+ right control after wrapping. Width serves the content; rails, forms, and tables use it deliberately.
266
+ - **Type and reflow:** line length, baseline alignment, line-height, numeric comparison, and fallback
267
+ text work at the declared widths and enlarged text. No essential content is clipped or hidden.
268
+ - **Color, depth, and imagery:** transitions between declared themes preserve hierarchy without gratuitous text overrides; color has a second encoding;
269
+ elevation describes layers; crops and icon sizes preserve useful detail; the frame stays quiet.
270
+ - **States and restraint:** first-use, filtered-empty, loading, partial, and error retain a useful
271
+ next step. Long or missing content holds up. The signature belongs to the brief; accessories do not
272
+ compete with the task. Motion-free operation remains complete.
273
+
274
+ A visual review does not establish keyboard behavior, contrast arithmetic, or full WCAG conformance.
275
+ Pair each such claim with the relevant instrument or interaction test and its actual coverage.
154
276
 
155
277
  ## When an authored rule is already earned
156
278
 
157
- Leave rung 4 to the developer, per [SKILL.md](../SKILL.md) → When custom CSS is justified. Write an
158
- authored rule without asking only when every one of these holds:
279
+ Leave the authored rung to the developer, per [SKILL.md](../SKILL.md) → When custom CSS is
280
+ justified. Write a rule without asking only when every condition holds:
159
281
 
160
- - an instrument here reports the vendor cascade failing a stated bar — the focus ring under 3:1, the
161
- status text under 4.5:1, the shipped component with no class for the state the surface must
162
- show;
163
- - the rule cites that reading beside it, naming the instrument, the bar, and the value read;
164
- - the rule restores the bar and does nothing else;
165
- - the rule is written over `--bs-*` tokens, so both color modes move with the theme.
282
+ - an instrument reports a vendor failure against a stated requirement, such as a focus ring below
283
+ 3:1 or information-bearing status text below 4.5:1;
284
+ - the rule cites the instrument, failing reading, and required bar beside it;
285
+ - the component, utility, and extension rungs cannot restore the requirement, and the rule repairs that failure without unrelated polish;
286
+ - the rule uses `--bs-*` paint tokens and declared scales, and the repaired result is re-measured in
287
+ every affected theme and state.
166
288
 
167
- Treat anything wider as a proposal: name what the rule would buy, and stop.
289
+ A visual preference alone does not open this exception. Treat anything wider as a proposal: name
290
+ what the rule would buy and stop until authorized.