Latitude LaneBuild guide

How Latitude Lane was built

Site 219 of the Generative Assets collection — the fourth of the Industry Demos: a conversion-focused landing page for a fictional Perth mortgage & finance broking practice. Every visual is procedural; every dollar figure is computed by the page itself.

Concept

Latitude Lane Finance Co. is a fictional Subiaco broker for first-home buyers and refinancers who find banks opaque. The page has one job: book a free 15-minute call. The design argument is that on a finance page, honesty is the aesthetic — ledger paper, a banker's bottle-green, no hype, rates plainly labelled illustrative, and a fee section that explains exactly how brokers are paid.

Palette

Argued from ledger and trust, not defaults. Brass is a line-and-mark token only — it never sets body text (it fails 4.5:1 as small type on paper, so copy stays in the greens).

Ledger paper#F7F4EE the ground — warm, unhurried
Bottle-green ink#1E3A2F structure & primary ink — the banker's ledger green
Brass#A8863C LINE/MARK only — chart curves, rules, the gap band
Slate blue#41586E data, links, the river and coast on the map
Soft ink#43584C derived body-ink for secondary copy (≥4.5:1 on paper)
Deep green#16291F the demo band and code panels

Type

Source Serif 4 carries the display and longform — an editorial serif that reads like considered advice rather than a pitch. IBM Plex Sans does the working parts: labels, forms, figures (tabular numerals in every readout). The typographic bravery is restraint plus one italic — straight — sitting inside the headline, and the big serif numerals in the worked-example card.

Techniques & the signature

The Repayment Visualiser is a canvas-2D chart driven by three keyboard-accessible sliders (loan, rate, term). It computes standard principal-and-interest amortisation — M = P·i / (1−(1+i)−n) — and draws the balance curve at the chosen rate, a dashed brass curve at 0.50% lower, the shaded gap between them, and a measured annotation at the month of maximum divergence. Every displayed figure (monthly repayment, difference, total interest saved) comes from that live code path, never from copy. Slider changes tween the curves over 340ms (cubic ease-out); prefers-reduced-motion renders instantly. A pointer probe reads out year-by-year balances on hover; a static HTML table stands in when canvas is unavailable, guarded by [hidden]{display:none !important}.

Everything else is procedural too: the Perth service-area map is hand-plotted SVG (coastline, Swan River, twelve named suburbs, a dashed brass reach-ring centred on the Subiaco office), the hero's worked-example card draws its cumulative-interest curves from the same amortisation functions, and all iconography is inline stroke SVG in the two inks.

Conversion decisions

Local SEO we'd implement for the real business

This demo deliberately ships no LocalBusiness, Review, or AggregateRating structured data — fictional entities don't belong in a real search index; the page carries only WebPage schema naming itself a demonstration. For a real broking client we would ship:

<!-- real client only — never with fictional data -->
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": ["FinancialService", "LocalBusiness"],
  "name": "«Client trading name»",
  "url": "https://«domain»/",
  "telephone": "+61 8 «real number»",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "«street»",
    "addressLocality": "Subiaco",
    "addressRegion": "WA",
    "postalCode": "6008",
    "addressCountry": "AU"
  },
  "geo": { "@type": "GeoCoordinates",
           "latitude": -31.95, "longitude": 115.83 },
  "openingHoursSpecification": [{
    "@type": "OpeningHoursSpecification",
    "dayOfWeek": ["Monday","Tuesday","Wednesday",
                  "Thursday","Friday"],
    "opens": "08:30", "closes": "17:30"
  }],
  "areaServed": "Perth WA",
  "memberOf": { "@type": "Organization",
                "name": "MFAA" },
  "aggregateRating": { "@type": "AggregateRating",
    "ratingValue": "«from live review feed»",
    "reviewCount": "«count»" },
  "review": [{ "@type": "Review",
    "author": { "@type": "Person", "name": "«real client»" },
    "reviewRating": { "@type": "Rating", "ratingValue": "5" },
    "reviewBody": "«verified review text»" }]
}
</script>

Plus the usual: Google Business Profile linkage, suburb-intent FAQ markup, and per-service landing pages once the single-pager earns them.

What changes for the real client

Iteration log

Pass 1

Craft

Driving the page at 375×667 found the trust line first landing at 673px (below the fold), and after the first fix, at 625px — above the fold but under the 57px sticky bar. Tightened the hero rhythm (paddings, rule/eyebrow/sub margins, one-line trust copy) until CTA bottom measured 498px and the trust line cleared the bar. One CSS lesson caught here: a mobile media-query override was silently beaten by a later base rule at equal specificity — fixed with a scoped selector. Also darkened the map's "Indian Ocean" label from 4.4:1 to pass contrast, and strengthened the gap band between the curves from 16% to 30% alpha.

Measured at rest, $650,000 / 5.89% / 30yr: $3,851/mo vs $3,646/mo · difference $205/mo · interest saved $73,921 — each asserted equal to the amortisation formula computed independently in the harness.
Pass 2

Depth

Two honest-visualisation problems surfaced by screenshots, not asserts. First: at chart scale, the two balance curves nearly coincide — the measured maximum divergence at rest is $11,045 at year 19, about 5px, so the planned inline gap bracket never rendered (its threshold was 14px). Replaced it with an always-on measured annotation: a brass dot at the widest point and the figure floating in the open sky above the descending curve, with an inline bracket when the gap is genuinely wide. Second: the hero worked-example card's balance curves read as one line, so the card now plots cumulative interest paid, whose curves diverge to exactly the $73,921 saved — same code path, better geometry. Also added the pointer probe (year-by-year balances on hover) and the readout bump micro-interaction.

Driven to $800,000 / 5.50% / 25yr and asserted: $4,913/mo vs $4,677/mo · difference $236/mo · saved $70,794 — displayed values equal the formula; canvas screenshot hashes differ before/after the drive.
Pass 3

Hardening

Full driven suite, 39 asserts, all green: empty form submit flags all four fields and shows no confirmation; filled submit renders the local confirmation and hides the form; FAQ accordion driven open; sticky-bar targets ≥44px; scrollWidth exactly 375 with zero offenders; header tel: link in-viewport; the canvas fallback table asserted invisible while the canvas runs (the W10 [hidden] guard); reduced-motion emulated — hero settles visible and a driven slider recomputes instantly ($500,000 → $2,962/mo, verified). Zero console errors across desktop, mobile, and reduced-motion runs. Chanel rule: deleted the hero's decorative background curves at desktop widths — the worked-example card made them ornament.

Guide-drift check (W8): every number above was re-measured from the shipped code via the window.__broker probe after the final edit, not carried from an earlier draft.