krz/domain-dig

an ios app for DNS & SSL analysis

clone: git clone https://gitbay.org/krz/domain-dig.git

eb8a0d30da0cc150e95d44bad998c13ee2defc25

unsigned

author: Christian Cleberg <hello@cleberg.net> · 2026-07-20T23:16:01Z

feat(a11y): semantic colour system (#21 phase 1)

Replaces every hard-coded colour with semantic asset colours that adapt to
light, dark, and Increase Contrast. Dark mode stays locked, so this is a
pure refactor: the audit reports the same findings before and after.

The accent is now blue rather than cyan, per the tech/DNS theme.

Why custom values rather than the system palette: every system colour
fails WCAG AA in light mode. Measured on white — systemYellow 1.51:1,
systemOrange 2.20:1, systemGreen 2.22:1, systemCyan 2.54:1, systemRed
3.55:1. All of them pass in dark mode, which is why the dark-locked app
looked fine, and why unlocking light mode was never a matter of deleting
.preferredColorScheme(.dark). Every new value clears 4.5:1 as text on its
page, its card, and its own 16% badge tint — the way AppStatusBadgeView
actually draws it.

The accent needed splitting in two. As text on a dark background it must
be light; as a fill behind a white label it must be dark. #4DA3FF reads
8.00:1 as text on black but 2.63:1 behind white text, so StatusInfo /
AccentColor cover the foreground role and AccentFill covers
.borderedProminent. AppOnAccent is the label colour for a solid fill and
flips by scheme.

Colours live in Shared/Colors.xcassets rather than the app catalog: the
Shared folder is already a synchronized group in all three targets, so
the widget and share extension pick the palette up with no project-file
surgery. AccentColor stays in the app catalog as the global tint — and is
now actually defined, having been an empty colorset that silently left
system controls rendering in stock blue while custom chrome used cyan.

Two deliberate visual changes: orange folds into StatusWarning and pink
into StatusCritical. They encoded the same severity as the colours they
now share, and both sites also carry a text label.

Audit findings drop 15 to 14, and one of the originals turned out to be
a phantom: the Inspect contrast failure was the Run button in its
disabled state, which WCAG 1.4.3 exempts. testInspectScreen now types a
domain first so the audit measures an enabled control. Findings also
carry the offending element now, so the remaining clipped-text items name
themselves ("No Portfolio Yet", "Search domains") instead of being
anonymous.
 Docs/ACCESSIBILITY.md                              |  58 ++++++++
 .../AccentColor.colorset/Contents.json             |  77 ++++++++++-
 DomainDig/BatchResultsView.swift                   |  20 +--
 DomainDig/ContentView.swift                        | 150 +++++++++++----------
 DomainDig/DashboardView.swift                      |  62 ++++-----
 DomainDig/DomainCompareView.swift                  |   4 +-
 DomainDig/DomainDig/AuditViews.swift               |  48 +++----
 DomainDig/DomainDigUI.swift                        |  42 +++---
 DomainDig/HistoryView.swift                        |  18 +--
 DomainDig/IntegrationsView.swift                   |   6 +-
 DomainDig/MonitoringView.swift                     |  28 ++--
 DomainDig/PaywallView.swift                        |   2 +-
 DomainDig/SavedDomainsView.swift                   |   6 +-
 DomainDig/ScheduledReportsView.swift               |   8 +-
 DomainDig/TimelineView.swift                       |  10 +-
 DomainDig/WatchlistView.swift                      |  46 +++----
 DomainDig/WorkflowsView.swift                      |  18 +--
 DomainDigUITests/AccessibilityAuditHarness.swift   |   8 +-
 DomainDigUITests/AccessibilityAuditTests.swift     |  15 ++-
 DomainDigWidget/DomainDigPortfolioWidget.swift     |  20 +--
 DomainDigWidget/SweepLiveActivity.swift            |  12 +-
 .../AccentFill.colorset/Contents.json              |  78 +++++++++++
 .../AppBackground.colorset/Contents.json           |  38 ++++++
 .../AppOnAccent.colorset/Contents.json             |  38 ++++++
 .../AppSeparator.colorset/Contents.json            |  78 +++++++++++
 .../AppSurface.colorset/Contents.json              |  78 +++++++++++
 .../AppSurfaceElevated.colorset/Contents.json      |  78 +++++++++++
 Shared/Colors.xcassets/Contents.json               |   6 +
 .../StatusCritical.colorset/Contents.json          |  78 +++++++++++
 .../StatusInfo.colorset/Contents.json              |  78 +++++++++++
 .../StatusNeutral.colorset/Contents.json           |  78 +++++++++++
 .../StatusPositive.colorset/Contents.json          |  78 +++++++++++
 .../StatusWarning.colorset/Contents.json           |  78 +++++++++++
 33 files changed, 1189 insertions(+), 253 deletions(-)

diff --git a/Docs/ACCESSIBILITY.md b/Docs/ACCESSIBILITY.md
index 1045df9..128bf3f 100644
--- a/Docs/ACCESSIBILITY.md
+++ b/Docs/ACCESSIBILITY.md
@@ -6,6 +6,58 @@ large Dynamic Type, element descriptions, trait correctness, and Dynamic Type
 support — the same ground the accessibility pass tracked in
 [issue #21](https://github.com/zerolabsco/domain-dig/issues/21) covers.
 
+## The colour palette
+
+Semantic colours live in `Shared/Colors.xcassets`, which is inside the `Shared`
+file-system-synchronized group and therefore reaches the app, the widget, and
+the share extension automatically. `AccentColor` stays in
+`DomainDig/Assets.xcassets` because it is the system-wide tint resolved via
+`ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME`.
+
+Use the generated asset symbols — `Color(.statusCritical)`, `Color(.appSurface)`
+— never a literal. `ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS`
+is on, so these are compile-time checked; a typo will not build.
+
+Every value clears WCAG AA (4.5:1) as text on its page, on its card, **and on
+its own 16% badge tint** — the way `AppStatusBadgeView` actually draws it. The
+worst of those three is shown:
+
+| Role | Light | Dark | Worst light | Worst dark |
+| --- | --- | --- | --- | --- |
+| `StatusInfo` / `AccentColor` | `#0000FF` | `#4DA3FF` | 5.50 | 5.85 |
+| `StatusPositive` | `#146C2E` | `#30D158` | 4.65 | 7.32 |
+| `StatusWarning` | `#7A5600` | `#FFD60A` | 4.74 | 9.61 |
+| `StatusCritical` | `#B3261E` | `#FF6961` | 4.51 | 5.54 |
+| `StatusNeutral` | `#5A5A5F` | `#A1A1A6` | 4.92 | 5.88 |
+
+High Contrast variants push further in the same direction. Surfaces
+(`AppBackground`, `AppSurface`, `AppSurfaceElevated`, `AppSeparator`) carry no
+meaning, so they get Any/Dark and, where useful, High Contrast — but no status
+semantics.
+
+Why custom values instead of the system palette: **every** system colour fails
+in light mode. Measured on white — systemYellow 1.51:1, systemOrange 2.20:1,
+systemGreen 2.22:1, systemCyan 2.54:1, systemRed 3.55:1. All of them pass in
+dark mode, which is why the dark-locked app looked fine and why unlocking light
+mode is impossible without this work.
+
+### The accent has two roles, and they conflict
+
+An accent used as **text on a dark background** must be light. The same accent
+used as a **fill behind a white label** must be dark. One value cannot do both:
+`#4DA3FF` reads at 8.00:1 as text on black, but only 2.63:1 behind white text.
+
+So there are two colours:
+
+- `StatusInfo` / `AccentColor` — the accent as *foreground*: text, icons,
+  bordered-button labels, tab bar.
+- `AccentFill` — the accent as a *filled background* behind a label, used by
+  `.borderedProminent`. Stays dark in both schemes so a white label clears AA
+  (8.59:1 light, 7.56:1 dark).
+
+`AppOnAccent` is the label colour for a solid accent fill and flips by scheme —
+white on the light accent, black on the dark one.
+
 ## Findings are reported, not enforced
 
 The audit surfaces violations that exist today, so failing on all of them would
@@ -85,6 +137,12 @@ pre-commit that blocks every commit. A hook routinely bypassed with
 
 ## Notes
 
+- **Disabled controls are a false positive.** WCAG 1.4.3 exempts inactive
+  components from contrast requirements, but the audit flags them anyway. The
+  Inspect screen's Run button is disabled until a domain is typed, and auditing
+  the empty state reported a contrast failure that was never a real defect —
+  which is why `testInspectScreen` types a domain before auditing. Watch for
+  this before "fixing" a contrast finding on a disabled control.
 - Audits retry up to three times. Slower machines can miss the audit's internal
   deadline (`Audit failed to complete in time`, code `-56`), which is a tooling
   timeout, not an app defect. A screen that still cannot be audited is reported
diff --git a/DomainDig/Assets.xcassets/AccentColor.colorset/Contents.json b/DomainDig/Assets.xcassets/AccentColor.colorset/Contents.json
index eb87897..9d1e3b9 100644
--- a/DomainDig/Assets.xcassets/AccentColor.colorset/Contents.json
+++ b/DomainDig/Assets.xcassets/AccentColor.colorset/Contents.json
@@ -1,11 +1,78 @@
 {
-  "colors" : [
+  "colors": [
     {
-      "idiom" : "universal"
+      "idiom": "universal",
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0x00",
+          "green": "0x00",
+          "blue": "0xFF",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "luminosity",
+          "value": "dark"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0x4D",
+          "green": "0xA3",
+          "blue": "0xFF",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "contrast",
+          "value": "high"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0x00",
+          "green": "0x00",
+          "blue": "0xCC",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "luminosity",
+          "value": "dark"
+        },
+        {
+          "appearance": "contrast",
+          "value": "high"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0x7F",
+          "green": "0xBF",
+          "blue": "0xFF",
+          "alpha": "1.000"
+        }
+      }
     }
   ],
-  "info" : {
-    "author" : "xcode",
-    "version" : 1
+  "info": {
+    "author": "xcode",
+    "version": 1
   }
 }
diff --git a/DomainDig/BatchResultsView.swift b/DomainDig/BatchResultsView.swift
index 027d074..afef5cb 100644
--- a/DomainDig/BatchResultsView.swift
+++ b/DomainDig/BatchResultsView.swift
@@ -13,7 +13,7 @@ struct BatchResultsView: View {
                 if viewModel.batchLookupRunning {
                     VStack(alignment: .trailing, spacing: 4) {
                         ProgressView(value: Double(viewModel.batchCompletedCount), total: Double(max(viewModel.batchTotalCount, 1)))
-                            .tint(.cyan)
+                            .tint(Color(.statusInfo))
                             .frame(width: 120)
                         Text(viewModel.batchProgressLabel)
                             .font(appDensity.font(.caption2))
@@ -110,7 +110,7 @@ struct BatchResultRowView: View {
             if let errorMessage = result.errorMessage {
                 Text(errorMessage)
                     .font(appDensity.font(.caption2))
-                    .foregroundStyle(result.status == .failed ? .red : .secondary)
+                    .foregroundStyle(result.status == .failed ? Color(.statusCritical) : .secondary)
             }
         }
         .frame(maxWidth: .infinity, alignment: .leading)
@@ -138,29 +138,29 @@ struct BatchResultRowView: View {
             title: availabilityText,
             systemImage: "exclamationmark.circle",
             foregroundColor: .secondary,
-            backgroundColor: Color(.systemGray5).opacity(0.55)
+            backgroundColor: Color(.appSurfaceElevated)
         )
     }
 
     private var quickStatusBadge: AppStatusBadgeModel {
         switch result.status {
         case .pending:
-            return .init(title: "Pending", systemImage: "clock", foregroundColor: .secondary, backgroundColor: Color(.systemGray5).opacity(0.55))
+            return .init(title: "Pending", systemImage: "clock", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated))
         case .running:
-            return .init(title: "Running", systemImage: "arrow.clockwise", foregroundColor: .cyan, backgroundColor: .cyan.opacity(0.16))
+            return .init(title: "Running", systemImage: "arrow.clockwise", foregroundColor: Color(.statusInfo), backgroundColor: Color(.statusInfo).opacity(0.16))
         case .completed:
             if result.changeClassification == .critical || result.certificateWarningLevel == .critical || result.riskLevel == .high {
-                return .init(title: "Critical", systemImage: "exclamationmark.octagon.fill", foregroundColor: .red, backgroundColor: .red.opacity(0.16))
+                return .init(title: "Critical", systemImage: "exclamationmark.octagon.fill", foregroundColor: Color(.statusCritical), backgroundColor: Color(.statusCritical).opacity(0.16))
             }
             if result.changeClassification == .warning || result.changeSeverity == .medium || result.certificateWarningLevel == .warning {
-                return .init(title: "Warning", systemImage: "exclamationmark.triangle.fill", foregroundColor: .yellow, backgroundColor: .yellow.opacity(0.16))
+                return .init(title: "Warning", systemImage: "exclamationmark.triangle.fill", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarning).opacity(0.16))
             }
             if result.quickStatus == "Changed" {
-                return .init(title: "Changed", systemImage: "arrow.triangle.2.circlepath", foregroundColor: .cyan, backgroundColor: .cyan.opacity(0.16))
+                return .init(title: "Changed", systemImage: "arrow.triangle.2.circlepath", foregroundColor: Color(.statusInfo), backgroundColor: Color(.statusInfo).opacity(0.16))
             }
-            return .init(title: "Stable", systemImage: "checkmark.circle.fill", foregroundColor: .green, backgroundColor: .green.opacity(0.16))
+            return .init(title: "Stable", systemImage: "checkmark.circle.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositive).opacity(0.16))
         case .failed:
-            return .init(title: "Failed", systemImage: "xmark.circle.fill", foregroundColor: .red, backgroundColor: .red.opacity(0.16))
+            return .init(title: "Failed", systemImage: "xmark.circle.fill", foregroundColor: Color(.statusCritical), backgroundColor: Color(.statusCritical).opacity(0.16))
         }
     }
 }
diff --git a/DomainDig/ContentView.swift b/DomainDig/ContentView.swift
index 40c97d1..7eec8a0 100644
--- a/DomainDig/ContentView.swift
+++ b/DomainDig/ContentView.swift
@@ -167,7 +167,7 @@ struct ContentView: View {
             }
             .background(
                 LinearGradient(
-                    colors: [Color.black, Color(.systemGray6).opacity(0.12)],
+                    colors: [Color(.appBackground), Color(.appSurface)],
                     startPoint: .top,
                     endPoint: .bottom
                 )
@@ -302,7 +302,7 @@ struct ContentView: View {
                     .keyboardType(.URL)
                     .padding(.horizontal, 12)
                     .padding(.vertical, appDensity.metrics.controlVerticalPadding)
-                    .background(Color(.systemGray6))
+                    .background(Color(.appSurfaceElevated))
                     .clipShape(RoundedRectangle(cornerRadius: appDensity.metrics.cardCornerRadius))
                     .focused($focusedInputField, equals: .singleDomain)
                     .onSubmit {
@@ -320,6 +320,7 @@ struct ContentView: View {
                         .frame(minHeight: appDensity.metrics.controlMinHeight)
                 }
                 .buttonStyle(.borderedProminent)
+                .tint(Color(.accentFill))
                 .disabled(viewModel.trimmedDomain.isEmpty)
             } else {
                 if FeatureAccessService.hasAccess(to: .batchOperations) {
@@ -346,7 +347,7 @@ struct ContentView: View {
                         .lineLimit(4...10)
                         .padding(.horizontal, 12)
                         .padding(.vertical, appDensity.metrics.controlVerticalPadding)
-                        .background(Color(.systemGray6))
+                        .background(Color(.appSurfaceElevated))
                         .clipShape(RoundedRectangle(cornerRadius: appDensity.metrics.cardCornerRadius))
                         .focused($focusedInputField, equals: .bulkDomains)
 
@@ -360,6 +361,7 @@ struct ContentView: View {
                                 .frame(minHeight: appDensity.metrics.controlMinHeight)
                         }
                         .buttonStyle(.borderedProminent)
+                        .tint(Color(.accentFill))
                         .disabled(viewModel.bulkInput.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || viewModel.batchLookupRunning)
                     }
                 } else {
@@ -549,7 +551,7 @@ struct ContentView: View {
                 } label: {
                     Image(systemName: viewModel.isCurrentDomainSaved ? "bookmark.fill" : "bookmark")
                         .font(appDensity.font(.body, design: .default))
-                        .foregroundStyle(viewModel.isCurrentDomainSaved ? .yellow : .secondary)
+                        .foregroundStyle(viewModel.isCurrentDomainSaved ? Color(.statusWarning) : .secondary)
                 }
                 Menu {
                     Button("Export TXT") {
@@ -671,7 +673,7 @@ struct ContentView: View {
                         .frame(maxWidth: .infinity, alignment: .leading)
                         .padding(.vertical, 8)
                         .padding(.horizontal, 10)
-                        .background(Color(.systemGray6).opacity(0.5))
+                        .background(Color(.appSurface))
                         .clipShape(RoundedRectangle(cornerRadius: appDensity.metrics.cardCornerRadius))
                 }
             }
@@ -696,7 +698,7 @@ struct ContentView: View {
         }
         .frame(maxWidth: .infinity, alignment: .leading)
         .padding(appDensity.metrics.cardPadding)
-        .background(Color(.systemGray6))
+        .background(Color(.appSurfaceElevated))
         .clipShape(RoundedRectangle(cornerRadius: appDensity.metrics.cardCornerRadius))
     }
 
@@ -792,7 +794,7 @@ struct SummaryView: View {
                     .frame(minHeight: appDensity.metrics.rowMinHeight + 12, alignment: .topLeading)
                     .frame(maxWidth: .infinity, alignment: .leading)
                     .padding(appDensity.metrics.cardPadding)
-                    .background(Color(.systemGray6).opacity(0.5))
+                    .background(Color(.appSurface))
                     .clipShape(RoundedRectangle(cornerRadius: appDensity.metrics.cardCornerRadius))
                 }
             }
@@ -851,22 +853,22 @@ struct RiskSummaryCardView: View {
     private var levelColor: Color {
         switch report.riskAssessment.level {
         case .low:
-            return .green
+            return Color(.statusPositive)
         case .medium:
-            return .yellow
+            return Color(.statusWarning)
         case .high:
-            return .red
+            return Color(.statusCritical)
         }
     }
 
     private func factorColor(_ impact: RiskImpact) -> Color {
         switch impact {
         case .positive:
-            return .green
+            return Color(.statusPositive)
         case .neutral:
             return .secondary
         case .negative:
-            return .red
+            return Color(.statusCritical)
         }
     }
 }
@@ -888,7 +890,7 @@ struct InsightsSummaryCardView: View {
                         HStack(alignment: .top, spacing: 8) {
                             Image(systemName: "chart.line.uptrend.xyaxis")
                                 .font(appDensity.font(.caption2))
-                                .foregroundStyle(.cyan)
+                                .foregroundStyle(Color(.statusInfo))
                                 .padding(.top, 2)
                             Text(insight)
                                 .font(appDensity.font(.caption))
@@ -995,13 +997,13 @@ struct LookupStatusBannerView: View {
     private var color: Color {
         switch resultSource {
         case .live:
-            return .green
+            return Color(.statusPositive)
         case .cached:
             return .secondary
         case .mixed:
-            return .yellow
+            return Color(.statusWarning)
         case .snapshot:
-            return .orange
+            return Color(.statusWarning)
         }
     }
 
@@ -1029,7 +1031,7 @@ struct DomainChangeSummaryView: View {
             HStack {
                 Label(summary.hasChanges ? "Changed" : "Stable", systemImage: summary.hasChanges ? "arrow.triangle.2.circlepath" : "checkmark.circle")
                     .font(appDensity.font(.caption))
-                    .foregroundStyle(summary.hasChanges ? severityColor(summary.severity) : .green)
+                    .foregroundStyle(summary.hasChanges ? severityColor(summary.severity) : Color(.statusPositive))
                 Spacer()
                 Text(summary.severity.title.uppercased())
                     .font(appDensity.font(.caption2))
@@ -1079,13 +1081,13 @@ struct DomainChangeSummaryView: View {
                         if let riskScoreDelta = summary.riskScoreDelta {
                             Text("Risk delta: \(riskScoreDelta >= 0 ? "+" : "")\(riskScoreDelta)")
                                 .font(appDensity.font(.caption2))
-                                .foregroundStyle(riskScoreDelta > 0 ? .orange : .secondary)
+                                .foregroundStyle(riskScoreDelta > 0 ? Color(.statusWarning) : .secondary)
                         }
 
                         if let contextNote = summary.contextNote {
                             Text(contextNote)
                                 .font(appDensity.font(.caption2))
-                                .foregroundStyle(.orange)
+                                .foregroundStyle(Color(.statusWarning))
                         }
                     }
                     .padding(.top, 4)
@@ -1101,9 +1103,9 @@ struct DomainChangeSummaryView: View {
         case .low:
             return .secondary
         case .medium:
-            return .yellow
+            return Color(.statusWarning)
         case .high:
-            return .red
+            return Color(.statusCritical)
         }
     }
 
@@ -1205,7 +1207,7 @@ struct DomainDiffView: View {
                                     }
                                 }
                                 .padding(10)
-                                .background(item.hasChanges ? changeColor(for: item).opacity(0.08) : Color(.systemGray6).opacity(0.25))
+                                .background(item.hasChanges ? changeColor(for: item).opacity(0.08) : Color(.appSurface))
                                 .cornerRadius(8)
                             }
                         } label: {
@@ -1225,7 +1227,7 @@ struct DomainDiffView: View {
                     .overlay {
                         if highlightedSectionID == section.id {
                             RoundedRectangle(cornerRadius: 12)
-                                .stroke(Color.cyan.opacity(0.55), lineWidth: 1)
+                                .stroke(Color(.statusInfo).opacity(0.55), lineWidth: 1)
                         }
                     }
                 }
@@ -1258,9 +1260,9 @@ struct DomainDiffView: View {
         case .low:
             return .blue
         case .medium:
-            return .yellow
+            return Color(.statusWarning)
         case .high:
-            return .red
+            return Color(.statusCritical)
         }
     }
 
@@ -1269,9 +1271,9 @@ struct DomainDiffView: View {
         case .low:
             return .blue
         case .medium:
-            return .yellow
+            return Color(.statusWarning)
         case .high:
-            return .red
+            return Color(.statusCritical)
         }
     }
 
@@ -1337,7 +1339,7 @@ struct DomainSectionView: View {
         CollapsibleSectionView(title: "Domain", isCollapsed: $isCollapsed) {
             if let trackedDomain {
                 HStack(spacing: 8) {
-                    AppStatusBadgeView(model: .init(title: "Tracked", systemImage: "eye.fill", foregroundColor: .green, backgroundColor: .green.opacity(0.16)))
+                    AppStatusBadgeView(model: .init(title: "Tracked", systemImage: "eye.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositive).opacity(0.16)))
                     Button {
                         onTogglePinned()
                     } label: {
@@ -1638,7 +1640,7 @@ struct IntelligenceSectionView: View {
                                         if item.isEphemeral {
                                             Text("Ephemeral")
                                                 .font(appDensity.font(.caption2))
-                                                .foregroundStyle(.yellow)
+                                                .foregroundStyle(Color(.statusWarning))
                                         }
                                     }
                                     Text("First \(item.firstSeen.formatted(date: .abbreviated, time: .omitted)) • Last \(item.lastSeen.formatted(date: .abbreviated, time: .omitted)) • Seen \(item.recurrenceCount)x")
@@ -1667,7 +1669,7 @@ struct IntelligenceSectionView: View {
         VStack(alignment: .leading, spacing: 8) {
             Text(title)
                 .font(appDensity.font(.subheadline, weight: .semibold))
-                .foregroundStyle(.cyan)
+                .foregroundStyle(Color(.statusInfo))
             content()
         }
     }
@@ -1758,7 +1760,7 @@ struct SubdomainsSectionView: View {
                             HStack {
                                 Text("\(group.label).*")
                                     .font(appDensity.font(.caption))
-                                    .foregroundStyle(.cyan)
+                                    .foregroundStyle(Color(.statusInfo))
                                 Spacer()
                                 Text("\(group.subdomains.count)")
                                     .font(appDensity.font(.caption2))
@@ -1776,10 +1778,10 @@ struct SubdomainsSectionView: View {
                             if row.isInteresting {
                                 Text("Interesting")
                                     .font(.system(.caption2, design: .monospaced))
-                                    .foregroundStyle(.yellow)
+                                    .foregroundStyle(Color(.statusWarning))
                                     .padding(.horizontal, 8)
                                     .padding(.vertical, 4)
-                                    .background(Color.yellow.opacity(0.14))
+                                    .background(Color(.statusWarning).opacity(0.14))
                                     .clipShape(Capsule())
                             }
                         }
@@ -1883,7 +1885,7 @@ struct DNSSectionView: View {
                         Text(section.title)
                             .font(.system(.subheadline, design: .monospaced))
                             .fontWeight(.semibold)
-                            .foregroundStyle(.cyan)
+                            .foregroundStyle(Color(.statusInfo))
 
                         if let message = section.message {
                             MessageRowView(text: message.text, isError: message.isError)
@@ -1910,7 +1912,7 @@ struct DNSSectionView: View {
                         Text("PTR")
                             .font(.system(.subheadline, design: .monospaced))
                             .fontWeight(.semibold)
-                            .foregroundStyle(.cyan)
+                            .foregroundStyle(Color(.statusInfo))
                         SectionTrustMetadataView(provenance: ptrProvenance, confidence: nil)
                         MessageRowView(text: ptrMessage.text, isError: ptrMessage.isError)
                     }
@@ -1920,7 +1922,7 @@ struct DNSSectionView: View {
                     HStack {
                         Text("History")
                             .font(appDensity.font(.subheadline, weight: .semibold))
-                            .foregroundStyle(.cyan)
+                            .foregroundStyle(Color(.statusInfo))
                         Spacer()
                         if let onLoadHistory, history.isEmpty, !historyLoading, !showsHistoryPlaceholder {
                             Button("Load") {
@@ -1990,7 +1992,7 @@ struct WebSectionView: View {
                 HStack {
                     Text("TLS")
                         .font(appDensity.font(.subheadline, weight: .semibold))
-                        .foregroundStyle(.cyan)
+                        .foregroundStyle(Color(.statusInfo))
                     Spacer()
                     if !sslLoading {
                         AppStatusBadgeView(model: AppStatusFactory.tls(sslInfo: sslInfo, error: sslError))
@@ -2034,7 +2036,7 @@ struct WebSectionView: View {
             CardView {
                 Text("Headers")
                     .font(appDensity.font(.subheadline, weight: .semibold))
-                    .foregroundStyle(.cyan)
+                    .foregroundStyle(Color(.statusInfo))
                 SectionTrustMetadataView(provenance: httpProvenance, confidence: nil)
                 if headersLoading {
                     ProgressView("Fetching headers…")
@@ -2052,7 +2054,7 @@ struct WebSectionView: View {
                             HStack(alignment: .top, spacing: 4) {
                                 Text(header.name + ":")
                                     .font(appDensity.font(.caption))
-                                    .foregroundStyle(header.isSecurityHeader ? .yellow : .cyan)
+                                    .foregroundStyle(header.isSecurityHeader ? Color(.statusWarning) : Color(.statusInfo))
                                 Text(header.value)
                                     .font(appDensity.font(.caption))
                                     .foregroundStyle(.primary)
@@ -2067,7 +2069,7 @@ struct WebSectionView: View {
                 HStack {
                     Text("Redirects")
                         .font(appDensity.font(.subheadline, weight: .semibold))
-                        .foregroundStyle(.cyan)
+                        .foregroundStyle(Color(.statusInfo))
                     Spacer()
                     if let finalURL {
                         AppCopyButton(value: finalURL, label: "Copy redirect URL")
@@ -2093,7 +2095,7 @@ struct WebSectionView: View {
                                 .frame(width: 16, alignment: .trailing)
                             Text(redirect.statusCode)
                                 .font(appDensity.font(.caption))
-                                .foregroundStyle(.cyan)
+                                .foregroundStyle(Color(.statusInfo))
                                 .frame(width: 36, alignment: .leading)
                             Text(redirect.url)
                                 .font(appDensity.font(.caption))
@@ -2163,7 +2165,7 @@ struct EmailSectionView: View {
                             HStack(spacing: 8) {
                                 Text(row.label)
                                     .font(appDensity.font(.caption))
-                                    .foregroundStyle(.cyan)
+                                    .foregroundStyle(Color(.statusInfo))
                                     .frame(width: 76, alignment: .leading)
                                 AppStatusBadgeView(model: emailRowBadge(row))
                             }
@@ -2186,13 +2188,13 @@ struct EmailSectionView: View {
     private func emailRowBadge(_ row: EmailRowViewData) -> AppStatusBadgeModel {
         switch row.statusTone {
         case .success:
-            return .init(title: row.status, systemImage: "checkmark.shield.fill", foregroundColor: .green, backgroundColor: .green.opacity(0.16))
+            return .init(title: row.status, systemImage: "checkmark.shield.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositive).opacity(0.16))
         case .warning:
-            return .init(title: row.status, systemImage: "shield.lefthalf.filled", foregroundColor: .yellow, backgroundColor: .yellow.opacity(0.16))
+            return .init(title: row.status, systemImage: "shield.lefthalf.filled", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarning).opacity(0.16))
         case .failure:
-            return .init(title: row.status, systemImage: "minus.circle", foregroundColor: .secondary, backgroundColor: Color(.systemGray5).opacity(0.55))
+            return .init(title: row.status, systemImage: "minus.circle", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated))
         case .primary, .secondary:
-            return .init(title: row.status, systemImage: "circle", foregroundColor: .secondary, backgroundColor: Color(.systemGray5).opacity(0.55))
+            return .init(title: row.status, systemImage: "circle", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated))
         }
     }
 }
@@ -2227,7 +2229,7 @@ struct NetworkSectionView: View {
             CardView {
                 Text("Reachability")
                     .font(appDensity.font(.subheadline, weight: .semibold))
-                    .foregroundStyle(.cyan)
+                    .foregroundStyle(Color(.statusInfo))
                 SectionTrustMetadataView(provenance: reachabilityProvenance, confidence: nil)
                 if reachabilityLoading {
                     ProgressView("Checking ports…")
@@ -2252,7 +2254,7 @@ struct NetworkSectionView: View {
             CardView(allowsHorizontalScroll: false) {
                 Text("Location")
                     .font(appDensity.font(.subheadline, weight: .semibold))
-                    .foregroundStyle(.cyan)
+                    .foregroundStyle(Color(.statusInfo))
                 SectionTrustMetadataView(provenance: geolocationProvenance, confidence: geolocationConfidence)
                 if geolocationLoading {
                     ProgressView("Looking up location…")
@@ -2284,13 +2286,13 @@ struct NetworkSectionView: View {
             CardView(allowsHorizontalScroll: false) {
                 Text("Port Scan")
                     .font(appDensity.font(.subheadline, weight: .semibold))
-                    .foregroundStyle(.cyan)
+                    .foregroundStyle(Color(.statusInfo))
                 SectionTrustMetadataView(provenance: portScanProvenance, confidence: nil)
 
                 if isCloudflareProxied {
                     Text("Domain is behind Cloudflare's proxy. Results reflect the edge, not the origin.")
                         .font(appDensity.font(.caption2))
-                        .foregroundStyle(.orange)
+                        .foregroundStyle(Color(.statusWarning))
                         .fixedSize(horizontal: false, vertical: true)
                 }
 
@@ -2314,7 +2316,7 @@ struct NetworkSectionView: View {
                             .autocorrectionDisabled()
                             .keyboardType(.numberPad)
                             .padding(10)
-                            .background(Color(.systemGray6).opacity(0.5))
+                            .background(Color(.appSurface))
                             .clipShape(RoundedRectangle(cornerRadius: appDensity.metrics.cardCornerRadius))
 
                         Button("Scan") {
@@ -2322,6 +2324,7 @@ struct NetworkSectionView: View {
                             onScanCustomPorts()
                         }
                         .buttonStyle(.borderedProminent)
+                        .tint(Color(.accentFill))
                         .disabled(customPortScanLoading)
 
                         if customPortScanLoading {
@@ -2344,13 +2347,13 @@ struct NetworkSectionView: View {
     private func reachabilityBadge(_ row: ReachabilityRowViewData) -> AppStatusBadgeModel {
         switch row.statusTone {
         case .success:
-            return .init(title: row.statusLabel, systemImage: "checkmark.circle.fill", foregroundColor: .green, backgroundColor: .green.opacity(0.16))
+            return .init(title: row.statusLabel, systemImage: "checkmark.circle.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositive).opacity(0.16))
         case .warning:
-            return .init(title: row.statusLabel, systemImage: "exclamationmark.triangle.fill", foregroundColor: .yellow, backgroundColor: .yellow.opacity(0.16))
+            return .init(title: row.statusLabel, systemImage: "exclamationmark.triangle.fill", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarning).opacity(0.16))
         case .failure:
-            return .init(title: row.statusLabel, systemImage: "xmark.circle.fill", foregroundColor: .red, backgroundColor: .red.opacity(0.16))
+            return .init(title: row.statusLabel, systemImage: "xmark.circle.fill", foregroundColor: Color(.statusCritical), backgroundColor: Color(.statusCritical).opacity(0.16))
         case .primary, .secondary:
-            return .init(title: row.statusLabel, systemImage: "circle", foregroundColor: .secondary, backgroundColor: Color(.systemGray5).opacity(0.55))
+            return .init(title: row.statusLabel, systemImage: "circle", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated))
         }
     }
 }
@@ -2395,13 +2398,13 @@ struct PortRowsView: View {
     private func portBadge(_ row: PortScanRowViewData) -> AppStatusBadgeModel {
         switch row.statusTone {
         case .success:
-            return .init(title: row.statusLabel, systemImage: "checkmark.circle.fill", foregroundColor: .green, backgroundColor: .green.opacity(0.16))
+            return .init(title: row.statusLabel, systemImage: "checkmark.circle.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositive).opacity(0.16))
         case .warning:
-            return .init(title: row.statusLabel, systemImage: "exclamationmark.triangle.fill", foregroundColor: .yellow, backgroundColor: .yellow.opacity(0.16))
+            return .init(title: row.statusLabel, systemImage: "exclamationmark.triangle.fill", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarning).opacity(0.16))
         case .failure:
-            return .init(title: row.statusLabel, systemImage: "xmark.circle.fill", foregroundColor: .red, backgroundColor: .red.opacity(0.16))
+            return .init(title: row.statusLabel, systemImage: "xmark.circle.fill", foregroundColor: Color(.statusCritical), backgroundColor: Color(.statusCritical).opacity(0.16))
         case .primary, .secondary:
-            return .init(title: row.statusLabel, systemImage: "circle", foregroundColor: .secondary, backgroundColor: Color(.systemGray5).opacity(0.55))
+            return .init(title: row.statusLabel, systemImage: "circle", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated))
         }
     }
 }
@@ -2413,7 +2416,7 @@ struct SectionTitleView: View {
     var body: some View {
         Text(title)
             .font(appDensity.font(.headline, design: .default, weight: .semibold))
-            .foregroundStyle(.white)
+            .foregroundStyle(.primary)
     }
 }
 
@@ -2442,7 +2445,7 @@ struct CardView<Content: View>: View {
         }
         .frame(maxWidth: .infinity, alignment: .leading)
         .padding(appDensity.metrics.cardPadding)
-        .background(Color(.systemGray6).opacity(0.5))
+        .background(Color(.appSurface))
         .clipShape(RoundedRectangle(cornerRadius: appDensity.metrics.cardCornerRadius))
     }
 
@@ -2484,7 +2487,7 @@ struct MessageRowView: View {
     var body: some View {
         Label(text, systemImage: isError ? "exclamationmark.triangle.fill" : "info.circle")
             .font(appDensity.font(.caption))
-            .foregroundStyle(isError ? .red : .secondary)
+            .foregroundStyle(isError ? Color(.statusCritical) : .secondary)
             .lineLimit(nil)
             .fixedSize(horizontal: false, vertical: true)
     }
@@ -2576,6 +2579,11 @@ struct LabeledValueRow: View {
     }
 }
 
+/// Maps a row's semantic tone onto the app palette.
+///
+/// See `Docs/ACCESSIBILITY.md` for the measured contrast ratios behind these
+/// colours. Never reach for a literal (`Color(.statusCritical)`, `Color(.statusWarning)`, …) — the system
+/// palette fails WCAG AA badly in light mode (systemYellow is 1.28:1 on white).
 enum ResultColors {
     static func color(for tone: ResultTone) -> Color {
         switch tone {
@@ -2584,11 +2592,11 @@ enum ResultColors {
         case .secondary:
             return .secondary
         case .success:
-            return .green
+            return Color(.statusPositive)
         case .warning:
-            return .yellow
+            return Color(.statusWarning)
         case .failure:
-            return .red
+            return Color(.statusCritical)
         }
     }
 }
@@ -2654,7 +2662,7 @@ struct SettingsView: View {
                 if let errorMessage = purchaseService.errorMessage {
                     Text(errorMessage)
                         .font(appDensity.font(.caption, design: .default))
-                        .foregroundStyle(.red)
+                        .foregroundStyle(Color(.statusCritical))
                 }
             }
 
@@ -2789,7 +2797,7 @@ private struct HistoryNetworkSettingsView: View {
                     if let customResolverError {
                         Text(customResolverError)
                             .font(appDensity.font(.caption, design: .default))
-                            .foregroundStyle(.red)
+                            .foregroundStyle(Color(.statusCritical))
                     }
                 }
             }
@@ -2871,7 +2879,7 @@ private struct CloudSyncSettingsView: View {
                 if let lastErrorMessage = cloudSyncService.lastErrorMessage {
                     Text(lastErrorMessage)
                         .font(appDensity.font(.caption, design: .default))
-                        .foregroundStyle(.red)
+                        .foregroundStyle(Color(.statusCritical))
                 }
             }
         }
@@ -2964,7 +2972,7 @@ private struct LocalAPISettingsView: View {
                                 Spacer()
                                 Text("\(log.statusCode)")
                                     .font(appDensity.font(.caption, design: .default))
-                                    .foregroundStyle(log.statusCode >= 400 ? .red : .secondary)
+                                    .foregroundStyle(log.statusCode >= 400 ? Color(.statusCritical) : .secondary)
                             }
 
                             Text(log.timestamp.formatted(date: .abbreviated, time: .standard))
@@ -3744,8 +3752,8 @@ extension ChangeImpactClassification {
     var color: Color {
         switch self {
         case .informational: return .secondary
-        case .warning: return .yellow
-        case .critical: return .red
+        case .warning: return Color(.statusWarning)
+        case .critical: return Color(.statusCritical)
         }
     }
 }
diff --git a/DomainDig/DashboardView.swift b/DomainDig/DashboardView.swift
index 398ff3e..da8d90a 100644
--- a/DomainDig/DashboardView.swift
+++ b/DomainDig/DashboardView.swift
@@ -22,20 +22,20 @@ struct DashboardView: View {
                         showsCardBackground: false
                     )
                 }
-                .listRowBackground(Color(.systemGray6).opacity(0.5))
+                .listRowBackground(Color(.appSurface))
             } else {
                 Section {
                     LazyVGrid(columns: summaryColumns, spacing: 10) {
-                        summaryCard(title: "Total Domains", value: viewModel.portfolioDashboardData.snapshot.totalDomains, filter: .all, tint: .cyan)
-                        summaryCard(title: "Healthy", value: viewModel.portfolioDashboardData.snapshot.healthyCount, filter: .healthy, tint: .green)
-                        summaryCard(title: "Warning", value: viewModel.portfolioDashboardData.snapshot.warningCount, filter: .warning, tint: .yellow)
-                        summaryCard(title: "Critical", value: viewModel.portfolioDashboardData.snapshot.criticalCount, filter: .critical, tint: .red)
-                        summaryCard(title: "Changes (24h)", value: viewModel.portfolioDashboardData.snapshot.changedLast24h, filter: .changed, tint: .orange)
-                        summaryCard(title: "Unreachable", value: viewModel.portfolioDashboardData.snapshot.unreachableCount, filter: .unreachable, tint: .pink)
+                        summaryCard(title: "Total Domains", value: viewModel.portfolioDashboardData.snapshot.totalDomains, filter: .all, tint: Color(.statusInfo))
+                        summaryCard(title: "Healthy", value: viewModel.portfolioDashboardData.snapshot.healthyCount, filter: .healthy, tint: Color(.statusPositive))
+                        summaryCard(title: "Warning", value: viewModel.portfolioDashboardData.snapshot.warningCount, filter: .warning, tint: Color(.statusWarning))
+                        summaryCard(title: "Critical", value: viewModel.portfolioDashboardData.snapshot.criticalCount, filter: .critical, tint: Color(.statusCritical))
+                        summaryCard(title: "Changes (24h)", value: viewModel.portfolioDashboardData.snapshot.changedLast24h, filter: .changed, tint: Color(.statusWarning))
+                        summaryCard(title: "Unreachable", value: viewModel.portfolioDashboardData.snapshot.unreachableCount, filter: .unreachable, tint: Color(.statusCritical))
                     }
                     .padding(.vertical, 4)
                 }
-                .listRowBackground(Color(.systemGray6).opacity(0.5))
+                .listRowBackground(Color(.appSurface))
 
                 Section("Quick Filters") {
                     ScrollView(.horizontal, showsIndicators: false) {
@@ -46,10 +46,10 @@ struct DashboardView: View {
                                 } label: {
                                     Text(filter.title)
                                         .font(appDensity.font(.caption, weight: .semibold))
-                                        .foregroundStyle(viewModel.dashboardFilter == filter ? Color.black : Color.white)
+                                        .foregroundStyle(viewModel.dashboardFilter == filter ? Color(.appOnAccent) : Color.primary)
                                         .padding(.horizontal, 12)
                                         .padding(.vertical, 8)
-                                        .background(viewModel.dashboardFilter == filter ? Color.cyan : Color(.systemGray5).opacity(0.6))
+                                        .background(viewModel.dashboardFilter == filter ? Color(.statusInfo) : Color(.appSurfaceElevated))
                                         .clipShape(Capsule())
                                 }
                                 .buttonStyle(.plain)
@@ -58,7 +58,7 @@ struct DashboardView: View {
                         .padding(.vertical, 4)
                     }
                 }
-                .listRowBackground(Color(.systemGray6).opacity(0.5))
+                .listRowBackground(Color(.appSurface))
 
                 Section("Recent Activity") {
                     if viewModel.filteredPortfolioRecentActivity.isEmpty {
@@ -76,7 +76,7 @@ struct DashboardView: View {
                         }
                     }
                 }
-                .listRowBackground(Color(.systemGray6).opacity(0.5))
+                .listRowBackground(Color(.appSurface))
 
                 Section("Attention Required") {
                     if viewModel.filteredPortfolioAttentionRequired.isEmpty {
@@ -94,7 +94,7 @@ struct DashboardView: View {
                         }
                     }
                 }
-                .listRowBackground(Color(.systemGray6).opacity(0.5))
+                .listRowBackground(Color(.appSurface))
 
                 Section("Expiring Soon") {
                     if viewModel.filteredPortfolioExpiringSoon.isEmpty {
@@ -110,7 +110,7 @@ struct DashboardView: View {
                         }
                     }
                 }
-                .listRowBackground(Color(.systemGray6).opacity(0.5))
+                .listRowBackground(Color(.appSurface))
 
                 Section("Portfolio List") {
                     if viewModel.filteredPortfolioGroups.isEmpty {
@@ -150,11 +150,11 @@ struct DashboardView: View {
                         }
                     }
                 }
-                .listRowBackground(Color(.systemGray6).opacity(0.5))
+                .listRowBackground(Color(.appSurface))
             }
         }
         .scrollContentBackground(.hidden)
-        .background(Color.black)
+        .background(Color(.appBackground))
         .navigationTitle("Dashboard")
         .searchable(text: $viewModel.dashboardSearchText, prompt: "Search portfolio")
         .toolbar {
@@ -196,7 +196,7 @@ struct DashboardView: View {
                     .foregroundStyle(.secondary)
                 Text("\(value)")
                     .font(.system(size: 28, weight: .bold, design: .rounded))
-                    .foregroundStyle(.white)
+                    .foregroundStyle(.primary)
                 HStack {
                     Circle()
                         .fill(tint)
@@ -218,13 +218,13 @@ struct DashboardView: View {
         if viewModel.dashboardFilter == filter {
             return AnyShapeStyle(
                 LinearGradient(
-                    colors: [Color.cyan.opacity(0.28), Color.cyan.opacity(0.12)],
+                    colors: [Color(.statusInfo).opacity(0.28), Color(.statusInfo).opacity(0.12)],
                     startPoint: .topLeading,
                     endPoint: .bottomTrailing
                 )
             )
         }
-        return AnyShapeStyle(Color(.systemGray5).opacity(0.45))
+        return AnyShapeStyle(Color(.appSurfaceElevated))
     }
 
     private func dashboardEmptyRow(_ message: String) -> some View {
@@ -243,15 +243,15 @@ struct DashboardView: View {
 
         if criticalCount > 0 {
             title = "\(criticalCount) critical"
-            color = .red
+            color = Color(.statusCritical)
             systemImage = "exclamationmark.octagon.fill"
         } else if warningCount > 0 {
             title = "\(warningCount) warning"
-            color = .yellow
+            color = Color(.statusWarning)
             systemImage = "exclamationmark.triangle.fill"
         } else {
             title = "Healthy"
-            color = .green
+            color = Color(.statusPositive)
             systemImage = "checkmark.circle.fill"
         }
 
@@ -297,11 +297,11 @@ private struct PortfolioActivityRow: View {
     private var iconColor: Color {
         switch item.health {
         case .healthy:
-            return .cyan
+            return Color(.statusInfo)
         case .warning:
-            return .yellow
+            return Color(.statusWarning)
         case .critical:
-            return .red
+            return Color(.statusCritical)
         }
     }
 }
@@ -332,11 +332,11 @@ private struct PortfolioAttentionRow: View {
     private var badgeModel: AppStatusBadgeModel {
         switch item.health {
         case .healthy:
-            return .init(title: "Healthy", systemImage: "checkmark.circle.fill", foregroundColor: .green, backgroundColor: .green.opacity(0.16))
+            return .init(title: "Healthy", systemImage: "checkmark.circle.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositive).opacity(0.16))
         case .warning:
-            return .init(title: "Warning", systemImage: "exclamationmark.triangle.fill", foregroundColor: .yellow, backgroundColor: .yellow.opacity(0.16))
+            return .init(title: "Warning", systemImage: "exclamationmark.triangle.fill", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarning).opacity(0.16))
         case .critical:
-            return .init(title: "Critical", systemImage: "exclamationmark.octagon.fill", foregroundColor: .red, backgroundColor: .red.opacity(0.16))
+            return .init(title: "Critical", systemImage: "exclamationmark.octagon.fill", foregroundColor: Color(.statusCritical), backgroundColor: Color(.statusCritical).opacity(0.16))
         }
     }
 }
@@ -371,11 +371,11 @@ private struct PortfolioExpiryRow: View {
     private var badgeModel: AppStatusBadgeModel {
         switch state.certificateExpiryState {
         case .none:
-            return .init(title: "Healthy", systemImage: "lock.fill", foregroundColor: .green, backgroundColor: .green.opacity(0.16))
+            return .init(title: "Healthy", systemImage: "lock.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositive).opacity(0.16))
         case .warning:
-            return .init(title: "Warning", systemImage: "exclamationmark.triangle.fill", foregroundColor: .yellow, backgroundColor: .yellow.opacity(0.16))
+            return .init(title: "Warning", systemImage: "exclamationmark.triangle.fill", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarning).opacity(0.16))
         case .critical:
-            return .init(title: "Critical", systemImage: "xmark.octagon.fill", foregroundColor: .red, backgroundColor: .red.opacity(0.16))
+            return .init(title: "Critical", systemImage: "xmark.octagon.fill", foregroundColor: Color(.statusCritical), backgroundColor: Color(.statusCritical).opacity(0.16))
         }
     }
 }
diff --git a/DomainDig/DomainCompareView.swift b/DomainDig/DomainCompareView.swift
index 96341c2..90ee5b1 100644
--- a/DomainDig/DomainCompareView.swift
+++ b/DomainDig/DomainCompareView.swift
@@ -63,11 +63,11 @@ struct DomainCompareView: View {
                         showsCardBackground: false
                     )
                 }
-                .listRowBackground(Color(.systemGray6).opacity(0.5))
+                .listRowBackground(Color(.appSurface))
             }
         }
         .scrollContentBackground(.hidden)
-        .background(Color.black)
+        .background(Color(.appBackground))
         .navigationTitle("Compare Domains")
     }
 
diff --git a/DomainDig/DomainDig/AuditViews.swift b/DomainDig/DomainDig/AuditViews.swift
index 8602bb3..df5a9a9 100644
--- a/DomainDig/DomainDig/AuditViews.swift
+++ b/DomainDig/DomainDig/AuditViews.swift
@@ -27,7 +27,7 @@ struct AuditListView: View {
                         showsCardBackground: false
                     )
                 }
-                .listRowBackground(Color(.systemGray6).opacity(0.5))
+                .listRowBackground(Color(.appSurface))
             } else {
                 Section("Audit Domains") {
                     ForEach(groupedSessions, id: \.domain) { group in
@@ -65,11 +65,11 @@ struct AuditListView: View {
                         }
                     }
                 }
-                .listRowBackground(Color(.systemGray6).opacity(0.5))
+                .listRowBackground(Color(.appSurface))
             }
         }
         .scrollContentBackground(.hidden)
-        .background(Color.black)
+        .background(Color(.appBackground))
         .navigationTitle("Audit Mode")
         .toolbar {
             if !viewModel.searchedDomain.isEmpty {
@@ -132,7 +132,7 @@ struct AuditDomainTimelineView: View {
                     }
                 }
             }
-            .listRowBackground(Color(.systemGray6).opacity(0.5))
+            .listRowBackground(Color(.appSurface))
 
             Section("Trend") {
                 ForEach(viewModel.auditTimeline(for: domain)) { point in
@@ -152,10 +152,10 @@ struct AuditDomainTimelineView: View {
                     .padding(.vertical, 2)
                 }
             }
-            .listRowBackground(Color(.systemGray6).opacity(0.5))
+            .listRowBackground(Color(.appSurface))
         }
         .scrollContentBackground(.hidden)
-        .background(Color.black)
+        .background(Color(.appBackground))
         .navigationTitle(domain)
         .toolbar {
             ToolbarItem(placement: .topBarTrailing) {
@@ -218,7 +218,7 @@ struct AuditSessionDetailView: View {
                                 .foregroundStyle(.secondary)
                         }
                     }
-                    .listRowBackground(Color(.systemGray6).opacity(0.5))
+                    .listRowBackground(Color(.appSurface))
 
                     Section("Audit Summary") {
                         LabeledContent("Findings", value: "\(session.findings.count)")
@@ -228,7 +228,7 @@ struct AuditSessionDetailView: View {
                             LabeledContent("Highest Severity", value: severity.title)
                         }
                     }
-                    .listRowBackground(Color(.systemGray6).opacity(0.5))
+                    .listRowBackground(Color(.appSurface))
 
                     Section("Reviewer Notes") {
                         TextEditor(text: $notesDraft)
@@ -240,7 +240,7 @@ struct AuditSessionDetailView: View {
                             viewModel.updateAuditNotes(notesDraft, sessionID: session.id)
                         }
                     }
-                    .listRowBackground(Color(.systemGray6).opacity(0.5))
+                    .listRowBackground(Color(.appSurface))
 
                     Section("Checklist") {
                         ForEach(session.checklist) { item in
@@ -249,7 +249,7 @@ struct AuditSessionDetailView: View {
                             } label: {
                                 HStack(alignment: .top, spacing: 10) {
                                     Image(systemName: item.isComplete ? "checkmark.circle.fill" : "circle")
-                                        .foregroundStyle(item.isComplete ? Color.green : .secondary)
+                                        .foregroundStyle(item.isComplete ? Color(.statusPositive) : .secondary)
                                     VStack(alignment: .leading, spacing: 4) {
                                         Text(item.title)
                                             .font(appDensity.font(.callout))
@@ -264,7 +264,7 @@ struct AuditSessionDetailView: View {
                             .buttonStyle(.plain)
                         }
                     }
-                    .listRowBackground(Color(.systemGray6).opacity(0.5))
+                    .listRowBackground(Color(.appSurface))
 
                     Section("Findings") {
                         if session.findings.isEmpty {
@@ -301,7 +301,7 @@ struct AuditSessionDetailView: View {
                             }
                         }
                     }
-                    .listRowBackground(Color(.systemGray6).opacity(0.5))
+                    .listRowBackground(Color(.appSurface))
 
                     Section("Evidence Snapshot") {
                         LabeledContent("Availability", value: availabilityTitle(session.evidence.report.availability))
@@ -311,7 +311,7 @@ struct AuditSessionDetailView: View {
                         LabeledContent("Reachability", value: session.evidence.report.network.reachabilitySummary)
                         LabeledContent("Registrar", value: session.evidence.report.ownership?.registrar ?? "Unavailable")
                     }
-                    .listRowBackground(Color(.systemGray6).opacity(0.5))
+                    .listRowBackground(Color(.appSurface))
 
                     if !session.evidence.historicalContext.isEmpty {
                         Section("Historical Context") {
@@ -325,7 +325,7 @@ struct AuditSessionDetailView: View {
                                 }
                             }
                         }
-                        .listRowBackground(Color(.systemGray6).opacity(0.5))
+                        .listRowBackground(Color(.appSurface))
                     }
 
                     Section("Audit Timeline") {
@@ -345,10 +345,10 @@ struct AuditSessionDetailView: View {
                             }
                         }
                     }
-                    .listRowBackground(Color(.systemGray6).opacity(0.5))
+                    .listRowBackground(Color(.appSurface))
                 }
                 .scrollContentBackground(.hidden)
-                .background(Color.black)
+                .background(Color(.appBackground))
                 .navigationTitle("Audit Session")
                 .toolbar {
                     ToolbarItemGroup(placement: .topBarTrailing) {
@@ -398,7 +398,7 @@ struct AuditSessionDetailView: View {
                 }
             } else {
                 ContentUnavailableView("Audit Session Missing", systemImage: "exclamationmark.triangle")
-                    .background(Color.black)
+                    .background(Color(.appBackground))
             }
         }
         .preferredColorScheme(.dark)
@@ -477,7 +477,7 @@ private struct AuditFindingEditorView: View {
                                 Text(area.title)
                                 Spacer()
                                 Image(systemName: selectedAreas.contains(area) ? "checkmark.circle.fill" : "circle")
-                                    .foregroundStyle(selectedAreas.contains(area) ? Color.green : .secondary)
+                                    .foregroundStyle(selectedAreas.contains(area) ? Color(.statusPositive) : .secondary)
                             }
                         }
                         .buttonStyle(.plain)
@@ -528,11 +528,11 @@ private func auditStatusBadge(_ status: AuditStatus) -> some View {
     let model: AppStatusBadgeModel
     switch status {
     case .draft:
-        model = .init(title: "Draft", systemImage: "square.and.pencil", foregroundColor: .yellow, backgroundColor: .yellow.opacity(0.16))
+        model = .init(title: "Draft", systemImage: "square.and.pencil", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarning).opacity(0.16))
     case .inReview:
-        model = .init(title: "In Review", systemImage: "doc.text.magnifyingglass", foregroundColor: .cyan, backgroundColor: .cyan.opacity(0.16))
+        model = .init(title: "In Review", systemImage: "doc.text.magnifyingglass", foregroundColor: Color(.statusInfo), backgroundColor: Color(.statusInfo).opacity(0.16))
     case .complete:
-        model = .init(title: "Complete", systemImage: "checkmark.seal.fill", foregroundColor: .green, backgroundColor: .green.opacity(0.16))
+        model = .init(title: "Complete", systemImage: "checkmark.seal.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositive).opacity(0.16))
     }
     return AppStatusBadgeView(model: model)
 }
@@ -543,11 +543,11 @@ private func findingSeverityBadge(_ severity: AuditFindingSeverity) -> some View
     case .informational:
         color = .secondary
     case .low:
-        color = .green
+        color = Color(.statusPositive)
     case .medium:
-        color = .yellow
+        color = Color(.statusWarning)
     case .high:
-        color = .red
+        color = Color(.statusCritical)
     }
     return AppStatusBadgeView(
         model: .init(
diff --git a/DomainDig/DomainDigUI.swift b/DomainDig/DomainDigUI.swift
index 272c678..9c63e73 100644
--- a/DomainDig/DomainDigUI.swift
+++ b/DomainDig/DomainDigUI.swift
@@ -92,48 +92,48 @@ enum AppStatusFactory {
     static func availability(_ status: DomainAvailabilityStatus?) -> AppStatusBadgeModel {
         switch status {
         case .available:
-            return .init(title: "Available", systemImage: "checkmark.circle.fill", foregroundColor: .green, backgroundColor: .green.opacity(0.16))
+            return .init(title: "Available", systemImage: "checkmark.circle.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositive).opacity(0.16))
         case .registered:
-            return .init(title: "Registered", systemImage: "circle.fill", foregroundColor: .yellow, backgroundColor: .yellow.opacity(0.16))
+            return .init(title: "Registered", systemImage: "circle.fill", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarning).opacity(0.16))
         case .unknown, .none:
-            return .init(title: "Unknown", systemImage: "questionmark.circle", foregroundColor: .secondary, backgroundColor: Color(.systemGray5).opacity(0.55))
+            return .init(title: "Unknown", systemImage: "questionmark.circle", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated))
         }
     }
 
     static func tls(sslInfo: SSLCertificateInfo?, error: String?) -> AppStatusBadgeModel {
         if error != nil || sslInfo == nil {
-            return .init(title: "Invalid", systemImage: "xmark.octagon.fill", foregroundColor: .red, backgroundColor: .red.opacity(0.16))
+            return .init(title: "Invalid", systemImage: "xmark.octagon.fill", foregroundColor: Color(.statusCritical), backgroundColor: Color(.statusCritical).opacity(0.16))
         }
         if let sslInfo, sslInfo.daysUntilExpiry <= 14 {
-            return .init(title: "Expiring", systemImage: "exclamationmark.triangle.fill", foregroundColor: .yellow, backgroundColor: .yellow.opacity(0.16))
+            return .init(title: "Expiring", systemImage: "exclamationmark.triangle.fill", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarning).opacity(0.16))
         }
-        return .init(title: "Valid", systemImage: "lock.fill", foregroundColor: .green, backgroundColor: .green.opacity(0.16))
+        return .init(title: "Valid", systemImage: "lock.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositive).opacity(0.16))
     }
 
     static func email(_ result: EmailSecurityResult?, error: String?) -> AppStatusBadgeModel {
         guard error == nil, let result else {
-            return .init(title: "Missing", systemImage: "minus.circle", foregroundColor: .secondary, backgroundColor: Color(.systemGray5).opacity(0.55))
+            return .init(title: "Missing", systemImage: "minus.circle", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated))
         }
 
         let foundCount = [result.spf.found, result.dmarc.found, result.dkim.found].filter { $0 }.count
         switch foundCount {
         case 3:
-            return .init(title: "Secure", systemImage: "checkmark.shield.fill", foregroundColor: .green, backgroundColor: .green.opacity(0.16))
+            return .init(title: "Secure", systemImage: "checkmark.shield.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositive).opacity(0.16))
         case 1, 2:
-            return .init(title: "Partial", systemImage: "shield.lefthalf.filled", foregroundColor: .yellow, backgroundColor: .yellow.opacity(0.16))
+            return .init(title: "Partial", systemImage: "shield.lefthalf.filled", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarning).opacity(0.16))
         default:
-            return .init(title: "Missing", systemImage: "minus.circle", foregroundColor: .secondary, backgroundColor: Color(.systemGray5).opacity(0.55))
+            return .init(title: "Missing", systemImage: "minus.circle", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated))
         }
     }
 
     static func change(_ summary: DomainChangeSummary?) -> AppStatusBadgeModel {
         guard let summary else {
-            return .init(title: "Unchanged", systemImage: "circle", foregroundColor: .secondary, backgroundColor: Color(.systemGray5).opacity(0.55))
+            return .init(title: "Unchanged", systemImage: "circle", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated))
         }
         if summary.hasChanges {
-            return .init(title: "Changed", systemImage: "arrow.triangle.2.circlepath", foregroundColor: .cyan, backgroundColor: .cyan.opacity(0.16))
+            return .init(title: "Changed", systemImage: "arrow.triangle.2.circlepath", foregroundColor: Color(.statusInfo), backgroundColor: Color(.statusInfo).opacity(0.16))
         }
-        return .init(title: "Unchanged", systemImage: "checkmark.circle", foregroundColor: .secondary, backgroundColor: Color(.systemGray5).opacity(0.55))
+        return .init(title: "Unchanged", systemImage: "checkmark.circle", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated))
     }
 }
 
@@ -184,9 +184,9 @@ struct AppCopyButton: View {
         } label: {
             Image(systemName: didCopy ? "checkmark" : "doc.on.doc")
                 .font(appDensity.font(.caption))
-                .foregroundStyle(didCopy ? Color.green : .secondary)
+                .foregroundStyle(didCopy ? Color(.statusPositive) : .secondary)
                 .frame(width: 30, height: 30)
-                .background(Color(.systemGray5).opacity(0.35))
+                .background(Color(.appSurfaceElevated))
                 .clipShape(RoundedRectangle(cornerRadius: 8))
         }
         .buttonStyle(.plain)
@@ -264,11 +264,11 @@ struct EmptyStateCardView: View {
 
             Text(suggestion)
                 .font(appDensity.font(.caption))
-                .foregroundStyle(.cyan)
+                .foregroundStyle(Color(.statusInfo))
         }
         .frame(maxWidth: .infinity, alignment: .leading)
         .padding(appDensity.metrics.cardPadding)
-        .background(showsCardBackground ? Color(.systemGray6).opacity(0.45) : Color.clear)
+        .background(showsCardBackground ? Color(.appSurface) : Color.clear)
         .clipShape(RoundedRectangle(cornerRadius: appDensity.metrics.cardCornerRadius))
     }
 }
@@ -307,7 +307,7 @@ struct CollapsibleSectionView<HeaderTrailing: View, Content: View>: View {
                     VStack(alignment: .leading, spacing: 3) {
                         Text(title)
                             .font(appDensity.font(.headline, design: .default, weight: .semibold))
-                            .foregroundStyle(.white)
+                            .foregroundStyle(.primary)
                         if let subtitle {
                             Text(subtitle)
                                 .font(appDensity.font(.caption))
@@ -346,7 +346,7 @@ struct TagChipRowView: View {
                         .font(.caption)
                         .padding(.horizontal, 10)
                         .padding(.vertical, 5)
-                        .background(Color(.systemGray5).opacity(0.6), in: Capsule())
+                        .background(Color(.appSurfaceElevated), in: Capsule())
                 }
             }
         }
@@ -380,8 +380,8 @@ struct TagFilterChipRowView: View {
                 .font(.caption)
                 .padding(.horizontal, 10)
                 .padding(.vertical, 5)
-                .background(isSelected ? Color.cyan.opacity(0.3) : Color(.systemGray5).opacity(0.6), in: Capsule())
-                .foregroundStyle(isSelected ? Color.cyan : Color.primary)
+                .background(isSelected ? Color(.statusInfo).opacity(0.3) : Color(.appSurfaceElevated), in: Capsule())
+                .foregroundStyle(isSelected ? Color(.statusInfo) : Color.primary)
         }
         .buttonStyle(.plain)
     }
diff --git a/DomainDig/HistoryView.swift b/DomainDig/HistoryView.swift
index 5350168..ffa7745 100644
--- a/DomainDig/HistoryView.swift
+++ b/DomainDig/HistoryView.swift
@@ -25,7 +25,7 @@ struct HistoryView: View {
                     systemImage: "clock.arrow.trianglehead.counterclockwise.rotate.90",
                     showsCardBackground: false
                 )
-                    .listRowBackground(Color(.systemGray6).opacity(0.5))
+                    .listRowBackground(Color(.appSurface))
             } else {
                 Section("Domains") {
                     ForEach(domainSummaries, id: \.domain) { item in
@@ -55,21 +55,21 @@ struct HistoryView: View {
                                             model: .init(
                                                 title: severity.title,
                                                 systemImage: "arrow.triangle.2.circlepath",
-                                                foregroundColor: severity == .high ? .red : .yellow,
-                                                backgroundColor: (severity == .high ? Color.red : .yellow).opacity(0.16)
+                                                foregroundColor: severity == .high ? Color(.statusCritical) : Color(.statusWarning),
+                                                backgroundColor: (severity == .high ? Color(.statusCritical) : Color(.statusWarning)).opacity(0.16)
                                             )
                                         )
                                     }
                                 }
                             }
                         }
-                        .listRowBackground(Color(.systemGray6).opacity(0.5))
+                        .listRowBackground(Color(.appSurface))
                     }
                 }
             }
         }
         .scrollContentBackground(.hidden)
-        .background(Color.black)
+        .background(Color(.appBackground))
         .navigationTitle("History")
         .searchable(text: $viewModel.timelineDomainFilter, prompt: "Search domains")
         .toolbar {
@@ -321,7 +321,7 @@ struct HistoryDetailView: View {
             .padding(.horizontal)
             .padding(.bottom, 32)
         }
-        .background(Color.black)
+        .background(Color(.appBackground))
         .navigationTitle(entry.domain)
         .toolbar {
             ToolbarItemGroup(placement: .topBarTrailing) {
@@ -390,12 +390,12 @@ struct HistoryDetailView: View {
             if let mismatchNote = viewModel.resolverMismatchNote(for: entry) {
                 Text(mismatchNote)
                     .font(appDensity.font(.caption2))
-                    .foregroundStyle(.orange)
+                    .foregroundStyle(Color(.statusWarning))
             }
             if entry.isPartialSnapshot {
                 Text("Partial snapshot: \(entry.validationIssues.joined(separator: " | "))")
                     .font(appDensity.font(.caption2))
-                    .foregroundStyle(.yellow)
+                    .foregroundStyle(Color(.statusWarning))
             }
             if let note = entry.note, !note.isEmpty {
                 Text(note)
@@ -406,7 +406,7 @@ struct HistoryDetailView: View {
         .foregroundStyle(.secondary)
         .padding(8)
         .frame(maxWidth: .infinity, alignment: .leading)
-        .background(Color(.systemGray6).opacity(0.3))
+        .background(Color(.appSurface))
         .clipShape(RoundedRectangle(cornerRadius: appDensity.metrics.cardCornerRadius))
         .padding(.vertical, 12)
     }
diff --git a/DomainDig/IntegrationsView.swift b/DomainDig/IntegrationsView.swift
index 73f511a..163d4d1 100644
--- a/DomainDig/IntegrationsView.swift
+++ b/DomainDig/IntegrationsView.swift
@@ -52,7 +52,7 @@ struct IntegrationsSettingsView: View {
                                 if !target.isEnabled {
                                     Text("Disabled")
                                         .font(.caption2)
-                                        .foregroundStyle(.orange)
+                                        .foregroundStyle(Color(.statusWarning))
                                 }
                             }
                         }
@@ -158,7 +158,7 @@ private struct IntegrationDetailView: View {
                                     .foregroundStyle(.secondary)
 
                                 if let failureReason = record.failureReason {
-                                    let failureColor: Color = record.status == .skipped ? .secondary : .red
+                                    let failureColor: Color = record.status == .skipped ? .secondary : Color(.statusCritical)
                                     Text(failureReason)
                                         .font(.caption)
                                         .foregroundStyle(failureColor)
@@ -324,7 +324,7 @@ private struct IntegrationEditorView: View {
                 Section {
                     Text(validationMessage)
                         .font(.caption)
-                        .foregroundStyle(.red)
+                        .foregroundStyle(Color(.statusCritical))
                 }
             }
         }
diff --git a/DomainDig/MonitoringView.swift b/DomainDig/MonitoringView.swift
index fc0b8ab..decad35 100644
--- a/DomainDig/MonitoringView.swift
+++ b/DomainDig/MonitoringView.swift
@@ -41,7 +41,7 @@ struct MonitoringView: View {
                 }
                 .padding(.vertical, 4)
             }
-            .listRowBackground(Color(.systemGray6).opacity(0.5))
+            .listRowBackground(Color(.appSurface))
 
             if viewModel.monitoringLogs.isEmpty {
                 Section {
@@ -53,7 +53,7 @@ struct MonitoringView: View {
                         showsCardBackground: false
                     )
                 }
-                .listRowBackground(Color(.systemGray6).opacity(0.5))
+                .listRowBackground(Color(.appSurface))
             } else {
                 Section("Recent Runs") {
                     ForEach(viewModel.monitoringLogs) { log in
@@ -78,10 +78,10 @@ struct MonitoringView: View {
                                 HStack(spacing: 8) {
                                     metricBadge(title: "\(log.domainsChecked) checked")
                                     if log.changesFound > 0 {
-                                        metricBadge(title: "\(log.changesFound) changed", tint: .orange)
+                                        metricBadge(title: "\(log.changesFound) changed", tint: Color(.statusWarning))
                                     }
                                     if log.alertsTriggered > 0 {
-                                        metricBadge(title: "\(log.alertsTriggered) alerts", tint: .red)
+                                        metricBadge(title: "\(log.alertsTriggered) alerts", tint: Color(.statusCritical))
                                     }
                                 }
                             }
@@ -89,11 +89,11 @@ struct MonitoringView: View {
                         }
                     }
                 }
-                .listRowBackground(Color(.systemGray6).opacity(0.5))
+                .listRowBackground(Color(.appSurface))
             }
         }
         .scrollContentBackground(.hidden)
-        .background(Color.black)
+        .background(Color(.appBackground))
         .navigationTitle("Monitoring")
         .preferredColorScheme(.dark)
         .onAppear {
@@ -101,7 +101,7 @@ struct MonitoringView: View {
         }
     }
 
-    private func metricBadge(title: String, tint: Color = .cyan) -> some View {
+    private func metricBadge(title: String, tint: Color = Color(.statusInfo)) -> some View {
         Text(title)
             .font(appDensity.font(.caption2))
             .foregroundStyle(tint)
@@ -133,7 +133,7 @@ struct MonitoringLogDetailView: View {
                 LabeledContent("Alerts", value: "\(log.alertsTriggered)")
                 LabeledContent("Timestamp", value: log.timestamp.formatted(date: .abbreviated, time: .shortened))
             }
-            .listRowBackground(Color(.systemGray6).opacity(0.5))
+            .listRowBackground(Color(.appSurface))
 
             Section("Domains") {
                 ForEach(log.checkedDomains) { result in
@@ -167,7 +167,7 @@ struct MonitoringLogDetailView: View {
                         if let errorMessage = result.errorMessage {
                             Text(errorMessage)
                                 .font(appDensity.font(.caption2))
-                                .foregroundStyle(.yellow)
+                                .foregroundStyle(Color(.statusWarning))
                         }
 
                         if let historyEntryID = result.historyEntryID,
@@ -181,7 +181,7 @@ struct MonitoringLogDetailView: View {
                     .padding(.vertical, 4)
                 }
             }
-            .listRowBackground(Color(.systemGray6).opacity(0.5))
+            .listRowBackground(Color(.appSurface))
 
             if !log.errors.isEmpty {
                 Section("Errors") {
@@ -191,11 +191,11 @@ struct MonitoringLogDetailView: View {
                             .foregroundStyle(.secondary)
                     }
                 }
-                .listRowBackground(Color(.systemGray6).opacity(0.5))
+                .listRowBackground(Color(.appSurface))
             }
         }
         .scrollContentBackground(.hidden)
-        .background(Color.black)
+        .background(Color(.appBackground))
         .navigationTitle("Run Details")
         .preferredColorScheme(.dark)
     }
@@ -205,9 +205,9 @@ struct MonitoringLogDetailView: View {
         case .info:
             return .secondary
         case .warning:
-            return .yellow
+            return Color(.statusWarning)
         case .critical:
-            return .red
+            return Color(.statusCritical)
         }
     }
 }
diff --git a/DomainDig/PaywallView.swift b/DomainDig/PaywallView.swift
index cad8be4..27e80ee 100644
--- a/DomainDig/PaywallView.swift
+++ b/DomainDig/PaywallView.swift
@@ -75,7 +75,7 @@ struct PaywallView: View {
                     if let errorMessage = purchaseService.errorMessage {
                         Text(errorMessage)
                             .font(appDensity.font(.caption, design: .default))
-                            .foregroundStyle(.red)
+                            .foregroundStyle(Color(.statusCritical))
                     }
                 }
 
diff --git a/DomainDig/SavedDomainsView.swift b/DomainDig/SavedDomainsView.swift
index f407d78..59dcb73 100644
--- a/DomainDig/SavedDomainsView.swift
+++ b/DomainDig/SavedDomainsView.swift
@@ -10,7 +10,7 @@ struct SavedDomainsView: View {
                 Text("No saved domains")
                     .font(.system(.callout, design: .monospaced))
                     .foregroundStyle(.secondary)
-                    .listRowBackground(Color(.systemGray6).opacity(0.5))
+                    .listRowBackground(Color(.appSurface))
             } else {
                 ForEach(viewModel.savedDomains, id: \.self) { domain in
                     Button {
@@ -22,7 +22,7 @@ struct SavedDomainsView: View {
                             .font(.system(.callout, design: .monospaced))
                             .foregroundStyle(.primary)
                     }
-                    .listRowBackground(Color(.systemGray6).opacity(0.5))
+                    .listRowBackground(Color(.appSurface))
                 }
                 .onDelete { offsets in
                     viewModel.removeSavedDomains(at: offsets)
@@ -30,7 +30,7 @@ struct SavedDomainsView: View {
             }
         }
         .scrollContentBackground(.hidden)
-        .background(Color.black)
+        .background(Color(.appBackground))
         .navigationTitle("Saved Domains")
         .toolbar {
             if !viewModel.savedDomains.isEmpty {
diff --git a/DomainDig/ScheduledReportsView.swift b/DomainDig/ScheduledReportsView.swift
index 170e02d..dffafe3 100644
--- a/DomainDig/ScheduledReportsView.swift
+++ b/DomainDig/ScheduledReportsView.swift
@@ -67,7 +67,7 @@ struct ScheduledReportsView: View {
                 }
                 .disabled(isGenerating || !FeatureAccessService.hasAccess(to: .automatedMonitoring))
             }
-            .listRowBackground(Color(.systemGray6).opacity(0.5))
+            .listRowBackground(Color(.appSurface))
 
             if logs.isEmpty {
                 Section {
@@ -79,7 +79,7 @@ struct ScheduledReportsView: View {
                         showsCardBackground: false
                     )
                 }
-                .listRowBackground(Color(.systemGray6).opacity(0.5))
+                .listRowBackground(Color(.appSurface))
             } else {
                 Section("Recent Reports") {
                     ForEach(logs) { log in
@@ -96,11 +96,11 @@ struct ScheduledReportsView: View {
                         }
                     }
                 }
-                .listRowBackground(Color(.systemGray6).opacity(0.5))
+                .listRowBackground(Color(.appSurface))
             }
         }
         .scrollContentBackground(.hidden)
-        .background(Color.black)
+        .background(Color(.appBackground))
         .navigationTitle("Scheduled Reports")
     }
 
diff --git a/DomainDig/TimelineView.swift b/DomainDig/TimelineView.swift
index 8680d15..052b088 100644
--- a/DomainDig/TimelineView.swift
+++ b/DomainDig/TimelineView.swift
@@ -45,12 +45,12 @@ struct TimelineView: View {
                             }
                         }
                     }
-                    .listRowBackground(Color(.systemGray6).opacity(0.5))
+                    .listRowBackground(Color(.appSurface))
                 }
             }
         }
         .scrollContentBackground(.hidden)
-        .background(Color.black)
+        .background(Color(.appBackground))
         .navigationTitle(domain)
         .toolbar {
             ToolbarItemGroup(placement: .topBarTrailing) {
@@ -116,8 +116,8 @@ private struct TimelineRow: View {
                         model: .init(
                             title: severity.title,
                             systemImage: "arrow.triangle.2.circlepath",
-                            foregroundColor: severity == .high ? .red : .yellow,
-                            backgroundColor: (severity == .high ? Color.red : .yellow).opacity(0.16)
+                            foregroundColor: severity == .high ? Color(.statusCritical) : Color(.statusWarning),
+                            backgroundColor: (severity == .high ? Color(.statusCritical) : Color(.statusWarning)).opacity(0.16)
                         )
                     )
                 }
@@ -203,7 +203,7 @@ struct TimelineDiffView: View {
                 }
                 .padding()
             }
-            .background(Color.black)
+            .background(Color(.appBackground))
             .navigationTitle("Compare Snapshots")
             .navigationBarTitleDisplayMode(.inline)
             .onAppear {
diff --git a/DomainDig/WatchlistView.swift b/DomainDig/WatchlistView.swift
index 389ae91..5c5609e 100644
--- a/DomainDig/WatchlistView.swift
+++ b/DomainDig/WatchlistView.swift
@@ -38,7 +38,7 @@ struct WatchlistView: View {
                 Section("Refresh Progress") {
                     VStack(alignment: .leading, spacing: 8) {
                         ProgressView(value: Double(viewModel.batchCompletedCount), total: Double(max(viewModel.batchTotalCount, 1)))
-                            .tint(.cyan)
+                            .tint(Color(.statusInfo))
                         HStack {
                             Text(viewModel.batchProgressLabel)
                                 .font(appDensity.font(.caption))
@@ -59,7 +59,7 @@ struct WatchlistView: View {
                     }
                     .padding(.vertical, 4)
                 }
-                .listRowBackground(Color(.systemGray6).opacity(0.5))
+                .listRowBackground(Color(.appSurface))
             }
 
             if viewModel.filteredTrackedDomains.isEmpty {
@@ -72,7 +72,7 @@ struct WatchlistView: View {
                         showsCardBackground: false
                     )
                 }
-                .listRowBackground(Color(.systemGray6).opacity(0.5))
+                .listRowBackground(Color(.appSurface))
             } else {
                 if let limitMessage = FeatureAccessService.trackedDomainLimitMessage(currentCount: viewModel.trackedDomains.count) {
                     Section {
@@ -80,7 +80,7 @@ struct WatchlistView: View {
                             .font(appDensity.font(.caption))
                             .foregroundStyle(.secondary)
                     }
-                    .listRowBackground(Color(.systemGray6).opacity(0.5))
+                    .listRowBackground(Color(.appSurface))
                 }
 
                 if !pinnedDomains.isEmpty {
@@ -94,7 +94,7 @@ struct WatchlistView: View {
         }
         .animation(.easeInOut(duration: 0.2), value: viewModel.filteredTrackedDomains.map(\.id))
         .scrollContentBackground(.hidden)
-        .background(Color.black)
+        .background(Color(.appBackground))
         .navigationTitle("Watchlist")
         .searchable(text: $viewModel.watchlistSearchText, prompt: "Search tracked domains")
         .toolbar {
@@ -215,7 +215,7 @@ struct WatchlistView: View {
                         Section {
                             Text(addDomainError)
                                 .font(appDensity.font(.caption))
-                                .foregroundStyle(.red)
+                                .foregroundStyle(Color(.statusCritical))
                         }
                     }
                 }
@@ -317,14 +317,14 @@ struct WatchlistView: View {
             } label: {
                 Label("Refresh", systemImage: "arrow.clockwise")
             }
-            .tint(.cyan)
+            .tint(Color(.statusInfo))
 
             Button {
                 viewModel.togglePinned(for: trackedDomain)
             } label: {
                 Label(trackedDomain.isPinned ? "Unpin" : "Pin", systemImage: trackedDomain.isPinned ? "pin.slash" : "pin")
             }
-            .tint(.yellow)
+            .tint(Color(.statusWarning))
         }
         .swipeActions(edge: .trailing, allowsFullSwipe: false) {
             Button {
@@ -333,7 +333,7 @@ struct WatchlistView: View {
             } label: {
                 Label("Refresh", systemImage: "arrow.clockwise")
             }
-            .tint(.cyan)
+            .tint(Color(.statusInfo))
 
             if viewModel.canDelete(trackedDomain) {
                 Button(role: .destructive) {
@@ -380,7 +380,7 @@ struct WatchlistView: View {
                 }
             }
         }
-        .listRowBackground(Color(.systemGray6).opacity(0.5))
+        .listRowBackground(Color(.appSurface))
     }
 
     private var batchSummaryBinding: Binding<BatchSweepSummary?> {
@@ -437,7 +437,7 @@ struct WatchlistRowView: View {
                 if trackedDomain.isPinned {
                     Image(systemName: "pin.fill")
                         .font(.caption2)
-                        .foregroundStyle(.yellow)
+                        .foregroundStyle(Color(.statusWarning))
                 }
                 Text(trackedDomain.domain)
                     .font(appDensity.font(.callout))
@@ -502,7 +502,7 @@ struct WatchlistRowView: View {
     @ViewBuilder
     private var statusBadge: some View {
         if isRefreshing {
-            AppStatusBadgeView(model: .init(title: "Refreshing", systemImage: "arrow.clockwise", foregroundColor: .secondary, backgroundColor: Color(.systemGray5).opacity(0.6)))
+            AppStatusBadgeView(model: .init(title: "Refreshing", systemImage: "arrow.clockwise", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated)))
         } else {
             AppStatusBadgeView(model: AppStatusFactory.availability(trackedDomain.lastKnownAvailability))
         }
@@ -516,8 +516,8 @@ struct WatchlistRowView: View {
                     model: .init(
                         title: "Shared",
                         systemImage: "person.2.fill",
-                        foregroundColor: .cyan,
-                        backgroundColor: .cyan.opacity(0.16)
+                        foregroundColor: Color(.statusInfo),
+                        backgroundColor: Color(.statusInfo).opacity(0.16)
                     )
                 )
             }
@@ -534,11 +534,11 @@ struct WatchlistRowView: View {
         let days = trackedDomain.certificateDaysRemaining.map { "\($0)d" } ?? "Soon"
         switch trackedDomain.certificateWarningLevel {
         case .critical:
-            return .init(title: "Invalid \(days)", systemImage: "xmark.octagon.fill", foregroundColor: .red, backgroundColor: .red.opacity(0.16))
+            return .init(title: "Invalid \(days)", systemImage: "xmark.octagon.fill", foregroundColor: Color(.statusCritical), backgroundColor: Color(.statusCritical).opacity(0.16))
         case .warning:
-            return .init(title: "Expiring \(days)", systemImage: "exclamationmark.triangle.fill", foregroundColor: .yellow, backgroundColor: .yellow.opacity(0.16))
+            return .init(title: "Expiring \(days)", systemImage: "exclamationmark.triangle.fill", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarning).opacity(0.16))
         case .none:
-            return .init(title: "Valid", systemImage: "lock.fill", foregroundColor: .green, backgroundColor: .green.opacity(0.16))
+            return .init(title: "Valid", systemImage: "lock.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositive).opacity(0.16))
         }
     }
 }
@@ -577,7 +577,7 @@ struct TrackedDomainDetailView: View {
                     isRefreshing: viewModel.refreshingTrackedDomainID == liveTrackedDomain.id
                 )
             }
-            .listRowBackground(Color(.systemGray6).opacity(0.5))
+            .listRowBackground(Color(.appSurface))
 
             Section {
                 Button {
@@ -652,13 +652,13 @@ struct TrackedDomainDetailView: View {
                     Label(liveTrackedDomain.collaboration?.isShared == true ? "Manage Share" : "Share Domain", systemImage: "person.2")
                 }
             }
-            .listRowBackground(Color(.systemGray6).opacity(0.5))
+            .listRowBackground(Color(.appSurface))
 
             if !liveTrackedDomain.tags.isEmpty {
                 Section("Tags") {
                     TagChipRowView(tags: liveTrackedDomain.tags)
                 }
-                .listRowBackground(Color(.systemGray6).opacity(0.5))
+                .listRowBackground(Color(.appSurface))
             }
 
             Section("Monitoring Status") {
@@ -672,7 +672,7 @@ struct TrackedDomainDetailView: View {
                     LabeledContent("Queued Alerts", value: "\(liveTrackedDomain.pendingMonitoringAlerts.count)")
                 }
             }
-            .listRowBackground(Color(.systemGray6).opacity(0.5))
+            .listRowBackground(Color(.appSurface))
 
             if let summary = viewModel.latestChangeSummary(for: liveTrackedDomain) {
                 Section("Latest Change Summary") {
@@ -718,10 +718,10 @@ struct TrackedDomainDetailView: View {
                     }
                 }
             }
-            .listRowBackground(Color(.systemGray6).opacity(0.5))
+            .listRowBackground(Color(.appSurface))
         }
         .scrollContentBackground(.hidden)
-        .background(Color.black)
+        .background(Color(.appBackground))
         .navigationTitle(liveTrackedDomain.domain)
         .preferredColorScheme(.dark)
         .onChange(of: viewModel.rerunNavigationToken) { _, _ in
diff --git a/DomainDig/WorkflowsView.swift b/DomainDig/WorkflowsView.swift
index ce889fb..2195af5 100644
--- a/DomainDig/WorkflowsView.swift
+++ b/DomainDig/WorkflowsView.swift
@@ -24,13 +24,13 @@ struct WorkflowsView: View {
                         .font(appDensity.font(.caption))
                         .foregroundStyle(.secondary)
                 }
-                .listRowBackground(Color(.systemGray6).opacity(0.5))
+                .listRowBackground(Color(.appSurface))
             }
 
             workflowContent
         }
         .scrollContentBackground(.hidden)
-        .background(Color.black)
+        .background(Color(.appBackground))
         .refreshable {
             await viewModel.refreshWorkflowList()
         }
@@ -73,7 +73,7 @@ struct WorkflowsView: View {
                         value: Double(viewModel.batchCompletedCount),
                         total: Double(max(viewModel.batchTotalCount, 1))
                     )
-                    .tint(.cyan)
+                    .tint(Color(.statusInfo))
 
                     HStack {
                         Text(viewModel.batchProgressLabel)
@@ -91,7 +91,7 @@ struct WorkflowsView: View {
                 }
                 .padding(.vertical, 4)
             }
-            .listRowBackground(Color(.systemGray6).opacity(0.5))
+            .listRowBackground(Color(.appSurface))
         }
 
         if viewModel.workflows.isEmpty {
@@ -104,7 +104,7 @@ struct WorkflowsView: View {
                     showsCardBackground: false
                 )
             }
-            .listRowBackground(Color(.systemGray6).opacity(0.5))
+            .listRowBackground(Color(.appSurface))
         } else {
             ForEach(viewModel.workflows) { workflow in
                 NavigationLink {
@@ -112,7 +112,7 @@ struct WorkflowsView: View {
                 } label: {
                     WorkflowRowView(workflow: workflow)
                 }
-                .listRowBackground(Color(.systemGray6).opacity(0.5))
+                .listRowBackground(Color(.appSurface))
             }
             .onDelete { offsets in
                 let workflows = offsets.map { viewModel.workflows[$0] }
@@ -133,7 +133,7 @@ private struct WorkflowRowView: View {
                 if workflow.collaboration?.isShared == true {
                     Image(systemName: "person.2.fill")
                         .font(.caption2)
-                        .foregroundStyle(.cyan)
+                        .foregroundStyle(Color(.statusInfo))
                 }
                 Text(workflow.name)
                     .font(appDensity.font(.callout, design: .default, weight: .semibold))
@@ -335,7 +335,7 @@ struct WorkflowDetailView: View {
                     }
                 }
                 .scrollContentBackground(.hidden)
-                .background(Color.black)
+                .background(Color(.appBackground))
                 .navigationTitle(workflow.name)
                 .toolbar {
                     if !workflow.domains.isEmpty {
@@ -640,7 +640,7 @@ struct WorkflowBulkAddSheet: View {
                                     .foregroundStyle(.primary)
                                 Spacer()
                                 Image(systemName: selectedDomains.contains(domain) ? "checkmark.circle.fill" : "circle")
-                                    .foregroundStyle(selectedDomains.contains(domain) ? .cyan : .secondary)
+                                    .foregroundStyle(selectedDomains.contains(domain) ? Color(.statusInfo) : .secondary)
                             }
                         }
                         .buttonStyle(.plain)
diff --git a/DomainDigUITests/AccessibilityAuditHarness.swift b/DomainDigUITests/AccessibilityAuditHarness.swift
index 9767d95..ca4d12b 100644
--- a/DomainDigUITests/AccessibilityAuditHarness.swift
+++ b/DomainDigUITests/AccessibilityAuditHarness.swift
@@ -87,7 +87,13 @@ enum AccessibilityAuditHarness {
                 try app.performAccessibilityAudit { issue in
                     let isEnforced = !enforcedAuditTypes.intersection(issue.auditType).isEmpty
                     let marker = isEnforced ? "FAIL" : "report"
-                    findings.append("[\(marker)][\(name(for: issue.auditType))] \(issue.compactDescription)")
+                    // Include the element so the burndown says *what* to fix, not
+                    // just that something is wrong.
+                    let element = issue.element.map { el -> String in
+                        let label = el.label.isEmpty ? el.identifier : el.label
+                        return label.isEmpty ? "\(el.elementType)" : "\"\(label)\""
+                    } ?? "unknown element"
+                    findings.append("[\(marker)][\(name(for: issue.auditType))] \(issue.compactDescription) — \(element)")
                     // true suppresses the finding, false reports it as a test failure.
                     return !isEnforced
                 }
diff --git a/DomainDigUITests/AccessibilityAuditTests.swift b/DomainDigUITests/AccessibilityAuditTests.swift
index 6a90bac..63ae584 100644
--- a/DomainDigUITests/AccessibilityAuditTests.swift
+++ b/DomainDigUITests/AccessibilityAuditTests.swift
@@ -17,7 +17,20 @@ final class AccessibilityAuditTests: XCTestCase {
     // MARK: Per-screen audits
 
     func testInspectScreen() throws {
-        try auditRootTab("Inspect")
+        let app = AccessibilityAuditHarness.launch()
+        app.selectRootTab("Inspect")
+
+        // Type a domain so the Run button is enabled. A disabled control has no
+        // contrast requirement under WCAG 1.4.3, but the audit still flags it,
+        // so auditing the empty state would report a false positive forever.
+        let field = app.textFields.firstMatch
+        if field.waitForExistence(timeout: 5) {
+            field.tap()
+            field.typeText("example.com")
+        }
+
+        let audited = try AccessibilityAuditHarness.audit(app, screen: "inspect", test: self)
+        try XCTSkipUnless(audited, "Audit did not complete in time for Inspect")
     }
 
     func testDashboardScreen() throws {
diff --git a/DomainDigWidget/DomainDigPortfolioWidget.swift b/DomainDigWidget/DomainDigPortfolioWidget.swift
index bc88ac0..a3335c8 100644
--- a/DomainDigWidget/DomainDigPortfolioWidget.swift
+++ b/DomainDigWidget/DomainDigPortfolioWidget.swift
@@ -91,9 +91,9 @@ struct DomainDigWidgetView: View {
             Spacer(minLength: 0)
 
             HStack(spacing: 10) {
-                countPill(data.healthyCount, .green)
-                countPill(data.warningCount, .orange)
-                countPill(data.criticalCount, .red)
+                countPill(data.healthyCount, Color(.statusPositive))
+                countPill(data.warningCount, Color(.statusWarning))
+                countPill(data.criticalCount, Color(.statusCritical))
             }
         }
     }
@@ -121,10 +121,10 @@ struct DomainDigWidgetView: View {
             }
 
             HStack(spacing: 12) {
-                summaryStat(data.healthyCount, "Healthy", .green)
-                summaryStat(data.warningCount, "Warning", .orange)
-                summaryStat(data.criticalCount, "Critical", .red)
-                summaryStat(data.expiringSoonCount, "Expiring", .yellow)
+                summaryStat(data.healthyCount, "Healthy", Color(.statusPositive))
+                summaryStat(data.warningCount, "Warning", Color(.statusWarning))
+                summaryStat(data.criticalCount, "Critical", Color(.statusCritical))
+                summaryStat(data.expiringSoonCount, "Expiring", Color(.statusWarning))
             }
 
             Divider()
@@ -180,9 +180,9 @@ struct DomainDigWidgetView: View {
 
     private func color(for status: DomainDigWidgetStatus) -> Color {
         switch status {
-        case .healthy: return .green
-        case .warning: return .orange
-        case .critical: return .red
+        case .healthy: return Color(.statusPositive)
+        case .warning: return Color(.statusWarning)
+        case .critical: return Color(.statusCritical)
         }
     }
 }
diff --git a/DomainDigWidget/SweepLiveActivity.swift b/DomainDigWidget/SweepLiveActivity.swift
index b99a070..b96f8bf 100644
--- a/DomainDigWidget/SweepLiveActivity.swift
+++ b/DomainDigWidget/SweepLiveActivity.swift
@@ -24,7 +24,7 @@ struct SweepLiveActivity: Widget {
                 DynamicIslandExpandedRegion(.bottom) {
                     VStack(alignment: .leading, spacing: 4) {
                         ProgressView(value: context.state.fractionComplete)
-                            .tint(.cyan)
+                            .tint(Color(.statusInfo))
                         if let current = context.state.currentDomain {
                             Text(current)
                                 .font(.caption2)
@@ -35,7 +35,7 @@ struct SweepLiveActivity: Widget {
                 }
             } compactLeading: {
                 Image(systemName: "arrow.trianglehead.2.clockwise")
-                    .foregroundStyle(.cyan)
+                    .foregroundStyle(Color(.statusInfo))
             } compactTrailing: {
                 Text("\(context.state.completed)/\(context.state.total)")
                     .font(.caption2)
@@ -43,7 +43,7 @@ struct SweepLiveActivity: Widget {
             } minimal: {
                 ProgressView(value: context.state.fractionComplete)
                     .progressViewStyle(.circular)
-                    .tint(.cyan)
+                    .tint(Color(.statusInfo))
             }
         }
     }
@@ -66,7 +66,7 @@ private struct SweepActivityBannerView: View {
             }
 
             ProgressView(value: context.state.fractionComplete)
-                .tint(.cyan)
+                .tint(Color(.statusInfo))
 
             HStack {
                 if let current = context.state.currentDomain {
@@ -83,12 +83,12 @@ private struct SweepActivityBannerView: View {
                 if context.state.changed > 0 {
                     Text("\(context.state.changed) changed")
                         .font(.caption2)
-                        .foregroundStyle(.orange)
+                        .foregroundStyle(Color(.statusWarning))
                 }
                 if context.state.warnings > 0 {
                     Text("\(context.state.warnings) warnings")
                         .font(.caption2)
-                        .foregroundStyle(.red)
+                        .foregroundStyle(Color(.statusCritical))
                 }
             }
         }
diff --git a/Shared/Colors.xcassets/AccentFill.colorset/Contents.json b/Shared/Colors.xcassets/AccentFill.colorset/Contents.json
new file mode 100644
index 0000000..ae20bb8
--- /dev/null
+++ b/Shared/Colors.xcassets/AccentFill.colorset/Contents.json
@@ -0,0 +1,78 @@
+{
+  "colors": [
+    {
+      "idiom": "universal",
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0x00",
+          "green": "0x00",
+          "blue": "0xFF",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "luminosity",
+          "value": "dark"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0x00",
+          "green": "0x40",
+          "blue": "0xDD",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "contrast",
+          "value": "high"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0x00",
+          "green": "0x00",
+          "blue": "0xCC",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "luminosity",
+          "value": "dark"
+        },
+        {
+          "appearance": "contrast",
+          "value": "high"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0x00",
+          "green": "0x33",
+          "blue": "0xCC",
+          "alpha": "1.000"
+        }
+      }
+    }
+  ],
+  "info": {
+    "author": "xcode",
+    "version": 1
+  }
+}
diff --git a/Shared/Colors.xcassets/AppBackground.colorset/Contents.json b/Shared/Colors.xcassets/AppBackground.colorset/Contents.json
new file mode 100644
index 0000000..ac109ac
--- /dev/null
+++ b/Shared/Colors.xcassets/AppBackground.colorset/Contents.json
@@ -0,0 +1,38 @@
+{
+  "colors": [
+    {
+      "idiom": "universal",
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0xFF",
+          "green": "0xFF",
+          "blue": "0xFF",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "luminosity",
+          "value": "dark"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0x00",
+          "green": "0x00",
+          "blue": "0x00",
+          "alpha": "1.000"
+        }
+      }
+    }
+  ],
+  "info": {
+    "author": "xcode",
+    "version": 1
+  }
+}
diff --git a/Shared/Colors.xcassets/AppOnAccent.colorset/Contents.json b/Shared/Colors.xcassets/AppOnAccent.colorset/Contents.json
new file mode 100644
index 0000000..ac109ac
--- /dev/null
+++ b/Shared/Colors.xcassets/AppOnAccent.colorset/Contents.json
@@ -0,0 +1,38 @@
+{
+  "colors": [
+    {
+      "idiom": "universal",
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0xFF",
+          "green": "0xFF",
+          "blue": "0xFF",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "luminosity",
+          "value": "dark"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0x00",
+          "green": "0x00",
+          "blue": "0x00",
+          "alpha": "1.000"
+        }
+      }
+    }
+  ],
+  "info": {
+    "author": "xcode",
+    "version": 1
+  }
+}
diff --git a/Shared/Colors.xcassets/AppSeparator.colorset/Contents.json b/Shared/Colors.xcassets/AppSeparator.colorset/Contents.json
new file mode 100644
index 0000000..3f5960a
--- /dev/null
+++ b/Shared/Colors.xcassets/AppSeparator.colorset/Contents.json
@@ -0,0 +1,78 @@
+{
+  "colors": [
+    {
+      "idiom": "universal",
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0xC6",
+          "green": "0xC6",
+          "blue": "0xC8",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "luminosity",
+          "value": "dark"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0x38",
+          "green": "0x38",
+          "blue": "0x3A",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "contrast",
+          "value": "high"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0xA0",
+          "green": "0xA0",
+          "blue": "0xA3",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "luminosity",
+          "value": "dark"
+        },
+        {
+          "appearance": "contrast",
+          "value": "high"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0x54",
+          "green": "0x54",
+          "blue": "0x56",
+          "alpha": "1.000"
+        }
+      }
+    }
+  ],
+  "info": {
+    "author": "xcode",
+    "version": 1
+  }
+}
diff --git a/Shared/Colors.xcassets/AppSurface.colorset/Contents.json b/Shared/Colors.xcassets/AppSurface.colorset/Contents.json
new file mode 100644
index 0000000..94ae3c7
--- /dev/null
+++ b/Shared/Colors.xcassets/AppSurface.colorset/Contents.json
@@ -0,0 +1,78 @@
+{
+  "colors": [
+    {
+      "idiom": "universal",
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0xF2",
+          "green": "0xF2",
+          "blue": "0xF7",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "luminosity",
+          "value": "dark"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0x0E",
+          "green": "0x0E",
+          "blue": "0x0F",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "contrast",
+          "value": "high"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0xEB",
+          "green": "0xEB",
+          "blue": "0xF0",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "luminosity",
+          "value": "dark"
+        },
+        {
+          "appearance": "contrast",
+          "value": "high"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0x16",
+          "green": "0x16",
+          "blue": "0x18",
+          "alpha": "1.000"
+        }
+      }
+    }
+  ],
+  "info": {
+    "author": "xcode",
+    "version": 1
+  }
+}
diff --git a/Shared/Colors.xcassets/AppSurfaceElevated.colorset/Contents.json b/Shared/Colors.xcassets/AppSurfaceElevated.colorset/Contents.json
new file mode 100644
index 0000000..775eafb
--- /dev/null
+++ b/Shared/Colors.xcassets/AppSurfaceElevated.colorset/Contents.json
@@ -0,0 +1,78 @@
+{
+  "colors": [
+    {
+      "idiom": "universal",
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0xE5",
+          "green": "0xE5",
+          "blue": "0xEA",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "luminosity",
+          "value": "dark"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0x1A",
+          "green": "0x1A",
+          "blue": "0x1C",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "contrast",
+          "value": "high"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0xDC",
+          "green": "0xDC",
+          "blue": "0xE1",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "luminosity",
+          "value": "dark"
+        },
+        {
+          "appearance": "contrast",
+          "value": "high"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0x23",
+          "green": "0x23",
+          "blue": "0x26",
+          "alpha": "1.000"
+        }
+      }
+    }
+  ],
+  "info": {
+    "author": "xcode",
+    "version": 1
+  }
+}
diff --git a/Shared/Colors.xcassets/Contents.json b/Shared/Colors.xcassets/Contents.json
new file mode 100644
index 0000000..73c0059
--- /dev/null
+++ b/Shared/Colors.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/Shared/Colors.xcassets/StatusCritical.colorset/Contents.json b/Shared/Colors.xcassets/StatusCritical.colorset/Contents.json
new file mode 100644
index 0000000..8f97cd9
--- /dev/null
+++ b/Shared/Colors.xcassets/StatusCritical.colorset/Contents.json
@@ -0,0 +1,78 @@
+{
+  "colors": [
+    {
+      "idiom": "universal",
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0xB3",
+          "green": "0x26",
+          "blue": "0x1E",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "luminosity",
+          "value": "dark"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0xFF",
+          "green": "0x69",
+          "blue": "0x61",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "contrast",
+          "value": "high"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0x8C",
+          "green": "0x1D",
+          "blue": "0x16",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "luminosity",
+          "value": "dark"
+        },
+        {
+          "appearance": "contrast",
+          "value": "high"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0xFF",
+          "green": "0x9A",
+          "blue": "0x94",
+          "alpha": "1.000"
+        }
+      }
+    }
+  ],
+  "info": {
+    "author": "xcode",
+    "version": 1
+  }
+}
diff --git a/Shared/Colors.xcassets/StatusInfo.colorset/Contents.json b/Shared/Colors.xcassets/StatusInfo.colorset/Contents.json
new file mode 100644
index 0000000..9d1e3b9
--- /dev/null
+++ b/Shared/Colors.xcassets/StatusInfo.colorset/Contents.json
@@ -0,0 +1,78 @@
+{
+  "colors": [
+    {
+      "idiom": "universal",
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0x00",
+          "green": "0x00",
+          "blue": "0xFF",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "luminosity",
+          "value": "dark"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0x4D",
+          "green": "0xA3",
+          "blue": "0xFF",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "contrast",
+          "value": "high"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0x00",
+          "green": "0x00",
+          "blue": "0xCC",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "luminosity",
+          "value": "dark"
+        },
+        {
+          "appearance": "contrast",
+          "value": "high"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0x7F",
+          "green": "0xBF",
+          "blue": "0xFF",
+          "alpha": "1.000"
+        }
+      }
+    }
+  ],
+  "info": {
+    "author": "xcode",
+    "version": 1
+  }
+}
diff --git a/Shared/Colors.xcassets/StatusNeutral.colorset/Contents.json b/Shared/Colors.xcassets/StatusNeutral.colorset/Contents.json
new file mode 100644
index 0000000..9e7bb36
--- /dev/null
+++ b/Shared/Colors.xcassets/StatusNeutral.colorset/Contents.json
@@ -0,0 +1,78 @@
+{
+  "colors": [
+    {
+      "idiom": "universal",
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0x5A",
+          "green": "0x5A",
+          "blue": "0x5F",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "luminosity",
+          "value": "dark"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0xA1",
+          "green": "0xA1",
+          "blue": "0xA6",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "contrast",
+          "value": "high"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0x3A",
+          "green": "0x3A",
+          "blue": "0x3C",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "luminosity",
+          "value": "dark"
+        },
+        {
+          "appearance": "contrast",
+          "value": "high"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0xC7",
+          "green": "0xC7",
+          "blue": "0xCC",
+          "alpha": "1.000"
+        }
+      }
+    }
+  ],
+  "info": {
+    "author": "xcode",
+    "version": 1
+  }
+}
diff --git a/Shared/Colors.xcassets/StatusPositive.colorset/Contents.json b/Shared/Colors.xcassets/StatusPositive.colorset/Contents.json
new file mode 100644
index 0000000..22ce5e5
--- /dev/null
+++ b/Shared/Colors.xcassets/StatusPositive.colorset/Contents.json
@@ -0,0 +1,78 @@
+{
+  "colors": [
+    {
+      "idiom": "universal",
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0x14",
+          "green": "0x6C",
+          "blue": "0x2E",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "luminosity",
+          "value": "dark"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0x30",
+          "green": "0xD1",
+          "blue": "0x58",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "contrast",
+          "value": "high"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0x0B",
+          "green": "0x50",
+          "blue": "0x23",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "luminosity",
+          "value": "dark"
+        },
+        {
+          "appearance": "contrast",
+          "value": "high"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0x5B",
+          "green": "0xE5",
+          "blue": "0x84",
+          "alpha": "1.000"
+        }
+      }
+    }
+  ],
+  "info": {
+    "author": "xcode",
+    "version": 1
+  }
+}
diff --git a/Shared/Colors.xcassets/StatusWarning.colorset/Contents.json b/Shared/Colors.xcassets/StatusWarning.colorset/Contents.json
new file mode 100644
index 0000000..cc79e86
--- /dev/null
+++ b/Shared/Colors.xcassets/StatusWarning.colorset/Contents.json
@@ -0,0 +1,78 @@
+{
+  "colors": [
+    {
+      "idiom": "universal",
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0x7A",
+          "green": "0x56",
+          "blue": "0x00",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "luminosity",
+          "value": "dark"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0xFF",
+          "green": "0xD6",
+          "blue": "0x0A",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "contrast",
+          "value": "high"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0x5C",
+          "green": "0x41",
+          "blue": "0x00",
+          "alpha": "1.000"
+        }
+      }
+    },
+    {
+      "idiom": "universal",
+      "appearances": [
+        {
+          "appearance": "luminosity",
+          "value": "dark"
+        },
+        {
+          "appearance": "contrast",
+          "value": "high"
+        }
+      ],
+      "color": {
+        "color-space": "srgb",
+        "components": {
+          "red": "0xFF",
+          "green": "0xE5",
+          "blue": "0x66",
+          "alpha": "1.000"
+        }
+      }
+    }
+  ],
+  "info": {
+    "author": "xcode",
+    "version": 1
+  }
+}