Tokens
Override hex primitives in :root:
:root {
--af-base-primary: #018183;
}Interaction is derived via color-mix():
:root {
--af-hover-mix: 12%;
--af-active-mix: 18%;
}For dark mode and theme overrides, see Theming.
Color Palette
Section titled “Color Palette”Airframe ships with a calm, modern default palette designed for product UI.
Neutrals form the structure—they provide the foundation for surfaces, borders, and text. Accent colors indicate motion and intent—they signal actions, states, and meaning.
Everything is overridable. Override primitives in :root to change the entire system, or adjust semantic tokens for targeted changes.
Color Primitives
Section titled “Color Primitives”:root {
/* Accent colors */
--af-base-primary: #4663f5;
--af-base-secondary: #22d3ee;
--af-base-tertiary: #111827;
--af-base-success: #22c55e;
--af-base-warning: #fbbf24;
--af-base-danger: #dc2626;
--af-base-info: #38bdf8;
/_ Neutrals _/
--af-base-white: #ffffff;
--af-base-black: #000000;
--af-base-neutral-50: #f8fafc;
--af-base-neutral-100: #f1f5f9;
--af-base-neutral-200: #e2e8f0;
--af-base-neutral-300: #cbd5e1;
--af-base-neutral-400: #94a3b8;
--af-base-neutral-500: #64748b;
--af-base-neutral-600: #475569;
--af-base-neutral-700: #334155;
--af-base-neutral-800: #1f2937;
--af-base-neutral-900: #111827;
}Global Color Mix Knobs
Section titled “Global Color Mix Knobs”These control how interaction states are derived via color-mix():
:root {
--af-hover-mix: 12%; /* Hover state color mix */
--af-active-mix: 18%; /* Active state color mix */
--af-soft-mix: 12%; /* Soft variant color mix (lighter) */
--af-hard-mix: 45%; /* Hard variant color mix (darker; AA text on soft) */
--af-border-mix: 22%; /* Border color mix */
}Soft intent surfaces (*-soft) pair with hard text (*-hard) in badges, chips, and KPI deltas so small text meets WCAG AA (4.5:1). Mid-tone intent colors (--af-color-success, etc.) stay vivid for fills and icons — do not use them as small text on soft tints.
Action color (theme-overridable)
Section titled “Action color (theme-overridable)”The action token (--af-color-action) is the semantic “main CTA/brand color” used for buttons, links, focus rings, and other interactive elements. It defaults to primary; --af-color-primary (and --af-color-on-primary) are resolved from action, so all existing components that use primary automatically respect the override.
Override action per theme when you want a different accent in dark or high-contrast modes. For high-contrast themes, ensure colors meet WCAG 2.2 AA contrast requirements (4.5:1 for normal text, 3:1 for large text):
/* Dark mode */
@media (prefers-color-scheme: dark) {
:root {
--af-color-action--dark: #60a5fa;
--af-color-on-action--dark: #0f172a;
}
}
/_ Or when using a manual dark theme class _/
[data-theme="dark"], .dark {
--af-color-action--dark: #60a5fa;
--af-color-on-action--dark: #0f172a;
}
/_ High-contrast light - use stronger colors for better contrast _/
:root {
--af-color-action--hc-light: #0066cc; /_ Stronger blue meets WCAG AA _/
--af-color-on-action--hc-light: #ffffff;
}
/_ High-contrast dark - lighter colors for dark backgrounds _/
:root {
--af-color-action--hc-dark: #60a5fa; /_ Lighter blue for dark mode _/
--af-color-on-action--hc-dark: #000000;
}Note: High-contrast overrides work automatically with system prefers-contrast: more or prefers-contrast: high preference. No media queries needed—just define the --hc-light and --hc-dark tokens in :root. See High Contrast Theming for complete examples.
Derived tokens (--af-color-action-hover, -action-active, -action-soft, -action-hard) are computed from the resolved action via color-mix(), so they stay consistent when you override.
Typography Tokens
Section titled “Typography Tokens”Typography is driven by semantic tokens so brands can override safely:
Font Families
Section titled “Font Families”:root {
/* Font primitives */
--af-base-font-sans: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji";
--af-base-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
/_ Semantic font tokens _/
--af-font-primary: var(--af-base-font-sans); /_ Primary font (used for body text by default) _/
--af-font-heading: var(--af-font-primary); /_ Heading font (applied to h1-h6, .af-text-h_, .af-text-display) _/
--af-font-body: var(--af-base-font-sans); /_ Body text font _/
--af-font-code: var(--af-base-font-mono); /_ Code font _/
--af-font-mono: var(--af-base-font-mono); /_ Monospace font */
}Customizing fonts:
:root {
/* Use custom web fonts */
--af-font-primary: 'Inter', 'Roboto', sans-serif;
--af-font-heading: 'Playfair Display', serif; /* Different font for headings */
--af-font-body: var(--af-font-primary); /* Body uses primary */
}Type Scale
Section titled “Type Scale”:root {
/* Core type scale */
--af-text-xs: 0.75rem;
--af-text-sm: 0.875rem;
--af-text-md: 1rem;
--af-text-lg: 1.125rem;
--af-text-xl: 1.25rem;
--af-text-2xl: 1.5rem;
--af-text-3xl: 1.875rem;
/_ Leading (line-height) - typography term for vertical spacing between lines _/
/_ Use --af-leading-_ tokens; these map to CSS line-height property */
--af-leading-tight: 1.1;
--af-leading-normal: 1.5;
--af-leading-loose: 1.7;
/_ Weights _/
--af-weight-regular: 400;
--af-weight-medium: 500;
--af-weight-semibold: 600;
--af-weight-bold: 700;
--af-weight-extrabold: 800;
}Role Tokens (Override-Friendly)
Section titled “Role Tokens (Override-Friendly)”Typography role tokens map semantic roles (h1, h2, body, etc.) to type scale values. Override these to customize typography without touching primitives:
:root {
/* Display type */
--af-type-display-size: var(--af-text-3xl);
--af-type-display-weight: var(--af-weight-bold);
--af-type-display-leading: var(--af-leading-tight);
/_ Heading sizes _/
--af-type-h1-size: var(--af-text-3xl);
--af-type-h2-size: var(--af-text-2xl);
--af-type-h3-size: var(--af-text-xl);
--af-type-h4-size: var(--af-text-lg);
--af-type-h5-size: var(--af-text-md);
--af-type-h6-size: var(--af-text-sm);
/_ Heading weights _/
--af-type-h1-weight: var(--af-weight-semibold);
--af-type-h2-weight: var(--af-weight-semibold);
--af-type-h3-weight: var(--af-weight-semibold);
--af-type-h4-weight: var(--af-weight-semibold);
--af-type-h5-weight: var(--af-weight-semibold);
--af-type-h6-weight: var(--af-weight-semibold);
/_ Heading leading _/
--af-type-h1-leading: var(--af-leading-tight);
--af-type-h2-leading: var(--af-leading-tight);
--af-type-h3-leading: var(--af-leading-tight);
--af-type-h4-leading: var(--af-leading-normal);
--af-type-h5-leading: var(--af-leading-normal);
--af-type-h6-leading: var(--af-leading-normal);
/_ Heading letter spacing _/
--af-type-h1-tracking: -0.02em;
--af-type-h2-tracking: -0.01em;
--af-type-h3-tracking: 0em;
--af-type-h4-tracking: 0em;
--af-type-h5-tracking: 0em;
--af-type-h6-tracking: 0em;
/_ Body and caption _/
--af-type-body-size: var(--af-text-md);
--af-type-body-weight: var(--af-weight-regular);
--af-type-body-leading: var(--af-leading-normal);
--af-type-caption-size: var(--af-text-sm);
--af-type-caption-weight: var(--af-weight-regular);
--af-type-caption-leading: var(--af-leading-normal);
/_ Semantic typography roles _/
--af-text-body-size: var(--af-text-md);
--af-text-body-leading: var(--af-leading-normal);
--af-text-heading-leading: var(--af-leading-tight);
--af-text-heading-weight: var(--af-weight-semibold);
}Spacing Tokens
Section titled “Spacing Tokens”The space scale provides consistent spacing values used throughout the system:
:root {
--af-space-0: 0px;
--af-space-1: 4px;
--af-space-2: 8px;
--af-space-3: 12px;
--af-space-4: 16px;
--af-space-5: 24px;
--af-space-6: 32px;
--af-space-7: 40px;
--af-space-8: 48px;
}These tokens are used by spacing utilities (af-p-*, af-m-*, af-gap-*) and layout recipes.
Border Radius Tokens
Section titled “Border Radius Tokens”Radius tokens control the roundness of corners:
:root {
--af-radius-0: 0px;
--af-radius-sm: 6px;
--af-radius-md: 10px;
--af-radius-lg: 16px;
--af-radius-xl: 24px;
--af-radius-full: 9999px;
}Breakpoint Tokens
Section titled “Breakpoint Tokens”Breakpoint tokens define responsive breakpoints used by responsive suffixes (@md, @lg, etc.):
:root {
--af-bp-xs: 360px;
--af-bp-sm: 640px;
--af-bp-md: 768px;
--af-bp-lg: 1024px;
--af-bp-xl: 1280px;
--af-bp-2xl: 1536px;
}Shadow Tokens
Section titled “Shadow Tokens”Shadow tokens provide consistent elevation:
:root {
--af-shadow-sm: 0 1px 2px rgba(0,0,0,.06);
--af-shadow-md: 0 6px 16px rgba(0,0,0,.10);
--af-shadow-lg: 0 16px 40px rgba(0,0,0,.14);
}Z-Index Tokens
Section titled “Z-Index Tokens”Z-index tokens provide a consistent layering system:
:root {
--af-z-base: 0;
--af-z-dropdown: 1000;
--af-z-sticky: 1100;
--af-z-overlay: 1200;
--af-z-modal: 1300;
--af-z-toast: 1400;
}Border Tokens
Section titled “Border Tokens”Border tokens control border width and hit target sizes:
:root {
--af-border-width: 2px;
--af-hit-size: 2.75rem; /* Minimum touch target size */
}Layout Tokens
Section titled “Layout Tokens”Layout tokens control container widths and layout spacing:
:root {
--af-layout-gap: var(--af-space-4);
--af-container-padding-x: var(--af-space-4);
--af-container-max-w: 90em; /* 1440px - default container */
--af-container-max-w-xs: 25rem; /* 400px */
--af-container-max-w-sm: 40rem; /* 640px */
--af-container-max-w-md: 48rem; /* 768px */
--af-container-max-w-lg: 64rem; /* 1024px */
--af-container-max-w-xl: 80rem; /* 1280px */
--af-container-max-w-2xl: 96rem; /* 1536px */
}Component Tokens
Section titled “Component Tokens”Component tokens are a thin, override-friendly layer for common sizing tweaks. They sit on top of global tokens so you can adjust buttons and form controls without rewriting styles.
Shared Control Tokens
Section titled “Shared Control Tokens”:root {
--af-control-min-height: auto;
--af-control-radius: var(--af-radius-xl);
--af-control-padding-y: var(--af-space-2);
--af-control-padding-x: var(--af-space-3);
--af-control-border: var(--af-color-border);
}Button Tokens
Section titled “Button Tokens”:root {
/* Button sizing */
--af-btn-min-height: var(--af-control-min-height);
--af-btn-radius: var(--af-radius-full);
--af-btn-padding-y: var(--af-control-padding-y);
--af-btn-padding-x: var(--af-space-4);
--af-btn-gap: var(--af-space-2);
--af-btn-icon-size: 1.25em;
--af-btn-font-weight: var(--af-weight-medium);
--af-btn-border-width: var(--af-border-width);
/_ Button colors (primary/default) _/
--af-btn-default-bg: var(--af-color-primary);
--af-btn-default-color: var(--af-color-on-primary);
--af-btn-default-hover: var(--af-color-primary-hover);
--af-btn-default-active: var(--af-color-primary-active);
/_ Button colors (secondary) _/
--af-btn-secondary-bg: var(--af-base-secondary);
--af-btn-secondary-color: var(--af-color-on-secondary);
--af-btn-secondary-hover: color-mix(in srgb, var(--af-btn-secondary-bg), black 4%);
--af-btn-secondary-active: color-mix(in srgb, var(--af-btn-secondary-bg), black 8%);
/_ Button colors (outline) _/
--af-btn-outline-color: var(--af-color-primary);
--af-btn-outline-border: var(--af-color-primary);
--af-btn-outline-hover: var(--af-btn-outline-border);
--af-btn-outline-active: color-mix(in srgb, var(--af-color-primary), var(--af-color-surface-primary) 84%);
}Input Tokens
Section titled “Input Tokens”:root {
--af-input-min-height: var(--af-control-min-height);
--af-input-radius: var(--af-control-radius);
--af-input-padding-y: var(--af-control-padding-y);
--af-input-padding-x: var(--af-control-padding-x);
--af-input-font-size: var(--af-text-md);
--af-input-leading: var(--af-leading-normal);
--af-input-placeholder-color: var(--af-color-text-muted);
}Link Tokens
Section titled “Link Tokens”:root {
--af-link-primary: var(--af-color-primary);
--af-link-hover-primary: var(--af-color-primary-hover);
}Card Tokens
Section titled “Card Tokens”:root {
--af-card-radius: var(--af-radius-lg);
--af-card-padding: var(--af-space-4);
--af-card-shadow: var(--af-shadow-sm);
--af-card-shadow-hover: var(--af-shadow-md);
}Focus Ring Tokens
Section titled “Focus Ring Tokens”:root {
--af-focus-ring-color: var(--af-color-focus);
--af-focus-ring-width: 2px;
--af-focus-ring-offset: 2px;
}Example Override
Section titled “Example Override”:root {
--af-control-min-height: 3rem;
--af-btn-gap: 0.75rem;
--af-input-placeholder-color: rgba(0, 0, 0, 0.45);
}Motion Tokens
Section titled “Motion Tokens”Motion tokens provide consistent timing for transitions and animations, with automatic reduced motion support built-in.
Duration Variables
Section titled “Duration Variables”Transition durations (for CSS transitions):
:root {
--af-duration-fast: 120ms; /* Quick interactions */
--af-duration-md: 200ms; /* Standard transitions */
--af-duration-slow: 320ms; /* Deliberate changes */
}Animation durations (for keyframe animations):
:root {
--af-animation-duration-fast: 200ms; /* Quick animations */
--af-animation-duration-md: 400ms; /* Standard animations */
--af-animation-duration-slow: 600ms; /* Slower animations */
--af-animation-duration-slower: 1500ms; /* Very slow animations */
}Easing Functions
Section titled “Easing Functions”:root {
--af-ease-standard: cubic-bezier(.2, .0, .2, 1); /* Default easing */
--af-ease-emphasized: cubic-bezier(.2, .0, 0, 1); /* More pronounced */
--af-ease-in: cubic-bezier(.4, .0, 1, 1); /* Ease in */
--af-ease-out: cubic-bezier(.0, .0, .2, 1); /* Ease out */
--af-ease-in-out: cubic-bezier(.4, .0, .2, 1); /* Ease in-out */
--af-ease-linear: linear; /* Linear */
}Usage Examples
Section titled “Usage Examples”Transitions:
/* Button hover transition */
.af-btn {
transition: background-color var(--af-duration-fast) var(--af-ease-standard);
}
/_ Card shadow transition _/
.af-card {
transition: box-shadow var(--af-duration-md) var(--af-ease-out);
}
/_ Multiple properties _/
.element {
transition:
background-color var(--af-duration-fast) var(--af-ease-standard),
transform var(--af-duration-md) var(--af-ease-emphasized);
}Animations:
/* Spinner animation */
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.af-spinner {
animation: spin var(--af-animation-duration-md) var(--af-ease-linear) infinite;
}
/_ Skeleton loading animation _/
@keyframes skeleton-load {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.af-skeleton {
animation: skeleton-load var(--af-animation-duration-slower) var(--af-ease-in-out) infinite;
}Reduced Motion Support
Section titled “Reduced Motion Support”All motion tokens automatically respect the user’s prefers-reduced-motion preference. When reduced motion is enabled, all durations are set to 0.01ms (effectively instant).
No additional code needed - just use the tokens:
/* This automatically respects reduced motion */
.button {
transition: background-color var(--af-duration-fast) var(--af-ease-standard);
}
/_ This also respects reduced motion _/
.spinner {
animation: spin var(--af-animation-duration-md) linear infinite;
}Customizing motion tokens:
:root {
/* Override default durations */
--af-duration-fast: 100ms;
--af-animation-duration-slow: 800ms;
/_ Custom easing _/
--af-ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
}Note: The reduced motion override still applies even when you customize these values, ensuring accessibility is maintained.