diff --git a/resources/boost/guidelines/material-3.blade.php b/resources/boost/guidelines/material-3.blade.php new file mode 100644 index 00000000..b2863777 --- /dev/null +++ b/resources/boost/guidelines/material-3.blade.php @@ -0,0 +1,58 @@ +@verbatim +## Material 3 + +Every view in this application is Material 3 Expressive (m3.material.io), through `nonameweb/livewire-material`. These rules decide what to write; the `material-3-design` skill carries the tables, the numbers and Google's source pages behind each one — activate it before designing a screen. + +### Colour +- A colour is always a role: `bg-primary`, `text-on-surface-variant`, `border-outline-variant`. Never a hex, an arbitrary value, a palette tone or an opacity; Tailwind's palette does not compile. +- Pair a role only with its `on-` partner: `bg-primary text-on-primary`, `bg-secondary-container text-on-secondary-container`. That pair is the one whose contrast is guaranteed at every contrast level; mixing pairs (`bg-primary-container text-on-surface`) is not. +- `primary` is the one key action on a screen (a filled button; the FAB in `primary-container`). `secondary-container` is the quiet fill (tonal buttons, selected navigation, selected chips). `tertiary` is a contrasting accent, used rarely. `error`, `success`, `warning`, `info` mean state and nothing else: the `-container` for a tinted panel, the role itself for its text and icon. +- Ink is `text-on-surface`; lower emphasis is `text-on-surface-variant` (`text-body`, `text-meta`); decoration is `text-outline` (`text-quiet`). Never dim ink with an opacity: 38% means disabled. +- `border-outline` is a boundary that must be read (a text field, the edge of a target). `border-outline-variant` (`border-divider`, `border-structure`, `border-chrome`) is a divider or a card edge. Never `outline` on a divider. +- Fixed and dim roles (`primary-fixed`, `surface-dim`, …) are for a colour that must not change with the theme; if unsure, don't. Inverse roles only on an inverse surface (the snackbar). +- A link is `text-primary` and underlined (`link`); colour alone signals nothing. +- Contrast: 4.5:1 for text, 3:1 for large text, icons and grouped controls; disabled is exempt. Three contrast levels exist (``: standard, medium, high) and every role changes with them — which is why only roles are allowed. + +### Surfaces and elevation +- The page is `bg-surface`. Panels separate by tone first: `surface-container-lowest` … `surface-container-highest` is a hierarchy of emphasis, not of height. Navigation chrome is `surface-container`; a dialog, a menu, the search bar are `surface-container-high`; a modal sheet is `surface-container-low`; a filled card is `surface-container-highest`. A region keeps its role at every width. +- Shadows (`shadow-elevation-1…5`) are for what floats or lifts: 1 for elevated cards, buttons and modal sheets; 2 for menus, the navigation bar, a scrolled app bar; 3 for the FAB, dialogs, pickers and search; one level more on hover; nothing rests above 3. Fewer shadows carry more meaning. +- A scrim is `bg-scrim/32`. + +### Shape +- Corners come from the scale `rounded-corner-{none|xs|sm|md|lg|lg-increased|xl|xl-increased|xxl|full}`; Tailwind's `rounded-*` does not compile. +- By family: `full` buttons, icon buttons, chips' avatars, badges, switches, sliders, the search bar, navigation indicators; `xs` text fields, menus, snackbars, plain tooltips; `sm` chips; `md` cards, rich tooltips; `lg` the FAB and a side sheet's inner corners; `xl` dialogs, bottom sheets, the search view, pickers, carousel items; `xxl` large hero containers. +- Nested shapes: inner radius = outer radius − padding; never the same radius inside and out. +- A press squares a round shape (the components do it; nothing morphs on hover). The 35 ``s are decoration, never meaning, used sparingly. + +### Type +- Every text element carries one `type-*` style: `display` for hero figures and short marketing lines; `headline` for page and section titles; `title` for card, dialog and list-section titles; `body` for paragraphs (`body-lg` for reading); `label` inside components (buttons, chips, tabs, captions). Never `text-sm`, `font-medium`, `leading-*`, `tracking-*` — they do not compile. +- `type-emphasized-*` is opt-in: a selected item, a primary action, a headline, a badge — not decoration. +- 40–60 characters per line; `tabular-nums` on figures that change; text must scale to 200% without loss (containers grow, rows wrap, no fixed heights on text, no ellipsis without a way to read the rest). + +### Motion +- Position, size and shape move on the spatial springs (they overshoot): `transition-transform duration-(--md-sys-motion-spatial-default-duration) ease-spatial-default` — `fast` for small elements, `slow` for large ones. Colour and opacity move on the effects springs (`ease-effects-*`), which never overshoot. Always pair an easing with its duration. +- Entering decelerates, a permanent exit accelerates, a temporary exit (a sheet, a drawer) takes the emphasized curve; exits are shorter than entrances. +- Everything that moves goes through these tokens, so reduced motion makes it instant; a literal duration is a bug. + +### States and targets +- Interactive elements carry `state-layer focus-ring`: hover 8%, focus 10%, pressed 10%, dragged 16% (`data-dragged`) of the content colour; disabled is `disabled:text-on-surface/38 disabled:bg-on-surface/12` and has no hover. Every state shows two indicators: colour plus a shape, an outline, an icon or a word. +- Every target is at least 48×48px with 8px between targets (`touch-target` on anything drawn smaller); a denser layout is an opt-in prop, never a default. +- Keyboard: Tab between components, arrows within one, Enter and Space activate, Escape dismisses; a dialog takes focus and gives it back to what opened it. + +### Layout and breakpoints +- Widths are M3's window size classes, the only variants that compile: compact below 600px (the default), `medium:` 600, `expanded:` 840, `large:` 1200, `extra-large:` 1600, and `max-medium:` … for "below". In scripts, `from()` and `upTo()` from `resources/js/breakpoints.js`. +- What changes per class: compact — navigation bar, one pane, full-screen dialogs, a bottom sheet for choices; medium — collapsed rail, one pane; expanded — rail (collapsible), two panes, menus and basic dialogs; large and extra-large — the rail expanded, two panes, a third only at extra-large as a side sheet. `` does this; content lives in panes (``), never beside the rail by hand. +- Margins are 16px below `medium` and 24px from it; spacing sits on the 4px grid, as padding and gaps on the parent, with margins only between layout regions. A fixed pane is 360px (expanded) or 412px (large); a side sheet at most 400px. +- Write logical properties (`ps-*`, `me-*`, `start-*`, `text-start`); directional icons mirror in RTL; charts and media controls stay LTR. Keep controls inside the safe area (`--material-safe-*`). + +### Accessibility +- Native elements first (`