@orkestrel/scaffold 0.0.59 → 0.0.61
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.
- package/README.md +13 -10
- package/dist/bin/main.js +632 -320
- package/dist/bin/main.js.map +1 -1
- package/dist/host/CLAUDE.md +5 -1
- package/dist/host/agents/orchestration.md +44 -19
- package/dist/host/agents/skills/enterprise-bootstrap/SKILL.md +91 -82
- package/dist/host/agents/skills/enterprise-bootstrap/references/bootstrap-reference.md +5 -5
- package/dist/host/agents/skills/enterprise-bootstrap/references/components.md +15 -15
- package/dist/host/agents/skills/enterprise-bootstrap/references/inputs.md +501 -0
- package/dist/host/agents/skills/enterprise-bootstrap/references/inspection.md +167 -0
- package/dist/host/agents/skills/enterprise-bootstrap/references/utilities.md +2 -2
- package/dist/host/agents/skills/orkestrel-debrief/SKILL.md +2 -2
- package/dist/host/agents/skills/orkestrel-debrief/references/instruction-audit.md +10 -9
- package/dist/host/agents/skills/orkestrel-falsify/SKILL.md +21 -11
- package/dist/host/agents/skills/orkestrel-falsify/references/brief.md +20 -2
- package/dist/host/agents/skills/orkestrel-harden-package/SKILL.md +1 -1
- package/dist/host/agents/skills/orkestrel-harden-package/references/hardening.md +1 -1
- package/dist/host/agents/skills/orkestrel-harden-package/references/research.md +1 -1
- package/dist/host/agents/skills/orkestrel-polish-surface/SKILL.md +4 -1
- package/dist/host/agents/skills/orkestrel-polish-surface/references/capture-harness.md +71 -50
- package/dist/host/agents/skills/orkestrel-prove-journey/SKILL.md +93 -29
- package/dist/host/agents/skills/orkestrel-prove-journey/agents/openai.yaml +1 -1
- package/dist/host/agents/skills/orkestrel-prove-journey/references/captures.md +62 -38
- package/dist/host/agents/skills/orkestrel-prove-journey/references/decide.md +68 -0
- package/dist/host/agents/skills/orkestrel-prove-journey/references/layer.md +107 -79
- package/dist/host/agents/skills/orkestrel-prove-journey/references/statechart.md +84 -0
- package/dist/host/agents/skills/orkestrel-prove-journey/references/styles.md +87 -0
- package/dist/host/agents/templates/brief.md +16 -7
- package/dist/host/agents/transports/claude.md +4 -2
- package/dist/host/agents/transports/codex.md +4 -1
- package/dist/host/claude/agents/analyst.md +3 -1
- package/dist/host/claude/agents/application.md +1 -1
- package/dist/host/claude/agents/builder.md +3 -3
- package/dist/host/claude/agents/checker.md +5 -0
- package/dist/host/claude/agents/grok.md +15 -5
- package/dist/host/claude/agents/implementer.md +1 -1
- package/dist/host/claude/agents/orkestrel.md +12 -11
- package/dist/host/claude/agents/planner.md +10 -0
- package/dist/host/claude/agents/reviewer.md +14 -8
- package/dist/host/claude/agents/sol.md +3 -1
- package/dist/host/claude/agents/verifier.md +2 -4
- package/dist/host/claude/rules/architecture.md +7 -5
- package/dist/host/claude/rules/documentation.md +1 -0
- package/dist/host/claude/rules/names.md +23 -5
- package/dist/host/claude/rules/patterns.md +1 -0
- package/dist/host/claude/rules/quality.md +1 -1
- package/dist/host/claude/rules/tests.md +3 -3
- package/dist/host/claude/rules/typescript.md +4 -1
- package/dist/host/claude/rules/writing.md +2 -2
- package/dist/host/claude/skills/orkestrel-prove-journey/SKILL.md +1 -1
- package/dist/host/codex/agents/builder.toml +6 -6
- package/dist/host/codex/agents/checker.toml +2 -1
- package/dist/host/codex/agents/grok.toml +12 -5
- package/dist/host/codex/agents/implementer.toml +2 -2
- package/dist/host/codex/agents/opus.toml +6 -1
- package/dist/host/codex/agents/planner.toml +11 -6
- package/dist/host/codex/agents/reviewer.toml +8 -6
- package/dist/host/guides/scaffold.md +39 -14
- package/dist/host/manifest.json +81 -51
- package/dist/host/scripts/codex.sh +0 -0
- package/dist/host/scripts/cursor.sh +0 -0
- package/dist/host/scripts/deps.sh +0 -0
- package/dist/host/scripts/ollama.sh +0 -0
- package/dist/src/core/index.cjs +424 -282
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +361 -220
- package/dist/src/core/index.d.ts +361 -220
- package/dist/src/core/index.js +421 -283
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +208 -170
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +276 -152
- package/dist/src/server/index.d.ts +276 -152
- package/dist/src/server/index.js +200 -172
- package/dist/src/server/index.js.map +1 -1
- package/package.json +8 -7
package/dist/host/CLAUDE.md
CHANGED
|
@@ -9,7 +9,8 @@ follows it. This file adds only what Claude Code does differently, and cannot we
|
|
|
9
9
|
## Dispatch mechanism
|
|
10
10
|
|
|
11
11
|
- Use the Agent tool for a single dispatch, including when later control flow depends on its result.
|
|
12
|
-
- Use a Workflow for a deterministic fan-out, staged pipeline, or loop. Serialize writing nodes
|
|
12
|
+
- Use a Workflow for a deterministic fan-out, staged pipeline, or loop. Serialize writing nodes, and
|
|
13
|
+
name each node's model alias per § Models.
|
|
13
14
|
- Recover an interrupted Workflow with `resumeFromRunId`.
|
|
14
15
|
- Foreground Bash is hard-capped at 10 minutes regardless of its timeout parameter. Launch anything
|
|
15
16
|
that can exceed it as a harness-tracked background command.
|
|
@@ -20,6 +21,9 @@ follows it. This file adds only what Claude Code does differently, and cannot we
|
|
|
20
21
|
|
|
21
22
|
- Use the aliases `opus` and `sonnet`. Never use a fixed Claude model ID and never use `inherit`.
|
|
22
23
|
- Never set `CLAUDE_CODE_SUBAGENT_MODEL`. It flattens the engine split.
|
|
24
|
+
- Every Workflow `agent()` node names its model alias explicitly. The Workflow custom-agent path
|
|
25
|
+
does not apply a role file's `model:` pin, so a node that omits the alias runs on the session
|
|
26
|
+
model and the lane reads normal on the wrong engine.
|
|
23
27
|
- Run the main session on `opus` at high effort, set by `/model opus` or `"model": "opus"`. Opus 5
|
|
24
28
|
is the Orchestrator in this harness. Its Orchestrator duties are unchanged if it is configured
|
|
25
29
|
otherwise.
|
|
@@ -35,8 +35,7 @@ One workflow runs across all providers. Each engine has one job and never takes
|
|
|
35
35
|
- Route each nontrivial implementation unit to Opus or Sol. Objective, constraint-heavy,
|
|
36
36
|
mechanical-precision work goes to Sol. API-shape, naming, and documentation-voice work goes to
|
|
37
37
|
Opus. Cursor Composer is not an implementation route, and no `composer` role exists.
|
|
38
|
-
- Design runs the adversarial pass.
|
|
39
|
-
engine did not write the work.
|
|
38
|
+
- Design runs the adversarial pass. § Execution loop's audit step fixes which lanes an audit runs.
|
|
40
39
|
|
|
41
40
|
## Orchestration by harness
|
|
42
41
|
|
|
@@ -64,12 +63,15 @@ the execution loop's audit step names, on the same clean-context terms.
|
|
|
64
63
|
|
|
65
64
|
| Lane | Argues |
|
|
66
65
|
| -------------- | --------------------------------------------------------------------------- |
|
|
67
|
-
| **Subjective** | Shape, taste, naming, ergonomics, design fit,
|
|
66
|
+
| **Subjective** | Shape, taste, naming, ergonomics, design fit, the feel the API must present |
|
|
68
67
|
| **Objective** | Correctness, constraints, and what the code and contracts actually permit |
|
|
69
68
|
|
|
70
69
|
**A required lane always runs.** Never collapse required lanes into one. Never let an engine's
|
|
71
70
|
absence stand in for a required lane.
|
|
72
71
|
|
|
72
|
+
Call a lane the round did not dispatch **not run**. `dark` names a bench that cannot round-trip and
|
|
73
|
+
names nothing else, so never write it of a lane. A verdict file's recorded reason uses those words.
|
|
74
|
+
|
|
73
75
|
### Clean contexts
|
|
74
76
|
|
|
75
77
|
- Dispatch each lane as a fresh subagent. Never run a lane inside the Orchestrator's own context.
|
|
@@ -134,6 +136,9 @@ Fall back in this order and record the substitution:
|
|
|
134
136
|
nothing, and returns the required distillate.
|
|
135
137
|
- Work directly on a typo, a one-line fix, or a single lookup. Orchestrate when isolation,
|
|
136
138
|
parallelism, independent review, or substantial context justifies it.
|
|
139
|
+
- Dispatch staging, packing, gate-chain invocation, and instrument authorship as units — `builder`
|
|
140
|
+
for a fully specified script, `verifier` for its evidence — each with a brief and an audit like
|
|
141
|
+
any other unit. Only the commit and the push stay with the Orchestrator.
|
|
137
142
|
|
|
138
143
|
## Roles
|
|
139
144
|
|
|
@@ -196,8 +201,8 @@ Every role honours this floor. No dispatch may widen it.
|
|
|
196
201
|
those roles cannot inspect the tree by writing to it, the Orchestrator supplies the actual diff
|
|
197
202
|
and status evidence in every review dispatch.
|
|
198
203
|
- `verifier` has no edit or write tools and never fixes a failure.
|
|
199
|
-
- Run writing
|
|
200
|
-
|
|
204
|
+
- Run one writing role per checkout, on disjoint checkouts, each dispatched from a clean committed
|
|
205
|
+
baseline and each owning disjoint files. In a single checkout that is one writer at a time.
|
|
201
206
|
- Treat every shared file as report-only.
|
|
202
207
|
- No role commits, pushes, tags, publishes, installs dependencies, or runs a destructive command.
|
|
203
208
|
- No role runs `git checkout`, `git restore`, `git stash`, `git reset`, or `git clean`. Each discards
|
|
@@ -249,8 +254,8 @@ Every role honours this floor. No dispatch may widen it.
|
|
|
249
254
|
Concurrent executors share a filesystem unless isolated. Follow these rules to prevent clobbered
|
|
250
255
|
edits, formatter and build races, cache phantoms, and validation cross-talk.
|
|
251
256
|
|
|
252
|
-
1. Serialize
|
|
253
|
-
dispatch so git is the rollback mechanism.
|
|
257
|
+
1. Serialize writers as § Permission floor states: one per checkout, checkouts disjoint. Commit a
|
|
258
|
+
checkpoint before each writing dispatch so git is the rollback mechanism.
|
|
254
259
|
2. Assign disjoint owned files plus explicit shared and off-limits files.
|
|
255
260
|
3. Keep shared files report-only. Executors return exact patches for serial integration.
|
|
256
261
|
4. Restrict concurrent executors to read-only, scoped validation. A tree-wide result may contain a
|
|
@@ -272,8 +277,8 @@ edits, formatter and build races, cache phantoms, and validation cross-talk.
|
|
|
272
277
|
and a flake makes that look like it worked. Refuse the failed row, name it, and re-run it alone
|
|
273
278
|
before deciding what it was.
|
|
274
279
|
9. Run a fleet pass in slices that report as they finish, never as one block. A block hides its first
|
|
275
|
-
failure behind every target that follows, so the failure surfaces after the work it
|
|
276
|
-
|
|
280
|
+
failure behind every target that follows, so the failure surfaces after the work it exists to
|
|
281
|
+
stop. A slice hands control back while most of the fleet is still unstarted.
|
|
277
282
|
10. Re-run a timing or resource failure alone before believing it. Concurrent slices, builds, and
|
|
278
283
|
suites make a container miss deadlines it meets when idle, so a red result under load is a
|
|
279
284
|
question rather than an answer. A unit re-running the file alone is not alone: its own exec,
|
|
@@ -326,21 +331,21 @@ longer holds.
|
|
|
326
331
|
ends the campaign, each to end implemented, repaired, retained, or intentionally excluded on
|
|
327
332
|
evidence. A plan that names work but not its end can only be abandoned, never finished.
|
|
328
333
|
3. **Implement.** Route each nontrivial objective unit to the Sol `implementer` and each nontrivial
|
|
329
|
-
subjective unit to the Opus `implementer`, in the
|
|
330
|
-
fully specified taste-free unit to `builder`. Never route implementation to an
|
|
331
|
-
judgment load exceeds.
|
|
334
|
+
subjective unit to the Opus `implementer`, in the checkout the unit writes, one writer per
|
|
335
|
+
checkout. Route a fully specified taste-free unit to `builder`. Never route implementation to an
|
|
336
|
+
engine the unit's judgment load exceeds.
|
|
332
337
|
4. **Integrate.** Evaluate each distillate against its acceptance criteria, apply shared-file
|
|
333
338
|
patches serially, and route cross-cutting findings. Integration applies exact returned patches
|
|
334
339
|
and mechanical conflict resolution only. A new type, mechanism, behavior, or acceptance
|
|
335
340
|
criterion discovered at integration is a successor brief routed to a writer, never an
|
|
336
341
|
integration edit.
|
|
337
|
-
5. **Audit adversarially.** Audit every nontrivial implementation with
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
342
|
+
5. **Audit adversarially.** Audit every nontrivial implementation with the objective lane and the
|
|
343
|
+
subjective lane — `analyst` and `reviewer`, the way the design step names its lanes — at least
|
|
344
|
+
one of them on an engine that did not write the work. Dispatch `checker` in addition when the
|
|
345
|
+
acceptance criteria are mechanical — counts, paths, parity rows, scope honesty — never in place
|
|
346
|
+
of a lane. A round that runs fewer lanes than its brief names, or omits the checker its criteria
|
|
347
|
+
call for, records the deviation in its verdict file with that round's own reason, never a
|
|
348
|
+
template sentence.
|
|
344
349
|
- State the audit's subject as numbered falsifiable claims and require per-claim verdicts with
|
|
345
350
|
evidence, per the Falsification law in `.claude/rules/quality.md` and the `orkestrel-falsify`
|
|
346
351
|
value set, unless the dispatch names a different skill that fixes another.
|
|
@@ -447,6 +452,8 @@ The harness bridge names the concrete mechanism for each of these.
|
|
|
447
452
|
the record transcribes them, because the committed instrument re-produces the film. The **Bench
|
|
448
453
|
laws** rule "Ephemeral streams, durable records" owns journals and points here for everything
|
|
449
454
|
durable.
|
|
455
|
+
- Name a retained log with the `<unit>.log.txt` pattern, never with a bare `.log` suffix, which the
|
|
456
|
+
root `.gitignore` file ignores.
|
|
450
457
|
- Promote anything that must outlive the campaign into a durable artifact before the sweep — a
|
|
451
458
|
commit message, a guide, a rule, a retrospective. What is only in a swept file did not survive,
|
|
452
459
|
and a debrief that must quote the record verbatim has nothing to quote.
|
|
@@ -461,6 +468,11 @@ The harness bridge names the concrete mechanism for each of these.
|
|
|
461
468
|
wave's plan, routing ledger, and verdicts sit together rather than split across the packages they
|
|
462
469
|
rule on.
|
|
463
470
|
- Never put them in the package they are about. A published package's tree is its product.
|
|
471
|
+
- Where the orchestrator's repository is itself a subject package, keep `.orkestrel/` as the
|
|
472
|
+
artifact home and stage every landing chain by path, never with `git add -A`. Run that
|
|
473
|
+
checkout's own CLI through the built `node dist/bin/main.js` entry, never through the `npx`
|
|
474
|
+
launcher, and record its audit reading beside the landing instead of gating the landing on it.
|
|
475
|
+
Commit the records before the landing's commit step, never during it.
|
|
464
476
|
- Claim nothing outside `.orkestrel/` unless Orkestrel scaffold mandates it. Everything Orkestrel
|
|
465
477
|
owns in a consumer's tree lives beneath that folder, so a convention can be settled there without
|
|
466
478
|
colliding with a convention that is not Orkestrel's.
|
|
@@ -537,6 +549,9 @@ each check. Then run this checklist against what you filled.
|
|
|
537
549
|
derived from it, and a template change with the materialized copy the package generates from it.
|
|
538
550
|
- Read each criterion against the off-limits list, line by line. Grant the file a criterion needs or
|
|
539
551
|
strike that criterion. A file the change will break that appears in neither list is unscoped.
|
|
552
|
+
- Where a scope line names the `tests/**` or `src/**` glob, name the paths the `scaffold repair`
|
|
553
|
+
command restores as off-limits in the same sentence. Bound a criterion wider than its Sites by
|
|
554
|
+
the brief's scope.
|
|
540
555
|
- Scope a unit that changes a mechanism to own the prose describing it. Where a brief scopes that
|
|
541
556
|
prose out, name the carrier and dispatch it before the change ships.
|
|
542
557
|
- Give a small unrelated obligation its own unit.
|
|
@@ -747,6 +762,8 @@ transport.
|
|
|
747
762
|
|
|
748
763
|
### Recovering a dark bench
|
|
749
764
|
|
|
765
|
+
- A probe that finds no bench binary records the bench dark and, in the same turn, names to the user
|
|
766
|
+
the install command and the bench it unblocks. Re-probe when the user answers.
|
|
750
767
|
- A probe that finds a bench binary present but authentication unavailable starts recovery in the
|
|
751
768
|
same turn. Do not record the bench dark and wait.
|
|
752
769
|
- Background the login command with its output captured under `tmp/<bench>/`, surface the
|
|
@@ -775,6 +792,9 @@ five-minute upload window in `references/window.md`. Load the skill when the use
|
|
|
775
792
|
release, and follow it there rather than reconstructing the procedure here. What remains in this
|
|
776
793
|
section binds an executor who is not publishing.
|
|
777
794
|
|
|
795
|
+
A wave over unpublished tips derives its order per run from the graph and records only the round
|
|
796
|
+
each package landed in, never the order itself.
|
|
797
|
+
|
|
778
798
|
### Fixing a dependency before it publishes
|
|
779
799
|
|
|
780
800
|
A defect a consumer meets sometimes lives in a package the consumer only has from the registry.
|
|
@@ -793,6 +813,11 @@ Build the dependency from source, pack it, and **install the tarball** into the
|
|
|
793
813
|
- **Rebuild and repack whenever the source moves.** A stale tarball is the same defect as a stale
|
|
794
814
|
`dist/`, and it is worse for being invisible: the consumer's gates go green against a fix that no
|
|
795
815
|
longer exists in the dependency's tree.
|
|
816
|
+
- **Run one unit per checkout, at that checkout's catalog layer.** Give a checkout with no rows an
|
|
817
|
+
adopt unit only when its typecheck against the staged closure reddens.
|
|
818
|
+
- **Fetch and merge the dependency's default branch before packing it**, wherever another session
|
|
819
|
+
can move that branch. A pack from a stale tip ships the consumer a dependency the dependency's own
|
|
820
|
+
repository no longer has.
|
|
796
821
|
- **Restore the registry copy before any gate that must prove the published artifact, and before
|
|
797
822
|
publishing anything.** A distribution proof run against a local tarball proves the local tarball.
|
|
798
823
|
The release still follows layer order: the dependency publishes first, then the consumer re-pins to
|
|
@@ -24,18 +24,22 @@ every claim about the result from what renders.
|
|
|
24
24
|
Open the reference that owns a subject before writing markup. Never guess a class name: an invented
|
|
25
25
|
utility (`.vw-50`, `.pointer-events-none`) has no rule in the shipped CSS and fails silently. Pick
|
|
26
26
|
components from [components.md](references/components.md) → Choosing components, take their markup
|
|
27
|
-
from the same file, and take fine layout from [utilities.md](references/utilities.md).
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
from the same file, and take fine layout from [utilities.md](references/utilities.md). Pick an
|
|
28
|
+
input's affordance from [inputs.md](references/inputs.md) by what the person is asked for, not by
|
|
29
|
+
what a schema calls the field. Where Bootstrap ships no component for the need — combobox, date
|
|
30
|
+
picker, tags input, data grid, tree — work the native-first ladder in
|
|
31
|
+
[bootstrap-reference.md](references/bootstrap-reference.md) → When not to hand-roll before building
|
|
32
|
+
one.
|
|
31
33
|
|
|
32
34
|
| Layer | File | Holds |
|
|
33
35
|
| -------------- | ----------------------------------------------------------- | --------------------------------------------------------------------------------- |
|
|
34
|
-
| Operate | `SKILL.md`
|
|
36
|
+
| Operate | `SKILL.md` | Process, decision rules, checklist |
|
|
35
37
|
| Design craft | [frontend-design.md](references/frontend-design.md) | Aesthetic, typography, signature, interface copy, anti-defaults |
|
|
36
38
|
| Components | [components.md](references/components.md) | Bootstrap component markup + enterprise selection notes |
|
|
39
|
+
| Inputs | [inputs.md](references/inputs.md) | Affordance per input category, its alternates, its rung, its states |
|
|
37
40
|
| Utilities | [utilities.md](references/utilities.md) | Class index, helpers, composition notes |
|
|
38
41
|
| Bootstrap deep | [bootstrap-reference.md](references/bootstrap-reference.md) | Color modes, theming/tokens, forms, JS lifecycle, a11y depth, enterprise patterns |
|
|
42
|
+
| Instruments | [inspection.md](references/inspection.md) | Property, population, reading, negative control, and coverage per instrument |
|
|
39
43
|
|
|
40
44
|
---
|
|
41
45
|
|
|
@@ -43,20 +47,20 @@ not to hand-roll before building one.
|
|
|
43
47
|
|
|
44
48
|
1. **Assume no stack.** Infer it from the workspace. Do not assume Vue, React, a skin library, a folder layout, or a named product.
|
|
45
49
|
2. **Target Bootstrap 5.3.x** class names and behaviors. Hold a compatible skin that keeps `.btn`, `.card`, `.form-control`, and `data-bs-*` to the same contracts.
|
|
46
|
-
3. **Follow the project's code law.**
|
|
50
|
+
3. **Follow the project's code law.** Take language, layout, and forbidden patterns from its `AGENTS.md` file, its lint rules, and its design system. Take UI craft and Bootstrap usage from here, and never language law.
|
|
47
51
|
4. **Write framework-neutral markup** — semantic HTML plus Bootstrap classes. Wire behavior with what the project already uses; in an SPA prefer the framework-native Bootstrap wrappers over raw `bootstrap.*` JS ([bootstrap-reference.md](references/bootstrap-reference.md) → JavaScript lifecycle).
|
|
48
52
|
5. **Keep this folder intact** so the relative links between its files resolve. Install or vendor it wherever the tooling looks for skills; the paths are tooling-specific, the content is not.
|
|
49
53
|
6. **Use the project's installed Bootstrap** when it has one; otherwise take the CDN snippet from [bootstrap-reference.md](references/bootstrap-reference.md) → Quick start (5.3.8).
|
|
50
|
-
7. **Apply this package** to UI, Bootstrap, and visual-design work matching the description
|
|
54
|
+
7. **Apply this package** to UI, Bootstrap, and visual-design work matching the frontmatter description. When the user points at it, treat it as authoritative for the visual pass.
|
|
51
55
|
|
|
52
56
|
---
|
|
53
57
|
|
|
54
58
|
## The mandate
|
|
55
59
|
|
|
56
60
|
1. **Design direction** — take a point of view rooted in the _subject_ (audience, job-to-be-done, vernacular). Take one justified aesthetic risk, in one place.
|
|
57
|
-
2. **Bootstrap execution** — components and utilities first
|
|
61
|
+
2. **Bootstrap execution** — take components and utilities first, custom CSS only when the system cannot express the need, and paint through `--bs-*` so light and dark both survive.
|
|
58
62
|
|
|
59
|
-
Match the density to the context: a marketing page
|
|
63
|
+
Match the density to the context: a marketing page can open with a thesis-hero, an authenticated
|
|
60
64
|
tool opens with clarity and scan paths. In product UI put the signature in the chrome, never in the
|
|
61
65
|
data ([frontend-design.md](references/frontend-design.md) → Where the signature lives).
|
|
62
66
|
|
|
@@ -64,9 +68,9 @@ data ([frontend-design.md](references/frontend-design.md) → Where the signatur
|
|
|
64
68
|
|
|
65
69
|
## Process
|
|
66
70
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
71
|
+
Read [frontend-design.md](references/frontend-design.md) before setting a direction; it owns subject
|
|
72
|
+
grounding, hero and thesis, typography, structure, motion, restraint, and interface copy. Then work
|
|
73
|
+
this loop:
|
|
70
74
|
|
|
71
75
|
1. **Ground** — name the subject, the audience, and the screen's single job, and state them. Use known user preferences and prior designs as hints, not templates.
|
|
72
76
|
2. **Plan** — build a token system: **color** (4–6 named values), **type** (display / body / utility), **layout** (prose plus ASCII if useful), **signature** (one memorable element).
|
|
@@ -74,53 +78,51 @@ setting a direction. The loop:
|
|
|
74
78
|
4. **Build** — compose Bootstrap components and utilities; map the plan's tokens onto theme variables or a thin skin, with no scattered one-off hex ([bootstrap-reference.md](references/bootstrap-reference.md) → Theming & design tokens). Watch selector specificity: a utility and a custom rule that cancel each other show up as padding and margin bugs.
|
|
75
79
|
5. **Critique the render** — remove one accessory. Check contrast, focus, `prefers-reduced-motion`, mobile, and every data state. Critique what rendered, not the markup.
|
|
76
80
|
|
|
77
|
-
|
|
78
|
-
([frontend-design.md](references/frontend-design.md) → Process).
|
|
81
|
+
Show a direction only after it satisfies the brief and the quality floor, and keep every earlier
|
|
82
|
+
draft private ([frontend-design.md](references/frontend-design.md) → Process).
|
|
79
83
|
|
|
80
84
|
**Rendered proof.** Settle every claim about a screen from a capture, never from source alone;
|
|
81
|
-
`.agents/orchestration.md` owns this law where it is present.
|
|
82
|
-
|
|
83
|
-
mechanism. For a full review-round campaign built on that evidence, use the
|
|
85
|
+
`.agents/orchestration.md` owns this law where it is present. Take captures at every viewport and
|
|
86
|
+
every theme the surface declares, plus an accessibility snapshot, as the review input, and use source only to corroborate
|
|
87
|
+
the mechanism. For a full review-round campaign built on that evidence, use the
|
|
84
88
|
`orkestrel-polish-surface` skill instead of improvising one here.
|
|
85
89
|
|
|
86
|
-
**Mechanical proof.**
|
|
87
|
-
control
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
**Mechanical proof.** Run every instrument in [inspection.md](references/inspection.md) with the
|
|
91
|
+
negative control it names, and treat an instrument whose negative control passes as broken;
|
|
92
|
+
`.claude/rules/quality.md` owns that law where it is present. Those instruments settle what a capture
|
|
93
|
+
cannot: composited contrast, authored classes against the shipped cascade, declared class
|
|
94
|
+
combinations, style escapes, token discipline, a custom rule doing a utility's job, and one glyph per
|
|
95
|
+
meaning. Hold every check the deliverable lists to that shape, whether or not inspection.md names
|
|
96
|
+
it: each states its population, its negative control, and its coverage, and a check that cannot
|
|
97
|
+
name a negative control is recorded as open rather than listed as a check.
|
|
93
98
|
|
|
94
99
|
---
|
|
95
100
|
|
|
96
101
|
## Bootstrap operating principles
|
|
97
102
|
|
|
98
|
-
1. **Mobile first** — smallest screen first, then `sm` / `md` / `lg` / `xl` / `xxl`.
|
|
99
|
-
2. **Semantic HTML** — `nav`, `main`, `section`, heading order.
|
|
100
|
-
3. **Work down the styling ladder
|
|
103
|
+
1. **Mobile first** — build the smallest screen first, then `sm` / `md` / `lg` / `xl` / `xxl`.
|
|
104
|
+
2. **Semantic HTML** — use `nav`, `main`, and `section`, and hold the heading order.
|
|
105
|
+
3. **Work down the styling ladder that follows** — component classes, then utilities, then Bootstrap's own extension points.
|
|
101
106
|
4. **Test every breakpoint you claim.**
|
|
102
107
|
5. **Reach for Bootstrap's own transitions before writing custom animation**, spend one orchestrated moment at most, and wrap any custom animation in `prefers-reduced-motion: no-preference` ([bootstrap-reference.md](references/bootstrap-reference.md) → Reduced motion).
|
|
103
|
-
6. **Resolve every treatment in the shipped cascade** — Bootstrap plus every skin and dependency stylesheet the page pulls in — never from docs memory. A class with no rule of its own
|
|
108
|
+
6. **Resolve every treatment in the shipped cascade** — Bootstrap plus every skin and dependency stylesheet the page pulls in — never from docs memory. A class with no rule of its own can still inherit one, and a token pair that passes in stock Bootstrap can fail under a compatible skin. Measure the `*-subtle` / `*-emphasis` recipes too, once per theme, with a reader that composites the translucent layers ([bootstrap-reference.md](references/bootstrap-reference.md) → Measuring the bars).
|
|
104
109
|
|
|
105
110
|
### The styling ladder
|
|
106
111
|
|
|
107
|
-
Work down these rungs in order. Reach a
|
|
108
|
-
the need.
|
|
112
|
+
Work down these rungs in order. Reach a rung only when the preceding one cannot express the need.
|
|
109
113
|
|
|
110
|
-
1. **The component's own classes, in its documented structure.** Use the right elements, nesting, class names, and required ARIA: a card is `.card` wrapping `.card-body` wrapping `.card-title`, not a `div` with borrowed padding.
|
|
114
|
+
1. **The component's own classes, in its documented structure.** Use the right elements, nesting, class names, and required ARIA: a card is `.card` wrapping `.card-body` wrapping `.card-title`, not a `div` with borrowed padding. Modifier classes, affordance states, color modes, and responsive behavior all hang off that structure.
|
|
111
115
|
2. **Bootstrap utilities, for refinement.** Spacing, flex, display, sizing, text, borders, color. Compose utilities rather than reaching past them, and use only classes that exist in [utilities.md](references/utilities.md).
|
|
112
116
|
3. **Bootstrap's own extension points.** Component `--bs-{component}-*` variables and the utilities API, when a real gap remains after the component-class and utility tiers.
|
|
113
|
-
4. **
|
|
117
|
+
4. **Leave anything beyond Bootstrap's conventions to the developer.** Stop at rung 3 and say plainly what rung 4 would require. Take rung 4 unasked only where [inspection.md](references/inspection.md) → When an authored rule is already earned opens it.
|
|
114
118
|
|
|
115
|
-
Never
|
|
119
|
+
Never reach first for any of these, because each ends the cascade for that element and then survives
|
|
120
|
+
no `--bs-*` retheming, no breakpoint change, and no color-mode change:
|
|
116
121
|
|
|
117
122
|
- a `style="..."` attribute;
|
|
118
123
|
- a `<style>` block in a page or component;
|
|
119
124
|
- a new stylesheet rule for something a utility already does.
|
|
120
125
|
|
|
121
|
-
Each ends the cascade for that element: it outranks the utilities, it ignores `--bs-*` retheming, and
|
|
122
|
-
it does not change across breakpoints or color modes.
|
|
123
|
-
|
|
124
126
|
### Hierarchy & actions
|
|
125
127
|
|
|
126
128
|
| Intent | Typical choice |
|
|
@@ -131,61 +133,67 @@ it does not change across breakpoints or color modes.
|
|
|
131
133
|
| Tertiary | `btn-link` or text links |
|
|
132
134
|
| Status | `badge` / `alert` / `*-emphasis` — **icon + color + word** |
|
|
133
135
|
|
|
134
|
-
**
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
consequence the solid variant. Solid variants paint their own background and measure identically on
|
|
139
|
-
every surface, and the stock fills sit at the 4.5:1 bar with nothing to spare. Re-measure a solid
|
|
140
|
-
variant whenever anything layers over it — an `opacity-*` utility, a translucent overlay, a skin's
|
|
141
|
-
own tint.
|
|
136
|
+
**Give any action that carries information or consequence a solid `btn-*` class, and keep outline
|
|
137
|
+
buttons decorative.** Against stock Bootstrap the whole `btn-outline-*` family misses 4.5:1 across
|
|
138
|
+
the dark theme and on light tinted surfaces — cards, subtle alerts — because an outline button
|
|
139
|
+
paints no background of its own and borrows the surface it sits on.
|
|
142
140
|
|
|
143
|
-
|
|
141
|
+
**Re-measure a solid fill whenever anything layers over it** — an `opacity-*` utility, a translucent
|
|
142
|
+
overlay, a skin's own tint — because the stock fills sit at the 4.5:1 bar with nothing to spare.
|
|
143
|
+
|
|
144
|
+
Draw a status mark with **no text** as an icon glyph, never as a `badge`
|
|
144
145
|
([components.md](references/components.md) → Badge).
|
|
145
146
|
|
|
146
147
|
### Surfaces, color, contrast
|
|
147
148
|
|
|
148
|
-
- **
|
|
149
|
-
- **
|
|
150
|
-
- `text-body-tertiary`
|
|
151
|
-
- **
|
|
152
|
-
- **
|
|
153
|
-
-
|
|
149
|
+
- **Measure these contrast bars in both themes:** **≥ 4.5:1** for anything information-bearing — `small`, captions, and meta text included — and **≥ 3:1** for textless marks, state indicators, and the hover/focus chrome that carries state. Verify Bootstrap's own palette too; the docs admit some defaults fall short. Read both themes — a pairing that passes light routinely fails dark.
|
|
150
|
+
- **Take the `-emphasis` pair for information-bearing status text.** Plain `text-success` and `text-danger` miss the bar across the dark theme and on light tinted surfaces, and `text-warning` is theme-asymmetric — unreadable on light, comfortable on dark. Never make a plain semantic color the encoding; use it only as decoration beside an encoding that already passes.
|
|
151
|
+
- **Tier text a person must read `text-body-secondary` or better**, and keep `text-body-tertiary` for decorative marks: tertiary measures under 4.5:1 on every surface in both themes, so it carries no information anywhere.
|
|
152
|
+
- **Inside `alert-*` and the `*-subtle` backgrounds, take `-emphasis` for information-bearing text and a solid `btn-*` class for every button.** A subtle fill degrades everything inside it one notch, so outline buttons and plain semantic text fail there even in light.
|
|
153
|
+
- **Carry no tone class inside a primary fill.** On `.active`, `.bg-primary`, and `text-bg-*` surfaces every tone class measured lands under the bar in both themes, the `-emphasis` family included, because the fill supplies its own contrast color and the tone class overrides it with one tuned for a different background. Let the surface's contrast color take the text, keep the status encoded by icon and word, and verify by capturing the selected state ([components.md](references/components.md) → Selection fills).
|
|
154
|
+
- Exempt a disabled control from the bars, but never leave a disabled **destructive** control at full danger saturation — at full strength it still reads as armed. Neutralize the danger tone while the control is disabled and carry the reason on the control with `aria-describedby` (plus `title` for pointer users), never `title` alone.
|
|
154
155
|
- Prefer `bg-body`, `bg-body-secondary`, `bg-body-tertiary` over raw `bg-white` / `bg-light`, and drive custom paint from `var(--bs-…)` — they track `data-bs-theme`, a hard-coded hex does not.
|
|
155
|
-
-
|
|
156
|
-
- On **dark surfaces**, scope `data-bs-theme="dark"` rather than the deprecated component
|
|
157
|
-
- Support `data-bs-theme="light"` and `dark` when the product offers both
|
|
156
|
+
- Take pairings from `text-bg-*`, `*-subtle`, `*-emphasis`, and `text-body` / `text-body-secondary`. `text-muted` is deprecated — use `text-body-secondary`.
|
|
157
|
+
- On **dark surfaces**, scope `data-bs-theme="dark"` rather than the deprecated `*-dark` component classes `navbar-dark`, `dropdown-menu-dark`, `btn-close-white`, and `carousel-dark`; gray-on-dark outlines often fail contrast.
|
|
158
|
+
- Support `data-bs-theme="light"` and `dark` when the product offers both, and take the mechanics from [bootstrap-reference.md](references/bootstrap-reference.md) → Color modes.
|
|
158
159
|
|
|
159
160
|
### Density, layout, responsive
|
|
160
161
|
|
|
161
|
-
-
|
|
162
|
+
- Take enterprise density from `table-sm`, `btn-sm` / `btn-group-sm`, and compact toolbars, but keep every interactive target **≥ 24×24px**, measured on the rendered box rather than assumed from the class (WCAG 2.2); pad hit areas rather than shrinking them.
|
|
162
163
|
- Where information density is the screen's job, take the `-sm` family across a control row together — `btn-sm` with `form-control-sm`, `form-select-sm`, `input-group-sm` — so the row shares one height. Never mix control sizes within one row.
|
|
163
|
-
-
|
|
164
|
+
- Take `.card` where grouping earns it; otherwise carry the grouping with spacing and type.
|
|
164
165
|
- Swap conditional chrome in place. A bulk-action bar or an alert that shoves the toolbar down shifts the layout mid-task.
|
|
165
|
-
-
|
|
166
|
+
- Take the app shell, dense tables, filter bars, and the ranked responsive strategies for wide data from [bootstrap-reference.md](references/bootstrap-reference.md) → Enterprise patterns, and spacing, toolbar, truncation, and print composition from [utilities.md](references/utilities.md) → Composition habits.
|
|
166
167
|
|
|
167
168
|
### States & feedback
|
|
168
169
|
|
|
169
|
-
- **
|
|
170
|
+
- **Ship every one of these states on every data surface:** ideal, empty, loading, partial, error. Treat the surface as unfinished until every one exists. Take loading thresholds, empty and error specifics, and the channel matrix for toast / inline alert / banner / modal from [bootstrap-reference.md](references/bootstrap-reference.md) → The data states, Feedback discipline.
|
|
170
171
|
- **Build a blocking decision on the native `<dialog>`.** `showModal()` brings focus containment, Esc, an inert background, and top-layer stacking from the platform, with no instance to construct and none to leak on unmount. Dress it with Bootstrap chrome inside ([components.md](references/components.md) → Modal). Reach for `.modal` and its JS only when the project already drives its dialogs that way.
|
|
171
|
-
- **
|
|
172
|
+
- **Make a destructive action undoable rather than interrupting**, and take the ladder and the confirmation contracts from [bootstrap-reference.md](references/bootstrap-reference.md) → Destructive actions.
|
|
172
173
|
|
|
173
174
|
### Forms
|
|
174
175
|
|
|
176
|
+
- Choose each field's affordance in [inputs.md](references/inputs.md) → The catalog by what the person is asked for, draw every state in that file's fixed set, and obey its cross-category rules — read-only chrome, the locked select, the chosen filter's accent tone, the non-drag path for a file drop.
|
|
175
177
|
- Give every field a visible label (top-aligned by default) or `.form-floating` — never placeholder-only.
|
|
176
178
|
- Validate on **blur**, re-validate error fields on input, re-check everything on submit, and keep submit **enabled**. Never disable submit as a validation strategy.
|
|
177
179
|
- Pair a focusable error summary with inline `.invalid-feedback` per field (`aria-describedby`, `aria-invalid`).
|
|
178
|
-
-
|
|
180
|
+
- Take layout, validation mechanics and their assistive-technology limitation, input groups, autosave, and multi-step rules from [bootstrap-reference.md](references/bootstrap-reference.md) → Forms in production, Wizards & multi-step forms.
|
|
179
181
|
|
|
180
182
|
### When custom CSS is justified
|
|
181
183
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
utilities, then the extension points
|
|
185
|
-
utilities API for missing utility steps
|
|
186
|
-
→ Theming).
|
|
184
|
+
Treat custom CSS as rung 4 and the developer's decision: propose it, name what it buys, and take it
|
|
185
|
+
unprompted only under the exception that follows. Exhaust rungs 1–3 first — correct component
|
|
186
|
+
structure, then utilities, then the extension points: component `--bs-{component}-*` variables for
|
|
187
|
+
restyling, the utilities API for missing utility steps
|
|
188
|
+
([bootstrap-reference.md](references/bootstrap-reference.md) → Theming).
|
|
189
|
+
|
|
190
|
+
Take an authored rule without asking only where an instrument in
|
|
191
|
+
[inspection.md](references/inspection.md) reports the vendor cascade failing a stated bar, the rule
|
|
192
|
+
cites that reading, the rule restores the bar and does nothing else, and the rule is written over
|
|
193
|
+
tokens. [inspection.md](references/inspection.md) → When an authored rule is already earned states
|
|
194
|
+
the whole condition. Treat anything wider as a proposal.
|
|
187
195
|
|
|
188
|
-
When the developer authorizes it:
|
|
196
|
+
When the developer authorizes it, or that exception opens:
|
|
189
197
|
|
|
190
198
|
- Name it in Bootstrap vocabulary.
|
|
191
199
|
- Take colors from `var(--bs-…)` and theme tokens so light and dark both work.
|
|
@@ -197,20 +205,20 @@ When the developer authorizes it:
|
|
|
197
205
|
|
|
198
206
|
## Accessibility baseline
|
|
199
207
|
|
|
200
|
-
-
|
|
201
|
-
- `aria-label
|
|
202
|
-
- `aria-current` / `aria-selected`
|
|
203
|
-
- `aria-expanded`
|
|
204
|
-
-
|
|
205
|
-
-
|
|
206
|
-
-
|
|
207
|
-
-
|
|
208
|
-
-
|
|
209
|
-
-
|
|
210
|
-
-
|
|
211
|
-
-
|
|
212
|
-
|
|
213
|
-
WCAG 2.2 deltas, APG pattern contracts, reduced motion, and SPA focus recipes
|
|
208
|
+
- Give the page a skip link to main, landmarks, and `h1` → `h2` heading order.
|
|
209
|
+
- Name every icon-only control with `aria-label`, and keep every target ≥ 24×24px.
|
|
210
|
+
- Mark active nav and tabs with `aria-current` / `aria-selected` — exactly one `aria-current` per selection.
|
|
211
|
+
- Wire every disclosure with `aria-expanded` and `aria-controls`.
|
|
212
|
+
- Wire help and errors with `aria-describedby`, and mark a failed field `aria-invalid`.
|
|
213
|
+
- Match the live region to the message: `role="status"` for an async status mark, `role="alert"` for an alert-styled notice.
|
|
214
|
+
- Associate a form with the name its host already gives the request (`aria-labelledby`) rather than repeating the prompt as its own label.
|
|
215
|
+
- Keep focus visible: keep the Bootstrap rings, use the `.focus-ring` helper for custom elements, and never write `outline: none`.
|
|
216
|
+
- Keep focus clear of sticky chrome (`scroll-margin-top`), and move focus deliberately on SPA route change, failed submit, and row delete.
|
|
217
|
+
- Never carry meaning by color alone, and verify the contrast.
|
|
218
|
+
- Give every drag interaction a non-drag alternative.
|
|
219
|
+
- Give every dialog `aria-labelledby`, let the platform or Bootstrap trap and restore focus rather than scripting it, and dispose Bootstrap instances in an SPA on unmount.
|
|
220
|
+
|
|
221
|
+
Take WCAG 2.2 deltas, APG pattern contracts, reduced motion, and SPA focus recipes from
|
|
214
222
|
[bootstrap-reference.md](references/bootstrap-reference.md) → Accessibility.
|
|
215
223
|
|
|
216
224
|
---
|
|
@@ -219,10 +227,12 @@ WCAG 2.2 deltas, APG pattern contracts, reduced motion, and SPA focus recipes:
|
|
|
219
227
|
|
|
220
228
|
```
|
|
221
229
|
Progress:
|
|
230
|
+
- [ ] Every check that follows, inspection.md instrument or not, reports its population, names the negative control that failed, and states its coverage; a check that can name no negative control is listed as open instead
|
|
222
231
|
- [ ] Project code law followed; no wrong-stack assumptions
|
|
223
232
|
- [ ] Subject, audience, single job stated
|
|
224
233
|
- [ ] Design plan critiqued against the AI defaults: palette, type, layout, one signature
|
|
225
234
|
- [ ] Shell from components.md, utilities from utilities.md; no invented class
|
|
235
|
+
- [ ] Input affordances from inputs.md; every state in its fixed set drawn, per field
|
|
226
236
|
- [ ] Styling ladder held: no `style` attribute, no `<style>` block, no custom rule doing a utility's job
|
|
227
237
|
- [ ] Plan tokens mapped to theme / --bs-* (no hex scatter); light and dark both shipped where both are offered
|
|
228
238
|
- [ ] Copy in user language, verbs consistent, empty/error/loading text useful
|
|
@@ -230,12 +240,11 @@ Progress:
|
|
|
230
240
|
- [ ] Contrast composited and measured in both themes: ≥ 4.5:1 information-bearing (small included), ≥ 3:1 marks and state chrome; meaning not color-alone
|
|
231
241
|
- [ ] Tiers held: `-emphasis` for information-bearing status, solid buttons for real actions, no tone class inside a filled surface
|
|
232
242
|
- [ ] Every treatment resolved in the shipped cascade, not from docs memory
|
|
233
|
-
- [ ] Authored classes checked against that cascade; one glyph per meaning; every instrument's control failed
|
|
234
243
|
- [ ] Keyboard: focus visible, not obscured, targets ≥ 24px, icon controls named
|
|
235
244
|
- [ ] Reduced motion respected; every drag has a non-drag path
|
|
236
245
|
- [ ] Forms: labels visible, blur validation, error summary + inline, submit enabled
|
|
237
246
|
- [ ] Claimed breakpoints spot-checked; RTL-safe (start/end only)
|
|
238
247
|
- [ ] States present: hover / focus / disabled / invalid / active
|
|
239
248
|
- [ ] SPA hygiene: JS instances disposed on unmount, or framework wrappers used
|
|
240
|
-
- [ ] Rendered proof: captures at
|
|
249
|
+
- [ ] Rendered proof: captures at every viewport and every theme the surface declares + an accessibility snapshot
|
|
241
250
|
```
|
|
@@ -81,7 +81,7 @@ CDN (5.3.8 is the current — and final — 5.3.x patch before 5.4):
|
|
|
81
81
|
|
|
82
82
|
## Color Modes (light / dark / custom)
|
|
83
83
|
|
|
84
|
-
The 5.3 color-mode system replaces the old per-component dark
|
|
84
|
+
The 5.3 color-mode system replaces the old per-component `*-dark` classes.
|
|
85
85
|
|
|
86
86
|
### Mechanics
|
|
87
87
|
|
|
@@ -290,7 +290,7 @@ Client-side, the documented pattern:
|
|
|
290
290
|
</div>
|
|
291
291
|
```
|
|
292
292
|
|
|
293
|
-
Details: input groups with feedback need `.has-validation` on the group (border-radius fix). `.valid
|
|
293
|
+
Details: input groups with feedback need `.has-validation` on the group (border-radius fix). `.valid-tooltip` and `.invalid-tooltip` need a `position-relative` parent. Validation colors are mode-adaptive via `--bs-form-valid-color`, `--bs-form-valid-border-color`, `--bs-form-invalid-color`, `--bs-form-invalid-border-color`.
|
|
294
294
|
|
|
295
295
|
### Autosave vs explicit save
|
|
296
296
|
|
|
@@ -354,7 +354,7 @@ Hold the baseline in [SKILL.md](../SKILL.md) → Accessibility baseline. Its Boo
|
|
|
354
354
|
- collects every painted layer from the element upward to the first opaque one, then composites them top over bottom (Porter-Duff `over`) onto that opaque base;
|
|
355
355
|
- composites a translucent foreground over that result before taking the ratio, rather than reading the declared color;
|
|
356
356
|
- measures both themes in one run, since the theme swap re-points the tokens under every layer;
|
|
357
|
-
- carries a negative control drawn from outside the population it covers — a pairing known to fail — and voids the run if that control passes.
|
|
357
|
+
- carries a negative control drawn from outside the population it covers — a pairing known to fail — and voids the run if that negative control passes.
|
|
358
358
|
|
|
359
359
|
Wire the reader into the suite once it has settled a question.
|
|
360
360
|
|
|
@@ -485,7 +485,7 @@ The Bootstrap implementation — a responsive offcanvas that renders inline abov
|
|
|
485
485
|
</div>
|
|
486
486
|
```
|
|
487
487
|
|
|
488
|
-
Give header cells an **opaque background** (`bg-body-secondary` or a table
|
|
488
|
+
Give header cells an **opaque background** (`bg-body-secondary` or a `.table-*` tone class) — table backgrounds are transparent by default, so rows show through a sticky header otherwise. Sticky chrome is the prime Focus-Not-Obscured offender: add `scroll-margin-top` on row focusables equal to the header height. Sticky first column only when row identity is lost on horizontal scroll — it costs paint and complexity.
|
|
489
489
|
|
|
490
490
|
- **Sorting:** the whole header is a button (not a bare caret), with a visible direction indicator, and `aria-sort="ascending|descending"` on the active `<th>` only:
|
|
491
491
|
|
|
@@ -551,7 +551,7 @@ Match friction to reversibility × blast radius:
|
|
|
551
551
|
|
|
552
552
|
Do not type-gate a single-row delete; do not one-tap a tenant wipe. Confirm only where this ladder calls for it — a confirmation on every action gets clicked through.
|
|
553
553
|
|
|
554
|
-
**Neutralize a disabled destructive control.** `btn-danger` at full saturation reads as armed whatever the `disabled` attribute says, and the contrast exemption for disabled controls does not excuse it. While the action is unavailable, drop to the neutral or outline
|
|
554
|
+
**Neutralize a disabled destructive control.** `btn-danger` at full saturation reads as armed whatever the `disabled` attribute says, and the contrast exemption for disabled controls does not excuse it. While the action is unavailable, drop to the neutral or outline `btn-*` class (or let the disabled state mute the fill) so the color stops promising an action, and say _why_ it is unavailable in text the assistive layer reaches: `aria-describedby` pointing at the reason, with `title` only as the pointer-user convenience on top. Never use `title` alone — it never reaches a keyboard or screen-reader user, and it disappears on touch.
|
|
555
555
|
|
|
556
556
|
## RTL
|
|
557
557
|
|