Files
gw-svelte/MOBILEPOLISH.md
2026-05-06 11:36:19 +12:00

333 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Mobile Polish — Conversion & Comfort Audit Tracker
## New Rescan Items — Mobile Conversion Opportunities
Fresh opportunities from a second mobile-first pass over the main site.
These are intentionally only the new items, kept separate from the
existing audit below.
### High — conversion strategy and flow
- [ ] **Hero CTA hierarchy still prioritises browsing over booking**
- Files: `src/lib/content/homepage.ts:37-39`, `src/lib/components/HeroSection.svelte`
- Current: the yellow primary CTA is `Explore our services →`, while
`Book a Meet & Greet` is secondary.
- Why: on mobile, high-intent users should be able to choose the next
step immediately. Making the exploratory path more visually dominant
adds friction before the user reaches the lead form.
- Opportunity: test flipping the hierarchy on mobile so booking
becomes the primary CTA and service exploration becomes secondary.
- [ ] **Homepage social proof appears too late in the scroll**
- File: `src/routes/+page.svelte:143-147`
- Current order: `Services -> Values -> Testimonials -> Booking`.
- Why: testimonials are one of the strongest conversion levers, but
on mobile they arrive after several large sections. Users are asked
to keep scrolling before seeing the strongest emotional proof.
- Opportunity: move testimonials above values on the homepage, or
surface one featured review snippet earlier in the page.
- [ ] **Hero still relies on the next section for trust**
- Files: `src/lib/content/homepage.ts:43-49`, `src/lib/components/HeroSection.svelte`,
`src/lib/components/IntroStrip.svelte`
- Current: the hero presents the headline and CTAs, but the review
proof sits in the intro strip below.
- Why: on mobile, the hero needs to answer both "what is this?" and
"can I trust them?" before the user scrolls away. Separating those
two jobs weakens the first decision moment.
- Opportunity: add a compact review/trust chip directly under the
hero subtitle or near the hero CTAs on mobile.
- [ ] **Booking flow asks for dog details before it captures the lead**
- File: `src/lib/components/BookingSection.svelte:298-441`
- Current: step 1 asks for dog name, location, message, and services;
contact details are only requested in step 2.
- Why: this is a higher-friction sequence on mobile. Users often feel
more comfortable giving owner details first, then expanding into pet
specifics once they have mentally committed.
- Opportunity: test reversing the step order so step 1 captures name,
email, and phone first, then dog details second.
### Medium — mobile persuasion and CTA timing
- [ ] **Sticky mobile CTA appears on a fixed pixel threshold rather than page context**
- File: `src/lib/components/MobileBookBar.svelte:26-37`
- Current: visibility is driven by `SHOW_AFTER_PX = 480` and
`HIDE_BELOW_PX = 120`.
- Why: a fixed threshold will feel early on some phones and late on
others. It also ignores whether the hero or booking section is
actually in view.
- Opportunity: switch to an `IntersectionObserver` tied to the hero or
booking section so the bar appears based on user context rather than
raw scroll position.
- [ ] **Testimonials section pushes users off-site before finishing the proof story**
- File: `src/lib/components/TestimonialsSection.svelte:128-134`
- Current: the Instagram CTA appears near the top of the testimonials
section, before the user has fully consumed the review content.
- Why: on mobile, sending users to Instagram this early interrupts the
conversion journey and competes with the booking path.
- Opportunity: demote the Instagram CTA below the carousel, or replace
it with a tighter trust-oriented proof CTA higher up.
- [ ] **Mobile pricing pages lose the consultative "not sure?" nudge**
- File: `src/lib/components/PricingPage.svelte:12-19`
- Current: the meet-and-greet reminder prompt is gated behind
`min-width: 769px`, so desktop gets a tailored nudge and mobile
does not.
- Why: mobile users are more likely to feel overwhelmed by stacked
pricing cards, not less. Removing the consultative reassurance on
the smallest screens is directionally backwards for conversion.
- Opportunity: add an inline mobile prompt after the first pricing
section that says, in effect, "Not sure which option fits? Book a
free Meet & Greet and well help you choose."
### Medium — stacked-page CTA noise
- [ ] **Stacked pricing/service cards repeat the same CTA too many times**
- Files: `src/lib/components/PricingPage.svelte:141-159`,
`src/lib/components/ServiceLandingPage.svelte:94-112`
- Current: when cards collapse to one column on mobile, each card
keeps a full "Book a Meet & Greet" button.
- Why: the repetition turns persuasive choice architecture into visual
noise. Instead of helping the user decide, the page starts feeling
like a stack of repeated asks.
- Opportunity: treat this as a shared mobile pattern across pricing
and service pages. Keep one strong CTA per section, let the popular
card carry the primary action, and demote the rest.
Findings from a focused mobile-experience review (≤768px, with extra
attention to 375px small-phones). Desktop is considered done. Each item
records the where, why, and the concrete change.
> Important context for prioritisation: a dog-walking business is a
> jobs-to-be-done service that users research on the couch. Mobile
> conversion lower-bound is "they Meet & Greet". So the dial-movers
> are: thumb-reach for the booking CTA, legibility, friction-free
> form, and trust signals visible on the first scroll.
---
## High — direct conversion impact
- [x] **Hero buttons stack awkwardly at ~375px**
- File: `src/lib/styles/responsive.css` (new ≤480px block)
- Implementation: At `@media (max-width: 480px)` the hero buttons
flip to `flex-direction: column; gap: 12px;` and each button
becomes full-width with padding `16px 24px`. The 768px-specific
`padding-right: 18px` on the buttons row and the
`margin-right: 12px` on `:last-child` are both reset so the two
CTAs read as a clean stacked stack.
- Why: At 375px the side-by-side primary + outline CTAs were wrapping
unevenly and the primary's prominence collapsed.
- [x] **Mobile header phone button is low-contrast and small**
- File: `src/lib/styles/responsive.css:88-100`
- Implementation: Background bumped from `rgba(33, 48, 33, 0.06)`
`0.10`; padding 9px 12px → 11px 14px (and at ≤480px, 10px 12px);
`font-weight: 600`; `min-height: 44px` to meet the touch-target
minimum; icon size also bumped from 13px → 14px.
- Why: The tap-to-call on the mobile header is one of the highest
intent actions on the site. It now reads as a button rather than a
barely-visible label.
- [x] **Booking form inputs trigger iOS zoom-on-focus**
- File: `src/lib/styles/responsive.css:453-462`
- Implementation: Input `font-size: 15px``16px` at ≤768px. Comment
added explaining the iOS-Safari 16px threshold so a future edit
doesn't accidentally drop it again.
- Why: Below 16px Safari auto-zooms on focus; the page jolts every
time a field is tapped. Critical at the booking conversion step.
- [ ] **Testimonial carousel arrows hard to reach at 375px**
- File: `src/lib/components/TestimonialsSection.svelte` (mobile rules
lines ~640-660)
- Current: arrows pinned to `bottom: 24px` inside a stage with
`padding-bottom: 116px`. Visually at the bottom of a tall card —
requires deliberate stretching.
- Why: The carousel feels passive. Users don't realise they can advance
it; testimonials sell — losing that engagement matters.
- Fix: Lift arrows on small screens:
```css
@media (max-width: 480px) {
.testimonial-arrow { bottom: 80px; }
}
```
- [x] **No persistent "Book Meet & Greet" CTA on mobile after hero scrolls past**
- Files: `src/lib/components/MobileBookBar.svelte` (new),
`src/routes/+layout.svelte` (mount), `src/lib/styles/responsive.css`
(`body { padding-bottom: 64px }` at ≤768px).
- Implementation v2 — *Airbnb-style soft-container, scroll-triggered*:
- **Soft container**: a translucent white tray (`rgba(255, 255,
255, 0.96)` with backdrop-filter blur) sits flush at the bottom
with a thin top hairline and a soft shadow. The brand-yellow CTA
pill lives *inside* the tray, not as the tray itself — so the
action stays unmistakable but the surrounding chrome is calm.
- **Scroll-triggered**: the bar slides up + fades in only after the
user has scrolled ~480px (≈ one mobile viewport, hero out of
view). Slides back out below ~120px to avoid flicker near the
top. `prefers-reduced-motion` respected — the slide is dropped,
only the opacity fade remains.
- **Hidden on `/contact-us` and `/booking`** (already in the form).
- **Resets on navigation**: `afterNavigate` resets `visible = false`
so each new page starts hidden until the user has earned it again.
- **Accessibility**: `aria-hidden` toggles with visibility; CTA
`tabindex` flips to `-1` while hidden so keyboard users don't
stumble onto an off-screen control; `pointer-events: none` while
hidden so the user can't accidentally tap it during the fade.
- **Safe-area aware**: `env(safe-area-inset-bottom)` so iPhones
with the home-bar gesture area get correct spacing.
- Body bottom-padding of 64px on mobile keeps the footer from sitting
behind the bar when it's visible at the bottom of long pages.
- Why: Sticky mobile CTAs are a validated conversion pattern (Airbnb,
Booking.com, etc.), but the v1 full-yellow bar was tonally wrong
for Goodwalk — it competed with the calm brand voice and dominated
the screen permanently. v2 keeps the conversion benefit (one-tap
booking, always one swipe away after engagement) without yelling.
## Medium — legibility & polish
- [x] **Hero title can wrap awkwardly at 375px**
- File: `src/lib/styles/responsive.css` (≤480px block)
- Implementation: At ≤480px the desktop H1 drops to 32px /
line-height 1.12 and the dedicated `.hero-heading-mobile` element
drops to 30px / 1.12 (it was 33.5px). The two-line "Unleashing Fun
in / Your Dog's Day!" now sits comfortably with breathing room
above the subtitle.
- Why: Previous 38px / 33.5px sizings were a hair too big for 375px;
line-2 felt cramped against the subtitle.
- [x] **Body text 15px feels small on mobile (and on ultra-wide desktop)**
- File: `src/lib/styles/responsive.css` (≤768px body rule)
- Implementation: `body { font-size: 16px; }` at ≤768px, with a
comment noting the iOS-Safari 16px zoom threshold so this rule
isn't accidentally undone.
- Desktop (≥769px) still inherits 15px from `base.css` for now — the
ultra-wide bump is tracked separately at the bottom of this file
so it can be reasoned about independently (clamp vs. breakpoint).
- Why: 16px is the modern legibility standard on mobile, dovetails
with the iOS zoom-on-focus rule for inputs, and reduces read
fatigue on long pages (about, FAQ answers, legal).
- [ ] **FAQ summary tap target too small**
- File: `src/lib/styles/sections.css` (`.faq summary` rules)
- Current: just text height (~22-26px) — below the 44px minimum.
- Fix:
```css
.faq summary {
padding: 12px 0;
min-height: 44px;
display: flex; align-items: center;
}
```
- [ ] **Booking service-option chips wrap awkwardly at 375px**
- File: `src/lib/styles/responsive.css:468-470`
- Fix at ≤480px: 2-up grid with tighter gap:
```css
.booking-service-options { gap: 10px 12px; }
.booking-toggle-option { flex: 1 1 calc(50% - 6px); }
```
- [ ] **Footer social icons spaced too tight for thumbs**
- File: `src/lib/styles/sections.css` (`.social-links { gap: 14px }`)
- Current 14px gap with 40px icons → centres are 54px apart. Apple
HIG wants 8px+ between targets after the 44px minimum.
- Fix:
```css
@media (max-width: 768px) { .social-links { gap: 18px; } }
```
- [ ] **Pricing cards stack to 1-col with multiple "Book" buttons in a row**
- File: `src/lib/components/PricingPage.svelte` (and ServiceLandingPage
plan grids)
- Why: After stacking, the user sees Plan → Book → Plan → Book → Plan
→ Book in vertical sequence. The repetition reads as noise rather
than choice; the "popular" anchor disappears.
- Fix (opinionated): on mobile, only the popular plan keeps its CTA
button. Other plans show a smaller "Choose this plan" link instead,
or no per-card CTA at all (a single CTA appears under the grid):
```css
@media (max-width: 768px) {
.pricing-plan-card:not(.pricing-plan-popular) .pricing-plan-cta {
display: none;
}
}
```
Then keep the existing under-grid `.service-plan-reassurance` pill
and add a single "Book a Meet & Greet" button below it.
- [ ] **Mobile nav header is too tall — eats above-the-fold real estate**
- File: `src/lib/styles/responsive.css:74`
- Current: `nav { padding: 20px 24px; }` + 25px logo = ~65px header.
On iPhone 13 (844px), this leaves ~380px for hero before scroll —
less than what the Goodwalk dog-image needs to feel like a hero.
- Fix at ≤480px:
```css
nav { padding: 14px 20px; }
.logo img { height: 22px; }
```
## Low — incremental polish
- [ ] **Hero top padding generous at 375px**
- File: `src/lib/styles/responsive.css:179`
- Reduce hero `padding-top` from 50px to 32px at ≤480px.
- [ ] **Intro trust badge feels edge-to-edge at 375px**
- File: `src/lib/styles/responsive.css:296-301`
- Add `padding: 18px 16px; margin: 0 12px;` at ≤480px.
- [ ] **Testimonial quote mark too large at 375px**
- File: `src/lib/components/TestimonialsSection.svelte:~595`
- Current: 44px. Reduce to 36px at ≤480px.
- [ ] **Booking form labels could shrink slightly at 375px**
- File: `src/lib/styles/responsive.css:450`
- Optional: 16px → 15px at ≤480px to give field width back to the
input value (where it actually matters for legibility).
- [ ] **No scroll-to-top affordance on long pages (booking, pricing)**
- Currently absent. Low priority but helpful when users have scrolled
past the booking form and want to re-read service details. Could be
folded into the same sticky-book-bar work above (one bar, both jobs).
## Open from elsewhere
- [ ] **Ultra-wide desktop body font feels small** *(noted by user)*
- Currently `body { font-size: 15px }` ([base.css:15](src/lib/styles/base.css#L15)).
On ≥1800px screens with the `--max-w` already widening (per the
1800px breakpoint), 15px in long-form sections (about, FAQ answers,
legal) becomes uncomfortable.
- Suggested fix: bump to `clamp(15px, 0.95vw, 17px)` on `body`, OR
introduce a `@media (min-width: 1600px) { body { font-size: 17px; } }`.
Either keeps the desktop ≤1599px experience identical and only
expands type when there's genuinely more reading width.
## Deliberately not actioning
- **Drop reveal animations on mobile to "save bandwidth".** They're
IntersectionObserver-driven, cost nothing perceivable, and add brand
polish. Removing them would make the mobile site feel cheaper for no
measurable performance gain.
- **Replace the testimonial carousel with a stacked list on mobile.**
Tempting (carousels famously hide content), but the carousel is
central to the brand's "see real dogs" pitch. Better to fix the arrow
reachability and let the autoplay do the work.
---
## Suggested order of attack
If you want one batch that moves the dial: **High items 1, 2, 3, 5**
together is roughly an hour of work — they hit the hero, the header
tap-to-call, the booking form's biggest mobile bug (zoom-on-focus), and
add the sticky CTA. That's the package I'd ship first. Item 4 (carousel
arrows) is a one-line fix once you're already in `responsive.css`.
The Medium list is best as a second pass — body-text bump,
header-padding reduction, FAQ tap-target, and pricing-card-CTA dedupe
all compound into a noticeably more "intentional on mobile" feel
without any structural change.