Commit bd717e08f for llama.cpp

commit bd717e08f38f9715a315adfdc431fb3424095f06
Author: Aleksander Grygier <aleksander.grygier@gmail.com>
Date:   Wed Nov 11 23:25:35 2026 +0100

    ui: take the logo and favicons from the llama-brand package (#32039)

    * ui : take the logo and favicons from llama-brand

    The web UI's logo mark and favicons now come from llama-brand, added as a
    dev dependency from GitHub and pinned to a commit, so the UI draws the
    same icon as the README cover instead of its own copy of an older one.
    Logo.svelte inlines the brand's icon and fills it with currentColor, and
    the PWA asset generator starts from the brand's web favicons, which carry
    their own margin and optical centring, so the UI's colouring and padding
    script, its test and its logo.svg go.

    Assisted-by: Claude (Opus 5.5 Medium)

    * ui : follow llama-brand's master instead of a pinned commit

    Assisted-by: Claude (Opus 5.5 Medium)

diff --git a/tools/ui/package-lock.json b/tools/ui/package-lock.json
index df25e0aa2..8452ad52f 100644
--- a/tools/ui/package-lock.json
+++ b/tools/ui/package-lock.json
@@ -53,6 +53,7 @@
 				"globals": "16.5.0",
 				"highlight.js": "11.11.1",
 				"http-server": "14.1.1",
+				"llama-brand": "github:ggml-org/llama-brand#master",
 				"mdast": "3.0.0",
 				"mdsvex": "0.12.7",
 				"mermaid": "11.17.2",
@@ -12326,6 +12327,12 @@
 				"node": ">=10"
 			}
 		},
+		"node_modules/llama-brand": {
+			"version": "0.1.0",
+			"resolved": "git+ssh://git@github.com/ggml-org/llama-brand.git#f05540643c1ca2a18d732ed6491c839686da9a3a",
+			"dev": true,
+			"license": "CC-BY-NC-4.0"
+		},
 		"node_modules/locate-character": {
 			"version": "3.0.0",
 			"resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",
diff --git a/tools/ui/package.json b/tools/ui/package.json
index 00049071e..c57edf092 100644
--- a/tools/ui/package.json
+++ b/tools/ui/package.json
@@ -78,6 +78,7 @@
 		"globals": "16.5.0",
 		"highlight.js": "11.11.1",
 		"http-server": "14.1.1",
+		"llama-brand": "github:ggml-org/llama-brand#master",
 		"mdast": "3.0.0",
 		"mdsvex": "0.12.7",
 		"mermaid": "11.17.2",
diff --git a/tools/ui/pwa-assets-dark.config.ts b/tools/ui/pwa-assets-dark.config.ts
index 4d8114ee7..7a1128f35 100644
--- a/tools/ui/pwa-assets-dark.config.ts
+++ b/tools/ui/pwa-assets-dark.config.ts
@@ -1,10 +1,8 @@
-import { writeThemeFavicons } from './scripts/favicon-colorize';
-import { FAVICON_COLORS, PWA_ASSET_GENERATOR } from './src/lib/constants/pwa.constants';
+import { writeBrandFavicons } from './scripts/brand-favicons';
+import { PWA_ASSET_GENERATOR } from './src/lib/constants/pwa.constants';
 import { defineConfig } from '@vite-pwa/assets-generator/config';

-writeThemeFavicons(FAVICON_COLORS.LIGHT, FAVICON_COLORS.DARK, {
-	padding: PWA_ASSET_GENERATOR.FAVICON_PADDING
-});
+writeBrandFavicons();

 export default defineConfig({
 	headLinkOptions: {
diff --git a/tools/ui/pwa-assets.config.ts b/tools/ui/pwa-assets.config.ts
index f9f8662a2..bd0bc0024 100644
--- a/tools/ui/pwa-assets.config.ts
+++ b/tools/ui/pwa-assets.config.ts
@@ -1,6 +1,5 @@
-import { writeThemeFavicons } from './scripts/favicon-colorize';
+import { writeBrandFavicons } from './scripts/brand-favicons';
 import {
-	FAVICON_COLORS,
 	PWA_ASSET_GENERATOR,
 	PWA_GENERATOR_DEVICES,
 	THEME_COLORS
@@ -14,9 +13,7 @@ import {
 import { readFileSync } from 'node:fs';
 import { resolve } from 'node:path';

-writeThemeFavicons(FAVICON_COLORS.LIGHT, FAVICON_COLORS.DARK, {
-	padding: PWA_ASSET_GENERATOR.FAVICON_PADDING
-});
+writeBrandFavicons();

 export default defineConfig({
 	headLinkOptions: {
@@ -26,7 +23,7 @@ export default defineConfig({
 	preset: combinePresetAndAppleSplashScreens(
 		{
 			...minimal2023Preset,
-			// tiny margin so favicon.ico / pwa-*.png breathe inside the canvas
+			// llama-brand's favicons carry their own margin
 			transparent: {
 				...minimal2023Preset.transparent,
 				padding: PWA_ASSET_GENERATOR.FAVICON_PADDING
diff --git a/tools/ui/scripts/brand-favicons.ts b/tools/ui/scripts/brand-favicons.ts
new file mode 100644
index 000000000..87a058516
--- /dev/null
+++ b/tools/ui/scripts/brand-favicons.ts
@@ -0,0 +1,27 @@
+import { FAVICON_PATHS } from '../src/lib/constants/pwa.constants';
+import { copyFileSync, mkdirSync } from 'node:fs';
+import { createRequire } from 'node:module';
+import { dirname, resolve } from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+const HERE = dirname(fileURLToPath(import.meta.url));
+const DEFAULT_OUT_DIR = resolve(HERE, '..', 'static');
+const require = createRequire(import.meta.url);
+
+/** The web favicons llama-brand draws for the UI, optically centred, keyed by the file they become. */
+export const BRAND_FAVICONS = {
+	[FAVICON_PATHS.SVG_DARK]: 'llama-brand/logo/svg/app/web/favicon-dark.svg',
+	[FAVICON_PATHS.SVG_LIGHT]: 'llama-brand/logo/svg/app/web/favicon.svg'
+} as const;
+
+/**
+ * Copy llama-brand's light and dark favicons into the static directory, where
+ * they are served as they are and feed the PWA asset generator.
+ */
+export function writeBrandFavicons(outDir: string = DEFAULT_OUT_DIR): void {
+	mkdirSync(outDir, { recursive: true });
+
+	for (const [fileName, specifier] of Object.entries(BRAND_FAVICONS)) {
+		copyFileSync(require.resolve(specifier), resolve(outDir, fileName));
+	}
+}
diff --git a/tools/ui/scripts/favicon-colorize.ts b/tools/ui/scripts/favicon-colorize.ts
deleted file mode 100644
index 54a951296..000000000
--- a/tools/ui/scripts/favicon-colorize.ts
+++ /dev/null
@@ -1,113 +0,0 @@
-import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
-import { dirname, resolve } from 'node:path';
-import { fileURLToPath } from 'node:url';
-
-const HERE = dirname(fileURLToPath(import.meta.url));
-const PROJECT_ROOT = resolve(HERE, '..');
-const DEFAULT_LOGO = resolve(PROJECT_ROOT, 'src/lib/assets/logo.svg');
-const DEFAULT_OUT_DIR = resolve(PROJECT_ROOT, 'static');
-const DEFAULT_OUT_LIGHT = resolve(DEFAULT_OUT_DIR, 'favicon.svg');
-const DEFAULT_OUT_DARK = resolve(DEFAULT_OUT_DIR, 'favicon-dark.svg');
-const CURRENT_COLOR = 'currentColor';
-
-export interface ColorizedFavicon {
-	light: string;
-	dark: string;
-}
-
-export interface WriteThemeFaviconsOptions {
-	sourcePath?: string;
-	lightOutPath?: string;
-	darkOutPath?: string;
-	/**
-	 * Fraction of the icon (0..1) to leave as an even margin on each side.
-	 * Applied by wrapping the inner content in a `<g transform="...">` so the
-	 * source `src/lib/assets/logo.svg` is not modified. Pass 0 to disable.
-	 */
-	padding?: number;
-}
-
-/**
- * Replace every `currentColor` occurrence in the SVG with the given color.
- * Pure: no filesystem access, so it is straightforward to unit-test.
- */
-export function colorizeFaviconSvg(
-	svg: string,
-	lightColor: string,
-	darkColor: string
-): ColorizedFavicon {
-	return {
-		dark: svg.replaceAll(CURRENT_COLOR, darkColor),
-		light: svg.replaceAll(CURRENT_COLOR, lightColor)
-	};
-}
-
-/**
- * Shrink the inner SVG content uniformly and re-center it so `padding` (a
- * 0..1 fraction) is reserved as equal margin on each side. Returns the input
- * unchanged for non-positive padding, missing/invalid `viewBox`, or unexpected
- * markup so the caller always gets a renderable SVG.
- */
-export function padFaviconSvg(svg: string, padding: number): string {
-	if (!(padding > 0) || padding >= 1) return svg;
-
-	const viewBoxMatch = svg.match(/viewBox\s*=\s*["']([^"']+)["']/i);
-
-	if (!viewBoxMatch) return svg;
-
-	const parts = viewBoxMatch[1]
-		.trim()
-		.split(/[\s,]+/)
-		.map(Number);
-
-	if (parts.length !== 4 || parts.some((n) => !Number.isFinite(n))) return svg;
-
-	const [, , width, height] = parts;
-
-	if (width <= 0 || height <= 0) return svg;
-
-	const scale = 1 - padding;
-	const translateX = (padding * width) / 2;
-	const translateY = (padding * height) / 2;
-	const openTagStart = svg.search(/<svg\b/i);
-
-	if (openTagStart === -1) return svg;
-
-	const openTagEnd = svg.indexOf('>', openTagStart);
-
-	if (openTagEnd === -1) return svg;
-
-	const closeStart = svg.lastIndexOf('</svg');
-
-	if (closeStart === -1 || closeStart <= openTagEnd) return svg;
-
-	const openTag = svg.slice(0, openTagEnd + 1);
-	const inner = svg.slice(openTagEnd + 1, closeStart);
-	const closeTag = svg.slice(closeStart);
-	const group = `<g transform="translate(${translateX} ${translateY}) scale(${scale})">`;
-
-	return `${openTag}${group}${inner}</g>${closeTag}`;
-}
-
-/**
- * Read `src/lib/assets/logo.svg`, colorize it for both themes, and write
- * the results to the static directory so the PWA asset generator can consume
- * them. Paths can be overridden for tests.
- */
-export function writeThemeFavicons(
-	lightColor: string,
-	darkColor: string,
-	{
-		darkOutPath = DEFAULT_OUT_DARK,
-		lightOutPath = DEFAULT_OUT_LIGHT,
-		padding = 0,
-		sourcePath = DEFAULT_LOGO
-	}: WriteThemeFaviconsOptions = {}
-): void {
-	const source = readFileSync(sourcePath, 'utf-8');
-	const { dark, light } = colorizeFaviconSvg(source, lightColor, darkColor);
-
-	mkdirSync(dirname(lightOutPath), { recursive: true });
-	writeFileSync(lightOutPath, padFaviconSvg(light, padding));
-	writeFileSync(darkOutPath, padFaviconSvg(dark, padding));
-}
diff --git a/tools/ui/src/lib/assets/logo.svg b/tools/ui/src/lib/assets/logo.svg
deleted file mode 100644
index 05424790a..000000000
--- a/tools/ui/src/lib/assets/logo.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
-    <path d="M244.95 8C215.233 8 187.774 23.8591 172.923 49.5999L95.6009 183.625C60.2162 244.959 104.481 321.6 175.29 321.6H208L316.977 132.708C348.959 77.2719 308.95 8 244.95 8ZM208 321.6H351.947C415.982 321.6 456.013 390.91 424.013 446.377C409.155 472.132 381.681 488 351.947 488H271.29C200.481 488 156.216 411.359 191.601 350.026L208 321.6Z" fill="currentColor"/>
-    <path d="M208 321.6H16L106.462 164.8L208 321.6Z" fill="currentColor"/>
-    <path d="M388.923 8L208 321.6L253.6 8H388.923Z" fill="currentColor"/>
-    <path d="M304 488H112L202.462 331.2L304 488Z" fill="currentColor"/>
-    <path d="M496 321.6H208L419.399 454.4L496 321.6Z" fill="currentColor"/>
-</svg>
diff --git a/tools/ui/src/lib/components/app/misc/Logo.svelte b/tools/ui/src/lib/components/app/misc/Logo.svelte
index ff2b7f2f0..0dc5bb0bd 100644
--- a/tools/ui/src/lib/components/app/misc/Logo.svelte
+++ b/tools/ui/src/lib/components/app/misc/Logo.svelte
@@ -1,5 +1,9 @@
 <script>
-	import logoMark from '$lib/assets/logo.svg?raw';
+	import icon from 'llama-brand/logo/svg/icon/icon-light.svg?raw';
+
+	// llama-brand draws the icon in its ink; currentColor lets it follow the text colour.
+	const logoMark = icon.replace(/fill="#[0-9a-f]{3,8}"/gi, 'fill="currentColor"');
+
 	let { class: className = '', style = '' } = $props();
 </script>

diff --git a/tools/ui/src/lib/constants/pwa.constants.ts b/tools/ui/src/lib/constants/pwa.constants.ts
index bd6c95346..e8f346817 100644
--- a/tools/ui/src/lib/constants/pwa.constants.ts
+++ b/tools/ui/src/lib/constants/pwa.constants.ts
@@ -36,13 +36,6 @@ export const FAVICON_PATHS = {
 	SVG_LIGHT: 'favicon.svg'
 } as const;

-// Substituted for `currentColor` in src/lib/assets/logo.svg when generating
-// the light/dark static sources consumed by the PWA asset generator.
-export const FAVICON_COLORS = {
-	DARK: '#fafafa',
-	LIGHT: '#111111'
-} as const;
-
 export const FAVICON_SELECTORS = {
 	ICO_48X48: 'link[rel="icon"][sizes="48x48"]',
 	SVG_ANY: 'link[rel="icon"][type="image/svg+xml"]'
@@ -232,14 +225,13 @@ export const PWA_GENERATOR_DEVICES = [

 // PWA assets generator configuration — used by pwa-assets.config.ts
 // FAVICON_PADDING: fraction (0..1) of the icon reserved as equal margin on
-// each side. Applied to icon PNG/ICO outputs by @vite-pwa/assets-generator and
-// post-processed into the static favicon.svg so the in-app logo (which reads
-// src/lib/assets/logo.svg directly) is unaffected.
+// each side of the icon PNG/ICO outputs. 0, because llama-brand's favicons
+// already carry their margin and optical centring.
 export const PWA_ASSET_GENERATOR = {
 	ADD_MEDIA_SCREEN: true,
 	BASE_PATH: './',
 	DARK_PREFIX: 'dark-',
-	FAVICON_PADDING: 0.04,
+	FAVICON_PADDING: 0,
 	FIT_MODE: 'contain',
 	LINK_PRESET: '2023',
 	PNG_COMPRESSION_LEVEL: 9,
diff --git a/tools/ui/tests/unit/brand-favicons.test.ts b/tools/ui/tests/unit/brand-favicons.test.ts
new file mode 100644
index 000000000..a1fb9e564
--- /dev/null
+++ b/tools/ui/tests/unit/brand-favicons.test.ts
@@ -0,0 +1,37 @@
+import { BRAND_FAVICONS, writeBrandFavicons } from '../../scripts/brand-favicons';
+import { mkdtempSync, readFileSync, rmSync } from 'node:fs';
+import { createRequire } from 'node:module';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { afterEach, beforeEach, describe, expect, it } from 'vitest';
+
+const require = createRequire(import.meta.url);
+
+describe('writeBrandFavicons', () => {
+	let tmpDir: string;
+
+	beforeEach(() => {
+		tmpDir = mkdtempSync(join(tmpdir(), 'favicon-'));
+	});
+
+	afterEach(() => {
+		rmSync(tmpDir, { force: true, recursive: true });
+	});
+
+	it("writes llama-brand's light and dark favicons unchanged", () => {
+		writeBrandFavicons(tmpDir);
+
+		for (const [fileName, specifier] of Object.entries(BRAND_FAVICONS)) {
+			expect(readFileSync(join(tmpDir, fileName), 'utf-8')).toBe(
+				readFileSync(require.resolve(specifier), 'utf-8')
+			);
+		}
+	});
+
+	it('draws the light favicon in ink and the dark one in light', () => {
+		writeBrandFavicons(tmpDir);
+
+		expect(readFileSync(join(tmpDir, 'favicon.svg'), 'utf-8')).toContain('fill="#111111"');
+		expect(readFileSync(join(tmpDir, 'favicon-dark.svg'), 'utf-8')).toContain('fill="#FAFAFA"');
+	});
+});
diff --git a/tools/ui/tests/unit/favicon-colorize.test.ts b/tools/ui/tests/unit/favicon-colorize.test.ts
deleted file mode 100644
index b286db37d..000000000
--- a/tools/ui/tests/unit/favicon-colorize.test.ts
+++ /dev/null
@@ -1,211 +0,0 @@
-import {
-	colorizeFaviconSvg,
-	padFaviconSvg,
-	writeThemeFavicons
-} from '../../scripts/favicon-colorize';
-import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
-import { tmpdir } from 'node:os';
-import { join } from 'node:path';
-import { afterEach, beforeEach, describe, expect, it } from 'vitest';
-
-const SOURCE_SVG = [
-	'<svg xmlns="http://www.w3.org/2000/svg">',
-	'  <path d="M0 0" fill="currentColor"/>',
-	'  <path d="M1 1" fill="#ff00aa"/>',
-	'  <circle fill="currentColor"/>',
-	'</svg>'
-].join('\n');
-
-describe('colorizeFaviconSvg', () => {
-	it('substitutes every currentColor occurrence for the light variant', () => {
-		const { light } = colorizeFaviconSvg(SOURCE_SVG, '#111111', '#fafafa');
-
-		expect(light.match(/currentColor/g)).toBeNull();
-		expect(light).toContain('fill="#111111"');
-		expect(light).toContain('<circle fill="#111111"/>');
-	});
-
-	it('substitutes every currentColor occurrence for the dark variant', () => {
-		const { dark } = colorizeFaviconSvg(SOURCE_SVG, '#111111', '#fafafa');
-
-		expect(dark.match(/currentColor/g)).toBeNull();
-		expect(dark).toContain('fill="#fafafa"');
-		expect(dark).toContain('<circle fill="#fafafa"/>');
-	});
-
-	it('leaves non-currentColor colors untouched in both variants', () => {
-		const { dark, light } = colorizeFaviconSvg(SOURCE_SVG, '#111111', '#fafafa');
-
-		expect(light).toContain('fill="#ff00aa"');
-		expect(dark).toContain('fill="#ff00aa"');
-	});
-
-	it('does not alter any other part of the SVG', () => {
-		const { dark, light } = colorizeFaviconSvg(SOURCE_SVG, '#111111', '#fafafa');
-		const stripColors = (s: string) =>
-			s.replaceAll('#111111', '').replaceAll('#fafafa', '').replaceAll('currentColor', '');
-		const expected = stripColors(SOURCE_SVG);
-
-		expect(stripColors(light)).toBe(expected);
-		expect(stripColors(dark)).toBe(expected);
-	});
-
-	it('returns the same SVG for light and dark when called with the same color', () => {
-		const result = colorizeFaviconSvg(SOURCE_SVG, '#abcdef', '#abcdef');
-
-		expect(result.light).toBe(result.dark);
-	});
-
-	it('returns the source unchanged when given a color that does not appear (no currentColor in source)', () => {
-		const plain = '<svg><path fill="#000"/></svg>';
-		const { dark, light } = colorizeFaviconSvg(plain, '#111111', '#fafafa');
-
-		expect(light).toBe(plain);
-		expect(dark).toBe(plain);
-	});
-});
-
-describe('padFaviconSvg', () => {
-	const SIZED_SVG =
-		'<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">' +
-		'<path d="M244.95 8L388.923 8Z" fill="currentColor"/>' +
-		'</svg>';
-
-	it('wraps inner content in a translate-then-scale group that matches padding', () => {
-		const padded = padFaviconSvg(SIZED_SVG, 0.05);
-
-		// scale = 1 - 0.05 = 0.95
-		// translate = (0.05 * 512) / 2 = 12.8 on each axis
-		expect(padded).toContain('transform="translate(12.8 12.8) scale(0.95)"');
-		expect(padded).toContain('<g transform="translate(12.8 12.8) scale(0.95)">');
-		expect(padded).toContain('<path d="M244.95 8L388.923 8Z" fill="currentColor"/>');
-		expect(padded.endsWith('</g></svg>')).toBe(true);
-	});
-
-	it('preserves the outer <svg> tag attributes', () => {
-		const padded = padFaviconSvg(SIZED_SVG, 0.1);
-
-		expect(padded.startsWith('<svg width="512" height="512" viewBox="0 0 512 512"')).toBe(true);
-	});
-
-	it('returns the input unchanged for zero or negative padding', () => {
-		expect(padFaviconSvg(SIZED_SVG, 0)).toBe(SIZED_SVG);
-		expect(padFaviconSvg(SIZED_SVG, -0.1)).toBe(SIZED_SVG);
-	});
-
-	it('returns the input unchanged when padding would fully collapse the icon (>= 1)', () => {
-		expect(padFaviconSvg(SIZED_SVG, 1)).toBe(SIZED_SVG);
-		expect(padFaviconSvg(SIZED_SVG, 1.5)).toBe(SIZED_SVG);
-	});
-
-	it('returns the input unchanged when no viewBox is present', () => {
-		const noViewBox = '<svg width="32" height="32"><path d="M0 0Z"/></svg>';
-
-		expect(padFaviconSvg(noViewBox, 0.1)).toBe(noViewBox);
-	});
-
-	it('returns the input unchanged when viewBox values are not finite numbers', () => {
-		const bad = '<svg viewBox="auto auto 0 0"><path/></svg>';
-
-		expect(padFaviconSvg(bad, 0.1)).toBe(bad);
-	});
-
-	it('tolerates a non-square viewBox', () => {
-		const wide = '<svg viewBox="0 0 100 50"><rect/></svg>';
-		const padded = padFaviconSvg(wide, 0.1);
-
-		// scale 0.9, translate (5, 2.5)
-		expect(padded).toContain('transform="translate(5 2.5) scale(0.9)"');
-	});
-});
-
-describe('writeThemeFavicons', () => {
-	const LOGO =
-		'<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">' +
-		'<path d="M244.95 8L388.923 8Z" fill="currentColor"/>' +
-		'</svg>';
-
-	let tmpDir: string;
-
-	beforeEach(() => {
-		tmpDir = mkdtempSync(join(tmpdir(), 'favicon-'));
-	});
-
-	afterEach(() => {
-		rmSync(tmpDir, { force: true, recursive: true });
-	});
-
-	function setupSource() {
-		const sourcePath = join(tmpDir, 'logo.svg');
-
-		writeFileSync(sourcePath, LOGO);
-
-		return {
-			darkPath: join(tmpDir, 'favicon-dark.svg'),
-			lightPath: join(tmpDir, 'favicon.svg'),
-			sourcePath
-		};
-	}
-
-	it('writes colorized, un-padded favicons without modifying the source', () => {
-		const { darkPath, lightPath, sourcePath } = setupSource();
-		const before = readFileSync(sourcePath, 'utf-8');
-
-		writeThemeFavicons('#abcdef', '#012345', {
-			darkOutPath: darkPath,
-			lightOutPath: lightPath,
-			sourcePath
-		});
-
-		const lightOut = readFileSync(lightPath, 'utf-8');
-		const darkOut = readFileSync(darkPath, 'utf-8');
-
-		// currentColor swapped to the requested palette in both files
-		expect(lightOut).toContain('fill="#abcdef"');
-		expect(lightOut).not.toContain('currentColor');
-		expect(darkOut).toContain('fill="#012345"');
-		expect(darkOut).not.toContain('currentColor');
-
-		// default padding (0) keeps the wrapper off the output
-		expect(lightOut).not.toContain('<g ');
-		expect(darkOut).not.toContain('<g ');
-
-		// source file is unchanged after the call
-		expect(readFileSync(sourcePath, 'utf-8')).toBe(before);
-	});
-
-	it('writes colorized favicons wrapped in a padding <g transform>...</g>', () => {
-		const { darkPath, lightPath, sourcePath } = setupSource();
-		// mirror the production wiring: PWA_ASSET_GENERATOR.FAVICON_PADDING
-		const padding = 0.04;
-		// scale = 1 - 0.04 = 0.96; translate = (0.04 * 512) / 2 = 10.24
-		const expectedTransform = 'transform="translate(10.24 10.24) scale(0.96)"';
-
-		writeThemeFavicons('#111111', '#fafafa', {
-			darkOutPath: darkPath,
-			lightOutPath: lightPath,
-			padding,
-			sourcePath
-		});
-
-		const lightOut = readFileSync(lightPath, 'utf-8');
-		const darkOut = readFileSync(darkPath, 'utf-8');
-
-		// both files get the same padding wrapper derived from the viewBox
-		expect(lightOut).toContain(`<g ${expectedTransform}>`);
-		expect(lightOut.endsWith('</g></svg>')).toBe(true);
-		expect(darkOut).toContain(`<g ${expectedTransform}>`);
-		expect(darkOut.endsWith('</g></svg>')).toBe(true);
-
-		// colorization still happens inside the wrapped group
-		expect(lightOut).toContain('fill="#111111"');
-		expect(lightOut).not.toContain('currentColor');
-		expect(darkOut).toContain('fill="#fafafa"');
-		expect(darkOut).not.toContain('currentColor');
-		// light palette colour must not leak into dark output
-		expect(darkOut).not.toContain('#111111');
-
-		// source file is not modified by the padding step
-		expect(readFileSync(sourcePath, 'utf-8')).toBe(LOGO);
-	});
-});