Vandoko Dark Theme
Dark-only oklch theme with signal-cyan primary and sand secondary accent. Install with npx shadcn@latest add @vandoko/vandoko-theme.
Vandoko Dark Theme
Starting a new Vandoko brand concept or project? Install the approved theme to get the full oklch color system, typography tokens, and chart colors aligned with the Vandoko brand.
Dark-only oklch color system with signal-cyan primary (#00EEFF) on obsidian surfaces with a sand paired accent. Chart colors derive from the cool cyan/azure/teal spectrum. Lime is retired from the core system (opt in via @vandoko/vandoko-campaign-tokens). This is the canonical Vandoko design system.
Installation
1. Add the @vandoko registry to your project's components.json:
{
"registries": {
"@vandoko": "https://registry.vandoko.com/r/{name}.json"
}
}2. Install the Vandoko dark theme:
npx shadcn@latest add @vandoko/vandoko-theme3. Import in your globals.css:
@import "tailwindcss";
@import "./vandoko-theme.css";4. Start adding components:
npx shadcn@latest add @vandoko/glass-card
npx shadcn@latest add @vandoko/icp-overview-strip
npx shadcn@latest add @vandoko/channel-kpi-strip
npx shadcn@latest add @vandoko/competitor-radar
npx shadcn@latest add @vandoko/market-composition-cardBrand Accent Pair
| Token | Value | Hex | Purpose |
|---|---|---|---|
--brand-cyan | oklch(0.865 0.1475 204.0) | #00EEFF | Primary interactive — buttons, links, focus rings, primary data |
--brand-cyan-light | oklch(0.96 0.02 208) | — | Titles, highlights |
Lime accent (
--brand-lime) is quarantined per v2 brand lock 2026-05-06. For celebration / hero-CTA / "money found" moments, install@vandoko/vandoko-campaign-tokensseparately. For everyday secondary accents, use the sand family (see v2 Brand Tokens below).
Surface Tokens
| Token | Value | Purpose |
|---|---|---|
--background | oklch(0.12 0.015 285) | Deep dark canvas |
--foreground | oklch(0.93 0.018 70) | Warm-whisper text · v2 lock 2026-05-06 |
--card | oklch(0.16 0.015 285) | Elevated surface |
--card-foreground | oklch(0.96 0.01 285) | Card text (cool white — intentional divergence) |
--popover | oklch(0.16 0.015 285) | Popover background |
--popover-foreground | oklch(0.96 0.01 285) | Popover text |
--muted | oklch(0.22 0.015 285) | Subdued backgrounds |
--muted-foreground | oklch(0.68 0.02 285) | Secondary text |
--muted-fg-low | oklch(0.55 0.012 285) | Replaces opacity 0.6–0.7 on --muted-foreground |
--muted-fg-vlow | oklch(0.43 0.012 285) | Replaces opacity 0.4–0.5 on --muted-foreground |
Semantic Tokens
| Token | Value | Purpose |
|---|---|---|
--primary | oklch(0.865 0.1475 204.0) | Cyan — primary actions |
--primary-foreground | oklch(0.12 0.015 285) | Text on primary |
--secondary | oklch(0.22 0.02 70) | Sand-tinted background |
--secondary-foreground | oklch(0.83 0.04 75) | Sand text on secondary |
--accent | oklch(0.22 0.04 195) | Cyan-tint hover states |
--accent-foreground | oklch(0.96 0.01 285) | Text on accent |
--destructive | oklch(0.704 0.191 22.216) | Error/danger |
--border | oklch(0.26 0.015 285) | Subtle borders |
--input | oklch(0.26 0.015 285) | Input borders |
--ring | oklch(0.865 0.1475 204.0) | Focus ring |
Chart Colors (accent-derived)
Chart colors derive from the cool cyan/azure/teal spectrum for visual consistency on data surfaces. Lime is fully retired from the data-series palette as of the v2.2 brand lock (2026-06-02) — --chart-2 is now azure and --chart-4 is teal. Lime survives only in the opt-in @vandoko/vandoko-campaign-tokens block.
| Token | Value | Purpose |
|---|---|---|
--chart-1 | oklch(0.865 0.1475 204.0) | Cyan — primary data series |
--chart-2 | oklch(0.72 0.15 255) | Azure — secondary data series |
--chart-3 | oklch(0.75 0.12 195) | Cyan muted — tertiary |
--chart-4 | oklch(0.8 0.12 180) | Teal |
--chart-5 | oklch(0.70 0.10 210) | Deep cyan |
Sidebar Tokens
| Token | Value | Purpose |
|---|---|---|
--sidebar | oklch(0.12 0.015 285) | Sidebar background |
--sidebar-foreground | oklch(0.65 0.015 285) | Sidebar text |
--sidebar-primary | oklch(0.865 0.1475 204.0) | Active item |
--sidebar-primary-foreground | oklch(0.10 0.015 285) | Active item text |
--sidebar-accent | oklch(0.18 0.04 195) | Hover state |
--sidebar-accent-foreground | oklch(0.92 0.01 285) | Hover text |
--sidebar-border | oklch(0.22 0.012 285) | Sidebar borders |
--sidebar-ring | oklch(0.865 0.1475 204.0) | Sidebar focus ring |
Typography
| Token | Value |
|---|---|
--font-sans | "Inter", ui-sans-serif, system-ui, sans-serif |
--font-mono | "JetBrains Mono", ui-monospace, monospace |
Other
| Token | Value | Purpose |
|---|---|---|
--radius | 0.625rem | Default border radius |
--title-foreground | oklch(0.96 0.02 208) | Vibrant title color utility |
v2 Brand Tokens
Locked 2026-05-06, mirror of vandoko-ai's PR A token foundation. Sand is the warm voice for premium accents and alternative CTA fills; brand-ice is the cool atmospheric counterpoint. Cyan stays as the brand signal color (focus rings, gauge primary, primary CTA on the registry app).
The registry's own primary CTA stays on
bg-primary(cyan) — sand is available as a premium-accent option for consumer projects but is not consumed on the registry app's surfaces. To migrate your own CTAs to sand, swapbg-primary→bg-sandandtext-primary-foreground→text-sand-light(or override--primarydirectly).
Sand family
| Token | Value | Purpose |
|---|---|---|
--sand | oklch(0.71 0.04 70) | Premium accent fill, alternative CTA background |
--sand-light | oklch(0.83 0.04 75) | CTA text on sand fill, hover-state text, premium labels |
--sand-whisper | oklch(0.89 0.04 80) | Hairline borders (use at low alpha) |
Tailwind utilities: bg-sand, bg-sand-light, bg-sand-whisper, text-sand, border-sand-whisper, etc.
Atmospheric
| Token | Value | Purpose |
|---|---|---|
--brand-ice | oklch(0.84 0.025 235) | Cool atmospheric counterpoint to sand — live-ping accents, mist |
Tailwind utility: bg-brand-ice, text-brand-ice, etc.
Foreground (warm whisper)
The base --foreground token shifted from cool-white oklch(0.96 0.01 285) to warm-whisper oklch(0.93 0.018 70). Every text-foreground consumer site-wide picks up the slightly warmer + dimmer body text. Card and popover foregrounds (--card-foreground, --popover-foreground) deliberately stay cool-white for in-card readability — intentional divergence inherited from vandoko-ai PR A.
Prestige Editorial Layer
Surface ladder, cyan rank ramp, brand-tokened shadow set, and a display-typeface placeholder. These tokens enable editorial sections (statement heroes, blueprint panels, ranked-row tables, prestige cards) without redeclaring values per component. All shadow tokens reference var(--brand-cyan) via color-mix() indirection — no literal cyan duplication.
Surface ladder
| Token | Value | Purpose |
|---|---|---|
--obsidian | oklch(0.08 0.012 285) | Full-bleed darkest layer; hero rims, cinematic close |
--surface-1 | oklch(0.135 0.012 285) | Slight lift over --background; section separators |
--surface-2 | oklch(0.155 0.014 285) | Card surface for editorial panels |
--surface-3 | oklch(0.185 0.014 285) | Hover/active raise on cards |
Mono cyan rank ramp
For editorial rank tables (ranked-row mini-tables, "top categories" lists). Lightness ascends 0.20 → 0.84; hue locked to brand cyan band (210).
| Token | Value |
|---|---|
--rank-1 | oklch(0.20 0.10 210) |
--rank-2 | oklch(0.30 0.12 210) |
--rank-3 | oklch(0.42 0.13 210) |
--rank-4 | oklch(0.55 0.14 210) |
--rank-5 | oklch(0.70 0.14 210) |
--rank-6 | oklch(0.84 0.15 210) |
Tailwind utilities: bg-rank-{1..6}, text-rank-{1..6}, border-rank-{1..6}.
Brand-tokened shadow set
| Token | Purpose |
|---|---|
--shadow-card | Card depth (inset highlight + outer drop + 1px hairline) |
--shadow-signal | Glow on active gauge ticks / segmented bar segments (60% cyan) |
--shadow-cta-glow | Hover state on primary CTAs (25% cyan) |
--shadow-sheet | Sheet/drawer ambient glow (5% cyan + drop) |
Tailwind utilities: shadow-card, shadow-signal, shadow-cta-glow, shadow-sheet.
Display typeface
| Token | Value | Purpose |
|---|---|---|
--font-display | var(--font-inter), ui-sans-serif, system-ui, sans-serif | Heavy hero / section headlines |
Currently aliases --font-inter as a placeholder. When a heavy display face is selected (ongoing brand decision), swap this single var — every font-display consumer site-wide picks up the new face on next render.
A11y Baseline
The theme ships an opinionated a11y baseline so consumers inherit the same focus-ring + reduced-motion contract as the registry app itself.
Universal focus ring
*:focus-visible {
outline: 2px solid var(--brand-cyan);
outline-offset: 2px;
border-radius: inherit;
}Applied to every interactive element on Tab navigation. Beats default browser styling. The border-radius: inherit keeps the ring shape matching pill / rounded-card affordances.
Reduced-motion-gated smooth scroll
@media (prefers-reduced-motion: no-preference) {
html { scroll-behavior: smooth; }
}TOC and anchor links scroll smoothly only when the user hasn't requested reduced motion. Don't redeclare per page or per component — the gate is global.
Reduced-motion helper (consumer-side)
For client components that own a RAF loop, scripted scroll, or animated count-up: import respectsReducedMotion() from lib/respects-reduced-motion.ts (mirror of the vandoko-ai helper). Branch on its return value to snap to final state instead of suppressing the end visual.
Motion contract
See docs/brand/motion-rules.md for the page-level motion budget, card-hover do/don't (banned single-side border reveal; approved interim lift+press; pending two-connected-sides refinement), and the cross-repo source-of-truth pointer.
Lineage
| Property | Value |
|---|---|
| Source | @vandoko/original |
| License | MIT |
| Curated | 2026-03-30 |
Modifications
- All oklch values — no HSL or hex in token definitions
- Chart colors use the cool cyan/azure/teal data-series spectrum (lime retired to campaign-tokens at v2.2 brand lock)
- Typography tokens for Inter and JetBrains Mono
- Sidebar tokens for dashboard navigation
- Title foreground utility for vibrant headings
- Gauge zone palette + heatmap intensity ramp (data-viz primitives)
- Prestige editorial layer — surface ladder, mono cyan rank ramp, brand-tokened shadow set, display-typeface placeholder
- A11y baseline — universal
*:focus-visiblecyan ring, reduced-motion-gated smooth-scroll - v2 brand lock 2026-05-06 — sand family (
--sand,--sand-light,--sand-whisper),--brand-iceatmospheric, warm-whisper--foreground(was cool-white),--muted-fg-low/vlowAA-verified opacity-stack replacements - Lime quarantine 2026-05-06 —
--brand-limeextracted tovandoko-campaign-tokensblock (gated install)