hermes-hub/.agents/skills/frontend-design/color.md

8.3 KiB
Raw Blame History

Color — Tokens, Palettes, Restraint

Color is punctuation, not wallpaper. One accent, many neutrals, used surgically.


The Token System

Every project defines these tokens. No raw hex in components.

:root {
  /* Surface (background) */
  --surface: ...;             /* primary background */
  --surface-elevated: ...;    /* cards, modals — slightly different */
  --surface-sunken: ...;      /* inputs, code blocks — slightly darker/lighter */

  /* Ink (text) */
  --ink: ...;                 /* primary text */
  --ink-muted: ...;           /* secondary text */
  --ink-subtle: ...;          /* tertiary, placeholders */

  /* Lines */
  --hairline: ...;            /* borders, dividers, rules */
  --hairline-strong: ...;     /* emphasized borders */

  /* Accent */
  --accent: ...;              /* the brand color */
  --accent-ink: ...;          /* text on accent surfaces */
  --accent-soft: ...;         /* tinted backgrounds for accent states */

  /* State */
  --success: ...;
  --warning: ...;
  --error: ...;
  --info: ...;
}

Neutral Palette Library

Pick ONE neutral system. Then add an accent.

Bright / Paper (Refined Minimal, Editorial, Soft)

--surface:        #FFFFFF   /* or #FAFAFA */
--surface-elevated: #FFFFFF
--surface-sunken: #F7F7F5

--ink:            #0A0A0A
--ink-muted:      #6B6B6B
--ink-subtle:     #A3A3A3

--hairline:       #EAEAEA
--hairline-strong:#D4D4D4

Warm / Cream (Editorial, Soft)

--surface:        #FAF6F0
--surface-elevated: #FFFFFF
--surface-sunken: #F0EBE3

--ink:            #1A1714
--ink-muted:      #6B5E51
--ink-subtle:     #9C8E7E

--hairline:       #E5DDD0
--hairline-strong:#D4C9B6

Deep / Ink (Technical, Brutalist, Editorial)

--surface:        #0E0E0E
--surface-elevated: #161616
--surface-sunken: #050505

--ink:            #F5F5F5
--ink-muted:      #A3A3A3
--ink-subtle:     #6B6B6B

--hairline:       #262626
--hairline-strong:#3D3D3D

Cold / Stone (Swiss, Technical)

--surface:        #F4F4F2
--surface-elevated: #FFFFFF
--surface-sunken: #ECECEA

--ink:            #1A1A1A
--ink-muted:      #595959
--ink-subtle:     #8C8C8C

--hairline:       #DCDCD8
--hairline-strong:#C2C2BD

True Black (Brutalist, Manifestos)

--surface:        #000000
--surface-elevated: #0A0A0A
--surface-sunken: #000000

--ink:            #FFFFFF
--ink-muted:      #B3B3B3
--ink-subtle:     #808080

--hairline:       #1F1F1F
--hairline-strong:#404040

Accent Library

Pick ONE. Use it on 510% of pixels max. If you find yourself using it everywhere, it's not an accent — it's a brand color that needs a different neutral system.

Refined Minimal accents

  • Linear-style purple: #5E6AD2 (with #0A0A0A ink)
  • Stripe indigo: #635BFF
  • Mercury green: #1B4332
  • Cron red-orange: #E0533D
  • Vercel on white: no accent — pure black ink IS the accent

Editorial accents

  • Editorial red: #C8281C or #A91D1D
  • Newspaper yellow: #E6B800 (used as mark, not fill)
  • Ink blue: #1B3A5C

Swiss accents

  • Müller-Brockmann red: #E63946 or #D62828
  • Electric blue: #0066FF
  • Often no accent. Pure monochrome.

Brutalist accents

  • Hot pink: #FF3EA5
  • Hazard yellow: #FFE600
  • Toxic green: #39FF14
  • Often used in block shapes, not fine details

Soft / Warm accents

  • Terracotta: #C65D3A
  • Sage: #7A8471
  • Dusty blue: #5C7A8A
  • Mustard: #C99632
  • Plum: #6B3D5C

Technical accents

  • Terminal green: #00FF66 or #00CC66 (softer)
  • Amber: #FFB000
  • Cyan: #00C2FF
  • Hot pink (Vercel-style): #FF0080

Playful accents

  • Multi-hue palette — pick 34 working together:
    • Coral #FF6B6B + Mustard #FFC857 + Teal #3DCCC7 + Plum #5B5F97
    • Or simpler 2-color: Lime #C5E063 + Deep Navy #1A1A40

How to Use the Accent

The 510% rule

If the accent fills more than 10% of the page, it's no longer an accent. It's a brand background. Pick a different neutral system or reduce accent usage.

Where accents go

  • Primary CTA button (one per page)
  • Active nav item, current page marker
  • Links (or use ink color with underline)
  • Focus rings
  • Key data point in a statistic block
  • A small mark (a dot, a bar, a single character)
  • Selected state in a list
  • Logo

Where accents DON'T go

  • Hero background
  • Section backgrounds (full-bleed tints)
  • Every card border
  • Every icon
  • Multiple CTA buttons on the same page (pick the one that matters)
  • Body text (links are the exception)
  • Drop shadows (use ink, not accent)
  • Every heading

Contrast (WCAG)

Use Min ratio Aim for
Body text 4.5:1 (AA) 7:1 (AAA)
Large text (18px+ or 14px bold+) 3:1 (AA) 4.5:1+
UI components, icons 3:1 4.5:1+
Non-essential decorative none
Focus rings 3:1 vs adjacent visible

Tools: Stark (Figma plugin), WebAIM Contrast Checker, Polypane.

Rule of thumb:

  • Pure black #000 on pure white #FFF = 21:1
  • #0A0A0A on #FFFFFF = 19.4:1
  • #6B6B6B on #FFFFFF = 5.7:1 (acceptable for secondary text)
  • #A3A3A3 on #FFFFFF = 2.8:1 (only for placeholders, never for real text)
  • #5E6AD2 on #FFFFFF = 5.1:1 (acceptable as text or UI)

Dark Mode

Dark mode is not "invert the colors." Build it intentionally.

Principles

  • Don't use pure black #000 for surfaces. It creates harsh contrast against text. Use #0E0E0E or #121212 — there's a reason Material Design picked these.
  • Don't use pure white #FFF for text. Soften to #F5F5F5 or #EDEDED.
  • Reduce contrast slightly — text doesn't need to be 21:1 on dark. Aim for 12:1+ (more comfortable).
  • Accents usually brighten in dark mode. A #5E6AD2 purple becomes #7B85E6 or #8B95FF.
  • Shadows become subtle borders or glows. Dark UIs rarely use shadows; they use hairlines and elevation via lighter surfaces.

Token approach

:root {
  /* Light */
  --surface: #FFFFFF;
  --ink: #0A0A0A;
  /* ... */
}

[data-theme="dark"] {
  --surface: #0E0E0E;
  --ink: #F5F5F5;
  /* Don't redefine everything — only invert what needs inverting */
}

Dark mode anti-patterns

  • Pure black #000 background (harsh, increases eye strain)
  • Pure white #FFF text (vibrates against dark backgrounds)
  • Same accent as light mode (often too dark to read)
  • Drop shadows that were already wrong in light mode (now invisible)
  • Inverting images with CSS filter: invert() (breaks photos)

Gradients

Default: don't use them.

When gradients ARE appropriate

  • Hero text on dark backgrounds (subtle, low-contrast, mostly for atmosphere)
  • Loading states / skeleton screens
  • Data visualization (color scales)
  • Photo overlays (dark gradient over image for legibility)

When gradients are NOT appropriate

  • Hero backgrounds (the #1 AI slop signal)
  • CTA buttons
  • Section dividers
  • "Mesh gradient" backgrounds
  • Animated gradient backgrounds
  • Purple → pink → orange "sunset" effects
  • Multi-stop gradients on text

If you must use one

/* Subtle, dark, for atmosphere only */
background: linear-gradient(
  to bottom,
  rgba(0, 0, 0, 0) 0%,
  rgba(0, 0, 0, 0.4) 100%
);

/* Image overlay */
background: linear-gradient(
  180deg,
  rgba(0, 0, 0, 0.2) 0%,
  rgba(0, 0, 0, 0.8) 100%
);

Avoid: linear-gradient(135deg, #667eea 0%, #764ba2 100%) and all its cousins.


Color Anti-Patterns

Don't Do
#667eea → #764ba2 purple gradient hero White background, ink-black headline
Multiple accent colors competing One accent, used 510%
#999 gray for body text Use a tested muted ink (#6B6B6B+)
Random hex everywhere (#3B82F6 next to #1D4ED8) Token system, semantic names
Color-coded everything (red/yellow/green for non-state things) Restraint. State colors for state only.
Hard-coded brand colors in components Use --accent token
Inverting colors for dark mode Re-tune the palette, don't invert
Tint backgrounds behind every paragraph White space, not tinted space
Box-shadows in accent color Ink-colored shadows, or no shadows
Stock-photo color overlays Let photos speak, use overlays only for legibility
4 brand colors in the logo, used equally One brand color + a system of neutrals