Skip to content

v3.51.4: cockpit fits the iPhone 18 Pro Max home-screen app (dashboard 0.26.1) - #141

Merged
puretensor merged 1 commit into
mainfrom
fix/iphone-pro-max-standalone-header
Oct 19, 2026
Merged

puretensor merged 1 commit into
mainfrom
fix/iphone-pro-max-standalone-header

Conversation

@puretensor

Copy link
Copy Markdown
Owner

The pTask cockpit now fits the iPhone 18 Pro Max when it runs as the Home Screen app. I checked every tab, the task sheet and the composer in the iOS 27 simulator (440×956 CSS px, 62px status-bar inset), launched from the Home Screen against a snapshot of the production task DB.

What was wrong, and the fix

Problem on the iPhone 18 Pro Max Fix
After a cold launch the board sat under a doubled 124px gap. About 2s in, iOS parks the page at scrollY −62 while the sticky header already pads itself by the 62px inset. Once the page rests below 0 with no finger down, it scrolls back to 0. A real pull-to-bounce settles at 0 on its own, so it never trips this.
The brand + counts row was greyed out. iOS 26+ lays a dark scrim over a web app's status bar that fades ~28px below it. In the Home Screen app only (display-mode: standalone), the header starts 16px lower.
The last ~108px of every pane sat under the tab bar, and a 5-card lane could not scroll at all. body{height:100%} kept its tab-bar padding inside the viewport. body{min-height:100%}.
The lane picker pinned too high and hid under the header. Its offset came from a content-box ResizeObserver, which misses the inset iOS fills in after launch. The observer watches the header's border box.
On lane and review cards, a deadline chip pushed snooze · dismiss · done onto an empty row of their own. The chips wrap in their own column and the actions keep the right edge. Desktop is unchanged (the wrapper is display:contents).
A flick inside an open task sheet scrolled the board behind it. An open sheet locks the board (overflow:hidden plus overscroll containment).
The composer's Deadline date field ran past the card. The native date field is constrained to the card width.
On the timeline, NOW collided with a nearby date ("09-21 +1NOW"). NOW gets its own row.
The hidden skip link peeked out from behind the status bar. It is parked fully above the screen.

Versions: pt 3.51.4, dashboard 0.26.1, with a README changelog entry.

Tests

  • New dashboard/tests/phone_layout.test.mjs (9 tests), added to the CI node list. It runs the shipped launch-offset handler against fake scroll and touch events, and pins the CSS and markup contracts above. I checked that disabling the snap-back makes it fail.
  • Locally, all 124 dashboard Python tests and all 33 Node tests pass.
  • In the simulator, I confirmed each fix by cold-launching the Home Screen app and going through Critical, Lanes (P5 and the 29-task P2), Recent, Review, More, the task sheet and the composer.

🤖 Generated with Claude Code

…d 0.26.1)

Checked in the iOS 27 simulator on an iPhone 18 Pro Max (440x956 CSS px,
62px status-bar inset), launched from the Home Screen like the operator's
phone, against a snapshot of the production task DB.

- Cold launch: ~2s in, iOS parks the page at scrollY -62 while the sticky
  header already pads itself by env(safe-area-inset-top), so the board sat
  under a doubled 124px gap until the first scroll. Once the page rests
  below 0 with no finger down, it goes back to 0. A real pull-to-bounce
  keeps firing scroll events until it settles at 0, so it never trips this.
- iOS 26+ lays a dark scrim over a web app's status bar that fades out
  ~28px below it and greyed the brand + counts row. In the home-screen app
  only, the header starts 16px lower.
- body is min-height:100% instead of height:100%. Pinned to the viewport,
  its 74px + home-indicator padding added no scroll room, so the last
  ~108px of every pane sat under the tab bar and a 5-card lane could not
  scroll at all.
- The lane picker's sticky offset watches the header's border box. iOS
  fills the safe-area inset in after launch, which grows the padding but
  not the content box, so the picker pinned too high and hid under the
  header.
- Lane and review cards wrap their chips in their own column so snooze,
  dismiss and done stay on the right. A deadline chip used to push all
  three onto an empty row of their own. Desktop is unchanged (the wrapper
  is display:contents there).
- An open task sheet locks the board (overflow hidden + overscroll
  containment); a flick inside the sheet used to scroll the page behind it.
- Composer: the native date field ignored width:100% and ran past the
  card. Timeline: NOW gets its own row instead of colliding with a nearby
  date ("09-21 +1NOW"). The hidden skip link no longer peeks out from
  behind the status bar.

Tests: tests/phone_layout.test.mjs (9) runs the shipped launch-offset
handler against fake scroll/touch events and pins the CSS and markup
contracts above; added to the CI node list. Mutation check: disabling the
snap-back fails it. All 124 dashboard Python tests and 33 Node tests pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@puretensor
puretensor merged commit e1b3b86 into main Oct 19, 2026
5 checks passed
@puretensor
puretensor deleted the fix/iphone-pro-max-standalone-header branch October 19, 2026 20:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant