diff --git a/frontend/public/index.html b/frontend/public/index.html
index cc93caf7..a651cecf 100644
--- a/frontend/public/index.html
+++ b/frontend/public/index.html
@@ -51,7 +51,7 @@
var g = null;
try { g = JSON.parse(localStorage.getItem('self-swarm-theme-gradient') || 'null'); } catch (e) {}
var accent = localStorage.getItem('self-swarm-theme-accent');
- var stops = Array.isArray(g) && g.length > 1 ? g : (accent ? [accent, accent] : ['#B7CDEA', '#EFE0D2', '#E7BDD1']);
+ var stops = Array.isArray(g) && g.length > 1 ? g : (accent ? [accent, accent] : ['#DACEDA']);
if (stops.length === 1) stops = [stops[0], stops[0]];
var alpha = parseFloat(localStorage.getItem('self-swarm-theme-wash-opacity') || '');
if (!isFinite(alpha) || alpha < 0 || alpha > 1) alpha = 0.17;
diff --git a/frontend/src/shared/styles/washBackground.test.ts b/frontend/src/shared/styles/washBackground.test.ts
index f99895b5..fe2c6973 100644
--- a/frontend/src/shared/styles/washBackground.test.ts
+++ b/frontend/src/shared/styles/washBackground.test.ts
@@ -9,7 +9,7 @@
*/
import { test } from 'node:test';
import assert from 'node:assert/strict';
-import { washIsUniform, washBackgroundLayers, washUnderlayColor, washOpaqueBackgroundUrl } from './washBackground.ts';
+import { washIsUniform, washBackgroundLayers, washUnderlayColor, washOpaqueBackgroundUrl, DEFAULT_WASH_STOPS, effectiveWashStops } from './washBackground.ts';
const PAGE = '#F5F4ED';
@@ -58,3 +58,18 @@ test('no stops and no grain means no background image at all', () => {
assert.equal(washBackgroundLayers([], 0.17, PAGE, null), null);
assert.equal(washIsUniform([]), true);
});
+
+test('the STOCK theme is uniform, so a default install cannot tear', () => {
+ // Everyone who never opened the theme pad lands here. Making this multi-stop again would put a
+ // full-window texture back under every default install, which is the band, so it is asserted.
+ assert.equal(washIsUniform(DEFAULT_WASH_STOPS), true, 'default wash must stay one flat colour');
+ assert.equal(washBackgroundLayers(DEFAULT_WASH_STOPS, 0.17, PAGE, null), null);
+ assert.equal(washIsUniform(effectiveWashStops(null, null)), true, 'no accent, no gradient');
+ assert.equal(washIsUniform(effectiveWashStops(null, '#B7CDEA')), true, 'a picked accent is one stop');
+});
+
+test('a user who picks a real gradient still gets one, texture and all', () => {
+ const chosen = ['#B7CDEA', '#E7BDD1'];
+ assert.equal(washIsUniform(effectiveWashStops(chosen, null)), false);
+ assert.ok(washBackgroundLayers(chosen, 0.17, PAGE, null));
+});
diff --git a/frontend/src/shared/styles/washBackground.ts b/frontend/src/shared/styles/washBackground.ts
index f24eda01..cb8b4e72 100644
--- a/frontend/src/shared/styles/washBackground.ts
+++ b/frontend/src/shared/styles/washBackground.ts
@@ -79,9 +79,13 @@ export function washUnderlayColor(stops: string[], washOpacity: number, pageBg:
return mixHex(pageBg, mean, alpha);
}
-// Stock wallpaper when the user hasn't picked an accent yet: a designed blue-to-cream-to-pink
-// gradient (contrasting stops), so a fresh install and the onboarding stage never look flat/white.
-export const DEFAULT_WASH_STOPS = ['#B7CDEA', '#EFE0D2', '#E7BDD1'];
+// Stock wallpaper when the user hasn't picked an accent yet. ONE stop on purpose: a multi-stop
+// default needs a full-window texture, and Chromium fills any tile it drops with the layer's single
+// background colour, which is why the gradient used to tear into a hard-edged rectangle under GPU
+// pressure. This is the mean of the old blue-cream-pink trio, i.e. exactly the colour those torn
+// tiles already painted, so the stock look is now what the worst case used to be. Picking any accent
+// is also one stop; only a user-chosen gradient opts back into the texture.
+export const DEFAULT_WASH_STOPS = ['#DACEDA'];
export function effectiveWashStops(gradient: string[] | null, accent: string | null): string[] {
if (gradient && gradient.length > 0) return gradient;