Files
livewire-material/resources/css/components/navigation.css
T
Andreas Reinhold / reiniandClaude Opus 5 2482a0b6d4 Square the rail's collapsed FAB whatever size it is
The actions stream has since given the small extended FAB an 80px minimum width,
which the morph would have kept once the label closed. Dropping that minimum and
squaring the box against the height its size already sets gives back the 56, 80
or 96px FAB without this file naming any of those numbers.
Plan: docs/plans/material-3-alignment.md, step 21 (navigation N-23).

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

690 lines
27 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* M3 Expressive navigation: the flexible navigation bar and the navigation rail — collapsed,
* expanded and modal.
*
* Values from androidx Compose Material 3 (Apache-2.0) at androidx-main
* 27cf9a7d5788aa0f5f2d8b6699ce279560daf326: tokens/NavigationBarTokens.kt,
* NavigationBarVerticalItemTokens.kt, NavigationBarHorizontalItemTokens.kt,
* NavigationRailCollapsedTokens.kt, NavigationRailExpandedTokens.kt,
* NavigationRailBaselineItemTokens.kt, NavigationRailVerticalItemTokens.kt,
* NavigationRailHorizontalItemTokens.kt, NavigationRailColorTokens.kt, and the layout in
* ShortNavigationBar.kt, WideNavigationRail.kt and NavigationItem.kt.
*
* [data-navigation-bar] surface-container, 64px, the bottom safe area under it
* [data-navigation-bar-items] equal widths; centred from a 600px-wide bar
* [data-navigation-bar-item] data-active
* [data-navigation-pill] icon and label; the indicator itself from 600px
* [data-navigation-indicator] the 56×32 indicator around the icon below 600px
* [data-navigation-label]
*
* [data-navigation-rail="collapsed|expanded|collapsible|modal|adaptive"] data-open
* [data-navigation-rail-scrim] modal and adaptive rails
* [data-navigation-rail-panel] the <nav>
* [data-navigation-rail-header] menu button, brand, FAB — never scrolls
* [data-navigation-rail-destinations] scrolls when the window is too short
* [data-navigation-rail-section] a heading (expanded only) and its items
* [data-navigation-rail-item] data-active; the full-width pill when expanded
* [data-navigation-indicator] the 56×32 indicator when collapsed
* [data-navigation-label]
* [data-navigation-rail-footer] never scrolls
*
* `rail-collapsed:` matches a rail, and everything in it, while it is drawn collapsed — whatever
* made it so: its mode, the visitor's choice on <html data-rail> (set before the first paint by
* <x-theme-script>), or a window below `expanded` (840px) for the adaptive rail. A rail item is written once
* and takes both shapes from it; so can anything an application puts in a rail
* (`<span class="rail-collapsed:hidden">`).
*
* The two widths the adaptive rail turns on are M3's window size classes, not Tailwind's screens
* (docs/reference/m3/foundations.md § Layout, foundations-supplement.md § Breakpoints): 37.5rem
* (600px) is the compact/medium boundary — below it the navigation bar carries the destinations and
* the rail takes no room in the layout; 52.5rem (840px) is `expanded`, where M3 asks for a standard
* rail in the layout rather than one that opens over a scrim; 75rem (1200px) is `large`, where the
* rail starts expanded instead of collapsed. The bar's own item layout is a *container* query at
* the same 37.5rem, so a bar in a narrow column lays out by its own width.
*
* Everything here is in `@layer components` except the last block, which restyles a FAB the
* application put in the rail: that one has to beat a utility, and a layer never does.
*/
@custom-variant rail-collapsed {
&:where([data-navigation-rail='collapsed'], [data-navigation-rail='collapsed'] *) {
@slot;
}
&:where([data-rail='collapsed'] [data-navigation-rail='collapsible'], [data-rail='collapsed'] [data-navigation-rail='collapsible'] *) {
@slot;
}
&:where([data-navigation-rail='modal']:not([data-open]), [data-navigation-rail='modal']:not([data-open]) *) {
@slot;
}
/* Below `medium` a 220360px rail would be most of the screen, so a rail whose width is the
visitor's choice is held collapsed there whatever they chose. */
@media (width < 37.5rem) {
&:where([data-navigation-rail='collapsible'], [data-navigation-rail='collapsible'] *) {
@slot;
}
}
@media (width < 52.5rem) {
&:where([data-navigation-rail='adaptive']:not([data-open]), [data-navigation-rail='adaptive']:not([data-open]) *) {
@slot;
}
}
/* Expanded (8401199): a standard rail, collapsed unless the visitor expanded it. `data-rail`
alone cannot say that — it carries `rail.default` for a visitor who never chose — so
`data-rail-auto`, which <x-theme-script> sets while nothing is stored, stands for "no
choice yet" and the class's own default applies. */
@media (52.5rem <= width < 75rem) {
&:where(:is([data-rail='collapsed'], [data-rail-auto]) [data-navigation-rail='adaptive'], :is([data-rail='collapsed'], [data-rail-auto]) [data-navigation-rail='adaptive'] *) {
@slot;
}
}
/* Large and extra-large (from 1200): expanded to begin with, which is what M3 prefers there. */
@media (width >= 75rem) {
&:where([data-rail='collapsed'] [data-navigation-rail='adaptive'], [data-rail='collapsed'] [data-navigation-rail='adaptive'] *) {
@slot;
}
}
}
@layer components {
/* ---------------------------------------------------------------- the navigation bar */
[data-navigation-bar] {
container-type: inline-size;
padding-inline: var(--material-safe-left, env(safe-area-inset-left)) var(--material-safe-right, env(safe-area-inset-right));
padding-bottom: var(--material-safe-bottom, env(safe-area-inset-bottom));
background-color: var(--md-sys-color-surface-container);
color: var(--md-sys-color-on-surface-variant);
}
[data-navigation-bar-items] {
display: flex;
min-height: 4rem;
margin-inline: auto;
}
[data-navigation-bar-item] {
--navigation-layer: 0;
position: relative;
display: flex;
flex: 1 1 0;
min-width: 0;
align-items: center;
justify-content: center;
padding-block: 0.375rem;
color: var(--md-sys-color-on-surface-variant);
text-decoration: none;
cursor: pointer;
outline: none;
-webkit-tap-highlight-color: transparent;
}
[data-navigation-bar-item] [data-navigation-pill] {
display: flex;
min-width: 0;
max-width: 100%;
flex-direction: column;
align-items: center;
gap: 0.25rem;
border-radius: var(--md-sys-shape-corner-full);
font: var(--md-sys-typescale-label-md);
letter-spacing: var(--md-sys-typescale-label-md-tracking);
}
[data-navigation-bar-item] [data-navigation-label] {
max-width: 100%;
padding-inline: 0.25rem;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
[data-navigation-bar-item][data-active] {
color: var(--md-sys-color-secondary);
}
/* From 600dp (M3's medium window), icon and label side by side in a 40px indicator, and the
items centred with the padding ShortNavigationBar's Centered arrangement computes. */
@container (width >= 37.5rem) {
[data-navigation-bar-items] {
width: calc(10% * (var(--navigation-bar-count, 7) + 3));
min-width: fit-content;
max-width: 100%;
}
[data-navigation-bar-items]:has(> :last-child:nth-child(1)) { --navigation-bar-count: 1; }
[data-navigation-bar-items]:has(> :last-child:nth-child(2)) { --navigation-bar-count: 2; }
[data-navigation-bar-items]:has(> :last-child:nth-child(3)) { --navigation-bar-count: 3; }
[data-navigation-bar-items]:has(> :last-child:nth-child(4)) { --navigation-bar-count: 4; }
[data-navigation-bar-items]:has(> :last-child:nth-child(5)) { --navigation-bar-count: 5; }
[data-navigation-bar-items]:has(> :last-child:nth-child(6)) { --navigation-bar-count: 6; }
[data-navigation-bar-item] {
min-width: max-content;
}
/* The label stays label-medium: NavigationBarTokens.LabelTextFont is the bar's only label
token, and Compose's ShortNavigationBarItem passes it for both icon positions. (The
*rail's* horizontal item is label-large — NavigationRailHorizontalItemTokens — which is
a different component.) */
[data-navigation-bar-item] [data-navigation-pill] {
position: relative;
isolation: isolate;
flex-direction: row;
height: 2.5rem;
padding-inline: 1rem;
}
[data-navigation-bar-item] [data-navigation-label] {
padding-inline: 0;
}
[data-navigation-bar-item][data-active] {
color: var(--md-sys-color-on-secondary-container);
}
[data-navigation-bar-item][data-active] [data-navigation-pill] {
background-image: linear-gradient(var(--md-sys-color-secondary-container), var(--md-sys-color-secondary-container));
}
}
/* ---------------------------------------------------------------- the navigation rail */
[data-navigation-rail] {
--navigation-rail-expanded-width: clamp(13.75rem, var(--navigation-rail-width, 16rem), 22.5rem);
position: relative;
flex-shrink: 0;
width: var(--navigation-rail-expanded-width);
transition: width var(--md-sys-motion-spatial-default-duration) var(--md-sys-motion-spatial-default);
@variant rail-collapsed {
width: 6rem;
}
}
/* A modal rail keeps its collapsed width in the layout while it is open over it, as Compose's
ModalWideNavigationRail does; the adaptive rail does below `expanded`, and takes no room on a compact window. */
[data-navigation-rail='modal'] {
width: 6rem;
}
@media (width < 52.5rem) {
[data-navigation-rail='adaptive'] {
width: 6rem;
}
}
@media (width < 37.5rem) {
[data-navigation-rail='adaptive'] {
width: 0;
}
/* "Compact → don't use a standard rail, use a navigation bar." A `collapsible` rail takes
the width the visitor chose, which on a 360px screen would be two-thirds of it, so it
is floored at the collapsed 96px. `collapsed` and `expanded` mean what they say and are
left alone: wrap one in a `medium:` element if it must not show on a phone. */
[data-navigation-rail='collapsible'] {
width: 6rem;
}
}
/* `--material-banner` is the height of a bar pinned across the top of the window — what
<x-app-shell>'s `banner` slot holds, if the application made it sticky. The rail sticks
under it rather than behind it; 0 without one. */
[data-navigation-rail-panel] {
position: sticky;
top: var(--material-banner, 0px);
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
max-height: calc(100dvh - var(--material-banner, 0px));
/* Clip, not hide: no scroll container, so the destinations below can still scroll and
nothing sticky breaks. What only an expanded rail draws — a label, the brand — is drawn
at once when the rail expands, while the width is still growing; the clip keeps it
from spilling over the page for those frames. */
overflow-x: clip;
padding-bottom: var(--material-safe-bottom, env(safe-area-inset-bottom));
background-color: var(--md-sys-color-surface);
color: var(--md-sys-color-on-surface);
transition:
width var(--md-sys-motion-spatial-fast-duration) var(--md-sys-motion-spatial-fast),
background-color var(--md-sys-motion-effects-default-duration) var(--md-sys-motion-effects-default);
}
/* M3's two optional container treatments: "optional vertical divider separates rail from
content, placed on the content-adjacent edge" — also its answer to a page scrolling under a
fixed rail — and "container fill can be turned off (transparent) as long as items keep ≥3:1
contrast". Neither applies to a rail open over a scrim, which is a surface over the page. */
[data-navigation-rail][data-divider]:not([data-open]) > [data-navigation-rail-panel] {
border-inline-end: 1px solid var(--md-sys-color-outline-variant);
}
[data-navigation-rail][data-fill='false']:not([data-open]) > [data-navigation-rail-panel] {
background-color: transparent;
}
/* Open: expanded over a scrim, in surface-container with a large corner at its inner edge. */
[data-navigation-rail][data-open] > [data-navigation-rail-panel] {
position: fixed;
inset-block: 0;
inset-inline-start: 0;
z-index: 50;
width: var(--navigation-rail-expanded-width);
max-width: calc(100vw - 3.5rem);
height: 100dvh;
max-height: none;
border-start-end-radius: var(--md-sys-shape-corner-lg);
border-end-end-radius: var(--md-sys-shape-corner-lg);
background-color: var(--md-sys-color-surface-container);
box-shadow: var(--md-sys-elevation-2);
}
/* On a compact window there is no collapsed rail to grow out of: the open rail slides in from the edge,
on emphasized decelerate rather than a spring, which would overshoot and open a gap. */
@media (width < 37.5rem) {
[data-navigation-rail='adaptive'] > [data-navigation-rail-panel] {
position: fixed;
inset-block: 0;
inset-inline-start: 0;
z-index: 50;
display: none;
width: var(--navigation-rail-expanded-width);
max-width: calc(100vw - 3.5rem);
height: 100dvh;
max-height: none;
border-start-end-radius: var(--md-sys-shape-corner-lg);
border-end-end-radius: var(--md-sys-shape-corner-lg);
background-color: var(--md-sys-color-surface-container);
box-shadow: var(--md-sys-elevation-2);
translate: -100% 0;
transition:
translate var(--md-sys-motion-effects-default-duration) var(--md-sys-motion-easing-emphasized-accelerate),
display var(--md-sys-motion-effects-default-duration) allow-discrete;
&:dir(rtl) {
translate: 100% 0;
}
}
[data-navigation-rail='adaptive'][data-open] > [data-navigation-rail-panel] {
display: flex;
translate: 0 0;
transition:
translate var(--md-sys-motion-spatial-default-duration) var(--md-sys-motion-easing-emphasized-decelerate),
display var(--md-sys-motion-spatial-default-duration) allow-discrete;
@starting-style {
translate: -100% 0;
}
&:dir(rtl) {
translate: 0 0;
@starting-style {
translate: 100% 0;
}
}
}
}
[data-navigation-rail-scrim] {
position: fixed;
inset: 0;
z-index: 40;
display: none;
background-color: color-mix(in srgb, var(--md-sys-color-scrim) 32%, transparent);
opacity: 0;
transition:
opacity var(--md-sys-motion-effects-default-duration) var(--md-sys-motion-effects-default),
display var(--md-sys-motion-effects-default-duration) allow-discrete;
}
[data-navigation-rail][data-open] > [data-navigation-rail-scrim] {
display: block;
opacity: 1;
@starting-style {
opacity: 0;
}
}
/* 44px above the header (TopSpace), 40px under it (HeaderSpaceMinimum) — 32 here and 8 as
the destinations' own padding, which keeps the first item's focus ring inside the scroller. */
[data-navigation-rail-header] {
display: flex;
flex-shrink: 0;
flex-direction: column;
align-items: flex-start;
gap: 0.5rem;
padding-top: calc(var(--material-safe-top, env(safe-area-inset-top)) + 2.75rem);
padding-bottom: 2rem;
}
[data-navigation-rail-panel] > [data-navigation-rail-destinations]:first-child {
padding-top: calc(var(--material-safe-top, env(safe-area-inset-top)) + 2.75rem);
}
[data-navigation-rail-destinations] {
flex: 1 1 auto;
min-height: 0;
overflow-y: auto;
overscroll-behavior: contain;
padding-block: 0.5rem;
scrollbar-width: thin;
}
[data-navigation-rail-destinations],
[data-navigation-rail-section],
[data-navigation-rail-footer] {
display: flex;
flex-direction: column;
@variant rail-collapsed {
gap: 0.25rem;
}
}
[data-navigation-rail-footer] {
flex-shrink: 0;
padding-block: 0.5rem 1rem;
}
[data-navigation-rail-heading] {
display: flex;
align-items: center;
min-height: 3rem;
padding-inline: 2.25rem 1.25rem;
overflow: hidden;
color: var(--md-sys-color-on-surface-variant);
font: var(--md-sys-typescale-title-sm);
letter-spacing: var(--md-sys-typescale-title-sm-tracking);
white-space: nowrap;
text-overflow: ellipsis;
@variant rail-collapsed {
display: none;
}
}
[data-navigation-rail-section]:not(:first-child) {
@variant rail-collapsed {
margin-top: 0.75rem;
}
}
/* Expanded: a 56px full-width pill, icon and label 8px apart, label-large. */
[data-navigation-rail-item] {
--navigation-layer: 0;
position: relative;
isolation: isolate;
display: flex;
flex-shrink: 0;
align-items: center;
gap: 0.5rem;
height: 3.5rem;
margin-inline: 1.25rem;
padding-inline: 1rem;
border-radius: var(--md-sys-shape-corner-full);
color: var(--md-sys-color-on-surface-variant);
font: var(--md-sys-typescale-label-lg);
letter-spacing: var(--md-sys-typescale-label-lg-tracking);
text-align: start;
text-decoration: none;
white-space: nowrap;
cursor: pointer;
outline: none;
-webkit-tap-highlight-color: transparent;
/* Collapsed: the icon in its 56×32 indicator over a label-medium label, 64px tall. */
@variant rail-collapsed {
flex-direction: column;
justify-content: center;
gap: 0.25rem;
height: auto;
min-height: 4rem;
margin-inline: 0;
padding: 0.375rem 0.25rem;
border-radius: 0;
font: var(--md-sys-typescale-label-md);
letter-spacing: var(--md-sys-typescale-label-md-tracking);
white-space: normal;
}
}
[data-navigation-rail-item] [data-navigation-label] {
flex: 1 1 auto;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
@variant rail-collapsed {
flex: none;
display: -webkit-box;
max-width: 100%;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
text-align: center;
overflow-wrap: anywhere;
}
}
[data-navigation-rail-item][data-active] {
background-image: linear-gradient(var(--md-sys-color-secondary-container), var(--md-sys-color-secondary-container));
color: var(--md-sys-color-on-secondary-container);
@variant rail-collapsed {
background-image: none;
color: var(--md-sys-color-secondary);
}
}
[data-navigation-rail-item] [data-navigation-indicator] {
position: relative;
isolation: isolate;
display: flex;
flex-shrink: 0;
align-items: center;
justify-content: center;
border-radius: var(--md-sys-shape-corner-full);
@variant rail-collapsed {
width: 3.5rem;
height: 2rem;
}
}
/* ---------------------------------------------------------------- both: indicator, states */
[data-navigation-bar-item] [data-navigation-indicator] {
position: relative;
isolation: isolate;
display: flex;
flex-shrink: 0;
align-items: center;
justify-content: center;
width: 3.5rem;
height: 2rem;
border-radius: var(--md-sys-shape-corner-full);
}
[data-navigation-bar-item][data-active] [data-navigation-indicator] {
color: var(--md-sys-color-on-secondary-container);
}
@container (width < 37.5rem) {
[data-navigation-bar-item][data-active] [data-navigation-indicator] {
background-image: linear-gradient(var(--md-sys-color-secondary-container), var(--md-sys-color-secondary-container));
}
}
[data-navigation-rail-item][data-active] [data-navigation-indicator] {
@variant rail-collapsed {
background-image: linear-gradient(var(--md-sys-color-secondary-container), var(--md-sys-color-secondary-container));
color: var(--md-sys-color-on-secondary-container);
}
}
/* The active indicator is a secondary-container fill painted as a background image, so it can
grow out of its centre without stretching the icon: when a page arrives through
wire:navigate, resources/js/navigation.js starts it at zero width for a moment, and it
springs open on the default spatial spring, as Compose's indicator does when the selection
changes (NavigationItem.kt). A full page load draws it at once; reduced motion zeroes it. */
[data-navigation-bar-item] :is([data-navigation-indicator], [data-navigation-pill]),
[data-navigation-rail-item],
[data-navigation-rail-item] [data-navigation-indicator] {
background-position: center;
background-repeat: no-repeat;
background-size: 100% 100%;
transition: background-size var(--md-sys-motion-spatial-default-duration) var(--md-sys-motion-spatial-default);
}
/* The state layer covers only the indicator: the pill when the indicator holds the label
too, the 56×32 shape when it holds the icon alone. Hover only where a pointer can hover. */
@media (hover: hover) {
:is([data-navigation-bar-item], [data-navigation-rail-item]):hover {
--navigation-layer: 0.08;
}
}
:is([data-navigation-bar-item], [data-navigation-rail-item]):is(:focus-visible, :active) {
--navigation-layer: 0.1;
}
[data-navigation-bar-item] [data-navigation-indicator]::before,
[data-navigation-bar-item] [data-navigation-pill]::before,
[data-navigation-rail-item] [data-navigation-indicator]::before,
[data-navigation-rail-item]::before {
content: '';
position: absolute;
inset: 0;
z-index: -1;
border-radius: inherit;
background-color: var(--md-sys-color-on-surface);
opacity: var(--navigation-layer);
pointer-events: none;
transition: opacity var(--md-sys-motion-effects-fast-duration) var(--md-sys-motion-effects-fast);
}
/* A navigation item's state layer is on-secondary-container, active or not: the only
state-layer tokens M3 states for one are NavigationRailColorTokens', which give that colour
to all six. The rail follows them two blocks below; the bar follows them here, over its
secondary-container pill. */
[data-navigation-bar-item] :is([data-navigation-indicator], [data-navigation-pill])::before {
background-color: var(--md-sys-color-on-secondary-container);
}
@container (width < 37.5rem) {
[data-navigation-bar-item] [data-navigation-pill]::before {
display: none;
}
}
@container (width >= 37.5rem) {
[data-navigation-bar-item] [data-navigation-indicator]::before {
display: none;
}
}
/* The rail item's layer is on the item while expanded and on its indicator while collapsed. A
variant cannot follow a pseudo-element in a selector, so the item hands the layer on through
variables; each rule below outweighs its line in the list above. */
[data-navigation-rail-item] {
--navigation-item-layer: var(--navigation-layer);
--navigation-indicator-layer: 0;
@variant rail-collapsed {
--navigation-item-layer: 0;
--navigation-indicator-layer: var(--navigation-layer);
}
}
[data-navigation-rail-item][data-navigation-rail-item]::before {
background-color: var(--md-sys-color-on-secondary-container);
opacity: var(--navigation-item-layer);
}
[data-navigation-rail-item][data-navigation-rail-item] [data-navigation-indicator]::before {
background-color: var(--md-sys-color-on-secondary-container);
opacity: var(--navigation-indicator-layer);
}
/* M3's focus indicator, 3px of secondary 2px out, around the same shape. */
@container (width < 37.5rem) {
[data-navigation-bar-item]:focus-visible [data-navigation-indicator] {
outline: 3px solid var(--md-sys-color-secondary);
outline-offset: 2px;
}
}
@container (width >= 37.5rem) {
[data-navigation-bar-item]:focus-visible [data-navigation-pill] {
outline: 3px solid var(--md-sys-color-secondary);
outline-offset: 2px;
}
}
[data-navigation-rail-item]:focus-visible {
outline: 3px solid var(--md-sys-color-secondary);
outline-offset: 2px;
@variant rail-collapsed {
outline: none;
}
}
[data-navigation-rail-item]:focus-visible [data-navigation-indicator] {
@variant rail-collapsed {
outline: 3px solid var(--md-sys-color-secondary);
outline-offset: 2px;
}
}
}
/* A FAB in the rail's header rests at elevation 0, not the 3 a standalone FAB has
* (docs/reference/m3/components-navigation-selection-inputs.md § Navigation rail: "when nested
* within another component, such as the navigation rail, the FAB's resting elevation should be
* level 0"). Unlayered on purpose: the FAB draws its shadow with a utility, and a rule in any
* layer loses to a utility — the same reason toolbar.css gives for its vibrant recolouring. */
[data-navigation-rail-header] [data-fab],
[data-navigation-rail-header] [data-fab]:hover {
box-shadow: none;
}
/* "Rail transitions from collapsed to expanded should animate the FAB into and out of an extended
* FAB" — so the header takes one <x-fab label icon> and morphs it, rather than swapping two by
* `display`, which showed the collapsed one at once while the rail's width was still springing.
* The label's width springs on the rail's own spatial spring; with the gap closed and the extended
* FAB's own minimum width off, `aspect-ratio` squares what is left against the height its size
* already sets — 56, 80 or 96px, the three FAB sizes — so no number is repeated here. The label
* stays in the accessibility tree at both widths, so the FAB keeps its name. Unlayered for the
* same reason as the rule above: `gap-2` and `min-w-20` are utilities, and a layer would lose to
* them. The cap is there because a transition needs a length to travel to; a rail FAB's label is a
* word or two. */
[data-navigation-rail-header] [data-fab] > span {
max-width: 16rem;
overflow: hidden;
white-space: nowrap;
transition:
max-width var(--md-sys-motion-spatial-default-duration) var(--md-sys-motion-spatial-default),
opacity var(--md-sys-motion-effects-default-duration) var(--md-sys-motion-effects-default);
@variant rail-collapsed {
max-width: 0;
opacity: 0;
}
}
[data-navigation-rail-header] [data-fab] {
@variant rail-collapsed {
min-width: 0;
aspect-ratio: 1;
gap: 0;
}
}