(motir-core) The authed top bar OVERFLOWS below md — the right cluster is 290–409px in a 375px viewport, and it covers the hamburger
Repo: motir-core. One PR. Surfaced while building MOTIR-1150 (the brand slot in TopNav), which deliberately scoped the sweep out and shipped a md: guard around its own addition instead. Logged as its own card rather than absorbed (notes.html #27 / the drive-by-fix rule).
⚠️ AMENDED 2026-08-08 by its design blocker, MOTIR-2374 (
notes.html#242 — a design that lands after the card it feeds amends that card, rather than leaving it to build the thing the design replaced). The design's render found a band this card did not know about and settled the shape of the fix; the acceptance criteria below are the design's, not the original improvisation menu. Readdesign/shell/design-notes.md§ The top bar's control budget anddesign/shell/top-bar.pngbefore starting. Re-estimated 3 → 5 points as a result.
The defect
app/(authed)/_components/TopNav.tsx renders <nav className="flex h-14 items-center justify-between gap-2 px-4"> with a left cluster (min-w-0) and a right cluster that carries up to eight controls. The right cluster cannot shrink — its children are fixed-size icon buttons plus two LABELLED buttons ("Build in public", "Plan with AI") — so the left cluster is squeezed to zero width and its children spill out underneath the right cluster, which paints over them.
The visible consequence is that the mobile hamburger stops being clickable: elementFromPoint at its centre returns whatever right-cluster control happens to sit there.
Measured — by MOTIR-2374's render, on origin/main
Right-cluster width, by viewport and by which optional slots are live:
| viewport | private project + AI | public project + AI | self-hosted, no AI, private |
|---|---|---|---|
| 375px | 350px — hamburger covered | 409px — the <nav> scrolls to 433px, hamburger covered | 208px — fits, with 0px to spare |
| 700px | 656px — hamburger covered | 670px — scrolls to 702px | 383px |
⚠️ The worst band is sm–md (640–767px), not < md. At 640px every label switches on at once (hidden sm:inline) and the cluster jumps 350 → 656px inside a 640px viewport — while the hamburger is still mounted, because it is md:hidden and lives to 767px. A fix scoped to 375px leaves that band broken, and a hit-test asserted only at 375×812 passes while it is. That is why the criteria below name two viewports.
Two more measured facts the fix has to carry:
BuildingInPublicHeaderLinkis the one control whose label was never breakpoint-gated — 117px at 375px against the 38px CTA it replaces. That asymmetry, not the control count, is what makes the public state the widest surface in the product.- The cluster already squeezes its own controls below their box: in the public state at 375px the theme toggle and the avatar measure 28px wide against a 36px height (the avatar's
rounded-fullrenders as an ellipse). Three box sizes coexist — 28 / 36 / 38.
Why MOTIR-1150 did not fix it here
That card added a 24px brand mark + divider (57px) at the head of the left cluster. That pushed the hamburger from x=16 to x=73 — into the right cluster's span — and turned the pre-existing overflow into two red E2E specs (shell-flows "mobile drawer opens…", settings-area "the settings nav collapses into the mobile drawer at narrow width"). It shipped hidden md:flex on the brand slot so its own diff is byte-identical to main below md, and left the underlying overflow to this card.
Acceptance criteria
- The four-slot budget below
md. The right cluster carries exactly four controls belowmd—CommandPaletteTrigger,CreateIssueButton,NotificationBell,UserMenu— each one--height-controlsquare,gap-2, 168px total at the default style. The right cluster isflex-none, so it can no longer take width from the left one. - The label breakpoint moves from
smtolg— labels AND their<kbd>hint chips together. Gating one without the other leaves an icon beside a bare⌘Kchip and overflows the square box. This is the change that closes the 640–767px band. PlanWithAILauncher,ReportButton,ThemeToggleand the build-in-public slot arehidden md:inline-flex— they REPLACE their base display utility, since.hiddenand.inline-flexhave equal specificity and the one that wins is whichever Tailwind emits last.SidebarDrawergains the footer utility strip that receives them (design Panel D):flex h-14 shrink-0 items-center gap-2 border-t border-(--el-sidebar-border) px-3, holding the build-in-public slot (labelled, in amin-w-0 flex-1wrapper) thenReportButtonthenThemeToggle. No new component — each is the element that left the bar. The Plan-with-AI pill is NOT in the strip: it is dropped, becausePlanWithAIFabalready ships on every authed screen under the same gate.- The six controls that hard-code their own box take
--height-controlinstead ofh-9/w-9/p-(--spacing-icon-btn)— that is what makes the four slots one square, removes the 28/36/38 mixture, and lets the budget survive adata-styleswap. - At 375×812 AND at 700×812, with every optional slot live (
showPlanWithAi,buildingInPublic,buildInPublicProjectKey, a non-nullinitialUnreadCount),document.elementFromPointat the centre of[aria-label="Open navigation"]returns that button or a descendant of it. Assert it at BOTH widths, do not eyeball it. - No control silently disappears: every displaced control is reachable at phone width, and the test names where — the orb for planning, the drawer strip for theme / report / build-in-public.
- A Playwright case at 375px opens the drawer with the crowded state seeded — the state the current specs do not cover, which is why this shipped — and reaches the theme + report controls inside it.
TopNav's docstring records the budget rule verbatim fromdesign/shell/design-notes.md§ The rule for the ninth control: the below-mdbar is closed at four slots, a new control ismd-and-up by default, and anything it displaces must land in the drawer strip.tests/components/top-nav-brand-slot.test.tsxpins MOTIR-1150'smd:guard. The guard STAYS (the brand is still amd+ slot in the design), but its comment describing the overflow as unfixed is now stale — update it to cite the budget.
Context refs
app/(authed)/_components/TopNav.tsx— the bar; its left cluster ismin-w-0, the right cluster is not.design/shell/design-notes.md+design/shell/top-bar.mock.html/.png(MOTIR-2374) — the design of record. Panels C–E carry the target markup with the exact class strings.components/ui/SidebarDrawer.tsx— gains the footer strip.components/planning/PlanWithAIFab.tsx,app/(authed)/layout.tsx:279— the second door that lets the pill be dropped.tests/e2e/shell-flows.spec.ts·tests/e2e/settings-area.spec.ts— the two specs that exercise this width today, neither with the crowded state.tests/components/top-nav-brand-slot.test.tsx— pins themd:guard MOTIR-1150 shipped.