Generative Assets · industry demonstration 416

How the Kerbline Lawn & Garden page was made

Kerbline is a fictional two-mower round through Perth’s south-east. The page has one job: get a household onto a recurring fortnightly round, with a phone call as the fallback. Everything below is what we decided, what we measured, and what we refused to publish.

The concept

The business

Two mowers, one trailer, a fortnightly round through Willetton, Rossmoyne, Canning Vale, Riverton, Leeming, Bull Creek, Thornlie and Southern River. Nine years, 340 lawns.

The competitive reality in this trade is that nobody publishes a price and half the operators do not answer the phone. So the page publishes the price and leads with turning up.

The customer

A working household whose lawn got away from them, plus property managers running six rentals on one invoice. Neither is comparing craft. Both want the same two answers: what does a fortnightly round cost at my place, and will someone actually turn up.

So the estimate answers the first in three taps, and the run-days card, the rain answer and the night-before text answer the second.

The proof element: the round estimate

Three controls and two toggles, one result card, and a drawn block plan whose lawn grows with the size control. No instructions, no email wall, no “request a quote”.

Why three controls and not seven. A mowing quote in the real world turns on lawn area, how often, and whether there are hedges and clippings to shift. Everything else — slope, gate width, dog, kikuyu against buffalo — is what the first visit is for, and the page says so rather than pretending a form can price it. Every extra control is a chance for the customer to decide the number is not for them.

Why the recurring round is the product, not the one-off. A one-off tidy is a transaction; a fortnightly round is an annuity. The estimate is therefore framed per visit and per year, the comparison table is always visible, and the copy argues openly that monthly costs more a visit and less a year. A page that argues against its own dearer option is the one they ring.

The arithmetic, and where it is licensed

Every figure below was asserted by check-w52.mjs before a line of the page was written, and then driven out of the running page and re-asserted on all 48 cells in each of the three passes.

ControlRuleValues
Lawn sizebase per visit $45 · $60 · $80 · $110
How oftenmultiplier, rounded to the dollar ×1.00 · ×1.15 · ×1.60
Visits a yearfortnightly / monthly / one-off 26 · 12 · 1
Hedges & shrubsflat, added after the multiplier +$40
Green wasteflat, added after the multiplier +$35
Measured off the running pageA visitA year
Rest state — standard block, fortnightly, no extras $60$1,560
Same block, monthly$69$828
Same block, one-off tidy$96$96
Cheapest cell — courtyard, fortnightly, no extras $45$1,170
Dearest cell — big block, one-off, both extras $251$251

The cheapest cell, $45, is also the services-grid “from” anchor — the estimate has no floor the price list does not already publish. The sweep also proves price never falls as the lawn gets bigger, and that an extra can never reduce a price.

The second read. Skipping a fortnight saves the customer $60, but four weeks of November growth comes back as a one-off tidy, which on the same block is $96. Both numbers are licensed and both are drawn live from the same model, so the sentence re-prices itself when you change the block. It is the most useful thing on the page and it is an argument against skipping, which is why people believe it.

Technique

The block plan

Plain inline SVG, rebuilt from a small geometry table on every state change. A dashed hairline frame draws the widest block on the round and never moves, so the solid lawn growing inside it reads as growth rather than as a redraw. Mower stripes are drawn at a pitch that tightens with the block, which is the cheapest possible way to say “lawn” without a photograph.

The gap in the left boundary is a side gate. It is the page’s quietest detail and it answers the most common question in the trade before the FAQ does.

Motion

One CSS keyframe, 260 ms, staggered 22 ms per mower stripe. There is no requestAnimationFrame loop anywhere on the page, so there is nothing to pause, nothing to accumulate and nothing still moving at rest. The page is pixel-identical between two screenshots 900 ms apart, and the state probe is byte identical eight seconds after the thumbnail instant.

prefers-reduced-motion: reduce removes the animation entirely rather than shortening it — verified by reading the computed animation-name under an emulated media feature.

The service-area map

An angular polygon over a land fill, with the Canning River as a stroked ribbon along the north and eight named suburb dots. No roads: the only hairline available measures 1.4:1 on the lawn fill and is a declared forbidden pair, and a road drawn in a colour that changes when it crosses the boundary is worse than no road.

State

window.__lawnmowing exposes the size, frequency, both toggles, the base rate, the multiplier, the extras total, the per-visit and per-year figures and the count of drawn marks — all as plain numbers, so every pass asserts state rather than scraping rendered text.

Palette

Limestone and cut grass, argued from a Perth verge rather than from a stock “landscaping green”. Every hex and every ratio below is quoted from the same run of the wave’s contrast sweep — 152 declared pairs, zero failures.

Paper#F5F2EAThe page. Warm limestone, not white.
Panel#E8E3D6Cards, tiles, map land. Ink 13.3:1.
Ink#1A1D1715.24:1 on paper.
Muted#4B53467.15:1 on paper. Body seconds only.
Green ink#31570F7.51:1 on paper. Every figure.
CTA green#3F6B1EPaper reversed on it, 5.63:1.
CTA green, pressed#365D19Minted here. Paper on it 6.86:1; the chip sub-label at 86 % blends to #DADDCD, 5.56:1.
Band#1F2A18Paper reversed, 13.38:1.
Hairline#C0B9A61.75:1 on paper.
Field border#6C72634.44:1 as a mark on paper.
Lawn fill#CFE0B4Ink on it 12.15:1.
Lawn edge#4E7A2A3.62:1 on the lawn fill.
Paving#DCD6C6Ink on it 11.75:1.
Roof#B9AE99Carries no marks at all — every ink is a forbidden pair on it, so the house footprint is left flat.
Map water#BFD3D8Coast mark on it, 4.06:1.
Map coast#4A646C4.92:1 on map land. Marks only, never text.

One colour was minted during the build#365D19, the pressed and hover state of the CTA and of a selected chip. It was added to the wave’s contrast sweep, along with the 86 % paper sub-label that sits on it, and both pairs were measured before they shipped: 6.86:1 and 5.56:1. Two other candidate mints were removed rather than measured — a translucent hover wash on the demonstration band, and a translucent body copy on it — because a border change and full-strength paper do the same job without inventing a colour.

Type

Barlow 600/700

A grotesque with slightly narrow, squared-off forms — it reads like signwriting on the side of a trailer rather than like a design studio. Headline, section headings, chip labels, and every price figure.

Inter 400/500

The workhorse. Body copy is 17 px at 375 and stays 17 px — a mowing customer is often reading this one-handed in a car park, and shrinking body text on mobile is the most common failure on trade sites.

The one typographic move: the per-visit figure is set in Barlow 700 at 4 rem with −.045 em tracking, a size nothing else on the page approaches, with the yearly figure directly beneath it at body size. That size gap is the argument: the per-visit number is what the customer decides on, the yearly number is what they check.

The three passes

Every pass drove the enquiry form (submitted empty, then filled) and drove the estimate (control vectors set, window.__lawnmowing read, asserted against check-w52.mjs). Findings below are the real ones.

  1. Pass 1 — Craft

    • The price figure sat at y 738–793 at 1200 wide, so the rest-state number fell outside the 750 px thumbnail frame while the drawing was comfortably inside it. The estimate card was reordered to lead with the plan, then the figure, then the controls; the figure moved to y 428 and the thumbnail now carries both. Reordering was the right fix rather than tightening padding — a card that opens with your block and your price and then asks you to adjust reads better anyway.
    • The trust line rendered as “9 years , 340 lawns”. Making the list item a flex container to position the bullet turned the bold span and the following text node into two flex items with an 7 px gap between them, so the comma detached. Replaced with an absolutely positioned pseudo-element.
    • “You are asking about a a standard block”. The article was in both the static copy and the generated label. Removed from the static copy.
    • The service-area map was rebuilt entirely. The first version drew the Canning River as a slab covering a third of the frame, had a stray leader line hanging into the shaded area, and gave the round a formless outline. It is now a stroked ribbon, an angular boundary, and eight dots placed in roughly correct relative geography.
    • Estimate driven at all 48 vectors: every per-visit and per-year figure matched the licence, minimum $45, maximum $251.
  2. Pass 2 — Depth

    • Added the skip-a-visit sentence, computed live from two licensed figures ($60 fortnightly, $96 one-off on the standard block) and re-priced on every size change. It is the page’s best line and the only one that argues against the customer’s instinct.
    • Added the constant dashed reference frame to the block plan. Before it, the lawn simply redrew at a new width and the growth did not register; against a fixed frame the same change is unmistakable. It also gave the plan a stable composition across all four sizes.
    • Added the side gate — a real 26 px break in the boundary stroke with a swing arc — and explained it in one line beneath the legend rather than as a label inside the drawing, because every ink is a forbidden pair on the house fill and the only clear space collided with it.
    • Added the three-row comparison table (fortnightly / monthly / one-off, per visit and per year, mowing only) with the selected row marked. The “monthly is dearer per visit and cheaper per year” claim is proven for every lawn size by the licence, so the table can be live rather than a fixed example.
    • Form re-driven: empty submit flagged three fields with visible messages and left the confirmation hidden; filled submit hid the form, revealed the confirmation, named the person and echoed the estimate vector.
  3. Pass 3 — Hardening

    • Text inputs had no focus outline. A :focus rule set outline:none and replaced it with a border-colour change from #6C7263 to #3F6B1E — two colours close enough in luminance that the change is a weak indicator on its own. The outline:none was removed so the 3 px focus ring returns, and the glow now supplements it.
    • Removed one ornament (the Chanel rule): the compass rose on the map. The map is not to scale and carries no other orientation cue, so a north arrow was decoration claiming precision the drawing does not have.
    • 375 px: “One-off tidy” wrapped to three lines in the three-across frequency chips and made the row lopsided; the chip is now “One-off”. The comparison table’s visit counts are hidden below 420 px so each row stays one line.
    • Verified at 375, 768 and 1440, plus a 320 → 1440 → 375 resize with the estimate holding state; no element box escapes the viewport at any width, and all tap targets are at least 44 px.
    • Zero console errors at every width and under reduced motion; both pages scanned for curly quotes used as attribute delimiters; page weight is well under the 120 KB ceiling with no libraries and no raster assets.

Why this converts

The call button is the first thing under the headline and the first thing in the sticky bar because most of this traffic is a phone held one-handed, and the enquiry form is the second option on mobile and the primary one on desktop — the same page, weighted differently to the device.

The form asks four things and no more: a name, a number, a suburb and a rough lawn size, because every additional field on a trade form is a customer who decides to ring someone else, and the suburb is the one answer that decides which run day they land on.

The estimate is the proof element rather than a gallery, because this customer’s question is a number and every competitor answers it with “contact us for a quote” — publishing $60 a visit and $1,560 a year, and letting them see that monthly is cheaper across the year, buys more trust than any photograph would.

The trust strip is three short facts a customer can check on the first visit — nine years, insured, the quote is free and the first visit is the quote — rather than badges nobody reads, and the run-days card turns “we are reliable” into a specific claim you could hold us to.

And the estimate feeds the enquiry form, so the customer who has already priced their own block arrives at the form with the answer attached and only four boxes left to fill.

What this page refused to publish

This trade sits next to a real scheme whose numbers move and which we cannot verify. The rule is to decline, not to soften.

Local SEO we’d implement for the real business

The live page emits WebPage and CreativeWork only, and names itself a demonstration. Fictional LocalBusiness and Review markup in a real search index is dishonest markup, so the schema a real Kerbline would ship lives here as a sample instead.

{
  "@context": "https://schema.org",
  "@type": ["LocalBusiness", "HomeAndConstructionBusiness"],
  "name": "Kerbline Lawn & Garden",
  "url": "https://kerbline.com.au/",
  "telephone": "+61 8 ____ ____",
  "priceRange": "$$",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "<the real depot address>",
    "addressLocality": "Willetton",
    "addressRegion": "WA",
    "postalCode": "6155",
    "addressCountry": "AU"
  },
  "geo": { "@type": "GeoCoordinates", "latitude": "<lat>", "longitude": "<lng>" },
  "areaServed": [
    { "@type": "City", "name": "Willetton" },
    { "@type": "City", "name": "Rossmoyne" },
    { "@type": "City", "name": "Canning Vale" },
    { "@type": "City", "name": "Southern River" }
  ],
  "openingHoursSpecification": [{
    "@type": "OpeningHoursSpecification",
    "dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
    "opens": "06:30", "closes": "17:00"
  }],
  "hasOfferCatalog": {
    "@type": "OfferCatalog",
    "name": "Mowing and garden care",
    "itemListElement": [{
      "@type": "Offer",
      "itemOffered": { "@type": "Service", "name": "Fortnightly mow, edge and blow down" },
      "priceSpecification": {
        "@type": "PriceSpecification",
        "price": "60.00", "priceCurrency": "AUD",
        "valueAddedTaxIncluded": true
      }
    }]
  },
  "review": [{
    "@type": "Review",
    "author": { "@type": "Person", "name": "<the real customer, with permission>" },
    "datePublished": "<the real date>",
    "reviewRating": { "@type": "Rating", "ratingValue": "5", "bestRating": "5" },
    "reviewBody": "<the review they actually wrote>"
  }],
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "<from the real Google Business Profile>",
    "reviewCount": "<from the real Google Business Profile>"
  }
}

Alongside it: a claimed and verified Google Business Profile with the service area set to the eight suburbs rather than a radius; the same NAP string byte-for-byte on the site, the profile and every directory; a suburb landing page per run day once there is real content to put on it; and review requests fired from the job management system the morning after each visit, which is when a mowing customer is most likely to write one.

What would change for the real client

Round scheduling

ServiceM8 or Fergus for the recurring round — both handle a repeating job template, the night-before SMS, on-site quoting from the phone, and the skip that does not break the sequence. The enquiry form posts straight into the inbox as an unscheduled job with the suburb already set, so the run day is assigned before anyone calls back.

Invoicing and reviews

Xero behind whichever of those two they pick, so the property-manager customer gets one consolidated monthly invoice instead of six. Review requests triggered from the completed job, feeding the real Google Business Profile that the demonstration reviews stand in for.

Their photographs

The drawn block plan is a demonstration device. A real operator has before-and-afters on their phone, and those replace the plan in the hero with the estimate moving alongside them — the plan exists to prove the page carries without stock photography, not to argue against real ones.

Their prices

The whole model is five numbers and three multipliers in one table at the top of the script. Changing a rate is a one-line edit, and every figure on the page — the services grid anchors included — moves with it.