Skip to content

fix(landing): compact mobile hero - #2396

Merged
Asherlc merged 2 commits into
mainfrom
codex/issue-2095
Aug 2, 2026
Merged

Asherlc merged 2 commits into
mainfrom
codex/issue-2095

Conversation

@Asherlc

@Asherlc Asherlc commented Aug 2, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Compact the responsive mobile landing hero so the product demonstration appears in the first viewport.
  • Preserve the desktop layout while adding a concrete decision-support example and accessible labels.
  • Add web regression, Storybook, and Cypress coverage.

Validation

  • Focused landing-page tests and typecheck run by the implementation worker.

Closes #2095
Fixes #2095

Summary by Sourcery

Compact the mobile landing hero so the recovery preview demo appears within the first viewport while preserving the desktop layout and validating the new behavior.

New Features:

  • Add a Storybook scenario that verifies the mobile first viewport keeps the concrete recovery outcome visible.
  • Add a Cypress E2E spec to assert the landing hero shows the recovery outcome within a 390 × 667 viewport.

Bug Fixes:

  • Ensure the concrete recovery preview appears before proof points on mobile to keep the product demonstration in view.

Enhancements:

  • Adjust landing hero spacing, typography, and layout to better prioritize the recovery preview on smaller screens while keeping desktop unchanged.

Documentation:

  • Document the LAND-04 local E2E Docker network allocation incident and its impact on landing-page validation.

Tests:

  • Add unit and visual tests for the landing page hero ordering and mobile viewport behavior.

Summary by cubic

Compacts the mobile landing hero so the recovery demo appears in the first viewport and before proof points, while keeping the desktop layout intact. Aligns with Linear issue 2095 to prioritize the concrete recovery preview on narrow screens.

  • Bug Fixes
    • Reordered mobile content and tightened spacing/typography so "Today's recovery picture" and key values are visible within a 390×667 viewport.
    • Preserved the existing desktop grid and layout.
    • Hardened coverage: Cypress spec with stubbed auth/provider requests and explicit first-viewport checks; a unit test for content order; and a Storybook story with a fixed 390×667 frame and play assertions.

Written for commit e54363b. Summary will update on new commits.

Review in cubic

Show the existing recovery example before secondary proof points on narrow screens while retaining the desktop grid.

Refs #2095
Copilot AI review requested due to automatic review settings August 2, 2026 08:41
@Asherlc Asherlc linked an issue Aug 2, 2026 that may be closed by this pull request
@codereviewbot-ai

Copy link
Copy Markdown

🤖 Review skipped: Repository rate limit exceeded. Free accounts are limited to 2 reviews per 4 hours per repository. Upgrade to a paid plan for unlimited reviews.

@cursor

cursor Bot commented Aug 2, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry @Asherlc, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Aug 2, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

@Asherlc, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 2 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4e919568-95c3-44c2-91a2-86504d48a566

📥 Commits

Reviewing files that changed from the base of the PR and between f63c7b4 and e54363b.

📒 Files selected for processing (5)
  • cypress/e2e/landing.cy.ts
  • docs/production-incident-baseline.md
  • packages/web/src/pages/LandingPage.stories.tsx
  • packages/web/src/pages/LandingPage.test.tsx
  • packages/web/src/pages/LandingPage.tsx

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai

sourcery-ai Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Compacts the mobile landing hero so the dashboard preview and recovery outcome are visible in the first viewport while preserving desktop layout, and adds Storybook, unit, Cypress, and incident documentation for the new behavior.

Sequence diagram for the Cypress mobile landing hero viewport test

sequenceDiagram
  participant Cypress
  participant Browser
  participant LandingPage
  participant API_auth_me
  participant API_auth_providers
  participant TRPC_sync_usableProviders

  Cypress->>Cypress: stubPublicLandingRequests()
  Cypress->>Browser: cy.viewport(390, 667)
  Cypress->>Browser: cy.visit("/")

  Browser->>API_auth_me: GET /api/auth/me
  API_auth_me-->>Browser: 401 { error: Unauthorized }

  Browser->>API_auth_providers: GET /api/auth/providers
  API_auth_providers-->>Browser: 200 { identity: [], data: [], password: true }

  Browser->>TRPC_sync_usableProviders: POST /api/trpc/sync.usableProviders*
  TRPC_sync_usableProviders-->>Browser: 200 [{ result: { data: usableProviders } }]

  Browser->>LandingPage: render HeroSection()

  Cypress-->>Browser: cy.wait("@usableProviders")
  Cypress->>Browser: expectWithinFirstViewport("Today's recovery picture")
  Cypress->>Browser: expectWithinFirstViewport("74%")
  Cypress->>Browser: expectWithinFirstViewport("Near baseline")
Loading

File-Level Changes

Change Details Files
Reworked hero layout to prioritize the dashboard preview and concrete recovery outcome in the mobile first viewport while keeping desktop unchanged.
  • Reduced minimum height and vertical spacing in the hero container for small screens, while keeping the original min height for large screens.
  • Adjusted typography and spacing for the headline, body copy, and primary CTA to be more compact on mobile via responsive Tailwind classes.
  • Repositioned the dashboard preview and proof points using grid row/column utilities so the demo appears before proof points on mobile and layout remains consistent on desktop.
  • Made the hero chip row hidden on the smallest breakpoint and only visible from small screens upward.
packages/web/src/pages/LandingPage.tsx
Added Storybook coverage to assert the concrete recovery outcome stays visible within a specific mobile viewport.
  • Introduced a new Mobile first viewport story with a custom 390×667 viewport configuration.
  • Added a play function using Testing Library assertions to verify visibility of the recovery picture, percentage value, and qualitative status in the canvas.
  • Documented the story as ensuring the concrete recovery outcome is visible in the first viewport.
packages/web/src/pages/LandingPage.stories.tsx
Extended unit tests to enforce the visual ordering of the recovery preview and proof points in the DOM.
  • Added a test that renders the landing page and compares DOM positions of the recovery preview and a proof point.
  • Asserted that the recovery preview node precedes the proof point node using DOCUMENT_POSITION_FOLLOWING bitwise check.
packages/web/src/pages/LandingPage.test.tsx
Documented a local E2E validation blocker related to Docker network exhaustion for the landing-page spec.
  • Recorded incident LAND-04 describing inability to allocate a Docker network while running the focused landing Cypress spec.
  • Captured symptoms, evidence, root cause, mitigation, and remaining follow-up for the unresolved local validation blocker.
  • Linked to Docker address pool configuration documentation as supporting evidence.
docs/production-incident-baseline.md
Added a focused Cypress spec to validate the mobile landing hero behavior under stubbed backend conditions.
  • Stubbed public auth and providers endpoints and the sync.usableProviders TRPC call to control landing page state.
  • Implemented a helper to assert that specific text elements are visible and their bottom edge is within the 667px viewport height.
  • Created a mobile hero test that sets a 390×667 viewport, visits the landing page, waits for provider stubbing, and verifies the recovery picture, percentage, and status are within the first viewport.
cypress/e2e/landing.cy.ts

Assessment against linked issues

Issue Objective Addressed Explanation
#2095 Compress the mobile landing hero so that the product demonstration / concrete decision-support example is visible within the first mobile viewport. ✅
#2095 Add automated regression coverage (tests/story) to ensure the mobile hero keeps the product demonstration within the first viewport and before secondary content. ✅

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Compact mobile landing hero to keep recovery demo in first viewport

🐞 Bug fix 🧪 Tests 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Reorder/compact the mobile landing hero so the recovery demo appears in the first viewport.
• Preserve desktop grid behavior while tightening mobile spacing and typography.
• Add Storybook, RTL, and Cypress coverage for mobile viewport visibility and ordering.
Diagram

graph TD
  UT["LandingPage.test.tsx"] -->|"asserts DOM order"| LP["LandingPage.tsx (HeroSection)"] --> DEMO["DashboardPreview"]
  LP --> PP["Hero proof points"]
  SB["LandingPage.stories.tsx"] -->|"mobile viewport play"| LP
  CYP["cypress/e2e/landing.cy.ts"] --> STUB["Stub public auth/providers"] -->|"visit / @ 390x667"| LP
  DOC["production-incident-baseline.md"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Use CSS `order` to visually reorder hero sections
  • ➕ Smaller DOM/diff changes; keeps markup structure constant across breakpoints
  • ➕ Potentially fewer layout shifts if desktop/mobile share the same tree
  • ➖ Screen reader/tab order can diverge from visual order if not carefully managed
  • ➖ Harder to assert ordering semantically in tests; can regress accessibility unintentionally
2. Keep ordering but only reduce spacing/typography via `clamp()`
  • ➕ Minimal structural changes; lowest risk to desktop layout
  • ➖ May still fail the core requirement on small devices (content can remain below the fold)
  • ➖ More iteration needed across device sizes to guarantee first-viewport visibility

Recommendation: Current approach (DOM-level reordering plus mobile-specific spacing/typography adjustments) is the most robust way to guarantee the demo appears early on mobile while keeping desktop intact. It also aligns visual and semantic order, and the added RTL/Storybook/Cypress coverage directly guards the stated viewport requirement.

Files changed (5) +106 / -16

Bug fix (1) +16 / -16
LandingPage.tsxRework hero responsive layout to prioritize demo on mobile without impacting desktop +16/-16

Rework hero responsive layout to prioritize demo on mobile without impacting desktop

• Adjusts hero grid/min-height and spacing for small screens, hides the sources pill on mobile, and tweaks typography/button padding. Moves the proof-points block below the demo on mobile while pinning desktop placement via explicit grid row/column positioning.

packages/web/src/pages/LandingPage.tsx

Tests (3) +81 / -0
landing.cy.tsAdd mobile hero E2E asserting demo stays within first viewport +43/-0

Add mobile hero E2E asserting demo stays within first viewport

• Introduces a landing-page Cypress spec that stubs unauthenticated/auth-provider requests and asserts key recovery demo text remains within a 390×667 first viewport using bounding-rect checks.

cypress/e2e/landing.cy.ts

LandingPage.stories.tsxAdd Storybook viewport scenario validating mobile first-viewport demo visibility +27/-0

Add Storybook viewport scenario validating mobile first-viewport demo visibility

• Adds a Storybook story configured to a 390×667 viewport and a play function asserting the concrete recovery outcome text is visible, providing a lightweight regression signal for the hero layout.

packages/web/src/pages/LandingPage.stories.tsx

LandingPage.test.tsxAssert recovery preview precedes proof points in the rendered DOM +11/-0

Assert recovery preview precedes proof points in the rendered DOM

• Adds a React Testing Library test that ensures the concrete recovery preview appears before the mobile proof points by checking document position ordering.

packages/web/src/pages/LandingPage.test.tsx

Documentation (1) +9 / -0
production-incident-baseline.mdDocument LAND-04 local Docker network allocation blocker for E2E validation +9/-0

Document LAND-04 local Docker network allocation blocker for E2E validation

• Adds an incident entry describing a local validation failure caused by Docker address pool exhaustion when bringing up the repo-managed E2E stack, including evidence, root cause, and follow-up risk.

docs/production-incident-baseline.md

@github-actions

github-actions Bot commented Aug 2, 2026 •

Copy link
Copy Markdown
Contributor

Storybook previews for f584b421 are ready:

This comment updates automatically on each PR push.

@qodo-code-review

qodo-code-review Bot commented Aug 2, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (1) 📜 Skill insights (0)

Context used
✅ Compliance rules (platform): 178 rules

Grey Divider


Remediation recommended

1. Non-retryable viewport measurement ✓ Resolved 🐞 Bug ☼ Reliability
Description
The Cypress expectWithinFirstViewport check uses a single getBoundingClientRect() measurement
inside .then(), which Cypress does not retry; this can miss late layout shifts that push content
below the fold and can also be flaky if layout is still settling when the measurement runs.
Code

cypress/e2e/landing.cy.ts[R23-26]

+    .then(($element) => {
+      const bottom = $element[0].getBoundingClientRect().bottom;
+      expect(bottom, `${text} bottom edge`).to.be.at.most(667);
+    });
Relevance

●●● Strong

Team previously accepted stabilizing/retrying Cypress layout measurements to avoid missing late
layout shifts.

PR-#2039

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new helper computes and asserts the element’s bottom edge inside .then(...), which runs once
and is not retried; this is the exact pattern that can miss later layout shifts in layout-regression
tests.

cypress/e2e/landing.cy.ts[20-27]
PR-#2039

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`expectWithinFirstViewport` performs a one-time layout measurement in a `.then()` callback after `.should('be.visible')`. Cypress will retry the `.should('be.visible')` step, but it will not retry the `.then()` measurement/assertion if layout is still shifting (fonts/images/follow-up renders).

### Issue Context
This test is meant to be a regression for “content stays within first viewport.” A one-shot measurement can both:
- produce false negatives (passes early, then shifts below fold later), and
- produce intermittent failures (measures during a transient layout).

### Fix Focus Areas
- cypress/e2e/landing.cy.ts[20-27]

### Suggested fix
Refactor to a retryable assertion, e.g.:
- `cy.contains(text).should('be.visible').should(($el) => { ...expect(bottom).to.be.at.most(Cypress.config('viewportHeight')) })`

Optionally add a bounded stabilization step (wait for fonts/images/quiet window) before the measurement if this page has late layout changes.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Viewport story not applied ✓ Resolved 🐞 Bug ≡ Correctness
Description
MobileFirstViewport relies on parameters.viewport to force a 390×667 frame, but the web
Storybook config does not register the viewport addon, so the story will render at the default size
and won’t validate the “first viewport” requirement.
Code

packages/web/src/pages/LandingPage.stories.tsx[R94-97]

+    viewport: {
+      defaultViewport: "landingMobile",
+      options: {
+        landingMobile: {
Relevance

●● Moderate

No clear precedent on requiring addon-viewport; Storybook config historically only included a11y
addon.

PR-#686

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new story configures a custom viewport, but the web Storybook addons list only includes
@storybook/addon-a11y, so nothing consumes parameters.viewport.

packages/web/src/pages/LandingPage.stories.tsx[91-116]
packages/web/.storybook/main.ts[1-18]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`MobileFirstViewport` sets `parameters.viewport` expecting Storybook to apply a custom 390×667 viewport, but `packages/web/.storybook/main.ts` does not include the viewport addon. This makes the new Storybook scenario ineffective for validating the mobile first-viewport constraint.

### Issue Context
The PR adds a story intended to verify the mobile hero fits in the first viewport. Without the addon, Storybook ignores `parameters.viewport`.

### Fix Focus Areas
- packages/web/.storybook/main.ts[1-18]
- packages/web/src/pages/LandingPage.stories.tsx[91-116]

### Suggested fix
Add `@storybook/addon-viewport` (or `@storybook/addon-essentials` if that’s the standard here) to `packages/web/.storybook/main.ts` `addons`, so `parameters.viewport` is honored. If you intentionally don’t want the addon, replace the viewport parameters with a decorator that wraps the story in a fixed-size container (390×667) so the play assertion runs under the intended dimensions.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

3. landing.cy.ts missing cy.cleanTestData() 📘 Rule violation ☼ Reliability
Description
The new Cypress suite in cypress/e2e/landing.cy.ts defines beforeEach() and tests but does not
include an afterEach() hook that unconditionally calls cy.cleanTestData(). This violates the
Cypress test hygiene requirement and can leave state behind that causes cross-test flakiness.
Code

cypress/e2e/landing.cy.ts[R29-32]

+describe("Landing page mobile hero", () => {
+  beforeEach(() => {
+    stubPublicLandingRequests();
+  });
Relevance

● Weak

Very similar requests to add afterEach cy.cleanTestData() were explicitly rejected in prior Cypress
specs.

PR-#2295
PR-#2370

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 721885 requires every Cypress test suite to include an afterEach() hook that
unconditionally calls cy.cleanTestData(). In cypress/e2e/landing.cy.ts, the suite defines
beforeEach() and an it() block but contains no afterEach() cleanup hook.

Rule 721885: Call cy.cleanTestData() in afterEach() in every Cypress test suite
cypress/e2e/landing.cy.ts[29-43]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The Cypress spec `cypress/e2e/landing.cy.ts` does not include a top-level `afterEach()` that calls `cy.cleanTestData()`, which is required for Cypress suites.

## Issue Context
Compliance requires each Cypress spec to include an `afterEach(() => { cy.cleanTestData(); })` hook that runs unconditionally.

## Fix Focus Areas
- cypress/e2e/landing.cy.ts[29-43]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Qodo Logo

Comment thread packages/web/src/pages/LandingPage.stories.tsx Outdated
Comment thread cypress/e2e/landing.cy.ts Outdated
@codereviewbot-ai

Copy link
Copy Markdown

🤖 Review skipped: Repository rate limit exceeded. Free accounts are limited to 2 reviews per 4 hours per repository. Upgrade to a paid plan for unlimited reviews.

@Asherlc

Asherlc commented Aug 2, 2026

Copy link
Copy Markdown
Owner Author

Addressed in e54363b: the Storybook mobile story now uses a fixed 390x667 decorator rather than an unregistered viewport parameter, and the Cypress first-viewport measurement is now a retryable assertion. Focused landing tests and web typecheck pass.

@Asherlc
Asherlc merged commit bc13a28 into main Aug 2, 2026
99 checks passed
@Asherlc
Asherlc deleted the codex/issue-2095 branch August 2, 2026 09:12
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.

[LAND-04] Mobile hero pushes product demonstration below the fold

2 participants