Customising the Oat UI theme
Full Oat default theme for reference, this site overrides, and how to customise it.

This site styles with Oat UI. Oat ships its defaults in 01-theme.css, loaded from @knadh/oat/oat.min.css. Our overrides live in src/lib/global.css, loaded after Oat via src/layouts/BaseHead.astro, so our values win. Only values that differ from Oat defaults are kept in global.css.
How to customise
- Override a variable in
src/lib/global.cssunder:root. Example: change the brand colour. - Use
light-dark(light, dark)for values that follow the OS colour scheme. - Force one mode with the theme switcher: it sets
data-theme="light|dark"on<html>.global.csspinscolor-schemeunder that selector (which forces nativelight-dark()in dev) plus the--lightningcss-light/--lightningcss-darkswitch variables (which is what the production build actually reads — it compileslight-dark()away into an OS-media-query-only polyfill, so pinningcolor-schemealone does nothing in prod). - Layout knobs:
--container-maxcaps.container,--grid-gapspaces.rowcolumns,--sidebar-widthsizes the sidebar layout.
:root {
--primary: light-dark(#3e63dd, #3e63dd);
--container-max: 1080px;
--grid-gap: 1rem;
}
This site’s overrides (src/lib/global.css)
:root {
color-scheme: light dark;
--primary: light-dark(#3e63dd, #3e63dd);
--primary-foreground: light-dark(#ffffff, #ffffff);
--secondary-foreground: light-dark(#09090b, #fafafa);
--ring: light-dark(#4f46e5, #a5b4fc);
--radius-small: 0;
--radius-medium: 0;
--radius-large: 0;
--radius-full: 0;
--font-sans: var(--font-inter), system-ui, sans-serif;
--container-max: 1080px;
--grid-gap: 1rem;
}
Everything else (background, spacing scale, typography, shadows, motion, stacking) is identical to Oat defaults, so it is not repeated here.
Full Oat default theme reference (@knadh/oat@0.8.0, css/01-theme.css)
:root {
color-scheme: light dark;
--background: light-dark(#fff, #09090b);
--foreground: light-dark(#09090b, #fafafa);
--card: light-dark(#fff, #18181b);
--card-foreground: light-dark(#09090b, #fafafa);
--primary: light-dark(#574747, #fafafa);
--primary-foreground: light-dark(#fafafa, #18181b);
--secondary: light-dark(#f4f4f5, #27272a);
--secondary-foreground: light-dark(#574747, #fafafa);
--muted: light-dark(#f4f4f5, #27272a);
--muted-foreground: light-dark(#71717a, #a1a1aa);
--faint: light-dark(#fafafa, #1e1e21);
--faint-foreground: light-dark(#a1a1aa, #71717a);
--accent: light-dark(#f4f4f5, #27272a);
--danger: light-dark(#d32f2f, #f4807b);
--danger-foreground: light-dark(#fafafa, #18181b);
--success: light-dark(#008032, #6cc070);
--success-foreground: light-dark(#fafafa, #18181b);
--warning: light-dark(#a65b00, #f0a030);
--warning-foreground: #09090b;
--border: light-dark(#d4d4d8, #52525b);
--input: light-dark(#d4d4d8, #52525b);
--ring: light-dark(#574747, #d4d4d8);
--space-1: 0.25rem;
--space-2: 0.5rem;
--space-3: 0.75rem;
--space-4: 1rem;
--space-5: 1.25rem;
--space-6: 1.5rem;
--space-8: 2rem;
--space-10: 2.5rem;
--space-12: 3rem;
--space-14: 3.5rem;
--space-16: 4rem;
--space-18: 4.5rem;
--radius-small: 0.125rem;
--radius-medium: 0.375rem;
--radius-large: 0.75rem;
--radius-full: 9999px;
--bar-height: 0.5rem;
--font-sans: system-ui, sans-serif;
--font-mono: ui-monospace, Consolas, monospace;
--text-1: clamp(1.75rem, 1.5rem + 1.1vw, 2.25rem);
--text-2: clamp(1.5rem, 1.3rem + 0.8vw, 1.875rem);
--text-3: clamp(1.25rem, 1.1rem + 0.5vw, 1.5rem);
--text-4: clamp(1.125rem, 1.05rem + 0.3vw, 1.25rem);
--text-5: 1.125rem;
--text-6: 1rem;
--text-7: 0.875rem;
--text-8: 0.75rem;
--text-regular: var(--text-6);
--leading-normal: 1.5;
--font-normal: 400;
--font-medium: 500;
--font-semibold: 600;
--font-bold: 600;
--shadow-small: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow-medium:
0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
--shadow-large:
0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
--transition-fast: 120ms cubic-bezier(0.4, 0, 0.2, 1);
--transition: 200ms cubic-bezier(0.4, 0, 0.2, 1);
--z-dropdown: 50;
--z-modal: 200;
}
[data-variant='success'] {
--_variant-color: var(--success);
}
[data-variant='warning'] {
--_variant-color: var(--warning);
}
:is([data-variant='danger'], [data-variant='error']) {
--_variant-color: var(--danger);
}
Layout defaults from Oat (css/grid.css, css/sidebar.css):
:root {
--grid-cols: 12;
--grid-gap: 1.5rem;
--container-max: 1280px;
--container-pad: 1rem;
--sidebar-width: 15rem;
}