Using this with Claude: Download design-system-guide.md and add it as Project Knowledge in your own Claude Project. Claude will automatically apply the correct tokens and components. Your HTML pages should include <link rel="stylesheet" href="design-system.css">.

1. Design Tokens — Colors

All colors are CSS custom properties defined in :root. Use the variable names, never raw hex values.

accessibility_new Accessibility
This color system is designed to meet WCAG 2.2 Level AA contrast requirements. Every foreground/background pairing has been audited to ensure a minimum 4.5:1 contrast ratio for normal text and 3:1 for large text and UI components. Use --gray-500 or darker for any text that conveys information; --gray-400 is reserved for placeholder text and decorative elements only.
Brand
--primary
#1966d2
--primary-dark
#11508c
--primary-light
#e8f0fe
Semantic
--success
#15803d
--success-bg
#f0fdf4
--warning
#b45309
--warning-bg
#fffbeb
--error
#b91c1c
--error-bg
#fef2f2
--info
#2563eb
--info-bg
#eff6ff
Gray Scale
--gray-50
#f8f9fa
--gray-100
#f0f1f3
--gray-200
#e5e7eb
--gray-300
#d1d5db
--gray-400
#9ca3af
--gray-500
#6b7280
--gray-600
#4b5563
--gray-700
#374151
--gray-800
#1f2937
--gray-900
#1a1a2e
Extended Palette
--purple
#7c3aed
--purple-bg
#f3e8ff
--amber
#b45309
--amber-bg
#fef3c7
--blue-dark
#1d4ed8
--blue-bg
#dbeafe

2. Typography

Primary font: Inter (400, 500, 600, 700) — matching the Gateway app's stack exactly. Monospace for manuscript IDs: the system ui-monospace stack.

Changed from Roboto on 28 Sept 2026. The design system previously specified Roboto and forbade Inter; that rule predated Gateway and was enforcing the prototype's choice against the product's. 600 is available in Inter and is legal — existing 700s were left alone, since under Roboto they already rendered at 700.

Page Title — 24px / 700
Section Heading — 20px / 700
Component Label — 15px / 700
Body Text — 14px / 400
Body Medium — 14px / 500
Secondary Text — 13px / 400 / gray-500
Caption — 12px / 400 / gray-500
Section Label — 11px / 700 / uppercase / gray-400
JEM-2025-1847 — Manuscript ID (monospace / 13px / 600 / primary)

3. Status Badges

Used in queue tables and manuscript lists. Classes: .status-badge + .urgent | .warning | .info | .success

error Overdue schedule Due Soon hourglass_top In Review check_circle Complete
<span class="status-badge urgent"> <span class="material-symbols-outlined">error</span> Overdue </span>

4. Status Dot Indicator

Inline colored dot + descriptive text. Used in Gateway table STATUS columns as an alternative to the pill-style status badges. Class: .status-dot + state modifier.

Gateway live app — This pattern matches the live production app. In Gateway, it's implemented with DaisyUI + Tailwind CSS + Alpine.js.
Status Dot Variants
Make Decision — 9 days overdue Awaiting Referee Reports — due in 3 days Review Complete Submitted — under review Draft — not yet submitted
In a Table Context
Manuscript Status Days
EJP-109449
A third resonance in the damped oscillator
Make Decision — 9 days overdue 12 days
NJP-119321
Performance of Parity QAOA
Invite Referees — due in 5 days 25 days
QST-104090
Monitoring photonic linear clusters
Review Complete 8 days
Comparison: Dot vs Badge
Status dots (.status-dot) are used in Gateway table rows where space is tight and the status text itself is descriptive. Status badges (.status-badge) are the pill-style indicators used in prototypes and contexts where a compact label is needed. Both use the same semantic color tokens.
<span class="status-dot overdue">Make Decision — 9 days overdue</span> <span class="status-dot warning">Awaiting Reports — due in 3 days</span> <span class="status-dot on-track">Review Complete</span> <span class="status-dot in-progress">Submitted — under review</span> <span class="status-dot neutral">Draft — not yet submitted</span>

5. Health Status Badges

Pill badges for journal health indicators on the analytics dashboard. Used inline with section titles. Classes: .gw-health-badge + .critical / .warning / .good

Gateway live app — This pattern matches the live production app. In Gateway, it's implemented with DaisyUI + Tailwind CSS + Alpine.js.
Badge Variants
Critical Warning Good
Health Cards (In Context)

Submission Volume

Critical

Comparing submission counts between quarters

Editorial Quality

Good

Acceptance rate stability indicates healthy editorial process

Process Efficiency

Good

Time to decision trends affect author satisfaction

Activity Level

Warning

Recent submission activity indicates declining engagement

<div class="gw-health-card"> <div class="gw-health-card-header"> <h4>Submission Volume</h4> <span class="gw-health-badge critical">Critical</span> </div> <p>Comparing submission counts between quarters</p> </div> <!-- Badge alone --> <span class="gw-health-badge good">Good</span>

6. Article Type Badges

Used in queue rows. Classes: .article-type-badge + type modifier.

Special Issue Clinical Trial Review Original Research
<span class="article-type-badge special-issue">Special Issue</span>

7. Match Score, Load, & Value Indicators

Used in reviewer tables and grid cards. Semantic coloring based on quality tier.

Match Badges
92% 74% 45%
Load Indicators
Light Moderate Heavy
Value Indicators
14 days 21 days 38 days
85% 62% 28%
Editorial Board Badge
verified Board Member

8. Recommendation & Review Badges

Used in decisions page and manuscript detail.

Recommendation Badges
check_circle Accept edit Minor Revisions rate_review Major Revisions cancel Reject compare_arrows Split
Review Dots (completion indicators)
Timeline Badges (history page)
Accept Minor Major Reject

9. Keyword Tags

Two sizes: compact for table rows, standard for flyout panels.

Table size (.keyword-tag)
Immunotherapy Melanoma Clinical Trials
Flyout size (.flyout-keyword)
Immunotherapy Melanoma PD-L1 Inhibitors

10. Buttons

General purpose and flyout action buttons.

General Buttons
Flyout Buttons (flex: 1, fill footer)
AI Chat FAB
auto_awesome Ask AI Assistant

11. Search & Filter Bar

Search across manuscripts and filter results by urgency, status, type, and other attributes.

Search Box
Filter Toolbar
search
Filter Panel (Expanded)

Filters

Urgency
Days in Status
Article Type
<!-- Search box --> <!-- Filter toolbar and panel --> <!-- Filter toolbar --> <div class="gw-filter-toolbar"> <button class="gw-filter-toggle active"> <span class="material-symbols-outlined">filter_list</span> Hide filters </button> <div class="gw-search-input"> <span class="material-symbols-outlined">search</span> <input type="text" placeholder="Search..."> </div> </div> <!-- Filter panel --> <div class="gw-filter-panel"> <div class="gw-filter-panel-header"> <h3>Filters</h3> </div> <div class="gw-filter-group"> <div class="gw-filter-group-label">Urgency</div> <label class="gw-filter-option"> <input type="checkbox"> <span class="status-dot overdue">Overdue</span> <span class="gw-filter-count">69</span> </label> </div> </div>

12. Tab Bar — Gateway (Underline Style)

Horizontal tabs with underline indicator, icons, and count badges. Matches the live Gateway Editor Center and Dashboard tabs. Classes: .gw-tab-bar, .gw-tab, .gw-tab-count

Gateway live app — This pattern matches the live production app. In Gateway, it's implemented with DaisyUI + Tailwind CSS + Alpine.js.
Editor Center Tabs (with count badges)
Simple Tabs (no badges)
Count Badge Variants
42 .urgent 3 .success 12 .info 70 .neutral
<div class="gw-tab-bar"> <button class="gw-tab"> <span class="material-symbols-outlined">notifications</span> Needs Action <span class="gw-tab-count urgent">42</span> </button> <button class="gw-tab active">All Manuscripts <span class="gw-tab-count neutral">70</span> </button> </div>

13. Flyout Panel (right rail)

480px wide panel that slides from the right. Used for reviewer details, manuscript previews, and decision forms.

MJ
Dr. Michael Johnson
Professor of Oncology
Stanford University
Match Score
92%
Excellent match based on expertise, publication history, and availability
Performance
14d
Avg. Turnaround
85%
Accept Rate
3
Current Load
Keywords
Immunotherapy Melanoma PD-L1

14. Modal / Dialog

Centered overlay dialog for confirmations, forms, and detail views. Includes backdrop, header with close button, scrollable body, and action footer. Classes: .gw-modal-backdrop, .gw-modal, .gw-modal-header

Gateway live app — This pattern matches the live production app. In Gateway, it's implemented with DaisyUI + Tailwind CSS + Alpine.js.
Confirmation Dialog

Confirm Decision

You are about to accept manuscript EJP-109449. This will notify the author and move the manuscript to production. This action cannot be undone.
Wide Variant (for forms)

Invite Referee

<div class="gw-modal-backdrop"> <div class="gw-modal"> <div class="gw-modal-header"> <h3>Confirm Decision</h3> <button class="gw-modal-close"> <span class="material-symbols-outlined">close</span> </button> </div> <div class="gw-modal-body"> Dialog content here... </div> <div class="gw-modal-footer"> <button class="btn btn-ghost">Cancel</button> <button class="btn btn-primary">Confirm</button> </div> </div> </div> <!-- Wide variant: add .wide to .gw-modal --> <div class="gw-modal wide">...</div>

15. Toast Notification

Fixed bottom-center. Dark background with success icon.

check
Invitation Sent
Dr. Michael Johnson has been invited to review

16. View Toggle

Switch between table and grid/card views. Used in invite-reviewers and all-manuscripts.

17. Pagination

Navigate between pages of results. The prototype uses numbered page buttons; the live Gateway app uses a summary + per-page dropdown + page navigation pattern. Both are valid; use whichever matches your context.

Numbered Pages (Prototype)
Page 2 of 156
Items-per-page (Gateway)
Default State
Showing 1 – 25 of 70
Page 1 of 3
Mid-page State
Showing 26 – 50 of 70
Page 2 of 3
<!-- Prototype: Numbered pages --> <!-- Gateway: Items-per-page pattern --> <div class="gw-pagination"> <span class="gw-pagination-summary">Showing 1 – 25 of 70</span> <div class="gw-pagination-controls"> <div class="gw-per-page"> <select> <option>25 per page</option> <option>50 per page</option> </select> </div> <div class="gw-page-nav"> <button class="gw-page-nav-btn" disabled> <span class="material-symbols-outlined">chevron_left</span> </button> <span class="gw-page-info">Page 1 of 3</span> <button class="gw-page-nav-btn"> <span class="material-symbols-outlined">chevron_right</span> </button> </div> </div> </div>

18. Sortable Table Headers

Uppercase column headers with bi-directional sort arrows. Active sort column highlights in blue. Classes: .gw-table, .gw-th.sortable, .sorted-asc / .sorted-desc

Gateway live app — This pattern matches the live production app. In Gateway, it's implemented with DaisyUI + Tailwind CSS + Alpine.js.
With Active Sort
Manuscript ▲▼ Status Journal ▲▼ Days ▲▼ In Status Since ▲▼
EJP-109449
A third resonance in the damped oscillator
Make Decision — 9 days overdue European Journal of Physics 12 days 04-Mar-2026
NJP-119321
Performance of Parity QAOA
Invite Referees — due in 5 days New Journal of Physics 25 days 19-Feb-2026
QST-104090
Monitoring photonic linear clusters
Review Complete Quantum Science and Technology 8 days 08-Mar-2026
<table class="gw-table"> <thead> <tr> <th class="gw-th sortable sorted-asc"> Manuscript <span class="gw-th-sort"> <span class="gw-th-sort-arrow">▲</span> <span class="gw-th-sort-arrow">▼</span> </span> </th> <th class="gw-th">Status</th> <th class="gw-th sortable">Journal ...</th> </tr> </thead> <tbody>...</tbody> </table>

19. Sidebar (Light / Expanded)

White background, 220px wide, text + icon labels, blue active state with left border. Matches the live Gateway app layout. Classes: .gw-sidebar, .gw-nav-item, .gw-beta-badge

Gateway live app — This pattern matches the live production app. In Gateway, it's implemented with DaisyUI + Tailwind CSS + Alpine.js.
<div class="gw-sidebar"> <div class="gw-sidebar-section"> <a href="#" class="gw-nav-item"> <span class="material-symbols-outlined">home</span> Home </a> <a href="#" class="gw-nav-item active"> <span class="material-symbols-outlined">edit_square</span> Editor Center <span class="gw-beta-badge">Beta</span> </a> </div> </div>

20. Hero Banner

Full-width gradient banner with icon, title, document count, and subtitle. Used at the top of each Gateway center page. Classes: .gw-hero, .gw-hero-icon, .gw-hero-title

Gateway live app — This pattern matches the live production app. In Gateway, it's implemented with DaisyUI + Tailwind CSS + Alpine.js.
Default Hero
edit_note

Editor Center (70 documents)

Manage manuscripts in your queue

Author Center Variant
description

Author Center (12 documents)

Track your submitted manuscripts

<div class="gw-hero"> <div class="gw-hero-icon"> <span class="material-symbols-outlined">edit_note</span> </div> <div class="gw-hero-content"> <h2 class="gw-hero-title"> Editor Center <span class="count">(70 documents)</span> </h2> <p class="gw-hero-subtitle">Manage manuscripts in your queue</p> </div> </div>

21. KPI Stat Cards

Metric cards for the Analytics dashboard. Each shows a label, large value, trend arrow with delta, comparison text, and a colored progress bar. Classes: .gw-kpi-grid, .gw-kpi-card, .gw-kpi-trend

Gateway live app — This pattern matches the live production app. In Gateway, it's implemented with DaisyUI + Tailwind CSS + Alpine.js.
KPI Grid
Submissions arrow_downward -31%
19,717 vs 28,579 previous period
Acceptance Rate arrow_upward 1.4pp
21.7% vs 20.3% previous period
Time to First Decision arrow_upward -2.3%
59.9 days Target: < 30 days
Reviewer Response arrow_upward 1.3pp
10.1% Invitation acceptance rate
<div class="gw-kpi-grid"> <div class="gw-kpi-card"> <div class="gw-kpi-header"> <span class="gw-kpi-label">Submissions</span> <span class="gw-kpi-trend down"> <span class="material-symbols-outlined">arrow_downward</span> -31% </span> </div> <span class="gw-kpi-value">19,717</span> <span class="gw-kpi-compare">vs 28,579 previous period</span> <div class="gw-kpi-bar"> <div class="gw-kpi-bar-fill critical" style="width: 69%;"></div> </div> </div> </div>

22. Empty States

Placeholder for tables or pages with no data. Centered layout with icon, title, description, and optional action button. Class: .gw-empty-state

Gateway live app — This pattern matches the live production app. In Gateway, it's implemented with DaisyUI + Tailwind CSS + Alpine.js.
Table Empty State
inbox

No manuscripts found

There are no manuscripts matching your current filters. Try adjusting your search criteria or removing some filters.

Search Empty State
search_off

No results for "quantum entanglement"

We couldn't find any manuscripts matching your search. Check for typos or try a broader search term.

<div class="gw-empty-state"> <div class="gw-empty-state-icon"> <span class="material-symbols-outlined">inbox</span> </div> <h3>No manuscripts found</h3> <p>There are no manuscripts matching your filters.</p> <button class="btn btn-ghost">Clear Filters</button> </div>

23. Loading States

Skeleton shimmer placeholders and spinner for content loading. Apply .gw-skeleton to any element for the shimmer effect. Classes: .gw-skeleton-text, .gw-skeleton-heading, .gw-spinner

Gateway live app — This pattern matches the live production app. In Gateway, it's implemented with DaisyUI + Tailwind CSS + Alpine.js.
Skeleton Card
Skeleton Table Rows
Spinner

Loading manuscripts…

<!-- Skeleton placeholders --> <div class="gw-skeleton gw-skeleton-heading" style="width: 50%;"></div> <div class="gw-skeleton gw-skeleton-text" style="width: 100%;"></div> <div class="gw-skeleton gw-skeleton-text" style="width: 80%;"></div> <!-- Circle avatar skeleton --> <div class="gw-skeleton gw-skeleton-circle" style="width: 40px; height: 40px;"></div> <!-- Spinner with message --> <div class="gw-loading-state"> <div class="gw-spinner"></div> <p>Loading manuscripts…</p> </div>

24. Additional Patterns

Active Filter Tags (on dark backgrounds)
Immunology close 2024 close Available close
Page Footer
Shadows
--shadow-sm
--shadow-md
--shadow-lg
Border Radius Scale
4px
8px
12px
16px

25. Manuscript Flags

A journal-configured label an office puts on a manuscript. Two facts drive every rule here: flags are multi-select (a manuscript carries a set, possibly empty — “unflagged” is the empty set, not a list member), and their meaning is configured per journal, so no component may hard-code a label, colour or icon. All three come from the journal’s list (components/ms-flags.js).

Colour is never the only difference between two flags — every flag has a distinct glyph as well, because the queue row renders some flags icon-only and colour alone would fail WCAG 1.4.1.

Icon set A — legacy shapes

The twelve shapes legacy actually ships, redrawn as vectors. Legacy offers 22 flag slots, but those are these twelve repeated in different colours with the colour baked into a 12×12 bitmap. Abstract by design: a purple dot means whatever the journal typed into its label. Shown at 26px and at 14px — the size a flag is read at in a queue row. Foundry, with a colour picker and copyable SVG: lab/flag-shapes.html.

Circle
Square
Triangle up
Triangle down
Diamond
Star
Cross
Check
Box, horizontal bar
Box, vertical bar
Box, cross
Star of Life
Icon set B — Material Symbols

The production set. Material Symbols outlined at FILL 1 — the same family the design system already loads, so a flag and a nav icon are the same typeface rather than two icon languages in one app. Semantic rather than abstract, which lowers the memory burden when an office runs a dozen flags. Again at 24px and 14px.

search
help
check_circle
mail
cancel
block
warning
star
Chips

Class: .flag-chip, with --flag-color set per chip from the flag record. The chip body stays neutral and the icon carries the colour — colouring the whole chip spends the reader’s alarm on “Special Collection”. .blocking is reserved for flags that literally instruct people to stop.

Editorial Office Started Looking for an AEAE is a maybeAE agreedQuery out with AE/Reviewer/AuthorPossible Desk Reject by AEBlocker Issue — Don't Move ForwardSensitive Subject — Needs EB ReviewSpecial Collection
<span class="flag-chip" style="--flag-color:#1966d2"> <span class="material-symbols-outlined" aria-hidden="true">search</span> <span>Editorial Office Started Looking for an AE</span> </span>
Header group

Classes: .ms-flag-chip wrapping .ms-flag-prefix, .flag-chip-group and .flag-edit-btn. Sits with the manuscript ID and type badges, not in the status row — a flag labels the manuscript, it isn’t a stage of it. The empty state is an add control, not the words “No flags”: the control must exist when there are none, or the first flag is unaddable.

Flags AE is a maybe Blocker
Queue row

The hard case: a row has space for one flag and may hold many. Show the first with its label, the rest icon-only, collapse past three into .q-flag-more. Order the set so blocking flags come first — if a manuscript is blocked, truncation must never be what hides it. Never wrap: a row that grows a second line when someone adds a flag makes every row below it jump.

Blocker +1

Required on every icon-only chip: role="img" plus an aria-label carrying the full label, and aria-hidden on the icon span. Material Symbols render from ligature text, so without both a screen reader announces the glyph name (“mail”) instead of the flag. The +N chip needs an aria-label naming what it hides.

Edit rail

Flags are shared office state, so editing is batched behind an explicit Save rather than committed per click — a half-made selection should not reach another editor mid-click, and Cancel has to mean cancel. Save stays disabled until the draft differs from what is stored. The opt-out is a radio outside the checkbox list, mirroring legacy’s DO_NOT_CONSIDER_MS_FLAG; it is not one of the flags. A label search is required once a journal configures more than about ten. Classes: .flag-selected, .flag-search, .flag-unflag, .flag-list, .flag-row, .flag-rail-footer.

Selected (1)
AE is a maybe
Standard flags

26. Page Background & Page Header

The surface every full-page view sits on. Token: --gradient-page. Applied by components/gateway-shell.css to .content-area, so a page gets it by doing nothing — a page that sets its own .content-area background is opting out, and should say so in a comment.

background: var(--gradient-page); background-attachment: fixed;

background-attachment: fixed is part of the pattern, not decoration: it holds the gradient still while content scrolls. Without it the gradient travels with the page and the colour under the header shifts as you move.

Page header — a white card

This is the part that keeps getting re-decided, so it is settled here. A page title goes in a white card (.gw-page-header), never as text placed straight onto the gradient. Dark text directly on this background is unreadable (#111 on #2d1b4e), and light text is fragile because the gradient runs from dark purple to mid teal — contrast changes across the width of the screen. A card sidesteps both, and it is what the Editor dashboard has always done.

Assignment & workload

Who is holding what, and where the load is uneven.

<div class="gw-page-header"> <h1>Assignment &amp; workload</h1> <p>Who is holding what, and where the load is uneven.</p> </div>
Opting out

A page that genuinely wants a flat surface uses .gw-page-bg-flat rather than hardcoding a colour, so the decision reads as deliberate instead of looking like an oversight.

← Prototype Hub