UMBRA/.claude/context/stylesheet.md
Kyle Pope cd868bd6ea Compact todo items to single-line rows, update stylesheet
- TodoItem: flatten to single-line row layout — checkbox, title,
  pills, date/reset info, actions all inline. Use hover:bg-card-elevated
  instead of bordered card with shadow.
- TodoList: tighten spacing from space-y-2 to space-y-0.5
- stylesheet.md: document list-view vs card-view convention —
  list pages use single-line rows, grid pages use multi-line cards

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 20:19:20 +08:00

13 KiB

UMBRA Design System & Stylesheet

This document defines the visual language for every page in UMBRA. All frontend work MUST conform to these patterns. Do not invent new colors, spacing scales, or component styles.


Visual Reference

The dashboard establishes the canonical look: a near-black canvas with thin-bordered cards, cyan accent highlights, the Sora/DM Sans type pairing, and subtle glow effects on interactive elements. Every page should feel like a natural extension of this dashboard.

Key visual characteristics:

  • Ultra-dark background (~#0a0a0a) with very subtle card elevation (#0d0d0d cards)
  • Thin 1px borders in dark gray (#262626) - never heavy or prominent
  • Accent color (default cyan) used sparingly: active nav, stat icons, today highlights, hover glows
  • High-contrast white text on dark, with muted gray (#a3a3a3) for secondary content
  • Cards have a gentle hover glow (shadow-accent/5) - not dramatic, just a hint of life
  • Clean data-dense layouts with compact spacing - no wasted space
  • Type badges and priority pills use color-coded backgrounds at 10% opacity (e.g. bg-blue-500/10 text-blue-400)

1. Color Tokens (CSS Custom Properties)

All colors use HSL format via CSS variables. Never hardcode hex values.

Surface Colors

Token HSL Approx Hex Usage
--background 0 0% 3.9% #0a0a0a Page background
--card 0 0% 5% #0d0d0d Card/panel surfaces
--card-elevated 0 0% 7% #121212 Hover states, elevated surfaces
--secondary 0 0% 10% #1a1a1a Secondary backgrounds, muted surfaces
--muted 0 0% 10% #1a1a1a Disabled/muted backgrounds

Text Colors

Token HSL Approx Hex Usage
--foreground 0 0% 98% #fafafa Primary text
--muted-foreground 0 0% 63.9% #a3a3a3 Secondary/subtle text

Border & Input

Token HSL Approx Hex Usage
--border 0 0% 14.9% #262626 All borders, dividers
--input 0 0% 14.9% #262626 Input borders

Semantic Colors

Token HSL Usage
--destructive 0 62.8% 30.6% Delete actions, errors
--primary / --accent-color / --ring Dynamic (accent HSL) Primary actions, focus rings

Accent System (Dynamic)

The accent is composed of three root variables set at runtime by useTheme:

  • --accent-h (hue)
  • --accent-s (saturation)
  • --accent-l (lightness)

These feed into --primary, --ring, and --accent-color.

Presets:

Name H S L Approx Color
cyan (default) 187 85.7% 53.3% Teal-cyan
blue 217 91.2% 59.8% Bright blue
purple 258 89.5% 66.3% Violet
orange 21 94.6% 53.3% Warm orange
green 142 70.6% 45.3% Emerald

Semantic Color Assignments (Fixed per feature)

These are NOT theme-dependent. They provide visual consistency for item types:

Feature Text Background Usage
Todos text-blue-400 bg-blue-500/10 Todo badges, type indicators
Events text-purple-400 bg-purple-500/10 Event badges, calendar items
Reminders text-orange-400 bg-orange-500/10 Reminder badges
Projects text-blue-400 bg-blue-500/10 Project counts
In Progress text-purple-400 bg-purple-500/10 Status indicators
Open Todos text-teal-400 bg-teal-500/10 Stat cards
Weather text-amber-400 bg-amber-500/10 Weather widget
High priority text-red-400 bg-red-500/10 Priority pills
Medium priority text-yellow-400 bg-yellow-500/10 Priority pills
Low priority text-green-400 bg-green-500/10 Priority pills

2. Typography

Font Families

  • Headings: Sora (font-heading) — all h1-h6, card titles, stat values, logo
  • Body: DM Sans (font-body) — everything else

Type Scale (as used)

Class Usage
text-[9px] Micro labels (priority badges, type tags)
text-[10px] tracking-wider uppercase Stat labels
text-[11px] Small metadata
text-xs Timestamps, secondary metadata
text-sm Body text, list items, form inputs, nav items
text-lg font-semibold Card titles (with font-heading)
text-xl font-bold tabular-nums Stat values (with font-heading)
text-3xl font-bold tracking-tight Page greeting/hero (with font-heading)

Font Rendering

font-feature-settings: "rlig" 1, "calt" 1;
-webkit-font-smoothing: antialiased;

3. Spacing & Layout

Border Radius

Token Value Usage
rounded-lg 0.5rem (8px) Cards, panels
rounded-md ~6px Buttons, inputs
rounded-sm ~4px Small elements
rounded-full Pill Badges, dots, icon containers

Page Layout

App Shell: flex h-screen overflow-hidden bg-background
├── Sidebar: w-64 (expanded) / w-16 (collapsed), border-r, bg-card
│   transition-all duration-300
└── Content: flex-1 flex flex-col overflow-hidden
    ├── MobileHeader: md:hidden, h-14, border-b, bg-card
    └── <main>: flex-1 overflow-y-auto
        └── Page content: px-6 py-6

Grid Patterns

Pattern Classes Usage
Stat row grid gap-2.5 grid-cols-2 lg:grid-cols-4 Dashboard stats
Main + sidebar grid gap-5 lg:grid-cols-5lg:col-span-3 + lg:col-span-2 Dashboard layout
Card grid grid gap-4 md:grid-cols-2 lg:grid-cols-3 List pages (people, locations, projects)

Standard Spacing

  • Page padding: px-6 py-6
  • Card padding: p-5 (header), p-5 pt-0 (content/footer)
  • Card gap in grid: gap-4 to gap-5
  • List row padding: py-1.5 px-2
  • Section gap: space-y-4 to space-y-6

4. Component Patterns

Card

Base:     rounded-lg border bg-card text-card-foreground shadow-sm
Hover:    hover:shadow-lg hover:shadow-accent/5 hover:border-accent/20
Motion:   transition-all duration-200
Header:   flex flex-col space-y-1.5 p-5
Title:    font-heading text-lg font-semibold leading-none tracking-tight
Content:  p-5 pt-0
Footer:   flex items-center p-5 pt-0

Button (CVA variants)

Base:     inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium
          transition-colors focus-visible:ring-2 focus-visible:ring-ring
Variants:
  default:     bg-accent text-accent-foreground hover:bg-accent/90
  destructive: bg-destructive text-destructive-foreground hover:bg-destructive/90
  outline:     border border-input bg-background hover:bg-accent/10 hover:text-accent
  secondary:   bg-secondary text-secondary-foreground hover:bg-secondary/80
  ghost:       hover:bg-accent/10 hover:text-accent
  link:        text-accent underline-offset-4 hover:underline
Sizes:
  default: h-10 px-4 py-2
  sm:      h-9 px-3
  lg:      h-11 px-8
  icon:    h-10 w-10

Badge

Base:     inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold
Variants:
  default:     border-transparent bg-accent text-accent-foreground
  secondary:   border-transparent bg-secondary text-secondary-foreground
  destructive: border-transparent bg-destructive text-destructive-foreground
  outline:     text-foreground

Input / Select / Textarea

h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm
placeholder:text-muted-foreground
focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2
disabled:cursor-not-allowed disabled:opacity-50

Dialog

Overlay:  fixed inset-0 bg-background/80 backdrop-blur-sm
Content:  border bg-card p-6 shadow-lg rounded-lg max-w-xl
Header:   flex flex-col space-y-1.5
Title:    text-lg font-semibold leading-none tracking-tight
Footer:   flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2
Close:    absolute right-4 top-4, X icon h-4 w-4

Empty State

Container: flex flex-col items-center justify-center py-16 px-4
Icon:      rounded-full bg-muted p-4 mb-4, icon h-8 w-8 text-muted-foreground
Title:     text-lg font-semibold mb-1
Desc:      text-sm text-muted-foreground text-center max-w-sm mb-4
Action:    <Button> with Plus icon

Skeleton

Base: animate-pulse rounded-md bg-muted

5. Widget & Data Patterns

Stat Card

Container: Card with bg-gradient-to-br from-accent/[0.03] to-transparent
Icon:      p-1.5 rounded-md bg-{color}/10
Label:     text-[10px] tracking-wider uppercase text-muted-foreground
Value:     font-heading text-xl font-bold tabular-nums

List Row (full-page lists: todos, reminders, etc.)

Container:  space-y-0.5 (tight stacking, no card borders)
Row:        flex items-center gap-3 px-3 py-2 rounded-md
            hover:bg-card-elevated transition-colors duration-150
Layout:     Everything on ONE line. Left-to-right:
            [interactive control] [title truncate flex-1] [pills/badges] [metadata] [actions]
Title:      text-sm font-medium truncate flex-1 min-w-0
Metadata:   text-[11px] shrink-0, right-aligned before actions
Actions:    ghost icon buttons h-7 w-7, last in row

List view vs card view: If a page shows items as a list (todos, upcoming), use single-line rows with hover:bg-card-elevated — no borders, no shadow, no multi-line content. If a page shows items as a grid of cards (projects, people, locations), use the Card component with p-5, multi-line content, and hover:shadow-lg hover:shadow-accent/5.

Widget List Row (dashboard widgets — more compact)

flex items-center gap-2 py-1.5 px-2 rounded-md
hover:bg-card-elevated transition-colors duration-150

Section Header (widget title)

Icon wrapped in p-1.5 rounded-md bg-{color}/10
alongside CardTitle
"View all" or count label: text-xs text-muted-foreground

Priority Pills

text-[9px] px-1.5 py-0.5 rounded-full font-medium
High:   bg-red-500/20 text-red-400
Medium: bg-yellow-500/20 text-yellow-400
Low:    bg-green-500/20 text-green-400

Type Tags

text-[9px] px-1.5 py-0.5 rounded font-medium uppercase tracking-wide
Todo:     bg-blue-500/15 text-blue-400
Event:    bg-purple-500/15 text-purple-400
Reminder: bg-orange-500/15 text-orange-400

Week Timeline (today highlight)

bg-accent/10 border border-accent/30 rounded-lg
shadow-[0_0_12px_hsl(var(--accent-color)/0.15)]

6. Navigation

Base:     flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium
          transition-all duration-200 border-l-2
Active:   bg-accent/15 text-accent border-accent
Inactive: text-muted-foreground hover:bg-accent/10 hover:text-accent border-transparent
Icon:     h-5 w-5 shrink-0
font-heading text-xl font-bold tracking-tight text-accent

Logout

hover:bg-destructive/10 hover:text-destructive

7. Animations & Transitions

Keyframes

Name Effect Duration Easing
fade-in opacity 0 → 1 300ms ease-out
slide-up opacity 0→1 + Y(8px→0) 400ms ease-out

Staggered Entry (dashboard sections)

animationDelay: '50ms' / '100ms' / '150ms'
animationFillMode: 'backwards'

Standard Transitions

Usage Classes
Interactive elements transition-all duration-200
Color changes transition-colors duration-150
Sidebar collapse transition-all duration-300

8. Scrollbar

scrollbar-width: thin;
scrollbar-color: hsl(0 0% 20%) transparent;  /* #333 thumb on transparent */
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-thumb:hover { background: hsl(var(--accent-color) / 0.5); }

9. Design Principles

  1. Dark-first: Everything is designed for the dark palette. There is no light mode.
  2. Accent as highlight, not flood: The accent color draws attention to interactive/important elements. It should never dominate a section.
  3. 10% opacity backgrounds: Feature colors (blue, purple, orange, etc.) are always at 10-20% opacity for backgrounds, with 400-level text on top. Never use full-saturation backgrounds.
  4. Data density: Compact rows, small text for metadata, efficient use of space. This is a productivity tool, not a marketing page.
  5. Consistent card pattern: Every distinct content section is a Card. Cards have uniform padding (p-5), title styling, and hover behavior.
  6. Typography hierarchy: Sora for headings/numbers, DM Sans for body. This distinction creates visual rhythm without extra decoration.
  7. Subtle motion: Hover glows, fade-ins, and slide-ups. No bouncing, spinning, or attention-grabbing animations.
  8. Icon consistency: All icons from Lucide React, sized at h-5 w-5 for nav/actions, h-4 w-4 for inline, h-8 w-8 for empty states.