@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.
@@ -0,0 +1,356 @@
1
+ # Color modes and inheritance
2
+
3
+ > Part of the `enterprise-bootstrap` skill. Use for foreground ownership, adaptive surfaces,
4
+ > nested themes, and color-mode repairs. Take the contrast bars from [SKILL.md](../SKILL.md).
5
+
6
+ ## Contents
7
+
8
+ - [Choose the surface](#choose-the-surface)
9
+ - [Fixed and adaptive classes](#fixed-and-adaptive-classes)
10
+ - [Text tiers](#text-tiers)
11
+ - [Preserve the cascade](#preserve-the-cascade)
12
+ - [Scope the mode](#scope-the-mode)
13
+ - [Respect component ownership](#respect-component-ownership)
14
+ - [Extend the theme](#extend-the-theme)
15
+ - [Verify the result](#verify-the-result)
16
+
17
+ ## Choose the surface
18
+
19
+ Default to inherited text. When ordinary content owns no background, add no foreground override.
20
+ For quiet containers and status, prefer adaptive backgrounds without an added text-color class.
21
+ Treat this as the skill's default, not a claim that Bootstrap forbids its documented emphasis pairs.
22
+
23
+ | Context | Use | Refuse by default |
24
+ | -------------------------------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
25
+ | Ordinary content | Inherited body or component text | A leaf `color` declaration or `text-*` color chosen without a surface contract |
26
+ | Neutral separation | `bg-body`, `bg-body-secondary`, or `bg-body-tertiary`; inherit text | `bg-white`, `bg-light`, or `bg-dark` as an adaptive surface |
27
+ | Quiet semantic status | `bg-*-subtle`; inherit text and state the meaning in words | Automatically matching the fill with `text-*` or `text-*-emphasis` |
28
+ | Intentional solid or inverse treatment | A component-owned pair, or a measured `text-bg-*` helper | A solid `bg-*` with an unrelated inherited foreground |
29
+ | Selected control | The component's checked/active treatment and foreground | Descendant text or icon colors that override the selected foreground |
30
+ | Secondary information | Spacing and weight first; `text-body-secondary` for a deliberate tier ([Text tiers](#text-tiers)) | Opacity, `text-body-tertiary`, or a neutral grey on a colored fill |
31
+
32
+ Use these quiet treatments inside an ordinary body-color context:
33
+
34
+ ```html
35
+ <section class="bg-body-tertiary rounded p-3" aria-labelledby="sync-heading">
36
+ <h2 id="sync-heading" class="h6">Synchronization</h2>
37
+ <p class="mb-0">Updates appear after the next sync.</p>
38
+ </section>
39
+ <span class="d-inline-flex rounded-pill bg-success-subtle px-2 py-1 small fw-semibold">Paid</span>
40
+ ```
41
+
42
+ Measure the inherited result on its actual background. A subtle fill changes only the background;
43
+ it cannot repair a fixed, translucent, or inverse foreground inherited from an ancestor. Remove
44
+ that conflict or establish an owned surface boundary before adding a leaf override.
45
+
46
+ ## Fixed and adaptive classes
47
+
48
+ Every Bootstrap color class resolves through one of two kinds of variable. **Adaptive** classes
49
+ read a variable the `[data-bs-theme=dark]` block redefines — `--bs-body-color`/`-bg`,
50
+ `--bs-emphasis-color`, `--bs-secondary-color`/`-bg`, `--bs-tertiary-color`/`-bg`,
51
+ `--bs-*-text-emphasis`, `--bs-*-bg-subtle`, `--bs-*-border-subtle`, `--bs-border-color`,
52
+ `--bs-link-color` — and change with the mode. **Fixed** classes read `--bs-{theme}-rgb`,
53
+ `--bs-white-rgb`, `--bs-black-rgb`, `--bs-light-rgb`, or `--bs-dark-rgb`, which no mode
54
+ redefines, and paint the same value in light and dark.
55
+
56
+ This table classifies a class by the variable it reads, and nothing else. Deprecation is a separate
57
+ axis: `text-muted` reads the adaptive secondary color and is deprecated, so it classifies as
58
+ adaptive here and still gives way to `text-body-secondary` on its deprecation.
59
+
60
+ | Family | Adaptive | Fixed |
61
+ | ---------- | ----------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
62
+ | Text | `text-body`, `text-body-emphasis`, `text-body-secondary`, `text-body-tertiary`, `text-muted` (alias), `text-*-emphasis` | `text-primary` … `text-danger`, `text-light`, `text-dark`, `text-white`, `text-black`, `text-white-50`, `text-black-50` |
63
+ | Background | `bg-body`, `bg-body-secondary`, `bg-body-tertiary`, `bg-*-subtle` | `bg-primary` … `bg-danger`, `bg-light`, `bg-dark`, `bg-white`, `bg-black`, `bg-gradient` |
64
+ | Border | `border` (default color, decorative at 1.3:1), `border-*-subtle` | `border-primary` … `border-dark`, `border-white`, `border-black` |
65
+ | Links | plain `<a>`, `btn-link`, `link-body-emphasis` | `link-primary` … `link-dark`, `link-light` |
66
+ | Own pairs | `.alert-*`, `.list-group-item-*`, `.form-control`, `.card`, `.dropdown-menu`, `.modal-content`, `.toast`, `.btn-close` | `text-bg-*`, solid `btn-*`, `btn-light`/`btn-dark`, `table-*` row variants, `progress-bar`, active nav/list/page states |
67
+ | No pair | — | `btn-outline-*`: a fixed label and border on whatever surface the page has |
68
+
69
+ **Pair like with like.** Adaptive text on an adaptive surface; fixed text on a fixed fill. Treat
70
+ every mixed pair as unproven until measured: some clear one mode and fail the other, and some fail
71
+ light and dark alike. Read the outcome from the measurement, never from the mixture.
72
+
73
+ The following readings bound stock Bootstrap 5.3.8 and nothing else. A declared theme, a skin, or an
74
+ overridden token re-points every value in the table, so measure that theme yourself rather than
75
+ carrying a stock number into it. Light | dark:
76
+
77
+ | Mixed pair | Light | Dark |
78
+ | ------------------------------------------------------- | ------------- | ------------- |
79
+ | `text-primary` / `-success` / `-danger` on `bg-body` | 4.5 | 3.4 ✗ |
80
+ | `text-secondary` on `bg-body` | 4.7 | 3.3 ✗ |
81
+ | `text-warning` / `text-info` on `bg-body` | 1.6 ✗ / 2.0 ✗ | 9.5 / 7.9 |
82
+ | `text-dark`, `text-black` on `bg-body` | 15.4 / 21.0 | 1.0 ✗ / 1.4 ✗ |
83
+ | `text-white`, `text-light` on `bg-body` | 1.0 ✗ / 1.1 ✗ | 15.4 / 14.6 |
84
+ | Inherited text on `bg-light` / `bg-white` | 14.6 / 15.4 | 1.2 ✗ / 1.3 ✗ |
85
+ | Inherited text on `bg-dark` / `bg-black` | 1.0 ✗ / 1.4 ✗ | 11.8 / 16.1 |
86
+ | Inherited text on `bg-primary` / `-danger` / `-success` | 3.4 ✗ | 3.5 ✗ |
87
+ | `btn-outline-secondary` label on `bg-body` | 4.7 | 3.3 ✗ |
88
+ | `btn-outline-primary` label on `bg-body` | 4.5 | 3.4 ✗ |
89
+ | `link-primary` (`--bs-primary-rgb`) on `bg-body` | 4.5 | 3.4 ✗ |
90
+
91
+ The adaptive pairs hold: `text-*-emphasis` on `bg-body` is 6.1–13.6 in light and dark and on
92
+ `bg-*-subtle` 7.2–10.8, with one exception — `text-dark-emphasis` is 3.7 on the dark body; use
93
+ `text-body-emphasis` for neutral emphasis. A plain link is 4.5 light and 6.4 dark because
94
+ `--bs-link-color` is redefined; `text-primary` and `link-primary` are not.
95
+
96
+ Rules:
97
+
98
+ - Default to adaptive on adaptive: inherited text on `bg-body*` or `bg-*-subtle`; status text as
99
+ `text-*-emphasis`; links as plain links or `link-body-emphasis`.
100
+ - A fixed fill needs a fixed foreground you can name: `text-bg-*` (white on primary, secondary,
101
+ success, and danger at 4.5–4.7; black on warning, info, and light; white on dark), the
102
+ component's own foreground, or a `data-bs-theme` scope that carries `text-body` on the same
103
+ element. Inherited text on a fixed fill is never a pair.
104
+ - A `data-bs-theme` scope redefines variables only. Text color is painted once, on `<body>`, from
105
+ the outer mode, and plain descendants inherit that computed color — not the variable. Inside
106
+ the scope only rules that resolve `color` through a variable re-align: `text-body*`,
107
+ `text-*-emphasis`, buttons, links, `list-group-item`, form controls, `btn-close`. A paragraph,
108
+ a `span`, a heading without a text class, and `.card` (its `--bs-card-color` is empty, so it
109
+ inherits) keep the outer mode's color. The symptom is a headline in `text-body-emphasis`
110
+ reading correctly beside a paragraph that vanishes. Restate the surface and the foreground on
111
+ the scope element: take `bg-body text-body` where the fill must follow the mode, and a fixed
112
+ `bg-*` plus `text-body` where it must not
113
+ (`<section class="bg-dark text-body" data-bs-theme="dark">`).
114
+ Check components that leave the scope: dropdown menus, and dialogs mounted at the root.
115
+ - Outline buttons carry a fixed label. Lift the neutral one once at the theme root —
116
+ `.btn-outline-secondary { --bs-btn-color: var(--bs-emphasis-color); }` — its `#6c757d` border
117
+ still clears the 3:1 boundary bar in light and dark (4.7 | 3.3). For an adaptive primary outline set
118
+ `--bs-btn-color` and `--bs-btn-border-color` to `var(--bs-link-color)`; `btn-link` already adapts.
119
+ `btn-outline-light` and `btn-outline-dark` belong only inside a fixed fill of the opposite tone.
120
+ - Shadows are fixed black alphas and nearly vanish on dark surfaces; carry depth with the
121
+ `bg-body*` steps in dark mode.
122
+ - Icon fonts and `fill="currentColor"` follow the text; a literal hex in an inline SVG or an
123
+ `<img>` is fixed. Give logos and illustrations a scoped variant or a `currentColor` path.
124
+
125
+ | Legacy or mixed | Adaptive replacement |
126
+ | ------------------------------------------------ | ------------------------------------------------------------------------- |
127
+ | `bg-light` panel | `bg-body-tertiary` |
128
+ | `bg-white` | `bg-body` |
129
+ | Neutral `bg-dark` region | `bg-dark` with `data-bs-theme="dark"`, or `bg-body` inside a dark scope |
130
+ | `text-dark`, `text-black` | `text-body-emphasis`, or inherit |
131
+ | `text-white` on an adaptive surface | inherit |
132
+ | `text-muted`, `text-black-50`, `text-white-50` | `text-body-secondary` |
133
+ | `text-primary` … `text-danger` as running text | `text-*-emphasis`, measured |
134
+ | `border-light`, `border-dark` | `border`, or `border-*-subtle` |
135
+ | `navbar-light`, `navbar-dark`, `btn-close-white` | `data-bs-theme` on the navbar or region |
136
+ | `badge bg-primary` with inherited text | `badge text-bg-primary`, or `badge bg-primary-subtle` with inherited text |
137
+ | `link-primary` … `link-dark` | plain link, or `link-body-emphasis` |
138
+
139
+ Read that table as a replacement map, not as a classification. Replace `bg-light`, `bg-white`,
140
+ `bg-dark`, `text-dark`, `text-black`, `text-white`, `text-black-50`, `text-white-50`,
141
+ `border-light`, `border-dark`, and the colored `text-*` and `link-*` families because they are
142
+ fixed. Replace `text-muted`, `navbar-light`, `navbar-dark`, and `btn-close-white` because 5.3
143
+ deprecates them — `text-muted` already adapts, so its replacement closes a deprecation rather than
144
+ a contrast defect.
145
+
146
+ ## Text tiers
147
+
148
+ Stock Bootstrap ships the inherited body color and `text-body-secondary` as its readable tiers;
149
+ `text-body-tertiary` is not readable text. `--bs-secondary-color` is the body color at 75 % alpha
150
+ and `--bs-tertiary-color` at 50 % alpha, so each composites against whatever sits beneath it.
151
+
152
+ The following readings bound stock 5.3.8 on its own body surfaces (`bg-body` / `bg-body-tertiary` /
153
+ `bg-body-secondary`). Measure a declared theme or a skin yourself; its tokens re-point every value
154
+ here.
155
+
156
+ | Tier | Light | Dark | 4.5:1 bar |
157
+ | --------------------- | ------------------ | ----------------- | ---------------- |
158
+ | Inherited body | 15.4 / 14.6 / 13.0 | 11.9 / 10.2 / 8.8 | Passes |
159
+ | `text-body-secondary` | 6.8 / 6.6 / 6.2 | 7.3 / 6.5 / 5.8 | Passes |
160
+ | `text-body-tertiary` | 3.1 / 3.1 / 3.0 | 4.1 / 3.8 / 3.5 | Fails everywhere |
161
+
162
+ - Use `text-body-secondary` as the one shipped quiet tier. Use `text-body-tertiary` for decoration
163
+ or disabled chrome only; it never carries a caption, timestamp, or count someone reads.
164
+ - Declare any further readable tier as an opaque token — override `$body-tertiary-color` and
165
+ `$body-tertiary-color-dark`, or add a semantic token — and measure it on each surface it sits on.
166
+ The opaque `text-secondary` (`$gray-600`) clears 4.5:1 only on pure white and does not adapt.
167
+ - Component variables consume the translucent secondary color — placeholders,
168
+ `.form-text`, table captions, breadcrumb dividers and the active crumb, toast headers, figure
169
+ captions, list-group action text, and disabled states — and inherit this table.
170
+ - On a colored fill, `text-body-secondary` composites the body color over the hue — grey on color —
171
+ and `text-white-50` or `text-opacity-*` let the fill show through the glyphs. The quiet tone on a
172
+ fill is the same hue at lower contrast: keep the owning component's foreground and quiet a line
173
+ with weight or size, or declare a same-hue token (for the stock blue, the `$blue-200`–`$blue-300`
174
+ region in light mode) through the component's own variable and measure it.
175
+ - For a tinted region, use the shipped same-hue pair: `text-*-emphasis` on `bg-*-subtle` (about
176
+ 10:1 for primary in the stock light theme), adapting in light and dark. Keep `text-bg-*` solids for
177
+ the primary element.
178
+
179
+ When checking utility behavior, see Bootstrap's [Background](https://getbootstrap.com/docs/5.3/utilities/background/)
180
+ and [Colors](https://getbootstrap.com/docs/5.3/utilities/colors/) references. Distinguish the
181
+ adaptive families from the original contextual families:
182
+
183
+ - Use `bg-*-subtle`, `border-*-subtle`, and body-role variables for mode-aware surfaces and boundaries.
184
+ Measure a required control boundary separately; a subtle border is not a focus treatment.
185
+ - Treat original contextual `bg-primary`, `text-primary`, and their semantic siblings as
186
+ non-adaptive in stock 5.3. Treat `bg-light`, `bg-dark`, `text-light`, and `text-dark` the same way.
187
+ Do not confuse `bg-secondary` with `bg-body-secondary`.
188
+ - Treat `text-*-emphasis` as adaptive but optional. Use it only for a deliberate semantic foreground
189
+ on a known, measured surface, not merely because that surface has a subtle fill.
190
+ - Reserve `text-bg-*` for a deliberate solid pair. Bootstrap selects its foreground with Sass at
191
+ build time, not through runtime contrast calculation. Recheck after theme-variable changes;
192
+ see [Color and background](https://getbootstrap.com/docs/5.3/helpers/color-background/).
193
+ - Do not invent `text-bg-*-subtle`; stock Bootstrap does not ship that helper.
194
+
195
+ ## Preserve the cascade
196
+
197
+ Inspect the winning declaration before changing a color. Remove a conflicting utility or local
198
+ rule before adding specificity. A literal moved into an unchanging `--bs-*` variable remains an
199
+ unchanging color; the prefix does not prove adaptation.
200
+
201
+ Keep native component foregrounds and states. Do not apply `color: inherit` to all descendants or
202
+ strip every text utility: alerts, validation feedback, links, and selected controls own meaningful
203
+ foreground behavior. Override only the element that violates its surface contract.
204
+
205
+ Use `text-reset` only to restore inheritance where a component or utility has replaced it. The
206
+ helper sets `color: inherit`, not a chosen palette color. Use `text-body` only when the element
207
+ must establish the active mode's body foreground on an owned surface, not as a universal reset.
208
+ Neither helper repairs an inappropriate ancestor by itself.
209
+
210
+ Keep links on Bootstrap's link rules. For a deliberate high-contrast neutral link, use
211
+ `link-body-emphasis`; among stock 5.3 colored-link helpers, only that helper adapts to color modes.
212
+ Do not override a link with a text utility and lose its hover/focus treatment; see
213
+ [Colored links](https://getbootstrap.com/docs/5.3/helpers/colored-links/).
214
+
215
+ Use opacity utilities only where the painted rule consumes their variable. Stock `bg-*-subtle`
216
+ rules do not consume `--bs-bg-opacity`; adding `bg-opacity-*` does not tint them. Check the same
217
+ relationship for emphasis text and subtle borders. Do not use whole-element opacity to create a
218
+ quiet panel with information-bearing children.
219
+
220
+ ## Scope the mode
221
+
222
+ Use the host's mode controller. With Bootstrap's attribute strategy, set the resolved `light` or
223
+ `dark` value on `<html>`; scope an intentional exception with `data-bs-theme` on its boundary.
224
+ Do not pin components to dark merely because the page happens to be dark during development.
225
+
226
+ A nested scope changes variables, not painted colors: `color` is set on `<body>` by the outer
227
+ mode and inherited as a computed value, so plain text inside the scope stays the outer color
228
+ until the boundary restates it. Establish both the surface and the foreground on the scope
229
+ element — never rely on the attribute alone, and never fix the symptom by sprinkling `text-white`
230
+ on individual descendants:
231
+
232
+ ```html
233
+ <section data-bs-theme="dark" class="bg-body text-body p-3" aria-labelledby="preview-heading">
234
+ <h2 id="preview-heading" class="h6">Preview</h2>
235
+ <div class="bg-primary-subtle rounded p-3">This text inherits from the preview.</div>
236
+ </section>
237
+
238
+ <!-- Fixed fill or image that must not follow the page mode: keep bg-*, still restate text-body. -->
239
+ <section data-bs-theme="dark" class="bg-dark text-body py-5" aria-labelledby="hero-heading">
240
+ …
241
+ </section>
242
+ ```
243
+
244
+ Keep the body foreground at that owned boundary; add no text-color classes to its ordinary
245
+ children. A component that already consumes its mode's foreground and background, such as a
246
+ `.dropdown-menu`, can establish its own pair without these utilities.
247
+
248
+ Do not treat `data-bs-theme` as paint. Changing variables on a plain element does not recompute a
249
+ `color` already inherited from outside the scope. Check the boundary guidance in Bootstrap's
250
+ [5.3.0 color-mode notes](https://blog.getbootstrap.com/2023/05/30/bootstrap-5-3-0/).
251
+
252
+ Resolve a portal, teleport, or `container: 'body'` overlay at its actual DOM mount point. Carry an
253
+ intentional local mode to that mount point; do not assume the trigger's ancestry follows it.
254
+
255
+ Avoid mode-sensitive aliases declared only at the root, such as `--app-text: var(--bs-body-color)`,
256
+ then inherited into a different local mode. Consume the Bootstrap variable at the component, or
257
+ rebind the alias at every supported mode boundary. Custom properties resolve their references
258
+ before inheritance; see [CSS Custom Properties](https://www.w3.org/TR/css-variables-1/).
259
+
260
+ When implementing a picker, validate persisted values, tolerate unavailable storage, and resolve
261
+ `auto` through `prefers-color-scheme` before setting the attribute. Follow system changes only
262
+ while the preference is automatic. Apply the resolved mode before first paint, keep server/client
263
+ initial state consistent, and update the picker's accessible state. Do not write
264
+ `data-bs-theme="auto"` without an explicitly implemented custom mode. Take the integration details
265
+ from [Bootstrap color modes](https://getbootstrap.com/docs/5.3/customize/color-modes/).
266
+
267
+ ## Respect component ownership
268
+
269
+ ### Badges and removable tags
270
+
271
+ For quiet status, prefer the utility-composed span in [Choose the surface](#choose-the-surface).
272
+ When preserving `.badge`, restore inheritance explicitly:
273
+
274
+ ```html
275
+ <span class="badge bg-success-subtle text-reset">Paid</span>
276
+ ```
277
+
278
+ Do not use `.badge bg-success-subtle` alone: stock `.badge` supplies a white foreground, not
279
+ inherited body text. Do not mistake the absence of a `text-*` class for the absence of a color
280
+ rule. Confirm the skin's badge rule; see [Badges](https://getbootstrap.com/docs/5.3/components/badge/).
281
+ Keep a removable tag's close button in the same mode and measure its hit area; a badge's small
282
+ font must not shrink the control below the target floor in
283
+ [bootstrap-reference.md](bootstrap-reference.md) → WCAG 2.2 requirements for app UI.
284
+
285
+ ### Alerts, buttons, and selection
286
+
287
+ Leave `.alert-*` on its native foreground, subtle background, border, and `.alert-link` treatment.
288
+ Do not add `text-reset` to an alert merely to enforce inheritance. Choose its announcement role
289
+ by urgency, not by the color or visual component.
290
+
291
+ Choose button rank before color. Keep `.btn-*` state rules; do not add `bg-*-subtle` to a button
292
+ and override its hover/active backgrounds with a utility's `!important`. For a custom variant,
293
+ map the full state contract through component variables and test it. Do not assume an outline
294
+ variant is safe or that a solid variant automatically passes.
295
+
296
+ Within an active row, tab, or filter, let ordinary labels and glyphs follow its tested foreground.
297
+ Remove a competing status tint before changing the selected fill. Keep a genuinely independent
298
+ nested badge on its own measured surface, or remove its fill and restore inheritance.
299
+
300
+ ### Tables and overlays
301
+
302
+ Prefer the uncolored `.table` for automatic light/dark behavior. Treat `.table-primary` and the
303
+ other `.table-*` color variants as non-adaptive in stock 5.3 even though they expose CSS variables.
304
+ Do not describe their Sass-generated values as runtime color-mode mappings.
305
+
306
+ Inspect cells, not only the table or row. The base `--bs-table-bg` uses the body background; the
307
+ transparent default belongs to `--bs-table-accent-bg`. Striping, hover, and active states paint
308
+ cell overlays. Use the table's component variables for a required custom treatment rather than
309
+ stacking generic background utilities on a row; see
310
+ [Tables](https://getbootstrap.com/docs/5.3/content/tables/).
311
+
312
+ Let neutral cards, dropdowns, modals, offcanvas panels, and toasts retain their component-owned
313
+ surfaces. For an intentional local dark region, use `data-bs-theme` rather than the deprecated
314
+ `navbar-dark`, `dropdown-menu-dark`, `btn-close-white`, or `carousel-dark` classes. Check close
315
+ icons and overlay content after every supported mode transition.
316
+
317
+ ## Extend the theme
318
+
319
+ Reuse the installed theme before introducing a palette. Keep primitives in the token source and
320
+ map only the required semantics and component states. Define light and dark as deliberate
321
+ hierarchies; do not mechanically invert every shade or increase decoration in dark mode.
322
+
323
+ Keep RGB companions aligned when a consumer reads them. Changing `--bs-primary` alone does not
324
+ update a utility reading `--bs-primary-rgb`, rebuild `.btn-primary`, or recompute a `text-bg-*`
325
+ foreground. Use the actual consumer's extension point and inspect the emitted rule.
326
+
327
+ Stock ramps are mechanical: `$blue-100…400` are `tint-color` mixes with white and `$blue-600…900`
328
+ are `shade-color` mixes with black, and the `-text-emphasis` / `-bg-subtle` / `-border-subtle`
329
+ triads are the same mixes. Hue stays fixed and saturation can only fall, so any brand base short
330
+ of full saturation washes out at the light end and goes muddy at the dark end; stock blue survives
331
+ only because its base is 98 % saturated. For a brand color, override the `$brand-100…900` shade
332
+ variables and the triad variables (`$brand-text-emphasis`, `-bg-subtle`, `-border-subtle`,
333
+ each with its `-dark` twin) with hand-picked values before `variables` is imported; every
334
+ `.alert-brand`, `bg-brand-subtle`, `text-brand-emphasis`, and `table-brand` then consumes them.
335
+ Stock greys sit at hue 210° with 7–17 % saturation — cool, matched to the stock blue. For a warm
336
+ brand, override `$gray-100…900` as a complete set at one hue and temperature; never drop
337
+ one warm grey into the cool set. Take the picking method from
338
+ [frontend-design.md](frontend-design.md) → Color as a constrained system.
339
+
340
+ With Sass, complete the light and dark emphasis/subtle maps for an added theme color. Inspect the
341
+ utility-value maps and extend the generated utilities when the build requires it. A variable's
342
+ presence does not prove that its expected class exists. Follow
343
+ [Theming & design tokens](bootstrap-reference.md#theming--design-tokens) for import order and
344
+ extension points. Add no custom color mode without a brief that requires it.
345
+
346
+ ## Verify the result
347
+
348
+ Cross theme changes with narrow/wide layout states from [responsive-layout.md](responsive-layout.md).
349
+ Check a light page with its local dark hero, an opened mobile drawer, and any root-mounted dialog.
350
+ Do not infer their foregrounds from a desktop capture or from the theme attribute alone.
351
+
352
+ Run [Color-mode inheritance](inspection.md#color-mode-inheritance) and the applicable contrast,
353
+ target, and rendered-review checks against the loaded Bootstrap build and skin. Exercise the
354
+ existing mounted UI through every declared mode and back, including supported local scopes and
355
+ overlays.
356
+ Report actual coverage; do not claim a host application pass from documentation or a stock fixture.