/* * Lantern — warm paper, kitchen table not clinic. * * An access-first theme: WCAG AAA as identity, not compliance. Lantern is the * proof that AAA can feel warm and human. The surface is warm ivory paper — * high lightness on purpose, so 7:1 ink is easy and nothing has to shout. * Ink is a near-black warm umber (~15:1 on paper). The single accent is a deep * amber-brown gold — a lantern's brass, not a yellow hazard — carrying a * warm-white label well above 7:1. Links share the same deep gold and are * underlined by default. Built for people who deserve dignity, clarity, and * zero squinting: NDIS participants, their families, older support * coordinators. The discipline IS the personality. * * Dark mode is the lantern lit: warm dark umber, warm-white ink, and the gold * turned luminous with a black-umber label on top (bright-swatch/dark-ink, the * high-contrast direction). * * Family DNA (shared across the access candidates): * - Type ramp starts larger (body 1.125rem/1.65); captions never below 14px. * - Body ink AND muted-foreground >= 7:1 on background AND card, both modes. * - Primary label >= 7:1 on primary; status labels >= 7:1 where feasible. * - Focus: 3px solid outline + 2px offset; inputs get border change + ring. * - Links underlined by default; underline thickens on hover. * - Touch targets: 2.75rem min-height on buttons/inputs GLOBALLY. * - Borders strong (ink at ~0.25-0.3 alpha) — boundaries, not decoration. * - Motion minimal and quick; springs alias standard; reduced-motion honored. * * Computed contrast (exact WCAG 2.1 relative-luminance math, oklch -> sRGB; * sketched first with Y ~ L^3, then verified with the validator's converter): * LIGHT * foreground L0.16 on background L0.97 ..... 17.81:1 * foreground L0.16 on card L0.995 .......... 19.14:1 * muted-foreground L0.36 on background ..... 9.99:1 * muted-foreground L0.36 on card ........... 10.73:1 * muted-foreground L0.36 on muted L0.93 .... 8.86:1 * primary-foreground L0.985 on primary L0.40 9.00:1 * status labels L0.985 on L0.40-0.42 fills . 8.09-8.77:1 * DARK * foreground L0.95 on background L0.17 ..... 16.54:1 * foreground L0.95 on card L0.22 ........... 14.98:1 * muted-foreground L0.78 on background ..... 9.55:1 * muted-foreground L0.78 on card ........... 8.65:1 * muted-foreground L0.78 on muted L0.27 .... 7.54:1 * primary-foreground L0.15 on primary L0.78 9.73:1 * status inks L0.16 on L0.72-0.80 fills .... 7.40-10.22:1 * * Token contract: Crema v1 (create-crema-app/TOKEN_CONTRACT.md). */ /* * Fonts: consuming apps load Lexend (400/500/600/700) + JetBrains Mono * (400/500/600) at the top of their entry CSS via the URL documented in this * theme's README. Lexend is chosen deliberately — it was designed to improve * reading proficiency — and serves body AND headings. No @import here (PostCSS * ordering) and no URL smuggled in comments. */ :root { --font-sans: "Lexend", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; --font-heading: "Lexend", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace; /* Tailwind utility families — mirror --font-heading/--font-sans. */ --heading-family: "Lexend", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; --body-family: "Lexend", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; /* ── Colors ── warm ivory paper, warm-white cards, near-black warm ink. * High-lightness surface keeps every 7:1 pair easy. */ --background: oklch(0.97 0.012 85); --foreground: oklch(0.16 0.01 60); /* ~17.8:1 on background */ --card: oklch(0.995 0.006 85); --card-foreground: oklch(0.16 0.01 60); /* ~19.1:1 on card */ --popover: oklch(0.99 0.007 85); --popover-foreground: oklch(0.16 0.01 60); /* Primary — the lantern's brass: deep amber-brown gold with a warm-white * label. L0.40 fill vs L0.985 label ~8.8:1 (>= 7:1 AAA). */ --primary: oklch(0.4 0.11 70); --primary-foreground: oklch(0.985 0.008 85); --secondary: oklch(0.91 0.025 80); --secondary-foreground: oklch(0.25 0.03 65); /* ~12.2:1 on secondary */ /* Muted stays light so muted-foreground can hold 7:1 on it too. */ --muted: oklch(0.93 0.015 83); --muted-foreground: oklch(0.36 0.015 65); /* ~9.96:1 bg / ~10.7:1 card / ~8.8:1 muted */ /* Accent — warm gold wash for hover/selection with deep gold-brown ink. */ --accent: oklch(0.9 0.055 85); --accent-foreground: oklch(0.33 0.09 70); /* ~9.1:1 on accent */ /* ── Status ── deep fills carrying warm-white labels, all >= 7:1. * Warning is pulled to deep amber-ORANGE (hue 55) and darker than any * yellow so it never reads as a pale hazard stripe. */ --destructive: oklch(0.42 0.16 27); --destructive-foreground: oklch(0.985 0.008 27); /* ~8.1:1 */ --success: oklch(0.4 0.1 150); --success-foreground: oklch(0.985 0.008 150); /* ~8.8:1 */ --warning: oklch(0.42 0.12 55); --warning-foreground: oklch(0.985 0.008 55); /* ~8.1:1 */ --info: oklch(0.42 0.1 250); --info-foreground: oklch(0.985 0.008 250); /* ~8.1:1 */ /* Borders STRONG — ink at 0.25-0.3 alpha. Visible boundaries. */ --border: oklch(0.16 0.01 60 / 0.27); --input: oklch(0.16 0.01 60 / 0.32); --ring: oklch(0.4 0.11 70); /* Charts — hues >= 60 degrees apart (80/150/220/290/20), adjacent * lightness varied, all deep enough to sit legibly on paper. */ --chart-1: oklch(0.55 0.12 80); --chart-2: oklch(0.45 0.1 150); --chart-3: oklch(0.6 0.1 220); --chart-4: oklch(0.45 0.12 290); --chart-5: oklch(0.52 0.14 20); /* Sidebar — slightly deeper paper, same ink, same brass. */ --sidebar: oklch(0.945 0.014 84); --sidebar-foreground: oklch(0.16 0.01 60); --sidebar-primary: oklch(0.4 0.11 70); --sidebar-primary-foreground: oklch(0.985 0.008 85); --sidebar-accent: oklch(0.9 0.055 85); --sidebar-accent-foreground: oklch(0.33 0.09 70); --sidebar-border: oklch(0.16 0.01 60 / 0.22); --sidebar-ring: oklch(0.4 0.11 70); /* Syntax — deep, calm hues on the paper; comments stay >= 7:1 too. */ --syntax-keyword: oklch(0.42 0.12 290); --syntax-string: oklch(0.42 0.1 150); --syntax-number: oklch(0.44 0.12 55); --syntax-comment: oklch(0.44 0.015 65); --syntax-function: oklch(0.42 0.1 250); --syntax-type: oklch(0.42 0.08 200); /* ── Chat surfaces ── * User bubble is a deep warm-umber panel with warm-white text (~13:1); * assistant bubble is a warm-white card with a strong border. */ --chat-user-bg: oklch(0.3 0.05 65); --chat-user-fg: oklch(0.985 0.008 85); --chat-assistant-bg: oklch(0.995 0.006 85); --chat-assistant-fg: oklch(0.16 0.01 60); --chat-assistant-border: oklch(0.16 0.01 60 / 0.27); /* Soft but modest. */ --radius: 0.625rem; /* ── Motion ── minimal and quick; nothing essential is motion-only. * Springs alias to standard — calm by construction. */ --duration-fast: 120ms; --duration-base: 200ms; --duration-slow: 300ms; --duration-slower: 400ms; --duration-spring: 200ms; --ease-standard: cubic-bezier(0.2, 0, 0, 1); --ease-decelerate: cubic-bezier(0, 0, 0, 1); --ease-accelerate: cubic-bezier(0.3, 0, 1, 1); --ease-emphasized: cubic-bezier(0.2, 0, 0, 1); --ease-spring-gentle: var(--ease-standard); --ease-spring-snappy: var(--ease-standard); --ease-spring-bouncy: var(--ease-standard); /* ── Typography ── access ramp: starts larger, generous line-heights, * caption never below 14px. Fixed rem, product register. */ --text-hero-size: 3rem; --text-hero-lh: 1.1; --text-display-size: 2.5rem; --text-display-lh: 1.15; --text-headline-size: 1.875rem; --text-headline-lh: 1.25; --text-title-size: 1.5rem; --text-title-lh: 1.35; --text-subtitle-size: 1.25rem; --text-subtitle-lh: 1.5; --text-body-size: 1.125rem; --text-body-lh: 1.65; --text-label-size: 1rem; --text-label-lh: 1.5; --text-caption-size: 0.875rem; --text-caption-lh: 1.4; /* ── Elevation ── low and warm; separation is the borders' job. */ --elevation-0: none; --elevation-1: 0 1px 2px oklch(0.16 0.01 60 / 0.05); --elevation-2: 0 1px 3px oklch(0.16 0.01 60 / 0.07), 0 1px 2px oklch(0.16 0.01 60 / 0.04); --elevation-3: 0 4px 8px -2px oklch(0.16 0.01 60 / 0.08), 0 2px 4px -2px oklch(0.16 0.01 60 / 0.04); --elevation-4: 0 10px 20px -6px oklch(0.16 0.01 60 / 0.1), 0 4px 8px -4px oklch(0.16 0.01 60 / 0.05); --elevation-5: 0 18px 36px -8px oklch(0.16 0.01 60 / 0.14); --spacing: 0.25rem; /* Border widths — no sub-pixel hairlines in an access theme. */ --border-width-thin: 1px; --border-width-base: 1.5px; --border-width-thick: 3px; --border-width-heavy: 5px; /* No glass — inert values so consuming apps referencing these get no-ops. */ --glass-blur: 0px; --glass-saturate: 100%; --glass-brightness: 1; --glass-contrast: 1; } /* * Dark mode — the lantern lit. Warm dark umber, warm-white ink, cards a full * +0.05 L above the background, popover above card and below muted so the * altitude ladder stays readable. The gold turns luminous and carries a * black-umber label (bright-swatch/dark-ink), as do all dark status fills. */ .dark { --background: oklch(0.17 0.012 60); --foreground: oklch(0.95 0.01 80); /* ~16.5:1 on background */ --card: oklch(0.22 0.012 60); --card-foreground: oklch(0.95 0.01 80); /* ~15.0:1 on card */ --popover: oklch(0.245 0.012 60); --popover-foreground: oklch(0.95 0.01 80); /* Luminous warm gold, black-umber ink — ~9.8:1. */ --primary: oklch(0.78 0.13 80); --primary-foreground: oklch(0.15 0.03 70); --secondary: oklch(0.27 0.02 65); --secondary-foreground: oklch(0.93 0.01 80); --muted: oklch(0.27 0.015 62); --muted-foreground: oklch(0.78 0.015 75); /* ~9.6:1 bg / ~8.7:1 card / ~7.5:1 muted */ --accent: oklch(0.3 0.05 75); --accent-foreground: oklch(0.85 0.11 82); /* ~8.6:1 on accent */ /* Status — bright fills, dark umber inks, all >= 7:1. */ --destructive: oklch(0.72 0.14 25); --destructive-foreground: oklch(0.16 0.03 25); /* ~7.8:1 */ --success: oklch(0.78 0.15 150); --success-foreground: oklch(0.16 0.03 150); /* ~9.7:1 */ --warning: oklch(0.8 0.14 60); --warning-foreground: oklch(0.16 0.03 60); /* ~10.4:1 */ --info: oklch(0.75 0.1 250); --info-foreground: oklch(0.16 0.03 250); /* ~8.7:1 */ --border: oklch(0.95 0.01 80 / 0.25); --input: oklch(0.95 0.01 80 / 0.3); --ring: oklch(0.78 0.13 80); --chart-1: oklch(0.8 0.13 80); --chart-2: oklch(0.7 0.13 150); --chart-3: oklch(0.75 0.1 220); --chart-4: oklch(0.68 0.12 290); --chart-5: oklch(0.72 0.14 20); --sidebar: oklch(0.2 0.012 60); --sidebar-foreground: oklch(0.95 0.01 80); --sidebar-primary: oklch(0.78 0.13 80); --sidebar-primary-foreground: oklch(0.15 0.03 70); --sidebar-accent: oklch(0.3 0.05 75); --sidebar-accent-foreground: oklch(0.85 0.11 82); --sidebar-border: oklch(0.95 0.01 80 / 0.2); --sidebar-ring: oklch(0.78 0.13 80); --syntax-keyword: oklch(0.78 0.1 290); --syntax-string: oklch(0.78 0.12 150); --syntax-number: oklch(0.82 0.12 70); --syntax-comment: oklch(0.72 0.015 70); --syntax-function: oklch(0.75 0.1 250); --syntax-type: oklch(0.78 0.08 200); /* ── Chat surfaces (dark) ── */ --chat-user-bg: oklch(0.32 0.04 70); --chat-user-fg: oklch(0.96 0.01 80); --chat-assistant-bg: oklch(0.22 0.012 60); --chat-assistant-fg: oklch(0.95 0.01 80); --chat-assistant-border: oklch(0.95 0.01 80 / 0.25); --elevation-1: 0 1px 2px oklch(0 0 0 / 0.3); --elevation-2: 0 1px 3px oklch(0 0 0 / 0.4), 0 1px 2px oklch(0 0 0 / 0.25); --elevation-3: 0 4px 8px -2px oklch(0 0 0 / 0.4), 0 2px 4px -2px oklch(0 0 0 / 0.25); --elevation-4: 0 10px 20px -6px oklch(0 0 0 / 0.45), 0 4px 8px -4px oklch(0 0 0 / 0.25); --elevation-5: 0 18px 36px -8px oklch(0 0 0 / 0.55); } /* * @layer base — Lantern's warm, legible philosophy. * * Lexend for everything (it earns its keep at reading time), strong visible * boundaries, one brass accent, links that look like links, and focus you can * find from across the kitchen table. */ @layer base { body { min-height: 100vh; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; font-family: var(--font-sans); font-size: var(--text-body-size); line-height: var(--text-body-lh); } /* Headings — Lexend 600. `color: inherit` so headings inside colored * surfaces (primary buttons, status banners, chat bubbles) stay legible. */ h1, h2, h3, h4, [data-slot="card-title"], [data-slot="dialog-title"], [data-slot="sheet-title"], [data-slot="alert-dialog-title"] { font-family: var(--font-heading); font-weight: 600; letter-spacing: -0.01em; color: inherit; } code, kbd, samp, pre, [data-slot="code"], [data-slot="code-block"] { font-family: var(--font-mono); } /* Inline code — foreground-tint chip, foreground ink. */ :not(pre) > code { padding: 0.1em 0.35em; border-radius: calc(var(--radius) * 0.5); background: color-mix(in oklch, var(--foreground) 7%, transparent); color: var(--foreground); font-size: 0.92em; } /* Selection — the brass, as a wash. */ ::selection { background: color-mix(in oklch, var(--primary) 30%, transparent); color: var(--foreground); } /* Links — deep gold, UNDERLINED BY DEFAULT (a link must look like a link * without color vision); underline thickens on hover. */ a { color: var(--primary); text-decoration-line: underline; text-decoration-thickness: 0.07em; text-underline-offset: 0.18em; transition: text-decoration-thickness var(--duration-fast) var(--ease-standard); } a:hover { text-decoration-thickness: 0.14em; } [data-slot="sidebar"] { background: var(--sidebar); border-right: var(--border-width-base) solid var(--sidebar-border); } } /* * Focus-visible — 3px solid brass outline, 2px offset. Always visible, * findable at arm's length. Placed outside @layer base so it beats Tailwind's * default ring utilities. */ [data-slot="button"]:focus-visible, [data-slot="select-trigger"]:focus-visible { outline: 3px solid var(--ring); outline-offset: 2px; box-shadow: none; } /* Buttons — medium weight, generous letterforms, no shrinking targets. */ [data-slot="button"] { font-weight: 500; } /* Card titles — pinned to the subtitle role so the scale is the theme's * decision, not the card primitive's default. */ [data-slot="card-title"] { font-size: var(--text-subtitle-size); line-height: var(--text-subtitle-lh); } /* * Touch targets — 44px floor GLOBALLY, not just for coarse pointers. Tremor, * arthritis, and a hurried mouse all deserve the same landing pad. */ [data-slot="button"] { min-height: 2.75rem; min-width: 2.75rem; } [data-slot="input"], [data-slot="select-trigger"] { min-height: 2.75rem; } /* Coarse pointers keep their explicit guarantee too. */ @media (pointer: coarse) { [data-slot="button"] { min-height: 2.75rem; min-width: 2.75rem; } [data-slot="input"], [data-slot="select-trigger"] { min-height: 2.75rem; } } [data-slot="button"]:hover:not(:disabled) { opacity: 0.92; } [data-slot="button"]:active:not(:disabled) { opacity: 0.84; } /* Inputs — warm-white field, STRONG border, brass focus: border-color change * plus a 2px ring so focus survives low vision and bright rooms. */ [data-slot="input"], [data-slot="textarea"], [data-slot="select-trigger"] { background: var(--card); border: var(--border-width-base) solid var(--input); border-radius: var(--radius); color: var(--foreground); transition: border-color var(--duration-fast) var(--ease-standard), box-shadow var(--duration-fast) var(--ease-standard); } [data-slot="input"]::placeholder, [data-slot="textarea"]::placeholder { color: var(--muted-foreground); } [data-slot="input"]:hover:not(:disabled), [data-slot="textarea"]:hover:not(:disabled), [data-slot="select-trigger"]:hover:not(:disabled) { border-color: color-mix(in oklch, var(--foreground) 45%, transparent); } [data-slot="input"]:focus, [data-slot="input"]:focus-visible, [data-slot="textarea"]:focus, [data-slot="textarea"]:focus-visible, [data-slot="select-trigger"]:focus { border-color: var(--primary); box-shadow: 0 0 0 2px var(--ring); outline: none; } /* Reduced motion — zero transitions on the interactive slots; nothing in * Lantern depends on movement to be understood. */ @media (prefers-reduced-motion: reduce) { [data-slot="button"], [data-slot="input"], [data-slot="textarea"], [data-slot="select-trigger"], a { transition: none; } }