Generative Assets · industry demonstration 420

How the Sidelift Cartage page was built

A fictional Hazelmere container-cartage operator, built as a lead-generation landing page. Its single job is a phone call or an enquiry carrying the container number, the size and the delivery suburb — and its whole conversion argument is that it prices its own cartage and refuses to print a figure for anybody else’s charges.

The concept

A business receiving a container has two questions and one fear. The questions are what does the cartage cost and when can you get a slot. The fear is the invisible extras — the wharf line, the slot fee, the empty-park charge, the detention nobody explained.

Every competitor answers the first question with “contact us”. This page answers it in the hero, with a three-control estimate, and then does something better with the fear: it says plainly that wharf, port, slot-booking, empty-park and detention charges are passed through at cost, and that no figure for any of them appears anywhere on the page, because those are real charges set by other parties and they move. The honesty about pass-throughs is the conversion argument, not the disclaimer at the bottom.

B2B, business hours, so the phone leads: the masthead carries a click-to-call, the hero’s primary button is the call, and the sticky bar on a phone is call-first with the form anchor beside it.

Why this converts

The call button is the first thing under the headline because this buyer is an allocator or a warehouse manager reading the page at 8am with a box already on the water, and for them a phone call is faster than any form — so the form is the fallback, not the funnel. The estimate sits beside the headline rather than three screens down, which means the answer to “what does this cost” is visible before the visitor has decided whether to keep reading, and it is a real answer, not a range with an asterisk. The form asks for seven things and no more — business, contact, phone, container number, size, delivery suburb, unload method — because those are exactly the fields an allocator needs to price and book, and the container number is marked optional so a first-time importer whose release has not come through can still get in touch. The trust strip is three sentences the competitors cannot copy without changing how they invoice: we book the slot on our own account, pass-throughs go through at cost on the line’s own paperwork, and there is a yard if the site is not ready. And the high-cube control is the whole page in miniature: it changes the drawing and not the price, it says so out loud, and a page that volunteers where it does not charge you is the one that gets rung.

The proof element — the cartage estimate

Three controls, one card: the box (20ft, 40ft, 40ft high cube), the delivery zone (four distance bands out from the wharf), and how it comes off (live unload, side-loader, drop trailer overnight). The card answers with a single figure, the two line items behind it, and the waiting-time rate held separately.

The arithmetic is a 36-cell rate table, checked by a small node script before a line of the page was written. Three properties were proven over the whole domain, not at a handful of cells:

  • The price only ever rises with distance, in every box-and-unload combination. A quote that falls as the job gets further away does not read as rounding — it reads as a made-up number.
  • A 40ft always costs more than a 20ft on the same run.
  • A 40ft high cube is price-neutral against the 40ft on all 36 vectors.
Cartage, ex GST. Handling is added on top: live $0, drop trailer $120, side-loader $180.
Zone20ft40ft40ft high cube
1 · Inner harbour$340$390$390
2 · Metro$430$490$490
3 · Outer metro$560$640$640
4 · Peel$980$1,120$1,120

The rest state — the state the page loads in and the state the preview thumbnail captures — is a 40ft to zone 2 on the side-loader: $490 + $180 = $670. The cheapest cell on the whole domain is $340 (20ft, zone 1, live unload) and that is exactly the “from” price in the services grid; the dearest is $1,300.

Two things the page says because they are proven, not asserted

High cube costs the same. There is a line beside the control — “a high cube changes what fits under, not what you pay” — and when you actually select it, a flag appears in the result naming the standard 40ft price on the same run so you can see the two numbers are identical. A control that visibly changes the drawing and provably does not change the price is the most trust-building thing a quoting page can show, so it is stated in the open rather than buried.

Waiting time is a rate, not part of the estimate. $95 an hour after the first hour on a live unload, printed beside the result and never folded into the total. Folding it in would make the live-unload option look dearer than it is; leaving it out silently would make the invoice a surprise.

The drawn subject

A stylised side elevation of a skel trailer with the selected box on it, drawn in SVG and redrawn on every change: a 20ft is visibly short and sits over the bogie, a 40ft fills the deck, a high cube is visibly taller on the same deck. There are no dimension callouts and no true-scale claim — the drawing tells you which box is on the trailer, not how big it is to the millimetre. Corrugation ribs, top and bottom rails, door bars and the size plate are all generated from the same geometry, so the plate reading “40 HC” and the box being one foot taller are the same fact drawn twice.

Second read: under the line items sits the whole distance ladder for the currently selected box and unload — all four zones, the current one marked. It is there so a buyer can see the shape of the pricing in one glance rather than clicking four times, and so the monotonicity the check proves is visible on the page rather than only in a test file.

What this page declined to publish

Every figure below was considered, could not be verified as a current published charge, and was left off both pages. The page states the mechanism instead — who charges it, who pays it, and that it reaches the customer at cost.

  • Any wharf or container terminal charge at Fremantle, in any form — landside access, terminal access, infrastructure surcharge.
  • Any slot-booking, VBS or 1-Stop fee. 1-Stop is named in these notes as tooling a real operator uses; no charge from it is quoted anywhere.
  • Any empty-container-park fee or de-hire charge.
  • Any detention or demurrage rate, and any free-time period. The page says detention is the shipping line’s charge, that it varies by line and contract, and that we would tell the customer the date the free time ends — and stops there.
  • Any Fremantle Ports figure of any kind, including port infrastructure surcharges.
  • Any heavy-vehicle accreditation, mass-management or fatigue-scheme claim. The operator is fictional; asserting a real accreditation would be a false claim about a real scheme, so the footer carries an ABN placeholder pattern and nothing else.

What is published is the fictional operator’s own commercial rates and nothing else: the 36-cell cartage table, the two handling fees, the $95 waiting rate and the $9-a-day yard storage. That is the whole of it.

Palette

Marine grey-green and container paint — the two colours you actually see standing at a wharf gate, and deliberately not the fleet-navy every transport site defaults to. Every hex and every ratio below is quoted from the same run of the contrast sweep, taken after the last palette change. 154 declared pairs, zero failures.

Paper #EEF2F1Page ground. Body ink reads 16.25:1 on it.
Panel #DBE4E1Cards, alternating bands, and the map’s land fill. Ink 14.14:1.
Ink #0F161416.25:1 on paper, 14.14:1 on panel.
Muted #3E4B47Secondary copy. 8.08:1 on paper, 7.04:1 on panel.
Marine #12514ECTA, figures, selected chips. 8.05:1 as ink on paper and 8.05:1 with paper reversed on it.
Marine hover #0D403EMinted here. Paper reversed 10.22:1; the chip sub-label at 86% blends to #CFD9D8, 8.01:1.
Rust ink #96351FWaiting-time rate and form errors. 6.58:1 on paper, 5.73:1 on panel.
Band #0F1917Demo band, footer, sticky bar, wheels. Paper reversed 15.88:1.
Container #A63A22The drawn box. Paper reversed 5.73:1; the size plate at 94% blends to #EAE7E5, 5.25:1.
Rib #7A2817Minted here. Corrugation, rails and door bars. 1.52:1 on the container fill — texture, judged as a hairline.
Deck #A3B0ADTrailer beam and gooseneck. Marine marks on it 4.05:1.
Map water #B9D0D3With coast #54737A at 3.17:1 on it. No label is ever set over water.
Zone 1 #A9C5C1Minted here. Ink 9.99:1, marine 4.95:1 — the tightest declared pair on the page, so zone 1 goes no darker.
Zone 2 #BFD4D1Minted here. Ink 11.84:1, marine 5.86:1.
Zone 3 #D5E2DFMinted here. Ink 13.77:1, marine 6.82:1.
Zone 4 #EAF0EEMinted here. Ink 15.89:1, marine 7.87:1. Band edges are #7E948F, 1.76:1 to 2.79:1.

Six colours were minted during this build — the four zone band fills, the band-edge hairline and the container rib — plus the CTA hover ground. All seven were added to the wave’s contrast sweep and re-measured rather than eyeballed, because the previous wave’s only two real colour defects both lived in exactly this class: a map fill and an opacity-blended label.

Type

Archivo 600/700 carries the headings and every figure. It is plated and slightly condensed — container-stencil adjacent without dressing up as one — and it holds its shape at the 58px the price figure runs at. Inter 400/500 does the body at 17px on a phone, which is a size an allocator can read on a forklift dock.

The one typographic move is the pairing the spec asked for: the price and the container size set as a pair, the way a job card reads. The figure sits large on the left, the box and zone sit small and bold immediately to its right on the same baseline, with the unload method and “ex GST” on a second line underneath. That is the shape of the line an allocator writes on a run sheet, and it is the shape the estimate answers in.

Technique

One file, all CSS and JS inline, no libraries, no raster images, about 70 KB. Every visual is drawn: the trailer elevation, the four-zone service-area map, the icons, the favicon.

The layout trick

The DOM order is the mandated mobile stack — masthead, hero, services grid, estimate. At 940px and up a single CSS grid with named areas moves the estimate into the hero’s second column and drops the services grid underneath, without moving a single element in the markup. That keeps the reading order honest for a screen reader and puts the answer, not a menu of tiles, in the preview thumbnail.

The animation

The truck slides in once on load, driven by performance.now() wall-clock deltas rather than a per-frame accumulator, and pauses if the tab is hidden. That distinction matters more than it sounds: a per-frame delta in a headless renderer advances only as fast as frames are requested, so a preview taken seven seconds in can catch a page that thinks it is half a second old. Under prefers-reduced-motion the entrance is skipped entirely and the drawing is placed in its final position on the first paint. After the entrance the page is completely at rest — no loops, no timers, no mutations — which is exactly what the thumbnail contract needs.

The drawing

The container is six SVG elements whose geometry is recomputed from one {w, h} pair: body, top rail, bottom rail, door bars, corner post and the size plate, plus up to thirty corrugation ribs laid on a 13-unit pitch and hidden beyond the box length. CSS transitions on the SVG geometry properties do the interpolation, so changing the box animates without a single frame of JavaScript.

The map

Four nested ellipses, painted largest first, so the zones read as distance bands out from the wharf rather than as council boundaries — which is what they actually are. The coastline is a single path drawn over the bands, so the rings are clipped by the ocean the way real delivery zones are. On a phone the map keeps one named suburb per zone and the other nine labels are hidden, because the complete list of fourteen sits directly underneath in real, selectable text.

The three passes

Pass 1 · Craft

The drawing was a silhouette, the map bands were invisible, and the desktop hero had a hole in it

Driven first: the estimate at rest read $670 / $490 / $180 with the plate reading 40 FT, the form rejected an empty submit with six errors and confirmed on a filled one. Then the rendered page was looked at rather than asserted, and three things were wrong.

(a) The first trailer was a grey bar with wheels; the prime mover read as a blob and the deck floated. It was rebuilt as an actual skel — rear bumper, main beam, gooseneck rising to a kingpin plate, landing legs, tri-axle bogie — and the prime mover got a cab, an exhaust stack, a roof deflector and a windscreen. The container gained top and bottom rails, door bars, a corner post and a plate panel so the size text is not fighting the corrugation behind it.

(b) The four zone fills were originally spaced about 1.10:1 apart in luminance and were indistinguishable on screen — the legend swatches all looked like the same near-white. They were respread to 1.15–1.18:1 steps and re-swept: ink now reads 9.99 / 11.84 / 13.77 / 15.89:1 and marine 4.95 / 5.86 / 6.82 / 7.87:1. Zone 1 goes no darker than #A9C5C1 because 4.95:1 is the tightest declared pair on the page.

(c) At 1200 wide the estimate card ran about 900px tall and the hero column about 400, leaving a 500px hole beside it — and the rest figure sat below the thumbnail’s 750px line. Both were fixed at once: the result moved directly under the drawing (which is also the better reading order — picture, then price, then the controls to change it) and the hero gained the three-point trust strip that was missing from the checklist anyway. The figure now sits at y 426. The hero subline was cut from five lines to one.

Pass 2 · Depth

Make the neutrality claim visible at the moment it applies, and show the whole ladder

Driven again, this time across the entire 36-cell domain in the browser: every cell’s window.__containertransport total was compared against the check script’s table, and the displayed string against the total. 36 of 36.

The high-cube line was a sentence beside the control and nothing more, which is an assertion. Now, selecting the high cube reveals a flag in the result that names the standard 40ft price on the same run — two identical numbers, side by side, at the moment the customer is wondering. Verified on all twelve high-cube vectors: the flag is hidden for the 20 and the 40, shown for the high cube, and its figure equals the 40ft price every time.

The second-read addition is the distance ladder: four cells under the line items showing what this same box and this same unload cost in all four zones, with the current one marked. It re-labels itself (“A 40 ft HC, side-loader unload, zone by zone”) and was verified to be monotonic in all 36 states. It turns the thing the check proves into something the buyer can see.

Micro-interactions: the chips are a proper radiogroup with roving tabindex and arrow-key navigation (verified — ArrowRight on zone 2 moves focus to zone 3 and the total to $820), and the container animates its geometry rather than jumping.

Pass 3 · Hardening

A CSS selector that silently did nothing, and one ornament removed

The 375px pass found a real defect that no state assertion could see. The rule that hides the optional map labels on a phone was written .lbl.opt — but .lbl is on the parent group and .opt is on the text elements, so the selector matched nothing and all fourteen suburb labels rendered on top of each other at 375. Corrected to a descendant selector, and four more labels were marked optional, so a phone shows one named suburb per zone and the full fourteen sit in the list below.

The zone-1 labels were then re-laid: at the mobile label size the wharf and Cockburn labels touched, and one suburb had drifted outside its own ellipse — Bibra Lake was drawn in the zone 2 band while the legend listed it in zone 1. Every one of the fourteen dots was re-checked against the ellipse equation of the band it is supposed to be in.

Chanel rule: the hero trust points had three different coloured markers (marine, rust, deck grey) for no reason other than decoration. All three are marine now. The smallest type on the page — the ladder’s zone labels at 10px — went to 11px.

Final state: no console errors or failed requests on either page, no horizontal overflow at 375 (document scrollWidth 375, no element past the viewport box, masthead wordmark and call button 24px apart with the call button ending at 357), exactly one h1 per page, no curly quotes in any attribute, [hidden] guarded, reduced motion settles on the first paint, and the probe figures are byte-identical between the 7-second thumbnail instant and 15 seconds.

Local SEO we would implement for the real business

This demonstration page deliberately emits only WebPage, CreativeWork and BreadcrumbList structured data, and it names itself a demonstration. Putting a fictional business into a real search index with LocalBusiness markup and invented reviews would be dishonest, so the markup we would ship for a real operator is shown here as a sample only — it is not live on either page.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "MovingCompany",
  "name": "<real trading name>",
  "image": "https://<domain>/yard.jpg",
  "telephone": "+61 8 <real number>",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "<real street address>",
    "addressLocality": "Hazelmere",
    "addressRegion": "WA",
    "postalCode": "6055",
    "addressCountry": "AU"
  },
  "geo": { "@type": "GeoCoordinates", "latitude": "<lat>", "longitude": "<lng>" },
  "areaServed": [
    { "@type": "City", "name": "Perth" },
    { "@type": "AdministrativeArea", "name": "Peel" }
  ],
  "openingHoursSpecification": [{
    "@type": "OpeningHoursSpecification",
    "dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
    "opens": "05:00", "closes": "17:00"
  }],
  "hasOfferCatalog": {
    "@type": "OfferCatalog",
    "name": "Container cartage",
    "itemListElement": [
      { "@type": "Offer", "itemOffered": { "@type": "Service", "name": "20ft wharf to door" } },
      { "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Side-loader unload" } },
      { "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Empty container return" } }
    ]
  },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "<from the live reviews feed>",
    "reviewCount": "<from the live reviews feed>"
  }
}
</script>

Alongside it: a Google Business Profile with the yard’s real address and photographs of the actual side-loaders, the four zone bands turned into four indexable suburb sections rather than one page, and the FAQ marked up as FAQPage — the questions on this page are the ones the trade is actually asked, so they are worth the markup. The aggregateRating block is filled from the live reviews feed, never typed by hand.

What would change for the real client

  • Their fleet, not our drawing. Photographs of the actual side-loaders and skels replace the SVG elevation on the services tiles, though the drawn estimate stays — it is faster than a photograph and it changes with the controls.
  • MTData or Geotab on the trucks. The delivery window the page promises “in writing” comes from telematics, not from a dispatcher’s memory, and the same feed drives the SMS the customer gets when the driver leaves the wharf.
  • 1-Stop for slot bookings. The enquiry form’s container number is validated against the real release, so an allocator is not chasing a typo. Named as tooling only — no charge from it is quoted on either page.
  • Xero for invoicing. Pass-throughs are attached to the invoice as the original charge document, which is the operational habit the page is selling; the invoice line and the promise on the page have to match or the promise is worthless.
  • Their reviews, pulled live. The three quotes on the page are demonstration copy and are deliberately not marked up. On a real build they come from the Google Business Profile feed and the rating block above fills itself.
  • The rate card behind a login for regular accounts, so the public page keeps the honest “from” prices and contracted customers see their own.