Components

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-theme

3. 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-card

Brand Accent Pair

TokenValueHexPurpose
--brand-cyanoklch(0.865 0.1475 204.0)#00EEFFPrimary interactive — buttons, links, focus rings, primary data
--brand-cyan-lightoklch(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-tokens separately. For everyday secondary accents, use the sand family (see v2 Brand Tokens below).

Surface Tokens

TokenValuePurpose
--backgroundoklch(0.12 0.015 285)Deep dark canvas
--foregroundoklch(0.93 0.018 70)Warm-whisper text · v2 lock 2026-05-06
--cardoklch(0.16 0.015 285)Elevated surface
--card-foregroundoklch(0.96 0.01 285)Card text (cool white — intentional divergence)
--popoveroklch(0.16 0.015 285)Popover background
--popover-foregroundoklch(0.96 0.01 285)Popover text
--mutedoklch(0.22 0.015 285)Subdued backgrounds
--muted-foregroundoklch(0.68 0.02 285)Secondary text
--muted-fg-lowoklch(0.55 0.012 285)Replaces opacity 0.6–0.7 on --muted-foreground
--muted-fg-vlowoklch(0.43 0.012 285)Replaces opacity 0.4–0.5 on --muted-foreground

Semantic Tokens

TokenValuePurpose
--primaryoklch(0.865 0.1475 204.0)Cyan — primary actions
--primary-foregroundoklch(0.12 0.015 285)Text on primary
--secondaryoklch(0.22 0.02 70)Sand-tinted background
--secondary-foregroundoklch(0.83 0.04 75)Sand text on secondary
--accentoklch(0.22 0.04 195)Cyan-tint hover states
--accent-foregroundoklch(0.96 0.01 285)Text on accent
--destructiveoklch(0.704 0.191 22.216)Error/danger
--borderoklch(0.26 0.015 285)Subtle borders
--inputoklch(0.26 0.015 285)Input borders
--ringoklch(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.

TokenValuePurpose
--chart-1oklch(0.865 0.1475 204.0)Cyan — primary data series
--chart-2oklch(0.72 0.15 255)Azure — secondary data series
--chart-3oklch(0.75 0.12 195)Cyan muted — tertiary
--chart-4oklch(0.8 0.12 180)Teal
--chart-5oklch(0.70 0.10 210)Deep cyan
TokenValuePurpose
--sidebaroklch(0.12 0.015 285)Sidebar background
--sidebar-foregroundoklch(0.65 0.015 285)Sidebar text
--sidebar-primaryoklch(0.865 0.1475 204.0)Active item
--sidebar-primary-foregroundoklch(0.10 0.015 285)Active item text
--sidebar-accentoklch(0.18 0.04 195)Hover state
--sidebar-accent-foregroundoklch(0.92 0.01 285)Hover text
--sidebar-borderoklch(0.22 0.012 285)Sidebar borders
--sidebar-ringoklch(0.865 0.1475 204.0)Sidebar focus ring

Typography

TokenValue
--font-sans"Inter", ui-sans-serif, system-ui, sans-serif
--font-mono"JetBrains Mono", ui-monospace, monospace

Other

TokenValuePurpose
--radius0.625remDefault border radius
--title-foregroundoklch(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, swap bg-primarybg-sand and text-primary-foregroundtext-sand-light (or override --primary directly).

Sand family

TokenValuePurpose
--sandoklch(0.71 0.04 70)Premium accent fill, alternative CTA background
--sand-lightoklch(0.83 0.04 75)CTA text on sand fill, hover-state text, premium labels
--sand-whisperoklch(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

TokenValuePurpose
--brand-iceoklch(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

TokenValuePurpose
--obsidianoklch(0.08 0.012 285)Full-bleed darkest layer; hero rims, cinematic close
--surface-1oklch(0.135 0.012 285)Slight lift over --background; section separators
--surface-2oklch(0.155 0.014 285)Card surface for editorial panels
--surface-3oklch(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).

TokenValue
--rank-1oklch(0.20 0.10 210)
--rank-2oklch(0.30 0.12 210)
--rank-3oklch(0.42 0.13 210)
--rank-4oklch(0.55 0.14 210)
--rank-5oklch(0.70 0.14 210)
--rank-6oklch(0.84 0.15 210)

Tailwind utilities: bg-rank-{1..6}, text-rank-{1..6}, border-rank-{1..6}.

Brand-tokened shadow set

TokenPurpose
--shadow-cardCard depth (inset highlight + outer drop + 1px hairline)
--shadow-signalGlow on active gauge ticks / segmented bar segments (60% cyan)
--shadow-cta-glowHover state on primary CTAs (25% cyan)
--shadow-sheetSheet/drawer ambient glow (5% cyan + drop)

Tailwind utilities: shadow-card, shadow-signal, shadow-cta-glow, shadow-sheet.

Display typeface

TokenValuePurpose
--font-displayvar(--font-inter), ui-sans-serif, system-ui, sans-serifHeavy 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

PropertyValue
Source@vandoko/original
LicenseMIT
Curated2026-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-visible cyan ring, reduced-motion-gated smooth-scroll
  • v2 brand lock 2026-05-06 — sand family (--sand, --sand-light, --sand-whisper), --brand-ice atmospheric, warm-whisper --foreground (was cool-white), --muted-fg-low/vlow AA-verified opacity-stack replacements
  • Lime quarantine 2026-05-06 — --brand-lime extracted to vandoko-campaign-tokens block (gated install)

On this page