feat(t5): Darstellung hell/dunkel/Sonne ohne Flackern (T5a A2)

Blockierendes Skript im <head> setzt Darstellung, Kontrast und
Bewegung vor dem ersten Zeichnen (gleiche Logik wie resolveAppearance,
für alle Eingaben getestet), theme-color je Satz, Wahl je Gerät in
localStorage mit Rückfall bei gesperrtem Speicher; Abgleich über Tabs,
Systemeinstellungen und Seitenwechsel an einer Stelle. Profil-Karte
„Darstellung“, Sonnenmodus im Benutzermenü; Dunkel bleibt bis A4 hinter
NEXT_PUBLIC_APPEARANCE_DARK. next-themes entfernt. ARCHITECTURE §9:
'unsafe-inline' der Frontend-CSP als getragenes Risiko mit Begründung.

Refs #26

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
Nick.RosenloecherandClaude Opus 5.5 committed 2026-10-16 16:35:28 +02:00
1 parent 947a46f435
commit cf53cf35ac
22 files changed
+980 -97

No files matched your search

+16
View File
@@ -4,6 +4,9 @@ import "./globals.css";
import { Providers } from "./providers";
import { Toaster } from "@/components/ui/sonner";
import { ServiceWorkerRegistration } from "@/components/service-worker-registration";
import { AppearanceScript } from "@/components/appearance-script";
import { AppearanceSync } from "@/components/appearance-sync";
import { THEME_COLORS } from "@/lib/appearance/appearance-core";
// Self-hosted (OFL-1.1, see ./fonts/OFL.txt): no Google request at build or runtime.
const spaceGrotesk = localFont({
@@ -40,18 +43,31 @@ export const viewport: Viewport = {
// Without "cover" iOS reports env(safe-area-inset-*) as 0, and the bottom
// nav and save bar would sit under the home indicator.
viewportFit: "cover",
// The inline appearance script overwrites these when a manual choice differs
// from the device setting.
themeColor: [
{ media: "(prefers-color-scheme: light)", color: THEME_COLORS.light },
{ media: "(prefers-color-scheme: dark)", color: THEME_COLORS.dark },
],
};
export default function RootLayout({ children }: LayoutProps<"/">) {
return (
<html
lang="de"
// The inline script sets class="dark", data-contrast and data-motion
// before hydration; React must keep the document's values.
suppressHydrationWarning
className={`${spaceGrotesk.variable} ${inter.variable} ${plexMono.variable} h-full antialiased`}
>
<head>
<AppearanceScript />
</head>
<body className="min-h-full flex flex-col">
<Providers>{children}</Providers>
<Toaster richColors />
<ServiceWorkerRegistration />
<AppearanceSync />
</body>
</html>
);