Skeuomorphism — Phased Rollout
The redesign ships in 8 phases, ordered so the highest-leverage, lowest-risk work lands first (the shared token layer + primitives repaint the whole app at once). Each phase lists scope, files, acceptance criteria, and status.
Legend: ✅ Shipped · 🟡 In progress · ⏳ Planned.
Phase 0 — Tokens & material system ✅
Scope. The elevation/material foundation everything else builds on: two material colours (--tactile-hi/lo), the five elevation shadows (raised, raised-hover, floating, well, pressed), the --sheen-top gradient, and the .sheen / .glass utilities — all with light and dark values. Tailwind boxShadow mappings so components can use shadow-raised etc.
Files. app/globals.css (tokens + utilities), tailwind.config.ts (boxShadow).
Acceptance.
- All five
shadow-*utilities resolve in light and dark. .sheenand.glassrender,.glasshas a@supportsfallback.- No component hardcodes a shadow.
Status. ✅ Shipped.
Phase 1 — Core primitives ✅
Scope. The shared UI kit that appears on every screen — repainting these transforms ~80% of the surface area:
- Card → raised material (
sheen shadow-raised, softened border). - Button (primary / secondary / outline / destructive / ghost) → tactile: sheen +
shadow-raised, hover lift,:activepress-in; ghost stays flat. - Input / Select / Textarea → recessed wells (
bg-surface-sunken shadow-well) that flatten to a plain field on focus.
Files. components/ui/{card,button,input,select,textarea}.tsx.
Acceptance.
- KPI tiles and cards read as raised panels; inputs read as carved wells.
- Buttons visibly lift on hover and press on click; disabled buttons stay flat.
tscclean; existing pages unchanged structurally.
Status. ✅ Shipped. (Evidence: docs/engineering/qa-evidence/skeu-chiller.png.)
Phase 2 — Navigation & chrome ⏳
Scope.
- Top bar →
.glass(frosted, translucent) with a hairline bottom border; content scrolls under it. - Sidebar → a raised rail; the active nav item becomes a pressed/recessed pill (selected = pushed in), inactive items flat with hover lift.
- Page headers, tabs (active tab raised, inactive recessed), breadcrumbs, command palette (
⌘K) as a floating glass panel.
Files. components/app/{topbar,sidebar,page-header}.tsx (or equivalents in components/admin/ui), lib/nav.tsx consumers, command-palette component.
Acceptance. Top bar is frosted over scrolled content; the current route's nav item is unmistakably "pressed"; keyboard focus and contrast preserved.
Phase 3 — Data surfaces ⏳
Scope.
- Tables → raised container, inset header strip, subtle zebra; row hover lifts faintly.
- KPI tiles → refine the Phase-1 Card treatment (tighter sheen, value emphasis).
- Meters / progress bars → inset track (well) with a raised fill — a physical gauge; reuse for load bars, circuit share bars, NILM stacked bar, staging load.
- Badges / status pills → subtle inset chips; keep icon+label+colour for status (UX_patterns §3.1).
- Sparkline framing → seat charts in a faint recessed plate.
Files. table components, components/**/console.tsx bar/meter markup, components/ui/badge.tsx.
Acceptance. Progress/meter tracks look carved with a raised fill; tables have clear header/body depth; contrast on status pills ≥ AA.
Phase 4 — Module consoles (CPMS / EMS) ⏳
Scope. The operator surfaces get true physical controls:
- Control panels → toggle switches as physical rockers (on = raised knob shifted, off = recessed), demand/limit inputs as wells, "Apply/Execute/Reconcile" as tactile primaries.
- Enabled/Sheddable toggles in the chiller/energy tables → physical switch styling.
- Plant schematic → pipes with a soft bevel, equipment blocks as raised modules, running state with an emissive glow; loops read as depth.
- Gauges (efficiency, forecast peak) → recessed dial faces with a raised needle/arc.
Files. components/chillers/*, components/energy/*, components/fdd/findings-panel.tsx, components/chillers/plant-schematic.tsx.
Acceptance. Toggles read as switches; schematic has depth; no regression in the QA E2E flows (docs/engineering/qa_results_e2e.md).
Phase 5 — Overlays & feedback ⏳
Scope. Everything transient uses glass + shadow-floating:
- Dialog / Sheet / Popover / Dropdown / Tooltip → floating glass panels.
- Toasts / notifications → floating cards that slide + settle.
- Skeleton loaders → shimmer over a well; empty states → recessed plate with a raised icon.
Files. components/ui/dialog.tsx, popover/tooltip/toast components, skeleton/empty-state components.
Acceptance. Overlays float above content with frosted material; focus trap and Esc unaffected; motion respects reduced-motion.
Phase 6 — Dashboards & widgets 🟡
Shipped — all dashboard widgets.
- Widget frames (both grid + mobile renderers) → raised material panels (
sheen shadow-raised, softened border, recessed header strip). - Drag interaction → a dragged widget lifts to
shadow-floating; the drop placeholder reads as a recessed well cut into the canvas (react-grid-layout classes styled inglobals.css). - Widget internals → meter/share bars become carved tracks (
shadow-well) with glossy fills (sheen); sparklines are seated in a recessed "screen" plate with a soft area fill; the radial gauge has a recessed dial + raised (drop-shadowed) arc.
Files. components/dashboards/dashboard-canvas.tsx (frames), components/dashboards/widgets.tsx (Sparkline, bars, gauge), app/globals.css (rgl drag/placeholder). Evidence: evidence/dashboard-widgets.png.
Remaining ⏳.
- Dashboard canvas → a faintly recessed "board" the widgets sit on.
- Per-theme accents → verify elevation reads well under each
[data-dashboard-theme](ocean/forest/sunset/violet/midnight). - TV / war-room → higher-contrast material for at-a-distance legibility.
Acceptance. Dragging a widget visibly lifts it ✅; widget frames + internals are material ✅; canvas board depth + per-theme contrast ⏳.
Phase 7 — Polish: dark-mode, a11y, performance, visual regression ⏳
Scope.
- Dark-mode depth tuning — verify highlight/shadow balance on every surface in dark.
- Contrast audit — automated WCAG AA check on text and non-text (control edges, focus rings) after material is applied.
- Reduced-motion — confirm lift/press degrade to instant.
- Performance — cap shadow layers, ensure
backdrop-filteris only on chrome/overlays, check paint cost on large tables/dashboards; promote animating layers withwill-changeonly where needed. - Cross-browser —
backdrop-filterfallback verified (Safari/Firefox). - Visual regression — capture before/after screenshots of key pages via ego lite and diff.
Files. globals.css tuning, a11y/perf audit notes under this folder.
Acceptance. AA contrast everywhere; no jank on dashboards/tables; glass falls back gracefully; reduced-motion honoured; screenshots archived.
Sequencing & risk
- 0 → 1 are done and are the biggest visual win (shared kit). Safe: additive tokens + class swaps,
tscclean, no structural change. - 2 → 6 are independent and can run in parallel after Phase 1; each is scoped to a component group.
- 7 is the gate before calling the redesign complete.
- Rollback is trivial per phase: the changes are class-level; reverting a component restores the flat look without touching logic.