---
version: alpha
name: Vanilla
description: A minimal, monochrome design system built with vanilla CSS for static pages.
colors:
  primary: "#000000"
  on-primary: "#ffffff"
  secondary: "#eeeeee"
  on-secondary: "#000000"
  muted: "#666666"
  border: "#cccccc"
  surface: "#ffffff"
  danger: "#dc2626"
  on-danger: "#ffffff"
  success-bg: "#dcfce7"
  success-text: "#166534"
  warning-bg: "#fef9c3"
  warning-text: "#854d0e"
  error-bg: "#fee2e2"
  error-text: "#991b1b"
typography:
  h1:
    fontFamily: sans-serif
    fontSize: 2.25rem
    fontWeight: 700
    lineHeight: 1.2
  h2:
    fontFamily: sans-serif
    fontSize: 1.5rem
    fontWeight: 700
    lineHeight: 1.3
  h3:
    fontFamily: sans-serif
    fontSize: 1.25rem
    fontWeight: 700
    lineHeight: 1.4
  h4:
    fontFamily: sans-serif
    fontSize: 1rem
    fontWeight: 700
    lineHeight: 1.5
  body:
    fontFamily: sans-serif
    fontSize: 1rem
    fontWeight: 400
    lineHeight: 1.5
rounded:
  sm: 0.5rem
  md: 0.75rem
  lg: 1rem
spacing:
  xs: 0.25rem
  sm: 0.5rem
  md: 0.75rem
  lg: 1rem
  xl: 2rem
  section: 4rem
components:
  button-primary:
    backgroundColor: "{colors.primary}"
    textColor: "{colors.on-primary}"
    rounded: "{rounded.md}"
    padding: 0.5rem 0.75rem
    height: 2.5rem
  button-secondary:
    backgroundColor: "{colors.secondary}"
    textColor: "{colors.on-secondary}"
    rounded: "{rounded.md}"
    padding: 0.5rem 0.75rem
    height: 2.5rem
  button-outline:
    backgroundColor: transparent
    textColor: "{colors.primary}"
    rounded: "{rounded.md}"
    padding: 0.5rem 0.75rem
    height: 2.5rem
  button-ghost:
    backgroundColor: transparent
    textColor: "{colors.primary}"
    rounded: "{rounded.md}"
    padding: 0.5rem 0.75rem
    height: 2.5rem
  button-danger:
    backgroundColor: "{colors.danger}"
    textColor: "{colors.on-danger}"
    rounded: "{rounded.md}"
    padding: 0.5rem 0.75rem
    height: 2.5rem
  icon-button:
    rounded: "{rounded.md}"
    size: 2.5rem
  icon-button-primary:
    backgroundColor: "{colors.primary}"
    textColor: "{colors.on-primary}"
    rounded: "{rounded.md}"
    size: 2.5rem
  input-border:
    backgroundColor: "transparent"
    textColor: "{colors.primary}"
    rounded: "{rounded.md}"
    padding: 0.5rem 0.75rem
  input-filled:
    backgroundColor: "{colors.secondary}"
    textColor: "{colors.primary}"
    rounded: "{rounded.md}"
    padding: 0.5rem 0.75rem
  input-white:
    backgroundColor: "{colors.surface}"
    textColor: "{colors.primary}"
    rounded: "{rounded.md}"
    padding: 0.5rem 0.75rem
  card:
    backgroundColor: "{colors.secondary}"
    rounded: "{rounded.lg}"
    padding: 1rem
  hero:
    backgroundColor: "{colors.primary}"
    textColor: "{colors.on-primary}"
    rounded: "{rounded.lg}"
    padding: 2rem
  tab-active:
    textColor: "{colors.primary}"
  tab-inactive:
    textColor: "{colors.muted}"
  pagination-item-active:
    backgroundColor: "{colors.primary}"
    textColor: "{colors.on-primary}"
    rounded: "{rounded.md}"
    size: 2.5rem
  chip:
    textColor: "{colors.muted}"
  plain-button:
    backgroundColor: "transparent"
    textColor: "{colors.primary}"
  alert-info:
    backgroundColor: "{colors.secondary}"
    textColor: "{colors.on-secondary}"
    rounded: "{rounded.md}"
    padding: 0.75rem 1rem
  alert-success:
    backgroundColor: "{colors.success-bg}"
    textColor: "{colors.success-text}"
    rounded: "{rounded.md}"
    padding: 0.75rem 1rem
  alert-warning:
    backgroundColor: "{colors.warning-bg}"
    textColor: "{colors.warning-text}"
    rounded: "{rounded.md}"
    padding: 0.75rem 1rem
  alert-error:
    backgroundColor: "{colors.error-bg}"
    textColor: "{colors.error-text}"
    rounded: "{rounded.md}"
    padding: 0.75rem 1rem
  badge-primary:
    backgroundColor: "{colors.primary}"
    textColor: "{colors.on-primary}"
    rounded: "{rounded.sm}"
  badge-secondary:
    backgroundColor: "{colors.secondary}"
    textColor: "{colors.on-secondary}"
    rounded: "{rounded.sm}"
  blockquote:
    textColor: "{colors.muted}"
  code:
    backgroundColor: "{colors.secondary}"
    rounded: 0.25rem
  code-block:
    backgroundColor: "{colors.secondary}"
    rounded: "{rounded.md}"
    padding: 1rem
  empty:
    padding: 2rem
  disclosure:
    rounded: "{rounded.md}"
    padding: 1rem
  table:
    borderColor: "{colors.border}"
    rounded: "{rounded.md}"
    cellPadding: 0.5rem
    headerFontWeight: bold
  table-wrapper:
    rounded: "{rounded.md}"
    borderColor: "{colors.border}"
    overflowX: auto
  avatar:
    rounded: 50%
    sizes:
      xs: 1.5rem
      sm: 2rem
      default: 2.5rem
      lg: 3.5rem
      xl: 5rem
  avatar-placeholder:
    backgroundColor: "{colors.primary}"
    textColor: "{colors.on-primary}"
---

## Overview

A minimal, monochrome design system for static pages built with vanilla CSS. The aesthetic is clean, functional, and content-first — no frameworks, no build tools. The UI should feel modern and uncluttered, using whitespace and subtle gray tones to create hierarchy.

The system prioritizes clarity over decoration. Black provides authority for primary actions and text. Grays create layering and secondary surfaces. A single accent color (red) is reserved strictly for destructive actions.

CSS implementation details (naming, nesting, modern features, reset, layout patterns) are in `CSS.md`.

## Colors

The palette is intentionally constrained to a monochrome spectrum plus semantic colors for feedback states.

- **Primary (#000000):** Pure black for headlines, primary buttons, active states, and core text. Provides maximum contrast and authority.
- **On-Primary (#ffffff):** White text on primary backgrounds.
- **Secondary (#eeeeee):** Light gray for secondary buttons, cards, hero sections, and container backgrounds. Creates subtle layering without competing with content.
- **On-Secondary (#000000):** Black text on secondary backgrounds.
- **Muted (#666666):** Medium gray for breadcrumb links, chip items, inactive tabs, and de-emphasized text.
- **Border (#cccccc):** Light gray for input borders, outline buttons, fieldset borders, tab underlines, and breadcrumb separators.
- **Surface (#ffffff):** White background for the page and input fields.
- **Danger (#dc2626):** Red reserved exclusively for destructive actions. Never used for decoration.
- **On-Danger (#ffffff):** White text on danger backgrounds.
- **Success (#dcfce7 / #166534):** Green background/text pair for success alerts and badges.
- **Warning (#fef9c3 / #854d0e):** Yellow background/text pair for warning alerts and badges.
- **Error (#fee2e2 / #991b1b):** Red background/text pair for error alerts and badges.

## Typography

A single system font stack (`sans-serif`) is used throughout. No custom fonts — the system relies on the user's native sans-serif for maximum performance and zero loading overhead.

- **Headings (h1-h4):** All bold (700 weight). Sizes scale from `2.25rem` (h1) down to `1rem` (h4) in consistent steps. Utility classes `.h1`–`.h4` mirror heading styles — use to override visual size while keeping semantic hierarchy (e.g. `<h3 class="h4">`).
- **Body:** `1rem` at regular weight (400) with `1.5` line-height for comfortable reading.
- **Labels and legends:** Bold weight inherited from body size. Used in form fieldsets and navigation.

## Page Structure

Always use semantic HTML5 structure: `<header>`, `<main>`, `<footer>` as direct `<body>` children. Wrap page `<section>` elements inside `<main>` — the `main` element has `display: flex; flex-direction: column; gap: 2rem` so sections receive the same `2rem` spacing as if they were direct body children.

```html
<body>
  <header class="header">…</header>
  <main>
    <section>…</section>
    <section>…</section>
  </main>
  <footer class="footer">…</footer>
</body>
```

**Do not** place `<section>` elements as direct `<body>` children — use `<main>` as the wrapper.

## Layout & Spacing

Page max-width is `1280px`, centered. For full-width layouts (admin panels, wide data tables), add `class="fluid"` to `<body>` — this removes the max-width cap so content spans the whole viewport.

Spacing follows a **4px base unit** system expressed in `rem` values. All spacing values are multiples of 4px (0.25rem).

| Token     | Value          | Usage                                                                                             |
| :-------- | :------------- | :------------------------------------------------------------------------------------------------ |
| `xs`      | 0.25rem (4px)  | Color input padding                                                                               |
| `sm`      | 0.5rem (8px)   | Form-group gap, radio/checkbox gap, breadcrumb gap, vertical nav gap, tab padding, pagination gap |
| `md`      | 0.75rem (12px) | Input padding, button padding, horizontal nav gap, chip-group gap                                 |
| `lg`      | 1rem (16px)    | Form gap, card padding, fieldset padding, section gap                                             |
| `xl`      | 2rem (32px)    | Hero padding                                                                                      |
| `section` | 4rem (64px)    | Gap between major page sections                                                                   |

## Elevation & Depth

No box shadows or elevation in this system. Depth is conveyed through background color contrast — secondary (`#eee`) surfaces on white (`#fff`) page background.

## Shapes

The shape language uses three levels of border-radius, all in `rem` for scalability:

| Token    | Value   | Usage                                                                                        |
| :------- | :------ | :------------------------------------------------------------------------------------------- |
| `sm`     | 0.5rem  | Badges                                                                                       |
| `md`     | 0.75rem | Buttons, inputs, textareas, selects, fieldsets, icon buttons, pagination items, tabs, tables |
| `lg`     | 1rem    | Cards, hero sections                                                                         |
| `circle` | 50%     | Avatars only                                                                                 |

`0.75rem` is the default radius for all interactive elements. `1rem` is used for larger container surfaces. Circular (50%) radius is used exclusively for avatars.

## Components

### Buttons

Five button variants share a common base: `inline-flex`, centered content, `0.75rem` border-radius, `0.5rem 0.75rem` padding, `1.5` line-height, `cursor: pointer`. All work on both `<button>` and `<a>` tags via `text-decoration: none`. A `0.5rem` gap separates icon and text when both are present. Group buttons with `.button-group` (flex row, `1rem` gap, wrapping). Multi-line button text must be centered — always add `text-align: center` to the button base styles.

- **Primary:** Black background, white text. The main call-to-action.
- **Secondary:** Light gray (#eee) background, black text. For secondary actions.
- **Outline:** Transparent background, 1px #ccc border, black text. Lighter emphasis.
- **Ghost:** Transparent background, no border, black text. Minimal presence.
- **Danger:** Red (#dc2626) background, white text. Destructive actions only.
- **Disabled:** Any variant with `opacity: 0.5` and `cursor: not-allowed`.

Icon buttons are `2.5rem x 2.5rem` squares with the same `0.75rem` radius. SVG icons render at `1.5rem x 1.5rem`. Icon buttons support primary, secondary, outline, and ghost variants.

Plain buttons (`.plain-button`) are bare icon triggers — no padding, no background, no border, no fixed dimensions. SVG icons render at `1.5rem x 1.5rem`. Use for inline actions (share, delete) where a boxed button adds too much visual weight.

Buttons with icons support three patterns:

1. **SVG element** — separate child element, `gap: 0.5rem` provides spacing automatically.
2. **Span-wrapped char** — `<span>&rarr;</span>` as separate element, gap works.
3. **Inline char** — `+ Add` as single text node, natural space character suffices.

### Header

`<header>` is a flex column with `1rem` gap. Contains site name, optional search bar, navigation, and breadcrumb. Breadcrumb lives inside header when present — keeps page navigation context together and avoids excess spacing. Still uses its own `<nav>` tag for SEO.

- **Description list (.description-list):** Label/value metadata as a `<dl>`. Wrap each `<dt>`/`<dd>` pair in a `<div>` (valid in `<dl>`) so all variants share one markup. Three layout modifiers: `.vertical` (label above value), `.horizontal` (side by side; label is content-sized but capped at half the row and wraps there, value fills the rest), `.between` (side by side, value pushed to the end with `space-between`, right-aligned). **Colour is not baked in** — add `.text-muted` to the `<dt>` (muted label, the common case) or to the `<dd>` (muted value) explicitly. Use for channel/profile detail panels instead of faking it with a two-column `.table`.
- **Site name (.site-name):** `1.5rem` weight-900 text, `width: fit-content`. Click target matches text width only — never full row. **Logo variant (.site-name.logo):** add when the site name is an `<img>` instead of text — switches to `inline-flex` + `line-height: 0` and renders the image as `display: block`, removing the baseline gap the text line-box would otherwise add around the logo. Use `.site-name.logo` for image logos, plain `.site-name` for text.
- **Search bar (.search-bar):** Flex row with `0.5rem` gap. Input inside auto-fills available width.
- **Footer (.footer):** Flex column with `1rem` gap. Contains nav links and copyright text.

### Navigation

- **Horizontal nav (.nav):** Flex row with `1rem` column-gap, `0.5rem` row-gap, wrapping. Regular weight links. Add `.bold` modifier for bold links.
- **Vertical nav (.nav-vertical):** Flex column with `0.5rem` gap.
- **Tabs (.tabs, .tab):** Flex row with bottom border, horizontal scroll on overflow. Tabs never wrap. Active tab has bold text, black color, and `2px` black bottom border. Inactive tabs use muted (#666) color. `.tab` must reset browser button defaults: `background: none; border: none; cursor: pointer`.
- **Fit tabs (.tabs.fit):** Forces all tabs into one row with no horizontal scroll — each `.tab` is equal-width (`flex: 1`), center-aligned, and truncates with an ellipsis (`min-width: 0; overflow: hidden; text-overflow: ellipsis`). Combine with segmented: `.tabs.segmented.fit`. Use when the tab set is fixed and must always be fully visible (no scroll), accepting truncated labels on narrow screens.
- **Wrap tabs (.tabs.wrap):** Like `.fit` (equal-width segments stay in one row, no scroll) but labels **wrap** to multiple lines instead of truncating (`white-space: normal; overflow-wrap: break-word` — long single words break mid-word so they never overflow their segment). Use when full labels must stay readable and the extra height is acceptable. `.tabs.segmented.wrap` for the segmented look.
- **Tab icons:** Any `<svg>` inside a `.tab` renders at `1.5rem` (24px), vertically centered. Works for icon-only segments (`<a class="tab"><svg…></a>` — add `aria-label` for accessibility) or icon-plus-text. `stroke="currentColor"` so the icon follows the active/inactive tab colour.
- **Pill tabs (.tabs.pills):** No underline; each tab is a rounded pill (`--radius`), `0.5rem` gap. Active is a filled black (`--color-primary`) pill with white text. For filters / category switches ("All · Active · Archived").
- **Boxed tabs (.tabs.boxed):** Enclosed folder tabs. Active tab gets a top + side border, white background, and `margin-bottom: -1px` so it merges with the panel (a `.card` or bordered region) below it. For desktop-style settings panels.
- **Ghost tabs (.tabs.ghost):** No underline, no fill — active is just bold + black. The most minimal style, for dense toolbars.
- **Bottom-nav tabs (.tabs.bottom-nav):** Equal-width (`flex: 1`) segments with the icon **stacked above** the label, centered. The label is `0.625rem` (10px) — a sanctioned sub-1rem exception, since mobile bottom-nav labels must stay tiny under a 24px icon. The app supplies fixed positioning; this is just the bar style. Use for mobile-app primary navigation.
- **Segmented tabs (.tabs.segmented):** iOS-style segmented control — same `.tab` children, but the underline becomes a rounded pill track. The wrapper gets a gray (`--color-secondary`) background and the larger `--radius-lg`; each segment is equal-width (`flex: 1`), button-sized padding (`0.5rem 0.75rem`), and the one-step-smaller `--radius`. The active segment is a white (`--color-on-primary`) pill. Use for compact mutually-exclusive switches (Day/Week/Month, period/mode toggles) where the underline `.tabs` would be too heavy.
- **Breadcrumb (.breadcrumb):** Flex row with `0.5rem` gap, wrapping. Links in muted (#666), separators in border (#ccc), current page as plain `<span>`.
- **Chips (.chip-group, .chip):** Flex row with `1rem` gap. Muted (#666) text. Generic container for tags, filters, categories.

### Forms

Forms use `.form` (flex column, `1rem` gap) and `.form-group` (flex column, `0.5rem` gap) for layout. Three input styles share `0.75rem` radius and `0.5rem 0.75rem` padding:

- **Border (.input):** `1px #ccc` border, transparent background. Works on any surface. Focus changes border to `#000`.
- **Filled (.input-filled):** `#eee` gray background, no border. Use on white surfaces.
- **White (.input-white):** White background, no border. Use on gray surfaces (cards, heroes).

- **Textarea (.textarea):** Same as `.input` with `resize: vertical`.
- **Select (.select):** Same as `.input` with `appearance: none` and custom SVG chevron positioned at `right 0.75rem center`. Extra right padding (`2rem`) for chevron space.
- **File input (.file-input):** Unstyled wrapper. `::file-selector-button` styled as secondary button.
- **Color input (.color-input):** `3rem x 2rem`, `1px #ccc` border, `0.75rem` radius.
- **Range (.range):** Browser default with `cursor: pointer`.
- **Fieldset (.fieldset):** `1px #ccc` border, `0.75rem` radius, `1rem` padding, flex column with `0.5rem` gap.
- **Legend (.legend):** Bold, `0 0.5rem` horizontal padding.
- **Radio/Checkbox labels:** Flex row, `align-items: center`, `0.5rem` gap, `cursor: pointer`.

For long forms with logical sections, use `<h3>` headings directly inside `.form` to separate groups — no fieldset needed. The `1rem` gap in `.form` provides natural spacing between heading and fields.

```html
<form class="form">
  <h3>Personal Information</h3>
  <div class="form-grid">
    <div class="form-group">...</div>
    <div class="form-group">...</div>
  </div>

  <h3>Account</h3>
  <div class="form-grid">
    <div class="form-group">...</div>
  </div>

  <h3>Notifications</h3>
  <label class="checkbox-label">...</label>
</form>
```

Use `.fieldset` when the border grouping adds semantic or visual value (e.g. address blocks, payment details). Use `h3` sections for general settings forms where the border adds visual noise.

### Pagination

Three pagination styles, all using `.pagination` container (flex row, `align-items: center`, `0.5rem` gap). Alignment modifiers: `.pagination.center`, `.pagination.end`.

1. **Simple:** Icon buttons (chevron SVGs) + text counter (`<span class="pagination-info">1 / 51</span>`) — muted color, `0.875rem` font-size.
2. **Numbered:** Icon buttons + `.pagination-item` links. Active item uses primary (#000) background with white text. Items are `2.5rem` min-width/height. Ellipsis uses `.pagination-dots` in muted (#666).
3. **Compact:** Secondary buttons with SVG chevrons and "Previous"/"Next" text.

### Cards

Cards use `#eee` background, `1rem` border-radius, `1rem` padding, flex column with `1rem` gap. Card footer (`.card-footer`) is a flex row with `space-between` alignment, `1rem` gap, `align-items: flex-end` for placing chips and action buttons.

### Hero

Hero sections use primary (#000) background with white text, `1rem` border-radius, `2rem` padding, centered text.

### Alerts

Four alert variants with `0.75rem` radius, `0.75rem 1rem` padding:

- **Info (.alert.info):** Secondary (#eee) background, black text. Neutral messages.
- **Success (.alert.success):** Green (#dcfce7) background, dark green text. Confirmations.
- **Warning (.alert.warning):** Yellow (#fef9c3) background, dark yellow text. Cautions.
- **Error (.alert.error):** Red (#fee2e2) background, dark red text. Failures.

### Badges

Inline labels with `0.5rem` radius, `0.75rem` font size, bold. Five variants: primary, secondary, success, warning, danger. Use for counts, statuses, tags.

### Avatar

Circular image or placeholder for user representation. Five sizes:

| Class               | Size          | Use case                   |
| :------------------ | :------------ | :------------------------- |
| `.avatar-xs`        | 1.5rem (24px) | Inline text, compact lists |
| `.avatar-sm`        | 2rem (32px)   | Table cells, comments      |
| `.avatar` (default) | 2.5rem (40px) | Standard UI                |
| `.avatar-lg`        | 3.5rem (56px) | Profile cards              |
| `.avatar-xl`        | 5rem (80px)   | Profile pages              |

**With image:** `<div class="avatar"><img src="..." alt="..."></div>` — image fills circle via `object-fit: cover`. The element is `display: inline-flex`, so `<div>` and `<span>` render identically — use `<div>` for a standalone avatar block, `<span>` only when it must sit inline within a line of text. For a clickable avatar, put the class on the `<a>` directly: `<a href="…" class="avatar">…</a>`.

**Placeholder (no image):** Add `.avatar-placeholder` — black (#000) background, white (#fff) text, bold initials. Font size scales with avatar size.

Avatars use `border-radius: 50%` — the only component with circular radius. `flex-shrink: 0` prevents compression in flex layouts.

### Table

`.table-wrapper` wraps every table — provides `overflow-x: auto` for mobile horizontal scrolling, `1px #ccc` border, and `0.75rem` border-radius. The table itself uses `border-collapse: separate` with `border-spacing: 0`.

`.table` with full width. `<th>` bold. Inner grid lines from `1px #ccc` bottom and right borders on cells. Last column drops right border, last row drops bottom border. Cell padding `0.5rem` on all sides.

**Cell alignment:** `.text-right` for numbers/prices/quantities, `.text-center` for IDs/checkboxes/status badges. Both scoped inside `.table`.

**Usage pattern:**

```html
<div class="table-wrapper">
  <table class="table">
    <thead>
      ...
    </thead>
    <tbody>
      ...
    </tbody>
  </table>
</div>
```

### Divider

`.divider` on `<hr>` — `1px solid #ccc` top border, no other borders.

### Lists

- **Styled list (.list):** Flex column, `0.5rem` gap, `1.5rem` left padding. Works on `<ul>` and `<ol>`.
- **Unstyled list (.list-none):** Same layout, no markers, no padding.

### Blockquote

`.blockquote` — `3px` solid black left border, `0.5rem 1rem` padding, muted (#666) text.

### Code

- **Inline (.code):** Monospace, `1rem`, secondary (#eee) background, `0.25rem` radius.
- **Block (.code-block):** Monospace, `1rem`, secondary (#eee) background, `0.75rem` radius, `1rem` padding, horizontal scroll.

### Empty State

`.empty` — flex column, centered, `2rem` padding, `1rem` gap, `text-align: center`. Used for 404 pages, no-results, empty lists, onboarding prompts.

Flexible composition — combine any of these children:

- **Icon:** SVG at `48x48`, placed above title
- **Title:** `h1` for page-level (404) or `h2` for section-level empty states
- **Description:** `<div>` with explanation text
- **CTA:** Button link (primary or outline)

Common variants: icon+title+description+CTA, icon+title+CTA, title+description+CTA, title+CTA, icon+description.

### Disclosure

`.disclosure` on native `<details>` element — `1px #ccc` border, `0.75rem` radius, `1rem` padding. Summary is bold, no default marker. `1rem` gap between summary and content when open. No JS required.

Use for: FAQ sections, show/hide answers, collapsible content, spoiler text. Stack multiple for accordion-style layout.

### Article

`.article` — flex column, `1rem` gap. Wraps long-form content with multiple sections. Use on `<article>` tag.

## Utilities

Small, single-purpose classes. Use over inline styles.

- **`.text-muted`** — `color: #666`. For secondary labels, metadata, de-emphasized values.
- **`.text-small`** — `font-size: 0.875rem`. For captions, table metadata, compact UI.
- **`.text-right`** — `text-align: right`. For numeric / value table columns (counts, change %) and their `<th>` headers.
- **`.text-success`** — vivid green text (`--color-success`, `#16a34a` / green-600). For positive deltas / success values shown as **plain coloured text**, not a `.badge`. Use when a filled pill would be too heavy (e.g. a dense stats table of +N changes). Note: this is brighter than the muted `--color-success-text` used *inside* `.badge.success` — badge text sits on a tinted background, plain text needs the stronger colour.
- **`.text-danger`** — vivid red text (`--color-danger`, `#dc2626` / red-600). The negative counterpart of `.text-success`.
- **`.row`** — horizontal flex, `1rem` gap, wraps. Base for inline control rows (buttons, badges, avatar + text). **No default alignment** — state it explicitly with scoped modifiers (base + modifier, like `.pagination.center`). Different words per axis so there's never any ambiguity: **vertical** (align-items) `.top` / `.middle` / `.bottom`; **horizontal** (justify-content) `.start` / `.center` / `.end` / `.between`. So `.row.middle` = vertically centered, `.row.center` = horizontally centered — two different centers, two different words. Combine freely, e.g. `.row.middle.between` or `.row.bottom.end`. Keep modifiers scoped to `.row` — never global utilities — and add new ones only when a layout actually needs them.
- **`.grow`** — `flex: 1; min-width: 0`. Put on the one row child that should fill the remaining space. The `min-width: 0` is essential for **text that wraps**: flex items default to `min-width: auto`, so a long title/label won't shrink below its content width and instead overflows the row or bumps the whole item onto a new line. `.grow` lets the text wrap inside its column instead. (We deliberately do **not** bake `min-width: 0` into all `.row` children — explicit `.grow` keeps the behavior visible at the call site rather than as action-at-a-distance.)
- **`.container-sm`** — `max-width: 24rem; margin: 0 auto`. For auth forms, narrow single-column content (login, verify, OTP pages).
- **`.container-md`** — `max-width: 32rem; margin: 0 auto`. For slightly wider single-column forms (apply, checkout).
- **`.form-grid`** — Two-column `1fr 1fr` grid with `1rem` gap. For admin forms, settings panels. Add `.full` to a child to span both columns (`grid-column: 1 / -1`).

Never use these as substitutes for proper component structure — they fill gaps where no component exists, not replace components.

## Do's and Don'ts

- **Never** use inline `style="..."` attributes in HTML — always use a class. If no class exists for the need, add it to `styles.css` first.
- **Do** use `currentColor` in SVG `stroke` attributes so icons inherit button/link color.
- **Don't** add hover background color changes — `cursor: pointer` is sufficient feedback for now.
- **Don't** use circular border-radius (50%) except for avatars — all other elements use `0.75rem` or `1rem`.
- **Do** wrap every `<table class="table">` in a `<div class="table-wrapper">` for mobile scrolling.
- **Do** use `.text-right` on numeric/price columns and `.text-center` on checkbox/status columns.
- **Don't** introduce new colors outside the defined palette.
- **Don't** use custom fonts — the system relies on `sans-serif` system font stack.
