# SmallWorld Frontend Style Guide

Visual language for SmallWorld's React pages. Extracted from the Connector Dashboard, Target Companies, and navigation redesign. **Use this as the reference for all new frontend work.**

> Visual reference with live examples: [style-guide.html](./style-guide.html) (also published at https://assets.smallworld.ai/style-guide.html)

---

## Color System

### Primary

| Token | Hex | Usage |
|-------|-----|-------|
| Blue 500 | `#3f84e5` | Primary CTA, active states, links |
| Blue 600 | `#2e6ec5` | Hover state for primary |
| Blue 50 | `#F1F7FF` | Active filter bg, selected states |
| Blue 100 | `#dbeafe` | Info badges, light blue bg |
| Blue 700 | `#2563eb` | Badge text on blue bg |

### Neutrals

| Token | Hex | Usage |
|-------|-----|-------|
| Gray 900 | `#222222` | Headings, primary text |
| Gray 700 | `#444444` | Strong secondary text |
| Gray 500 | `#77797B` | Body text, descriptions, labels |
| Gray 400 | `#9DA1A5` | Placeholder, muted text, icons |
| Gray 200 | `#e1e5e9` | Borders, dividers, tab rules |

### Surfaces

| Token | Hex | Usage |
|-------|-----|-------|
| Page Background | `#FBFCFE` | Body background |
| Surface Muted | `#f5f7fa` | Alternate bg, footer |
| Surface White | `#FFFFFF` | Cards, header, inputs |
| Surface Subtle | `#F1F5F9` | Secondary buttons, inactive badges |
| Table Header | `#fafbfc` | Table header row bg |

### Semantic

| Token | Hex | Usage |
|-------|-----|-------|
| Success | `#16a34a` | Positive outcomes, confirmations |
| Warning | `#d97706` | Pending, attention needed |
| Danger | `#dc2626` | Errors, destructive actions, alerts |
| Danger Vivid | `#ff0007` | Destructive confirm buttons |

---

## Typography

**Font:** Montserrat (single family for everything). Weights 300-800. Weight and size create hierarchy, not font changes.

| Style | Spec | Example Usage |
|-------|------|---------------|
| Page Title | 20px / 400 / -0.2px | "Can you help SmallWorld get an introduction?" |
| Hero Title | 28px / 300 / -0.3px | "Who do you want to **meet today**?" |
| Section Label | 13px / 600 / 0.8px uppercase | "YOUR ACTION ITEMS" |
| Tab | 13px / 600 | "Target Companies" |
| Nav Item | 14px / 500 | "Relationship Leads" |
| Table Header | 11px / 600 / 0.5px uppercase | "COMPANY  PRIORITY  TYPE" |
| Body | 12-13px / 400-500 | "Richard Perrott — Sr. Director, Engineering" |
| Caption | 11px / 500 | "10mo ago · Targeted by David Rush" |
| Button | 12px / 600-700 | "Share Dashboard", "Offer Help" |

---

## Buttons

### Variants

| Variant | Background | Text | Hover | Use For |
|---------|-----------|------|-------|---------|
| Primary | `#3f84e5` | white | `#2e6ec5` | Main actions: Offer Help, Share |
| Secondary | `#F1F5F9` | `#57595B` | `#e1e5e9` | Cancel, secondary actions |
| Ghost | transparent + blue border | `#3f84e5` | `#F1F7FF` bg | Tertiary actions |
| Danger | `#ff0007` | white | opacity 0.85 | Destructive confirms: Hide, Delete |
| Disabled | any + opacity 0.4 | — | cursor: not-allowed | Inactive state |

### Sizes

| Size | Font | Padding |
|------|------|---------|
| Small | 11px | 5px 14px |
| Medium | 12px | 7px 16px |
| Large | 14px | 10px 20px |

### Filter Buttons

- Default: white bg, `#e1e5e9` border, `#77797B` text
- Active: `#F1F7FF` bg, `#3f84e5` border + text
- Clear: red text (`#ef4444`), red border (`#fecaca`)

---

## Badges & Pills

### Status Badges

| Variant | Background | Text |
|---------|-----------|------|
| Blue | `#dbeafe` | `#2563eb` |
| Red | `#fee2e2` | `#dc2626` |
| Green | `#f0fdf4` | `#16a34a` |
| Yellow | `#fef3c7` | `#d97706` |
| Gray | `#F1F5F9` | `#77797B` |

Size: 10px font, 2px 8px padding, 10px border-radius (pill shape).

### Type Badges

| Type | Background | Text |
|------|-----------|------|
| New Business | `#dbeafe` | `#2563eb` |
| Expansion | `#fef3c7` | `#d97706` |
| Retention | `#f0fdf4` | `#16a34a` |

Size: 11px / 600, 3px 10px padding, 4px border-radius.

---

## Tabs

- Active: `#3f84e5` text + 2px blue bottom border
- Inactive: `#77797B` text, no border
- Font: 13px / 600
- Badge colors are contextual: alert red for counts needing attention, blue for informational

---

## Data Display Components

### Relevance Bars vs. Strength — DO NOT MIX

These two visual patterns look similar but represent different concepts. Picking the wrong one is a confusing UX mistake.

| Concept | Visual | Where it's used |
|---------|--------|-----------------|
| **Relevance** (how well a record matches the user's filters/ICP) | **5 vertical signal bars**, increasing height 5→16px, 3px wide, 2px gap. Filled `#3f84e5`, unfilled `#e1e5e9`. | Connector dashboard, Discover page row scoring. **Bars, never emoji.** |
| **Relationship Strength** (how well a connector knows a prospect) | **Emoji + label** in a colored pill. Always one of the canonical 5 emojis below. **Emoji, never bars.** | Relationship Leads, Introductions, anywhere a `Relationship.strength` is rendered. |

#### Canonical Strength values (use these exactly)

| Key | Emoji | Label | Pill background | Pill text |
|-----|-------|-------|-----------------|-----------|
| `very_strong` | 🔥 | Very Strong       | `#fff0e3` | `#b04300` |
| `strong`      | 💪 | Strong            | `#e6f4ea` | `#1f7a3d` |
| `avg`         | 🤝 | Average           | `#e8f0fe` | `#1a56b8` |
| `weak`        | 👎 | Weak              | `#fef3e2` | `#92560b` |
| `very_weak`   | ❓ | No Relationship   | `#ffe3e3` | `#b50005` |
| (unrated)     | ❓ | Unrated           | `#f1f3f5` | `#77797B` |

Never substitute different emojis (e.g. star, fire variants), never re-use these emojis for non-strength concepts, and never render strength as bars or dots. The single source of truth in code is `STRENGTH_CONFIG` in `frontend/src/components/RelationshipLeads/StrengthBadge.tsx`; keep any prototype mock in sync with it.

### Strength Widget (rating UI)
- **Rated state:** the strength chip above (emoji + label).
- **Unrated state:** a row of 5 clickable emoji icons in 24px boxes with border, in the canonical order. Clicking a level rates the relationship.

### Avatars
Initials on colored circle background. Sizes: 24px (sm), 32px (md), 40px (lg).

### Tables
- Header: 11px / 600 uppercase, `#9DA1A5` text, `#fafbfc` bg, 1px `#e1e5e9` bottom border
- Rows: 12px / 400, `#222` text, 1px `#f0f2f5` bottom border
- Row hover: subtle lift (translateY -1px) + shadow

---

## Popovers & Confirmations

- White bg, `#e8ebef` border, 8px radius, `0 4px 16px rgba(0,0,0,0.08)` shadow
- Title: 12px / 600 / `#222`
- Description: 11px / 400 / `#77797B`
- Buttons right-aligned: Cancel (secondary) + Action (primary or danger)

---

## Layout & Spacing

| Token | Value | Usage |
|-------|-------|-------|
| Max Width | 1200px | All page content containers |
| Page Padding | 20px 1rem | Dashboard main container |
| Card Border Radius | 10px | Cards, modals, popovers |
| Button Border Radius | 4px | All buttons, inputs, selects |
| Badge Border Radius | 10px | Pill badges, count badges |
| Border Color | `#e1e5e9` | Default borders, card edges, tab rules |
| Card Border | `#e8ebef` | Slightly softer, used on cards specifically |
| Row Divider | `#f0f2f5` | Table row borders, subtle dividers |
| Hover Lift | translateY(-1px) | Card hover, row hover |
| Hover Shadow | 0 2px 12px rgba(0,0,0,0.05) | Card hover shadow |
| Transition | all 0.15s | Default for interactive elements |

---

## Shadcn & Tailwind Guidelines

### Component Hierarchy

1. **Shadcn first.** Before building any interactive component (dialog, popover, tooltip, select, dropdown, tabs, accordion), check if Shadcn has it. Use `yarn shadcn:add [component]`. These are in `src/components/ui/shadcn/` — never edit generated files directly.
2. **Wrap with custom styles.** Create thin wrappers in `src/components/ui/` that apply SmallWorld styling via component CSS (not Tailwind utilities).
3. **Custom only when Shadcn doesn't cover it.** Strength widget, relevance bars, avatar — build from scratch with Montserrat + our color tokens.

### Shadcn Components in Use

| Component | Radix Source | Used For |
|-----------|-------------|----------|
| Dialog | `@radix-ui/react-dialog` | Offer Help modal, Offer Intro modal, Strength Info |
| Popover | `@radix-ui/react-popover` | Hide/Flag confirmation popovers |
| Tooltip | `@radix-ui/react-tooltip` | Strength emoji tooltips, relevance tooltip |
| Select | `@radix-ui/react-select` | Filter dropdowns (relevance, type, account owner) |

### Tailwind Usage

**Do:**
- Use Tailwind for layout utilities: `flex`, `gap-2`, `grid`, `p-4`, `max-w-screen-xl`
- Write component-scoped CSS in a `.css` file next to the component (e.g., `ConnectorDashboard.css`)

**Don't:**
- Use Tailwind utilities to style Shadcn components — specificity conflicts with Tailwind v4's `@layer` system make this unreliable
- Mix Tailwind utilities with component CSS for the same element — choose one approach per component

### Styling Shadcn Overrides

```tsx
/* Good — inline style on the Shadcn component */
<DialogContent style={{ border: '1px solid #e1e5e9', maxWidth: '480px' }}>

/* Good — className with component CSS */
<PopoverContent className="action-confirm-popover">

/* Good — className + custom render for complex overrides */
<DialogClose style={{ all: 'unset', position: 'absolute', ... }}>

/* Bad — Tailwind utilities get out-specificed */
<DialogContent className="border border-gray-200 max-w-md">
```

---

## Gotchas & Patterns

1. **Radix portal scoping.** Dialog, Popover, Tooltip render at `document.body`, outside your component's DOM tree. Scope portal styles to a class on the portal content (e.g., `.action-confirm-popover`), never to a page container (e.g., `.connector-dashboard`).

2. **Shadcn + Tailwind specificity.** Tailwind v4's `@layer` system means utility classes often lose to Shadcn's component styles. Use inline styles or component CSS for overrides.

3. **TanStack Query for all API data.** Invalidate queries after mutations. Use optimistic updates for UI that needs to feel instant (like strength rating).

4. **Turbolinks stylesheet persistence.** Use `turbolinks-visit-control: reload` meta tag on React layouts to flush old Rails CSS when navigating from legacy pages.
