Files
Andreas Reinhold / reiniandClaude Opus 5 f5f040516e Smooth the page's text in the foundation, not per surface
The showcase and the error pages set grayscale font smoothing on
themselves, but the foundation did not, so an application that dropped
Tailwind's antialiased class rendered heavier text on macOS than the
package's own pages, silently. base.css now sets it on the page; the
showcase's and error page's copies go, and the guard tells a leftover
antialiased class to go too. Decided with the user (plan step 46).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-15 12:41:20 +02:00

321 lines
13 KiB
CSS

/*
* The showcase's own chrome: what its pages draw beyond the layout components, the `md-*` text
* classes and the shared interaction classes (plan step 38) — the rail's wordmark, the search box
* and its results, a keyboard key in running text, an example's card and its code sample, and the
* foundation pages' specimens: a colour swatch, a type-scale row, a corner swatch, an elevation
* tile, a motion track and its dot, an icon search result and the Layout page's breakpoint cards.
*
* Only the showcase's own pages use it. The examples do not: an example's code is what an
* application copies, so it writes only what an application has — the components and their props,
* the layout components, the text classes, and an inline `style` from the `--md-sys-*` tokens where
* a demo needs a size, a frame or a colour of its own.
*
* In `material.components`: the showcase is one more page drawn over the foundation and the layout
* components, where `components/error-page.css` sits for the same reason, and an application's
* unlayered CSS still outranks it. Keyed on `data-md-showcase-*` hooks, never a bare element
* selector, since `ShowcaseAssetController` bundles this file with `all.css` and it must restyle
* nothing outside those hooks. It imports nothing: every token and layout rule it builds on is in
* `all.css`, ahead of it in the bundle. Values are tokens, apart from a specimen's own size; its
* media queries are M3's breakpoints, in px.
*
* Two kinds of rule sit outside the layers on purpose, as an application's own classes would:
* `.showcase-w-narrow` proves the point its example makes (Text fields, "Narrower": an unlayered
* rule from the call site beats the package's layered default, which an inline `style` would win
* regardless of layers, proving nothing), and `.showcase-ink-*` are the colours the Menus example
* passes to `icon-class`, the application's own class that prop takes.
*/
@layer material.reset, material.tokens, material.base, material.layout, material.components, material.text, material.visibility;
@layer material.components {
/* The rail's wordmark: `md-type-title-lg md-truncate md-focus-ring` cover the type, the
ellipsis and the ring; `display: block` gives the truncated text a width to ellipsize
within, and the corner rounds the ring to match the state layer every other rail control
draws (foundation/interaction.css's `md-focus-ring` takes its shape from the element). */
[data-md-showcase-brand] {
display: block;
border-radius: var(--md-sys-shape-corner-xs);
}
/* The search bar fills the app bar's search slot. */
[data-md-showcase-search] {
width: 100%;
}
[data-md-showcase-search-hint] {
padding: var(--md-sys-measurement-space125) var(--md-sys-measurement-space200);
}
/* A kbd in running text: the search hint's "/", and the intro paragraph's own. */
[data-md-showcase-kbd] {
display: inline-block;
border-radius: var(--md-sys-shape-corner-xs);
background-color: var(--md-sys-color-surface-container-highest);
padding: 0 var(--md-sys-measurement-space75);
}
/* One search result: title over kind and context, centred in a 56px row (space700, M3's list
row) the way a menu item is. */
[data-md-showcase-search-result] {
display: flex;
flex-direction: column;
justify-content: center;
min-height: var(--md-sys-measurement-space700);
padding: var(--md-sys-measurement-space100) var(--md-sys-measurement-space200);
}
/* The bottom breathing room under a showcase page's content, inside the pane's own margins. */
[data-md-showcase-page] {
padding-block-end: var(--md-sys-measurement-space600);
}
/* Each section's group of components on the overview: a tonal box behind its icon, the way a
list's leading icon sits in a container (M3's small tonal container). */
[data-md-showcase-section-icon] {
display: grid;
place-items: center;
width: var(--md-sys-measurement-space600);
height: var(--md-sys-measurement-space600);
border-radius: var(--md-sys-shape-corner-lg);
background-color: var(--md-sys-color-secondary-container);
color: var(--md-sys-color-on-secondary-container);
}
/* An example: scroll-margin so a hash link (the search result, the "next section" nav) lands
clear of the sticky app bar above it. */
[data-md-showcase-example] {
scroll-margin-top: var(--md-sys-measurement-space900);
}
[data-md-showcase-code-summary] {
display: inline-block;
cursor: pointer;
border-radius: var(--md-sys-shape-corner-xs);
}
[data-md-showcase-code] {
margin-top: var(--md-sys-measurement-space100);
overflow-x: auto;
border-radius: var(--md-sys-shape-corner-sm);
background-color: var(--md-sys-color-surface-container-highest);
padding: var(--md-sys-measurement-space125);
}
/* Colour: a role swatch. Its fill is the one declaration that has to be the caller's inline
`style` (the role it shows decides it), so this rule only gives it a size and an edge; `lg`
is the big per-theme grid's, the plain attribute the smaller contrast-level list's. */
[data-md-showcase-swatch] {
display: block;
flex-shrink: 0;
width: var(--md-sys-measurement-space300);
height: var(--md-sys-measurement-space300);
border-radius: var(--md-sys-shape-corner-xs);
border: 1px solid var(--md-sys-color-outline-variant);
}
[data-md-showcase-swatch][data-md-showcase-size='lg'] {
width: var(--md-sys-measurement-space400);
height: var(--md-sys-measurement-space400);
}
/* Lets the role name beside a swatch ellipsize inside its row instead of widening the grid. */
[data-md-showcase-swatch-label] {
min-width: 0;
}
/* Type: one typescale style beside its label and its emphasized twin, a row of the surface
they share. A single column below `expanded` (840px), where the label, the regular sample
and the emphasized one no longer fit a line each. */
[data-md-showcase-type-row] {
display: grid;
gap: var(--md-sys-measurement-space100);
padding: var(--md-sys-measurement-space200);
}
[data-md-showcase-type-row] + [data-md-showcase-type-row] {
border-top: 1px solid var(--md-sys-color-outline-variant);
}
@media (width >= 840px) {
[data-md-showcase-type-row] {
grid-template-columns: 192px 1fr 1fr;
align-items: baseline;
}
}
/* Shape: a corner swatch, filled with a tonal colour that is decoration only (never meaning,
same as the corner it demonstrates), one per corner token. */
[data-md-showcase-shape-swatch] {
display: block;
height: 80px;
background-color: var(--md-sys-color-primary-container);
}
[data-md-showcase-shape-swatch][data-md-corner='none'] {
border-radius: var(--md-sys-shape-corner-none);
}
[data-md-showcase-shape-swatch][data-md-corner='xs'] {
border-radius: var(--md-sys-shape-corner-xs);
}
[data-md-showcase-shape-swatch][data-md-corner='sm'] {
border-radius: var(--md-sys-shape-corner-sm);
}
[data-md-showcase-shape-swatch][data-md-corner='md'] {
border-radius: var(--md-sys-shape-corner-md);
}
[data-md-showcase-shape-swatch][data-md-corner='lg'] {
border-radius: var(--md-sys-shape-corner-lg);
}
[data-md-showcase-shape-swatch][data-md-corner='lg-increased'] {
border-radius: var(--md-sys-shape-corner-lg-increased);
}
[data-md-showcase-shape-swatch][data-md-corner='xl'] {
border-radius: var(--md-sys-shape-corner-xl);
}
[data-md-showcase-shape-swatch][data-md-corner='xl-increased'] {
border-radius: var(--md-sys-shape-corner-xl-increased);
}
[data-md-showcase-shape-swatch][data-md-corner='xxl'] {
border-radius: var(--md-sys-shape-corner-xxl);
}
[data-md-showcase-shape-swatch][data-md-corner='full'] {
border-radius: var(--md-sys-shape-corner-full);
}
/* Elevation: a tile at one shadow level, on the surface-container-high M3 pairs a shadow with. */
[data-md-showcase-elevation-tile] {
display: flex;
align-items: center;
justify-content: center;
height: 96px;
border-radius: var(--md-sys-shape-corner-md);
background-color: var(--md-sys-color-surface-container-high);
}
[data-md-showcase-elevation-tile][data-md-elevation='1'] {
box-shadow: var(--md-sys-elevation-1);
}
[data-md-showcase-elevation-tile][data-md-elevation='2'] {
box-shadow: var(--md-sys-elevation-2);
}
[data-md-showcase-elevation-tile][data-md-elevation='3'] {
box-shadow: var(--md-sys-elevation-3);
}
[data-md-showcase-elevation-tile][data-md-elevation='4'] {
box-shadow: var(--md-sys-elevation-4);
}
[data-md-showcase-elevation-tile][data-md-elevation='5'] {
box-shadow: var(--md-sys-elevation-5);
}
/* Motion: one spring's row (its name, and a track the dot travels), and the dot itself — its
colour is decoration, its size is the only thing this file fixes; the transition is the
spring under test, so it stays the view's own inline style. */
[data-md-showcase-motion-row] {
display: grid;
grid-template-columns: 144px 1fr;
align-items: center;
gap: var(--md-sys-measurement-space200);
}
[data-md-showcase-motion-track] {
height: var(--md-sys-measurement-space400);
}
[data-md-showcase-motion-dot] {
width: var(--md-sys-measurement-space400);
height: var(--md-sys-measurement-space400);
border-radius: var(--md-sys-shape-corner-full);
background-color: var(--md-sys-color-tertiary);
}
/* Icons: one search result's mask (its `mask` shorthand is the fetched symbol, so it stays the
view's own x-bind:style), 24px by default and 20px once optical size 20 is on — the state a
script toggles as data-md-showcase-icon-size, never a class. */
[data-md-showcase-icon-mask] {
display: block;
width: 24px;
height: 24px;
background-color: currentColor;
}
[data-md-showcase-icon-mask][data-md-showcase-icon-size='20'] {
width: 20px;
height: 20px;
}
/* Layout: the five breakpoint cards, each lit by the same range query the layout components'
own stylesheets use, so the page proves the breakpoints rather than only describing them. */
[data-md-showcase-breakpoint-card] {
border-radius: var(--md-sys-shape-corner-md);
background-color: var(--md-sys-color-surface-container);
padding: var(--md-sys-measurement-space200);
}
@media (width < 600px) {
[data-md-showcase-breakpoint-card='compact'] {
background-color: var(--md-sys-color-primary-container);
color: var(--md-sys-color-on-primary-container);
}
}
@media (600px <= width < 840px) {
[data-md-showcase-breakpoint-card='medium'] {
background-color: var(--md-sys-color-primary-container);
color: var(--md-sys-color-on-primary-container);
}
}
@media (840px <= width < 1200px) {
[data-md-showcase-breakpoint-card='expanded'] {
background-color: var(--md-sys-color-primary-container);
color: var(--md-sys-color-on-primary-container);
}
}
@media (1200px <= width < 1600px) {
[data-md-showcase-breakpoint-card='large'] {
background-color: var(--md-sys-color-primary-container);
color: var(--md-sys-color-on-primary-container);
}
}
@media (width >= 1600px) {
[data-md-showcase-breakpoint-card='extra-large'] {
background-color: var(--md-sys-color-primary-container);
color: var(--md-sys-color-on-primary-container);
}
}
}
/* Deliberately unlayered, to make the point fields.blade.php's hint names: an application's own
rule beats the package's layered default even though both set the same property. An inline
`style` would win regardless of layers, which would not demonstrate that. */
.showcase-w-narrow {
max-width: 320px;
}
/* An application's own icon colours, for menus.blade.php's `icon-class` example: unlayered, as the
menu item's header says a caller's class is, so it paints the icon over the item's ink (and a
disabled item's icon still stays disabled). */
.showcase-ink-tertiary {
color: var(--md-sys-color-tertiary);
}
.showcase-ink-secondary {
color: var(--md-sys-color-secondary);
}