Phone layout: fill the screen in the home-screen app, drop the title row

In the iOS home-screen app the layout viewport - `100dvh`, `innerHeight`, even a
`position: fixed; inset: 0` box - can come back one status bar short, which left the
dock floating that far above the bottom of the screen with an empty strip below it.
In standalone mode the stage now takes its height from `screen` instead (swapped for
landscape, since iOS reports it in portrait), via a `--full-height` variable that
lib/fullHeight.ts sets only there; the keyboard inset is measured against the same
height. A Safari tab, Android and the kiosk are unchanged.

The mascot and app title above the group switch only cost a row on a phone, so they
are gone; the connection/figure pill moves above the group switch, centred, and only
shows while it has something to say.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-03 07:40:21 +02:00
parent 1da2274076
commit 34656a8517
5 changed files with 62 additions and 41 deletions

View File

@@ -13,11 +13,12 @@
--m-dock-clearance: calc(96px + env(safe-area-inset-bottom));
}
/* iOS can leave the layout viewport shorter than the screen - after the keyboard has
been up, `100dvh` in a home-screen app comes back one status bar short - and the
page behind the stage showed as a white strip along the bottom. Pinning the stage to
the viewport's edges does not depend on that height at all, and the sea colour
underneath covers whatever might still peek through. */
/* iOS can leave the layout viewport shorter than the screen in a home-screen app -
`100dvh`, and even `position: fixed; inset: 0`, come back one status bar short - so
the dock floated that far above the bottom with an empty strip below it. There the
stage takes its height from the screen instead (`--full-height` and
`data-standalone`, set by lib/fullHeight.ts only in standalone mode); everywhere else it pins to the viewport.
The sea colour underneath covers whatever might still peek through. */
html,
body {
background: var(--stage-deep, #001b21);
@@ -29,6 +30,11 @@ body {
height: auto;
}
:root[data-standalone] .stage[data-phone] {
bottom: auto;
height: var(--full-height);
}
.m-glass {
background: var(--m-glass-fill);
backdrop-filter: blur(14px) saturate(1.7);
@@ -62,30 +68,12 @@ body {
/* ------------------------------------------------------------------ header -- */
.m-title-row {
display: flex;
align-items: center;
gap: 10px;
padding: calc(14px + env(safe-area-inset-top)) var(--m-gutter) 4px;
}
.m-title-mascot {
width: 44px;
height: 44px;
object-fit: contain;
filter: drop-shadow(0 3px 8px oklch(15% 0.05 var(--hue) / 0.5));
}
.m-title {
flex: 1;
font-size: 28px;
font-weight: 900;
color: var(--paper);
letter-spacing: -0.01em;
text-shadow: 0 2px 10px oklch(15% 0.05 var(--hue) / 0.45);
}
/* Connection lost, or the figure on the reader - centred above the group switch, and
only there while it has something to say. No app title above it: that only cost a
row of space on a phone. */
.m-status {
width: fit-content;
margin: 0 auto 8px;
font-size: 13px;
font-weight: 800;
color: var(--paper);
@@ -114,12 +102,6 @@ body {
padding: calc(10px + env(safe-area-inset-top)) var(--m-gutter) 14px;
}
/* Under the title row, overlap the row by the status bar's height: the bar keeps its
place in the layout but already covers the status bar once it sticks. */
.m-title-row + .m-sticky {
margin-top: calc(-1 * env(safe-area-inset-top));
}
.m-sticky::before {
content: "";
position: absolute;