feat(app): native-feel pass - #55
Conversation
Press feedback on every control, direction-aware tab transitions and a haptic tick on tab switch. The shell keeps a phone shape on wide screens; the theme follows the OS live; the Android keyboard shrinks the layout so bottom sheets stay usable. Two failure paths now leave on their own: a stalled passkey ceremony gets a Cancel, and an open that outlives a beat says what it is doing. Manifest gains id and long-press shortcuts; update checks run at launch. Polish: scrim, z-index and pill tokens replace literals in the sheets and the canvas zero-line; micro-text sits at 10px or above; range pickers meet the 44px target floor.
The hero's box-page snapshot and the charger ask land in chunks after mount, inside the window this test judged. Let them settle first, so the assertion measures what the tap alone adds — which is the thing it was written to prove.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 83375eb093
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| max-width: 34rem; | ||
| margin-inline: auto; |
There was a problem hiding this comment.
Keep fixed sheets within the capped shell
On viewports wider than 34rem, this caps and centers the main app but not its modal sheets: the .sheet rules in both LivePanel.svelte and EvPanel.svelte use position: fixed; left: 0; right: 0, so they remain viewport-wide because this ancestor does not establish their fixed-position containing block. Opening a live-flow or EV sheet on a tablet/desktop therefore produces a full-width panel beneath a narrow centered app; constrain those sheets to the same width and centering as the shell.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 83375eb. Configure here.
| position: fixed; | ||
| inset: 0; | ||
| max-width: 34rem; | ||
| margin-inline: auto; |
There was a problem hiding this comment.
Sheets ignore phone-shaped shell
Medium Severity
Capping .app at 34rem and centering it does not create a containing block for position: fixed descendants. EvPanel and LivePanel sheets still use left: 0 / right: 0 against the viewport, so on tablet and desktop they span the full window while the shell stays phone-width. portal places those layers on .app, but fixed positioning remains viewport-relative without a transform or similar on the shell.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit 83375eb. Configure here.
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
ftw-webapp | 83375eb | Commit Preview URL Branch Preview URL |
Aug 21 2026, 05:22 PM |




Two commits: the UX pass, and one small test fix that unblocks CI (details below). No merge until reviewed.
What changed
Native feel
:activerule plustouch-action: manipulationin base.css (previously only the four tab buttons answered a press).routeIndexexported from route.svelte.ts). Hidden views never animate; reduced motion collapses to an instant swap through the existing token..appcaps at 34rem and centres, so iPad/desktop no longer show a left-hugging column under a full-width tab bar.interactive-widget=resizes-content: Android Chrome shrinks the layout for the keyboard instead of painting it over the EV sheet's inputs.matchMedialistener follows the OS mid-session unless a choice is stored."id": "/", long-press shortcuts for Plan and History.Robustness
pairingandrecoveringstages — a stalled passkey ceremony no longer needs the OS to escape. A result that lands anyway still applies.Polish
--scrimper theme,--z-band/overlay/sheet,--radius-pill. Both sheets and the canvas zero-line consume them; no raw colour outside tokens.css except documented cases..label.The test-fix commit
LivePanel.svelte.test.tsfailed onmainbefore this PR: Now's hero (from #53/#54) fetches/api/statusand/api/savings/dailyin chunks that land inside the window the test judged, so "the live line needs only the stream" read as a failure. The fix lets those background asks settle first, then measures what the tap alone adds — which is the thing the test was written to prove. Fails onmain, passes here.Verification
npm run verify: 918 tests passed, 1 skipped, svelte-check 0 errors / 0 warnings, production build clean.Deferred (need device testing or their own PR)
black → default— must be verified against the WebKit inset bug on hardware.Note
Cursor Bugbot is generating a summary for commit 83375eb. Configure here.