135 lines
6.8 KiB
Markdown
135 lines
6.8 KiB
Markdown
# v5: Simplify the message on service pages
|
|||
|
|
|
||
|
|
## Goal
|
||
|
|
|
||
|
|
Every service page should say one clear message, once, in a fixed order, using the
|
||
|
|
homepage's single visual language. No restated sections, no card-grid sprawl. Lead
|
||
|
|
with trust, show the emotional outcome, let the page breathe (PRODUCT.md principles).
|
||
|
|
|
||
|
|
The Tiny Gang page is the finished reference. The rest of this task is applying the
|
||
|
|
same treatment to the other two service pages.
|
||
|
|
|
||
|
|
## The problem we are fixing
|
||
|
|
|
||
|
|
The current `ServiceLandingPage.svelte` stacks ~10 sections that repeat each other:
|
||
|
|
hero, highlight collage, a 6-card benefit pager, an intro badge block, a decision
|
||
|
|
card, a pricing block with an extras grid, an areas card, a FAQ card, and a related
|
||
|
|
services grid. The same promise (matched groups, safe, free pickup) is said three or
|
||
|
|
four times in three or four different card styles. It reads as pages of text and
|
||
|
|
boxes, not one calm argument.
|
||
|
|
|
||
|
|
## The v5 rule
|
||
|
|
|
||
|
|
**Say it once, in order. One design system.**
|
||
|
|
|
||
|
|
Canonical section spine for every service page (this is the order):
|
||
|
|
|
||
|
|
1. **Hero** - what it is (shared `ServiceHero`: green copy left, photo right).
|
||
|
|
2. **What's different** - the 3-4 things that actually set this service apart.
|
||
|
|
3. **How it works** - the steps to get started, made explicit.
|
||
|
|
4. **Honest fit check** - who it suits, who it does not (two columns, one card).
|
||
|
|
5. **Proof** - `TestimonialsSection`.
|
||
|
|
6. **One deliberate image** - a real photo that breaks the text and carries meaning.
|
||
|
|
7. **Price** - even plan cards, plus a short row of promise notes.
|
||
|
|
8. **FAQ** - a calm ruled list, not stacked cards.
|
||
|
|
9. **Service area** - `ServiceAreaCoverage`: an Auckland hub with all suburbs as
|
||
|
|
tappable links. Robust on every screen (no pin map). Per-page stats, so puppy-visits
|
||
|
|
reads "in-home", not "pickup & drop-off".
|
||
|
|
10. **Book** - `BookingWizard`.
|
||
|
|
|
||
|
|
If a piece of content does not fit one of those ten slots, it is probably a repeat.
|
||
|
|
Cut it.
|
||
|
|
|
||
|
|
## Design rules (non-negotiable, taken from the Tiny Gang build)
|
||
|
|
|
||
|
|
- **Lists, not cards.** "What's different" is an icon + text list. "How it works" is
|
||
|
|
numbered items. Reserve real cards for pricing only. Never nest cards.
|
||
|
|
- **One heading grammar.** Every section opens with the same centered eyebrow + H2
|
||
|
|
(`.tg-eyebrow` + `.tg-h2`). No per-section badges, marks, or collages.
|
||
|
|
- **One token set.** Use the shared CSS variables (colours, radius, shadow, spacing).
|
||
|
|
No new gradients or per-section colour systems. Goodwalk green `#213021`, yellow
|
||
|
|
`#FFD100` for buttons only.
|
||
|
|
- **Pricing cards stay even.** Four equal cards in a row on desktop, 2-up at 980px,
|
||
|
|
1-up on mobile. Do not put images inside or beside the cards.
|
||
|
|
- **One image, deliberate.** A single full-width photo band between sections, with a
|
||
|
|
short keyword-bearing caption. It must mean something (the pack, the pickup, the
|
||
|
|
outcome), not decorate. See SEO rules below.
|
||
|
|
- **FAQ is a ruled list.** Hairline dividers between questions, no card chrome.
|
||
|
|
- **Copy: half it, then half it again.** Active voice. No em dashes. No heading that
|
||
|
|
restates the one above it.
|
||
|
|
|
||
|
|
## Image and SEO rules
|
||
|
|
|
||
|
|
- Use real Goodwalk photos from `static/images/` (keyword-rich filenames already).
|
||
|
|
- Register width + height in `src/lib/image-metadata.ts` so there is zero layout shift.
|
||
|
|
- Set explicit `width`, `height`, `loading="lazy"`, `decoding="async"` on every `<img>`.
|
||
|
|
- Alt text is a full, natural, location-aware sentence (e.g. "Four small Tiny Gang dogs
|
||
|
|
looking up together in the long grass at an Auckland park"), not "dogs".
|
||
|
|
- Keep the `FaqSection` schema (`emitSchema`) and the `Service` + `AggregateOffer`
|
||
|
|
structured data in `src/routes/[slug]/+page.svelte` intact.
|
||
|
|
|
||
|
|
## Reference implementation (copy this)
|
||
|
|
|
||
|
|
- Component: `src/lib/components/pages/ServiceClarityPage.svelte` (shared by all three
|
||
|
|
service pages, content-driven)
|
||
|
|
- Pricing variant: `src/lib/components/pages/PricingClarityPage.svelte`
|
||
|
|
- Coverage section: `src/lib/components/sections/ServiceAreaCoverage.svelte`
|
||
|
|
- Preview routes (noindex): `/variants/tiny-gang`, `/variants/solo-walks`,
|
||
|
|
`/variants/puppy-visits`, `/variants/our-pricing`
|
||
|
|
- Content: the `clarity` block in `pack-walks.ts`, `dog-walking.ts`, `puppy-visits.ts`
|
||
|
|
- Variant switcher (preview only): `src/lib/components/ui/VariantNav.svelte`, mounted in
|
||
|
|
`src/routes/+layout.svelte`
|
||
|
|
|
||
|
|
Read the header comment in `ServiceClarityPage.svelte` first. It states the philosophy
|
||
|
|
and the section order in one place.
|
||
|
|
|
||
|
|
## Status
|
||
|
|
|
||
|
|
Done (built, svelte-check clean, server-rendered):
|
||
|
|
|
||
|
|
- `ServiceClarityPage` generalised and content-driven; `ServicePageContent.clarity`
|
||
|
|
added in `src/lib/types.ts`. Old `TinyGangPage.svelte` deleted.
|
||
|
|
- `clarity` content written for pack-walks, dog-walking, puppy-visits. Tiny Gang renders
|
||
|
|
identically to before.
|
||
|
|
- Coverage spine slot added (`ServiceAreaCoverage`), with per-page stats so puppy-visits
|
||
|
|
reads "in-home" not "pickup & drop-off".
|
||
|
|
- Preview routes for all four variants, plus a global `VariantNav` to compare them.
|
||
|
|
|
||
|
|
## Live now
|
||
|
|
|
||
|
|
The clarity pages are the live pages. `src/routes/[slug]/+page.svelte` renders
|
||
|
|
`ServiceClarityPage` for pack-walks / dog-walking / puppy-visits and `PricingClarityPage`
|
||
|
|
for our-pricing. The old `ServiceLandingPage.svelte`, `PricingPage.svelte`, and
|
||
|
|
`ServiceAreaMap.svelte` have been deleted.
|
||
|
|
|
||
|
|
The `/variants/*` routes still exist as a sandbox (the minimal-footer test lives there),
|
||
|
|
but are **dev/localhost only**: `src/hooks.server.ts` returns 500 for the `/variants`
|
||
|
|
namespace off-localhost in production, and `VariantNav` is hidden the same way in
|
||
|
|
`+layout.svelte`. Verified on a real `node build`: public host → 500 for any
|
||
|
|
`/variants/*` and no `VariantNav`; localhost → variants load.
|
||
|
|
|
||
|
|
Footer note: the live pages keep the default footer. The `minimal` footer is still only
|
||
|
|
on the `/variants/*` pages, a separate decision from the page-design swap.
|
||
|
|
|
||
|
|
## Definition of done
|
||
|
|
|
||
|
|
- [x] One `ServiceClarityPage` component drives all three service pages.
|
||
|
|
- [x] Page-specific copy lives in content files, not the component.
|
||
|
|
- [x] All three pages follow the spine, say each point once, share one heading grammar
|
||
|
|
and one token set.
|
||
|
|
- [x] Pricing cards are even on every page. No image in the pricing block.
|
||
|
|
- [x] Exactly one deliberate, captioned, fully-SEO'd image band per service page.
|
||
|
|
- [x] FAQ is a ruled list. Schema preserved.
|
||
|
|
- [x] `npx svelte-check` clean (no new errors).
|
||
|
|
- [x] Live `[slug]` branches swapped to the clarity pages.
|
||
|
|
- [x] Old `ServiceLandingPage.svelte` / `PricingPage.svelte` / `ServiceAreaMap.svelte` deleted.
|
||
|
|
- [x] `/variants/*` blocked in production (500) and `VariantNav` hidden there.
|
||
|
|
- [ ] Decide whether to promote the `minimal` footer to the live pages.
|
||
|
|
|
||
|
|
## Do not
|
||
|
|
|
||
|
|
- Do not redesign the brand or introduce new colours, fonts, or gradients.
|
||
|
|
- Do not add card grids, badges, collages, or mobile pagers back in.
|
||
|
|
- Do not change wording on a page unless it is a repeat being removed or copy being
|
||
|
|
shortened. Keep the meaning.
|