Files
livewire-material/resources/css/components/error-page.css
T
Andreas Reinhold / reiniandClaude Opus 5 a764fddf27 Style the body only on the error page
Plan step 36 review of a8c2d88f. error-page.css drew a bare `body`, which
components.css already bundles into every Workbench page and step 37's
all.css would put in every application page: each would take the error
page's background, margin and system font. The rule now matches
body:has(> [data-md-error-page]); the fallback stylesheet, inlined into
the error page alone, keeps its own. A test in the containment harness
and in ErrorPagesTest rejects an unscoped html, body, dialog or :root.

The body's system font stack is gone: the old `font-sans` was the brand
typeface (tokens/theme.css), which the page inherits from the
foundation's html rule, and the header's claim otherwise was wrong. The
shape's slow turn, which moved from the view's inline style into the
stylesheet, is back in the fallback so the no-build page still turns.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
2026-09-14 22:06:56 +02:00

148 lines
5.5 KiB
CSS

/*
* `errors::minimal`: the layout the package's 403/404/419/429/500/503 pages and the framework's
* own 401/402 (which extend this layout, `src/Support/ErrorPage.php`'s docblock) render through.
* A page's own `@section`s fill `title`, `code`, `headline`, `message`, `shape` and `actions`
* (`resources/views/error-pages/errors/minimal.blade.php`'s header) — none of that is this file's
* concern, only the geometry and colour of the parts that show them:
*
* body:has(> [data-md-error-page])
* [data-md-error-page]
* [data-md-error-art]
* [data-md-error-shape] an <x-shape>, turning once a minute unless reduced motion asks
* otherwise (its `svg` fills the art box and is coloured here,
* since <x-shape size> only takes a fixed px, not "fill parent")
* [data-md-error-code] the status, in display type over the shape
* [data-md-error-headline] what happened
* [data-md-error-message] one sentence on what to do, only when `headline` is its own
* section (otherwise `message` doubles as the headline)
* [data-md-error-actions]
*
* The body is matched only when it holds the layout (`body:has(> [data-md-error-page])`): this
* file sits in the application's bundle beside every other page, where a bare `body` rule would
* restyle them all. `src/Support/ErrorPage.php`'s `fallbackStyles()`, the stylesheet an
* application without a Vite build gets instead, is inlined into the error page alone, so it keeps
* a bare `body`; it still needs updating by hand when this file changes, until step 40 replaces
* how it is built.
*
* The page's font is the foundation's, `--md-ref-typeface-brand` on `html` (foundation/base.css),
* as the old `font-sans` was; only the fallback, which has no `@font-face`, uses a system stack.
*
* Colours from the roles (`docs/reference/m3/styles.md` § Typography, "Accessibility
* requirements": surface/on-surface); the display code over its primary-container shape is the
* pairing `docs/audits/m3-alignment/containment.md`'s "Aligned" section confirms; 24px page
* gutters and the 600px growth of the art and headline are the same numbers the audit found
* clean. `--md-sys-typescale-emphasized-display-lg` is the code's weight and roundedness; the
* shape's 60s linear turn has no motion token (`--md-sys-motion-*` pairs a duration with a spring
* for a state change, not an ambient loop) and stays a literal, gated the way the audit's
* "Aligned" section already found it: behind `prefers-reduced-motion: no-preference`.
*/
@layer material.reset, material.tokens, material.base, material.layout, material.components, material.text, material.visibility;
@import './button.css';
@import './shape.css';
@layer material.components {
body:has(> [data-md-error-page]) {
margin: 0;
min-height: 100dvh;
background-color: var(--md-sys-color-surface);
color: var(--md-sys-color-on-surface);
-webkit-font-smoothing: antialiased;
}
[data-md-error-page] {
display: flex;
min-height: 100dvh;
max-width: 576px;
margin-inline: auto;
flex-direction: column;
align-items: center;
justify-content: center;
padding-inline: var(--md-sys-measurement-space300);
padding-block: var(--md-sys-measurement-space600);
text-align: center;
}
[data-md-error-art] {
position: relative;
display: grid;
flex-shrink: 0;
place-items: center;
width: 192px;
height: 192px;
}
@media (width >= 600px) {
[data-md-error-art] {
width: 240px;
height: 240px;
}
}
[data-md-error-shape] {
position: absolute;
inset: 0;
}
[data-md-error-shape] svg {
width: 100%;
height: 100%;
color: var(--md-sys-color-primary-container);
}
@media (prefers-reduced-motion: no-preference) {
[data-md-error-shape] {
animation: material-error-turn 60s linear infinite;
}
}
@keyframes material-error-turn {
to {
transform: rotate(1turn);
}
}
[data-md-error-code] {
position: relative;
margin: 0;
color: var(--md-sys-color-on-primary-container);
font: var(--md-sys-typescale-emphasized-display-lg);
letter-spacing: var(--md-sys-typescale-emphasized-display-lg-tracking);
font-variation-settings: 'ROND' 100;
font-variant-numeric: tabular-nums;
}
[data-md-error-headline] {
margin: var(--md-sys-measurement-space500) 0 0;
font: var(--md-sys-typescale-headline-md);
letter-spacing: var(--md-sys-typescale-headline-md-tracking);
text-wrap: balance;
}
@media (width >= 600px) {
[data-md-error-headline] {
font: var(--md-sys-typescale-headline-lg);
letter-spacing: var(--md-sys-typescale-headline-lg-tracking);
}
}
[data-md-error-message] {
margin: 12px 0 0;
max-width: 448px;
color: var(--md-sys-color-on-surface-variant);
font: var(--md-sys-typescale-body-lg);
letter-spacing: var(--md-sys-typescale-body-lg-tracking);
text-wrap: balance;
}
[data-md-error-actions] {
display: flex;
margin-top: var(--md-sys-measurement-space500);
flex-wrap: wrap;
align-items: center;
justify-content: center;
gap: 12px;
}
}