Skip to content

🤖 fix: reclaim the mobile bottom band and move the PR badge to the header - #3757

Merged
ibetitsmike merged 5 commits into
mainfrom
mike/mobile-status-bar
Jul 29, 2026
Merged

🤖 fix: reclaim the mobile bottom band and move the PR badge to the header#3757
ibetitsmike merged 5 commits into
mainfrom
mike/mobile-status-bar

Conversation

@ibetitsmike

@ibetitsmike ibetitsmike commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Summary

On phones the workspace footer info bar stranded a band of empty space below it, and its PR badge overlapped the drift toggle. This hands the bottom safe-area inset to the chat column so the footer bar reaches the screen edge with a small home-indicator clearance, and moves the PR badge into the workspace header below 768px.

Background

Reported from an iPhone against the chrome redesign in #3753.

The footer bar was written to own the mobile bottom inset: a negative margin was supposed to pull its fill down to the screen edge while its own padding kept the controls clear of the home indicator. That never worked. .mobile-main-content, .mobile-layout, and the workspace shell all set overflow: hidden and end at the app root's content edge, so anything the footer painted inside the root's pb-[env(safe-area-inset-bottom)] was clipped. The result was a ~34pt band under the bar in the root's own fill, which reads as dead space.

The overlapping PR badge is a separate mobile-only bug: the touch-target rule in globals.css puts an explicit min-width: 44px on every link, which replaces the flex min-content floor, so the badge could shrink to 44px inside the footer's scrolling row while its label spilled over the next item.

Implementation

  • Inset ownership: since the padding holder cannot be an ancestor of the row that wants the space, ownership is declared by the column rather than inferred from the route. ChatPane marks itself data-bottom-inset-owner while visible (dropped when immersive review hides it), and globals.css drops the root's bottom padding at narrow widths via .mobile-bottom-inset-host:has([data-bottom-inset-owner]). Immersive review, the loading placeholder, settings, analytics, creation, and the root shells keep the inset with no route knowledge in App, and any future footerless workspace surface inherits the safe default.
  • WorkspaceFooterBar: no negative margin; at narrow widths it reserves an 8px-capped clearance. Its fill genuinely reaches the screen edge, and ~26pt comes back to the transcript.
  • WorkspaceMenuBar: renders the PR badge below 768px; the footer copy hides at the same width. Duplicate-and-hide via CSS rather than a width hook, so there is no resize state and the hidden copy leaves the accessibility tree. WorkspaceLinks forwards a className to the badge itself so hiding it does not leave an empty flex item behind in a gap-2 row.
  • PRLinkBadge: shrink-0, fixing the overlap for any row that holds it.

Validation

env(safe-area-inset-bottom) is 0 in a desktop browser, so the band this PR removes is invisible to normal Storybook checks. Measured over CDP (Emulation.setSafeAreaInsetsOverride with bottom 34px, plus touch emulation and mobile device metrics):

state root padding-bottom owners evidence
workspace chat, before 34px n/a footer fill clipped at y=810, controls end at y=810
workspace chat, after 0px 1 footer fill to y=844, controls end at y=836
immersive review, 440x956 34px 0 immersive view ends at y=922
project creation, 390x844 34px 0 column ends at y=810

Wide touch (1024px, same insets) is unchanged: the root keeps its inset, the footer reserves nothing, and the row still ends at the column's content edge. Light theme has no colour seam at the bottom edge, because the footer's own fill covers the clearance.

Two story assertions, both red-green verified:

  • IPhone16ePRLinkPlacement: exactly one PR link is visible, in the header when the viewport matches the narrow query and in the footer otherwise. Un-hiding the header copy fails with At 1280px the PR link belongs in the footer, but 1 were visible in the header and 1 in the footer. Pixel captures the narrow placement; the test-runner runs at desktop width and covers the wide placement.
  • IPhone17ProMaxTouchReviewImmersive: while immersive review is open, nothing claims data-bottom-inset-owner. Making the attribute unconditional fails with Immersive review left the bottom safe-area inset unowned. This one holds without an inset override because it tests the handoff, not the resolved padding.

Risks

Footer controls now sit 8px above the physical edge rather than 34pt, so their bottom sliver overlaps the home-indicator strip. The indicator itself is a ~5pt pill within the bottom ~13pt, the strip is reserved for edge-swipe drags rather than taps, and touch targets there are 44px tall, so taps on the labels still land. Raising or removing the pb-[min(env(safe-area-inset-bottom,0px),8px)] cap is a one-line change if it reads badly on device.

Two surfaces now subscribe to PRStatusStore for the same workspace. The store keys its cache and refresh batching by workspace id, so this adds a subscriber rather than a second gh pr view.


Generated with mux • Model: anthropic:claude-opus-5 • Thinking: xhigh

…ader

The workspace footer bar reserved the full iOS bottom safe-area inset, but every
ancestor between it and the app root clips overflow at the root's content edge,
so its negative margin never reached the screen edge. Drop the root's bottom
inset at narrow widths and let the footer own a small clearance instead.

Also move the PR badge to the workspace header below 768px (it was overlapping
the drift toggle on phones because the touch-target min-width lets a link shrink
below its content), and add a phone story asserting the placement.
@ibetitsmike

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5c51762b18

ℹ️ 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".

Comment thread src/browser/App.tsx Outdated
@ibetitsmike

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d00ceaeaf9

ℹ️ 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".

Comment thread src/browser/components/ChatPane/WorkspaceFooterBar.tsx
@ibetitsmike

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 078a582c71

ℹ️ 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".

Comment thread src/browser/components/ChatPane/WorkspaceFooterBar.tsx
@ibetitsmike

Copy link
Copy Markdown
Contributor Author

@codex review

The only remaining thread was the footer clearance cap, which is an intentional owner-requested tradeoff (rationale in the resolved thread). Nothing else changed since the last round. Please confirm the rest of the diff.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 078a582c71

ℹ️ 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".

Comment thread src/browser/App.tsx Outdated
@ibetitsmike

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 411632987c

ℹ️ 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".

Comment thread src/browser/stories/App.phoneViewports.stories.tsx
@ibetitsmike

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7cbdb293b0

ℹ️ 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".

Comment thread src/browser/components/ChatPane/WorkspaceFooterBar.tsx
@ibetitsmike

Copy link
Copy Markdown
Contributor Author

@codex review

All functional checks pass on 7cbdb293b, and the two substantive findings from the last round are fixed in code: inset ownership is now declared by the chat column (data-bottom-inset-owner + :has() in globals.css) so immersive review and the loading shell keep the inset, and the placement story pins a phone viewport global.

The footer clearance cap is an intentional owner-requested tradeoff with the rationale recorded in the resolved thread; please review the rest of the diff on that basis rather than re-raising it.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Swish!

Reviewed commit: 7cbdb293b0

ℹ️ 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".

@ibetitsmike
ibetitsmike merged commit 8cc3eae into main Jul 29, 2026
20 of 21 checks passed
@ibetitsmike
ibetitsmike deleted the mike/mobile-status-bar branch July 29, 2026 15:28
ibetitsmike added a commit that referenced this pull request Jul 29, 2026
…transcript column (#3758)

## Summary

Removes the "Let's get building." headline from the creation page, and
lines every surface in the composer dock up with the transcript column
so the composer stops floating in the middle of a full-width transcript.

## Background

Both reported from the chrome redesign in #3753. Rebased onto `main` now
that #3757 has merged, so this diff is only the two commits below.

The headline gave a static string the largest type on the page. It was
already `sr-only` below 768px, so this removes it outright.

The alignment bug is structural. The composer dock lives *inside* the
transcript scrollport and cancels its `px-[15px]` gutter with
`mx-[-15px]` so it can paint full-bleed. Every surface inside the dock
therefore has to re-apply that gutter and follow the transcript's width
mode. They all hardcoded `px-4` (16px) plus `mx-auto max-w-4xl` instead.

Centered mode hid this completely: the transcript and the docked
surfaces shared both a center line and the same `4xl` cap, so their
edges coincided by accident. Turn on `chatTranscriptFullWidth` and the
transcript uncaps while everything docked stays 896px wide.

## Implementation

`CHAT_DOCK_GUTTER_CLASS` (in `constants/layout`) plus
`ChatDockColumnProvider` / `useChatDockColumnWidthClass` /
`ChatDockSurface` (in `components/ChatPane/chatDockColumn`) now carry
the contract. The dock provides the width mode; surfaces inside consume
it.

Applied to the composer section, `ChatInputDecoration` (todos,
background bashes, reviews, queued messages, chat instructions),
`ConcurrentLocalWarningDecoration`, and `TranscriptOnlyNoticePane`. The
second commit sweeps three decoration-lane entries that never followed
the column in *either* mode: the compaction warning and context-switch
banner carried their own `mx-4`, and the pre-stream task card had no
gutter at all. All three go through `ChatDockSurface`, and the two
`mx-4` values are removed so the wrapper is the single source of the
inset.

The width mode resolves through context rather than calling
`useChatTranscriptFullWidth` per surface, because that hook also issues
a `config.getConfig` fetch and an `onConfigChanged` subscription per
instance, and the dock can hold several decorations at once.

## Validation

Measured at 1500px with the left sidebar collapsed: in full-width mode
the transcript rows, composer box, background-bash decoration, and
auto-compact label all span 35..1465; centered, all cap at 896.

Two play tests (`FullWidthTranscriptAlignment`,
`CenteredTranscriptAlignment`) assert every docked surface shares the
transcript column's left and right edges, including each
`ChatDockSurface`-wrapped entry. Four red-green toggles:

| toggle | failure |
| --- | --- |
| width class reverted to the hardcoded cap | `Docked composer is inset
... by 157px left and 157px right` |
| gutter reverted to `px-4` | `... by 1px left and 1px right` |
| compaction warning unwrapped | `No ChatDockSurface-wrapped entry
rendered` |
| transcript pinned to centered | `Transcript is 896px wide, so this
story is not in full-width mode` |

The centered story separately asserts the scrollport has room to exceed
the cap, so it proves the cap is what limits the column rather than the
available width.

One trap worth recording:
`updatePersistedState(CHAT_TRANSCRIPT_FULL_WIDTH_KEY, true)` does
**not** enable full width in a story, because
`useChatTranscriptFullWidth` syncs from `config.getConfig` and
overwrites it. The story would silently run centered and pass with the
bug present. `setupSimpleChatStory` now takes `chatTranscriptFullWidth`
and threads it to the mock config.

## Risks

Expect Pixel diffs on any story showing the compaction warning,
context-switch banner, or pre-stream task card: those move from a 16px
full-bleed inset onto the composer column, which is the intended
correction.

Not fixed here, pre-existing and unrelated to width mode: in centered
mode the composer's toast overlay is positioned against the outer
section rather than the inner column, so it spans nearly the whole dock.
Moving its containing block would also shift it vertically, so it needs
its own change.

---

_Generated with `mux` • Model: `anthropic:claude-opus-5` • Thinking:
`xhigh`_

<!-- mux-attribution: model=anthropic:claude-opus-5 thinking=xhigh -->
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