Hover or select a step to read its value and contrast.
Status tones
Six tones, in order of severity, each with seven roles. A tone’s text and icon pass on its own surface. onFill is for text or an icon on the solid fill.
Success
Done, healthy, in range
fill
onFill
surface
border
icon
text
textStrong
Warning
Marginal, worth watching
fill
onFill
surface
border
icon
text
textStrong
Attention
Someone needs to act
fill
onFill
surface
border
icon
text
textStrong
Error
Failed, unsafe, out of range
fill
onFill
surface
border
icon
text
textStrong
Info
Running now, or news
fill
onFill
surface
border
icon
text
textStrong
Neutral
Idle, off, no status
fill
onFill
surface
border
icon
text
textStrong
The Vue library’s --color-success, --color-warning and --color-error are the fill role here.
Roles
Every other colour role, named by job. Hover a swatch for its value.
Text
primary
secondary
tertiary
disabled
placeholder
inverse
onPrimary
link
linkHover
linkInverse
Icon
primary
secondary
disabled
inverse
interactive
Surface
page
card
raised
overlay
inset
hover
pressed
selected
disabled
skeleton
inverse
Border
divider
field
strong
fieldHover
control
disabled
focus
error
Interactive
primary
primaryHover
primaryPressed
secondary
secondaryHover
secondaryPressed
ghostHover
ghostPressed
danger
dangerHover
dangerPressed
selected
selectedText
disabled
Chart
series1
series2
series3
series4
series5
grid
axis
axisLabel
thresholdWarning
thresholdCritical
Brand
primary
surface
Plus surface.scrim, grey-1300 at 50%, behind dialogs and drawers.
Where they're used
Dashboard widgets: the status panel, badges and freshness read SEMANTIC.status, under their widget names (ok, note, act, bad, live, idle).
Mobile: the same tokens. Screens import them, so a phone and the dashboard can’t drift apart.
Controls: alerts, field errors and toasts take a tone’s surface, border and text.
Accessibility
Key
What it does
Tab
Moves focus to the selected grey step.
Right / Down
Selects the next, darker step.
Left / Up
Selects the previous, lighter step.
Home / End
Selects the lightest or darkest step.
Palettes
The twenty-three global ramps that every semantic colour token is cut from.
Live React portSource file: src/assets/css/global.css
Solid families
Eighteen families at thirteen steps each: fourteen hues, then four greys. Every colour a component paints is a step on one of these ramps. Indigo ships here, but no component uses it: blue roles use the blue ramp.
Hover or tab to a cell to read its token, value and contrast.
Semantic mapping
The primary tokens and the global steps they come from.
Semantic token
Global step
Value
--color-primary
--global-blue-900
#00AEEF
--color-primary-hover
--global-blue-800
#0ABEFF
--color-primary-active
--global-blue-1000
#1877F2
--color-primary-dark
--global-blue-1100
#0C296A
The blue ramp holds one hue from 100 to 1300. Pressed, 1000, is a deeper cyan-blue rather than a different blue, so a pressed primary darkens without changing hue. It’s also the first step to pass 4.5:1 on white.
Alpha families
Five ramps in rgba(), for scrims, hover washes and anything that sits over a map, chart or photo.
neutral-grey-alpha
flat-grey-alpha
cool-grey-alpha
bright-grey-alpha
alpha-white
10013 steps1300
--global-neutral-grey-alpha-900rgba(6, 0, 11, 0.48)alpha — no fixed ratio
Usage
Reach for a semantic token on Colour first. Use a global step only when none fits.
Use an alpha family over a map, chart or photo, where a solid fill would hide what’s underneath.
Check an alpha colour’s contrast in place, because it depends on what’s behind it.
Typography
Inter at twelve sizes and five weights, tuned for dense tables of readings.
Live React portSource file: src/assets/css/tokens.css
Scale
Twelve sizes, from 9 to 36px, all in Inter (--font-family-base). Half of them sit under 14px.
--font-size-5xl · 36pxSoil moisture 300 mm
--font-size-4xl · 30pxSoil moisture 300 mm
--font-size-3xl · 24pxSoil moisture 300 mm
--font-size-2xl · 20pxSoil moisture 300 mm
--font-size-xl · 18pxSoil moisture 300 mm
--font-size-lg · 16pxSoil moisture 300 mm
--font-size-base · 14pxSoil moisture 300 mm
--font-size-md · 13pxSoil moisture 300 mm
--font-size-sm · 12pxSoil moisture 300 mm
--font-size-xs · 11pxSoil moisture 300 mm
--font-size-2xs · 10pxSoil moisture 300 mm
--font-size-3xs · 9pxSoil moisture 300 mm
Weights
Five weights. The names run one step light: semibold is 500 and bold is 600.
Ag
400 · normal
Bore 12 · 4.2 m
Ag
475 · medium
Bore 12 · 4.2 m
Ag
500 · semibold
Bore 12 · 4.2 m
Ag
600 · bold
Bore 12 · 4.2 m
Ag
700 · extrabold
Bore 12 · 4.2 m
475 is the house medium. It stays open at 11px, where 500 fills in, and holds a row apart better than 400.
Roles
The size and weight each part of the interface uses.
Role
Size
Weight
Metrics tile figure
5xl · 36
700
Gauge reading
3xl–4xl · 24–30
600
Inline edit title
2xl · 20
500
Dialog and empty-state title
lg · 16
600
Body text, checkbox and radio labels
base · 14
400
Button label
base · 14
475
Field value
base · 14
500; placeholder 400
Table cell
md · 13
400; numbers 475
Table header, field label, badge
sm · 12
475
Helper and error text
xs · 11
400
Tooltip
2xs · 10
500
Menu group label
2xs · 10
600, capitals
Usage
Use 14px for body text, and 13px inside tables.
Set numbers in a table at 475 with tabular figures, so the columns line up.
Use 475 (--font-weight-medium) for button labels, field labels, badges and table headers.
Spacing
A 4px scale for padding, gaps and layout, in twenty-two steps.
Live React portSource file: src/assets/css/tokens.cssStorybook story: Foundation/Spacing
Scale
Twenty-two steps on a 4px base. They run in fine steps up to 48, then widen to 56, 64, 80, 96, 112 and 128.
--spacing-0-5
2
--spacing-1
4
--spacing-1-5
6
--spacing-2
8
--spacing-2-5
10
--spacing-3
12
--spacing-3-5
14
--spacing-4
16
--spacing-5
20
--spacing-6
24
--spacing-7
28
--spacing-8
32
--spacing-9
36
--spacing-10
40
--spacing-11
44
--spacing-12
48
--spacing-14
56
--spacing-16
64
--spacing-20
80
--spacing-24
96
--spacing-28
112
--spacing-32
128
The grid behind each bar is 4px.
Usage
Use --spacing-2 (8px) between adjacent controls in a toolbar.
Use --spacing-3 (12px) between rows inside a card.
Use --spacing-4 (16px) for card padding.
Use --spacing-6 (24px) for the page gutter and between sections.
Use the half-steps (2, 6, 10 and 14px) for padding and gaps inside small controls such as buttons and badges.
Keep steps up to 48 for components, and the wider steps for page layout.
Don’t use values between steps. For 52px, pick 48 or 56.
Radius
Corner radii for each kind of surface, from 6px buttons to fully round pills.
Live React portSource file: src/assets/css/tokens.css
Scale
Eight values, from square to pill.
none · 0
sm · 4px
md · 6px
lg · 8px
xl · 10px
2xl · 12px
3xl · 16px
full · 9999px
In components
Each kind of object has its own radius. The bigger the box, the bigger the corner.
button · 6
Online
badge · 6
card · 8
Bore 12
field · 10
dialog · 16
Bore 12
chip · 24
Usage
Use --radius-sm (4px) for checkboxes and skeleton text.
Use --radius-md (6px) for buttons, badges, icon buttons and menu rows.
Use --radius-lg (8px) for cards, selects, chip inputs, dropdowns and alerts.
Use --radius-xl (10px) for the text input.
Use --radius-3xl (16px) for dialogs.
Use --radius-full for radios, toggles, avatars and presence dots.
Use 24px for chips. It has no token.
Elevation
Shadows that separate cards, menus and dialogs from the page beneath them.
Live React portSource file: src/assets/css/tokens.cssStorybook story: Foundation/Shadows
Scale
Seven steps, each tinted with the system’s black, #0A090B, so shadows stay warm against the greys.
xs
sm
md
lg
xl
2xl
inner
Component shadows
Four shadows, each named for the component it sits under.
input
card
dropdown
tooltip
--shadow-card has three layers, and the third is 0 0 0 1px. It draws the card’s edge without a border, so the edge adds nothing to the layout.
--shadow-input
0 1px 2px 0 rgba(10, 9, 11, 0.05)
--shadow-card
0 2px 12px -1px rgba(10, 9, 11, 0.10)
0 2px 2px -1px rgba(10, 9, 11, 0.04)
0 0 0 1px rgba(10, 9, 11, 0.05) ← the hairline
--shadow-dropdown
0 4px 12px rgba(0, 0, 0, 0.08)
0 2px 4px rgba(0, 0, 0, 0.04)
--shadow-tooltip
0 2px 8px rgba(0, 0, 0, 0.15)
Focus rings
button
Bore 12
chip
Bore 12
field
Every focus ring is a box-shadow, so focus never moves the layout.
Token
Value
Where it lands
(no token)
2px gap, 2px ring
Buttons.
--shadow-button-focus
2px white + 2px #1877F2
Chips, and small buttons inside fields. Was 0 0 0 3px rgba(0,174,239,.3).
(no token)
2px #1877F2 border, 3px halo at 6%
Text fields. The border carries focus; the halo is decoration.
Usage
Don’t add a border to a surface that has --shadow-card. Its third layer already draws the edge.
Use --shadow-dropdown for menus and dropdowns.
Iconography
Bespoke glyphs for agricultural measurements, with Heroicons for general interface actions.
Live React portSource file: icons/heroicons.tsStorybook story: Foundation/IconReact component: Glyph, WGlyph
Try it
Switch sets, change the size, and turn off Animate to see each glyph’s resting frame.
Each glyph is one SVG on a 96×96 canvas, so the same file works at every size.
Measurement glyphs
Forty-seven glyphs, one for each thing a sensor measures. Each one moves, and the movement shows the reading.
Air & weather
windspeed
wind-direction
temperature
pressure
humidity
dew-point
solar-radiation
fire-index
frost
Water
rainfall
water-flow
irrigation-spray
flow-total
water-pressure
water-temperature
water-quality
effluent
weir
Level & storage
tank-level
reservoir
river
silo
trough
fuel
fertilizer
Soil & plant
soil-moisture
soil-temperature
leaf-wetness
evapotranspiration
conductivity
dendrometer
Power, control & movement
battery
power
signal
schedule
engine
pump
valve
tilt
movement
piezometer
Stations & assets
weather-station
soil-probe
rain-gauge
fridge
gps
generic
rainfallfalls
windspeedsways
temperaturerises
pressureswings
signalfills
batteryglows
water-flowspins
irrigation-spraydrips
evapotranspirationlifts
fire-indexflickers
Each glyph carries its own motion, so it animates wherever you place it.
Interface icons
Everything that isn’t a measurement uses Heroicons from the solid set, at 24×24: navigation, settings and alerts.
Graphs
Sites
Groups
Users
Map View
Clients
Operations
Settings
Log out
bell
edit
alertTriangle
shield
key
Sizes
Five sizes, shared by both sets.
xs · 14
sm · 16
md · 20
lg · 24
xl · 32
Usage
Use a measurement glyph to show what a sensor measures.
Use a solid Heroicon for navigation, settings and alerts.
Size both sets with the five icon tokens. Don’t use sizes between them.
Accessibility
A glyph has no text of its own, so show the measurement’s name beside it. With reduced motion on, every glyph holds a resting frame that still shows the reading.
Soil moisture
reading, labelled
Tokens
Token
Value
Where it lands
--size-icon-xs
14px
Inline with 11px table text.
--size-icon-sm
16px
Inside a button or field. The default.
--size-icon-md
20px
Card headers.
--size-icon-lg
24px
Sidebar and dialog headers.
--size-icon-xl
32px
Empty states.
--size-icon-button
24px
Icon button hit area.
Motion
Durations and easings for every transition, so the whole product moves at one pace.
Live React port
Try it
Pick a duration, a curve and a property. Changing any control replays the move.
Delay waits --duration-slower before the move starts.
Durations
Seven steps, from 50 to 500ms. Most of the product moves at 100 or 150ms.
--duration-instant
50ms
--duration-fast
100ms
--duration-normal
150ms
--duration-moderate
200ms
--duration-slow
300ms
--duration-slower
400ms
--duration-slowest
500ms
All seven run on --ease-in-out, so only the duration differs.
1150ms · easeOutCubicThe gauge the product ships.
500ms · --ease-outThe ceiling, on the same arc.
Gauges sweep over 1150ms, past the top of the scale, because a reading is arriving rather than a control responding.
Easings
Six curves. Press Replay to run a dot along each one.
Duration
Slowed down so each curve’s shape shows.
linear
linear
cubic-bezier(0.4, 0, 1, 1)
in
cubic-bezier(0, 0, 0.2, 1)
out
cubic-bezier(0.4, 0, 0.2, 1)
in-out
cubic-bezier(0.34, 1.56, 0.64, 1)
spring
cubic-bezier(0.68, -0.55, 0.265, 1.55)
bounce
Spring and bounce overshoot the end. Bounce also dips below the start.
Composed transitions
Four tokens are whole transition values, each on --duration-normal.
Loops every 2s, slowed to 450ms.
--transition-transformtransform only
Save
Duplicate
Delete
--transition-allevery property, layout included
Save
Duplicate
Delete
/* Same duration. Only one of them moves the rest of the row. */
.save { transition: var(--transition-transform); }
.save--lazy { transition: var(--transition-all); }
/* --transition-all: all var(--duration-normal) var(--ease-in-out)
and `all` includes width, padding and radius — every property
that forces the elements beside it to be laid out again. */
--transition-all animates width too, so the buttons beside it move. --transition-transform leaves them still.
Usage
Use --duration-normal (150ms) for most transitions, and --duration-fast (100ms) for hover colour changes.
Keep anything a person acts on at 200ms or less. Use 400ms and 500ms only for skeletons and page transitions.
Use --ease-out for things entering, and --ease-in-out for everything else.
Use a composed token instead of listing properties, so every component animates the same ones.
Keep --ease-bounce for a button’s success and error pops.
Don’t use --transition-all. It animates layout, so the things around it move.
With reduced motion on, skip the move and show the end state.
Tokens
Token
Value
Where it lands
--duration-instant
50ms
—
--duration-fast
100ms
Hover colour and background changes.
--duration-normal
150ms
The default. Most component transitions.
--duration-moderate
200ms
Disclosures and dropdowns opening.
--duration-slow
300ms
—
--duration-slower
400ms
Skeletons and page transitions.
--duration-slowest
500ms
Skeletons and page transitions.
--ease-linear
linear
—
--ease-in
cubic-bezier(.4,0,1,1)
—
--ease-out
cubic-bezier(0,0,.2,1)
Anything entering.
--ease-in-out
cubic-bezier(.4,0,.2,1)
The default curve.
--ease-spring
cubic-bezier(.34,1.56,.64,1)
Not in use.
--ease-bounce
cubic-bezier(.68,-.55,.265,1.55)
Button success and error pops.
--transition-colors
color, background, border · 150ms
Text, fill and border colour.
--transition-opacity
opacity · 150ms
Opacity only.
--transition-transform
transform · 150ms · ease-out
Transform only. The one on ease-out.
--transition-all
all · 150ms
Every property, layout included. Avoid.
(no token)
1150ms · easeOutCubic
Gauge sweep.
(no token)
1800ms
Compass needle settling onto its bearing.
Logo
The Wildeye lockups, the animated mark and the reseller versions, and where each one is used.
Live React portVue source: WildLogoFull.vueReact component: WildeyeLogoAnimated
Try it
Change the theme and speed, or turn off the water fill. With reduced motion on, the logo shows its final frame.