Add dark mode with toggle for prototyping tool

- Add ThemeProvider context with system/light/dark modes
- Add ThemeToggle button to all pages (Gallery, DemoMode, UserStoriesPage, SpecsPage)
- Add --tool-* CSS variables for outer app theming
- Keep inner Festipod mockup screens always in light mode
- Add subtle glow around phone frame in dark mode for visibility

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Sylvain Duchesne
2026-01-18 12:19:53 +01:00
parent f04f15d926
commit eb36f37d64
9 changed files with 316 additions and 86 deletions
+6 -3
View File
@@ -1,5 +1,6 @@
import React from 'react';
import { RouterProvider, useRouter } from './router';
import { ThemeProvider } from './context/ThemeContext';
import { Gallery } from './components/Gallery';
import { DemoMode } from './components/DemoMode';
import { UserStoriesPage } from './components/UserStoriesPage';
@@ -50,9 +51,11 @@ function AppContent() {
export function App() {
return (
<RouterProvider>
<AppContent />
</RouterProvider>
<ThemeProvider>
<RouterProvider>
<AppContent />
</RouterProvider>
</ThemeProvider>
);
}
+53 -21
View File
@@ -3,6 +3,7 @@ import { PhoneFrame } from './sketchy';
import { screens, getScreen } from '../screens';
import { getStoriesForScreen, categoryLabels, categoryColors, priorityColors } from '../data';
import { getStoryUrl } from '../router';
import { ThemeToggle } from './ThemeToggle';
interface DemoModeProps {
initialScreenId: string;
@@ -52,8 +53,9 @@ export function DemoMode({ initialScreenId, onBack, onNavigateToStory }: DemoMod
display: 'flex',
flexDirection: 'row',
height: '100vh',
background: 'var(--sketch-bg)',
background: 'var(--tool-bg)',
overflow: 'hidden',
transition: 'background-color 0.2s ease',
}}>
{/* Left Sidebar */}
<div style={{
@@ -61,26 +63,36 @@ export function DemoMode({ initialScreenId, onBack, onNavigateToStory }: DemoMod
flexShrink: 0,
display: 'flex',
flexDirection: 'column',
borderRight: '2px solid var(--sketch-black)',
background: 'var(--sketch-white)',
borderRight: '2px solid var(--tool-border)',
background: 'var(--tool-surface)',
transition: 'background-color 0.2s ease, border-color 0.2s ease',
}}>
{/* Back button */}
<div style={{ padding: 16, borderBottom: '1px solid var(--sketch-light-gray)' }}>
{/* Back button and theme toggle */}
<div style={{ padding: 16, borderBottom: '1px solid var(--tool-border-light)', display: 'flex', gap: 8 }}>
<button
onClick={onBack}
className="sketchy-btn"
style={{ padding: '8px 16px', width: '100%' }}
style={{
flex: 1,
padding: '8px 16px',
background: 'none',
border: '2px solid var(--tool-border)',
borderRadius: '255px 15px 225px 15px/15px 225px 15px 255px',
fontFamily: 'var(--font-sketch)',
cursor: 'pointer',
color: 'var(--tool-text)',
}}
>
Galerie
</button>
<ThemeToggle />
</div>
{/* Current screen & navigation */}
<div style={{ padding: 16, borderBottom: '1px solid var(--sketch-light-gray)' }}>
<div style={{ padding: 16, borderBottom: '1px solid var(--tool-border-light)' }}>
<div style={{
fontFamily: 'var(--font-sketch)',
fontSize: 12,
color: 'var(--sketch-gray)',
color: 'var(--tool-text-muted)',
marginBottom: 8,
}}>
Écran actuel
@@ -90,22 +102,41 @@ export function DemoMode({ initialScreenId, onBack, onNavigateToStory }: DemoMod
fontSize: 16,
fontWeight: 'bold',
marginBottom: 12,
color: 'var(--tool-text)',
}}>
{currentScreen?.name}
</div>
<div style={{ display: 'flex', gap: 8 }}>
<button
onClick={goBack}
className="sketchy-btn"
style={{ padding: '6px 12px', opacity: canGoBack ? 1 : 0.4, flex: 1 }}
style={{
padding: '6px 12px',
opacity: canGoBack ? 1 : 0.4,
flex: 1,
background: 'none',
border: '2px solid var(--tool-border)',
borderRadius: '255px 15px 225px 15px/15px 225px 15px 255px',
fontFamily: 'var(--font-sketch)',
cursor: canGoBack ? 'pointer' : 'default',
color: 'var(--tool-text)',
}}
disabled={!canGoBack}
>
Retour
</button>
<button
onClick={goForward}
className="sketchy-btn"
style={{ padding: '6px 12px', opacity: canGoForward ? 1 : 0.4, flex: 1 }}
style={{
padding: '6px 12px',
opacity: canGoForward ? 1 : 0.4,
flex: 1,
background: 'none',
border: '2px solid var(--tool-border)',
borderRadius: '255px 15px 225px 15px/15px 225px 15px 255px',
fontFamily: 'var(--font-sketch)',
cursor: canGoForward ? 'pointer' : 'default',
color: 'var(--tool-text)',
}}
disabled={!canGoForward}
>
Suivant
@@ -116,18 +147,18 @@ export function DemoMode({ initialScreenId, onBack, onNavigateToStory }: DemoMod
{/* User Stories for this screen */}
{linkedStories.length > 0 && (
<div style={{
borderBottom: '1px solid var(--sketch-light-gray)',
borderBottom: '1px solid var(--tool-border-light)',
maxHeight: '40%',
overflow: 'auto',
}}>
<div style={{
fontFamily: 'var(--font-sketch)',
fontSize: 12,
color: 'var(--sketch-gray)',
color: 'var(--tool-text-muted)',
padding: '12px 16px 8px',
position: 'sticky',
top: 0,
background: 'var(--sketch-white)',
background: 'var(--tool-surface)',
}}>
User Stories ({linkedStories.length})
</div>
@@ -142,9 +173,9 @@ export function DemoMode({ initialScreenId, onBack, onNavigateToStory }: DemoMod
style={{
display: 'block',
padding: '8px 16px',
borderBottom: '1px solid var(--sketch-light-gray)',
borderBottom: '1px solid var(--tool-border-light)',
textDecoration: 'none',
color: 'inherit',
color: 'var(--tool-text)',
cursor: 'pointer',
}}
>
@@ -193,7 +224,7 @@ export function DemoMode({ initialScreenId, onBack, onNavigateToStory }: DemoMod
<div style={{
fontFamily: 'var(--font-sketch)',
fontSize: 12,
color: 'var(--sketch-gray)',
color: 'var(--tool-text-muted)',
padding: '8px 16px',
}}>
Tous les écrans
@@ -207,8 +238,9 @@ export function DemoMode({ initialScreenId, onBack, onNavigateToStory }: DemoMod
fontFamily: 'var(--font-sketch)',
fontSize: 14,
cursor: 'pointer',
background: s.id === currentScreenId ? 'var(--sketch-light-gray)' : 'transparent',
borderLeft: s.id === currentScreenId ? '3px solid var(--sketch-black)' : '3px solid transparent',
background: s.id === currentScreenId ? 'var(--tool-border-light)' : 'transparent',
borderLeft: s.id === currentScreenId ? '3px solid var(--tool-text)' : '3px solid transparent',
color: 'var(--tool-text)',
}}
>
{s.name}
+18 -11
View File
@@ -1,6 +1,7 @@
import React, { useState } from 'react';
import { PhoneFrame } from './sketchy';
import { screenGroups, type Screen } from '../screens';
import { ThemeToggle } from './ThemeToggle';
interface GalleryProps {
onSelectScreen: (screenId: string) => void;
@@ -19,8 +20,9 @@ export function Gallery({ onSelectScreen, onShowStories, onShowSpecs }: GalleryP
<div>
<div style={{
padding: '24px 32px',
borderBottom: '2px solid var(--sketch-black)',
background: 'var(--sketch-white)',
borderBottom: '2px solid var(--tool-border)',
background: 'var(--tool-surface)',
transition: 'background-color 0.2s ease, border-color 0.2s ease',
}}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
<div>
@@ -28,13 +30,14 @@ export function Gallery({ onSelectScreen, onShowStories, onShowSpecs }: GalleryP
fontFamily: 'var(--font-sketch)',
fontSize: 28,
margin: 0,
color: 'var(--tool-text)',
}}>
Festipod
</h1>
<p style={{
fontFamily: 'var(--font-sketch)',
fontSize: 16,
color: 'var(--sketch-gray)',
color: 'var(--tool-text-muted)',
margin: '8px 0 0 0',
}}>
Cliquez sur un écran pour le prévisualiser
@@ -51,12 +54,13 @@ export function Gallery({ onSelectScreen, onShowStories, onShowSpecs }: GalleryP
onClick={onShowStories}
style={{
background: 'none',
border: '2px solid var(--sketch-black)',
border: '2px solid var(--tool-border)',
borderRadius: '255px 15px 225px 15px/15px 225px 15px 255px',
padding: '8px 16px',
fontFamily: 'var(--font-sketch)',
fontSize: 14,
cursor: 'pointer',
color: 'var(--tool-text)',
}}
>
User Stories
@@ -67,9 +71,9 @@ export function Gallery({ onSelectScreen, onShowStories, onShowSpecs }: GalleryP
<button
onClick={onShowSpecs}
style={{
background: 'var(--sketch-black)',
color: 'var(--sketch-white)',
border: '2px solid var(--sketch-black)',
background: 'var(--tool-text)',
color: 'var(--tool-bg)',
border: '2px solid var(--tool-border)',
borderRadius: '255px 15px 225px 15px/15px 225px 15px 255px',
padding: '8px 16px',
fontFamily: 'var(--font-sketch)',
@@ -88,7 +92,7 @@ export function Gallery({ onSelectScreen, onShowStories, onShowSpecs }: GalleryP
gap: 12,
fontFamily: 'var(--font-sketch)',
}}>
<span style={{ fontSize: 14, color: 'var(--sketch-gray)' }}>Zoom</span>
<span style={{ fontSize: 14, color: 'var(--tool-text-muted)' }}>Zoom</span>
<input
type="range"
min={MIN_SCALE * 100}
@@ -97,11 +101,14 @@ export function Gallery({ onSelectScreen, onShowStories, onShowSpecs }: GalleryP
onChange={(e) => setScale(Number(e.target.value) / 100)}
style={{
width: 100,
accentColor: 'var(--sketch-black)',
accentColor: 'var(--tool-text)',
}}
/>
<span style={{ fontSize: 14, width: 40 }}>{Math.round(scale * 100)}%</span>
</div>
{/* Theme toggle */}
<ThemeToggle />
</div>
</div>
</div>
@@ -114,7 +121,7 @@ export function Gallery({ onSelectScreen, onShowStories, onShowSpecs }: GalleryP
fontFamily: 'var(--font-sketch)',
fontSize: 18,
margin: '0 0 16px 32px',
color: 'var(--sketch-black)',
color: 'var(--tool-text)',
}}>
{group.name}
</h2>
@@ -179,7 +186,7 @@ function GalleryItem({ screen, scale, onClick }: GalleryItemProps) {
fontSize: 14,
textAlign: 'center',
marginTop: 8,
color: 'var(--sketch-black)',
color: 'var(--tool-text)',
}}>
{screen.name}
</p>
+59
View File
@@ -0,0 +1,59 @@
import React from 'react';
import { useTheme } from '../context/ThemeContext';
import { Sun, Moon, Monitor } from 'lucide-react';
export function ThemeToggle() {
const { theme, setTheme } = useTheme();
const cycleTheme = () => {
if (theme === 'system') setTheme('light');
else if (theme === 'light') setTheme('dark');
else setTheme('system');
};
const getIcon = () => {
switch (theme) {
case 'light':
return <Sun size={18} />;
case 'dark':
return <Moon size={18} />;
case 'system':
return <Monitor size={18} />;
}
};
const getLabel = () => {
switch (theme) {
case 'light':
return 'Clair';
case 'dark':
return 'Sombre';
case 'system':
return 'Auto';
}
};
return (
<button
onClick={cycleTheme}
title={`Mode: ${getLabel()} (cliquez pour changer)`}
style={{
display: 'flex',
alignItems: 'center',
gap: 6,
background: 'none',
border: '2px solid var(--tool-border)',
borderRadius: '255px 15px 225px 15px/15px 225px 15px 255px',
padding: '6px 12px',
fontFamily: 'var(--font-sketch)',
fontSize: 14,
cursor: 'pointer',
color: 'var(--tool-text)',
transition: 'all 0.2s ease',
}}
>
{getIcon()}
<span>{getLabel()}</span>
</button>
);
}
+59 -48
View File
@@ -10,6 +10,7 @@ import {
type StoryCategory,
} from '../data';
import { getScreen, screens } from '../screens';
import { ThemeToggle } from './ThemeToggle';
interface UserStoriesPageProps {
selectedStoryId?: string;
@@ -101,64 +102,71 @@ export function UserStoriesPage({ selectedStoryId, onBack, onSelectScreen }: Use
const hasFilters = selectedCategories.size > 0 || selectedPriorities.size > 0 || selectedScreens.size > 0;
return (
<div style={{ minHeight: '100vh', background: 'var(--sketch-white)' }}>
<div style={{ minHeight: '100vh', background: 'var(--tool-bg)', transition: 'background-color 0.2s ease' }}>
{/* Header */}
<div style={{
padding: '24px 32px',
borderBottom: '2px solid var(--sketch-black)',
background: 'var(--sketch-white)',
borderBottom: '2px solid var(--tool-border)',
background: 'var(--tool-surface)',
display: 'flex',
alignItems: 'center',
gap: 16,
justifyContent: 'space-between',
transition: 'background-color 0.2s ease, border-color 0.2s ease',
}}>
<button
onClick={onBack}
style={{
background: 'none',
border: '2px solid var(--sketch-black)',
borderRadius: '255px 15px 225px 15px/15px 225px 15px 255px',
padding: '8px 16px',
fontFamily: 'var(--font-sketch)',
fontSize: 14,
cursor: 'pointer',
}}
>
Retour
</button>
<div>
<h1 style={{
fontFamily: 'var(--font-sketch)',
fontSize: 28,
margin: 0,
}}>
User Stories
</h1>
<p style={{
fontFamily: 'var(--font-sketch)',
fontSize: 16,
color: 'var(--sketch-gray)',
margin: '8px 0 0 0',
}}>
{filteredStories.length} / {userStories.length} stories · Cliquez sur un écran pour voir le mockup
</p>
<div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
<button
onClick={onBack}
style={{
background: 'none',
border: '2px solid var(--tool-border)',
borderRadius: '255px 15px 225px 15px/15px 225px 15px 255px',
padding: '8px 16px',
fontFamily: 'var(--font-sketch)',
fontSize: 14,
cursor: 'pointer',
color: 'var(--tool-text)',
}}
>
Retour
</button>
<div>
<h1 style={{
fontFamily: 'var(--font-sketch)',
fontSize: 28,
margin: 0,
color: 'var(--tool-text)',
}}>
User Stories
</h1>
<p style={{
fontFamily: 'var(--font-sketch)',
fontSize: 16,
color: 'var(--tool-text-muted)',
margin: '8px 0 0 0',
}}>
{filteredStories.length} / {userStories.length} stories · Cliquez sur un écran pour voir le mockup
</p>
</div>
</div>
<ThemeToggle />
</div>
{/* Filter bar */}
<div style={{
padding: '16px 32px',
borderBottom: '1px solid var(--sketch-light-gray)',
background: 'var(--sketch-white)',
borderBottom: '1px solid var(--tool-border-light)',
background: 'var(--tool-surface)',
display: 'flex',
flexDirection: 'column',
gap: 12,
transition: 'background-color 0.2s ease, border-color 0.2s ease',
}}>
{/* Category filters */}
<div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
<span style={{
fontFamily: 'var(--font-sketch)',
fontSize: 13,
color: 'var(--sketch-gray)',
color: 'var(--tool-text-muted)',
minWidth: 70,
}}>
Catégorie
@@ -179,7 +187,7 @@ export function UserStoriesPage({ selectedStoryId, onBack, onSelectScreen }: Use
<span style={{
fontFamily: 'var(--font-sketch)',
fontSize: 13,
color: 'var(--sketch-gray)',
color: 'var(--tool-text-muted)',
minWidth: 70,
}}>
Priorité
@@ -200,7 +208,7 @@ export function UserStoriesPage({ selectedStoryId, onBack, onSelectScreen }: Use
<span style={{
fontFamily: 'var(--font-sketch)',
fontSize: 13,
color: 'var(--sketch-gray)',
color: 'var(--tool-text-muted)',
minWidth: 70,
}}>
Écran
@@ -209,7 +217,7 @@ export function UserStoriesPage({ selectedStoryId, onBack, onSelectScreen }: Use
<FilterChip
key={screen.id}
label={screen.name}
color="var(--sketch-black)"
color="var(--tool-text)"
selected={selectedScreens.has(screen.id)}
onClick={() => toggleScreen(screen.id)}
/>
@@ -243,7 +251,7 @@ export function UserStoriesPage({ selectedStoryId, onBack, onSelectScreen }: Use
<p style={{
fontFamily: 'var(--font-sketch)',
fontSize: 16,
color: 'var(--sketch-gray)',
color: 'var(--tool-text-muted)',
textAlign: 'center',
padding: 40,
}}>
@@ -259,6 +267,7 @@ export function UserStoriesPage({ selectedStoryId, onBack, onSelectScreen }: Use
display: 'flex',
alignItems: 'center',
gap: 12,
color: 'var(--tool-text)',
}}>
<span style={{
display: 'inline-block',
@@ -273,7 +282,7 @@ export function UserStoriesPage({ selectedStoryId, onBack, onSelectScreen }: Use
Priorité {priorityLabels[priority]}
<span style={{
fontSize: 14,
color: 'var(--sketch-gray)',
color: 'var(--tool-text-muted)',
fontWeight: 'normal',
}}>
({stories.length} stories)
@@ -345,10 +354,10 @@ const StoryCard = React.forwardRef<HTMLDivElement, StoryCardProps>(
<div
ref={ref}
style={{
border: isSelected ? '3px solid #2563eb' : '2px solid var(--sketch-black)',
border: isSelected ? '3px solid #2563eb' : '2px solid var(--tool-border)',
borderRadius: '255px 15px 225px 15px/15px 225px 15px 255px',
padding: 16,
background: isSelected ? '#eff6ff' : 'var(--sketch-white)',
background: isSelected ? '#eff6ff' : 'var(--tool-surface)',
transition: 'all 0.2s ease',
}}
>
@@ -370,6 +379,7 @@ const StoryCard = React.forwardRef<HTMLDivElement, StoryCardProps>(
fontFamily: 'var(--font-sketch)',
fontSize: 16,
margin: 0,
color: 'var(--tool-text)',
}}>
{story.title}
</h3>
@@ -378,7 +388,7 @@ const StoryCard = React.forwardRef<HTMLDivElement, StoryCardProps>(
<p style={{
fontFamily: 'var(--font-sketch)',
fontSize: 13,
color: 'var(--sketch-gray)',
color: 'var(--tool-text-muted)',
margin: '0 0 12px 0',
lineHeight: 1.5,
}}>
@@ -392,13 +402,14 @@ const StoryCard = React.forwardRef<HTMLDivElement, StoryCardProps>(
key={id}
onClick={() => onSelectScreen(id)}
style={{
background: 'var(--sketch-light-gray)',
border: '1px solid var(--sketch-black)',
background: 'var(--tool-border-light)',
border: '1px solid var(--tool-border)',
borderRadius: '255px 15px 225px 15px/15px 225px 15px 255px',
padding: '6px 12px',
fontFamily: 'var(--font-sketch)',
fontSize: 13,
cursor: 'pointer',
color: 'var(--tool-text)',
}}
>
{screen!.name}
@@ -409,7 +420,7 @@ const StoryCard = React.forwardRef<HTMLDivElement, StoryCardProps>(
<p style={{
fontFamily: 'var(--font-sketch)',
fontSize: 13,
color: 'var(--sketch-gray)',
color: 'var(--tool-text-muted)',
fontStyle: 'italic',
margin: 0,
}}>
+2 -1
View File
@@ -13,7 +13,7 @@ export function PhoneFrame({ children, scale = 1, className = '' }: PhoneFramePr
return (
<div
className={className}
className={`phone-frame-wrapper ${className}`}
style={{
width: width * scale,
height: height * scale,
@@ -67,6 +67,7 @@ export function PhoneFrame({ children, scale = 1, className = '' }: PhoneFramePr
fontSize: 12 * scale,
fontFamily: 'var(--font-sketch)',
flexShrink: 0,
color: 'var(--sketch-black)',
}}
>
<span>9:41</span>
+3
View File
@@ -8,6 +8,7 @@ import { Card, CardHeader, CardTitle, CardContent, CardDescription } from '../ui
import { Button } from '../ui/button';
import { ArrowLeft, FileText, Monitor, CheckCircle2, XCircle, AlertCircle, ExternalLink } from 'lucide-react';
import type { ParsedFeature } from '../../types/gherkin';
import { ThemeToggle } from '../ThemeToggle';
interface SpecsPageProps {
selectedFeatureId?: string;
@@ -109,8 +110,10 @@ export function SpecsPage({ selectedFeatureId, onBack, onSelectScreen, onSelectS
Rapport HTML
</Button>
</a>
<ThemeToggle />
</div>
)}
{testSummary.totalScenarios === 0 && <ThemeToggle />}
</div>
</div>
+83
View File
@@ -0,0 +1,83 @@
import React, { createContext, useContext, useEffect, useState, type ReactNode } from 'react';
type Theme = 'light' | 'dark' | 'system';
interface ThemeContextValue {
theme: Theme;
resolvedTheme: 'light' | 'dark';
setTheme: (theme: Theme) => void;
}
const ThemeContext = createContext<ThemeContextValue | null>(null);
const STORAGE_KEY = 'festipod-theme';
function getSystemTheme(): 'light' | 'dark' {
if (typeof window === 'undefined') return 'light';
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
function getStoredTheme(): Theme {
if (typeof window === 'undefined') return 'system';
const stored = localStorage.getItem(STORAGE_KEY);
if (stored === 'light' || stored === 'dark' || stored === 'system') {
return stored;
}
return 'system';
}
export function ThemeProvider({ children }: { children: ReactNode }) {
const [theme, setThemeState] = useState<Theme>(getStoredTheme);
const [resolvedTheme, setResolvedTheme] = useState<'light' | 'dark'>(
theme === 'system' ? getSystemTheme() : theme
);
const setTheme = (newTheme: Theme) => {
setThemeState(newTheme);
localStorage.setItem(STORAGE_KEY, newTheme);
};
useEffect(() => {
const resolved = theme === 'system' ? getSystemTheme() : theme;
setResolvedTheme(resolved);
const root = document.documentElement;
if (resolved === 'dark') {
root.classList.add('dark');
} else {
root.classList.remove('dark');
}
}, [theme]);
useEffect(() => {
if (theme !== 'system') return;
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
const handler = (e: MediaQueryListEvent) => {
setResolvedTheme(e.matches ? 'dark' : 'light');
const root = document.documentElement;
if (e.matches) {
root.classList.add('dark');
} else {
root.classList.remove('dark');
}
};
mediaQuery.addEventListener('change', handler);
return () => mediaQuery.removeEventListener('change', handler);
}, [theme]);
return (
<ThemeContext.Provider value={{ theme, resolvedTheme, setTheme }}>
{children}
</ThemeContext.Provider>
);
}
export function useTheme() {
const context = useContext(ThemeContext);
if (!context) {
throw new Error('useTheme must be used within a ThemeProvider');
}
return context;
}
+33 -2
View File
@@ -10,6 +10,24 @@
--sketch-accent: #4a90d9;
--sketch-line-width: 2px;
--font-sketch: 'Architects Daughter', cursive;
/* Prototyping tool theme (outer app) */
--tool-bg: #fafafa;
--tool-surface: #ffffff;
--tool-text: #2d2d2d;
--tool-text-muted: #666;
--tool-border: #2d2d2d;
--tool-border-light: #e5e5e5;
}
/* Dark mode for prototyping tool only */
.dark {
--tool-bg: #1a1a1a;
--tool-surface: #2d2d2d;
--tool-text: #f5f5f5;
--tool-text-muted: #a0a0a0;
--tool-border: #4a4a4a;
--tool-border-light: #3a3a3a;
}
* {
@@ -18,10 +36,11 @@
body {
font-family: var(--font-sketch);
background-color: var(--sketch-bg);
color: var(--sketch-black);
background-color: var(--tool-bg);
color: var(--tool-text);
margin: 0;
padding: 0;
transition: background-color 0.2s ease, color 0.2s ease;
}
/* Sketchy border effect using border-radius variations */
@@ -312,6 +331,18 @@ body {
- Blue = user-provided content only (names, event titles, descriptions, usernames)
=========================================== */
/* Force phone screen to always use light mode colors */
.phone-screen {
color: var(--sketch-black);
background: var(--sketch-white);
}
/* Dark mode: add outer glow to phone frame for visibility */
.dark .phone-frame-wrapper {
box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.15);
border-radius: 44px;
}
/* User content - displayed in blue */
.phone-screen .user-content {
color: var(--sketch-accent);