# Brand Kit — Agent Authoring Guide

This document is the source of truth for Florent Stroppa's personal brand. Any agent that generates slides, announcements, social posts, or any branded content for florentstroppa.com **must** read this guide first, then follow it.

A machine-readable mirror of this guide exists as JSON embedded in `/brand-kit/index.html` — see the "Reading the JSON" section below. Everything in this markdown document also exists in the JSON, so agents can pick whichever format is easier to consume.

---

## 1. What you have to work with

| Resource | Path | Purpose |
|---|---|---|
| Shared viewer CSS | `/slide-viewer.css` | All slide layout, typography, variants, primitives |
| Shared viewer JS | `/slide-viewer.js` | Navigation, sidebar, fullscreen, uniform scaling |
| Brand JSON | `<script id="brand-data">` inside `/brand-kit/index.html` | Programmatic access to everything |
| Logo | `/fs-icon.svg` | Monochrome FS mark, always SVG |
| Visual reference | `/brand-kit/` | 12 slides showing every variant and primitive in action |
| This guide | `/brand-kit/AGENTS.md` | Human-readable rules for agents |

Every slide-based page imports `slide-viewer.css` and `slide-viewer.js`. Agents must never duplicate or re-implement these — reuse them.

---

## 2. Reading the JSON programmatically

```js
const res = await fetch('/brand-kit/');
const doc = new DOMParser().parseFromString(await res.text(), 'text/html');
const brand = JSON.parse(doc.getElementById('brand-data').textContent);

brand.tagline;                 // 'Forty years of computing, through my own eyes.'
brand.typography.scale;        // { detail, body, subhead, title } with px values
brand.variants;                // { dark, bright, c64, split }
brand.layouts;                 // Layout primitives reference
brand.voice.forbidden;         // Phrases and chars to never use
brand.phrases.use;             // Approved taglines
brand.checklist;               // Validation checklist
```

The JSON is the authoritative spec. If anything disagrees between this markdown and the JSON, the JSON wins.

---

## 3. The golden rule: no inline font-size

The slide viewer exposes **exactly 4 text sizes** as CSS variables. These are the only sizes allowed inside a slide.

| Token | Value | Use for |
|---|---|---|
| `--s-detail` | 26px | Captions, metadata, small supporting copy |
| `--s-body` | 32px | Default reading size, list items, swatch labels |
| `--s-subhead` | 44px | Subtitles (h3), large labels, font samples |
| `--s-title` | 92px | h1, h2, main headlines |

**Never set `font-size` inline in HTML.** If content overflows, switch to a denser layout primitive (see section 6), not a smaller arbitrary size.

The one exception: `font-family` inline on `.font-sample` inside `.font-row`, because the purpose of the slide is to demonstrate different fonts.

---

## 4. Slide skeleton

```html
<div class="slide" data-slide="N">
  <div class="slide-branding"><img src="/fs-icon.svg" alt="FS"></div>

  <div class="slide-header">
    <span class="slide-label">SURTITLE</span>
    <h2>Title of the slide</h2>
  </div>

  <div class="slide-content">
    <p>Primary body text.</p>
    <p class="slide-detail">Secondary caption or metadata.</p>
  </div>
</div>
```

Rules:

- `data-slide` is the slide's **1-indexed** position. The JS auto-generates a padded `data-num` (01, 02, ...) for the editorial background number.
- `.slide-branding` is **always a direct child** of `.slide` (or a sibling of `.slide-body` and `.slide-media` in the split variant). Never nest it deeper.
- `.slide-header` holds the surtitle (`.slide-label`) plus the title (`h1` or `h2`).
- `.slide-content` holds the body and any layout primitives.
- Slides are authored at a fixed intrinsic canvas of **1600 × 900 px**. The viewer scales them uniformly to fit any container. Do not target viewport sizes.
- Every new slide **must** also get a matching entry in the sidebar `.slide-list` with the same `data-slide` number.

---

## 5. The 4 variants

| Class | Use for | Background | Text | Accent |
|---|---|---|---|---|
| `.slide` | Default body content, specs, reference | Dark gradient `#0f1014` → `#141520` | `#f5f5f7` | `#22d3ee` |
| `.slide.slide--bright` | Announcements, punchy claims (max 2 per deck) | Cyan gradient `#22d3ee` → `#0891b2` | `#0a0a0b` | `#0a0a0b` |
| `.slide.slide--c64` | Retro computing nostalgia, Commodore callbacks | C64 blue gradient `#40318D` → `#2a2266` | `#f5f5f7` | `#7B71D5` |
| `.slide.slide--split` | Content + hero image for announcements | Dark content left + full-bleed image right (50/50) | `#f5f5f7` on content side | `#22d3ee` |

### Dark (default)

```html
<div class="slide" data-slide="5">
  <div class="slide-branding"><img src="/fs-icon.svg" alt="FS"></div>
  <div class="slide-header">
    <span class="slide-label">Chapter</span>
    <h2>Headline</h2>
  </div>
  <div class="slide-content">
    <p>Body copy.</p>
    <p class="slide-detail">Caption.</p>
  </div>
</div>
```

### Bright

```html
<div class="slide slide--bright" data-slide="9">
  <div class="slide-branding"><img src="/fs-icon.svg" alt="FS"></div>
  <div class="slide-header">
    <span class="slide-label">Announcement</span>
    <h2>Bold claim.</h2>
  </div>
  <div class="slide-content">
    <p>Why it matters in one short paragraph.</p>
  </div>
</div>
```

The logo is automatically inverted via CSS filter so it stays visible on the cyan background.

### C64

```html
<div class="slide slide--c64" data-slide="10">
  <div class="slide-branding"><img src="/fs-icon.svg" alt="FS"></div>
  <div class="slide-header">
    <span class="slide-label">Retro</span>
    <h2>Retro claim.</h2>
  </div>
  <div class="slide-content">
    <p>C64 flavored copy, with Commodore references welcome.</p>
    <p class="slide-detail">READY. · LOAD "*",8,1 · RUN</p>
  </div>
</div>
```

### Split (50/50 content + image)

```html
<div class="slide slide--split" data-slide="12">
  <div class="slide-body">
    <div class="slide-header">
      <span class="slide-label">Announcement</span>
      <h2>New thing coming.</h2>
    </div>
    <div class="slide-content">
      <p>Description.</p>
      <p class="slide-detail">Smaller details.</p>
    </div>
  </div>
  <div class="slide-media" style="background-image: url('/path/to/image.webp');"></div>
  <div class="slide-branding"><img src="/fs-icon.svg" alt="FS"></div>
</div>
```

**Critical for split:**

- `.slide-branding` is a **sibling** of `.slide-body` and `.slide-media`, **not** nested inside `.slide-body`. This is what makes the logo land in the bottom-right corner over the image (with a drop-shadow filter for visibility).
- `.slide-media` holds the hero image via `background-image` inline. No `<img>` tag.
- No separator line between the two halves. The base `.slide` CSS handles the clean cut.

---

## 6. Layout primitives

All primitives live inside `.slide-content`. Pick the one that matches your content shape.

### `two-columns`

Two side-by-side content columns.

```html
<div class="two-columns">
  <div class="column">
    <h3>Left</h3>
    <p>...</p>
  </div>
  <div class="column">
    <h3>Right</h3>
    <p>...</p>
  </div>
</div>
```

### `comparison`

Two panels for binary comparisons (good / bad, on-brand / off-brand).

```html
<div class="comparison">
  <div class="comparison-col">
    <h3>On brand</h3>
    <ul><li>...</li></ul>
  </div>
  <div class="comparison-col muted">
    <h3>Off brand</h3>
    <ul><li>...</li></ul>
  </div>
</div>
```

### `feature-grid`

2-column grid of tile cards. Each tile has an `h4` heading + `p` description.

```html
<div class="feature-grid">
  <div class="feature-item">
    <h4>Heading</h4>
    <p>Description in one line.</p>
  </div>
  <!-- ... -->
</div>
```

### `icon-grid`

3-column grid of icon tiles. Each tile has a Lucide SVG + an uppercase name label.

```html
<div class="icon-grid">
  <div class="icon-tile">
    <svg class="icon icon--lg" viewBox="0 0 24 24">
      <polyline points="4 17 10 11 4 5"/>
      <line x1="12" y1="19" x2="20" y2="19"/>
    </svg>
    <span class="icon-name">Terminal</span>
  </div>
  <!-- ... -->
</div>
```

**Do not** add `flex: 1` to `.icon-grid` — it will stretch the grid to fill remaining space and push sibling paragraphs out of the slide.

### `principle-list`

Vertical list of yes/no principle rows. Each row has a colored circular mark and a bold lead + trailing explanation.

```html
<div class="principle-list">
  <div class="principle-row yes">
    <span class="mark">✓</span>
    <div class="principle-text"><strong>Do:</strong> short explanation.</div>
  </div>
  <div class="principle-row no">
    <span class="mark">✕</span>
    <div class="principle-text"><strong>Don't:</strong> what to avoid.</div>
  </div>
</div>
```

For **6 or more** items, add the grid modifier so the list wraps into 2 columns:

```html
<div class="principle-list principle-list--grid">
  ...
</div>
```

### `color-grid`

4-column grid of color swatches.

```html
<div class="color-grid">
  <div class="color-swatch" style="background: #0a0a0b; color: #f5f5f7;">
    <div class="swatch-name">Ink</div>
    <div class="swatch-hex">#0a0a0b</div>
  </div>
  <!-- ... -->
</div>
```

### `font-row`

A row in a font specimen list.

```html
<div class="font-row">
  <span class="font-sample" style="font-family: 'Space Grotesk', sans-serif; font-weight: 600;">Space Grotesk</span>
  <span class="font-meta">UI · Titles</span>
</div>
```

This is the one place where inline `font-family` is allowed, because the purpose is to demonstrate different fonts. The size is still controlled by the token.

---

## 7. Iconography

Icons come from **Lucide** (https://lucide.dev). Always inline as SVG with `class="icon"` plus a size modifier.

```html
<svg class="icon icon--lg" viewBox="0 0 24 24">
  <!-- paste the Lucide SVG child nodes here -->
</svg>
```

| Class | Size |
|---|---|
| `.icon--sm` | 32px |
| `.icon--md` | 48px |
| `.icon--lg` | 72px |
| `.icon--xl` | 112px |

The CSS enforces the style so you don't have to set it on each SVG:

```css
.slide svg.icon {
  stroke: currentColor;
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
```

- Always inherit color via `currentColor` — this makes icons adapt automatically to each variant.
- Never fill, never add color, never change the stroke width.
- Never mix Lucide with other icon libraries in the same deck.
- Never use solid or duotone variants.

---

## 8. Voice and tone

### Do

- Direct and factual. Never friendly, never cute.
- Show craft over status. Demonstrate, don't claim.
- Short sentences. Strong claims. No hedging.
- Passionate about computing, not about "tech" in the abstract.
- Technical precision beats broad enthusiasm.

### Don't

- **No em-dashes** in any text, not even in titles. Use periods or commas.
- No emoji in headings, captions, or body.
- No stock phrases: "passion for tech", "tech enthusiast", "digital native", "unlocking the power of AI", "bringing innovation to the forefront".
- No exclamation marks except inside code strings.
- No corporate stock-photo language.

### Approved taglines

- Forty years of computing, through my own eyes.
- From the Commodore 64 to Claude Code.
- Interactive retro terminals, C64 to Claude.
- Documenting my 40-year love story with computers.
- Hands-on Claude, MCP, and AI coding.

### Phrases to avoid

- Passion for tech
- Tech enthusiast
- Bringing innovation to the forefront
- Unlocking the power of AI
- Digital native

---

## 9. Imagery

### On brand

- Retro machines: C64, Amiga, Atari ST, Mac OS X classic, terminals
- CRT screens, phosphor glow, scanlines, PETSCII art
- Hand-written code with real syntax highlighting
- TV frames, bezels, showroom compositions
- Archival photos of hardware

### Off brand

- Generic stock photography
- Glossy 3D renders of laptops on clean desks
- Abstract corporate gradients without computing reference
- Modern skeuomorphism or glassmorphism as standalone aesthetic
- Generic AI-generated images

---

## 10. Pre-publish checklist

Before publishing any new slide, verify every item:

1. No inline `font-size` anywhere in the slide
2. No em-dashes in any text
3. No emoji in text content
4. Uses only the 4 type tokens (`--s-detail`, `--s-body`, `--s-subhead`, `--s-title`)
5. Uses CSS variables for colors in helpers, not hardcoded hex
6. Slide fits within 1600 × 900 visually (overflow is hidden, but verify)
7. Variant class matches the content purpose
8. `.slide-branding` is in the correct position for the variant
9. `data-slide` has a unique 1-indexed number matching the slide position
10. Captions use `<p class="slide-detail">`, primary body uses plain `<p>`
11. Icons come from Lucide with `stroke-width="2"`, `currentColor`, `fill="none"`
12. No forbidden phrases (see `voice.forbidden` or section 8)
13. Sidebar `.slide-list` has a matching entry for the new slide

---

## 11. When to break the rules

Don't. If a new use case can't be expressed with the existing variants and primitives, raise it as a design decision first. New variants are only worth creating if they will be reused at least 3 times. Otherwise, bend an existing variant with inline wrapper styles (margins, grid columns, background-image) but never override text sizes.
