STYLE.md ·
How Exhale works. Every rule, written down.
A pilates and yoga studio as a website. It has three pieces:
- A breathing pacer inside an arch. Its rings fill and settle in box, 4-7-8 or even breathing.
- A week timetable with day tabs, type and level filters, and bars that fill as classes book out. Full classes offer a waitlist.
- A pass finder. Slide to how often you'll come and it shows the cost per month and per class of every option, with the cheapest marked.
The look is Marcellus and Jost on linen, with moss ink and one terracotta clay.
Calm · clear · honest
Best for
- Pilates, reformer and yoga studios: class types by level, a timetable with spots left, intro offers, passes and memberships. Written to the fitness industry codes (see "Studios: what we build in").
- Anyone who runs a timetable and sells passes or terms:
- Swim schools (Deep End: breathe every three strokes, lessons by level, term or casual)
- Singing schools and choirs (Open Throat: breath for singers, choir nights)
- Barre, dance and climbing studios
- Meditation and breathwork
- Audiences: people who are new and a bit unsure, and want to know which class, when, and the cheapest way to come.
Less suited to: high-intensity gyms (Marquee); retail (Polish, Catalogue); anything loud.
Personality and voice
Calm, clear and honest, like a good teacher at the front desk: here's a class for where you're at, here's when, and here's what it really costs.
- Headlines: "Slow down, get stronger." · "Four ways to move." · "The cheapest way to come." · "What you'll pay, all of it."
- Buttons: "Book a class" · "Start here" · "Waitlist" · "Request the intro offer"
- Microcopy: "Try a minute of box breathing while you choose." · "Beginners welcome in every level-one class." · "Nothing renews."
- Words to avoid on a studio site:
- "cures", "heals" or "fixes your back", and any treatment claim
- "clinical pilates" unless a physio runs it
- "limited time" or "only today" pressure
- a "free" offer that hides its usual price
Colour
| Token | Morning (light) | Evening (dark) | Role |
|---|---|---|---|
--paper |
#f6f1e9 |
#141712 |
Linen; the evening room |
--card |
#fffdf9 |
#1d211b |
The arch, the pass finder |
--well |
#ede5d8 |
#181b16 |
Alternate sections |
--line |
#e0d6c6 |
#30352d |
Hairlines and the horizon |
--ink / --ink-2 |
#22281f / #444a40 |
#efeae0 / #d3cfc4 |
Moss text and the closing card |
--muted |
#5f6158 |
#a6a99c |
Labels |
--clay |
#9a4a32 |
#efa184 |
The one accent: buttons, links, the lit word, the selected day, best value |
--sage |
#4d6a4f |
#9cc39f |
Levels, spots left, term labels |
--sand |
#ecd9bf |
#3a3122 |
The warm highlight behind the breath, picked classes, the top line (background only) |
Measured contrast (WCAG):
- Morning:
- ink on paper 13.4:1
- muted on paper 5.6:1 (5.0:1 on well)
- clay on paper 5.5:1 (4.9:1 on its soft fill and on well)
- white on clay 6.2:1
- sage on paper 5.4:1
- ink on sand 11.0:1
- Evening:
- ink 15.1:1
- muted 7.6:1 (6.8:1 on card)
- clay 8.7:1
- text on clay 8.6:1
- clay on its soft fill 7.4:1
- sage 9.2:1
- Example dials on paper (light / dark):
- indigo (Deep End) 7.8:1 / 9.0:1
- wine (Open Throat) 8.5:1 / 9.2:1
- tide blue (Tidewater) 6.6:1 / 10.2:1
Typography
- Display: Marcellus, 400. Open, inscriptional and unhurried.
- Body: Jost, 300–600. A light geometric face for the timetable, prices and the big breath count.
| Token | Size | Use |
|---|---|---|
--fs-h1 |
clamp(44px, 6vw, 92px) | Page headline |
--fs-h2 |
clamp(32px, 3.9vw, 58px) | Section headline |
--fs-h3 |
22px | Card titles |
--fs-lead |
clamp(17.5px, 1.35vw, 20.5px) | Intro paragraphs |
--fs-body |
17px | Body |
--fs-label |
12.5px, wide caps | Eyebrows after a small arch (LS·01) |
The signature move: the lit word turns clay, and a long, tapering line draws out beneath it, like a breath out.
Layout
- A 1200px wrap with a gutter of
max(20px, 4vw). Above the header is a sand top line with the intro offer and its usual price, and the header itself is calm and sticky. - Hero: the copy sits on the left. On the right is the breath, inside a tall arch with a horizon line.
- Then:
- Class types as arch windows with a setting sun, each with its level
- The timetable
- The intro offer beside the pass finder
- Teachers in arch frames
- Visit facts and FAQ
- A moss closing card with a rising sun
Shape
- Arches everywhere:
--arch(fully round on top,--r-mat the bottom) frames the breath, class windows, teachers and even the day tabs. - Soft corners:
--r-sis 12px,--r-m22px and--r-l36px, and buttons are pills. - Levels: shown as three short bars in sage.
- The brand mark: a small arch with a clay sun setting into it.
Motion language
- The breath: the orb fills in time with the breath in, holds, then settles as you breathe out. Each phase lasts as long as the pattern says, and the count ticks once a second. It starts when it comes into view (where the page asks it to), pauses when the tab is hidden, and has a Start/Pause button.
- The timetable: spots-left bars fill slowly as they appear, and picked classes glow sand.
- The pass finder: "Best for you" moves as you slide.
- The lit word: its line draws out on load.
- Class windows: their suns rise on hover, and the closing card's sun rises and falls.
- Reveals: an 18px rise and fade over 900ms.
- Motion switch in the footer (
[data-motion-toggle],html.calm, remembered assite-motion, defaults fromprefers-reduced-motion). Calm stops the orb, rings and suns. The breath still counts if you press Start, and nothing starts by itself. - Evening switch (
[data-theme-toggle]), remembered assite-theme;theme-colorfollows.
Imagery and illustration
The arches are the pictures. Real photos of the room, the light and the teachers are welcome. Avoid photos that promise a body shape, and stock poses on cliffs.
Signature components
- The breath:
.breath[data-breath][data-auto][data-words]›.breath-arch›.orb(.fill,.ring.r1–r3) +.orb-core([data-breath-say],[data-breath-count]);.breath-ctrl(button[data-pattern="in,hold,out,rest"][data-words],[data-breath-toggle]),.breath-note. - The timetable:
.timetable[data-timetable]›.tt-days[role=tablist] > button[data-day],.tt-filters([data-tt-type],[data-tt-level]),ol.tt-list > li[data-day][data-type][data-level][data-spots][data-cap](time,b,.who,.meta > .lvl[data-l] + .spots,[data-tt-book]),[data-tt-none],[data-tt-out]. - The pass finder:
.passes[data-passes]›input.range[data-pass-n]+output[data-pass-n-out],ul.pass-list > li[data-pass="casual"|"pack"|"weekly"|"monthly"][data-price][data-size][data-months][data-limit][data-extra](b,small,.term,strong,.each),[data-passes-out]. - Supporting pieces:
.arch-card(.windowwith--tint).person(an arch.face).card(.pick).facts(.stack).notice,.topline,.faq,.licence.close-card(--close-em)
Multi-page kit
- Phone menu:
.menu-btn[aria-controls]opens.site-menu. Escape, an outside click or a link closes it, and Tab stays inside it while it's open. - Current page:
aria-current="page"gets a clay-soft pill. - Inner pages:
.page-head,.crumbs, a.tagand a smaller.h1. - Fields:
.field,.fields,.field-wide,fieldset.field-set,.check,.form-card,[aria-invalid="true"];form[data-template]. - Tiles:
.choices›label.choice > input + span > b + small. - Segmented control:
.seg. Filters work on[data-tags]. - Gate:
[data-gate]withbutton[data-show="panel-id"]. - Slider, switch, tables and layout:
input.range,.switch[role=switch],.table/.table.stack,.r,.grid-2.lean. - Events:
breath(detail.phase, seconds)pick(detail.name, day, time, who, waitlist, or null)passes(detail.perWeek, best, monthly)
- Helper:
Exhale.refresh(root).
Studios: what we build in
Fitness and group exercise memberships are covered by state codes (Queensland, WA, NSW and others) on top of the Australian Consumer Law. Here's what we checked in October 2026:
- The total, in plain English. Queensland's code requires a written, plain-English statement of the total fees for the membership (joining, membership and other fees). WA's code requires a summary of costs. The pass finder shows the monthly cost of every option, and the industry template includes a fee statement with the 12-month total.
- Ongoing or fixed-term, said clearly. Agreements must be labelled. In Queensland, members must be written to at least 2 months before an initial period ends. Each pass shows its term ("Ongoing · 2 weeks' notice", "Prepaid · expires after 3 months").
- Cooling-off. In Queensland it's 48 hours from signing (or from opening day), refunded within 14 days less services used. In WA it's 7 days. The industry template says which applies and how.
- No more than 12 months prepaid, and packs expire inside that.
- Medical cancellation. Members can end an agreement because of permanent sickness or injury.
- Intro offers show the usual price ("$45, usually $105"), and nothing renews by itself.
- No treatment claims. Classes are described as general exercise. "Clinical pilates" is only offered when a registered physiotherapist runs it (Ahpra's rules then apply to that page). The template also has a short pre-exercise check based on the Adult Pre-exercise Screening System, and pregnancy notes that send people to their doctor or midwife first.
These notes are design guidance, not legal advice.
Do and don't
- Do show the usual price next to any offer.
- Do label every pass ongoing, prepaid or fixed-term, with how to leave.
- Do mark levels on every class so beginners know where to start.
- Don't claim a class treats or cures anything.
- Don't pressure: no countdowns, no "only today".
- Don't set text on sand, except ink.
Accessibility
- General: AA contrast throughout (measured above), a skip link and a 3px focus ring.
- The breath: a labelled group with a pressed state on the pattern buttons and a real Start/Pause button. It doesn't auto-start with motion off, and pauses when the tab is hidden.
- The timetable:
- Day tabs are a tablist that responds to the arrow keys and has full date labels.
- Each level is a labelled image ("Level 1 of 3: Beginner").
- Spots left are written out in words.
- Booking buttons have a pressed state, and the pick is announced politely.
- The pass finder: a labelled slider whose result is announced politely.
- Forms: every field is labelled, errors are marked with
aria-invalid, and an alert says what's missing. - Testing: responsive to 360px, and tested with motion on and off, in Morning and Evening.
How to make it yours
| Dial | Range |
|---|---|
| Accent | Clay (default), indigo (Deep End), wine (Open Throat), tide blue (Tidewater). Set --clay, --clay-2, --clay-soft, --focus (plus --on-clay at night) and --close-em. |
| The breath | Any patterns (in, hold, out, rest seconds) with your own words: box, 4-7-8, every three strokes, singers' hiss. |
| Timetable | Your days, types, levels, capacities and spots. |
| Passes | Casual, packs with expiry, weekly with a limit and extra-class price, or monthly. |
| Not negotiable | Marcellus with the drawn line, the arches, the breath, the timetable with spots left, the pass finder, every price with its term, and the Motion switch. |



