diff --git a/src/app/globals.css b/src/app/globals.css index 558d1b8..2e32973 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -51,6 +51,8 @@ } html { + height: 100%; + overflow: hidden; overscroll-behavior: none; } @@ -59,6 +61,18 @@ body { -moz-osx-font-smoothing: grayscale; } +/* + * Keep the application attached to Safari's current visible viewport. A + * percentage height can retain the old layout viewport after an iOS tab is + * restored, leaving the normal-flow mobile navigation above the bottom edge. + */ +.app-viewport { + height: 100vh; + height: 100dvh; + min-height: 0; + overflow: hidden; +} + button, a, input, @@ -128,6 +142,6 @@ html[data-reader-width="wide"] .mail-reader-container { } @media print { - html, body { height: auto !important; overflow: visible !important; } + html, body, .app-viewport { height: auto !important; overflow: visible !important; } body > div, main { height: auto !important; overflow: visible !important; } } diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 97e0f70..2936145 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -56,8 +56,12 @@ export default async function RootLayout({ const session = await auth(); return ( - -
+ + @@ -128,7 +132,7 @@ export default async function RootLayout({ {/* Mobile bottom nav — hidden on desktop */} {session && ( -+ The navigation stays attached to the live mobile viewport. +
+
diff --git a/src/app/smoke-tests/page.tsx b/src/app/smoke-tests/page.tsx
index cf0846f..7f33187 100644
--- a/src/app/smoke-tests/page.tsx
+++ b/src/app/smoke-tests/page.tsx
@@ -14,6 +14,7 @@ const smokePanels = new Set