Foundation
Theming
Every visual decision lives in a CSS variable. Components only read tokens, so one change restyles the whole system.
Colors#
Text is pure near-black #0a0a0a. Fills and tracks use cool slate, and one blue, #056dff, carries every primary action. Hairlines and hover fills are transparent black, so they sit well on any surface. Every pair follows the name / name-foreground convention.
Base
--backgroundPage background--foregroundDefault text--cardCard surface--popoverMenus, popoversActions
--primaryDefault button, emphasis--ringFocus ring--secondaryLow-emphasis fills--destructiveDanger, errorsNeutrals
--mutedSubtle fills--muted-foregroundSecondary text--accentHover fills--borderHairlinesCharts
--chart-1Series 1--chart-2Series 2--chart-3Series 3--chart-4Series 4Surfaces#
Depth is a token too. The primary surface is a vertical gradient from #3c86ff to #056dff with a 1px inner edge. Raised controls are white with a hairline ring and a 0 1px 2px shadow. Tracks are flat slate. Panels are warm off-white.
Radius#
One base value, --radius: 0.5rem. The scale is md 6px (tab trigger), lg 8px (controls, menu items), xl 12px (menus, popovers) and 2xl 16px (cards, bubbles). Nested shapes use a smaller step than their container.
smmdlgxl2xlfullTypography#
Inter for interface text, Geist Mono for code. Buttons use -0.01em tracking, headings use tight tracking.
Full source#
The complete foundation file. Copy it into your project.
@import "tailwindcss";@import "tw-animate-css";@import "./variants.css";@custom-variant dark (&:is(.dark *));/* ------------------------------------------------------------------ * Sabil UI — design foundation * All components read these tokens. Change a token, the whole * system follows. * ------------------------------------------------------------------ *//* Motion. Overrides Tailwind's default `ease-out` / `ease-in-out` * with stronger curves, so every existing utility gets the upgrade. */@theme { --ease-out: cubic-bezier(0.23, 1, 0.32, 1); --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1); --ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);}@theme inline { --font-heading: var(--font-sans); --font-mono: var(--font-geist-mono); --font-sans: var(--font-inter); --color-brand: var(--brand); --color-brand-foreground: var(--brand-foreground); --color-panel: var(--panel); --color-bubble: var(--bubble); --color-bubble-strong: var(--bubble-strong); --color-overlay-border: var(--overlay-border); --color-sidebar-ring: var(--sidebar-ring); --color-sidebar-border: var(--sidebar-border); --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); --color-sidebar-accent: var(--sidebar-accent); --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); --color-sidebar-primary: var(--sidebar-primary); --color-sidebar-foreground: var(--sidebar-foreground); --color-sidebar: var(--sidebar); --color-chart-5: var(--chart-5); --color-chart-4: var(--chart-4); --color-chart-3: var(--chart-3); --color-chart-2: var(--chart-2); --color-chart-1: var(--chart-1); --color-ring: var(--ring); --color-input: var(--input); --color-border: var(--border); --color-destructive: var(--destructive); --color-accent-foreground: var(--accent-foreground); --color-accent: var(--accent); --color-muted-foreground: var(--muted-foreground); --color-muted: var(--muted); --color-secondary-foreground: var(--secondary-foreground); --color-secondary: var(--secondary); --color-primary-foreground: var(--primary-foreground); --color-primary: var(--primary); --color-popover-foreground: var(--popover-foreground); --color-popover: var(--popover); --color-card-foreground: var(--card-foreground); --color-card: var(--card); --color-foreground: var(--foreground); --color-background: var(--background); --radius-sm: calc(var(--radius) * 0.5); --radius-md: calc(var(--radius) * 0.75); --radius-lg: var(--radius); --radius-xl: calc(var(--radius) * 1.5); --radius-2xl: calc(var(--radius) * 2); --radius-3xl: calc(var(--radius) * 2.5); --radius-4xl: calc(var(--radius) * 3);}/* * Light. Pure neutrals (#0a0a0a family), slate fills for tracks, * one blue for primary actions. Values taken from the reference design. * Radius scale: md 6 · lg 8 · xl 12 · 2xl 16. */:root { --radius: 0.5rem; --background: #ffffff; --foreground: #0a0a0a; --card: #ffffff; --card-foreground: #0a0a0a; --popover: #ffffff; --popover-foreground: #0a0a0a; --primary: #056dff; --primary-foreground: #ffffff; --secondary: #f1f5f9; --secondary-foreground: #0f172b; --muted: #f1f5f9; --muted-foreground: #45556c; --accent: #0a0a0a0a; --accent-foreground: #0a0a0a; --destructive: #e7000b; --border: #0a0a0a14; --input: #0a0a0a1f; --ring: #056dff; --brand: var(--primary); --brand-foreground: var(--primary-foreground); --chart-1: #056dff; --chart-2: #3c86ff; --chart-3: #8ec5ff; --chart-4: #1447e6; --chart-5: #bedbff; --sidebar: #fafafa; --sidebar-foreground: #0a0a0a; --sidebar-primary: #056dff; --sidebar-primary-foreground: #ffffff; --sidebar-accent: #0a0a0a0a; --sidebar-accent-foreground: #0a0a0a; --sidebar-border: #0a0a0a14; --sidebar-ring: #056dff; /* Depth */ --primary-highlight: #3c86ff; --surface-edge: #00000040; --overlay-border: #0a0a0a0f; --panel: #f9f8f6; --bubble: #0a0a0a0a; --bubble-strong: #0a0a0a14; --raised: #ffffff; --sunken: #f1f5f9; --dot: #0a0a0a1f; --shadow-color: #0000000d;}.dark { --background: #0a0a0a; --foreground: #fafafa; --card: #121212; --card-foreground: #fafafa; --popover: #161616; --popover-foreground: #fafafa; --primary: #2b7bff; --primary-foreground: #ffffff; --secondary: #1d1d1f; --secondary-foreground: #fafafa; --muted: #1d1d1f; --muted-foreground: #a1a1a6; --accent: #ffffff0f; --accent-foreground: #fafafa; --destructive: #ff6467; --border: #ffffff17; --input: #ffffff24; --ring: #3c86ff; --chart-1: #3c86ff; --chart-2: #6aa6ff; --chart-3: #8ec5ff; --chart-4: #1f63e8; --chart-5: #bedbff; --sidebar: #0f0f0f; --sidebar-foreground: #fafafa; --sidebar-primary: #3c86ff; --sidebar-primary-foreground: #ffffff; --sidebar-accent: #ffffff0f; --sidebar-accent-foreground: #fafafa; --sidebar-border: #ffffff17; --sidebar-ring: #3c86ff; --primary-highlight: #5c9bff; --surface-edge: #00000080; --overlay-border: #ffffff14; --panel: #1a1918; --bubble: #ffffff0f; --bubble-strong: #ffffff1f; --raised: #1d1d1f; --sunken: #1d1d1f; --dot: #ffffff1a; --shadow-color: #00000066;}/* * Surface utilities — the signature look. * surface-primary : blue gradient, 1px inner edge, soft drop shadow. * surface-raised : white control with a hairline ring (outline button). * surface-sunken : slate track (tab list, segmented control). * bg-dots : dotted canvas for previews. */@utility surface-primary { background-image: linear-gradient(180deg, var(--primary-highlight) 0%, var(--primary) 100%); box-shadow: inset 0 0 1px var(--surface-edge), inset 0 1px 0 0 #ffffff1f, 0 1px 2px 0 var(--shadow-color);}@utility surface-raised { background-color: var(--raised); box-shadow: 0 0 0 1px var(--border), 0 1px 2px 0 var(--shadow-color);}@utility surface-sunken { background-color: var(--sunken);}@utility bg-dots { background-color: var(--background); background-image: radial-gradient(var(--dot) 1px, transparent 1px); background-size: 20px 20px;}@layer base { * { @apply border-border outline-ring/50; } html { @apply font-sans; scroll-padding-top: 5rem; } body { @apply bg-background text-foreground; letter-spacing: -0.006em; } ::selection { background-color: color-mix(in oklch, var(--brand) 22%, transparent); } button:not(:disabled), [role="button"]:not(:disabled) { cursor: pointer; } /* Every overlay (dropdown, popover, dialog, sheet, tooltip...) enters * with the strong ease-out unless a component sets its own easing. */ [data-slot$="-content"] { --tw-ease: var(--ease-out); }}@media (prefers-reduced-motion: reduce) { *, ::before, ::after { animation-duration: 1ms !important; transition-duration: 1ms !important; }}