Foundations
Visual building blocks backed by semantic tokens - not raw hex or ramp step names.
Color
Use semantic color.* tokens for product UI. Avoid raw hex values in components.
Color palette contains full swatches and ramp references.
Quick rules
- Start with
surface.defaultfor the page background. - Use
container.lowfor sections andcontainer.lowestfor cards. - Use
color.textfor body copy andcolor.text.subtlefor support text. - Use brand tokens only for actions, focus, and key status emphasis.
Surface stack
Build depth with tones, not heavy borders: canvas → section → card.
Core surface tokens
| Token | Value | Role |
|---|---|---|
color.background.surface.default |
#f7f9fb |
App canvas |
color.background.surface.container.low |
#f2f4f6 |
Sections within the canvas |
color.background.surface.container.lowest |
#ffffff |
Cards and interactive surfaces |
color.background.surface.container.high |
#e8ecef |
Secondary UI, progress tracks |
color.background.surface.container.highest |
#dde2e6 |
Input field tracks |
Text and brand tokens
| Token | Usage |
|---|---|
color.text |
Primary copy (do not use pure #000) |
color.text.subtle |
Labels and sub-headers |
color.text.brand |
Text on primary brand surfaces |
color.background.brand.bold |
Primary action fill |
color.background.brand.gradient |
Hero/CTA gradients when needed |
Example
.my-section {
background: var(--tn-color-background-surface-container-low);
}
.my-card {
background: var(--tn-color-background-surface-container-lowest);
color: var(--tn-color-text);
}
Typography
Inter (400-800) with a mobile-first scale for workforce dashboards - greeting, metric tiles, labels, and list rows.
Product typefaces and scale - full typescale table, OpenType guidance, and workforce preview mapping.
Spacing
Layout rhythm uses semantic space.* tokens with a numbered scale - not arbitrary pixel
values. Token IDs map to CSS variables such as --tn-space-200.
Scale
| Token | Value | Design scale | Typical use |
|---|---|---|---|
space.0 | 0 | - | Reset gutters |
space.050 | 4px | 1 | Tight inline gaps |
space.100 | 8px | 2 | List gaps |
space.150 | 12px | 3 | Compact stacks |
space.200 | 16px | 4 | Button padding |
space.300 | 24px | 6 | Card padding; pairs with squircle radius |
space.400 | 32px | 8 | Dense section padding |
space.600 | 48px | 12 | Section whitespace |
space.800 | 64px | 16 | Editorial section padding |
When in doubt, increase whitespace - prefer space.600 or space.800 over cramming content.
.tn-card {
padding: var(--tn-space-300);
gap: var(--tn-space-100);
}
Elevation
Depth comes from tonal layering (surface tokens), not default drop shadows. Shadows and blur are reserved for floating UI that must read above the page.
When to use what
| Approach | Token / pattern | Use |
|---|---|---|
| Default lift | color.background.surface.container.lowest on …container.low |
Cards, panels, sections - primary depth model |
| Ambient shadow | elevation.shadow.ambient |
Modals, floating action buttons only |
| Glass / blur | elevation.backdrop.blur.default (20px) |
Top bars, floating nav |
| Subtle blur | elevation.backdrop.blur.subtle (12px) |
Secondary floating elements |
Do not stack more than three surface tiers; use glass for additional depth instead of more shadow.
.tn-fab {
box-shadow: var(--tn-elevation-shadow-ambient);
}
.tn-top-bar {
backdrop-filter: blur(var(--tn-elevation-backdrop-blur-default));
}
Border
TimeNode follows a no-line rule for layout: sectioning is done with surface color steps, not 1px rules between blocks.
Tokens
| Token | Value | When |
|---|---|---|
border.width.none |
0 |
Default - prefer tonal surfaces |
border.width.ghost |
1px |
With color.border.ghost - outdoor glare accessibility only |
color.border.ghost |
20% outline-variant | Fallback edge when contrast on sunlit screens needs help |
color.border.focus |
Brand emerald | Focus rings |
.tn-card--ghost-border {
border: var(--tn-border-width-ghost) solid var(--tn-color-border-ghost);
}
Radius
Corners use semantic border.radius.* tokens. Squircle radius is the brand signature -
do not use ad-hoc 4px or 8px radii on product UI.
Tokens
| Token | Value | Usage |
|---|---|---|
border.radius.squircle |
1.5rem (24dp) | Cards, buttons, containers |
border.radius.pill |
9999px |
Input fields |
.tn-card {
border-radius: var(--tn-border-radius-squircle);
}
.tn-input {
border-radius: var(--tn-border-radius-pill);
}