IronlineBuild notes

Generative Assets · Industry demonstration 415

How the Ironline Heavy Haulage page was made

A lead-generation page for a fictional Kwinana Beach float operator, built so a maintenance supervisor with a crusher to move can price the movement and send a scoped enquiry in about a minute — and so the page never states a regulatory number it cannot stand behind.

The concept

Ironline Heavy Haulage runs drop-decks, low loaders and a widening extendable out of Kwinana Beach — mine site relocations, crushers, tanks, transportables and ag headers, across metro, the Wheatbelt and Goldfields, and the Mid West and Pilbara. The audience is B2B: a project or maintenance supervisor with a machine that has to be somewhere by a date, who wants a number and a phone call, not a brochure.

The page has one job: a scoped enquiry with the load details attached. That is why this form has the most fields of the five sites in the wave and why the estimate sits above it — the estimate exists to make filling that form feel worth it. A supervisor who has already watched the price move with the rig, the distance and the pilots understands why we are asking for mass, dimensions and access, and answers instead of bouncing.

The honesty constraint, stated plainly. This page publishes no numeric oversize or over-mass dimension or mass threshold, no permit fee, no notice period, and no claim about when pilot vehicles or a police escort are legally required. What it does state is the mechanism, which is verifiable: oversize and over-mass movements in Western Australia run on a Main Roads WA permit, and Ironline prepares and lodges that application as part of the job. Pilots on the estimate are a user toggle — “add pilots to see the effect” — and the rate board says so in as many words: “Pilot vehicle requirements are set by the permit for your load and route, not by this page.”

Every figure that is on the page is either the fictional business’s own commercial rate or a road distance. Nothing about a real regulator is quantified.

Palette — steel and oxide

Argued from the trade, not from a mood board: cold rolled steel for the grounds, oxide primer for the marks and the calls to action, and a deck blue that draws the trailers and the route corridors. No cream, no acid accent. Ratios below are measured with WCAG arithmetic and quoted with the hex from the same row of the wave’s contrast sweep.

Steel #EEF1F3The page ground. Cold, slightly blue, the colour of a swept workshop floor rather than paper.
Panel #DCE2E7Alternating section ground, so a long page still has rhythm without a second hue.
Ink #131A20Body copy. 15.47:1 on steel, 13.44:1 on panel.
Muted #414E58Secondary copy and field hints. 7.54:1 on steel, 6.55:1 on panel.
Oxide #9C3A22CTA fills, eyebrows, the “billed” mark. As ink: 6.09:1 on steel, 5.28:1 on panel. Steel reversed on it: 6.09:1.
Deck blue #1E4A6BTrailers, route corridors, the selected chip. As ink: 8.24:1 on steel, 7.15:1 on panel. Steel reversed on it: 8.24:1.
Band #16222EThe rate board, the result header, the price plate and the footer. Steel reversed on it: 14.21:1.
Field #66757FInput and chip borders, a mark not a text colour. 4.19:1 on steel, 3.64:1 on panel.
Hairline #A9B5BERules and the road’s dash row. 1.84:1 on steel, 1.60:1 on panel — a line token, never type.

Forbidden grounds, declared. Ink and muted are never placed on band, oxide or deck blue — they measure 1.09:1, 2.54:1 and 1.88:1 there. Dark grounds carry steel only. That is why the rate board’s six plates, the result header and the on-drawing price plate all reverse to steel rather than tinting the type, and why the SVG map labels are body ink with a steel halo instead of being drawn in the blue that draws the corridors.

Type

Barlow Condensed 600/700 for headings, the rate figures and every number in the drawing — condensed grotesque is the face of a truck door, a placard and a load plate, and it is the only condensed face in the wave. Barlow 400/500 carries body copy, the ledger keys, the form and the FAQ. One family, two widths: the page reads as one voice, and the width change alone marks what is a figure and what is a sentence.

Tabular numerals are on globally (font-variant-numeric: tabular-nums plus the tnum feature). A rate board where $1,450 and $2,950 do not align on the comma reads amateur to someone who reads rate sheets for a living. Body is 17px at 375 and the headline runs clamp(2.05rem, 7vw, 2.6rem), so the four-line phone headline becomes a three-line desktop one without a separate copy deck.

The one typographic move is the movement total: Barlow Condensed 700 at clamp(2.4rem, 8vw, 3.4rem), reversed out of the band in the result header, and repeated at 23px on a band plate inside the drawing. Nothing else on the page comes near either size.

The proof element — the movement estimate

Three controls, one result card, and a side elevation of the selected float drawn beside them. Rig: drop-deck to 24 t, low loader to 45 t, widening extendable to 60 t. Destination: a metro band to 120 km, or a country distance on a slider with Geraldton (420 km), Kalgoorlie (595 km) and Port Hedland (1,640 km) as presets. Pilots: none, one or two.

The model

ScenarioRigkmPilotsTotal
Floor — equals the rate board’s “from”Drop-deck1200$1,450
Metro with one pilotLow loader1201$2,440
First country cellLow loader1210$2,750
GeraldtonDrop-deck4200$2,620
Rest state — Kalgoorlie, the thumbnailLow loader5951$5,960
The same run without pilotsLow loader5950$4,530
Port Hedland, two pilotsExtendable1,6402$23,070

The pilot line at the rest state is $1,430 — $5,960 less $4,530 — and the ledger prints it as its own row so the toggle’s cost is never buried in the total. The floor, $1,450, is exactly the rate board’s from $1,450 a day, metro: the estimate’s cheapest output and the grid’s cheapest anchor are the same number, so the page cannot argue with itself.

The band-edge inversion, and why the max() is load-bearing

This is the best trust story on the page, and it was caught by the wave’s arithmetic check before a line of the page existed. Write the country formula the obvious way — kilometres times the rate, plus mobilisation — and the price falls as the load crosses the metro band edge:

Low loader, no pilots120 km121 kmReads as
Naive: km × rate + mobilisation$2,150$1,400one more kilometre, $750 cheaper
Shipped: max(day rate, km × rate) + mobilisation$2,150$2,750monotone, and true to how the day is actually consumed

The naive figure is not merely odd, it is wrong about the world: a 121 km run still burns a driver’s day and a float’s day, so it cannot cost less than the metro day rate. The max() is the honest floor, and the shipped model is monotone in distance for every rig and every pilot count from 121 km to 2,000 km — verified cell by cell against an independently reimplemented oracle rather than against the page’s own function.

Rather than hide the comparison, the ledger shows it. Whichever of the two lines loses is struck through in muted; the one that bills carries a — billed mark in oxide. At 121 km on the low loader the ledger reads Loaded kilometres · 121 × $6.60/km — under the day rate: $798.60, then Low loader day rate, whichever is greater — billed: $2,150. At 595 km the strike-through swaps sides. A supervisor sees the rule work once and stops wondering whether the number is a guess.

The drawing

A procedural side elevation of the selected float, laid out in real CSS pixels (one SVG unit is one device-independent pixel) so a label is never 4px tall on a phone, dimensioned on the deck that decides what fits: Deck 13.6 m, Well 9.0 m, Deck 12.5 m with a dashed Extends to 19.0 m. Pilot vehicles appear in the convoy when the toggle turns them on, which makes the pilot line in the ledger legible without a caption. The dimension rule breaks for its label rather than the label being cased over it — a halo alone lets the rule show through the word gaps and the type reads dotted.

The whole sheet is assembled synchronously and rebuilt on resize with no entrance choreography, and the price plate is a rect inside the artwork, tested at 375, 768, 1000, 1200 and 1440 (and at device pixel ratio 2) so its box never intersects any drawn part of the rig at any rig or pilot count.

The conversion decisions

Why the phone and the form, in that order

Trades pages usually make the call the only real CTA. Heavy haulage is different: allocations cannot price a movement over a thirty-second call, because the answer needs mass, dimensions, access at both ends, a date window and whether the machine drives on or gets lifted. So the masthead and the mobile sticky bar own a real tel: link for the supervisor who wants a human, and the hero’s primary button goes to the form for the one who has the spec sheet in front of him. Both are above the fold at 375 without scrolling, together with the trust line.

Why the form is long on purpose

Eighteen fields, fifteen of them required, is heresy on a landing page — unless the fields are exactly the list the business already works from. The page says out loud, twice, what it needs to quote: as a numbered aside beside the form, and in the first FAQ. The form then asks for precisely those five things and nothing decorative. A long form that mirrors a stated list reads as competence; a short form that then triggers a phone call asking for the same detail reads as a lead-capture trick. The estimate’s Send these details button carries the scenario into the notes field and pre-fills the two suburbs, so the form starts partly answered.

Honest states

Submitting empty raises a message on every required field, focuses the first one, and keeps the confirmation panel hidden. Submitting a valid form shows a designed local confirmation that echoes back the machine, dimensions, route, date and loading method — and says plainly that this is a demonstration page, so it stopped in the browser and nothing was sent. There is no fake network round-trip and no fake delay.

Why this converts

  1. The primary CTA is in the masthead, in the hero, on the estimate card, on the form and in a sticky bar that follows the phone down the page — so the decision to act is never more than a thumb-length away, and the phone number is a real tel: link everywhere it appears, not an image of a number.
  2. The form asks for the five things this trade genuinely needs to quote, in the order allocations would ask for them, which turns the longest form of the five sites into the most credible one: a supervisor who recognises the list assumes the people behind it have loaded a machine before.
  3. The proof element lets a stranger price their own movement without ringing anyone, and the price moves in ways they can check — more distance costs more, a second pilot costs a visible $2.40 a kilometre — so the number reads as a model rather than a marketing figure.
  4. The trust strip does not claim awards; it claims a yard, a count and a mechanism (“we prepare and lodge the Main Roads WA permit… as part of the job”), which is the specific job a supervisor is quietly worried about having to do themselves.
  5. Everything the page will not swear to, it declines to say — no permit fees, no thresholds, no legal claims about pilots — and that restraint is visible on the page, which is the cheapest credibility a business can buy.

Local SEO we would implement for the real business

The live page emits only WebPage, CreativeWork, WebSite and BreadcrumbList schema, naming itself a demonstration. Publishing LocalBusiness or Review markup for a business that does not exist would put fictional data into a real index, so we do not. For a real Ironline, the block below is what would ship — shown here as a code sample only, and never emitted live from either page in this collection.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "MovingCompany",
  "@id": "https://ironlineheavyhaulage.com.au/#business",
  "name": "Ironline Heavy Haulage",
  "description": "Drop-deck, low loader and widening extendable movements across WA. Permits prepared and lodged with Main Roads WA.",
  "url": "https://ironlineheavyhaulage.com.au/",
  "telephone": "+61 8 XXXX XXXX",
  "priceRange": "$$$",
  "image": "https://ironlineheavyhaulage.com.au/img/yard.jpg",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "<street>",
    "addressLocality": "Kwinana Beach",
    "addressRegion": "WA",
    "postalCode": "6167",
    "addressCountry": "AU"
  },
  "geo": { "@type": "GeoCoordinates", "latitude": -32.23, "longitude": 115.77 },
  "openingHoursSpecification": [{
    "@type": "OpeningHoursSpecification",
    "dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
    "opens": "05:30", "closes": "17:00"
  }],
  "areaServed": [
    { "@type": "AdministrativeArea", "name": "Perth metropolitan area" },
    { "@type": "AdministrativeArea", "name": "Wheatbelt, Western Australia" },
    { "@type": "AdministrativeArea", "name": "Goldfields-Esperance, Western Australia" },
    { "@type": "AdministrativeArea", "name": "Mid West, Western Australia" },
    { "@type": "AdministrativeArea", "name": "Pilbara, Western Australia" }
  ],
  "hasOfferCatalog": {
    "@type": "OfferCatalog",
    "name": "Movements",
    "itemListElement": [
      { "@type": "Offer", "name": "Drop-deck float, metro day rate",
        "priceSpecification": { "@type": "PriceSpecification",
          "minPrice": 1450, "priceCurrency": "AUD" } },
      { "@type": "Offer", "name": "Low loader, metro day rate",
        "priceSpecification": { "@type": "PriceSpecification",
          "minPrice": 2150, "priceCurrency": "AUD" } }
    ]
  },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.9", "reviewCount": "41"
  },
  "review": [{
    "@type": "Review",
    "author": { "@type": "Person", "name": "<real reviewer>" },
    "reviewRating": { "@type": "Rating", "ratingValue": "5" },
    "reviewBody": "<verbatim from the review platform, never written by us>"
  }]
}
</script>

Beside the markup, the real build would carry: a Google Business Profile with the primary category set to the movement type the business actually wants calls for; the same NAP string byte-for-byte on the page, the profile and every directory; corridor landing pages that earn their keep (“low loader hire Kalgoorlie”, “transportable transport Geraldton”) rather than a suburb-spam doorway set; and reviews pulled live from the profile so the testimonials are never hand-typed marketing copy. AggregateRating only ever reflects a real, auditable review feed.

What would change for the real client

The iteration log

Three passes, each driving the real controls in headless Chrome — sweeping rig × destination × pilots against an independently reimplemented oracle, submitting the form empty and filled, tapping the sticky bar — and each one reading the rendered pixels, not only the asserts.

Pass 1 — Craft

  1. The header CTA was live at 375 and the masthead ran 33px past the viewport (scrollWidth 408 against a 375 box). .mast-cta{display:none} was declared above .btn{display:inline-block}, and at equal specificity source order wins, so the button un-hid itself on every phone. Moved the hide rule below the button block, with a comment saying why it lives there.
  2. The 7-second preview contained no drawing at all. The rig elevation started at y = 1,029 at 1200×750, so the collection’s headline sales asset was a page of copy. Rebuilt the vertical rhythm above it: the hero splits into a headline column and a supporting column at ≥1000px, the rate board’s caption sits on the heading line, and the drawing’s reserved plate band and headroom were cut to exactly what the tallest rig needs (4.5 m clears the extendable’s 4.25 m tank). The elevation now sits 606–746 — entirely inside the frame, price plate and deck dimension included.
  3. The deck dimension label printed nothing. dimension() was handed g.deckLabel from the geometry table, where the label actually lives on the rig table. Every state assert was green while the one measurement the drawing exists to give was absent. Now rig.deckLabel.
  4. The rate plates broke “a day, / metro” across two lines with a 24px hole — the unit was inline inside a 22px condensed line box. The unit is a block now, so every plate reads figure-then-unit; and “After hours & weekends” became “After hours” so its heading is one line like its five neighbours.
  5. The entrance was a rAF-driven class toggle. Headless Chrome services requestAnimationFrame only when a frame is requested, so the preview could have captured the drawing at opacity 0. Replaced with a CSS keyframe animation with both fill, which is settled long before the capture and is killed outright under prefers-reduced-motion.

Pass 2 — Depth

  1. Made the max() visible instead of merely correct. The losing line in the ledger is struck through in muted; the winning line carries an oxide — billed mark. Drove 121 km on the low loader (kilometres $798.60, day rate $2,150 billed, $2,750 total) and 595 km (kilometres $3,927 billed, day rate $2,150) and read both renderings. This is now the page’s second read.
  2. Redrew the low loader’s machine. It was three stacked boxes and a floating parallelogram; it is now tracks with a roller line, a slew deck, a house with cab glass, and a boom and bucket folded down for transport. Added a riser web between decks of different heights so a step-deck reads as one trailer rather than two disconnected halves, and moved the drop-deck’s transportable off the upper deck so the step is actually visible.
  3. The dimension rule now breaks for its label. With a halo alone the rule showed through the word gaps and “Deck 12.5 m” rendered as dotted type — only visible in a 3× capture.
  4. The service-area map had colliding labels. Northam, Merredin and Southern Cross were all set above a corridor 40px apart, and “Merredin” was completely hidden under “Southern Cross”. Alternated them above and below the corridor and spread the nodes; moved the metro-band caption off the Esperance spur to under the ring; cropped the viewBox west of the coast so the corridors fill the card instead of 90px of empty ocean.
  5. Copy. Off-preset distances read “Kwinana Beach to a 121 km run” rather than the tautological “to 121 km out, 121 km”.

Pass 3 — Hardening

  1. Six FAQ disclosures had the browser’s default 1px focus ring — the :focus-visible selector list covered links, buttons and fields but not summary. Walked the first 22 tab stops — skip link, wordmark, nav, phone, both hero calls to action, all three chip groups, the distance slider, the estimate’s two buttons and every FAQ disclosure — and confirmed each carries the same 3px oxide ring on a visible box.
  2. Badge-versus-subject clearance, tested rather than eyeballed. The price plate’s box is checked against every drawn part of the rig at 375, 768, 1000, 1200 and 1440, at device pixel ratio 1 and 2, across all three rigs and both pilot extremes — 36 combinations, no intersection. (The first version of that probe grabbed the first <rect> in the sheet, which is the prime mover’s chassis, and reported six collisions that did not exist; the plate now carries a data attribute and the probe targets it. A new check is wrong before the page is.)
  3. Resize. The sheet is redrawn on a debounced width change and tracks its container exactly at 1200 → 700 → 1440, with the scene still fully opaque afterwards — a resize must never re-enter an entrance, because taking a clipped screenshot changes device metrics and would photograph a fading page.
  4. Rapid-fire. Nine control clicks dispatched in one evaluate with no settle between them land on the rest total of $5,960 with the drawing intact — no stale closure, no half-built sheet.
  5. Form. Empty submit: 15 messages against 15 required fields, first bad field focused, confirmation stays hidden. Filled submit: zero errors, panel visible, four summary lines echoing the load. Then a bad email, a three-digit phone and a 900-tonne mass, each rejected with its own message, and the panel correctly re-hides.
  6. 375. scrollWidth exactly 375, wordmark and phone both inside the viewport box with clearance between them, no overflow offenders, sticky bar flush to the bottom with 48px targets, and the whole above-the-fold contract (headline, both CTAs, trust line) satisfied at 375×667 as well as 375×812.
  7. The live region was announcing a table. aria-live="polite" sat on the ledger, which rewrites five rows on every tick of the distance slider — hostile to anyone driving the estimate with a screen reader. The ledger is quiet now and a visually-hidden role="status" carries one sentence instead: “Low loader · Kwinana Beach to Kalgoorlie, 595 km · 1 pilot. Billed on the loaded kilometres, which are greater than the day rate. Estimated movement $5,960 ex GST.” — so the max() reaches the third surface too, not just the ledger and the drawing.
  8. The Chanel rule. Removed the .reveal stagger machinery entirely rather than porting it — the page has one entrance, on the drawing, and nothing else moves.

Techniques

This is a demonstration build by Sapience Analytics

Want one pointed at your customers? We build lead-generation pages that price the thing your customers actually ring about, and we write down the arithmetic before we write the page.