Create a theme
Start from a brand color or your logo. The generator builds 12-step scales in OKLCH for light and dark, tunes them until every text pair passes WCAG AA, and exports CSS, Figma variables and a built-in theme.
Compute spend rose 38% after the September 9 deploy
The nightly ledger export now runs on every workspace instead of only active ones. It accounts for $11,900 of the increase.
Compute spend rose 38% after the September 9 deploy
The nightly ledger export now runs on every workspace instead of only active ones. It accounts for $11,900 of the increase.
Scales
Twelve steps each. 1 to 2 backgrounds, 3 to 5 component fills, 6 to 8 borders, 9 to 10 solids, 11 to 12 text.
Contrast
70 of 70 passThe generator keeps your hue and only moves lightness: solids until their text reaches 4.5:1, text steps until they read on their own tints.
| Pair | Light | Dark | Min |
|---|---|---|---|
| foregroundon background | 15.68 | 16.41 | 7:1 |
| foregroundon card | 16.00 | 15.57 | 7:1 |
| muted-foregroundon background | 5.88 | 9.63 | 4.5:1 |
| muted-foregroundon card | 6.00 | 9.14 | 4.5:1 |
| muted-foregroundon muted | 5.34 | 7.72 | 4.5:1 |
| primary-foregroundon primary | 5.72 | 4.62 | 4.5:1 |
| primary-foregroundon primary-hover | 6.97 | 5.48 | 4.5:1 |
| secondary-foregroundon secondary | 14.24 | 13.15 | 4.5:1 |
| brand-subtle-foregroundon brand-subtle | 5.49 | 8.38 | 4.5:1 |
| brand-subtle-foregroundon card | 6.17 | 9.08 | 4.5:1 |
| destructive-foregroundon destructive | 4.97 | 4.76 | 4.5:1 |
| destructive-subtle-foregroundon card | 6.59 | 8.68 | 4.5:1 |
| success-subtle-foregroundon card | 5.65 | 9.55 | 4.5:1 |
| warning-subtle-foregroundon card | 6.18 | 8.91 | 4.5:1 |
| info-subtle-foregroundon card | 6.01 | 9.19 | 4.5:1 |
| destructive-subtle-foregroundon destructive-subtle | 5.83 | 8.12 | 4.5:1 |
| success-foregroundon success | 4.62 | 4.62 | 4.5:1 |
| success-subtle-foregroundon success-subtle | 5.08 | 8.65 | 4.5:1 |
| Pair | Light | Dark | Min |
|---|---|---|---|
| warning-foregroundon warning | 9.06 | 9.06 | 4.5:1 |
| warning-subtle-foregroundon warning-subtle | 5.49 | 8.23 | 4.5:1 |
| info-foregroundon info | 4.66 | 4.66 | 4.5:1 |
| info-subtle-foregroundon info-subtle | 5.36 | 8.44 | 4.5:1 |
| ai-foregroundon ai-subtle | 5.86 | 9.08 | 4.5:1 |
| ai-foregroundon card | 6.17 | 9.08 | 4.5:1 |
| sidebar-foregroundon sidebar | 15.19 | 16.41 | 7:1 |
| tertiary-foregroundon background | 4.66 | 4.88 | 4.5:1 |
| tertiary-foregroundon card | 4.75 | 4.63 | 4.5:1 |
| severity-critical-foregroundon severity-critical | 4.97 | 4.76 | 4.5:1 |
| severity-high-foregroundon severity-high | 4.65 | 4.65 | 4.5:1 |
| severity-elevated-foregroundon severity-elevated | 11.31 | 11.31 | 4.5:1 |
| severity-routine-foregroundon severity-routine | 4.65 | 4.66 | 4.5:1 |
| severity-critical-subtle-foregroundon severity-critical-subtle | 5.83 | 8.12 | 4.5:1 |
| severity-high-subtle-foregroundon severity-high-subtle | 5.73 | 8.13 | 4.5:1 |
| severity-elevated-subtle-foregroundon severity-elevated-subtle | 5.37 | 8.38 | 4.5:1 |
| severity-routine-subtle-foregroundon severity-routine-subtle | 5.34 | 8.40 | 4.5:1 |
Export
Paste after prodular-ui.css and set data-theme="custom" on html or any element. Add class="dark" for dark mode.
/* Prodular UI theme "Custom". Paste after prodular-ui.css,
then set <html data-theme="custom"> (add class="dark" for dark mode). */
[data-theme="custom"] {
--background: oklch(0.993 0.0033 263.81);
--foreground: oklch(0.25 0.009 263.81);
--card: oklch(1 0 0);
--card-foreground: oklch(0.25 0.009 263.81);
--popover: oklch(1 0 0);
--raised: oklch(1 0 0);
--popover-foreground: oklch(0.25 0.009 263.81);
--primary: oklch(0.5196 0.1828 263.81);
--primary-hover: oklch(0.4746 0.1828 263.81);
--primary-foreground: oklch(1 0 0);
--secondary: oklch(0.96 0.0102 263.81);
--secondary-hover: oklch(0.937 0.0115 263.81);
--secondary-foreground: oklch(0.25 0.009 263.81);
--muted: oklch(0.96 0.0102 263.81);
--muted-foreground: oklch(0.5 0.0115 263.81);
--accent: oklch(0.96 0.0102 263.81);
--accent-foreground: oklch(0.25 0.009 263.81);
--border: oklch(0.88 0.0128 263.81);
--border-strong: oklch(0.772 0.0128 263.81);
--input: oklch(0.838 0.0128 263.81);
--ring: oklch(0.772 0.1156 263.81);
--brand-subtle: oklch(0.96 0.0188 263.81);
--brand-subtle-foreground: oklch(0.5 0.1572 263.81);
--sidebar: oklch(0.982 0.0077 263.81);
--sidebar-foreground: oklch(0.25 0.009 263.81);
--sidebar-primary: oklch(0.5196 0.1828 263.81);
--sidebar-primary-foreground: oklch(1 0 0);
--sidebar-accent: oklch(0.937 0.0115 263.81);
--sidebar-accent-foreground: oklch(0.25 0.009 263.81);
--sidebar-border: oklch(0.88 0.0128 263.81);
--sidebar-ring: oklch(0.772 0.1156 263.81);
--chart-1: oklch(0.5196 0.1828 263.81);
--chart-2: oklch(0.83 0.1447 73.82);
--chart-3: oklch(0.55 0.0974 184);
--chart-4: oklch(0.58 0.2 12);
--chart-5: oklch(0.55 0.2 325);
--ai-1: oklch(0.5196 0.1828 263.81);
--ai-2: oklch(0.54 0.21 284);
--ai-3: oklch(0.7 0.13 232);
--ai-subtle: oklch(0.982 0.0084 263.81);
--ai-border: oklch(0.88 0.0583 263.81);
--ai-foreground: oklch(0.5 0.1572 263.81);
--destructive: oklch(0.57 0.21 25);
--destructive-foreground: oklch(1 0 0);
--destructive-subtle: oklch(0.96 0.0197 25);
--destructive-subtle-foreground: oklch(0.5 0.1806 25);
--destructive-border: oklch(0.838 0.0891 25);
--success: oklch(0.545 0.1592 147.64);
--success-foreground: oklch(1 0 0);
--success-subtle: oklch(0.96 0.0288 150.91);
--success-subtle-foreground: oklch(0.5 0.1376 146.55);
--success-border: oklch(0.838 0.096 148.73);
--warning: oklch(0.8 0.1551 67.27);
--warning-foreground: oklch(0.22 0.0498 64);
--warning-subtle: oklch(0.96 0.0306 73.82);
--warning-subtle-foreground: oklch(0.5 0.1121 65.09);
--warning-border: oklch(0.838 0.102 69.45);
--info: oklch(0.56 0.1585 250);
--info-foreground: oklch(1 0 0);
--info-subtle: oklch(0.96 0.0197 250);
--info-subtle-foreground: oklch(0.5 0.1415 250);
--info-border: oklch(0.838 0.0837 250);
--tertiary-foreground: oklch(0.555 0.0128 263.81);
--severity-critical: oklch(0.57 0.21 25);
--severity-critical-foreground: oklch(1 0 0);
--severity-critical-subtle: oklch(0.96 0.0197 25);
--severity-critical-subtle-foreground: oklch(0.5 0.1806 25);
--severity-critical-border: oklch(0.838 0.0891 25);
--severity-high: oklch(0.58 0.1834 39.64);
--severity-high-foreground: oklch(1 0 0);
--severity-high-subtle: oklch(0.96 0.021 42.91);
--severity-high-subtle-foreground: oklch(0.5 0.1617 38.55);
--severity-high-border: oklch(0.838 0.0932 40.73);
--severity-elevated: oklch(0.86 0.16 92.18);
--severity-elevated-foreground: oklch(0.22 0.0449 90);
--severity-elevated-subtle: oklch(0.96 0.0288 96.55);
--severity-elevated-subtle-foreground: oklch(0.5 0.1022 90.73);
--severity-elevated-border: oklch(0.838 0.096 93.64);
--severity-routine: oklch(0.56 0.0128 263.81);
--severity-routine-foreground: oklch(1 0 0);
--severity-routine-subtle: oklch(0.96 0.0102 263.81);
--severity-routine-subtle-foreground: oklch(0.5 0.0115 263.81);
--severity-routine-border: oklch(0.838 0.0128 263.81);
--brand-1: oklch(0.993 0.0032 263.81);
--brand-2: oklch(0.982 0.0084 263.81);
--brand-3: oklch(0.96 0.0188 263.81);
--brand-4: oklch(0.937 0.0299 263.81);
--brand-5: oklch(0.912 0.0422 263.81);
--brand-6: oklch(0.88 0.0583 263.81);
--brand-7: oklch(0.838 0.08 263.81);
--brand-8: oklch(0.772 0.1156 263.81);
--brand-9: oklch(0.5196 0.1828 263.81);
--brand-10: oklch(0.4746 0.1828 263.81);
--brand-11: oklch(0.5 0.1572 263.81);
--brand-12: oklch(0.25 0.0768 263.81);
--gray-1: oklch(0.993 0.0033 263.81);
--gray-2: oklch(0.982 0.0077 263.81);
--gray-3: oklch(0.96 0.0102 263.81);
--gray-4: oklch(0.937 0.0115 263.81);
--gray-5: oklch(0.912 0.0128 263.81);
--gray-6: oklch(0.88 0.0128 263.81);
--gray-7: oklch(0.838 0.0128 263.81);
--gray-8: oklch(0.772 0.0128 263.81);
--gray-9: oklch(0.58 0.0128 263.81);
--gray-10: oklch(0.535 0.0128 263.81);
--gray-11: oklch(0.5 0.0115 263.81);
--gray-12: oklch(0.25 0.009 263.81);
--radius: 0.625rem;
--font-ui: var(--font-geist), ui-sans-serif, system-ui, sans-serif;
}
.dark[data-theme="custom"],
.dark [data-theme="custom"],
[data-theme="custom"].dark {
--background: oklch(0.165 0.009 263.81);
--foreground: oklch(0.945 0.0064 263.81);
--card: oklch(0.195 0.0102 263.81);
--card-foreground: oklch(0.945 0.0064 263.81);
--popover: oklch(0.232 0.0128 263.81);
--raised: oklch(0.295 0.0128 263.81);
--popover-foreground: oklch(0.945 0.0064 263.81);
--primary: oklch(0.5696 0.1828 263.81);
--primary-hover: oklch(0.5296 0.1828 263.81);
--primary-foreground: oklch(1 0 0);
--secondary: oklch(0.262 0.0128 263.81);
--secondary-hover: oklch(0.295 0.0128 263.81);
--secondary-foreground: oklch(0.945 0.0064 263.81);
--muted: oklch(0.262 0.0128 263.81);
--muted-foreground: oklch(0.78 0.0115 263.81);
--accent: oklch(0.262 0.0128 263.81);
--accent-foreground: oklch(0.945 0.0064 263.81);
--border: oklch(0.335 0.0128 263.81);
--border-strong: oklch(0.47 0.0128 263.81);
--input: oklch(0.392 0.0128 263.81);
--ring: oklch(0.47 0.1389 263.81);
--brand-subtle: oklch(0.232 0.0548 263.81);
--brand-subtle-foreground: oklch(0.78 0.1112 263.81);
--sidebar: oklch(0.165 0.009 263.81);
--sidebar-foreground: oklch(0.945 0.0064 263.81);
--sidebar-primary: oklch(0.5696 0.1828 263.81);
--sidebar-primary-foreground: oklch(1 0 0);
--sidebar-accent: oklch(0.232 0.0128 263.81);
--sidebar-accent-foreground: oklch(0.945 0.0064 263.81);
--sidebar-border: oklch(0.335 0.0128 263.81);
--sidebar-ring: oklch(0.47 0.1389 263.81);
--chart-1: oklch(0.5696 0.1828 263.81);
--chart-2: oklch(0.83 0.1447 73.82);
--chart-3: oklch(0.55 0.0974 184);
--chart-4: oklch(0.585 0.2 12);
--chart-5: oklch(0.585 0.2 325);
--ai-1: oklch(0.5696 0.1828 263.81);
--ai-2: oklch(0.58 0.21 284);
--ai-3: oklch(0.72 0.13 232);
--ai-subtle: oklch(0.195 0.0256 263.81);
--ai-border: oklch(0.335 0.1024 263.81);
--ai-foreground: oklch(0.78 0.1112 263.81);
--destructive: oklch(0.58 0.21 25);
--destructive-foreground: oklch(1 0 0);
--destructive-subtle: oklch(0.232 0.063 25);
--destructive-subtle-foreground: oklch(0.78 0.1283 25);
--destructive-border: oklch(0.392 0.1302 25);
--success: oklch(0.545 0.1592 147.64);
--success-foreground: oklch(1 0 0);
--success-subtle: oklch(0.232 0.048 150.91);
--success-subtle-foreground: oklch(0.78 0.1184 146.55);
--success-border: oklch(0.392 0.0992 148.73);
--warning: oklch(0.8 0.1551 67.27);
--warning-foreground: oklch(0.22 0.0498 64);
--warning-subtle: oklch(0.232 0.0492 73.82);
--warning-subtle-foreground: oklch(0.78 0.1258 65.09);
--warning-border: oklch(0.392 0.0852 69.45);
--info: oklch(0.56 0.1585 250);
--info-foreground: oklch(1 0 0);
--info-subtle: oklch(0.232 0.054 250);
--info-subtle-foreground: oklch(0.78 0.1163 250);
--info-border: oklch(0.392 0.1109 250);
--tertiary-foreground: oklch(0.6 0.0128 263.81);
--severity-critical: oklch(0.58 0.21 25);
--severity-critical-foreground: oklch(1 0 0);
--severity-critical-subtle: oklch(0.232 0.063 25);
--severity-critical-subtle-foreground: oklch(0.78 0.1283 25);
--severity-critical-border: oklch(0.392 0.1302 25);
--severity-high: oklch(0.58 0.1834 39.64);
--severity-high-foreground: oklch(1 0 0);
--severity-high-subtle: oklch(0.232 0.057 42.91);
--severity-high-subtle-foreground: oklch(0.78 0.1324 38.55);
--severity-high-border: oklch(0.392 0.1178 40.73);
--severity-elevated: oklch(0.86 0.16 92.18);
--severity-elevated-foreground: oklch(0.22 0.0449 90);
--severity-elevated-subtle: oklch(0.232 0.0478 96.55);
--severity-elevated-subtle-foreground: oklch(0.78 0.1184 90.73);
--severity-elevated-border: oklch(0.392 0.0803 93.64);
--severity-routine: oklch(0.615 0.0128 263.81);
--severity-routine-foreground: oklch(0.22 0.0045 263.81);
--severity-routine-subtle: oklch(0.232 0.0128 263.81);
--severity-routine-subtle-foreground: oklch(0.78 0.0115 263.81);
--severity-routine-border: oklch(0.392 0.0128 263.81);
--brand-1: oklch(0.165 0.0183 263.81);
--brand-2: oklch(0.195 0.0256 263.81);
--brand-3: oklch(0.232 0.0548 263.81);
--brand-4: oklch(0.262 0.0768 263.81);
--brand-5: oklch(0.295 0.0914 263.81);
--brand-6: oklch(0.335 0.1024 263.81);
--brand-7: oklch(0.392 0.1133 263.81);
--brand-8: oklch(0.47 0.1389 263.81);
--brand-9: oklch(0.5696 0.1828 263.81);
--brand-10: oklch(0.5296 0.1828 263.81);
--brand-11: oklch(0.78 0.1112 263.81);
--brand-12: oklch(0.945 0.026 263.81);
--gray-1: oklch(0.165 0.009 263.81);
--gray-2: oklch(0.195 0.0102 263.81);
--gray-3: oklch(0.232 0.0128 263.81);
--gray-4: oklch(0.262 0.0128 263.81);
--gray-5: oklch(0.295 0.0128 263.81);
--gray-6: oklch(0.335 0.0128 263.81);
--gray-7: oklch(0.392 0.0128 263.81);
--gray-8: oklch(0.47 0.0128 263.81);
--gray-9: oklch(0.6 0.0128 263.81);
--gray-10: oklch(0.645 0.0128 263.81);
--gray-11: oklch(0.78 0.0115 263.81);
--gray-12: oklch(0.945 0.0064 263.81);
}
.dark[data-theme="custom"], .dark [data-theme="custom"], [data-theme="custom"].dark { color-scheme: dark; }