From c1a2608bddf13497051cf64b4ac8dee206797532 Mon Sep 17 00:00:00 2001 From: KeelrLeek <156356974+KeelrLeek@users.noreply.github.com> Date: Mon, 14 Sep 2026 15:31:31 -0500 Subject: [PATCH] =?UTF-8?q?android:=20three=20the=20audit=20found=20?= =?UTF-8?q?=E2=80=94=20bars=20translucent=20over=20nothing,=20and=20two=20?= =?UTF-8?q?insets=20the=20WebView=20does=20not=20report?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A pass over every screen the app can reach, at rest and scrolled, shot from the DEVICE so the Android status bar is in the frame. Three of what it found are nothing to do with the page's top edge and predate it; they are here on their own. **The bars are translucent over nothing.** Glass — the backdrop blur behind the chrome — is off by default on the phone, deliberately: perf.mjs measured three blurred bands taking a 60 Hz scroll to 30. But the bars kept the alphas that were chosen to sit ON that blur, so what shipped was the middle state, 92% and 94% over no backdrop at all. The audit reads "Random Access Memories", "Alive 2007", "Latest release" and "Touch (feat. Paul Williams) 8:17" straight through the navigation bar. The base values are the no-glass case — `html[data-glass="blur"]` overrides them — so the base is what had to be opaque; the blurred variants keep their alphas, because there they have something to be translucent against. The device now answers `rgb(16, 16, 19)` for the nav and `rgb(28, 28, 32)` for the mini bar, no alpha on either. **The bottom inset is reported as zero, and the gesture pill is drawn anyway.** The WebView answers 51px for the top and 0 for the bottom, while the page runs the full height under Android's gesture handle — the nav measured y 855→915 of a 915 viewport — so its labels sat exactly where the pill lands, straight through the word "Library". **And in landscape the top goes to zero too.** The cutout's inset correctly moves to the side (portrait top=51 left=0; landscape top=0 left=51), but the status bar is still drawn across the top there, so the clock sat on "MONDAY, SEPTEMBER 14" and the battery icons sat on the floating ⋯. Both are floors rather than replacements: `max(env(...), 18px)` and `max(env(...), 24px)`, 24 being Android's own status bar height. A device that reports its insets properly is untouched — portrait's 51 wins on its own — and only one that reports nothing gets the floor, which every Android with a gesture pill or a status bar needs. Everything along the bottom is already anchored to `--inset-bottom`, so the mini bar, `.endpad`, the composer, the sheets and the player frame all move in step with it. What the pass did NOT find, having looked: the chip rows clipped at the right edge of the sleep-timer and sort sheets are not broken — `scrollWidth 458` in a `clientWidth 412` with `overflow-x: auto`, so they are meant to be swiped, though nothing on screen says so. The player's three faces, the artwork viewer, the track sheet, the page overflow and Community's four tabs all render correctly. The harness is in research/ (gitignored): shots.mjs walks every reachable screen and shoots the device frame at several offsets, contact.mjs tiles a pass into one sheet, clip.mjs records a GIF of the app scrolling, fadetry.mjs previews a CSS value live without a build, and selectors.mjs checks in one minute what the full walk takes twenty to cover. Two things it learned the hard way are written into it: every overlay sits on top of whatever page is behind it, and a pass once came back as twenty-five photographs of the same player sheet; and every tab keeps its own stack, so go(tab) shows that stack's top and only resets when the tab is already active — a pass shot Discography and labelled it You. --- src/mobile/mobile.css | 13 +++++++++++-- src/mobile/shell.css | 8 +++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/mobile/mobile.css b/src/mobile/mobile.css index f75d0c0..c53197c 100644 --- a/src/mobile/mobile.css +++ b/src/mobile/mobile.css @@ -55,8 +55,17 @@ --tap: 48px; /* Android's own insets: the status bar above, the gesture handle below. */ - --inset-top: env(safe-area-inset-top, 0px); - --inset-bottom: env(safe-area-inset-bottom, 0px); + /* A floor, for the same reason as --inset-bottom. Landscape reports the + cutout on the side and the top as 0, but the status bar is still drawn + across the top there — without this the clock sits on the page's own + kicker and the battery icons sit on the floating ⋯. Portrait reports 51 + (the punch-hole included) and keeps it. */ + --inset-top: max(env(safe-area-inset-top, 0px), 24px); + /* A floor, because this WebView reports the bottom inset as 0 while it + reports the top as 51 — and the gesture pill is still drawn down there, + straight across the nav's "Library". A device that reports its own + inset keeps it; only one that reports nothing gets the floor. */ + --inset-bottom: max(env(safe-area-inset-bottom, 0px), 18px); /* landscape moves the cutout and the gesture pill to the SIDES, and viewport-fit=cover puts our content under both */ --inset-left: env(safe-area-inset-left, 0px); diff --git a/src/mobile/shell.css b/src/mobile/shell.css index 57cdeb7..cdf6741 100644 --- a/src/mobile/shell.css +++ b/src/mobile/shell.css @@ -628,7 +628,7 @@ html[data-material="solid"] .card, html[data-material="solid"] .group { backgrou align-items: center; gap: 11px; padding: 0 10px 26px 8px; /* 4 above the lane, 16 of lane, 6 below */ - background: rgba(28, 28, 33, 0.94); + background: #1c1c20; /* opaque for the same reason as .nav */ box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.09), 0 10px 28px -10px rgba(0, 0, 0, 0.9); overflow: hidden; transition: transform var(--m-sheet), opacity 200ms ease; @@ -654,7 +654,9 @@ html[data-material="solid"] .mini { background: #1c1c20; backdrop-filter: none; height: calc(var(--nav-h) + var(--inset-bottom)); padding-bottom: var(--inset-bottom); display: flex; - background: rgba(16, 16, 19, 0.92); + /* opaque: glass is off by default, so there is no blur for an alpha to + sit on — 0.92 here let album titles read through the nav */ + background: #101013; box-shadow: 0 -1px 0 rgba(255, 255, 255, 0.06); transition: transform var(--m-sheet); } @@ -892,7 +894,7 @@ html[data-material="solid"] .nav { background: #101013; backdrop-filter: none; - display: flex; flex-direction: column; border-radius: var(--r-sheet) var(--r-sheet) 0 0; - background: rgba(26, 26, 30, 0.97); + background: #1a1a1e; /* opaque for the same reason as .nav */ box-shadow: 0 -14px 40px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.1); transform: translateY(102%); transition: transform var(--spd-spatial-default) var(--sp-spatial-default);