# ContentOps — Foundational UX & Design Spec

> Locked decisions feed every screen. Edit here; do not re-litigate in screen files.

## 1. Product UX Archetype

**Pipeline workspace with entity hierarchies and a calendar surface.**

Linear's state-machine discipline (every ContentItem moves through 12 strict states with one-way gates) wrapped around Attio's entity hierarchy (Org → Brand → Campaign → ContentItem → Draft Vn → AssetSet Vn → PublishJob), with Buffer's calendar as the publish-side surface. Not a dashboard, not a marketplace, not a CMS, not an inbox. User mental model: "I am moving N posts through a production line, I need to see each one's state at a glance, jump in, do the next action, and ship it on a calendar."

## 2. Navigation & Information Architecture

**Primary**: persistent collapsible left sidebar (240px expanded / 56px collapsed icon-only) + thin top bar (48px).

### Sidebar (locked order)

```
─ Workspace ─────────────────
  ◆ Home               (workspace dashboard)
  ◆ Calendar           (org-wide publish surface)

─ Pipeline ──────────────────
  ◆ Campaigns          (default landing for active work)
  ◆ Content            (flat list, cross-campaign)
  ◆ Activity           (audit feed)

─ Library ───────────────────
  ◆ Brand profiles

─ Bottom-pinned ─────────────
  ◆ Settings           (General / Members / Billing / Integrations sub-nav)
  ◆ Cost meter chip    ($128 / $500 MTD → Billing)
  ◆ User avatar menu   (profile, sign out, org switcher)
```

### Secondary

- **Inside Campaign**: horizontal tabs — Board · List · Settings · Analytics. Board default.
- **Inside ContentItem**: horizontal stepper — Ideation → Draft → Assets → Publish — doubles as breadcrumb + state indicator. Current = filled accent; completed = filled stone + checkmark, clickable; future = outlined, disabled.
- **Breadcrumbs** in top bar, max 3 levels: `Campaign › Item title`.
- **Inside Brand profile / Settings**: left sub-nav within the page.

### Global actions (top bar L→R)

| Slot | Element |
|---|---|
| Far left | Sidebar collapse toggle |
| Left | Breadcrumb |
| Center | Empty |
| Right | Global search (⌘K palette: jump + create + recent) |
| Right | `+ New` split button (Campaign / ContentItem / Brand profile) |
| Right | Notifications |
| Right | User avatar |

## 3. Layout System

**Template**: sidebar + top bar + main. Main is fluid up to 1440px max-width on prose-heavy screens (brand profile, content item shell); full-bleed on calendar / board / list.

**ContentItem screens use a three-pane variant**: stepper header (full width) + main canvas (fluid) + right inspector (320px, collapsible). Inspector holds item metadata, version rails (drafts V1..V5, asset_set V1..Vn), live cost meter.

**Density**: comfortable-dense. Base font 13px, base row 36px, input 36px, primary button 32px. Tables get compact/comfortable toggle.

**Responsive at desktop**:
- ≥1440px: sidebar expanded, inspector open.
- 1280–1440px: inspector collapsible (default open).
- 1024–1280px: sidebar auto-collapses to icon rail, inspector → tab-on-edge.
- <1024px: sidebar overlay, inspector → modal sheet.
- <768px: "open on desktop" splash. Out of scope.

## 4. Visual Design Language

### Tone

Reference products:
1. **Linear** — state-pill rigor, keyboard-first, state legibility in <100ms.
2. **Attio** — entity-aware workspace, record-like filter/group/sort.
3. **Vercel dashboard** — deploy-history / version-rail pattern maps onto V1..V5 drafts and Vn asset_sets.

Feel: precise, calm, content-focused, slightly editorial. Not creative-tool. Not Salesforce.

### Color palette

Light theme canonical. Warm-neutral grays (stone) + single cool accent (indigo).

| Token | Hex | Use |
|---|---|---|
| `bg` | `#FAFAF9` | App background |
| `surface` | `#FFFFFF` | Cards, inputs, modals, rows |
| `surface-2` | `#F5F5F4` | Hover, section bands, secondary btn |
| `surface-3` | `#E7E5E4` | Selected row, code blocks |
| `border` | `#E7E5E4` | Default 1px |
| `border-strong` | `#D6D3D1` | Input border, weighted dividers |
| `text` | `#1C1917` | Headings, body |
| `text-muted` | `#57534E` | Secondary labels, metadata |
| `text-subtle` | `#A8A29E` | Placeholders, disabled, timestamps |
| `accent` | `#4F46E5` | Primary actions, links, focus, selected |
| `accent-hover` | `#4338CA` | Primary btn hover |
| `accent-bg` | `#EEF2FF` | Selected row, accent pill bg |
| `success` | `#15803D` | Published, ready, active |
| `success-bg` | `#DCFCE7` | Success pill bg |
| `warning` | `#B45309` | Cost soft-warn, must-include, cap amber |
| `warning-bg` | `#FEF3C7` | Warning pill bg |
| `danger` | `#B91C1C` | Failures, banned terms, hard-block, destructive |
| `danger-bg` | `#FEE2E2` | Danger pill bg |
| `info` | `#1D4ED8` | Generating / publishing in-flight |
| `info-bg` | `#DBEAFE` | Info pill bg |

### Typography

**Hanken Grotesk** (UI + headings) + **JetBrains Mono** (numerals, IDs, timestamps, costs, char counters, version labels). Both Google Fonts.

| Token | px | LH | Weight | Use |
|---|---|---|---|---|
| xs | 11 | 14 | 500 | Pills, badges, char-counter prefix |
| sm | 12 | 16 | 400/500 | Secondary labels, helper, dense cells |
| base | 13 | 18 | 400 | UI body, default table, form labels |
| md | 14 | 20 | 500 | Buttons, primary labels, card titles |
| lg | 16 | 24 | 500 | Section headings |
| xl | 18 | 26 | 500 | Card-row titles (ContentItem on board) |
| 2xl | 22 | 28 | 600 | Page title, Campaign name, H1 |
| 3xl | 28 | 34 | 600 | Empty-state hero, sign-in/up |
| display | 36 | 42 | 600 | Workspace home greeting |

Letter-spacing −0.01em on ≥18px. Numeric always tabular-nums.

### Radius

| Token | px | Use |
|---|---|---|
| xs | 4 | Chips, inline tags, swatches |
| sm | 6 | Buttons, inputs, state pills |
| md | 8 | Cards, popovers, dropdowns |
| lg | 12 | Modals, asset previews |
| full | 9999 | Avatars only |

State pills are 6px not full-pill (crisp/precise like Linear, not casual like Slack).

### Elevation

Border-led, shadow-light. The workspace should feel printed, not floating.

| Token | Definition | Use |
|---|---|---|
| e0 | 1px solid border | Default surface separation |
| e1 | 0 1px 2px rgba(0,0,0,.06) + 1px border | Kanban, hovered rows |
| e2 | 0 4px 12px rgba(0,0,0,.08) | Popovers, dropdowns, floating inspector |
| e3 | 0 12px 32px rgba(0,0,0,.12) | Modals, command palette |
| focus | 0 0 0 3px rgba(79,70,229,.18) + 1px accent | Every interactive focus |

### Iconography

**Lucide, 1.5px stroke**, 16px default (20px in headers, 14px in dense tables). Outline-only. Functional, not decorative.

## 5. Component Conventions

### Buttons (heights 28 / 32 / 40)

| Variant | Treatment | When |
|---|---|---|
| Primary | Solid accent bg, white text, no border | One per screen: state-advancing action |
| Secondary | White bg, 1px border-strong, text color | Save draft, Save as V_n, Edit |
| Tertiary / Ghost | No bg/border, hover surface-2 | Dense menus, row actions, modal Cancel, sidebar |
| Destructive | Solid danger bg, white text | Confirm step inside delete/archive modals only |
| Icon-only | 28×28, ghost default | Row actions, close X, collapse |

Disabled = 50% opacity. Loading = leading spinner inside same variant.

### Cards / surfaces

White bg, 1px border, 8px radius, 16px padding (20px for "feature" cards). Hover = border darkens to border-strong. Kanban cards use e1. Asset previews use 12px radius.

### Form fields

- Input height **36px**, 1px border-strong, 6px radius, 13px text, 12px h-padding.
- Label 12px/500/text, 6px above input. No floating labels.
- Helper 12px/text-muted, 6px below.
- Error 1px danger border, 12px/danger below.
- Focus 1px accent border + 3px ring.
- **Chip inputs** (must_include, banned_terms, hashtags, platforms): chips 22px, 6px radius, surface-2 bg, X on hover. Enter/comma commits. Used everywhere — get it perfect.
- Textareas: min-height 80px, auto-grow to 320px then scroll.
- Inline validation badges always with text.

### Tables / lists

- Header 36px, 11px uppercase tracking +0.04em text-muted, surface-2 bg, sticky.
- Body row 40px (comfortable) / 32px (compact), 13px text, 1px bottom border.
- Row hover bg subtle warm wash.
- Row selected: 2px left accent border + accent-bg tint.
- Empty-state inside table: full-width row, centered message + primary CTA.
- **Kanban cards** (Campaign board): column-per-state, 12px padding, 8px radius, e1 shadow. Card shows title, state pill, format icon, platform chips, last-touched, owner.

### State pills (most-used component)

22px tall, 6px radius, 11px/500, 6px h-padding, leading 6px dot. **Fixed mapping reused identically across lists, kanban, calendar, item header, stepper.**

| State | Dot | Bg | Text | Notes |
|---|---|---|---|---|
| draft_new | stone-400 | surface-2 | text-muted | Awaiting input |
| ideating | info | info-bg | info | Exploring |
| direction_selected / draft_pending | accent | accent-bg | accent | "Drafting" |
| draft_locked | warning | warning-bg | warning | Owes a brief |
| asset_generating | info + pulse | info-bg | info | In flight |
| asset_review | accent | accent-bg | accent | Awaiting decision |
| ready_to_publish | success | success-bg | success | Cleared |
| scheduled | success | surface | success | **Outlined, not filled** — distinguishes promise vs receipt |
| publishing | info + pulse | info-bg | info | Provider call |
| published | success | success-bg | success | ✓ inside dot |
| failed | danger | danger-bg | danger | Action: Retry |
| canceled | stone-400 | surface-2 | text-subtle | Italicized |
| archived | stone-400 | surface-2 | text-subtle | Hidden default |

### Empty / loading / error

- **Empty**: centered 32px Lucide line icon (stone-400), 18px text title, 13px text-muted sub, single primary CTA. ~280px max width. No illustrations.
- **Loading**: skeleton in surface-2, 1.5s linear shimmer. Tables show 4–6 rows matching column widths. Per-slot generation uses real provider-job state, not skeleton.
- **Error**: top-of-page banner 1px danger border + danger-bg + danger text, leading alert icon, inline retry CTA. Field-level errors below field. Banned-term blocks show banner + inline highlight on offending text.

---

## Deliberate non-decisions (push back to change)

1. No top-level tabs. Sidebar carries all IA.
2. No floating action buttons. `+ New` is top-bar split-button.
3. No illustrations in empty states. Quiet and functional.
4. No dark theme in v1.
5. Inspector defaults open on ContentItem screens.
6. Cost meter ambient (sidebar bottom), not top bar.
7. State pills use a strict 13-entry color map identical across surfaces.
