Articles, notes, and bookmarks were all sharing amber, which defeats the purpose of per-type color identity. New complete color map (7 unique colors): - Articles: indigo (long-form writing) - Notes: teal (short posts) - Bookmarks: amber (saved links) - Likes: red (heart) - Replies: sky (conversation) - Reposts: green (sharing) - Photos: purple (visual) Updated across collection pages, blog.njk mixed view, recent-posts widget (now shows type-specific icons and colors for all 7 types), and design system documentation. Confab-Link: http://localhost:8080/sessions/0ec83454-d346-4329-8aaf-6b12139bf596
16 KiB
Design System — rmendes.net
Palette
Surfaces: Warm stone — not yellow, not cold. The difference is felt, not seen.
| Token | Hex | Role |
|---|---|---|
| surface-50 | #faf8f5 |
Canvas (light) |
| surface-100 | #f4f2ee |
Cards, elevated surfaces (light) |
| surface-200 | #e8e5df |
Standard borders, dividers |
| surface-300 | #d5d0c8 |
Strong borders, input borders |
| surface-400 | #a09a90 |
Muted text, placeholders |
| surface-500 | #7a746a |
Secondary text |
| surface-600 | #5c5750 |
Supporting text |
| surface-700 | #3f3b35 |
Dark mode borders |
| surface-800 | #2a2722 |
Cards, elevated surfaces (dark) |
| surface-900 | #1c1b19 |
Canvas (dark) |
| surface-950 | #0f0e0d |
Deepest dark |
Accent (Warm Amber): Default interactive color — links, CTAs, focus rings.
| Token | Hex | Usage |
|---|---|---|
| accent-400 | #fbbf24 |
Dark mode: links, hover |
| accent-500 | #f59e0b |
— |
| accent-600 | #d97706 |
Light mode: links, buttons |
| accent-700 | #b45309 |
Light mode: hover, pressed |
Domain Colors
Every post type and section has its own unique color identity. On collection pages, sparklines, card borders, icons, labels, hover states, and permalink links all use the domain color. No two post types share the same color.
Post Type Colors (each unique — no sharing)
| Post Type | Tailwind color | Light text | Dark text | Icon | Pages |
|---|---|---|---|---|---|
| Articles | indigo | indigo-600 | indigo-400 | document | /articles/ |
| Notes | teal | teal-600 | teal-400 | chat bubble | /notes/ |
| Bookmarks | amber | amber-600 | amber-400 | bookmark | /bookmarks/ |
| Likes | red | red-600 | red-400 | heart (filled) | /likes/ |
| Replies | sky | sky-600 | sky-400 | reply arrow | /replies/ |
| Reposts | green | green-600 | green-400 | refresh arrows | /reposts/ |
| Photos | purple | purple-600 | purple-400 | camera | /photos/ |
Each color is applied consistently across: sparkline wrapper, card border-l, SVG icon, label text, title hover, and permalink link.
Section Colors (non-post-type pages)
| Section | Tailwind color | Light text | Dark text | Pages |
|---|---|---|---|---|
| Blog (mixed) | amber | amber-600 | amber-400 | /blog/ (sparkline only — individual cards use their post-type color) |
| Code | emerald | emerald-600 | emerald-400 | /github/, /github/starred/ |
| Music | purple | purple-600 | purple-400 | /funkwhale/, /listening/ |
| Video | red | red-600 | red-400 | /youtube/ |
| Reading | orange | orange-600 | orange-400 | /blogroll/, /podroll/, /readlater/ |
| Neutral | accent (amber) | — | — | / (home), /about/, /cv/, /slashes/, /search/, /changelog/, /404 |
Brand Colors (hardcoded hex — not domain colors)
These are third-party brand colors used in syndication badges and social widgets. Not part of the domain system.
| Brand | Hex | Where |
|---|---|---|
| Mastodon | #a730b8 |
Syndication badges, social-activity widget |
| Bluesky | #0085ff |
Syndication badges, social-activity widget |
#0a66c2 |
Syndication badges | |
| IndieNews | #ff5c00 |
Syndication badges |
| Mastodon alt | #6364ff |
Syndication badges |
Domain Prominence (medium)
On a domain page, these elements adopt the domain color:
- Page title — tinted text or accent underline
- Links —
text-[domain]-600 dark:text-[domain]-400 - Hover states —
hover:text-[domain]-700 dark:hover:text-[domain]-300 - Card borders on hover —
hover:border-[domain]-400 dark:hover:border-[domain]-600 - Post-type badges — domain-colored background/text
These stay neutral (accent or surface) regardless of domain:
- Header/navigation
- Sidebar widget containers
- Footer
- Global UI (search, theme toggle)
Depth
Subtle shadows. One consistent shadow level for elevated surfaces. Borders + shadow together.
| Element | Treatment |
|---|---|
| Cards, widgets | shadow-sm + border border-surface-200 dark:border-surface-700 |
| Avatars, album art | shadow-lg (depth gives images presence against flat surfaces) |
| Modals | shadow-xl (overlay needs clear elevation) |
| Hover on cards | No shadow change — border color shift only |
Gradients are allowed for:
- Now-playing cards (domain color tinted:
bg-gradient-to-br from-[color]-500/10) - YouTube hero/live cards
- Icon containers in reading pages (
from-[color]-400 to-[color]-600)
Gradients are NOT used for:
- Standard cards, widgets, or page backgrounds
Typography
| Role | Style | Usage |
|---|---|---|
| Page titles | Inter, text-2xl sm:text-3xl font-bold |
Main page headings |
| Section headings | Inter, text-xl sm:text-2xl font-bold |
Widget titles, section headers |
| Subheadings | Inter, text-lg font-semibold |
Card titles, list item titles |
| Body | Inter, text-sm or text-base |
Paragraphs, descriptions |
| Labels | Inter, font-medium or font-semibold |
Badges, nav items, metadata labels |
| Dates/timestamps | font-mono text-sm |
Every <time> element, stat numbers, version numbers |
| Code | font-mono |
Commit SHAs, code blocks, technical identifiers |
| Small text | text-xs |
Metadata, secondary info, captions |
Date treatment rule
Every rendered date (via dateDisplay or date() filter) gets font-mono. This adds technical texture throughout the site — like timestamps in a log.
Weight scale
| Weight | Class | Frequency | Usage |
|---|---|---|---|
| 400 | (default) | Body text | Paragraphs, descriptions |
| 500 | font-medium |
146x | Labels, metadata, nav items |
| 600 | font-semibold |
100x | Subheadings, emphasis |
| 700 | font-bold |
138x | Page titles, section headings |
Spacing
Base: 4px (Tailwind default rem scale).
Spacing scale (by frequency)
| Token | px | Frequency | Primary usage |
|---|---|---|---|
0.5 |
2px | 62x | Micro gaps (badge padding-y, icon margins) |
1 |
4px | 150x | Tight internal spacing |
1.5 |
6px | 45x | Button padding-y, small gaps |
2 |
8px | 350x+ | Standard small spacing (px, py, gap, m) |
3 |
12px | 180x | Standard medium spacing |
4 |
16px | 200x+ | Card padding, section gaps |
5 |
20px | 30x | Featured card padding |
6 |
24px | 80x | Section margins |
8 |
32px | 40x | Large section separation |
10 |
40px | 8x | Page-level vertical rhythm |
12 |
48px | 5x | Major section breaks |
Common spacing patterns
| Pattern | Classes | Where |
|---|---|---|
| Card padding | p-4 |
Standard cards, widgets |
| Compact padding | p-3 |
List items, tight cards |
| Featured padding | p-5 |
Hero cards, featured items |
| Tight list gap | gap-2 |
Inline elements, tag lists |
| Standard gap | gap-3 |
Card grids, form elements |
| Spacious gap | gap-4 |
Section-level grids |
| Section break | mb-6 to mb-8 |
Between page sections |
| Badge padding | px-2 py-0.5 |
Small badges, pills |
| Pill padding | px-3 py-1.5 |
Larger pills, filter buttons |
Border Radius
| Element | Radius | Frequency |
|---|---|---|
| Cards, inputs, buttons | rounded-lg |
154x (dominant) |
| Avatars, status dots, badges | rounded-full |
134x |
| Featured/hero cards | rounded-xl |
23x |
| Now-playing sections | rounded-xl sm:rounded-2xl |
2x |
| Audio players | rounded-md |
— |
Card Patterns
Five distinct card variants used across the site:
Standard card (.post-card)
p-5 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm
hover: border-[domain]-400 dark:border-[domain]-600
Used for: blog post listings, search results
Widget card (.widget)
p-4 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm
Used for: sidebar widgets, info panels
Compact list card
p-3 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm
Used for: list view items in news/podroll, compact listings
Featured card
p-5 sm:p-6 bg-gradient-to-br from-[color]-500/10 rounded-xl border border-surface-200 dark:border-surface-700 shadow-sm
Used for: now-playing, YouTube hero, featured items
Stat card
p-3 sm:p-4 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm text-center
Used for: statistics grids (GitHub, Funkwhale, Last.fm)
Button Patterns
Six button variants:
Primary action
px-4 py-2 bg-accent-600 hover:bg-accent-700 text-white rounded-lg font-medium
focus:ring-2 focus:ring-accent-500 transition-colors
Used for: form submits, main CTAs
Secondary action
px-3 py-1.5 bg-surface-100 dark:bg-surface-800 hover:bg-surface-200 dark:hover:bg-surface-700
border border-surface-200 dark:border-surface-700 rounded-lg text-sm font-medium
focus:ring-2 focus:ring-accent-500 transition-colors
Used for: filter toggles, view mode switches, secondary actions
Icon button
p-2 rounded-lg hover:bg-surface-200 dark:hover:bg-surface-700
focus:ring-2 focus:ring-accent-500 transition-colors
Used for: theme toggle, menu toggle, refresh buttons
Domain-colored button
px-3 py-1.5 bg-[domain]-600 hover:bg-[domain]-700 text-white rounded-lg text-sm font-medium
focus:ring-2 focus:ring-[domain]-500 transition-colors
Used for: domain-specific actions (e.g., orange "Load More" on podroll)
Link button
text-[domain]-600 dark:text-[domain]-400 hover:text-[domain]-700 dark:hover:text-[domain]-300
hover:underline font-medium transition-colors
Used for: inline actions, "View all" links
Pagination button
px-3 py-1 bg-surface-100 dark:bg-surface-800 hover:bg-surface-200 dark:hover:bg-surface-700
border border-surface-200 dark:border-surface-700 rounded-lg text-sm
focus:ring-2 focus:ring-accent-500 transition-colors
disabled:opacity-50 disabled:cursor-not-allowed
Used for: pagination controls
Badge/Pill Patterns
Four badge variants:
Post-type badge
px-2 py-0.5 text-xs font-medium rounded-full
bg-[domain]-100 dark:bg-[domain]-900/30 text-[domain]-700 dark:text-[domain]-300
Used for: post type indicators on cards
Category tag
px-2 py-0.5 text-xs bg-surface-100 dark:bg-surface-800
text-surface-600 dark:text-surface-400 rounded-full
hover:bg-surface-200 dark:hover:bg-surface-700 transition-colors
Used for: category tags, hashtags
Status badge
px-2 py-0.5 text-xs font-medium rounded-full
bg-emerald-100 dark:bg-emerald-900/30 text-emerald-700 dark:text-emerald-300
Variants: emerald (active/success), amber (warning), red (error) Used for: status indicators, sync state
Syndication badge
px-2 py-0.5 text-xs font-medium rounded-full text-white
bg-[brand-hex]
Used for: Mastodon/Bluesky/LinkedIn syndication indicators
Layout Patterns
Page layouts
| Layout | Classes | Usage |
|---|---|---|
| Full-width | max-w-7xl mx-auto px-4 sm:px-6 |
Page container |
| With sidebar | .layout-with-sidebar = grid grid-cols-1 lg:grid-cols-[1fr_320px] gap-6 lg:gap-8 |
Blog, post pages |
| Content area | .main-content = min-w-0 (prevents overflow in grid) |
Main column |
| Sidebar | .sidebar = space-y-4 lg:space-y-6 |
Sidebar column |
| Centered narrow | max-w-3xl mx-auto |
About, CV pages |
Grid patterns
| Pattern | Classes | Usage |
|---|---|---|
| Stats grid | grid grid-cols-2 sm:grid-cols-4 gap-3 |
Statistics panels |
| Card grid | grid grid-cols-1 sm:grid-cols-2 gap-4 |
Card view mode |
| Post list | space-y-4 or space-y-3 |
List view mode |
| Widget stack | space-y-4 lg:space-y-6 |
Sidebar widgets |
Responsive breakpoints
| Breakpoint | px | Frequency | Purpose |
|---|---|---|---|
sm: |
640px | 170x+ | Primary responsive step (dominant) |
md: |
768px | 19x | Tablet-specific adjustments |
lg: |
1024px | 6x | Sidebar layout switch |
Mobile-first: Base styles are mobile. sm: is the primary breakpoint for responsive changes. Most layouts switch from stacked to side-by-side at sm:.
Interaction States
Every interactive element needs:
- hover: color shift (
transition-colors— dominant at 131x) - focus: visible ring (
focus:ring-2 focus:ring-accent-500or domain equivalent) - active: not currently implemented — add where it matters (buttons)
Hover patterns
| Element | Hover treatment |
|---|---|
| Text links | hover:underline (163x — dominant link hover) |
| Card borders | hover:border-[domain]-400 dark:hover:border-[domain]-600 |
| Buttons (filled) | Background darken (hover:bg-[color]-700) |
| Buttons (ghost) | hover:bg-surface-200 dark:hover:bg-surface-700 |
| Nav items | hover:text-surface-900 dark:hover:text-surface-100 |
Focus pattern
All interactive elements: focus:ring-2 focus:ring-[domain]-500 rounded (or focus:ring-accent-500 on neutral pages).
Transitions
Default: transition-colors (131x). No duration override — uses Tailwind default (150ms).
Exceptions:
- Collapsible widgets:
transition-allfor height animation - Mobile menu:
transition-transformfor slide-in
Dark Mode
- Class-based:
darkMode: "class"— toggled via button in header - Surfaces invert: light canvas (
surface-50) -> dark canvas (surface-900) - Cards:
surface-100->surface-800 - Domain colors shift to 400-weight (brighter) in dark mode
- Borders:
surface-200->surface-700 - Shadows remain
shadow-sm(less visible but still present for subtle lift)
Dark mode pairs (reference)
| Light | Dark |
|---|---|
bg-surface-50 |
dark:bg-surface-900 (canvas) |
bg-surface-100 |
dark:bg-surface-800 (cards) |
bg-surface-200 |
dark:bg-surface-700 (hover bg) |
border-surface-200 |
dark:border-surface-700 |
text-surface-900 |
dark:text-surface-100 (primary text) |
text-surface-600 |
dark:text-surface-400 (secondary text) |
text-[domain]-600 |
dark:text-[domain]-400 (domain color) |
bg-[domain]-100 |
dark:bg-[domain]-900/30 (badge bg) |
CSS Component Classes
Reusable utility classes defined in css/tailwind.css:
| Class | Definition | Usage |
|---|---|---|
.widget |
p-4 bg-surface-50 rounded-lg border shadow-sm + dark |
Sidebar widgets |
.widget-title |
text-lg font-semibold |
Widget headings |
.widget-header |
flex items-center justify-between mb-3 |
Widget header row |
.widget-collapsible |
Alpine.js collapsible wrapper | Expandable widgets |
.post-card |
p-5 bg-surface-50 rounded-lg border shadow-sm + dark |
Post listing cards |
.post-list |
space-y-4 |
Post list container |
.layout-with-sidebar |
grid grid-cols-1 lg:grid-cols-[1fr_320px] gap-6 lg:gap-8 |
Two-column layout |
.main-content |
min-w-0 |
Main column (prevents grid overflow) |
.sidebar |
space-y-4 lg:space-y-6 |
Sidebar stack |
.share-post-btn |
Blue share button | Post sharing |
.save-later-btn |
Accent save button | Read-later action |
What Needs Implementation
Audit findings — remaining gaps between this system and the current code:
Domain colors on section pages— ✅ Done: all 7 post-type collections + blog.njk mixed view + recent-posts widget use per-type colors- Active states — add to buttons where appropriate
- Consistent card hover — some older templates use
hover:border-surface-400instead of domain-colored border hover