diff --git a/src/__tests__/pwa-mobile-shell-guard.test.ts b/src/__tests__/pwa-mobile-shell-guard.test.ts index 22558121e..0daf812ef 100644 --- a/src/__tests__/pwa-mobile-shell-guard.test.ts +++ b/src/__tests__/pwa-mobile-shell-guard.test.ts @@ -60,6 +60,15 @@ describe("the shell owns the safe area", () => { expect(css).toMatch(/@custom-variant pointer-fine/); }); + it("bottom toasts clear the bar under the same query the bar follows", () => { + // Sonner's own mobile offset stops at 600 px; the bar shows up to `md` + // and on a phone held sideways, so the lift keys on `shell-mobile`. + const css = code(read("src/app/globals.css")); + expect(css).toMatch( + /html \[data-sonner-toaster\]\[data-y-position="bottom"\]\s*\{\s*@variant shell-mobile\s*\{\s*bottom:\s*calc\(4rem \+ env\(safe-area-inset-bottom/, + ); + }); + it("the bottom bar and the Coach button step aside for the keyboard", () => { expect(read("src/components/layout/bottom-nav.tsx")).toContain( 'data-keyboard-hide=""', diff --git a/src/app/globals.css b/src/app/globals.css index 9f8b8e3b3..6d230f1fe 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -628,6 +628,21 @@ html[data-keyboard="open"] [data-keyboard-hide] { display: none !important; } +/* + * Toasts clear the bottom bar wherever the phone shell shows it. The + * toaster's `mobileOffset` (providers.tsx) applies below 600 px only, while + * the bar follows the shell (up to `md`, and a phone held sideways): between + * the two the "new version" toast sat over the tabs. Unlayered and one `html` + * deeper than Sonner's injected `[data-sonner-toaster][data-y-position]` + * rule, which is unlayered too and lands after this sheet. The Coach panel's + * rule further down still outranks it while that panel is open. + */ +html [data-sonner-toaster][data-y-position="bottom"] { + @variant shell-mobile { + bottom: calc(4rem + env(safe-area-inset-bottom, 0px) + 0.75rem); + } +} + /* * Side and top sheets run the full height of the window. In an installed * app on a tablet the status bar sits over their first 24 px, and a phone diff --git a/src/components/providers.tsx b/src/components/providers.tsx index 55e3ec559..07d77b6dc 100644 --- a/src/components/providers.tsx +++ b/src/components/providers.tsx @@ -392,8 +392,9 @@ function OfflineMutationToaster() { * Below 600 px Sonner lays toasts across the bottom edge, 16 px up, which on * a phone is on top of the bottom bar: the "new version" hint sat over the * tabs and the add button until it was dismissed. The mobile offset lifts - * them above the bar and the home indicator. From `md` the bar is gone and - * the desktop offset applies. + * them above the bar and the home indicator. Sonner applies it below 600 px + * only, while the bar follows the shell (up to `md`, and a phone held + * sideways), so `globals.css` repeats the lift under `shell-mobile`. */ function AppToaster() { const { resolvedTheme } = useTheme();