# Phase 4: Visual & Styling Enhancements **Status:** ✅ Complete **Parent plan:** [PLAN.md](./PLAN.md) **Domain:** frontend ## Objective Implement all 6 visual/styling features: glassmorphism cards, board-level themes, animated status rings, card size options, custom CSS injection, and wallpaper backgrounds. ## Tasks ### 4.1 Glassmorphism Card Style - [x] Add card style system to theme store — extend `src/lib/stores/theme.svelte.ts`: - New property: `cardStyle: 'solid' | 'glass' | 'outline'` (default: 'solid') - Persist to localStorage, broadcast across tabs - [x] Add CSS classes in `src/app.css`: - `.card-solid` — current default card style - `.card-glass` — `backdrop-filter: blur(12px); background: hsl(var(--card) / 0.6); border: 1px solid hsl(var(--border) / 0.3)` - `.card-outline` — `background: transparent; border: 1px solid hsl(var(--border))` - [x] Update widget/card components to use dynamic card style class - [x] Add card style picker to theme settings UI (3-way toggle: solid/glass/outline) ### 4.2 Board-Level Themes - [x] Create `src/lib/components/board/BoardThemeProvider.svelte` - Reads board's themeHue, themeSaturation, backgroundType from board data - Overrides CSS variables when viewing that board (--primary-h, --primary-s) - Smooth transition when switching boards (CSS transition on :root variables) - Restores global theme when navigating away from the board - [x] Update board edit form to include theme settings: - Hue slider (0-360 with color preview) - Saturation slider (0-100) - Background type selector (mesh/particles/aurora/none/wallpaper) - [x] Update board data loading to include theme fields - [x] Fix updateBoard server action to extract theme fields from formData - [x] Fix backgroundType validator to accept all background types (mesh/particles/aurora/wallpaper/none) ### 4.3 Animated SVG Status Ring - [x] Create `src/lib/components/app/AnimatedStatusRing.svelte` - SVG circle around app icon with status-dependent animation: - Online: animated green fill sweep (stroke-dashoffset animation) - Offline: pulsing red ring (opacity animation) - Degraded: partial yellow arc (75% fill, subtle pulse) - Unknown: gray dashed ring (rotating dash pattern) - Props: status, size (scales with card size), animated (boolean) - [x] Replace static status dots in AppWidget.svelte with AnimatedStatusRing - [x] Ensure ring scales appropriately with compact/medium/large card sizes ### 4.4 Card Size Options - [x] Add `CardSize` support to section and board levels: - Per-section: `section.cardSize` overrides board default - Per-board: `board.cardSize` as fallback - Global default: 'medium' - [x] Create card size variants in widget components: - `compact` — icon + name only, smaller padding, single row grid - `medium` — current default (icon + name + status + description on hover) - `large` — icon + name + description + sparkline + tags, more padding - [x] Add card size picker to section edit form (DraggableSection) and board settings - [x] Update WidgetGrid to adjust grid columns based on card size - [x] Wire up onUpdateSection handler through DraggableBoard to board edit page ### 4.5 Custom CSS Injection - [x] Create `src/lib/components/settings/CustomCssEditor.svelte` - Textarea with monospace font for custom CSS - Live preview toggle - Sanitization: strip `