Usage

The kumo-* prefix is inherited from upstream Kumo and remains Clock’s compatibility namespace. Use it for current semantic classes; do not substitute raw Tailwind colors or invent a parallel prefix.

Always use semantic tokens instead of raw Tailwind colors. This ensures your UI automatically adapts to light and dark mode, and that your components remain consistent across themes.

Correct

<div className="bg-kumo-base text-kumo-default border-kumo-hairline">
  <button className="bg-kumo-brand text-white">Primary</button>
  <button className="bg-kumo-control text-kumo-default">Secondary</button>
</div>

Incorrect

{
  /* Never use raw Tailwind colors */
}
<div className="bg-white dark:bg-gray-900 text-black dark:text-white">
  <button className="bg-blue-500">Primary</button>
</div>;

Lint rules enforce this: The no-primitive-colors rule will flag any raw Tailwind colors like bg-blue-500.

Mode

Set data-mode on a parent element to control light/dark mode. Never use Tailwind’s dark: variant — semantic tokens handle dark mode automatically via CSS light-dark().

// Set mode on html or body
<html data-mode="light">  // Light mode
<html data-mode="dark">   // Dark mode

// Components automatically adapt - no dark: variants needed
<div className="bg-kumo-base text-kumo-default" />

Themes

Themes override semantic token values while preserving the same token names. Set data-theme on a parent element to apply a theme.

Available Themes

  • kumo — Clock’s Cobalt Ink default (no attribute needed; name retained for compatibility)
  • fedramp — Government compliance styling
// Apply a theme to a section or the whole app
<div data-theme="fedramp">
  {/* All Clock components inside use fedramp token overrides */}
  <Button>FedRAMP Styled</Button>
</div>

// Themes work with both light and dark mode
<html data-mode="dark" data-theme="fedramp">

Theme Generator

Themes are defined in a centralized config and generated as CSS files. The theme generator ensures consistency across all themes.


# List all tokens and their theme overrides

pnpm --filter @comhora/clock codegen:themes --list

# Generate theme CSS files

pnpm --filter @comhora/clock codegen:themes

# Preview changes without writing files

pnpm --filter @comhora/clock codegen:themes --dry-run

Theme config: packages/kumo/scripts/theme-generator/config.ts

Creating a New Theme

Add theme overrides in the config file. Only override tokens that need to change — all other tokens inherit from the base kumo theme.

// In scripts/theme-generator/config.ts
export const THEME_CONFIG: ThemeConfig = {
  color: {
    "kumo-base": {
      newName: "",
      theme: {
        kumo: {
          light: "var(--color-white, #fff)",
          dark: "var(--color-black, #000)",
        },
        // Add your theme override
        myTheme: {
          light: "#f0f4f8",
          dark: "#1a1f2e",
        },
      },
    },
    // ... other tokens
  },
};

// Add to available themes
export const AVAILABLE_THEMES = ["kumo", "fedramp", "myTheme"] as const;

Then run pnpm codegen:themes to generate the CSS.

Semantic Tokens

We use semantic tokens to group colors by purpose. Use the token that matches the role of the element, not the color you want to achieve.

Semantic tokens are named by role, not by hue. A token like bg-kumo-danger communicates intent — it doesn’t imply a specific shade of red, and its exact value can change per theme or color mode without touching your component code.

Surface Hierarchy

Surfaces establish depth and layering in the UI. Use them in order from the outermost background inward.

TokenPurpose
bg-kumo-canvasThe outermost page background — sits behind everything
bg-kumo-baseDefault component background
bg-kumo-elevatedSlightly elevated surface, e.g. LayerCard.Secondary
bg-kumo-recessedRecessed surface with a subtly darker fill, e.g. segmented Tabs background
bg-kumo-tintSubtle tinted background for tables or hover states
bg-kumo-contrastHigh-contrast, inverted background

Brand

TokenPurpose
bg-kumo-brandPrimary brand background
bg-kumo-brand-hoverHover state for brand backgrounds

Semantic Status Colors

Each status color comes in two variants: a solid color for icons and indicators, and a -tint variant for background fills behind content (i.e. Badge or Banner).

TokenPurpose
bg-kumo-infoInfo indicator
bg-kumo-successSuccess indicator
bg-kumo-warningWarning indicator
bg-kumo-dangerError/destructive indicator

Use the solid token bg-kumo-* for status dots, fill-kumo-* for icons, and border-kumo-*, ring-kumo-* for borders and rings. Banners and badges use the -tint variant with varying opacity values.

Something went wrong.
import { WarningIcon } from "@phosphor-icons/react";

export function StatusBannerDemo() {
  return (
    <div className="flex items-center gap-2 rounded-lg bg-kumo-danger-tint/70 p-4">
      <WarningIcon weight="fill" className="fill-kumo-danger" />
      <span className="text-sm text-kumo-danger">Something went wrong.</span>
    </div>
  );
}

Text Colors

TokenPurpose
text-kumo-defaultPrimary body text
text-kumo-strongStronger text contrast than default for headers and important labels
text-kumo-subtleMuted text for descriptions, captions, or secondary labels
text-kumo-inactiveDisabled or inactive text
text-kumo-placeholderPlaceholder text in inputs
text-kumo-inverseText intended for use on high-contrast or inverted backgrounds
text-kumo-linkLink text
text-kumo-infoInfo-colored text
text-kumo-successSuccess-colored text
text-kumo-warningWarning-colored text
text-kumo-dangerError/destructive text

Semantic text colors (i.e. text-kumo-success) are darker by default to provide better contrast and readability against tint-* backgrounds.

Borders & Rings

TokenPurpose
kumo-hairlineNewA border/ring color to distinguish between flat surfaces where no shadow is present (i.e. LayerCard).
kumo-hairlineA thicker border/ring color that defines the edge of an elevated surface alongside a shadow.

Token Reference

Toggle the theme in the header to see how tokens adapt. Tokens marked as “global” are explicit opt-in classes available regardless of theme.

Clock color system

Canonical

Clock’s canonical plum-biased neutral system with controlled cobalt interaction signals. Large surfaces stay near-neutral; #231223 and #F7EAF7 anchor compact contrast roles while blue carries interaction and information.

CanvasNear-neutral
BaseCards and dialogs
ElevatedContained depth
RecessedQuiet separation
ContrastBrand pole, kept compact

Colors

Displaying 56 tokens

Text Colors (12)

--text-color-kumo-default
Lightoklch(0.225 0.013 326)
Dark#fff
--text-color-kumo-inverse
Light#F7EAF7
Dark#F7EAF7
--text-color-kumo-strong
Light#231223
Darkoklch(0.992 0.003 326)
--text-color-kumo-subtle
Lightoklch(0.48 0.013 326)
Darkoklch(0.72 0.011 326)
--text-color-kumo-inactive
Lightoklch(0.84 0.01 326)
Darkoklch(0.39 0.014 326)
--text-color-kumo-placeholder
Lightoklch(0.55 0.013 326)
Darkoklch(0.65 0.012 326)
--text-color-kumo-brand
Lightoklch(0.47 0.155 258)
Darkoklch(0.69 0.12 258)
--text-color-kumo-link
Lightoklch(0.47 0.155 258)
Darkoklch(0.69 0.12 258)
--text-color-kumo-info
Lightoklch(0.47 0.155 258)
Darkoklch(0.69 0.12 258)
--text-color-kumo-success
Lightoklch(0.45 0.085 160)
Darkoklch(0.81 0.09 160)
--text-color-kumo-danger
Lightoklch(0.46 0.16 25)
Darkoklch(0.8 0.085 25)
--text-color-kumo-warning
Lightoklch(0.49 0.085 78)
Darkoklch(0.84 0.105 78)

Surface, State & Theme Colors (28)

--color-kumo-canvas
Lightoklch(0.986 0.004 326)
Dark#000
--color-kumo-elevated
Lightoklch(0.978 0.005 326)
Darkoklch(0.145 0.009 326)
--color-kumo-recessed
Lightoklch(0.958 0.007 326)
Darkoklch(0.165 0.01 326)
--color-kumo-base
Lightoklch(0.992 0.003 326)
Darkoklch(0.19 0.012 326)
--color-kumo-tint
Lightoklch(0.94 0.008 326)
Darkoklch(0.29 0.014 326)
--color-kumo-contrast
Light#231223
Dark#231223
--color-kumo-overlay
Lightoklch(0.978 0.005 326)
Darkoklch(0.29 0.014 326)
--color-kumo-control
Lightoklch(0.992 0.003 326)
Darkoklch(0.225 0.013 326)
--color-kumo-interact
Lightoklch(0.84 0.01 326)
Darkoklch(0.39 0.014 326)
--color-kumo-fill
Lightoklch(0.91 0.009 326)
Darkoklch(0.29 0.014 326)
--color-kumo-fill-hover
Lightoklch(0.958 0.007 326)
Darkoklch(0.34 0.014 326)
--color-kumo-brand
Lightoklch(0.37 0.135 258)
Darkoklch(0.37 0.135 258)
--color-kumo-brand-hover
Lightoklch(0.32 0.11 258)
Darkoklch(0.32 0.11 258)
--color-kumo-line
Lightcolor-mix(in oklch, #231223 12%, transparent)
Darkoklch(0.34 0.014 326)
--color-kumo-hairline
Lightoklch(0.94 0.008 326)
Darkoklch(0.29 0.014 326)
--color-kumo-focus
Lightoklch(0.37 0.135 258)
Darkoklch(0.69 0.12 258)
--color-kumo-shadow-edge
Lightoklch(0 0 0 / 0.12)
Darkoklch(1 0 0 / 0.1)
--color-kumo-shadow-drop
Lightoklch(0 0 0 / 0.08)
Darkoklch(0 0 0 / 0.3)
--color-kumo-tip-shadow
Lightoklch(0.91 0.009 326)
Darktransparent
--color-kumo-tip-stroke
Lighttransparent
Darkoklch(0.29 0.014 326)
--color-kumo-info-tint
Lightcolor-mix(in oklch, oklch(0.93 0.032 258) 65%, transparent)
Darkcolor-mix(in oklch, oklch(0.32 0.11 258) 50%, transparent)
--color-kumo-info
Lightoklch(0.6 0.145 258)
Darkoklch(0.6 0.145 258)
--color-kumo-warning-tint
Lightcolor-mix(in oklch, oklch(0.97 0.025 78) 75%, transparent)
Darkcolor-mix(in oklch, oklch(0.41 0.085 78) 55%, transparent)
--color-kumo-warning
Lightoklch(0.67 0.12 78)
Darkoklch(0.75 0.13 78)
--color-kumo-danger-tint
Lightcolor-mix(in oklch, oklch(0.95 0.022 25) 75%, transparent)
Darkcolor-mix(in oklch, oklch(0.4 0.135 25) 55%, transparent)
--color-kumo-danger
Lightoklch(0.51 0.17 25)
Darkoklch(0.51 0.17 25)
--color-kumo-success-tint
Lightcolor-mix(in oklch, oklch(0.96 0.035 160) 75%, transparent)
Darkcolor-mix(in oklch, oklch(0.39 0.075 160) 55%, transparent)
--color-kumo-success
Lightoklch(0.52 0.105 160)
Darkoklch(0.71 0.115 160)

Component Colors (16)

Badge (12)

--text-color-kumo-badge-orange-subtle
Lightoklch(0.49 0.085 78)
Darkoklch(0.84 0.105 78)
--text-color-kumo-badge-teal-subtle
Lightoklch(0.45 0.07 190)
Darkoklch(0.81 0.075 190)
--text-color-kumo-badge-neutral-subtle
Lightoklch(0.29 0.014 326)
Darkoklch(0.91 0.009 326)
--text-color-kumo-badge-inverted
Light#F7EAF7
Dark#F7EAF7
--color-kumo-badge-red
Lightoklch(0.46 0.16 25)
Darkoklch(0.46 0.16 25)
--color-kumo-badge-green
Lightoklch(0.45 0.085 160)
Darkoklch(0.45 0.085 160)
--color-kumo-badge-orange
Lightoklch(0.75 0.13 78)
Darkoklch(0.75 0.13 78)
--color-kumo-badge-purple
Lightoklch(0.44 0.14 300)
Darkoklch(0.44 0.14 300)
--color-kumo-badge-teal
Lightoklch(0.52 0.08 190)
Darkoklch(0.52 0.08 190)
--color-kumo-badge-blue
Lightoklch(0.47 0.155 258)
Darkoklch(0.47 0.155 258)
--color-kumo-badge-neutral
Lightoklch(0.48 0.013 326)
Darkoklch(0.48 0.013 326)
--color-kumo-badge-inverted
Light#231223
Dark#231223

Banner (2)

--color-kumo-banner-info
Lightcolor-mix(in oklch, oklch(0.93 0.032 258) 85%, transparent)
Darkcolor-mix(in oklch, oklch(0.32 0.11 258) 65%, transparent)
--color-kumo-banner-warning
Lightoklch(0.97 0.025 78)
Darkcolor-mix(in oklch, oklch(0.41 0.085 78) 65%, transparent)

Button (2)

--color-kumo-button-primary
Lightoklch(0.47 0.28 284.98)
Darkoklch(0.47 0.28 284.98)
--color-kumo-button-destructive
Lightoklch(0.59 0.22 26.41)
Darkoklch(0.59 0.22 26.41)