One palette, one set of marks, one voice — behind the site, the emails, and the room.


Photography is the philosophy. Every image is real — our room, our water, our people. Authentic bathing, never stock.
Chromatic Pro carries the body. Seventy-five minutes of heat, cold, and rest — towels, lockers and amenities included. Just bring a swimsuit.
Peer-reviewed evidence sits behind every claim — see the research on cold immersion for sources.
Long-form pages cap their content at 62rem and centre it. Above the heading sits a page opener: an Orange Ink kicker and a Muted lede capped at 46ch. A single full-bleed photo band — 440px desktop, 260px phone — punctuates the page where the subject changes. One per page; it is punctuation, not a gallery.
Press logos sit at 22px — 17px on phones — in grayscale at 0.72 opacity, wrapped and centred between dotted rules under a Muted label. The footer carries a quiet legal line beneath its links: Muted at .85rem, underlined, 4.89:1 on Beige.
Raw Orange never carries text. It measures 2.66:1 on Beige and 3.04:1 on White — below AA at any size. Star ratings, the 190° figure and every kicker use Orange Ink. White text on an orange surface needs Orange Ink as the ground (5.49:1), not Orange (3.04:1).
Plunge is bright enough to defeat two tokens that pass everywhere else: Orange Ink is 4.30:1 on it and Muted is 4.37:1 — both fail. Plunge Ink is 5.20:1 and is the required ink there; body copy on a plunge ground should be Black.
Beige at low alpha on Forest was used for small labels across the sweepstakes pages. 0.40 measures 3.30:1 and 0.50 measures 4.39:1 — both fail. 0.75 (8.14:1) is the floor for any Beige-on-Forest label.
Labels at 8px and 9px were scattered through the splash pages. They are now 0.7rem (11.2px). Below that, uppercase type tracked at .22em stops being readable regardless of contrast — it is decorative, not informational.
/404, /401 and /llms-txt sat outside every audit because nothing links to them — and all three rendered in Arial. Webflow's stock utility markup carries no font-family, and /llms-txt was bare headings and paragraphs with no classes at all. Both utility pages also shipped with no h1.
Hours, prices, the address, session length — anything that appears on more than one surface — live in docs/facts.md in the repo. Copy them from there. The hours are Mon–Fri 7am–10pm, Sat–Sun 9am–10pm; a single session is $65 and memberships start at $140.




Considered, sensory, understated. A fact, then the feeling. Every line should have a temperature.
Live on /bookings and /membership. Replaces Arketa's seven-day scrolling embed with one day at a time, showing only sessions that can still be booked — nothing already started, nothing full. Specimens below use the real classes, so they change when the component changes.
The stock Arketa iframe stays in the page, hidden. If the schedule request fails the module removes itself and the iframe is what renders, so a failure looks like the old booking box rather than a broken page.
Day chip — default, selected, full
Band head
Slot chip — default, scarcity, Members, Aufguss
Rules. Remaining counts appear only at three or fewer — “9 left” on most chips is noise. Scarcity is Orange Ink; restricted sessions take the Plunge ground with a Plunge Ink tag. Sessions are grouped by time of day, never by Arketa's session type, because those types overlap in time and produce chips out of chronological order. Day numerals set lining figures: Louize's default oldstyle 1 reads as a Roman I.