Why this converts
The phone number and a "Hold a date" button sit in the header on every screen, and on a phone a bar at the bottom keeps both under the thumb, so nobody has to scroll back up to act.
The price appears before any contact: the event check sits beside the headline on a laptop, and it reads out the per-head rate, the guests charged, the deposit and the total as you move one slider.
The 12-guest minimum is stated above the total with the exact cost of the empty seats, and the cheaper public-class option is shown in every state, which is what makes the dearer private number believable.
The form asks only what the school needs to hold a date (who, how to reach them, day, head count, menu), with the company optional because gift buyers do not have one.
Trust comes from specifics a prospect can check against their own experience: a count of events cooked, a plan of the actual room, and a promise that the price on the page is the price on the invoice.
Palette
A white-tiled teaching kitchen, a tomato on the board and oil in the pan. The ground is tile rather than cream, so the hero carries a faint 48 px grout grid. Ratios for the declared tokens are pasted from contrast-w59.log; the colours minted during the build were measured the same way and are listed with the job they are allowed to do.
Type
DM Serif Display
Headings, the service prices and the event total. It has the warmth of a printed menu without tipping into a bistro pastiche, and its italic carries the one moment of typographic bravery: dinner you made in tomato.
Manrope 400 and 600
Body, controls and every small figure. It stays legible at 13 px in the card's result row and its tabular numerals keep the total from jittering as the slider moves.
The proof element: the event check
Three inputs: guests on a 6 to 44 slider, a menu chip (pasta $110, three-course $135, banquet $155 per head) and weekday or Saturday (+$15 per head). Private events charge for at least 12 guests and take a 25% deposit. Money is held in whole dollars and the deposit in cents, so $1,755 prints a $438.75 deposit rather than a rounded one. Benches are the guests divided by four, rounded up.
The drawing is a floor plan of the kitchen built once in SVG at load: the chef's bench at the front (with a tomato on the board for anyone who looks twice), eleven benches of four in two rows, a sink station in the twelfth slot and a door in the wall. Each render only swaps classes: guest seats fill tomato, seats paid for under the minimum get a dashed tomato ring, and the benches in use darken. The cold-load fill is a CSS transition staggered 18 ms per seat, so it runs on the wall clock, never replays on resize and is finished well before the 7-second thumbnail. window.__cookingschool exposes the inputs, per head, guests charged, total, deposit, benches, whether the minimum applied, the empty-seat cost, the public-class alternative with isSubstitute:false and its reason, the plan's seat counts and the form state.
| Worked example (figures-w59.mjs) | Charged | Total | Deposit | Benches | Public class instead |
|---|---|---|---|---|---|
| 8 guests, three-course, weekday | 12 × $135 | $1,620 | $405 | 2 | 8 × $125 = $1,000, $620 less |
| 20 guests, banquet, Saturday (the rest state) | 20 × $170 | $3,400 | $850 | 5 | 20 × $160 = $3,200, $200 less |
| 44 guests, pasta, weekday | 44 × $110 | $4,840 | $1,210 | 11 | 44 × $99 = $4,356, not seatable |
| 12 guests, pasta, weekday | 12 × $110 | $1,320 | $330 | 3 | 12 × $99 = $1,188, $132 less |
The $1,320 floor is the services grid's "private pasta workshop from"; three-course from $1,620 and banquet from $1,860 are the same 12-guest floor on the other menus.
Where the page argues against its own sale
The public class is printed under the total in every state, not only below 12 guests. Under the minimum it explains why it is cheaper (you pay for your 8 seats rather than 12), and it always says why it is not a substitute: a public class shares the room with other bookings, on the school's date and menu rather than yours. At 44 guests the reason changes, because 44 is every seat in the kitchen and no public class could seat that group. The minimum line offers something to do today: "Add 4 guests", because those seats are already paid for.
Iteration log
Each pass drove the page in headless Chrome: the slider, chips and form to the worked examples above, the form empty, with junk and filled, and the full 234-cell grid (39 guest counts × 3 menus × 2 days) through the page's own model against the figures script, with 0 cells disagreeing.
Pass 1: Craft
- The filled form would not submit when clicked. Mousedown on the button blurred the email field, blur validation cleared its message, the layout moved up and the mouseup landed beside the button. Messages now appear on submit and clear while the field is being corrected, with nothing validating on blur.
- At 1200 × 750 the total sat at 710 to 778 px, half out of the thumbnail. The plan's height came down from 236 to 212 units, the legend moved into the card header and the control gaps tightened; the total now ends at 725 px with the plan fully in frame.
- The card said 2 benches for 8 guests while the plan lit 3, because the highlight followed guests charged. It now follows the figures' definition, so the four paid, empty seats sit dashed on an unlit third bench.
- The hero eyebrow wrapped to two lines at 375 px and now drops the business name there, since the wordmark already carries it. The subline's italic was a synthetic slant of Manrope and is now set in DM Serif Display italic.
- The confirmation read "a $850 deposit"; reworded so the article never meets a figure.
Pass 2: Depth
- Added an "Add 4 guests" button on the minimum line. Driven at 8 guests, three-course, weekday: it jumps to 12 guests, the total stays $1,620 and the button disappears.
- At 11 guests the copy read in the plural; it now says "the 1 empty seat costs $155" and the button reads "Add 1 guest".
- The total gets a 260 ms settle when it changes. It is skipped on the cold draw and under reduced motion, so the 7-second thumbnail is never caught mid-animation.
- The plan's SVG title is rewritten on every change ("11 guests seated across 3 of 11 four-person benches") so a screen reader hears the drawing, not just the numbers.
Pass 3: Hardening
- At 375 px the 78 px label column squeezed the menu chips into three stacked rows; under 600 px each label now sits above its control.
- East Perth's map label crowded Perth CBD at 375 px and joined the labels hidden on phones. The rule's match count (5) is asserted, not assumed, and every suburb is still listed beside the map.
- Input borders measured 1.95:1 and chip borders 1.36:1 against white, under the 3:1 floor for form controls. Both now use the seat token at 3.57:1.
- Checked 320, 375, 768 and 1440 px for horizontal overflow; arrow keys on the menu chips wrap from banquet to pasta; keyboard focus shows a 3 px ring; reduced motion paints the seated plan immediately. Junk in the phone field ("ring me maybe") is refused by the script and by the native pattern, which compiles under the
vflag. - Chanel rule: removed the hairline above the hero's gift note. The note reads as an aside without it.
Conversion decisions
- Two CTAs, one job each. "Hold a date" goes to the form; "Price your event" goes to the check on a phone, where it sits below the services grid. On a laptop the check is already beside the headline.
- The minimum before the total. A buyer who learns about a 12-guest minimum on the invoice calls it a trick; one who reads it above the figure, with the empty seats priced, calls it fair.
- Book direct, argued without naming anyone. The page says what direct means (one contact, one invoice with your PO number, re-pricing on the same check) and leaves the comparison to the reader.
- A gift route in the hero. The second audience gets one sentence and a link to public seats from $99, so the private-event pitch never has to serve both.
- Confirmation that repeats the numbers. The confirmation restates the date, head count and the event check's total and deposit, and says nothing is booked until the deposit is paid.
Market band
Prices were argued from published Perth cooking-class rates, kept unattributed: from about $120 per person all-inclusive, $121 to $127 per person at 12 or more guests, and $170 per person with a 12-guest minimum and a 44-guest cap. Longbench's $110 to $155 per head, plus $15 on Saturday, sits inside that band.
What this page declined to publish
- No booking platform is named on the site and no commission figure appears anywhere.
- No food-safety, allergen-free, liquor licence or BYO claim. The dietary answer says what the kitchen handles and promises nothing; the drinks answer says "ask us".
- No travel times, parking claims or street address. The map shows distance rings only.
Local SEO we would implement for the real business
The live page carries only a WebPage block naming it a demonstration, because structured data about a fictional business in a real index is dishonest markup. For the real school we would ship the block below, with their verified details and reviews pulled from a real source.
{
"@context": "https://schema.org",
"@type": "LocalBusiness",
"additionalType": "https://schema.org/EducationalOrganization",
"name": "[Business name]",
"url": "https://[their-domain]/",
"telephone": "+61 8 0000 0000",
"priceRange": "$99–$170 per person",
"address": {
"@type": "PostalAddress",
"streetAddress": "[street address]",
"addressLocality": "Maylands",
"addressRegion": "WA",
"postalCode": "6051",
"addressCountry": "AU"
},
"openingHoursSpecification": [{
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
"opens": "09:00", "closes": "21:00"
}],
"makesOffer": [{
"@type": "Offer",
"name": "Private three-course cooking class",
"priceSpecification": { "@type": "UnitPriceSpecification", "price": 135, "priceCurrency": "AUD", "unitText": "per guest, 12-guest minimum" }
}],
"review": [{
"@type": "Review",
"author": { "@type": "Person", "name": "[Verified reviewer]" },
"reviewRating": { "@type": "Rating", "ratingValue": 5, "bestRating": 5 },
"reviewBody": "[Review text from their Google Business Profile]"
}]
}
Also for the real site: a Google Business Profile in the Maylands service area, one page per class type, and Event markup generated from their live timetable rather than typed by hand.
What changes for the real client
- Their booking system. The event check and the public-class dates would read availability from whatever they run, such as Bookwhen, Rezdy, FareHarbor or Square Appointments, so "Hold this date" can offer real open dates. The demo's four dates come from a fixed weekly timetable and claim no availability.
- Gift-voucher sales. The voucher tile becomes a real purchase through the same platform's voucher or gift-card product, sold straight from the page.
- Xero invoicing for corporate bookings. A confirmed enquiry creates the deposit invoice in Xero with the company's PO number, and the balance invoice seven days before the event, which is the "one invoice" promise made on the page.
- Their own proof. Photographs of their room replacing the drawn plan beside it, their event count, and reviews from their Google Business Profile in place of the demo copy.
- Their policies, verbatim. Cancellation, dietary handling and drinks answers written by the owner; the demo's wording is a placeholder for decisions only they can make.