fix(mobile/iOS): double-scroll container in orbit shell — real root of header overlay/logo cut
The real root of the iOS header saga — double scroll container (verified, not theorized)
Measured on live prod with Linux WebKit 26.5 (iPhone emulation), matching Catalyst's on-device symptoms exactly:
- Page has two scroll containers: the body AND orbit's
.notLoggedInshell (which carries inlineoverflow: hidden). - On WebKit, the inner container accumulates its own scrollTop (measured 48px) which
window.scrollTo(0,0)cannot reset (body's 76px and the inner 48px hold independently). - At "scroll zero" the header/logo/main still sat at −48px — the top ~100–150px of the page is unreachable. Fixed menu displaced. Exactly Catalyst's report.
- With the fix applied live (
overflow: visible !important) + a scroll-down-and-back cycle:scrollY=0, inner=0, headerTop=0, logoTop=0, mainTop=0— state fully healed.
Why this explains every observed pattern:
- First-load logo full-screen flash (~0.1s, sometimes): content paints while the two scrollers negotiate offsets.
- Short routes (appels, consultations) heal the page after visiting: they never scroll, so the inner scroller holds no offset — tall routes keep drift.
- Deterministic on first load, Android always fine: Blink reconciles nested scrollers differently — no negative offset at scroll 0.
- Why it "came with !65 (merged)": before, the same broken state rendered as an invisible overlap (header painted over content); blockifying the header made the offset state visible instead.
The fix (11 lines, CSS-only, upgrade-safe)
.notLoggedIn { overflow: visible !important } — orbit's inline overflow:hidden beats plain class rules, hence !important. Removes the inner scroll container entirely; body becomes the only scroller. Horizontal clipping is unaffected: body's own overflow-x: hidden propagates to the viewport per spec.
Light-DOM global CSS — applies before component hydration, immune to the iOS shadow-style registration race we also identified today.
Falsified along the way (kept for the record)
-
Service worker stale cache(cleared on-device, no change) -
Document height limit(no height change in !65 (merged)/!66 (merged); short/long pages both misbehave depending on route history) -
risefor-img height-cycle (MR !68 (merged))— closed; cut exists only when the route state puts the header above the viewport. - Deploy/CF cache staleness — real ops hazard, but not this bug.
Deploy note (⚠ ️ important)
/static/* sits behind Cloudflare with a 4h TTL. After merge + prod pull: purge CF (or wait) or the phone keeps the old core.css and the test reads false. (Burned once today.)
iPhone checklist
- Listing pages: titles fully visible, header/logo intact at top.
- Menu icon: positioned normally (top-right, not displaced).
- The route-alternation pattern (appels fix it, tall pages break it) should be gone entirely.
- Desktop/Android: zero visual change (Blink rendered both states the same).