Skip to content

Latest commit

 

History

History
740 lines (578 loc) · 15.3 KB

File metadata and controls

740 lines (578 loc) · 15.3 KB

Project Lighthouse Style Guide

A minimal, light-mode design system with hand-drawn accents. Clean, professional, and easy on the eyes.


Design Philosophy

  • Light & Minimal — White backgrounds, neutral grays, no dark mode
  • Hand-crafted Details — Pencil/sketchy borders for personality
  • High Contrast — Near-black text on white for readability
  • Generous Spacing — Let content breathe

Color Palette

All colors use HSL for easy manipulation.

Core Colors

Token HSL Hex Usage
--background 0 0% 100% #FFFFFF Page background
--foreground 0 0% 3.9% #0A0A0A Primary text
--card 0 0% 100% #FFFFFF Card backgrounds
--card-foreground 0 0% 3.9% #0A0A0A Card text

Interactive Colors

Token HSL Hex Usage
--primary 0 0% 9% #171717 Buttons, active states
--primary-foreground 0 0% 98% #FAFAFA Text on primary
--secondary 0 0% 92.1% #EBEBEB Secondary buttons
--secondary-foreground 0 0% 9% #171717 Text on secondary

Muted & Accent

Token HSL Hex Usage
--muted 0 0% 96.1% #F5F5F5 Disabled backgrounds
--muted-foreground 0 0% 45.1% #737373 Secondary text
--accent 0 0% 96.1% #F5F5F5 Hover states
--accent-foreground 0 0% 9% #171717 Text on accent

Borders & Inputs

Token HSL Hex Usage
--border 0 0% 92.8% #EDEDED Standard borders
--input 0 0% 89.8% #E5E5E5 Input borders
--ring 0 0% 3.9% #0A0A0A Focus ring

Feedback Colors

Token HSL Hex Usage
--destructive 0 84.2% 60.2% #EF4444 Errors, delete actions
--destructive-foreground 0 0% 98% #FAFAFA Text on destructive

Chart Colors (Data Visualization)

Token HSL Hex
--chart-1 12 76% 61% #E97451
--chart-2 173 58% 39% #2A9D8F
--chart-3 197 37% 24% #264653
--chart-4 43 74% 66% #E9C46A
--chart-5 27 87% 67% #F4A261

Sidebar Colors

Token HSL Hex
--sidebar-background 0 0% 98% #FAFAFA
--sidebar-foreground 240 5.3% 26.1% #3F3F46
--sidebar-border 0 0% 91% #E8E8E8
--sidebar-accent 0 0% 94% #F0F0F0

Typography

Font Stack

/* primary ui font */
--font-sans: 'Inter', ui-sans-serif, system-ui, sans-serif;

/* code & monospace */
--font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, monospace;

/* decorative/display (optional) */
--font-display: 'Fredericka the Great', cursive;

Type Scale

Purpose Size Weight Class
Body 16px 400 text-base
Small text 14px 400 text-sm
Labels 12px 500 text-xs font-medium
Button 14px 500 text-sm font-medium
Heading 1 36px 700 text-4xl font-bold
Heading 2 30px 600 text-3xl font-semibold
Heading 3 24px 600 text-2xl font-semibold
Code 15px 400 font-mono

Line Heights

  • Body text: 1.5 (default)
  • Headings: 1.2
  • Blockquotes: 1.8

Border & Radius

Border Radius Scale

--radius: 0.5rem;                        /* 8px - base */
--radius-lg: var(--radius);              /* 8px - cards, modals */
--radius-md: calc(var(--radius) - 2px);  /* 6px - buttons, inputs */
--radius-sm: calc(var(--radius) - 4px);  /* 4px - badges, chips */

Border Styles

Style Width Color Usage
Default 1px var(--border) Cards, containers
Input 1px var(--input) Form fields
Focus ring 3px var(--ring) at 50% Focus states
Pencil 1-2px #1b1b18 Hand-drawn effect
Pencil light 1px #c4c0b8 Subtle sketchy

Shadows

Minimal shadows for subtle depth:

/* extra small - buttons, inputs */
shadow-xs: 0 1px 2px rgb(0 0 0 / 0.05);

/* small - cards, dropdowns */
shadow-sm: 0 1px 3px rgb(0 0 0 / 0.1), 0 1px 2px rgb(0 0 0 / 0.06);

Spacing

Using 4px base unit (Tailwind default):

Token Value Common Use
1 4px Tight gaps
2 8px Button padding, icon gaps
3 12px Input padding
4 16px Standard padding
6 24px Card padding, section gaps
8 32px Section spacing
12 48px Large section spacing

Component Spacing Patterns

Component Pattern
Button px-4 py-2 (16px/8px)
Button (sm) px-3 py-1.5 (12px/6px)
Input px-3 py-2 (12px/8px)
Card p-6 (24px)
Badge px-2 py-0.5 (8px/2px)
Alert px-4 py-3 (16px/12px)

Components

Button Variants

/* default - dark bg */
.btn-default {
  background: var(--primary);
  color: var(--primary-foreground);
  shadow: shadow-xs;
}

/* outline - bordered */
.btn-outline {
  background: var(--background);
  border: 1px solid var(--border);
  shadow: shadow-xs;
}
.btn-outline:hover {
  background: var(--accent);
}

/* secondary - light bg */
.btn-secondary {
  background: var(--secondary);
  color: var(--secondary-foreground);
}

/* ghost - no bg */
.btn-ghost {
  background: transparent;
}
.btn-ghost:hover {
  background: var(--accent);
}

/* destructive - red */
.btn-destructive {
  background: var(--destructive);
  color: var(--destructive-foreground);
}

Button Sizes

Size Height Padding Icon size
sm 32px px-3 16px
default 36px px-4 py-2 18px
lg 40px px-6 20px
icon 36px square 18px

Input/Textarea

.input {
  height: 36px;
  padding: 4px 12px;
  border: 1px solid var(--input);
  border-radius: var(--radius-md);
  background: transparent;
  font-size: 16px;
  box-shadow: shadow-xs;
}

.input:focus {
  border-color: var(--ring);
  box-shadow: 0 0 0 3px hsl(var(--ring) / 0.5);
}

.input:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.input[aria-invalid="true"] {
  border-color: var(--destructive);
  box-shadow: 0 0 0 3px hsl(var(--destructive) / 0.2);
}

Card

.card {
  background: var(--card);
  color: var(--card-foreground);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 24px;
  box-shadow: shadow-sm;
}

Badge

.badge {
  font-size: 12px;
  font-weight: 500;
  padding: 2px 8px;
  border-radius: var(--radius-md);
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

/* variants */
.badge-default { background: var(--primary); color: var(--primary-foreground); }
.badge-secondary { background: var(--secondary); color: var(--secondary-foreground); }
.badge-outline { border: 1px solid var(--border); background: transparent; }
.badge-destructive { background: var(--destructive); color: var(--destructive-foreground); }

Hand-Drawn / Pencil Effect

The signature aesthetic detail. Uses SVG filters for wavy, organic lines.

SVG Filter (add to HTML)

<svg style="position: absolute; width: 0; height: 0;">
  <filter id="pencil-filter" x="-20%" y="-20%" width="140%" height="140%">
    <feTurbulence type="fractalNoise" baseFrequency="0.03" numOctaves="3" result="noise"/>
    <feDisplacementMap in="SourceGraphic" in2="noise" scale="2" xChannelSelector="R" yChannelSelector="G"/>
  </filter>
</svg>

CSS Classes

.border-pencil {
  position: relative;
}

.border-pencil::after {
  content: '';
  position: absolute;
  inset: 0;
  border: 1px solid #1b1b18;
  border-radius: inherit;
  pointer-events: none;
  filter: url(#pencil-filter);
}

.border-pencil-light::after {
  border-color: #c4c0b8;
}

/* hover variant */
.hover-border-pencil::after {
  opacity: 0;
  transition: opacity 200ms;
}
.hover-border-pencil:hover::after {
  opacity: 1;
}

Pencil Colors

Name Hex Usage
Dark pencil #1b1b18 Standard sketchy borders
Light pencil #c4c0b8 Subtle, secondary elements

Background Patterns

Dotted Background

.dotted-bg {
  background-image: radial-gradient(circle, white 1px, transparent 1px);
  background-size: 16px 16px;
}

Subtle Gray Overlay

.subtle-gray-bg {
  background: linear-gradient(
    rgb(243 244 246 / 0.4),
    rgb(243 244 246 / 0.4)
  ), white;
}

Focus & Accessibility

Focus Ring

/* standard focus */
:focus-visible {
  outline: none;
  border-color: var(--ring);
  box-shadow: 0 0 0 3px hsl(var(--ring) / 0.5);
}

/* destructive/error focus */
[aria-invalid="true"]:focus-visible {
  border-color: var(--destructive);
  box-shadow: 0 0 0 3px hsl(var(--destructive) / 0.2);
}

Disabled States

:disabled,
[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
  pointer-events: none;
}

Animation

Keyframes

/* typing indicator */
@keyframes typing {
  0%, 100% { opacity: 0.3; }
  50% { opacity: 1; }
}

/* slow spin (loading) */
@keyframes spin-slow {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

/* network pulse */
@keyframes network {
  0%, 100% { transform: scale(1); opacity: 0.5; }
  50% { transform: scale(1.1); opacity: 1; }
}

Transitions

/* color transitions */
transition: color 200ms ease-out,
            background-color 200ms ease-out,
            border-color 200ms ease-out;

/* focus transitions */
transition: color 200ms,
            box-shadow 200ms;

/* layout transitions (sidebar) */
transition: left 200ms,
            right 200ms,
            width 200ms;

Responsive Breakpoints

sm:  640px   /* mobile landscape */
md:  768px   /* tablet */
lg:  1024px  /* desktop */
xl:  1280px  /* large desktop */
2xl: 1536px  /* extra large */

Common Patterns

/* hide on mobile, show on desktop */
.desktop-only { display: none; }
@media (min-width: 1024px) {
  .desktop-only { display: flex; }
}

/* sidebar visibility */
.sidebar { display: none; }
@media (min-width: 768px) {
  .sidebar { display: block; }
}

/* container max-width */
.container {
  width: 100%;
  max-width: 1280px;
  margin: 0 auto;
  padding: 0 16px;
}
@media (min-width: 640px) {
  .container { padding: 0 24px; }
}

Code Block Styling

pre, code {
  font-family: var(--font-mono);
  font-size: 15px;
}

pre {
  background: #f8f7f7;
  border-radius: 6px;
  padding: 16px;
  overflow-x: auto;
}

code {
  background: var(--muted);
  padding: 2px 6px;
  border-radius: 4px;
}

/* code inside pre shouldn't have extra styling */
pre code {
  background: none;
  padding: 0;
}

Table Styling

table {
  width: 100%;
  border-collapse: collapse;
}

th {
  text-align: left;
  font-weight: 600;
  padding: 12px;
  border-bottom: 2px solid #1b1b18;
  background: #f9f8f4;
}

td {
  padding: 12px;
  border-bottom: 1px solid #1b1b18;
}

tr:nth-child(even) {
  background: #fefefe;
}

tr:hover {
  background: #f9f8f4;
}

Blockquote

blockquote {
  border-left: 3px solid #5a5a52;
  padding: 24px 32px;
  font-family: Georgia, 'Times New Roman', serif;
  font-style: italic;
  font-size: 1.15rem;
  line-height: 1.8;
  color: #2d2d28;
  filter: url(#pencil-filter);
}

Quick Reference: CSS Custom Properties

:root {
  /* colors */
  --background: 0 0% 100%;
  --foreground: 0 0% 3.9%;
  --card: 0 0% 100%;
  --card-foreground: 0 0% 3.9%;
  --primary: 0 0% 9%;
  --primary-foreground: 0 0% 98%;
  --secondary: 0 0% 92.1%;
  --secondary-foreground: 0 0% 9%;
  --muted: 0 0% 96.1%;
  --muted-foreground: 0 0% 45.1%;
  --accent: 0 0% 96.1%;
  --accent-foreground: 0 0% 9%;
  --destructive: 0 84.2% 60.2%;
  --destructive-foreground: 0 0% 98%;
  --border: 0 0% 92.8%;
  --input: 0 0% 89.8%;
  --ring: 0 0% 3.9%;

  /* radius */
  --radius: 0.5rem;

  /* sidebar */
  --sidebar-background: 0 0% 98%;
  --sidebar-foreground: 240 5.3% 26.1%;
  --sidebar-border: 0 0% 91%;
  --sidebar-accent: 0 0% 94%;
  --sidebar-ring: 217.2 91.2% 59.8%;
}

Data Display Principles

Progressive Disclosure

Start with essential information. Allow users to drill deeper on demand.

Level What to Show Example
1 Name, status, key metric Pod: nginx-abc123 Running
2 + namespace, node, IP + production, node-1, 10.244.0.15
3 + containers, ports, resources + container details, resource requests
4+ + env vars, mounts, probes, events Full specification

Rules:

  • List views show Level 1-2
  • Detail views start at Level 2-3
  • Expandable sections for Level 4+
  • Never overwhelm; let users pull information

Consistent Field Ordering

Fields appear in the same position regardless of whether they have values.

Port hierarchy example:

Port        →  80
NodePort    →  30080
TargetPort  →  8080
ContainerPort → 8080

If NodePort is not defined:

Port        →  80
NodePort    →  —          (muted, placeholder)
TargetPort  →  8080
ContainerPort → 8080

General field order:

  1. Identifiers (name, uid, namespace)
  2. Status/phase
  3. Network (IP, ports, DNS)
  4. Resources (CPU, memory)
  5. Relationships (node, owner, selectors)
  6. Timestamps (created, started, last updated)
  7. Labels & annotations (always last, always sorted)

Placeholder States

When a field has no value but belongs in the hierarchy:

/* placeholder value */
.field-empty {
  color: var(--muted-foreground);
  font-style: normal;
}

Display: (em dash) or - for missing values, never hide the field.

Labels & Annotations

Always sorted alphabetically (ascending):

app=nginx
environment=production
tier=frontend
version=v1.2.0

Display rules:

  • Sort by key, ascending (a-z)
  • Show key=value format
  • Truncate long values with tooltip
  • Group system labels (kubernetes.io/*) separately if needed

Lists & Collections

Sorting defaults:

Collection Default Sort
Labels Key ascending
Containers Definition order
Conditions Type alphabetically
Events Timestamp descending (newest first)
Ports Port number ascending
Env vars Name ascending

Empty States

When a collection is empty:

  • Show the section header
  • Display: "No {items}" in muted text
  • Never hide the entire section
<h3>Labels</h3>
<p class="text-muted-foreground text-sm">No labels</p>

Hierarchy Depth Indicator

For nested resources, indicate depth visually:

Deployment: nginx-deployment
  └─ ReplicaSet: nginx-deployment-7fb96c846b
       └─ Pod: nginx-deployment-7fb96c846b-abc12
            └─ Container: nginx

Checklist for New Projects

  1. Set up CSS custom properties (colors, radius)
  2. Import Inter and JetBrains Mono fonts
  3. Add pencil filter SVG to HTML
  4. Configure Tailwind with custom theme
  5. Set up component variants (buttons, inputs, cards)
  6. Test focus states for accessibility
  7. Verify responsive breakpoints
  8. Implement consistent field ordering
  9. Add placeholder states for empty fields
  10. Sort labels/annotations alphabetically
  11. Define progressive disclosure levels per view

This style guide extracted from Project Lighthouse (projectlighthouse.io)