// NOTE: verbatim copy of apps/web/src/styles/_theme.scss. Extracting these // tokens into a shared package (consumed by both apps) is tracked separately // — keep the two files in sync by hand until then. // ============================================================================= // Design tokens — the single source of truth for colors, spacing, typography // and other reusable values across the whole app. // // Exposed as CSS custom properties on :root (not plain SCSS variables) so // they're available at *runtime*, not just compile time — this is what lets // dark mode work below by simply redefining these variables instead of // rebuilding the stylesheet. Every other .scss file should reference // `var(--token-name)`, never a hardcoded color/size. // // Palette name: "Mise en Place" — a kitchen-operations identity (batch // cooking as logistics: everything labeled and in its place before you // start) rather than a food-blog one. See the design proposal for the full // rationale: https://claude.ai/code/artifact/1db63af0-cfd1-4f77-9369-71ca6accd06f // // Import this partial once, globally (see global.scss) — never re-import it // from a component-level .scss file, `:root` only needs to be declared once. // ============================================================================= :root { // --- Surfaces & ink --------------------------------------------------- // Neutral surface: page background ("porcelaine") vs. the card surface // content sits on, plus a recessed variant for panels/table headers. --color-background: #eef2ed; --color-surface: #ffffff; --color-surface-alt: #e2e8e0; // Text. --color-text: #1f2a22; --color-text-muted: #57685a; --color-border: #c7d0c4; // --- Brand accents, each with one job -------------------------------- // Basil — primary actions, links, brand presence. --color-primary: #2e6b4a; --color-primary-hover: #244f38; // Vermillion — secondary accent for urgency/strong calls to action // (e.g. a timer, "start session"). Never reused for allergen alerts // below — those need their own, unambiguous color. --color-accent: #cc4b26; --color-accent-hover: #a83c1c; // Turmeric — category/classification tags. --color-tag: #c98a1b; --color-tag-ink: #3a2c05; // pairs with a solid --color-tag fill only. // --- Feedback ----------------------------------------------------------- --color-success: #2e6b4a; --color-warning: #c98a1b; --color-error: #b3271e; // --- Allergens / intolerances -------------------------------------------- // A 3-tier food-safety scale, kept distinct from --color-error so an // allergen warning is never confused with a form validation error: // - critical (declared allergen): its own color, solid/inverted fill // - moderate (intolerance): reuses --color-warning, tinted fill // - trace ("may contain traces of…"): neutral, dashed outline // The severity is carried by the FILL TREATMENT, not the hue alone, so // it stays legible for color-blind users. See the design proposal's // "Alertes & allergènes" section for the full component set. --color-allergen: #a8123f; --color-allergen-ink: #ffe9ef; // pairs with a solid --color-allergen fill only. // --- Spacing scale --------------------------------------------------------- // Multiples of a 4px base unit — use these instead of ad hoc px values so // spacing stays visually consistent as the app grows. --space-xs: 0.25rem; // 4px --space-sm: 0.5rem; // 8px --space-md: 1rem; // 16px --space-lg: 1.5rem; // 24px --space-xl: 2rem; // 32px --space-2xl: 3rem; // 48px — inter-section spacing // --- Typography -------------------------------------------------------- // System font stacks only — no remote webfont, so there's zero loading // latency and no flash of unstyled text, which fits an app meant to be // used quickly under time pressure. Three roles: a condensed "label" // face for headings/eyebrows, a humanist face for body copy, and a // monospace for anything that lines up in columns (times, quantities). --font-display: "Bahnschrift", "Arial Narrow", "Segoe UI", sans-serif; --font-body: "Segoe UI", "Helvetica Neue", Arial, sans-serif; --font-mono: "Cascadia Mono", Consolas, "SF Mono", "Liberation Mono", monospace; --font-size-xs: 0.75rem; // 12px — captions, meta --font-size-sm: 0.875rem; // 14px — labels, secondary text --font-size-base: 1rem; // 16px — body --font-size-md: 1.125rem; // 18px — lead paragraph --font-size-lg: 1.375rem; // 22px — H3 / card titles --font-size-xl: 1.75rem; // 28px — H2 / section titles --font-size-2xl: 2.25rem; // 36px — H1 / page titles --font-size-3xl: 3rem; // 48px — display, exceptional use only // --- Shape / elevation -------------------------------------------------- --radius-base: 4px; // controls (inputs, buttons) — deliberately flat --radius-md: 10px; // cards --radius-lg: 18px; // panels, modals --radius-pill: 999px; // tags, badges --max-width-form: 22rem; --shadow-sm: 0 1px 2px rgba(31, 42, 34, 0.08), 0 1px 1px rgba(31, 42, 34, 0.06); --shadow-md: 0 6px 16px rgba(31, 42, 34, 0.12), 0 2px 6px rgba(31, 42, 34, 0.08); } // Lets the browser pick sensible default colors (form controls, scrollbars) // for whichever mode the user ends up in. :root { color-scheme: light dark; } // --- Dark mode --------------------------------------------------------- // Follows the OS/browser preference by default. Guarded with // `:root:not([data-theme="light"])` so an explicit "light" choice (see // apps/web's `ThemeContext`, `SYSTEM` = no `data-theme` attribute at all — // this block then decides) can override a dark OS setting. @media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { --color-background: #14181a; --color-surface: #1c221e; --color-surface-alt: #262e27; --color-text: #edf1ea; --color-text-muted: #a9b5a6; --color-border: #384038; --color-primary: #5fae7e; --color-primary-hover: #7cc496; --color-accent: #ea7a48; --color-accent-hover: #f0946c; --color-tag: #e8b84b; --color-tag-ink: #2a2005; --color-success: #5fae7e; --color-warning: #e8b84b; --color-error: #e5675a; --color-allergen: #e2547b; --color-allergen-ink: #3a0416; --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.35); --shadow-md: 0 8px 20px rgba(0, 0, 0, 0.45); } } // Mirrors the block above for an explicit "dark" choice (`ThemeContext` // sets `data-theme="dark"` on ``), so it wins over the OS setting in // both directions. :root[data-theme="dark"] { --color-background: #14181a; --color-surface: #1c221e; --color-surface-alt: #262e27; --color-text: #edf1ea; --color-text-muted: #a9b5a6; --color-border: #384038; --color-primary: #5fae7e; --color-primary-hover: #7cc496; --color-accent: #ea7a48; --color-accent-hover: #f0946c; --color-tag: #e8b84b; --color-tag-ink: #2a2005; --color-success: #5fae7e; --color-warning: #e8b84b; --color-error: #e5675a; --color-allergen: #e2547b; --color-allergen-ink: #3a0416; --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.35); --shadow-md: 0 8px 20px rgba(0, 0, 0, 0.45); }