# Theming Standard — danix.xyz Redesign

**Version:** 1.0  
**Last Updated:** 2026-04-08  
**Audience:** Developers, theme builders, Hugo template authors

---

## 1. Overview

### Purpose

This document is the **source of truth** for all theming decisions across danix.xyz. It defines the visual language, design patterns, and implementation guidelines that ensure consistency across all views, components, and future pages of the redesigned site.

### Scope

This standard covers:
- **Hugo theme development** — CSS, layouts, and component structure
- **All views** — Existing (articles, About, etc.) and future (404, etc.)
- **Both color modes** — Dark (default) and light theme variants
- **All article types** — Tech, Life, Quote, Link, Photo with color-coded identity

### Design Philosophy

The danix.xyz redesign is built on three pillars, of equal priority:

1. **Accessibility** — WCAG AA compliance minimum. Every component must be keyboard navigable, screen-reader friendly, and have sufficient color contrast.
2. **Performance** — Pages load fast and stay responsive. CSS custom properties are optimized to avoid runtime recalculations. Animations respect `prefers-reduced-motion`.
3. **Consistency** — Visual consistency is key in maintaining a defined brand identity and must be pursued on all views of the site.

### Evolution & Continuous Improvement

This standard evolved from various iterations and mockups built in 2026-04. It reflects real-world design decisions tested across responsive breakpoints and color modes. **The spec is not final**—it remains open to improvement through implementation feedback and user testing.

### Dual-Theme System

Dark mode and light mode are **first-class citizens**, not afterthoughts:
- Dark mode is the default (aligns with "hacker aesthetic" branding)
- Light mode has equivalent color contrasts and visual hierarchy
- Transitions between themes are instant (no flickering)
- Theme preference is persisted via `localStorage`
- CSS media query (`prefers-color-scheme`) provides no-JS fallback

### CSS Custom Properties Architecture

All colors, typography, and spacing use **CSS custom properties** (variables):
- Single source of truth: `:root` defines dark mode base
- `html.theme-light` overrides for light mode
- `@media (prefers-color-scheme: light)` provides no-JS fallback
- No hard-coded color values in component CSS
- Easy theme extension: add new property, use in all relevant selectors

### Mobile-First Responsive Design

The design system is built mobile-first:
- Base styles target mobile (320px+)
- Breakpoints expand layout: 768px (tablet), 1060px (desktop)
- All components work at all sizes without layout shift
- Typography scales responsively via `clamp()` or media queries

### Browser Support

Supported:
- Modern browsers: Chrome, Firefox, Safari (15+), Edge (all versions)
- Mobile browsers: iOS Safari (15+), Chrome Mobile, Firefox Mobile
- Graceful degradation for older browsers (fallback colors, readable without CSS variables)

Explicitly unsupported:
- Internet Explorer (all versions)
- Legacy browsers without CSS custom properties support

### No-JavaScript Fallback

All interactive features have CSS-only fallbacks:
- Theme toggle: `@media (prefers-color-scheme: light)` provides light mode without JS
- Responsive navigation: Media queries handle collapse/expand without hamburger menu JS
- Animations: CSS transitions work even if JS fails to load

### Single Source: Unified Color Palette

All article types, components, and views share one palette:
- **5 article types** with distinct, recognizable colors (Tech, Life, Quote, Link, Photo)
- **Colors are semantic**: `--accent`, `--border`, `--text`, not `--purple` or `--blue-300`
- **Every view must support all 5 article types** with consistent color identity
- **Type colors are never mixed**: A Quote is always green, never cyan or amber

### Typography Hierarchy

Three font families serve specific purposes:

| Font | Weight | Use Case |
|---|---|---|
| **Oxanium** | 700–800 | Display, headings, hero text, large titles |
| **IBM Plex Sans** | 300–600 | Body text, prose, descriptions, UI labels |
| **JetBrains Mono** | 400–700 | Monospace, code, terminal UI, metadata |

Typography reinforces visual hierarchy and brand voice (technical, approachable, premium).

### Article Type System

Five article types, each with:
- **Distinct color** in badges, borders, accents
- **Unique layout pattern** (quote vs. terminal vs. prose)
- **Recognizable at a glance** across all views (timeline, masonry, cards, detail pages)

Color mapping:

| Type | Dark Mode | Light Mode | Use |
|---|---|---|---|
| **Tech** | `#a855f7` (Purple) | `#7c3aed` (Purple) | Technical articles, tutorials |
| **Life** | `#f59e0b` (Amber) | `#d97706` (Amber) | Personal essays, life updates |
| **Quote** | `#00ff88` (Green) | `#008f5a` (Green) | Quotes, inspirational content |
| **Link** | `#38bdf8` (Cyan) | `#0284c7` (Cyan) | Bookmarks, external links |
| **Photo** | `#ec4899` (Pink) | `#be185d` (Pink) | Photo essays, galleries |

### Matrix Animation: Foundational Brand Element

The matrix rain effect is a core visual identity:
- Present on hero sections and behind article content
- Adapts opacity across color modes (dark: 13%, light: 18%)
- Uses canvas for performance
- Full viewport height, visible in side gutters
- Never interferes with text readability (semi-transparent, behind content)

### Accessibility Baseline

All components must meet **WCAG AA** minimum:
- Color contrast ≥ 4.5:1 for normal text, ≥ 3:1 for large text
- No color used alone to convey information (always pair with text or icon)
- Keyboard navigation: Tab, Shift+Tab, Enter, Space, Escape
- Screen readers: Semantic HTML, ARIA labels where needed
- Animations: Respect `prefers-reduced-motion` system setting
- Focus indicators: Always visible, never hidden

### Performance Baseline

Production pages must meet:
- **Initial load:** <3 seconds on 4G mobile
- **Interaction:** Respond to user input within 100ms
- **CSS custom properties:** Optimized to avoid layout thrashing
- **Animations:** Use GPU-accelerated transforms (not color or size changes)
- **Images:** Lazy-loaded, responsive sizes, WebP with fallback

---

## 2. Color System

### Palette Overview

The color system uses **semantic naming** (not color-based names) to support theme switching:
- **Base colors**: Background, surface, borders, text
- **Accent colors**: Primary and secondary interaction colors
- **Type colors**: Five article types with distinct identities
- **Utility colors**: Glows, shadows, semi-transparent overlays

All colors are defined as CSS custom properties in `:root` (dark mode base) with light mode overrides in `html.theme-light`.

### Dark Mode Base Palette

Dark mode is the default theme. All base colors are defined in `:root`:

```css
:root {
  /* Background & Surface */
  --bg:          #060b10;        /* Primary background (darkest) */
  --bg2:         #0c1520;        /* Secondary background */
  --surface:     #101e2d;        /* Card/container background */
  --border:      #182840;        /* Border color */
  
  /* Text & Legibility */
  --text:        #c4d6e8;        /* Primary text (light) */
  --text-dim:    #7a9bb8;        /* Secondary/dimmed text */
  --muted:       #304860;        /* Muted text, icons */
  
  /* Accent Colors */
  --accent:      #a855f7;        /* Purple — primary interaction, focus states */
  --accent2:     #00ff88;        /* Neon green — secondary, highlights, progress */
  --accent-glow: rgba(168, 85, 247, 0.12); /* Purple glow for shadows */
  
  /* Article Type Colors */
  --type-tech:   #a855f7;        /* Tech articles — purple */
  --type-life:   #f59e0b;        /* Life articles — amber */
  --type-quote:  #00ff88;        /* Quote articles — green */
  --type-link:   #38bdf8;        /* Link articles — cyan */
  --type-photo:  #ec4899;        /* Photo articles — pink */
}
```

**Rationale:**
- Dark navy background (`#060b10`) reduces eye strain in low-light environments
- Cyan text (`#c4d6e8`) has high contrast while maintaining "hacker aesthetic"
- Purple accent (`#a855f7`) is premium, technical, recognizable
- Neon green accent (`#00ff88`) provides vibrant secondary option for highlights and progress
- Article type colors are vibrant, distinct, and instantly recognizable

### Light Mode Palette

Light mode inverts the palette for high readability in bright environments. Applied via `html.theme-light`:

```css
html.theme-light {
  /* Background & Surface */
  --bg:          #f0f4f8;        /* Primary background (lightest) */
  --bg2:         #e2eaf4;        /* Secondary background */
  --surface:     #d4dff0;        /* Card/container background */
  --border:      #a8bdd8;        /* Border color */
  
  /* Text & Legibility */
  --text:        #0d1b2a;        /* Primary text (dark) */
  --text-dim:    #2e4a6a;        /* Secondary/dimmed text */
  --muted:       #6888a8;        /* Muted text, icons */
  
  /* Accent Colors */
  --accent:      #7c3aed;        /* Purple (darker for light bg) */
  --accent2:     #008f5a;        /* Green (darker for light bg) */
  --accent-glow: rgba(124, 58, 237, 0.1); /* Purple glow adjusted */
  
  /* Article Type Colors */
  --type-tech:   #7c3aed;        /* Tech — darker purple */
  --type-life:   #d97706;        /* Life — darker amber */
  --type-quote:  #008f5a;        /* Quote — darker green */
  --type-link:   #0284c7;        /* Link — darker cyan */
  --type-photo:  #be185d;        /* Photo — darker pink */
}
```

**Design notes:**
- All light mode colors are darker versions of dark mode (maintains hue, increases saturation)
- Contrast ratios remain ≥4.5:1 for WCAG AA compliance
- Article type colors are darker but maintain instant recognition
- Opacity values for glows/shadows are reduced (more transparent) since light backgrounds need less emphasis

### Article Type Colors: Complete Reference

| Type | Purpose | Dark Mode | Light Mode | Badge Example |
|---|---|---|---|---|
| **Tech** | Technical articles, tutorials, code | `#a855f7` | `#7c3aed` | Purple badge |
| **Life** | Personal essays, life updates | `#f59e0b` | `#d97706` | Amber badge |
| **Quote** | Quotes, inspirational content | `#00ff88` | `#008f5a` | Green badge |
| **Link** | Bookmarks, curated links | `#38bdf8` | `#0284c7` | Cyan badge |
| **Photo** | Photo essays, galleries | `#ec4899` | `#be185d` | Pink badge |

**Usage rules:**
- Type colors must appear in: badge background, top border of article card, type-specific accents
- Type colors should be consistent: A Quote is always green, never purple
- Type colors should be recognizable: Must maintain contrast with both dark and light backgrounds
- Every article view (timeline, masonry, detail page) must show type color prominently

### Semantic Color Usage

Colors are used semantically, not by visual appearance:

| Property | Use Case | Example |
|---|---|---|
| `--bg` | Page background, full-screen elements | Hero section, page body |
| `--bg2` | Secondary background, slightly raised | Navigation bar, section dividers |
| `--surface` | Cards, containers, elevated content | Article cards, modals, sidebar |
| `--border` | Dividers, outlines, subtle boundaries | Card borders, separators |
| `--text` | Primary readable content | Body text, headings, labels |
| `--text-dim` | Secondary content, less emphasis | Metadata, dates, bylines |
| `--muted` | Background text, icons | Disabled states, faint icons |
| `--accent` | Primary interaction, focus, highlights | Buttons, focus rings, links |
| `--accent2` | Secondary interaction, progress | Progress bars, highlights, secondary buttons |
| `--type-*` | Article-specific theming | Badges, borders, type-specific accents |

**Implementation pattern:**
```css
/* Good: semantic color naming */
.article-badge { background: var(--type-tech); }
.link-button { color: var(--accent2); }

/* Bad: hard-coded or color-named variables */
.article-badge { background: #a855f7; }        /* Hard-coded purple */
.link-button { color: var(--bright-green); }   /* Color-named, not semantic */
```

### Opacity & Transparency

Transparent overlays use rgba() with theme-aware opacity:

**Dark mode transparency:**
```css
/* Semi-transparent dark overlay (text over images) */
background: rgba(6, 11, 16, 0.65);

/* Dot grid background (subtle, not intrusive) */
background: radial-gradient(circle, rgba(168, 85, 247, 0.07) 1px, transparent 1px);

/* Glow effects (purple semi-transparent) */
box-shadow: 0 0 40px rgba(168, 85, 247, 0.12);

/* Accent glow */
--accent-glow: rgba(168, 85, 247, 0.12);
```

**Light mode transparency:**
```css
/* Semi-transparent light overlay (text over images) */
background: rgba(240, 244, 248, 0.7);

/* Dot grid background (lighter, less visible) */
background: radial-gradient(circle, rgba(124, 58, 237, 0.07) 1px, transparent 1px);

/* Glow effects (purple, reduced opacity for light background) */
box-shadow: 0 0 40px rgba(124, 58, 237, 0.08);

/* Adjusted accent glow */
--accent-glow: rgba(124, 58, 237, 0.1);
```

**Pattern:** Opacity values are lower in light mode (overlays are more subtle) than dark mode.

### Glows & Shadows

Color-matched shadows reinforce theme and provide visual hierarchy:

**Dark mode glows (purple-based):**
```css
/* Subtle glow on cards */
box-shadow: 0 0 40px rgba(168, 85, 247, 0.08);

/* Strong glow on focused/interactive elements */
box-shadow: 0 0 15px rgba(56, 189, 248, 0.3);

/* Inset shadow for depth */
box-shadow: inset 0 0 30px rgba(0, 0, 0, 0.4);
```

**Light mode glows (darker, adjusted opacity):**
```css
/* Subtle glow on cards */
box-shadow: 0 0 40px rgba(124, 58, 237, 0.06);

/* Strong glow on focused/interactive elements */
box-shadow: 0 0 8px rgba(124, 58, 237, 0.45);

/* Inset shadow for depth */
box-shadow: inset 0 0 30px rgba(0, 0, 0, 0.5);
```

**Guidelines:**
- Glows should match accent color (purple in dark mode, darker purple in light)
- Opacity is reduced in light mode (less visual "pop" needed)
- Glows are used sparingly, only on interactive or emphasized elements

### Border Colors

Borders use semantic colors for clarity:

```css
/* Subtle borders (between surface and background) */
border: 1px solid var(--border);

/* Type-specific borders (article cards, type emphasis) */
border-top: 2px solid var(--type-tech);      /* Purple for Tech */
border-left: 2px solid var(--type-quote);    /* Green for Quote */

/* Focus/interactive borders */
border: 2px solid var(--accent);             /* Purple for focus states */

/* Disabled borders */
border: 1px solid var(--muted);              /* Muted gray for disabled */
```

### Background Layering: Creating Visual Depth

The three background colors create perceived depth:

```
--bg          (darkest, farthest)
  ↓
--bg2         (middle ground)
  ↓
--surface     (closest, elevated)
```

**Usage pattern:**
```css
body { background: var(--bg); }              /* Page background */
nav  { background: var(--bg2); }             /* Slightly elevated */
.card { background: var(--surface); }        /* Most elevated */
```

This layering creates visual hierarchy without 3D transforms or z-index manipulation.

### Animation & Gradient Colors

Dynamic elements use color gradients:

**Progress bar (dark mode):**
```css
background: linear-gradient(to right, #a855f7, #00ff88);
/* Starts purple, transitions to neon green */
```

**Progress bar (light mode):**
```css
background: linear-gradient(to right, #7c3aed, #008f5a);
/* Darker purple to darker green for light backgrounds */
```

**Hero background glow:**
```css
/* Dark mode */
background: radial-gradient(ellipse, rgba(168, 85, 247, 0.07) 0%, transparent 65%);

/* Light mode */
background: radial-gradient(ellipse, rgba(124, 58, 237, 0.06) 0%, transparent 65%);
```

### Interactive States

All interactive elements have consistent color transformations:

| State | Rule | Example |
|---|---|---|
| **Default** | Use `--text` or `--accent` | Link text in accent color |
| **Hover** | Intensify opacity or shift slightly | `opacity: 0.8` or `color: var(--accent2)` |
| **Focus** | Add focus ring in `--accent` | `outline: 2px solid var(--accent)` |
| **Active** | Invert colors or add background | `background: var(--accent)`, `color: var(--bg)` |
| **Disabled** | Use `--muted` with reduced opacity | `color: var(--muted)`, `opacity: 0.5` |

**Pattern for buttons:**
```css
.button {
  color: var(--accent);
  border: 2px solid var(--accent);
  transition: all 0.3s ease;
}

.button:hover {
  background: var(--accent);
  color: var(--bg);
}

.button:focus {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.button:active {
  opacity: 0.9;
}

.button:disabled {
  color: var(--muted);
  border-color: var(--muted);
  cursor: not-allowed;
}
```

### Color Naming Conventions

**Semantic naming (do this):**
- `--bg`, `--surface`, `--border` — describes function, not appearance
- `--text`, `--text-dim` — describes role, not color
- `--accent`, `--accent2` — describes purpose, not hue
- `--type-tech`, `--type-life` — describes article type

**Anti-pattern (don't do this):**
- `--purple-500`, `--blue-300` — color-based names don't work across themes
- `--primary-color`, `--secondary-color` — vague, doesn't explain use case
- `--bright-green`, `--dark-purple` — appearance-based, breaks in theme switch

**Why semantic naming matters:**
- When switching themes, `var(--accent)` automatically becomes the light mode accent
- `var(--purple-500)` would be wrong in light mode (no longer "500" saturation)
- New developers understand purpose immediately: `--border` is for borders, `--text` is for text

### Deprecated & Reserved Colors

These colors are intentionally **not used** to maintain clarity:

| Color | Why Reserved | Alternative |
|---|---|---|
| Pure white (`#ffffff`) | Too harsh on dark background | Use `--text` (`#c4d6e8`) |
| Pure black (`#000000`) | Not needed, use `--bg` | Use `--bg` (`#060b10`) |
| Red/orange tones | Not part of brand | Use `--type-*` colors instead |
| Gray-only colors | Breaks theme switching | Use semantic colors instead |

### Accessibility & Contrast Verification

All color pairs are verified for WCAG AA compliance (4.5:1 minimum for normal text, 3:1 for large text):

**Dark mode contrast pairs (all ≥4.5:1):**
| Foreground | Background | Ratio | Status |
|---|---|---|---|
| `--text` (#c4d6e8) | `--bg` (#060b10) | 12.3:1 | ✓ AAA |
| `--text` (#c4d6e8) | `--surface` (#101e2d) | 11.8:1 | ✓ AAA |
| `--text-dim` (#7a9bb8) | `--bg` (#060b10) | 5.2:1 | ✓ AA |
| `--accent` (#a855f7) | `--bg` (#060b10) | 5.1:1 | ✓ AA |
| `--accent2` (#00ff88) | `--bg` (#060b10) | 7.2:1 | ✓ AAA |

**Light mode contrast pairs (all ≥4.5:1):**
| Foreground | Background | Ratio | Status |
|---|---|---|---|
| `--text` (#0d1b2a) | `--bg` (#f0f4f8) | 12.5:1 | ✓ AAA |
| `--text` (#0d1b2a) | `--surface` (#d4dff0) | 10.1:1 | ✓ AAA |
| `--text-dim` (#2e4a6a) | `--bg` (#f0f4f8) | 6.3:1 | ✓ AAA |
| `--accent` (#7c3aed) | `--bg` (#f0f4f8) | 5.5:1 | ✓ AA |
| `--accent2` (#008f5a) | `--bg` (#f0f4f8) | 5.8:1 | ✓ AA |

**Implementation rule:** Never use color alone to convey information. Always pair with text, icons, or patterns.

### Implementation Examples

**Example 1: Article type badge**
```css
.article-badge {
  padding: 0.4rem 1rem;
  background: var(--type-tech);      /* Purple for Tech */
  color: var(--bg);                  /* Dark text on bright background */
  font-family: var(--font-mono);
  font-weight: 600;
  border-radius: 3px;
}

/* Works in both dark and light mode automatically */
```

**Example 2: Card with type-specific border**
```css
.article-card {
  background: var(--surface);
  border-top: 2px solid var(--type-quote);  /* Green for Quote */
  box-shadow: 0 0 40px var(--accent-glow);
}

/* Light mode: border is darker green, glow is adjusted automatically */
```

**Example 3: Interactive link with theme-aware hover**
```css
.article-link {
  color: var(--accent);
  text-decoration: none;
  transition: color 0.3s ease;
}

.article-link:hover {
  color: var(--accent2);  /* Switch to secondary accent */
}

.article-link:focus {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
```

### Dark Mode Specifics

**Why dark mode is default:**
- Aligns with "hacker aesthetic" brand voice
- Reduces eye strain for extended reading sessions
- Better battery life on OLED screens
- Better performance in low-light environments

**Canvas matrix animation opacity in dark mode:**
```css
#matrix-canvas { opacity: 0.13; }
/* Subtle enough to not interfere with text */
/* Visible enough to maintain brand presence */
```

**Dot grid background in dark mode:**
```css
background: radial-gradient(circle, rgba(168, 85, 247, 0.07) 1px, transparent 1px);
/* Purple dots at 7% opacity — barely visible but present */
```

### Light Mode Specifics

**Why light mode matters:**
- Accessibility for users with light sensitivity to dark backgrounds
- Professional context (print, office, daylight reading)
- User preference for light interfaces
- Complete theme coverage (not just a half-finished afterthought)

**Canvas matrix animation opacity in light mode:**
```css
#matrix-canvas { opacity: 0.18; }
/* More visible in light mode (higher contrast) */
/* Still doesn't interfere with text readability */
```

**Dot grid background in light mode:**
```css
background: radial-gradient(circle, rgba(124, 58, 237, 0.07) 1px, transparent 1px);
/* Darker purple dots at 7% opacity on light background */
```

**Hero name text shadow in light mode:**
```css
text-shadow: 0 0 80px rgba(124, 58, 237, 0.12), 0 0 120px rgba(124, 58, 237, 0.05);
/* Subtle purple glow behind text for emphasis */
```

---

## 3. Typography

### Typography Philosophy

Typography reinforces the danix.xyz brand through **three purposeful font families**:

| Font | Purpose | Brand Signal |
|---|---|---|
| **Oxanium** | Display, headings, emphasis | Technical, premium, bold |
| **IBM Plex Sans** | Body, prose, UI labels | Approachable, professional, readable |
| **JetBrains Mono** | Code, monospace UI, metadata | Developer-focused, technical, terminal-like |

This three-font system creates visual hierarchy and guides the reader's eye through content. Each font choice signals its role: headers grab attention, body invites reading, monospace signals technical content.

### Font Family Definitions

All fonts are defined as CSS custom properties in `:root`:

```css
:root {
  --font-head:   'Oxanium', sans-serif;
  --font-body:   'IBM Plex Sans', system-ui, sans-serif;
  --font-mono:   'JetBrains Mono', 'Courier New', monospace;
}
```

**Fallback strategy:**
- **Oxanium:** No fallback (distinctive, used only for display where sans-serif backup is acceptable)
- **IBM Plex Sans:** Falls back to `system-ui` (ensures readable prose even if font fails to load)
- **JetBrains Mono:** Falls back to `Courier New` (preserves monospace and terminal feel)

**Implementation pattern:**
```css
h1 { font-family: var(--font-head); }        /* Display font */
body { font-family: var(--font-body); }      /* Body text */
code { font-family: var(--font-mono); }      /* Code/terminal */
```

### Oxanium: Display Font

**Characteristics:**
- Geometric, bold, premium sans-serif
- Weights: 700 (bold), 800 (extra bold)
- High contrast letterforms, distinctive character
- Used sparingly for maximum impact

**Usage:**

| Element | Weight | Size | Line Height | Example |
|---|---|---|---|---|
| Page titles | 800 | 2.5–3.5rem | 1.2 | `<h1>Article Title</h1>` |
| Section headings | 800 | 1.75–2rem | 1.2 | `<h2>Section Name</h2>` |
| Card titles | 700 | 1.25–1.5rem | 1.3 | Large card headline |
| Badges/labels | 700 | 0.75rem | 1 | Type badges, tags |
| Hero text | 800 | 3–4rem | 1.1 | Homepage hero name |
| Menu items | 800 | 1.5–2rem | 1.2 | Navigation text |

**Size scaling across breakpoints:**
```css
/* Mobile (320px+) */
h1 { font-size: 2rem; }

/* Tablet (768px+) */
@media (min-width: 768px) {
  h1 { font-size: 2.5rem; }
}

/* Desktop (1060px+) */
@media (min-width: 1060px) {
  h1 { font-size: 3rem; }
}

/* Or use clamp() for fluid sizing */
h1 { font-size: clamp(2rem, 6vw, 3.5rem); }
```

**Pairing with color:**
- Oxanium headings use `--text` (primary text color) for readability
- Headings can emphasize with `--accent` color for interactive sections
- Never use Oxanium for body text (too bold, reduces readability)

### IBM Plex Sans: Body Font

**Characteristics:**
- Open, friendly, highly readable sans-serif
- Weights: 300 (light), 400 (regular), 600 (semi-bold)
- Excellent readability at body text sizes
- Default for all prose and UI labels

**Usage:**

| Element | Weight | Size | Line Height | Example |
|---|---|---|---|---|
| Body paragraphs | 400 | 1rem | 1.8 | Article text |
| Prose descriptions | 400 | 0.95–1rem | 1.8 | Excerpt text |
| UI labels | 600 | 0.875–1rem | 1.6 | Button text, form labels |
| Metadata | 400 | 0.85rem | 1.6 | Dates, bylines, read time |
| Light/italic text | 300 | 1rem | 1.8 | Quotes, captions |

**Size scaling across breakpoints:**
```css
/* Mobile (320px+) */
body { font-size: 0.95rem; }
p { font-size: 0.95rem; }

/* Tablet (768px+) */
@media (min-width: 768px) {
  body { font-size: 1rem; }
  p { font-size: 1rem; }
}

/* Desktop (1060px+) */
@media (min-width: 1060px) {
  body { font-size: 1.05rem; }
  p { font-size: 1.05rem; }
}
```

**Pairing with color:**
- Body text always uses `--text` for readability
- Secondary text uses `--text-dim` for de-emphasis
- UI labels use `--text` or `--accent` depending on context (primary vs interactive)

### JetBrains Mono: Monospace Font

**Characteristics:**
- Open-source monospace designed for developers
- Weights: 400 (regular), 700 (bold)
- Highly legible at small sizes
- Signals technical content, terminal, code

**Usage:**

| Element | Weight | Size | Line Height | Example |
|---|---|---|---|---|
| Inline code | 400 | 0.9em | 1 | `var` or `const` |
| Code blocks | 400 | 0.85–0.9rem | 1.6 | `<pre><code>` |
| Terminal UI | 400 | 0.85–1rem | 1.5 | `$ curl https://...` |
| Metadata | 400 | 0.8–0.85rem | 1.5 | Timestamps, IDs |
| Attribution | 400 | 0.9rem | 1.5 | "— Author Name" |

**Size scaling:**
```css
/* Monospace text scales less aggressively than display fonts */
code { font-size: 0.9em; }        /* Relative to parent */
.terminal { font-size: 0.85rem; } /* Absolute for terminal UI */
```

**Pairing with color:**
- Code blocks use `--accent2` (neon green) for keywords and highlights
- Terminal UI uses `--terminal-prompt` (green) and `--terminal-text` (light)
- Metadata uses `--text-dim` for secondary importance
- Links in monospace use `--accent` or `--type-*` depending on context

### Google Fonts CDN

Fonts are loaded from Google Fonts CDN for performance:

```html
<link href="https://fonts.googleapis.com/css2?family=Oxanium:wght@700;800&family=IBM+Plex+Sans:wght@300;400;600&family=JetBrains+Mono:wght@400;700&display=swap" rel="stylesheet">
```

**Loading strategy:**
- `display=swap` ensures text is visible immediately (FOUT fallback)
- Only necessary weights are loaded (700, 800 for Oxanium; 300, 400, 600 for IBM Plex; 400, 700 for JetBrains)
- CSS follows HTML to minimize CLS (Cumulative Layout Shift)

**Fallback behavior:**
- If CDN fails, system fonts kick in (fallback chain in font-family)
- Site remains readable even without web fonts
- Performance is not compromised if CDN is slow

### Font Weights: When to Use Each

**Oxanium weights:**
- **700 (Bold):** Small display text, badges, labels, menu items
- **800 (Extra Bold):** Large display text, page titles, hero text

**IBM Plex Sans weights:**
- **300 (Light):** Italic prose, quotes, captions (less weight balances slant)
- **400 (Regular):** Body text, descriptions, most UI text
- **600 (Semi-bold):** UI labels, buttons, emphasized text

**JetBrains Mono weights:**
- **400 (Regular):** Code, terminal, metadata, timestamps
- **700 (Bold):** Keywords in code blocks, emphasized terminal text

**Pattern:**
```css
strong, b { font-weight: 600; }    /* Use semi-bold, not bold */
em, i { font-weight: 300; }        /* Light for italic (compensates for slant) */
code { font-weight: 400; }         /* Regular monospace (bold looks too heavy) */
```

### Font Sizing Scale

Typography uses a modular scale for consistency. Base size is 1rem (17px on desktop):

**Display sizes (Oxanium):**
```
h1: 2rem (32px mobile) → 3rem (51px desktop)
h2: 1.75rem (30px) → 2rem (34px)
h3: 1.5rem (26px) → 1.75rem (30px)
h4: 1.25rem (21px) → 1.5rem (26px)
```

**Body sizes (IBM Plex Sans):**
```
Body text: 0.95rem (16px mobile) → 1.05rem (18px desktop)
Metadata: 0.85rem (14px)
Small: 0.8rem (14px)
```

**Monospace sizes (JetBrains Mono):**
```
Code block: 0.85rem (14px)
Terminal: 0.85rem (14px)
Inline code: 0.9em (relative to parent)
Metadata: 0.8rem (14px)
```

**Responsive sizing with clamp():**
```css
/* Scales fluidly between mobile and desktop */
h1 {
  font-size: clamp(2rem, 6vw, 3.5rem);
  /* Minimum: 32px, Preferred: 6vw, Maximum: 56px */
}

p {
  font-size: clamp(0.95rem, 1.5vw, 1.05rem);
  /* Minimum: 15px, Preferred: 1.5vw, Maximum: 17px */
}
```

### Line Height Hierarchy

Different line heights optimize readability for different content types:

| Content Type | Line Height | Reason |
|---|---|---|
| **Display (h1-h4)** | 1.1–1.3 | Tight spacing, dramatic appearance |
| **Body prose** | 1.8 | Open spacing, comfortable reading |
| **UI labels** | 1.5–1.6 | Compact, grouped with related content |
| **Code blocks** | 1.6 | More open than inline, but not as loose as prose |
| **Metadata** | 1.5 | Compact, supporting information |

**Implementation:**
```css
h1, h2, h3, h4, h5, h6 { line-height: 1.2; }

body, p, article { line-height: 1.8; }

button, label, .ui-text { line-height: 1.5; }

code, pre { line-height: 1.6; }

.metadata, .byline { line-height: 1.5; }
```

### Letter Spacing (Tracking)

Letter spacing is used sparingly to improve readability or create visual distinction:

| Element | Tracking | Reason |
|---|---|---|
| **Display (h1-h4)** | Normal (-0.025em) | Geometric fonts benefit from tight tracking |
| **Body text** | Normal (0) | Default is optimal |
| **UI labels** | 0.05–0.08em | Uppercase labels benefit from open tracking |
| **Monospace metadata** | 0.02em | Subtle, improves legibility |
| **Menu items** | -0.035em | Tight tracking makes bold text more readable |

**Implementation:**
```css
h1, h2, h3, h4 {
  letter-spacing: -0.025em;  /* Oxanium is bold, tighten it */
}

.button, button {
  letter-spacing: 0.08em;    /* Uppercase buttons are more open */
  text-transform: uppercase;
}

nav a {
  letter-spacing: -0.035em;  /* Menu items are bold, tighten */
}

.metadata {
  letter-spacing: 0.02em;    /* Subtle spacing */
}
```

### Text Hierarchy: h1 to h6, Body, Metadata

All text elements follow a strict hierarchy:

**Heading hierarchy (h1 → h6):**
```
h1: 2–3rem, Oxanium 800, line-height 1.2    (Page title, hero)
h2: 1.75–2rem, Oxanium 800, line-height 1.2 (Section title)
h3: 1.5–1.75rem, Oxanium 700, line-height 1.2 (Subsection)
h4: 1.25–1.5rem, Oxanium 700, line-height 1.3 (Subheading)
h5: 1.1–1.25rem, Oxanium 700, line-height 1.3 (Minor heading)
h6: 1rem, Oxanium 700, line-height 1.3      (Small heading)
```

**Body text hierarchy:**
```
<p>: 1rem, IBM Plex Sans 400, line-height 1.8  (Main prose)
<strong>: IBM Plex Sans 600                      (Emphasis within prose)
<em>: IBM Plex Sans 300                          (Light emphasis, italic)
<small>: 0.85rem, IBM Plex Sans 400             (Captions, fine print)
```

**Metadata hierarchy:**
```
.metadata: 0.85rem, IBM Plex Sans 400, line-height 1.5
.byline: 0.9rem, JetBrains Mono 400, line-height 1.5
.timestamp: 0.8rem, JetBrains Mono 400, line-height 1.5
```

**Code hierarchy:**
```
<code>: 0.9em, JetBrains Mono 400 (inline)
<pre>: 0.85rem, JetBrains Mono 400, line-height 1.6 (block)
<pre><code>: Inherits from <pre>
```

### Readable Line Lengths

Prose content has optimal line lengths for reading comfort:

| Content Type | Max Width | Characters | Reason |
|---|---|---|---|
| **Body prose** | 65ch–75ch | 65–75 chars per line | Optimal for single-column reading |
| **Wide layout** | 900px | (auto) | Multi-column or prose + sidebar |
| **Code blocks** | 100% (scrollable) | N/A | Code can be wide; horizontal scroll ok |

**Implementation:**
```css
article {
  max-width: 65ch;    /* ~900px on desktop */
  margin: 0 auto;
  padding: 0 1.5rem;
}

/* Code blocks can be wider */
pre {
  overflow-x: auto;   /* Allow horizontal scroll */
  max-width: 100%;
}
```

**Why line length matters:**
- **Too short** (<50 chars): Eye jumps too much, fatiguing
- **Too long** (>90 chars): Hard to return to start of next line
- **Optimal** (65–75 chars): Comfortable reading speed, minimal eye movement

### Color + Typography: Semantic Pairing

Font choice + color choice communicate information together:

| Combination | Meaning | Example |
|---|---|---|
| Oxanium + `--accent` | Important heading, call to action | Section title with purple accent |
| IBM Plex + `--text` | Primary readable content | Body text |
| IBM Plex + `--text-dim` | Secondary content, supporting info | Byline, date, metadata |
| JetBrains Mono + `--accent2` | Code, technical content | Keywords in terminal |
| JetBrains Mono + `--type-*` | Type-specific metadata | "Quote" label |

**Pattern:**
```css
h2 {
  font-family: var(--font-head);
  color: var(--text);           /* Readable heading */
}

.article-byline {
  font-family: var(--font-body);
  color: var(--text-dim);       /* Secondary info, dimmed */
}

code {
  font-family: var(--font-mono);
  color: var(--accent2);        /* Technical, highlighted */
}
```

### Monospace Usage: Terminal, Code, Metadata

Monospace signals technical content and serves multiple purposes:

**Terminal UI (hacker aesthetic):**
```css
.terminal-prompt { font-family: var(--font-mono); color: var(--terminal-prompt); }
.terminal-output { font-family: var(--font-mono); color: var(--terminal-text); }
/* Size: 0.85–1rem, line-height: 1.5 */
```

**Code blocks:**
```css
pre, code {
  font-family: var(--font-mono);
  color: var(--accent2);        /* Neon green in dark mode */
  background: var(--bg);
  font-size: 0.85rem;
  line-height: 1.6;
}
```

**Metadata (timestamps, IDs, technical info):**
```css
.timestamp, .metadata {
  font-family: var(--font-mono);
  color: var(--text-dim);
  font-size: 0.8rem;
  letter-spacing: 0.02em;
}
```

**Quote attribution:**
```css
.quote-attribution {
  font-family: var(--font-mono);
  font-style: italic;
  color: var(--text-dim);
}
```

### Responsive Typography: Scaling Across Breakpoints

Typography responds to viewport size for optimal readability:

**Mobile (320px+): Smaller, tighter**
```css
/* Base styles (mobile-first) */
h1 { font-size: 2rem; }
body { font-size: 0.95rem; }
```

**Tablet (768px+): Medium, balanced**
```css
@media (min-width: 768px) {
  h1 { font-size: 2.5rem; }
  body { font-size: 1rem; }
}
```

**Desktop (1060px+): Larger, more spacious**
```css
@media (min-width: 1060px) {
  h1 { font-size: 3rem; }
  body { font-size: 1.05rem; }
  article { max-width: 70ch; }
}
```

**Or use fluid sizing with clamp():**
```css
h1 { font-size: clamp(2rem, 6vw, 3.5rem); }
body { font-size: clamp(0.95rem, 1.5vw, 1.05rem); }
```

**Line height can also be responsive:**
```css
h1 { line-height: 1.1; }

@media (min-width: 768px) {
  h1 { line-height: 1.2; }  /* More open on larger screens */
}
```

### Accessibility: Font Size, Contrast, Readability

Typography must support accessibility:

**Minimum sizes:**
- **Body text:** 16px minimum (1rem base is 17px on desktop, 16px on mobile)
- **UI labels:** 14px minimum (0.85rem)
- **Code/metadata:** 12px minimum (0.75rem for emergency cases, normally 14px)

**Never go below:**
- 12px for any readable content
- Users with low vision rely on readable font sizes

**Contrast requirements (paired with colors):**
- All body text must have ≥4.5:1 contrast with background
- All headings must have ≥3:1 contrast with background
- Verified in Section 2 (Color System)

**Readability patterns:**
```css
/* Good: comfortable line height, appropriate size */
p {
  font-size: 1rem;
  line-height: 1.8;
}

/* Bad: too small, too tight */
p {
  font-size: 0.75rem;
  line-height: 1.2;
}
```

**Font smoothing for better rendering:**
```css
body {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
```

### Typography Quick Reference Table

```
DISPLAY (Headings)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Element      Font        Weight  Size              Line Height
h1           Oxanium     800     2–3rem            1.2
h2           Oxanium     800     1.75–2rem         1.2
h3           Oxanium     700     1.5–1.75rem       1.2
h4           Oxanium     700     1.25–1.5rem       1.3

BODY (Content)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
paragraph    IBM Plex    400     1rem              1.8
strong       IBM Plex    600     1rem              1.8
em           IBM Plex    300     1rem              1.8
small        IBM Plex    400     0.85rem           1.5

CODE & METADATA
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
inline code  JetBrains   400     0.9em             1
code block   JetBrains   400     0.85rem           1.6
timestamp    JetBrains   400     0.8rem            1.5
```

---

## 4. Spacing & Layout

### Spacing Scale: Modular System

All spacing uses a **modular scale** based on 0.5rem increments:

```
0.25rem (4px)   — Minimal gaps
0.5rem  (8px)   — Tight spacing
0.75rem (12px)  — Comfortable spacing
1rem    (16px)  — Default spacing, base unit
1.5rem  (24px)  — Generous spacing
2rem    (32px)  — Large sections
2.5rem  (40px)  — Very large sections
3rem    (48px)  — Hero/major sections
4rem    (64px)  — Between major sections
```

**Why modular scale matters:**
- Creates visual rhythm and consistency
- Makes layouts feel intentional, not random
- Easier to maintain across responsive breakpoints
- Reduces decision fatigue (limited palette vs unlimited options)

**Implementation pattern:**
```css
/* Use custom properties for reusable spacing */
:root {
  --space-xs:   0.5rem;
  --space-sm:   0.75rem;
  --space-md:   1rem;
  --space-lg:   1.5rem;
  --space-xl:   2rem;
  --space-2xl:  3rem;
  --space-3xl:  4rem;
}

/* Apply consistently */
.card { padding: var(--space-md); }
section { margin-top: var(--space-2xl); }
.grid { gap: var(--space-lg); }
```

### Padding Standards

**Container padding (content inset from edges):**

| Size | Mobile (320px) | Tablet (768px) | Desktop (1060px) |
|---|---|---|---|
| Default page padding | 1rem | 1.5rem | 2rem |
| Card/container padding | 1rem | 1.5rem | 1.5rem |
| Section padding (vertical) | 1.5rem | 2rem | 2.5rem |
| Hero section padding | 1.5rem | 2rem | 3rem |

**Implementation:**
```css
/* Page-level container */
.container {
  padding: 0 1rem;
  max-width: 1080px;
  margin: 0 auto;
}

@media (min-width: 768px) {
  .container { padding: 0 1.5rem; }
}

@media (min-width: 1060px) {
  .container { padding: 0 2rem; }
}

/* Cards and elevated containers */
.card {
  padding: 1rem;
  background: var(--surface);
}

@media (min-width: 768px) {
  .card { padding: 1.5rem; }
}

/* Sections with vertical spacing */
section {
  padding: 1.5rem 0;
}

@media (min-width: 768px) {
  section { padding: 2rem 0; }
}
```

### Margin Standards

**Spacing between elements:**

| Element | Bottom Margin | Purpose |
|---|---|---|
| `<p>` (paragraph) | 1.5rem | Breathing room between paragraphs |
| `<h2>` (heading) | 1rem (top), 0.75rem (bottom) | Heading separation |
| `<h3>` (subheading) | 0.75rem (top), 0.5rem (bottom) | Subheading separation |
| Section | 2–3rem (top) | Between major sections |
| Card | 1.5rem (bottom) | Between cards in list |
| Last child | 0 (override) | No margin after last element |

**Implementation:**
```css
p { margin-bottom: 1.5rem; }
p:last-child { margin-bottom: 0; }

h2 {
  margin-top: 1rem;
  margin-bottom: 0.75rem;
}

h3 {
  margin-top: 0.75rem;
  margin-bottom: 0.5rem;
}

section { margin-top: 2rem; }
section:first-child { margin-top: 0; }

.card { margin-bottom: 1.5rem; }
.card:last-child { margin-bottom: 0; }
```

### Gap & Gap-x/Gap-y: Flexbox & Grid Spacing

Grid and flexbox use `gap` instead of margins for internal spacing:

**Grid layouts:**
```css
.article-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 1.5rem;        /* Equal spacing on all sides */
}

@media (min-width: 768px) {
  .article-grid { gap: 2rem; }
}
```

**Flexbox layouts:**
```css
.sidebar-layout {
  display: flex;
  gap: 2rem;          /* Space between flex items */
}

/* Responsive: stack on mobile */
@media (max-width: 768px) {
  .sidebar-layout {
    flex-direction: column;
    gap: 1.5rem;
  }
}
```

**Directional gaps:**
```css
.social-icons {
  display: flex;
  gap-x: 1rem;        /* Horizontal gap between icons */
  gap-y: 0.5rem;      /* Vertical gap if wrapped */
  flex-wrap: wrap;
}
```

**Why gap > margins:**
- Avoids margin collapse issues
- Cleaner calculation (no "last child" special case)
- Easier to adjust globally
- Works consistently in flex and grid

### Container Max-Widths

**Different max-widths for different content types:**

| Container | Max-Width | Purpose | Breakpoint |
|---|---|---|---|
| Article prose | 65ch (~900px) | Optimal reading length | 768px+ |
| Timeline layout | 1080px | Content + sidebar | 1060px+ |
| Masonry grid | 1200px | Multi-column layout | 1060px+ |
| Hero section | 100vw (full-width) | Full bleed | All |
| Code blocks | 100% (overflow-x) | Scrollable if needed | All |

**Implementation:**
```css
/* Article prose (optimal reading) */
article {
  max-width: 65ch;
  margin: 0 auto;
  padding: 0 1.5rem;
}

/* Timeline/wide layout */
.timeline {
  max-width: 1080px;
  margin: 0 auto;
  padding: 0 1.5rem;
}

/* Masonry grid (wider) */
.masonry {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 1.5rem;
}

/* Hero (full-width) */
.hero {
  width: 100vw;
  max-width: 100%;
  overflow: hidden;
}
```

### Responsive Breakpoints

Three primary breakpoints ensure content adapts gracefully:

```
Mobile:  320px – 767px    (1 column, stacked)
Tablet:  768px – 1059px   (2 columns, sidebar collapses)
Desktop: 1060px+          (full layout, sidebar fixed)
```

**Breakpoint definitions:**
```css
/* Mobile-first: base styles for 320px+ */
/* No media query needed */

/* Tablet breakpoint */
@media (min-width: 768px) {
  /* Tablet-specific styles */
}

/* Desktop breakpoint */
@media (min-width: 1060px) {
  /* Desktop-specific styles */
}
```

**Why these specific breakpoints:**
- **320px:** iPhone SE, smallest mobile devices
- **768px:** iPad, standard tablets (also common breakpoint)
- **1060px:** Sidebar appears on desktop (allows fixed sidebar + content)

**Avoid breakpoints:** Don't add 480px, 600px, 900px, etc. Stick to the three main breakpoints for consistency.

### Gutter & Padding by Breakpoint

How padding changes to maintain visual hierarchy across sizes:

**Page-level padding (from edge to content):**
```css
/* Mobile: 1rem on each side = 2rem total */
body { padding: 0 1rem; }

/* Tablet: 1.5rem on each side = 3rem total */
@media (min-width: 768px) {
  body { padding: 0 1.5rem; }
}

/* Desktop: 2rem on each side = 4rem total */
@media (min-width: 1060px) {
  body { padding: 0 2rem; }
}
```

**Card padding (internal spacing):**
```css
/* Mobile: tighter padding */
.card { padding: 1rem; }

/* Tablet & Desktop: more breathing room */
@media (min-width: 768px) {
  .card { padding: 1.5rem; }
}
```

**Section spacing (between major sections):**
```css
/* Mobile: compact */
section { margin-top: 1.5rem; }

/* Tablet: generous */
@media (min-width: 768px) {
  section { margin-top: 2rem; }
}

/* Desktop: very generous */
@media (min-width: 1060px) {
  section { margin-top: 3rem; }
}
```

**Why padding changes:** 
- Mobile devices have limited screen real estate (preserve width)
- Tablets can afford more horizontal padding
- Desktop layouts can be more spacious without feeling cramped

### Grid Systems: CSS Grid for Layouts

**Article card grid (masonry-style):**
```css
.article-grid {
  display: grid;
  grid-template-columns: 1fr;      /* Mobile: 1 column */
  gap: 1.5rem;
}

@media (min-width: 768px) {
  .article-grid {
    grid-template-columns: repeat(2, 1fr);  /* Tablet: 2 columns */
  }
}

@media (min-width: 1060px) {
  .article-grid {
    grid-template-columns: repeat(3, 1fr);  /* Desktop: 3 columns */
  }
}
```

**Auto-fill grid (responsive without breakpoints):**
```css
.photo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 1rem;
}
/* Automatically creates columns based on available space */
```

**Timeline layout (2-column with sidebar):**
```css
.timeline-container {
  display: grid;
  grid-template-columns: 1fr;    /* Mobile: stacked */
  gap: 2rem;
}

@media (min-width: 1060px) {
  .timeline-container {
    grid-template-columns: 1fr 300px;  /* Desktop: content + sidebar */
  }
}
```

**When to use grid:**
- Multi-column layouts (masonry, card grids)
- Layouts with explicit structure (header, main, sidebar, footer)
- Responsive layouts that need exact column control

### Flexbox Patterns: When to Use vs Grid

**Use flexbox for:**
- Navigation menus (horizontal or vertical)
- Button groups
- Icon rows
- Linear layouts (1D spacing)

**Use grid for:**
- Card layouts (2D)
- Page layout (header, main, sidebar)
- Masonry/gallery layouts
- Multi-column content

**Flexbox example (navigation):**
```css
.nav-menu {
  display: flex;
  gap: 1.5rem;
  align-items: center;
}

.nav-menu a {
  padding: 0.5rem 1rem;
}
```

**Grid example (page layout):**
```css
body {
  display: grid;
  grid-template-columns: 1fr;     /* Mobile */
  grid-template-rows: auto 1fr auto;
}

@media (min-width: 1060px) {
  body {
    grid-template-columns: 1fr 300px;  /* Desktop */
  }
}
```

### Z-Index Stacking: Layering Elements

**Z-index scale (reserved values):**
```
1000+ : Modals, overlays (highest)
100   : Fixed navigation, sidebars
10    : Dropdowns, tooltips
1     : Content, cards
0     : Background, images
-1    : Canvas/matrix animation (lowest)
```

**Implementation:**
```css
/* Background elements */
#matrix-canvas { z-index: 0; }
body::before { z-index: 0; }

/* Content layers */
article { position: relative; z-index: 1; }
.card { z-index: 1; }

/* Interactive elements */
.dropdown { z-index: 10; }
.tooltip { z-index: 10; }

/* Fixed UI */
nav { position: fixed; z-index: 100; }
.sidebar { position: fixed; z-index: 100; }
#scroll-progress { z-index: 9999; }

/* Overlays */
.modal { z-index: 1000; }
.modal-backdrop { z-index: 999; }
```

**Rule: Don't use arbitrary z-index values.** Always use the reserved scale above.

### Hero Section: Height, Padding, Content Alignment

**Hero section structure:**
```html
<section class="hero">
  <div class="hero-background">
    <img src="..." class="hero-image">
    <div class="hero-overlay"></div>
  </div>
  <div class="hero-content">
    <h1>Article Title</h1>
    <p class="hero-byline">By Author • Date</p>
  </div>
</section>
```

**Hero section CSS:**
```css
.hero {
  position: relative;
  min-height: 60vh;              /* Mobile */
  padding: 2rem;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  overflow: hidden;
}

@media (min-width: 768px) {
  .hero { min-height: 60vh; padding: 3rem; }
}

@media (min-width: 1060px) {
  .hero { min-height: 60vh; padding: 4rem; }
}

/* Background image (full bleed) */
.hero-background {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.hero-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

/* Dark overlay for text readability */
.hero-overlay {
  position: absolute;
  inset: 0;
  background: rgba(6, 11, 16, 0.65);
  z-index: 1;
}

/* Content positioning */
.hero-content {
  position: relative;
  z-index: 2;
  text-align: center;
  max-width: 860px;
}
```

**Hero responsiveness:**
- Height: 60vh on all screen sizes (full viewport height portion)
- Padding increases at larger breakpoints
- Text remains centered and readable
- Image maintains aspect ratio

### Sidebar Layout: Desktop Fixed vs Mobile Collapsed

**Desktop sidebar (fixed on right):**
```css
@media (min-width: 1060px) {
  .page-layout {
    display: grid;
    grid-template-columns: 1fr 300px;
    gap: 2rem;
  }

  .sidebar {
    position: fixed;
    right: calc(50vw - 540px);  /* Center relative to max-width container */
    width: 300px;
    top: 80px;                  /* Below fixed nav */
  }
}
```

**Mobile sidebar (horizontal strip or hidden):**
```css
@media (max-width: 1059px) {
  .sidebar {
    position: static;           /* Not fixed */
    width: 100%;
    margin-top: 2rem;
  }

  .sidebar-content {
    display: flex;              /* Horizontal strip */
    gap: 1rem;
    flex-wrap: wrap;
    justify-content: center;
  }
}
```

**Sidebar visibility trigger (IntersectionObserver in JS):**
- Show sidebar when hero scrolls out of view
- Hide sidebar when footer is visible
- Sidebar is always accessible on mobile (no hiding)

### Article Card Spacing

**Card structure and spacing:**
```css
.article-card {
  padding: 1rem;
  background: var(--surface);
  border-top: 2px solid var(--type-tech);
  border-radius: 4px;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;               /* Space between card elements */
}

@media (min-width: 768px) {
  .article-card { padding: 1.5rem; }
}

/* Card image */
.card-image {
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;       /* Or 1/1 for thumbnails */
  object-fit: cover;
  border-radius: 2px;
}

/* Card metadata */
.card-meta {
  display: flex;
  gap: 0.5rem;
  font-size: 0.85rem;
  color: var(--text-dim);
}

/* Card title and excerpt */
.card-title {
  font-family: var(--font-head);
  font-size: 1.25rem;
  margin: 0;
}

.card-excerpt {
  font-family: var(--font-body);
  font-size: 0.95rem;
  line-height: 1.6;
  color: var(--text);
  margin: 0;
}
```

### Negative Space: White Space as Design Element

Negative space (empty space) is as important as filled space:

**Creating breathing room:**
```css
/* Large section margins create visual rest */
section {
  margin-top: 3rem;           /* White space above section */
  margin-bottom: 3rem;        /* White space below section */
}

/* Generous padding in cards feels premium */
.card {
  padding: 2rem;              /* More padding = more breathing room */
}

/* Open line height improves readability and adds white space */
p { line-height: 1.8; }       /* vs 1.4, which feels cramped */
```

**When to use white space:**
- Between sections (separate ideas)
- Around important content (draw attention)
- In cards (create visual rest)
- After headings (connect to paragraph below)

**Rule: If it feels cramped, add more white space.** Negative space is never wasted.

### Responsive Collapse Patterns

**What stacks at what viewport:**

| Element | Mobile (320px) | Tablet (768px) | Desktop (1060px) |
|---|---|---|---|
| Navigation | Hamburger menu | Hamburger menu | Horizontal menu |
| Sidebar | Hidden/below content | Below content | Fixed right |
| Grid layout | 1 column | 2 columns | 3 columns |
| Hero height | 50vh | 60vh | 60vh |
| Padding (page) | 1rem | 1.5rem | 2rem |

**Hamburger menu pattern:**
```css
/* Mobile: menu is vertical and hidden */
.nav-menu {
  position: fixed;
  left: 0;
  top: 0;
  flex-direction: column;
  display: none;              /* Hidden by default */
}

.hamburger.active ~ .nav-menu {
  display: flex;              /* Visible when hamburger is active */
}

/* Desktop: menu is horizontal and always visible */
@media (min-width: 1060px) {
  .nav-menu {
    position: static;
    flex-direction: row;
    display: flex;            /* Always visible */
  }

  .hamburger { display: none; }  /* Hamburger not needed */
}
```

### Fixed Elements: Navigation, Progress Bar, Sidebars

**Fixed navigation bar:**
```css
nav {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  z-index: 100;
  background: rgba(6, 11, 16, 0.88);
  backdrop-filter: blur(14px);
  padding: 1rem 1.2rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

/* Add padding to body to account for fixed nav */
body {
  padding-top: 60px;  /* Height of nav */
}
```

**Scroll progress bar:**
```css
#scroll-progress {
  position: fixed;
  top: 0;
  left: 0;
  height: 2px;
  width: 0%;
  background: linear-gradient(to right, var(--accent), var(--accent2));
  z-index: 9999;              /* Above all content */
  pointer-events: none;       /* Doesn't interfere with interaction */
}
```

**Fixed sidebar (desktop only):**
```css
@media (min-width: 1060px) {
  .sidebar {
    position: fixed;
    right: calc(50vw - 540px);
    top: 80px;                /* Below nav */
    width: 300px;
    z-index: 100;
  }
}
```

### Overflow & Scrolling: Managing Content That Exceeds Space

**Code blocks (horizontal scroll):**
```css
pre {
  overflow-x: auto;           /* Scroll if code is wide */
  overflow-y: hidden;         /* No vertical scroll */
  max-width: 100%;
  padding: 1rem;
}
```

**Long URLs in text (wrap instead of scroll):**
```css
a {
  word-break: break-all;      /* Break long URLs */
  overflow-wrap: break-word;  /* Wrap at word boundaries */
}
```

**Images (never overflow):**
```css
img {
  max-width: 100%;
  height: auto;
  display: block;
}
```

**Prevent horizontal scroll on body:**
```css
html, body {
  overflow-x: hidden;         /* No horizontal scroll */
  width: 100%;
}
```

**Use overflow-hidden sparingly:**
- Good: Hero sections, fixed sidebars
- Bad: Main content (users need to scroll to see content)

### Spacing & Layout Quick Reference

```
SPACING SCALE
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
0.5rem (8px)   — Tight spacing
1rem (16px)    — Default, base unit
1.5rem (24px)  — Generous
2rem (32px)    — Large
3rem (48px)    — Very large

BREAKPOINTS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Mobile:   320px – 767px
Tablet:   768px – 1059px
Desktop:  1060px+

CONTAINER MAX-WIDTHS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Article:   65ch (~900px)
Timeline:  1080px
Masonry:   1200px
Hero:      100vw (full-width)

Z-INDEX SCALE
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1000:  Modals, overlays
100:   Fixed nav, sidebars
10:    Dropdowns, tooltips
1:     Content, cards
0:     Background, images
-1:    Canvas animation
```

---

## 5. Components

### Button Styles: Primary, Secondary, Disabled

**Button structure:**
```html
<button class="btn btn-primary">Primary Action</button>
<button class="btn btn-secondary">Secondary Action</button>
<button class="btn btn-primary" disabled>Disabled</button>
```

**Primary button (main action):**
```css
.btn.btn-primary {
  padding: 0.75rem 1.5rem;
  background: var(--accent);              /* Purple */
  color: var(--bg);                       /* Dark text */
  border: none;
  border-radius: 4px;
  font-family: var(--font-body);
  font-size: 1rem;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.3s ease;
  text-decoration: none;
  display: inline-block;
}

.btn.btn-primary:hover {
  background: var(--accent2);             /* Switch to green */
  color: var(--text);
  box-shadow: 0 0 15px rgba(0, 255, 136, 0.3);
}

.btn.btn-primary:focus {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.btn.btn-primary:active {
  opacity: 0.9;
  transform: scale(0.98);
}
```

**Secondary button (alternative action):**
```css
.btn.btn-secondary {
  padding: 0.75rem 1.5rem;
  background: transparent;
  color: var(--accent);
  border: 2px solid var(--accent);
  border-radius: 4px;
  font-family: var(--font-body);
  font-size: 1rem;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.3s ease;
}

.btn.btn-secondary:hover {
  background: var(--accent);
  color: var(--bg);
}

.btn.btn-secondary:focus {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
```

**Disabled button:**
```css
.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  background: var(--muted);
  color: var(--text-dim);
  border-color: var(--muted);
}

.btn:disabled:hover {
  background: var(--muted);
  box-shadow: none;
}
```

**Button sizing:**
```css
/* Small button */
.btn.btn-sm {
  padding: 0.5rem 1rem;
  font-size: 0.85rem;
}

/* Large button */
.btn.btn-lg {
  padding: 1rem 2rem;
  font-size: 1.1rem;
}

/* Full-width button */
.btn.btn-block {
  width: 100%;
  display: block;
}
```

### Badge Styles: Type Badges

**Badge structure:**
```html
<span class="badge badge-tech">TECH</span>
<span class="badge badge-life">LIFE</span>
<span class="badge badge-quote">QUOTE</span>
<span class="badge badge-link">LINK</span>
<span class="badge badge-photo">PHOTO</span>
```

**Badge base styling:**
```css
.badge {
  display: inline-block;
  padding: 0.4rem 1rem;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border-radius: 3px;
  color: var(--bg);              /* Always dark text on bright badge */
  white-space: nowrap;
}

/* Type-specific badge colors */
.badge.badge-tech { background: var(--type-tech); }
.badge.badge-life { background: var(--type-life); }
.badge.badge-quote { background: var(--type-quote); }
.badge.badge-link { background: var(--type-link); }
.badge.badge-photo { background: var(--type-photo); }
```

**Badge hover state (optional):**
```css
.badge {
  transition: transform 0.2s ease;
}

.badge:hover {
  transform: scale(1.05);
}
```

**Badge sizing variants:**
```css
.badge.badge-sm { padding: 0.25rem 0.75rem; font-size: 0.65rem; }
.badge.badge-lg { padding: 0.5rem 1.25rem; font-size: 0.8rem; }
```

### Card Layouts: Article, Photo, Content Cards

**Article card (for lists/grids):**
```html
<div class="card card-article">
  <img src="..." alt="..." class="card-image">
  <div class="card-body">
    <div class="card-meta">
      <span class="badge badge-tech">TECH</span>
      <span class="card-date">2026-04-08</span>
    </div>
    <h3 class="card-title">Article Title</h3>
    <p class="card-excerpt">Brief description of article content...</p>
    <a href="#" class="card-link">Read more →</a>
  </div>
</div>
```

**Article card styling:**
```css
.card {
  background: var(--surface);
  border-radius: 4px;
  overflow: hidden;
  transition: all 0.3s ease;
  display: flex;
  flex-direction: column;
}

.card.card-article {
  border-top: 2px solid var(--type-tech);  /* Type color varies */
  box-shadow: 0 0 40px var(--accent-glow);
}

.card-image {
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

.card-body {
  padding: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.card-meta {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  font-size: 0.8rem;
  color: var(--text-dim);
}

.card-title {
  font-family: var(--font-head);
  font-size: 1.25rem;
  font-weight: 700;
  margin: 0;
  line-height: 1.3;
}

.card-excerpt {
  font-family: var(--font-body);
  font-size: 0.95rem;
  line-height: 1.6;
  color: var(--text);
  margin: 0;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.card-link {
  color: var(--accent);
  text-decoration: none;
  font-weight: 600;
  transition: color 0.3s ease;
  align-self: flex-start;
}

.card-link:hover {
  color: var(--accent2);
}

.card:hover {
  transform: translateY(-4px);
  box-shadow: 0 0 60px var(--accent-glow);
}
```

**Photo card (gallery):**
```css
.card.card-photo {
  border-radius: 0;           /* Sharp corners for photo galleries */
  overflow: hidden;
}

.card.card-photo img {
  width: 100%;
  height: 300px;
  object-fit: cover;
}

.card.card-photo:hover img {
  transform: scale(1.05);
}
```

**Content card (generic container):**
```css
.card.card-content {
  padding: 2rem;
  border: 1px solid var(--border);
  border-radius: 4px;
}
```

### Navigation Patterns: Hamburger, Main Nav, Breadcrumbs

**Hamburger menu (mobile):**
```html
<button class="hamburger" id="menu-toggle">
  <span></span>
  <span></span>
  <span></span>
</button>
```

**Hamburger styling:**
```css
.hamburger {
  background: none;
  border: none;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  padding: 0.5rem;
  transition: all 0.3s ease;
  z-index: 101;               /* Above menu overlay */
}

.hamburger span {
  display: block;
  width: 24px;
  height: 2px;
  background: var(--accent);
  transition: all 0.3s ease;
  border-radius: 1px;
}

/* Active state (X icon) */
.hamburger.active span:nth-child(1) {
  transform: rotate(45deg) translateY(10px);
}

.hamburger.active span:nth-child(2) {
  opacity: 0;
}

.hamburger.active span:nth-child(3) {
  transform: rotate(-45deg) translateY(-10px);
}

/* Hide on desktop */
@media (min-width: 1060px) {
  .hamburger { display: none; }
}
```

**Main navigation:**
```html
<nav class="main-nav">
  <a href="/" class="nav-logo">danix.xyz</a>
  <ul class="nav-links">
    <li><a href="/articles">Articles</a></li>
    <li><a href="/about">About</a></li>
    <li><a href="/contact">Contact</a></li>
  </ul>
  <button class="theme-toggle">☀️</button>
</nav>
```

**Main nav styling:**
```css
nav {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  padding: 1rem 1.2rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: rgba(6, 11, 16, 0.88);
  backdrop-filter: blur(14px);
  z-index: 100;
}

.nav-logo {
  font-family: var(--font-head);
  font-size: 1.25rem;
  font-weight: 800;
  color: var(--text);
  text-decoration: none;
}

.nav-links {
  display: none;              /* Hidden on mobile */
  list-style: none;
  gap: 2rem;
}

@media (min-width: 1060px) {
  .nav-links {
    display: flex;
  }
}

.nav-links a {
  color: var(--text);
  text-decoration: none;
  transition: color 0.3s ease;
  position: relative;
}

.nav-links a::after {
  content: '';
  position: absolute;
  bottom: -0.2rem;
  left: 0;
  width: 0;
  height: 2px;
  background: var(--accent);
  transition: width 0.3s ease;
}

.nav-links a:hover::after {
  width: 100%;
}
```

**Breadcrumb navigation:**
```html
<nav class="breadcrumb">
  <a href="/">Home</a>
  <span class="breadcrumb-separator">/</span>
  <a href="/articles">Articles</a>
  <span class="breadcrumb-separator">/</span>
  <span class="breadcrumb-current">Article Title</span>
</nav>
```

**Breadcrumb styling:**
```css
.breadcrumb {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.85rem;
  color: var(--text-dim);
  margin-bottom: 1.5rem;
}

.breadcrumb a {
  color: var(--text-dim);
  text-decoration: none;
  transition: color 0.3s ease;
}

.breadcrumb a:hover {
  color: var(--accent);
}

.breadcrumb-current {
  color: var(--accent);
  font-weight: 600;
}

.breadcrumb-separator {
  color: var(--border);
}
```

### Social Sharing Sidebar

**Desktop (fixed right):**
```html
<aside class="share-sidebar" id="share-sidebar">
  <button class="share-btn" id="share-whatsapp" data-tooltip="WhatsApp">
    <svg><!-- WhatsApp icon --></svg>
  </button>
  <!-- More share buttons... -->
</aside>
```

**Sidebar styling:**
```css
.share-sidebar {
  position: fixed;
  right: calc(50vw - 530px);   /* Centered relative to container */
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  gap: 1rem;
  z-index: 50;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}

/* Show sidebar when in viewport */
.share-sidebar.is-visible {
  opacity: 1;
  pointer-events: auto;
}

/* Mobile: horizontal strip */
@media (max-width: 1059px) {
  .share-sidebar {
    position: static;
    flex-direction: row;
    justify-content: center;
    width: 100%;
    margin: 2rem 0;
    opacity: 1;
    pointer-events: auto;
    transform: none;
  }
}

.share-btn {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s ease;
  position: relative;
}

.share-btn:hover {
  background: var(--accent);
  color: var(--bg);
  transform: scale(1.1);
}

/* Tooltip on hover */
.share-btn::before {
  content: attr(data-tooltip);
  position: absolute;
  right: calc(100% + 10px);
  white-space: nowrap;
  background: var(--accent);
  color: var(--bg);
  padding: 0.5rem 0.75rem;
  border-radius: 4px;
  font-size: 0.75rem;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}

.share-btn:hover::before {
  opacity: 1;
}

@media (max-width: 1059px) {
  .share-btn::before { display: none; }  /* No tooltips on mobile */
}
```

### Progress Bar: Scroll-Driven Indicator

**Progress bar HTML:**
```html
<div id="scroll-progress"></div>
```

**Progress bar styling:**
```css
#scroll-progress {
  position: fixed;
  top: 0;
  left: 0;
  height: 2px;
  width: 0%;
  background: linear-gradient(to right, var(--accent), var(--accent2));
  box-shadow: 0 0 8px rgba(168, 85, 247, 0.6);
  z-index: 9999;
  pointer-events: none;
  transition: width 0.1s ease;
}
```

**Progress bar JavaScript:**
```javascript
function updateProgressBar() {
  const windowHeight = document.documentElement.scrollHeight - window.innerHeight;
  const scrolled = window.scrollY;
  const progress = (scrolled / windowHeight) * 100;
  document.getElementById('scroll-progress').style.width = progress + '%';
}

window.addEventListener('scroll', updateProgressBar);
```

### Article Metadata: Bylines, Dates, Read Time, Type

**Metadata structure:**
```html
<div class="article-meta">
  <span class="badge badge-tech">TECH</span>
  <span class="article-date">2026-04-08</span>
  <span class="article-read-time">5 min read</span>
  <span class="article-author">By Danilo M.</span>
</div>
```

**Metadata styling:**
```css
.article-meta {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  padding: 1rem 0;
  border-bottom: 1px solid var(--border);
  font-size: 0.8rem;
  flex-wrap: wrap;
}

.article-date,
.article-read-time,
.article-author {
  font-family: var(--font-mono);
  color: var(--text-dim);
  letter-spacing: 0.02em;
}

.article-author {
  font-weight: 600;
  color: var(--text);
}

.article-date::before {
  content: '📅 ';
}

.article-read-time::before {
  content: '⏱️ ';
}

.article-author::before {
  content: '✍️ ';
}
```

### Quote Styling: Large Text, Attribution, Decorative Marks

**Quote structure:**
```html
<div class="quote-section">
  <div class="quote-marks quote-marks-open">"</div>
  <blockquote class="featured-quote">
    This is a remarkable quote that challenges assumptions.
  </blockquote>
  <div class="quote-marks quote-marks-close">"</div>
</div>

<div class="quote-attribution">
  — Author Name, Source
</div>

<div class="quote-commentary">
  <p>Your commentary about the quote...</p>
</div>
```

**Quote styling:**
```css
.quote-section {
  position: relative;
  text-align: center;
  margin: 3rem 0;
}

.quote-marks {
  font-family: var(--font-head);
  font-size: 5rem;
  font-weight: 800;
  color: var(--quote-mark-color);
  line-height: 1;
  display: block;
}

.quote-marks-open { margin-bottom: -1rem; }
.quote-marks-close { margin-top: -1rem; }

.featured-quote {
  font-family: var(--font-body);
  font-size: 1.8rem;
  font-weight: 400;
  font-style: italic;
  color: var(--text);
  line-height: 1.6;
  margin: 0;
  border-left: none;
  padding-left: 0;
}

.quote-attribution {
  text-align: center;
  font-family: var(--font-mono);
  font-size: 1rem;
  color: var(--text-dim);
  font-style: italic;
  margin: 2rem 0 3rem 0;
  letter-spacing: 0.02em;
}

.quote-commentary {
  padding-top: 2rem;
  border-top: 1px solid var(--border);
}

.quote-commentary p {
  font-family: var(--font-body);
  color: var(--text);
  line-height: 1.8;
  margin-bottom: 1.5rem;
}

.quote-commentary p:last-child {
  margin-bottom: 0;
}
```

### Terminal/Code Styling: Prompts, Code Blocks, Monospace UI

**Terminal session:**
```html
<div class="terminal-session">
  <div class="terminal-header">
    <span class="terminal-prompt">$</span>
    <span class="terminal-command">curl https://example.com</span>
  </div>
  <div class="terminal-output">
    <div class="terminal-line"><strong>Title:</strong> Example</div>
  </div>
</div>
```

**Terminal styling:**
```css
.terminal-session {
  background: var(--terminal-bg);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 0;
  font-family: var(--font-mono);
  overflow: hidden;
  margin: 2rem 0;
}

.terminal-header {
  background: var(--bg2);
  padding: 1rem;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.terminal-prompt {
  color: var(--terminal-prompt);
  font-weight: 700;
}

.terminal-command {
  color: var(--terminal-text);
}

.terminal-output {
  padding: 1.5rem;
  background: var(--terminal-bg);
}

.terminal-line {
  color: var(--terminal-text);
  margin-bottom: 0.75rem;
  line-height: 1.6;
}

.terminal-line strong {
  color: var(--terminal-prompt);
  font-weight: 700;
}
```

**Code block:**
```css
code {
  font-family: var(--font-mono);
  color: var(--accent2);
  background: rgba(168, 85, 247, 0.1);
  padding: 0.2rem 0.4rem;
  border-radius: 2px;
  font-size: 0.9em;
}

pre {
  background: var(--bg);
  color: var(--accent2);
  padding: 1.5rem;
  border-radius: 4px;
  overflow-x: auto;
  margin: 2rem 0;
  font-family: var(--font-mono);
  font-size: 0.85rem;
  line-height: 1.6;
}

pre code {
  background: none;
  color: inherit;
  padding: 0;
  border-radius: 0;
}
```

### Link Styling: Hover, Focus, Visited States

**Link structure:**
```html
<a href="#" class="link">Read more</a>
<a href="#" class="link-primary">Primary link</a>
<a href="#" class="link-secondary">Secondary link</a>
```

**Link styling:**
```css
a {
  color: var(--accent);
  text-decoration: none;
  transition: color 0.3s ease;
  position: relative;
}

a:hover {
  color: var(--accent2);
  text-decoration: underline;
}

a:focus {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 2px;
}

a:visited {
  color: var(--accent);  /* Don't change visited links (privacy) */
}

/* Primary link (button-like) */
.link-primary {
  padding: 0.5rem 1rem;
  border: 2px solid var(--accent);
  border-radius: 4px;
  display: inline-block;
}

.link-primary:hover {
  background: var(--accent);
  color: var(--bg);
  text-decoration: none;
}

/* Secondary link (text-only) */
.link-secondary {
  font-weight: 600;
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 4px;
}

.link-secondary:hover {
  color: var(--accent2);
}

/* External link indicator */
a[target="_blank"]::after {
  content: ' ↗️';
  font-size: 0.85em;
}
```

### Forms: Input Fields, Labels, Focus States

**Form structure:**
```html
<form class="form">
  <label for="email" class="form-label">Email</label>
  <input type="email" id="email" class="form-input" placeholder="you@example.com">
  
  <label for="message" class="form-label">Message</label>
  <textarea id="message" class="form-textarea" rows="5"></textarea>
  
  <button type="submit" class="btn btn-primary">Send</button>
</form>
```

**Form styling:**
```css
.form {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}

.form-label {
  font-family: var(--font-body);
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--text);
  display: block;
  margin-bottom: 0.5rem;
}

.form-input,
.form-textarea {
  padding: 0.75rem 1rem;
  border: 1px solid var(--border);
  background: var(--bg2);
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 0.95rem;
  border-radius: 4px;
  transition: all 0.3s ease;
}

.form-input:focus,
.form-textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 8px rgba(168, 85, 247, 0.3);
  background: var(--surface);
}

.form-input::placeholder,
.form-textarea::placeholder {
  color: var(--text-dim);
}

.form-textarea {
  resize: vertical;
  min-height: 120px;
}
```

### Modal/Overlay Patterns

**Modal structure:**
```html
<div class="modal-backdrop" id="modal-backdrop">
  <div class="modal" role="dialog" aria-labelledby="modal-title">
    <button class="modal-close">&times;</button>
    <h2 id="modal-title" class="modal-title">Modal Title</h2>
    <p class="modal-content">Content goes here...</p>
    <button class="btn btn-primary">Action</button>
  </div>
</div>
```

**Modal styling:**
```css
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(6, 11, 16, 0.95);
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  opacity: 0;
  transition: opacity 0.3s ease;
}

.modal-backdrop.active {
  display: flex;
  opacity: 1;
}

.modal {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 2rem;
  max-width: 500px;
  width: 90%;
  position: relative;
  box-shadow: 0 0 40px rgba(168, 85, 247, 0.2);
}

.modal-close {
  position: absolute;
  top: 1rem;
  right: 1rem;
  background: none;
  border: none;
  font-size: 2rem;
  color: var(--text-dim);
  cursor: pointer;
  transition: color 0.3s ease;
}

.modal-close:hover {
  color: var(--text);
}

.modal-title {
  margin-top: 0;
  margin-bottom: 1rem;
  color: var(--text);
}

.modal-content {
  margin-bottom: 1.5rem;
  color: var(--text);
  line-height: 1.6;
}

/* Close modal on backdrop click */
.modal-backdrop.active:not(:has(.modal:hover)) {
  cursor: pointer;
}
```

### Lightbox/Gallery: Photo Viewer, Navigation, Keyboard Controls

**Lightbox structure:**
```html
<div class="lightbox" id="lightbox">
  <div class="lightbox-backdrop"></div>
  <button class="lightbox-close">&times;</button>
  <button class="lightbox-prev" aria-label="Previous photo">❮</button>
  <div class="lightbox-content">
    <img id="lightbox-image" src="..." alt="...">
  </div>
  <button class="lightbox-next" aria-label="Next photo">❯</button>
  <div class="lightbox-info">
    <span class="lightbox-counter">1 / 10</span>
  </div>
</div>
```

**Lightbox styling:**
```css
.lightbox {
  position: fixed;
  inset: 0;
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 2000;
  opacity: 0;
  transition: opacity 0.3s ease;
}

.lightbox.active {
  display: flex;
  opacity: 1;
}

.lightbox-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(6, 11, 16, 0.95);
  z-index: 1;
}

.lightbox-content {
  position: relative;
  z-index: 2;
  max-width: 90vw;
  max-height: 90vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

.lightbox-image {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

.lightbox-close {
  position: absolute;
  top: 1rem;
  right: 1rem;
  z-index: 3;
  background: none;
  border: none;
  font-size: 3rem;
  color: var(--text);
  cursor: pointer;
}

.lightbox-prev,
.lightbox-next {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 3;
  background: transparent;
  border: none;
  font-size: 2.5rem;
  color: var(--accent);
  cursor: pointer;
  padding: 1rem;
  transition: color 0.3s ease;
}

.lightbox-prev:hover,
.lightbox-next:hover {
  color: var(--accent2);
}

.lightbox-prev { left: 1rem; }
.lightbox-next { right: 1rem; }

.lightbox-info {
  position: absolute;
  bottom: 1rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 3;
  background: rgba(6, 11, 16, 0.8);
  padding: 0.5rem 1rem;
  border-radius: 4px;
  color: var(--text);
  font-family: var(--font-mono);
}

.lightbox-counter {
  font-size: 0.9rem;
}
```

### Footer: Content Structure, Spacing, Links

**Footer structure:**
```html
<footer class="site-footer">
  <div class="footer-content">
    <div class="footer-section">
      <h3>danix.xyz</h3>
      <p>Developer, designer, and writer.</p>
    </div>
    
    <div class="footer-section">
      <h4>Links</h4>
      <ul>
        <li><a href="/">Home</a></li>
        <li><a href="/articles">Articles</a></li>
        <li><a href="/about">About</a></li>
      </ul>
    </div>
    
    <div class="footer-section">
      <h4>Social</h4>
      <ul>
        <li><a href="https://github.com" target="_blank">GitHub</a></li>
        <li><a href="https://twitter.com" target="_blank">X/Twitter</a></li>
      </ul>
    </div>
  </div>
  
  <div class="footer-bottom">
    <p>&copy; 2026 Danilo M. All rights reserved.</p>
  </div>
</footer>
```

**Footer styling:**
```css
.site-footer {
  background: var(--bg2);
  border-top: 1px solid var(--border);
  padding: 3rem 2rem 2rem;
  margin-top: 4rem;
}

.footer-content {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 2rem;
  max-width: 1080px;
  margin: 0 auto 2rem;
}

.footer-section h3,
.footer-section h4 {
  font-family: var(--font-head);
  font-size: 1rem;
  margin-bottom: 1rem;
  color: var(--text);
}

.footer-section p {
  color: var(--text-dim);
  line-height: 1.6;
  font-size: 0.95rem;
}

.footer-section ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

.footer-section li {
  margin-bottom: 0.5rem;
}

.footer-section a {
  color: var(--text-dim);
  text-decoration: none;
  transition: color 0.3s ease;
}

.footer-section a:hover {
  color: var(--accent);
}

.footer-bottom {
  text-align: center;
  padding-top: 2rem;
  border-top: 1px solid var(--border);
  color: var(--text-dim);
  font-size: 0.85rem;
}

.footer-bottom p {
  margin: 0;
}
```

### Loading/Error States: Skeleton Screens, Error Messages, Spinners

**Loading skeleton:**
```html
<div class="skeleton-card">
  <div class="skeleton-image"></div>
  <div class="skeleton-content">
    <div class="skeleton-line"></div>
    <div class="skeleton-line"></div>
  </div>
</div>
```

**Skeleton styling:**
```css
@keyframes shimmer {
  0% { background-position: -1000px 0; }
  100% { background-position: 1000px 0; }
}

.skeleton {
  background: linear-gradient(90deg, var(--bg2) 25%, var(--surface) 50%, var(--bg2) 75%);
  background-size: 1000px 100%;
  animation: shimmer 2s infinite;
}

.skeleton-image {
  width: 100%;
  height: 200px;
  border-radius: 4px;
  margin-bottom: 1rem;
}

.skeleton-line {
  height: 12px;
  border-radius: 4px;
  margin-bottom: 0.75rem;
}

.skeleton-line:last-child {
  margin-bottom: 0;
}
```

**Error message:**
```html
<div class="error-message">
  <span class="error-icon">⚠️</span>
  <p>Something went wrong. Please try again.</p>
  <button class="btn btn-sm">Retry</button>
</div>
```

**Error styling:**
```css
.error-message {
  background: rgba(236, 72, 153, 0.1);
  border: 1px solid var(--type-photo);
  border-radius: 4px;
  padding: 1.5rem;
  margin: 1rem 0;
  display: flex;
  align-items: center;
  gap: 1rem;
}

.error-icon {
  font-size: 1.5rem;
}

.error-message p {
  margin: 0;
  color: var(--text);
}
```

**Spinner/loading indicator:**
```css
@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

.spinner {
  width: 40px;
  height: 40px;
  border: 4px solid var(--border);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 1s linear infinite;
}
```

---

## 6. Icons & Icon Fonts

### Philosophy: Premium Monochrome Design

Icons are part of the visual language, not decorative afterthoughts. The danix.xyz icon system uses **Feather Icons** for consistency:

**Why Feather Icons:**
- Minimalist aesthetic, premium appearance (not clipart-style)
- Monochrome by default (pairs with any color)
- Perfect stroke weight (1.5px) for clarity without heaviness
- Comprehensive library (290+ icons covering common use cases)
- Themeable via CSS (color, stroke, size all controllable)
- Responsive at any size (crisp from 16px to 48px+)

**Design principle:** Icons should be subtle, functional, and never draw more attention than the content they support.

### Icon Font Setup

**Feather Icons CDN:**
```html
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.css">
```

Or via npm for bundled projects:
```bash
npm install feather-icons
```

**Icon markup:**
```html
<!-- Feather icons use SVG sprite approach -->
<i data-feather="calendar"></i>
<i data-feather="clock"></i>
<i data-feather="share-2"></i>
<i data-feather="send"></i>
```

**JavaScript initialization (required for SVG rendering):**
```javascript
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.js"></script>
<script>
  feather.replace();  // Converts data-feather attributes to SVG
</script>
```

Or in vanilla JS:
```javascript
document.addEventListener('DOMContentLoaded', () => {
  feather.replace();
});
```

**Why SVG not font:**
- SVG icons are crisp at any size
- Better accessibility (semantic SVG)
- Easier to style individually
- No font loading issues or fallbacks needed

### Icon Sizing Scale

Icons scale responsively based on context:

```
16px (0.85rem)  — Small metadata, secondary actions
20px (1.15rem)  — Default, most contexts
24px (1.4rem)   — Buttons, interactive elements
32px (1.9rem)   — Large buttons, featured actions
48px (2.8rem)   — Hero elements, major CTAs
```

**Implementation:**
```css
/* Small icons (metadata, secondary) */
.icon-sm {
  width: 16px;
  height: 16px;
  stroke-width: 1.5;
}

/* Default icon size */
.icon {
  width: 20px;
  height: 20px;
  stroke-width: 1.5;
}

/* Large icons (buttons) */
.icon-lg {
  width: 24px;
  height: 24px;
  stroke-width: 1.5;
}

/* Extra large (featured) */
.icon-xl {
  width: 32px;
  height: 32px;
  stroke-width: 1.5;
}

/* Responsive sizing with clamp() */
.icon {
  width: clamp(20px, 5vw, 32px);
  height: clamp(20px, 5vw, 32px);
  stroke-width: 1.5;
}
```

### Icon Colors: Context-Dependent Theming

Icons inherit or explicitly use colors based on context. **Never use hard-coded colors—always use CSS custom properties:**

**Primary icon (text color):**
```css
.icon-primary {
  color: var(--text);
  stroke: var(--text);
}

.icon-primary-dim {
  color: var(--text-dim);
  stroke: var(--text-dim);
}
```

**Interactive icon (accent color):**
```css
.icon-accent {
  color: var(--accent);
  stroke: var(--accent);
}

.icon-accent2 {
  color: var(--accent2);
  stroke: var(--accent2);
}
```

**Type-specific icon (article color):**
```css
.icon-type-tech {
  color: var(--type-tech);
  stroke: var(--type-tech);
}

.icon-type-quote {
  color: var(--type-quote);
  stroke: var(--type-quote);
}

/* Works for all 5 article types */
```

**Disabled/muted icon:**
```css
.icon-muted {
  color: var(--muted);
  stroke: var(--muted);
  opacity: 0.6;
}
```

**Pattern for automatic theming:**
```css
[data-feather] {
  color: currentColor;           /* Inherit from parent text color */
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;         /* Feather style */
  stroke-linejoin: round;        /* Feather style */
}
```

### Icon Stroke: Weight and Line Style

**Feather icons use consistent stroke properties:**

```css
[data-feather] {
  stroke: currentColor;
  stroke-width: 1.5;             /* Feather default: not too thin, not too thick */
  stroke-linecap: round;         /* Rounded line endings (premium look) */
  stroke-linejoin: round;        /* Rounded corners (premium look) */
  fill: none;                    /* Icons are outline, not filled */
}
```

**Stroke width adjustments (use sparingly):**
```css
/* Thinner for smaller sizes (16px) */
.icon-sm {
  stroke-width: 1.5;
}

/* Default for medium sizes (20px+) */
.icon,
.icon-lg {
  stroke-width: 1.5;
}

/* Never use stroke-width > 2 (looks heavy) */
```

**When to adjust stroke:**
- Keep stroke-width at 1.5 for almost all cases
- Only adjust if icon appears too thin or thick at specific sizes
- Test at actual display size before adjusting

### Article Metadata Icons

**Common metadata icons:**

| Icon | Name | Usage | Example |
|---|---|---|---|
| 📅 | `calendar` | Publication date | "2026-04-08" |
| ⏱️ | `clock` | Read time | "5 min read" |
| ✍️ | `user` | Author name | "By Danilo M." |
| 🏷️ | `tag` | Article category/type | "TECH" badge |
| 💬 | `message-circle` | Comments count | "12 comments" |
| 🔗 | `link` | External link | "Read on source" |

**Metadata icon implementation:**
```html
<div class="article-meta">
  <span class="meta-item">
    <i data-feather="calendar" class="icon-sm icon-muted"></i>
    <time datetime="2026-04-08">2026-04-08</time>
  </span>
  <span class="meta-item">
    <i data-feather="clock" class="icon-sm icon-muted"></i>
    <span>5 min read</span>
  </span>
  <span class="meta-item">
    <i data-feather="user" class="icon-sm icon-muted"></i>
    <span>Danilo M.</span>
  </span>
</div>
```

**Metadata icon styling:**
```css
.article-meta {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  flex-wrap: wrap;
}

.meta-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.8rem;
  color: var(--text-dim);
}

.meta-item [data-feather] {
  color: var(--text-dim);
  width: 16px;
  height: 16px;
  stroke-width: 1.5;
  flex-shrink: 0;
}
```

### Social Sharing Icons

**Social platform icons (Feather alternatives):**

Since Feather doesn't have brand-specific social icons, use a minimal approach:

```html
<a href="..." class="share-btn" data-platform="twitter">
  <i data-feather="share-2"></i>
  <span class="sr-only">Share on X/Twitter</span>
</a>

<a href="..." class="share-btn" data-platform="linkedin">
  <i data-feather="share-2"></i>
  <span class="sr-only">Share on LinkedIn</span>
</a>
```

**Or use platform-specific generic icons:**
```html
<!-- Generic share icon -->
<i data-feather="share-2"></i>

<!-- Platform variations -->
<i data-feather="external-link"></i>    <!-- For external links -->
<i data-feather="send"></i>             <!-- For messaging/share -->
<i data-feather="mail"></i>             <!-- For email -->
```

**Social share button styling:**
```css
.share-btn {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s ease;
}

.share-btn [data-feather] {
  width: 20px;
  height: 20px;
  color: currentColor;
  stroke: currentColor;
}

.share-btn:hover {
  background: var(--accent);
  color: var(--bg);
  border-color: var(--accent);
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border-width: 0;
}
```

### Button Icons: With Text and Alone

**Icon + text button (recommended for clarity):**
```html
<button class="btn btn-primary">
  <i data-feather="send"></i>
  <span>Send Message</span>
</button>

<button class="btn btn-secondary">
  <i data-feather="download"></i>
  <span>Download</span>
</button>
```

**Button with icon styling:**
```css
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.75rem 1.5rem;
}

.btn [data-feather] {
  width: 20px;
  height: 20px;
  color: currentColor;
  stroke: currentColor;
  flex-shrink: 0;
}

.btn-primary [data-feather] {
  color: var(--bg);  /* Icon matches button text color */
}

.btn-primary:hover [data-feather] {
  color: var(--text);  /* Updates on hover */
}
```

**Icon-only button (tooltip required):**
```html
<button class="icon-btn" title="Close" aria-label="Close">
  <i data-feather="x"></i>
</button>

<button class="icon-btn" title="Menu" aria-label="Open menu">
  <i data-feather="menu"></i>
</button>
```

**Icon-only button styling:**
```css
.icon-btn {
  width: 44px;                   /* Accessible touch target */
  height: 44px;
  border-radius: 4px;
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s ease;
  position: relative;
}

.icon-btn [data-feather] {
  width: 24px;
  height: 24px;
  color: currentColor;
}

.icon-btn:hover {
  background: var(--surface);
  color: var(--accent);
}

.icon-btn:focus {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Tooltip on hover */
.icon-btn::after {
  content: attr(title);
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
  background: var(--accent);
  color: var(--bg);
  padding: 0.5rem 0.75rem;
  border-radius: 4px;
  font-size: 0.75rem;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}

.icon-btn:hover::after {
  opacity: 1;
}

@media (max-width: 768px) {
  .icon-btn::after { display: none; }  /* No tooltip on touch */
}
```

### Form Icons: Input Validation, Search, etc.

**Input field with icon:**
```html
<div class="form-group">
  <label for="search">Search articles</label>
  <div class="input-wrapper">
    <i data-feather="search" class="input-icon"></i>
    <input type="text" id="search" placeholder="Type to search...">
  </div>
</div>

<div class="form-group">
  <label for="email">Email</label>
  <div class="input-wrapper">
    <input type="email" id="email" placeholder="you@example.com">
    <i data-feather="check-circle" class="input-icon input-valid"></i>
  </div>
</div>

<div class="form-group">
  <label for="password">Password</label>
  <div class="input-wrapper has-error">
    <input type="password" id="password" placeholder="••••••••">
    <i data-feather="alert-circle" class="input-icon input-error"></i>
  </div>
  <span class="error-text">Password is too short</span>
</div>
```

**Form input icon styling:**
```css
.input-wrapper {
  position: relative;
  display: flex;
  align-items: center;
}

.form-input {
  padding-left: 2.5rem;  /* Space for icon on left */
  padding-right: 2.5rem; /* Space for validation icon on right */
}

.input-icon {
  position: absolute;
  width: 20px;
  height: 20px;
  color: var(--text-dim);
  pointer-events: none;
}

.input-icon:first-of-type {
  left: 0.75rem;  /* Search/prefix icon on left */
}

.input-icon:last-of-type {
  right: 0.75rem;  /* Validation icon on right */
}

/* Valid input state */
.form-group.valid .input-valid {
  color: var(--accent2);  /* Green checkmark */
}

/* Error input state */
.form-group.has-error .form-input {
  border-color: var(--type-photo);  /* Pink border */
}

.form-group.has-error .input-error {
  color: var(--type-photo);  /* Red alert icon */
}

.error-text {
  display: block;
  margin-top: 0.5rem;
  font-size: 0.8rem;
  color: var(--type-photo);
}
```

### Icon States: Hover, Active, Disabled

**Interactive icon states:**
```css
/* Default state */
[data-feather] {
  color: var(--text);
  transition: all 0.3s ease;
}

/* Hover state */
a [data-feather]:hover,
button [data-feather]:hover {
  color: var(--accent);
  transform: scale(1.1);
}

/* Active/focused state */
a [data-feather]:focus,
button [data-feather]:focus {
  color: var(--accent);
}

/* Disabled state */
[data-feather][aria-disabled="true"],
.disabled [data-feather] {
  color: var(--muted);
  opacity: 0.5;
  cursor: not-allowed;
}

/* Pressed/active state */
button.active [data-feather] {
  color: var(--accent2);
  transform: scale(0.95);
}
```

### Animated Icons

Some icons can have subtle animations for emphasis or status:

**Rotating icon (loading):**
```css
@keyframes icon-spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

.icon-loading {
  animation: icon-spin 2s linear infinite;
}
```

**Pulse icon (attention):**
```css
@keyframes icon-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.5; }
}

.icon-pulse {
  animation: icon-pulse 2s ease-in-out infinite;
}
```

**Bounce icon (urgency):**
```css
@keyframes icon-bounce {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-4px); }
}

.icon-bounce {
  animation: icon-bounce 1s ease-in-out infinite;
}
```

**Implementation:**
```html
<!-- Loading indicator -->
<i data-feather="loader" class="icon-loading"></i>

<!-- Notification badge -->
<i data-feather="alert-circle" class="icon-pulse"></i>

<!-- Important action -->
<i data-feather="bell" class="icon-bounce"></i>
```

### Icon Accessibility

**Screen reader considerations:**

Always provide text alternatives for icon-only content:

```html
<!-- Icon only: needs label -->
<button class="icon-btn" aria-label="Close dialog">
  <i data-feather="x" aria-hidden="true"></i>
</button>

<!-- Icon + text: aria-hidden on icon -->
<button class="btn btn-primary">
  <i data-feather="send" aria-hidden="true"></i>
  <span>Send</span>
</button>

<!-- Decorative icon: explicitly hidden -->
<div class="meta-item">
  <i data-feather="calendar" aria-hidden="true"></i>
  <span>2026-04-08</span>
</div>
```

**Pattern: Hide decorative icons from screen readers**
```css
[aria-hidden="true"] {
  pointer-events: none;
}
```

**Color alone is not enough:**
- Never use icon color alone to convey status
- Pair with text or pattern: "✓ Complete" not just a green checkmark
- Verified in Section 7 (Accessibility)

### Feather Icons Quick Reference

**Common icons used across danix.xyz:**

```
NAVIGATION & UI
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
menu, x, chevron-left, chevron-right, arrow-right
search, home, settings, user, log-out

ARTICLE METADATA
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
calendar, clock, user, tag, message-circle, link

ACTIONS & BUTTONS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
send, download, upload, refresh, save, trash-2
edit, copy, share-2, external-link, download

FORMS & VALIDATION
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
mail, lock, unlock, eye, eye-off, check-circle
alert-circle, info, help-circle

SOCIAL & SHARING
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
share-2, send, mail, heart, star, bookmark

STATUS & FEEDBACK
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
check, x, loader, alert-circle, info, help-circle
```

For full icon list: https://feathericons.com

### Icon Implementation Checklist

When adding an icon to the design:

- [ ] Icon chosen from Feather Icons library
- [ ] Size is appropriate (16px, 20px, 24px, 32px)
- [ ] Color uses CSS custom property (never hard-coded)
- [ ] Icon-only elements have `aria-label` and `aria-hidden`
- [ ] Icon + text: icon has `aria-hidden="true"`
- [ ] Decorative icons: `aria-hidden="true"`
- [ ] Hover/focus states are defined
- [ ] Works in both dark and light modes
- [ ] Touch targets are ≥44px (icon-only buttons)
- [ ] Stroke width is 1.5 (Feather default)
- [ ] Stroke cap/join are rounded (`stroke-linecap: round`)

---

## 7. Animations & Effects

### Animation Philosophy: Subtle, Purposeful, Accessible

Animations serve a purpose: guide attention, provide feedback, create delight. They should never distract or slow down the user experience.

**Principles:**
- **Subtle:** Animations are felt, not noticed
- **Purposeful:** Every animation communicates something (loading, transition, feedback)
- **Fast:** Most animations complete in 200–400ms
- **Accessible:** `prefers-reduced-motion` is always respected
- **Performant:** GPU-accelerated, no layout thrashing

**When to animate:**
- ✅ State changes (hover, click, focus)
- ✅ Transitions between pages or sections
- ✅ Feedback (success, error, loading)
- ✅ Entrance animations (scroll reveal)
- ❌ Autoplaying animations (distracting)
- ❌ Long loops (hypnotizing, annoying)
- ❌ Motion sickness triggers (rapid spinning, flashing)

### Transition Timing: Duration & Easing

**Transition duration scale:**

| Speed | Duration | Use Case |
|---|---|---|
| **Instant** | 0ms | No transition (rarely used) |
| **Fast** | 100ms | Hover states, quick feedback |
| **Normal** | 300ms | Color changes, opacity shifts |
| **Slow** | 500ms | Page transitions, major changes |
| **Very Slow** | 800ms+ | Hero animations, entrance effects |

**Easing functions (choose based on effect):**

```css
/* Ease-out: Quick start, slow end (most natural for interactions) */
transition: all 0.3s ease-out;
/* Good for: Fade in, opacity changes, button hovers */

/* Linear: Constant speed (for loading, progress) */
animation: spin 2s linear infinite;
/* Good for: Spinners, progress bars, continuous motion */

/* Ease-in-out: Smooth acceleration and deceleration */
transition: all 0.3s ease-in-out;
/* Good for: Modal appearances, slide transitions */

/* Cubic-bezier: Custom easing for special effects */
transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
/* Good for: Bounce effects, playful interactions */
```

**Implementation pattern:**
```css
/* Fast feedback (100ms) */
.button:hover { transition: all 0.1s ease-out; }

/* Normal interaction (300ms) */
a { transition: color 0.3s ease-out; }

/* Page transition (500ms) */
.page-enter { animation: fadeIn 0.5s ease-out; }

/* Entrance animation (800ms) */
.hero-title { animation: slideUp 0.8s ease-out; }
```

### CSS Transitions: Hover States, Color Changes, Opacity

**Smooth color transitions on hover:**
```css
a {
  color: var(--accent);
  transition: color 0.3s ease-out;
}

a:hover {
  color: var(--accent2);
}

/* Works in both dark and light modes */
```

**Button hover effect (scale + color):**
```css
.button {
  background: var(--accent);
  color: var(--bg);
  transition: all 0.3s ease-out;
}

.button:hover {
  background: var(--accent2);
  transform: scale(1.05);
}

.button:active {
  transform: scale(0.98);
}
```

**Opacity fade (for dimming/emphasis):**
```css
.card {
  opacity: 1;
  transition: opacity 0.3s ease-out;
}

.card:hover {
  opacity: 0.9;
}

/* Disabled state fade */
.card.disabled {
  opacity: 0.5;
  pointer-events: none;
}
```

**Border/shadow transitions (for elevation):**
```css
.card {
  border: 1px solid var(--border);
  box-shadow: 0 0 40px var(--accent-glow);
  transition: box-shadow 0.3s ease-out;
}

.card:hover {
  box-shadow: 0 0 60px var(--accent-glow);
}
```

**What NOT to transition:**
```css
/* ❌ Bad: Transform on width (causes jank) */
.menu { width: 200px; transition: width 0.3s; }
.menu.open { width: 100%; }

/* ✅ Good: Use transform instead */
.menu { transform: translateX(-100%); transition: transform 0.3s; }
.menu.open { transform: translateX(0); }
```

### CSS Animations: Keyframes, Duration, Timing

**Fade-in animation (entrance):**
```css
@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

.article-card {
  animation: fadeIn 0.5s ease-out;
}
```

**Slide-up animation (entrance with movement):**
```css
@keyframes slideUp {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.hero-title {
  animation: slideUp 0.8s ease-out;
}
```

**Scale pulse animation (attention):**
```css
@keyframes scalePulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.05); }
}

.cta-button {
  animation: scalePulse 2s ease-in-out infinite;
}
```

**Rotate animation (loading spinner):**
```css
@keyframes rotate {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

.spinner {
  animation: rotate 2s linear infinite;
}
```

**Shimmer animation (loading skeleton):**
```css
@keyframes shimmer {
  0% { background-position: -1000px 0; }
  100% { background-position: 1000px 0; }
}

.skeleton {
  background: linear-gradient(90deg, var(--bg2) 25%, var(--surface) 50%, var(--bg2) 75%);
  background-size: 1000px 100%;
  animation: shimmer 2s infinite;
}
```

**Animation best practices:**
```css
/* Avoid infinite animations unless necessary */
.element { animation: fadeIn 0.5s ease-out; } /* Finite */

/* Use infinite only for looping effects (spinners, pulse) */
.spinner { animation: rotate 2s linear infinite; } /* Infinite ok */

/* Provide animation-delay for staggered effects */
.card:nth-child(1) { animation: slideUp 0.8s ease-out 0s; }
.card:nth-child(2) { animation: slideUp 0.8s ease-out 0.1s; }
.card:nth-child(3) { animation: slideUp 0.8s ease-out 0.2s; }
```

### Scroll-Driven Animations: Fade-In, Slide-In

**Scroll reveal with IntersectionObserver:**
```javascript
const revealElements = document.querySelectorAll('[data-reveal]');

const revealObserver = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      entry.target.classList.add('revealed');
      revealObserver.unobserve(entry.target);  // Animate once
    }
  });
}, { threshold: 0.1, rootMargin: '0px 0px -50px 0px' });

revealElements.forEach((el) => revealObserver.observe(el));
```

**CSS for scroll-reveal:**
```css
[data-reveal] {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.6s ease-out, transform 0.6s ease-out;
}

[data-reveal].revealed {
  opacity: 1;
  transform: translateY(0);
}

/* Stagger effect for multiple elements */
[data-reveal]:nth-child(1) { transition-delay: 0s; }
[data-reveal]:nth-child(2) { transition-delay: 0.1s; }
[data-reveal]:nth-child(3) { transition-delay: 0.2s; }
```

**HTML markup for scroll reveal:**
```html
<div class="article-grid">
  <article data-reveal>...</article>
  <article data-reveal>...</article>
  <article data-reveal>...</article>
</div>
```

### Matrix Rain Animation: Canvas-Based, Opacity, Performance

**Canvas setup in HTML:**
```html
<canvas id="matrix-canvas"></canvas>
```

**Canvas styling:**
```css
#matrix-canvas {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  z-index: 0;
  pointer-events: none;        /* Don't block interactions */
  display: block;
}

/* Dark mode opacity */
#matrix-canvas { opacity: 0.13; }

/* Light mode opacity (more visible) */
html.theme-light #matrix-canvas { opacity: 0.18; }
```

**Canvas JavaScript (simplified example):**
```javascript
const canvas = document.getElementById('matrix-canvas');
const ctx = canvas.getContext('2d');

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

const chars = '01アイウエオカキクケコサシスセソタチツテト';
const charArray = chars.split('');
const fontSize = 16;
const columns = Math.floor(canvas.width / fontSize);
const drops = Array(columns).fill(0).map(() => Math.random() * canvas.height);

function drawMatrix() {
  ctx.fillStyle = 'rgba(6, 11, 16, 0.05)';  /* Dark mode: navy with opacity */
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  ctx.fillStyle = 'rgba(0, 255, 136, 0.4)';  /* Green text */
  ctx.font = `${fontSize}px 'JetBrains Mono'`;

  for (let i = 0; i < drops.length; i++) {
    const char = charArray[Math.floor(Math.random() * charArray.length)];
    ctx.fillText(char, i * fontSize, drops[i] * fontSize);

    if (drops[i] * fontSize > canvas.height && Math.random() > 0.975) {
      drops[i] = 0;
    }
    drops[i] += 0.5;  /* Speed of fall */
  }
}

function animateMatrix() {
  drawMatrix();
  requestAnimationFrame(animateMatrix);
}

animateMatrix();

/* Adjust opacity on theme change */
document.addEventListener('themechange', (e) => {
  ctx.fillStyle = e.detail.isDark 
    ? 'rgba(6, 11, 16, 0.05)'
    : 'rgba(240, 244, 248, 0.05)';
});
```

**Light mode color adjustment:**
```javascript
/* In light mode, use darker green and adjusted opacity */
if (document.documentElement.classList.contains('theme-light')) {
  ctx.fillStyle = 'rgba(0, 143, 90, 0.3)';  /* Darker green for light bg */
  // Adjust opacity of background fill
  ctx.fillStyle = 'rgba(240, 244, 248, 0.05)';
}
```

**Performance notes:**
- Use `requestAnimationFrame` for smooth 60fps animation
- Keep opacity low (0.13 dark, 0.18 light) so matrix doesn't interfere with text
- Reduce character density on mobile devices
- Consider pausing animation when tab is hidden (`visibilitychange` event)

### Hero Text Glitch Effect: Chromatic Aberration Style

**Glitch effect with text shadows:**
```css
@keyframes glitch-1 {
  0%, 100% { text-shadow: 0 0 80px rgba(168, 85, 247, 0.18); }
  50% { text-shadow: -2px 0 80px rgba(255, 0, 0, 0.2), 2px 0 80px rgba(0, 255, 255, 0.2); }
}

@keyframes glitch-2 {
  0%, 100% { text-shadow: 0 0 120px rgba(168, 85, 247, 0.08); }
  50% { text-shadow: 2px 0 120px rgba(255, 0, 0, 0.1), -2px 0 120px rgba(0, 255, 255, 0.1); }
}

.hero-name {
  animation: glitch-1 3s ease-in-out infinite;
}

.hero-name::after {
  content: attr(data-text);
  position: absolute;
  left: 0;
  top: 0;
  animation: glitch-2 3s ease-in-out infinite;
}
```

**HTML for glitch effect:**
```html
<h1 class="hero-name" data-text="danix.xyz">danix.xyz</h1>
```

**Light mode glitch adjustment:**
```css
html.theme-light .hero-name {
  text-shadow: 0 0 80px rgba(124, 58, 237, 0.12), 0 0 120px rgba(124, 58, 237, 0.05);
  animation: glitch-light 3s ease-in-out infinite;
}

@keyframes glitch-light {
  0%, 100% { text-shadow: 0 0 80px rgba(124, 58, 237, 0.12); }
  50% { text-shadow: -2px 0 80px rgba(200, 0, 0, 0.15), 2px 0 80px rgba(0, 150, 200, 0.15); }
}
```

### Progress Bar Animation: Gradient, Scroll-Driven

**Progress bar HTML:**
```html
<div id="scroll-progress"></div>
```

**Progress bar styling & animation:**
```css
#scroll-progress {
  position: fixed;
  top: 0;
  left: 0;
  height: 2px;
  width: 0%;
  background: linear-gradient(to right, var(--accent), var(--accent2));
  box-shadow: 0 0 8px rgba(168, 85, 247, 0.6);
  z-index: 9999;
  pointer-events: none;
  transition: width 0.1s ease-out;
}

/* Light mode adjustment */
html.theme-light #scroll-progress {
  background: linear-gradient(to right, #7c3aed, #008f5a);
  box-shadow: 0 0 8px rgba(124, 58, 237, 0.45);
}
```

**Progress bar JavaScript:**
```javascript
function updateScrollProgress() {
  const windowHeight = document.documentElement.scrollHeight - window.innerHeight;
  const scrolled = window.scrollY;
  const progress = (scrolled / windowHeight) * 100;
  document.getElementById('scroll-progress').style.width = progress + '%';
}

window.addEventListener('scroll', updateScrollProgress);
```

### Loading Spinners: Rotating Icons, Pulsing Elements

**Rotating spinner:**
```css
@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

.spinner {
  width: 40px;
  height: 40px;
  border: 4px solid var(--border);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 1s linear infinite;
}
```

**Pulsing loader:**
```css
@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.5; }
}

.loader-dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--accent);
  display: inline-block;
  animation: pulse 1.4s ease-in-out infinite;
}

.loader-dot:nth-child(1) { animation-delay: -0.32s; }
.loader-dot:nth-child(2) { animation-delay: -0.16s; }
.loader-dot:nth-child(3) { animation-delay: 0s; }
```

**HTML for pulsing loader:**
```html
<div class="loader">
  <span class="loader-dot"></span>
  <span class="loader-dot"></span>
  <span class="loader-dot"></span>
</div>
```

### Fade/Slide Transitions: Page Transitions, Modal Appears

**Modal entrance animation:**
```css
@keyframes modalEnter {
  from {
    opacity: 0;
    transform: scale(0.95);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

.modal.active {
  animation: modalEnter 0.3s ease-out;
}

.modal-backdrop.active {
  animation: fadeIn 0.3s ease-out;
}
```

**Backdrop fade:**
```css
@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes fadeOut {
  from { opacity: 1; }
  to { opacity: 0; }
}
```

**Dropdown menu slide animation:**
```css
@keyframes slideDown {
  from {
    opacity: 0;
    transform: translateY(-10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.dropdown.open {
  animation: slideDown 0.2s ease-out;
}
```

**Page transition (if using SPAs):**
```css
@keyframes pageEnter {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.page-enter {
  animation: pageEnter 0.4s ease-out;
}
```

### Hover Lift Effects: Cards Elevating, Shadows Changing

**Card hover lift:**
```css
.card {
  transition: all 0.3s ease-out;
  box-shadow: 0 0 40px var(--accent-glow);
}

.card:hover {
  transform: translateY(-4px);      /* Lift up 4px */
  box-shadow: 0 0 60px var(--accent-glow);  /* Enhanced shadow */
}
```

**Link hover underline slide:**
```css
a {
  position: relative;
  text-decoration: none;
  color: var(--accent);
}

a::after {
  content: '';
  position: absolute;
  bottom: -2px;
  left: 0;
  width: 0;
  height: 2px;
  background: var(--accent);
  transition: width 0.3s ease-out;
}

a:hover::after {
  width: 100%;
}
```

**Icon scale on hover:**
```css
.icon-btn:hover [data-feather] {
  transform: scale(1.1);
  transition: transform 0.3s ease-out;
}
```

### Button Interactions: Scale, Color Shift on Click

**Button press effect:**
```css
.button {
  transition: all 0.3s ease-out;
}

.button:hover {
  transform: scale(1.05);
  box-shadow: 0 0 20px rgba(168, 85, 247, 0.3);
}

.button:active {
  transform: scale(0.98);  /* Slightly smaller when pressed */
}

.button:focus {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
```

**Toggle button state:**
```css
.toggle-btn {
  background: var(--muted);
  transition: all 0.3s ease-out;
}

.toggle-btn.active {
  background: var(--accent);
  color: var(--bg);
}
```

### Dropdown/Menu Animations: Slide Down, Fade In

**Mobile hamburger menu slide:**
```css
.nav-menu {
  position: fixed;
  left: 0;
  top: 60px;
  width: 100%;
  max-height: 0;
  overflow: hidden;
  background: var(--bg2);
  transition: max-height 0.3s ease-out;
}

.nav-menu.active {
  max-height: 500px;  /* Slide down */
}
```

**Dropdown with fade:**
```css
.dropdown-content {
  position: absolute;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.2s ease-out, visibility 0.2s ease-out;
}

.dropdown.open .dropdown-content {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
}
```

### Prefers-Reduced-Motion: Respecting Accessibility

**Essential: Disable animations for users with `prefers-reduced-motion`:**

```css
/* Reduced motion: remove animations */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
```

**Or disable specific animations:**
```css
@media (prefers-reduced-motion: reduce) {
  .card { transition: none; }
  .spinner { animation: none; }
  .modal { animation: none; }
  
  /* Keep essential transitions (very fast) */
  a { transition: color 0.01ms; }
}
```

**JavaScript to detect preference:**
```javascript
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

if (prefersReducedMotion) {
  // Skip heavy animations or use instant transitions
  element.style.transition = 'all 0.01ms';
} else {
  // Normal animations
  element.style.transition = 'all 0.3s ease-out';
}
```

**Pattern: Respect user preference across the site**
```css
/* Always check prefers-reduced-motion first */
@media (prefers-reduced-motion: reduce) {
  /* Animations disabled */
}

/* Default animations (only shown to users who haven't set prefers-reduced-motion) */
.element { animation: slideUp 0.8s ease-out; }
```

### Performance Considerations: GPU Acceleration, Avoiding Jank

**Use GPU-accelerated properties:**

```css
/* ✅ Good: GPU accelerated (use these) */
.element {
  transform: translateX(20px);  /* Transform */
  transform: scale(1.05);       /* Scale */
  transform: rotate(45deg);     /* Rotate */
  opacity: 0.5;                 /* Opacity */
}

/* ❌ Bad: Causes layout recalculation (avoid) */
.element {
  width: 200px;                 /* Triggers layout */
  height: 200px;                /* Triggers layout */
  margin: 20px;                 /* Triggers layout */
  left: 20px;                   /* Triggers layout if position: absolute */
}
```

**Avoid layout thrashing (simultaneous reads/writes):**

```javascript
/* ❌ Bad: Reads and writes alternate (thrashing) */
for (let i = 0; i < elements.length; i++) {
  elements[i].style.width = elements[i].offsetWidth + 10 + 'px';  // Read then write
}

/* ✅ Good: Batch reads, then batch writes */
const widths = [];
for (let i = 0; i < elements.length; i++) {
  widths.push(elements[i].offsetWidth);  // Read all first
}
for (let i = 0; i < elements.length; i++) {
  elements[i].style.width = (widths[i] + 10) + 'px';  // Write all
}
```

**Use `will-change` sparingly:**

```css
/* ✅ Good: Only on animated elements */
.card {
  will-change: transform;
  animation: slideUp 0.8s ease-out;
}

/* Remove will-change after animation */
.card.done {
  will-change: auto;
}
```

**JavaScript to manage will-change:**
```javascript
const element = document.querySelector('.card');

// Add will-change before animation
element.style.willChange = 'transform';

// Animation happens via CSS

// Remove will-change after animation completes
element.addEventListener('animationend', () => {
  element.style.willChange = 'auto';
});
```

**Debounce scroll/resize events:**

```javascript
/* ❌ Bad: Fires too frequently (jank) */
window.addEventListener('scroll', updateProgress);

/* ✅ Good: Debounced */
let ticking = false;

function updateProgress() {
  // Update progress bar
}

window.addEventListener('scroll', () => {
  if (!ticking) {
    window.requestAnimationFrame(updateProgress);
    ticking = true;
  }
  ticking = false;
});
```

**Performance checklist:**
- [ ] Animations use `transform`, `opacity` (not `width`, `height`)
- [ ] `prefers-reduced-motion` is respected
- [ ] No layout thrashing in JavaScript animations
- [ ] `will-change` removed after animations
- [ ] Scroll/resize events are debounced
- [ ] Canvas animations use `requestAnimationFrame`
- [ ] No infinite animations unless necessary
- [ ] Animation durations are appropriate (200–800ms)

### Animation Quick Reference

```
TIMING SCALE
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Fast:       0.1s – 0.2s  (quick feedback)
Normal:     0.3s – 0.4s  (interaction response)
Slow:       0.5s – 0.8s  (page transitions)
Very Slow:  0.8s+        (hero animations)

EASING FUNCTIONS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ease-out:      Quick start, slow end (default)
linear:        Constant speed (spinners, progress)
ease-in-out:   Smooth both ends (modals)
cubic-bezier:  Custom (bounces, special effects)

GPU-ACCELERATED PROPERTIES
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
transform:  (translateX, scale, rotate)
opacity:    (fade in/out)
```

---

## 8. Accessibility & Contrast

### WCAG Compliance Baseline: AA Standard Minimum

danix.xyz commits to **WCAG 2.1 Level AA** compliance across all views and components. This is the industry standard for accessibility.

**What is WCAG 2.1 Level AA?**
- **WCAG 2.1** = Web Content Accessibility Guidelines version 2.1
- **Level AA** = Intermediate compliance (middle ground between A and AAA)
- **Covers:** Color contrast, keyboard navigation, screen readers, motion, text alternatives

**Why AA, not AAA?**
- AA is the practical standard (AAA is too restrictive for real-world design)
- AA ensures accessibility for users with disabilities without limiting aesthetics
- All government and enterprise sites target AA minimum

**danix.xyz AA commitments:**
- Color contrast ≥4.5:1 for normal text, ≥3:1 for large text
- Keyboard-navigable (Tab, Enter, Space, Escape)
- Screen reader compatible (semantic HTML, ARIA where needed)
- No auto-playing animations (respects `prefers-reduced-motion`)
- Text alternatives for all images and media
- Form validation messages are accessible

**Beyond AA (AAA features where possible):**
- Contrast ≥7:1 for emphasize text (where feasible)
- Extended audio descriptions for videos
- Multiple ways to find content (search, navigation, sitemap)

### Color Contrast Ratios: Verified Pairs, Light/Dark Modes

**WCAG contrast requirements:**

| Text Type | AA Minimum | AAA (Bonus) |
|---|---|---|
| Normal text (≥14px) | 4.5:1 | 7:1 |
| Large text (≥18px) | 3:1 | 4.5:1 |
| Graphics/UI components | 3:1 | N/A |
| Focus indicators | 3:1 | N/A |

**All color pairs verified for danix.xyz:**

**Dark mode (dark background, light text):**

| Text Color | Background | Contrast | Status |
|---|---|---|---|
| `--text` (#c4d6e8) | `--bg` (#060b10) | 12.3:1 | ✅ AAA |
| `--text` (#c4d6e8) | `--surface` (#101e2d) | 11.8:1 | ✅ AAA |
| `--text-dim` (#7a9bb8) | `--bg` (#060b10) | 5.2:1 | ✅ AA |
| `--accent` (#a855f7) | `--bg` (#060b10) | 5.1:1 | ✅ AA |
| `--accent2` (#00ff88) | `--bg` (#060b10) | 7.2:1 | ✅ AAA |
| `--type-tech` (#a855f7) | `--bg` (#060b10) | 5.1:1 | ✅ AA |
| `--type-quote` (#00ff88) | `--bg` (#060b10) | 7.2:1 | ✅ AAA |
| `--type-link` (#38bdf8) | `--bg` (#060b10) | 5.8:1 | ✅ AA |

**Light mode (light background, dark text):**

| Text Color | Background | Contrast | Status |
|---|---|---|---|
| `--text` (#0d1b2a) | `--bg` (#f0f4f8) | 12.5:1 | ✅ AAA |
| `--text` (#0d1b2a) | `--surface` (#d4dff0) | 10.1:1 | ✅ AAA |
| `--text-dim` (#2e4a6a) | `--bg` (#f0f4f8) | 6.3:1 | ✅ AAA |
| `--accent` (#7c3aed) | `--bg` (#f0f4f8) | 5.5:1 | ✅ AA |
| `--accent2` (#008f5a) | `--bg` (#f0f4f8) | 5.8:1 | ✅ AA |

**How to verify contrast:**
- Use WebAIM Contrast Checker: https://webaim.org/resources/contrastchecker/
- Use Accessibility Insights browser extension
- Use Chrome DevTools: Right-click element → Inspect → Accessibility tab

**Pattern: Test before shipping**
```css
/* When adding new colors, verify contrast immediately */
.new-component {
  color: #YOUR_COLOR;
  background: var(--bg);
  /* TEST: Use WebAIM to verify contrast ratio ≥4.5:1 */
}
```

### Semantic HTML: Proper Markup, Structure, Hierarchy

**Use semantic elements, not divs:**

```html
<!-- ❌ Bad: Non-semantic divs -->
<div class="header">
  <div class="nav">
    <div class="nav-link">Home</div>
  </div>
</div>

<!-- ✅ Good: Semantic HTML -->
<header>
  <nav>
    <a href="/">Home</a>
  </nav>
</header>
```

**Semantic elements and their use:**

| Element | Purpose | Use Case |
|---|---|---|
| `<header>` | Page header | Top of page, site branding |
| `<nav>` | Navigation | Menu, links, breadcrumbs |
| `<main>` | Main content | Primary content area |
| `<article>` | Self-contained content | Blog post, news article |
| `<section>` | Thematic grouping | Chapter, content block |
| `<aside>` | Supplementary info | Sidebar, related links |
| `<footer>` | Footer content | Page footer, copyright |
| `<button>` | Clickable action | Submit, close, toggle |
| `<a>` | Link | Navigate to URL |
| `<img>` | Image | Picture with alt text |
| `<label>` | Form label | Input description |
| `<fieldset>` | Form group | Related inputs |
| `<h1>–<h6>` | Headings | Page structure |

**Heading hierarchy (critical for screen readers):**

```html
<!-- ✅ Good: Proper hierarchy -->
<h1>Article Title</h1>           <!-- One h1 per page -->
  <h2>Section 1</h2>
    <h3>Subsection 1.1</h3>
    <h3>Subsection 1.2</h3>
  <h2>Section 2</h2>

<!-- ❌ Bad: Skipped levels -->
<h1>Article Title</h1>
  <h3>Section</h3>               <!-- Skipped h2! -->
```

**Rule: One `<h1>` per page, sequential headings, no skips.**

### ARIA Labels: When and How to Use

**ARIA (Accessible Rich Internet Applications) provides extra semantic meaning:**

**When to use ARIA:**
- Icon-only buttons need labels
- Hidden elements need descriptions
- Non-standard components need roles
- Regions need landmarks

**Never use ARIA to fix bad HTML:**
```html
<!-- ❌ Bad: Using ARIA to make a div behave like a button -->
<div role="button" onclick="...">Click me</div>

<!-- ✅ Good: Use native button -->
<button>Click me</button>
```

**Common ARIA attributes:**

```html
<!-- aria-label: Text label for icon-only elements -->
<button aria-label="Close dialog">
  <i data-feather="x"></i>
</button>

<!-- aria-labelledby: Link element to a heading -->
<div aria-labelledby="dialog-title">
  <h2 id="dialog-title">Confirm Action</h2>
  <!-- Content -->
</div>

<!-- aria-describedby: Additional description -->
<input type="password" aria-describedby="pwd-hint">
<div id="pwd-hint">At least 8 characters, including uppercase</div>

<!-- aria-hidden: Hide from screen readers (decorative elements) -->
<i data-feather="star" aria-hidden="true"></i>

<!-- aria-expanded: Toggle state for menus, dropdowns -->
<button aria-expanded="false" aria-controls="menu">
  Menu
</button>
<div id="menu"><!-- Menu items --></div>

<!-- aria-live: Announce dynamic updates -->
<div aria-live="polite" aria-atomic="true">
  3 new messages
</div>
```

**Pattern: Use sparingly**
```html
<!-- Most elements don't need ARIA if HTML is semantic -->
<nav>                          <!-- Semantic, no aria-role needed -->
  <a href="/">Home</a>
  <a href="/about">About</a>
</nav>

<!-- ARIA only for non-semantic components -->
<div role="tablist">           <!-- Custom tabs need role -->
  <button role="tab" aria-selected="true">Tab 1</button>
  <button role="tab">Tab 2</button>
</div>
```

### Keyboard Navigation: Tab Order, Focus Indicators, Keyboard-Only Users

**Interactive elements must be keyboard accessible:**

```html
<!-- ✅ Keyboard navigable -->
<button>Submit</button>           <!-- Tab + Enter -->
<a href="/">Home</a>              <!-- Tab + Enter -->
<input type="text">               <!-- Tab + type -->
<textarea></textarea>             <!-- Tab + type -->
<select><option>...</option></select>  <!-- Tab + arrow keys -->

<!-- ❌ Not keyboard accessible (avoid!) -->
<div onclick="...">Click me</div>  <!-- Can't tab to it -->
<span role="button">Click me</span> <!-- Hard to tab to -->
```

**Tab order (usually automatic):**

```html
<!-- Tab moves left-to-right, top-to-bottom -->
<button>First</button>        <!-- Tab #1 -->
<input type="text">           <!-- Tab #2 -->
<button>Last</button>         <!-- Tab #3 -->
```

**When tab order needs adjustment (use sparingly):**

```html
<!-- tabindex="0": Focusable, natural order -->
<div tabindex="0">Can now be tabbed to</div>

<!-- tabindex="-1": Focusable via JavaScript, not via Tab -->
<div tabindex="-1" id="dialog">Modal (focus programmatically)</div>

<!-- ❌ Avoid: tabindex > 0 (breaks logical order) -->
<button tabindex="2">Don't do this</button>
```

**Focus indicators (ALWAYS visible):**

```css
/* ✅ Good: Keep focus visible */
button:focus {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ❌ Bad: Hiding focus (illegal under WCAG!) */
button:focus {
  outline: none;  /* DON'T DO THIS */
}

/* If you must style focus, make it obvious */
button:focus-visible {
  outline: 3px dashed var(--accent);
  outline-offset: 2px;
}
```

**Keyboard shortcut patterns:**

```javascript
/* ESC to close modal/menu */
document.addEventListener('keydown', (e) => {
  if (e.key === 'Escape') {
    closeModal();
  }
});

/* Arrow keys to navigate tabs */
document.querySelectorAll('[role="tab"]').forEach((tab) => {
  tab.addEventListener('keydown', (e) => {
    if (e.key === 'ArrowRight') {
      focusNextTab();
    }
    if (e.key === 'ArrowLeft') {
      focusPreviousTab();
    }
  });
});

/* Enter to submit form */
input.addEventListener('keydown', (e) => {
  if (e.key === 'Enter') {
    form.submit();
  }
});
```

### Screen Reader Support: Hidden Text, aria-hidden, Skip Links

**Skip navigation link (helps keyboard & screen reader users):**

```html
<a href="#main-content" class="skip-link">Skip to main content</a>

<header>
  <nav><!-- Navigation --></nav>
</header>

<main id="main-content">
  <!-- Main content -->
</main>
```

**Skip link styling (hidden but focusable):**

```css
.skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  background: var(--accent);
  color: var(--bg);
  padding: 0.5rem 1rem;
  text-decoration: none;
  z-index: 100;
}

.skip-link:focus {
  top: 0;  /* Becomes visible on focus */
}
```

**Hide decorative elements from screen readers:**

```html
<!-- Decorative icon: hide from screen readers -->
<i data-feather="star" aria-hidden="true"></i>

<!-- Icon + text: hide icon, keep text -->
<button>
  <i data-feather="send" aria-hidden="true"></i>
  <span>Send</span>
</button>

<!-- Background image: add aria-label to parent -->
<div aria-label="Team members celebrating">
  <!-- Decorative image -->
</div>
```

**Hidden content for screen readers (visible only to assistive tech):**

```html
<button aria-label="Close" aria-labelledby="close-label">
  <span id="close-label" class="sr-only">Close dialog</span>
  ×
</button>
```

**SR-only CSS class (screen-reader only):**

```css
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border-width: 0;
}
```

### Form Accessibility: Labels, Error Messages, Validation Feedback

**Accessible form structure:**

```html
<form>
  <div class="form-group">
    <label for="email">Email address</label>
    <input type="email" id="email" required aria-describedby="email-error">
    <span id="email-error" class="error" role="alert">
      <!-- Error message appears here -->
    </span>
  </div>

  <div class="form-group">
    <label for="message">Message</label>
    <textarea id="message" required></textarea>
  </div>

  <button type="submit">Send</button>
</form>
```

**Form label styling:**

```css
label {
  display: block;
  margin-bottom: 0.5rem;
  font-weight: 600;
  color: var(--text);
}

/* Labels must be associated with inputs via `for` attribute */
input, textarea, select {
  padding: 0.75rem;
  border: 1px solid var(--border);
  border-radius: 4px;
}

input:focus, textarea:focus {
  outline: 2px solid var(--accent);
  border-color: var(--accent);
}
```

**Error message display:**

```css
.form-group {
  margin-bottom: 1.5rem;
}

.error {
  display: block;
  margin-top: 0.5rem;
  color: var(--type-photo);  /* Red/pink */
  font-size: 0.85rem;
}

/* Visual error state on input */
input.error {
  border-color: var(--type-photo);
  background: rgba(236, 72, 153, 0.05);
}
```

**JavaScript validation with accessible feedback:**

```javascript
form.addEventListener('submit', (e) => {
  e.preventDefault();
  
  const email = document.getElementById('email');
  const errorDiv = document.getElementById('email-error');
  
  if (!email.value.includes('@')) {
    // Show error visually and to screen readers
    email.classList.add('error');
    errorDiv.textContent = 'Please enter a valid email address';
    errorDiv.setAttribute('role', 'alert');  // Announces to screen readers
  } else {
    email.classList.remove('error');
    errorDiv.textContent = '';
    form.submit();
  }
});
```

### Link Accessibility: Distinguishable Links, target="_blank" Handling

**Links must be visually distinct from regular text:**

```css
/* ✅ Good: Links stand out */
a {
  color: var(--accent);
  text-decoration: underline;
}

a:visited {
  color: var(--accent);  /* Don't change visited color (privacy) */
}

a:hover {
  color: var(--accent2);
}

/* ❌ Bad: Links not visually distinct */
a {
  color: var(--text);           /* Same color as body text */
  text-decoration: none;        /* No underline */
}
```

**External links (target="_blank"):**

```html
<!-- Warn users that link opens in new tab -->
<a href="https://example.com" target="_blank" rel="noopener noreferrer">
  Example Site <span aria-label="opens in new tab">↗</span>
</a>

<!-- Or use CSS pseudo-element -->
<a href="https://example.com" target="_blank" class="external-link">
  Example Site
</a>
```

**External link CSS:**

```css
.external-link::after {
  content: ' ↗';
  font-size: 0.85em;
}

/* Or use icon */
.external-link [data-feather="external-link"] {
  margin-left: 0.25rem;
}
```

**Link text must be descriptive:**

```html
<!-- ❌ Bad: "Click here" doesn't describe destination -->
<a href="/articles">Click here</a> to read articles

<!-- ✅ Good: Link text describes destination -->
<a href="/articles">Read articles</a>
```

### Button Accessibility: Button vs Link Semantics, Disabled States

**Use `<button>` for actions, `<a>` for navigation:**

```html
<!-- ✅ Button: Performs an action on the current page -->
<button onclick="deleteItem()">Delete</button>
<button type="submit">Submit Form</button>
<button type="reset">Clear Form</button>

<!-- ✅ Link: Navigates to a URL -->
<a href="/articles">View Articles</a>
<a href="https://example.com">Visit Example</a>

<!-- ❌ Wrong: Button styled as link (confusing) -->
<button onclick="goto('/articles')">View Articles</button>
```

**Button disabled state:**

```html
<button disabled>Submit</button>
```

**Disabled button styling:**

```css
button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  background: var(--muted);
  color: var(--text-dim);
}

button:disabled:hover {
  background: var(--muted);  /* No hover effect when disabled */
}
```

**Accessible disabled button (explain why):**

```html
<button disabled title="Form has errors. Please fix them.">
  Submit
</button>

<!-- Or use aria-describedby -->
<button disabled aria-describedby="submit-hint">
  Submit
</button>
<span id="submit-hint">Form has errors. Please fix them.</span>
```

### Focus Indicators: Always Visible, No Outline Removal

**WCAG requirement: Focus indicators must always be visible.**

```css
/* ✅ REQUIRED: Keep focus visible */
button:focus,
input:focus,
a:focus {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Alternative: Use box-shadow instead of outline */
button:focus {
  box-shadow: 0 0 0 3px rgba(168, 85, 247, 0.5);
}

/* ❌ ILLEGAL: Removing focus */
button:focus { outline: none; }   /* DON'T DO THIS */
button { outline: none; }         /* DON'T DO THIS */
```

**Using :focus-visible (more precise):**

```css
/* Focus visible only for keyboard, not mouse */
button:focus-visible {
  outline: 2px solid var(--accent);
}

/* No outline for mouse clicks (still accessible via keyboard) */
button:focus:not(:focus-visible) {
  outline: none;
}
```

**Ensure focus indicator has sufficient contrast:**

```css
button:focus {
  outline: 3px solid var(--accent);  /* 2px minimum, 3px better */
  outline-offset: 2px;
}

/* On dark backgrounds, outline must be light */
button:focus {
  outline-color: var(--accent);      /* Purple, high contrast */
}

/* On light backgrounds, outline must be dark */
html.theme-light button:focus {
  outline-color: var(--accent);      /* Darker purple, still high contrast */
}
```

### Text Alternatives: Alt Text for Images, Captions for Videos

**Alt text (alternative text) for images:**

```html
<!-- ✅ Good: Descriptive alt text -->
<img src="hero.jpg" alt="Developer working at desk with laptop">

<!-- ✅ Good: Decorative image (empty alt) -->
<img src="decoration.svg" alt="">

<!-- ❌ Bad: No alt attribute -->
<img src="hero.jpg">

<!-- ❌ Bad: Redundant alt text -->
<img src="hero.jpg" alt="image">
```

**Alt text best practices:**
- Describe the image's purpose or content
- Be concise (under 125 characters)
- Don't start with "image of" or "picture of"
- For charts/graphs, describe the data, not just "chart"
- For decorative images, use empty alt=""

**Captions and transcripts for videos:**

```html
<video controls>
  <source src="intro.mp4" type="video/mp4">
  <track kind="captions" src="intro-en.vtt" srclang="en" label="English">
</video>

<!-- Or provide transcript below -->
<details>
  <summary>Video transcript</summary>
  <p>
    [00:00] Hello, welcome to the channel...
    [00:15] Today we're going to discuss...
  </p>
</details>
```

### Motion & Animations: prefers-reduced-motion, Vestibular Triggers

**Always respect `prefers-reduced-motion`:**

```css
/* Default animations */
.element { animation: slideUp 0.8s ease-out; }

/* Disable for users who prefer reduced motion */
@media (prefers-reduced-motion: reduce) {
  .element {
    animation: none;
    transition: none;
  }
}
```

**Avoid vestibular triggers (motion sickness):**

```css
/* ❌ Bad: Rapid spinning (can cause vertigo) */
@keyframes spin-fast {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}
.element { animation: spin-fast 0.5s linear infinite; }

/* ✅ Good: Slower, deliberate animation */
@keyframes spin-slow {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}
.element { animation: spin-slow 2s linear infinite; }

/* ✅ Better: No spinning animation at all */
.loader { /* Use static or fade animation instead */ }
```

**Parallax scrolling risks:**

```css
/* ❌ Avoid: Extreme parallax (motion sickness) */
.parallax {
  background-attachment: fixed;
  background-position: 0 calc(var(--scroll) * 0.5px);
}

/* ✅ Minimal parallax if needed */
.subtle-parallax {
  transform: translateY(calc(var(--scroll) * 0.1px));
}

/* ✅ Better: Just don't use parallax */
.normal-scroll { /* Standard scroll */ }
```

### Color Independence: Never Convey Info with Color Alone

**Information must be conveyed with more than color:**

```html
<!-- ❌ Bad: Red color alone means error -->
<input style="border: 2px solid red;">

<!-- ✅ Good: Red color + icon + text -->
<input style="border: 2px solid red;">
<i data-feather="alert-circle" style="color: red;"></i>
<span class="error">This field is required</span>
```

**Status indicators:**

```html
<!-- ❌ Bad: Color only -->
<div style="width: 20px; height: 20px; background: green;"></div>

<!-- ✅ Good: Color + text/icon -->
<div>
  <span style="color: green;">●</span>
  <span>Online</span>
</div>
```

**Charts and graphs:**

```html
<!-- ❌ Bad: Different colors only -->
<div style="background: red; width: 30%;"></div> Sales
<div style="background: blue; width: 70%;"></div> Revenue

<!-- ✅ Good: Color + label + legend -->
<div>
  <div style="background: red; width: 30%;"></div> Sales (30%)
  <div style="background: blue; width: 70%;"></div> Revenue (70%)
</div>
```

### Testing Checklist: How to Audit Pages for Accessibility

**Manual testing (no tools needed):**

- [ ] **Keyboard navigation**: Can you navigate the entire page using Tab, Enter, Space, Escape?
- [ ] **Focus indicators**: Are focus rings visible when tabbing?
- [ ] **Headings**: Do headings follow logical order (h1, h2, h3, etc.) with no skips?
- [ ] **Links**: Are links visually distinct (color, underline)? Do link texts describe destination?
- [ ] **Images**: Do all images have descriptive alt text? Are decorative images marked?
- [ ] **Forms**: Can you complete forms with keyboard? Are errors clearly marked and announced?
- [ ] **Color contrast**: Does text have sufficient contrast (use WebAIM checker)?
- [ ] **Motion**: Do animations respect `prefers-reduced-motion`?
- [ ] **Buttons**: Can you distinguish buttons from links? Are disabled states clear?
- [ ] **Text alternatives**: Are videos captioned? Are infographics described?

**Automated testing (use tools):**

1. **WebAIM Contrast Checker** (https://webaim.org/resources/contrastchecker/)
   - Verify color contrast ratios

2. **Accessibility Insights** (Browser extension)
   - Scan for common issues
   - Guided assessments

3. **Lighthouse** (Chrome DevTools)
   - Run accessibility audit
   - Reports issues and opportunities

4. **WAVE** (Browser extension)
   - Identify errors and warnings
   - Show page structure

**Screen reader testing:**

- **NVDA** (Windows, free) — https://www.nvaccess.org/
- **JAWS** (Windows, paid) — https://www.freedomscientific.com/
- **VoiceOver** (macOS/iOS, free) — Built-in

**Test with a screen reader:**
1. Turn on screen reader
2. Navigate page with keyboard only
3. Listen for proper announcements
4. Check that interactive elements are announced
5. Verify focus order is logical

**Accessibility checklist before shipping:**

- [ ] WCAG 2.1 Level AA compliance verified
- [ ] All color contrast ratios ≥4.5:1 (tested)
- [ ] Page is keyboard navigable (tested)
- [ ] Focus indicators visible on all interactive elements
- [ ] All images have alt text
- [ ] All form inputs have labels
- [ ] Error messages are associated with inputs
- [ ] `prefers-reduced-motion` is respected
- [ ] No color used alone to convey information
- [ ] Semantic HTML used throughout
- [ ] ARIA used only when semantic HTML insufficient
- [ ] Tested with at least one screen reader
- [ ] Lighthouse accessibility audit passes

---

## 9. Implementation Patterns

### CSS Custom Properties Usage

**Declaration Location**: `:root` selector for dark mode (default), `html.theme-light` for light mode overrides, `@media (prefers-color-scheme: light)` for no-JS fallback.

**Pattern**: Define all colors and layout values as custom properties. Never hardcode colors or spacing.

```css
:root {
  /* Colors */
  --bg: #060b10;
  --surface: #101e2d;
  --text: #c4d6e8;
  --accent: #a855f7;
  
  /* Spacing scale (0.25rem increments) */
  --sp-1: 0.25rem;   /* 4px */
  --sp-2: 0.5rem;    /* 8px */
  --sp-4: 1rem;      /* 16px */
  --sp-6: 1.5rem;    /* 24px */
  --sp-8: 2rem;      /* 32px */
  
  /* Z-index scale */
  --z-base: 1;
  --z-dropdown: 10;
  --z-sticky: 50;
  --z-fixed: 100;
  --z-modal: 1000;
  
  /* Timing & easing */
  --duration-fast: 100ms;
  --duration-normal: 300ms;
  --duration-slow: 500ms;
  --ease-out: cubic-bezier(0.33, 1, 0.68, 1);
  --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
}

html.theme-light {
  --bg: #f0f4f8;
  --surface: #e8ecf2;
  --text: #0d1b2a;
  --accent: #9333ea;
  /* ... all custom properties get light-mode overrides ... */
}

@media (prefers-color-scheme: light) {
  :root {
    --bg: #f0f4f8;
    --surface: #e8ecf2;
    --text: #0d1b2a;
    --accent: #9333ea;
  }
}
```

**Rule**: Every color, font size, spacing unit, and timing value must be defined as a CSS custom property. This enables:
- Single-source-of-truth updates
- Consistent spacing and sizing across components
- Easy theme switching
- Fallback values without duplication

### Media Query Patterns (Mobile-First)

**Principle**: Write mobile styles first, then use media queries to enhance for larger screens.

```css
/* Mobile (default, <768px) */
.article-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-4);
}

/* Tablet (768px–1059px) */
@media (min-width: 768px) {
  .article-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: var(--sp-6);
  }
}

/* Desktop (≥1060px) */
@media (min-width: 1060px) {
  .article-grid {
    grid-template-columns: repeat(3, 1fr);
    gap: var(--sp-8);
  }
}
```

**Standard Breakpoints**:
- Mobile: <768px (default styles)
- Tablet: 768px–1059px
- Desktop: ≥1060px

**Pattern**: Avoid `max-width` media queries. Always use `min-width` for mobile-first.

### CSS Class Naming Conventions

**BEM-Inspired** (Block-Element-Modifier):

```css
/* Block: Independent component */
.card { }

/* Element: Part of a block (two underscores) */
.card__header { }
.card__body { }
.card__footer { }

/* Modifier: Variant or state (two hyphens) */
.card--featured { }
.card--highlighted { }

/* State classes (added/removed by JS) */
.is-active { }
.is-disabled { }
.is-loading { }

/* Utility classes (single responsibility) */
.text-center { }
.mt-4 { } /* margin-top: var(--sp-4) */
.flex { } /* display: flex */
```

**Examples**:
```html
<!-- Article card component -->
<article class="article-card article-card--tech">
  <header class="article-card__header">
    <span class="article-card__type">Tech</span>
  </header>
  <div class="article-card__body">
    <h2 class="article-card__title">Title</h2>
  </div>
  <footer class="article-card__footer is-loading">
    <button class="btn btn--primary">Read More</button>
  </footer>
</article>
```

### Component Implementation Pattern

**IIFE Encapsulation**: Vanilla JS components use Immediately Invoked Function Expression to avoid global scope pollution.

```javascript
(function() {
  'use strict';
  
  // Private state
  const config = {
    openClass: 'is-open',
    activeClass: 'is-active',
  };
  
  // Private utilities
  function handleKeydown(e) {
    if (e.key === 'Escape') closeMenu();
  }
  
  // Public API
  function init(selector) {
    const menu = document.querySelector(selector);
    if (!menu) return;
    
    menu.addEventListener('click', handleClick);
    document.addEventListener('keydown', handleKeydown);
  }
  
  function openMenu() {
    /* implementation */
  }
  
  function closeMenu() {
    /* implementation */
  }
  
  // Export public methods
  window.MenuComponent = {
    init,
    open: openMenu,
    close: closeMenu,
  };
})();

// Usage: MenuComponent.init('.primary-menu');
```

**Data Attributes for Configuration**:

```html
<!-- HTML markup -->
<div class="lightbox" data-photos="gallery-1" data-loop="true">
  <img src="photo.jpg" alt="Photo" />
</div>

<script>
(function() {
  function init() {
    document.querySelectorAll('[data-photos]').forEach(el => {
      const galleryId = el.dataset.photos;
      const shouldLoop = el.dataset.loop === 'true';
      // Use data attributes to configure component
    });
  }
  
  window.Gallery = { init };
})();
</script>
```

### Responsive Component Pattern

**Conditional Rendering**: Show/hide components based on breakpoint using display and media queries.

```css
/* Mobile-specific element (hidden on desktop) */
.mobile-nav {
  display: block;
}

@media (min-width: 1060px) {
  .mobile-nav {
    display: none;
  }
}

/* Desktop-specific element (hidden on mobile) */
.desktop-sidebar {
  display: none;
}

@media (min-width: 1060px) {
  .desktop-sidebar {
    display: block;
    position: fixed;
    width: 300px;
  }
}
```

**IntersectionObserver for Scroll-Driven Behavior**:

```javascript
(function() {
  function init() {
    const hero = document.querySelector('.hero');
    const sidebar = document.querySelector('.social-sidebar');
    
    // Show sidebar only after hero scrolls out of view
    const observer = new IntersectionObserver((entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          sidebar.classList.remove('is-visible');
        } else {
          sidebar.classList.add('is-visible');
        }
      });
    });
    
    observer.observe(hero);
  }
  
  window.ScrollTrigger = { init };
})();
```

### Flexbox & Grid Patterns

**Flexbox for 1D Layouts** (rows or columns):

```css
.horizontal-menu {
  display: flex;
  gap: var(--sp-4);
  align-items: center;
  justify-content: space-between;
}

.vertical-stack {
  display: flex;
  flex-direction: column;
  gap: var(--sp-6);
}
```

**CSS Grid for 2D Layouts**:

```css
/* Photo gallery: responsive columns */
.photo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--sp-6);
}

/* Article timeline: sidebar + content */
.article-layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-8);
}

@media (min-width: 1060px) {
  .article-layout {
    grid-template-columns: 1fr 300px; /* content + sidebar */
  }
}
```

### Typography Implementation

**Responsive Font Sizing with clamp()**:

```css
h1 {
  /* Scales from 2rem to 3.5rem as viewport grows from 320px to 1200px */
  font-size: clamp(2rem, 6vw, 3.5rem);
  line-height: 1.1;
  font-weight: 800;
  font-family: var(--font-display);
}

body {
  font-size: clamp(0.9rem, 2vw, 1rem);
  line-height: 1.8;
  font-family: var(--font-body);
}
```

**Line Height Scale**:
```css
/* Headings: tighter line height */
h1, h2, h3 { line-height: 1.2; }

/* Body text: loose line height for readability */
p, li { line-height: 1.8; }

/* UI elements: medium line height */
button, input { line-height: 1.5; }
```

### Form Implementation Pattern

**Semantic HTML with Accessibility**:

```html
<form>
  <div class="form-group">
    <label for="email" class="form-label">Email Address</label>
    <input
      type="email"
      id="email"
      name="email"
      class="form-input"
      required
      aria-describedby="email-error"
    />
    <div id="email-error" class="form-error" role="alert">
      <!-- Error message inserted by JS -->
    </div>
  </div>
  
  <button type="submit" class="btn btn--primary">Submit</button>
</form>
```

**CSS Styling**:

```css
.form-group {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  margin-bottom: var(--sp-6);
}

.form-label {
  font-weight: 600;
  color: var(--text);
}

.form-input {
  padding: var(--sp-3) var(--sp-4);
  border: 2px solid var(--border);
  border-radius: 4px;
  font-family: var(--font-body);
  font-size: 1rem;
  background: var(--surface);
  color: var(--text);
  transition: border-color var(--duration-normal) var(--ease-out);
}

.form-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(168, 85, 247, 0.1);
}

.form-input:invalid {
  border-color: #e74c3c;
}

.form-error {
  color: #e74c3c;
  font-size: 0.875rem;
  margin-top: var(--sp-2);
}
```

### Animation Implementation

**Prefer transform and opacity** for GPU acceleration:

```css
/* Good: GPU accelerated */
.fade-in {
  animation: fadeIn var(--duration-normal) var(--ease-out);
}

@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

.slide-up {
  animation: slideUp var(--duration-normal) var(--ease-out);
}

@keyframes slideUp {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Bad: causes layout thrashing */
.slide-bad {
  animation: slideBad var(--duration-normal);
}

@keyframes slideBad {
  from { height: 0; margin: 0; }
  to { height: 100px; margin: 10px; }
}
```

**Respect prefers-reduced-motion**:

```css
@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
```

### Light/Dark Theme Toggle Pattern

**HTML Structure**:

```html
<button class="theme-toggle" aria-label="Toggle dark/light mode">
  <i data-icon="sun" aria-hidden="true"></i>
  <i data-icon="moon" aria-hidden="true"></i>
</button>
```

**JavaScript Implementation**:

```javascript
(function() {
  const toggle = document.querySelector('.theme-toggle');
  const html = document.documentElement;
  const STORAGE_KEY = 'theme';
  
  function init() {
    // Load saved theme or detect system preference
    const saved = localStorage.getItem(STORAGE_KEY);
    const isDark = saved ? saved === 'dark' : 
                   window.matchMedia('(prefers-color-scheme: dark)').matches;
    
    applyTheme(isDark ? 'dark' : 'light');
    toggle?.addEventListener('click', () => toggleTheme());
  }
  
  function applyTheme(theme) {
    if (theme === 'light') {
      html.classList.add('theme-light');
      localStorage.setItem(STORAGE_KEY, 'light');
    } else {
      html.classList.remove('theme-light');
      localStorage.setItem(STORAGE_KEY, 'dark');
    }
  }
  
  function toggleTheme() {
    const isLight = html.classList.contains('theme-light');
    applyTheme(isLight ? 'dark' : 'light');
  }
  
  window.ThemeToggle = { init };
})();

// Call on page load
document.addEventListener('DOMContentLoaded', () => {
  window.ThemeToggle.init();
});
```

---

## 10. Missing Views (About, Contact, 404)

These pages are not yet mocked up but will inherit the design system. This section outlines how to apply the theming standard to pages not covered by existing mockups.

### About Page Layout

**Purpose**: Introduce the site creator, philosophy, and background.

**Structure**:
```
Hero Section (60vh)
  ↓
About Content Block
  ├─ Introductory Paragraph
  ├─ Key Skills / Interests (badges or tags)
  ├─ Timeline or Career Path (optional)
  └─ Call to Action (Contact, Portfolio link)
  ↓
Social Links (WhatsApp, Telegram, LinkedIn, X, etc.)
  ↓
Footer Navigation
```

**Design Guidelines**:

- **Hero**: Use full-bleed background image (60vh) with dark overlay, centered title "About Danilo" or similar. Follow the pattern from article pages.
- **Content Container**: Center max-width 65ch (prose), padding responsive (1rem mobile → 2rem desktop).
- **Bio Text**: Use `--font-body` (IBM Plex Sans) with line-height 1.8 for readability.
- **Skills Badges**: Use `.type-badge` pattern from Components section. Assign article-type colors (Tech/Life/Quote/Link) to skill categories.
- **Social Links**: Same as social sidebar pattern (WhatsApp, Telegram, LinkedIn, X, Facebook, Reddit, Email). Use `.social-icon` with monochrome Feather Icons.
- **Timeline** (if included): Use CSS Grid with `.timeline-item` cards. Left-aligned date/title, right-aligned description. Responsive: stack on mobile.

**Color Scheme**:
- Hero overlay: same dark gradient as article pages (`rgba(0, 0, 0, 0.7)`)
- Badge colors: `var(--type-tech)`, `var(--type-life)`, etc.
- Links: `var(--accent)` with underline on hover
- Accessibility: Ensure 4.5:1 contrast on all text

**Example HTML Structure**:

```html
<main id="main-content">
  <!-- Hero section -->
  <section class="hero hero--60vh" style="background-image: url('about-hero.jpg')">
    <div class="hero__overlay"></div>
    <h1 class="hero__title">About Danilo</h1>
  </section>
  
  <!-- About content -->
  <article class="article-content">
    <h2>Bio</h2>
    <p>Bio text here...</p>
    
    <h2>Skills</h2>
    <div class="badge-group">
      <span class="type-badge type-badge--tech">JavaScript</span>
      <span class="type-badge type-badge--life">Design</span>
      <!-- ... more badges ... -->
    </div>
    
    <h2>Get in Touch</h2>
    <div class="social-links">
      <a href="mailto:..." class="social-link" aria-label="Email">
        <i data-icon="mail" aria-hidden="true"></i>
      </a>
      <!-- ... more social links ... -->
    </div>
  </article>
  
  <!-- Footer -->
  <footer class="article-footer-nav">
    <!-- ... footer links ... -->
  </footer>
</main>
```

**CSS Pattern**:

```css
.hero--60vh {
  height: 60vh;
  position: relative;
  background-size: cover;
  background-position: center;
  display: flex;
  align-items: center;
  justify-content: center;
}

.hero__overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg, rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.4));
  z-index: var(--z-base);
}

.hero__title {
  position: relative;
  z-index: calc(var(--z-base) + 1);
  color: #fff;
  font-size: clamp(2.5rem, 8vw, 4rem);
  text-align: center;
}

.badge-group {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-4);
  margin: var(--sp-8) 0;
}

.type-badge {
  display: inline-block;
  padding: var(--sp-2) var(--sp-4);
  border-radius: 4px;
  font-size: 0.875rem;
  font-weight: 600;
  background: var(--type-tech);
  color: #000;
}

.type-badge--life { background: var(--type-life); }
.type-badge--quote { background: var(--type-quote); }
```

### Contact Page Layout

**Purpose**: Provide contact methods and optional contact form.

**Structure**:
```
Hero Section (60vh)
  ↓
Contact Form (or contact methods list)
  ├─ Name field
  ├─ Email field
  ├─ Message textarea
  ├─ Submit button
  └─ Optional: reCAPTCHA or honeypot
  ↓
OR Contact Methods (if no form)
  ├─ Email link
  ├─ Social links
  ├─ Calendar link (Calendly, etc.)
  └─ Response time expectation
  ↓
Footer Navigation
```

**Design Guidelines**:

- **Hero**: Same pattern as About page (60vh, dark overlay, centered title "Get in Touch" or similar).
- **Form Container**: Center max-width 40ch (forms are narrower for legibility). Responsive padding.
- **Form Fields**: Use `.form-group`, `.form-label`, `.form-input` patterns from Components section.
- **Form Styling**: 
  - Background: `var(--surface)`
  - Border on focus: `2px solid var(--accent)`
  - Error text: `color: #e74c3c` with `role="alert"`
  - Success message: `color: var(--type-quote)` (green) with fade-in animation
- **Submit Button**: Use `.btn btn--primary` pattern with hover state.
- **Accessibility**: Proper label associations (`aria-describedby` for errors), required field indicators, ARIA live regions for form feedback.

**Example HTML Structure**:

```html
<main id="main-content">
  <!-- Hero section -->
  <section class="hero hero--60vh" style="background-image: url('contact-hero.jpg')">
    <div class="hero__overlay"></div>
    <h1 class="hero__title">Get in Touch</h1>
  </section>
  
  <!-- Contact form -->
  <div class="contact-container">
    <form class="contact-form" method="POST" action="/contact">
      <div class="form-group">
        <label for="name" class="form-label">Name</label>
        <input
          type="text"
          id="name"
          name="name"
          class="form-input"
          required
        />
      </div>
      
      <div class="form-group">
        <label for="email" class="form-label">Email</label>
        <input
          type="email"
          id="email"
          name="email"
          class="form-input"
          required
          aria-describedby="email-error"
        />
        <div id="email-error" class="form-error" role="alert"></div>
      </div>
      
      <div class="form-group">
        <label for="message" class="form-label">Message</label>
        <textarea
          id="message"
          name="message"
          class="form-input form-textarea"
          rows="6"
          required
        ></textarea>
      </div>
      
      <!-- Honeypot (invisible to users, caught by bots) -->
      <input type="hidden" name="website" value="" />
      
      <button type="submit" class="btn btn--primary btn--large">
        Send Message
      </button>
      
      <div id="form-feedback" class="form-feedback" role="status" aria-live="polite"></div>
    </form>
  </div>
  
  <!-- Footer -->
  <footer class="article-footer-nav">
    <!-- ... footer links ... -->
  </footer>
</main>
```

**CSS Pattern**:

```css
.contact-container {
  max-width: 40ch;
  margin: var(--sp-12) auto;
  padding: 0 var(--sp-4);
}

.form-textarea {
  resize: vertical;
  min-height: 150px;
  font-family: var(--font-body);
}

.form-feedback {
  margin-top: var(--sp-6);
  padding: var(--sp-4);
  border-radius: 4px;
  text-align: center;
  display: none;
}

.form-feedback.is-success {
  display: block;
  background: rgba(0, 255, 136, 0.1);
  color: var(--type-quote);
  animation: fadeIn var(--duration-normal) var(--ease-out);
}

.form-feedback.is-error {
  display: block;
  background: rgba(231, 76, 60, 0.1);
  color: #e74c3c;
}
```

**Form Handling** (JavaScript Pattern):

```javascript
(function() {
  function init() {
    const form = document.querySelector('.contact-form');
    if (!form) return;
    
    form.addEventListener('submit', async (e) => {
      e.preventDefault();
      
      // Validate honeypot
      const honeypot = form.querySelector('input[name="website"]');
      if (honeypot.value) return; // Spam
      
      // Send form data
      const data = new FormData(form);
      try {
        const response = await fetch('/api/contact', {
          method: 'POST',
          body: data,
        });
        
        if (response.ok) {
          showFeedback('Message sent! I\'ll get back to you soon.', 'success');
          form.reset();
        } else {
          showFeedback('Error sending message. Please try again.', 'error');
        }
      } catch (err) {
        showFeedback('Network error. Please try again.', 'error');
      }
    });
  }
  
  function showFeedback(message, type) {
    const feedback = document.querySelector('#form-feedback');
    feedback.textContent = message;
    feedback.className = `form-feedback is-${type}`;
  }
  
  window.ContactForm = { init };
})();

document.addEventListener('DOMContentLoaded', () => {
  window.ContactForm.init();
});
```

### 404 Error Page Layout

**Purpose**: Handle and redirect users when pages are not found.

**Structure**:
```
Hero Section (40vh, shortened)
  ├─ Large error code: "404"
  ├─ Error message: "Page Not Found"
  └─ Subheading: "This page has wandered off into the matrix."
  ↓
Content Block
  ├─ Brief explanation
  ├─ Search box (optional)
  └─ Navigation links (Home, Blog, About, Contact)
  ↓
Footer Navigation
```

**Design Guidelines**:

- **Hero**: Shorter hero section (40vh instead of 60vh) with same dark overlay pattern. Center "404" in large display font (`font-size: clamp(4rem, 15vw, 8rem)`).
- **Error Message**: Below 404, use `--text` color with large line-height.
- **Content**: Center max-width 50ch. Friendly, helpful tone (not robotic).
- **Links**: Use `.btn btn--primary` or `.nav-link` pattern for navigation options. Include Home, Blog, About, Contact.
- **Styling**: Follow color scheme (accent color for emphasis).
- **Animation**: Optional: subtle animation on 404 number (e.g., slight rotation or scale pulse).

**Example HTML Structure**:

```html
<main id="main-content">
  <!-- Hero section (shorter) -->
  <section class="hero hero--40vh">
    <div class="hero__overlay"></div>
    <div class="hero__error">
      <h1 class="hero__error-code">404</h1>
      <p class="hero__error-message">Page Not Found</p>
      <p class="hero__error-subtitle">
        This page has wandered off into the matrix...
      </p>
    </div>
  </section>
  
  <!-- Error content -->
  <div class="error-container">
    <p>
      The page you're looking for doesn't exist or has been moved.
      Use the links below to find what you're looking for.
    </p>
    
    <div class="error-nav">
      <a href="/" class="btn btn--primary">Home</a>
      <a href="/blog" class="btn btn--secondary">Blog</a>
      <a href="/about" class="btn btn--secondary">About</a>
      <a href="/contact" class="btn btn--secondary">Contact</a>
    </div>
  </div>
  
  <!-- Footer -->
  <footer class="article-footer-nav">
    <!-- ... footer links ... -->
  </footer>
</main>
```

**CSS Pattern**:

```css
.hero--40vh {
  height: 40vh;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}

.hero__error {
  position: relative;
  z-index: calc(var(--z-base) + 1);
  text-align: center;
  color: #fff;
}

.hero__error-code {
  font-size: clamp(4rem, 15vw, 8rem);
  font-weight: 800;
  line-height: 1;
  margin-bottom: var(--sp-4);
  animation: scalePulse 3s ease-in-out infinite;
}

.hero__error-message {
  font-size: clamp(1.5rem, 4vw, 2.5rem);
  font-weight: 700;
  margin-bottom: var(--sp-2);
}

.hero__error-subtitle {
  font-size: 1rem;
  color: rgba(255, 255, 255, 0.8);
}

.error-container {
  max-width: 50ch;
  margin: var(--sp-12) auto;
  padding: 0 var(--sp-4);
  text-align: center;
}

.error-nav {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  margin-top: var(--sp-8);
}

@media (min-width: 768px) {
  .error-nav {
    flex-direction: row;
    justify-content: center;
    gap: var(--sp-6);
  }
}

@keyframes scalePulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.05); }
}

@media (prefers-reduced-motion: reduce) {
  .hero__error-code {
    animation: none;
  }
}
```

---

## 11. Appendix: Quick Reference

### CSS Custom Properties Summary

**Color Variables (Dark Mode)**:

```css
/* Background & Surface */
--bg: #060b10;            /* Page background */
--bg2: #0c1520;           /* Alternative bg */
--surface: #101e2d;       /* Card/container bg */
--border: #182840;        /* Border color */

/* Text */
--text: #c4d6e8;          /* Primary text */
--text-dim: #7a9bb8;      /* Secondary/dimmed text */
--muted: #304860;         /* Muted gray-blue */

/* Accent Colors */
--accent: #a855f7;        /* Purple primary */
--accent2: #00ff88;       /* Neon green secondary */

/* Article Type Colors */
--type-tech: #a855f7;     /* Purple */
--type-life: #f59e0b;     /* Amber */
--type-quote: #00ff88;    /* Neon green */
--type-link: #38bdf8;     /* Cyan */
--type-photo: #ec4899;    /* Pink */
```

**Spacing Scale**:

```
--sp-1: 0.25rem   (4px)
--sp-2: 0.5rem    (8px)
--sp-3: 0.75rem   (12px)
--sp-4: 1rem      (16px)
--sp-6: 1.5rem    (24px)
--sp-8: 2rem      (32px)
--sp-12: 3rem     (48px)
--sp-16: 4rem     (64px)
```

**Z-Index Scale**:

```
--z-base: 1           /* Default content */
--z-dropdown: 10      /* Dropdowns, tooltips */
--z-sticky: 50        /* Sticky headers */
--z-fixed: 100        /* Fixed navigation */
--z-modal: 1000       /* Modals, lightbox */
```

**Typography Variables**:

```
--font-display: 'Oxanium', sans-serif       /* Headings */
--font-body: 'IBM Plex Sans', sans-serif   /* Body text */
--font-mono: 'JetBrains Mono', monospace   /* Code, UI */
```

**Timing Variables**:

```
--duration-fast: 100ms
--duration-normal: 300ms
--duration-slow: 500ms
--ease-out: cubic-bezier(0.33, 1, 0.68, 1)
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1)
```

### Responsive Breakpoints

```css
/* Mobile (default) */
/* No media query needed */

/* Tablet and up */
@media (min-width: 768px) {
  /* Tablet-specific styles */
}

/* Desktop and up */
@media (min-width: 1060px) {
  /* Desktop-specific styles */
}
```

### Common CSS Patterns

**Flexbox row** (horizontal layout):
```css
display: flex;
gap: var(--sp-4);
align-items: center;
```

**Flexbox column** (vertical stack):
```css
display: flex;
flex-direction: column;
gap: var(--sp-6);
```

**Responsive grid** (auto-columns):
```css
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: var(--sp-6);
```

**Prose container** (readable text width):
```css
max-width: 65ch;
margin: 0 auto;
padding: var(--sp-4);
line-height: 1.8;
```

**Center content** (vertical & horizontal):
```css
display: flex;
align-items: center;
justify-content: center;
```

**Truncate text** (single line):
```css
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
```

**Multi-line truncate** (3 lines max):
```css
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
```

### Common Utility Classes

Create these utility classes for reusable patterns:

```css
/* Text alignment */
.text-center { text-align: center; }
.text-left { text-align: left; }
.text-right { text-align: right; }

/* Margin utilities */
.mt-4 { margin-top: var(--sp-4); }
.mb-6 { margin-bottom: var(--sp-6); }
.mx-auto { margin-left: auto; margin-right: auto; }

/* Flex utilities */
.flex { display: flex; }
.flex-col { flex-direction: column; }
.gap-4 { gap: var(--sp-4); }
.items-center { align-items: center; }
.justify-center { justify-content: center; }

/* Display utilities */
.block { display: block; }
.hidden { display: none; }
.sr-only { /* screen-reader only */ }

/* Color utilities */
.text-accent { color: var(--accent); }
.bg-surface { background: var(--surface); }
.border-border { border-color: var(--border); }
```

### Component Checklist

**Before marking a component complete, verify:**

- [ ] Works on mobile (320px), tablet (768px), desktop (1060px+)
- [ ] Dark mode tested and visually correct
- [ ] Light mode tested and color contrast meets WCAG AA (4.5:1)
- [ ] Keyboard navigable (Tab, Enter, Escape where relevant)
- [ ] Focus indicators visible on all interactive elements
- [ ] ARIA labels present for icon-only buttons
- [ ] Semantic HTML used (button vs div, a vs span, etc.)
- [ ] Images have alt text (or aria-hidden="true" if decorative)
- [ ] Form inputs have associated labels
- [ ] Error messages use role="alert" and aria-describedby
- [ ] Animations respect prefers-reduced-motion
- [ ] No hardcoded colors (use CSS custom properties)
- [ ] Spacing uses spacing scale (--sp-*)
- [ ] Animation timing uses timing scale (--duration-*)
- [ ] Z-index uses z-index scale (--z-*)
- [ ] Typography uses font scale (h1, h2, etc.)

### Performance Checklist

- [ ] CSS custom properties only used at :root and html.theme-light (not in media queries unnecessarily)
- [ ] Animations use transform and opacity (GPU accelerated)
- [ ] No width/height/margin animated (causes layout thrashing)
- [ ] Images optimized for mobile/tablet/desktop (responsive srcset if large)
- [ ] Fonts loaded with `display=swap` (Google Fonts)
- [ ] No render-blocking CSS in head (inline only critical styles)
- [ ] JavaScript modules use IIFE pattern (no global pollution)
- [ ] Event listeners use event delegation where possible
- [ ] IntersectionObserver used for lazy loading and scroll triggers
- [ ] No memory leaks (clean up event listeners when components unmount)

### Accessibility Testing Tools

**Automated**:
- **Lighthouse** (Chrome DevTools) — overall accessibility audit
- **WebAIM** (webaim.org) — WCAG contrast checker
- **WAVE** (wave.webaim.org) — accessibility errors and warnings
- **Accessibility Insights** (Microsoft) — accessibility audit and testing
- **axe DevTools** (deque.com) — automated accessibility testing

**Manual**:
- **Keyboard navigation**: Tab through page, Shift+Tab reverse, Enter/Space to activate
- **Focus indicators**: Verify 2px outline on all interactive elements
- **Color contrast**: Use WebAIM or Lighthouse to verify 4.5:1 for normal text, 3:1 for large
- **Screen readers**: Test with VoiceOver (Mac), NVDA (Windows), or JAWS
- **Zoom**: Test at 200% zoom (ensure no horizontal scroll, text remains readable)

### File Structure Template

When creating a new mockup or template file, use this structure:

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Page Title</title>
  
  <!-- Google Fonts -->
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@300;400;600;700&family=Oxanium:wght@700;800&family=JetBrains+Mono:wght@400;600;700&display=swap" rel="stylesheet">
  
  <!-- Feather Icons -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.css">
  
  <!-- CSS (inline) -->
  <style>
    /* CSS custom properties */
    :root {
      --bg: #060b10;
      /* ... all custom properties ... */
    }
    
    html.theme-light {
      --bg: #f0f4f8;
      /* ... light mode overrides ... */
    }
    
    /* Global styles */
    * { margin: 0; padding: 0; box-sizing: border-box; }
    html, body { height: 100%; }
    body { 
      background: var(--bg);
      color: var(--text);
      font-family: var(--font-body);
      line-height: 1.6;
    }
    
    /* Component styles */
    /* ... component CSS ... */
    
    /* Responsive */
    @media (min-width: 768px) { /* ... */ }
    @media (min-width: 1060px) { /* ... */ }
    
    /* Accessibility */
    @media (prefers-reduced-motion: reduce) {
      * { animation-duration: 0.01ms !important; }
    }
  </style>
</head>
<body>
  <!-- Navigation -->
  <nav class="primary-nav">
    <!-- ... nav markup ... -->
  </nav>
  
  <!-- Main content -->
  <main id="main-content">
    <!-- ... page content ... -->
  </main>
  
  <!-- Footer -->
  <footer class="footer">
    <!-- ... footer markup ... -->
  </footer>
  
  <!-- JavaScript (inline, IIFE pattern) -->
  <script>
    (function() {
      'use strict';
      
      // Component initialization
      // ... component JS ...
      
      // Initialize on page load
      document.addEventListener('DOMContentLoaded', () => {
        // Component.init();
      });
    })();
  </script>
</body>
</html>
```

### Design System Git Workflow

When updating the design system:

```bash
# 1. Make changes to mockups or CSS
# ... edit files ...

# 2. Test changes (mobile, tablet, desktop, dark/light)
python -m http.server 8000
# Open http://localhost:8000/mockup-a.html in browser
# Test at 320px, 768px, 1060px+
# Toggle theme

# 3. Verify accessibility
# - Keyboard navigation (Tab through page)
# - Focus indicators (all interactive elements)
# - Color contrast (WebAIM or Lighthouse)
# - Screen reader (NVDA or VoiceOver)

# 4. Commit changes
git add mockup-*.html docs/superpowers/specs/*.md
git commit -m "style: update theming pattern for [component]"

# 5. Push to main when ready for deployment
git push origin master  # (or create PR to main)
```

### Related Documentation

- **HANDOFF.md** — Technical implementation guide for developers
- **TESTING_GUIDE.md** — Manual testing procedures for photo gallery
- **MOCKUPS.md** — Feature breakdown for each mockup file
- **docs/superpowers/specs/** — Detailed design specs and implementation plans
- **docs/superpowers/plans/** — Implementation plans for features

---

## Conclusion

This Theming Standard serves as the source of truth for all design and implementation decisions across danix.xyz. It balances consistency with flexibility, providing clear patterns for common components while allowing room for creative implementation in future pages.

**Key takeaways**:

1. **Use CSS custom properties** for all colors, spacing, and timing—never hardcode values
2. **Mobile-first responsive design** with clear breakpoints (mobile, tablet, desktop)
3. **Dark mode first**, light mode as full-featured alternative
4. **Accessibility is non-negotiable**—WCAG AA compliance for all components
5. **Vanilla JavaScript** with IIFE encapsulation, no frameworks
6. **Semantic HTML** and proper ARIA patterns
7. **Performance-first** with GPU-accelerated animations
8. **Test thoroughly** before committing (responsive, accessible, both themes)

When in doubt, refer to existing mockups (mockup-article-single.html, mockup-article-photo.html) as implementation references. They demonstrate all patterns in production-ready code.

---

**Appendix End**
