# Calispec Design System

> **Calispec** is a next-generation SaaS platform for managing the entire lifecycle of gauges, fixtures, calibration events,
> inspection processes and metrology studies in one intelligent interface.
>
> Version 2 documents the system **as it is built and shipped**: every value below comes from the live component library,
> not from a mock-up. Version 1 (`design_system.md`) remains the original palette and scale reference.

**Contents**

1. Principles
2. Foundations — colour, typography, spacing, radius, elevation, motion, iconography
3. Components — buttons, inputs, selection controls, tabs and toggles, badges and status, feedback, overlays, cards
4. Navigation — app shell, header, breadcrumbs, sidebar
5. Data — tables, pagination, charts
6. Patterns — dashboard and module hubs, list pages, detail pages, forms, authentication
7. Accessibility and content rules
8. Token reference and known gaps

---

## 1. Principles

| Principle | What it means in the interface |
|---|---|
| **Calm, single accent** | Calispec Blue is the only interactive accent. Module colours, rainbow badges and decorative gradients are not used for navigation or chrome. Colour is reserved for state (success, warning, error) and data. |
| **Dense but readable** | Enterprise screens carry a lot of data. Use 14px body text, 36–40px controls and 16–24px padding — compact, never cramped. |
| **Depth through light, not weight** | Surfaces separate with a 1px border and a hairline shadow. Buttons and pills get a soft top highlight; nothing glows or uses heavy drop shadows. |
| **One component, one look** | A button, input, table or pagination bar is built once and reused. Pages choose a variant and size; they never restyle a primitive. |
| **Motion explains, never decorates** | Transitions are short (140–300ms), respond to the pointer, and are removed for people who ask for reduced motion. |
| **Never colour alone** | Every colour-coded value (status, criticality, chart series) also carries text, an icon or a pattern. |

---

## 2. Foundations

### 2.1 Colour

#### Brand

| Token | Value | Use |
|---|---|---|
| `color.brand.blue` | `#0274BB` | Primary actions, links, focus rings, active icons, current page |
| `color.brand.navy` | `#003B8C` | Active text on tinted fills, table header text, emphasis |
| `color.brand.orange` | `#EF7626` | Accent — alerts, reminders, chart series (never for primary actions) |
| `color.brand.blue-light` | `#E6F2FF` | Icon tiles, detail-table header fill |
| `color.brand.blue-50` | `#E8F3FC` | **Selected / active fill** — sidebar active row, current page, list table header |

#### Blue tints and button states

| Token | Value | Use |
|---|---|---|
| `color.blue.100` | `#CFE3F5` | List table header border and column separators |
| `color.blue.150` | `#C9DEF5` | Detail-table header border |
| `color.blue.200` | `#BCDCF3` | Hover border on cards |
| `color.blue.bg-100` | `#DBEAFE` | Table cell column separators |
| `color.blue.link` | `#1D4ED8` | Record links inside tables |
| `color.primary.top` / `bottom` | `#3A93CA` / `#0274BB` | Primary button gradient |
| `color.primary.hover-top` / `-bottom` | `#53A1D1` / `#2185C3` | Primary button hover gradient |
| `color.primary.ring` | `#0269B2` | Primary button inset ring |
| `color.primary.pressed` | `#02508A` | Primary button pressed |

#### Semantic

| Token | Value | Use |
|---|---|---|
| `color.success` | `#16A34A` | Healthy, completed, active, approved |
| `color.warning` | `#FFCC00` | Pending, due soon, needs attention |
| `color.error` | `#DC2626` | Failed, overdue, rejected, destructive actions, required marker |
| `color.analytics` | `#F7981E` | Insights, trends, measurement-system analysis |
| `color.info` | `#0284C7` | Neutral information |

#### Neutrals

| Token | Value | Use |
|---|---|---|
| `color.bg.page` | `#FAFAFA` | Application background |
| `color.bg.surface` | `#FFFFFF` | Cards, tables, inputs, popovers, sidebar |
| `color.bg.subtle` | `#F5F7FA` | Hover on secondary controls, secondary surfaces |
| `color.border.default` | `#E5E7EB` | Card, table and divider borders (`#E4E4E4` on module cards) |
| `color.border.control` | `#D9DCE1` | Secondary button border (hover `#C7CBD1`) |
| `color.border.input` | `#E2E8F0` | Input and select resting border |
| `color.text.strong` | `#111827` | Headings, values, key information |
| `color.text.body` | `#374151` | Secondary headings, detail-table header text |
| `color.text.muted` | `#6B7280` | Descriptions, labels, captions |
| `color.text.subtle` | `#9CA3AF` | Placeholders, inactive pagination, disabled text |
| `color.disabled.bg` | `#E5E7EB` | Disabled control fill |

Dark mode is not supported; the interface is a light theme only.

#### Status colours

The same word always has the same colour across lists, badges and charts.

| Status family | Mapping |
|---|---|
| General state | Active / In service / Available / Pass / Approved / Completed → success green · Calibration / Maintenance / Pending / Under review → warning amber · Retired / Scrapped / Obsolete / Rejected / Fail → error red (or neutral grey for end-of-life) · everything else → neutral grey |
| Fixture lifecycle (charts) | Active `#10B981` · Stock `#3B82F6` · Repair `#EAB308` · Scrap `#6B7280` · Missing `#DC2626` |
| Inspection | Pass `#10B981` · Fail `#DC2626`; approval Pending `#FFCC00` · Approved `#16A34A` · Rejected `#DC2626` |
| Repair | Diagnosed `#7C3AED` · Pending approval `#FFCC00` · Approved `#EF7626` · Completed `#16A34A` · Rejected `#DC2626` |
| Calibration due | Overdue `#DC2626` · 7 days `#F97316` · 30 days `#F59E0B` · 60 days `#0EA5E9` · 90 days `#0274BB` |
| Scrap request | Pending approval `#FFCC00` · Approved `#16A34A` · Rejected `#DC2626` · Acknowledged (terminal) `#6B7280` |

#### Criticality

A value with a coloured arrowhead beside the text. The words are matched by meaning because each organisation configures its
own scale.

| Meaning (examples) | Arrow | Colour |
|---|---|---|
| High, Highest, Severe, Safety critical, Critical | Double up-arrow | `#DC2626` |
| Medium, Major, Moderate, Quality critical | Up-arrow | `#F97316` |
| Production critical | Up-arrow | `#F59E0B` |
| Low, Minor, Non-critical | Down-arrow | `#059669` |
| Anything else | None — plain text | — |

#### Chart colours

| Palette | Values | Use |
|---|---|---|
| Brand series | `#0274BB` `#16A34A` `#EF7626` `#7C3AED` `#DC2626` `#F59E0B` `#0EA5E9` `#14B8A6` | Cards and their matching chart slices (same hue for the same bucket) |
| Categorical (non-status) | `#0EA5E9` `#F97316` `#10B981` `#38BDF8` `#FB923C` `#34D399` `#0284C7` `#EA580C` `#059669` `#7DD3FC` `#FDBA74` `#6EE7B7` | Category, location, reason, month and similar breakdowns |

### 2.2 Typography

**Typeface:** Inter (weights 400, 500, 600, 700), system sans-serif fallback. Headings and controls use slightly negative
tracking; small uppercase labels use positive tracking.

| Token | Size / weight / tracking | Use |
|---|---|---|
| `type.hub-title` | `30px / 600 / -0.02em` | Hub and dashboard page titles (greeting, module name) |
| `type.page-title` | `24px / 600 / -0.02em` | Page titles, auth headings |
| `type.record-title` | `28px (clamp 20–28) / 600 / -0.02em` | Record header on detail pages (code in brand blue, name after a thin divider) |
| `type.card-title` | `20px / 600 / -0.03em` | Module card and stat card titles |
| `type.section-title` | `18px / 600 / -0.01em` | Detail-section and table-card headers |
| `type.kpi` | `42px / 600 / -0.03em` | Large figures on stat cards |
| `type.body` | `16px / 400 / -0.01em` | Card descriptions, intro text |
| `type.body-sm` | `14px / 400 / 0` | Page descriptions, table cells, helper text, form text |
| `type.label` | `14px / 500 / 0` | Form labels (form screens use 16px) |
| `type.field-label` | `13px / 500 / -0.01em`, `#6B7280` | Read-only field names on detail views |
| `type.field-value` | `17px / 500`, `#111827` | Read-only field values on detail views |
| `type.table-header` | `13px / 600 / 0.04em`, uppercase | Table column headers |
| `type.button` | `14px / 400 / -0.02em` | Every button size (compact `sm`: 12px) |
| `type.nav` | `14px / 500 / -0.01em` | Sidebar rows and sub-links |
| `type.section-label` | `14px / 700 / 0.025em`, uppercase | Forms / Logs / Approvals group labels |
| `type.badge` | `12px / 600` (status pill `11px / 600 / 0.04em` uppercase) | Badges and status pills |
| `type.tooltip` | `13px / 400` | Tooltips |
| `type.caption` | `12px / 400`, `#6B7280` | Helper and secondary text |

Rules: no weight above 600 in body text or controls · never underline except links on hover and the pagination *Go* action ·
long text truncates with a tooltip rather than wrapping inside a row.

### 2.3 Spacing and layout

An **8px base grid** with a 4px half-step.

| Token | Value | Typical use |
|---|---|---|
| `space.1` | 4px | Icon-to-label gap inside dense chips, row gap in the sidebar |
| `space.2` | 8px | Button groups, control gaps, nav padding |
| `space.3` | 12px | Row inset, compact padding |
| `space.4` | 16px | Card padding (compact), gutters on mobile, table cell padding |
| `space.5` | 20px | Gap under section labels |
| `space.6` | 24px | Card padding, desktop page gutter, table cell side padding |
| `space.8` | 32px | Card padding (module cards), gap between page sections |
| `space.12` | 48px | Large separations, tall empty states |

**Page frame**

| Part | Value |
|---|---|
| Sidebar | `272px` expanded · `56px` collapsed |
| Header | `64px` tall, white, 1px bottom border, sticky |
| Breadcrumb strip | Below the header, white, 1px bottom border, `10px` vertical padding |
| Main area | Fluid width (no max-width), `16px` side padding on mobile, `24px` from 640px up, `24px` vertical |
| Page rhythm | `32px` between page sections; `24px` between a title block and the content |
| Card grids | 1 column on mobile, 2 from 640px, 3 from 1024px; `16px` gap (module hubs `32px`) |
| Form field grid | 2 columns from 640px, 1 on mobile; wide fields (documents, text areas) span both |

### 2.4 Radius and borders

| Token | Value | Use |
|---|---|---|
| `radius.control` | `5px` | Buttons, checkboxes, icon tiles |
| `radius.row` | `8px` | Sidebar rows, page numbers, tab triggers, the pill inside toggles |
| `radius.field` | `10px` | Inputs, selects, tab lists, module cards, panels, table containers, alert boxes |
| `radius.surface` | `12px` | Dialogs, default card primitive |
| `radius.hero` | `16px` | Stat cards, marketing panels |
| `radius.pill` | `999px` | Count pills, avatars, badges |

Borders are `1px`; stat cards use `1.5px`. Default border colour is `#E5E7EB`. Never combine a border and a heavy shadow.

### 2.5 Elevation

| Token | Value | Use |
|---|---|---|
| `shadow.hairline` | `0 1px 0 rgba(17,24,39,.08), 0 1px 2px rgba(17,24,39,.05)` | Secondary buttons — a line under the bottom edge |
| `shadow.sunken` | `inset 0 1px 2px rgba(15,23,42,.08)` | Toggle trays, checkboxes, unchecked switches |
| `shadow.card-hover` | `0 0 0 3px rgba(2,116,187,.07), 0 10px 24px -12px rgba(15,23,42,.14), 0 2px 6px rgba(15,23,42,.04)` | Interactive card on hover (with a `-4px` lift) |
| `shadow.stat-hover` | `0 10px 24px -12px rgba(15,23,42,.14), 0 2px 6px rgba(15,23,42,.04)` | Stat card on hover |
| `shadow.popover` | Medium soft shadow (`shadow-md`); profile menu `shadow-lg` | Popovers, selects, dropdowns |
| `shadow.dialog` | Large shadow over an 80% black overlay | Modal dialogs |
| `shadow.primary-inset` | `inset 0 0 0 1px #0269B2, inset 0 1.5px 0 rgba(255,255,255,.28)` | Primary buttons and the toggle pill — **no outer glow** |

### 2.6 Motion

| Token | Duration · easing | Use |
|---|---|---|
| `motion.control` | `140ms ease-out` | Buttons, hover and pressed states |
| `motion.field` | `150ms` | Input and select border and ring |
| `motion.sidebar` | `200ms` | Sidebar width |
| `motion.card` | `300ms ease-out` | Card lift, icon lift and scale, dot overlay fade |
| `motion.stat` | `220ms cubic-bezier(.4,0,.2,1)` | Stat card lift and tint |
| `motion.spring` | `380ms cubic-bezier(.34,1.45,.64,1)` | Toggle pill, small icon pops |
| `motion.tooltip` | `150ms` fade and 4px slide | Tooltips |

Interaction effects used by cards: lift `-4px`; icon lifts `-6px` and scales to `1.1`; a dotted overlay (`9px` grid,
`#0274BB` dots at 40%) fades in and is **masked to a ~130px spotlight that follows the pointer**. Press: scale `0.96`.
Every animation must stop under `prefers-reduced-motion`.

### 2.7 Iconography and artwork

| Item | Specification |
|---|---|
| Icon set | Lucide, outline style |
| Stroke | `1.5` for navigation and cards; `1.8` for stat-card tiles; `2.75` for criticality arrows |
| Sizes | `14px` chevrons · `16px` buttons and inputs · `18px` navigation and section tiles · `22px` stat tiles · `40px` hub-card badges |
| Colour | Inherit text colour; inactive nav icons `#475569`; active `#0274BB`; chevrons `#94A3B8` |
| Icon tile | 32px (`#E6F2FF`, 5px radius, blue icon) for section headers; 46px bordered tile for stat cards; 56px gradient tile (3px blue gradient frame `#4DA3E8 → #0A5CAB`, white-to-`#D3E6FA` face, 22px icon) for the Management hub |
| 3D artwork | Hub cards use transparent **AVIF** illustrations, 768 × 768px, rendered in a 98px box inside an 80px slot. The artwork fills about **66%** of the frame so every card icon looks the same size (some module icons use a 92% fill when a larger mark is wanted). Backgrounds must be removed — never ship an opaque white or black square |
| Brand mark | Full wordmark logo at 48px high in the sidebar; the gear-only mark (the wordmark's "C" masked out) is used for the collapsed sidebar and the favicon (`favicon.ico`, `favicon.png` 256px, `apple-touch-icon.png` 180px) |

---

## 3. Components

### 3.1 Buttons

One shared component with three emphasis levels. Pages pick a `variant` and `size`; they never override radius, weight or size.

**Base:** Inter `14px / 400 / -0.02em` · radius `5px` · `8px` icon gap · single line · `140ms ease-out` · focus ring `2px #0274BB` with
a `2px` white offset (keyboard focus only).

| Size | Height | Padding | Note |
|---|---|---|---|
| `default` | 40px | 12px | Standard |
| `sm` | 32px | 12px | 12px text, inside tables and toolbars |
| `lg` | 44px | 32px | Authentication and prominent calls to action |
| `icon` | 40 × 40px | — | Icon-only (36px inside pagination) |

| Variant | Role | Default | Hover | Pressed | Disabled |
|---|---|---|---|---|---|
| **Primary** | The one main action | Gradient `#3A93CA → #0274BB`, white text, inset ring `#0269B2`, top highlight `rgba(255,255,255,.28)` | Gradient `#53A1D1 → #2185C3`, ring `#0274BB`, highlight `.35` | Solid `#02508A` | Fill `#E5E7EB`, text `#9CA3AF`, no shadow |
| **Secondary** (outline) | Supporting actions | White, 1px `#D9DCE1`, text `#111827`, `shadow.hairline` | Fill `#F9FAFB`, border `#C7CBD1` | Fill `#F1F3F5`, `shadow.sunken` | Fill `#E5E7EB`, no border, text `#9CA3AF` |
| **Tertiary** (ghost) | Low emphasis, icon-only, pagination | No border, text `#0F172A` | Fill `#F4F6F8` | Fill `#E5E7EB` | Transparent, text `#9CA3AF` |
| **Destructive** | Delete, reject | `#EF4444` (the destructive token), white text, small shadow | `#EF4444` at 90% | — | 50% opacity |
| **Link** | Inline text action | Brand blue | Underline | — | 50% opacity |

Rules: one Primary per view · the primary action is right-most with `8px` between buttons · icon-only buttons need an
`aria-label` and a tooltip · success and warning button variants are reserved and not yet part of the component.

### 3.2 Text inputs, text areas and selects

| Part | Specification |
|---|---|
| Height | `36px` (text areas `60px` minimum) |
| Shape | Radius `10px`, 1px border `#E2E8F0`, `shadow-sm`, transparent fill over white surfaces |
| Text | `14px`; placeholder `#9CA3AF` |
| Hover | Border `#0274BB` |
| Focus | Border `#0274BB` + `2px` ring `rgba(2,116,187,.20)`; no default outline |
| Error | Border and focus ring switch to `#DC2626` with a message beneath |
| Disabled | 50% opacity, `not-allowed` cursor |
| Read only | Greyed background, **Locked** note beside the label |
| Select trigger | Same box as an input, chevron `16px` at 50%; placeholder in `#9CA3AF` |
| Select menu | White popover, 1px border, `shadow-md`, `4px` padding, items `14px`, check mark on the selected item |

Add-on pattern: a **"+" quick-add** icon button (36px, Secondary) sits beside a select to create a missing option in a small
popover; the popover can also delete options. Amount fields pair a `176px` currency select with a flexible number input.

### 3.3 Labels and required fields

`14px / 500`; form screens use `16px`. A trailing ` *` is drawn in `#DC2626`. Read-only fields add `(Locked)` in `12px` muted text.
Labels sit `4px` above their control.

### 3.4 Checkbox and switch

| Control | Specification |
|---|---|
| Checkbox | `18px`, radius `5px`, border `#CBD5E1`, inset shadow; hover border `#0274BB`; checked: border `#0274BB`, gradient `#2B8BCB → #0274BB`, white check at stroke 3 |
| Switch | `36 × 20px` track, radius `7px`; on: gradient `#2B8BCB → #0274BB`; off: input colour with `shadow.sunken`; thumb `16px`, radius `5px`, white-to-`#F1F5F9`, slides `16px` |

### 3.5 Tabs and toggles

| Component | Specification |
|---|---|
| **Segmented tabs** (`TabsList`) | 40px tray, radius `10px`, fill `#F1F5F9`, 1px `#E2E8F0`, `shadow.sunken`, `4px` padding; trigger radius `8px`, `14px / 500`; the active trigger is a white-to-`#F8FAFC` chip with a soft shadow and 1px ring `#E2E8F0` |
| **Toggle** (two-way view switch) | Same tray (36px options, `2px` padding) with a **sliding Primary-coloured pill** (`#3A93CA → #0274BB`, inset ring, 8px radius, no outer glow) that moves with `motion.spring`; active label white, inactive `#475569`; icons scale up on hover |
| **Section tabs** (underline) | 52px tall, full width, background = page, 1px bottom border `#E5E7EB`; label `15px / 500`, `#6B7280`; active label `#0274BB` / 600 with a `2px` blue underline; sticky under the header while the content scrolls; scrolls horizontally on small screens |
| **Stepper** | Numbered circles `38px` joined by a `2px` line. Completed: green `#16A34A` fill; current: navy `#003B8C` fill; upcoming: white with a `#E5E7EB` border and navy number. Connector colour follows the step before it. Labels `15px`, centred below (hidden under 1024px) |

### 3.6 Badges and status

| Component | Specification |
|---|---|
| Badge | Pill, 1px border, `12px / 600`; sizes `sm` (`px-8`), default (`px-10`), `lg` (`px-12`, 14px); variants default / secondary / destructive / success / warning / outline |
| Status pill | `22px` tall, radius `10px`, `11px / 600 / 0.04em` uppercase, white text; **Active = `#16A34A`, any other status = `#9CA3AF`** |
| Count pill | `28px` tall, 1px `#E5E7EB`, fill `#F9FAFB`, `12px / 600`, text `#374151` — "12 Line Items" |
| Criticality | Text with a coloured arrowhead (see 2.1) |
| Notification dot | `10px` red dot on the bell; count badge for unread totals |

### 3.7 Feedback

| Component | Specification |
|---|---|
| Alert | Radius `10px`, 1px border, `16px` padding, leading `16px` icon; destructive: red border at 50%, red text and icon |
| Inline error | `12px` red text under the field; the control border turns red |
| Empty state | A single centred message (`14px`, muted) inside the container that would hold the data — never a blank area |
| Loading | Centred blue spinner (`20px`) with a short label; tables use skeleton rows |
| Skeleton | `bg-muted` blocks, `animate-pulse`, radius `10px` |
| Banner | Full-width banners for session notices (previous device signed out, handoff request, MFA reminder) with an Allow / Deny or dismiss action |

### 3.8 Overlays

| Component | Specification |
|---|---|
| Dialog | Centred, max width `512px`, white, 1px border, `shadow.dialog`, radius `12px`, `24px` padding, `16px` gap; overlay black at 80%; close icon top-right; footer buttons right-aligned, Secondary then Primary |
| Popover / dropdown | White, 1px border, `shadow-md`, radius `10px`; the profile menu is 256px with a header row (avatar, name, email), a 1px divider, then rows of icon + label (`14px / 500`, `36px` high, hover `#F1F5F9`, sign-out in red); it opens `20px` below the trigger, right-aligned |
| Tooltip | Dark slate `#0F172A` pill, white `13px` text, radius `6px`, `150ms` fade; placed right of icons or below rows; native browser tooltips are not used |

### 3.9 Cards

| Card | Specification |
|---|---|
| **Module card** (hub entry) | White, 1px `#E4E4E4`, radius `10px`, `32px` padding, centred; 80px icon slot (98px artwork), title `20px / 600`, description `16px` muted. Hover: lift `-4px`, border `#BCDCF3`, `shadow.card-hover`, pointer-following dot spotlight |
| **Management tile card** | Same card with a 56px gradient icon tile instead of artwork |
| **Stat card** | White, `1.5px` toned border, radius `16px`, `26px` / `24px` padding; 46px bordered icon tile, title `20px / 600`, description `14px`, value `42px / 600`, dashed divider, up to three 40px mini-stat rows. Hover: lift, a tone gradient (`160deg`) to white, tone border, a 5%-opacity watermark of its own icon, row chevrons slide in. Tones: blue, green, purple, fuchsia, sky, amber, orange, red — each with its own border, tile, watermark and row-hover colours |
| **Section card** (detail) | White, 1px `#E5E7EB`, radius `10px`; header 16px/24px padding with a 32px icon tile, `18px / 600` title, `14px` muted caption and a bottom border; body fields in a 2-column grid |
| **Form card** | Default card primitive (radius `12px`, 1px border, `shadow-sm`), `24px` padding |
| **Record header card** | White, 1px `#E5E7EB`, radius `10px`, `16px` / `28px` padding; record code in brand blue, thin divider, record name uppercase, status pill; actions on the right (template select, Secondary and Primary buttons, view toggle) |

Detail field pair: label `13px` muted over value `17px / 500`; pairs separated by a 1px `#F1F2F4` rule; `24px` column gap, `16px` row gap; long
text and document lists span both columns.

---

## 4. Navigation

### 4.1 App shell

```
┌─────────┬──────────────────────────────────────────────┐
│ Sidebar │ Header  (64px, sticky)                       │
│ 272/56  ├──────────────────────────────────────────────┤
│         │ Breadcrumbs                                  │
│         ├──────────────────────────────────────────────┤
│         │ Page content (fluid, scrolls)                │
└─────────┴──────────────────────────────────────────────┘
```

The sidebar runs the full height of the screen; the header lives in the column beside it, so it never takes space from the
sidebar. On mobile the sidebar becomes a drawer opened from a menu button in the header.

### 4.2 Header

`64px`, white, bottom border and a light shadow, three columns `[1fr · auto · 1fr]`:

| Zone | Content |
|---|---|
| Left | Menu button (mobile), logo (mobile), product name `16px / 600` with subtitle `12px` muted |
| Centre | Organisation switcher |
| Right | Optional help/support button · notification bell (36px) · `32px` vertical divider · profile button |

Profile button: 40px avatar (two-letter initials on a `#DBEAFE → #60A5FA` gradient, navy text) with the name `14px / 600`
and email `12px` muted beside it. It opens the profile popover (name, email, security settings, **Sign Out** in red).

### 4.3 Breadcrumbs

White strip under the header, `14px`; links in `#6B7280`, current page in `#111827 / 500`; `14px` chevron separators in `#CBD5E1`. No home icon.

| Page | Trail |
|---|---|
| Module landing | `Dashboard › Module` |
| Form or log | `Dashboard › Module › Page` |
| Record detail | `Dashboard › Module › List name › Details` |
| Module whose landing page is one of its pages | `Dashboard › Module` (no repeat) |

The trail is built from the same module list as the sidebar, so a new page appears with no extra setup. The dashboard shows none.

### 4.4 Sidebar

One accent only — Calispec Blue. Per-module colours are not used here.

| State | Width | Behaviour |
|---|---|---|
| Expanded | `272px` | Logo, labels, module accordion |
| Collapsed | `56px` | Icon rail; navigation never disappears |
| Hover on collapsed | `272px` | Opens after `120ms`, closes when the pointer leaves |
| Mobile (< md) | hidden | Drawer from the header menu button |

Toggle: panel button at the bottom (36px, `#F1F5F9`, hover `#E8F3FC`) or **Ctrl / Cmd + B** (ignored while typing). Width animates `200ms`.
Surface white with a 1px right border.

**Brand row** — 64px, bottom border (lines up with the header's). Expanded: full logo 48px high, `16px` from the left. Collapsed: gear mark only, centred.

**Rows**

| Part | Specification |
|---|---|
| Row | `36px` tall, radius `8px`, `12px` side padding and gap, `14px / 500 / -0.01em` |
| Icon | `18px`, stroke 1.5, same x-position in both states |
| Idle | Black text, icon `#475569`, hover fill `#F1F5F9` |
| Active | Fill `#E8F3FC`, text `#003B8C`, icon `#0274BB` |
| Open module containing the active page | Normal fill, label `#003B8C` |
| Chevron | `14px`, `#94A3B8`, rotates 90° when open |
| Nav area | `8px` padding (`12px` top), `4px` row gap, 4px pale scrollbar |

Order: Dashboard → separator → modules (only those the user may open).

**Sub-menu (accordion)** — one module open at a time. A thin vertical rail (1px `#E2E8F0`, `21px` in, under the icon centre) holds
*Overview* then collapsible *Forms · Logs · Approvals · Acknowledgments* groups; each group's pages nest behind a second, shorter rail.
Groups with no links are hidden. The module and group containing the current page open automatically. Sub-links have no icons.

**Tooltips** — dark pill, placed to the right of collapsed icons and under expanded sub-links; the toggle's tooltip adds the shortcut.

---

## 5. Data

### 5.1 List tables

White container, 1px `#E5E7EB`, radius `10px`, horizontal scroll when wide.

| Part | Specification |
|---|---|
| Header row | `44px`, **solid Calispec Blue `#0274BB`**, 2px bottom border `rgba(0,0,0,.10)`; cells separated by 1px `rgba(255,255,255,.25)` (none after the last) |
| Header cell | `13px / 600`, uppercase, white text, `16px` side padding, no wrapping; label on the left, controls on the right |
| Sort | The label is the button, followed by an arrow icon `14px`: up-and-down arrows in white at 60% when idle, a single arrow in full white for the active sort |
| Column filter | Funnel icon `16px` at the right of the header cell, white at 80% (full white on hover); opens an Excel-style multi-select popover with search, apply and clear |
| Body cell | `24px × 16px` padding, `14px / 400`, no wrapping, `#DBEAFE` column separators, row borders, hover `muted/50%`, no border under the last row |
| Record link | Identifier in `#1D4ED8 / 600`, underline on hover; the whole row opens the record |
| Status | Pill badge (`px-12 py-4`) in the status colour |
| Row actions | Icon-only ghost buttons `#94A3B8`, hover `#1D4ED8` on light blue; must not trigger the row click |
| Empty / loading | One centred message row; skeleton rows while loading |
| Toolbar | Search and filters left; **Manage Columns** (Secondary, 40px) and actions right |
| Preferences | Column visibility is saved per account; sort, filters and page persist across a refresh |


### 5.2 Detail tables (line items)

| Part | Specification |
|---|---|
| Card | Section card (3.9) with a count pill |
| Header row | Fill `#E6F2FF`, border `#C9DEF5`; `13px / 600 / 0.04em`, uppercase, text `#374151`; `14px` vertical padding |
| Body | `15px / 500`, text `#111827`; separators `#F1F2F4`; cell padding `16px`; hover `#F9FAFB`; tabular figures for numbers |
| Identifier cells | Brand blue `#0274BB` |
| Load more | Secondary `sm` button, centred under the table, 1px top border |

### 5.3 Pagination

One shared control for every list. Three columns `[1fr · auto · 1fr]`, top-aligned, `16px` gap; it stacks on mobile.

| Column | Content |
|---|---|
| Left | `Rows per page:` + an `84 × 36px` white select of page sizes |
| Centre | `« ‹ Previous  1 2 … 1952  Next › »`, with `Showing 1–15 of 29258 results` `16px` below |
| Right | Page-jump box — **only when there are more than 50 pages** |

| Part | Specification |
|---|---|
| First / Last | Icon-only Tertiary buttons, 36 × 36px, double chevrons |
| Previous / Next | Tertiary, 36px, chevron + label |
| Page number | 36px tall, min 36px wide, radius `8px`, `14px / 400` |
| Colours | Inactive text, arrows and ellipsis `#9CA3AF`; hover `#F1F5F9`; **current**: 1px `#0274BB` border, `#E8F3FC` fill, `#003B8C` text, regular weight |
| Window | ≤ 7 pages: all. Otherwise first, current ± 1, last, with a non-clickable `…` |
| Disabled ends | 60% opacity |
| Jump | `Page [ 12 ] of 210  Go`; 64 × 36px numeric input (digits only); Enter or *Go* applies; the value is clamped; invalid input resets |
| Empty | `No results`, no page controls |

Changing rows per page returns to page 1.

### 5.4 Charts

Use the series palettes in 2.1. A card and its matching chart slice share the same hue. Axes and grid lines are dashed light grey,
axis text `12px` `#6B7280`; tooltips follow the popover style; legends sit under the chart. Colour is never the only encoding for
critical data — add labels or patterns (a pattern-fill option exists for print and colour-blind use).

---

## 6. Patterns

### 6.1 Dashboard and module hubs

* **Dashboard:** greeting (`hub-title`) with a muted subtitle on the left and date + live clock on the right, on the plain page background (no gradient banner). Below, a 2-column grid of module cards; each card has an icon, name, description, up to **six** page links (hover row with a sliding chevron) and a *View all N* link. Cards in a row share one height.
* **Module overview:** centred title and description, then sections *Forms · Logs · Approvals · Acknowledgments* — each a `14px / 700` uppercase label with a `20px` gap above its card grid. Modules with a single landing page (Management) open it directly instead.
* **Compact hubs** (forms only): the cards sit in a centred, auto-fit row (`300–359px` per card).

### 6.2 List pages

Title (`page-title`) + description → toolbar (search, filters, Manage Columns, primary action) → table (5.1) → pagination (5.3). Records open
the detail page; the breadcrumb ends in the list name when you arrive from it.

### 6.3 Detail pages

1. **Record header card** — code | name, status pill; right side: template select, Secondary actions, view toggle, Primary export.
2. **Sections** — either as **underline tabs** (default, one section visible) or **Full** (all sections stacked), chosen by the toggle and remembered per person.
3. **Section cards** with icon tile, title and caption; **detail tables** for line items; a change-history card at the end.
4. Approvals add an action panel (Approve / Reject / Rework with required notes); the page keeps the same header and cards.

All record detail pages share the same header and card chrome so any record looks like any other.

### 6.4 Forms

* **Layout choice:** *Stepper* (one section per step, Previous / Save Draft / Next) or *Single form* (all sections stacked, Save Draft Locally / Save). The toggle sits in the page header.
* **Page header:** title + subtitle, autosave indicator (Saving… amber, Saved green, Draft restored blue), draft actions (View Drafts, Clear Draft as a red outline), toggle.
* **Fields:** two-column grid; label above control; helper text `12px` muted; errors in red beneath; required marker red; amounts use a currency select + number input; options that can be extended use the "+" quick-add.
* **Validation:** inline per field plus a summary at submit that scrolls to and briefly rings the first invalid field; submit buttons show a spinner and disable while saving.
* **Drafts:** unsaved work is recovered with a banner (Restore / Discard); named drafts can be saved, renamed and deleted from a drafts panel.
* **Text entry:** standards-style forms upper-case free text as it is typed; dates use the organisation's date format.

### 6.5 Authentication

| Screen | Specification |
|---|---|
| **Sign in** | Two halves on `#FAFAFA` with `10px` outer padding. Left: logo (74px high), heading `24px / 500`, labelled email and password fields (41px high, `#9CA3AF` border, left icons, show/hide eye), full-width 44px Primary **Login**. Right (≥ 1024px, half width): rounded `10px` panel with a 4px white border and a gradient that runs white at the top to `#0284C7` at the bottom, headline `24px / 500`, four frosted-glass cards (white at 10%, 1px white at 30%, radius `16px`, light blur; title `20px / 500` navy, body `14px`), and a large product photo anchored to the bottom whose top edge overlaps the lower cards. The page never scrolls; the form column scrolls on very short windows |
| **Two-factor** | Centred card (max 384–512px) with a shield icon tile, title, one large centred monospaced code field, Primary **Verify**, and links to switch method (authenticator, email code, backup code) |
| **Waiting for approval** | Centred 440px card: logo, 80px pulsing blue ring around a device icon, `24px / 500` title, one sentence of explanation, and a pill with a spinner and the text "Continuing automatically in a few seconds" |
| **Errors** | Alert box above the fields (red); the common "invalid credentials" message is rewritten in plain language |

### 6.6 Session banners

Full-width banner pinned above the page: icon, message, and at most two buttons (Primary + Secondary). Used for MFA reminders,
"another device wants to sign in" (Allow / Deny) and "signed out on your previous device".

---

## 7. Accessibility and content

* **Focus:** every interactive element shows a `2px #0274BB` ring (offset `2px` white) on keyboard focus. Never remove focus styles.
* **Targets:** controls are at least 36px tall; icon buttons have visible hit areas of 36–40px.
* **Contrast:** body text `#111827` / `#374151` on white. `#9CA3AF` is for placeholders, inactive pagination and disabled text only, never for information the user needs.
* **Semantics:** tables use real `table` markup; the current page is `aria-current="page"`; tab lists use tab roles; tooltips and icon-only buttons have labels; live regions announce status screens.
* **Motion:** all animation is disabled under `prefers-reduced-motion`.
* **Content:** sentence-case labels; buttons start with a verb (Save, Export, Add); empty values show an em dash `—`; counts read "12 Line Items"; dates use the organisation's configured format; free-text data in standards screens is stored and shown upper-case.
* **Errors:** show plain-language messages with a next step; never expose technical or database text.

---

## 8. Token reference and known gaps

### 8.1 Theme variables used by the base components

The shared primitives read these CSS variables (HSL). They are the bridge between this document and the code.

| Variable | HSL | Approximate colour | Maps to |
|---|---|---|---|
| `--background` | `210 40% 98%` | `#F8FAFC` | Page background (the shell uses `#FAFAFA`) |
| `--foreground` | `222 84% 5%` | `#020817` | Default text |
| `--card` / `--popover` | `0 0% 100%` | `#FFFFFF` | Surfaces |
| `--primary` | `199 84% 48%` | `#14A8E4` | Spinners, text-primary links (lighter sky) |
| `--secondary` | `25 95% 53%` | `#F97316` | Accent orange |
| `--accent` / `--ring` | `202 98% 37%` | `#0277BB` | **Calispec Blue** — focus rings, accent |
| `--muted` / `--muted-foreground` | `210 40% 96%` / `215 16% 47%` | `#F1F5F9` / `#64748B` | Subtle fills, secondary text |
| `--destructive` | `0 84% 60%` | `#EF4444` | Destructive actions |
| `--border` / `--input` | `214 32% 91%` | `#E2E8F0` | Borders and input outlines |
| `--radius` | `0.75rem` | 12px | Base for large (12), medium (10) and small (8) corner sizes |

### 8.2 Known gaps to close

1. **Token drift** — many component values (`#E8F3FC`, `#CFE3F5`, `#D9DCE1`, `#9CA3AF`, …) are written as literals. They should be promoted to the named tokens above and referenced by name; `--primary` should be aligned with `color.brand.blue`.
2. **Table headers** — one list page uses a light-blue header; align it to the solid-blue standard (5.1).
3. **Button variants** — success, warning and coloured-outline variants are specified in the original design source but not implemented.
4. **Semantic colours in badges** — the badge component uses stock green and yellow; align with `color.success` and `color.warning`.
5. **Artwork scale** — hub artwork fill varies (66% / 92%); standardise per module.
6. **Chart palettes** — two overlapping palettes exist; keep the status maps and the categorical palette, and retire the duplicate brand series where charts do not share a card.
7. **Dark theme** — not defined.

---

*Version 2 · Last updated October 2026*
