diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6dd7e1e7..d5b10fcc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,19 @@ That paragraph is not decoration: the release workflow copies each entry verbati
the GitHub release body and the announcement discussion, so it is the first thing a
prospective user reads. CI fails a pull request whose newest entry is missing it.
+## [1.76.15] - 2026-09-04
+
+On any of the six light colour themes, the green tick on the little "finished" pop-up was almost invisible
+against its own background. It was a fixed green picked for the dark themes and never changed for the others.
+
+### Fixed
+- **The "finished" pop-up's tick is readable on the light themes.** Its background follows whichever theme you
+ picked, but the tick, its circle and the border were fixed to one green chosen against a dark background. On
+ the light themes that left the tick at between 1.65 and 2.08 times the contrast of its background, where 4.5
+ is the readable threshold — so the pop-up said something had finished and you could barely see the mark
+ confirming it. All three now come from the theme, which already keeps a lighter green for dark themes and a
+ darker one for light. A check now fails the build if any screen fixes a colour the theme cannot change.
+
## [1.76.14] - 2026-09-04
Double-clicking a cell in the App Updates or Windows Update list used to put a cursor in it, as if you could
diff --git a/SysManager/SysManager.Tests/ArchitectureTests.cs b/SysManager/SysManager.Tests/ArchitectureTests.cs
index bc014ed7..4a32e716 100644
--- a/SysManager/SysManager.Tests/ArchitectureTests.cs
+++ b/SysManager/SysManager.Tests/ArchitectureTests.cs
@@ -5496,6 +5496,80 @@ public void TheTimerResolutionQuery_BindsItsOutParametersCoarsestFinestCurrent()
private static partial Regex TimerQueryCall();
+ ///
+ /// A view may not paint itself with a literal colour; the theme decides colours.
+ ///
+ ///
+ /// The completion toast fixed three greens at #22C55E — the DARK-mode value — while its container
+ /// followed the theme through Surface2. Measured against each preset's real Surface2, the
+ /// tick came out at 1.65:1 on soft-blossom and never better than 2.08:1 on any of the six light presets,
+ /// against 7.66:1 on midnight-indigo where the value was chosen. WCAG asks 4.5:1 for text and 3:1 for a
+ /// meaningful graphic; it cleared neither.
+ /// NoThemedFill_CarriesAHardcodedWhiteForeground pins the same class and could not see this
+ /// one: it reads App.xaml styles whose Background binds Accent or Danger, and looks for the
+ /// literal White. Different file, different fill, different literal. This is the general rule, and
+ /// it is cheap because the view layer is nearly clean already — seven literals in total before the toast
+ /// was fixed, four of which are legitimate.
+ ///
+ [Fact]
+ public void NoViewPaintsItselfWithALiteralColour()
+ {
+ // file -> the reason its literals are colours being SHOWN rather than colours being applied.
+ var swatches = new Dictionary(StringComparer.Ordinal)
+ {
+ ["ThemePopup.xaml"] = "the custom-theme editor's 24x24 preview squares: each is an x:Name'd Border "
+ + "whose fill the code-behind replaces with the value being edited, so the "
+ + "literal is a designer-time default and the swatch's job is to BE a colour",
+ };
+
+ // Literals that must NOT follow the theme, allowed by exact value and only where they appear. The
+ // FocusRing is two stacked strokes precisely because no single themed colour survives every surface
+ // it lands on — PrimaryButton's accent fill, DangerButton's red, a raised grey and a card — where the
+ // accent itself falls to 1.00:1 against one of them. Theme-independence is the feature.
+ var themeIndependent = new Dictionary(StringComparer.Ordinal)
+ {
+ ["App.xaml"] = ["Stroke=\"#111111\"", "Stroke=\"#FFFFFF\""],
+ };
+
+ var appDir = FindAppProjectDir();
+ var files = Directory.GetFiles(appDir, "*.xaml")
+ .Concat(Directory.GetFiles(Path.Combine(appDir, "Views"), "*.xaml"))
+ .Where(f => !f.Contains($"{Path.DirectorySeparatorChar}obj{Path.DirectorySeparatorChar}",
+ StringComparison.Ordinal))
+ .ToList();
+
+ // Vacuity floor: the view layer is 30-odd files. Zero would mean the enumeration broke.
+ Assert.True(files.Count >= 25,
+ $"only {files.Count} view files were enumerated — this guard is reading the wrong folder.");
+
+ var offenders = new List();
+ foreach (var file in files)
+ {
+ var name = Path.GetFileName(file);
+ if (swatches.ContainsKey(name)) continue;
+
+ var text = File.ReadAllText(file);
+ var allowed = themeIndependent.TryGetValue(name, out var values) ? values : [];
+ foreach (var m in LiteralColourAttribute().Matches(text).Cast())
+ {
+ if (allowed.Contains(m.Value, StringComparer.Ordinal)) continue;
+ var line = text[..m.Index].Count(c => c == '\n') + 1;
+ offenders.Add($"{name}:{line} {m.Value}");
+ }
+ }
+
+ Assert.True(offenders.Count == 0,
+ "these views set a colour the theme cannot change, so whichever preset they were eyeballed against "
+ + "is the only one they are correct on. Bind a themed brush — Success/SuccessText/SuccessBorder, "
+ + "Danger…, TextPrimary, Surface… — or, if the element's purpose is to display a colour rather "
+ + "than be styled by one, name the file in the exception list in this test WITH that reason:\n "
+ + string.Join("\n ", offenders));
+ }
+
+ /// A colour-bearing attribute given a literal hex value.
+ [GeneratedRegex(@"(?:Foreground|Background|Fill|Stroke|BorderBrush)=""#[0-9A-Fa-f]{6,8}""")]
+ private static partial Regex LiteralColourAttribute();
+
///
/// A text column in a report grid must not accept typing.
///
diff --git a/SysManager/SysManager/MainWindow.xaml b/SysManager/SysManager/MainWindow.xaml
index b81d7d7c..c9a9273b 100644
--- a/SysManager/SysManager/MainWindow.xaml
+++ b/SysManager/SysManager/MainWindow.xaml
@@ -498,8 +498,14 @@
HorizontalAlignment="Right" VerticalAlignment="Bottom"
AutomationProperties.LiveSetting="Assertive"
Margin="0,0,20,20" Visibility="Collapsed">
+
@@ -511,9 +517,9 @@
+ Background="{DynamicResource SuccessBgSubtle}" Margin="0,0,10,0">
diff --git a/SysManager/SysManager/SysManager.csproj b/SysManager/SysManager/SysManager.csproj
index 2b605436..27fb2c4d 100644
--- a/SysManager/SysManager/SysManager.csproj
+++ b/SysManager/SysManager/SysManager.csproj
@@ -10,9 +10,9 @@
SysManager
true
NU1603;NU1701
- 1.76.14
- 1.76.14.0
- 1.76.14.0
+ 1.76.15
+ 1.76.15.0
+ 1.76.15.0
SysManager
SysManager — Windows system monitoring toolkit by laurentiu021. Network, updates, health, logs, safe deep cleanup.
https://github.com/laurentiu021/SystemManager