---
name: mobile-first-responsive
description: Build and audit mobile-first responsive UI in React + Tailwind + shadcn/ui. Use when creating any new page or surface, or when the user says "mobile", "responsive", "touch", "breakpoints", "safe area", "works on phones", or reports a phone-only layout bug. Not for desktop-only admin consoles (confirm that scope first), and not for 3D canvas tuning: use build-3d-website.
license: MIT
metadata:
  author: TechTide AI (Alex Cinovoj)
  provenance: original
  category: Build & Implementation
---

# Mobile-First Responsive Build

Build for a 375px phone first, then enhance upward. Most shipped apps get opened on a phone, so a layout that only resolves at desktop width is unfinished, not "responsive later."

## When this applies

- Any new page, route, or major UI surface, public or authenticated.
- Any bug report shaped like "broken on my phone", "horizontal scroll", "button too small", "hidden by the notch", "keyboard covers the input".

Skip only for surfaces the user has explicitly confirmed as desktop-only. Do not assume desktop-only.

## Workflow

1. Set the preview to 375 x 667 before writing layout. Compose the whole screen at that width with zero horizontal scroll.
2. Add `sm:` / `md:` / `lg:` enhancements upward. Never start at desktop and shrink.
3. Apply the hard rules below while building, not after.
4. Run the self-audit before declaring done. Read references/mobile-audit-checklist.md when you reach verification or when debugging a phone-only bug.

## Hard rules

| Rule | Why |
|---|---|
| Base Tailwind classes target the phone; `sm:`+ only add | `lg:` defaults with mobile overrides invert the model |
| No element wider than the viewport | Fixed `px` widths, `w-screen`, `whitespace-nowrap`, and unbroken strings cause it |
| `min-w-0` on flex/grid children holding text | Flex children refuse to shrink without it; the #1 overflow bug |
| Touch targets at least 44 x 44px (`min-h-11 min-w-11`), 8px apart | Below that, taps miss |
| `h-dvh` / `min-h-dvh`, never `h-screen` | `100vh` is wrong on mobile Safari and Chrome URL-bar math |
| Body text 16px minimum, inputs 16px minimum | Smaller triggers iOS input zoom |
| `viewport-fit=cover` plus `env(safe-area-inset-*)` padding on fixed bars | Content hides under the notch or home bar otherwise |
| Every animation has a `prefers-reduced-motion: reduce` fallback | Motion sensitivity is an accessibility requirement |
| Never set `maximum-scale=1` or `user-scalable=no` | Blocking pinch-zoom is an a11y failure |

## Touch ergonomics

- Primary actions in the bottom two thirds of the screen, thumb reach.
- Correct `type` / `inputmode` on inputs so the right keyboard opens.
- No hover-only affordances. `:hover` does not exist on touch. Add tap-visible equivalents and `active:` states.
- `touch-action: manipulation` on interactive elements kills the 300ms tap delay.
- Bottom-fixed CTAs must not sit under the on-screen keyboard when an input is focused.

## Performance and accessibility

Assume slow network and weak CPU. Responsive images with dimensions set, lazy-load below the fold, defer heavy sections, cap canvas DPR at 2. Semantic landmarks, one `<h1>` per route, `aria-label` on icon-only buttons, contrast 4.5:1 for body text. Full lists live in references/mobile-audit-checklist.md.

## Good vs bad

Good: a card row written as `flex flex-col gap-3 md:flex-row`, children carry `min-w-0`, buttons are `min-h-11`.

Bad: `flex flex-row lg:gap-6` with a `hidden lg:block` sidebar and a `w-[420px]` card, then patching with `overflow-x-hidden` on `body`. Hiding the scrollbar does not fix the layout, it hides the evidence.

## Verification

Do this: render the page at a real 375px viewport (device emulator or screenshot tool) and run the counts in references/mobile-audit-checklist.md. Expect every count to be 0 and no horizontal scroll. If any count is above 0, fix the finding and re-render. Desktop screenshots do not count as verification.

## Completion checklist

- [ ] Built and verified at 375px before any desktop pass
- [ ] All audit counts in references/mobile-audit-checklist.md are 0
- [ ] Fixed bars padded with safe-area insets
- [ ] Inputs have correct `type` / `inputmode` and 16px font
- [ ] Reduced-motion fallback on every animation

Any box unchecked: not done. Fix or say so.

## Footguns

- `h-screen` on a full-height hero: bottom content sits under the mobile URL bar. Fix: `min-h-dvh`.
- Text overflowing a flex row: the child lacks `min-w-0`. Fix: add `min-w-0` and `break-words`, not a hardcoded width.
- Bottom nav floating above the home indicator gap, or under it: missing `pb-[env(safe-area-inset-bottom)]` plus `viewport-fit=cover` in the viewport meta. Both are required together.
- iOS zooms on input focus: input font-size below 16px. Fix the font size, do not disable zoom.
