Archetype spec · Enterprise / Product
Sentinel
An enterprise-grade design system for monitoring tools, dashboards, and data-dense products. Clear, helpful, respectful of expertise.
§1.1
Color system
Two-layer architecture: Layer 1 primitive ramps + Layer 2 semantic aliases. Components reference only Layer 2.
Layer 1 — Primitive ramps
Primary navy (anchor 700 = #1B2A4A)
Accent orange — CTA anchor 500 = #FF9900 — bg-only, never text on light surface
Success
Warning
Error
Neutral warm gray (workhorse)
Layer 2 — Semantic aliases
Text tokens
--text-primary--text-secondary--text-tertiary--text-disabled--text-linkSurface tokens
--surface-page--surface-card--surface-sunken--surface-sidebar--surface-headerBorder + focus tokens
--border-subtle--border-default--border-strong--border-focus--color-focus-ringAccent-CTA rule
The Accent-CTA Rule — Sentinel keystone
--color-accent-500 (#FF9900) is a background color only. Never use it as text color on light surfaces. Primary CTA = orange bg + dark text (#1C1917). Ratio: 7.0:1 AAA.
WCAG accessibility verification
| Swatch | Foreground | Background | Ratio | Status | Use case |
|---|---|---|---|---|---|
neutral-900 | surface-page | 16.75:1 | AAA | Body text on page | |
neutral-900 | surface-card | 18.10:1 | AAA | Body text on card | |
neutral-700 | surface-page | 9.73:1 | AAA | Secondary text | |
neutral-500 | surface-page | 4.58:1 | AA | Tertiary / helper text | |
link-500 | surface-card | 5.74:1 | AA | Link text | |
neutral-900 | accent-500 | 7.00:1 | AAA | CTA label — dark text on orange | |
| #FFFFFF white | accent-500 #FF9900 | 2.30:1 | FAIL | BANNED — white-on-orange forbidden | |
#FFFFFF | error-500 | 4.56:1 | AA | Destructive button label | |
neutral-50 | surface-header | 19.50:1 | AAA | Header / sidebar text | |
success-700 | success-100 | 5.92:1 | AA | Success badge | |
error-700 | error-100 | 8.14:1 | AAA | Error badge | |
warning-700 | warning-100 | 5.53:1 | AA | Warning badge |
§1.2
Typography
Fixed px modular scale (ratio 1.125). Inter only — no serif, no fluid clamp(). Base 14px. Tabular numerals required on all data columns.
Type scale — 12 steps
| Token | px | Weight | Leading | Use | Sample |
|---|---|---|---|---|---|
--text-h1 | 34 | 700 | 1.20 | Page title (max in Sentinel) | Dashboard |
--text-h2 | 30 | 700 | 1.20 | Major section, entity page title | Issues |
--text-h3 | 26 | 600 | 1.30 | Subsection heading | Critical alerts |
--text-h4 | 22 | 600 | 1.30 | Card title, dialog title | Confirm deletion |
--text-h5 | 20 | 600 | 1.30 | Sidebar headers | Settings |
--text-h6 | 18 | 500 | 1.50 | Inline group headers | Notification preferences |
--text-body-lg | 16 | 400 | 1.60 | Hero paragraphs | Configure your workspace |
--text-body | 14 | 400 | 1.50 | DEFAULT — UI, forms, tables | Status: active · Updated 2h ago |
--text-body-sm | 13 | 400 | 1.50 | Dense UI, table cells | API endpoint · v2.1.0 |
--text-caption | 12 | 400 | 1.50 | Metadata, timestamps | 3 minutes ago · 128 KB |
--text-overline | 12 | 700 | 1.50 | Section labels (small caps + tracking) | Foundation |
--text-code | 13 | 400 | 1.50 | Monospace code | GET /api/v2/issues |
Tabular numerals demo
Required on every numeric column
Apply font-feature-settings: "tnum" 1, "lnum" 1. Digits align vertically regardless of value width — critical for scanning tables with 50+ rows.
| Metric | Proportional | Tabular (required) |
|---|---|---|
| Requests / s | 1,111.00 | 1,111.00 |
| Errors / s | 999.11 | 999.11 |
| Latency p95 (ms) | 1,024.50 | 1,024.50 |
| Uptime (%) | 99.97 | 99.97 |
§1.3
Spacing
Compact density. 4px base, 12-step scale. Section padding 24px standard. Page horizontal padding 32px.
| Token | px | Visual | Use case |
|---|---|---|---|
--space-25 | 2 | Tight icon-text gap | |
--space-50 | 4 | Inline gap, badge padding | |
--space-75 | 6 | Badge inner padding | |
--space-100 | 8 | DEFAULT gap | |
--space-150 | 12 | Form field internal, table cell v-padding | |
--space-200 | 16 | Card padding, between fields | |
--space-300 | 24 | Section padding (standard) | |
--space-400 | 32 | Page horizontal padding | |
--space-500 | 40 | Page top spacing | |
--space-600 | 48 | Major breakpoint (rare) | |
--space-800 | 64 | Header/sidebar offset | |
--space-1000 | 80 | Full-page hero (rare in product UI) |
§1.4
Elevation
Flat with hairline borders by default. Cold rgba shadows for floating elements only. Warm oklch shadows are banned (that is Harbor).
| Token | Value | Use case | Demo |
|---|---|---|---|
--shadow-0 |
none + 1px border |
Card default — flat surface | |
--shadow-1 |
0 1px 2px rgba(0,0,0,0.05) |
Card:hover, card raised (above sunken bg) | |
--shadow-2 |
0 2px 4px rgba(0,0,0,0.08) |
Dropdown popover | |
--shadow-4 |
0 4px 8px rgba(0,0,0,0.10) |
Tooltip, menu popover | |
--shadow-8 |
0 8px 16px rgba(0,0,0,0.12) |
Dialog, modal, command palette | |
--shadow-16 |
0 16px 32px rgba(0,0,0,0.16) |
Drag preview, drawer |
Cold rgba only
Sentinel uses rgba(0,0,0,*) shadows. Warm oklch or colored shadows are a Harbor trait. A shadow in Sentinel always means "this element floats above the page." Default surfaces use borders, not shadows.
§1.5
Shape & borders
8-step radius scale. Default --radius-sm (4px) for cards, alerts, inputs. Pill shape for chips and filters. Circle for avatars and annotation pins.
| Token | Value | Use case | Demo |
|---|---|---|---|
--radius-none | 0 | Table cells, sticky headers | |
--radius-xs | 2px | Badges, severity pills (small) | |
--radius-sm | 4px | DEFAULT — cards, alerts, inputs | |
--radius-md | 6px | Buttons, switches | |
--radius-lg | 8px | Primary buttons (Amazon-style CTA) | |
--radius-xl | 12px | Dialogs, drawers, command palette | |
--radius-pill | 9999px | Chips, removable filters | |
--radius-circle | 50% | Avatars, annotation pins |
Banned radius patterns
Super-rounded cards (>16px) feel playful, not enterprise. Pill-rounded buttons belong to Current (consumer/mobile). Every surface has a specific radius — do not override with arbitrary values.
§1.6
Motion
Functional motion only — state, position, visibility changes. Never decorative. prefers-reduced-motion: remove transforms, keep instantaneous opacity only.
Durations
| Token | ms | Use |
|---|---|---|
--duration-shortest | 100 | Hover color, icon swap |
--duration-short | 150 | DEFAULT — buttons, dropdowns, toggles |
--duration-standard | 200 | Dialog open/close, drawer slide |
--duration-long | 300 | Page transitions, major state changes |
Easings
| Token | Curve | Use |
|---|---|---|
--easing-standard | 0.4, 0, 0.2, 1 | Default all transitions |
--easing-enter | 0, 0, 0.2, 1 | Elements entering (decelerate) |
--easing-exit | 0.4, 0, 1, 1 | Elements exiting (accelerate) |
Banned motion patterns
Bouncing / overshoot easing on UI, decorative flourishes on data updates, parallax, scroll-jacking, animated gradient backgrounds, marquee, rotating headlines. The principle: 150ms says "the system responded." Anything longer says "the system thinks slowly."
§1.7
Iconography
Family: Lucide — the modern enterprise / SaaS convention. Tailwind, Vercel, Linear, Notion, Supabase and modern dashboards converge on it. Neutral, functional, instantly recognizable. 2px stroke matches Sentinel's compact density. Substitute Material Symbols (Google enterprise default) if Lucide is unavailable. Never Phosphor (too editorial) or Tabler (too monospace-tool — that is Lattice).
| Property | Value | Rationale |
|---|---|---|
| Family | Lucide | Enterprise/SaaS standard — Vercel, Linear, Notion, Tailwind UI |
| Grid | 24px standard · 16px dense table/inline · 20px buttons | Consistent optical weight across UI densities |
| Stroke | 2px at 24px · 1.5px at 16px · rounded caps + joins | Never mix stroke widths in one icon group |
| Color | currentColor — inherit from parent | Never hardcode hex in SVG attributes |
| Style | Line icons default · Filled for severity / status only | Fill encodes meaning (critical = filled triangle, info = filled circle) |
| Decorative | aria-hidden="true" | Screen readers skip decorative icons |
| Meaningful | role="img" + <title> | Standalone icons need accessible name |
Sample icon grid — 16 Lucide icons at 24px, line style
Filled severity variants (fill encodes meaning)
§2
Voice & content
Three pillars: clear, helpful, respectful of expertise. Sentence case everywhere. Verb-first CTAs. No marketing fluff in product UI. No exclamation marks.
Do / Don't pairs
Do
"Upload a screenshot to get started."
Direct, action-oriented, no drama.
Don't
"Let's embark on your design journey!"
Marketing fluff in product UI. User is doing work, not being sold to.
Do
"Contrast ratio 3.1:1 — fails WCAG AA for body text."
Respects reader's expertise. Specific, actionable.
Don't
"Your colors might not be accessible (that's bad!)"
Condescending, vague, and uses an exclamation mark.
Do
"Upload failed. The file is over 10 MB. Try compressing it."
What / Why / How — gives recovery, not just failure notification.
Don't
"Error: Invalid file."
No context, no recovery path. User doesn't know what to do next.
Do
"Save changes" / "Delete report" / "Run critique"
Verb + object. Specific. Sentence case.
Don't
"Submit" / "Apply" / "OK" / "Click here"
Zero specificity. Sentence case "Submit" is still vague.
Do
Email address (required)
Parenthetical "(required)" is screen-reader friendly and clear.
Don't
Email address *
Asterisk-only required indicator fails a11y without extra aria markup. Also never floating-label it.
Do
"Saved." / "Deleted 3 reports."
Declarative. Calm. Respectful of the user's focus.
Don't
"Saved!" / "Great choice!" / "Awesome!"
Exclamation marks are banned in Sentinel product UI. Tonal mismatch.
Error message formula
What / Why / How — universal formula
Every error follows this structure: What happened (plain language) → Why it failed (the cause) → How to recover (concrete, doable action). Banned: stack traces in user-facing copy, generic "Oops!", error codes without explanation.
Upload failed — file is over 10 MB.
Large files exceed the processing limit. Compress the screenshot to under 10 MB and try again, or use the batch upload API for files over this limit.
Session expires in 5 minutes.
Your session will time out after 30 minutes of inactivity. Save your work now to avoid losing unsaved changes.
§3.F
Foundation components
Layer 1 primitives: Button, Icon button, Field, Selection controls, Tag/Badge, Chip, Avatar. All generated in this priority order.
Button — 4 variants × 3 sizes × all states
Size variants — primary (orange bg + dark text — accent-CTA rule)
All variants — md size
States
Icon button — sm / md / lg — ghost + tooltip
Field — text / with icon / error / disabled / select
Used for notifications and login.
Password must be at least 8 characters. Add 5 more characters.
Contact admin to rotate this key.
Selection controls — checkbox / radio / switch
Checkboxes
Radios
Switches
Tag / Badge — variants + sizes
sm neutral sm active sm failed 12
Chips — static / removable / selected / icon-leading
Avatars — sm / md / lg / xl + photo / initials
§3.C
Composite components
Layer 2: Card variants, Alert, Toast, Tooltip, Dialog, Drawer, Tabs, Loading, Dropdown, Date picker mock, Command palette, Code block.
Card — 4 variants
Flat (default)
Response time
142 ms
p95 · last 1h
Raised
Error rate
0.02%
Interactive (hover)
API endpoints
24
View all →
Selected (left-border accent)
Active alerts
7
Alert — info / success / warning / error
Scheduled maintenance
The API will be unavailable on 2026-05-01 from 02:00–04:00 UTC. Plan accordingly.
Deployment succeeded.
Version 2.4.1 is live. 0 errors in the last 5 minutes.
Rate limit at 80%.
You have used 800 of 1,000 monthly API calls. Upgrade your plan to avoid interruption.
Webhook delivery failed — endpoint unreachable.
3 consecutive deliveries to https://app.example.com/hook timed out. Check the endpoint and retry, or disable this webhook to stop retries.
Toast notifications
Tabs — line style with badge counts
Tab panel content renders here. Use ArrowLeft / ArrowRight to cycle tabs, Home / End for first / last.
Loading states — spinner / progress bar / skeleton
Skeleton (matches content shape)
Command palette (⌘K)
Code block — default / dark variant
Default (surface-sunken bg)
function contrastRatio(l1: number, l2: number): number {
const lighter = Math.max(l1, l2);
const darker = Math.min(l1, l2);
return (lighter + 0.05) / (darker + 0.05);
}
Dark variant (dev paste into Slack/docs)
--text-primary: var(--color-neutral-900); --surface-card: #FFFFFF; --border-focus: var(--color-accent-500);
§3.D
Domain layer components
Product-specific composites: Severity badge, Annotation pin, Critique card, Dropzone, Charts. Each composes Layer 1–3 with Sentinel rules.
Severity badges — all 5 levels (color + icon + text)
Annotation pins
Critique card
Dropzone
Drop a screenshot here
PNG, JPG, WebP · Max 10 MB · or
Charts mock (categorical palette)
Bar chart — issues by severity (with legend)
§3.L
Application layouts
Every product page is one of these six layouts. The system assembles into a layout, never invents new chrome.
L1 — Page shell (app frame)
(scrolls independently)
L2 — List + Detail
320–400px
L3 — Full-width dashboard
L4 — Split panel (60/40)
L5 — Focus mode / Wizard
L6 — Empty app state
§3.K — NEW
Keyboard-first interaction
Sentinel users spend hours per day in the product. Keyboard fluency is a productivity multiplier. Less aggressive than Lattice's terminal-grade doctrine, but more rigorous than Harbor / Current / Meridian. Mouse remains first-class.
Standard shortcut map
| Key | Action | Context | Sentinel rule |
|---|---|---|---|
| ⌘K / Ctrl+K | Open command palette | Global (any screen) | Must include every UI-reachable action — not a separate feature set |
| ⌘/ / Ctrl+/ | Keyboard shortcut help overlay | Global | Required — users need discoverability of all shortcuts |
| ⌘F / Ctrl+F | Focus search input | Pages with search | Intercept before browser default; restore on Esc |
| ⌘↵ / Ctrl+Enter | Submit / commit action | Dialogs, forms, inline editors | Submits from any focused field — Tab order must not break this |
| Esc | Close dialog / drawer / popover; clear focus | Floating elements | Returns focus to the trigger element |
| Tab / Shift+Tab | Navigate forward / back through focusable elements | All | Tab order matches DOM / visual order — no tabindex tricks |
| ↑ ↓ ← → | Navigate within tabs, radio groups, menus, data-table rows, dropdowns | Composite widgets | Roving tabindex pattern — only one item in tab sequence at a time |
| Home / End | First / last item in lists, table cells | Lists, tables, menus | Required — prevents repeated arrow-key pressing in long lists |
| Space | Activate buttons, toggle switches, select list item | Buttons, switches, checkboxes | Space selects in dropdowns; Enter activates |
| Enter | Activate links, primary action in dialogs | Links, dialogs, table rows | Enter opens detail row in data table |
| Shift+↑↓ | Extend row selection in data table | Data table with multi-select | Contiguous range select from anchor row |
| ⌘A / Ctrl+A | Select all rows | Data table | Triggers bulk action bar; shows count + actions |
| ⌘C / Ctrl+C | Copy selected row data | Data table | TSV format to clipboard for spreadsheet paste |
Focus ring — visual specification
Required focus ring (all keyboard-reachable elements)
Focus ring spec
3px solid --color-focus-ring = rgba(255,153,0,0.4), outline-offset: 2px. Applied via :focus-visible (not :focus). Pointer interactions do NOT show the ring — only keyboard navigation does.
Sentinel-specific keyboard rules
Command palette (⌘K)
- Focus trap while open
- Esc closes, returns focus
- ↑↓ navigate results
- Enter executes action
- Includes ALL UI actions
Data table navigation
- ↑↓ move between rows
- Enter opens row detail
- Space selects row
- Shift+↑↓ extends range
- ⌘A selects all visible
Form Tab order
- Tab advances field to field
- Shift+Tab goes back
- ⌘↵ submits from any field
- Tab order = DOM order
- No tabindex="2+" tricks
Banned keyboard-breaking patterns
| Banned pattern | Why it breaks keyboard-first | Required alternative |
|---|---|---|
| Custom focus styling that hides focus ring | Keyboard users lose position context — they cannot tell where they are | 3px --color-focus-ring on all :focus-visible elements |
| Click-only interactions (drag without keyboard alt) | Users who cannot use a mouse are excluded from the feature entirely | Keyboard alternative for all drag-and-drop (button + position input or ↑↓ reorder) |
| Modal triggers that don't accept keyboard activation | The action exists visually but is unreachable without a mouse | <button> elements activate on Enter + Space natively |
| Hover-only menus | :hover fires on mouse; :focus-visible fires on keyboard — both must open the menu | Menu opens on both hover and focus+Enter; never :hover-only |
§4.1
Data table
The iconic Sentinel component. Sticky header, hoverable rows, sortable columns, tabular numerals on all numeric columns, bulk action bar. 50 rows rendered below.
Tabular numerals on all numeric columns
Every column with numbers uses font-feature-settings: "tnum" 1 and text-align: end. Column headers for numeric columns are right-aligned to match. Zebra striping is banned — use hover state + row dividers instead.
| ID | Title | Severity | Status | Assignee | Score | Created |
|---|
§4.2
Form layout
Single-column. Labels above inputs. 16px between fields, 24px between groups. "(required)" parenthetical — never asterisk-only. Inline validation on blur.
§4.3
Empty state
Every empty state offers an action (CTA). Helpful, not apologetic. 64px circle icon (surface-sunken bg), h4 heading, 1–2 sentence body, primary CTA. Never a dead end.
No critiques yet
Upload a screenshot to start an accessibility and design review. Results appear here within 30 seconds.
§4.4
Search + filter pattern
Search input (icon-leading) + removable filter chips + sort dropdown — all in one row above data. ⌘F focuses search. Applied filters always visible as chips.
Showing 12 of 50 issues · 3 filters applied · Clear all
§4.5
Wizard / Stepper
Top progress with numbered steps and connectors. One step at a time. Sticky footer with Back (left) and Next / primary action (right). Max 5 steps.
§4.6
Detail header
Entity page header: breadcrumb + title (--text-h2) + status badge + metadata row + right-aligned actions. Page title is always h2 — h1 is reserved for the page shell.
§5
Accessibility
WCAG 2.1 AA minimum; AAA target for primary body text. Screen-reader tested on VoiceOver + NVDA. Keyboard navigable throughout. Color + icon + text for all status indicators.
WCAG conformance target
Body text
AAA
≥ 7:1 for primary body
UI text / labels
AA
≥ 4.5:1 minimum
Non-text UI
AA
≥ 3:1 icons, focus rings, charts
Screen-reader requirements
| Requirement | Implementation | Test platform |
|---|---|---|
| Icon-only buttons | aria-label required on every icon button | VoiceOver / Safari macOS |
| Form fields | label[for] above — never placeholder-as-label | NVDA / Firefox Windows |
| Toast / async results | aria-live="polite" default; "assertive" for blocking errors only | VoiceOver / Safari macOS |
| Decorative SVGs | aria-hidden="true" | All screen readers |
| Meaningful SVGs | role="img" + <title> | VoiceOver |
| Status indicators | Color + icon + text label — never color alone | TalkBack / Chrome Android |
| Data tables | scope="col" on headers; aria-label on the table | NVDA / Firefox Windows |
Keyboard navigation map (summary)
Full shortcut map in §3.K Keyboard-first
The complete keyboard shortcut specification lives at §3.K. This section summarizes the universal gates inherited from governance.spec.
- Every interactive element reachable via Tab in DOM order
- Focus indicator visible: 3px
--color-focus-ring, offset 2px, via :focus-visible - Standard key bindings honored: Enter/Space, Esc, Arrows, Home/End, Tab/Shift+Tab
- Focus trap inside modals, drawers, command palette — Esc returns to trigger
- Skip-to-content link at top of page
- Roving tabindex on tab panels, radio groups, menu bars
Performance budgets (Sentinel tier)
| Metric | Target | Notes |
|---|---|---|
| First Contentful Paint (FCP) | < 1.5s | 4G mobile |
| Largest Contentful Paint (LCP) | < 2.5s | 4G mobile |
| Cumulative Layout Shift (CLS) | < 0.10 | Universal |
| Time to Interactive (TTI) | < 3.5s | 4G mobile |
| Initial JS bundle (gzipped) | < 100 KB | Sentinel floor |
| CSS bundle (gzipped) | < 30 KB | Universal |
| Web font payload | < 100 KB | Inter subset + woff2 |
§6
Versioning & changelog
SemVer (MAJOR.MINOR.PATCH). Deprecated tokens/components ship for 2 MINOR versions before removal. Deprecation warnings logged at build time.
SemVer policy
| Bump | Trigger | Examples |
|---|---|---|
| MAJOR | Breaking token rename, removed component, breaking API change | Renaming --color-accent to --color-cta |
| MINOR | New component, new variant, new token, deprecation notice | Adding keyboard shortcut overlay component |
| PATCH | Bug fix, doc update, non-visual refactor | Fixing focus ring offset in Safari |
Changelog
- Initial release — full spec including two-layer token architecture
- Added KEYBOARD-FIRST INTERACTION section (§3.K) with full shortcut map
- Added BYOC required color roles — 7 ramps × 9 steps specification
- Added WHEN TO PICK with sample adjectives and real-world examples
- Added FAILURE MODES — 5 scenarios with cross-archetype cross-references
- Iconography rationale strengthened — Lucide retained with explicit rationale
- Domain layer components: Severity badge, Annotation pin, Critique card, Dropzone, Charts
- Composite components: Command palette, Date picker, Code block
- Layout system: L1–L6 vocabulary locked
Quality-gate checklist (PR / release blocking)
- Contrast ratios verified (AA minimum, AAA for primary body)
- Keyboard navigable — Tab / Space / Enter / Esc / Arrows all honored
- Screen-reader tested (VoiceOver + NVDA minimum)
- prefers-reduced-motion honored — transforms removed, not just shortened
- Both light and dark mode tokens defined for every Layer 2 semantic token
- No raw hex in component CSS — all colors through var(--token)
- No emoji in UI — SVG icons only
- Component implements default / hover / focus-visible / active / disabled
- Error messages follow What / Why / How formula
- Tabular numerals on all numeric columns
- Accent-CTA rule passes — no white-text-on-orange-500
- Components reference only Layer 2 semantic tokens
- Typography uses fixed px — no clamp()
- Changelog entry filed under correct semver bump
Governance overrides
Sentinel governance overrides
Inherits governance.spec in full. Sentinel additionally enforces these 10 rules on top of the universal gates.
| # | Rule | Enforcement |
|---|---|---|
| 1 | Two-layer token architecture — any component referencing Layer 1 primitive directly fails lint | CSS lint rule: no var(--color-*) in component files, only var(--text-*), var(--surface-*), etc. |
| 2 | Accent-CTA rule — white-text-on-accent-500 pairing fails CI contrast check | Automated contrast scan on build; flags any #FFFFFF on #FF9900 |
| 3 | Tabular numerals required on all numeric columns | font-feature-settings: "tnum" 1 enforced via CSS class lint |
| 4 | Typography is fixed px modular — any --text-* declared with clamp() fails lint | Regex lint: no clamp( in typography token declarations |
| 5 | Sans-serif only — any --font-serif declaration fails lint | Design token audit: zero serif families in the token file |
| 6 | Cold rgba shadows enforced — any oklch or warm shadow fails lint | CSS lint: shadow values must match rgba(0,0,0,*) pattern |
| 7 | Dark mode tokens defined for every Layer 2 semantic token | Token completeness check: every :root token has a [data-theme="dark"] override |
| 8 | WCAG verification table required in spec page output | Prompt 49 must enumerate every text/background pairing with ratio |
| 9 | Color-only encoding banned — every severity/status indicator combines color + icon + text label | Design review checklist; automated alt-text scan |
| 10 | "(required)" parenthetical enforced — asterisk-only fails form lint | Form audit: no field with required attribute that lacks the parenthetical in its label text |
BYOC — required color roles
Bring Your Own Colors
If you use a custom palette instead of Sentinel's canonical navy + orange, your supplied palette must cover these 7 ramps at minimum. 7 ramps × ~9 steps = ~63 required colors. Layer 2 semantic aliases are then auto-derived.
Required Layer 1 ramps
1 · Primary
50/100/200/300/400/500/600/700/800/900 — anchor at 7002 · Accent (CTA)
500 = bg-only. Accent-CTA rule: dark text on 500 ≥ 4.5:13 · Link
500 minimum — distinct from primary. Never reuse navy for links.4 · Success
50/100/300/500/700 minimum5 · Warning
50/100/300/500/700 minimum6 · Error
50/100/300/500/700 minimum7 · Neutral (warm gray workhorse)
50/100/200/300/400/500/600/700/800/900 — full 10-stepRequired Layer 2 aliases (auto-derived)
| Category | Required aliases | Derived from |
|---|---|---|
| Text | --text-primary / secondary / tertiary / disabled / inverse / link | Neutral 900/700/500/300/50; Link-500 |
| Surface | --surface-page / card / sunken / sidebar / header / subheader | Neutral 50/white/100; Primary 700/900/500 |
| Border | --border-subtle / default / strong / focus | Neutral 100/300/500; Accent-500 |
| Focus | --color-focus-ring | Accent-500 at 40% opacity |
BYOC validation rules
Rejected palettes (Prompt 1b will fail)
Single-hue strategy (that is Harbor), indigo / purple in any ramp (cliched "AI startup" signal — Sentinel anti-pattern), pastel-only palettes (insufficient contrast for status differentiation).
- Each ramp has minimum 6 steps (50/100/300/500/700/900)
- Accent-CTA rule passes: dark-text on accent-500 ≥ 4.5:1 contrast
- White-text on accent-500 explicitly rejected unless annotated "dark surfaces only"
- Components reference ONLY Layer 2 aliases — never primitives directly
When to pick
When to pick Sentinel
Use this section to route to the correct archetype. If three or more of your brand adjectives appear in the list below, Sentinel is likely your archetype.
Pick Sentinel if…
Use case signals
- Internal tool, B2B SaaS, dashboard, admin, monitoring, analytics
- User session is hours, not minutes
- Information density beats whitespace
- Multiple status / state combinations (workflows, approvals, severities)
- Keyboard navigation must be first-class
- Charts, tables, or domain-specific data viz required
- User base has expertise; efficiency over hand-holding
Sample adjectives — 3+ routes to Sentinel
Real-world examples — calibrate against these
| Product | Sentinel principle exemplified |
|---|---|
| Linear.app (the product, not the marketing site) | Light surfaces, hairline borders, accent CTA, dense data, keyboard-first |
| Notion.so (the product) | Sentence-case throughout, flat elevation, multi-state badges |
| Figma's app interface | Neutral chrome, color reserved for data and selection only |
| Vercel dashboard | Orange accent CTA on light surfaces — exact Sentinel pattern |
| Asana / Jira / GitHub Issues | Workflow + status badges, multi-ramp semantic palette |
| Salesforce Lightning | Multi-ramp semantic palette, governed, enterprise density |
| Atlassian Confluence / Trello | Flat with hairlines, compact density |
| AWS Console (newer surfaces) | Sentinel-aligned; older surfaces are pre-Sentinel anti-pattern catalog |
Do not pick Sentinel if…
| Use case | Right archetype |
|---|---|
| Marketing site or brand-forward portfolio | Harbor — editorial rhythm, warm shadows, generous space |
| Mobile-first consumer app with bold, atmospheric feel | Current — 44px targets, bottom nav, sheets-not-modals |
| Read-focused docs with body text as hero | Meridian — 17–19px body, 1.75 leading, 68ch reading-width |
| Trading desk / observability with 5,000+ rows of dense data | Lattice — terminal-grade keyboard-first, virtualized grids |
| Editorial content where structure should be felt, not seen | Harbor — atmospheric, serif display, flowing layout |
Failure modes — NEW
Failure modes
When teams force Sentinel onto the wrong use case, predictable failures appear in this order. Knowing the failure pattern helps route to the correct archetype before shipping.
Atmospheric flattening
Trigger: using Sentinel on a marketing site
Mobile thumb-misses
Trigger: scaling Sentinel down to mobile via responsive CSS
Reading fatigue
Trigger: using Sentinel for long-form documentation
Operator key-shortcut frustration
Trigger: using Sentinel on a terminal / observability product
Indigo-purple drift
Trigger: Sentinel without color discipline enforcement
#6366F1, #7C3AED, indigo, purple, violet.