Clara. Healthcare landing page.

A calm, accessibility-first healthcare homepage in soft clinical whites with a sage/teal accent and rounded geometry. A breathing gradient orb sits behind a working appointment widget (visit type, day chips, a highlight pill that springs between time slots, a confirm button that morphs through a spinner into a drawn check). A sticky care-journey story morphs one illustration through four steps; a phone mock plays a clinician chat; outcome stats count up; a fictional insurer marquee, clinician cards with gentle lift, a monthly/annual pricing toggle with rolling prices and FAQ accordions round it out. AA+ contrast, 44px+ targets, full keyboard support and reduced-motion paths.

  • Breathing gradient orb
  • Spring time-slot picker
  • Sticky morphing storytelling
  • Count-up stats
  • Logo marquee
  • Pricing roll toggle
  • Accordion FAQ
Full screen

The preview is interactive — scroll inside it to run the animations.

The whole page. One file, nothing left out.

1,258 lines · 81.7 KB · imports React only. This is the exact file behind the preview above — every section, interaction and style.

  1. 01Save it as clara-health.tsx in any React 18+ project.
  2. 02Render <Page /> on a route of its own — it brings its own nav and footer.
  3. 03Swap the copy and tokens. Keep the DESIGN.md next to it so your AI agent follows the system.
clara-health.tsx
1/**
2 * Clara — modern primary care & virtual clinic.
3 *
4 * Calm, accessible healthcare homepage: soft clinical whites, a sage/teal
5 * accent, rounded geometry and a friendly rounded sans. Everything is
6 * procedural (CSS gradients + inline SVG) — no images, no web fonts.
7 *
8 * Motion
9 * - Breathing gradient orb behind the hero (8s inhale/exhale, follows the pointer).
10 * - Booking widget: visit-type switch, day chips, and a highlight pill that
11 * springs between time slots; confirm button morphs into a drawn check.
12 * - Sticky care-journey storytelling: 4 steps; the illustration is built from
13 * the same 7 primitives that morph between "phone", "video call",
14 * "care plan" and "follow-up chat".
15 * - Virtual-visit phone mock whose messages arrive in sequence.
16 * - Count-up outcome stats, insurance marquee, clinician cards with gentle
17 * lift, monthly/annual pricing toggle with rolling prices, FAQ accordions.
18 *
19 * Accessibility: AA+ contrast, 44px+ targets, real buttons/radios/regions,
20 * aria-live for booking + pricing, visible focus rings, reduced-motion paths
21 * (no orb breathing, no marquee, no count-up, instant morphs).
22 * SSR-safe: no window/document access during render.
23 */
24import { useEffect, useRef, useState, type CSSProperties } from "react";
25
26/* ------------------------------------------------------------------ */
27/* Data */
28/* ------------------------------------------------------------------ */
29const DAYS = [
30 { key: "mon", dow: "Mon", date: "3", label: "Monday 3 November" },
31 { key: "tue", dow: "Tue", date: "4", label: "Tuesday 4 November" },
32 { key: "wed", dow: "Wed", date: "5", label: "Wednesday 5 November" },
33 { key: "thu", dow: "Thu", date: "6", label: "Thursday 6 November" },
34 { key: "fri", dow: "Fri", date: "7", label: "Friday 7 November" },
35];
36const TIMES = ["8:20", "9:00", "9:40", "10:40", "11:20", "1:00", "2:20", "3:40", "4:40"];
37/** Deterministic availability so SSR and client agree. */
38const isFree = (day: number, t: number) => ((day * 7 + t * 5) % 11) % 4 !== 0;
39
40const INSURERS = [
41 { name: "Bluefield Health", glyph: "leaf" },
42 { name: "Cascadia Mutual", glyph: "wave" },
43 { name: "Harbor & Pine", glyph: "pine" },
44 { name: "Meridian Care", glyph: "sun" },
45 { name: "Solace Assurance", glyph: "ring" },
46 { name: "Evergreen PPO", glyph: "leaf" },
47 { name: "Union Lakes", glyph: "wave" },
48 { name: "Atlas Benefit", glyph: "ring" },
49] as const;
50
51const SERVICES = [
52 { t: "Annual physicals", d: "A full hour with your clinician, labs drawn on site, results explained the same week.", icon: "heart", wide: true },
53 { t: "Chronic care", d: "Diabetes, hypertension and asthma plans with check-ins between visits.", icon: "pulse" },
54 { t: "Mental health", d: "Therapy and medication management, in person or by video.", icon: "mind" },
55 { t: "Women's health", d: "Contraception, menopause care and cervical screening.", icon: "flower" },
56 { t: "On-site labs", d: "Bloodwork in the room — most results within 24 hours.", icon: "drop" },
57 { t: "Same-day sick visits", d: "Colds, UTIs, rashes and sprains, usually seen within the hour.", icon: "clock", wide: true },
58] as const;
59
60const STEPS = [
61 { k: "Book", t: "Pick a time that fits your day", d: "See real availability across all six clinics and video. Most members book a same- or next-day visit in under a minute — no phone tree, no hold music." },
62 { k: "Meet", t: "Unhurried time with one clinician", d: "Visits are 30 minutes, not 7. Meet in person or on video with the same doctor who knows your history, your meds and how you like to be spoken to." },
63 { k: "Plan", t: "A plan you can actually follow", d: "Leave with a written care plan in the app: what we found, what we're testing, what to take, and what “better” should feel like by when." },
64 { k: "Follow up", t: "We check in, so you don't have to chase", d: "Your care team messages you after labs, before refills and at the milestones in your plan. Replies from a clinician within 2 hours, 7am–9pm." },
65];
66
67const STATS = [
68 { v: 4, suffix: " min", label: "Average wait in our waiting rooms", dec: 0 },
69 { v: 92, suffix: "%", label: "Members seen same or next day", dec: 0 },
70 { v: 4.9, suffix: "", label: "Average rating from 18,400 visit reviews", dec: 1 },
71 { v: 31, suffix: "%", label: "Fewer ER visits among chronic-care members", dec: 0 },
72];
73
74const LOOK: Record<string, string> = { p1: "a woman with a gray bob", p2: "a bearded man with dark hair", p3: "a woman with braided hair", p4: "a man with short curly hair", p5: "a smiling man with a short beard", p6: "a woman with long wavy dark hair", p7: "a bearded man in round glasses", p8: "a smiling man with swept-back hair", p9: "a woman with natural curly hair" };
75const portraitAlt = (n: string, r: string, src: string) => `${n}, ${r}: portrait of ${LOOK[src.match(/p\d/)?.[0] ?? ""] ?? "a person"} in a black sweater`;
76
77const CLINICIANS = [
78 { name: "Dr. Amara Osei", role: "Family medicine, MD", langs: "English, Twi, French", next: "Today 3:40 pm", img: "/img/people/p3.webp" },
79 { name: "Dr. Lena Park", role: "Internal medicine, MD", langs: "English, Korean", next: "Tomorrow 9:00 am", img: "/img/people/p6.webp" },
80 { name: "Mateo Ruiz, PA-C", role: "Urgent & sick visits", langs: "English, Spanish", next: "Today 1:00 pm", img: "/img/people/p8.webp" },
81 { name: "Dr. Ruth Adler", role: "Psychiatry, MD", langs: "English, German, Hebrew", next: "Thu 6 Nov, 10:40 am", img: "/img/people/p1.webp" },
82] as const;
83
84const PLANS = [
85 { name: "Pay per visit", monthly: 0, annual: 0, visit: "No membership fee", note: "We bill your insurance first; self-pay is $129.", feats: ["In-person & video visits", "On-site labs at cost", "Care plan in the app"], cta: "Book a visit" },
86 { name: "Clara Membership", monthly: 19, annual: 199, visit: "$0 primary-care visits", note: "Most members — it pays for itself at two visits.", feats: ["Unlimited primary-care visits", "Message a clinician 7am–9pm", "Same- or next-day booking", "Annual physical with full panel"], cta: "Start membership", featured: true },
87 { name: "Family", monthly: 49, annual: 499, visit: "Up to 5 people", note: "Kids 2+ and partners on one plan.", feats: ["Everything in Membership", "Pediatric well visits", "One shared family inbox"], cta: "Cover your family" },
88];
89
90const FAQ = [
91 { q: "Do you take my insurance?", a: "We're in network with most major PPO and HMO plans in Washington and Oregon, including all eight shown above. Without insurance, a visit is $129 and labs are billed at cost. Check your plan at booking — it takes about ten seconds." },
92 { q: "What does the membership actually cover?", a: "Unlimited primary-care visits in person or by video, messaging with your care team, and an annual physical with a full lab panel. Specialist referrals, imaging and prescriptions are billed to your insurance as usual." },
93 { q: "Can I keep the same clinician?", a: "Yes. You choose a primary clinician when you join and can switch at any time. When they're away, someone on the same small care team who has read your chart will see you." },
94 { q: "Is a video visit as good as coming in?", a: "For many things — follow-ups, medication changes, mental health, rashes, colds — yes. If your clinician needs to examine you or draw labs, they'll book an in-clinic slot that day at no extra cost." },
95 { q: "What if it's an emergency?", a: "Clara is not an emergency service. If you have chest pain, trouble breathing, signs of stroke or a severe injury, call 911 or go to the nearest emergency room." },
96];
97
98/* ------------------------------------------------------------------ */
99/* Small pieces */
100/* ------------------------------------------------------------------ */
101function Icon({ name }: { name: string }) {
102 const p = { fill: "none", stroke: "currentColor", strokeWidth: 1.7, strokeLinecap: "round" as const, strokeLinejoin: "round" as const };
103 let g = null;
104 if (name === "heart") g = <path {...p} d="M12 20s-7-4.4-7-10a4 4 0 0 1 7-2.6A4 4 0 0 1 19 10c0 5.6-7 10-7 10Z" />;
105 else if (name === "pulse") g = <path {...p} d="M3 12h4l2-5 4 10 2-5h6" />;
106 else if (name === "mind") g = <><path {...p} d="M8.5 19v-2.5A6.5 6.5 0 1 1 18 11c0 1.2.8 1.6 1.5 2.5L18 15v2a2 2 0 0 1-2 2h-1.5" /><path {...p} d="M10 9.5a2 2 0 1 1 3 1.7c-.6.4-1 .8-1 1.6" /></>;
107 else if (name === "flower") g = <><circle {...p} cx="12" cy="10" r="2.4" /><path {...p} d="M12 7.6C12 4 9 4 9 6s1.6 3 3 4c1.4-1 3-2 3-4s-3-2-3 1.6ZM9.6 10C6 10 6 13 8 13s3-1.6 4-3M14.4 10c3.6 0 3.6 3 1.6 3s-3-1.6-4-3M12 12.4V20" /></>;
108 else if (name === "drop") g = <path {...p} d="M12 3.5s6 6.4 6 10.5a6 6 0 0 1-12 0c0-4.1 6-10.5 6-10.5Z M9.5 14.5a2.5 2.5 0 0 0 2.5 2.5" />;
109 else if (name === "clock") g = <><circle {...p} cx="12" cy="12" r="8" /><path {...p} d="M12 7.5V12l3 2" /></>;
110 else if (name === "video") g = <><rect {...p} x="3" y="6.5" width="12.5" height="11" rx="3" /><path {...p} d="m15.5 10.5 5-3v9l-5-3" /></>;
111 else if (name === "pin") g = <><path {...p} d="M12 21s-6.5-5.6-6.5-11a6.5 6.5 0 0 1 13 0C18.5 15.4 12 21 12 21Z" /><circle {...p} cx="12" cy="10" r="2.3" /></>;
112 else if (name === "check") g = <path {...p} d="m5 12.5 4.5 4.5L19 7.5" />;
113 else if (name === "arrow") g = <path {...p} d="M5 12h14m-5-5 5 5-5 5" />;
114 else if (name === "plus") g = <path {...p} d="M12 5v14M5 12h14" />;
115 return (
116 <svg className="cl-ico" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
117 {g}
118 </svg>
119 );
120}
121
122function InsurerMark({ name, glyph }: { name: string; glyph: string }) {
123 const s = { fill: "none", stroke: "currentColor", strokeWidth: 1.8, strokeLinecap: "round" as const };
124 return (
125 <span className="cl-ins">
126 <svg viewBox="0 0 28 28" aria-hidden="true" focusable="false">
127 {glyph === "leaf" && <path {...s} d="M6 22C6 11 12 6 22 6c0 10-5 16-16 16Zm0 0 9-9" />}
128 {glyph === "wave" && <path {...s} d="M3 11c3-3 5-3 8 0s5 3 8 0 5-3 6-1M3 18c3-3 5-3 8 0s5 3 8 0 5-3 6-1" />}
129 {glyph === "pine" && <path {...s} d="M14 3 6 15h5l-4 6h14l-4-6h5L14 3Zm0 18v4" />}
130 {glyph === "sun" && <><circle {...s} cx="14" cy="14" r="5" /><path {...s} d="M14 3v3M14 22v3M3 14h3M22 14h3M6.2 6.2l2.1 2.1M19.7 19.7l2.1 2.1M6.2 21.8l2.1-2.1M19.7 8.3l2.1-2.1" /></>}
131 {glyph === "ring" && <><circle {...s} cx="11" cy="14" r="7" /><circle {...s} cx="17" cy="14" r="7" /></>}
132 </svg>
133 {name}
134 </span>
135 );
136}
137
138/** Morphing care-journey illustration: 7 primitives, 4 layouts. */
139type Prim = { x: number; y: number; w: number; h: number; r: number; bg: string; o?: number; rot?: number };
140const MORPH: Prim[][] = [
141 // 0 Book — phone with calendar rows and a chosen slot
142 [
143 { x: 150, y: 40, w: 220, h: 400, r: 36, bg: "#FFFFFF" },
144 { x: 178, y: 92, w: 164, h: 54, r: 14, bg: "#E4EFEA" },
145 { x: 178, y: 162, w: 76, h: 44, r: 22, bg: "#EEF2F1" },
146 { x: 266, y: 162, w: 76, h: 44, r: 22, bg: "#1F6F68" },
147 { x: 178, y: 220, w: 76, h: 44, r: 22, bg: "#EEF2F1" },
148 { x: 266, y: 220, w: 76, h: 44, r: 22, bg: "#EEF2F1" },
149 { x: 178, y: 370, w: 164, h: 46, r: 23, bg: "#0F2420" },
150 ],
151 // 1 Meet — video call: screen, clinician, self-view, controls
152 [
153 { x: 40, y: 80, w: 440, h: 300, r: 32, bg: "#FFFFFF" },
154 { x: 60, y: 100, w: 400, h: 220, r: 22, bg: "#DCEBE4" },
155 { x: 205, y: 140, w: 110, h: 110, r: 55, bg: "#C48A62" },
156 { x: 360, y: 230, w: 82, h: 72, r: 14, bg: "#1F6F68" },
157 { x: 205, y: 330, w: 40, h: 40, r: 20, bg: "#EEF2F1" },
158 { x: 275, y: 330, w: 40, h: 40, r: 20, bg: "#E26D5A" },
159 { x: 165, y: 236, w: 190, h: 84, r: 60, bg: "#2C6E67" },
160 ],
161 // 2 Plan — care-plan document with checklist
162 [
163 { x: 110, y: 40, w: 300, h: 400, r: 28, bg: "#FFFFFF" },
164 { x: 140, y: 72, w: 150, h: 22, r: 11, bg: "#0F2420" },
165 { x: 140, y: 130, w: 26, h: 26, r: 13, bg: "#1F6F68" },
166 { x: 180, y: 134, w: 190, h: 18, r: 9, bg: "#E4EFEA" },
167 { x: 140, y: 182, w: 26, h: 26, r: 13, bg: "#1F6F68" },
168 { x: 180, y: 186, w: 150, h: 18, r: 9, bg: "#E4EFEA" },
169 { x: 140, y: 250, w: 240, h: 150, r: 18, bg: "#F3E3D3" },
170 ],
171 // 3 Follow up — chat bubbles + heart
172 [
173 { x: 60, y: 60, w: 400, h: 360, r: 36, bg: "#FFFFFF" },
174 { x: 90, y: 96, w: 230, h: 60, r: 24, bg: "#EEF2F1" },
175 { x: 90, y: 176, w: 40, h: 40, r: 20, bg: "#C48A62" },
176 { x: 200, y: 176, w: 230, h: 60, r: 24, bg: "#1F6F68" },
177 { x: 90, y: 256, w: 180, h: 60, r: 24, bg: "#EEF2F1" },
178 { x: 90, y: 340, w: 58, h: 34, r: 17, bg: "#E4EFEA" },
179 { x: 340, y: 300, w: 80, h: 80, r: 40, bg: "#E26D5A" },
180 ],
181];
182
183/* ------------------------------------------------------------------ */
184/* Page */
185/* ------------------------------------------------------------------ */
186export function Page() {
187 const rootRef = useRef<HTMLDivElement>(null);
188 const slotsRef = useRef<HTMLDivElement>(null);
189 const [scrolled, setScrolled] = useState(false);
190 const [menuOpen, setMenuOpen] = useState(false);
191 const [mode, setMode] = useState<"clinic" | "video">("clinic");
192 const [day, setDay] = useState(0);
193 const [slot, setSlot] = useState<number | null>(3);
194 const [pill, setPill] = useState<{ x: number; y: number; w: number; h: number } | null>(null);
195 const [booking, setBooking] = useState<"idle" | "busy" | "done">("idle");
196 const [step, setStep] = useState(0);
197 const [annual, setAnnual] = useState(false);
198 const [open, setOpen] = useState<number | null>(0);
199 const [counts, setCounts] = useState<number[]>(STATS.map((s) => s.v));
200 const [chatIn, setChatIn] = useState(false);
201
202 const slotFree = (t: number) => isFree(day, t) && !(mode === "video" && t === 0);
203 const slotLabel = slot !== null ? `${TIMES[slot]} ${slot < 5 ? "am" : "pm"}` : "";
204 const firstFree = TIMES.findIndex((_, t) => slotFree(t));
205
206 // Move the highlight pill onto the selected slot (measured, so it works at any width).
207 useEffect(() => {
208 const grid = slotsRef.current;
209 if (!grid || slot === null) {
210 setPill(null);
211 return;
212 }
213 const measure = () => {
214 const b = grid.querySelector<HTMLElement>(`[data-slot="${slot}"]`);
215 if (b) setPill({ x: b.offsetLeft, y: b.offsetTop, w: b.offsetWidth, h: b.offsetHeight });
216 };
217 measure();
218 const win = grid.ownerDocument.defaultView;
219 const ro = win && "ResizeObserver" in win ? new win.ResizeObserver(measure) : null;
220 ro?.observe(grid);
221 return () => ro?.disconnect();
222 }, [slot, day, mode]);
223
224 // Keep the selection valid when day/mode changes.
225 useEffect(() => {
226 if (slot !== null && !slotFree(slot)) setSlot(firstFree >= 0 ? firstFree : null);
227 setBooking("idle");
228 // eslint-disable-next-line react-hooks/exhaustive-deps
229 }, [day, mode]);
230
231 // Scroll: nav state + active story step + pointer-follow orb + reveals + counters + chat.
232 useEffect(() => {
233 const root = rootRef.current;
234 if (!root) return;
235 const doc = root.ownerDocument;
236 const win = doc.defaultView;
237 if (!win) return;
238 const reduce = win.matchMedia("(prefers-reduced-motion: reduce)").matches;
239 root.classList.add("cl-js");
240
241 // Hosts that set overflow:hidden on BOTH <html> and <body> turn <body> into a
242 // scroll container that never scrolls, which silently breaks position:sticky.
243 // `clip` looks identical without that side effect; restored on unmount.
244 let restoreBody: (() => void) | null = null;
245 const fixRaf = win.requestAnimationFrame(() => {
246 const b = doc.body;
247 const bs = win.getComputedStyle(b);
248 const hs = win.getComputedStyle(doc.documentElement);
249 if (hs.overflowX !== "visible" && (bs.overflowX === "hidden" || bs.overflowY === "auto")) {
250 const prev = [b.style.overflowX, b.style.overflowY];
251 b.style.overflowX = "clip";
252 b.style.overflowY = "visible";
253 restoreBody = () => {
254 b.style.overflowX = prev[0];
255 b.style.overflowY = prev[1];
256 };
257 }
258 });
259
260 const steps = Array.from(root.querySelectorAll<HTMLElement>("[data-cl-step]"));
261 let raf = 0;
262 let lastS = false;
263 let lastStep = -1;
264 const update = () => {
265 raf = 0;
266 const y = win.scrollY || doc.documentElement.scrollTop;
267 const s = y > 16;
268 if (s !== lastS) {
269 lastS = s;
270 setScrolled(s);
271 }
272 const mid = win.innerHeight * 0.55;
273 let best = 0;
274 let bestD = Infinity;
275 steps.forEach((el, i) => {
276 const r = el.getBoundingClientRect();
277 const d = Math.abs(r.top + r.height / 2 - mid);
278 if (d < bestD) {
279 bestD = d;
280 best = i;
281 }
282 });
283 if (best !== lastStep) {
284 lastStep = best;
285 setStep(best);
286 }
287 };
288 const onScroll = () => {
289 if (!raf) raf = win.requestAnimationFrame(update);
290 };
291 update();
292 win.addEventListener("scroll", onScroll, { passive: true });
293 win.addEventListener("resize", onScroll);
294
295 // Orb follows the pointer with a critically-damped lerp.
296 const orb = root.querySelector<HTMLElement>(".cl-orb");
297 let tx = 0, ty = 0, cx = 0, cy = 0, orbRaf = 0;
298 const tick = () => {
299 cx += (tx - cx) * 0.06;
300 cy += (ty - cy) * 0.06;
301 orb?.style.setProperty("--mx", cx.toFixed(2));
302 orb?.style.setProperty("--my", cy.toFixed(2));
303 orbRaf = Math.abs(tx - cx) + Math.abs(ty - cy) > 0.01 ? win.requestAnimationFrame(tick) : 0;
304 };
305 const onMove = (e: PointerEvent) => {
306 if (reduce || e.pointerType !== "mouse") return;
307 tx = (e.clientX / win.innerWidth - 0.5) * 2;
308 ty = (e.clientY / win.innerHeight - 0.5) * 2;
309 if (!orbRaf) orbRaf = win.requestAnimationFrame(tick);
310 };
311 win.addEventListener("pointermove", onMove, { passive: true });
312
313 // Reveals.
314 const io = new win.IntersectionObserver(
315 (es) => es.forEach((e) => {
316 if (e.isIntersecting) {
317 e.target.classList.add("is-in");
318 io.unobserve(e.target);
319 }
320 }),
321 { rootMargin: "0px 0px -10% 0px", threshold: 0.15 },
322 );
323 root.querySelectorAll("[data-cl-rv]").forEach((el) => io.observe(el));
324
325 // Count-up stats (armed only when JS runs and motion is allowed).
326 const statsEl = root.querySelector(".cl-stats");
327 let countRaf = 0;
328 let sio: IntersectionObserver | null = null;
329 if (!reduce && statsEl) {
330 setCounts(STATS.map(() => 0));
331 sio = new win.IntersectionObserver(
332 (es) => {
333 if (!es[0].isIntersecting) return;
334 sio?.disconnect();
335 const t0 = win.performance.now();
336 const run = (now: number) => {
337 const k = Math.min(1, (now - t0) / 1800);
338 const e = 1 - Math.pow(1 - k, 4);
339 setCounts(STATS.map((s) => s.v * e));
340 if (k < 1) countRaf = win.requestAnimationFrame(run);
341 };
342 countRaf = win.requestAnimationFrame(run);
343 },
344 { threshold: 0.4 },
345 );
346 sio.observe(statsEl);
347 }
348
349 // Chat mock plays when visible.
350 const phone = root.querySelector(".cl-phone");
351 const pio = new win.IntersectionObserver(
352 (es) => {
353 if (es[0].isIntersecting) {
354 setChatIn(true);
355 pio.disconnect();
356 }
357 },
358 { threshold: 0.35 },
359 );
360 if (phone) pio.observe(phone);
361
362 return () => {
363 win.cancelAnimationFrame(fixRaf);
364 restoreBody?.();
365 if (raf) win.cancelAnimationFrame(raf);
366 if (orbRaf) win.cancelAnimationFrame(orbRaf);
367 if (countRaf) win.cancelAnimationFrame(countRaf);
368 win.removeEventListener("scroll", onScroll);
369 win.removeEventListener("resize", onScroll);
370 win.removeEventListener("pointermove", onMove);
371 io.disconnect();
372 sio?.disconnect();
373 pio.disconnect();
374 root.classList.remove("cl-js");
375 };
376 }, []);
377
378 const book = () => {
379 if (slot === null || booking !== "idle") return;
380 setBooking("busy");
381 const win = rootRef.current?.ownerDocument.defaultView;
382 win?.setTimeout(() => setBooking("done"), 900);
383 };
384
385 const onSlotKey = (e: React.KeyboardEvent<HTMLDivElement>) => {
386 if (!["ArrowRight", "ArrowLeft", "ArrowDown", "ArrowUp"].includes(e.key)) return;
387 e.preventDefault();
388 const free = TIMES.map((_, t) => t).filter(slotFree);
389 const cur = Math.max(0, free.indexOf(slot ?? free[0]));
390 const delta = e.key === "ArrowRight" ? 1 : e.key === "ArrowLeft" ? -1 : e.key === "ArrowDown" ? 3 : -3;
391 const next = free[Math.min(free.length - 1, Math.max(0, cur + delta))];
392 setSlot(next);
393 setBooking("idle");
394 const btn = slotsRef.current?.querySelector<HTMLElement>(`[data-slot="${next}"]`);
395 btn?.focus();
396 };
397
398 const nav = ["Services", "How it works", "Clinicians", "Pricing", "FAQ"];
399 const navId = (l: string) => "cl-" + l.toLowerCase().replace(/\s/g, "-");
400
401 return (
402 <div ref={rootRef} className="cl">
403 <style>{css}</style>
404 <a className="cl-skip" href="#cl-main">Skip to content</a>
405
406 {/* NAV */}
407 <header className={`cl-nav${scrolled ? " is-scrolled" : ""}${menuOpen ? " is-open" : ""}`}>
408 <div className="cl-nav-in">
409 <a href="#cl-top" className="cl-logo" aria-label="Clara Health — home">
410 <span className="cl-logo-mark" aria-hidden="true"><i /><i /></span>
411 clara
412 </a>
413 <nav className="cl-nav-links" aria-label="Primary">
414 {nav.map((l) => <a key={l} href={`#${navId(l)}`}>{l}</a>)}
415 </nav>
416 <div className="cl-nav-end">
417 <a href="#cl-top" className="cl-nav-sign">Sign in</a>
418 <a href="#cl-book" className="cl-btn cl-btn-primary cl-btn-sm">Book a visit</a>
419 <button type="button" className="cl-burger" aria-expanded={menuOpen} aria-label={menuOpen ? "Close menu" : "Open menu"} onClick={() => setMenuOpen((o) => !o)}>
420 <span /><span />
421 </button>
422 </div>
423 </div>
424 <div className="cl-sheet" hidden={!menuOpen}>
425 {nav.map((l) => <a key={l} href={`#${navId(l)}`} onClick={() => setMenuOpen(false)}>{l}</a>)}
426 <a href="#cl-top" onClick={() => setMenuOpen(false)}>Sign in</a>
427 </div>
428 </header>
429
430 <main id="cl-main">
431 {/* HERO */}
432 <section id="cl-top" className="cl-hero" aria-labelledby="cl-hero-title">
433 <div className="cl-orb" aria-hidden="true">
434 <span className="cl-orb-a" />
435 <span className="cl-orb-b" />
436 <span className="cl-orb-c" />
437 </div>
438 <div className="cl-wrap cl-hero-grid">
439 <div className="cl-hero-copy">
440 <p className="cl-badge"><span className="cl-dot" aria-hidden="true" /> Open today until 8 pm · 6 clinics in Seattle & Portland</p>
441 <h1 id="cl-hero-title" className="cl-h1">Primary care that has time for you.</h1>
442 <p className="cl-lede">Thirty-minute visits with a clinician who knows you — in clinic or on video, usually the same day. Most insurance accepted; $19 a month for everything else.</p>
443 <div className="cl-hero-ctas">
444 <a href="#cl-book" className="cl-btn cl-btn-primary">Find a time <Icon name="arrow" /></a>
445 <a href="#cl-pricing" className="cl-btn cl-btn-ghost">See membership</a>
446 </div>
447 <ul className="cl-hero-proof">
448 <li><strong>4.9</strong> from 18,400 reviews</li>
449 <li><strong>2 h</strong> clinician reply time</li>
450 <li><strong>In network</strong> with 40+ plans</li>
451 </ul>
452 </div>
453
454 {/* BOOKING WIDGET */}
455 <div id="cl-book" className="cl-widget" aria-labelledby="cl-widget-title">
456 <div className="cl-widget-head">
457 <h2 id="cl-widget-title" className="cl-widget-title">Book a visit</h2>
458 <div className="cl-seg" role="radiogroup" aria-label="Visit type">
459 {(["clinic", "video"] as const).map((m) => (
460 <button key={m} type="button" role="radio" aria-checked={mode === m} className={mode === m ? "is-on" : ""} onClick={() => setMode(m)}>
461 <Icon name={m === "clinic" ? "pin" : "video"} />
462 {m === "clinic" ? "In clinic" : "Video"}
463 </button>
464 ))}
465 <span className="cl-seg-thumb" style={{ transform: `translateX(${mode === "clinic" ? 0 : 100}%)` }} aria-hidden="true" />
466 </div>
467 </div>
468 <p className="cl-widget-where">{mode === "clinic" ? "Capitol Hill · 1520 E Pine St, Seattle" : "From anywhere in WA or OR · link sent by text"}</p>
469
470 <div className="cl-days" role="radiogroup" aria-label="Day">
471 {DAYS.map((d, i) => (
472 <button key={d.key} type="button" role="radio" aria-checked={day === i} aria-label={d.label} className={day === i ? "is-on" : ""} onClick={() => setDay(i)}>
473 <small>{d.dow}</small>
474 <span>{d.date}</span>
475 </button>
476 ))}
477 </div>
478
479 <div className="cl-slots" ref={slotsRef} role="radiogroup" aria-label={`Times on ${DAYS[day].label}`} onKeyDown={onSlotKey}>
480 <span className={`cl-slot-pill${pill ? " is-on" : ""}`} aria-hidden="true" style={pill ? ({ transform: `translate(${pill.x}px, ${pill.y}px)`, width: pill.w, height: pill.h } as CSSProperties) : undefined} />
481 {TIMES.map((t, i) => {
482 const free = slotFree(i);
483 const on = slot === i;
484 return (
485 <button key={t} type="button" role="radio" data-slot={i} aria-checked={on} tabIndex={on || (slot === null && i === firstFree) ? 0 : -1} disabled={!free} className={`cl-slot${on ? " is-on" : ""}`} onClick={() => { setSlot(i); setBooking("idle"); }}>
486 {t}<small>{i < 5 ? " am" : " pm"}</small>
487 </button>
488 );
489 })}
490 </div>
491
492 <div className="cl-widget-who">
493 <span className="cl-mini-av" aria-hidden="true" />
494 <p><strong>Dr. Amara Osei</strong><span>Family medicine · your primary clinician</span></p>
495 </div>
496
497 <button type="button" className={`cl-confirm is-${booking}`} onClick={book} disabled={slot === null} aria-describedby="cl-book-status">
498 <span className="cl-confirm-label">{slot === null ? "No times left — try another day" : `Book ${DAYS[day].dow} ${slotLabel}`}</span>
499 <span className="cl-confirm-spin" aria-hidden="true" />
500 <svg className="cl-confirm-check" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="m5 12.5 4.5 4.5L19 7.5" /></svg>
501 </button>
502 <p id="cl-book-status" className="cl-book-status" aria-live="polite">
503 {booking === "done"
504 ? `Booked: ${DAYS[day].label}, ${slotLabel}, ${mode === "clinic" ? "Capitol Hill" : "video"}. Confirmation sent by text.`
505 : "Free cancellation up to 2 hours before."}
506 </p>
507 </div>
508 </div>
509 </section>
510
511 {/* INSURANCE MARQUEE */}
512 <section className="cl-insurers" aria-labelledby="cl-ins-title">
513 <h2 id="cl-ins-title" className="cl-ins-title">In network with the plans most Washingtonians and Oregonians carry</h2>
514 <div className="cl-marquee">
515 <div className="cl-marquee-track">
516 {[0, 1].map((k) => (
517 <ul key={k} className="cl-marquee-set" aria-hidden={k === 1}>
518 {INSURERS.map((n) => <li key={n.name}><InsurerMark name={n.name} glyph={n.glyph} /></li>)}
519 </ul>
520 ))}
521 </div>
522 </div>
523 </section>
524
525 {/* SERVICES */}
526 <section id="cl-services" className="cl-services" aria-labelledby="cl-services-title">
527 <div className="cl-wrap">
528 <div className="cl-head" data-cl-rv>
529 <p className="cl-eyebrow">What we care for</p>
530 <h2 id="cl-services-title" className="cl-h2">Everything a good family doctor does — with the time to do it well.</h2>
531 </div>
532 <ul className="cl-bento">
533 {SERVICES.map((s, i) => (
534 <li key={s.t} className={`cl-card cl-svc${"wide" in s && s.wide ? " is-wide" : ""}`} data-cl-rv style={{ "--d": `${i * 60}ms` } as CSSProperties}>
535 <span className="cl-svc-ico"><Icon name={s.icon} /></span>
536 <h3 className="cl-h3">{s.t}</h3>
537 <p className="cl-body">{s.d}</p>
538 </li>
539 ))}
540 </ul>
541 </div>
542 </section>
543
544 {/* CARE JOURNEY */}
545 <section id="cl-how-it-works" className="cl-journey" aria-labelledby="cl-journey-title">
546 <div className="cl-wrap">
547 <div className="cl-head" data-cl-rv>
548 <p className="cl-eyebrow">How it works</p>
549 <h2 id="cl-journey-title" className="cl-h2">Four steps. One team the whole way.</h2>
550 </div>
551 <div className="cl-journey-grid">
552 <div className="cl-stage-wrap">
553 <div className="cl-stage" aria-hidden="true">
554 <div className="cl-stage-canvas">
555 {MORPH[step].map((p, i) => (
556 <span key={i} className={`cl-prim cl-prim-${i}`} style={{ transform: `translate(${p.x}px, ${p.y}px) rotate(${p.rot ?? 0}deg)`, width: p.w, height: p.h, borderRadius: p.r, background: p.bg, opacity: p.o ?? 1 } as CSSProperties} />
557 ))}
558 <span className={`cl-stage-tag${step === 1 ? " is-on" : ""}`} style={{ transform: "translate(78px, 116px)" }}>● Live · 12:04</span>
559 <span className={`cl-stage-tag${step === 2 ? " is-on" : ""}`} style={{ transform: "translate(158px, 282px)" }}>A1c target: 6.8 by March</span>
560 <span className={`cl-stage-tag${step === 3 ? " is-on" : ""}`} style={{ transform: "translate(104px, 112px)" }}>Your labs are back ��</span>
561 <span className={`cl-stage-tag cl-stage-tag-light${step === 0 ? " is-on" : ""}`} style={{ transform: "translate(200px, 381px)" }}>Confirm 10:40</span>
562 </div>
563 </div>
564 <ol className="cl-stage-rail">
565 {STEPS.map((s, i) => <li key={s.k} className={i <= step ? "is-on" : ""}><span>{s.k}</span></li>)}
566 </ol>
567 </div>
568 <ol className="cl-steps">
569 {STEPS.map((s, i) => (
570 <li key={s.k} data-cl-step className={`cl-step${step === i ? " is-on" : ""}`}>
571 <p className="cl-step-n">0{i + 1} · {s.k}</p>
572 <h3 className="cl-h3 cl-step-t">{s.t}</h3>
573 <p className="cl-body">{s.d}</p>
574 </li>
575 ))}
576 </ol>
577 </div>
578 </div>
579 </section>
580
581 {/* VIRTUAL CARE */}
582 <section className="cl-virtual" aria-labelledby="cl-virtual-title">
583 <div className="cl-wrap cl-virtual-grid">
584 <div data-cl-rv>
585 <p className="cl-eyebrow">Virtual clinic</p>
586 <h2 id="cl-virtual-title" className="cl-h2">A clinician in your pocket, 7am to 9pm.</h2>
587 <p className="cl-body cl-virtual-lede">Message your care team about anything — a new rash, a refill, a lab result you don't understand. A licensed clinician replies within two hours, and can move you to a video visit with one tap.</p>
588 <ul className="cl-ticks">
589 <li><Icon name="check" /> Prescriptions sent to any pharmacy</li>
590 <li><Icon name="check" /> Photos and lab results in one thread</li>
591 <li><Icon name="check" /> Notes written in plain language</li>
592 </ul>
593 </div>
594 <div className={`cl-phone${chatIn ? " is-in" : ""}`} role="img" aria-label="Clara app conversation: a member sends a photo of a rash, Dr. Lena Park replies and books a video visit for 4:40 pm.">
595 <div className="cl-phone-screen">
596 <div className="cl-phone-top">
597 <span className="cl-mini-av cl-mini-av-b" />
598 <p><strong>Dr. Lena Park</strong><span>Usually replies in 40 min</span></p>
599 </div>
600 <div className="cl-chat">
601 <p className="cl-msg cl-msg-me" style={{ "--d": "200ms" } as CSSProperties}>Hi! This rash on my forearm appeared yesterday and it's itchy. Should I worry?</p>
602 <div className="cl-msg cl-msg-me cl-msg-photo" style={{ "--d": "700ms" } as CSSProperties}><span /></div>
603 <p className="cl-typing" style={{ "--d": "1300ms" } as CSSProperties}><i /><i /><i /></p>
604 <p className="cl-msg cl-msg-dr" style={{ "--d": "2600ms" } as CSSProperties}>Thanks, Jordan — that looks like contact dermatitis, likely from the new detergent you mentioned. Nothing urgent.</p>
605 <p className="cl-msg cl-msg-dr" style={{ "--d": "3300ms" } as CSSProperties}>I'd like a quick look on video to be sure. I have 4:40 pm today?</p>
606 <p className="cl-chip-row" style={{ "--d": "3900ms" } as CSSProperties}><span className="cl-chip is-on">4:40 pm ✓</span><span className="cl-chip">Tomorrow</span></p>
607 </div>
608 </div>
609 </div>
610 </div>
611 </section>
612
613 {/* OUTCOMES */}
614 <section className="cl-outcomes" aria-labelledby="cl-outcomes-title">
615 <div className="cl-wrap">
616 <div className="cl-head cl-head-center" data-cl-rv>
617 <p className="cl-eyebrow">Outcomes, measured</p>
618 <h2 id="cl-outcomes-title" className="cl-h2">Care you can feel — and numbers we publish.</h2>
619 </div>
620 <dl className="cl-stats">
621 {STATS.map((s, i) => (
622 <div key={s.label} className="cl-stat">
623 <dt>{s.label}</dt>
624 <dd>
625 <span className="cl-stat-num">{counts[i].toFixed(s.dec)}</span>
626 <span className="cl-stat-suf">{s.suffix}</span>
627 </dd>
628 <span className="cl-stat-bar" style={{ "--k": String(counts[i] / s.v) } as CSSProperties} aria-hidden="true" />
629 </div>
630 ))}
631 </dl>
632 <p className="cl-footnote">Clara internal data, Jan–Sep 2026, across 41,200 members. ER comparison against matched non-member patients in the same ZIP codes.</p>
633 </div>
634 </section>
635
636 {/* CLINICIANS */}
637 <section id="cl-clinicians" className="cl-clinicians" aria-labelledby="cl-clin-title">
638 <div className="cl-wrap">
639 <div className="cl-head cl-head-row" data-cl-rv>
640 <div>
641 <p className="cl-eyebrow">Your care team</p>
642 <h2 id="cl-clin-title" className="cl-h2">Clinicians who stay.</h2>
643 </div>
644 <p className="cl-body cl-head-aside">Our clinicians average seven years with Clara and see 12 patients a day — about half the national average.</p>
645 </div>
646 <ul className="cl-clin-grid">
647 {CLINICIANS.map((c, i) => (
648 <li key={c.name} className="cl-clin" data-cl-rv style={{ "--d": `${i * 80}ms` } as CSSProperties}>
649 <a href="#cl-book" className="cl-clin-link">
650 <div className="cl-clin-img"><img className="cl-portrait" src={c.img} alt={portraitAlt(c.name, c.role.toLowerCase(), c.img)} width={300} height={340} loading="lazy" decoding="async" /></div>
651 <div className="cl-clin-body">
652 <h3 className="cl-clin-name">{c.name}</h3>
653 <p className="cl-clin-role">{c.role}</p>
654 <p className="cl-clin-langs">Speaks {c.langs}</p>
655 <p className="cl-clin-next"><span className="cl-dot" aria-hidden="true" /> Next: {c.next}</p>
656 </div>
657 </a>
658 </li>
659 ))}
660 </ul>
661 </div>
662 </section>
663
664 {/* PRICING */}
665 <section id="cl-pricing" className="cl-pricing" aria-labelledby="cl-pricing-title">
666 <div className="cl-wrap">
667 <div className="cl-head cl-head-center" data-cl-rv>
668 <p className="cl-eyebrow">Membership</p>
669 <h2 id="cl-pricing-title" className="cl-h2">Simple prices. No surprise bills.</h2>
670 <div className="cl-seg cl-seg-lg" role="radiogroup" aria-label="Billing period">
671 <button type="button" role="radio" aria-checked={!annual} className={!annual ? "is-on" : ""} onClick={() => setAnnual(false)}>Monthly</button>
672 <button type="button" role="radio" aria-checked={annual} className={annual ? "is-on" : ""} onClick={() => setAnnual(true)}>Annual <em>save 12%</em></button>
673 <span className="cl-seg-thumb" style={{ transform: `translateX(${annual ? 100 : 0}%)` }} aria-hidden="true" />
674 </div>
675 </div>
676 <ul className="cl-plans" aria-live="polite">
677 {PLANS.map((p, i) => {
678 const price = annual ? p.annual : p.monthly;
679 return (
680 <li key={p.name} className={`cl-plan${p.featured ? " is-featured" : ""}`} data-cl-rv style={{ "--d": `${i * 80}ms` } as CSSProperties}>
681 {p.featured && <span className="cl-plan-flag">Most popular</span>}
682 <h3 className="cl-plan-name">{p.name}</h3>
683 <p className="cl-plan-price">
684 <span className="cl-roll" key={`${p.name}-${annual}`}>{price === 0 ? "$129" : `$${price}`}</span>
685 <span className="cl-plan-per">{price === 0 ? "/ visit" : annual ? "/ year" : "/ month"}</span>
686 </p>
687 <p className="cl-plan-visit">{p.visit}</p>
688 <p className="cl-plan-note">{p.note}</p>
689 <ul className="cl-plan-feats">
690 {p.feats.map((f) => <li key={f}><Icon name="check" />{f}</li>)}
691 </ul>
692 <a href="#cl-book" className={`cl-btn ${p.featured ? "cl-btn-primary" : "cl-btn-soft"} cl-btn-block`}>{p.cta}</a>
693 </li>
694 );
695 })}
696 </ul>
697 <p className="cl-footnote cl-footnote-center">HSA/FSA eligible. Cancel any time from the app. Prices for Washington and Oregon residents, effective 1 January 2027.</p>
698 </div>
699 </section>
700
701 {/* FAQ */}
702 <section id="cl-faq" className="cl-faq" aria-labelledby="cl-faq-title">
703 <div className="cl-wrap cl-faq-grid">
704 <div data-cl-rv>
705 <p className="cl-eyebrow">Questions</p>
706 <h2 id="cl-faq-title" className="cl-h2">Good to know.</h2>
707 <p className="cl-body cl-faq-aside">Can't find an answer? Our member team picks up in under a minute: <a href="#cl-faq">(206) 555-0148</a>.</p>
708 </div>
709 <div className="cl-acc">
710 {FAQ.map((f, i) => {
711 const on = open === i;
712 return (
713 <div key={f.q} className={`cl-acc-item${on ? " is-open" : ""}`}>
714 <h3 className="cl-acc-h">
715 <button type="button" id={`cl-faq-b${i}`} aria-expanded={on} aria-controls={`cl-faq-p${i}`} onClick={() => setOpen(on ? null : i)}>
716 {f.q}
717 <span className="cl-acc-ico" aria-hidden="true"><Icon name="plus" /></span>
718 </button>
719 </h3>
720 <div id={`cl-faq-p${i}`} role="region" aria-labelledby={`cl-faq-b${i}`} className="cl-acc-panel" aria-hidden={!on}>
721 <div><p>{f.a}</p></div>
722 </div>
723 </div>
724 );
725 })}
726 </div>
727 </div>
728 </section>
729
730 {/* CTA */}
731 <section className="cl-cta" aria-labelledby="cl-cta-title">
732 <div className="cl-wrap">
733 <div className="cl-cta-card" data-cl-rv>
734 <span className="cl-cta-orb" aria-hidden="true" />
735 <h2 id="cl-cta-title" className="cl-h2 cl-cta-title">Your first visit could be this afternoon.</h2>
736 <p className="cl-cta-sub">14 open times across Seattle and Portland today.</p>
737 <a href="#cl-book" className="cl-btn cl-btn-light">Find a time <Icon name="arrow" /></a>
738 </div>
739 </div>
740 </section>
741 </main>
742
743 {/* FOOTER */}
744 <footer className="cl-foot">
745 <div className="cl-wrap">
746 <p className="cl-emergency"><strong>In an emergency, call 911.</strong> Clara provides primary and urgent care, not emergency care.</p>
747 <div className="cl-foot-grid">
748 <div className="cl-foot-brand">
749 <a href="#cl-top" className="cl-logo" aria-label="Clara Health — home"><span className="cl-logo-mark" aria-hidden="true"><i /><i /></span>clara</a>
750 <p>Primary care with time for you. Six clinics, one virtual clinic, about 41,000 members.</p>
751 </div>
752 <div>
753 <p className="cl-foot-h">Clinics</p>
754 <ul>
755 <li>Capitol Hill, Seattle</li>
756 <li>Ballard, Seattle</li>
757 <li>South Lake Union, Seattle</li>
758 <li>Pearl District, Portland</li>
759 <li>Alberta Arts, Portland</li>
760 <li>Bellevue Downtown</li>
761 </ul>
762 </div>
763 <div>
764 <p className="cl-foot-h">Care</p>
765 <ul>{["Primary care", "Urgent & sick visits", "Mental health", "Women's health", "Labs & vaccines"].map((x) => <li key={x}><a href="#cl-services">{x}</a></li>)}</ul>
766 </div>
767 <div>
768 <p className="cl-foot-h">Company</p>
769 <ul>{["About Clara", "Careers — we're hiring", "Clinician handbook", "Press", "Contact"].map((x) => <li key={x}><a href="#cl-top">{x}</a></li>)}</ul>
770 </div>
771 <div>
772 <p className="cl-foot-h">Hours</p>
773 <ul>
774 <li>Clinics Mon–Fri 7am–8pm</li>
775 <li>Sat–Sun 9am–5pm</li>
776 <li>Messaging daily 7am–9pm</li>
777 <li><a href="#cl-faq">(206) 555-0148</a></li>
778 </ul>
779 </div>
780 </div>
781 <div className="cl-foot-legal">
782 <span>© 2026 Clara Health PC. Clinical services provided by Clara Medical Group, PLLC.</span>
783 <span className="cl-foot-legal-links"><a href="#cl-top">Privacy</a><a href="#cl-top">HIPAA notice</a><a href="#cl-top">Accessibility</a><a href="#cl-top">Non-discrimination</a></span>
784 </div>
785 </div>
786 </footer>
787 </div>
788 );
789}
790
791export default Page;
792
793/* ------------------------------------------------------------------ */
794/* Styles */
795/* ------------------------------------------------------------------ */
796const css = String.raw`
797.cl {
798 --cl-canvas: #F6F8F7;
799 --cl-surface: #FFFFFF;
800 --cl-tint: #EAF2EE;
801 --cl-tint-2: #DCEBE4;
802 --cl-sage: #9DBFAE;
803 --cl-teal: #1F6F68;
804 --cl-teal-ink: #17544F;
805 --cl-ink: #0F2420;
806 --cl-ink-2: #465A55;
807 --cl-ink-3: #66776F;
808 --cl-line: #DFE7E3;
809 --cl-coral: #E26D5A;
810 --cl-peach: #F3D3BC;
811 --cl-font: ui-rounded, "SF Pro Rounded", ui-sans-serif, -apple-system, BlinkMacSystemFont, "SF Pro Text", "Inter", "Segoe UI", Roboto, sans-serif;
812 --cl-display: ui-rounded, "SF Pro Rounded", "SF Pro Display", ui-sans-serif, -apple-system, "Inter Display", "Inter", "Segoe UI", Roboto, sans-serif;
813 --fd-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
814 --fd-ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
815 --fd-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
816 --fd-dur-1: 120ms;
817 --fd-dur-2: 240ms;
818 --fd-dur-3: 420ms;
819 --fd-dur-4: 700ms;
820 --cl-r-card: 28px;
821 --cl-r-inner: 18px;
822 position: relative;
823 display: block;
824 width: 100%;
825 margin: 0;
826 padding: 0;
827 overflow-x: clip;
828 background: var(--cl-canvas);
829 color: var(--cl-ink);
830 font: 400 17px/1.6 var(--cl-font);
831 letter-spacing: 0;
832 text-align: left;
833 -webkit-font-smoothing: antialiased;
834 -moz-osx-font-smoothing: grayscale;
835}
836.cl *, .cl *::before, .cl *::after {
837 box-sizing: border-box;
838 margin: 0;
839 padding: 0;
840 border: 0 solid transparent;
841 font: inherit;
842 color: inherit;
843 letter-spacing: inherit;
844 text-decoration: none;
845 list-style: none;
846 background: none;
847 -webkit-appearance: none;
848 appearance: none;
849 min-width: 0;
850}
851.cl :where(svg) { display: block; }
852.cl :where(button) { cursor: pointer; text-align: inherit; line-height: inherit; }
853.cl :where(button:disabled) { cursor: not-allowed; }
854.cl :focus-visible { outline: 2px solid rgba(31, 111, 104, 0.7); outline-offset: 2px; border-radius: 12px; }
855.cl [hidden] { display: none !important; }
856.cl-skip { position: absolute; left: 16px; top: -60px; z-index: 100; padding: 12px 18px; border-radius: 9999px; background: var(--cl-ink); color: #FFFFFF; font: 600 15px/1 var(--cl-font); }
857.cl-skip:focus { top: 12px; }
858.cl-ico { width: 20px; height: 20px; flex: none; }
859.cl-wrap { width: 100%; max-width: 1200px; margin: 0 auto; padding: 0 32px; }
860
861.cl-eyebrow { font: 600 13px/1.4 var(--cl-font); letter-spacing: 0.06em; text-transform: uppercase; color: var(--cl-teal); }
862.cl-h1 { font: 600 clamp(44px, 5.6vw, 76px)/1.02 var(--cl-display); letter-spacing: -0.035em; color: var(--cl-ink); text-wrap: balance; }
863.cl-h2 { font: 600 clamp(32px, 3.6vw, 48px)/1.08 var(--cl-display); letter-spacing: -0.028em; color: var(--cl-ink); text-wrap: balance; }
864.cl-h3 { font: 600 20px/1.3 var(--cl-display); letter-spacing: -0.01em; color: var(--cl-ink); }
865.cl-body { font: 400 17px/1.6 var(--cl-font); color: var(--cl-ink-2); }
866.cl-head { max-width: 720px; margin-bottom: 56px; }
867.cl-head .cl-h2 { margin-top: 12px; }
868.cl-head-center { margin-left: auto; margin-right: auto; text-align: center; display: flex; flex-direction: column; align-items: center; }
869.cl-head-row { max-width: none; display: flex; align-items: flex-end; justify-content: space-between; gap: 40px; }
870.cl-head-aside { max-width: 380px; }
871.cl-footnote { margin-top: 28px; font: 400 13px/1.5 var(--cl-font); color: var(--cl-ink-3); }
872.cl-footnote-center { text-align: center; }
873.cl-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: #2E9B6A; box-shadow: 0 0 0 4px rgba(46, 155, 106, 0.18); flex: none; }
874
875/* Buttons */
876.cl-btn { display: inline-flex; align-items: center; justify-content: center; gap: 10px; min-height: 52px; padding: 0 26px; border-radius: 9999px; font: 600 16px/1 var(--cl-font); white-space: nowrap; transition: background-color var(--fd-dur-2) var(--fd-ease-out), box-shadow var(--fd-dur-2) var(--fd-ease-out), transform var(--fd-dur-2) var(--fd-spring), color var(--fd-dur-2) var(--fd-ease-out); }
877.cl-btn .cl-ico { width: 18px; height: 18px; transition: transform var(--fd-dur-2) var(--fd-ease-out); }
878.cl-btn:hover .cl-ico { transform: translateX(3px); }
879.cl-btn:active { transform: scale(0.96); transition-duration: var(--fd-dur-1); }
880.cl-btn-sm { min-height: 44px; padding: 0 20px; font-size: 15px; }
881.cl-btn-block { width: 100%; }
882.cl-btn-primary { background: var(--cl-teal); color: #FFFFFF; box-shadow: 0 1px 0 rgba(255, 255, 255, 0.2) inset, 0 8px 20px -10px rgba(31, 111, 104, 0.7); }
883.cl-btn-primary:hover { background: var(--cl-teal-ink); }
884.cl-btn-ghost { background: rgba(255, 255, 255, 0.7); color: var(--cl-ink); box-shadow: inset 0 0 0 1.5px var(--cl-line); }
885.cl-btn-ghost:hover { background: #FFFFFF; box-shadow: inset 0 0 0 1.5px var(--cl-sage); }
886.cl-btn-soft { background: var(--cl-tint); color: var(--cl-teal-ink); }
887.cl-btn-soft:hover { background: var(--cl-tint-2); }
888.cl-btn-light { background: #FFFFFF; color: var(--cl-teal-ink); }
889.cl-btn-light:hover { background: var(--cl-tint); }
890
891/* NAV */
892.cl-nav { position: sticky; top: 0; z-index: 60; height: 84px; margin-bottom: -84px; padding: 12px 20px 0; pointer-events: none; }
893.cl-nav-in { pointer-events: auto; display: flex; align-items: center; justify-content: space-between; gap: 24px; max-width: 1200px; height: 60px; margin: 0 auto; padding: 0 12px 0 20px; border-radius: 9999px; transition: max-width var(--fd-dur-4) var(--fd-ease-out), background-color var(--fd-dur-3) var(--fd-ease-out), box-shadow var(--fd-dur-3) var(--fd-ease-out); }
894.cl-nav.is-scrolled .cl-nav-in { max-width: 1000px; background: rgba(255, 255, 255, 0.82); -webkit-backdrop-filter: saturate(1.6) blur(20px); backdrop-filter: saturate(1.6) blur(20px); box-shadow: 0 0 0 1px rgba(15, 36, 32, 0.06), 0 12px 32px -16px rgba(15, 36, 32, 0.25); }
895.cl-logo { display: inline-flex; align-items: center; gap: 10px; font: 700 24px/1 var(--cl-display); letter-spacing: -0.04em; color: var(--cl-ink); }
896.cl-logo-mark { position: relative; width: 28px; height: 28px; }
897.cl-logo-mark i { position: absolute; width: 18px; height: 18px; border-radius: 50%; }
898.cl-logo-mark i:first-child { left: 0; top: 5px; background: var(--cl-sage); }
899.cl-logo-mark i:last-child { right: 0; top: 5px; background: var(--cl-teal); mix-blend-mode: multiply; }
900.cl-nav-links { display: flex; gap: 6px; }
901.cl-nav-links a { display: inline-flex; align-items: center; min-height: 44px; padding: 0 14px; border-radius: 9999px; font: 500 15px/1 var(--cl-font); color: var(--cl-ink-2); transition: background-color var(--fd-dur-1) var(--fd-ease-out), color var(--fd-dur-1) var(--fd-ease-out); }
902.cl-nav-links a:hover { background: rgba(15, 36, 32, 0.05); color: var(--cl-ink); }
903.cl-nav-end { display: flex; align-items: center; gap: 6px; }
904.cl-nav-sign { display: inline-flex; align-items: center; min-height: 44px; padding: 0 14px; font: 500 15px/1 var(--cl-font); color: var(--cl-ink); border-radius: 9999px; }
905.cl-nav-sign:hover { background: rgba(15, 36, 32, 0.05); }
906.cl-burger { display: none; position: relative; width: 44px; height: 44px; border-radius: 50%; }
907.cl-burger span { position: absolute; left: 13px; right: 13px; height: 2px; border-radius: 2px; background: var(--cl-ink); transition: transform var(--fd-dur-3) var(--fd-ease-out); }
908.cl-burger span:first-child { top: 18px; }
909.cl-burger span:last-child { top: 25px; }
910.cl-nav.is-open .cl-burger span:first-child { transform: translateY(3.5px) rotate(45deg); }
911.cl-nav.is-open .cl-burger span:last-child { transform: translateY(-3.5px) rotate(-45deg); }
912.cl-sheet { pointer-events: auto; max-width: 1000px; margin: 8px auto 0; padding: 10px; border-radius: 24px; background: #FFFFFF; box-shadow: 0 0 0 1px rgba(15, 36, 32, 0.06), 0 24px 48px -20px rgba(15, 36, 32, 0.3); animation: cl-pop var(--fd-dur-3) var(--fd-ease-out); }
913.cl-sheet a { display: flex; align-items: center; min-height: 52px; padding: 0 16px; border-radius: 14px; font: 500 18px/1 var(--cl-font); color: var(--cl-ink); }
914.cl-sheet a:hover { background: var(--cl-tint); }
915@keyframes cl-pop { from { opacity: 0; transform: translateY(-6px) scale(0.98); } to { opacity: 1; transform: none; } }
916
917/* HERO */
918.cl-hero { position: relative; padding: 150px 0 110px; overflow: hidden; }
919.cl-orb { position: absolute; left: 50%; top: 46%; width: 1100px; height: 1100px; margin: -550px 0 0 -550px; pointer-events: none; --mx: 0; --my: 0; transform: translate3d(calc(var(--mx) * 24px), calc(var(--my) * 18px), 0); }
920.cl-orb span { position: absolute; inset: 0; border-radius: 50%; will-change: transform, opacity; }
921.cl-orb-a { background: radial-gradient(closest-side, rgba(157, 191, 174, 0.75), rgba(157, 191, 174, 0.28) 55%, rgba(157, 191, 174, 0) 100%); animation: cl-breathe 9s var(--fd-ease-in-out) infinite; }
922.cl-orb-b { inset: 18% 6% 8% 30% !important; background: radial-gradient(closest-side, rgba(243, 211, 188, 0.85), rgba(243, 211, 188, 0) 100%); animation: cl-breathe-b 9s var(--fd-ease-in-out) infinite; }
923.cl-orb-c { inset: 8% 34% 30% 4% !important; background: radial-gradient(closest-side, rgba(146, 205, 196, 0.7), rgba(146, 205, 196, 0) 100%); animation: cl-breathe-c 9s var(--fd-ease-in-out) infinite; }
924@keyframes cl-breathe { 0%, 100% { transform: scale(0.9); opacity: 0.75; } 45% { transform: scale(1.06); opacity: 1; } }
925@keyframes cl-breathe-b { 0%, 100% { transform: translate(-4%, 3%) scale(0.92); } 45% { transform: translate(3%, -2%) scale(1.08); } }
926@keyframes cl-breathe-c { 0%, 100% { transform: translate(3%, -2%) scale(1.04); } 45% { transform: translate(-3%, 4%) scale(0.9); } }
927.cl-hero-grid { position: relative; display: grid; grid-template-columns: 1.08fr 0.92fr; gap: 64px; align-items: center; }
928.cl-badge { display: inline-flex; align-items: center; gap: 10px; min-height: 36px; padding: 0 16px 0 14px; border-radius: 9999px; background: rgba(255, 255, 255, 0.75); box-shadow: inset 0 0 0 1px rgba(15, 36, 32, 0.07); font: 500 14px/1.3 var(--cl-font); color: var(--cl-ink-2); }
929.cl-hero-copy .cl-h1 { margin-top: 24px; max-width: 12ch; }
930.cl-lede { margin-top: 24px; max-width: 520px; font: 400 20px/1.55 var(--cl-font); color: var(--cl-ink-2); }
931.cl-hero-ctas { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 36px; }
932.cl-hero-proof { display: flex; flex-wrap: wrap; gap: 10px 28px; margin-top: 40px; font: 400 15px/1.4 var(--cl-font); color: var(--cl-ink-2); }
933.cl-hero-proof strong { font-weight: 700; color: var(--cl-ink); }
934.cl-hero-copy > * { animation: cl-up var(--fd-dur-4) var(--fd-ease-out) both; }
935.cl-hero-copy > *:nth-child(2) { animation-delay: 80ms; }
936.cl-hero-copy > *:nth-child(3) { animation-delay: 160ms; }
937.cl-hero-copy > *:nth-child(4) { animation-delay: 240ms; }
938.cl-hero-copy > *:nth-child(5) { animation-delay: 320ms; }
939.cl-widget { animation: cl-up 900ms var(--fd-ease-out) 200ms both; }
940@keyframes cl-up { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: none; } }
941
942/* Booking widget */
943.cl-widget { position: relative; padding: 28px; border-radius: 32px; background: rgba(255, 255, 255, 0.86); -webkit-backdrop-filter: saturate(1.4) blur(24px); backdrop-filter: saturate(1.4) blur(24px); box-shadow: 0 0 0 1px rgba(15, 36, 32, 0.06), 0 40px 80px -40px rgba(15, 36, 32, 0.35), 0 2px 6px rgba(15, 36, 32, 0.04); }
944.cl-widget-head { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
945.cl-widget-title { font: 600 24px/1.2 var(--cl-display); letter-spacing: -0.02em; color: var(--cl-ink); }
946.cl-widget-where { margin-top: 8px; font: 400 15px/1.4 var(--cl-font); color: var(--cl-ink-2); min-height: 21px; }
947.cl-seg { position: relative; display: inline-grid; grid-template-columns: 1fr 1fr; padding: 4px; border-radius: 9999px; background: var(--cl-tint); }
948.cl-seg button { position: relative; z-index: 1; display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-height: 40px; padding: 0 14px; border-radius: 9999px; font: 600 14px/1 var(--cl-font); color: var(--cl-ink-2); white-space: nowrap; transition: color var(--fd-dur-2) var(--fd-ease-out); }
949.cl-seg button .cl-ico { width: 16px; height: 16px; }
950.cl-seg button.is-on { color: var(--cl-teal-ink); }
951.cl-seg button em { font-style: normal; margin-left: 6px; padding: 3px 8px; border-radius: 9999px; background: #FFF1E8; color: #A3412F; font: 600 12px/1 var(--cl-font); }
952.cl-seg-thumb { position: absolute; top: 4px; bottom: 4px; left: 4px; width: calc(50% - 4px); border-radius: 9999px; background: #FFFFFF; box-shadow: 0 1px 2px rgba(15, 36, 32, 0.08), 0 6px 14px -6px rgba(15, 36, 32, 0.2); transition: transform var(--fd-dur-3) var(--fd-spring); }
953.cl-seg-lg { margin-top: 32px; }
954.cl-seg-lg button { min-height: 48px; padding: 0 22px; font-size: 16px; }
955.cl-days { display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; margin-top: 22px; }
956.cl-days button { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; min-height: 64px; border-radius: 18px; background: var(--cl-canvas); box-shadow: inset 0 0 0 1px var(--cl-line); color: var(--cl-ink); transition: background-color var(--fd-dur-2) var(--fd-ease-out), box-shadow var(--fd-dur-2) var(--fd-ease-out), color var(--fd-dur-2) var(--fd-ease-out), transform var(--fd-dur-2) var(--fd-spring); }
957.cl-days button small { font: 500 12px/1 var(--cl-font); letter-spacing: 0.04em; text-transform: uppercase; color: var(--cl-ink-3); transition: color var(--fd-dur-2) var(--fd-ease-out); }
958.cl-days button span { font: 600 20px/1 var(--cl-display); }
959.cl-days button:hover { box-shadow: inset 0 0 0 1.5px var(--cl-sage); }
960.cl-days button:active { transform: scale(0.96); }
961.cl-days button.is-on { background: var(--cl-ink); color: #FFFFFF; box-shadow: none; }
962.cl-days button.is-on small { color: rgba(255, 255, 255, 0.75); }
963.cl-slots { position: relative; display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-top: 14px; }
964.cl-slot-pill { position: absolute; left: 0; top: 0; z-index: 0; border-radius: 9999px; background: var(--cl-teal); box-shadow: 0 8px 18px -8px rgba(31, 111, 104, 0.8); opacity: 0; transition: transform 520ms var(--fd-spring), width var(--fd-dur-3) var(--fd-ease-out), height var(--fd-dur-3) var(--fd-ease-out), opacity var(--fd-dur-2) var(--fd-ease-out); }
965.cl-slot-pill.is-on { opacity: 1; }
966.cl-slot { position: relative; z-index: 1; min-height: 48px; border-radius: 9999px; box-shadow: inset 0 0 0 1px var(--cl-line); background: transparent; font: 600 16px/1 var(--cl-font); color: var(--cl-ink); text-align: center; font-variant-numeric: tabular-nums; transition: color var(--fd-dur-2) var(--fd-ease-out), box-shadow var(--fd-dur-2) var(--fd-ease-out), background-color var(--fd-dur-2) var(--fd-ease-out); }
967.cl-slot small { font: 500 13px/1 var(--cl-font); color: var(--cl-ink-3); transition: color var(--fd-dur-2) var(--fd-ease-out); }
968.cl-slot:hover:not(:disabled):not(.is-on) { background: var(--cl-tint); box-shadow: inset 0 0 0 1px var(--cl-sage); }
969.cl-slot.is-on { color: #FFFFFF; box-shadow: none; }
970.cl-slot.is-on small { color: rgba(255, 255, 255, 0.82); }
971.cl-slot:disabled { color: #8C9A95; background: repeating-linear-gradient(-45deg, transparent 0 6px, rgba(15, 36, 32, 0.035) 6px 7px); text-decoration: line-through; text-decoration-color: rgba(15, 36, 32, 0.3); }
972.cl-slot:disabled small { color: #8C9A95; }
973.cl-widget-who { display: flex; align-items: center; gap: 12px; margin-top: 20px; padding: 12px; border-radius: 18px; background: var(--cl-canvas); }
974.cl-widget-who p { display: flex; flex-direction: column; gap: 2px; font: 400 14px/1.3 var(--cl-font); color: var(--cl-ink-2); }
975.cl-widget-who strong { font: 600 15px/1.3 var(--cl-font); color: var(--cl-ink); }
976.cl-mini-av { width: 40px; height: 40px; flex: none; border-radius: 50%; background: radial-gradient(circle at 50% 38%, #8B5A3C 0 26%, transparent 27%), radial-gradient(circle at 50% 118%, #FFFFFF 0 46%, transparent 47%), linear-gradient(135deg, #DCEBE4, #BFD8CB); box-shadow: inset 0 0 0 1px rgba(15, 36, 32, 0.06); }
977.cl-mini-av-b { background: radial-gradient(circle at 50% 38%, #E8C2A0 0 26%, transparent 27%), radial-gradient(circle at 50% 118%, #2C6E67 0 46%, transparent 47%), linear-gradient(135deg, #E6EEF5, #C9D9E8); }
978.cl-confirm { position: relative; display: flex; align-items: center; justify-content: center; width: 100%; min-height: 56px; margin-top: 16px; border-radius: 9999px; background: var(--cl-ink); color: #FFFFFF; font: 600 17px/1 var(--cl-font); overflow: hidden; transition: background-color var(--fd-dur-3) var(--fd-ease-out), transform var(--fd-dur-2) var(--fd-spring); }
979.cl-confirm:hover:not(:disabled) { background: #1E3A35; }
980.cl-confirm:active:not(:disabled) { transform: scale(0.97); }
981.cl-confirm:disabled { background: #C9D3CF; color: #3D4F4A; }
982.cl-confirm-label { transition: opacity var(--fd-dur-2) var(--fd-ease-out), transform var(--fd-dur-3) var(--fd-ease-out); }
983.cl-confirm-spin { position: absolute; left: 50%; top: 50%; width: 22px; height: 22px; margin: -11px 0 0 -11px; border-radius: 50%; border: 2.5px solid rgba(255, 255, 255, 0.3); border-top-color: #FFFFFF; opacity: 0; transition: opacity var(--fd-dur-2) var(--fd-ease-out); }
984.cl-confirm-check { position: absolute; left: 50%; top: 50%; width: 28px; height: 28px; margin: -14px 0 0 -14px; fill: none; stroke: #FFFFFF; stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 24; stroke-dashoffset: 24; }
985.cl-confirm.is-busy .cl-confirm-label, .cl-confirm.is-done .cl-confirm-label { opacity: 0; transform: translateY(-10px); }
986.cl-confirm.is-busy .cl-confirm-spin { opacity: 1; animation: cl-spin 700ms linear infinite; }
987.cl-confirm.is-done { background: #2E8A5F; }
988.cl-confirm.is-done .cl-confirm-check { stroke-dashoffset: 0; transition: stroke-dashoffset 520ms var(--fd-ease-out) 80ms; }
989@keyframes cl-spin { to { transform: rotate(360deg); } }
990.cl-book-status { margin-top: 12px; min-height: 42px; font: 400 14px/1.5 var(--cl-font); color: var(--cl-ink-2); text-align: center; }
991
992/* INSURERS */
993.cl-insurers { padding: 24px 0 96px; }
994.cl-ins-title { margin: 0 auto 28px; padding: 0 24px; max-width: 760px; font: 500 15px/1.5 var(--cl-font); color: var(--cl-ink-2); text-align: center; }
995.cl-marquee { position: relative; overflow: hidden; -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent); mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent); }
996.cl-marquee-track { display: flex; width: max-content; animation: cl-marquee 42s linear infinite; }
997.cl-marquee:hover .cl-marquee-track { animation-play-state: paused; }
998.cl-marquee-set { display: flex; gap: 56px; padding-right: 56px; }
999.cl-ins { display: inline-flex; align-items: center; gap: 10px; min-height: 48px; font: 600 19px/1 var(--cl-display); letter-spacing: -0.015em; color: #52645E; white-space: nowrap; }
1000.cl-ins svg { width: 26px; height: 26px; color: var(--cl-teal); opacity: 0.85; }
1001@keyframes cl-marquee { to { transform: translateX(-50%); } }
1002
1003/* SERVICES */
1004.cl-services { padding: 40px 0 140px; }
1005.cl-bento { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
1006.cl-card { position: relative; padding: 28px; border-radius: var(--cl-r-card); background: var(--cl-surface); box-shadow: 0 0 0 1px rgba(15, 36, 32, 0.05), 0 1px 2px rgba(15, 36, 32, 0.04); }
1007.cl-svc { display: flex; flex-direction: column; gap: 10px; min-height: 240px; transition: transform var(--fd-dur-3) var(--fd-ease-out), box-shadow var(--fd-dur-3) var(--fd-ease-out); }
1008.cl-svc.is-wide { grid-column: span 2; }
1009.cl-svc:hover { transform: translateY(-4px); box-shadow: 0 0 0 1px rgba(15, 36, 32, 0.05), 0 24px 40px -24px rgba(15, 36, 32, 0.28); }
1010.cl-svc-ico { display: grid; place-items: center; width: 52px; height: 52px; margin-bottom: auto; border-radius: 16px; background: var(--cl-tint); color: var(--cl-teal); }
1011.cl-svc-ico .cl-ico { width: 26px; height: 26px; }
1012.cl-svc .cl-h3 { margin-top: 28px; }
1013.cl-svc .cl-body { font-size: 16px; }
1014.cl-svc.is-wide:first-child { background: linear-gradient(135deg, #FFFFFF 0%, #EAF2EE 100%); }
1015
1016/* REVEALS */
1017.cl-js [data-cl-rv] { opacity: 0; transform: translateY(22px); transition: opacity var(--fd-dur-4) var(--fd-ease-out), transform var(--fd-dur-4) var(--fd-ease-out), box-shadow var(--fd-dur-3) var(--fd-ease-out); transition-delay: var(--d, 0ms); }
1018.cl-js [data-cl-rv].is-in { opacity: 1; transform: none; }
1019.cl-js .cl-svc[data-cl-rv].is-in:hover, .cl-js .cl-clin[data-cl-rv].is-in:hover { transition-delay: 0ms; }
1020.cl-js .cl-svc[data-cl-rv].is-in:hover { transform: translateY(-4px); }
1021
1022/* JOURNEY */
1023.cl-journey { padding: 130px 0 120px; background: var(--cl-surface); border-radius: 48px 48px 0 0; }
1024.cl-journey-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 80px; }
1025.cl-stage-wrap { position: sticky; top: 110px; align-self: start; }
1026.cl-stage { position: relative; aspect-ratio: 1; border-radius: 40px; background: radial-gradient(circle at 30% 20%, #F3F8F5, #DCEBE4 70%); overflow: hidden; box-shadow: inset 0 0 0 1px rgba(15, 36, 32, 0.05); }
1027.cl-stage-canvas { position: absolute; left: 50%; top: 50%; width: 520px; height: 480px; margin: -240px 0 0 -260px; transform: scale(var(--cl-stage-s, 1)); contain: layout paint; }
1028.cl-prim { position: absolute; left: 0; top: 0; box-shadow: 0 1px 2px rgba(15, 36, 32, 0.06); transition: transform 760ms var(--fd-spring), width 620ms var(--fd-ease-out), height 620ms var(--fd-ease-out), border-radius 620ms var(--fd-ease-out), background-color 620ms var(--fd-ease-in-out), opacity var(--fd-dur-3) var(--fd-ease-out); }
1029.cl-prim-0 { box-shadow: 0 30px 60px -30px rgba(15, 36, 32, 0.35), 0 0 0 1px rgba(15, 36, 32, 0.05); }
1030.cl-prim-1 { transition-delay: 30ms; }
1031.cl-prim-2 { transition-delay: 60ms; }
1032.cl-prim-3 { transition-delay: 90ms; }
1033.cl-prim-4 { transition-delay: 120ms; }
1034.cl-prim-5 { transition-delay: 150ms; }
1035.cl-prim-6 { transition-delay: 180ms; }
1036.cl-stage-tag { position: absolute; left: 0; top: 0; padding: 7px 12px; border-radius: 9999px; background: #FFFFFF; box-shadow: 0 6px 16px -8px rgba(15, 36, 32, 0.4); font: 600 13px/1 var(--cl-font); color: var(--cl-ink); white-space: nowrap; opacity: 0; scale: 0.9; transition: opacity var(--fd-dur-3) var(--fd-ease-out), scale var(--fd-dur-3) var(--fd-spring); }
1037.cl-stage-tag-light { background: transparent; box-shadow: none; color: #FFFFFF; }
1038.cl-stage-tag.is-on { opacity: 1; scale: 1; transition-delay: 420ms; }
1039.cl-stage-rail { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-top: 20px; }
1040.cl-stage-rail li { position: relative; padding-top: 14px; font: 600 13px/1.2 var(--cl-font); color: var(--cl-ink-3); transition: color var(--fd-dur-3) var(--fd-ease-out); }
1041.cl-stage-rail li::before { content: ""; position: absolute; left: 0; right: 0; top: 0; height: 4px; border-radius: 4px; background: var(--cl-line); }
1042.cl-stage-rail li::after { content: ""; position: absolute; left: 0; right: 0; top: 0; height: 4px; border-radius: 4px; background: var(--cl-teal); transform: scaleX(0); transform-origin: left; transition: transform var(--fd-dur-4) var(--fd-ease-out); }
1043.cl-stage-rail li.is-on { color: var(--cl-teal-ink); }
1044.cl-stage-rail li.is-on::after { transform: scaleX(1); }
1045.cl-steps { padding: 6vh 0 18vh; }
1046.cl-step { display: flex; flex-direction: column; justify-content: center; min-height: 64vh; padding: 0 0 0 28px; border-left: 2px solid var(--cl-line); opacity: 0.38; transition: opacity var(--fd-dur-4) var(--fd-ease-out), border-color var(--fd-dur-4) var(--fd-ease-out); }
1047.cl-step.is-on { opacity: 1; border-left-color: var(--cl-teal); }
1048.cl-step-n { font: 600 14px/1 var(--cl-font); letter-spacing: 0.04em; text-transform: uppercase; color: var(--cl-teal); }
1049.cl-step-t { margin: 14px 0 14px; font-size: 32px; line-height: 1.15; letter-spacing: -0.025em; }
1050.cl-step .cl-body { max-width: 460px; font-size: 18px; }
1051
1052/* VIRTUAL */
1053.cl-virtual { padding: 120px 0; background: var(--cl-surface); }
1054.cl-virtual-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 80px; align-items: center; }
1055.cl-virtual .cl-h2 { margin-top: 12px; }
1056.cl-virtual-lede { margin-top: 22px; max-width: 480px; }
1057.cl-ticks { display: grid; gap: 12px; margin-top: 28px; }
1058.cl-ticks li { display: flex; align-items: center; gap: 12px; font: 500 17px/1.4 var(--cl-font); color: var(--cl-ink); }
1059.cl-ticks .cl-ico { width: 26px; height: 26px; padding: 4px; border-radius: 50%; background: var(--cl-tint); color: var(--cl-teal); }
1060.cl-phone { justify-self: center; width: 360px; padding: 12px; border-radius: 52px; background: #0F2420; box-shadow: 0 50px 100px -40px rgba(15, 36, 32, 0.55), inset 0 0 0 2px #2A3D39; }
1061.cl-phone-screen { height: 600px; border-radius: 42px; background: linear-gradient(180deg, #F6F8F7, #EEF4F1); overflow: hidden; }
1062.cl-phone-top { display: flex; align-items: center; gap: 12px; padding: 44px 20px 14px; background: rgba(255, 255, 255, 0.9); box-shadow: 0 1px 0 var(--cl-line); }
1063.cl-phone-top p { display: flex; flex-direction: column; gap: 2px; font: 400 13px/1.3 var(--cl-font); color: var(--cl-ink-2); }
1064.cl-phone-top strong { font: 600 15px/1.3 var(--cl-font); color: var(--cl-ink); }
1065.cl-chat { display: flex; flex-direction: column; gap: 10px; padding: 18px 16px; }
1066.cl-msg { max-width: 82%; padding: 11px 15px; border-radius: 20px; font: 400 15px/1.42 var(--cl-font); }
1067.cl-msg-me { align-self: flex-end; background: var(--cl-teal); color: #FFFFFF; border-bottom-right-radius: 6px; }
1068.cl-msg-dr { align-self: flex-start; background: #FFFFFF; color: var(--cl-ink); border-bottom-left-radius: 6px; box-shadow: 0 1px 2px rgba(15, 36, 32, 0.06); }
1069.cl-msg-photo { width: 150px; height: 104px; padding: 5px; }
1070.cl-msg-photo span { display: block; width: 100%; height: 100%; border-radius: 15px; background: radial-gradient(ellipse 30% 22% at 46% 52%, rgba(214, 104, 98, 0.75), transparent), radial-gradient(ellipse 18% 14% at 62% 40%, rgba(214, 104, 98, 0.55), transparent), linear-gradient(160deg, #E9C3A6, #D9A985); }
1071.cl-typing { align-self: flex-start; display: flex; gap: 4px; padding: 14px 16px; border-radius: 20px; background: #FFFFFF; }
1072.cl-typing i { width: 7px; height: 7px; border-radius: 50%; background: #9AA7A3; animation: cl-dots 1.2s var(--fd-ease-in-out) infinite; }
1073.cl-typing i:nth-child(2) { animation-delay: 150ms; }
1074.cl-typing i:nth-child(3) { animation-delay: 300ms; }
1075@keyframes cl-dots { 0%, 60%, 100% { transform: translateY(0); opacity: 0.5; } 30% { transform: translateY(-4px); opacity: 1; } }
1076.cl-chip-row { display: flex; gap: 8px; }
1077.cl-chip { display: inline-flex; align-items: center; min-height: 36px; padding: 0 14px; border-radius: 9999px; background: #FFFFFF; box-shadow: inset 0 0 0 1px var(--cl-line); font: 600 14px/1 var(--cl-font); color: var(--cl-ink); }
1078.cl-chip.is-on { background: var(--cl-ink); color: #FFFFFF; box-shadow: none; }
1079.cl-js .cl-chat > * { opacity: 0; transform: translateY(10px) scale(0.97); }
1080.cl-js .cl-phone.is-in .cl-chat > * { animation: cl-msg 520ms var(--fd-spring) var(--d) forwards; }
1081.cl-js .cl-phone.is-in .cl-typing { animation: cl-typing 1300ms var(--fd-ease-out) var(--d) forwards; }
1082@keyframes cl-msg { to { opacity: 1; transform: none; } }
1083@keyframes cl-typing { 0% { opacity: 0; transform: translateY(10px); max-height: 60px; } 15%, 80% { opacity: 1; transform: none; max-height: 60px; } 100% { opacity: 0; max-height: 0; padding-top: 0; padding-bottom: 0; margin-top: -10px; } }
1084
1085/* OUTCOMES */
1086.cl-outcomes { padding: 130px 0; }
1087.cl-stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
1088.cl-stat { position: relative; display: flex; flex-direction: column-reverse; justify-content: flex-end; gap: 14px; padding: 28px; border-radius: var(--cl-r-card); background: var(--cl-surface); box-shadow: 0 0 0 1px rgba(15, 36, 32, 0.05); overflow: hidden; }
1089.cl-stat dt { font: 400 15px/1.45 var(--cl-font); color: var(--cl-ink-2); }
1090.cl-stat dd { display: flex; align-items: baseline; font: 600 64px/1 var(--cl-display); letter-spacing: -0.045em; color: var(--cl-ink); font-variant-numeric: tabular-nums; }
1091.cl-stat-suf { font-size: 32px; letter-spacing: -0.02em; color: var(--cl-teal); margin-left: 2px; }
1092.cl-stat-bar { position: absolute; left: 0; right: 0; bottom: 0; height: 4px; background: var(--cl-teal); transform: scaleX(var(--k)); transform-origin: left; }
1093
1094/* CLINICIANS */
1095.cl-clinicians { padding: 40px 0 130px; }
1096.cl-clin-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
1097.cl-clin-link { display: block; height: 100%; padding: 10px; border-radius: var(--cl-r-card); background: var(--cl-surface); box-shadow: 0 0 0 1px rgba(15, 36, 32, 0.05); transition: transform var(--fd-dur-3) var(--fd-ease-out), box-shadow var(--fd-dur-3) var(--fd-ease-out); }
1098.cl-clin-link:hover, .cl-clin-link:focus-visible { transform: translateY(-6px); box-shadow: 0 0 0 1px rgba(15, 36, 32, 0.05), 0 28px 44px -26px rgba(15, 36, 32, 0.35); }
1099.cl-clin-img { aspect-ratio: 300 / 340; border-radius: var(--cl-r-inner); overflow: hidden; }
1100.cl-portrait { display: block; width: 100%; height: 100%; object-fit: cover; object-position: center top; transition: transform var(--fd-dur-4) var(--fd-ease-out); }
1101.cl-clin-link:hover .cl-portrait { transform: scale(1.04); }
1102.cl-clin-body { padding: 16px 10px 10px; }
1103.cl-clin-name { font: 600 19px/1.3 var(--cl-display); letter-spacing: -0.01em; color: var(--cl-ink); }
1104.cl-clin-role { margin-top: 2px; font: 500 15px/1.4 var(--cl-font); color: var(--cl-teal-ink); }
1105.cl-clin-langs { margin-top: 10px; font: 400 14px/1.4 var(--cl-font); color: var(--cl-ink-2); }
1106.cl-clin-next { display: flex; align-items: center; gap: 10px; margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--cl-line); font: 500 14px/1.3 var(--cl-font); color: var(--cl-ink); }
1107
1108/* PRICING */
1109.cl-pricing { padding: 130px 0; background: linear-gradient(180deg, var(--cl-canvas), #EDF4F0); }
1110.cl-plans { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; align-items: stretch; }
1111.cl-plan { position: relative; display: flex; flex-direction: column; padding: 32px; border-radius: 32px; background: var(--cl-surface); box-shadow: 0 0 0 1px rgba(15, 36, 32, 0.06); }
1112.cl-plan.is-featured { background: var(--cl-ink); color: #FFFFFF; box-shadow: 0 40px 80px -40px rgba(15, 36, 32, 0.6); }
1113.cl-plan-flag { position: absolute; top: 28px; right: 28px; padding: 6px 12px; border-radius: 9999px; background: var(--cl-sage); color: var(--cl-ink); font: 600 13px/1 var(--cl-font); }
1114.cl-plan-name { font: 600 20px/1.3 var(--cl-display); color: inherit; }
1115.cl-plan-price { display: flex; align-items: baseline; gap: 8px; height: 72px; margin-top: 18px; overflow: hidden; }
1116.cl-roll { display: inline-block; font: 600 64px/72px var(--cl-display); letter-spacing: -0.045em; animation: cl-roll var(--fd-dur-4) var(--fd-spring); font-variant-numeric: tabular-nums; }
1117@keyframes cl-roll { from { transform: translateY(70%); opacity: 0; } to { transform: none; opacity: 1; } }
1118.cl-plan-per { font: 500 16px/1 var(--cl-font); color: var(--cl-ink-2); }
1119.cl-plan.is-featured .cl-plan-per { color: rgba(255, 255, 255, 0.75); }
1120.cl-plan-visit { margin-top: 4px; font: 600 16px/1.4 var(--cl-font); color: var(--cl-teal-ink); }
1121.cl-plan.is-featured .cl-plan-visit { color: #A9D7C3; }
1122.cl-plan-note { margin-top: 6px; font: 400 15px/1.5 var(--cl-font); color: var(--cl-ink-2); }
1123.cl-plan.is-featured .cl-plan-note { color: rgba(255, 255, 255, 0.78); }
1124.cl-plan-feats { display: grid; gap: 12px; margin: 26px 0 30px; padding-top: 24px; border-top: 1px solid var(--cl-line); flex: 1; }
1125.cl-plan.is-featured .cl-plan-feats { border-top-color: rgba(255, 255, 255, 0.14); }
1126.cl-plan-feats li { display: flex; gap: 10px; font: 400 16px/1.4 var(--cl-font); }
1127.cl-plan-feats .cl-ico { width: 20px; height: 20px; color: var(--cl-teal); }
1128.cl-plan.is-featured .cl-plan-feats .cl-ico { color: #A9D7C3; }
1129
1130/* FAQ */
1131.cl-faq { padding: 130px 0; background: var(--cl-surface); }
1132.cl-faq-grid { display: grid; grid-template-columns: 0.8fr 1.2fr; gap: 80px; align-items: start; }
1133.cl-faq .cl-h2 { margin-top: 12px; }
1134.cl-faq-aside { margin-top: 18px; max-width: 340px; }
1135.cl-faq-aside a { color: var(--cl-teal-ink); font-weight: 600; text-decoration: underline; text-underline-offset: 3px; }
1136.cl-acc { border-top: 1px solid var(--cl-line); }
1137.cl-acc-item { border-bottom: 1px solid var(--cl-line); }
1138.cl-acc-h button { display: flex; align-items: center; justify-content: space-between; gap: 24px; width: 100%; min-height: 76px; padding: 18px 4px; font: 600 19px/1.35 var(--cl-display); letter-spacing: -0.01em; color: var(--cl-ink); }
1139.cl-acc-h button:hover { color: var(--cl-teal-ink); }
1140.cl-acc-ico { display: grid; place-items: center; width: 40px; height: 40px; flex: none; border-radius: 50%; background: var(--cl-tint); color: var(--cl-teal); transition: transform var(--fd-dur-3) var(--fd-spring), background-color var(--fd-dur-2) var(--fd-ease-out), color var(--fd-dur-2) var(--fd-ease-out); }
1141.cl-acc-item.is-open .cl-acc-ico { transform: rotate(45deg); background: var(--cl-teal); color: #FFFFFF; }
1142.cl-acc-panel { display: grid; grid-template-rows: 0fr; transition: grid-template-rows var(--fd-dur-3) var(--fd-ease-out); }
1143.cl-acc-panel > div { overflow: hidden; }
1144.cl-acc-panel p { padding: 0 64px 26px 4px; font: 400 17px/1.65 var(--cl-font); color: var(--cl-ink-2); opacity: 0; transform: translateY(-6px); transition: opacity var(--fd-dur-3) var(--fd-ease-out), transform var(--fd-dur-3) var(--fd-ease-out); }
1145.cl-acc-item.is-open .cl-acc-panel { grid-template-rows: 1fr; }
1146.cl-acc-item.is-open .cl-acc-panel p { opacity: 1; transform: none; }
1147
1148/* CTA */
1149.cl-cta { padding: 0 0 110px; background: var(--cl-surface); }
1150.cl-cta-card { position: relative; display: flex; flex-direction: column; align-items: center; padding: 96px 32px; border-radius: 40px; background: var(--cl-teal); text-align: center; overflow: hidden; }
1151.cl-cta-orb { position: absolute; left: 50%; top: 50%; width: 900px; height: 900px; margin: -450px 0 0 -450px; border-radius: 50%; background: radial-gradient(closest-side, rgba(169, 215, 195, 0.55), rgba(169, 215, 195, 0)); animation: cl-breathe 9s var(--fd-ease-in-out) infinite; pointer-events: none; }
1152.cl-cta-title { position: relative; color: #FFFFFF; max-width: 680px; }
1153.cl-cta-sub { position: relative; margin: 16px 0 32px; font: 400 18px/1.5 var(--cl-font); color: rgba(255, 255, 255, 0.88); }
1154.cl-cta .cl-btn { position: relative; }
1155
1156/* FOOTER */
1157.cl-foot { padding: 64px 0 40px; background: var(--cl-ink); color: rgba(255, 255, 255, 0.82); }
1158.cl-emergency { padding: 18px 22px; border-radius: 18px; background: rgba(255, 255, 255, 0.06); font: 400 15px/1.5 var(--cl-font); color: rgba(255, 255, 255, 0.85); }
1159.cl-emergency strong { color: #FFFFFF; font-weight: 600; }
1160.cl-foot-grid { display: grid; grid-template-columns: 1.4fr repeat(4, 1fr); gap: 40px; padding: 56px 0; }
1161.cl-foot .cl-logo { color: #FFFFFF; }
1162.cl-foot .cl-logo-mark i:last-child { mix-blend-mode: normal; opacity: 0.9; }
1163.cl-foot-brand p { margin-top: 18px; max-width: 280px; font: 400 15px/1.6 var(--cl-font); color: rgba(255, 255, 255, 0.7); }
1164.cl-foot-h { margin-bottom: 16px; font: 600 13px/1 var(--cl-font); letter-spacing: 0.06em; text-transform: uppercase; color: #A9D7C3; }
1165.cl-foot-grid li { margin-bottom: 10px; font: 400 15px/1.45 var(--cl-font); color: rgba(255, 255, 255, 0.8); }
1166.cl-foot-grid a { color: rgba(255, 255, 255, 0.85); transition: color var(--fd-dur-1) var(--fd-ease-out); }
1167.cl-foot-grid a:hover { color: #FFFFFF; text-decoration: underline; text-underline-offset: 3px; }
1168.cl-foot-legal { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 16px; padding-top: 28px; border-top: 1px solid rgba(255, 255, 255, 0.12); font: 400 13px/1.5 var(--cl-font); color: rgba(255, 255, 255, 0.68); }
1169.cl-foot-legal-links { display: flex; flex-wrap: wrap; gap: 20px; }
1170.cl-foot-legal a { color: rgba(255, 255, 255, 0.8); }
1171.cl-foot-legal a:hover { color: #FFFFFF; }
1172
1173/* RESPONSIVE */
1174@media (max-width: 1080px) {
1175 .cl-nav-links { display: none; }
1176 .cl-burger { display: block; }
1177 .cl-hero-grid { grid-template-columns: 1fr; gap: 48px; }
1178 .cl-hero-copy .cl-h1 { max-width: 14ch; }
1179 .cl-widget { max-width: 560px; }
1180 .cl-bento { grid-template-columns: repeat(2, 1fr); }
1181 .cl-stats, .cl-clin-grid { grid-template-columns: repeat(2, 1fr); }
1182 .cl-foot-grid { grid-template-columns: repeat(3, 1fr); }
1183 .cl-foot-brand { grid-column: 1 / -1; }
1184 .cl-journey-grid { gap: 48px; }
1185 .cl-stage-canvas { --cl-stage-s: 0.82; }
1186}
1187@media (max-width: 860px) {
1188 .cl-wrap { padding: 0 20px; }
1189 .cl-nav { padding: 10px 12px 0; }
1190 .cl-nav-sign { display: none; }
1191 .cl-hero { padding: 120px 0 72px; }
1192 .cl-orb { top: 30%; width: 760px; height: 760px; margin: -380px 0 0 -380px; }
1193 .cl-lede { font-size: 18px; }
1194 .cl-widget { padding: 20px; border-radius: 28px; }
1195 .cl-widget-head { flex-direction: column; align-items: flex-start; gap: 12px; }
1196 .cl-widget-head .cl-seg { width: 100%; }
1197 .cl-head-row { flex-direction: column; align-items: flex-start; gap: 16px; }
1198 .cl-services, .cl-clinicians { padding-bottom: 96px; }
1199 .cl-svc { min-height: 0; }
1200 .cl-svc .cl-h3 { margin-top: 20px; }
1201 .cl-journey { padding: 96px 0 72px; border-radius: 32px 32px 0 0; }
1202 .cl-journey-grid { grid-template-columns: 1fr; gap: 0; }
1203 .cl-stage-wrap { top: 76px; z-index: 2; margin: 0 -20px; padding: 0 20px 16px; background: linear-gradient(180deg, #FFFFFF 85%, rgba(255, 255, 255, 0)); }
1204 .cl-stage { aspect-ratio: auto; height: 280px; border-radius: 28px; }
1205 .cl-stage-canvas { --cl-stage-s: 0.54; }
1206 .cl-stage-rail { margin-top: 12px; }
1207 .cl-steps { padding: 0 0 8vh; }
1208 .cl-step { min-height: 52vh; justify-content: flex-start; padding-top: 24px; }
1209 .cl-step-t { font-size: 26px; }
1210 .cl-step .cl-body { font-size: 17px; }
1211 .cl-virtual, .cl-outcomes, .cl-pricing, .cl-faq { padding: 96px 0; }
1212 .cl-virtual-grid, .cl-faq-grid { grid-template-columns: 1fr; gap: 56px; }
1213 .cl-plans { grid-template-columns: 1fr; }
1214 .cl-cta-card { padding: 72px 24px; border-radius: 32px; }
1215}
1216@media (max-width: 560px) {
1217 .cl-h1 { font-size: 44px; }
1218 .cl-bento, .cl-stats { grid-template-columns: 1fr; }
1219 .cl-svc.is-wide { grid-column: auto; }
1220 .cl-clin-grid { grid-template-columns: 1fr 1fr; gap: 10px; }
1221 .cl-clin-link { padding: 6px; border-radius: 22px; }
1222 .cl-clin-body { padding: 12px 6px 6px; }
1223 .cl-clin-name { font-size: 16px; }
1224 .cl-clin-role, .cl-clin-langs, .cl-clin-next { font-size: 13px; }
1225 .cl-stat dd { font-size: 56px; }
1226 .cl-days { gap: 6px; }
1227 .cl-days button { min-height: 60px; border-radius: 16px; }
1228 .cl-phone { width: 100%; max-width: 340px; }
1229 .cl-phone-screen { height: 560px; }
1230 .cl-acc-panel p { padding-right: 8px; }
1231 .cl-acc-h button { font-size: 17px; }
1232 .cl-foot-grid { grid-template-columns: 1fr 1fr; gap: 32px; }
1233 .cl-seg-lg button { padding: 0 14px; font-size: 15px; }
1234 .cl-plan { padding: 26px; }
1235}
1236
1237@media (prefers-reduced-motion: reduce) {
1238 .cl *, .cl *::before, .cl *::after { animation-duration: 1ms !important; animation-iteration-count: 1 !important; animation-delay: 0ms !important; transition-duration: 120ms !important; transition-delay: 0ms !important; }
1239 .cl-orb { transform: none; }
1240 .cl-orb span { animation: none !important; }
1241 .cl-marquee { -webkit-mask-image: none; mask-image: none; }
1242 .cl-marquee-track { animation: none !important; width: auto; justify-content: center; }
1243 .cl-marquee-set { flex-wrap: wrap; justify-content: center; gap: 16px 40px; padding: 0 20px; }
1244 .cl-marquee-set[aria-hidden="true"] { display: none; }
1245 .cl-js [data-cl-rv] { transform: none; }
1246 .cl-js .cl-chat > * { opacity: 1; transform: none; }
1247 .cl-js .cl-typing { display: none; }
1248}
1249@media (prefers-contrast: more) {
1250 .cl-widget, .cl-nav.is-scrolled .cl-nav-in { background: #FFFFFF; -webkit-backdrop-filter: none; backdrop-filter: none; box-shadow: 0 0 0 1px var(--cl-ink); }
1251 .cl-slot, .cl-days button { box-shadow: inset 0 0 0 1px var(--cl-ink-2); }
1252 .cl-card, .cl-plan, .cl-clin-link, .cl-stat { box-shadow: 0 0 0 1px var(--cl-ink-2); }
1253}
1254@media (prefers-reduced-transparency: reduce) {
1255 .cl-widget, .cl-nav.is-scrolled .cl-nav-in { background: #FFFFFF; -webkit-backdrop-filter: none; backdrop-filter: none; }
1256}
1257`;

The design brief. For you and your AI agent.

Tokens, type, layout, components and motion — written from the real values in the file, so a model can extend the page without drifting.

Clara — DESIGN.md

A modern primary-care and virtual clinic in Seattle and Portland. Calm and trustworthy: soft clinical whites, a sage / teal accent, rounded geometry, a friendly rounded sans, and accessibility first (AA+ contrast, 44px+ hit targets, full keyboard support).

All CSS lives in Page.tsx under the .cl prefix. Every element is reset explicitly, so the page is independent of host resets. Illustrations and portraits are inline SVG; there are no image files or web fonts.

1. Palette

RoleTokenHex
Page canvas--cl-canvas#F6F8F7
Cards, white bands--cl-surface#FFFFFF
Soft tint (icon tiles, segmented track)--cl-tint#EAF2EE
Tint 2 (hover)--cl-tint-2#DCEBE4
Sage (orb, logo, flags)--cl-sage#9DBFAE
Primary teal (CTA, selected slot)--cl-teal#1F6F68
Teal ink (hover, small teal text)--cl-teal-ink#17544F
Ink (headings, dark CTA, footer)--cl-ink#0F2420
Body text--cl-ink-2#465A55
Tertiary text--cl-ink-3#66776F
Hairlines--cl-line#DFE7E3
Warm accent (illustration only)--cl-coral / --cl-peach#E26D5A / #F3D3BC
Availability dot—#2E9B6A
Success (booked)—#2E8A5F
Light teal on ink—#A9D7C3

Contrast: ink on canvas is about 16:1, --cl-ink-2 on white about 7.3:1, --cl-ink-3 on white about 4.6:1, white on teal about 6:1, and disabled slot text #8C9A95 is decorative alongside a strikethrough plus a hatched fill.

2. Typography

  • Text (--cl-font): ui-rounded, "SF Pro Rounded", ui-sans-serif, -apple-system, BlinkMacSystemFont, "SF Pro Text", "Inter", "Segoe UI", Roboto, sans-serif
  • Display (--cl-display): ui-rounded, "SF Pro Rounded", "SF Pro Display", ui-sans-serif, -apple-system, "Inter Display", "Inter", …
StyleSpec
H1display 600, clamp(44px, 5.6vw, 76px) / 1.02, −0.035em, max 12ch
H2display 600, clamp(32px, 3.6vw, 48px) / 1.08, −0.028em
H3display 600, 20px / 1.3 (journey step titles 32px, −0.025em)
Stat numberdisplay 600, 64px, −0.045em, tabular; suffix 32px teal
Pricedisplay 600, 64px / 72px, −0.045em
Lede400, 20px / 1.55
Body400, 17px / 1.6
Eyebrow600, 13px, 0.06em, uppercase, teal
Button600, 16px (15px small)

3. Spacing, radii, elevation

  • Container 1200px with 32px side padding (20px at ≤860px). Section padding 120–140px (96px mobile).
  • Radii are concentric:
  • cards 28px (--cl-r-card), with the inner portrait at 18px (--cl-r-inner = 28 − 10 padding)
  • widget 32px, plans 32px
  • journey stage 40px; CTA band 40px
  • day chips 18px
  • all controls capsules (9999px).
  • Elevation is soft: a 1px ring rgba(15,36,32,.05) plus at most one long low shadow, e.g. widget 0 40px 80px -40px rgba(15,36,32,.35), hovered card 0 24px 40px -24px rgba(15,36,32,.28).
  • Hit targets: buttons 52px (44px small), slots 48px, day chips 64px, FAQ rows 76px, nav links 44px.

4. Motion tokens

--fd-ease-out    cubic-bezier(0.22, 1, 0.36, 1)
--fd-ease-in-out cubic-bezier(0.65, 0, 0.35, 1)
--fd-spring      cubic-bezier(0.34, 1.56, 0.64, 1)
--fd-dur-1 120ms · --fd-dur-2 240ms · --fd-dur-3 420ms · --fd-dur-4 700ms

Choreography

  1. Hero load. Copy children rise 18px in a 80ms stagger (700ms); the widget rises at 200ms.
  2. Breathing orb. Three radial blobs (sage, peach, aqua) "breathe" on a 9s in-out loop: the main one scales 0.9→1.06 and its opacity 0.75→1, and the others counter-drift. The whole orb follows the mouse at ±24/18px through a damped lerp (factor 0.06).
  3. Booking widget.
  4. The visit-type segmented thumb springs (420ms).
  5. The selected day chip turns ink.
  6. The slot highlight is one measured pill that springs between slots (transform 520ms with spring; width and height 420ms).
  7. Arrow keys move the selection across free slots (roving tabindex).
  8. Confirm morphs: label slides up and out → spinner (700ms rotation) → green fill with a check that draws (dash offset 520ms).
  9. Insurance marquee. Two identical sets translate −50% over 42s, with an edge mask; pauses on hover.
  10. Care journey (sticky storytelling). The left stage is position: sticky; top: 110px. The step nearest 55% of viewport height becomes active and steps fade from 0.38 to 1 opacity. The illustration is the same seven absolutely positioned primitives, re-laid out per step: transform (760ms spring), size and radius (620ms out), colour (620ms in-out), with a 30ms stagger per primitive. A caption chip pops in 420ms after each morph, and a 4-part progress rail fills.
  11. Virtual chat. When the phone is 35% visible, messages arrive in sequence (spring, delays 200–3900ms) and a typing indicator appears and collapses.
  12. Outcome stats. Count up from 0 over 1800ms (easeOutQuart) at 40% visibility; each card's 4px bottom bar scales with the value.
  13. Cards. Services lift 4px on hover; clinician cards lift 6px and the portrait zooms 1.04.
  14. Pricing toggle. Spring thumb; prices re-mount and roll up from 70% (700ms spring).
  15. FAQ. grid-template-rows: 0fr → 1fr (420ms); text fades and settles; the + rotates 45° with the spring and fills teal.
  16. Reveals. [data-cl-rv] fade up 22px (700ms) with per-item --d delays.

5. Sections

  1. Sticky nav. A floating capsule that gains white glass (blur(20px)), a ring and a shadow on scroll, and narrows from 1200 to 1000px.
  2. Hero. Badge, H1, lede, two CTAs, proof row, booking widget, breathing orb.
  3. Insurance marquee. Eight fictional insurers with line-glyph marks.
  4. Services bento. 4 columns, two wide cards.
  5. Care journey. Sticky morphing stage plus four steps.
  6. Virtual clinic. Copy, ticks, and an animated phone conversation.
  7. Outcomes. Four count-up stats plus a methodology footnote.
  8. Clinicians. Four illustrated portrait cards with languages and next availability.
  9. Pricing. Monthly/annual toggle and three plans (featured plan in ink).
  10. FAQ. Five accordions.
  11. CTA band. Teal with a breathing orb.
  12. Footer. Emergency notice, brand, clinics, care, company, hours, legal.

6. Components and states

  • Primary button. Teal, with an inner highlight and a teal glow shadow. Hover → teal-ink with the arrow nudged 3px; press scales to 0.96.
  • Ghost / soft / light buttons. Ghost is a 70%-white capsule with a 1.5px hairline (hover: white with a sage ring); soft uses the tint fill; light is white on teal.
  • Slot. States: idle (hairline), hover (tint plus sage ring), selected (white text over the moving teal pill), disabled (hatched, struck through, aria-disabled through native disabled).
  • Day chip. Idle canvas with a hairline; hover sage ring; selected ink.
  • Confirm. States idle | busy | done; disabled (no slots) is grey with a dark label; the status line is aria-live.
  • Accordion. Native button with aria-expanded and aria-controls; panel role="region".

7. Responsive

  • ≤1080px: burger menu, the hero stacks (widget max 560px), bento, stats and clinicians go 2-up, the stage canvas scales to 0.82.
  • ≤860px:
  • the widget header stacks
  • the journey becomes one column, with the stage sticky under the nav (280px tall, canvas scale 0.54, a white fade under it) and steps scrolling beneath
  • plans stack.
  • ≤560px: 44px H1, single-column bento and stats, 2-up compact clinician cards, full-width phone.

8. Accessibility and reduced motion

  • Skip link, landmarks, labelled sections, role="radiogroup"/radio for visit type, day, slot and billing. Arrow-key navigation in slots. Visible 2px teal focus ring at 70%.
  • prefers-reduced-motion:
  • no orb breathing or pointer follow
  • the marquee becomes a static wrapped list
  • no count-up (real values render immediately)
  • chat messages are visible with no typing indicator
  • transitions are capped at 120ms.
  • prefers-contrast: more: opaque surfaces with ink rings. prefers-reduced-transparency: opaque widget and nav.
  • Fixes the html+body overflow host quirk that breaks position: sticky, and restores it on unmount.

9. Do / Don't

  • Do keep one teal action per view and use ink for the confirm action.
  • Do keep radii concentric (outer − padding = inner) and controls capsule-shaped.
  • Do write numbers with units and sources; healthcare copy must be specific and calm.
  • Don't use red for anything but the illustration's "end call" and heart accents. Errors and emergencies use words, not colour alone.
  • Don't shrink targets below 44px or put body text below 13px.
  • Don't autoplay anything that carries essential information; the chat is illustrative and also described in its aria-label.

Assets

Clinician portraits: Placeholder portraits live in public/img/people/ (p1.webp to p9.webp, 328×328). Copy the folder next to the page so root-relative /img/people/... URLs resolve, or swap in your own photos. They are lazy-loaded and cropped with object-fit: cover; object-position: center top.

Questions about Clara

Primary care and a virtual clinic that has time for you. It is a free healthcare landing page for React with a matching DESIGN.md brief.

Open the page, click Copy full source or Download .tsx, and drop the single Page file into your React project. Copy the public/img folder next to it for the demo photography, or swap in your own images.

Yes. It is MIT-licensed: free for personal and commercial projects, no signup and no attribution required.

Yes. The DESIGN.md describes tokens, type scale, layout, components and motion so Claude Code, Cursor, Lovable or v0 can extend the page without drifting from its look.