|
| 1 | +# Google Material 3 (M3) Expressive Design Rules |
| 2 | + |
| 3 | +> **MANDATE:** All UI components, pages, views, modals, cards, widgets, and styles in `web/` must strictly adhere to Google Material 3 (M3) Expressive Design principles. Arbitrary hex colors, harsh drop shadows, sharp rectangular interactive elements, and un-scaled typography are strictly prohibited. |
| 4 | +
|
| 5 | +--- |
| 6 | + |
| 7 | +## 1. Core Design Philosophy |
| 8 | + |
| 9 | +Google Material 3 Expressive evolves Material Design into an emotional, tactile, and highly structured visual language: |
| 10 | +1. **Expressive Tone & Emotion**: UI is not merely functional; it conveys intent, hierarchy, and delight through deliberate color harmonies, organic shapes, and responsive physics. |
| 11 | +2. **Tonal Elevation over Drop Shadows**: Surfaces communicate depth through layered **Surface Containers** and tonal shifts rather than heavy, blurry drop shadows. |
| 12 | +3. **Shape as Hierarchy**: Curvature signals interactivity and role. High-curvature shapes (pills, squircles, `rounded-full`, `rounded-2xl`) create clear visual distinction between containers and action triggers. |
| 13 | +4. **Purposeful Motion**: Every transition is tactile, using spring-like physics and emphasized decelerations. Actions provide instant micro-feedback (`scale-[0.98]` press state). |
| 14 | +5. **Accessibility by Default**: High contrast ratios (WCAG AA/AAA), 48x48dp minimum touch targets, visible 2px offset focus rings, and full `prefers-reduced-motion` compliance. |
| 15 | + |
| 16 | +--- |
| 17 | + |
| 18 | +## 2. Color System & Dynamic Tonal Palette |
| 19 | + |
| 20 | +Never use arbitrary hex values or untyped colors. Always use M3 role-based semantic tokens: |
| 21 | + |
| 22 | +### Primary, Secondary, and Tertiary Roles |
| 23 | + |
| 24 | +| Token | CSS Variable | Purpose | |
| 25 | +|---|---|---| |
| 26 | +| **Primary** | `--md-sys-color-primary` | Key interactive actions, primary buttons, active indicator pills | |
| 27 | +| **On-Primary** | `--md-sys-color-on-primary` | Text and icons placed on top of Primary | |
| 28 | +| **Primary Container** | `--md-sys-color-primary-container` | High-prominence container surfaces needing emphasis without solid fill | |
| 29 | +| **On-Primary Container** | `--md-sys-color-on-primary-container` | Text and icons on Primary Container | |
| 30 | +| **Secondary** | `--md-sys-color-secondary` | Less prominent components, filter chips, secondary toggles | |
| 31 | +| **On-Secondary** | `--md-sys-color-on-secondary` | Text/icons on Secondary | |
| 32 | +| **Secondary Container** | `--md-sys-color-secondary-container` | Medium-emphasis containers, tonal buttons, active nav indicators | |
| 33 | +| **On-Secondary Container** | `--md-sys-color-on-secondary-container` | Text/icons on Secondary Container | |
| 34 | +| **Tertiary** | `--md-sys-color-tertiary` | **Expressive accent**: contrasting warm/vibrant hue for highlights, badges, AI insights | |
| 35 | +| **On-Tertiary** | `--md-sys-color-on-tertiary` | Text/icons on Tertiary | |
| 36 | +| **Tertiary Container** | `--md-sys-color-tertiary-container` | Expressive cards, special callouts, AI insight banners | |
| 37 | +| **On-Tertiary Container** | `--md-sys-color-on-tertiary-container` | Text/icons on Tertiary Container | |
| 38 | +| **Error** | `--md-sys-color-error` | Critical errors, destructive actions | |
| 39 | +| **Error Container** | `--md-sys-color-error-container` | Warning/error cards, danger banners | |
| 40 | + |
| 41 | +### Tonal Surface Hierarchy |
| 42 | + |
| 43 | +Do **not** use flat, monochromatic cards or arbitrary background shades. Layer depth using the 5-tier Surface Container system: |
| 44 | + |
| 45 | +``` |
| 46 | +┌────────────────────────────────────────────────────────┐ |
| 47 | +│ Surface Container Highest (Dialogs, Menus, Modals) │ |
| 48 | +│ ┌──────────────────────────────────────────────────┐ │ |
| 49 | +│ │ Surface Container High (Floating Bars, Popovers) │ │ |
| 50 | +│ │ ┌────────────────────────────────────────────┐ │ │ |
| 51 | +│ │ │ Surface Container (Standard Cards, Sheets) │ │ │ |
| 52 | +│ │ │ ┌──────────────────────────────────────┐ │ │ │ |
| 53 | +│ │ │ │ Surface Container Low (Subtle Panels)│ │ │ │ |
| 54 | +│ │ │ │ ┌────────────────────────────────┐ │ │ │ │ |
| 55 | +│ │ │ │ │ Surface / Lowest (Canvas/Page) │ │ │ │ │ |
| 56 | +``` |
| 57 | + |
| 58 | +- **`surface-container-lowest`**: Recessed areas, code editors, sunken background tracks. |
| 59 | +- **`surface-container-low`**: Structural sidebars, secondary grouping panels. |
| 60 | +- **`surface-container`**: Default standard cards, list rows, content panels. |
| 61 | +- **`surface-container-high`**: Elevated search bars, active tabs, floating headers. |
| 62 | +- **`surface-container-highest`**: Modals, dropdown menus, context popovers. |
| 63 | + |
| 64 | +### State Layers |
| 65 | + |
| 66 | +Interactive states must apply semi-transparent state overlays (rather than abruptly jumping color): |
| 67 | +- **Hover**: 8% opacity tint of the element's on-color |
| 68 | +- **Focus**: 12% opacity tint + 2px offset outline |
| 69 | +- **Press / Active**: 12% opacity tint + `scale-[0.98]` tactile dip |
| 70 | +- **Drag**: 16% opacity tint + Level 3 elevation |
| 71 | + |
| 72 | +--- |
| 73 | + |
| 74 | +## 3. Expressive Geometry & Shape Scale |
| 75 | + |
| 76 | +Material 3 Expressive pairs structured layouts with organic, rounded geometry: |
| 77 | + |
| 78 | +| Shape Token | Radius | Allowed Components | |
| 79 | +|---|---|---| |
| 80 | +| **None** | `0px` (`rounded-none`) | Full-bleed screen dividers, edge-to-edge layout borders | |
| 81 | +| **Extra Small** | `4px` (`rounded-xs`) | Micro tags, dense table inline badges | |
| 82 | +| **Small** | `8px` (`rounded-sm`) | Code snippets, compact data chips, inner item blocks | |
| 83 | +| **Medium** | `12px` (`rounded-md`) | Form inputs, select dropdowns, segmented button items | |
| 84 | +| **Large** | `16px` (`rounded-lg` / `rounded-xl`) | Standard content cards, snackbars, sub-panels | |
| 85 | +| **Extra Large** | `24px`–`28px` (`rounded-2xl` / `rounded-3xl`) | Modal dialogs, floating action sheets, hero cards | |
| 86 | +| **Full (Pill)** | `9999px` (`rounded-full`) | **Buttons**, **Filter chips**, **Status badges**, **Search bars**, **Floating pills** | |
| 87 | + |
| 88 | +### Shape Rules: |
| 89 | +- **Buttons must be Pill (`rounded-full`)**: Primary, secondary, tonal, and outline action buttons must use full pill curvature. |
| 90 | +- **Cards must be `rounded-2xl` (16px) or `rounded-3xl` (24px)**: Never use sharp, boxy 4px/8px corners for main UI cards. |
| 91 | +- **Badges & Chips must be Pill (`rounded-full`)**: Filter chips, status pills, and counter tags must be fully rounded. |
| 92 | + |
| 93 | +--- |
| 94 | + |
| 95 | +## 4. Typography Scale & Hierarchy |
| 96 | + |
| 97 | +Use the M3 15-step typography scale. All text must strictly map to one of these roles: |
| 98 | + |
| 99 | +1. **Display (Large 57px, Medium 45px, Small 36px)**: |
| 100 | + - For hero KPI numbers, executive summary scores, and landing headlines. |
| 101 | + - Tracking: `-0.25px` to `-0.5px` (tight, expressive). |
| 102 | +2. **Headline (Large 32px, Medium 28px, Small 24px)**: |
| 103 | + - For page titles and primary view section headers. |
| 104 | + - Font weight: `font-semibold` or `font-bold`. |
| 105 | +3. **Title (Large 22px, Medium 16px, Small 14px)**: |
| 106 | + - For card headers, list section dividers, and modal titles. |
| 107 | + - Font weight: `font-semibold`. |
| 108 | +4. **Body (Large 16px, Medium 14px, Small 12px)**: |
| 109 | + - For descriptive copy, analysis paragraphs, and data cell content. |
| 110 | + - Line height: Generous (`leading-relaxed`), font weight: `font-normal`. |
| 111 | +5. **Label (Large 14px, Medium 12px, Small 11px)**: |
| 112 | + - For buttons, chip labels, table column headers, and form input labels. |
| 113 | + - Font weight: `font-medium`, tracking: `tracking-wide`. |
| 114 | + |
| 115 | +--- |
| 116 | + |
| 117 | +## 5. Tonal Elevation & Surface Depth |
| 118 | + |
| 119 | +- **Level 0 (0dp)**: Flat surface, no elevation (`shadow-none`). |
| 120 | +- **Level 1 (1dp)**: Subtle separation, Surface Container Low (`--elevation-1`). |
| 121 | +- **Level 2 (3dp)**: Standard elevated cards, Surface Container (`--elevation-2`). |
| 122 | +- **Level 3 (6dp)**: Floating bars, filter pills, dropdowns. |
| 123 | +- **Level 4 (8dp)**: Modal dialogs, navigation drawers (`--elevation-3`). |
| 124 | +- **Level 5 (12dp)**: Floating Action Buttons (FAB), drag previews. |
| 125 | + |
| 126 | +*Rule:* Never apply dark, heavy CSS box shadows. Depth is communicated 90% by container tone and 10% by soft, ambient occlusion. |
| 127 | + |
| 128 | +--- |
| 129 | + |
| 130 | +## 6. Motion & Spring Physics |
| 131 | + |
| 132 | +Material 3 Expressive motion feels spring-like, physical, and alive: |
| 133 | + |
| 134 | +### Easing Tokens |
| 135 | +- **Emphasized Decelerate**: `cubic-bezier(0.05, 0.7, 0.1, 1.0)` (elements entering screen or expanding) |
| 136 | +- **Emphasized Accelerate**: `cubic-bezier(0.3, 0, 0.8, 0.15)` (elements exiting screen) |
| 137 | +- **Standard Spring**: `cubic-bezier(0.2, 0, 0, 1)` (hover, toggle, state transitions) |
| 138 | + |
| 139 | +### Durations |
| 140 | +- Micro-interactions (hover, focus, chip toggle): `150ms`–`200ms` |
| 141 | +- Medium transitions (sheet open, expand card): `250ms`–`350ms` |
| 142 | +- Large transitions (dialog open, page transition): `400ms`–`500ms` |
| 143 | + |
| 144 | +### Interactive Tactile Feedback: |
| 145 | +- All interactive elements must include active press scaling: `active:scale-[0.98]` or `.press`. |
| 146 | +- Card hover states must lift smoothly with `transition-all duration-200 ease-out hover:-translate-y-0.5`. |
| 147 | +- Grids and lists must feature staggered reveal transitions (30ms–50ms stagger per child). |
| 148 | +- **Reduced Motion**: Always include `motion-reduce:transition-none motion-reduce:transform-none`. |
| 149 | + |
| 150 | +--- |
| 151 | + |
| 152 | +## 7. Component Standards & Recipes |
| 153 | + |
| 154 | +### Buttons |
| 155 | +- **Filled Button (Primary)**: |
| 156 | + `rounded-full bg-md-sys-primary text-md-sys-on-primary font-medium px-5 py-2.5 transition-all duration-200 hover:shadow-md active:scale-[0.98]` |
| 157 | +- **Filled Tonal Button (Medium emphasis)**: |
| 158 | + `rounded-full bg-md-sys-secondary-container text-md-sys-on-secondary-container font-medium px-5 py-2.5 transition-all hover:bg-opacity-90 active:scale-[0.98]` |
| 159 | +- **Outlined Button**: |
| 160 | + `rounded-full border border-md-sys-outline text-md-sys-primary font-medium px-5 py-2.5 transition-all hover:bg-md-sys-primary/8 active:scale-[0.98]` |
| 161 | +- **Text Button**: |
| 162 | + `rounded-full text-md-sys-primary font-medium px-3 py-2 transition-all hover:bg-md-sys-primary/8 active:scale-[0.98]` |
| 163 | +- **Floating Action Button (FAB)**: |
| 164 | + `rounded-2xl bg-md-sys-primary-container text-md-sys-on-primary-container p-4 shadow-lg hover:shadow-xl active:scale-[0.96]` |
| 165 | + |
| 166 | +### Cards |
| 167 | +- Container: `bg-md-sys-surface-container rounded-2xl p-6 border border-md-sys-outline-variant/50 transition-all` |
| 168 | +- Clickable/Interactive Card: Add `hover:shadow-md hover:-translate-y-0.5 cursor-pointer active:scale-[0.99]` |
| 169 | +- **Mandatory Repository Rule**: Every report card and dashboard widget MUST wire `devData` on `<Card devData={...}>` (see `AGENT.md` § Dev widget JSON copy). |
| 170 | + |
| 171 | +### Chips & Badges |
| 172 | +- Filter Chip: `rounded-full px-4 py-1.5 text-xs font-medium border border-md-sys-outline transition-all` |
| 173 | +- Selected Chip: `bg-md-sys-secondary-container text-md-sys-on-secondary-container border-transparent` |
| 174 | +- Status Badge: `rounded-full px-3 py-1 text-xs font-semibold inline-flex items-center gap-1.5` |
| 175 | + |
| 176 | +### Form Controls & Inputs |
| 177 | +- Container: `bg-md-sys-surface-container-high rounded-xl border border-md-sys-outline-variant px-4 py-3 text-md-sys-on-surface` |
| 178 | +- Focus State: `focus:outline-none focus:ring-2 focus:ring-md-sys-primary focus:border-transparent` |
| 179 | +- Helper Text: `text-xs text-md-sys-on-surface-variant mt-1.5` |
| 180 | + |
| 181 | +--- |
| 182 | + |
| 183 | +## 8. Developer & Agent Strict Checklist |
| 184 | + |
| 185 | +Before committing any UI change in `web/`, verify each item: |
| 186 | + |
| 187 | +- [ ] **Color Roles**: Are colors sourced from M3 role tokens (`md-sys-*`) instead of hardcoded hex colors? |
| 188 | +- [ ] **Surface Containers**: Is depth layered using `surface-container-*` rather than arbitrary background grays? |
| 189 | +- [ ] **Shape Curvature**: Are action buttons and chips pill-shaped (`rounded-full`)? Are cards `rounded-2xl` or `rounded-3xl`? |
| 190 | +- [ ] **Typography Scale**: Do text elements strictly follow Display / Headline / Title / Body / Label hierarchy? |
| 191 | +- [ ] **Tactile Press**: Do buttons and clickable cards have active press feedback (`active:scale-[0.98]` / `.press`)? |
| 192 | +- [ ] **Dev Widget Copy**: Does every card/widget pass `devData` to `<Card>` or render `<DevCopyJsonButton>`? |
| 193 | +- [ ] **Accessibility**: Does the touch target meet 48x48dp minimum? Does text contrast exceed 4.5:1? Is there a visible focus ring? |
| 194 | +- [ ] **Dark Mode**: Do all components render cleanly in both Light mode and `html.dark` mode? |
0 commit comments