From 9f2d4c2468f9375fc24b64ec4823db23be9ca85c Mon Sep 17 00:00:00 2001 From: Evan Date: Thu, 27 Aug 2026 13:45:56 -0700 Subject: [PATCH 1/2] fix(client): scroll inside inline page modals again, not the document MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #5009 unbounded the layout height chain so the homepage scrolls at the document level (needed for ad viewability). That also unbounded the inline page modals rendered in the content area (store, settings, leaderboard, help, ...): they used to get a bounded height from `body h-full overflow-hidden` -> content div -> `main-layout`, so o-modal's `[data-modal-scroll]` container did the scrolling. Without it the modal grew to its full content height and the whole page scrolled. Re-lock the layout only while an inline page is open, keyed off a `page-open` body class toggled in showPage() (same pattern as `in-game`). body becomes a column there because #5009 made it a wrapping row to give the Playwire header-ad slot its own line — a column lets the content area take the height remaining under that slot instead of overflowing by its height. The `min-h-0` additions restore what the removed overflow rules implicitly gave those flex children; they are inert on the homepage, whose chain is auto-height. Co-Authored-By: Claude Fable 5 --- index.html | 8 +++++++- src/client/Navigation.ts | 2 ++ src/client/components/MainLayout.ts | 4 ++-- src/client/styles.css | 11 +++++++++++ 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index a0df7f83ad7..315f930332e 100644 --- a/index.html +++ b/index.html @@ -58,6 +58,12 @@ flex-basis: 100%; width: 100%; } + /* body is a column while an inline page is open (see styles.css): + size the slot to its content there, not to 100% of the height. */ + body.page-open #pw-oop-flex_container { + flex-basis: auto; + flex-shrink: 0; + } /* Google Funding Choices CCPA link override */ .fc-dns-link, @@ -234,7 +240,7 @@
diff --git a/src/client/Navigation.ts b/src/client/Navigation.ts index f83830a9c3f..8475a03eff7 100644 --- a/src/client/Navigation.ts +++ b/src/client/Navigation.ts @@ -15,6 +15,8 @@ export function closeMobileSidebar() { export function initNavigation() { const showPage = (pageId: string) => { window.currentPageId = pageId; + // Inline pages scroll inside their modal, not the document (see styles.css) + document.body.classList.toggle("page-open", pageId !== "page-play"); // Close mobile sidebar if a nav item was clicked closeMobileSidebar(); diff --git a/src/client/components/MainLayout.ts b/src/client/components/MainLayout.ts index 2b60b3ee4f7..6bf5a8f1153 100644 --- a/src/client/components/MainLayout.ts +++ b/src/client/components/MainLayout.ts @@ -19,10 +19,10 @@ export class MainLayout extends LitElement { render() { return html`
${this._initialChildren}
diff --git a/src/client/styles.css b/src/client/styles.css index 57f896bb6cf..3ec239fcaf9 100644 --- a/src/client/styles.css +++ b/src/client/styles.css @@ -101,6 +101,17 @@ body.in-game { overflow: hidden; } +/* An inline page (store, settings, leaderboard, ...) is a modal rendered in + the content area: lock the document so it scrolls inside the modal, and + stack body children in a column so the content area gets the height left + under the header-ad slot. */ +body.page-open { + height: 100%; + overflow: hidden; + flex-direction: column; + flex-wrap: nowrap; +} + * { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; From fe0617cf8253308dad0ddb1999b94ff91482c4aa Mon Sep 17 00:00:00 2001 From: Evan Date: Thu, 27 Aug 2026 16:30:51 -0700 Subject: [PATCH 2/2] fix(client): keep page-open across page-to-page navigation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit showPage() set the page-open body class before closing the previously visible modal. An inline modal's close() re-enters showPage("page-play"), which cleared the class again, and the outer call never restored it — so navigating Store -> Settings (nav bar, ModalRouter) still scrolled the document instead of the modal. Toggle the class after the close block. Co-Authored-By: Claude Fable 5 --- src/client/Navigation.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/client/Navigation.ts b/src/client/Navigation.ts index 8475a03eff7..e9408678dc3 100644 --- a/src/client/Navigation.ts +++ b/src/client/Navigation.ts @@ -15,8 +15,6 @@ export function closeMobileSidebar() { export function initNavigation() { const showPage = (pageId: string) => { window.currentPageId = pageId; - // Inline pages scroll inside their modal, not the document (see styles.css) - document.body.classList.toggle("page-open", pageId !== "page-play"); // Close mobile sidebar if a nav item was clicked closeMobileSidebar(); @@ -37,6 +35,11 @@ export function initNavigation() { } } + // Inline pages scroll inside their modal, not the document (see + // styles.css). Set after closing the previous modal: an inline modal's + // close() re-enters showPage("page-play"), which would clear this. + document.body.classList.toggle("page-open", pageId !== "page-play"); + // Handle page-play separately (it's not a page-content element) const pagePlayEl = document.getElementById("page-play"); if (pageId === "page-play") {