diff --git a/internal/generate-tree.mjs b/internal/generate-tree.mjs index c178a03e1..60529df7f 100644 --- a/internal/generate-tree.mjs +++ b/internal/generate-tree.mjs @@ -798,7 +798,12 @@ function studioRootHtml(bakedToken, integrity = '') { ${bakedToken ? ` \n` : ''}${DEST_CONFIG.apiBaseUrl ? ` \n` : ''}
@@ -1027,9 +1032,15 @@ ${hintBlock} ${peerBlock} font: 13px/1.6 ui-monospace, SFMono-Regular, Menlo, monospace; } #status.err { color: #f87171; }` : `/* BARE full-page map — no chrome. The custom element IS the page, so the - browser URL shares the map itself. */ + browser URL shares the map itself. + HEIGHT IN svh, NOT inset:0. A fixed box with inset:0 follows the phone's DYNAMIC viewport, so the map + (and a legend sheet sized from it) changes height every time the address bar hides or shows. 100svh is + the viewport WITH the bar shown and never changes; when the bar hides, the page background shows below + instead of the map resizing. On a desktop svh = the viewport, so nothing moves there. The 100% before it + is the fallback for a browser without svh, which would otherwise size the box to its content. + --profile-min-h:0 opts out of ProfileLoader's 100dvh floor, which would grow the element again. */ html, body { height: 100%; margin: 0; background: #0a0e15; } - #slot, ${esc(tag)} { position: fixed; inset: 0; width: 100%; height: 100%; display: block; } + #slot, ${esc(tag)} { position: fixed; inset: 0 auto auto 0; width: 100%; height: 100%; height: 100svh; --profile-min-h: 0; display: block; } #status { position: fixed; inset: 0; z-index: 2; display: grid; place-items: center; padding: 24px; text-align: center; color: #9aa7b8; font: 13px/1.6 ui-monospace, SFMono-Regular, Menlo, monospace; } diff --git a/internal/plugin-gallery/dev-plugin.mjs b/internal/plugin-gallery/dev-plugin.mjs index 26eca3a9c..5b6ff2b62 100644 --- a/internal/plugin-gallery/dev-plugin.mjs +++ b/internal/plugin-gallery/dev-plugin.mjs @@ -417,7 +417,10 @@ export function autoSpaDevPlugin(token = '') { // depends on no ancestor and stays a floor, so the page can still grow past it. `${tag}{display:block;width:100%;min-height:100dvh;}` : '`, + // 100svh (100% as the fallback), not 100vh: a phone's 100vh is taller than the view while the address + // bar shows, so the page scrolls by the bar and the app seems to resize; --profile-min-h:0 opts out of + // ProfileLoader's 100dvh floor. The same rule as generate-tree's fixed-viewport leaf. + `${tag}{display:block;width:100%;height:100%;height:100svh;--profile-min-h:0;}`, '', // tree-base ON THE LEAF TOO — cap-5 shells nested here fetch a manifest of their own. // doxa-maps-spa (like plugin-studio) discovers its tabs from the tree's manifest.json and @@ -483,7 +486,7 @@ export function autoSpaDevPlugin(token = '') { // that takes up so much space" is a layout requirement, so the host page contributes // ZERO text — every pixel belongs to the studio element. '', + 'plugin-studio{display:block;width:100%;height:100%;height:100svh;--profile-min-h:0;}', '', // tree-base IS REQUIRED IN DEV — without it the studio mounts EMPTY. // The studio builds its tab list at runtime by fetching `