tradecn-amber

An amber theme with a day side and a night side: warm paper in light, near-black in dark, and blue and vermilion for up and down.

:root {
  --accent: oklch(0.93 0.02 75);
  --accent-foreground: oklch(0.3 0.04 65);
  --background: oklch(0.99 0.004 85);
  --border: oklch(0.88 0.008 85);
  --card: oklch(0.97 0.005 85);
  --card-foreground: oklch(0.2 0.01 85);
  --chart-1: oklch(0.54 0.12 65);
  --chart-2: oklch(0.52 0.13 245);
  --chart-3: oklch(0.52 0.13 165);
  --chart-4: oklch(0.5 0.15 330);
  --chart-5: oklch(0.55 0.12 90);
  --chart-6: oklch(0.52 0.12 225);
  --chart-7: oklch(0.5 0.18 40);
  --chart-8: var(--color-foreground);
  --destructive: oklch(0.52 0.21 27);
  --down: oklch(0.56 0.19 45);
  --down-soft: oklch(0.56 0.19 45 / 18%);
  --expiring: oklch(0.53 0.2 350);
  --expiring-soft: oklch(0.53 0.2 350 / 18%);
  --flat: var(--color-muted-foreground);
  --flat-soft: oklch(0.55 0 0 / 14%);
  --foreground: oklch(0.2 0.01 85);
  --input: oklch(0.88 0.008 85);
  --link-1: oklch(0.53 0.2 25);
  --link-2: oklch(0.5 0.15 250);
  --link-3: oklch(0.5 0.13 150);
  --link-4: oklch(0.52 0.12 85);
  --muted: oklch(0.95 0.005 85);
  --muted-foreground: oklch(0.47 0.015 85);
  --panel-active: var(--color-primary);
  --panel-drag-target: var(--color-ring);
  --panel-error: var(--color-destructive);
  --panel-sync: oklch(0.5 0.12 220);
  --popover: oklch(0.985 0.004 85);
  --popover-foreground: oklch(0.2 0.01 85);
  --primary: oklch(0.54 0.12 65);
  --primary-foreground: oklch(0.99 0.01 85);
  --radius: 0.25rem;
  --ring: oklch(0.54 0.12 65);
  --secondary: oklch(0.95 0.006 85);
  --secondary-foreground: oklch(0.25 0.015 85);
  --sidebar: oklch(0.965 0.006 85);
  --sidebar-accent: oklch(0.92 0.02 75);
  --sidebar-accent-foreground: oklch(0.3 0.04 65);
  --sidebar-border: oklch(0.88 0.008 85);
  --sidebar-foreground: oklch(0.2 0.01 85);
  --sidebar-primary: oklch(0.54 0.12 65);
  --sidebar-primary-foreground: oklch(0.99 0.01 85);
  --sidebar-ring: oklch(0.54 0.12 65);
  --stale: oklch(0.52 0.13 75);
  --stale-soft: oklch(0.52 0.13 75 / 16%);
  --tradecn-color-body-bg: oklch(0.99 0.004 85);
  --tradecn-color-body-fg: oklch(0.2 0.01 85);
  --tradecn-font-accessible: 'Atkinson Hyperlegible Next', 'Atkinson Hyperlegible', ui-sans-serif, system-ui, sans-serif;
  --tradecn-font-accessible-mono: 'Atkinson Hyperlegible Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --tradecn-font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --tradecn-font-numeric: var(--tradecn-font-sans);
  --tradecn-font-sans: 'Inter', ui-sans-serif, system-ui, sans-serif;
  --tradecn-font-weight-body: 450;
  --tradecn-font-weight-grid: 500;
  --tradecn-line-height-body: 1.45;
  --tradecn-line-height-grid: 1.35;
  --tradecn-numeric-variant: lining-nums tabular-nums;
  --tradecn-text-size-body: 14px;
  --tradecn-text-size-grid: 13px;
  --tradecn-text-size-grid-min: 12px;
  --up: oklch(0.45 0.13 245);
  --up-soft: oklch(0.45 0.13 245 / 18%);
}

.dark {
  --accent: oklch(0.28 0.03 70);
  --accent-foreground: oklch(0.9 0.08 80);
  --background: oklch(0.14 0.005 85);
  --border: oklch(0.3 0.008 85);
  --card: oklch(0.19 0.006 85);
  --card-foreground: oklch(0.94 0.03 85);
  --chart-1: oklch(0.78 0.16 70);
  --chart-2: oklch(0.74 0.12 240);
  --chart-3: oklch(0.74 0.15 165);
  --chart-4: oklch(0.74 0.15 330);
  --chart-5: oklch(0.85 0.15 95);
  --chart-6: oklch(0.78 0.11 225);
  --chart-7: oklch(0.7 0.18 40);
  --chart-8: var(--color-foreground);
  --destructive: oklch(0.71 0.18 22);
  --down: oklch(0.78 0.18 45);
  --down-soft: oklch(0.78 0.18 45 / 18%);
  --expiring: oklch(0.74 0.17 350);
  --expiring-soft: oklch(0.74 0.17 350 / 18%);
  --flat: var(--color-muted-foreground);
  --flat-soft: oklch(0.7 0 0 / 14%);
  --foreground: oklch(0.94 0.03 85);
  --input: oklch(0.32 0.008 85);
  --link-1: oklch(0.7 0.19 25);
  --link-2: oklch(0.7 0.14 250);
  --link-3: oklch(0.74 0.14 150);
  --link-4: oklch(0.85 0.15 90);
  --muted: oklch(0.23 0.006 85);
  --muted-foreground: oklch(0.7 0.02 85);
  --panel-active: var(--color-primary);
  --panel-drag-target: var(--color-ring);
  --panel-error: var(--color-destructive);
  --panel-sync: oklch(0.78 0.12 220);
  --popover: oklch(0.21 0.006 85);
  --popover-foreground: oklch(0.94 0.03 85);
  --primary: oklch(0.78 0.16 70);
  --primary-foreground: oklch(0.16 0.02 70);
  --ring: oklch(0.7 0.15 70);
  --secondary: oklch(0.25 0.008 85);
  --secondary-foreground: oklch(0.92 0.02 85);
  --sidebar: oklch(0.11 0.005 85);
  --sidebar-accent: oklch(0.26 0.03 70);
  --sidebar-accent-foreground: oklch(0.9 0.08 80);
  --sidebar-border: oklch(0.3 0.008 85);
  --sidebar-foreground: oklch(0.94 0.03 85);
  --sidebar-primary: oklch(0.78 0.16 70);
  --sidebar-primary-foreground: oklch(0.16 0.02 70);
  --sidebar-ring: oklch(0.7 0.15 70);
  --stale: oklch(0.8 0.15 80);
  --stale-soft: oklch(0.8 0.15 80 / 16%);
  --tradecn-color-body-bg: oklch(0.14 0.005 85);
  --tradecn-color-body-fg: oklch(0.94 0.03 85);
  --tradecn-font-accessible: 'Atkinson Hyperlegible Next', 'Atkinson Hyperlegible', ui-sans-serif, system-ui, sans-serif;
  --tradecn-font-accessible-mono: 'Atkinson Hyperlegible Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --tradecn-font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --tradecn-font-numeric: var(--tradecn-font-sans);
  --tradecn-font-sans: 'Inter', ui-sans-serif, system-ui, sans-serif;
  --tradecn-font-weight-body: 450;
  --tradecn-font-weight-grid: 500;
  --tradecn-line-height-body: 1.45;
  --tradecn-line-height-grid: 1.35;
  --tradecn-numeric-variant: lining-nums tabular-nums;
  --tradecn-text-size-body: 14px;
  --tradecn-text-size-grid: 13px;
  --tradecn-text-size-grid-min: 12px;
  --up: oklch(0.66 0.12 240);
  --up-soft: oklch(0.66 0.12 240 / 18%);
}

@layer base {
  :root {
    font-variant-numeric: var(--tradecn-numeric-variant);
  }
  .tradecn-num, [data-numeric] {
    font-variant-numeric: var(--tradecn-numeric-variant);
  }
}
:root[data-accessibility="hyperlegible"], [data-accessibility="hyperlegible"] {
  --tradecn-font-sans: var(--tradecn-font-accessible);
  --tradecn-font-mono: var(--tradecn-font-accessible-mono);
}

Installation

pnpm dlx shadcn@latest add tradecn/ui/tradecn-amber#v2.0.0
npx shadcn@latest add tradecn/ui/tradecn-amber#v2.0.0
yarn dlx shadcn@latest add tradecn/ui/tradecn-amber#v2.0.0
bunx --bun shadcn@latest add tradecn/ui/tradecn-amber#v2.0.0

Usage

A theme installs no files. It rewrites the variables in your stylesheet. Configure the @tradecn namespace for the release you want, following Installation. When reading an older versioned page, select that same release in the Installation guide's version menu before copying the namespace. Replace src/index.css below with the tailwind.css path from your components.json:

pnpm dlx shadcn@latest add @tradecn/tradecn-amber --diff src/index.css
npx shadcn@latest add @tradecn/tradecn-amber --diff src/index.css
yarn dlx shadcn@latest add @tradecn/tradecn-amber --diff src/index.css
bunx --bun shadcn@latest add @tradecn/tradecn-amber --diff src/index.css

A bare --diff does not show theme CSS changes. Review the stylesheet diff and commit your current files, then remove --diff and the stylesheet path to install the theme.

API Reference

The default theme

Amber is tradecn.dev's default theme: the terminal look with a day side. Installing components without a theme keeps green for up. Those items use slate's light marks and dark marks tuned for shadcn's dark surfaces; installing amber moves up to blue.

This one overwrites

Like every tradecn theme, it replaces shadcn's palette variables, all eight --chart-* colors, sidebar colors, and --radius, and sets every tradecn token in both modes. It leaves your app's --font-sans alone but resets tradecn's typography tokens to their defaults, including any custom --tradecn-font-* stacks.

It also adds the numeric variant on :root and the numeric hooks, plus the hyperlegible font remap described in Typography. Restore your stylesheet from version control to undo the installation.

Two sides

Light uses warm paper with near-black text. Dark uses near-black surfaces with lighter text and marks. The near-black background is a design preference for long sessions, not a measured legibility benefit.

Token Light Dark
--background oklch(0.99 0.004 85) oklch(0.14 0.005 85)
--foreground oklch(0.2 0.01 85) oklch(0.94 0.03 85)
--primary oklch(0.54 0.12 65) oklch(0.78 0.16 70)
--up oklch(0.45 0.13 245) oklch(0.66 0.12 240)
--down oklch(0.56 0.19 45) oklch(0.78 0.18 45)

Blue for up

Amber adapts the blue and vermilion from Okabe and Ito's palette for its two backgrounds. Their guidance combines color with labels, shapes, or patterns. Choose tradecn-slate when the desk expects green for up.

The repository's luminance calculation gives the direction pair a grayscale ratio of 1.45 to 1 in light and 1.33 to 1 in dark. Tests require at least 1.3 to 1. Both gaps are below the 3 to 1 threshold for lightness as an additional visual distinction in WCAG's use-of-color guidance, so keep direction visible in signs or labels.

stale and primary sit near each other in hue here; the badge's word carries the difference. flat follows your muted foreground, panel-active follows primary, panel-drag-target follows ring, and panel-error follows destructive.

The colors are checked

The contrast tests require 4.5 to 1 for the declared text/surface pairs and for primary, up, down, stale, expiring, link-1 through link-4, panel-sync, destructive, and ring on the background and card, in both modes, and for destructive on a destructive control's own tint, 10 percent in light mode and 20 in dark, over the background, a card, and a popover, as every shadcn style's destructive Button draws it. They blend a tint the way a browser does, in gamma-encoded sRGB.

The foreground clears 4.5 to 1 on every tint an item puts text on: the soft tints, and primary and destructive at 15 and 12 percent, over the background and a card. A tone's own color on its tint can fall below that in light mode, so tinted badges, rule highlights, a countdown running short, a stale feed tier, the session warning, the active inquiry, and the ladder's own size carry foreground text, state text inside them included, and a selected grid row is marked by a bar rather than filled. The marks a grid cell carries also clear 4.5 to 1 on the grid's own tints: the focused column and the ladder's mid row. A cell's fill flash starts at its direction's tint and fades within its window, holding for the whole window under reduced motion, and a new row's arrival highlight tints it flat-soft for a second and a half; state-colored text can read below 4.5 to 1 on either while it lasts. These checks do not cover every component state or chart colors.

The calculated light primary contrast is 5.1 to 1 on the page and 4.8 to 1 on a card. The tightest checked pair is down on the depth ladder's light mid row, at 4.54 to 1; on a light card it is 4.6 to 1. The browser matrix installs each theme separately into three consumers and reads every theme color back from the page in both modes.

What it does not do

The theme installs no components, font files, or runtime switcher. Your app controls the dark class to select between the installed palettes.

This page is docs/tradecn-amber.md at v2.0.0.