npm package: @geepers/theme
Description: Minimalist zinc/indigo CSS design system with light/dark mode — Swiss Design philosophy with 8px grid, system fonts, and 38 custom properties
Author: Luke Steuber
Latest version: 1.0.0

# @lukeslp/swiss-theme

Minimalist zinc/indigo CSS design system with light/dark mode.

![npm](https://img.shields.io/npm/v/@lukeslp/swiss-theme.svg)
![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)

Swiss Design philosophy: 8px grid, system fonts, sharp edges, 38 CSS custom properties. One stylesheet covers layout, typography, forms, buttons, tables, tabs, toasts, and responsive breakpoints. Light/dark toggle included.

## Install

```bash
npm install @lukeslp/swiss-theme
```

## Usage

### Via CSS import

```css
@import '@lukeslp/swiss-theme';
```

### Via `<link>` tag

```html
<link rel="stylesheet" href="node_modules/@lukeslp/swiss-theme/src/io-theme.css">
```

### With the theme toggle

The toggle script auto-initializes on load, reads `prefers-color-scheme`, and persists choice to `localStorage`.

```html
<!-- Add a button with class="theme-toggle" anywhere and it wires itself up -->
<button class="theme-toggle">Dark</button>

<script src="node_modules/@lukeslp/swiss-theme/src/theme-toggle.js"></script>
```

Or inject a button programmatically:

```js
import '@lukeslp/swiss-theme/toggle';

// Append a toggle button into any container
window.injectThemeToggle('.io-header-right');
```

## Design tokens

All values live on `:root` as CSS custom properties and flip automatically under `[data-theme="dark"]`.

| Variable | Light | Dark |
|----------|-------|------|
| `--bg-0` | `#f4f4f5` | `#09090b` |
| `--bg-1` | `#ffffff` | `#18181b` |
| `--text-0` | `#18181b` | `#fafafa` |
| `--text-1` | `#52525b` | `#a1a1aa` |
| `--accent` | `#4f46e5` | `#818cf8` |
| `--border` | `#e4e4e7` | `#27272a` |
| `--radius` | `10px` | `10px` |
| `--ease` | `180ms ease` | `180ms ease` |

Full list of 38 properties in `src/io-theme.css`.

## What's included

**Layout** — `.container`, `.container-narrow`, `.container-wide`, `.tool-layout`, `.tool-layout-narrow`, `.grid-2`, `.grid-3`, `.grid-auto`, flex utilities

**Components** — `.card`, `.card-padded`, `.btn`, `.btn-primary`, `.btn-sm`, `.btn-lg`, `.btn.loading`, `.tab-bar`, `.tab-btn`, `.tab-content`, `.toast`, `.drop-zone`, `.spinner`, `.status-dot`, `.status-msg`

**Typography** — `h1`–`h3`, `.eyebrow`, `.subtitle`, `.text-muted`, `.text-dim`, `.text-accent`, `.mono`

**Forms** — `input`, `select`, `textarea`, `label`, `.control-group`, `.form-group`, `.helper-text`, `.grid-controls`

**Navigation** — `.io-header`, `.io-nav-wrapper`, `.io-nav-dropdown`, `.io-nav-item`, `.io-footer`

**Responsive** — collapses grids and tool layouts to single-column at 768px; tightens padding at 480px

## Toggle API

When the toggle script loads it exposes three globals:

```js
window.initTheme()                    // Re-apply saved preference
window.toggleTheme()                  // Flip light ↔ dark
window.injectThemeToggle(selector)    // Append a button into a container
```

Storage key: `swiss-theme` in `localStorage`.

## Author

**Luke Steuber**
- Website: [lukesteuber.com](https://lukesteuber.com)
- Bluesky: [@lukesteuber.com](https://bsky.app/profile/lukesteuber.com)
- Email: luke@lukesteuber.com

## License

MIT License — see [LICENSE](LICENSE) for details.