diff --git a/frontend/e2e/header.spec.ts b/frontend/e2e/header.spec.ts
new file mode 100644
index 00000000..8317c742
--- /dev/null
+++ b/frontend/e2e/header.spec.ts
@@ -0,0 +1,96 @@
+import { test, expect } from '@playwright/test';
+import AxeBuilder from '@axe-core/playwright';
+
+// #012851 — brand-navy, defined as --c-primary in layout.css
+const BRAND_NAVY = 'rgb(1, 40, 81)';
+
+test.describe('Header — brand-navy background', () => {
+ test('header background is brand-navy in light mode', async ({ page }) => {
+ await page.goto('/');
+ await expect(page.getByRole('navigation')).toBeVisible();
+
+ const bg = await page.locator('header').evaluate((el) => getComputedStyle(el).backgroundColor);
+ expect(bg).toBe(BRAND_NAVY);
+ });
+
+ test('header passes accessibility audit in light mode', async ({ page }) => {
+ await page.goto('/');
+ await expect(page.getByRole('navigation')).toBeVisible();
+
+ const results = await new AxeBuilder({ page }).include('header').analyze();
+ expect(results.violations).toEqual([]);
+ });
+
+ test('header background stays brand-navy after switching to dark mode', async ({ page }) => {
+ await page.goto('/');
+ await expect(page.getByRole('navigation')).toBeVisible();
+
+ await page
+ .getByRole('banner')
+ .getByRole('button', { name: /dark mode/i })
+ .click();
+ await expect(page.locator('html')).toHaveAttribute('data-theme', 'dark');
+
+ const bg = await page.locator('header').evaluate((el) => getComputedStyle(el).backgroundColor);
+ expect(bg).toBe(BRAND_NAVY);
+ });
+
+ test('header passes accessibility audit in dark mode', async ({ page }) => {
+ await page.goto('/');
+ await expect(page.getByRole('navigation')).toBeVisible();
+
+ await page
+ .getByRole('banner')
+ .getByRole('button', { name: /dark mode/i })
+ .click();
+ await expect(page.locator('html')).toHaveAttribute('data-theme', 'dark');
+
+ const results = await new AxeBuilder({ page }).include('header').analyze();
+ expect(results.violations).toEqual([]);
+ });
+
+ test('logo text is visible at 375px viewport', async ({ page }) => {
+ await page.setViewportSize({ width: 375, height: 812 });
+ await page.goto('/');
+
+ await expect(page.getByRole('banner').getByText('Familienarchiv')).toBeVisible();
+ });
+
+ test('hamburger menu opens on tablet viewport (768px)', async ({ page }) => {
+ await page.setViewportSize({ width: 768, height: 1024 });
+ await page.goto('/');
+ await expect(page.getByRole('navigation')).toBeVisible();
+
+ const hamburger = page.getByRole('button', { name: /menü öffnen/i });
+ await expect(hamburger).toBeVisible();
+ await hamburger.click();
+
+ await expect(
+ page.getByRole('navigation', { name: /mobile/i }).or(page.locator('#mobile-nav'))
+ ).toBeVisible();
+ });
+});
+
+test.describe('Login page — AuthHeader', () => {
+ test.use({ storageState: { cookies: [], origins: [] } });
+
+ test('login page has brand-navy header with language switcher', async ({ page }) => {
+ await page.goto('/login');
+
+ const header = page.locator('header');
+ await expect(header).toBeVisible();
+
+ const bg = await header.evaluate((el) => getComputedStyle(el).backgroundColor);
+ expect(bg).toBe(BRAND_NAVY);
+
+ await expect(header.getByRole('button', { name: 'DE' })).toBeVisible();
+ });
+
+ test('login page header passes accessibility audit', async ({ page }) => {
+ await page.goto('/login');
+ await expect(page.locator('header')).toBeVisible();
+
+ const results = await new AxeBuilder({ page }).include('header').analyze();
+ expect(results.violations).toEqual([]);
+ });
+});
diff --git a/frontend/src/lib/components/LanguageSwitcher.svelte b/frontend/src/lib/components/LanguageSwitcher.svelte
index e14029db..314fb54c 100644
--- a/frontend/src/lib/components/LanguageSwitcher.svelte
+++ b/frontend/src/lib/components/LanguageSwitcher.svelte
@@ -1,6 +1,8 @@
-
-
+
+
-