Apply the "Warm Editorial Refinement" design system — a sophisticated, executive-grade aesthetic with warm cream surfaces (light mode) and warm charcoal surfaces (dark mode), Bahnschrift + Plus Jakarta Sans typography, generous rounded corners, multi-layer shadows, and a warm neutral palette. Supports both light and dark themes via CSS custom properties and the `.dark` class. Use this skill whenever the user wants to build an app, dashboard, component, or web UI using the abc-project visual style. Trigger on phrases like "use our design system", "apply our template", "make it look like abc-project", "use the warm editorial style", "use our brand template", "add dark mode", or any request to build a new tool/app/dashboard for XYZ Brand or similar contexts. This is the canonical design template for all new frontend builds.
Resources
2Install
npx skillscat add saajunaid/caddis-plugin/warm-editorial-ui Install via the SkillsCat registry.
Warm Editorial Refinement — Design System
A premium, editorial-grade UI template built for data-rich internal tools. Combines the warmth of analogue design with the precision of modern SaaS.
Canonical reference apps: scratch/mockups/ceo-dashboard-mockup.html (executive-reviewed baseline)
Design Philosophy
Warm surfaces. Editorial type. Intentional depth. Not corporate grey — warm cream.
This system was designed for XYZ Brand internal tools but is brand-agnostic at the token level. It avoids cold grey SaaS aesthetics and instead uses warm-toned surfaces, editorial typography, and refined component geometry.
Design Tokens
Always define these CSS custom properties in :root:
:root {
/* Brand Accent — replace with your brand color */
--brand: #E10A0A;
--brand-dark: #C00909;
--brand-soft: #FEF2F2;
--brand-tint: rgba(225,10,10,0.08);
/* Warm Surfaces — NOT cold grey */
--bg: #F5F3F0; /* page background */
--surface: #FFFFFF; /* cards, panels */
--surface-2: #F9F8F6; /* subtle inset, inputs */
--surface-3: #F0EDE8; /* deeper inset, table rows */
--surface-hover: #EFEDE9; /* hover states */
/* Warm Borders */
--border: #E5E2DC;
--border-strong: #CCC9C2;
/* Warm Ink (text) — slightly brown-tinged, never cold */
--ink-1: #1A1816; /* primary text */
--ink-2: #3D3A36; /* secondary text */
--ink-3: #6B6760; /* tertiary text */
--ink-4: #9C9890; /* muted/placeholder */
/* Status Palette */
--green: #16A34A;
--green-soft: #F0FDF4;
--green-tint: rgba(22,163,74,0.12);
--green-border: #A7F3D0;
--amber: #D97706;
--amber-soft: #FFFBEB;
--red: #DC2626;
--red-soft: #FEF2F2;
--red-border: #FCA5A5;
--blue: #2563EB;
--blue-soft: #EFF6FF;
--blue-border: #BFDBFE;
/* Radius Scale — generous, not tight */
--r-xs: 4px;
--r-sm: 8px;
--r-md: 12px;
--r-lg: 16px; /* standard cards */
--r-xl: 22px; /* panels, large containers */
/* Shadows — multi-layer, warm-tinted (warm brown base, not cold black) */
--shadow-xs: 0 1px 2px rgba(26,24,22,0.04);
--shadow-sm: 0 1px 3px rgba(26,24,22,0.06), 0 1px 2px rgba(26,24,22,0.04);
--shadow-md: 0 4px 12px rgba(26,24,22,0.08), 0 2px 4px rgba(26,24,22,0.04);
--shadow-lg: 0 10px 30px rgba(26,24,22,0.12), 0 4px 8px rgba(26,24,22,0.06);
/* Typography */
/* NOTE: --font-heading uses Bahnschrift — a Windows 10+ system font.
Falls back to Franklin Gothic Medium on macOS/Linux. Correct for Windows-hosted tools. */
--font-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
--font-heading: 'Bahnschrift', 'Franklin Gothic Medium', 'Arial Narrow', sans-serif;
--font-mono: 'JetBrains Mono', monospace;
}Google Fonts Import
<!-- Plus Jakarta Sans (body) + JetBrains Mono (data). Bahnschrift is Windows system — no CDN needed. -->
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">Typography Rules
Default Pairing (active)
| Role | Font | Weight | Usage |
|---|---|---|---|
| UI body | Plus Jakarta Sans | 300–700 | Labels, body text, navigation |
| Numbers/data | JetBrains Mono | 400–600 | KPI values, counts, codes |
| Section headings | Bahnschrift (system) | 700–800 | KPI values, card titles, brand name |
Font Pairing Selection (agent decision logic)
Before generating any UI, resolve the font pairing using this priority:
- Check
project-config.md— if the project's profile has a Design System section with declared fonts, use those. Done. - No project-config? — Present the pairing table below to the user and ask: "Which font pairing would you like for this project? (A–F, or describe your preference)". Wait for the user to choose before generating UI.
- User says "you pick" or doesn't care — Use pairing E (Sora + Nunito Sans) as the default.
Never silently pick a non-default pairing. The user must explicitly opt in to A–E.
Alternative Font Pairings
All are Google Fonts unless marked (system).
| Pairing | Heading | Body | Character |
|---|---|---|---|
| A — Geometric Precision | Geist (system/self-host) | Plus Jakarta Sans | Clean SaaS feel, Linear/Vercel aesthetic |
| B — Neo-Industrial | Clash Display (self-host) | General Sans | Bold brutalist contrast, strong visual hierarchy |
| C — Refined Corporate | Manrope | Source Sans 3 | Polished enterprise, Microsoft/Notion vibe |
| D — Editorial Luxury | Fraunces | Outfit | Warm serif contrast, premium editorial weight |
| E — Modern Humanist | Sora | Nunito Sans | Approachable geometric, health/fintech feel |
| F — Condensed Executive | Bahnschrift (system) | Plus Jakarta Sans | (current default) — dense KPI headers |
To switch, update these tokens in :root:
/* Example: Pairing D — Editorial Luxury */
--font-heading: 'Fraunces', Georgia, serif;
--font-sans: 'Outfit', system-ui, sans-serif;And update the Google Fonts import:
<link href="https://fonts.googleapis.com/css2?family=Fraunces:wght@600;700;800&family=Outfit:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">Never use: Inter, DM Sans, Syne, Roboto, Space Grotesk as primary fonts.
Layout Architecture
App Shell with Left Sidebar
┌──────────────────────────────────────────────────────┐
│ Sidebar (236px) │ Top Filter Bar (52px) │
│ ├──────────────────────────────────┤
│ Brand Logo │ Sub-tab Bar (40px) │
│ Nav Groups ├──────────────────────────────────┤
│ Footer / User │ Page Content (scrollable) │
└──────────────────────────────────────────────────────┘Sidebar Pattern
.sidebar {
width: 236px;
background: var(--surface);
border-right: 1px solid var(--border);
}
/* Brand lockup */
.brand-logo {
width: 36px; height: 36px;
background: var(--brand);
border-radius: 10px;
box-shadow: 0 3px 10px rgba(225,10,10,0.3);
font-family: var(--font-heading);
font-size: 14px; font-weight: 800;
}
/* Active nav item */
.nav-item.active {
background: var(--brand-soft);
color: var(--brand);
font-weight: 600;
}
.nav-item.active::before {
content: '';
position: absolute; left: 0;
top: 5px; bottom: 5px; width: 3px;
background: var(--brand);
border-radius: 0 3px 3px 0;
}Component Patterns
KPI Cards
.kpi-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--r-lg); /* 16px */
padding: 14px 16px;
box-shadow: var(--shadow-sm);
transition: box-shadow 0.15s, transform 0.15s;
}
.kpi-card:hover { box-shadow: var(--shadow-md); transform: translateY(-1px); }
.kpi-card::before {
/* colored top bar */
content: ''; position: absolute; top: 0; left: 0; right: 0;
height: 3px; border-radius: var(--r-lg) var(--r-lg) 0 0;
background: var(--kpi-color, var(--border));
}
/* KPI value uses Bahnschrift for condensed executive punch */
.kpi-value {
font-family: var(--font-heading);
font-size: 30px; font-weight: 700; letter-spacing: -1px;
}Filter Pills (Topbar)
.fchip {
border: 1.5px solid var(--border);
border-radius: 20px;
padding: 4px 11px;
font-size: 12px; font-weight: 500;
background: var(--surface);
transition: all 0.12s;
}
.fchip:hover { border-color: var(--brand); color: var(--brand); background: var(--brand-soft); }
.fchip.active { border-color: var(--brand); color: var(--brand); background: var(--brand-soft); }Buttons
/* Primary */
.btn-primary {
height: 32px; padding: 0 16px;
background: var(--brand); color: white; border: none;
border-radius: var(--r-sm);
font-family: var(--font-heading); font-size: 12.5px; font-weight: 700;
box-shadow: 0 2px 8px rgba(225,10,10,0.2);
transition: all 0.12s;
}
.btn-primary:hover { transform: translateY(-1px); box-shadow: 0 4px 14px rgba(225,10,10,0.3); }
/* Ghost */
.btn-ghost {
height: 32px; padding: 0 12px;
border: 1.5px solid var(--border); border-radius: var(--r-sm);
background: var(--surface); color: var(--ink-3);
font-family: var(--font-sans); font-weight: 500;
}
.btn-ghost:hover { background: var(--surface-2); color: var(--ink-1); }Status Badges / Pills
.badge { padding: 2px 7px; border-radius: 20px; font-size: 10px; font-weight: 700; }
.badge.success { background: var(--green-soft); color: var(--green); border: 1px solid var(--green-tint); }
.badge.warning { background: var(--amber-soft); color: var(--amber); }
.badge.danger { background: var(--red-soft); color: var(--red); border: 1px solid var(--red-border); }Chart Cards
.chart-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--r-lg); /* 16px */
padding: 18px 20px;
box-shadow: var(--shadow-sm);
}
/* Card title uses Bahnschrift */
.chart-title { font-family: var(--font-heading); font-size: 13.5px; font-weight: 700; letter-spacing: -0.2px; }
.chart-sub { font-size: 11px; color: var(--ink-4); }Section Labels
.section-title {
font-size: 10px; font-weight: 700;
letter-spacing: 1.5px; text-transform: uppercase;
color: var(--ink-4);
font-family: var(--font-sans);
}Alert / Highlight Cards
/* Warning alert */
.alert-card {
background: linear-gradient(135deg, #FFF8F5 0%, #FFF2EE 100%);
border: 1.5px solid #FCCAB4;
border-radius: var(--r-lg);
}
/* Success callout */
.callout-green {
background: var(--green-soft);
border: 1px solid var(--green-border);
border-radius: var(--r-md);
padding: 10px 13px;
}
/* Info callout */
.callout-blue {
background: var(--blue-soft);
border: 1px solid var(--blue-border);
border-radius: var(--r-md);
padding: 10px 13px;
}React Component Structure
When building React components with this design system:
// Design tokens map directly to Tailwind-like CSS vars
// Use inline styles or a theme provider pattern:
const theme = {
surface: 'var(--surface)',
surface2: 'var(--surface-2)',
border: 'var(--border)',
ink1: 'var(--ink-1)',
ink4: 'var(--ink-4)',
brand: 'var(--brand)',
brandSoft: 'var(--brand-soft)',
fontHeading: 'var(--font-heading)',
fontMono: 'var(--font-mono)',
// Radius
rLg: 'var(--r-lg)',
rXl: 'var(--r-xl)',
// Shadows
shadowSm: 'var(--shadow-sm)',
shadowMd: 'var(--shadow-md)',
};
// KPI Card example
function KpiCard({ label, value, delta, color, trend }) {
return (
<div style={{
background: 'var(--surface)',
border: '1px solid var(--border)',
borderRadius: 'var(--r-lg)',
padding: '14px 16px',
boxShadow: 'var(--shadow-sm)',
position: 'relative',
overflow: 'hidden',
}}>
{/* Colored top bar */}
<div style={{ position:'absolute', top:0, left:0, right:0, height:'3px', background:color }} />
<p style={{ fontSize:'10px', fontWeight:700, letterSpacing:'1.2px', textTransform:'uppercase', color:'var(--ink-4)', marginBottom:'8px' }}>
{label}
</p>
<p style={{ fontFamily:'var(--font-heading)', fontSize:'30px', fontWeight:700, letterSpacing:'-1px', color }}>
{value}
</p>
</div>
);
}Grid Layouts
/* KPI row — 6 columns */
.kpi-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 10px; }
/* 2-column charts */
.charts-2col { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
/* 3-column charts */
.charts-3col { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 14px; }Sidebar Nav Badge Colors
.nav-badge.red { background: var(--red-soft); color: var(--red); border: 1px solid var(--red-border); }
.nav-badge.green { background: var(--green-soft); color: var(--green); }
.nav-badge.grey { background: var(--surface-3); color: var(--ink-4); }Dropdown / Select Panel Styling
Dropdowns must have a smooth, modern appearance — never blocky or browser-default.
Use these control-specific tokens (add to :root alongside the main token set):
:root {
--control-bg: var(--surface-2);
--control-bg-hover: var(--surface-hover);
--control-bg-active: var(--surface-3);
--control-border: var(--border);
--control-border-strong:var(--border-strong);
--control-ring: var(--brand);
--shadow-control: var(--shadow-xs);
--shadow-control-strong:var(--shadow-sm);
--radius-control: var(--r-sm); /* 8px */
}.select-panel {
background: var(--control-bg);
border: 1.5px solid var(--control-border);
border-radius: var(--radius-control);
box-shadow: var(--shadow-control-strong);
padding: 6px 0;
min-width: 180px;
transition: box-shadow 0.18s, border-color 0.18s;
}
.select-panel:focus-within {
outline: none;
box-shadow: 0 0 0 2px var(--control-ring), var(--shadow-control-strong);
border-color: var(--control-border-strong);
}
.select-panel__option {
padding: 8px 18px;
border-radius: 7px;
cursor: pointer;
transition: background 0.14s;
}
.select-panel__option:hover { background: var(--control-bg-hover); }- For shadcn/ui
<Select>: overrideSelectContentandSelectItemwith these tokens - Never use native browser
<select>appearance without overriding all visual states - Test in both light and dark mode — tokens swap automatically via
.dark
Appearance Settings Rules
These UX rules apply to all apps using this design system:
- Theme / accent controls belong in the Settings tab only. Do not place color or theme pickers in the main nav, topbar, or sidebar.
- The dark/light mode toggle must always be rendered as an icon (sun/moon), never as text.
// Correct: icon-only toggle in Settings tab
<button className="theme-toggle" aria-label="Switch theme" onClick={toggle}>
{dark ? <MoonIcon /> : <SunIcon />}
</button>- Place in the Settings tab, not in the topbar or sidebar footer
- Use
aria-labelfor screen reader accessibility
What Makes This Style Distinctive
- Warm vs cold: Surfaces are
#F8F7F5and#F2F0ED— cream/linen, not cold#F9FAFB - Ink tones: Text is
#1A1816(warm black) not#111827(cold) - Borders:
#E5E2DC(warm beige) not#E5E7EB(cool grey) - Typography: Bahnschrift headings give condensed executive weight; Plus Jakarta Sans body is premium and distinctive — not generic Inter/Roboto
- Radius: 16px cards, 22px panels — generous, contemporary
- Shadows: Always multi-layer (
0 1px 3px ... 0 1px 2px ...) for depth
Don'ts
- ❌ No
Inter,DM Sans,Syne,Roboto, orSpace Grotesk - ❌ No cold grey surfaces (
#F9FAFB,#F3F4F6) - ❌ No generic SaaS blue (
#3B82F6) as primary - ❌ No glass morphism effects
- ❌ No tight corners (avoid radius < 8px on cards)
- ❌ No single-layer flat shadows
- ❌ No uppercase text in
var(--font-heading)for body copy
Adapting for Different Brands
Change only the brand token and optionally the accent palette:
/* e.g. for a teal-branded product */
:root {
--brand: #0891B2;
--brand-dark: #0E7490;
--brand-soft: #ECFEFF;
--brand-tint: rgba(8,145,178,0.08);
}
/* All other tokens remain the same */The warm surface, ink, and border tokens are brand-neutral — they work for any brand colour.
Dark Mode — Warm Soft Dark
A warm, editorial-grade dark theme inspired by GitHub's Dark Dimmed aesthetic but with warm brown-grey tones instead of cold blue-grey. Not pure black — surfaces are tinted warm charcoal, like aged paper in low light.
Design Philosophy (Dark)
Soft dark. Warm charcoal. Never cold, never pure black.
- Backgrounds use warm near-black (
#1A1917) — NOT cold#0a0a0aor blue-tinted#1C2128 - Ink inverts to warm off-whites (
#E8E5DF) — NOT stark#FFFFFFor cold#C9D1D9 - Status colors brighten slightly for readability on dark surfaces
- Shadows shift to
rgba(0,0,0,...)(higher opacity) because dark surfaces absorb light - Brand accent brightens slightly to maintain vibrancy
Dark Mode Tokens
Apply under .dark (or [data-theme="dark"] for explicit toggling):
.dark {
/* Brand Accent — slightly brighter for dark backgrounds */
--brand: #F52D2D;
--brand-dark: #E41B1B;
--brand-soft: rgba(245,45,45,0.12);
--brand-tint: rgba(245,45,45,0.10);
/* Warm Soft Dark Surfaces — charcoal, not cold */
--bg: #1A1917; /* page background — warm near-black */
--surface: #242320; /* cards, panels — warm dark paper */
--surface-2: #1E1D1B; /* subtle inset, inputs — darker than surface */
--surface-3: #2A2926; /* deeper inset, table rows */
--surface-hover: #302E2A; /* hover states */
/* Warm Dark Borders */
--border: #3A3834;
--border-strong: #4D4A44;
/* Warm Ink (inverted) — off-white with warm tint */
--ink-1: #E8E5DF; /* primary text — warm off-white */
--ink-2: #C5C1B8; /* secondary text */
--ink-3: #A8A49C; /* tertiary text — lifted for readability on dark surfaces */
--ink-4: #8A8680; /* muted/placeholder — 4.5:1 on card surface (was #706C64, too dark) */
/* Status Palette — brightened for dark backgrounds */
--green: #3FB950;
--green-soft: rgba(63,185,80,0.12);
--green-tint: rgba(63,185,80,0.15);
--green-border: rgba(63,185,80,0.25);
--amber: #E3B341;
--amber-soft: rgba(227,179,65,0.12);
--red: #F85149;
--red-soft: rgba(248,81,73,0.12);
--red-border: rgba(248,81,73,0.25);
--blue: #58A6FF;
--blue-soft: rgba(88,166,255,0.12);
--blue-border: rgba(88,166,255,0.25);
/* Shadows — darker, higher opacity (dark surfaces absorb light) */
--shadow-xs: 0 1px 2px rgba(0,0,0,0.24);
--shadow-sm: 0 1px 3px rgba(0,0,0,0.32), 0 1px 2px rgba(0,0,0,0.24);
--shadow-md: 0 4px 12px rgba(0,0,0,0.40), 0 2px 4px rgba(0,0,0,0.24);
--shadow-lg: 0 10px 30px rgba(0,0,0,0.48), 0 4px 8px rgba(0,0,0,0.32);
/* Typography — unchanged (fonts don't change between modes) */
/* --font-sans, --font-heading, --font-mono remain the same */
/* Radius — unchanged */
/* --r-xs through --r-xl remain the same */
}Theme Toggle Setup
Use the .dark class on <html> or a container element. shadcn's next-themes or a simple toggle works:
// Minimal dark mode toggle (Vite / React)
import { useEffect, useState } from 'react';
function useTheme() {
const [dark, setDark] = useState(() =>
window.matchMedia('(prefers-color-scheme: dark)').matches
);
useEffect(() => {
document.documentElement.classList.toggle('dark', dark);
}, [dark]);
return { dark, toggle: () => setDark(d => !d) };
}<!-- The .dark class activates the override tokens -->
<html class="dark">
<!-- All var(--surface), var(--ink-1), etc. now resolve to dark values -->
</html>Tailwind CSS Integration
Map tokens to Tailwind in tailwind.config.js:
// tailwind.config.js (extends existing warm-editorial setup)
module.exports = {
darkMode: 'class', // Use .dark class, not media query
theme: {
extend: {
colors: {
background: 'var(--bg)',
surface: 'var(--surface)',
'surface-2': 'var(--surface-2)',
'surface-3': 'var(--surface-3)',
border: 'var(--border)',
'ink-1': 'var(--ink-1)',
'ink-2': 'var(--ink-2)',
'ink-3': 'var(--ink-3)',
'ink-4': 'var(--ink-4)',
brand: 'var(--brand)',
'brand-soft': 'var(--brand-soft)',
},
},
},
};Components then use bg-surface, text-ink-1, border-border — no dark: prefix needed. The CSS variables swap automatically when .dark is applied.
Dark Mode Component Adaptations
Alert / Highlight Cards
.dark .alert-card {
background: linear-gradient(135deg, rgba(248,81,73,0.08) 0%, rgba(248,81,73,0.04) 100%);
border-color: rgba(248,81,73,0.20);
}
.dark .callout-green {
background: var(--green-soft);
border-color: var(--green-border);
}
.dark .callout-blue {
background: var(--blue-soft);
border-color: var(--blue-border);
}Sidebar (Dark)
.dark .sidebar {
background: var(--surface); /* #242320 — warm dark */
border-right-color: var(--border); /* #3A3834 */
}
.dark .nav-item.active {
background: var(--brand-soft); /* rgba tint, not opaque */
color: var(--brand); /* #F52D2D — brightened */
}
.dark .brand-logo {
box-shadow: 0 3px 10px rgba(245,45,45,0.35); /* slightly more glow on dark */
}KPI Cards (Dark)
No CSS changes needed — KPI cards already use var(--surface), var(--border), var(--shadow-sm) which swap automatically. The colored top bar uses var(--kpi-color) which is set per-card (brand/green/amber/red).
Charts (Dark)
When using Recharts, Plotly, or similar:
// Chart colors adapt to theme via CSS variables
const chartConfig = {
backgroundColor: 'var(--surface)',
gridColor: 'var(--border)',
textColor: 'var(--ink-3)',
axisColor: 'var(--ink-4)',
};
// For Plotly specifically:
const plotlyLayout = {
paper_bgcolor: 'transparent',
plot_bgcolor: 'transparent',
font: { color: 'var(--ink-2)' },
xaxis: { gridcolor: 'var(--border)', zerolinecolor: 'var(--border-strong)' },
yaxis: { gridcolor: 'var(--border)', zerolinecolor: 'var(--border-strong)' },
};Dark Mode vs Light Mode — Quick Reference
| Token | Light | Dark | Notes |
|---|---|---|---|
--bg |
#F5F3F0 cream |
#1A1917 warm near-black |
Both warm-tinted |
--surface |
#FFFFFF white |
#242320 warm charcoal |
Cards, panels |
--surface-2 |
#F9F8F6 subtle |
#1E1D1B recessed |
Inputs, insets |
--border |
#E5E2DC warm beige |
#3A3834 warm dark |
Both avoid cold grey |
--ink-1 |
#1A1816 warm black |
#E8E5DF warm off-white |
Primary text |
--ink-3 |
#6B6760 warm grey |
#A8A49C lighter warm grey |
Tertiary text |
--ink-4 |
#9C9890 muted |
#8A8680 muted (lifted) |
Placeholder/section labels |
--brand |
#E10A0A |
#F52D2D |
Brightened for dark |
--green |
#16A34A |
#3FB950 |
Brightened for dark |
--red |
#DC2626 |
#F85149 |
Brightened for dark |
--shadow-sm |
rgba(26,24,22,0.06) |
rgba(0,0,0,0.32) |
Higher opacity on dark |
What Makes This Dark Mode Distinctive
- Warm charcoal, not cold: Backgrounds are
#1A1917(brown-black), not#0D1117(GitHub blue-black) or#0a0a0a(pure black) - Soft, not harsh: Surfaces at
#242320are visibly lighter than the#1A1917page — creating depth without being stark - Status colors breathe: Green/red/amber/blue are ~15% brighter than their light-mode counterparts — they pop without screaming
- Shadows still work: Unlike many dark themes where shadows vanish, the
rgba(0,0,0,0.3-0.5)range creates visible but subtle elevation - Brand stays warm: The red accent at
#F52D2Dglows slightly warmer, working with the warm charcoal surface instead of fighting it - Muted text stays readable:
--ink-4at#8A8680achieves 4.6:1 contrast on card surfaces — grey but never invisible
Don'ts (Dark Mode)
- ❌ No pure black backgrounds (
#000000,#0a0a0a) - ❌ No cold blue-grey (
#1C2128,#22272E) — use warm tones - ❌ No stark white text (
#FFFFFF) — use warm off-white#E8E5DF - ❌ No identical status colors as light mode — brighten them for dark backgrounds
- ❌ No
opacity: 0.5for muting — use dedicated muted tokens instead - ❌ No light-mode shadow values — dark surfaces need higher-opacity shadows