One system. Every surface.
GHDS is the single source of truth for how everything GreenHat ships looks, behaves, and is built — from greenhatsec.com to every tool in the monorepo. One core, two surfaces: brand and product share the same tokens, type, and atoms, diverging only at the outermost expressive layer.
How to use this system
This page is the normative reference for every GreenHat surface — the product tools, greenhatsec.com, and all content. Build to it, not from screenshots of existing pages: where a shipped page and this document disagree, this document wins.
Workflow Building any page or feature
- Pick the surface. Product chrome composes from Atoms → Organisms; brand and content pages compose from Marketing & Content. Same tokens underneath.
- Library first. Reach for an existing component before designing anything; if nothing fits, add the new component here — with its full matrix — before shipping it.
- Color by role, never by hex. Fills =
primary, green text =primary-text, tints =-subtle. - Type by role. Pick from the role scale; change density with
data-density, never with ad-hoc sizes. - Check the pairing. Every text/background combination must pass the Accessibility table — AA is the floor.
Color The ramp in practice
One ramp, one namespace --gh-*: green-700 is the filled primary CTA and text green; green-600 remains a brand/success fill where no text sits on top. Use step 400 (#62AC4A) as decorative fill only — never text. Use blue for link/info only — there is no second accent.
| Rule | Do | Never |
|---|---|---|
| Color by role | Primary CTA fill and green text = green-700; brand/success fills can use green-600 when text is not placed on top; tints = -subtle tokens. | Raw hex in components · green-600 as body text · leaf 400 as anything but decorative fill · a second accent (blue is link/info only). |
| Tokens only | One namespace --gh-*, three tiers, consumed downward: comp → sys → ref. | Forked or parallel token files — --md-*, --daisy-*, --gs-* are retired. |
| Buttons | Every button 8px (--gh-comp-button-radius), from the five-variant matrix below. | Pill buttons — pills are reserved for eyebrows, avatars and dots. |
| Type | Load fonts for real (next/font: Lexend, Lexend Deca, Geist Mono) and pick from the role scale. | Declaring a font-family that is never loaded — it silently renders system-ui · ad-hoc px sizes: switch data-density instead. |
| Theming | Theme with [data-theme] — a Tier-2 remap (plus the documented font exception). Try the toggle above. | Per-component dark: overrides or parallel theme files. |
| Components | Build each primitive once as a shared component and import it; new atoms ship their full Variants × Sizes × States matrix here. | Re-declaring primitives per page · shipping a component with missing state cells. |
| Status & a11y | Pair color with shape and a label; meet the Accessibility table. | Color alone for status · any normal-text pairing below 4.5:1. |
Delegating brand work — to a person or an agent? Hand over this file and require three things: tokens only, library first, and the definition of done in Governance. Reject any change that introduces raw hex, a non-8px button, or a font that isn't actually loaded.
Design principles
Operator-led
The voice and visual weight of people who run security — confident, plain, founder-friendly.
Calm & credible
Light canvas, generous whitespace, one deep-green accent used sparingly. Visual noise reads as untrustworthy.
Evidence & clarity
Every state legible, data first-class, status never ambiguous. Contrast and focus are non-negotiable.
One core, two surfaces
Brand and product diverge only at the surface layer, through documented overrides — never by forking tokens.
Token-driven, always
No hardcoded hex in components. If a value isn't a token, it isn't shippable.
Atomic Design, token-driven
Adopted from the Actionboard case study: components are the key building blocks, and their systematic reuse creates visual and functional consistency across products. Five layers compose bottom-up — and every layer resolves the same tokens.
Default · Hover · Pressed · Focused · Disabled · Loading; form atoms add {No-Hint | Hint} × {Unfilled, Filled, Error, Disabled} × {Default, Hover, Active}). A component isn't "done" until every cell exists. This page renders the core matrices live; the rebuilt Brand Hub becomes the normative per-cell artifact for the rest.Atomic layers map onto the token tiers: atoms consume component tokens (--gh-comp-*), component tokens point at semantic tokens (--gh-sys-*), semantics point at primitives (--gh-ref-*). A marketing hero and an exponential task card both resolve --gh-sys-primary; only the surface layer decides hero rhythm and the green-700 CTA override.
Color
One brand green — the forest family. Green-700 #0F7A35 is the text green and filled CTA (5.45:1 with white text). Green-600 #0F8A3D remains the brand/success fill when no normal-size white label sits on top. Click any swatch to copy.
Brand green ramp — --gh-ref-green-*
★ 600 = brand/success fill when no text sits on it · ★ 700 = primary text and filled CTA · 400 is the retired product green #62AC4A, demoted to decorative fill (status dots, chart series) — never text · 900 #0B3B2C is the logo deep green.
Neutral ramp (green-tinted) — --gh-ref-neutral-*
950 #0F1A12 is the brand's green-tinted near-black (body text on light). 100 is the surface tint; 300 the default border; 900 the dark-mode canvas.
Semantic roles — --gh-sys-* (what themes remap — these chips re-resolve live when you switch theme)
--gh-sys-primary-text / --gh-sys-success-text = green-700. Never render green-600 as normal-size text on white (4.45:1 — fails AA). Warning fill #D97706 uses --gh-sys-warning-text for text.Data-viz categorical palette (fills only — legend text is always a neutral token)
Typography
One role-based scale. Body = Lexend, display = Lexend Deca 700 (marketing headlines), code = Geist Mono. The legacy dual scales collapse into this one scale — the old 14px-base system is now the compact density. Flip the density toggle in the top bar and watch every sample below re-resolve.
Boutique cybersecurity services, a labs team that builds what the market needs, and an independent assurance arm.
Body text carries the interface. It stays Lexend 400 at a 1.6 line-height for calm, readable density across audit-heavy screens.
body-sm handles table cells, helper text and metadata.
CAPTION — timestamps, footnotes, chart axes.
--gh-sys-primary: #0F7A35| Role | Family / weight | Comfortable | Compact | Tracking |
|---|---|---|---|---|
| display | Lexend Deca 700 | 64 / 1.1 | 54 / 1.15 | -0.02em |
| display-sm | Lexend Deca 700 | 44 / 1.12 | 42 / 1.15 | -0.02em |
| h1 | Lexend 600 | 38 / 1.2 | 34 / 1.2 | -0.01em |
| h2 | Lexend 600 | 30 / 1.2 | 28 / 1.2 | -0.01em |
| h3 · h4 · h5 | Lexend 600 | 24 · 20 · 18 | 24 · 20 · 18 | -0.01em / 0 |
| body-lg · body · body-sm | Lexend 400 | 18 · 16 · 14 (lh 1.6/1.5) | 16 · 14 · 13 | 0 |
| caption | Lexend 400 | 12 / 1.4 | 11 / 1.4 | 0 |
| button | Lexend 600 | 14 / 1.0 (both densities) | 0 | |
| eyebrow / section-header | Lexend 600 | 11 / 1.0 · UPPERCASE | +0.09em | |
| code | Geist Mono 400 | 14 / 1.5 | 0 | |
Density remaps sizes only — never roles. A body is always a body; data-density=compact just resolves it at 14px. The legacy scales map cleanly: old "sm" scale = comfortable, old "lg" h1 = compact display. Geist Sans is retired from the core brand — the brand typeface is Lexend; Geist survives as Geist Mono for code, and as the assurance surface face via the documented theme font exception.
Spacing, Sizing & Grid
A 4px base grid expressed in Actionboard's 16×N model. Chrome is fixed-width; content is grid-bound on a 12-column, 1440px-max grid (16px gutter · 56px margin).
Spacing scale — --gh-ref-space-*
The 12-column content grid
list / rail
main content
properties panel
Each column ≈ 8.33%. The Actionboard 25/50/25 composition applies to content-area layouts only.
--gh-comp-sidebar-w: 240px (304px with module rail, 64px collapsed) — never an 8.33×3 column. The properties panel is fixed 320px (or ×3 when a page opts into pure grid). The 12-col grid is measured across the remaining content width. Breakpoints: sm 640 · md 768 · lg 1024 · xl 1280 · 2xl 1440; sidebar becomes a drawer under lg.Radius & Elevation
Two-tier shape system — 4px controls, 8px containers — and five elevation levels with light and dark primitive sets.
inputs, checkboxes, small chips
buttons, cards, containers
panels, modals
hero / feature blocks
pills, avatars, dots only
rounded-full was an isolated CRM-shell choice with no brand backing. Pills are reserved for genuinely circular elements.Elevation — 5 levels, semantic pointers over two primitive sets
card resting
raised
card hover
popover / dropdown
modal
Elevation lives at the semantic tier: --gh-sys-shadow-1..5 point at --gh-ref-shadow-light-* or --gh-ref-shadow-dark-*. Themes flip the pointer, never the primitive — switch to Dark above and these five cards deepen live.
Motion & Iconography
One curve family, four durations. 150ms cubic-bezier(0.4, 0, 0.2, 1) is the default transition on color, background, border, shadow, opacity and transform. prefers-reduced-motion collapses all durations to 0.01ms.
Card hover
translateY −1px + shadow-1→3 · base 150ms. Hover me.
Button press
scale 0.98 · fast 100ms.
Chevron
rotate 180° · base.
| Element | Enter | Exit | Timing |
|---|---|---|---|
| Popover / Dropdown / Menu | fade + scale 0.96→1, origin = trigger edge | reverse | slow in · fast out, ease-out |
| Modal | overlay fade + panel scale 0.98→1 + Y 8px→0 | reverse | slow 250ms, ease-out |
| Toast | slide Y +16→0 + fade | fade + Y −8 | slow in · base out |
| Tabs indicator | slide along track | base, ease-standard | |
| Accordion / row expand | measured height + fade | reverse | slow |
Iconography — lucide, line-first
aria-label
Focus & Accessibility
WCAG AA is the floor: normal text ≥ 4.5:1, large text and UI objects ≥ 3:1. Every default token pairing is measured — this table is normative, and it's why the old greens couldn't survive as text.
| Foreground on background | Ratio | Normal text | Large / UI |
|---|---|---|---|
fg #0F1A12 on white | 17.84:1 | PASS | PASS |
fg-muted / fg-subtle #586B5D on white | 5.71:1 | PASS | PASS |
primary-text / link #0F7A35 on white | 5.45:1 | PASS | PASS |
primary fill #0F8A3D as text on white | 4.45:1 | NEVER AS TEXT | LARGE ONLY |
white on primary CTA fill #0F7A35 (button label 14/600) | 5.45:1 | PASS | PASS |
retired #62AC4A on white | 2.79:1 | FAIL | FAIL |
#62AC4A as text on dark #132018 | 6.03:1 | PASS — dark-mode text green | PASS |
info-text #1D4ED8 on info-subtle | 5.91:1 | PASS | PASS |
danger-text #B91C1C on danger-subtle | 5.91:1 | PASS | PASS |
warning-text #B45309 on warning-subtle | 4.58:1 | PASS | PASS |
warning fill #D97706 as text on white | 3.19:1 | FILL / ICON ONLY | LARGE ONLY |
dark primary button #06251B on #2E9A4E | 4.54:1 | PASS | PASS |
dark danger-text #F87171 on #132018 | 6.09:1 | PASS | PASS |
Focus rings — per surface
2px ring, 2px offset, on :focus-visible everywhere. The ring sits outside the control so it remains visible on filled buttons, light surfaces and dark surfaces. Tab through these:
Never color alone
Status, priority and severity pair color with shape and label; charts pair hue with pattern or direct labels; errors pair the red border with a dot and message. Modals trap focus and honor Esc; menus are keyboard-navigable; loading/empty/error states are announced via aria-live.
RTL & bidi: logical properties only (ms-/me-/ps-/pe-) — the layout mirrors under dir="rtl"; numerals and code stay LTR islands.
Skip link · Visually hidden
Click into this card, then press Tab — the skip link drops into view. Ship it as the first focusable element on every page, jumping past the chrome to #main.
Pair with .sr-only (this sentence contains a visually hidden example) for text that only assistive tech should read — icon-only button labels, table summaries, live-region announcements.
Fieldset
Group related controls with a real <fieldset> + <legend> — screen readers announce the group name with each control. Visual weight stays light: hairline border, muted legend.
Token Architecture & Theming
Three tiers, one namespace: --gh-*. The Material-prefixed system, --daisy-* and --gs-* are all retired — same three-tier shape, one honest prefix. This very page is built on these tokens: the theme switcher above redeclares Tier 2 (plus, for the two surface-faithful themes, the documented font-primitive exception below).
Tier 1 Primitives
--gh-ref-* — raw ramps, spacing, radius, two shadow sets, type, motion, grid. Mode-agnostic; never referenced by components; never themed — sole exception: the three --gh-ref-font-* primitives, remappable by surface-faithful themes (see below).
Tier 2 Semantic
--gh-sys-* — role-based: bg, fg, primary, primary-text, border, focus-ring, shadow pointers. The tier themes remap (colors always; fonts only via the enumerated exception).
Tier 3 Component
--gh-comp-* — per-component: button radius, sidebar width, table-row hover. Points at Tier 2 only (geometry may use Tier 1).
Consuming GHDS
For this self-contained v1 repo, the canonical token artifact is the live stylesheet in index.html; consuming apps should pin this repo revision and import the extracted token block during adoption. The package target is ghds-tokens.css: root tokens, theme remaps, density remaps and the root attribute contract, without demo component CSS.
/* app root contract */ <html data-theme="light|dark|exponential|assurance" data-density="comfortable|compact" data-contrast="normal|more"> /* Tailwind v4 bridge */ @theme inline { --color-primary: var(--gh-sys-primary); --color-surface: var(--gh-sys-bg-surface); --radius-button: var(--gh-comp-button-radius); }
All tokens — generated from the live stylesheet
/* Tier 2 — what a theme remaps (excerpt of this page's own CSS) */ --gh-sys-primary: var(--gh-ref-green-700); /* CTA fill #0F7A35 */ --gh-sys-primary-text: var(--gh-ref-green-700); /* text #0F7A35 — AA on white */ --gh-sys-shadow-1: var(--gh-ref-shadow-light-1); /* dark theme → shadow-dark-1 */ /* Tier 3 — components consume semantics */ --gh-comp-button-radius: var(--gh-ref-radius-md); /* 8px — the single button rule */ --gh-comp-table-row-hover: var(--gh-sys-primary-subtle); /* Tailwind v4 bridge — @theme inline keeps existing utilities compiling */ @theme inline { --color-primary: var(--gh-sys-primary); --color-brand-primary: var(--gh-sys-primary); /* legacy alias */ --spacing-sidebar: var(--gh-comp-sidebar-w); }
| Theme | Canvas | Surface | fg | Primary fill / text | Notes |
|---|---|---|---|---|---|
light (default) | #FFFFFF | neutral-100 | neutral-950 | green-700 / green-700 | light shadow set; success fill remains green-600 |
dark | #132018 | neutral-800 | neutral-100 | green-500 / green-400; on-primary dark ink | dark shadow set; status text roles remap lighter |
exponential | #FFFFFF | #F4F7F2 | #1B1D1F | #16A34A / #15803D; on-primary dark ink | system-ui type, mint chrome, light table headers; pair with compact |
assurance | #FFFFFF | #ECF8F1 | #10332A | #F4D35E fill · on-primary #042825 (10.7:1) / text #007956 (5.43:1) | greenhatassurance.com — light-first; forest text, mint borders, yellow CTA; midnight nav/hero/footer are dark islands; Geist type |
[data-contrast=more] | pure #000/#FFF · primary→green-700 · 3px focus rings · subtle tints off | layers on any theme | |||
Stacked attributes on <html>: data-theme × data-contrast × data-density. daisy-notes' selectable "theme modes" become [data-theme] values — no parallel token file survives.
The font-primitive exception, enumerated. exponential remaps the font primitives to the system-ui stack — the tool ships no webfont, so this theme reflects what actually renders; if the tool adopts loaded fonts, re-point the theme here in the same change. assurance remaps them to Geist — load Geist via next/font on that surface and never rely on a base-rule fallback. Type sizes remain density-owned: a theme never remaps --gh-type-* (the later [data-density] block would clobber it anyway) — pair exponential with data-density="compact". Assurance CTAs render on the 8px button rule under GHDS; pills there are a documented surface divergence, not a license.
Atoms
Every load-bearing atom ships as a full Variants × Sizes × States matrix. The four core atoms are cell-normative below — every cell rendered live from tokens. Interactive cells respond to your cursor; forced-state cells show hover/pressed/focus frozen.
Button — the exemplar matrix · 5 variants × 3 sizes × 6 states · all 8px
| Variant | Default | Hover | Pressed | Focused | Disabled | Loading |
|---|---|---|---|---|---|---|
| Primary | ||||||
| Secondary | ||||||
| Danger | ||||||
| Ghost | ||||||
| Tertiary / Link |
Input — the form matrix · {No-Hint | Hint} × {Unfilled, Filled, Error, Disabled} × {Default, Hover, Active} · radius 4px
All 30 cells = {5 row-states} × {No-Hint/Hint} × {Default/Hover/Active where applicable}. The ×{Default/Hover/Active} axis modifies border/ring only; the error dot and lock glyph are fixed per row-state. Errors never rely on color alone.
Selection controls & small atoms
Checkbox · Radio · Switch · Slider
Badge · Chip · Kbd
Badges use -subtle fills + -text foregrounds. The eyebrow is the marketing idiom: green @8%, UPPERCASE, and a leading dot with a soft 3.2s glow pulse (freezes under prefers-reduced-motion).
Avatar · Tooltip · Spinner · Skeleton
Priority dots · Status circles
Use the --gh-comp-priority-* and status tokens — never hardcoded hex — and always pair the dot with a label: never color alone.
Done is green-600 — never #22c55e.
Links · Progress bar
Use the arrow text link as the card-footer CTA; use inline underlined links inside copy; muted links for low-emphasis utilities. Use the pill-track progress bar for wizards, calculators and readiness meters — track = primary-subtle, fill = primary.
Divider (Separator)
Section body above the break.
Plain hairline between blocks; labeled variant for grouped regions:
Use the semantic border token; never a darker one-off line. Prefer whitespace first — divide only when spacing alone can't separate.
Molecules
Atoms bonded into the smallest functional compounds. Everything below is live and consumes only --gh-sys-* / --gh-comp-*.
Alert banners — info / success / warning / error
fg + amber icon — never amber body copy.Search box · ⌘K trigger
Click it — it opens the real Command Palette organism.
Toast — trigger the live queue
Slide-in +16px, auto-dismiss timer bar, aria-live.
Tabs — animated indicator
Underline variant · indicator slides along the track at 150ms.
Stat card
Cards — task · marketing feature
Rotate exposed service tokens
Task card — hover lifts −1px with shadow-1→3 and a green-300 border.
Boutique Security Services
Marketing feature card — green line-icon top-left in primary-text, bold title, muted body.
GreenHat Labs
Hyper Audit Ledger, RiskAssure, and the free-tools suite — one card grammar across all of them.
Disclosure & wayfinding · use on both surfaces; names follow the Component Gallery taxonomy
Accordion (FAQ / disclosure)
Do you run the audit yourselves?
How long does readiness take?
Phase 1 Stabilize identity & access
Chevron rotates 180° at slow; open state carries primary-text. Always wire aria-expanded + aria-controls on the trigger, fire faq_open on open, and keep phased plans single-open.
Breadcrumbs · Filter pills
Use breadcrumbs on deep hierarchies — control libraries, research detail pages: link every ancestor, mark the leaf with aria-current="page", and don't fake them with slash-separated eyebrow text. Use filter pills on hub pages: track content_filter_select and sync the selection to ?tab= so filtered views are shareable. The underline Tabs molecule above stays the product idiom.
Stepper (wizard steps + progress)
Use for every multi-step tool (questionnaires, wizards, assessments): pair step pills with the Progress bar atom, mark completed steps with a check, keep step labels to a word or two.
Option cards (selectable checkbox / radio)
Use when a choice needs explanation — topic pickers, calculator options, wizard answers. Selected = primary-subtle fill + primary border; keep the native control visible for accessibility.
Spec list (label / value rows)
Use for spec sheets and estimate breakdowns: uppercase muted label, semibold value, hairline dividers — no zebra, no borders around the block.
Timeline (vertical, icon nodes)
Capture application state and traffic.
Plan authorization test candidates.
Execute and verify, evidence-first.
Use for architecture walk-throughs and engagement timelines: icon tile + hairline rail, one-line descriptions, close with a footnote strip when sourcing matters.
Menus, pickers & files · overlay panels shown frozen-open, like the forced-state button cells
Dropdown menu
Open from a kebab or ghost trigger; shadow-4, fade + scale 0.96 from the trigger edge (see Motion). Keyboard-navigable; destructive items in danger, last, after a separator.
Popover
Non-modal rich hint anchored to a trigger — dismiss on outside click or Esc. Use Tooltip for one-liners; Popover when the hint needs a title, body, or a link.
Combobox
Filter-as-you-type select — assignees, controls, projects. Highlight the match, keep full keyboard support (↑↓ ↵), fall back to "No matches" empty state.
Datepicker
Anchored to the Date input atom. Today = inset primary ring; selected = primary fill with on-primary. Typing a valid ISO date always works without the picker.
File upload
Evidence-first: state accepted types + size up front, reuse the Progress bar atom per file, and keep the zone keyboard-operable (↵ opens the browser).
Pagination · Button group
Paginate product tables past ~50 rows (with the virtualized list underneath); content pages cross-link with Related cards instead. Button group = attached single-select toggles via aria-pressed; use the Segmented control for view/theme switches.
Adopter molecules — audit-ledger & ARGUS
Use these before inventing local variants in audit-ledger, ARGUS, or dashboard work. They are small enough to stay molecules, but specific enough that teams otherwise drift.
Comment thread + composer
Can we attach the raw role-switch trace before approval?
Event log row
Actor, verb, object and immutable reference are always visible; hashes use the mono token and never replace the human-readable event.
Diff / log viewer
- GET /api/users/42 as jim -> 200 + GET /api/users/42 as jim -> 403 evidence_source: authorization_matrix replay: reports/juice/access-map.txt
Use for BAC diffs, runner logs and evidence snippets. Pair red/green with leading symbols and labels; never rely on hue alone.
Tag / multi-select input
Build from Chip + Input; remove buttons need labels, and overflow wraps before truncating tags.
Date range picker
Upload failure state
Every upload error has a visible cause and a recovery affordance; failed files keep their row so users can compare before replacing.
Deliberately not adopted from the Component Gallery taxonomy — check the alternative before building one: Carousel (use static grids; motion carries no evidence) · Rating (severity is badges + priority dots, never stars) · Color picker (color is token-governed, not user-picked) · Video (no embedded media on the brand surface today; wrap in the Figure shell if that changes) · Stack (a gap-spaced flex column on the 4px scale is the idiom — no dedicated component).
Organisms
Distinct interface sections. Two are already running on this page — the fixed Left Sidebar Nav with its green active state, and the sticky Top Bar. Below: Data Table, Modal, Command Palette, Empty State.
Data Table — zebra · hover · selected · sticky header
| Finding | Status | Priority | Owner | Updated | |
|---|---|---|---|---|---|
| IDOR on shared report links | Done | Urgent | ATAnt | 2h ago | |
| Cross-tenant object access in exports selected | In progress | High | KRKira | 1d ago | |
| Stale session on role downgrade | Todo | Medium | JMJules | 3d ago | |
| Verbose error leaks stack trace | Backlog | Low | ATAnt | 1w ago |
Header band = --gh-comp-table-header-bg: green-900 with white 11px caps in the default theme, light #FAFBFC with muted caps in Exponential, and forest with white caps in Assurance. Row hover = --gh-comp-table-row-hover. Selected = primary-subtle + inset 2px accent. Virtualized via react-virtual; reflows to cards under md.
ARGUS access-map matrix — endpoint × principal coverage
Rows are endpoint records; columns come from known_roles; cells prefer role_outcomes when present and fall back to role_results status arrays.
| Method | Path template | First seen | admin | jim | anonymous | Evidence |
|---|---|---|---|---|---|---|
| GET | /#/search | iteration 1 | 200 x4 | 200 x7 | No probe | organic navigation |
| GET | /rest/admin | iteration 3 | 500 x2 | 403 | authorization_matrix candidate | |
| GET | /rest/continue-code | iteration 7 | 200 | 200 x6 | 401 | role_results fallback |
| POST | /api/admin/users/{id} | projection | allowed | denied | role_outcomes preferred |
Dashboard rule: the coverage matrix consumes the full report.access_map object. Deduped unique findings can decorate cells and open proof drawers, but they must not be the only source for the endpoint × principal grid because empty, denied, mixed and untested cells are part of the evidence story.
ARGUS dashboard access-map flow — roles to endpoints
Use this view when ARGUS needs a dashboard-native scan map rather than a dense audit table. It is still fed by report.access_map: role nodes come from known_roles, endpoint nodes from endpoints[], and highlighted paths from finding overlays or unexpected role_outcomes. Motion mirrors the dashboard replay language: paths draw in, violation points pulse, and the scan sweep freezes under prefers-reduced-motion.
ARGUS dashboard endpoint-role matrix — finding overlay
| Endpoint | admin | jim | anonymous |
|---|---|---|---|
| /rest/admin | |||
| /api/Complaints | |||
| /rest/user/authentication-details |
Dashboard parity rule: this is the current argus-dashboard/components/EndpointMatrix.tsx visual model, retokenized for GHDS. Keep the check-only expected cells and warning-pill finding cells, but source rows from full report.access_map when available; selectUniques() decorates cells and drives the proof drawer.
Modal / Dialog
Center · confirm/destructive · drawer · full-screen. Scale 0.98→1 + translateY 8px, shadow-5, focus trap, Esc.
Command Palette — cmdk
Adopts the repo's unused cmdk dependency; retires the hand-rolled #62ac4a palette. ⌘K anywhere on this page.
Empty state
No findings yet
Run a scan to populate this view — results land here with full evidence trails.
Presets: no-data · no-results · error · permission-denied · coming-soon · calendar. Title states the situation plainly; description gives the one next step; a single primary action.
Tree view · Rich text editor · Drawer
Tree view
Evidence
Policies
Screenshots
Caret rotates 90° at base; selection = primary-subtle. For evidence trees, control hierarchies and nested notes. Try it — the branches are live.
Rich text editor
Task descriptions, notes, comments. Ghost icon buttons with aria-pressed; content uses the body type roles — never its own scale. Keep the toolbar to what the content model actually supports.
Drawer (side sheet)
Detail and filter panels that keep list context visible. Slides from inline-end (250ms ease-out), shadow-5 + scrim, focus trap and Esc like Modal, mirrors in RTL. Full-height on mobile.
Marketing & Content
The brand-surface library: use these components on greenhatsec.com and every marketing or content page. Product chrome lives in Organisms — both surfaces share the same tokens. Names follow the Component Gallery taxonomy. Surface rules: tints come from primary-subtle — never raw rgba() greens; radii come from tokens; buttons follow the 8px rule; and every pattern is built once as a shared component, then imported. The hero organism is demonstrated in Overview.
Header / NavBar · Footer
blur(16px) · canvas @ 92%) · height 4.5rem / 5rem ≥640px · collapse to a hamburger panel with a full-width CTA on mobile · mark external links with the diagonal-arrow glyph · track every click: nav items, CTA, and the logo link.Logo strip · Stat band
Grayscale at 70% opacity, full color on hover — marquee-scrolls only when overflowing; pauses on hover; static under prefers-reduced-motion.
Set stat values in primary-text with tabular numerals. Use bare cells for trust strips, carded tiles for feature sections, and compact mini-stat tiles inside CTA panels.
Process steps · CTA banner · Inline CTA panel
Security briefing
Ghost step numbers — primary-text @ 20%, the engagement-model idiom.
Scoped engagement
Fixed scope, clear deliverables.
Embedded execution
Operators in the loop, evidence-first.
Ready to get audit-ready?
Closing conversion band — centered heading, one muted line, a single primary action on a bg-surface section.
How quantum-ready is your stack?
Mid-article gradient panel — green→canvas→info-blue wash, kicker, heavy title, CTA pair.
Animated checklist — the readiness visual
Usage
Use for readiness meters, onboarding flows and completion screens. Sequence: each ring draws (420ms) then its tick snaps in (340ms, 220ms delay); the bar eases toward checked ÷ total — progress always tracks real state, never fakes ahead; the stamp pops only at 100%. Rows, ring, tick, bar and stamp all resolve primary tokens, so the component re-themes with the switcher above.
This demo auto-loops as ambient feedback — in production, drive each row from real completion state and drop the loop. Honors prefers-reduced-motion by rendering the completed state; pauses when the tab is hidden.
Article patterns — header · summary · takeaways · citation
SOC 2 changes coming in 2026
Use this summary card for top-of-article takeaways. For long reference pages (control libraries), use the anchor-linked "Jump To" nav instead — don't mix the two.
For in-article comparisons (framework vs framework, level vs level), use the content comparison table: the doc-table idiom in a carded shell with an uppercase green title bar, scrolling horizontally on narrow screens. Product data stays in the Data Table organism.
Content cards — article · related links · download
SOC 2 pricing calculator
Use related-links cards as the cross-linking engine at article and page ends — 2–4 per row, preferred over pagination.
Vendor security questionnaire
Download card — CSV/template with native download, check-list of contents below.
Give every figure a one-line hint-style caption; 16:9 media, radius-md, hairline border; lazy-load below the fold; meaningful alt text, never "image".
Comparison panel · Contact form states
Reserve the red-vs-green split for genuine either/or positioning — it is the only sanctioned red-toned organism on the brand surface. Accent border flips sides; danger tints never appear elsewhere as decoration.
Compose forms from topic Option cards + Input/Textarea atoms. Disable submit until required fields fill; show errors as a danger alert with a recovery path; on success, replace the form with the check state. Fire form_start / generate_lead.
Risk matrix heat grid · the one tool organism with its own anatomy
Severity ramp — tokenized
Build every severity ramp from success + the --gh-comp-priority-* tokens — never a custom traffic-light set. Tint cells at ≤18% so risk-ID chips stay legible, and pair every cell with a text label — never color alone. Rated rows land in the register table (the Data Table organism) with matching rating pills.
Compose interactive tools — calculators, questionnaires, wizards, risk builders, readiness meters — from these parts: Stepper + Progress + Option cards + Spec list + Stat tiles + result Callouts, plus the heat grid above. Reuse the .seg segmented control for locale and mode switches. And build each primitive once as a shared component, then import it everywhere — never re-declare a pattern inside a page file (adoption plan in Governance).
Data Visualization
Charts are first-class. Every chart lives in a bordered 8px Chart Card with title, legend and range control. SVG-rendered so they theme via CSS variables — watch them re-color when you switch theme. Legend text is always a neutral token; series hues are fills only.
Findings by quarter
FY 25–26Coverage trend
▲ on trackSeverity mix
Chart rules
- Set: bar, grouped/stacked bar, line/area, bubble, doughnut, pie + sparkline, progress, burndown.
- Up/positive = green fill · down/negative = danger · warning = amber.
- Single accent per chart unless categorical; series 1 is always brand green.
- Axis/ticks in
fg-muted; gridlines = neutral ramp low-opacity; tabular figures. - Never hue alone — pattern/shape/label pairs every series (see the dashed baseline).
- States: loading skeleton · empty preset · error + Retry · hover tooltip · legend toggle.
Content & Voice
"Security operators. Product builders. Independent auditors." — one company, three pillars, and the voice follows: operator-led, concise, confident, founder-friendly. Calm authority — never hype, never fear-selling. Overstatement erodes trust in a security and audit brand.
| Do | Don't |
|---|---|
| "Independent, separately-governed SOC 2 audits." | "The most trusted audits in the world." |
| Lead with the outcome, then the mechanism. | Bury the value under adjectives. |
| One green accent per view; whitespace carries weight. | Flood the page with green fills or multiple accents. |
| danger for genuine risk / destructive actions only. | Red used decoratively. |
| Sentence-case UI; UPPERCASE only for eyebrows. | Title-case or ALL-CAPS body copy. |
Idioms: eyebrow pills label sections · feature cards lead with a green line-icon · stats and the single accent word in a headline carry green-700 as text · partner logos grayscale.
Governance & Adoption
SemVer, additive-first — tokens and component APIs are contracts. The rebuilt Brand Hub becomes the living reference: it consumes the same --gh-* tokens it documents and renders every matrix cell. If docs and code disagree, the docs rendered from tokens win — the code is the bug.
Contribution rules
1 · Tokens only
No hardcoded hex/px in components. A lint rule blocks raw color literals and physical left/right spacing in app/**.
2 · Full matrices
New atoms ship with every Variants × Sizes × States cell rendered in Brand Hub — every cell, not just axis names.
3 · Update together
Token → component → Brand Hub → tests land as one change, mirroring the repo's existing update-together discipline.
4 · Tier discipline
comp → sys → ref, downward only. Marketing overrides at the surface layer through documented tokens — never by forking values.
Phased migration
| Phase | Work |
|---|---|
| 0 · Foundations | Load fonts for real (next/font: Lexend, Lexend Deca, Geist Mono). Introduce --gh-* three tiers + @theme inline aliases. Retire first: orphaned theme.css, the daisy blue --daisy-* system, the --gs-* set. |
| 1 · Green unification | Alias-first: point every legacy token at --gh-sys-primary (fills) / --gh-sys-primary-text (text) — every surface shifts at once. Sweep the 84 hardcoded #62ac4a sites; demote it to green-400, decorative fill only. |
| 2 · Real shared library | Define the currently-undefined btn-*/.input/.card/.empty-state-* classes against tokens. Promote the working icon system to shared atoms; delete dead .linear-* CSS. Adopt the unused cmdk for the Command Palette. |
| 3 · Converge tools | By fragmentation cost: daisy-notes (blue + system fonts → green + Lexend) → greenspot (gets its own [data-theme] value) → greenbooks/crm (shared Button/Badge/Sidebar) → exponential (closest already — its palette is the exponential theme above) → marketing site (shared tokens; keeps 8px + green-700 CTA at the surface). |
| 4 · Data viz | Ship Chart Card + green-led palette + the Actionboard chart set. Greenfield. |
| 5 · Enforce | Lint raw hex + physical direction props; Brand Hub renders every matrix cell from tokens; visual regression across theme × density × dir. |
cal app, route, or component exists in the monorepo (only a CalendarEmptyState preset). Blocked on product: is "cal" a calendar view of exponential, or a separate tool? GHDS reserves no template until that's confirmed.Definition of done — bringing any surface onto GHDS: fonts actually load (verify the rendered family in devtools, not the class name) · zero raw hex — the lint passes · every button 8px · every text pairing passes the Accessibility table · new components land in this document with their full matrices, in the same change. Every color pairing in this document has a measured contrast pass; every core-atom cell is enumerated and rendered live above.
GHDS v1.1.1 · synthesized from greenhatsec.com + the greenhat_tools monorepo + the Actionboard Design System methodology (Behance, kishore R) · this page is itself built on the tokens it documents.