# Responsive Checklist Run through every item before declaring a page done. ## Viewports to verify - **320 px** (iPhone SE 1st gen, smallest practical) - **375 px** (iPhone SE 2/3, iPhone 13 mini) - **390 px** (iPhone 14/15/16 default) - **414 px** (iPhone Plus) - **768 px** (iPad portrait, `md:` breakpoint) - **1024 px** (iPad landscape / small laptop, `lg:` breakpoint) - **1440 px** (full laptop) ## Global guards - [ ] `body { overflow-x: hidden }` in `globals.css`. - [ ] No `min-w-[...]` on root containers. - [ ] All decorative absolute elements live inside `relative isolate overflow-hidden` parents. - [ ] `max-w-*` containers always paired with `mx-auto px-6 md:px-10`. ## Header / Nav - [ ] Logo left, menu/CTA right on mobile. - [ ] Hamburger button is `size-10` minimum (touch target). - [ ] Mobile menu drawer closes when a link is clicked. - [ ] No sticky-nav overlap on anchored sections `scroll-mt-24 md:scroll-mt-28` on `
`. - [ ] Logo height responsive: `h-11 sm:h-14 md:h-16`. ## Hero - [ ] H1 clamp: `clamp(2.4rem, 7vw, 6.4rem)` never larger upper bound. - [ ] `leading-[1.0]` on serif H1 (not `0.95` clips ascenders). - [ ] Top padding generous: `pt-32 sm:pt-36 md:pt-44` (clears sticky nav + breathing room). - [ ] CTAs use `flex flex-wrap items-center gap-4` so they stack on narrow screens. - [ ] Stats panel: collapse 1-col-tall mobile layouts to a horizontal 3-col compact row. ## Cards & grids - [ ] Mobile: `grid-cols-1`. Tablet: `sm:grid-cols-2`. Desktop: `lg:grid-cols-N` matched to card count. - [ ] Avoid `lg:grid-cols-3` for a 5-card list (leaves orphan) use 5 or 2-row layout matched to count. - [ ] Aspect-ratio used over fixed heights: `aspect-[4/3]` or `aspect-[3/4]`. ## Typography - [ ] No tracking > `0.22em` on small labels. - [ ] `text-balance` on h1/h2. - [ ] `text-pretty` on body paragraphs. - [ ] Long tokens (cert numbers, emails) use `break-all` or `break-words` to wrap. ## Images - [ ] `next/image` with `sizes` attribute matched to layout. - [ ] Hero LCP image gets `priority`. - [ ] `object-cover` only when crop is visually intentional. - [ ] `object-contain` for logos. - [ ] Alt text meaningful never "image" or filename. ## Forms - [ ] Field grid: `grid gap-5 sm:grid-cols-2` for first/last + email/phone. - [ ] Inputs `text-base` (16 px+) on mobile to prevent iOS zoom-on-focus. - [ ] Submit button respects pending state w/ spinner. - [ ] Field errors render below field, not in a popup. - [ ] Success/error banner renders outside button. ## Motion - [ ] `useReducedMotion()` checked in every component using motion props. - [ ] Heavy halos / parallax skipped when reduced-motion is on. - [ ] Marquee paused when reduced-motion is on (or replaced with grid). ## External links - [ ] All `` carry `rel="noopener noreferrer"`. - [ ] WhatsApp / Instagram / store badges have `aria-label`. - [ ] App badges sized 132 px (footer) / 140-160 px (CTA). ## Footer - [ ] No duplicated link labels across columns. - [ ] Privacy Policy only in Legal column. - [ ] Agency credit row sits below copyright, subtle. - [ ] Watermark contained via `overflow-hidden` on footer root. ## Accessibility - [ ] Every interactive element keyboard-reachable. - [ ] `focus-visible:` rings on buttons, inputs, anchors. - [ ] Modal/lightbox: scroll-locked body + `Escape` closes + arrows navigate. - [ ] Color contrast checked (`text-bone` on obsidian = 16:1). ## Final smoke test ```bash npx tsc --noEmit # clean curl -s -o NUL -w "%{http_code}" http://localhost:3000/... # 200 on every route ``` Grep for placeholder leaks: ```bash grep -rn 'href="#"' src/ grep -rn 'href=""' src/ grep -rn 'href="/#' src/ ``` Should all return zero (unless intentional same-page anchors with matching IDs).