FirstSip.me is a calm morning-ritual product: warm minimalism, editorial feel, premium and timeless. The system avoids SaaS blue, neon gradients, and flashy UI; it prioritizes readability, soft contrast, ample whitespace, and daily comfort. Primary and secondary colors are chosen for clear contrast on the page background and distinct use (CTAs vs UI chrome).
| Role | Font | Rationale |
|---|---|---|
| Heading | Lora (serif) | Editorial, warm, excellent readability and Polish (ą, ę, ó, ś, etc.). Used by many newspapers/magazines. |
| Body | Source Sans 3 (sans) | Neutral, highly readable at small sizes, full Latin Extended. Pairs well with Lora. |
| Element | Class / size | Line-height | Letter-spacing |
|---|---|---|---|
| H1 | text-3xl / text-4xl | leading-tight | tracking-tight |
| H2 | text-2xl | leading-tight | tracking-tight |
| H3 | text-xl | leading-snug | default |
| H4 | text-lg | leading-snug | default |
| Body | text-base | leading-relaxed | default |
| Small / meta | text-sm | leading-normal | default |
| Token | Tailwind | Rationale / use |
|---|---|---|
| Primary | amber-700 | Links and primary CTAs; warm accent. |
| Primary foreground | stone-50 | Text on primary buttons/backgrounds. |
| Secondary | slate-600 | Secondary buttons, tabs, badges, UI chrome. |
| Secondary foreground | stone-50 | Text on secondary-filled elements. |
| Success | emerald-600 | Positive actions, success states. |
| Error / destructive | rose-600 | Calm destructive: alerts, delete buttons, errors. |
| Page background | stone-50 | Warm off-white, easy on the eyes. |
| Card background | stone-100 | Slightly warmer than white; editorial feel. |
| Border | stone-200 | Soft, consistent with warm palette. |
| Muted text | slate-500 | Timestamps, helper text, metadata; same hue as secondary. |
| Ring | amber-700 | Focus ring for inputs, buttons. |
Use secondary as background for filled UI: secondary buttons, selected tabs, filled badges, pill controls. Use secondary as text/chrome only when you need a subdued label that still reads as UI (e.g. “Cancel” next to primary). Keep secondary-foreground light (stone-50) on secondary fills for contrast. Prefer ghost for low-emphasis actions and muted (bg-muted, text-muted-foreground) for non-interactive chrome so content stays clearly primary.
shadcn: secondary button = fill; ghost = hover only; muted UI = CardDescription, table headers, helper text.
slate-500 for muted-foreground fits better with slate-600 secondary: same hue family, so UI chrome and metadata feel coherent. It stays readable for timestamps, bylines, helper text and placeholders without competing with body text. Slightly cooler than stone-500 but still calm and editorial.
Use for: timestamps, “2 min read”, captions, form hints, table secondary cells.
rose-600 is a calmer, more “human” destructive than red-600: less aggressive, still clearly an error or delete action. Use for destructive buttons, error alerts and inline error text. Contrast remains sufficient on light backgrounds; pair with light rose tint (e.g. rose-50 bg) in alerts.
When: delete/remove actions, validation errors, Alert variant="destructive".
Pure white on stone-50 page can feel a bit cold. stone-100 for card (and popover) gives a slightly warmer, off-white lift that fits the editorial morning vibe while keeping clear separation from the page. Border and shadow stay subtle.
Tailwind: stone-100 for card/popover; page stays stone-50.
Body text: a calm morning ritual. Read in five to ten minutes with your coffee. High-signal updates, no doom-scrolling. Polish characters: ą, ę, ó, ś, ź, ż, ć, ń.
Small / meta: byline, date, category, or caption.
Card content with comfortable padding. Use for article previews, settings panels, or grouped actions.
Border, focus ring and placeholder use theme tokens.
Inline default link and another link (visit to see muted). No neon; underline on hover.
Paste into app/globals.css :root to apply the FirstSip palette site-wide. Primary/ring: amber-700; secondary: slate-600; muted-foreground: slate-500; destructive: rose-600; card: stone-100.
:root {
--radius: 0.5rem;
--background: /* stone-50 */ oklch(0.985 0.002 56.043);
--foreground: /* stone-900 */ oklch(0.208 0.006 56.043);
--card: /* stone-100 */ oklch(0.966 0.004 56.043);
--card-foreground: oklch(0.208 0.006 56.043);
--primary: /* amber-700 */ oklch(0.555 0.163 49);
--primary-foreground: /* stone-50 */ oklch(0.985 0.002 56.043);
--secondary: /* slate-600 */ oklch(0.446 0.037 257);
--secondary-foreground: oklch(0.985 0.002 56.043);
--muted: oklch(0.968 0.003 56.043);
--muted-foreground: /* slate-500 */ oklch(0.554 0.046 257.417);
--accent: oklch(0.968 0.003 56.043);
--accent-foreground: oklch(0.208 0.006 56.043);
--destructive: /* rose-600 */ oklch(0.55 0.17 12);
--border: /* stone-200 */ oklch(0.922 0.004 56.043);
--input: oklch(0.922 0.004 56.043);
--ring: /* amber-700 */ oklch(0.555 0.163 49);
}