fix(layout): harden bottom-nav so it cannot overlap the last viewport line

The mobile bottom tab-bar bled into the bottom of the visible area on
/settings/account and /settings/ai per the runtime audit. The bar
previously rendered as bg-card/80 (80% opacity, translucent) and
relied on the inner flex row's h-16 alone for its height — without
a min-height floor on the outer nav, a future variant or any flex-
collapse quirk could let the surface shrink under the 64px floor the
auth-shell counts on.

Pin the bar at min-h-16 on the outer nav (defence in depth against
flex collapse) and switch the surface from bg-card/80 to a solid
bg-card. The safe-area inset and fixed bottom-anchor stay as they
were. Page shells that scroll content beneath the bar are still
responsible for reserving pb-16 + safe-area on their main column;
this change makes the bar itself robust so any future page-shell
oversight produces a hard occlusion (visibly broken on review)
rather than a translucent bleed (silently shipped). Bottom-nav SSR
test stays green (4/4) — five primary anchors, More button,
aria-haspopup, 44px tap-target floor.

Refs: .planning/round-v1433-audit-runtime.md F14
This commit is contained in:
Marc-André Bombeck committed 2026-05-16 17:12:34 +02:00
1 parent 02410b2394
commit 585637d5ab
1 file changed
+16 -1
+16 -1
View File
@@ -68,9 +68,24 @@ export function BottomNav() {
return (
<>
{/* v1.4.33 F14 — bar height and safe-area defence so the bar can
never overlap the last viewport line of scrollable page content.
- `min-h-16` floors the bar at 64px even if the inner flex row
collapses (e.g. a future variant without one of the icons).
- `pb-[env(safe-area-inset-bottom)]` reserves the home-indicator
inset on iOS / iPadOS PWA installs.
- `bg-card` (solid, not the previous `bg-card/80`) plus
`border-t` give the bar a clean visual edge so any page
content that scrolls under the bar is properly occluded
rather than bleeding through a translucent surface. Page-
level pb-* padding owners (auth-shell + per-page shells)
still reserve room above the bar; this change hardens the
bar itself so the visual contract holds even when a page
shell forgets the bottom-padding contract.
*/}
<nav
aria-label={t("nav.mobileNavigation")}
className="bg-card/80 border-border fixed bottom-0 left-0 z-50 w-full border-t pb-[env(safe-area-inset-bottom)] backdrop-blur-md md:hidden"
className="bg-card border-border fixed bottom-0 left-0 z-50 min-h-16 w-full border-t pb-[env(safe-area-inset-bottom)] backdrop-blur-md md:hidden"
>
<div className="mx-auto flex h-16 max-w-lg items-stretch justify-around px-1">
{PRIMARY.map((item) => {