Files
pn-new-crm/15-DESIGN-TOKENS.md

538 lines
21 KiB
Markdown
Raw Normal View History

# 15 — Design Tokens & CRM Theme
> **Source of truth:** Port Nimara Brand Guidelines (30-page PDF) + CRM-specific extensions for UI states, data visualization, and accessibility.
---
## 1. Brand Color Palette (from Guidelines)
### 1.1 Primary Colors
| Pantone | HEX | RGB | Role in brand |
| ----------- | --------- | ------------- | ----------------------------------------------- |
| **PMS 553** | `#1e2844` | 30, 40, 68 | Dark navy — headings, sidebar, dark backgrounds |
| **PMS 660** | `#3a7bc8` | 58, 123, 200 | Brand blue — logo, primary accent |
| **Black** | `#000000` | 0, 0, 0 | Text, logo variant |
| **White** | `#ffffff` | 255, 255, 255 | Backgrounds, reversed logo |
### 1.2 Secondary Colors
| Pantone | HEX | RGB | Role in brand |
| ------------ | --------- | ------------- | ----------------------------------- |
| **PMS 7485** | `#dae3c1` | 218, 227, 193 | Sage — soft accent, backgrounds |
| **PMS 344** | `#add5b3` | 173, 213, 179 | Mint — fresh accent, success hint |
| **PMS 5493** | `#83aab1` | 131, 170, 177 | Teal — muted accent, secondary info |
| **PMS 2725** | `#685aa3` | 104, 90, 163 | Purple — premium accent, highlights |
### 1.3 Brand Tint Ladder (from guidelines — 80%, 60%, 40%, 20% of each primary)
| Base | 80% | 60% | 40% | 20% |
| --------- | --------- | --------- | --------- | --------- |
| `#1e2844` | `#474e66` | `#71768a` | `#9ea1af` | `#cdcfd6` |
| `#3a7bc8` | `#6196d3` | `#89b0de` | `#b1cbe9` | `#d8e5f4` |
| `#000000` | `#333333` | `#666666` | `#999999` | `#cccccc` |
---
## 2. CRM Semantic Color Tokens
These map brand colors to UI purpose. Every component references semantic tokens, never raw hex values.
### 2.1 Light Mode (default)
```
/* === BACKGROUNDS === */
--background: #ffffff /* Page background */
--background-secondary: #f8f9fa /* Subtle section backgrounds (cards, sidebars) */
--background-tertiary: #f1f3f5 /* Inset panels, table header rows */
--background-brand: #3a7bc8 /* Brand-colored backgrounds (header bar, CTA buttons) */
--background-brand-dark: #1e2844 /* Dark brand sections (login page, onboarding) */
--background-muted: #d8e5f4 /* PMS 660 at 20% — subtle brand tint */
/* === TEXT === */
--text-primary: #1e2844 /* Primary body text — dark brand base */
--text-secondary: #474e66 /* Secondary/muted text — 80% of PMS 553 */
--text-tertiary: #71768a /* Placeholder text, captions — 60% of PMS 553 */
--text-on-brand: #ffffff /* Text on brand-colored backgrounds */
--text-on-dark: #ffffff /* Text on dark backgrounds */
--text-link: #3a7bc8 /* Hyperlinks — brand blue */
/* === BORDERS === */
--border: #cdcfd6 /* Default border — 20% of PMS 553 */
--border-strong: #9ea1af /* Emphasized border — 40% of PMS 553 */
--border-focus: #3a7bc8 /* Focus ring — brand blue */
--border-brand: #3a7bc8 /* Brand accent borders */
/* === INTERACTIVE === */
--primary: #3a7bc8 /* Primary button, active nav, selected tab */
--primary-hover: #2f6ab5 /* Primary hover (10% darker) */
--primary-active: #255a9e /* Primary pressed */
--primary-foreground: #ffffff /* Text on primary buttons */
--secondary: #1e2844 /* Secondary button fill */
--secondary-hover: #171f35 /* Secondary hover */
--secondary-foreground: #ffffff /* Text on secondary buttons */
--accent: #83aab1 /* Accent highlights — PMS 5493 teal */
--accent-hover: #6f959c /* Accent hover */
--accent-foreground: #ffffff /* Text on accent */
--ghost-hover: #f1f3f5 /* Ghost/outline button hover */
--muted: #f1f3f5 /* Muted/disabled backgrounds */
--muted-foreground: #71768a /* Muted text */
/* === STATUS === */
--success: #2d8a4e /* Confirmed, active, paid, signed */
--success-bg: #e8f5e9 /* Success background tint */
--success-border: #a5d6a7 /* Success border */
--warning: #e6a817 /* Expiring soon, pending, needs attention */
--warning-bg: #fff8e1 /* Warning background tint */
--warning-border: #ffe082 /* Warning border */
--error: #d32f2f /* Overdue, failed, rejected, expired */
--error-bg: #ffebee /* Error background tint */
--error-border: #ef9a9a /* Error border */
--info: #3a7bc8 /* Informational — uses brand blue */
--info-bg: #d8e5f4 /* Info background — brand blue 20% */
--info-border: #89b0de /* Info border — brand blue 60% */
/* === SIDEBAR / NAVIGATION === */
--sidebar-bg: #1e2844 /* Dark brand sidebar */
--sidebar-text: #cdcfd6 /* Sidebar text — 20% of PMS 553 (light) */
--sidebar-text-active: #ffffff /* Active nav item text */
--sidebar-icon: #83aab1 /* Nav icons — teal accent */
--sidebar-icon-active: #3a7bc8 /* Active nav icon — brand blue */
--sidebar-hover: #171f35 /* Sidebar hover background */
--sidebar-active: #3a7bc810 /* Brand blue at 6% opacity — subtle highlight */
--sidebar-divider: #474e66 /* Sidebar section dividers */
/* === DATA VISUALIZATION (6-color sequence) === */
--chart-1: #3a7bc8 /* Brand blue */
--chart-2: #1e2844 /* Dark brand */
--chart-3: #83aab1 /* Teal */
--chart-4: #685aa3 /* Purple */
--chart-5: #add5b3 /* Mint */
--chart-6: #dae3c1 /* Sage */
```
### 2.2 Dark Mode
The CRM is primarily a daytime work tool, but dark mode is supported for preference and low-light marina office use.
```
/* === BACKGROUNDS === */
--background: #131a2c /* Darkened navy base */
--background-secondary: #192239 /* Card/sidebar backgrounds */
--background-tertiary: #1e2844 /* PMS 553 as surface */
--background-brand: #3a7bc8 /* Brand blue stays consistent */
--background-brand-dark: #101625 /* Even darker navy */
/* === TEXT === */
--text-primary: #e8ece9 /* Light text on dark backgrounds */
--text-secondary: #9ea1af /* Secondary text */
--text-tertiary: #71768a /* Muted text */
--text-on-brand: #ffffff
--text-link: #6196d3 /* Lightened brand blue for readability */
/* === BORDERS === */
--border: #2d3c66 /* Subtle dark border */
--border-strong: #474e66 /* Emphasized */
--border-focus: #6196d3 /* Focus ring */
/* === INTERACTIVE === */
--primary: #4a8ad4 /* Slightly lightened for dark bg contrast */
--primary-hover: #6196d3
--primary-active: #3a7bc8
/* === STATUS (brightened for dark mode readability) === */
--success: #4caf50
--success-bg: #1b3d1e
--warning: #ffca28
--warning-bg: #3d3417
--error: #ef5350
--error-bg: #3d1a1a
--info: #6196d3
--info-bg: #1a2d3d
```
---
## 3. Typography
### 3.1 Brand Fonts (from guidelines)
| Role | Font | License | Notes |
| ---------------------- | --------------- | -------------------- | ---------------------------------------------------------------- |
| **Primary** | Bill Corporate | Commercial (MyFonts) | Outward-facing: marketing, website, PDFs, printed correspondence |
| **Secondary** | Adobe Garamond | Commercial (Adobe) | Captions only, outward-facing |
| **Default (in-house)** | Arial / Georgia | System fonts | Word documents, emails, internal communications |
### 3.2 CRM Font Strategy
The CRM is an **internal tool** — not outward-facing marketing collateral. Per the brand guidelines, Arial and Georgia are the approved default typefaces for in-house communications.
For a modern web application, we use **Inter** as the primary UI font. Inter is the de facto standard for web applications (used by Vercel, GitHub, Linear, etc.), is visually close to Arial (sans-serif, clean, neutral), and has excellent screen readability at all sizes. It's also the default font recommended by shadcn/ui.
| CRM Role | Font | Fallback | Notes |
| ------------------------------------------- | --------------------------------- | --------------------------------------------- | ----------------------------------------------- |
| **UI (body, labels, buttons)** | Inter | `system-ui, -apple-system, Arial, sans-serif` | Google Fonts or self-hosted |
| **Headings (page titles, section headers)** | Inter | Same fallback chain | Semi-bold (600) or Bold (700) weight |
| **Data (tables, numbers, code)** | `Inter Tight` or `JetBrains Mono` | `ui-monospace, monospace` | For tabular data alignment, code snippets |
| **Generated PDFs** | Arial | Helvetica, sans-serif | Brand-compliant for generated letters, invoices |
| **Generated formal documents** | Georgia | `Times New Roman, serif` | Brand-compliant for formal correspondence |
### 3.3 Type Scale (Tailwind classes)
```
/* Using Tailwind's default scale with Inter */
text-xs: 0.75rem / 1rem /* 12px — fine print, timestamps */
text-sm: 0.875rem / 1.25rem /* 14px — table cells, secondary info, form labels */
text-base: 1rem / 1.5rem /* 16px — body text, descriptions */
text-lg: 1.125rem / 1.75rem /* 18px — card titles, sub-headings */
text-xl: 1.25rem / 1.75rem /* 20px — section headings */
text-2xl: 1.5rem / 2rem /* 24px — page titles */
text-3xl: 1.875rem / 2.25rem /* 30px — dashboard hero numbers */
```
### 3.4 Font Weights
```
font-normal: 400 /* Body text, descriptions */
font-medium: 500 /* Labels, table headers, nav items */
font-semibold: 600 /* Section headings, card titles, important values */
font-bold: 700 /* Page titles, dashboard hero numbers */
```
---
## 4. Spacing & Layout
### 4.1 Base Grid
The CRM uses Tailwind's default 4px base unit system. Key spacing tokens:
```
space-1: 0.25rem (4px) /* Tight padding (badge internal) */
space-2: 0.5rem (8px) /* Compact spacing (between inline elements) */
space-3: 0.75rem (12px) /* Form field internal padding */
space-4: 1rem (16px) /* Standard padding (cards, sections) */
space-5: 1.25rem (20px) /* Comfortable gaps */
space-6: 1.5rem (24px) /* Section separators */
space-8: 2rem (32px) /* Major section gaps */
space-10: 2.5rem (40px) /* Page-level margins */
space-12: 3rem (48px) /* Dashboard widget gaps */
```
### 4.2 Container Widths
```
max-w-screen-sm: 640px /* Login page, modal content */
max-w-screen-md: 768px /* Narrow forms, PWA scanner */
max-w-screen-lg: 1024px /* Standard content area */
max-w-screen-xl: 1280px /* Wide tables, dashboard */
max-w-screen-2xl: 1536px /* Full-width admin views */
```
### 4.3 Sidebar
```
sidebar-width-collapsed: 64px /* Icon-only sidebar */
sidebar-width-expanded: 256px /* Full sidebar with labels */
sidebar-transition: 200ms ease-in-out
```
---
## 5. Border Radius
Rounded corners give the maritime/luxury feel without being overly playful.
```
rounded-sm: 0.25rem (4px) /* Subtle rounding — tags, badges */
rounded: 0.375rem (6px) /* Default — buttons, inputs, cards */
rounded-md: 0.5rem (8px) /* Slightly more — dialogs, dropdowns */
rounded-lg: 0.75rem (12px) /* Prominent — dashboard cards, modals */
rounded-xl: 1rem (16px) /* Feature cards, hero elements */
rounded-full: 9999px /* Avatars, status dots, icon buttons */
```
---
## 6. Shadows & Elevation
Three shadow levels, using the dark brand color for a cohesive feel:
```
shadow-sm: 0 1px 2px rgba(30, 40, 68, 0.06) /* Subtle lift — cards at rest */
shadow: 0 1px 3px rgba(30, 40, 68, 0.10), 0 1px 2px rgba(30, 40, 68, 0.06) /* Default — raised cards, buttons */
shadow-md: 0 4px 6px rgba(30, 40, 68, 0.10), 0 2px 4px rgba(30, 40, 68, 0.06) /* Hover state, dropdowns */
shadow-lg: 0 10px 15px rgba(30, 40, 68, 0.10), 0 4px 6px rgba(30, 40, 68, 0.05) /* Modals, dialogs, sheets */
shadow-xl: 0 20px 25px rgba(30, 40, 68, 0.10), 0 8px 10px rgba(30, 40, 68, 0.04) /* Toast notifications */
```
---
## 7. Wave Pattern (CSS)
The brand's wave pattern (from guidelines p18-19) can be subtly referenced in the UI:
```css
/* Subtle wave divider — used on login page, onboarding, section breaks */
.wave-divider {
background-image: url('data:image/svg+xml,...'); /* SVG wave in brand blue */
background-repeat: repeat-x;
height: 24px;
opacity: 0.15;
}
/* Wave watermark — login page background */
.wave-watermark {
background-image: repeating-linear-gradient(
135deg,
transparent,
transparent 10px,
rgba(58, 123, 200, 0.03) 10px,
rgba(58, 123, 200, 0.03) 20px
);
}
```
---
## 8. Component-Specific Tokens
### 8.1 Berth Status Colors
These are critical CRM semantics — each berth status gets a distinct color from the brand palette:
| Status | Color | HEX | Token |
| ----------- | -------------------- | --------- | --------------------- |
| Available | Mint (PMS 344) | `#add5b3` | `--berth-available` |
| Occupied | Brand blue (PMS 660) | `#3a7bc8` | `--berth-occupied` |
| Reserved | Purple (PMS 2725) | `#685aa3` | `--berth-reserved` |
| Maintenance | Warning amber | `#e6a817` | `--berth-maintenance` |
| Unavailable | Muted grey | `#999999` | `--berth-unavailable` |
### 8.2 EOI / Interest Stage Colors
| Stage | Color | HEX |
| ----------- | -------------------- | --------- |
| Lead | Sage (PMS 7485) | `#dae3c1` |
| Contacted | Teal (PMS 5493) | `#83aab1` |
| Qualified | Brand blue (PMS 660) | `#3a7bc8` |
| Negotiating | Purple (PMS 2725) | `#685aa3` |
| Won | Success green | `#2d8a4e` |
| Lost | Error red | `#d32f2f` |
| On Hold | Warning amber | `#e6a817` |
### 8.3 Priority / Urgency Badges
| Level | Color | Text color |
| -------- | -------------------------- | ---------------- |
| Low | `#dae3c1` (sage) | `#1e2844` (dark) |
| Medium | `#d8e5f4` (brand blue 20%) | `#3a7bc8` |
| High | `#fff8e1` (warning bg) | `#e6a817` |
| Critical | `#ffebee` (error bg) | `#d32f2f` |
---
## 9. Tailwind Config (actual `tailwind.config.ts`)
```typescript
import type { Config } from 'tailwindcss';
export default {
darkMode: 'class',
content: ['./src/**/*.{ts,tsx}'],
theme: {
extend: {
colors: {
// Brand primaries
brand: {
DEFAULT: '#3a7bc8', // PMS 660 — primary blue
dark: '#1e2844', // PMS 553 — dark base
50: '#d8e5f4', // 20%
100: '#b1cbe9', // 40%
200: '#89b0de', // 60%
300: '#6196d3', // 80%
400: '#3a7bc8', // 100%
500: '#2f6ab5', // hover
600: '#255a9e', // active
700: '#1c4a87', // dark
},
navy: {
DEFAULT: '#1e2844', // PMS 553
50: '#cdcfd6', // 20%
100: '#9ea1af', // 40%
200: '#71768a', // 60%
300: '#474e66', // 80%
400: '#1e2844', // 100%
500: '#171f35', // darker (hover)
600: '#101625', // darkest
},
// Secondary palette
sage: {
DEFAULT: '#dae3c1', // PMS 7485
light: '#edf1e2',
dark: '#b8c49e',
},
mint: {
DEFAULT: '#add5b3', // PMS 344
light: '#d6ead9',
dark: '#7dba85',
},
teal: {
DEFAULT: '#83aab1', // PMS 5493
light: '#b1cdd2',
dark: '#5a8a92',
},
purple: {
DEFAULT: '#685aa3', // PMS 2725
light: '#a49ac6',
dark: '#4d4280',
},
// Status colors
success: {
DEFAULT: '#2d8a4e',
bg: '#e8f5e9',
border: '#a5d6a7',
},
warning: {
DEFAULT: '#e6a817',
bg: '#fff8e1',
border: '#ffe082',
},
error: {
DEFAULT: '#d32f2f',
bg: '#ffebee',
border: '#ef9a9a',
},
// Sidebar
sidebar: {
DEFAULT: '#1e2844',
text: '#cdcfd6',
hover: '#171f35',
active: '#3a7bc8',
divider: '#474e66',
},
},
fontFamily: {
sans: ['Inter', 'system-ui', '-apple-system', 'Arial', 'sans-serif'],
mono: ['JetBrains Mono', 'ui-monospace', 'monospace'],
// For generated formal documents only
serif: ['Georgia', 'Times New Roman', 'serif'],
},
boxShadow: {
sm: '0 1px 2px rgba(30, 40, 68, 0.06)',
DEFAULT: '0 1px 3px rgba(30, 40, 68, 0.10), 0 1px 2px rgba(30, 40, 68, 0.06)',
md: '0 4px 6px rgba(30, 40, 68, 0.10), 0 2px 4px rgba(30, 40, 68, 0.06)',
lg: '0 10px 15px rgba(30, 40, 68, 0.10), 0 4px 6px rgba(30, 40, 68, 0.05)',
xl: '0 20px 25px rgba(30, 40, 68, 0.10), 0 8px 10px rgba(30, 40, 68, 0.04)',
},
borderRadius: {
sm: '0.25rem',
DEFAULT: '0.375rem',
md: '0.5rem',
lg: '0.75rem',
xl: '1rem',
},
width: {
sidebar: '256px',
'sidebar-collapsed': '64px',
},
},
},
plugins: [require('tailwindcss-animate')],
} satisfies Config;
```
---
## 10. CSS Variables (for shadcn/ui compatibility)
shadcn/ui uses CSS custom properties in HSL format. Here are the Port Nimara brand values converted:
```css
@layer base {
:root {
/* shadcn/ui variable format: H S% L% */
--background: 0 0% 100%; /* #ffffff */
--foreground: 224 39% 19%; /* #1e2844 */
--card: 0 0% 100%;
--card-foreground: 224 39% 19%;
--popover: 0 0% 100%;
--popover-foreground: 224 39% 19%;
--primary: 213 55% 56%; /* #3a7bc8 */
--primary-foreground: 0 0% 100%;
--secondary: 224 39% 19%; /* #1e2844 */
--secondary-foreground: 0 0% 100%;
--muted: 210 11% 96%; /* #f1f3f5 */
--muted-foreground: 228 10% 49%; /* #71768a */
--accent: 190 18% 60%; /* #83aab1 */
--accent-foreground: 0 0% 100%;
--destructive: 0 65% 51%; /* #d32f2f */
--destructive-foreground: 0 0% 100%;
--border: 227 10% 82%; /* #cdcfd6 */
--input: 227 10% 82%;
--ring: 213 55% 56%; /* #3a7bc8 focus ring */
--radius: 0.375rem;
/* Sidebar (using dark navy) */
--sidebar-background: 224 39% 19%;
--sidebar-foreground: 227 10% 82%;
--sidebar-primary: 213 55% 56%;
--sidebar-primary-foreground: 0 0% 100%;
--sidebar-accent: 224 39% 15%;
--sidebar-accent-foreground: 227 10% 82%;
--sidebar-border: 226 18% 34%;
--sidebar-ring: 213 55% 56%;
/* Chart colors for Recharts */
--chart-1: 213 55% 56%; /* Brand blue */
--chart-2: 224 39% 19%; /* Dark navy */
--chart-3: 190 18% 60%; /* Teal */
--chart-4: 254 29% 50%; /* Purple */
--chart-5: 130 30% 76%; /* Mint */
--chart-6: 75 30% 82%; /* Sage */
}
.dark {
--background: 224 40% 12%;
--foreground: 227 10% 91%;
--card: 224 39% 19%;
--card-foreground: 227 10% 91%;
--popover: 224 39% 19%;
--popover-foreground: 227 10% 91%;
--primary: 213 52% 62%;
--primary-foreground: 0 0% 100%;
--secondary: 224 39% 22%;
--secondary-foreground: 227 10% 82%;
--muted: 224 39% 18%;
--muted-foreground: 228 10% 49%;
--accent: 190 18% 50%;
--accent-foreground: 0 0% 100%;
--destructive: 0 72% 63%;
--destructive-foreground: 0 0% 100%;
--border: 224 35% 28%;
--input: 224 35% 28%;
--ring: 213 52% 62%;
}
}
```
---
## 11. Accessibility Notes
- **WCAG AA contrast ratios** verified for all text/background combinations:
- `#1e2844` on `#ffffff`**14.6:1** (passes AAA)
- `#ffffff` on `#3a7bc8`**4.3:1** (passes AA for large text; use semibold 16px+ or 14px bold)
- `#ffffff` on `#1e2844`**14.6:1** (passes AAA)
- `#474e66` on `#ffffff`**8.2:1** (passes AAA)
- `#71768a` on `#ffffff`**4.5:1** (passes AA)
- **Focus rings:** 2px solid `#3a7bc8` with 2px offset — clearly visible on both light and dark backgrounds
- **Status colors:** Never rely on color alone — always pair with icons (checkmark, warning triangle, X circle) and text labels
- **Color-blind safe:** The berth status palette uses distinct hue families (green, blue, purple, yellow, grey) that remain distinguishable under protanopia, deuteranopia, and tritanopia