Theming

Every component and block is styled with the shadcn/ui CSS variables, so they follow your theme. Install the Balick palette to get the exact look of this site.

Install the theme#

pnpm dlx shadcn@latest add @balick/theme

The CLI writes the colour tokens, the radius and their dark variants to your global CSS file. Review the diff before committing if you already customised your theme.

Tokens#

Paper and ink: one cool hue family instead of pure black and white. Light mode is ink on paper, dark mode is paper on ink. Cards and popovers sit above the canvas, muted surfaces below it, and emphasis comes from inverting foreground and background rather than from an accent colour. Radius: 0.5rem.

TokenLightDark
--backgroundoklch(0.9543 0.0067 295.4)oklch(0.1094 0.0374 256.1)
--foregroundoklch(0.1094 0.0374 256.1)oklch(0.9543 0.0067 295.4)
--cardoklch(1 0 0)oklch(0.175 0.03 264)
--card-foregroundoklch(0.1094 0.0374 256.1)oklch(0.9543 0.0067 295.4)
--popoveroklch(1 0 0)oklch(0.19 0.03 265)
--popover-foregroundoklch(0.1094 0.0374 256.1)oklch(0.9543 0.0067 295.4)
--primaryoklch(0.1094 0.0374 256.1)oklch(0.9543 0.0067 295.4)
--primary-foregroundoklch(0.9543 0.0067 295.4)oklch(0.1094 0.0374 256.1)
--secondaryoklch(0.925 0.01 290)oklch(0.215 0.026 268)
--secondary-foregroundoklch(0.1094 0.0374 256.1)oklch(0.9543 0.0067 295.4)
--mutedoklch(0.925 0.01 290)oklch(0.215 0.026 268)
--muted-foregroundoklch(0.5 0.022 275)oklch(0.72 0.018 285)
--accentoklch(0.93 0.01 290)oklch(0.235 0.025 270)
--accent-foregroundoklch(0.1094 0.0374 256.1)oklch(0.9543 0.0067 295.4)
--destructiveoklch(0.577 0.245 27.325)oklch(0.704 0.191 22.216)
--borderoklch(0.1094 0.0374 256.1 / 12%)oklch(0.9543 0.0067 295.4 / 12%)
--inputoklch(0.1094 0.0374 256.1 / 18%)oklch(0.9543 0.0067 295.4 / 16%)
--ringoklch(0.62 0.02 275)oklch(0.5 0.03 275)

Typography#

Components inherit your fonts. This site uses Geist and Geist Mono; to match it in a Next.js app, load them with next/font and map them to the Tailwind font variables.

app/layout.tsx
import { Geist, Geist_Mono } from "next/font/google"

const geistSans = Geist({ variable: "--font-geist-sans", subsets: ["latin"] })
const geistMono = Geist_Mono({ variable: "--font-geist-mono", subsets: ["latin"] })

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
        {children}
      </body>
    </html>
  )
}
app/globals.css
@theme inline {
  --font-sans: var(--font-geist-sans);
  --font-mono: var(--font-geist-mono);
}

Dark mode#

Dark values live under the .dark class, like shadcn/ui. Toggle it with next-themes using attribute="class". Every block is designed and checked in both modes.