Foundations
FoundationsTier 1 · Tokens
Token metadata
Human-readable descriptions of every token, for docs and swatch tables.
bunx --bun shadcn@latest add @woohl/tokens-metaReference
Installs this item, its registry dependencies and the token layer.
bunx --bun shadcn@latest add @woohl/tokens-metaregistry/tier-1-tokens/lib/tokens.ts
/**
* The token registry, in TypeScript.
*
* styles/tokens/*.css declares the tokens for the browser. This file
* describes them for code — so a swatch table, a theme picker, a Figma export
* or a lint rule is generated from the same list the stylesheet uses, never
* transcribed from it.
*
* If you add a token, add it in BOTH places. That rule is inherited from the
* design-system site and it is the only thing keeping the two halves honest.
*
* Nothing here is a runtime dependency of any component — components read CSS
* variables. This module exists for tooling and documentation.
*/
/* ------------------------------------------------------------------ colour */
export type Shade = {
/** The name the brand actually uses in conversation. */
name: string;
/** Numeric step, for code. */
step: string;
hex: string;
/** The CSS custom property that carries it. */
token: string;
/** Where this shade is allowed to appear. */
use: string;
};
export const BRAND_RAMP: Shade[] = [
{
name: "Whisper",
step: "50",
hex: "#FDEFE7",
token: "--color-brand-50",
use: "Tinted page sections, hover fills on white",
},
{
name: "Sand",
step: "100",
hex: "#FADECF",
token: "--color-brand-100",
use: "Badge and chip backgrounds, table row highlight",
},
{
name: "Peach",
step: "200",
hex: "#F8CEB6",
token: "--color-brand-200",
use: "Dividers on tinted surfaces, disabled accent",
},
{
name: "Apricot",
step: "300",
hex: "#F6BE9E",
token: "--color-brand-300",
use: "Illustration mid-tone, chart series 3",
},
{
name: "Coral",
step: "400",
hex: "#F19D6E",
token: "--color-brand-400",
use: "Illustration, chart series 2, decorative only",
},
{
name: "Tangerine",
step: "500",
hex: "#ED7D3D",
token: "--color-brand-500",
use: "Chart series 1, gradient stop, never text",
},
{
name: "Woohl Orange",
step: "600",
hex: "#F4521B",
token: "--color-brand-600",
use: "THE accent. Primary buttons, links, focus, the mark",
},
{
name: "Ember",
step: "700",
hex: "#E85C0D",
token: "--color-brand-700",
use: "Hover state for Woohl Orange surfaces",
},
{
name: "Rust",
step: "800",
hex: "#BA4A0A",
token: "--color-brand-800",
use: "Pressed state; accent text on white when AA is required",
},
{
name: "Cinnamon",
step: "900",
hex: "#8B3708",
token: "--color-brand-900",
use: "Accent text at small sizes, warm dark UI",
},
{
name: "Cocoa",
step: "950",
hex: "#5D2505",
token: "--color-brand-950",
use: "Deep warm backgrounds, print duotone shadow",
},
];
export const DEEP_TONES: Shade[] = [
{
name: "Espresso",
step: "—",
hex: "#461C04",
token: "--color-espresso",
use: "Warm dark surface alternative to Ink",
},
{
name: "Bark",
step: "—",
hex: "#2E1203",
token: "--color-bark",
use: "Packaging, print, deep editorial backgrounds",
},
{
name: "Pitch",
step: "—",
hex: "#170901",
token: "--color-pitch",
use: "Maximum-depth warm black",
},
];
/**
* The non-buyer product theme accents.
*
* Buyer runs on the brand ramp above. Seller, admin and creator each take their
* own hue, because they are surfaces a person signs into and telling them apart
* at a glance beats repeating the brand on a screen no customer sees.
*
* Every ramp uses the same steps for the same jobs, so the themes stay
* interchangeable: 600 fills on light, 700 hovers, 800 is accent text that must
* pass AA; 500 fills on dark, 400 hovers and carries accent text.
*
* Consumed only by themes/*.css, exactly like the brand ramp. A component asks
* for --surface-accent and gets whichever hue the active theme resolved.
*/
export const PRODUCT_THEME_RAMPS: Record<
"seller" | "admin" | "creator",
{ label: string; shades: Shade[] }
> = {
seller: {
label: "Merchant Forest",
shades: [
{
name: "Sprout",
step: "50",
hex: "#F0FDF4",
token: "--color-forest-50",
use: "Subtle accent fill on light",
},
{
name: "Mint",
step: "300",
hex: "#86EFAC",
token: "--color-forest-300",
use: "Strong accent text on dark",
},
{
name: "Leaf",
step: "400",
hex: "#4ADE80",
token: "--color-forest-400",
use: "Hover, accent text and border on dark",
},
{
name: "Forest",
step: "500",
hex: "#22C55E",
token: "--color-forest-500",
use: "THE seller accent on dark",
},
{
name: "Pine",
step: "600",
hex: "#16A34A",
token: "--color-forest-600",
use: "THE seller accent on light",
},
{
name: "Fern",
step: "700",
hex: "#15803D",
token: "--color-forest-700",
use: "Hover on light; accent text",
},
{
name: "Moss",
step: "800",
hex: "#166534",
token: "--color-forest-800",
use: "Pressed on light; accent text at small sizes",
},
],
},
admin: {
label: "Operations Gold",
shades: [
{
name: "Parchment",
step: "50",
hex: "#FFFBEB",
token: "--color-gold-50",
use: "Subtle accent fill on light",
},
{
name: "Straw",
step: "200",
hex: "#FDE68A",
token: "--color-gold-200",
use: "Strong accent text on dark",
},
{
name: "Honey",
step: "400",
hex: "#FBBF24",
token: "--color-gold-400",
use: "Hover, accent text and border on dark",
},
{
name: "Gold",
step: "500",
hex: "#F59E0B",
token: "--color-gold-500",
use: "THE admin accent on dark",
},
{
name: "Bronze",
step: "600",
hex: "#D97706",
token: "--color-gold-600",
use: "THE admin accent on light",
},
{
name: "Amber",
step: "700",
hex: "#B45309",
token: "--color-gold-700",
use: "Hover on light; accent text",
},
{
name: "Umber",
step: "800",
hex: "#92400E",
token: "--color-gold-800",
use: "Pressed on light; accent text at small sizes",
},
],
},
creator: {
label: "Creator Iris",
shades: [
{
name: "Petal",
step: "50",
hex: "#FAF5FF",
token: "--color-iris-50",
use: "Subtle accent fill on light",
},
{
name: "Lilac",
step: "300",
hex: "#D8B4FE",
token: "--color-iris-300",
use: "Strong accent text on dark",
},
{
name: "Wisteria",
step: "400",
hex: "#C084FC",
token: "--color-iris-400",
use: "Hover, accent text and border on dark",
},
{
name: "Iris",
step: "500",
hex: "#A855F7",
token: "--color-iris-500",
use: "THE creator accent on dark",
},
{
name: "Amethyst",
step: "600",
hex: "#9333EA",
token: "--color-iris-600",
use: "THE creator accent on light",
},
{
name: "Mulberry",
step: "700",
hex: "#7E22CE",
token: "--color-iris-700",
use: "Hover on light; accent text",
},
{
name: "Plum",
step: "800",
hex: "#6B21A8",
token: "--color-iris-800",
use: "Pressed on light; accent text at small sizes",
},
],
},
};
export const NEUTRAL_RAMP: Shade[] = [
{
name: "Paper",
step: "0",
hex: "#FFFFFF",
token: "--color-paper",
use: "Default surface — roughly 70% of every layout",
},
{
name: "Mist",
step: "50",
hex: "#FAF9F7",
token: "--color-neutral-50",
use: "Barely-there section banding",
},
{
name: "Canvas",
step: "100",
hex: "#F4F2EF",
token: "--color-neutral-100",
use: "Page background behind cards",
},
{
name: "Linen",
step: "200",
hex: "#EEEBE7",
token: "--color-neutral-200",
use: "Sunken wells, code blocks, inactive tabs",
},
{
name: "Chalk",
step: "300",
hex: "#E6E3DE",
token: "--color-neutral-300",
use: "Default border — the one you reach for",
},
{
name: "Stone",
step: "400",
hex: "#D8D4CE",
token: "--color-neutral-400",
use: "Strong border, unchecked control outline",
},
{
name: "Ash",
step: "500",
hex: "#B8B3AC",
token: "--color-neutral-500",
use: "Placeholder text, disabled labels, slide footers",
},
{
name: "Clay",
step: "600",
hex: "#9A958E",
token: "--color-neutral-600",
use: "Muted metadata and captions",
},
{
name: "Slate",
step: "700",
hex: "#6B6660",
token: "--color-neutral-700",
use: "Secondary body copy",
},
{
name: "Char",
step: "800",
hex: "#3A3835",
token: "--color-neutral-800",
use: "Lead paragraphs on light",
},
{
name: "Soot",
step: "900",
hex: "#1D1B19",
token: "--color-neutral-900",
use: "Alternative dark surface",
},
{
name: "Ink",
step: "950",
hex: "#111111",
token: "--color-ink",
use: "Primary text, and the dark surface for hero moments",
},
];
/**
* Measured off production. The neutral ramp above is the social-artboard
* system; these are what the storefront actually paints. Where the two
* disagree, the product wins for anything shipping on woohl.com.
*/
export const PRODUCT_SURFACES: Shade[] = [
{
name: "Warm text",
step: "—",
hex: "#4A4540",
token: "--color-warm-text",
use: "Body copy on the storefront",
},
{
name: "Warm muted",
step: "—",
hex: "#7A7268",
token: "--color-warm-muted",
use: "Metadata, captions, helper text",
},
{
name: "Warm surface",
step: "—",
hex: "#FFF7ED",
token: "--color-warm-surface",
use: "Section background behind cards",
},
{
name: "Warm dark",
step: "—",
hex: "#1C1610",
token: "--color-warm-dark",
use: "Footer and dark sections — not pure Ink",
},
{
name: "Cream",
step: "—",
hex: "#E8DCC8",
token: "--color-cream",
use: "Dividers and captions inside dark sections",
},
{
name: "Terracotta",
step: "—",
hex: "#C85A2A",
token: "--color-terracotta",
use: "Accent text at sizes where Woohl Orange fails AA",
},
];
export type StatusToken = {
name: string;
hex: string;
subtle: string;
border: string;
use: string;
};
/** Four, each with a solid, a subtle fill and a border. Never a brand accent. */
export const STATUS_TOKENS: StatusToken[] = [
{
name: "Success",
hex: "#0E7A50",
subtle: "#E6F3ED",
border: "#A8D8C2",
use: "Order confirmed, payout sent, verified maker",
},
{
name: "Warning",
hex: "#A9670B",
subtle: "#FBF0DC",
border: "#EBCB8E",
use: "Low stock, action needed, expiring soon",
},
{
name: "Danger",
hex: "#B3261E",
subtle: "#FBEAE8",
border: "#E9B5B0",
use: "Failed payment, destructive action, validation error",
},
{
name: "Info",
hex: "#1C5D9B",
subtle: "#E8F0F8",
border: "#A9C6E4",
use: "Neutral system messages, tips, shipping updates",
},
];
/**
* The semantic layer — the only colour interface components may use.
* `light` and `dark` are the base theme's resolved values; a product theme may
* change them, which is the entire point of the theme layer.
*/
export const SEMANTIC_COLOR_TOKENS = [
{
token: "--surface",
utility: "bg-surface",
role: "Canvas behind cards",
light: "#F4F2EF",
dark: "#17150F",
},
{
token: "--surface-raised",
utility: "bg-surface-raised",
role: "Cards, panels, inputs",
light: "#FFFFFF",
dark: "#211E17",
},
{
token: "--surface-sunken",
utility: "bg-surface-sunken",
role: "Wells, code, inactive tabs",
light: "#EEEBE7",
dark: "#100E0A",
},
{
token: "--surface-inverse",
utility: "bg-surface-inverse",
role: "Hero blocks, dark sections",
light: "#111111",
dark: "#F4F2EF",
},
{
token: "--surface-accent",
utility: "bg-surface-accent",
role: "Primary buttons, active states",
light: "#F4521B",
dark: "#F4521B",
},
{
token: "--surface-accent-hover",
utility: "bg-surface-accent-hover",
role: "Hover on an accent fill",
light: "#E85C0D",
dark: "#FF6A33",
},
{
token: "--surface-accent-pressed",
utility: "bg-surface-accent-pressed",
role: "Pressed on an accent fill",
light: "#BA4A0A",
dark: "#E85C0D",
},
{
token: "--surface-accent-subtle",
utility: "bg-surface-accent-subtle",
role: "Badge fills, hover tints",
light: "#FDEFE7",
dark: "rgb(244 82 27 / 0.14)",
},
{
token: "--border-subtle",
utility: "border-border-subtle",
role: "Default border",
light: "#E6E3DE",
dark: "#322D24",
},
{
token: "--border-strong",
utility: "border-border-strong",
role: "Hover border, control outline",
light: "#D8D4CE",
dark: "#453F33",
},
{
token: "--border-accent",
utility: "border-border-accent",
role: "Focused field, selected control",
light: "#F4521B",
dark: "#FF7A45",
},
{
token: "--border-inverse",
utility: "border-border-inverse",
role: "Dividers inside a dark section",
light: "rgb(255 255 255 / 0.18)",
dark: "rgb(17 17 17 / 0.18)",
},
{
token: "--text-primary",
utility: "text-text-primary",
role: "Body and headings",
light: "#111111",
dark: "#F6F3EE",
},
{
token: "--text-secondary",
utility: "text-text-secondary",
role: "Supporting copy",
light: "#4A4540",
dark: "#B8B0A3",
},
{
token: "--text-muted",
utility: "text-text-muted",
role: "Metadata, captions, placeholder",
light: "#7A7268",
dark: "#8D857A",
},
{
token: "--text-inverse",
utility: "text-text-inverse",
role: "Text on a dark surface",
light: "#FFFFFF",
dark: "#111111",
},
{
token: "--text-accent",
utility: "text-text-accent",
role: "Links, accent type at 24px+",
light: "#F4521B",
dark: "#FF7A45",
},
{
token: "--text-accent-strong",
utility: "text-text-accent-strong",
role: "Accent text under 24px — passes AA",
light: "#BA4A0A",
dark: "#FF9066",
},
{
token: "--text-on-accent",
utility: "text-text-on-accent",
role: "Text on Woohl Orange",
light: "#FFFFFF",
dark: "#FFFFFF",
},
] as const;
/* -------------------------------------------------------------------- type */
export type TypeStep = {
name: string;
/** Token name, and the Tailwind utility it generates. */
token: string;
utility: string;
/** Size on the web/product scale. */
web: string;
/** Size on the 1080px social artboard, where the editorial scale is 2×. */
social: string;
weight: string;
tracking: string;
leading: string;
use: string;
};
/** System A. Campaigns, social, print, decks, brand pages. Never product UI. */
export const EDITORIAL_SCALE: TypeStep[] = [
{
name: "Display",
token: "--text-editorial-display",
utility: "text-editorial-display",
web: "58px",
social: "116px",
weight: "800",
tracking: "-4.5%",
leading: "0.94",
use: "Cover slides and campaign hero lines. One per surface.",
},
{
name: "Headline",
token: "--text-editorial-headline",
utility: "text-editorial-headline",
web: "44px",
social: "88px",
weight: "800",
tracking: "-3.8%",
leading: "1.0",
use: "Section openers, slide headlines",
},
{
name: "Title",
token: "--text-editorial-title",
utility: "text-editorial-title",
web: "30px",
social: "60px",
weight: "700",
tracking: "-3%",
leading: "1.1",
use: "Card titles, sub-sections",
},
{
name: "Lead",
token: "--text-editorial-lead",
utility: "text-editorial-lead",
web: "19px",
social: "38px",
weight: "400",
tracking: "0",
leading: "1.4",
use: "The sentence under a headline",
},
{
name: "Body",
token: "--text-editorial-body",
utility: "text-editorial-body",
web: "15px",
social: "30px",
weight: "400",
tracking: "0",
leading: "1.5",
use: "Running copy. Max 40 words per slide.",
},
{
name: "Eyebrow",
token: "--text-editorial-eyebrow",
utility: "text-editorial-eyebrow",
web: "12px",
social: "24px",
weight: "700",
tracking: "+18%",
leading: "1",
use: "Uppercase label above a headline",
},
{
name: "Numeral",
token: "--text-editorial-numeral",
utility: "text-editorial-numeral",
web: "100px",
social: "200px",
weight: "800",
tracking: "-5.5%",
leading: "0.82",
use: "Statistic slides. Never more than one.",
},
{
name: "Quote",
token: "--text-editorial-quote",
utility: "text-editorial-quote",
web: "30px",
social: "76px",
weight: "400 italic",
tracking: "-2%",
leading: "1.15",
use: "Playfair Display. Pull quotes only.",
},
];
/** System B. Buyer, Seller, Creator, Admin, transactional email, help. */
export const PRODUCT_SCALE: TypeStep[] = [
{
name: "Display",
token: "--text-display",
utility: "text-display",
web: "56px",
social: "—",
weight: "500",
tracking: "-2.5%",
leading: "1.1",
use: "Marketing hero. Nunito Sans, light — the size carries it, not the weight.",
},
{
name: "H1",
token: "--text-h1",
utility: "text-h1",
web: "40px",
social: "—",
weight: "400",
tracking: "-2.5%",
leading: "1.15",
use: "Section heading. Line two goes to Playfair italic.",
},
{
name: "H2",
token: "--text-h2",
utility: "text-h2",
web: "28px",
social: "—",
weight: "500",
tracking: "-2%",
leading: "1.2",
use: "Sub-section heading",
},
{
name: "H3",
token: "--text-h3",
utility: "text-h3",
web: "20px",
social: "—",
weight: "700",
tracking: "-1%",
leading: "1.3",
use: "Card and panel heading",
},
{
name: "Body Large",
token: "--text-body-lg",
utility: "text-body-lg",
web: "17px",
social: "—",
weight: "400",
tracking: "0",
leading: "1.6",
use: "Intro paragraphs, product descriptions",
},
{
name: "Body",
token: "--text-body",
utility: "text-body",
web: "15px",
social: "—",
weight: "400",
tracking: "0",
leading: "1.55",
use: "Default UI text",
},
{
name: "Label",
token: "--text-label",
utility: "text-label",
web: "13px",
social: "—",
weight: "600",
tracking: "0",
leading: "1.4",
use: "Form labels, table headers, buttons",
},
{
name: "Caption",
token: "--text-caption",
utility: "text-caption",
web: "12px",
social: "—",
weight: "400",
tracking: "+1%",
leading: "1.4",
use: "Helper text, timestamps, metadata",
},
{
name: "Eyebrow",
token: "--text-eyebrow",
utility: "text-eyebrow",
web: "11px",
social: "—",
weight: "700",
tracking: "+10%",
leading: "1",
use: "Uppercase section label in orange, preceded by a 22px rule",
},
];
export const FONT_FAMILIES = [
{
name: "Nunito Sans",
token: "--font-ui",
utility: "font-ui",
system: "Product",
role: "UI and body",
weights: "400 · 600 · 700 · 800",
},
{
name: "Schibsted Grotesk",
token: "--font-editorial",
utility: "font-editorial",
system: "Editorial",
role: "Everything",
weights: "400 · 500 · 600 · 700 · 800 · 900",
},
{
name: "Playfair Display",
token: "--font-serif",
utility: "font-serif",
system: "Both",
role: "The accent line and pull quotes only",
weights: "400 · 500 · 400 italic · 500 italic",
},
{
name: "JetBrains Mono",
token: "--font-mono",
utility: "font-mono",
system: "Editorial",
role: "Data, labels, specs",
weights: "400 · 500 · 700",
},
{
name: "Baloo Bhaijaan 2",
token: "--font-display",
utility: "font-display",
system: "Product",
role: "The wordmark only — not a layout face",
weights: "800",
},
{
name: "Satisfy",
token: "--font-script",
utility: "font-script",
system: "Product",
role: "One accent word, at most once per page",
weights: "400",
},
] as const;
/* ----------------------------------------------------------------- layout */
export const SPACING = [
{ step: "1", px: 4, use: "Icon-to-label gap, hairline offsets" },
{ step: "2", px: 8, use: "Inside chips, tight stacks" },
{ step: "3", px: 12, use: "Button padding-y, list row gap" },
{ step: "4", px: 16, use: "Default gap between related elements" },
{ step: "5", px: 20, use: "Card padding on mobile" },
{ step: "6", px: 24, use: "Card padding, grid gutter" },
{ step: "8", px: 32, use: "Between cards" },
{ step: "10", px: 40, use: "Card padding on desktop" },
{ step: "12", px: 48, use: "Between sub-sections" },
{ step: "16", px: 64, use: "Between sections" },
{ step: "20", px: 80, use: "Section padding on desktop" },
{ step: "24", px: 96, use: "Between major page regions" },
] as const;
export const RADIUS = [
{
name: "xs",
token: "--radius-xs",
utility: "rounded-xs",
px: 4,
use: "Inline code, tags inside text",
},
{
name: "sm",
token: "--radius-sm",
utility: "rounded-sm",
px: 8,
use: "Small buttons, checkboxes",
},
{
name: "md",
token: "--radius-md",
utility: "rounded-md",
px: 12,
use: "Inputs, dropdown items",
},
{
name: "lg",
token: "--radius-lg",
utility: "rounded-lg",
px: 16,
use: "Buttons, small cards, product imagery",
},
{
name: "xl",
token: "--radius-xl",
utility: "rounded-xl",
px: 24,
use: "Cards — the default",
},
{
name: "2xl",
token: "--radius-2xl",
utility: "rounded-2xl",
px: 28,
use: "Panels, modals, hero blocks",
},
{
name: "3xl",
token: "--radius-3xl",
utility: "rounded-3xl",
px: 40,
use: "Full-bleed feature blocks",
},
{
name: "pill",
token: "--radius-pill",
utility: "rounded-pill",
px: 999,
use: "Chips, badges, CTA buttons, avatars",
},
] as const;
export const ELEVATION = [
{
name: "Hairline",
token: "--shadow-hairline",
utility: "shadow-hairline",
use: "Sticky bars, table headers",
},
{
name: "E1",
token: "--shadow-e1",
utility: "shadow-e1",
use: "Resting card, input",
},
{
name: "E2",
token: "--shadow-e2",
utility: "shadow-e2",
use: "Hovered card, dropdown, popover",
},
{
name: "E3",
token: "--shadow-e3",
utility: "shadow-e3",
use: "Modal, command palette, drawer",
},
] as const;
export const BREAKPOINTS = [
{
name: "xs",
min: "480px",
cols: 4,
gutter: 16,
margin: 20,
use: "Large phone",
},
{
name: "sm",
min: "640px",
cols: 6,
gutter: 20,
margin: 24,
use: "Small tablet, phone landscape",
},
{
name: "md",
min: "768px",
cols: 8,
gutter: 24,
margin: 32,
use: "Tablet portrait",
},
{
name: "lg",
min: "1024px",
cols: 12,
gutter: 24,
margin: 40,
use: "Tablet landscape, small laptop",
},
{
name: "xl",
min: "1280px",
cols: 12,
gutter: 32,
margin: 64,
use: "Desktop — the design target",
},
{
name: "2xl",
min: "1536px",
cols: 12,
gutter: 32,
margin: 80,
use: "Large desktop; content caps at 1440px",
},
] as const;
/* ----------------------------------------------------------------- motion */
export const MOTION = [
{
name: "Instant",
token: "--duration-instant",
utility: "motion-instant",
ms: 120,
ease: "--ease-out-woohl",
use: "Colour and opacity on hover",
},
{
name: "Fast",
token: "--duration-fast",
utility: "motion-fast",
ms: 180,
ease: "--ease-out-woohl",
use: "Buttons, toggles, tooltips",
},
{
name: "Base",
token: "--duration-base",
utility: "motion-base",
ms: 240,
ease: "--ease-out-woohl",
use: "Dropdowns, accordions, tab panels",
},
{
name: "Slow",
token: "--duration-slow",
utility: "motion-slow",
ms: 320,
ease: "--ease-in-out-woohl",
use: "Modals, drawers, page transitions",
},
{
name: "Deliberate",
token: "--duration-deliberate",
utility: "motion-deliberate",
ms: 480,
ease: "--ease-in-out-woohl",
use: "Onboarding, celebratory moments only",
},
] as const;
export const EASING = [
{
token: "--ease-out-woohl",
utility: "ease-out-woohl",
curve: "cubic-bezier(0.22, 1, 0.36, 1)",
use: "Things entering. Fast start, long settle.",
},
{
token: "--ease-in-out-woohl",
utility: "ease-in-out-woohl",
curve: "cubic-bezier(0.65, 0, 0.35, 1)",
use: "Things moving between two states. Symmetrical.",
},
{
token: "--ease-spring",
utility: "ease-spring",
curve: "cubic-bezier(0.34, 1.56, 0.64, 1)",
use: "One overshoot, for a moment worth celebrating. Rare.",
},
{
token: "linear",
utility: "ease-linear",
curve: "linear",
use: "Progress bars and spinners only. Never for anything a person triggered.",
},
] as const;
/* ---------------------------------------------------------------- z-index */
export const Z_LAYERS = [
{
token: "--z-raised",
utility: "z-raised",
value: 10,
use: "Hovered card, focused field, image overlay",
},
{
token: "--z-sticky",
utility: "z-sticky",
value: 100,
use: "Sticky headers, table headers, filter bars",
},
{
token: "--z-dropdown",
utility: "z-dropdown",
value: 200,
use: "Menus, comboboxes, autocomplete",
},
{
token: "--z-overlay",
utility: "z-overlay",
value: 300,
use: "Scrims behind a modal or drawer",
},
{
token: "--z-modal",
utility: "z-modal",
value: 400,
use: "Dialogs, drawers, command palette",
},
{
token: "--z-popover",
utility: "z-popover",
value: 500,
use: "Popovers that must clear an open dialog",
},
{ token: "--z-toast", utility: "z-toast", value: 600, use: "Toasts" },
{
token: "--z-tooltip",
utility: "z-tooltip",
value: 700,
use: "Tooltips — the top of the stack",
},
] as const;
/* ----------------------------------------------------------------- themes */
export const THEMES = ["buyer", "seller", "creator", "admin"] as const;
export type ThemeName = (typeof THEMES)[number];
export const APPEARANCES = ["light", "dark"] as const;
export type Appearance = (typeof APPEARANCES)[number];
export const THEME_DESCRIPTIONS: Record<ThemeName, string> = {
buyer:
"The storefront and app. Woohl Orange, warm neutrals, production surfaces. The theme that carries the brand.",
seller:
"The maker dashboard. Merchant Forest green — a signed-in surface, told apart from the storefront at a glance.",
creator:
"Publishing, campaigns and reach. Paper-first, Creator Iris purple — the one accent with no operational meaning attached.",
admin:
"Internal operations. Ink-led with an Operations Gold accent; the accent is signal, not brand expression.",
};
This item exports no props — it is a stylesheet, a helper or a set of constants.
Registry items
None — this item stands on its own.
npm packages
None beyond React itself.