DT.
DT.
Case study · 2026All work

Kryotera

A Greek-first B2B site for whole-body cryotherapy chambers.

Kryotera: Greek home page hero, whole-body cryotherapy down to −110 °C in ice blue, beside an eCham flow chamber in a dimly lit spa
Imagery: kryora.de (AI renders)

Kryotera is a Greek-first B2B site for ProseQ whole-body cryotherapy chambers. It began as Kryora, a Greek-market rebuild of kryora.de, and went live at kryotera.gr on 6 October 2026, with a working enquiry form and bilingual legal pages.

Role
Solo: direction, design, build
Year
2026
Status
Live
Stack
Next.js 16 · next-intl (EL/EN) · Tailwind v4 · CSS scroll-driven animation · Resend
Links
Live (opens in a new tab)

Context

The buyers are Greek businesses making a capital purchase: hotels, resorts and villas, sports clubs and physio practices, even yachts. The chambers go down to −110 °C for three-minute sessions, in six eCham models and a five-in-one vita cabin.

I set the direction, designed and built it solo: the front end in four days in late September 2026, the client’s new name and logo the day after, then the enquiry backend, the legal pages and the launch on 6 October. It runs on Next.js 16 with next-intl and Tailwind v4, and no animation library.

Problem

A buyer has three questions before a call: is this credible and safe, will it fit my space and my power supply, and what does the payback look like. The site’s job is to answer them plainly and turn the interest into a qualified enquiry, without promising returns.

−110 °C, counted in CSS.

Approach

  1. A direction grounded in references, critiqued into rules

    The direction came from Refero references for the mood, the hero and the navigation, and a design critique became audit rules the build follows: no section eyebrows or numbering, one label per call to action, nothing laid over images. The palette changed twice: from a cold cinematic look to Obsidian & Champagne, then, when the client’s logo arrived, to Ink & Ice, with navy-black surfaces and one ice-blue accent taken from the logo, never used as a fill.

  2. Greek done properly, from the typeface to the capitals

    The default display face had no Greek glyphs at all, so headings are set in Commissioner, from a Greek type designer, with Inter for body text. Greek capitals drop the tonos but keep the dialytika, so headings are uppercased on the server only, with toLocaleUpperCase('el'). Prices use hand-rolled formatters, because Intl.NumberFormat can differ between the server’s and the browser’s ICU data and break hydration.

  3. CSS-first motion; GSAP left out

    GSAP was rejected for its weight, its main-thread work and the layout shift its pin spacers cause. The −110 °C countdown animates a registered integer property through a CSS counter, gated on support and on reduced motion; browsers without scroll-driven animation get static layouts.

  4. A three-question model finder

    Venue type, sessions a day and power supply (230 V, 400 V or unsure) return the smallest model that fits, with a note when it needs three-phase power or the supply should be checked. Physio practices with 400 V get at least the clinic-grade model.

  5. An enquiry form that keeps what the visitor typed

    The form calls a server action from its submit handler, not through the form’s action prop, because React 19 resets uncontrolled inputs after a form action and a failed send would wipe the message. One hand-written validator for seven fields runs in the browser and again on the server, after a honeypot and Vercel BotID, so no validation library ships to the client. Resend delivers a branded email built from tables and hex colors, since mail apps don’t parse oklch. There is no auto-reply: it would let anyone make the site email any address.

  6. Search foundations, gated until launch

    Greek lives at the root and English under /en, with locale detection off so an English browser isn’t redirected away from Greek. Subpages have Greek slugs, per-page canonicals, hreflang and Open Graph, structured data without offers, and a sitemap. The preview stayed noindexed on three layers, and a guard in the Next config fails any indexable build until the legal pages are approved. Launching meant flipping that approval and setting two environment variables.

Uppercase, without the tonos.

Challenges

The first deploy returned 404 on every route: creating the Vercel project from the command line set its framework preset to Other, so nothing Next-shaped was built until the preset was pinned. On iOS, WebKit interpolated the countdown’s integer fractionally and it showed 0 until the value was rounded.

axe could not parse oklch colors, so its contrast checks came back incomplete while a zero-violation gate still passed; I sampled contrast from rendered pixels instead. The rebrand found another color trap: the build lowers the tokens to lab(), and on the way back to oklch Chrome dropped a low-chroma color’s hue but kept its chroma, so the navy-black header scrim rendered red until tints were mixed in oklab.

Launch day had its own. Unknown URLs such as /nope.php returned 500, not 404, because a not-found page inside a dynamic locale layout has no locale to render with, and only a production build showed it; turning dynamic params off and adding a global not-found page fixed it. Bot protection needed its path excluded from the i18n proxy, and deleting one translation key threw at render, because the home page’s structured data still read it, while tests, types and lint all passed.

Outcome

Kryotera has been live and open to search engines at kryotera.gr since 6 October 2026, the same day the client’s corrections shipped. Enquiries reach the client’s inbox through Resend; three test leads arrived, the last from the deployed site. Lint, typecheck, build and 53 Vitest tests pass.

Still open: a postal address for the legal pages, per-model prices and real installation photos. The scenes on the site, and on this page, are kryora.de’s AI renders.