Honey and cobalt: honey is the voice, cobalt the structure, on OKLCH ramps behind every semantic colour.
Concept · live ReactSource file: tokens.json
Themes
Light is the workspace: the host panel and the console. Dark is the stage and the brand: the shared screen, the phone during a round, the join screen. A surface gets its theme from what it is, never from the OS.
Light
bggray-50
surfacegray-0
textgray-1000
text-mutedgray-600
primarydusk-700
accenthoney-500
warningorange-500
Dark
bgink-950
surfaceink-900
textink-100
text-mutedink-400
primaryink-50
accenthoney-400
warningorange-400
Ramps
Seven primitive ramps, generated in OKLCH by scripts/hivemind-ramps.mjs. Every hue shares one lightness ladder, so step 600 of any ramp sits at the same lightness, and each step takes the most saturated colour that fits in sRGB. Product UI never uses a ramp directly; it goes through a semantic token.
grayGraphite with a faint violet tint. Every ground, every word.
0
50
100
200
300
400
500
600
700
800
900
950
1000
inkDark-theme neutrals: a cool blue-black, never violet-grey.
0
50
100
200
300
400
500
600
700
800
900
950
1000
honeyPrimary: the voice. Live, the record comb, the shared mind, the hero series. Bright, and only a fill, glow or dot.
50
100
200
300
400
500
600
700
800
900
950
duskSecondary: the counterpoint. The other side of a split, the brand’s dark atmosphere, cards that carry white type.
50
100
200
300
400
500
600
700
800
900
950
greenStatus only: success, a decision that held up. Never a brand colour.
50
100
200
300
400
500
600
700
800
900
950
orangeWarning, a clear step from honey, always with an icon and a word.
50
100
200
300
400
500
600
700
800
900
950
redDanger: errors and invalid fields.
50
100
200
300
400
500
600
700
800
900
950
Semantic tokens
Every semantic colour is an alias of a ramp step, chosen per theme. A theme can take a different step of the same ramp, or a different ramp: honey is a fill in both themes, but where the hero series is drawn as a line, paper gets ink and the dark theme gets honey. Each text token holds 4.5:1 on the grounds its usage note names; the ramp script checks every pair and fails the build if one drops.
Semantic
Light
Dark
Hex
bg
gray-50
ink-950
bg-subtle
gray-100
ink-1000
surface
gray-0
ink-900
surface-raised
gray-0
ink-800
surface-hover
gray-100
ink-800
border
gray-200
ink-800
border-control
gray-500
ink-500
scrim
rgba(20, 19, 24, 0.40)
rgba(10, 9, 13, 0.64)
text
gray-1000
ink-100
text-muted
gray-600
ink-400
text-subtle
gray-600
ink-400
primary
dusk-700
ink-50
primary-hover
dusk-800
ink-200
on-primary
gray-0
ink-1000
link
gray-1000
ink-100
Honey and cobalt
Two brand hues, each with a job. Honey is the voice; cobalt is the structure and the counterpoint. On paper the brand is cobalt with honey in it: the comb’s cells, the primary button, chart lines and focus are cobalt, and honey is the centre cell and the fills. On ink, the comb turns paper and honey carries the lines. Honey against cobalt is warm against cool and light against dark, so the two sides of a split hold apart for every kind of colour vision.
Honey · the voiceLive, the record comb, the shared mind, conditions, the hero fill.
Cobalt · the structureThe comb’s cells and the primary button on paper, the other side of a split, the dark atmosphere.
Semantic
Light
Dark
Hex
primary
dusk-700
ink-50
primary-hover
dusk-800
ink-200
on-primary
gray-0
ink-1000
secondary
dusk-600
dusk-400
secondary-text
dusk-700
dusk-300
secondary-subtle
dusk-50
dusk-950
logo-cells
dusk-700
ink-100
Honey: fill bright, draw ink
Honey is only ever a fill, a glow or a dot, and it always carries ink. On paper it never becomes a line or a word, because a honey dark enough to hold contrast on white turns brown. Lines and emphasis there are ink, with a honey highlighter under the words that matter.
Semantic
Light
Dark
Hex
accent
honey-500
honey-400
accent-hover
honey-600
honey-300
on-accent
gray-1000
ink-1000
accent-text
gray-1000
honey-300
accent-subtle
honey-100
honey-950
accent-border
honey-300
honey-800
focus-ring
dusk-600
honey-400
live
honey-500
honey-400
voice-dot
gray-300
ink-700
voice-dot-active
honey-500
honey-400
Use accent as a fill: the record comb, the live dot, the shared mind, condition dots. Content on it is ink (on-accent).
Draw the hero series with chart-agree-line: ink on paper, honey on ink.
Every honey mark on paper has a direct label or count beside it.
Don’t use it
Honey text or a darkened honey on paper. It goes mustard.
White on honey.
As a call to action. The primary button is ink or paper.
Status
Each status is a family of four from one ramp: a bright mark for the icon or dot, a darker text step that holds 4.5:1, a subtle ground and a border. The mark carries the colour; the words stay readable.
Held upRevisit dueReversedNot yet
Semantic
Light
Dark
Hex
danger
red-500
red-400
danger-text
red-700
red-300
danger-subtle
red-50
red-950
danger-border
red-200
red-800
success
green-600
green-400
success-text
green-700
green-300
success-subtle
green-50
green-950
success-border
green-200
green-800
warning
orange-500
orange-400
warning-text
orange-800
orange-300
warning-subtle
orange-50
orange-950
warning-border
orange-200
orange-800
Chart colours
The chart order is the palette: honey for the first side, the hero fill and conditions, cobalt for the second side and for lines on paper, then ink and greys. The heat ramp is one gray, light to dark.
Token
Value
Where it lands
--hm-chart-ink
#4163e4 / #6489fe
Single-series bars and columns: mid cobalt.
--hm-chart-muted
#a7a4b3 / #5f636b
Console charts: de-emphasised marks only — sparklines and secondary segments. Never text.
--hm-chart-grid
#e6e5eb / #2d323b
Console charts: 1px solid gridlines and axis rules. Recessive by design.
--hm-chart-agree
#2d49c9 / #6489fe
The hero series as a fill or dot: cobalt, the strongest step in each theme.
--hm-chart-agree-line
#1c2dad / #cad9fe
The hero series drawn as a line.
--hm-chart-agree-wash
#e5edff / #040939
Area fill under the hero line.
--hm-chart-b
#6489fe / #cad9fe
The second series, or the other side of a split: a lighter cobalt on paper, a deeper one on ink.
--hm-chart-b-wash
#f4f7fe / #040939
Wash for the second series.
--hm-chart-common
#2d49c9 / #6489fe
Theme bars in a readout: the hero cobalt.
--hm-heat-0
#f4f7fe / #1c2129
Heatmap, none.
--hm-heat-1
#cad9fe / #040939
Heatmap, low.
--hm-heat-2
#6489fe / #142380
Heatmap, some.
--hm-heat-3
#2d49c9
Heatmap, more.
--hm-heat-4
#142380 / #a2bcff
Heatmap, most.
Typography
Geist in three registers: Interface, Stage for the shared screen, and Numerals for numbers that change.
Concept · live ReactSource file: tokens.json
Interface
For the console, the host panel and phones. Weights 400, 500 and 600 only.
display 48px/52px · 600Every voice at once.
title-1 32px/40px · 600Your hives
title-2 24px/32px · 600What should we cut from v1?
title-3 18px/26px · 600Round 2
body 16px/24px · 400Speak freely. Your answer is never shown with your name.
body-sm 14px/20px · 400Audio is deleted as soon as it is transcribed.
label 14px/20px · 500Start round
caption 12px/16px · 500Updated 2 min ago
Stage
Only on the shared screen, designed at 1280×720 so it survives screen-share compression. Nothing on stage is smaller than stage-meta.
stage-headline 44px/52px · 600Most of you want to ship, but not without the export.
stage-theme 28px/36px · 500Onboarding is the real problem
stage-body 22px/30px · 400Two voices worry the deadline hides a quality problem.
stage-meta 18px/24px · 500Round 2 of 3
Numerals
Geist with tabular figures, for numbers that change: the timer, the room code, counts. Every digit takes the same width, so nothing jitters, without a monospace face.
timer 64px/64px · 5000:47
room-code 48px/56px · 500KX7-42Q
count 20px/24px · 5005 of 7
code 13px/20px · 400hive_9f2c
Rules
Sentence case everywhere, buttons and titles included.
Emphasis with weight 600, never italics or capitals.
Keep reading text under 68 characters a line.
Don’t use it
Letter-spaced capitals for labels.
Body text below 16px on a phone.
Iconography
Thirty-eight glyphs drawn for Hivemind, outline and solid, with the mark’s cell for its own ideas.
Concept · live ReactSource file: tokens.jsonReact component: HM_ICONS
The set
Thirty-eight glyphs, drawn for Hivemind: outline for the interface, solid for the few places an icon leads a line. Every surface Hivemind owns uses them; Lucide stays only in the generic call chrome, which stands in for someone else’s product.
Check
Minus
Plus
Copy
JoinLink
Search
Play
Stop
Retake
Refresh
Actions
ArrowLeft
ArrowUpRight
ArrowDownRight
ChevronDown
Direction
Mic
Keyboard
Handset
Lock
Listening
Voice and input
Idea
Tension
Help
CalendarClock
Calendar
The readout
Hives
Done
Pending
Settings
QuestionSets
People
Hives and status
TableView
ChartView
Sun
Moon
The console
LockSolid
HandsetSolid
MicSolid
KeyboardSolid
Solid, for the hero of a line
Construction
A 24-unit square with 2 units of clear space, so the live area is 20. One stroke, round caps and round joins, and corners rounded at about a quarter of their edge. Where a glyph stands for a Hivemind idea (a hive, a status, help, settings) it is built on the mark’s own cell, the rounded flat-top hexagon.
Hives · 7× scale
Done · 7× scale
Idea · 7× scale
Sizes
Three sizes, one weight. Below 16 the hexagon glyphs lose their corners, so 16 is the floor.
16px · inline, buttons
20px · lists, the stage
24px · navigation
When to use
Beside a word, never instead of one: the label is what the icon means.
In currentColor, so an icon takes its text’s colour and its contrast.
The cell glyphs (Done, Pending, Help, Hives) for Hivemind’s own ideas, so status looks like the brand.
Don’t use it
Lucide or any other set on a Hivemind surface. Mixed sets read as two products.
Honey on an icon. Honey is a fill for the room’s voice, not a decoration.
Filling the outline glyphs. Stop is the one solid form, inside the live record button.
Accessibility
Decorative by default: aria-hidden, not focusable. The word beside it is read instead.
Pass title when an icon carries meaning on its own. It becomes an image with that name.
At 1.75 the stroke is about 2px at 24, so an icon in text or text-muted clears the 3:1 non-text minimum (1.4.11) wherever its text does.
Props
Prop
Type
Default
Description
size
number | string
24
Width and height. 16, 20 or 24.
strokeWidth
number
1.75
One weight across the set. Change it only to match a heavier type weight.
title
string
—
Makes the icon an image with this name.
…svg
SVGProps
—
className, style, fill (for Stop) and the rest pass through.
Spacing and shape
A 4px spacing grid, six radii, and the fixed sizes every surface is laid out with.
Concept · live ReactSource file: tokens.json
Spacing
A 4px grid. Use the steps, not values in between.
space-14px
space-28px
space-312px
space-416px
space-520px
space-624px
space-832px
space-1040px
space-1248px
space-1664px
space-2496px
Radius
Controls at radius-md, cards at radius-lg, sheets at radius-xl. Every voice is a full circle.
radius-xs
radius-sm
radius-md
radius-lg
radius-xl
radius-full
Sizes
Token
Value
Where it lands
--hm-control-sm
32px
Dense controls in the console
--hm-control-md
40px
Default controls
--hm-control-lg
48px
Phone buttons
--hm-touch-min
44px
Minimum touch target
--hm-record-button
96px
The record button on a phone
--hm-stage-width
1280px
The stage design width
--hm-content-max
1200px
Console content column
--hm-measure
68ch
Reading measure
Elevation
Separate with borders, not shadows. Only things that float get shadow-overlay.
Motion explains a change of state. There is one loop and one orchestrated moment.
Concept · live ReactSource file: tokens.json
Durations
Token
Value
Where it lands
--hm-duration-fast
120ms
Hover and press
--hm-duration-base
200ms
Panels, sheets, a dot filling
--hm-duration-slow
320ms
Page transitions, a voice landing
--hm-duration-listen
1.6s
The listening breath
--hm-duration-reveal
640ms
Voices drifting into the readout
--hm-ease-out
cubic-bezier(0.2, 0, 0, 1)
Every transition
Listening
While a round runs, the record button scales 1 to 1.06 and back. It is the only looping animation in the product.
The reveal
When a readout appears, the room’s voices drift into the centre dot, then the headline and sections fade in, 80ms apart. It is the one orchestrated moment.
Reduced motion
Under prefers-reduced-motion, drop the breath and show a static 2px live ring.
Skip the drift and cut straight to the readout.
Charts appear drawn rather than growing in.
Logo
A seven-cell comb: six equal voices around one shared mind, with a Geist Semibold wordmark.
Concept · live ReactSource file: tokens.jsonReact component: Mark, Wordmark, Lockup
Construction
A seven-cell comb on a 64-unit square: flat-top hexagons of radius 9.6, corners rounded at 20% of the edge, with a 2.4-unit gutter. Six identical cells are the voices; the centre cell is the shared mind and the only one that may turn honey.
48 · 32 · 20 · 14
Lockups
The wordmark is Geist Semibold at −0.045em, outlined to a path. The comb is 1.55× the cap height, with half a cap of space between them. Hivemind is one word with a capital H.
App tile
The comb on a cobalt squircle, lit from above, and flat: an app icon carries no shadow of its own. For the app icon, favicons and anywhere the mark needs its own ground.
Usage
Clear space of one cell around the mark, two cells around the lockup.
Minimum sizes: mark 14px, lockup 96px wide.
Write the name Hivemind: one word, capital H, in copy, alt text and metadata.
Don’t use it
Recolouring outer cells, adding cells or rotating the comb.
Setting the wordmark in live text: use the outlined path, so it matches everywhere.