Halfvalue · build guide

Industry demo 458 · radiation safety

How Halfvalue X-ray Compliance was built

Halfvalue is a fictional Leederville business that tests diagnostic x-ray units for dental, chiropractic and medical practices across Perth and Peel. Its customer is a practice manager holding a certificate that expires next autumn, and the page has one job: show which month to book so every unit keeps its anniversary, price the visit to the cent, and take the booking or the free reminder.

Palette: the trefoil, deepened to text strength

The radiation trefoil is magenta on yellow. Magenta darkened to #7A1F5C carries the CTA and the new certificate; the warning yellow stays a drawn fill only (the booking window, the tube-head sticker), never behind words. Every token sits only on a ground contrast-w60.log declares for it.

#F5F4F7bg, a surgery neutral
#FFFFFFsurface
#17151Cink · 16.52:1 on bg
#4E4A58muted · 7.84:1
#7A1F5Ctrefoil magenta · 8.80:1; white on it 9.64:1
#7A5A00warning ochre · 5.83:1
#221A2Cband · #F3EFF6 on it 14.77:1
#F5C400drawn fill only: window, trefoil

Colours minted during the build, measured by rs-check.mjs: tint #F8EFF5 (ink 16.08:1, magenta 8.57:1), soft #F0EDF3 (muted 7.41:1), map ocean #E6E2EC (muted 6.73:1), current-certificate bar #8A8398 (3.63:1 as a mark on white), field border #7D7788 (4.32:1).

Type

Onest 600/700 for headings and figures: a modern grotesque with round, open counters that reads like a well-made clinical form rather than a brochure. Albert Sans 400/500 for body copy at 16 px and up. Dates and prices use tabular numerals so “1 Mar 2030” and “$925.65” don’t shimmer when the estimator changes them.

The proof element: “Keep your anniversary”

Three steppers (intraoral 0–6, OPG or ceph 0–3, CBCT 0–2), the current expiry as month and year selects, and the month you’d like the test. The model works in month indices (year × 12 + month) with certificates expiring on the 1st, and applies the Radiological Council’s four-row anniversary table: dental units on 36 months, CBCT on 24.

InputOutput on the page
3 intraoral + 1 OPG, expiry Mar 2027, test Jan 2027 (the default)New expiry 1 Mar 2030, anniversary kept; $990 − $148.50 = $841.50 + $84.15 GST = $925.65
Same units, test Sep 2026“Wait — book from Dec 2026”, $0 today; testing then gives 1 Sep 2029, 6 months of cover given up
CBCT, expiry Mar 2027, test Jan 20271 Mar 2029
2 intraoral + 1 CBCT$940 − $141 = $799 + GST = $878.90
1 intraoral$240 + GST = $264.00, no multi-unit discount
Expiry Mar 2027, test Jul 2027Lapsed: 1 Mar 2030 kept, the offence sentence replaces the saving line, hatched “do not use on patients” zone
Expiry Mar 2027, test Jan 20281 Jan 2031, anniversary moves to January

The drawing is one inline SVG: a static intraoral tube head on its wall arm (yoke, housing, cone, a yellow trefoil sticker built from three annulus sectors) with a certificate tag whose date follows the model, beside one timeline bar per unit type. Each bar shows the current certificate, the three-month window shaded in yellow, a hatched lapse zone when the test falls after expiry, the new certificate in magenta, a dashed ghost for any months given up, and a diamond at the new expiry. Unit types not on the visit stay drawn at 40 % so the CBCT’s 24-month date is visible beside the dental 36. The bars grow once on load, driven by performance.now(), pausing while the tab is hidden and skipped entirely under reduced motion; the page is at rest well before the 7-second thumbnail.

Everything the card shows is exposed on window.__radiationsafety: inputs, the table row, months before or after expiry, each type’s new expiry and months given up, the itemised quote, today’s price, the $0 alternative with its isSubstitute flag and reason, and the text actually rendered.

One place this page disagrees with the wave oracle

figures-w60.mjs keeps the anniversary for a test in the month six months after expiry. With certificates expiring on the 1st, a test on any day of that month but the 1st is more than six months after expiry, so this page resets the date there and says a test on the 1st itself would still count. Across 4,800 expiry, test and interval combinations the two models agree on 4,720; the 80 differences are all at that month. Every worked example matches.

Where the page argues against its own sale

When the chosen month is more than three months early, the card stops selling: “Wait — book from Dec 2026”, $0 today, the months the early test would throw away, and a button that moves the test into the window. Inside the window the $0 option is still on screen, marked “Not a substitute” with the Council’s offence sentence as the reason. A full-width licence panel quotes the Council that AHPRA-registered dentists need no licence for intraoral, OPG or lateral ceph units, and that CBCT does, then ends on the $0 reminder.

Verified at source, 14 September 2026

What this page declined to publish

Anything about veterinary test cycles, Radiation Safety Officer or radiation management plan duties, registration or licence fees, the history of the CBCT interval, per-category test counts, and any claim about a unit being unable to remain in clinical use beyond the Council’s offence sentence. No advice about a specific unit’s result.

Conversion decisions

Why this converts

A practice manager lands wanting one answer, which month to book, and the estimator beside the headline gives it with the price in the same glance. The primary button finds that month and the second button offers a free reminder, so someone not ready to book still leaves their details. The form asks only what a tester needs and fills the units and expiry in from the estimator, so most visitors type four fields. When the visitor picks a month that is too early, the page tells them to wait and shows the months they would lose, and that single honest moment is what makes the price believable. The trust line and the licence panel quote the regulator rather than the business, which answers “can I trust these people” without a badge.

Local SEO we would implement for the real business

The demo page carries only WebPage markup naming it a demonstration. For the real client we would ship LocalBusiness data with their verified details and genuine reviews, like this sample:

{
  "@context": "https://schema.org",
  "@type": "ProfessionalService",
  "name": "Halfvalue X-ray Compliance",
  "url": "https://www.example.com.au/",
  "telephone": "+61 8 9000 0603",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "Suite 0, 00 Example Street",
    "addressLocality": "Leederville",
    "addressRegion": "WA",
    "postalCode": "6007",
    "addressCountry": "AU"
  },
  "areaServed": ["Perth metropolitan area", "Peel region"],
  "openingHours": "Mo-Fr 07:00-17:30",
  "hasOfferCatalog": {
    "@type": "OfferCatalog",
    "name": "X-ray compliance testing",
    "itemListElement": [
      { "@type": "Offer", "name": "Intraoral unit test", "price": "240.00", "priceCurrency": "AUD" },
      { "@type": "Offer", "name": "OPG or OPG-ceph test", "price": "270.00", "priceCurrency": "AUD" },
      { "@type": "Offer", "name": "CBCT unit test", "price": "460.00", "priceCurrency": "AUD" }
    ]
  }
}

Review markup would be added only from the client’s genuine reviews. Beyond the schema: one page per suburb cluster (northern suburbs, south-east, Rockingham and Peel), an FAQ page marked up from the real answers, and a Google Business Profile with the booking link.

What would change for the real client

Iteration log

Pass 1 · Craft

Pass 2 · Depth

Pass 3 · Hardening