Design system
Colors, type, spacing and components used across VideoFrame. Everything on this page is built from design system tokens and classes, so it updates when they do.
Light values shown. Every color also has a dark value that swaps with the theme.
Ink, surfaces and borders
text-primary · #0E1F1A
text-secondary · #6E7976
surface-content · #F5F7F6
surface-card · #FFFFFF
surface-inset · #FAFBFA
border · #E6EAE8
border-input · #DCE1DF
border-divider · #EEF1F0
Brand, buttons and states
brand · #0F6E56
brand-hover · #0A4436
mint · #7EE8C7
primary · #0E1F1A
button-primary-hover · #0C3736
button-ghost-hover · #EEF1F0
button-danger · #B4472F
error-field · #C8553D
Tile pairs and deep panel
Aa
tile-neutral · #F5F7F6 / #0E1F1A
Aa
tile-brand · #E4F2ED / #0F6E56
Aa
tile-plan · #EEEBFB / #5B3BC4
Aa
tile-warning · #FFF4E0 / #8A5300
Aa
tile-error · #FDEEE8 / #A4412A
Aa
deep-panel · #0B3A33 → #152449 → #331B44
Instrument Serif for display and section titles, Instrument Sans for everything else, JetBrains Mono for ids and code. Use one italic accent word per display heading.
Display · Instrument Serif 400 · 40–64 / 1.0 · -3.5%
Video hosting that stays out of the way
Section · Instrument Serif 400 · 30–38 / 1.1 · -2%
Player settings
Card title · Instrument Sans 600 · 16 · -1%
Embed and sharing
Body · Instrument Sans 400 · 13.5–15.5 / 1.55
Choose who can watch this video and where it can be embedded. Changes apply as soon as you save.
Body secondary · same size · text-secondary color
Supporting copy, descriptions and hints sit one step quieter than the main text.
Label · Instrument Sans 600 · 13
Video title
Helper · Instrument Sans 400 · 12.5
Shown on the video page and in search results.
Eyebrow · Instrument Sans 700 · 11 · caps +9% · brand
Playback
Mono · JetBrains Mono 500 · 12.5
https://cdn.videoframe.net/hls/v_8f2a/master.m3u8
Card padding is 24, card gap 20, grid gap 18, field gap 7, section gap 44. Radius grows with the size of the surface.
Radius
radius-chip · 6
radius-tooltip · 8
radius-md · 10 (inputs, buttons, tiles)
radius-toast · 12
radius-card · 16
radius-soft · 20 (Dashboard, Library)
radius-shell · 24 (shell, popup)
radius-full · pill
Spacing scale
xs · 4
sm · 8
md · 16
lg · 24 (card padding)
xl · 32
section-gap · 44
Each example uses a design system class. Hover the buttons and menu items to see the hover looks.
Buttons
Primary is dark ink, never green or purple. Danger is only for destructive actions. The pill button is for the soft style (Dashboard, Library).
Inputs: default, focus, error
Untitled video
Shown on the video page.
videos.acme.com
Focus: 1px brand border and a 3px ring.
acme
Enter a full domain, like videos.acme.com.
Status pills and chips
Purple means paid feature and nothing else. Warning and error pills always carry text, never color alone.
Tooltip, toast, banner and menu
Video published
We could not save your changes. Check your connection and try again.
Surfaces: card, soft card, inset, deep panel
White, 1px border, radius 16, padding 24.
No border, radius 20. Dashboard and Library.
For code blocks and nested groups.
Gradient for upgrade and analytics hero blocks.
00 · Style guide · v1.0 · Locked · Oct 4, 2026
Everything below on this page follows these rules. Use them for any new card, popup or settings screen.
Neutral surfaces carry the UI. Colour only appears when it means something.
Each card ships clean, unsaved, saving, saved and error before it ships at all.
Errors keep the user's input. Destructive actions get a confirm or a 6s Undo.
Show the most severe. Never stack banners.
Page background only, never under text
white 42% · blur 22 · 1px white 70% · r24
#F5F7F6 · flat, so cards read clearly
#FFFFFF · 1px #E6EAE8 · two-layer shadow
#FAFBFA · save bars, inset tiles, empty states
122° #0B3A33 → #152449 → #331B44 · brand moments only
#0E1F1A · secondary and helper 60% minimum · disabled 38%
#0F6E56 · hover #0A4436
#F5F7F6 / #0E1F1A · default, list rows, settings
#E4F2ED / #0F6E56 · primary, success, ready
#EEEBFB / #5B3BC4 · paid features, upgrades, news
#FFF4E0 / #8A5300 · near a limit, processing
#FDEEE8 / #A4412A · failed, limit hit, destructive
text #FFF · secondary white 72% · accent mint #7EE8C7
Instrument Serif 400 · 40–64 / 1.0 · −3.5% · one italic accent word in #0F6E56
Instrument Serif 400 · 30–38 / 1.1 · −2%
Instrument Sans 600 · 16 · −1%
Instrument Sans 400 · 13.5–15.5 / 1.55 · ink 60–65%
Instrument Sans 600 · 13
Instrument Sans 400 · 12.5 · ink 60% (50% fails contrast)
Instrument Sans 700 · 11 · caps · +9% · #0F6E56
JetBrains Mono 400–500 · 12–12.5
shell 24 · card 16 · input / button / tile 10 · chip 6 · pill 99
card #E6EAE8 · divider #EEF1F0 · input #DCE1DF
0 1px 2px rgba(14,31,26,.04), 0 10px 30px rgba(14,31,26,.04)
0 40px 90px rgba(10,20,40,.4) · scrim rgba(10,20,17,.5)
0 24px 70px rgba(20,30,50,.16)
card padding 24 · card gap 20 · field gap 7 · grid gap 18 · section gap 44
1px #0F6E56 + 3px ring rgba(15,110,86,.12)
1px #C8553D + 3px ring rgba(200,85,61,.12) · text #A4412A
Header (title + description, gap 4) → fields → save bar
h44 · r10 · 1px #DCE1DF · padding 0 13 · text 14.5
h36 · r10 · #0E1F1A / #FFF · 13.5/700 · hover #0C3736
h36 · r10 · ink 70% · hover bg #EEF1F0
bg #EEF1F0 · ink 38%
S 32 · M 40 · r10 · tint bg, strong ink · colour from meaning
white · r24 · max 420–440 · Deep header only for welcome / upgrade
bottom centre · action + Undo · auto-dismiss 6s
helper text · disabled Save
orange dot #E08A5C + "Unsaved changes" #9A5A1F · Discard + Save · tab gets a dot
"Saving…" · primary at 70% · inputs stay editable
green dot #1F9C7A + "All changes saved" · ✓ Saved on #E4F2ED · clears after 2.4s
banner #FDEEE8 · 1px rgba(200,85,61,.25) · text #8A3522 · "Try again" · edits kept
Purple = "this is a paid feature". Nothing else. Never decoration, warnings or errors.
Icon tile ◆ #EEEBFB / #5B3BC4 + plan pill on the right of the row
Studio → #EEEBFB / #5B3BC4 · Starter → #E4F2ED / #0A4436 · 12/700 · r99
"New" pill uses plan purple · one per item
Never purple. Always primary #0E1F1A / #FFF · at a hard limit add a mint → #7EE8C7
Deep panel · once per screen · mint mono eyebrow · Serif 28 headline · white button, text #0A4436
Top of content, above the page title · one at a time · most severe wins
No alert. Usage only on the Billing page.
White card · brand tile "i" · "You've used 5.2 GB of 10 GB" · Dismiss + View usage · can be dismissed
bg #FFF4E0 · 1px rgba(138,83,0,.18) · title #5C3800 · tile white / #8A5300 · bar 4px #C98200 on rgba(138,83,0,.15) · Free up space + Upgrade
bg #FDEEE8 · 1px rgba(200,85,61,.25) · title #7A2E1D · body #8A3522 · tile white / #A4412A · "Upgrade to Starter →" · can't be dismissed
New uploads pause. Existing videos keep playing. Say both.
mesh page → frosted shell r20–24 → sidebar 220 (white 42%, blur 22) → content #F5F7F6
"Good morning, Sahil" + one plain stat sentence. No dashboards of numbers.
thumb · title · duration · quality · status pill · plays
Ready → brand · Processing → warning · Failed → error with Retry
Left: player + what you edit. Right: performance, embed code, who can watch.
Delete sits at the bottom of the right column, away from everyday actions
Name + one promise: "Three steps and your first video is live on your site."
Max 3 · icon tile + verb title + one line (Upload · Theme the player · Embed anywhere)
dashed 1px · "Drop your first video here" · formats + size limit underneath
Say what will appear: "Uploads show here with their status and plays."
Plain white · r24 · max 420–440 · padding 24 · scrim rgba(10,20,17,.5)
Only welcome and upgrade. Never for confirms or errors.
Danger button #B4472F · say exactly what is lost · Undo toast afterwards
Turning on signed URLs or revoking a key always asks to confirm first
✓ feature list · "Due today" + amount · "Uploads resume right away"
Any checkbox turns it on · every card shows its checkbox · Esc clears
1px #0F6E56 + 3px ring rgba(15,110,86,.14) · checkbox 22 r6 #0F6E56 + 2px white ring
Indeterminate box "–" 20 r6 + "3 of 9 videos selected"
Shift-click selects everything between
Dark, floats bottom centre · Move · Download · Delete
Folder · Filter (count badge) · Sort · Grid/List · h36 r10 · active = 1px #0F6E56
r10 · shadow 0 18px 40px rgba(21,36,73,.14) · items h36 r6 · current row #F5F7F6 + green ✓
Pill h30 · ✕ removes one · "Clear all" link in brand green
Target: dashed 1px #0F6E56 + ring · "Drop to move 3"
One switch, two modes: block listed / allow only listed · country chips · footer states how many countries can play
Shows key, link lifetime and a test link to try right away
Domains as mono chips r6 · "*.example.com includes subdomains" · bad input → error ring + example
One popover from "+ Upload video" · row: thumb, name, size · status · thin progress under the row
Works like a save bar · main action right, what will happen left · can close while uploading
Nothing from the workspace — not even its video count
Say which account is signed in
Request access (optional note to admin) · open a workspace you're in · switch account
Sidebar stays visible but locked · dashboard blurred behind
Dashboard and Library. Settings and forms stay in the quiet card style above.
Mesh page · frosted shell r28 · white 42% · blur 22
White · no border · r20 · hover shadow only
Pill h48 · primary #0E1F1A · secondary white · outline 1px #E6EAE8
Round 40–48 · white on shell, outline inside cards
Instrument Sans 400 · 24 · −2% inside cards
Short, plain, present tense. Say what happens next.
What happened + your work is safe + how to fix: "Couldn't save. Your edits are still here."
Name both effects: "New uploads are paused. Existing videos keep playing."
Verb + object: "Save changes", "Upgrade to Starter", "Request access"
"5.2 GB of 10 GB" · durations, codes and URLs in Mono
Exclamation marks, jargon without a reason, "Oops"
600 wide · Serif headline with one italic green word · Sans body · pill button #0E1F1A · codes in Mono
Georgia / Helvetica / Courier fallbacks where web fonts don't load
Covers built from product cards on one palette mesh · see Blog Art System
36×20 · knob 16 · on #0F6E56 · off #DCE1DF · saves instantly, no save bar
18 r5 · off 1.5px #C2CAC7 · on #0F6E56 + white ✓ · some selected "–"
18 circle · selected 5px #0F6E56 ring · use for 2–4 exclusive choices
h44 r10 · 1px #DCE1DF · ▾ at 60% · menu uses the Menu spec
h44 r10 · icon left · clear ✕ when filled · filters as you type
track #F5F7F6 p3 r10 · items h30 r7 · active white + 1px shadow · max 4
opacity 40% · keep the label · tooltip says why
Every control ≥ 36 on desktop, ≥ 44 on touch
Placeholder blocks #EEF1F0 at the real size · shimmer 1.4s · only if > 300ms
14px spinner inside the button · label becomes "Saving…" · 80% opacity
After 8s add a line: "Still working. Large files can take a minute."
Full-page spinners, or blocking inputs while saving
white · r10 · 1px #E6EAE8 · shadow 0 18px 40px rgba(21,36,73,.14) · items h36 r6 · hover #F5F7F6
Last item, below a divider · text #A4412A
Right-aligned in Mono at 60%
#0E1F1A · white 12.5 · r8 · padding 7 10 · 400ms delay · icon-only buttons only
#0E1F1A · h48 · r12 · bottom centre · one at a time · pause on hover
Success ✓ mint + Undo (6s) · Error × #F2A08B + Retry (stays) · Info (4s)
24 · stroke 1.6 (1.8 at 16px) · round caps and joins · no fills
16 in dense rows and chips · 20 in buttons and sidebar · 26 inside 56 tiles
Ink, or ink 60% when secondary · inside tiles take the tile foreground
Typed symbols ▤ ◆ ↑ ◐ ⌗ are placeholders · swap for the set in section 23
Sidebar 220 with labels · 3–4 card columns · popups centred
Sidebar → 64 icon rail with tooltips · wordmark hidden · 2 columns · toolbar wraps
Top bar + drawer · 1 column · popups → bottom sheets · action bar full width
Shrink the sidebar first, then columns, then padding (48 → 24 → 16)
Text 4.5:1 · large text 3:1 · ink 60% is the lightest allowed text on white
36 desktop · 44 touch
Keyboard only · 2px white gap + 2px #0F6E56
Tab in reading order · Esc closes menus, popups, selection · popups trap and return focus
Never colour alone · pills have words · dots sit next to labels
Icon-only buttons get an accessible name and a tooltip
Reduced motion: no shimmer, fades instead of slides
01 · Anatomy
How you appear on uploads, comments and invoices.
Sahil Rao
Shown to teammates.
Visible to teammates
Tokens
Card
#fff · 1px #E6EAE8 · r16 · padding 24 · gap 20 · two-layer shadow
Header
Title 16/600 · desc 13.5/400 @ 60% · gap 4
Field
Label 13/600 · input 44 r10 1px #DCE1DF · helper 12.5 @ 60% · gap 7
Save bar
#FAFBFA · top 1px #EEF1F0 · min-h 61 · padding 12 24 · button S 36 r10
Focus
#0F6E56 + 3px ring @ 12%
Error
#C8553D · text #A4412A · banner #FDEEE8
02 · Save bar states
Clean · nothing to save
Visible to teammates
Unsaved · tab gets an orange dot
Unsaved changes
Saving · inputs stay editable
Saving…
Saved · clears after 2.4s
All changes saved
Error · edits are kept
Couldn't save. Your edits are still here.
Try againUnsaved changes
03 · Profile
Clean · nothing to save
How you appear on uploads, comments and invoices.
Sahil Rao
Shown to teammates.
sahil@acme.com
Used for sign-in and invoices.
Visible to teammates
Editing · unsaved bar appears
How you appear on uploads, comments and invoices.
Sahil Rao Chawla
Shown to teammates.
sahil@acme.com
Used for sign-in and invoices.
Unsaved changes
Saved · email change pending
How you appear on uploads, comments and invoices.
Sahil Rao Chawla
sahil@acme.com
Check sahil@newco.com to confirm the change. Until then, sign in with sahil@acme.com.
Name updated · email pending
Validation · save failed
Couldn't save. Your edits are still here.
Try againHow you appear on uploads, comments and invoices.
Enter your name
Full name is required.
sahil@acme.com
Unsaved changes
04 · Change password
Clean · empty fields
Use 12+ characters. You will stay signed in on this device.
Enter current password
At least 12 characters
Repeat new password
Use 12+ characters
Typing · strength and match
Use 12+ characters. You will stay signed in on this device.
••••••••••
••••••••••••
Good · add a symbol for a stronger password
••••••••••••
Passwords match.
Unsaved changes
Saved · fields cleared
Use 12+ characters. You will stay signed in on this device.
Enter current password
At least 12 characters
Repeat new password
Password updated
Validation · three errors
Couldn't save. Your edits are still here.
Try againUse 12+ characters. You will stay signed in on this device.
••••••••••
Current password is wrong.
short1
Use at least 12 characters.
••••••••••
Passwords don't match.
Unsaved changes
05 · Hotlink protection
On · clean
Only the domains you list can embed your player.
Block other sites
Embeds from unlisted domains show a locked screen.
videos.acme.com
Protection is on
Saved · domain added
Only the domains you list can embed your player.
Block other sites
Embeds from unlisted domains show a locked screen.
Enter a domain
cdn.acme.com added
Invalid domain · save failed
Couldn't save. Your edits are still here.
Try againOnly the domains you list can embed your player.
Block other sites
Embeds from unlisted domains show a locked screen.
acme
Enter a full domain, like videos.acme.com.
Unsaved changes
Locked · Free plan
Only the domains you list can embed your player.
Block other sites
Available on Pro and above.
Upgrade to turn on
06 · Background layers
Mesh
Page background, never under text
Frosted shell
white 42% · blur 22 · r24 · sidebar lives here
Content area · #F5F7F6
Flat, so cards read clearly
Card · #FFFFFF
Hairline plus soft shadow
Save bar · #FAFBFA
Also inset tiles and empty states
07 · Picking colours
Two questions decide every colour. Where am I? Outside a card (page, shell, dark panel) or inside one. What does it mean? Neutral, brand, plan, warning or error. Icon tiles take their colour from what they mean, never for decoration.
Outside
Mesh
Page background
Frosted shell
Sidebar and chrome
Deep panel
Text on dark · #FFF
Secondary · white 72%
Accent · mint #7EE8C7
Inside
Content #F5F7F6
Flat canvas behind cards
Card #FFF
Hairline plus soft shadow
Inset #FAFBFA
Text on light · #0E1F1A
Secondary · ink 60%
Link · green #0F6E56
Icon tiles
Tint background, strong foreground. S 32 · M 40 · r10
Neutral
#F5F7F6 / #0E1F1A
Default. Empty states, list rows, settings.
Brand
#E4F2ED / #0F6E56
Primary actions, success, “ready”.
Plan
#EEEBFB / #5B3BC4
Paid features, upgrade prompts, news.
Warning
#FFF4E0 / #8A5300
Approaching a limit, processing.
Error
#FDEEE8 / #A4412A
Limit hit, failed, destructive.
On dark
white 12% / mint
Only inside Deep panels and popup headers.
20 · Form controls
Green means on or chosen. Everything else stays neutral. Disabled controls drop to 40% and keep their label so people know what they're missing.
Toggle · 36×20 · knob 16
On
Off
Disabled
Focus
Checkbox & radio · 18 · hit area 36
Unchecked
Checked
Some selected
Block
Allow only
Select, search, segmented
720p
▾onboard
✕21 · Loading
Placeholder blocks keep the layout still while data arrives. Spinners only live inside the button that started the work. If something takes longer than 8 seconds, say so.
Placeholder · same size as the real card
Button busy
Slow
Still working. Large files can take a minute.
Appears after 8 seconds.
22 · Menus, tooltips & toasts
Menus are white and sit on the page. Tooltips and toasts are dark, like the action bar, so they read as temporary. Destructive menu items go last, below a divider.
Menu · white, r10, items h36
Copy link
Copy embed code
Move to folder
MDelete
Tooltip
Copy embed code
Icon-only buttons only · 400ms delay · never holds the only copy of key info.
Toasts
Bottom centre · one at a time · 4s, or 6s with Undo · pause on hover
23 · App icons
One line icon set replaces the typed symbols (▤ ◆ ↑). Drawn on a 24 grid, 1.6 stroke, round ends, no fills. Use at 16 in dense rows and 20 in buttons and the sidebar. Same family as the blog topic icons.
24 · Screen sizes
Three layouts. The sidebar shrinks before anything else does. On phones, popups become bottom sheets and every tap target grows to 44.
Sidebar 220 with labels · 3–4 card columns · popups centred
Sidebar becomes a 64 icon rail with tooltips · wordmark hidden · 2 columns · toolbar wraps
Top bar + menu drawer · 1 column · popups as bottom sheets · action bar full width · targets 44
25 · Accessibility
Body text needs 4.5:1 against its background. Grey text at 50% only reaches 3.3:1, so helper and secondary text now start at 60%. Disabled controls are the only exception.
Contrast pairs
Ink on white
17.1PassBrand green on white
6.2PassInk 60% on white
4.5PassInk 50% on white
3.3FailError on error tint
5.5PassWarning on warning tint
5.8PassPlan on plan tint
6.3PassMint on deep panel
10.3PassTargets & focus
36 desktop
44 touch
keyboard focus
Keyboard, focus and motion
Focus ring shows on keyboard only: 2px white gap + 2px #0F6E56.
Tab order follows reading order. Esc closes menus, popups and selection.
Popups keep focus inside and return it to the button that opened them.
Never colour alone: status pills have words, dots sit next to a label.
Icon-only buttons need a label for screen readers and a tooltip.
Respect reduced motion: no shimmer, fades instead of slides.