diff --git a/resources/css/components/navigation.css b/resources/css/components/navigation.css
index a2f1db1b..6d2d9ba1 100644
--- a/resources/css/components/navigation.css
+++ b/resources/css/components/navigation.css
@@ -41,6 +41,9 @@
* 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 {
@@ -601,3 +604,13 @@
}
}
}
+
+/* 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;
+}
diff --git a/resources/views/components/navigation-rail.blade.php b/resources/views/components/navigation-rail.blade.php
index c9b4fa6a..1f712275 100644
--- a/resources/views/components/navigation-rail.blade.php
+++ b/resources/views/components/navigation-rail.blade.php
@@ -39,7 +39,8 @@
Slots: `brand` beside the menu button, only while expanded; `header` under it — a FAB, drawn
as an extended FAB when expanded (`rail-collapsed:` below); the destinations in the default
slot, which alone scroll when the window is too short; `footer`, pinned to the foot. Header and
- footer never scroll, so nothing in them is cut off by the scroller's edge.
+ footer never scroll, so nothing in them is cut off by the scroller's edge. A FAB in the header
+ rests flat: M3 puts a nested FAB at elevation 0, not the 3 a standalone one has.
Anything inside can take both shapes with the `rail-collapsed:` variant, which applies while
the rail is drawn collapsed for whatever reason:
diff --git a/tests/Feature/Components/NavigationRailTest.php b/tests/Feature/Components/NavigationRailTest.php
index 99223e02..4f0c54e3 100644
--- a/tests/Feature/Components/NavigationRailTest.php
+++ b/tests/Feature/Components/NavigationRailTest.php
@@ -51,6 +51,21 @@ it('keeps the header and footer out of the scrolling destinations', function ()
->toMatch('/data-navigation-rail-header.*Brand.*FAB.*data-navigation-rail-destinations.*Inbox.*data-navigation-rail-footer.*Account/s');
});
+it('flattens a FAB nested in the rail header to elevation 0', function () {
+ $html = (string) $this->blade(<<<'BLADE'
+
+
+
+ BLADE);
+
+ // The hook the unlayered rule in navigation.css needs (N-03).
+ expect($html)->toContain('data-fab');
+
+ expect(file_get_contents(__DIR__.'/../../../resources/css/components/navigation.css'))
+ ->toContain('[data-navigation-rail-header] [data-fab],')
+ ->toContain('[data-navigation-rail-header] [data-fab]:hover {');
+});
+
it('draws a destination in both shapes, with its count on the icon and at the end', function () {
$html = (string) $this->blade('');