fix(ui): size mobile layout from the live visible viewport, not dvh

Brave Android (custom bottom toolbar) and some other mobile browsers report
dvh taller than the actually visible area while position:fixed elements track
the visible viewport — so 100dvh containers extended under the browser tab
bar and the bottom of every page could never be scrolled into view.

main.ts now keeps --visual-viewport-height synced to window.innerHeight
(resize / orientationchange / visualViewport events — the same reference
frame as the fixed tab bar), and the dashboard shell, chat, and app-session
mobile heights consume it with 100dvh as fallback. The app now scales with
the browser chrome as it shows/hides. Scroll clearance margin 16px → 28px.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-07-14 09:31:52 +01:00
co-authored by Claude Fable 5
parent 85f9fc2296
commit cb4d17d1a9
3 changed files with 28 additions and 2 deletions
+8 -2
View File
@@ -175,11 +175,13 @@ select:focus-visible {
`.min-h-screen` (100vh) utility on specificity. */
.dashboard-view.dashboard-view {
height: 100dvh;
height: var(--visual-viewport-height, 100dvh);
min-height: 100dvh;
min-height: var(--visual-viewport-height, 100dvh);
}
.mobile-scroll-pad {
padding-bottom: calc(var(--mobile-tab-bar-height, 88px) + var(--safe-area-bottom, env(safe-area-inset-bottom, 0px)) + var(--audio-player-height, 0px) + 16px);
padding-bottom: calc(var(--mobile-tab-bar-height, 88px) + var(--safe-area-bottom, env(safe-area-inset-bottom, 0px)) + var(--audio-player-height, 0px) + 28px);
}
.mobile-scroll-pad-back {
padding-bottom: calc(var(--mobile-tab-bar-height, 88px) + var(--safe-area-bottom, env(safe-area-inset-bottom, 0px)) + var(--audio-player-height, 0px) + 64px);
@@ -202,7 +204,9 @@ select:focus-visible {
fully clear of the tab bar, with the .mobile-scroll-pad margin visible. */
.dashboard-view.dashboard-view {
height: 100dvh;
height: var(--visual-viewport-height, 100dvh);
min-height: 100dvh;
min-height: var(--visual-viewport-height, 100dvh);
}
.dashboard-view .app-header-inline-tabs {
@@ -224,7 +228,7 @@ select:focus-visible {
}
.mobile-scroll-pad {
padding-bottom: calc(var(--mobile-tab-bar-height, 88px) + var(--safe-area-bottom, env(safe-area-inset-bottom, 0px)) + var(--audio-player-height, 0px) + 16px);
padding-bottom: calc(var(--mobile-tab-bar-height, 88px) + var(--safe-area-bottom, env(safe-area-inset-bottom, 0px)) + var(--audio-player-height, 0px) + 28px);
}
.mobile-scroll-pad-back {
@@ -622,6 +626,7 @@ input[type="radio"]:active + * {
.chat-fullscreen {
max-height: 100vh;
max-height: 100dvh;
max-height: var(--visual-viewport-height, 100dvh);
}
}
@@ -648,6 +653,7 @@ input[type="radio"]:active + * {
.chat-iframe-mobile {
height: calc(100vh - var(--mobile-tab-bar-height, 72px) - var(--safe-area-top, env(safe-area-inset-top, 0px)) - var(--audio-player-height, 0px) - 16px) !important;
height: calc(100dvh - var(--mobile-tab-bar-height, 72px) - var(--safe-area-top, env(safe-area-inset-top, 0px)) - var(--audio-player-height, 0px) - 16px) !important;
height: calc(var(--visual-viewport-height, 100dvh) - var(--mobile-tab-bar-height, 72px) - var(--safe-area-top, env(safe-area-inset-top, 0px)) - var(--audio-player-height, 0px) - 16px) !important;
flex: none;
}
}