# ACIDBATH Design System — LLM Context
Version 1.0.0 · Compact reference for AI agents. Paste this into your coding agent's system prompt or context when building components for ACIDBATH or any project using this design system.

---

## IDENTITY

This is the ACIDBATH design system — a literary, editorial design language built entirely on Iosevka type variants. It is used on the amenoacids.com blog and is portable to other projects via `design-system/tokens.css`.

**Character**: Muted, refined, warm. Not flat-material. Not neon-tech. Think: quality printed matter meets developer tooling.

---

## NEVER DO THESE

- ❌ Hardcode hex colors (`#a65c3a`) — always `var(--color-accent-primary)`
- ❌ Use fonts outside the Iosevka family (no Inter, Roboto, system-ui as primary)
- ❌ Use raw px/rem for spacing — always `var(--space-N)`
- ❌ Use `opacity: 0.5` to mute text — use `var(--color-foreground-muted)` instead
- ❌ Use `rgba()` for borders directly — use `var(--border)`
- ❌ Use `display: flex` on `<li>` (breaks list markers)
- ❌ Add `overflow-x: hidden` to body (breaks sticky elements)

---

## COLOR TOKENS

All colors are CSS custom properties. Apply theme via `data-theme` on `<html>`.

### Backgrounds (5 levels of depth)
```
--color-background          Page background (lightest / darkest)
--color-background-alt      Section fills, stripes (slightly darker in light, lighter in dark)
--color-background-elevated Cards, modals, dropdowns (semi-transparent)
--color-background-hover    Interactive hover state backgrounds
--color-background-code     Code block backgrounds
```

### Text (3 hierarchy levels — use these, not opacity)
```
--color-foreground          Headings, strong text, highest contrast
--color-foreground-alt      Body paragraphs, descriptions (slightly softer)
--color-foreground-muted    Captions, metadata, placeholders, labels
```

### Accents
```
--color-accent-primary      Links, active states, underlines, kicker dots, borders
--color-accent-secondary    Deeper hover (slightly darker than primary)
--color-accent-muted        Low-opacity fill — tag backgrounds, selection bg, inline code bg
```

### Semantic (each has foreground + *-bg background variant)
```
--color-warning    / --color-warning-bg
--color-info       / --color-info-bg
--color-success    / --color-success-bg
--color-danger     / --color-danger-bg
--color-insight    / --color-insight-bg    (accent-colored insight highlights)
--color-data       / --color-data-bg       (secondary info, data tables)
```

### Structure
```
--border            All borders, dividers, separator lines
--input             Form field borders
--ring              Focus ring color (use as box-shadow: 0 0 0 3px var(--ring))
--card              Card/surface background (semi-transparent, use with backdrop-filter)
```

### shadcn/Radix UI aliases (auto-populated from theme)
```
--background --foreground --card --card-foreground --popover --popover-foreground
--primary --primary-foreground --secondary --secondary-foreground
--muted --muted-foreground --accent --accent-foreground
--destructive --destructive-foreground
--chart-1 through --chart-5
--sidebar and all --sidebar-* variants
```

---

## FONT TOKENS

All fonts are Iosevka variants. Never use a non-Iosevka font as the primary.

```
--font-family-body     Iosevka Etoile (quasi-proportional slab — reads like serif body text)
--font-family-heading  Iosevka Curly Slab (slab variant — use for h1-h3)
--font-family-mono     Iosevka (pure monospace — code, labels, metadata, badges)
--font-family-ui       Iosevka Etoile (same as body — buttons, inputs, UI chrome)
```

### When to use each font role:
- **body**: long-form prose paragraphs
- **heading**: h1, h2, h3, section titles
- **mono**: code blocks, tags, metadata, dates, labels, nav links, kickers, badges, form inputs
- **ui**: button text, dropdown options, tooltips

### Alternative Iosevka variants (if you need more variety)
```
--font-iosevka         Pure monospace (strict)
--font-iosevka-curly   Monospace with curly braces (friendlier)
--font-iosevka-slab    Curly Slab (heading variant)
--font-iosevka-aile    Quasi-proportional sans (geometric, clean)
--font-iosevka-etoile  Quasi-proportional slab (literary, default body)
```

### npm packages:
```
@fontsource/iosevka
@fontsource/iosevka-curly
@fontsource/iosevka-curly-slab
@fontsource/iosevka-aile
@fontsource/iosevka-etoile
```

---

## TYPE SCALE

All use `clamp(min, preferred, max)` — no breakpoint-specific font sizes needed.

```
--text-xs    clamp(0.72rem, 0.7rem + 0.15vw, 0.82rem)    ← labels, metadata, tags, mono text
--text-sm    clamp(0.88rem, 0.86rem + 0.18vw, 0.98rem)   ← secondary text, descriptions
--text-base  clamp(1rem,    0.98rem + 0.22vw, 1.1rem)    ← body paragraphs
--text-lg    clamp(1.1rem,  1.02rem + 0.38vw, 1.35rem)   ← lead paragraphs, standfirsts
--text-xl    clamp(1.35rem, 1.18rem + 0.65vw, 1.8rem)    ← h3, subheadings
--text-2xl   clamp(1.8rem,  1.5rem  + 1vw,    2.65rem)   ← h2, section headings
--text-3xl   clamp(2.7rem,  2.1rem  + 2vw,    4.8rem)    ← h1, hero titles
--text-4xl   clamp(3.5rem,  2.6rem  + 3vw,    6rem)      ← display, massive hero
--text-code  clamp(0.88rem, 0.85rem + 0.18vw, 1rem)      ← code blocks specifically
```

**Base font-size breakpoints** (compounds with clamp values):
- `≤ 900px`: `html { font-size: 15px }`
- `≤ 640px`: `html { font-size: 14px }`

---

## SPACING SCALE

4px base unit. Always use these — never raw values.

```
--space-1    0.25rem   4px
--space-2    0.5rem    8px
--space-3    0.75rem   12px
--space-4    1rem      16px
--space-5    1.25rem   20px
--space-6    1.5rem    24px
--space-8    2rem      32px
--space-10   2.5rem    40px
--space-12   3rem      48px
--space-14   3.5rem    56px
--space-16   4rem      64px
--space-20   5rem      80px
--page-inline-gutter   clamp(0.8125rem, 3.25vw, 1.3125rem)   ← responsive side padding
```

---

## BORDER RADIUS

Intentionally large — creates editorial softness, not web-app bubbles.

```
--radius-sm    10px    ← inline code, small inputs, copy buttons, badges
--radius-md    18px    ← code blocks, tables, form fields, modals, callouts
--radius-lg    28px    ← cards, media containers, large surface cards
--radius-full  9999px  ← tags, pills, icon buttons, circular elements
```

---

## TRANSITIONS

```
--transition-fast   120ms ease   ← icon toggles, micro-interactions
--transition-base   180ms ease   ← color changes, hover states
--transition-slow   280ms ease   ← background changes
(theme switch)      500ms ease   ← all color properties globally
```

---

## THEMES

Apply via `data-theme` attribute on `<html>`. 14 total (7 × light + dark).

| Theme | Mood | Accent Light | Accent Dark |
|-------|------|-------------|-------------|
| `dusk` / `dusk-dark` | Moody, literary, plum | `#8a5a6a` | `#c49aaa` |
| `parchment` / `parchment-dark` | Warm, scholarly, terracotta | `#a65c3a` | `#d4916a` |
| `seaside` / `seaside-dark` | Cool, coastal, slate-blue | `#4a7a8a` | `#7ab4c4` |
| `olive` / `olive-dark` | Earthy, Mediterranean, sage | `#6a7a4a` | `#9ab46a` |
| `ink` / `ink-dark` | Minimal, sharp, near-black | `#8a4a3a` | `#c48a7a` |
| `moss` / `moss-dark` | Rich forest greens | `#4a6b3a` | `#8ab46a` |
| `azure` / `azure-dark` | Deep ocean blues | `#3a6ab4` | `#6a9ad4` |

**Default theme**: `dusk`

### Theme init script (prevents flash on page load):
```html
<script>
  (() => {
    const t = localStorage.getItem('theme') || 'dusk';
    document.documentElement.dataset.theme = t;
  })();
</script>
```

### Theme JavaScript API (available as `window.acidbathTheme`):
```js
window.acidbathTheme.get()          // returns current theme name
window.acidbathTheme.set('parchment')  // switch theme
window.acidbathTheme.toggle()       // toggle light/dark for current base
window.acidbathTheme.list()         // all valid theme names
```

---

## TYPOGRAPHY PROFILES

Apply via `data-typography` on `<html>`. Controls body/heading rhythm.

| Profile | Body LH | Body Weight | Body LS | Heading LH | Heading Weight | Heading LS |
|---------|---------|-------------|---------|------------|----------------|------------|
| `measured` (default) | 1.72 | 400 | 0 | 1.1 | 500 | -0.03em |
| `compact` | 1.50 | 400 | 0 | 1.05 | 600 | -0.02em |
| `airy` | 1.90 | 300 | 0.01em | 1.15 | 400 | -0.04em |
| `sharp` | 1.60 | 400 | -0.01em | 1.08 | 600 | -0.035em |
| `minimal` | 1.75 | 300 | 0.02em | 1.12 | 400 | -0.02em |
| `editorial` | 1.85 | 350 | 0.005em | 1.05 | 500 | -0.05em |
| `technical` | 1.65 | 400 | 0 | 1.10 | 600 | -0.02em |

---

## COMPONENT PATTERNS

### surface-card
The primary elevated surface. Always use with backdrop-filter.
```css
.my-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: 0 18px 50px rgba(36, 25, 19, 0.06);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}
[data-theme$="-dark"] .my-card {
  box-shadow: 0 20px 56px rgba(0, 0, 0, 0.24);
}
```

### section-kicker
Uppercase label with glowing accent dot. Use above section headings.
```css
.section-kicker {
  display: inline-flex;
  align-items: center;
  gap: 0.65rem;
  font-family: var(--font-family-heading);
  font-size: var(--text-xs);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.11em;
  color: var(--color-foreground-muted);
}
.section-kicker::before {
  content: "";
  width: 0.62rem;
  height: 0.62rem;
  border-radius: var(--radius-full);
  background: var(--color-accent-primary);
  box-shadow: 0 0 0 0.4rem var(--color-accent-muted);
}
```

### tag / badge (pill)
```css
.tag {
  display: inline-flex;
  align-items: center;
  padding: 0.38rem 0.58rem;
  border-radius: var(--radius-full);
  background: var(--color-accent-muted);
  color: var(--color-foreground);
  font-family: var(--font-family-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.04em;
}
```

### meta / date label
```css
.meta-label {
  font-family: var(--font-family-mono);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-foreground-muted);
}
```

### active nav link underline (critical positioning detail)
```css
.nav-link.active::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -0.45rem;  /* ← this exact value */
  width: 100%;
  height: 1px;
  background: var(--color-accent-primary);
}
```

### standfirst / pull quote
```css
.standfirst {
  padding-left: var(--space-5);
  border-left: 2px solid var(--color-accent-primary);
  font-size: var(--text-lg);
  color: var(--color-foreground-alt);
  font-style: italic;
}
```

### callout icon dot
```css
.callout-dot {
  width: 0.68rem;
  height: 0.68rem;
  border-radius: 999px;
  background: currentColor;
  box-shadow: 0 0 0 0.35rem color-mix(in srgb, currentColor 16%, transparent);
}
```

### page background (body)
```css
body {
  background:
    radial-gradient(circle at top left, var(--atmosphere-glow), transparent 28%),
    radial-gradient(circle at 84% 12%, var(--color-accent-muted), transparent 24%),
    linear-gradient(180deg, var(--color-background), var(--color-background-alt));
}
body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  background-image:
    linear-gradient(rgba(89, 73, 61, 0.04) 1px, transparent 1px),
    linear-gradient(90deg, rgba(89, 73, 61, 0.04) 1px, transparent 1px);
  background-size: 32px 32px;
  mask-image: radial-gradient(circle at center, black 55%, transparent 96%);
  opacity: 0.22;
}
[data-theme$="-dark"] body::before {
  background-image:
    linear-gradient(rgba(235, 219, 178, 0.03) 1px, transparent 1px),
    linear-gradient(90deg, rgba(235, 219, 178, 0.03) 1px, transparent 1px);
}
```

### primary button
```css
.btn-primary {
  display: inline-flex;
  align-items: center;
  padding: var(--space-3) var(--space-6);
  background: var(--color-accent-primary);
  color: var(--primary-foreground);
  border: none;
  border-radius: var(--radius-sm);
  font-family: var(--font-family-mono);
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  cursor: pointer;
  transition: background-color var(--transition-base), transform var(--transition-fast);
}
.btn-primary:hover { background: var(--color-accent-secondary); transform: translateY(-1px); }
```

### text input
```css
.input {
  font-family: var(--font-family-mono);
  font-size: var(--text-sm);
  padding: var(--space-3) var(--space-4);
  background: var(--color-background);
  color: var(--color-foreground);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  width: 100%;
}
.input:focus {
  outline: none;
  border-color: var(--color-accent-primary);
  box-shadow: 0 0 0 3px var(--ring);
}
```

### note list item (date column pattern)
```css
.note-item {
  display: grid;
  grid-template-columns: 9rem minmax(0, 1fr);
  gap: var(--space-5);
  padding: var(--space-5) 0;
  border-bottom: 1px solid var(--border);
}
```

### post card image placeholder
```css
.post-card__placeholder {
  background:
    radial-gradient(circle at top left, var(--color-accent-muted), transparent 34%),
    linear-gradient(135deg, var(--color-background-alt), var(--color-background));
}
```

---

## LAYOUT TOKENS

```
--layout-max-width    1240px    Maximum content width
--layout-prose-width  46rem     Optimal reading column (blog posts)
--layout-rail-width   220px     Sidebar / TOC width
```

### Standard page wrapper:
```css
.site-main {
  width: min(1240px, calc(100% - (var(--page-inline-gutter) * 2)));
  margin: 0 auto;
  padding-bottom: var(--space-20);
  overflow-x: clip;
}
```

### Blog post layout (article + TOC rail):
```css
.post-body {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) 220px;
  gap: var(--space-8);
  align-items: start;
}
/* ≤ 1099px: single column */
```

---

## ATMOSPHERE / AMBIENT TOKENS

Each theme has these ambient tokens for the background glow effect:
```
--atmosphere-particle   Color for 3D particle systems
--atmosphere-glow       Low-opacity radial gradient color for body background
```

---

## CODE BLOCKS

Always dark, regardless of theme:
```
background: #171a18
color:       #ebdbb2  (Gruvbox cream)
dim-text:    #d5c4a1
border:      rgba(235, 219, 178, 0.1)
font:        var(--font-family-mono)
font-size:   var(--text-code)
line-height: 1.65
```

---

## TAILWIND SETUP

### Tailwind v4:
```css
@import "tailwindcss";
@import "./design-system/tokens.css";
@import "./design-system/tailwind-v4-theme.css";
```

### Tailwind v3:
```js
const acidbath = require('./design-system/tailwind.config.js');
module.exports = { ...acidbath, content: ['...'] };
```

### Dark mode selector:
```js
darkMode: ['selector', '[data-theme$="-dark"]']
```

---

## DESIGN PRINCIPLES (enforce these in generated code)

1. **Muted by default** — backgrounds soft, borders low-opacity, accents surface purposefully
2. **3-tier text hierarchy** — foreground → foreground-alt → foreground-muted. Use these, not opacity.
3. **One font family** — Iosevka variants everywhere. Body = Etoile. Headings = Curly Slab. Code = Iosevka.
4. **Large radii** — sm=10, md=18, lg=28. Soft without being bubbly.
5. **Fluid type** — clamp() at every step. No breakpoint-specific font sizes.
6. **Grid texture** — body::before creates a 32px grid at 22% opacity. Keep this in new page templates.
7. **Atmosphere** — body has a 3-layer gradient (glow + accent wash + color). Keep this in page layouts.
8. **Slow theme transitions** — 500ms ease on all color properties globally. Don't override unless necessary.
9. **Semantic spacing** — always --space-N, never magic numbers.
10. **Mono for metadata** — dates, categories, reading time, tags, nav links, form inputs all use --font-family-mono.
