Skip to content

UI Color Guide

Universal color vocabulary for the DCS gateway web UI. Each color has one semantic meaning across the entire interface. Never reuse a color for a different meaning.

Every value in this guide is verified against the shipped stylesheets in internal/gateway/static/css/ by make lint-docs-color-guide. If you change a token in CSS, update this guide in the same commit. The lint fails on any mismatch, on tokens documented here but absent from CSS, and on semantic tokens (--state-, --io-, --cat-, --alarm-, --sfc-, --cmd- families) added to CSS but missing from this guide.

Semantic Domains

Process State (ISA-88)

Used for equipment and procedural state badges, health indicators, and success/error feedback.

Semantic CSS Variable Color Hex Usage
Active / Running / Healthy --state-running #22c55e Running state (and Starting / Restarting / Resuming transitionals), healthy health indicator, runtime ready, success toasts
Warning / Paused / Stale --state-paused #f59e0b Paused/Pausing state, degraded health, stale data, Rejected decisions
Held --state-held #f59e0b Held/Holding state (ISA-88). Same amber as paused — the badge text carries the distinction; kept as a separate token so a future re-tint is a single edit
Error / Fault / Stopped --state-stopped #ef4444 Stopped/Stopping states, procedural Aborted/Aborting state badges, Failure outcomes, runtime offline, error toasts, validation errors
Abnormal termination (Aborted) --state-aborted #ea580c Device/equipment symbol run-state for Aborted — orange, deliberately off the health red so it does not read as an active fault alarm (issue 644)
Idle / Neutral --state-idle #888888 Idle state, Resetting, initial/unknown
Complete / Finished --state-complete #60a5fa Complete state (blue, distinct from idle gray), Approved decisions, success confirmations, valid-input feedback

Aborted is colored in two places by design (#644). Procedural state badges (stateColor(), js/utils.js) keep --state-stopped (red), and the badge text distinguishes it from Stopped. The device/equipment symbol run-state map (SYMBOL_STATE_COLORS, js/symbols/renderer.js) uses the dedicated --state-aborted (orange), because a symbol painted with the reserved health red would read as a live fault. Moving procedural Aborted off the reserved token is follow-up work.

I/O Values

Used for digital input/output value display, toggle buttons, and device/equipment symbol run-state. A device on/off is a field reading with no health verdict in it (#644, see Device run-state below).

Semantic CSS Variable Color Hex Usage
Energized / On / True --io-on #22d3ee Digital output ON button, digital value display, live/real-time indicators, device symbol running/on
De-energized / Off / False --io-off #888888 Digital output OFF button, digital value display, device symbol stopped/off

--io-off matches the neutral gray (--state-idle) numerically, because de-energized is a normal operating state. An error accent would be the wrong claim for it. (--text-muted was bumped to #9a9a9a for AA contrast in issue 708 and no longer shares the value.)

Device run-state

A device/equipment run-state (a pump running, a valve open, a motor stopped) is a field reading. It is not a health verdict. A stopped pump is de-energized and still healthy. Painting it with the reserved health green/red would erode the rule that green/red mean a health verdict, exactly where operators read it most (#644). Device run-state therefore uses the neutral palette:

Run-state Token Rationale
running / on (energized) --io-on live / energized, like any digital-ON value
stopped / off (de-energized) --io-off a normal operating state (never a fault)
aborted (abnormal end) --state-aborted abnormal/attention, but not the health red

This applies to the symbol run-state map (SYMBOL_STATE_COLORS, js/symbols/renderer.js), the faceplate boolean status dot (.hmi-fp-status-dot.on), and the equipment toggle (.hmi-equip-toggle.on). Genuine health/alarm signals (.hmi-fp-status-dot.alarm, control-module health banner) keep the reserved red.

Command Buttons

All ISA-88 command buttons share a single amber: commands are operator actions that demand attention. They are never green ("go") or red ("danger"). Green and red are reserved for health semantics (rules 1–2 below).

Semantic CSS Variables Color Hex Usage
ISA-88 command (any) --cmd-start, --cmd-stop, --cmd-hold, --cmd-pause, --cmd-resume, --cmd-restart, --cmd-abort, --cmd-reset #f59e0b cmd-btn border/text, faceplate command buttons, btn-danger hover

Per-command tokens exist so an individual command could be re-tinted in one edit, but they are deliberately identical today.

Alarm Severity

Used exclusively in alarm banners, badges, and diagnostic severity indicators.

Semantic CSS Variable Color Hex Usage
Critical --alarm-critical #dc2626 Critical alarms
High --alarm-high #ea580c High severity alarms
Medium --alarm-medium #d97706 Medium severity alarms (deliberately distinct from High — issue 694)
Low --alarm-low #707070 Low severity alarms
Alarm strip wash --alarm-strip-bg rgba(245, 158, 11, 0.15) Translucent amber backdrop of the inline faceplate alarm strip
Alarm strip border --alarm-strip-border rgba(245, 158, 11, 0.45) Border of the inline faceplate alarm strip

The values intentionally coincide with the state palette (critical = stopped red, high/medium = paused amber, low = idle gray), but the tokens are separate: alarm severity is its own domain (rule 9), and the coincidence is not a contract.

NE 107 Device Health

Used exclusively for an instrument's NE 107 self-diagnosis (ADR 0043): the faceplate DEVICE HEALTH row and any device-health badge. The colors are the NAMUR-standardized vocabulary operators know from vendor device-management screens. Normal and Failure carry no dedicated tokens. They render with the reserved health pair (--state-running / --state-stopped), because a device-health verdict is precisely what that reservation exists for. The three tokens below are reserved to NE 107 surfaces only. In particular they are not substitutes for --state-aborted (abnormal termination) or --state-complete (done/released), whose meanings they deliberately avoid overloading.

Semantic CSS Variable Color Hex Usage
Check Function (C) --ne107-check #e8964a Work in progress on the device; output temporarily invalid
Out of Specification (S) --ne107-offspec #d4b842 Operating outside specified conditions
Maintenance Required (M) --ne107-maintenance #6ea8dc Reading still valid; wear demands attention

Unknown renders in the neutral muted gray with its reason text. It is an absence of a verdict. A sixth color would claim one.

Categorical Palette

Used for type/kind identification in diagrams, editors, and palettes. These colors never carry state, health, or severity meaning. They identify what something is, not how it's doing.

CSS Variable Color Hex Sample Assignments
--cat-rose #fb7185 Enterprise (hierarchy), Math blocks (FB)
--cat-lime #84cc16 Area (hierarchy), Control blocks (FB)
--cat-purple #a855f7 ProcessCell (hierarchy), UnitProcedure (proc), Comparison blocks (FB)
--cat-violet #7c3aed Unit (hierarchy), Timer blocks (FB)
--cat-pink #ec4899 Reserved for future use
--cat-teal #14b8a6 ControlModule (hierarchy), Phase (proc), I/O blocks (FB), Composite blocks (FB)
--cat-indigo #6366f1 Site (hierarchy), Operation (proc), Counter blocks (FB)

SFC Chart Progress

Used by the live Sequential Function Chart viewer (HMI Phase / Operation / UnitProcedure / Procedure / Batch drill-down). Three tiers express temporal position (future, past, present) without re-using state colors. ISA-88 nuance (Running vs Holding vs Aborting) is conveyed by the adjacent state pill alone.

CSS Variable Color Hex Usage
--sfc-active #22d3ee Active step border + in-flight TRUE transition bar (the "present" element). Defined as an alias of --io-on
--sfc-active-fill rgba(34, 211, 238, 0.12) Active step translucent fill
--sfc-history #888888 Completed step border + already-fired transition bars (the "past" trail)
--sfc-history-line #888888 Travelled wires (line weight 2.5 px distinguishes from untravelled)
--sfc-future-line #3a3a3a Untravelled wires at default 1.5 px (matches --border)

--sfc-active is declared as var(--io-on) in CSS: the active step is a live/real-time indicator, which is cyan's job (rule 5). The history grays match --state-idle and the future-line matches --border numerically. Keeping each value defined once in base.css is intentional. A future tweak (warmer history, dimmer untravelled) is then a single edit.

Diagram Surfaces

Shared node/wire palette for the FB, SFC, LD, and procedure-flow SVG diagrams and editors. Node boxes sit between --bg-card and --border in visual depth. The diagram muted gray is dimmer than --text-muted on purpose: labels on nodes compete with wire routing, a fight page text never has.

CSS Variable Color Hex Usage
--node-fill #333333 Diagram node/block fill (FB blocks, SFC steps)
--node-fill-error #5f1e1e Node fill when the network/chart is in error
--node-stroke #444444 Node borders, connector lines, flow arrows
--diagram-muted #666666 LD rails, address/category labels on nodes
--wire-data-hl #5eead4 Data-wire hover highlight (lighter --cat-teal)
--wire-event-hl #bbbbbb Event-wire hover highlight (lighter --accent)
--canvas-grid rgba(136, 136, 136, 0.05) Editor-canvas background grid pattern

Chart Series

Multi-pen line-chart palette (HMI trend, historian). Series identity only. A pen carries no state, health, or severity meaning. The set deliberately avoids the reserved health green/red (--state-running/--state-stopped) so a pen never reads as a verdict. Emerald and rose stand in for them.

CSS Variable Color Hex
--chart-1 #60a5fa
--chart-2 #f59e0b
--chart-3 #34d399
--chart-4 #fb7185
--chart-5 #a78bfa
--chart-6 #f472b6
--chart-7 #14b8a6
--chart-8 #fb923c

--chart-limit (amber) paints the high/low deviation reference lines on trend charts. It never paints a series.

I/O Rack Grays

Module-type coding for the I/O rack sketch on the controller detail page. The rack is structural and stays out of the way: lighter shades for analog, darker for digital, outputs slightly warmer.

CSS Variable Color Hex Module type
--rack-ai #909090 AI
--rack-ao #989898 AO
--rack-do #787878 DO
--rack-di #707070 DI

UI Chrome (non-semantic)

Neutral colors for layout, text, borders. No state meaning.

CSS Variable Color Hex Usage
--bg-primary #1a1a1a Main background
--bg-secondary #222222 Sidebar, topbar
--bg-card #2a2a2a Cards, modals
--bg-input #141414 Input fields
--border #3a3a3a Borders, dividers
--text-primary #e2e2e2 Primary text
--text-secondary #aaaaaa Secondary text
--text-muted #9a9a9a Muted text, data port labels
--accent-bg #555555 Button backgrounds

Rules

  1. Green (--state-running) = process active / healthy. Never use for I/O on/off, device run-state (use --io-on), command buttons, or category identification.

  2. Red (--state-stopped) = error / fault / needs attention. Procedural Aborted state badges share this red (rule 8). Never use for I/O on/off, device run-state, command buttons, neutral markers, or category identification.

  3. Amber (--state-paused) = warning / attention needed. Also used for stale data readings (data freshness IS a warning), held state, high/medium alarms, and all command buttons. Never for category identification.

  4. Held (--state-held) shares amber with paused. The badge text carries the ISA-88 distinction. It stays a separate token so held could be re-tinted in a single edit. Do not introduce a distinct held color (e.g. orange) without updating this guide and the CSS together.

  5. Cyan (--io-on) = I/O energized / live. Digital value display, toggle buttons, and live/real-time indicators. The SFC active step (--sfc-active) aliases it.

  6. Gray (--io-off) = I/O de-energized. A normal operating state (never an error). Numerically the neutral gray, but use the I/O token in I/O contexts.

  7. Blue (--state-complete) = finished. Distinct from idle gray.

  8. Aborted: red for procedural state, --state-aborted (orange) for device symbols. Procedural Aborted/Aborting badges render with --state-stopped and rely on the badge text to distinguish them from Stopped. Device/equipment symbol run-state uses the dedicated --state-aborted so an aborted symbol does not read as a live fault alarm (#644). Do not paint device run-state with the reserved health red.

  9. Alarm colors are reserved for alarm severity. Don't reuse --alarm-critical for general errors (use --state-stopped) or for category identification (use --cat-rose).

  10. Categorical colors (--cat-*) are for type identification only. They identify resource types, procedure levels, FB block categories, and port types. They never indicate state, health, severity, or data quality.

  11. Module Rack slots use neutral grays. The rack diagram is structural, and module type is conveyed by text labels alone. Slightly different gray shades provide subtle grouping (lighter for analog, darker for digital) without competing for attention with live I/O values, state badges, or alarms.

  12. Diff colors (red/green for old/new values) are an exception. The red-removed / green-added convention in audit trail field changes is universally understood and appears only in diff context.

  13. Syntax highlighting (ST editor) is a separate domain with its own palette.

  14. Always use CSS variables where possible. Canvas and SVG-string renderers cannot read CSS custom properties. There, consume brand neutrals via the generated BRAND global (js/brand-tokens.js, regenerated by make brand). For product-semantic colors (states, severities, trend series), use hex values from this guide and keep varMap / SYMBOL_STATE_COLORS objects in sync. make lint-docs-color-guide verifies this guide against the shipped CSS, and make lint-ui-tokens verifies every var() reference in the gateway static files resolves to a defined custom property. An undefined token reference is invalid at computed-value time and silently falls back to inherit/initial. The check is shell-aware (issue 694): a token only counts as defined for the shells whose <link> tags load its stylesheet, and quoted token names in JS ('--alarm-critical') are checked too, since dynamically constructed var(${...}) references are invisible to the literal scan. Similarly, make lint-js-classes verifies every class emitted in JS-generated markup resolves to a stylesheet selector or JS hook. An undefined class silently renders unstyled (colorless badges, #693).

  15. SFC chart progress (--sfc-*) is its own vocabulary. Use cyan-active / history-gray / future-dim-gray for the live chart's three-tier hierarchy. Do not paint active steps green/amber/red based on ISA-88 state. The state pill carries that nuance. Do not animate (no pulse, blink, or breathing). The lone cyan element carries the liveness cue.

Quick Reference

PROCESS STATE (how is it doing?)
  Green  #22c55e  --state-running   active / healthy
  Amber  #f59e0b  --state-paused    paused / warning / stale data
  Amber  #f59e0b  --state-held      held (ISA-88) — badge text distinguishes from paused
  Red    #ef4444  --state-stopped   stopped / error / fault / procedural aborted
  Gray   #888888  --state-idle      idle / neutral
  Blue   #60a5fa  --state-complete  complete / finished

I/O VALUE (what is its electrical state?)
  Cyan   #22d3ee  --io-on           energized / on / true / live
  Gray   #888888  --io-off          de-energized / off / false

DEVICE RUN-STATE (field reading, not a health verdict — #644)
  Cyan   #22d3ee  --io-on           running / on (energized)
  Gray   #888888  --io-off          stopped / off (de-energized)
  Orange #ea580c  --state-aborted   aborted (abnormal termination)

COMMANDS (operator actions — uniformly amber)
  Amber  #f59e0b  --cmd-start --cmd-stop --cmd-hold --cmd-pause
  Amber  #f59e0b  --cmd-resume --cmd-restart --cmd-abort --cmd-reset

CATEGORY (what kind of thing is it?)
  Rose   #fb7185  --cat-rose        Enterprise, Math blocks
  Lime   #84cc16  --cat-lime        Area, Control blocks
  Purple #a855f7  --cat-purple      ProcessCell, UnitProcedure
  Violet #7c3aed  --cat-violet      Unit, Timers
  Pink   #ec4899  --cat-pink        Reserved for future use
  Teal   #14b8a6  --cat-teal        ControlModule, Phase, I/O blocks
  Indigo #6366f1  --cat-indigo      Site, Operation, Counters

SFC CHART PROGRESS (where in the chart's timeline?)
  Cyan   #22d3ee  --sfc-active        active step / in-flight TRUE transition (present; aliases --io-on)
  Gray   #888888  --sfc-history       completed step border / fired transition bar (past)
  Gray   #888888  --sfc-history-line  travelled wires (past, 2.5 px)
  Gray   #3a3a3a  --sfc-future-line   untravelled wires (future, 1.5 px)

MODULE RACK (structural — type shown by text label, not color)
  Grays  #707070–#b0b0b0           Lighter = analog, darker = digital

ALARM SEVERITY (how urgent is it?)
  Red    #dc2626  --alarm-critical
  Orange #ea580c  --alarm-high
  Amber  #d97706  --alarm-medium
  Gray   #707070  --alarm-low