Colors
Semantic color tokens used throughout the design system.
Color defines the visual tone of a design system. Ink UI uses a palette built around warm gray and orange, expanded into full scales in the OKLCH color space for consistent luminance and accessibility across light and dark modes.
The gray carries a subtle warm bias — warmer than neutral, but less pronounced than Tailwind's Stone — providing a balanced foundation. Orange serves as the primary accent, adding energy and warmth that complements the overall palette.
Gray
A warm gray scale for text, backgrounds, borders, and subtle fills across light and dark modes.
Red
A red scale for destructive actions, errors, and warning states.
Orange
The primary accent color for focus rings, active states, and blockquote accents.
Semantic tokens
These CSS variables map to the scales above and adapt between light and dark modes via the data-theme attribute.
Backgrounds
Actions
States
Borders & focus
Common Tailwind utilities like text-gray-500, bg-gray-100, border-gray-200, and dark: variants map to the underlying Ink UI theme tokens.
Interactive states
Every surface token ships a -hover and -active companion for interactive elements. Rather than fading a base color with opacity — which composites unpredictably against whatever sits behind it and muddies stacked surfaces — each state is a fixed, opaque step along the palette scale. The values are deliberately tuned per token: light surfaces darken toward the content, dark surfaces brighten, and solid fills move toward the mid-scale so the state always reads as a real change regardless of background.
Use them directly as Tailwind utilities — hover:bg-primary-hover, data-popup-open:bg-secondary-active, and so on — so the light/dark logic lives in the theme instead of being restated in every component.
secondary (and the ghost / outline surfaces built on it) stays alpha-based on purpose: it's an overlay tint meant to composite over varying backgrounds, so its -hover and -active steps deepen the alpha rather than swapping to a solid color.
Installation
Copy the CSS code into your global stylesheet, wrapped in a selector that applies the appropriate color scheme based on the data-theme attribute.
@theme {
/* gray */
--color-gray-50: oklch(0.98559 0.002 48.697);
--color-gray-100: oklch(0.95 0.001 48.697);
--color-gray-200: oklch(0.925 0.002 48.697);
--color-gray-300: oklch(0.84598 0.002 48.697);
--color-gray-400: oklch(0.7374 0.002 48.697);
--color-gray-500: oklch(0.585 0.003 48.697);
--color-gray-600: oklch(0.46 0.002 48.697);
--color-gray-700: oklch(0.37 0.002 48.697);
--color-gray-800: oklch(0.31 0.001 48.697);
--color-gray-900: oklch(0.265 0.001 48.697);
--color-gray-950: oklch(0.21 0.002 48.697);
/* red */
--color-red-50: oklch(0.96453 0.015 24);
--color-red-100: oklch(0.95036 0.03 24);
--color-red-200: oklch(0.92601 0.045 24);
--color-red-300: oklch(0.8455 0.07 24);
--color-red-400: oklch(0.73813 0.135 24);
--color-red-500: oklch(0.63497 0.18 24);
--color-red-600: oklch(0.50144 0.15 24);
--color-red-700: oklch(0.38998 0.125 24);
--color-red-800: oklch(0.30985 0.095 24);
--color-red-900: oklch(0.26461 0.06 24);
--color-red-950: oklch(0.21016 0.04 24);
/* orange */
--color-orange-50: oklch(0.96453 0.02 41.5);
--color-orange-100: oklch(0.95036 0.025 41.5);
--color-orange-200: oklch(0.92601 0.03 41.5);
--color-orange-300: oklch(0.8455 0.07 41.5);
--color-orange-400: oklch(0.73813 0.14 41.5);
--color-orange-500: oklch(0.63497 0.17 41.5);
--color-orange-600: oklch(0.50144 0.135 41.5);
--color-orange-700: oklch(0.38998 0.08 41.5);
--color-orange-800: oklch(0.30985 0.065 41.5);
--color-orange-900: oklch(0.26461 0.055 41.5);
--color-orange-950: oklch(0.21016 0.04 41.5);
}
@layer base {
:root {
color-scheme: light;
--background: oklch(0.98559 0.002 48.697);
--foreground: oklch(0.265 0.001 48.697);
--card: oklch(0.95 0.001 48.697);
--card-foreground: oklch(0.265 0.001 48.697);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.265 0.001 48.697);
--dialog: oklch(0.98559 0.002 48.697);
--dialog-foreground: oklch(0.265 0.001 48.697);
--primary: oklch(0.265 0.001 48.697);
--primary-foreground: oklch(1 0 0);
--secondary: oklch(0.21 0.002 48.697 / 0.08);
--secondary-foreground: oklch(0.265 0.001 48.697);
--muted: oklch(0.95 0.001 48.697);
--muted-foreground: oklch(0.585 0.003 48.697);
--accent: oklch(0.63497 0.17 41.5);
--accent-foreground: oklch(1 0 0);
--destructive: oklch(0.63497 0.18 24);
--destructive-foreground: oklch(1 0 0);
--border: oklch(0.21 0.002 48.697 / 0.1);
--input: oklch(0.21 0.002 48.697 / 0.1);
--ring: oklch(0.63497 0.17 41.5 / 0.3);
/* surface state variants — stepped down the palette scale */
--background-hover: var(--color-gray-100);
--background-active: var(--color-gray-200);
--card-hover: var(--color-gray-200);
--card-active: var(--color-gray-300);
--popover-hover: var(--color-gray-50);
--popover-active: var(--color-gray-100);
--dialog-hover: var(--color-gray-100);
--dialog-active: var(--color-gray-200);
--primary-hover: var(--color-gray-700);
--primary-active: var(--color-gray-600);
--secondary-hover: oklch(0.21 0.002 48.697 / 0.16);
--secondary-active: oklch(0.21 0.002 48.697 / 0.22);
--muted-hover: var(--color-gray-200);
--muted-active: var(--color-gray-300);
--accent-hover: var(--color-orange-600);
--accent-active: var(--color-orange-700);
--destructive-hover: var(--color-red-600);
--destructive-active: var(--color-red-700);
--chart-1: var(--orange-500, oklch(0.63497 0.17 41.5));
--chart-2: var(--red-500, oklch(0.63497 0.18 24));
--chart-3: oklch(0.585 0.003 48.697);
--chart-4: oklch(0.73813 0.14 41.5);
--chart-5: oklch(0.8455 0.07 24);
--sidebar: var(--card);
--sidebar-foreground: var(--foreground);
--sidebar-primary: var(--primary);
--sidebar-primary-foreground: var(--primary-foreground);
--sidebar-accent: var(--secondary);
--sidebar-accent-foreground: var(--secondary-foreground);
--sidebar-border: var(--border);
--sidebar-ring: var(--ring);
}
:root[data-theme="dark"],
.dark {
color-scheme: dark;
--background: oklch(0.21 0.002 48.697);
--foreground: oklch(0.95 0.001 48.697);
--card: oklch(0.21 0.002 48.697);
--card-foreground: oklch(0.95 0.001 48.697);
--popover: oklch(0.265 0.001 48.697);
--popover-foreground: oklch(0.95 0.001 48.697);
--dialog: oklch(0.265 0.001 48.697);
--dialog-foreground: oklch(0.95 0.001 48.697);
--primary: oklch(0.95 0.001 48.697);
--primary-foreground: oklch(0.265 0.001 48.697);
--secondary: oklch(0.98559 0.002 48.697 / 0.08);
--secondary-foreground: oklch(0.95 0.001 48.697);
--muted: oklch(0.31 0.001 48.697);
--muted-foreground: oklch(0.7374 0.002 48.697);
--accent: oklch(0.50144 0.135 41.5);
--accent-foreground: oklch(1 0 0);
--destructive: oklch(0.63497 0.18 24);
--destructive-foreground: oklch(1 0 0);
--border: oklch(0.98559 0.002 48.697 / 0.1);
--input: oklch(0.98559 0.002 48.697 / 0.1);
--ring: oklch(0.63497 0.17 41.5 / 0.3);
/* surface state variants — stepped toward the lighter end of the palette */
--background-hover: var(--color-gray-900);
--background-active: var(--color-gray-800);
--card-hover: var(--color-gray-900);
--card-active: var(--color-gray-800);
--popover-hover: var(--color-gray-800);
--popover-active: var(--color-gray-700);
--dialog-hover: var(--color-gray-800);
--dialog-active: var(--color-gray-700);
--primary-hover: var(--color-gray-300);
--primary-active: var(--color-gray-400);
--secondary-hover: oklch(0.98559 0.002 48.697 / 0.16);
--secondary-active: oklch(0.98559 0.002 48.697 / 0.22);
--muted-hover: var(--color-gray-700);
--muted-active: var(--color-gray-600);
--accent-hover: var(--color-orange-500);
--accent-active: var(--color-orange-400);
--destructive-hover: var(--color-red-400);
--destructive-active: var(--color-red-300);
--chart-1: oklch(0.50144 0.135 41.5);
--chart-2: oklch(0.63497 0.18 24);
--chart-3: oklch(0.7374 0.002 48.697);
--chart-4: oklch(0.38998 0.08 41.5);
--chart-5: oklch(0.8455 0.07 24);
--sidebar: var(--card);
--sidebar-foreground: var(--foreground);
--sidebar-primary: var(--primary);
--sidebar-primary-foreground: var(--primary-foreground);
--sidebar-accent: var(--secondary);
--sidebar-accent-foreground: var(--secondary-foreground);
--sidebar-border: var(--border);
--sidebar-ring: var(--ring);
}
* {
border-color: var(--border);
outline-color: color-mix(in oklab, var(--ring) 50%, transparent);
}
body {
color: var(--foreground);
background: var(--background);
}
}
@theme inline {
--color-background: var(--background);
--color-background-hover: var(--background-hover);
--color-background-active: var(--background-active);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-card-hover: var(--card-hover);
--color-card-active: var(--card-active);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-popover-hover: var(--popover-hover);
--color-popover-active: var(--popover-active);
--color-dialog: var(--dialog);
--color-dialog-foreground: var(--dialog-foreground);
--color-dialog-hover: var(--dialog-hover);
--color-dialog-active: var(--dialog-active);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-primary-hover: var(--primary-hover);
--color-primary-active: var(--primary-active);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-secondary-hover: var(--secondary-hover);
--color-secondary-active: var(--secondary-active);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-muted-hover: var(--muted-hover);
--color-muted-active: var(--muted-active);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-accent-hover: var(--accent-hover);
--color-accent-active: var(--accent-active);
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
--color-destructive-hover: var(--destructive-hover);
--color-destructive-active: var(--destructive-active);
--color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3);
--color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5);
--color-sidebar: var(--sidebar);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
}