From 9e58a36915bb1fe8cf88423c9519c0c12dbbf2e2 Mon Sep 17 00:00:00 2001 From: Christian Cleberg Date: Mon, 20 Jul 2026 20:25:01 -0500 Subject: fix(a11y): rebalance the light palette so hues survive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported as "colors seem muted and hard to see on light mode", and correct. The light palette optimised contrast and produced mud: #7A5600 reads olive rather than amber, #146C2E bottle-dark rather than green. Contrast passed while the UI got harder to read, because hue identity is what distinguishes warning from critical at a glance. Two causes, both fixed. Every foreground was required to clear 4.5:1 against its own 16% badge tint — the harshest surface it ever sits on — which pushed each colour about 20% darker than the common case needed. Most of what is actually on screen is plain text on a card, with far more headroom. The fill is now decoupled from the foreground: AppStatusTone carries a foreground and a surface authored independently, with matching …Surface colorsets, so a foreground no longer has to survive a wash of itself. Every status foreground is now fully saturated. And warning was yellow. Yellow cannot stay yellow at a lightness low enough to pass 4.5:1 on white — it becomes olive. That is colorimetric, not a tuning problem. Warning is now orange: #AD5100 light, #FF9F0A dark. New light values: positive #008035, warning #AD5100, critical #CC0700. Worst-case ratios 4.54–6.76 across page, card, and surface in both schemes. Audit findings are unchanged — light 21, dark 18 — so the vividness costs nothing. Also picks up a literal .blue missed in phase 1: DomainDiffItem's low-severity change colour, which the phase 1 sweep did not cover because its pattern listed only cyan/yellow/green/red/orange/pink. --- DomainDig/BatchResultsView.swift | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'DomainDig/BatchResultsView.swift') diff --git a/DomainDig/BatchResultsView.swift b/DomainDig/BatchResultsView.swift index bf211dc..4b4f6fd 100644 --- a/DomainDig/BatchResultsView.swift +++ b/DomainDig/BatchResultsView.swift @@ -104,13 +104,13 @@ struct BatchResultRowView: View { if let changeClassification = result.changeClassification { Text("Impact: \(changeClassification.title)") .font(appDensity.font(.caption2)) - .foregroundStyle(changeClassification.color) + .foregroundStyle(changeClassification.tone.foreground) } if let errorMessage = result.errorMessage { Text(errorMessage) .font(appDensity.font(.caption2)) - .foregroundStyle(result.status == .failed ? Color(.statusCritical) : .secondary) + .foregroundStyle(result.status == .failed ? Color(.statusCritical) : Color(.appTextSecondary)) } } .frame(maxWidth: .infinity, alignment: .leading) @@ -147,20 +147,20 @@ struct BatchResultRowView: View { case .pending: return .init(title: "Pending", systemImage: "clock", foregroundColor: Color(.appTextSecondary), backgroundColor: Color(.appSurfaceElevated)) case .running: - return .init(title: "Running", systemImage: "arrow.clockwise", foregroundColor: Color(.statusInfo), backgroundColor: Color(.statusInfo).opacity(0.16)) + return .init(title: "Running", systemImage: "arrow.clockwise", foregroundColor: Color(.statusInfo), backgroundColor: Color(.statusInfoSurface)) case .completed: if result.changeClassification == .critical || result.certificateWarningLevel == .critical || result.riskLevel == .high { - return .init(title: "Critical", systemImage: "exclamationmark.octagon.fill", foregroundColor: Color(.statusCritical), backgroundColor: Color(.statusCritical).opacity(0.16)) + return .init(title: "Critical", systemImage: "exclamationmark.octagon.fill", foregroundColor: Color(.statusCritical), backgroundColor: Color(.statusCriticalSurface)) } if result.changeClassification == .warning || result.changeSeverity == .medium || result.certificateWarningLevel == .warning { - return .init(title: "Warning", systemImage: "exclamationmark.triangle.fill", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarning).opacity(0.16)) + return .init(title: "Warning", systemImage: "exclamationmark.triangle.fill", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarningSurface)) } if result.quickStatus == "Changed" { - return .init(title: "Changed", systemImage: "arrow.triangle.2.circlepath", foregroundColor: Color(.statusInfo), backgroundColor: Color(.statusInfo).opacity(0.16)) + return .init(title: "Changed", systemImage: "arrow.triangle.2.circlepath", foregroundColor: Color(.statusInfo), backgroundColor: Color(.statusInfoSurface)) } - return .init(title: "Stable", systemImage: "checkmark.circle.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositive).opacity(0.16)) + return .init(title: "Stable", systemImage: "checkmark.circle.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositiveSurface)) case .failed: - return .init(title: "Failed", systemImage: "xmark.circle.fill", foregroundColor: Color(.statusCritical), backgroundColor: Color(.statusCritical).opacity(0.16)) + return .init(title: "Failed", systemImage: "xmark.circle.fill", foregroundColor: Color(.statusCritical), backgroundColor: Color(.statusCriticalSurface)) } } } -- cgit v1.2.3