GreenHat / Design System
GreenHat Design System

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

  1. Pick the surface. Product chrome composes from AtomsOrganisms; brand and content pages compose from Marketing & Content. Same tokens underneath.
  2. 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.
  3. Color by role, never by hex. Fills = primary, green text = primary-text, tints = -subtle.
  4. Type by role. Pick from the role scale; change density with data-density, never with ad-hoc sizes.
  5. Check the pairing. Every text/background combination must pass the Accessibility table — AA is the floor.

Color The ramp in practice

600 fill
700 text

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.

RuleDoNever
Color by rolePrimary 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 onlyOne namespace --gh-*, three tiers, consumed downward: comp → sys → ref.Forked or parallel token files — --md-*, --daisy-*, --gs-* are retired.
ButtonsEvery button 8px (--gh-comp-button-radius), from the five-variant matrix below.Pill buttons — pills are reserved for eyebrows, avatars and dots.
TypeLoad 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.
ThemingTheme with [data-theme] — a Tier-2 remap (plus the documented font exception). Try the toggle above.Per-component dark: overrides or parallel theme files.
ComponentsBuild 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 & a11yPair 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.

Methodology

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.

Atoms
Buttons, inputs, labels, badges — plus the color ramps & type roles themselves
Molecules
Bonded atoms: form fields, search boxes, cards, alerts, tabs
Organisms
Distinct sections: sidebar nav, data table, modal, command palette
Templates
App shell, dashboard grid, list/detail, marketing page
Pages
Templates filled with real content per tool
The exhaustive-matrix rule — Actionboard's key takeaway. Every load-bearing atom ships as a full matrix of Variants × Sizes × States (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.

Foundations · 01

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)

The fill/text split rule. Filled primary buttons resolve green-700 so white labels pass AA. Success and decorative green fills may still resolve green-600, but green rendered as text on the light canvas always resolves --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)

Foundations · 02

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.

display · Lexend Deca 700 · / 1.1 · -0.02em — marketing H1 only
Security operators.
display-sm · Lexend Deca 700 · / 1.12
Product builders.
h1 · Lexend 600 · / 1.2 — product page title
Authorization findings
h2 · Lexend 600 · / 1.2
Evidence ledger
h3 · Lexend 600 · / 1.25
Coverage summary
h4 · Lexend 600 · / 1.3  ·  h5 · / 1.35
Section headingCard heading
body-lg · body · body-sm · caption — Lexend 400

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.

button · Lexend 600 14px  ·  eyebrow · 11px 600 UPPERCASE +0.09em  ·  code · Geist Mono 400 14px
Eyebrow label--gh-sys-primary: #0F7A35
RoleFamily / weightComfortableCompactTracking
displayLexend Deca 70064 / 1.154 / 1.15-0.02em
display-smLexend Deca 70044 / 1.1242 / 1.15-0.02em
h1Lexend 60038 / 1.234 / 1.2-0.01em
h2Lexend 60030 / 1.228 / 1.2-0.01em
h3 · h4 · h5Lexend 60024 · 20 · 1824 · 20 · 18-0.01em / 0
body-lg · body · body-smLexend 40018 · 16 · 14 (lh 1.6/1.5)16 · 14 · 130
captionLexend 40012 / 1.411 / 1.40
buttonLexend 60014 / 1.0 (both densities)0
eyebrow / section-headerLexend 60011 / 1.0 · UPPERCASE+0.09em
codeGeist Mono 40014 / 1.50

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.

Foundations · 03

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

×3 · 25%
list / rail
×6 · 50%
main content
×3 · 25%
properties panel

Each column ≈ 8.33%. The Actionboard 25/50/25 composition applies to content-area layouts only.

Chrome is fixed; content is grid-bound. The sidebar is a fixed non-grid region — --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.
Foundations · 04

Radius & Elevation

Two-tier shape system — 4px controls, 8px containers — and five elevation levels with light and dark primitive sets.

radius-sm · 4px

inputs, checkboxes, small chips

Button
radius-md · 8px

buttons, cards, containers

radius-lg · 12px

panels, modals

radius-xl · 16px

hero / feature blocks

EyebrowGH
radius-full

pills, avatars, dots only

The single button rule: every button is 8px. The marketing site is the brand source of truth and already ships 8px; Actionboard puts controls at 4–8px; 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

shadow-1

card resting

shadow-2

raised

shadow-3

card hover

shadow-4

popover / dropdown

shadow-5

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.

Foundations · 05

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.

ElementEnterExitTiming
Popover / Dropdown / Menufade + scale 0.96→1, origin = trigger edgereverseslow in · fast out, ease-out
Modaloverlay fade + panel scale 0.98→1 + Y 8px→0reverseslow 250ms, ease-out
Toastslide Y +16→0 + fadefade + Y −8slow in · base out
Tabs indicatorslide along trackbase, ease-standard
Accordion / row expandmeasured height + fadereverseslow

Iconography — lucide, line-first

14 / 16 / 18 / 20 / 24 · stroke 1.75 (≤18) / 2 (≥20) · icon+text gap 8px · line = default, filled = active/selected only · directional icons mirror in RTL, logos and checkmarks don't · icon-only controls require aria-label
Foundations · 06

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 backgroundRatioNormal textLarge / UI
fg #0F1A12 on white17.84:1PASSPASS
fg-muted / fg-subtle #586B5D on white5.71:1PASSPASS
primary-text / link #0F7A35 on white5.45:1PASSPASS
primary fill #0F8A3D as text on white4.45:1NEVER AS TEXTLARGE ONLY
white on primary CTA fill #0F7A35 (button label 14/600)5.45:1PASSPASS
retired #62AC4A on white2.79:1FAILFAIL
#62AC4A as text on dark #1320186.03:1PASS — dark-mode text greenPASS
info-text #1D4ED8 on info-subtle5.91:1PASSPASS
danger-text #B91C1C on danger-subtle5.91:1PASSPASS
warning-text #B45309 on warning-subtle4.58:1PASSPASS
warning fill #D97706 as text on white3.19:1FILL / ICON ONLYLARGE ONLY
dark primary button #06251B on #2E9A4E4.54:1PASSPASS
dark danger-text #F87171 on #1320186.09:1PASSPASS

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

Notification channels

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.

Architecture

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);
}
ThemeCanvasSurfacefgPrimary fill / textNotes
light (default)#FFFFFFneutral-100neutral-950green-700 / green-700light shadow set; success fill remains green-600
dark#132018neutral-800neutral-100green-500 / green-400; on-primary dark inkdark shadow set; status text roles remap lighter
exponential#FFFFFF#F4F7F2#1B1D1F#16A34A / #15803D; on-primary dark inksystem-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 offlayers 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.

Library · Atoms

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

VariantDefaultHoverPressedFocusedDisabledLoading
Primary
Secondary
Danger
Ghost
Tertiary / Link
Sizes:

Input — the form matrix · {No-Hint | Hint} × {Unfilled, Filled, Error, Disabled} × {Default, Hover, Active} · radius 4px

Hint or helper message
Focus = green-600 border + 2px ring
Enter a valid work email
Lock glyph, surface fill
Same cells as Input + open/chevron states
Hover→green-300 · focus→ring
Same cells as Input · resize-y · used by contact & wizard forms
ISO dates · opens the Datepicker molecule · same cells as Input

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

Slider — basic / labeled / range

Badge · Chip · Kbd

NeutralPrimarySuccessInfoWarningDanger Eyebrow pill
⌘ KEsc

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

AGH AT KR

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.

Urgent High Medium Low None
Backlog Todo In progress Done Cancelled

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:

Older activity

Use the semantic border token; never a darker one-off line. Prefer whitespace first — divide only when spacing alone can't separate.

Library · Molecules

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

Scheduled maintenance
Report exports pause Sunday 02:00–03:00 UTC.
Audit evidence synced
142 artifacts verified against the ledger.
Token expiring
The service token rotates in 3 days. Warning text is fg + amber icon — never amber body copy.
Sync failed
Could not reach the evidence store. Retry — errors always ship a recovery affordance.

Search box · ⌘K trigger

⌘K

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

Findings resolved
1,284
12.4% vs last quarter

Cards — task · marketing feature

GH-482High

Rotate exposed service tokens

Task card — hover lifts −1px with shadow-1→3 and a green-300 border.

ATDue Jul 18security

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?
No — GreenHat Security provides readiness advisory; independent audit execution is separately governed. Answers support inline rich-text links.
How long does readiness take?
Typically 6–10 weeks depending on evidence quality and control ownership.
Phase 1 Stabilize identity & access
Carded, phased variant — the resource-article "action plan" accordion: phase pill + title header, rich body, single-open behavior on the live site.

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)

Step 1Scope ✓
Step 2Controls
Step 3Report

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)

PlatformDokkaebiONE
InfrastructureIBM LinuxONE
AttestationSOC 2 Type II

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)

Eyes — observe

Capture application state and traffic.

Brain — reason

Plan authorization test candidates.

Hands — act

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

Why this matters
Auditors weigh evidence gathered within the period higher. Anything older than 90 days is flagged for refresh.

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

KRKira Reyes
KWKim Wu

Filter-as-you-type select — assignees, controls, projects. Highlight the match, keep full keyboard support (↑↓ ), fall back to "No matches" empty state.

Datepicker

July 2026
MoTuWeThFrSaSu 293012345 6789101112 13141516171819 20212223242526 272829303112

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

Drop evidence here or click to browse PDF, PNG, CSV · 25 MB max
access-review-q2.pdf
64%
policy-encryption.pdf1.2 MB · uploaded

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

KR
Kira requested evidence clarification · 14m ago

Can we attach the raw role-switch trace before approval?

Add a concise response...

Event log row

agent:argus confirmed cross-role readsha256:8d2a...BAC evidence accepted12:43:22Z
kenny approved evidence packseq:000184immutable ledger append12:45:01Z
system exported report bundlebundle:019f...download ready12:47:18Z

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

BAC access-map Add tag...

Build from Chip + Input; remove buttons need labels, and overflow wraps before truncating tags.

Date range picker

to
July 2026range
MTWTFSS293012345

Upload failure state

report.jsonSchema validation failed at access_map.endpoints[2]

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).

Library · Organisms

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

FindingStatusPriorityOwnerUpdated
IDOR on shared report linksDoneUrgentATAnt2h ago
Cross-tenant object access in exports selectedIn progressHighKRKira1d ago
Stale session on role downgradeTodoMediumJMJules3d ago
Verbose error leaks stack traceBacklogLowATAnt1w 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

report.access_map.endpoints

Rows are endpoint records; columns come from known_roles; cells prefer role_outcomes when present and fall back to role_results status arrays.

Allowed Denied Finding Mixed Not tested
MethodPath templateFirst seenadminjimanonymousEvidence
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 × role access matrix
expected finding
Endpointadminjimanonymous
/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
Access control
Encryption
Screenshots
mfa-console.png

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

Rotate the service tokens before the audit window opens, then attach the evidence trail.

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.

Library · Marketing & Content

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

Fixed, blur-backed bar (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

Proud member of
CyberBC SecureCan TrustNet

Grayscale at 70% opacity, full color on hover — marquee-scrolls only when overflowing; pauses on hover; static under prefers-reduced-motion.

120+
Controls mapped
6–10
Weeks to ready
0
Failed audits

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

01

Security briefing

Ghost step numbers — primary-text @ 20%, the engagement-model idiom.

02

Scoped engagement

Fixed scope, clear deliverables.

03

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.

Book a Security Briefing
Free assessment

How quantum-ready is your stack?

Mid-article gradient panel — green→canvas→info-blue wash, kicker, heavy title, CTA pair.

12
Questions
4 min
To complete

Animated checklist — the readiness visual

Readiness 0%
Ready

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

CISO Guide

SOC 2 changes coming in 2026

GreenHat Security / 5 min read / Source: Forbes Tech Council
Last updated June 14, 2026
In this guide
What the 2026 revision actually changes Which controls need re-mapping A 90-day preparation plan

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.

Key takeaways
Evidence automation becomes table stakes.
Source & further reading. Original commentary via Forbes Tech Council — close every resource and news article with this citation footer, crediting the origin with an outbound link.

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

ArticleFORBES

The real cybersecurity divide isn't budget

Forbes / June 2026
Read summary
GreenHat link

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.

Template

Vendor security questionnaire

Download card — CSV/template with native download, check-list of contents below.

Download CSV
Figure — readiness coverage, FY 25–26 press briefing

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

Traditional audit
Evidence gathered once a year
Ledger-based assurance
Continuous, verifiable evidence trail

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.

Something went wrong — try again or email us directly.
Message sent.

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

Minor
Moderate
Major
Severe
Likely
Med
High
Crit · R-04
Crit
Possible
Low
Med · R-11
High
Crit
Unlikely
Low
Low
Med
High

Severity ramp — tokenized

Low Moderate High Critical

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).

Library · Data Visualization

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–26
9060300 Q2Q3Q4
Identified Resolved

Coverage trend

▲ on track
Endpoints covered Baseline (pattern-paired)

Severity mix

276 total
Resolved · 44% Medium · 22% Critical · 15% Low · 19%

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.
Practice · Voice

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.

DoDon'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.

Practice · Governance

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

PhaseWork
0 · FoundationsLoad 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 unificationAlias-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 libraryDefine 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 toolsBy 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 vizShip Chart Card + green-led palette + the Actionboard chart set. Greenfield.
5 · EnforceLint raw hex + physical direction props; Brand Hub renders every matrix cell from tokens; visual regression across theme × density × dir.
Open question — the "cal" tool. No 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.