Skip to content

H. Migration lists

Historical — do not copy (1A-E03): the disabled-opacity exception in this retained table is superseded below.

Site Today → measured Replacement
features/staff/panels/DashboardPanel.tsx:77–80,83,91 text-on-accent/75 (3.90), text-on-secondary/75, text-on-success/75, text-on-warn/75, text-bg/80 on danger (3.90), text-bg StatCard: a neutral panel with Outfit-600 number in text-{tone}-ink and a full-opacity label. The secondary tone becomes emphasis.
features/inventory/PublicInventoryParts.tsx:67 text-on-secondary/80 counter (4.22) text-on-brand
components/ui/StatusStepper.tsx:55 opacity-70 on fills full opacity, text-caption
features/inventory/RequestSummary.tsx:23,30 opacity-80 text-muted
features/staff/panels/OperationsReportState.tsx:74, features/stats/StatsParts.tsx:33 eyebrow opacity-70 on fills StatCard
features/inventory/ProductCard.tsx:71, ProductQuickViewModal.tsx:52 text-ink/15 decorative initials text-line + aria-hidden
styles/chrome.css .material-chrome panel @0.8 + blur delete
components.css ghost/nav hover:bg-accent/15; the .desk-shell .bg-secondary/10|15 color-mix block alpha tints hover:bg-accent-soft; bg-brand-soft; delete the color-mix block
119 bg-{tone}/NN occurrences in 58 files (12 of them hover:) alpha tints /5, /10, /15 → bg-{tone}-soft (secondary → brand-soft). bg-danger/NN → bg-panel border border-danger-line (the danger card; there is no danger-soft)
border-{tone}/20–40 (≈40) decorative allowed; border-danger/40 → border-danger-line
disabled:opacity-50 (14) WCAG-exempt allowed outside the button family

Current rule (v2.0.1, 2026-11-13): The opacity exemption above is historical. Disabled controls use explicit opaque bg-surface/text-muted/border-line states, no hover/press effects, the appropriate disabled semantics and a nearby explanation when needed. (1A-N11) — supersedes the line above; see docs/current-rules.md#cr-disabled-01.

Current example (1A-E03): explicit state and an enabling instruction; the disabled rule wins over all interaction rules.

<button class="current-disabled" type="button" disabled aria-describedby="issue-requirements">Confirm issue</button>
<p id="issue-requirements">Check all quantities and required asset scans before continuing.</p>
<style>
.current-disabled:disabled {
background: rgb(var(--color-surface)); color: rgb(var(--color-muted));
border: 1px solid rgb(var(--color-line)); opacity: 1;
transform: none; box-shadow: none; transition: none;
}
</style>

H.2 Fill tokens used as text, and undefined tokens (Codex 2)

Section titled “H.2 Fill tokens used as text, and undefined tokens (Codex 2)”
File:line Today Replacement
features/members/MemberAdmission.tsx:44, MemberArea.tsx:149, MemberReferrals.tsx:67,80, MemberVerifierPanel.tsx:20 text-success text-success-ink
features/staff/MembershipAdmissionSettings.tsx:70, panels/MachineTypesPanel.tsx:100, SetupChecklist.tsx:22, StaffBookingForm.tsx:63 text-success text-success-ink
features/members/MemberCertifications.tsx:18, MemberDashboardSections.tsx:122, features/staff/MembershipAdmissionSettings.tsx:56 text-warn text-warn-ink
features/staff/handover/IssueDialog.tsx:59 border-warn/40 bg-warn/10 text-warn border-warn bg-warn-soft text-warn-ink (5.54 light / 12.41 dark)
styles/components.css:191–192 hover:text-accent hover:text-accent-ink
features/staff/PlatformDashboardPanel.tsx (×5) text-brand (undefined today) text-accent-ink. After the rename, text-brand would otherwise become a fill used as text.
features/staff/panels/QueuesReturnRequestModal.tsx, features/staff/EvidenceRetentionPanel.tsx text-warning (undefined) text-warn-ink
features/staff/OfflineCheckInOperator.tsx, features/staff/EventStationSettings.tsx:44 border-warning bg-warning-soft text-warning-ink (undefined) border-warn bg-warn-soft text-warn-ink
text-danger (475) stays danger is text-capable (A.2)
text-info, text-secondary, text-accent-bright 0 sites —

H.3 text-bg on a danger fill → text-on-danger (9 sites)

Section titled “H.3 text-bg on a danger fill → text-on-danger (9 sites)”

components/ui/Badge.tsx:16, features/inventory/AvailabilityBadge.tsx:16, panels/machine/MachineTypeCards.tsx:24, panels/machine/SharedConsumablesSection.tsx:31, components.css .status-box-danger and .desk-button-danger, and DashboardPanel.tsx:91. The counters in StaffDock.tsx:209 and StaffDockPopover.tsx:105 become bg-emphasis text-on-emphasis; both files are removed in Phase 3. Status uses of a danger fill become the danger pill (C).

Do this as one mechanical commit before any new button variant lands.

Old New
--color-secondary, -hover, -active, -boundary --color-brand, -hover, -active, -boundary
--color-on-secondary --color-on-brand
--color-secondary-ink --color-brand-ink
--brand-tint-*-alpha removed (replaced by --color-brand-soft)
bg-secondary bg-brand
text-on-secondary text-on-brand
text-secondary-ink text-brand-ink
border-secondary border-brand
bg-secondary/10|15 bg-brand-soft
desk-button-secondary (113 / 65 files) desk-button-brand on stranger-facing surfaces; staff sites per the table below
Badge "secondary", StatTone "pink" "emphasis"
Staff/shared site using secondary today Remap (staff never takes the tenant colour)
DashboardPanel.tsx:78,88, OperationsReportState.tsx:68, stats/StatsParts.tsx:18,105, StatusStepper.tsx:6, Badge.tsx:18 emphasis / StatCard / pill tones
InventoryPanelParts.tsx:198, OperationsReportsFablab.tsx:69, forms/CustomAnswersView.tsx:5, forms/CustomFormBuilder.tsx:16 border-line bg-accent-soft
EventDrawer.tsx:61, MakerspaceLocationSettings.tsx:104, StaffDock.tsx:29,33 text-accent-ink / border-accent
components/MakerspaceMapLink.tsx:17 (shared) prop-driven: text-brand-ink on public pages, text-accent-ink on staff pages
desk-button-secondary in BillingDocumentsSettings:30, KioskStationSettings:82,83,90, AccountabilityPanel:191, DashboardMachineQueue:34, CapabilityPresetListEditor:46, MachineCreateForm:199, PoolColourSelector:192, SharedConsumablesSection:168, CardTemplateForm:153, DeliveryLogScreen:59,69, SuppressionAdmin:27 desk-button, or desk-button-primary when it is the screen’s main action
LoginPanel.tsx:100 desk-button-primary
MakerspaceThemeSettings.tsx:64 stays desk-button-brand (it previews the tenant colour)
Shared ToastHost:28, AnnouncementFeed:18, PersonalInbox:62, PaymentDocuments:39–52 desk-button (neutral)
Aspect Contract
What a tenant sets primary_color → the brand fill; optional accent_color → the seed for brand-ink. Nothing else.
Where it applies stranger-facing surfaces only: the 10 useTenantBranding callers (public inventory, item, events, event feedback, machines, bookings, self-checkout, print request, stats, MemberArea) and the Phase-5 PublicShell.
What it never touches accent, focus, emphasis, status tones, neutrals, sidebar. Staff screens contain zero brand-* classes (guard I).
Default brand = accent per mode.
Label PLAN v2 §10.1 overrides (owner rule “keep all functionality”): candidates Deep Ink, Warm Cream, white, then black (black is today’s label, kept as a functional fallback for tenant-chosen colours only).
Hover / active / soft / link ink the same rules as the product: shift away from the label; soft = strongest ≤12 % mix over panel that keeps every fixed text ≥4.55; link ink = accent_color (or the fill) mixed toward Ink (light) or Cream (dark) until ≥4.5 on 10 backgrounds. All of these are mixes with brand neutrals.
Pairs checked on-brand on brand/hover/active; brand-ink on bg, surface, panel, hover, brand-soft and the 5 softs; ink, muted and 5 fixed inks on brand-soft; boundary ≥3. The on-secondary/80 pair is removed together with its only call site.
Emitted vars (brandPaletteStyle) --color-brand, --color-on-brand, --color-brand-ink, --color-brand-hover, --color-brand-active, --color-brand-soft, --color-brand-boundary (7 keys; 8 today)
Acceptance (PLAN §10.1) Never reject a well-formed colour that today’s validator accepts. Acceptance set ⊇ today’s: if a derived pair fails, degrade the derived token (soft → panel, link ink → accent-ink, hover/active → today’s algorithm) instead of rejecting. Rejection only for malformed values. Proven by a sweep test over all 4,096 #RGB (with and without accent_color) asserting valid in both modes, plus a parity test: every colour today’s validator accepts is still accepted.

Changes the contract implies:

  • lib/brandColours.ts and theme_contrast.py move in lockstep:
    • BRAND_SURFACES is 4 per mode (A.1).
    • PRODUCT_FILL is per mode: [0,110,99] light, [87,156,144] dark.
    • BODY_TEXT is light [20,44,42], [91,104,99] and dark [255,244,232], [192,190,181].
    • FIXED_INKS holds accent-ink, success-ink, warn-ink, info-ink and danger.
    • FIXED_FILLS becomes FIXED_SOFTS (5 per mode).
    • Label candidates are ink, cream, white, then black (PLAN §10.1).
    • readBrandTokens reads brand, on-brand and the 4 surfaces.
  • MakerspaceThemeSettings:
    • Placeholder → #006e63.
    • Copy: “Leave blank to use Maker Teal. Staff screens always use the Space Works palette.”
    • Preview grounds use mode ink (#142C2A / #FFF4E8) instead of hard-coded white/black.
    • Add hover/active swatches and a brand-soft card with muted text.

A. → .code-text on Outfit (57 sites; machine strings; owner rule — no font-code/monospace family).

Kind Sites
Inputs KioskOfflineHandover:70,72, KioskOnlineScanner:26, MemberCalendarActions:83, MemberClaimRedemption:22, BillingDocumentsSettings:37, DirectLoanIssueFields:214, DirectLoanReturnModal:221, BulkImport:126, EmailTemplateEditor:180,184, MaterialCataloguePanel:34, ScanCardBox:41, ScannerPanel:190, PlatformSocialAuthPanel:91, SpacePacksPanel:43, TenantMigrationExports:107,152, TenantMigrationImports:41,162, TenantMigrationPairings:64,73,74,75,78,79, tenantMigrationUi:63
Display BorrowRequestCard:180, PublicToolScanPanel:21, ApiClientCreateCard:93, ApiClientListCard:144, ApiClientsAccessSummary:37, EventInvitesPanel:20, EventPromosPanel:24, KioskStationSettings:75, MakerspaceCustomDomainSettings:228,230,232, MemberClaimCodes:113, ModulesPanel:147, OrganizationInvitations:51, SuppressionAdmin:33, AuditLog:55, TenantMigrationDisclosure:69,76, TenantMigrationExports:128, TenantMigrationPairings:60,61,93, ResetPasswordModal:64, MemberCalendarActions:79, EmailTemplateEditor:237, OrganizationMemberships:28,29, KioskReplayDetail:18, EventOrganizers:34, OrganizedEventsPanel:85

C. → delete font-mono (30 sites; label voice). AppRoutes:37, AvailabilityCalendar:40, Badge:25, AvailabilityBadge:63, tenantMigrationUi:40, ImageUploader:190,200,217,229, ProcurementReceipts:83, WarrantySection:191, MakerspaceCustomDomainSettings:227,229,231 (→ .eyebrow), EmailTemplatesPanel:104, MachineTypePage:70 (→ .col-header), MachinesPanel:164,178, MakerspaceLocationSettings:104, DirectLoanIssueFields:172, QrTools:176, MakerspaceMapLink:17, ProductCard:126, LandingPage:156, PublicInventoryHeader:63, BorrowRequestCard:66, ArchivedPayments:46, and in CSS .eyebrow, .chip, .status-box.

B. → tabular-nums (the remaining ~143 lines; a codemod). These are counts, prices, quantities, dates, page counters, #id, card and request numbers, box codes, PINs (keep tracking-widest), versions and public codes. They include 8 inputs: EventCheckInStationPage:43, KioskStationPage:75, KioskOnlineHandover:67,74,84, PublicPrintRequestForm:173,187 and EventFormFields:60.

  • statusToneMap: issued and checked_out change danger → accent. Add every status in C.
  • The dashboard and stats tiles become StatCard: a neutral panel with the tone carried by the number (UX spec P4).
  • OperationsReportCharts marks need ≥3:1 on panel (SW-380, Design System v2.0, replaces the old ink shades). Series fills are the five bright brand colours in both themes; the mark boundary reaches 3:1 through --chart-edge (1 px edge on every filled mark, 4 px casing under 2 px lines): Deep Ink 14.75:1 on the light panel, Warm Cream 16.98:1 on the dark panel. Fills alone are 1.11 to 6.16 (light) and 2.99 to 16.53 (dark). Danger is not a series colour.
  • The PLAN’s “theme (Light/Dark/System)” in the user menu becomes Light/Dark (D11).

Current rule (v2.0.1, 2026-11-13): Retain Light / Dark / System in the user menu (SW-364, 2026-11-13); D11 and this migration instruction predate that decision. (1A-N12) — supersedes the line above; see docs/current-rules.md#cr-theme-01.