Skip to content

fix(website): mobile viewport fixes — overflow, touch targets, autocomplete#547

Merged
blove merged 1 commit into
mainfrom
claude/mobile-review
May 27, 2026
Merged

fix(website): mobile viewport fixes — overflow, touch targets, autocomplete#547
blove merged 1 commit into
mainfrom
claude/mobile-review

Conversation

@blove
Copy link
Copy Markdown
Contributor

@blove blove commented May 26, 2026

Summary

Full mobile audit (Playwright, 19 routes × 3 viewports = 360/390/768px) found 154 findings clustered into a few cross-cutting themes. This PR fixes the high-impact ones:

  • Horizontal overflow on 8 hero-style pages (home, /langgraph, /ag-ui, /chat, /render, /pilot-to-prod, /solutions, /solutions/compliance). Root cause: long unbreakable package names (e.g. @threadplane/langgraph, chat-timeline, app.config.ts) inside <h2> headings forced document width past viewport. Fixed globally via overflow-wrap: break-word on h1..h6 plus body { overflow-x: hidden } defensive belt.
  • Differentiator row had a flex-basis: 360px wider than its 320px content area at narrow viewports — caused the home page's 111px overflow even after heading fix. Trimmed to 200px.
  • Nav mobile hamburger hit area was 20×20. Bumped to 44×44 via padding: 12 / margin: -12 (no visual layout shift).
  • Email/name/org inputs across Footer, WhitePaperBlock, LeadForm, ContactForm now have autoComplete attributes for mobile keyboard/autofill.

Not changed (intentional): Eyebrow micro-labels and footer legal disclaimers stay at 12px mono — these are stylistic.

Audit report committed at .audit/mobile-audit-report.md in the audit subagent's worktree (not in this PR).

Test plan

  • CI green
  • Spot-check home, /ag-ui, /langgraph in mobile Chrome — no horizontal scroll, nav menu tap-target feels right
  • Submit #footer-email on mobile — keyboard suggests saved email
  • Lead form on /pricing autofills name + email + org

🤖 Generated with Claude Code

@vercel
Copy link
Copy Markdown

vercel Bot commented May 26, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
threadplane Ready Ready Preview, Comment May 26, 2026 4:53am

Request Review

@blove blove merged commit 2407532 into main May 27, 2026
22 checks passed
blove added a commit that referenced this pull request May 27, 2026
Follow-up to #547. body { overflow-x: hidden } prevents the user-visible scrollbar but doesn't stop mobile browsers from EXPANDING the layout viewport when child content (code blocks, wide grids) exceeds device-width. The fixed nav then renders at that expanded width — its right side (hamburger button) ends up clipped offscreen.

Two additions:

1. html { overflow-x: hidden } — anchors the layout viewport to the visual viewport so the fixed nav and other position:fixed elements stay aligned with what the user sees.
2. pre { max-width: 100%; overflow-x: auto } as a universal rule (was already on .shiki and .docs-prose pre; this catches any other pre that might appear in landing components without those classes).

Verified live in prod via Chrome MCP: the previous PR's body { overflow-x: hidden } and h1..h6 { word-break } are both applied; the remaining overflow numbers come from layout-viewport expansion, which this PR addresses.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
blove added a commit that referenced this pull request May 27, 2026
Follow-up to #547. body { overflow-x: hidden } prevents the user-visible scrollbar but doesn't stop mobile browsers from EXPANDING the layout viewport when child content (code blocks, wide grids) exceeds device-width. The fixed nav then renders at that expanded width — its right side (hamburger button) ends up clipped offscreen.

Two additions:

1. html { overflow-x: hidden } — anchors the layout viewport to the visual viewport so the fixed nav and other position:fixed elements stay aligned with what the user sees.
2. pre { max-width: 100%; overflow-x: auto } as a universal rule (was already on .shiki and .docs-prose pre; this catches any other pre that might appear in landing components without those classes).

Verified live in prod via Chrome MCP: the previous PR's body { overflow-x: hidden } and h1..h6 { word-break } are both applied; the remaining overflow numbers come from layout-viewport expansion, which this PR addresses.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
blove added a commit that referenced this pull request May 27, 2026
…onstraint (#549)

* fix(docs): defer sidebar reveal to lg breakpoint

Mobile audit flagged the docs sidebar as 500–925% viewport-height sticky on tablet (768px). At that width it crowded the article and was the largest sticky/fixed offender. Pushing the reveal from md:block (768px) to lg:block (1024px) hides it for tablet/narrow-desktop and lets the article use the full width. Mobile menu's docs tab already covers nav at <lg.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(website): constrain layout viewport on mobile

Follow-up to #547. body { overflow-x: hidden } prevents the user-visible scrollbar but doesn't stop mobile browsers from EXPANDING the layout viewport when child content (code blocks, wide grids) exceeds device-width. The fixed nav then renders at that expanded width — its right side (hamburger button) ends up clipped offscreen.

Two additions:

1. html { overflow-x: hidden } — anchors the layout viewport to the visual viewport so the fixed nav and other position:fixed elements stay aligned with what the user sees.
2. pre { max-width: 100%; overflow-x: auto } as a universal rule (was already on .shiki and .docs-prose pre; this catches any other pre that might appear in landing components without those classes).

Verified live in prod via Chrome MCP: the previous PR's body { overflow-x: hidden } and h1..h6 { word-break } are both applied; the remaining overflow numbers come from layout-viewport expansion, which this PR addresses.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
blove added a commit that referenced this pull request May 28, 2026
…onstraint (#549)

* fix(docs): defer sidebar reveal to lg breakpoint

Mobile audit flagged the docs sidebar as 500–925% viewport-height sticky on tablet (768px). At that width it crowded the article and was the largest sticky/fixed offender. Pushing the reveal from md:block (768px) to lg:block (1024px) hides it for tablet/narrow-desktop and lets the article use the full width. Mobile menu's docs tab already covers nav at <lg.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(website): constrain layout viewport on mobile

Follow-up to #547. body { overflow-x: hidden } prevents the user-visible scrollbar but doesn't stop mobile browsers from EXPANDING the layout viewport when child content (code blocks, wide grids) exceeds device-width. The fixed nav then renders at that expanded width — its right side (hamburger button) ends up clipped offscreen.

Two additions:

1. html { overflow-x: hidden } — anchors the layout viewport to the visual viewport so the fixed nav and other position:fixed elements stay aligned with what the user sees.
2. pre { max-width: 100%; overflow-x: auto } as a universal rule (was already on .shiki and .docs-prose pre; this catches any other pre that might appear in landing components without those classes).

Verified live in prod via Chrome MCP: the previous PR's body { overflow-x: hidden } and h1..h6 { word-break } are both applied; the remaining overflow numbers come from layout-viewport expansion, which this PR addresses.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
blove added a commit that referenced this pull request May 28, 2026
…refresh (#552)

* test(langgraph): pin multi-field structured resume payload forwarding

Also include the design spec + implementation plan for the HITL refund
work stream.

* feat(chat): add ChatApprovalCardComponent dialog composition

* refactor(chat): refresh ChatInterruptPanel visual treatment

Drop the thick amber left border and triangle warning icon. Adopt the
eyebrow + small dot pattern that matches the new ChatApprovalCard
composition. Share .btn / .btn-primary / .btn-secondary / .btn-text
styles across both compositions. No API change.

* fix(chat): mock HTMLDialogElement in tests; cover dialog effect + cancel

Drop the typeof-function guards from ChatApprovalCardComponent — they
were coupling production code to a JSDOM limitation. Stub
HTMLDialogElement.prototype.showModal/close in the spec's beforeEach so
Vitest still runs. Add two missing tests covering the dialog
open/close effect on interrupt presence and the native cancel event
(Escape) emitting 'cancel' with preventDefault.

* chore(docs): regenerate api docs

* test(examples-chat): delete fully-skipped stop-streaming spec (#548)

Added in PR #433 with `test.skip(...)` and no condition or comment
explaining the skip. Two years later it's still skipped and adds
nothing to CI signal.

The test's intent — assert the "Stop generating" button is visible
mid-stream, click it, observe abort — is fundamentally flaky against
aimock-replayed streams: the streaming chunks arrive in <100ms and
signal-batched updates can collapse the visible-then-hidden state
below Playwright's polling resolution. This is already documented
in test-helpers.ts:95-100 as the reason `submitAndWaitForResponse`
asserts on the rendered `chat-message` element's `data-streaming`
attribute (not on input/button affordances). The same constraint
makes this test unimplementable as-written against aimock.

If/when we add a slow-streaming fixture path (or run e2e against a
non-aimock backend), reintroduce the test alongside that. Until then
it's dead code.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(website): mobile hygiene — sidebar breakpoint + layout viewport constraint (#549)

* fix(docs): defer sidebar reveal to lg breakpoint

Mobile audit flagged the docs sidebar as 500–925% viewport-height sticky on tablet (768px). At that width it crowded the article and was the largest sticky/fixed offender. Pushing the reveal from md:block (768px) to lg:block (1024px) hides it for tablet/narrow-desktop and lets the article use the full width. Mobile menu's docs tab already covers nav at <lg.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(website): constrain layout viewport on mobile

Follow-up to #547. body { overflow-x: hidden } prevents the user-visible scrollbar but doesn't stop mobile browsers from EXPANDING the layout viewport when child content (code blocks, wide grids) exceeds device-width. The fixed nav then renders at that expanded width — its right side (hamburger button) ends up clipped offscreen.

Two additions:

1. html { overflow-x: hidden } — anchors the layout viewport to the visual viewport so the fixed nav and other position:fixed elements stay aligned with what the user sees.
2. pre { max-width: 100%; overflow-x: auto } as a universal rule (was already on .shiki and .docs-prose pre; this catches any other pre that might appear in landing components without those classes).

Verified live in prod via Chrome MCP: the previous PR's body { overflow-x: hidden } and h1..h6 { word-break } are both applied; the remaining overflow numbers come from layout-viewport expansion, which this PR addresses.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(cockpit): centralize port allocation behind cockpit/ports.mjs registry (#551)

* docs(spec): cockpit port registry design

* docs(plan): cockpit port registry implementation plan

* feat(ci): cockpit ports registry + verifier spec (skeleton)

Registry starts empty; the verifier spec tests both the registry
shape (positive int ports, no duplicates, range/convention checks)
and cross-file invariants (python --port + playwright baseURL match
registry). Empty registry intentionally fails the 'covers every
cap' test until Task 2 populates it.

Spec: docs/superpowers/specs/2026-05-27-cockpit-port-registry-design.md

* feat(ci): populate cockpit ports registry from on-disk values

31 entries, extracted from each cap's proxy.conf.json target +
playwright.config.ts baseURL (or langgraph - 1000 for non-e2e caps).
Verifier confirms the registry round-trips cleanly against every
python/project.json --port literal.

* test(ports): verifier skips python --port check for caps without literal

Only chat caps have --port in their python/project.json serve target;
langgraph/deep-agents/render caps rely on the e2e harness spawning
langgraph with explicit --port from global-setup-impl.ts. Skip
verifier check for those rather than fail.

* refactor(cockpit): 31 proxy.conf.json → proxy.conf.mjs (import ports registry)

Every cockpit cap's proxy.conf.json is replaced with proxy.conf.mjs
that imports portsFor(capName) from cockpit/ports.mjs and templates
the langgraph port into the target URL. Each angular/project.json's
serve.options.proxyConfig is updated to point at the .mjs file.

cockpit/ag-ui/streaming is excluded — non-LangGraph backend, kept
as proxy.conf.json with its /agent → :3000 literal.

* refactor(cockpit): 24 e2e configs import ports from registry

Each cap's e2e/global-setup-impl.ts now imports portsFor() and reads
angular/langgraph ports from the registry instead of literal numbers.
playwright.config.ts is updated similarly for baseURL.
All 24 e2e tsconfig.json files gain allowJs: true so tsc accepts the
.mjs import without a declaration file.

The verifier's playwright-baseURL check now skips templated configs
(its regex only matches literal URLs); drift is impossible because
the value imports directly from the registry.

* ci: gate cockpit-ports.spec.mjs in ci-scope test job

Appends the new verifier spec to the existing node --test invocation
so registry drift is caught at PR time.

* test(cockpit): wiring spec reads ports from registry; recognizes .mjs proxy

The drift-guard test previously parsed proxy.conf.json target + the
literal langgraphPort/angularPort lines in global-setup-impl.ts. Both
were removed by the port-registry migration:
- proxy.conf.json → proxy.conf.mjs (templates target from registry)
- global-setup-impl.ts now reads `ports.langgraph` / `ports.angular`

Updated wiring spec:
- Imports `portsFor` from cockpit/ports.mjs to look up expected ports
  by project name. Falls back to literal parsing for the ag-ui
  exception (not in registry).
- Replaces the proxy.conf.json content assertion with a proxy.conf.mjs
  existence + `portsFor('<name>')` call check. Drift is impossible
  because the .mjs templates from the same registry.
- Legacy proxy.conf.json branch retained for ag-ui (single-cap
  exception).

79/79 cockpit unit tests pass locally.

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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