# Building with the Hollie Tanner Design System

A short guide for anyone (person or AI agent) building a page, component, or project write-up in this system. Values come from [`tokens.ts`](./tokens.ts). The reference implementation is the portfolio site and its design-system page.

---

## 1. Principles

1. **Taste over templates.** If a pattern appears on every portfolio template (accent bars over headings, small colored labels, glowing cursors), it doesn't belong here.
2. **One accent, from the portrait.** Each theme's accent is sampled from the silhouette behind the portrait: teal in dark, orange in light. The accent does all the signaling.
3. **Calm hierarchy.** Few sizes, clear jumps, generous space. Nothing oversized.
4. **The work leads.** Case studies are text-led; shipped work is image-led. Chrome stays quiet.
5. **Write like a journalist.** Declarative, specific, certain. No filler, nothing cute.

---

## 2. Setup

### Fonts

```html
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Gloock&family=Cormorant+Garamond:ital,wght@0,400;0,500;0,600;1,400&family=Inter:wght@400;500;600&display=swap">
```

(Also exported as `fontStylesheetUrl`.)

### Tokens as CSS variables

```ts
import { cssVariablesStylesheet } from "./tokens";

// Inject once, e.g. at build time or in your root layout.
const style = document.createElement("style");
style.textContent = cssVariablesStylesheet;
document.head.append(style);
```

This writes the light theme to `:root` and the dark theme to `html[data-theme="dark"]`. Switch themes by setting `data-theme` on `<html>`; the site stores the choice in `localStorage` under `hollie-portfolio-theme` and **defaults to dark**.

### Stylesheet layers

Every page loads, in order:

1. The base site styles (`base`, `layout`, `components`, `animations`).
2. **`assets/css/system.css`**: theme tokens, the accent split, the two texture layers, and global cleanups. Shared by every page.
3. **Page styles** (in `assets/css/`): `home.css` for the home page; `case.css` for project pages; `home.css` plus `design-system.css` for this reference, which demos the home components.

Never put tokens or textures in a page stylesheet, and never load `home.css` and `case.css` together: both define `.case-list`, for different components.

### Tokens in TypeScript

```ts
import { themes, typeScale, space, media, cutPaperOffset } from "./tokens";

themes.dark.accent;              // "#61d889"
typeScale.sectionHeading.size;   // "1.65rem"
space[4];                        // 32
media.mobile;                    // "(max-width: 760px)"
```

---

## 3. Color

| Token | Dark | Light | Use |
|---|---|---|---|
| `background` | `#2a2d30` | `#f3f2ee` | Page ground |
| `surface-secondary` | `#3b3e42` | `#e9e7e2` | Image placeholders |
| `headline` | `#ffffff` | `#171717` | Name, section headings, titles |
| `lede` | `#dcdfe0` | `#55524e` | Bio blurb |
| `muted` | `#c2c6c8` | `#55524e` | Body copy, labels, tags |
| `accent` | `#61d889` | `#fc6400` | Fills, icons, the offset motif |
| `accent-text` | `#61d889` | `#ad4500` | Links, nav, footer, hover titles |
| `on-accent` | `#141414` | `#ffffff` | Text or icons on an accent fill |
| `toggle` | `#f5946f` | `#55524e` | The theme toggle |
| `menu-band` | black 15% | terracotta 12% | Menu band tint |

**Rules**

- Fills use `accent`. Text uses `accent-text`. In light mode they differ; the bright orange fails contrast as small text.
- Pure white is for headlines only, in dark mode.
- Never put white text on the teal. Use `on-accent`.
- The theme toggle always previews the *other* theme, so it never uses the current accent.

**Measured contrast** (WCAG 2): white headline on dark background 13.85:1; dark muted 8.05:1; teal on dark band 8.45:1; on-accent on teal 10.26:1; light headline 16.0:1; light muted 6.93:1; accent-text on cream 5.17:1 and on the light band 4.54:1. Small text must reach 4.5:1; icons and graphics 3:1.

---

## 4. Typography

| Role | Family | Size | Notes |
|---|---|---|---|
| Display | Gloock | 48–68px (`clamp(3rem, 5vw, 4.25rem)`) | The name only |
| Page title | Gloock | 42–68px (`clamp(2.6rem, 5vw, 4.25rem)`) | Project and reference pages |
| Section heading | Gloock | 26px, 24px on mobile | Short, Title Case, nothing above it |
| Headline figure | Gloock | 32–44px | Result numbers on project pages |
| Case-study title | Cormorant Garamond 600 | 24px | |
| Project title | Cormorant Garamond 600 | 19px | Title Case |
| Book title | Cormorant Garamond 500 | 16px | Short title, no subtitle |
| Lede | Cormorant Garamond italic | 19px | One line under a section opener |
| Intro / bio | Inter 400 | 16–17.6px, line-height 1.6 | Max 720px; `text-wrap: pretty` to avoid stranded last lines |
| Body | Inter 400 | 14–15px, line-height 1.55–1.7 | Max 68ch |
| Long-form body | Inter 400 | 16px, line-height 1.7 | Running text on project pages |
| Label | Inter 500, caps, 0.12em | 10.5px | Meta lines, e.g. `PLEX · MANUFACTURING` |
| Nav | Inter 600, caps, 0.12em | 12px | `accent-text` |

**Rules**

- Gloock appears only in the name, page titles, section headings, and headline figures. Never in body, buttons, or labels.
- Do not uppercase Gloock. It's built for mixed case.
- No eyebrow labels above headings, and no accent bars.
- Separate inline items with a middle dot ` · `, not slashes or pipes.

---

## 5. Space and layout

- **Rhythm:** 8, 16, 24, 32, 48, 64, 72px (`space`).
- **Sections:** 64px vertical padding (48 on mobile), separated by a 1px `border` rule. The first section after the menu band has no rule.
- **Heading to content:** 32px (24 on mobile).
- **Page:** max width 1500px; side padding `clamp(24px, 4vw, 64px)`.
- **Breakpoints:** tablet ≤1050px, mobile ≤760px, small ≤480px.

| | Desktop | Tablet | Mobile |
|---|---|---|---|
| Case studies | 2 columns | 2 | 1 |
| Portfolio | 3 columns | 2 | 2 |
| Bookshelf list | 2 columns | 2 | 1 |

Never run the portfolio wider than three columns.

**Phones (≤760px):** the menu becomes a pull-down tray and sections collapse behind their headings (see Components). Every touch target is at least **48px**.

**Project pages:** sections run heading left, body right, collapsing to one column at **900px**; the details column stacks below **620px**.

### Header

- Desktop: name and bio on the left, the bio capped at 820px. The portrait is pinned to the right edge of the content column, in line with the menu band and sections below; at least a 48px gap and a ~300px column are reserved for it, and on large screens extra width falls between the bio and the photo. its bottom sits on the menu band and its top runs to the top of the page (`top: 0`), so it renders slightly wider than the 300px column; the PNG's transparent left margin falls in the 48px gap.
- ≤1050px: the portrait floats left at a fixed height (280px tablet, 200px mobile). The bio wraps its silhouette with `shape-outside` set to the portrait PNG.
- The menu sits **below** the header in a full-bleed tinted band, with no rules above or below.

---

## 6. The signature: cut-paper offset

Taken from the portrait, where the cut-out photo sits up and right of an accent silhouette.

```css
.thumb {
  transition: transform 260ms cubic-bezier(0.2, 0.8, 0.2, 1),
              box-shadow 260ms cubic-bezier(0.2, 0.8, 0.2, 1);
  box-shadow: 0 0 0 var(--accent);
}
.card:hover .thumb,
.card:focus-visible .thumb {
  transform: translate(4px, -4px);
  box-shadow: -8px 6px 0 var(--accent);
}
```

- **Images only.** Never on text, headings, or the name.
- **Accent only.** Fill accent, not accent-text.
- **One per element.** Don't stack offsets or combine them with other shadows.

---

## 7. Texture

Two fixed, full-window layers between the background and the content:

1. **Crumpled paper** (`assets/images/textures/texture-overlay-softlight.jpg`), `background-size: cover`. Opacity 0.9 light, 0.2 dark.
2. **Paper tooth** (`assets/images/textures/paper-tooth.png`), a 256px seamless tile at 1:1 pixel size. Opacity 0.35 light, 0.3 dark.

Both use `mix-blend-mode: soft-light` and `pointer-events: none`, and sit at `z-index: 0` with content above.

**Preparing a new texture:** convert to grayscale, shift the average to 50% grey (128), adjust contrast to taste, and export a web-sized JPG (under ~400KB). Soft-light leaves 50% grey unchanged, so the background still averages to its token. Never use a texture with its own color.

---

## 8. Components

### Menu band
Links in `accent-text`, Inter 600 caps. The theme toggle comes last, directly after the final link, colored with `toggle`. Band tint per theme (`menu-band`).

### Design system callout
One per site, linking to the design-system reference. Icon tile: 48px, radius 10, `accent` fill, `on-accent` palette glyph (outline, stroke 2, same icon family as the case-study book), turning 15° on hover. Title in Cormorant 600 (24px, 21px on phones), turning `accent-text` on hover; one sub-line in muted body text. Placed directly under the menu band on desktop and tablet, with a 3px rule in the `menu-band` color separating it from the section below; on phones `<main>` becomes a flex column and the callout takes `order: 99`, landing just above the footer.

### Mobile menu tray (≤760px)
The band becomes a tray in the `accent` fill that sits above the top of the screen. A tab (min 120×52px, labeled **Menu** / **Close**, chevron) hangs from its bottom edge, so it rides down with the tray. Rows are 48px; text is `#141414` in both themes (10.3:1 on teal, 6.1:1 on orange). Any link, a tap outside, or Escape closes it; Escape returns focus to the tab. When closed, the links are `visibility: hidden` so they can't be tabbed into. Reference: `assets/js/mobile-menu.js`.

### Collapsible sections (≤760px)
Each section heading wraps a `<button>` with `aria-expanded` and `aria-controls` pointing at the section body. Sections start closed on phones; above 760px the button is disabled and styled as plain heading text. The whole heading row (min 48px) is the target, with an `accent-text` chevron that flips when open. Menu links open their destination section, and sections use `scroll-margin-top: 64px` so jumps land below the tab. Reference: `assets/js/mobile-sections.js`.

### Project page
- **Header:** the menu band pinned to the top, using solid band colors (`#242629` dark, `#ede2d9` light) so text stays legible over scrolling content. Back link left, theme toggle right.
- **Hero:** page title (Gloock), one-sentence intro (Inter, `lede` color), and a details column of muted labels with values in body text. The page's type ("Case Study", "Mini Project") is the first row, labeled **Type**, never a label above the title.
- **Sections:** section heading left, long-form body right. Lists are ruled rows, not boxes. Figures take 2px corners with no frame or shadow; captions use the label style.
- **Results:** headline figures in Gloock over muted labels, separated by rules.
- **Next project:** a single Gloock link in `accent-text`.

### Case study row
Icon (28px, radius 6, `accent` fill, `on-accent` glyph) · meta label · title · one sentence · tags as plain text. Title turns `accent-text` on hover. No arrows, no numbers.

### Portfolio card
4:3 image with the cut-paper offset on hover · `CLIENT · INDUSTRY` label · Title Case title · tech highlights as plain text. **No dates. No descriptions. No tag chips.**

### Filter pills
Filter by what was built (Mobile, Web & Dashboards, Kiosks & Displays, Print), not by process. Active pill: `accent` fill with `on-accent` text.

### Bookshelf row
Short title in Cormorant, author's last name as a label, right-aligned. Sorted by author's last name, then title.

---

## 9. Voice and copy

- First person, declarative, specific. "I create…", not "I love to…".
- No hedging, no cute phrasing. Exclamation points only for a direct invitation, like the design-system callout.
- Section headings are short and in Title Case: "Case Studies in Leadership & Strategy", "Portfolio of Shipped Work".
- When editing copy, change only what was asked.

---

## 10. Checklist before shipping

- [ ] Gloock only in the name, page titles, section headings, and headline figures
- [ ] No labels or bars above headings; page type lives in the details column
- [ ] Touch targets at least 48px on phones
- [ ] Links use `accent-text`; fills use `accent`; no white on teal
- [ ] All small text at 4.5:1 or better in **both** themes
- [ ] Offset motif only on images
- [ ] Portfolio ≤3 columns, no dates
- [ ] Checked at desktop, ≤1050px, and ≤760px, with no horizontal scroll
- [ ] Textures are grayscale, centered on 50% grey
