# CIM Service Suite — Design System ("Instrument") > **Scope: this is the binding visual standard for the whole suite.** Every current > and future module follows it so the unified app looks like one product. The > authoritative specification — every color token, type style, geometry value, and > component rule — is **[`Instrument Design Spec.md`](Instrument%20Design%20Spec.md)**. > This document is the working guide: where the implementation lives, how to adopt > it in a module, and the rules that keep it coherent. If a new module needs > something the system doesn't cover, **extend the theme/kit packages** — never > introduce per-module colors, fonts, or one-off styling. The mockups (`Instrument Suite (standalone).html`) are a visual reference ONLY — never pixel-measure or scrape values from them; the spec's tables are the source of truth. Rollout history: `docs/superpowers/specs/2026-06-10-instrument-design-system-rollout-design.md` (six phases, all merged — per-phase records in `docs/BACKLOG.md` BL-DS1..BL-DS-P6). ## Implementation map ``` cim_suite/core/ui/theme/ The theme layer — the only place colors/fonts/QSS live tokens.py Two theme dicts (light/dark) keyed by spec token names, + SEVERITY/STALENESS/CHART maps, Space/Radius/Metrics fonts.py Bundled IBM Plex Sans + IBM Plex Mono (OFL), loaded at startup type_styles.py The spec's named type styles as QFont factories (letter-spacing/weight included — QSS can't express tracking) stylesheet.py build_qss(...) — the entire QSS, generated from tokens manager.py current() accessor + themeChanged signal + persistence __init__.py apply_theme(app, theme=None) — fonts + QSS + Fusion base cim_suite/core/ui/kit/ The component kit (spec §5) — built once, adopted per module delegate.py InstrumentDelegate: cell kinds, §1.2 status tags, edge bars, alarm-row tint, hover edit affordance, styled editor, validation, write feedback (mark_pending/resolve), QUIET_ROLE settings_list.py SettingsList (§5.5): groups, hints, RO chips, toggles, choices summary_strip.py SummaryStrip (§5.4 footer) + the shared EDIT_HINT constant units_header.py UnitsHeaderView: microcaps header + mono units line tab_widget.py InstrumentTabWidget: §5.3 underline tabs toggle_switch.py ToggleSwitch (§5.4 boolean columns) connection_chip.py ConnectionChip (§5.2 toolbar pill) sidebar.py Sidebar (§5.7 device list) activity_log.py ActivityLogCard (§5.8) icons.py currentColor-tinted SVG icons cim_suite/core/ui/chrome/ Window chrome (spec §4): frameless TitleBar, AccentStrip, StatusFooter, ChromeDialog + message_box confirms ``` `apply_theme(app, theme=None)` is called once by the shell; it loads the saved theme choice when `theme` is omitted. Theme choice persists in the JSON config under `ui.json`. **Theme switching:** `set_theme(app, name)` regenerates and reapplies the QSS; anything that paints token colors in code must read `theme.current()` **at paint time** (delegates do this) or repaint on `manager.signals.themeChanged`. ## Rules (enforced) - **No hard-coded hex and no `setStyleSheet` outside `cim_suite/core/ui/theme/`** — `tests/core/test_design_discipline.py` fails the build otherwise. - **Fonts come from `type_styles`**, never ad-hoc `QFont(...)` — microcaps tracking and the Plex families only exist there (Qt ignores `text-transform`/tracking in QSS, so microcaps text is `.upper()` + the style's font, in code). - **Status is never color alone** (§1.2): the kit's status tags pair the dot shape with a text label; alarm rows pair the tint with the edge bar. - **One primary action per toolbar** (§5.1): the connect/disconnect verb gets `objectName="PrimaryAction"`; everything else is secondary/quiet. - **Single-click inline editing** (§5.6) via `TableTab`/the kit delegate; `Qt.ItemIsEditable` is the single source of editability. When repopulating a table from the model, run under the tab's `_loading` guard so programmatic fills don't fire phantom edits (write-storm protection — regression-tested). - Geometry/spacing from `Space`/`Radius`/`Metrics` tokens, not magic numbers. ## Component hooks | Intent | How | |---|---| | Highlighted toolbar action | tool button `objectName="PrimaryAction"` | | Brand marks in the toolbar | `QLabel` `objectName="BrandTitle"` / `"BrandTitleAccent"` | | Filled accent button | `button.setProperty("variant", "primary")` | | Footer readouts | `chrome.StatusFooter` — declarative `add_dot`/`add_field` | | Confirm/info dialogs | `chrome.message_box` submodule — `message_box.question/information/warning` (chrome-framed, breadcrumb titles) | | Grid summary footer | `TableTab.enable_summary(kit.EDIT_HINT)` + `summary.set_summary([...])` | ## For new modules — adoption checklist The worked examples are the three shipped modules; `cim_suite/modules/da07/ui/` is the most recent full adoption and `cim_suite/modules/iomodbus/ui/` shows the sidebar + activity log. Copy this checklist into the module's adoption plan: - [ ] Toolbar per spec §5.2: `← Suite` (emit `suiteRequested`; the shell wires it), brand labels + `kit.ConnectionChip` (the module feeds COM/SIM source labels), rare/risky commands behind a confirm-guarded `▾` menu (`menu.setToolTipsVisible(True)` — QMenu hides tooltips by default), primary Connect/Disconnect far right - [ ] Grid screens subclass `TableTab`; column kinds set on the delegate (`NUMERIC`/`IDENTIFIER`/`STATUS`/`TOGGLE`), units rows via `set_column_units`, header help via `set_column_help` (tooltips — never ⓘ markers) - [ ] Status columns use §1.2 status tags (`STATUS_ROLE`), full-row alarm treatment via `ALARM_ROW_ROLE` for alarm-class states only - [ ] Summary strip with `kit.EDIT_HINT` on every editable grid - [ ] Station/settings screens use `kit.SettingsList` (§5.5) with curated groups; read-only governed by the wire/protocol, never invented; toggles/choices only where the value's meaning is verified (VB6-fidelity rule) - [ ] Write feedback (§5.6): `delegate.mark_pending` on edit; `resolve` on the protocol's confirmation (echo or re-read) - [ ] No `setStyleSheet`, no hex, no ad-hoc fonts in module code (the guard test enforces it); custom paints read `theme.current()` at paint time - [ ] Spreadsheet export wired per `docs/EXPORT.md` - [ ] Status shown by color *and* text; exactly one primary action per surface ## Fonts & licensing IBM Plex Sans and IBM Plex Mono are bundled under the SIL Open Font License (`cim_suite/core/ui/theme/fonts/OFL-IBMPlex.txt`) and registered at startup via `QFontDatabase`; if the assets are missing, the theme degrades to system fonts rather than failing.