# PayCargo Forge — cartridge design system

Visual reference for cartridge frontends. Complements `CLAUDE.md` (rules-of-engagement) and `.claude/skills/forge-sdk/SKILL.md` (operational patterns). All tokens and components below are defined in the SDK bundle at `./forge-sdk/console/sdk/v1/css/tokens.css` and `./forge-sdk/console/sdk/v1/css/components.css`. At runtime they load from the Console origin — do NOT vendor, fork, or override them from a cartridge.

---

## External dependencies (already loaded by the Console SDK)

```html
<!-- Font Awesome 6 Pro (PayCargo kit — icons available across the platform) -->
<link rel="stylesheet"
      href="https://kit.fontawesome.com/d28826e619.css"
      crossorigin="anonymous">
<script src="https://kit.fontawesome.com/d28826e619.js"
        crossorigin="anonymous"></script>

<!-- Inter typeface (400/500/600/700) -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
      rel="stylesheet">

<!-- Design tokens + components — loaded from Console origin at boot -->
<link rel="stylesheet" data-pcsdk href="/sdk/v1/css/tokens.css">
<link rel="stylesheet" data-pcsdk href="/sdk/v1/css/components.css">
```

`PCSDK.auth.ready()` rewrites the `data-pcsdk` URLs to the Console origin (`https://<console-domain>/sdk/v1/…`) so the cartridge inherits every update the Console ships. Do not add cache-busters, do not remove the `data-pcsdk` marker.

---

## Design tokens

Every color, font size, and spacing constant in a cartridge frontend comes from a CSS custom property. Never hardcode a hex, never inline a font size. If a token you need is missing, propose adding it to `tokens.css` in the main repo — do not invent a per-cartridge shim.

### Brand colors

| Token | Value | Use for |
|---|---|---|
| `--pc-blue` | `#0094d9` | Primary brand; links; focus outlines; icon accents |
| `--pc-dark-blue` | `#006797` | Hover states on `--pc-blue`; strong emphasis text |
| `--pc-sidebar-bg` | `#1e5077` | Sidebar background; secondary buttons |
| `--pc-orange` | `#f69246` | Warm accent |
| `--pc-accent-orange` | `rgb(248, 147, 52)` | Primary CTA buttons |
| `--pc-green` | `#57c436` | Success indicators |
| `--pc-light-green` | `#81d4a5` | Muted success backgrounds |
| `--pc-yellow` | `#f9c562` | Warning accents |
| `--pc-red` | `#fe4a49` | Error accents |

### Neutrals

| Token | Value | Use for |
|---|---|---|
| `--pc-black` | `#181818` | Body copy; primary headings |
| `--pc-obsidian` | `#474747` | Secondary body copy |
| `--pc-grey` | `#a0a0a0` | Muted controls |
| `--pc-light-grey` | `#cdcdcd` | Borders; dividers |
| `--pc-white` | `#ffffff` | Card backgrounds |
| `--pc-cloud-white` | `#f1faff` | Hover backgrounds on tables |

### Surfaces

| Token | Value | Use for |
|---|---|---|
| `--pc-body-bg` | `#fafcfd` | Page background |
| `--pc-card-bg` | `#ffffff` | Card / modal background |
| `--pc-table-header-bg` | `#f5f6f8` | Table header rows; muted label cells |
| `--pc-input-bg` | `rgba(238, 238, 238, 0.6)` | Form input backgrounds |
| `--pc-info-blue-bg` | `#dff0f8` | Info callouts; handoff cards |
| `--pc-accent-orange-light` | `#feefe1` | Warning callouts |

### Sidebar-specific (dark background context)

| Token | Value | Use for |
|---|---|---|
| `--pc-sidebar-icon` | `rgba(255, 255, 255, 0.7)` | Sidebar nav icons at rest |
| `--pc-sidebar-text` | `rgba(255, 255, 255, 0.8)` | Sidebar nav labels at rest |
| `--pc-sidebar-hover` | `rgba(255, 255, 255, 0.15)` | Sidebar nav item hover background |

### Text

| Token | Value | Use for |
|---|---|---|
| `--pc-text-primary` | `rgba(0, 0, 0, 0.87)` | Body copy at rest |
| `--pc-text-secondary` | `rgb(80, 84, 88)` | Descriptions; helper text |
| `--pc-text-muted` | `rgb(121, 121, 121)` | Timestamps; least emphasis |
| `--pc-text-placeholder` | `rgb(158, 158, 158)` | Form placeholders |
| `--pc-link` | `#0094d9` | Anchor text (same as `--pc-blue`) |
| `--pc-error-red` | `rgb(233, 1, 1)` | Inline error copy |
| `--pc-status-orange-text` | `rgb(214, 106, 2)` | Warning callout labels |

### Typography

| Token | Value | Use for |
|---|---|---|
| `--pc-font-family` | `'Inter', sans-serif` | All UI text |
| `--pc-font-size-base` | `16px` | Body text |
| `--pc-font-size-sm` | `14px` | Buttons; table cells |
| `--pc-font-size-xs` | `12px` | Table headers; secondary text |
| `--pc-font-size-xxs` | `11.5px` | Badges; small counters |
| `--pc-font-size-h1` | `18px` (bold 700) | Page headings |

### Layout / dimensions

| Token | Value | Use for |
|---|---|---|
| `--pc-sidebar-width` | `213px` | Left sidebar width |
| `--pc-sidebar-item-height` | `40px` | Sidebar nav item height |
| `--pc-input-height` | `56px` | Form input height |
| `--pc-button-height` | `44px` | Primary button height |
| `--pc-border-radius` | `4px` | Default corner radius |
| `--pc-border-radius-sm` | `3px` | Small buttons, filter chips |

---

## Component patterns

### Buttons

Every button uses `font-family: var(--pc-font-family)`, `font-size: var(--pc-font-size-sm)`, and `font-weight: 500` unless otherwise noted.

| Variant | Background | Text | Height | Radius | When to use |
|---|---|---|---|---|---|
| **Primary CTA** | `var(--pc-accent-orange)` | `white` | `44px` | `3px` | Main action on a page (Save, Submit, Create). One per view. |
| **Secondary** | `var(--pc-sidebar-bg)` | `white` | `44px` | `3px` | Alternate action (Cancel, Back). |
| **Outline** | `transparent` | `var(--pc-blue)` | — | — | `border: 1px solid var(--pc-blue)`. Low-emphasis actions. |
| **Text / Link** | `transparent` | `var(--pc-blue)` | — | — | No border. Tertiary actions ("Learn more"). |
| **Filter** | `var(--pc-accent-orange)` | `white` | `40px` | `4px` | Apply Filter, Search on a data table. |
| **Clear / Export** | `transparent` | inherits | `40px` | — | `border: 1px solid var(--pc-light-grey)`. Reset / Export CSV / etc. |

```css
.pc-btn-primary {
  background: var(--pc-accent-orange);
  color: #fff;
  border: none;
  height: 44px;
  padding: 0 20px;
  border-radius: 3px;
  font-family: var(--pc-font-family);
  font-size: var(--pc-font-size-sm);
  font-weight: 500;
  cursor: pointer;
}
```

### Form inputs

```css
.pc-input {
  height: 56px;
  padding: 16.5px 14px;
  background: var(--pc-card-bg);
  border: 1px solid var(--pc-light-grey);
  border-radius: 4px;
  font-family: var(--pc-font-family);
  font-size: var(--pc-font-size-base);
  color: var(--pc-text-primary);
}
.pc-input:focus {
  outline: 2px solid var(--pc-blue);
  outline-offset: -1px;
}
.pc-input::placeholder { color: var(--pc-text-placeholder); }
```

### Data tables

```css
.pc-table th {
  background: var(--pc-table-header-bg);
  padding: 12px 16px;
  font-size: var(--pc-font-size-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--pc-text-primary);
  text-align: left;
}
.pc-table td {
  padding: 12px 16px;
  font-size: var(--pc-font-size-sm);
  font-weight: 400;
  color: var(--pc-text-primary);
  border-bottom: 1px solid var(--pc-light-grey);
}
.pc-table tr:hover td { background: var(--pc-cloud-white); }
```

The SDK's `PCSDK.ui.Table` component already renders these classes. Use it directly instead of hand-rolling — see `./forge-sdk/docs/handler-reference.md` and the SDK's `js/table.js`.

### Status badges

| Status | Background | Text |
|---|---|---|
| **Dismissed** | `#feefe1` | `rgb(214, 106, 2)` |
| **Approved** | `#e8f9e0` | `#2e7d32` |
| **Pending** | `var(--pc-info-blue-bg)` | `var(--pc-dark-blue)` |
| **Error** | `#fde8e8` | `#c62828` |

```css
.pc-badge {
  display: inline-block;
  padding: 3px 9px;
  font-size: var(--pc-font-size-xxs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  border-radius: 3px;
  white-space: nowrap;
}
.pc-badge.is-approved { background: #e8f9e0; color: #2e7d32; }
.pc-badge.is-pending  { background: var(--pc-info-blue-bg); color: var(--pc-dark-blue); }
.pc-badge.is-dismissed { background: #feefe1; color: var(--pc-status-orange-text); }
```

### Callouts

Info and warning callouts for operator instructions, notes, and warnings inside cartridge pages.

```css
.pc-callout {
  background: var(--pc-info-blue-bg);
  border-left: 4px solid var(--pc-blue);
  padding: 14px 18px;
  border-radius: 3px;
  margin: 12px 0;
  font-size: 14px;
  color: var(--pc-obsidian);
}
.pc-callout.is-warn {
  background: var(--pc-accent-orange-light);
  border-left-color: var(--pc-status-orange-text);
}
```

### Sidebar navigation (Console-style)

If the cartridge has its own left-rail nav (unusual — most cartridges use the Console launcher's rail), match the Console's shape:

```css
.pc-sidebar {
  width: var(--pc-sidebar-width);
  background: var(--pc-sidebar-bg);
  color: var(--pc-sidebar-text);
}
.pc-sidebar .nav-item {
  height: var(--pc-sidebar-item-height);
  color: var(--pc-sidebar-text);
  padding: 0 16px;
  display: flex;
  align-items: center;
  gap: 10px;
}
.pc-sidebar .nav-item:hover { background: var(--pc-sidebar-hover); }
.pc-sidebar .nav-item.is-active { background: rgba(255, 255, 255, 0.20); color: #fff; }
.pc-sidebar .nav-item i { color: var(--pc-sidebar-icon); font-size: 14px; }
```

---

## Iconography

**Font Awesome 6 Pro** via the PayCargo kit (see External Dependencies above). Use `fa-regular` weight for UI icons; `fa-solid` is reserved for diagrams and status indicators where the fill is meaningful.

Common navigation icons the platform uses:

| Purpose | Icon |
|---|---|
| Home | `fa-regular fa-house` |
| Make Payment | `fa-regular fa-file-circle-plus` |
| Funds | `fa-regular fa-wallet` |
| Vendors | `fa-regular fa-buildings` |
| Reports | `fa-regular fa-chart-column` |
| Cart | `fa-regular fa-cart-shopping` |
| Support | `fa-regular fa-headset` |
| Settings | `fa-regular fa-gear` |
| Setup / Integrations | `fa-solid fa-gears` |
| Documentation | `fa-regular fa-file-lines` |
| Copy | `fa-regular fa-copy` |
| Delete | `fa-regular fa-trash-can` |
| Check / Confirmed | `fa-solid fa-circle-check` |
| Warning | `fa-solid fa-triangle-exclamation` |
| External link | `fa-solid fa-arrow-up-right-from-square` |

For status pills use solid weight (`fa-solid fa-circle-check`) so the shape reads at small sizes; for rest-state nav icons use regular (`fa-regular fa-house`) so they don't compete with active state.

---

## Layout patterns

### Full-page app shell

```
+----------------------------------------------------+
|  Sidebar (213px)  |  Topbar (56px)                |
|                   |-------------------------------|
|                   |                               |
|                   |     Main pane                 |
|                   |     (grid, flex, or scrollable) |
|                   |                               |
+----------------------------------------------------+
```

The Console SDK provides this shell — cartridges that launch as iframes inside the Console do NOT redraw it. If you're building a standalone cartridge (rare — Obs is the only current example), model the shell after `console/frontend/index.html` in the main repo.

### Standard content area

- Max width: `960px` for reading content; `1200px` for data-dense pages
- Padding: `32px` on desktop, `16px` on mobile
- Body background: `var(--pc-body-bg)`

### Print styles

For docs and handoff pages that operators print or PDF:

```css
@media print {
  body { background: white; font-size: 11pt; }
  .wrap { padding: 0; max-width: none; }
  section { break-inside: avoid; margin-bottom: 20px; }
  table { break-inside: avoid; }
  .no-print { display: none; }
}
```

---

## Checklist before shipping a cartridge frontend

- [ ] No hardcoded hex colors — every color is a `var(--pc-*)`
- [ ] No hardcoded font sizes — every size is `var(--pc-font-size-*)`
- [ ] Font Awesome kit + Inter font loaded from the CDNs above (do not vendor)
- [ ] `data-pcsdk` marker on both SDK `<link>`/`<script>` tags
- [ ] Every button matches one of the six variants in Component Patterns
- [ ] Status badges use the four documented status classes
- [ ] Icon weight matches the "when to use" rule (regular for UI, solid for status/diagrams)
- [ ] All user-facing text runs through `PCSDK.i18n.t()` — no bare strings
- [ ] Print styles present if the page is a handoff or reference doc

---

## Source of truth

If this file and the SDK CSS ever disagree, the CSS wins:

- `./forge-sdk/console/sdk/v1/css/tokens.css` — every token
- `./forge-sdk/console/sdk/v1/css/components.css` — every component class

This DESIGN.md gets updated to match when the SDK ships new tokens or components. If you need a token or component that does not exist yet, propose it in the main `ai-sandbox` repo; do not shim it locally.
