v8.0 Updated May 2026

GFS Design System

Design tokens, component specs, and patterns for Global Food Solutions' internal operations dashboards. Flat design, corporate blue palette, Lucide icons.

Brand Mark & Logo
All approved logo forms for Global Food Solutions. Click any SVG to copy. Never modify, stretch, recolor, or add effects to these marks.
Logo Forms
Primary Icon Mark — Globe
Size Renders
Double Ring Globe at every standard size
64px
48px
32px
28px nav
24px sidebar
16px favicon
Wordmark Lockup
Global Food Solutions
Food Distribution & Manufacturing
Global Food Solutions
Food Distribution & Manufacturing
Buddy Mascot — Chat FAB
The GFS Buddy replaces the generic "?" on the chat floating action button. A friendly blue sphere with two white oval eyes.
Buddy at all sizes
52px FAB
52px on white
36px compact
24px inline
PropertySpec
ShapeCircle with radial gradient: #5B9EF4 center → #1A5799 edge
EyesTwo white ellipses: rx="3.5" ry="5", y=24 (slightly above center)
Inner ringrgba(255,255,255,.15), 1px stroke, r=23
FAB size52px, fixed bottom-right (24px inset)
Shadow0 4px 16px rgba(9,47,100,.3)
Hovertransform: scale(1.08)
UseAI chat trigger only — not a generic icon
Usage Rules
RuleSpec
Minimum icon size24px — never render smaller
Minimum wordmark width140px
Clear spaceMinimum padding = icon height × 0.5 on all sides
Approved backgroundsNavy (#092F64), White (#FFF), Page grey (#F7F7F8)
Icon on dark bgTranslucent rect fill: rgba(255,255,255,.1)
Icon on light bgSolid navy rect fill: #092F64
Favicon32×32 icon mark with navy background
Do
  • Use the exact SVG provided — copy from this page
  • Maintain the globe proportions and line weights
  • Use on navy, white, or light grey backgrounds only
  • Include the wordmark when space permits (>140px)
Don’t
  • Stretch, skew, or rotate the mark
  • Change the globe stroke colors or line weights
  • Place on busy backgrounds or photos
  • Add drop shadows, glows, or gradients
  • Recreate in a different style


Photography & Imagery
GFS dashboards are data-first. No decorative images, no stock photography, no clip art.
ContextRule
DashboardsData only — charts, tables, KPIs. No decorative imagery.
Product photosWhite background, consistent lighting, no props. Square crop.
Team headshotsProfessional only. Solid navy (#092F64) or white background. Square crop, 200×200px min.
Screenshots2× resolution, crop to content, include browser frame if showing a full page.
Logos (partners)SVG preferred. On white background. Never stretch or recolor.
Do
  • Use inline SVG illustrations for empty states (from the Empty States section)
  • Use Lucide icons for all iconography
  • Use the GFS globe mark for branding contexts
  • Screenshot at 2× and compress before embedding
Don’t
  • Use stock photography anywhere in dashboards
  • Use clip art, cartoon illustrations, or emoji as visual elements
  • Embed large raster images — SVG or CSS-only always
  • Use background images or hero photos on dashboard pages

Voice & Tone
How GFS dashboards speak. Factual, professional, concise. Every label, message, and description follows these rules.
Tone Principles
PrincipleExample
State facts, don’t sell"Revenue increased 12.3% vs last month" — not "Great news! Revenue is up!"
Be direct"3 orders past due" — not "It looks like some orders might need attention"
No exclamation marks"Report generated." — not "Report generated!"
No casual language"Failed to load data." — not "Oops! Something went wrong."
Use active voice"Export completed" — not "The export has been completed"
Be specific"NetSuite connection timed out after 30s" — not "Something went wrong"
Button Labels
LabelUse WhenNever Use
SavePersisting a draft or changes"Save Changes" (redundant)
SubmitSending for approval or processing"Send In"
ConfirmAcknowledging a destructive or irreversible action"Yes" / "OK"
CancelDismissing a modal or abandoning an action"Never Mind" / "Go Back"
DeletePermanently removing a record"Remove" (too soft for permanent actions)
ExportDownloading data as CSV/PDF"Download" (ambiguous)
CopyCopying text/table to clipboard"Copy to Clipboard" (too long)
RetryRe-attempting a failed operation"Try Again"
CloseClosing a panel or detail view"X" without label (needs accessible text)
Error Messages
ScenarioStandard Message
Data fetch failed"Failed to load data. Check your connection and retry."
NetSuite timeout"NetSuite connection timed out. Retry or try again later."
No permission"You don’t have permission to view this. Contact your admin."
Record not found"Record not found. It may have been deleted or moved."
Validation error"[Field name] is required." or "[Field name] must be a number."
No results"No records found. Try adjusting your filters."
Save failed"Failed to save. Your changes have not been lost — retry."
KPI Label Conventions
RuleExample
Always uppercaseRevenue MTD
Use standard abbreviationsMTD, YTD, QTD, WoW, MoM, YoY
Spell out when ambiguous"Open Orders" not "OO" — "Past Due" not "PD"
Max 3 words"Revenue MTD" not "Total Monthly Revenue to Date"
No units in labelShow units in the value: "$124K" not label: "Revenue ($)"
Do
  • "Report generated successfully."
  • "3 orders past due."
  • "No inventory records found."
  • "Copied to clipboard."
Don’t
  • "Yay! Your report is ready!"
  • "Uh oh, looks like some orders need attention!"
  • "Oops! We couldn’t find any inventory."
  • "Awesome! Copied!"

Naming Conventions
Consistent naming across every file, class, variable, and page title. No exceptions.
ContextConventionExample
HTML fileskebab-case.htmlcustomer-dashboard.html
CSS fileskebab-case.cssgfs-components.css
JS fileskebab-case.jsgfs-init.js
CSS classes.gfs- prefix, kebab-case.gfs-kpi-strip
CSS variables-- prefix, kebab-case--primary-dark
HTML IDskebab-caseid="revenue-kpi"
JS variablescamelCaseorderCount
JS constantsUPPER_SNAKEGFS_COLORS
JS functionscamelCase, verb-firstcopyTable(), formatCurrency()
Page titlesPage Name — GFS<title>Inventory — GFS</title>
Dashboard files[subject]-dashboard.htmlar-aging-dashboard.html
Report files[subject]-report.htmlmonthly-sales-report.html
Data attributeskebab-casedata-copy-label, data-countup
Page titles always use an em dash (—), not a hyphen (-). Example: Inventory — GFS
Color Palette
Five brand blues, five neutrals, five surfaces, and four semantic status colors. The brand palette stays consistent across light and dark modes.
Brand Blues
Cool Black
--primary-dark
Cobalt Blue
--primary
Tufts Blue
--primary-mid
Jordy Blue
--primary-light
Alice Blue
--primary-bg
Text Colors
Near Black
Header bar title
Eerie Black
--text-heading, --text-body
Steel Blue Grey
--text-secondary
Slate Grey
--text-muted
Muted Grey
--text-faint
Surfaces & Borders
White
--bg-card
Page Background
--bg-page
Sunken
--bg-sunken
Hover
--bg-hover
Active / Border
--bg-active, --border-light
Card Border
--border
Semantic Status — 8 Statuses, 3 Tokens Each
Each status has three tokens: --status (vibrant, for icons/dots), --status-text (darker, for text on bg), --status-bg (light, for backgrounds).
Success
--success
Success Text
--success-text
Success BG
--success-bg
Warning
--warning
Warning Text
--warning-text
Warning BG
--warning-bg
Danger
--danger
Danger Text
--danger-text
Danger BG
--danger-bg
Info
--info
Info Text
--info-text
Info BG
--info-bg
Purple
--purple
Purple Text
--purple-text
Purple BG
--purple-bg
Neutral
--neutral
Neutral Text
--neutral-text
Neutral BG
--neutral-bg
Teal
--teal
Teal Text
--teal-text
Teal BG
--teal-bg
Orange
--orange
Orange Text
--orange-text
Orange BG
--orange-bg
Typography
Inter for all UI text, JetBrains Mono for code. Both open-source via Google Fonts. Renders identically across every OS — no more platform-dependent font differences.
Font Stacks
Body — Inter
'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif
Loaded via Google Fonts CDN. Weights: 400, 500, 600, 700. Feature settings: cv01, cv02.
Monospace — JetBrains Mono
'JetBrains Mono', 'SF Mono', 'Fira Code', 'Consolas', monospace
Loaded via Google Fonts CDN. Weights: 400, 500, 600. Used for code blocks, hex values, and data.
HTML
<!-- Add to <head> — required for all GFS builds -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
Font Features
FeatureCSSEffect
Alternate glyphsfont-feature-settings: 'cv01', 'cv02'Cleaner a, g, and l letterforms
Tabular numbersfont-variant-numeric: tabular-numsFixed-width digits — columns align in tables and KPIs
Slashed zerofont-feature-settings: 'zero'Distinguishes 0 from O — use in code/data contexts
Type Scale — Live Samples
Page Title16px / 600 / #111111
Card Heading (h2)15px / 600 / #1F1F1F
Nav Item — Default14px / 400 / #4B5F7A
Nav Item — Active14px / 500 / #1F1F1F
Body text reads like this. Clean, comfortable, and easy to scan at 15px.15px / 400 / #1F1F1F
Section Label13px / 600 / #111111
Caption / Meta text12px / 500 / #6B7280
Table Header / Nav Group11px / 600 / uppercase
$124,50024px / 700 — KPI value
KPI Label11px / 500 / #888888
ElementSize / WeightDetails
Page Title16px / 600Color #111111, letter-spacing -.2px
Card Heading (h2)15px / 600Color #1F1F1F, border-bottom 1px #EBEBEB
Section Label13px / 600Color #111111, regular case
Nav Item14px / 400Color #4B5F7A, active: 500 / #1F1F1F
Nav Group Label11px / 500Color #8E8EA0, uppercase, letter-spacing .5px
Body Text15px / 400Color #1F1F1F, line-height 1.5
Table Cell14px / 400Color #1F1F1F
Table Header11px / 600Color #6B7280, uppercase, letter-spacing .5px
Caption / Meta12px / 500Color #6B7280
Badge / Micro10px / 600Uppercase optional, border-radius 8px
KPI Label11px / 500Color #888888, uppercase, letter-spacing .5px
KPI Value24px / 700Color #092F64, or var(--danger) for negative
Monospace / Skill13px / 600Font: SF Mono/Fira Code/Consolas
Spacing
4px base grid. All spacing values are multiples of 4. Consistent padding and gaps create visual rhythm.
Scale
4px
Tight gaps, icon spacing
8px
Button/action gap, sidebar nav padding, grid gap (small)
12px
Grid gap, nav item horizontal padding, card gap
16px
Card margin-bottom, KPI padding, sidebar header/footer padding
20px
Card vertical padding, card content indent
24px
Card horizontal padding, main content top padding
32px
Main content side padding
48px
Main content bottom padding
Layout Constants
TokenValueUsage
Sidebar width260pxFixed sidebar on desktop
Main max-width960pxContent area cap
Card padding20px 24pxAll .card elements
Card margin-bottom16pxBetween stacked cards
Grid gap12pxDashboard grids, card grids
Nav item padding8px 12pxSidebar navigation items
Nav item min-height36pxDesktop; 44px on touch
KPI card padding16pxDashboard KPI strip cells
Main content padding24px 32px 48pxmain element
Border Radius
Radius Tokens
6px
Buttons, inputs, badges
8px
Nav items, shortcuts, quick-ref
10px
Cards, KPIs (--radius)
12px
Blog posts, brand cards
20px
Filter pills
50%
Avatars, chat bubble
Shadows
GFS uses a flat design. Cards and surfaces have no box-shadow. Shadows are reserved for floating elements only: modals, chat panel, tooltips. When needed, shadows use a navy tint.
Cards
box-shadow: none
Border only
Floating SM
--shadow-md
Dropdowns, org details
Floating LG
0 8px 32px .12
Chat panel, modals
Chat Bubble
0 4px 16px .30
FAB button only
CSS
/* All shadows use navy tint — rgba(9,47,100, X) */
--shadow: none; /* cards, surfaces */
--shadow-md: 0 4px 16px rgba(9,47,100, .08); /* floating elements */
--shadow-lg: 0 8px 32px rgba(9,47,100, .12); /* modals, chat panel */
Components
Live component previews with specs. Every component in the hub is built from these primitives.
Buttons
Variants
VariantBackgroundTextBorderUse
Primary#1A5799#fffnoneMain CTAs, form submits
Dark#111111#fffnoneCopy buttons, secondary CTAs
Secondary#FFFFFF#1F1F1F1px #E5E5E5Cancel, alternate actions
Ghosttransparent#1A5799noneInline links styled as buttons
Dangervar(--danger)#fffnoneDelete, destructive actions
Successvar(--success)#fffnoneConfirm, notify
CSS
padding: 8px 16px;
border-radius: 6px; /* 20px for pill variant */
font-size: 13px;
font-weight: 600;
Badges & Status Pills
Status Badges
Active Info Pending Overdue Compliance Production Urgent Default
Category Tags (Blog/News)
Company Policy Customer Product Team Ops
CSS
font-size: 10px;
font-weight: 600;
padding: 2px 8px;
border-radius: 8px; /* 10px for category tags */
Cards

Standard Card

Content sits inside white cards with 1px borders. No shadows. Hover shifts border from #E5E5E5 to #D0D0D0. That's it.

Collapsible Card (collapsed)

Collapsible Card (expanded)

Card body content appears when expanded. The + toggles to −.

PropertyValue
Background#FFFFFF
Border1px solid #E5E5E5
Border Radius10px
Shadownone
Padding20px 24px (collapsed: 14px 24px)
Hoverborder-color: #D0D0D0
h2 inside15px / 600 with 1px bottom border #EBEBEB
KPI Cards
Dashboard KPI Strip
Revenue MTD
$124,500
Cases Today
312
Open Orders
47
AR Past Due
$18,200
Data Tables
Standard Table
NameRoleEmailStatus
Michael LevineCEOmikelevine@globalfoodsolutions.coActive
Martin BakerVP of Salesmartin@globalfoodsolutions.coActive
Sydney LanghornDir. Food SafetyTBDPending
CSS
font-size: 14px; /* table body */
thead th { font-size: 11px; text-transform: uppercase; background: #FAFAFA; }
tbody td { border-bottom: 1px solid #F0F0F0; }
tbody tr:hover { background: #FAFAFA; }
Alert Banners
Four Severity Levels
Connected to NetSuite for live analytics data.
Report generated and downloaded successfully.
SQF audit due in 14 days. Contact Sydney to prepare.
AR past due over 90 days: Gold Star Foods — $12,400.
Form Inputs
Text Input, Select, Search
CSS
padding: 8px 14px;
border: 1px solid #E5E5E5;
border-radius: 8px;
font-size: 13px;
:focus { border-color: #468BE6; }
File List Items
Document Row
XLS
Customer Setup Form
Complete form with payment terms and contacts
PDF
W-9 Tax Form
Current W-9 with EIN
Quick Reference Cards
Info Cards
EIN
81-3488877
DUNS
080593910
SQF Certified
Level 2
Food Safety Code for Manufacturing
FDA Registration
Active registration on file
KPI Patterns
Standardized KPI card layouts for all dashboards. Every financial, operational, and status dashboard follows these patterns.
Basic KPI Strip
4-Column — Default Dashboard Layout
Revenue MTD
$124,500
Cases Today
312
Open Orders
47
AR Past Due
$18,200
KPI with Trend Indicator
Trend arrows show period-over-period change
Revenue MTD
$124,500
12.3% vs last month
Cases Shipped
1,847
3.1% vs last month
Avg Order Value
$2,649
No change
Past Due AR
$18,200
8.5% worse
KPI with Icon Container
Icon box variant — use for overview/hero dashboards
Revenue MTD
$124,500
12.3%
Cases Today
312
5.2%
Past Due
$18,200
8.5%
Grid Layouts
LayoutCSSUse Case
3-Columnrepeat(3, minmax(0,1fr))Hero KPIs with icon containers
4-Columnrepeat(4, minmax(0,1fr))Default dashboard strip
6-Columnrepeat(6, minmax(0,1fr))Dense overview strips
Auto-fitrepeat(auto-fit, minmax(160px, 1fr))Responsive KPI grids
Always use minmax(0,1fr) — never plain 1fr. Long KPI values push columns wider with plain 1fr.
KPI Spec
PropertyValue
Card padding16px (centered) or 16px 20px (icon variant)
Value font24px / 700 (default) or 20-22px / 700 (icon variant)
Value colorvar(--primary-dark) or var(--danger) for negative
Label font11px / 500 / uppercase / letter-spacing .5px
Label color#888888 (var(--text-label))
Trend font11px / 600
Trend up colorvar(--success) #10B981
Trend down colorvar(--danger) #EF4444
Trend flat colorvar(--text-muted) #6B7280
Icon box40-44px square, 10px radius, semantic bg
Grid gap12px
Mobile (768px)4-col → 2-col, 6-col → 2-col
Mobile (380px)All → 1-col
CSS
/* Trend indicator */
.kpi-trend {
  display: inline-flex; align-items: center; gap: 3px;
  font-size: 11px; font-weight: 600; margin-top: 4px;
}
.kpi-trend.up { color: var(--success); }
.kpi-trend.down { color: var(--danger); }
.kpi-trend.flat { color: var(--text-muted); }

/* Icon container */
.kpi-icon-box {
  width: 44px; height: 44px; border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
Data Table Standards
Every data table across all GFS dashboards follows these exact patterns. Consistent row heights, alignment, and interaction.
Standard Table
Default data table with formatting rules applied
Customer Status Cases ▼ Revenue Balance
Gold Star Foods Active 1,247 $87,320 ($12,400)
Dawn Foods Active 834 $54,100 $0
Acme Distribution Pending 0 $0
Formatting Rules
RuleSpec
Row height (min)44px — comfortable click target
Cell padding10px 12px
Numeric columnstext-align: right; font-family: var(--font-mono); font-size: 13px
Negative numbersParentheses + color: var(--danger) — e.g. ($12,400)
CurrencyAlways include $ prefix, comma-separated thousands
PercentagesOne decimal place: 12.3%
DatesMay 11, 2026 (full) or 05/11/26 (compact)
Empty cellsUse (em dash), never leave blank
Sortable headerAdd or after active sort column
First columnfont-weight: 500 — primary identifier
Row hoverbackground: #FAFAFA
Row borderborder-bottom: 1px solid #F0F0F0
Copy buttonTop-right of table card, Dark variant, 11px
Empty Table State
When query returns zero rows
CustomerStatusRevenue
No records found
Try adjusting your filters or search terms.
Copy-to-Clipboard Standard
All data tables and text blocks include a copy button. Follow this exact pattern.
PropertySpec
Button styleDark variant (bg: #111; color: #fff), 11-12px font
Button positionTop-right of card, absolutely positioned or inline
Icon<i data-lucide="copy"> at 12-14px, left of label
Default labelCopy or Copy Table
Success labelCopied! with bg: var(--success)
Success duration1.5 seconds, then revert
Table copy formatTab-delimited text (pastes into Excel/Sheets)
Text copy formatPlain text, preserving line breaks
Copy button states
→ reverts after 1.5s
JS
/* Standard copy-to-clipboard function */
function copyTable(tableEl, btn) {
  const rows = [...tableEl.querySelectorAll('tr')];
  const text = rows.map(r =>
    [...r.cells].map(c => c.textContent.trim()).join('\t')
  ).join('\n');
  navigator.clipboard.writeText(text);
  btn.innerHTML = '<i data-lucide="check"></i> Copied!';
  btn.style.background = 'var(--success)';
  setTimeout(() => {
    btn.innerHTML = '<i data-lucide="copy"></i> Copy';
    btn.style.background = '#111';
    lucide.createIcons();
  }, 1500);
}
Summary / Totals Row
Bold bottom row with column totals
CustomerCasesRevenue
Gold Star Foods1,247$87,320
Dawn Foods834$54,100
Total 2,081 $141,420
Grouped Rows
Rows grouped by category with section headers
ItemCasesRevenue
Cheese (3 items)
Barrel Cheddar 40lb420$38,200
Mozzarella Block310$22,400
Dairy (2 items)
Heavy Cream 36%180$12,600
Expandable Detail Row
Click row to reveal detail panel beneath it
OrderCustomerTotal
SO-4821Gold Star Foods$12,400
Ship Date
May 14, 2026
Items
4 line items
Status
Pending Fulfillment
SO-4820Dawn Foods$8,200
Row Status Highlighting
Entire row tinted for overdue / critical / attention
OrderDue DateStatusAmount
SO-4821May 14, 2026Fulfilled$12,400
SO-4819May 8, 2026Due Tomorrow$6,200
SO-4815May 2, 2026Past Due$18,400
Action Column
Last column with icon action buttons
CustomerStatusRevenueActions
Gold Star Foods Active $87,320
Pagination
Below table — count + prev/next controls
Showing 1–25 of 312
Density Modes
Compact vs Comfortable (default) vs Spacious
Compact (4px 8px)
Name
Gold Star
Dawn Foods
Sysco NE
Comfortable (default)
Name
Gold Star
Dawn Foods
Sysco NE
Spacious (14px)
Name
Gold Star
Dawn Foods
Sysco NE
ModeCell PaddingFontUse Case
Compact4px 8px12px50+ rows, data-dense reports, print
Comfortable10px 12px14pxDefault for all dashboards
Spacious14px14pxDetail views, <10 rows, executive
Striped Rows & Clickable Rows
CSS
/* Striped — use on 20+ row tables */
table.striped tbody tr:nth-child(even) { background: var(--bg-sunken); }
table.striped tbody tr:nth-child(even):hover { background: var(--bg-hover); }

/* Clickable rows — navigates to detail view */
tr.clickable { cursor: pointer; transition: background .15s; }
tr.clickable:hover { background: var(--primary-bg-hover); }
tr.clickable td:first-child { color: var(--primary); }
Column Alignment Reference
Data TypeAlignFont
Names / textleftBody, 500 weight first col
CurrencyrightMono, tabular-nums
Counts / qtyrightMono, tabular-nums
PercentagesrightMono, tabular-nums
DatesleftBody, 12px
Status badgesleftBadge component
Email / linksleftcolor: var(--primary)
ActionsrightIcon buttons, 14px
Checkboxescenter18px checkbox

Data Visualization
Chart standards for all GFS dashboards. Every chart uses the brand blue sequence for series data, with semantic colors reserved for status indicators only.
Chart Color Sequence
Use colors in this exact order for multi-series data. Never skip or reorder.
Series Colors — In Order
#092F64
#1A5799
#468BE6
#93BFEF
#E9F5FF
OrderColorTokenUse
1st series#092F64--primary-darkPrimary / dominant data
2nd series#1A5799--primarySecondary comparison
3rd series#468BE6--primary-midTertiary
4th series#93BFEF--primary-lightQuaternary
5th series#E9F5FF--primary-bgFill / area charts
Positive delta#10B981--successGains, growth, target met
Negative delta#EF4444--dangerLosses, decline, target missed
Bar Chart
Vertical Bar — Monthly Revenue
$0 $50K $100K Jan Feb Mar Apr May Jun
Sparkline
Inline KPI Trend — 32px height, no axes
Revenue +12.3%
AR Aging +8.5%
Donut Chart
Category Breakdown — 120px diameter
72% Cheese
Cheese — 50%
Dairy — 25%
Frozen — 15%
Other — 10%
Progress / Gauge Bars
USDA Drawdown, Order Fulfillment, Compliance Scores
USDA Drawdown68,400 / 100,000 lbs
Order Fulfillment94%
SQF ScoreBelow Target
Chart Spec
ElementSpec
Axis labels11px / 500 / var(--text-muted) — Inter, tabular-nums
Grid lines1px solid var(--border-row) — dashed for horizontal guides
Bar radius3px top corners
Bar gap~15px between bars
TooltipDark bg (#1F1F1F), white text, 12px, 6px radius — same as map tooltip
Sparklineheight: 32px; stroke-width: 1.5; stroke-linecap: round — no axes
Progress bar height8px, border-radius: 4px
Progress bar trackvar(--bg-hover)
Donut strokestroke-width: 16 on r=50 circle
Legend dot10px square, 2px radius
Chart containerInside .ds-card-demo with standard card padding
Grouped Bar Chart
Month-over-Month Comparison
$0 $50K $100K Q1 Q2 Q3 Q4 2025 2026
Stacked Bar Chart
Revenue by Category — Stacked
Jan Feb Mar Apr Cheese Dairy Frozen
Horizontal Bar Chart
Top Customers by Revenue — Ranked
Gold Star Foods
$87.3K
Dawn Foods
$54.1K
Sysco Northeast
$38.2K
Ace Endico
$24.8K
Area Chart
Cumulative Revenue — Filled Area
$0 $250K $500K Jan Mar May Jul
Gauge / Radial Progress
Circular KPI — SQF Score, Fulfillment Rate, Drawdown %
94 SQF Score
68% Drawdown
42% Fill Rate
ElementSpec
Gauge size100px default, 80px compact
Trackstroke-width: 8; stroke: var(--bg-hover)
Fillstroke-width: 8; stroke-linecap: round
Fill circumference2 × π × r = 251 (r=40). Set stroke-dasharray: [value] 251
Color rules>80%: --success, 50-80%: --primary, <50%: --danger
Center text20px / 700 value + 9px label below
Grouped bar widthEach bar 18px, gap 2px between paired bars
Stacked barNo gap between segments, no border-radius on internal joins
Horizontal bar height20px, track: var(--bg-hover), radius 3px
Area fill--primary-bg (#E9F5FF) with --primary stroke line
Area dotsr=3, same color as line stroke
Production Charting — Chart.js
The SVG examples above define the visual spec. For production dashboards, use Chart.js via CDN. It renders to <canvas>, handles responsive sizing, tooltips, and animation automatically.
HTML
<!-- Add to <head> or end of <body> -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
JS
/* GFS Chart.js branded defaults — apply once at page load */
Chart.defaults.font.family = "'Inter', sans-serif";
Chart.defaults.font.size = 11;
Chart.defaults.color = '#6B7280'; /* axis labels */
Chart.defaults.borderColor = '#F0F0F0'; /* grid lines */
Chart.defaults.plugins.legend.labels.usePointStyle = true;
Chart.defaults.plugins.legend.labels.pointStyleWidth = 8;
Chart.defaults.plugins.tooltip.backgroundColor = '#1F1F1F';
Chart.defaults.plugins.tooltip.titleFont = { weight: 600 };
Chart.defaults.plugins.tooltip.cornerRadius = 6;
Chart.defaults.plugins.tooltip.padding = 8;
Chart.defaults.elements.bar.borderRadius = 3;
Chart.defaults.elements.line.tension = 0.3;
Chart.defaults.elements.point.radius = 3;
Chart.defaults.scale.grid.color = '#F0F0F0';

/* GFS brand color sequence for datasets */
const GFS_COLORS = [
  '#092F64', '#1A5799', '#468BE6',
  '#93BFEF', '#E9F5FF'
];
PropertyGFS Default
FontInter, 11px, #6B7280
Grid lines#F0F0F0 (matches --border-row)
Tooltip#1F1F1F bg, 6px radius, 8px padding
Bar radius3px top corners
Line tension0.3 (subtle curve, not angular)
Point radius3px
LegendPoint style (dots not rectangles)
Color sequenceGFS_COLORS array (5 brand blues)

Number & Date Formatting
Canonical formatting rules for every data type displayed across GFS dashboards. All numeric contexts require font-variant-numeric: tabular-nums.
Currency
ContextFormatExample
Full precision$ + commas + 2 decimals$124,500.00
Rounded (tables)$ + commas, no decimals$124,500
Abbreviated (KPIs)$ + 1 decimal + K/M suffix$124.5K or $1.2M
NegativeParentheses + danger color($12,400)
Zero$0 (never blank)$0
Quantities & Units
TypeFormatExample
CasesNumber + cs1,247 cs
WeightNumber + lbs68,400 lbs
PalletsNumber + plt24 plt
TemperatureNumber + °F38.5°F
Percentage1 decimal (whole = no decimal)12.3% or 100%
Large numbersK at 10,000+, M at 1,000,000+12.5K / 1.2M
Count (plain)Comma-separated1,247
Empty / no dataEm dash
Dates & Times
ContextFormatExample
Full dateMon DD, YYYYMay 11, 2026
Compact dateMM/DD/YY05/11/26
ISO dateYYYY-MM-DD2026-05-11
Date rangeEn dash, shared yearMay 1 – May 31, 2026
Time12-hour + AM/PM2:30 PM
Time + zone12-hour + timezone2:30 PM EST
Relative (recent)Natural language2 hours ago
Relative (older)Switch to full dateAfter 7 days, use May 4, 2026
Identifiers
TypeFormatFontExample
Phone(XXX) XXX-XXXXBody(631) 254-0001
EINXX-XXXXXXXMono81-3488877
Lot numberAs-isMonoLOT-2026-0511A
PO/SO numberAs-is from NetSuiteMonoPO-4821
EmailLowercase, linkedBodymike@globalfoodsolutions.co

Dashboard Patterns
Interaction patterns used across all GFS dashboards: time filters, data refresh, bulk actions, responsive tables, tooltips, modals, exports, and sorting.
Time Range Selector
Date filter — appears top-right of every dashboard
PropertySpec
StyleSame as filter pills: 5px 12px, 20px radius, 12px / 500
Active statebg: var(--primary); color: #fff
Default options7 Days, 30 Days, 90 Days, YTD, Custom
PositionTop-right of dashboard header, inline with page title
Custom pickerTwo date inputs appearing on "Custom" click
Data Refresh Indicator
Shows data freshness — required on all NetSuite-connected dashboards
Live — Updated 2 min ago
Stale — Updated 15 min ago
Error — Failed to refresh
StateDotTextThreshold
Livevar(--success)var(--text-muted)< 5 minutes
Stalevar(--warning)var(--warning-text)5 – 30 minutes
Errorvar(--danger)var(--danger-text)Failed or > 30 min
Bulk Action Toolbar
Appears when table rows are selected
3 selected
PropertySpec
Backgroundvar(--primary-dark) #092F64
PositionSticky top of table card, replaces table header
Left sideCheckbox + count: "3 selected"
Right sideAction buttons: Export, Print, Delete (destructive last, red bg)
Button stylergba(255,255,255,.12) bg, white text, 12px
Destructive buttonrgba(239,68,68,.8) bg
TransitionSlide down .2s ease when first row selected
Responsive Table
Tables on mobile (<768px): horizontal scroll with sticky first column. Never collapse to card layout unless the table has <4 columns.
CSS
.table-responsive {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.table-responsive td:first-child,
.table-responsive th:first-child {
  position: sticky;
  left: 0;
  background: var(--bg-card);
  z-index: 1;
  border-right: 1px solid var(--border);
}
Tooltip
Hover tooltips for truncated text, icons, chart data points
Hover me
Tooltip text here
PropertySpec
Background#1F1F1F
Text#fff, 11px, 400
Padding5px 10px
Radius5px
Arrow4px CSS triangle
Offset6px from trigger element
Delay300ms before showing, immediate hide
Max width240px, wrap long text
Modal / Dialog
Confirmation dialog — appears centered with backdrop overlay
Delete 3 orders?
This action cannot be undone. The selected sales orders will be permanently removed from NetSuite.
PropertySpec
Backdroprgba(0,0,0,.3)
Cardbg-card, 12px radius, shadow-lg
Max widthSmall: 400px, Medium: 560px, Large: 720px
Padding24px
Title16px / 600
Body13px / var(--text-muted)
ActionsRight-aligned, primary action last, destructive = danger btn
CloseEscape key, backdrop click, or Cancel button
Notification Badge
Count badge on nav items and icons
3
12
VariantSpec
Count badgebg: var(--danger); color: #fff; 9px/700; min-width: 16px; height: 16px; border-radius: 8px
Dot (no count)width: 8px; height: 8px; border-radius: 50%; bg: var(--danger)
Positionabsolute; top: -4px; right: -6px
Max countDisplay 99+ for counts over 99
Data Export Dropdown
Export button with format options
Export CSV
Export PDF
Copy to Clipboard
Sortable Table Headers
Click column header to sort — active column shows arrow
Customer Revenue ▼ Cases Status
Gold Star Foods$87,3201,247Active
Dawn Foods$54,100834Active
StateSpec
Default headercursor: pointer; color: var(--text-muted)
Active sort (asc)color: var(--primary) + after text
Active sort (desc)color: var(--primary) + after text
Hovercolor: var(--text-heading)
Text Wrapping & Overflow
Rules for when text wraps, when it truncates, and how to handle long strings like URLs, lot numbers, and descriptions.
Wrap vs Truncate — Live Examples
Wrapped (default for body text)
Global Food Solutions Customer Onboarding — New Account Setup and Payment Terms Configuration for Northeast Distribution Partners
Truncated (constrained spaces)
Global Food Solutions Customer Onboarding — New Account Setup and Payment Terms Configuration for Northeast Distribution Partners
Multi-Line Clamp (2 lines)
This description wraps to two lines maximum and then truncates with an ellipsis. It's used for card descriptions, timeline post previews, and table cell descriptions where space is limited but context matters more than a single-line truncation would provide.
Word Break — Long Strings Without Spaces
Without word-break (overflows)
LOT-2026-0511A-BONGARDS-BARRELCHEDDAR-40LB-USDA-COMMODITY
With word-break (wraps cleanly)
LOT-2026-0511A-BONGARDS-BARRELCHEDDAR-40LB-USDA-COMMODITY
When to Wrap vs Truncate
ContextBehaviorWhy
Card body textWrapUsers need full context in cards
Card descriptions (compact)Clamp at 2 linesPreserves card height consistency
Table cells (text)Wrap (default) or truncate with max-widthDepends on column importance
Table cells (names)Never truncate — let column growNames are identifiers, cutting them breaks usability
Table cells (descriptions)Clamp at 2 lines with tooltipKeeps rows consistent height
Nav items / sidebarTruncate single-lineFixed-width container
Badge textNo wrapwhite-space: nowrapBadges are single tokens
KPI labelsNo wrapMust stay on one line
KPI valuesNo wrapNumbers should never break mid-digit
URLs / lot numbers / IDsBreak allword-break: break-allNo natural break points in these strings
Email addressesBreak allLong emails overflow containers
Alert / banner textWrapAlerts need to be fully readable
Tooltip contentWrap at max-width: 240pxTooltips show full text that was truncated
CSS Reference
CSS
/* Single-line truncation */
.truncate {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Multi-line clamp (2 lines) */
.line-clamp-2 {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Break long strings (URLs, lot numbers, IDs) */
.break-all {
  word-break: break-all;
}

/* Break at word boundaries (default for most text) */
.break-word {
  overflow-wrap: break-word;
  word-wrap: break-word;
}

/* No wrap — badges, KPI labels, KPI values */
.nowrap { white-space: nowrap; }
Wrapped Text Line Heights
Contextline-heightWhy
Body text / paragraphs1.5Comfortable reading
Card descriptions1.6Slightly more open for scanability
Table cells1.4Tighter to keep rows compact
Timeline posts1.7Long-form content needs breathing room
Headings (h1-h3)1.2Tight — headings shouldn't look loose when they wrap
KPI labels / badges1Single line, no extra space needed
Code blocks1.7Code needs vertical space between lines
Alerts1.5Match body text

Dashboard Layouts
Full-page composition patterns. Every GFS dashboard follows one of these three layouts. Components from the design system snap into these grids.
Layout A — KPI + Table (most common)
Revenue Dashboard, Inventory Overview, Order Status
Dashboard Title
30d Refresh
Metric 1
$124K
Metric 2
312
Metric 3
47
Metric 4
$18K
Data Table
Layout B — Chart + Table Split
Trend Analysis, Forecasting, Vendor Scorecard
Analytics Dashboard Updated 2 min ago
KPI
$248K
KPI
1,847
KPI
+12%
Chart
Detail Table
Layout C — Multi-Card Grid
Overview Dashboards, Daily Health Check, Finance Summary
Overview
Revenue
$124.5K
Orders
47
Top Customers
Alerts
AR past due: $18.2K
SQF audit in 14 days
Layout Grid Rules
LayoutStructureBest For
A — KPI + Table4-col KPI strip → full-width table cardData-heavy: orders, inventory, AR aging
B — Chart + Table3-col KPI → 3fr chart + 2fr tableAnalysis: trends, forecasts, scorecards
C — Multi-Card2×2 or 3×2 card gridOverview: daily health, executive summary
Timeline & Blog
The Updates tab uses a vertical timeline layout with compose area, posts, comments, and filter bar. One of the most complex component systems in the hub.
Compose Area
Post Composer
What's happening at GFS?
Share an update, announcement, or note...
ElementCSS
.compose-areaborder-radius: 12px; padding: 20px 24px; border: 1px solid var(--gray-200)
.compose-area textareamin-height: 100px; font-size: 15px; border-radius: 8px
.post-btnpadding: 9px 20px; border-radius: 6px; font-size: 13px; font-weight: 600
.post-btn-primarybg: var(--blue); color: #fff
.post-btn-notifybg: var(--green); color: #fff
.post-btn-outlinebg: #fff; border: 1px solid var(--gray-300)
Timeline Post
Blog Post Card
Michael Levine May 11, 2026 Company
Q2 Production Update
Line #2 meal kit production hit 95% efficiency this week. Great work from the team.
Comment (2) Pin Delete
Elena Misoulis • May 9, 2026 POLICY
SQF Audit Prep Reminder
All departments: please complete pre-audit checklists by May 15.
ElementCSS
.timelinepadding-left: 28px with ::before 2px vertical line
.tl-postborder-radius: 12px; border: 1px solid var(--gray-200)
.tl-post::before10px circle, bg var(--blue), positioned -22px left
.tl-post.pinnedborder-left: 3px solid var(--gold); dot = gold
.tl-title16px / 700; color: var(--navy); padding: 0 20px
.tl-body15px / 400; line-height: 1.7; color: var(--gray-700)
.tl-meta12px; flex with author (600) + date (500) + category badge
.tl-action-btn12px / 500; bg: none; hover: bg var(--gray-100)
Comment Thread
Expanded Comments
MB
Martin Baker2 hours ago
Great numbers. Line #3 should hit the same target next week.
ElementCSS
.tl-commentsbg: var(--gray-50); border-top: 1px solid var(--gray-100); padding: 12px 20px
.tl-commentflex; gap: 10px; padding: 8px 0; border-bottom: 1px solid var(--gray-100)
.tl-comment-avatar28px circle; font-size: 11px / 700; color: #fff
.tl-comment-author12px / 600
.tl-comment-date11px; color: var(--gray-500); margin-left: 8px
Filter Bar
Category Filters (pill toggle)
Org Chart
Two views: interactive tree (pan/zoom canvas) and department list (accordion). Both share the same data but render differently.
View Toggle
Segmented Control
CSS
.org-view-toggle { background: var(--gray-100); border-radius: 8px; overflow: hidden; }
.org-view-toggle button.active { background: var(--blue); color: #fff; }
Org Chart Cards (Tree View)
Card Hierarchy
ML
Michael Levine
CEO
Martin Baker
VP of Sales
Richard Gallo
VP of Operations
Ian Lindsay
VP of Logistics
ElementCSS
.oc-cardbg: #fff; border: 1px solid var(--gray-200); border-radius: 10px; width: 170px; padding: 14px 16px
.oc-card.oc-ceowidth: 220px; border: 2px solid var(--blue); background: var(--blue-bg)
.oc-card.oc-smwidth: 155px; padding: 10px 12px (avatar hidden)
.oc-avatar38px circle; font-size: 13px / 700; color: #fff
.oc-name13px / 600; color: var(--navy) (CEO: 15px)
.oc-role11px; color: var(--gray-500)
.oc-linewidth: 2px; background: var(--blue-light)
.oc-detail (expanded)11px; color: var(--gray-600); border-top: 1px solid var(--gray-200)
.oc-dept-label11px / 600; color: #fff; padding: 4px 14px; border-radius: 6px
Department Accordion
Expandable Department Sections
Sales
4
MB
Martin Baker
VP of Sales
DS
Danielle Scibelli
Dir. Customer Service
Operations
12
ElementCSS
.dept-sectionbg: #fff; border: 1px solid var(--gray-200); border-radius: 12px
.dept-headerpadding: 16px 20px; border-left: 4px solid [dept color]
.dept-countbg: var(--gray-100); font-size: 12px / 600; padding: 2px 10px; border-radius: 10px
.dept-chevron15px; rotate(90deg) when .open
.person-cardflex; gap: 14px; padding: 14px 0; border-bottom: 1px solid var(--gray-100)
.p-avatar44px circle; font-size: 16px / 700; color: #fff
.p-name15px / 600; color: var(--navy)
.p-title13px; color: var(--gray-500)
.p-contact a12px; color: var(--blue)
.p-tag10px / 600; padding: 2px 8px; border-radius: 10px
Templates & Generators
Brand Center, letter templates, email signature generator, and form-driven email generators. These use specialized layouts distinct from the rest of the hub.
Brand Selector
Choose Brand Identity
Global Food Solutions
Corporate brand
River Street Brands
Consumer brand
Template Type Buttons
Segmented Template Picker
ElementCSS
.brand-cardborder: 2px solid var(--gray-200); border-radius: 12px; padding: 20px
.brand-card.selectedborder-color: var(--blue); box-shadow: 0 0 0 2px rgba(44,82,130,.2)
.tpl-type-btnpadding: 8px 16px; border: 1px solid var(--gray-200); border-radius: 6px; font-size: 13px / 500
.tpl-type-btn.selectedbg: var(--blue); color: #fff; border-color: var(--blue)
Letter Template Preview
Live Editable Document
Global Food Solutions, Inc.
131 Heartland Blvd
Edgewood, NY 11717
[Date]
[Recipient Name]
[Company]
[Address]
Dear [Name],
Letter body content goes here. All fields are contenteditable — click to type.
ElementCSS
.tpl-previewbg: #fff; border: 1px solid var(--gray-200); border-radius: 8px; box-shadow: var(--shadow-md)
.tpl-pagemax-width: 700px; padding: 40px 50px; font-family: Georgia, serif; font-size: 13px
.tpl-headerborder-bottom: 3px solid #1a2744 (RS brand: #2d6a4f)
.tpl-placeholdercolor: #a0aec0; font-style: italic
[contenteditable]:focusborder-bottom-color: var(--blue); background: #f7faff
.tpl-footerposition: absolute; bottom: 20px; font-size: 10px; color: #999
Letter Selector Grid
Email Template Picker (Templates tab)
Customer Welcome Email
New customer onboarding with payment instructions
Sales
Vendor Setup Request
Request W-9 and payment info from new vendor
Ops
Signature Generator Output
Email Signature Preview
Michael Levine
Chief Executive Officer

Global Food Solutions, Inc.
131 Heartland Blvd, Edgewood, NY 11717
ElementCSS
.sig-outputfont-family: Arial; font-size: 13px; border: 1px dashed var(--gray-300); border-radius: 6px
.sig-name15px / 700; color: var(--navy)
.sig-dividerborder-top: 2px solid var(--navy); width: 60px; margin: 8px 0
.sig-companyfont-weight: 600; color: var(--navy); 13px
.sig-detail12px; color: #555
Form-Driven Email Generator
gen-form + gen-output pattern
Subject: Welcome to Global Food Solutions
Generated email content appears here based on form inputs...
ElementCSS
.gen-formdisplay: grid; grid-template-columns: 1fr 1fr; gap: 12px 16px
.gen-form label12px / 600; uppercase; letter-spacing: .4px; color: var(--gray-500)
.gen-form inputpadding: 9px 12px; border-radius: 6px; font-size: 15px
.gen-outputbg: var(--gray-50); border: 1px solid var(--gray-200); border-radius: 6px; font-size: 13px; line-height: 1.7
.email-templatebg: var(--gray-50); border-radius: 6px; padding: 16px 20px; font-size: 13px; white-space: pre-wrap
.placeholderbackground: #fefcbf; padding: 1px 4px; border-radius: 3px; font-weight: 600
Kanban Board
Admin panel build tracker. Three-column layout with draggable cards and inline actions.
Board Layout
To Do
Employee handbook PDF upload ▶ ✕
PTO calendar visibility
In Progress
NetSuite KPI RESTlet
Done
File split (CSS/JS)
ElementCSS
.kanban-colbg: var(--gray-100); border-radius: 8px; padding: 10px; min-height: 150px
.kanban-cardbg: #fff; border: 1px solid var(--gray-200); border-radius: 6px; padding: 8px 10px; font-size: 12px
.kanban-card:hoverborder-color: var(--blue-mid)
.kb-textfont-weight: 500; line-height: 1.4
.kb-actionsopacity: 0 → 1 on card hover; flex; gap: 2px
.kb-btnbg: none; font-size: 11px; color: var(--gray-500); hover: bg var(--gray-100)
Checklist
HR Onboarding / Training Checklists
  • Complete W-4 and I-9 forms
    Required by end of first day
  • Paychex account setup
    HR creates account, employee completes profile
ElementCSS
.checklist liflex; gap: 10px; padding: 10px 0; border-bottom: 1px solid var(--gray-100); font-size: 15px
checkboxwidth: 18px; height: 18px; accent-color: var(--blue) (22px on touch)
.check-label.checkedtext-decoration: line-through; color: var(--gray-500)
.check-sub12px; color: var(--gray-500); margin-top: 2px
Micro Components
Small utility components used throughout the hub — toast notifications, copyable values, keyboard hints, map tooltips, and action buttons.
Toast Notification
Fixed position, bottom-right
Copied to clipboard
ElementCSS
.toastposition: fixed; bottom: 24px; right: 24px; bg: var(--gray-800); color: #fff; padding: 10px 20px; border-radius: 8px; font-size: 13px / 500; z-index: 200
.toast (hidden)opacity: 0; transform: translateY(8px)
.toast.showopacity: 1; transform: translateY(0); transition: all .2s
Copyable Value
Click-to-copy with tooltip
EIN: 81-3488877click to copy
ElementCSS
.copyablecursor: pointer
.copyable:hovercolor: var(--blue)
.copyable::after"click to copy"; bg: var(--gray-800); font-size: 10px; border-radius: 3px; opacity: 0 → 1 on hover
Keyboard Hint
Shortcut indicator
Search Ctrl+K
CSS
.kbd { padding: 1px 6px; background: var(--gray-100); border: 1px solid var(--gray-300); border-radius: 4px; font-size: 11px; font-family: monospace; }
Map Tooltip
Follows cursor over SVG map states
New York — Active Coverage
ElementCSS
.map-tooltipposition: fixed; bg: var(--gray-800); color: #fff; padding: 6px 12px; border-radius: 6px; font-size: 12px; z-index: 300; pointer-events: none
.map-statetransition: opacity .15s; cursor: pointer
.map-state:hoveropacity: .8
Copy Block Button
Full-width copy action
ElementCSS
.copy-block-btnbg: #111111; color: #fff; padding: 8px 16px; border-radius: 6px; font-size: 12px / 600
.copy-block-btn.copiedbg: var(--green) — auto-reverts after 2s
.copy-btnposition: absolute; top: 12px; right: 12px; bg: #fff; border: 1px solid var(--gray-300); font-size: 12px
.copy-btn.copiedbg: var(--green); color: #fff; border-color: var(--green)
Packet Header
Setup packet header with direction badge
Customer Setup Packet
Outbound
Vendor Information Packet
Inbound
Patterns & Conventions
Repeating layout patterns used across all 26 tabs. Use these exact patterns when adding new sections.
Page Header Pattern
Top of every tab section
Company Info
Header bar shows the tab name, auto-updated by goToTab()
HTML
<!-- Header bar auto-updates -->
<span class="header-title" id="header-title">Company Info</span>
Search + Filter Bar
Used in: Contacts, News, Skills, Employee Directory
CSS
.tl-filter {
  padding: 5px 12px;
  border: 1px solid #E5E5E5;
  border-radius: 20px;
  font-size: 12px; font-weight: 500;
}
.tl-filter.active {
  background: #1A5799; color: #fff;
}
Info Grid
Used in: Company Info, Facility, NetSuite, Suppliers
Legal NameGlobal Food Solutions, Inc. EIN81-3488877 Year Est.2003 OwnershipPrivate — 100% Family Owned Address131 Heartland Blvd, Edgewood, NY 11717
CSS
.info-grid {
  display: grid;
  grid-template-columns: 160px 1fr;
  gap: 6px 16px;
  font-size: 15px;
}
Workflow Steps
Used in: Customer Setup, Vendor Setup
1
Send Packet
2
Receive Docs
3
NetSuite Setup
4
Active
Empty State
Used when no data exists

No items found

Adjust your filters or add a new entry.

Dashboard Two-Column Layout
Quick Actions + Portals pattern (3fr / 2fr split)
Quick Actions (3fr)
Action
Action
Action
Action
Portals (2fr)
Link
Link
Link
Status Board (3-Column)
Used in: Company Calendar status cards
Overdue
Items past their date
Upcoming
Next 90 days
Completed
Past events
Grid Column Patterns
LayoutCSSUsed In
KPI Strip (6 cols)repeat(6, minmax(0,1fr))Dashboard top
Info Bar (4 cols)repeat(4, minmax(0,1fr))Dashboard clock/weather strip
Actions + Portals3fr 2frDashboard mid
Calendar3fr 2frCalendar view + add form
Two Equalminmax(0,1fr) minmax(0,1fr)Agents, Suitelets, Values
Auto-fitrepeat(auto-fit, minmax(200px, 1fr))KPI stats, shortcuts
Critical: Always use minmax(0,1fr) instead of just 1fr for equal columns. Plain 1fr allows content to push columns wider.
Loading States
Skeleton loading — use while fetching data
CSS
@keyframes shimmer {
  0% { background-position: -400px 0; }
  100% { background-position: 400px 0; }
}
.skeleton {
  background: linear-gradient(90deg, var(--bg-hover) 25%,
    var(--bg-sunken) 50%, var(--bg-hover) 75%)
;
  background-size: 800px 100%;
  animation: shimmer 1.5s infinite;
  border-radius: 6px;
}
Error state — when a data fetch fails
Failed to load data
NetSuite connection timed out. Try again or check your connection.
Design Principles
Do
  • Use flat design — no shadows on cards or surfaces
  • Use generous whitespace between sections
  • Use 1px borders for structure, not color fills
  • Use regular case for labels ("Quick Actions" not "QUICK ACTIONS")
  • Keep hover states subtle — border-color or background tint only
  • Use one accent color (Cobalt Blue) for interactive elements
  • Use system fonts for performance and native feel
  • Content is factual — state facts clearly, no selling
  • Status dots: 5px colored circles, not full badges
Don't
  • Add box-shadows to cards or containers
  • Use transform/lift on card hover
  • Use heavy borders or multiple border colors
  • Use uppercase text-transform on section headings
  • Use more than 2 accent colors at once
  • Add decorative icons where text works
  • Use colored backgrounds for cards (white only)
  • Use promotional or persuasive language
  • Use plain 1fr for equal-width grid columns

Status Workflows
Standard lifecycle states for GFS business objects. Every dashboard must use these exact status names and badge colors.
Sales Order Lifecycle
SO Status Flow
Draft Pending Approval Approved Pending Fulfillment Partially Fulfilled Fulfilled Closed
Purchase Order Lifecycle
PO Status Flow
Pending Approved Partially Received Received Closed
Work Order / Production
WO Status Flow
Planned Released In Progress Completed Closed
Status-to-Badge Mapping
Status ConceptBadge ClassToken
Draft / Planned / Inactive / Closedds-badge-default--neutral
Pending / Awaiting / Releasedds-badge-pending--warning
Approved / Confirmed / Scheduledds-badge-info--info
In Progress / Processing / Buildingds-badge-orange--orange
Partially Complete / Partial Receiptds-badge-teal--teal
Active / Complete / Fulfilled / Shippedds-badge-active--success
Overdue / Failed / Rejected / Past Dueds-badge-danger--danger
Compliance / Audit / Certificationds-badge-purple--purple

Empty State Illustrations
Lightweight SVG illustrations for empty, error, and onboarding states. 48px height, 2-color (primary-light + border), centered with heading + description.
Standard Empty States
No records
Table is empty
No results
Try different filters
All clear
No pending items
No inventory
Warehouse is empty
No messages
Inbox is empty
Connection error
Check your connection
PropertySpec
SVG size48px × 48px
Primary strokevar(--primary-light) #93BFEF
Secondary strokevar(--border) #E5E5E5
Error strokevar(--danger) #EF4444
Stroke width1.5px
Containerborder: 1px dashed var(--border)

Print & PDF Standards
Rules for printed dashboards, letters, compliance docs, and PDF exports.
CSS
@media print {
  .sidebar, nav, .chat-panel, .copy-btn,
  .search, .theme-toggle, .filter-bar { display: none !important; }
  body { background: #fff; font-size: 12pt; }
  .main-wrapper { margin-left: 0; }
  .card { break-inside: avoid; box-shadow: none; }
}
SpecValue
Page margins0.75in all sides
Body font12pt Inter
Footer"Global Food Solutions, Inc. — Confidential"
Hidden elementsSidebar, nav, search, copy buttons, theme toggle, filters, chat
Cardsbreak-inside: avoid, no shadow
Dark Mode
Full dark mode via [data-theme="dark"] on the <html> element. Toggled by the user via the theme button in the header. All CSS variables are overridden — no additional classes needed on components.
Token Overrides
TokenLightDark
--gray-50 (sunken bg)#FAFAFA#111827
--gray-100 (hover bg)#F0F0F0#1F2937
--gray-200 (borders)#E5E5E5#374151
--gray-300 (hover border)#D0D0D0#4B5563
--gray-500#6B7280#9CA3AF
--gray-600#4B5F7A#93BFEF
--gray-700#4B5F7A#D1D5DB
--gray-800#1F1F1F#F3F4F6
--gray-900#092F64#FFFFFF
--white (card bg)#FFFFFF#1F2937
--shadownone0 1px 3px rgba(0,0,0,.4)
Component Overrides
ComponentDark Override
headerbackground: #0a1628
.sidebarbackground: #111827; border-color: #1F2937
.sidebar .nav-item:hoverbackground: #1F2937
.sidebar .nav-item.activebackground: rgba(70,139,230,.15)
.cardbackground: #1F2937; border-color: #374151
thead thbackground: #111827
tbody tdborder-color: #374151
.org-card / .oc-cardbackground: #1F2937; border-color: #374151
.tl-postbackground: #2d3748; border-color: #4a5568
.compose-areabackground: #2d3748; inputs bg: #1a202c
.kanban-colbackground: #111827
.kanban-cardbackground: #1F2937; border-color: #374151
.dash-stat / .dash-shortcutbackground: #1F2937; border-color: #374151
a.email-linkcolor: #93BFEF
.placeholderbackground: #744210; color: #fefcbf
CSS
/* Dark mode is a CSS-only override — no JS class toggling needed beyond setting data-theme */
[data-theme="dark"] {
  --white: #1F2937; /* cards invert */
  --gray-800: #F3F4F6; /* text inverts */
  --shadow: 0 1px 3px rgba(0,0,0,.4); /* shadows appear in dark */
}
Responsive & Mobile
Three breakpoints plus touch-target and iOS safe area rules. The sidebar becomes a slide-out drawer on mobile.
Breakpoints
BreakpointTargetKey Changes
max-width: 768pxTablet & phoneSidebar → drawer, 2-col grids → 1-col, main padding 12px 14px, hamburger visible
max-width: 640pxSmall phonegen-form/sig-form → 1-col, letter-selector → 1-col
max-width: 380pxiPhone SEKPI grid → 1-col, badge hidden, org cards narrower
Mobile Sidebar
StateCSS
Default (hidden)transform: translateX(-100%); box-shadow: none
.sidebar.opentransform: translateX(0); box-shadow: 4px 0 20px rgba(0,0,0,.15)
.main-wrappermargin-left: 0 (sidebar overlay, not push)
.menu-toggledisplay: block (hamburger ☰)
Touch Targets
@media (pointer: coarse) — larger hit areas
ElementDesktopTouch
.nav-item36px min-height44px
.tl-action-btnauto36px; padding: 6px 12px
.tl-filterauto36px; padding: 6px 14px
checkbox18px22px
.dash-shortcutauto52px
.tpl-type-btnauto40px
.post-btnauto44px
iOS Safe Areas
CSS
@supports (padding: env(safe-area-inset-top)) {
  header { padding-top: calc(14px + env(safe-area-inset-top)); }
  main { padding-bottom: calc(40px + env(safe-area-inset-bottom)); }
}
Key Mobile Adaptations
ComponentDesktopMobile (768px)
Main padding24px 32px 48px12px 14px 40px
Card padding20px 24px16px
Dashboard grids2-col / 6-col1-col
Info grid160px / 1fr1-col stack
Org chartHorizontal treeVertical stack
Workflow stepsHorizontal flexVertical stack, arrows rotate 90deg
File list itemsRow with button rightStack, button self-end
Compose rowInline flexColumn stack, post-btn 100% width
Table font14px12px
Global searchVisibledisplay: none
Print Styles
RuleBehavior
Hidden elementssidebar, nav, copy buttons, search, theme toggle, shortcuts, checkboxes, generators, signatures
.main-wrappermargin-left: 0
mainmax-width: 100%; padding: 10px 20px
.cardbreak-inside: avoid; box-shadow: none; border: 1px solid #ddd; bg: #fff
bodybackground: #fff
Brand centerSelector/actions hidden; preview borderless
Motion & Transitions
Subtle, functional animations. Nothing decorative. Three speed tiers based on interaction type.
Transition Timings
SpeedDurationUsed By
Fast.1sFile list hover, kanban card hover
Standard.15sCard border-color, button hover, nav hover, link color, copy-btn, map state opacity, focus ring, email-link, toast
Medium.2sSidebar nav background, brand card hover, collapsible expand, dept chevron rotate, card h2 margin/padding, dept-body slide, org-detail slide, toast opacity
Slow.3sSidebar drawer transform (mobile)
Keyframe Animations
NameCSSUsed By
cardExpandfrom { opacity: 0 } to { opacity: 1 } — .2s easeCollapsible card body reveal
slideDownfrom { opacity: 0; translateY(-8px) } to { opacity: 1; translateY(0) } — .2s easeOrg detail panel, dept body expand
Hover State Catalog
ElementHover Effect
.cardborder-color: #D0D0D0 (subtle border shift only)
.nav-itembackground: #F0F0F0; color: #1F1F1F
.dash-stattransform: translateY(-2px); box-shadow: var(--shadow-md)
.dash-shortcutborder-color: var(--blue); background: #f7faff; translateY(-1px)
.brand-cardborder-color: var(--blue); translateY(-2px)
.org-cardborder-color: var(--blue); translateY(-2px); box-shadow: var(--shadow-md)
.oc-cardborder-color: var(--blue); translateY(-2px)
.kanban-cardborder-color: var(--blue-mid) + actions opacity 0→1
.tl-postbox-shadow: var(--shadow-md)
.file-list libackground: var(--gray-50)
tbody trbackground: #FAFAFA
.letter-btnborder-color: var(--blue); background: #ebf4ff
.tl-filterborder-color: var(--blue); color: var(--blue)
.tl-action-btnbackground: var(--gray-100); color: var(--gray-800)
.copyablecolor: var(--blue) + ::after tooltip opacity 1
.global-search input:focusbg: #fff; border-color: #468BE6; width: 280px; box-shadow: 0 0 0 2px rgba(70,139,230,.15)
Rule: Card hover should never add box-shadow. Only border-color shifts (except dash-stat and org-card which lift slightly for affordance). Timeline posts gain shadow on hover because they're interactive objects, not containers.

Accessibility
WCAG 2.1 AA contrast ratios for all text/background combinations. GFS standards require a minimum 4.5:1 for body text and 3:1 for large text (18px+ bold or 24px+).
Core Text Contrast Ratios
CombinationRatioWCAG
#1F1F1F on #FFFFFF16.3:1AAA
#1F1F1F on #F7F7F814.9:1AAA
#4B5F7A on #FFFFFF5.8:1AA
#6B7280 on #FFFFFF4.6:1AA
#8E8EA0 on #FFFFFF3.2:1AA Large
#888888 on #FFFFFF3.5:1AA Large
#FFFFFF on #092F6411.5:1AAA
#FFFFFF on #1A57996.6:1AA
Status Color Contrast (text on bg)
StatusText on BackgroundRatioWCAG
Success#065F46 on #ECFDF57.6:1AAA
Warning#92400E on #FFFBEB7.1:1AAA
Danger#991B1B on #FEF2F27.8:1AAA
Info#1A5799 on #E9F5FF5.8:1AA
Purple#7C3AED on #F5F3FF5.9:1AA
Neutral#4B5563 on #F3F4F67.5:1AAA
Teal#0D9488 on #F0FDFA4.6:1AA
Orange#EA580C on #FFF7ED4.9:1AA
Interactive Element Requirements
RequirementSpec
Focus ringoutline: 2px solid var(--primary-mid); outline-offset: 2px
Focus ring (dark bg)outline: 2px solid #FFFFFF; outline-offset: 2px
Min touch target (mobile)44px × 44px — per WCAG 2.5.8
Min click target (desktop)36px × 36px
Disabled state opacityopacity: .4; cursor: not-allowed
Color-only indicatorsNever — always pair with text, icon, or pattern
Keyboard navigationAll interactive elements must be focusable via Tab
Usage Guidelines
Do
  • Use --text-body or --text-heading for primary content
  • Use --text-muted (4.6:1) for secondary labels at 12px+
  • Add visible focus rings on all interactive elements
  • Ensure 44px minimum touch targets on mobile
  • Pair status colors with text labels or icons
  • Test with keyboard-only navigation
Don't
  • Use --text-faint (#8E8EA0, 3.2:1) for text smaller than 18px bold
  • Use --text-label (#888, 3.5:1) for critical information
  • Rely on color alone to communicate status — add text or icons
  • Remove focus outlines without providing visible alternatives
  • Use placeholder text as the only label for form fields
  • Create click targets smaller than 36px on desktop

Icon Standard
Lucide Icons is the official GFS icon library. Flat, 2px stroke, consistent geometry. Loaded via CDN — no build step needed. MIT licensed, free for commercial use.
CDN Setup
HTML
<!-- Add to <head> -->
<script src="https://unpkg.com/lucide@latest"></script>

<!-- Initialize at end of <body> -->
<script>lucide.createIcons();</script>
Usage
<!-- Basic icon -->
<i data-lucide="package"></i>

<!-- Sized icon -->
<i data-lucide="truck" style="width:18px;height:18px"></i>

<!-- Icons inherit currentColor — never hardcode color separately -->
<span style="color: var(--success)">
  <i data-lucide="check-circle"></i> Approved
</span>
Size Standards
ContextSizeStrokeExample
Inline with body text16px2pxBody text
Navigation items18px2px Dashboard
KPI cards / buttons20px2px
Empty states / hero32px1.5px
Alert banners16px2px
GFS Icon Map — v8.0 Expanded (10 Categories, 100+ Icons)
Standard icons for every GFS business concept. Always use these exact Lucide icon names. No freelancing.
Food Safety & Compliance
SQF / QC
Temperature
Recall
Lot Trace
HACCP
Certification
Expiration
Hold
Release
Corrective
Allergen
Inspection
Manufacturing & Production
Production
BOM
Work Order
Line / Machine
Batch
Yield
Waste
Raw Material
Finished Good
Packaging
Efficiency
Throughput
Logistics & Distribution
Delivery
Route
Pickup
Receiving
Pallet
Cold Chain
Freight
Tracking
ETA
Carrier
Inbound
Outbound
Product & Inventory
Item / SKU
Barcode
Label
Spec Sheet
Ingredients
Nutrition
Case Pack
Shelf Life
Storage
Weight
Sales & CRM
Prospect
Quote
Contract
Commission
Territory
Pipeline
Renewal
Broker
Margin
Discount
Reporting & Analytics
Dashboard
Summary
Detail
Drill-Down
Snapshot
Trend
Comparison
Forecast
Variance
Benchmark
KPI & Metrics
Target
Actual
Delta
Threshold
Anomaly
Correlation
Distribution
Funnel
Score
Gauge
Security & Access
Locked
Unlocked
Permission
Role
Audit Log
2FA
API Key
Hidden
Denied
Session
Finance & Accounting
Journal Entry
GL Account
Reconciled
Accrual
Budget
Expense
Reimbursement
Tax
Write-Off
Payment
USDA & Commodity
Commodity
Allocation
Entitlement
Drawdown
Bracket
Certified
Inspection
Grading
Complete Icon Map Reference — v8.0
CategoryConceptLucide NameUsage
Food Safety & Compliance (12)
SQF / QCshield-checkQuality control, SQF audit
TemperaturethermometerCold chain, storage temp
Recallalert-octagonFood safety recall
Lot Tracescan-lineLot traceability
HACCPclipboard-checkHazard analysis
Certificationbadge-checkSQF, organic, kosher
ExpirationtimerShelf life, best-by dates
HoldhandQC hold, quarantine
Releasecircle-checkQC release, approved
Corrective ActionwrenchCAPA, corrective action
AllergenwheatAllergen flags, warnings
InspectionmicroscopeUSDA inspection, lab
Manufacturing (12)
ProductionfactoryWork orders, lines
BOMlayersBill of materials
Work Orderclipboard-listWO lists, production
Line / MachinecogProduction line
Batchflask-conicalBatch runs
YieldtargetProduction yield %
Wastetrash-2Waste tracking
Raw MaterialboxIngredients, components
Finished Goodpackage-checkCompleted assemblies
PackaginggiftPackaging materials
EfficiencygaugeOEE, line efficiency
ThroughputzapCases/hour, speed
Logistics (12)
DeliverytruckOutbound shipments
RouterouteRoute planning
PickuppackageCustomer pickup
ReceivingwarehouseInbound receiving
PalletcontainerPallet counts
Cold ChainsnowflakeRefrigerated, frozen
FreightshipLTL, FTL shipping
Trackingmap-pinShipment tracking
ETAclockExpected arrival
CarriercontactCarrier/driver info
Inboundarrow-down-to-linePO receipts
Outboundarrow-up-from-lineSO fulfillment
Sales & CRM (10)
Prospectuser-plusNew lead
Quotefile-signaturePrice quotes
ContracthandshakeAgreements, terms
CommissionpercentBroker commissions
TerritorymapSales territory
Pipelinegit-branchSales pipeline
RenewalrepeatContract renewal
BrokerusersBroker partners
MargincalculatorProfit margin
Discountbadge-percentPricing discounts
Security (10)
LockedlockRestricted access
UnlockedunlockAccess granted
PermissionshieldRole permissions
Roleuser-cogUser role assignment
Audit Logscroll-textChange history
2FAfingerprintTwo-factor auth
API KeykeyAPI credentials
Hiddeneye-offSensitive data masked
DeniedbanAccess denied
Sessionlog-inLogin, session
Finance (10)
Journal Entrybook-openJE, GL posting
GL AccountlandmarkChart of accounts
Reconciledcheck-squareBank rec, matched
BudgetwalletBudget vs actual
ExpensereceiptExpense reports
TaxpercentTax calculations
Write-OffxBad debt, write-offs
Paymentcredit-cardAP/AR payments
USDA & Commodity (8)
CommodityscaleUSDA commodity
AllocationsliceCommodity allocation
EntitlementawardAnnual entitlement
Drawdownarrow-down-circleMonthly drawdown
Bracketgit-mergeRate bracket
Certifiedbadge-checkUSDA certified
GradingstarUSDA grading
Icon in Context
Buttons with Icons
Alert Banners with Lucide Icons
Connected to NetSuite for live analytics data.
Report generated and downloaded successfully.
SQF audit due in 14 days. Contact Sydney to prepare.
AR past due over 90 days: Gold Star Foods — $12,400.
Sidebar Nav with Icons (Standard)
Dashboard
Inventory
Orders
Customers
Vendors
Reports
KPI Card with Icon Container
Revenue MTD
$124,500
Cases Today
312
AR Past Due
$18,200
CSS
/* Default icon styling */
i[data-lucide] {
  width: 16px; /* default inline size */
  height: 16px;
  stroke-width: 2;
  vertical-align: text-bottom;
  flex-shrink: 0;
}

/* Icon container box — KPI cards, hero sections */
.icon-box {
  width: 40px; height: 40px;
  border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
Icon Usage Rules
Do
  • Use Lucide icons exclusively — no mixing libraries
  • Let icons inherit currentColor from parent
  • Use standard sizes: 16px inline, 18px nav, 20px KPI, 32px empty
  • Keep stroke-width at 2px (1.5px for 32px+ icons)
  • Pair icons with text labels — no icon-only buttons without tooltips
  • Use icon containers (colored bg box) in KPI cards
  • Use flex-shrink: 0 on icons in flex layouts
Don't
  • Mix Lucide with Font Awesome, Material, or other libraries
  • Use icons without text labels (always pair icon + text in sidebar nav)
  • Hardcode icon colors — always use CSS variables or currentColor
  • Use filled/solid variants — GFS uses outline stroke icons only
  • Make icons larger than 32px (use illustrations instead)
  • Use decorative icons that don't add meaning
  • Use emoji in place of icons in production dashboards
Legacy: Text-Based Indicators
These text-based patterns remain valid and preferred in dense data contexts where icons add visual noise.
Still valid — use when icons would be too heavy
ContextApproachExample
File type badges3-letter text badgeXLS PDF
Status dots5px colored circlesActive
Collapsible toggle+/− character+
Agent/Skill badges2-3 letter badgeNS

Map & Geography Standards
Territory maps, delivery zones, and broker coverage overlays. All maps use inline SVG with brand-consistent colors.
Territory Color Palette
Broker Territory Colors
GFS Direct
Broker A
Broker B
Broker C
Unassigned
ElementSpec
State fill (assigned)Brand blue sequence (#092F64 → #93BFEF)
State fill (unassigned)#D0D0D0
State stroke#FFFFFF at 0.5px
State hoveropacity: 0.8
TooltipSame as map tooltip: dark bg, white text, 12px, 6px radius
Containermax-width: 960px with viewBox scaling
LegendHorizontal flex, 14px color squares with 3px radius
Map territory colorsUse chart color sequence — never use semantic status colors for territories

Favicon & Meta Standards
Required meta tags, favicon, and Open Graph settings for every GFS page. These ensure correct display when bookmarked, shared in Slack, or pinned to home screen.
Favicon
32×32 Icon Mark on Navy Background
32px & 16px renders
Required Meta Block
HTML
<!-- Add to <head> of every GFS page -->
<meta name="theme-color" content="#092F64">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-title" content="GFS Hub">
<meta property="og:title" content="GFS Dashboard">
<meta property="og:description" content="Global Food Solutions internal dashboard">
<meta property="og:type" content="website">

Email Template Standards
HTML email rendering rules. Email clients strip CSS variables, so all values must be inline hex. Maximum width 600px, table-based layout.
ElementEmail-Safe Spec
Fontfont-family: Arial, Helvetica, sans-serif
Max width600px, centered
Body text14px / 1.6 / #1F1F1F
Header barbackground: #092F64; padding: 20px 24px; color: #fff
CTA buttonbackground: #1A5799; color: #fff; padding: 12px 24px; border-radius: 6px
Footerfont-size: 11px; color: #6B7280; border-top: 1px solid #E5E5E5
Footer textCompany name, address, confidentiality notice
Linkscolor: #1A5799; text-decoration: underline
Signature dividerborder-top: 2px solid #092F64; width: 60px
Email clients do not support CSS variables, var(--primary), Google Fonts, or Flexbox/Grid. All email styles must be inline with hardcoded hex values.

Document Confidentiality
Three classification levels for GFS documents. Every generated report, export, and compliance document must carry the appropriate marking.
Classification Badges
Public Internal Use Only Confidential
LevelBadgeUseMarking
Publicds-badge-activeMarketing, public-facing docsNo special marking required
Internalds-badge-infoDashboards, operational reports, hub pagesFooter: "Internal Use Only"
Confidentialds-badge-dangerFinancial data, customer PII, legal, USDA allocationsHeader badge + footer + watermark
Confidential Watermark
CSS watermark overlay for confidential documents
CONFIDENTIAL
Document content sits on top of the watermark. The watermark uses rgba(239,68,68,.06) — barely visible but present when printed.

Recommended Library Stack
Opinionated picks — one library per capability. All CDN-loadable, no build step. If it's not on this list, you probably don't need it.
CapabilityLibrarySizeCDN
FontsInter + JetBrains Mono~43KBfonts.googleapis.com
IconsLucide~65KBunpkg.com/lucide@latest
ChartsChart.js~67KBcdn.jsdelivr.net/npm/chart.js
KPI AnimationCountUp.js~4KBcdn.jsdelivr.net/npm/countup.js@2
PDF Exporthtml2pdf.js~14KBcdn.jsdelivr.net/npm/html2pdf.js
TooltipsNative Popover API0KBBrowser-native
ModalsNative <dialog>0KBBrowser-native
TransitionsCSS transitions + View Transitions API0KBBrowser-native
Use
  • Browser-native APIs first — they're free, fast, and maintained forever
  • Chart.js for all chart types — already branded with GFS defaults
  • CountUp.js for KPI number animations on page load
  • html2pdf.js when users need "Export PDF" functionality
  • CSS transitions for all hover/state animations
Don't add
  • GSAP, anime.js — CSS transitions cover 95% of dashboard needs
  • Three.js, deck.gl — overkill for food distribution data
  • Tabulator, AG Grid — hand-built tables work fine at our data scale
  • Lottie — requires After Effects assets we don't produce
  • Multiple libraries for the same job — one pick per capability
CountUp.js — KPI Number Animation
Makes KPI values count up from zero on page load. One line per number. Use on every dashboard's KPI strip.
HTML
<!-- CDN -->
<script src="https://cdn.jsdelivr.net/npm/countup.js@2/dist/countUp.umd.min.js"></script>
JS
/* Animate a KPI value */
new countUp.CountUp('revenue-kpi', 124500, {
  prefix: '$',
  separator: ',',
  duration: 1.5, /* seconds */
  useEasing: true
}).start();

/* Percentage */
new countUp.CountUp('fulfillment-kpi', 94, {
  suffix: '%',
  duration: 1.2
}).start();
OptionGFS Default
Duration1.5s for currency, 1.2s for counts
Easingtrue — decelerates at end
Separator, (comma thousands)
Prefix$ for currency, none for counts
Suffix% for percentages, cs for cases, lbs for weight
Decimals0 for rounded, 1 for abbreviated (124.5K)
html2pdf.js — One-Line PDF Export
JS
/* Export any element to PDF */
html2pdf()
  .set({
    margin: [0.5, 0.5, 0.75, 0.5],
    filename: 'GFS-Report.pdf',
    image: { type: 'jpeg', quality: 0.95 },
    html2canvas: { scale: 2 },
    jsPDF: { format: 'letter' }
  })
  .from(document.getElementById('dashboard'))
  .save();

Browser-Native CSS Patterns
Zero-library, zero-cost performance and interaction patterns built into modern browsers. Use these before reaching for any JS library.
content-visibility (7x render performance)
CSS
/* Skip rendering off-screen table rows — massive perf gain on long lists */
tbody tr {
  content-visibility: auto;
  contain-intrinsic-size: auto 44px; /* estimated row height */
}
Native <dialog> (replaces modal libraries)
HTML + CSS
<dialog id="confirm">
  <h3>Delete 3 orders?</h3>
  <button onclick="confirm.close()">Cancel</button>
  <button onclick="deleteOrders()">Delete</button>
</dialog>

/* Frosted glass backdrop */
dialog::backdrop { backdrop-filter: blur(4px); background: rgba(0,0,0,.3); }

/* Open it */
document.getElementById('confirm').showModal();
Container Queries (component-level responsive)
CSS
/* Card switches between table and stacked layout based on ITS OWN width */
.card { container-type: inline-size; }

@container (max-width: 400px) {
  .card table { display: none; }
  .card .card-view { display: block; }
}
:has() Selector (parent-aware styling)
CSS
/* Auto-highlight rows with danger badges — no JS class toggling */
tr:has(.ds-badge-danger) {
  background: var(--danger-bg);
}

/* KPI grid adjusts columns based on child count */
.kpi-grid:has(> :nth-child(5)) {
  grid-template-columns: repeat(5, minmax(0,1fr));
}
CSS Nesting (30% less CSS)
CSS
/* Before: flat selectors */
.card { ... }
.card h2 { ... }
.card:hover { ... }

/* After: nested (all modern browsers) */
.card {
  background: var(--bg-card);
  & h2 { font-size: 15px; font-weight: 600; }
  &:hover { border-color: var(--border-hover); }
}
Quick Reference
FeatureWhat it replacesBrowser Support
content-visibility: autoVirtual scrolling librariesChrome, Edge, Firefox 125+
<dialog> + ::backdropSweetAlert2, custom modalsAll modern browsers
container queriesJS resize observersAll modern browsers
:has()JS class toggling for parent stylingAll modern browsers
CSS nestingSass/SCSS preprocessorAll modern browsers
popover attributeTippy.js, Popper.jsAll modern browsers
@layer!important specificity warsAll modern browsers
color-mix()Sass color functionsAll modern browsers
Build Boilerplate
Starter template for every new GFS dashboard. Copy this entire block as your starting point. All design tokens, Lucide icons, and responsive meta tags are pre-loaded.
Pre-Build Checklist
Run through this before starting any new dashboard.
10-second preflight
  • 1 Copy the correct template (Starter or Page Shell)
  • 2 Set <title>Page Name — GFS</title>
  • 3 Add gfs-components.css + gfs-init.js
  • 4 Build content using .gfs- classes and var(--token) colors
  • 5 Use Lucide icons from the Icon Map — no freelancing
  • 6 Format numbers with GFS.format — currency, dates, cases, weight
  • 7 Add data-copyable to every data table
  • 8 Right-align numeric columns with .num class
  • 9 Test at 768px and 480px breakpoints
  • 10 Verify Voice & Tone — no exclamation marks, no casual copy
Which Template to Copy
TemplateUse WhenIncludes
Starter HTML (below)Simple single-page dashboards, reports, standalone toolsTokens + body reset only — no sidebar, no header
Page Shell (below)Full dashboard apps with navigationSidebar + header + main + mobile toggle + content zones
Starter HTML (Simple)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Dashboard Title — GFS</title> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet"> <script src="https://unpkg.com/lucide@latest"></script> <style> :root { /* Brand */ --primary: #1A5799; --primary-dark: #092F64; --primary-mid: #468BE6; --primary-light: #93BFEF; --primary-bg: #E9F5FF; /* Surfaces */ --bg-page: #F7F7F8; --bg-card: #FFFFFF; --bg-sunken: #FAFAFA; --bg-hover: #F0F0F0; --bg-active: #EBEBEB; /* Text */ --text-heading: #1F1F1F; --text-body: #1F1F1F; --text-secondary: #4B5F7A; --text-muted: #6B7280; --text-faint: #8E8EA0; --text-label: #888888; /* Borders */ --border: #E5E5E5; --border-light: #EBEBEB; --border-row: #F0F0F0; /* Status */ /* Status — 3 tokens each */ --success: #10B981; --success-text: #065F46; --success-bg: #ECFDF5; --warning: #F59E0B; --warning-text: #92400E; --warning-bg: #FFFBEB; --danger: #EF4444; --danger-text: #991B1B; --danger-bg: #FEF2F2; --purple: #8B5CF6; --purple-text: #7C3AED; --purple-bg: #F5F3FF; /* Layout */ --radius: 10px; --radius-sm: 8px; --radius-lg: 12px; --font-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; --font-mono: 'JetBrains Mono', 'SF Mono', 'Fira Code', 'Consolas', monospace; } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: var(--font-body); background: var(--bg-page); color: var(--text-body); line-height: 1.5; font-size: 15px; -webkit-font-smoothing: antialiased; font-feature-settings: 'cv01', 'cv02'; } </style> </head> <body> <!-- Your dashboard content here --> <script>lucide.createIcons();</script> </body> </html>
Page Anatomy
Every GFS dashboard has 5 zones. This is the skeleton — no exceptions.
Dashboard zones with pixel measurements
Logo
Nav
Active
Item
Item
User
Page Title
30d Refresh
KPI
$124K
KPI
312
KPI
47
KPI
$18K
Content Area
Sidebar: 260px fixed Header: 56px sticky Main: max-width 1080px, 20px 32px 48px padding KPI strip: always first in content
Content Stacking Order
OrderZoneRequired
1KPI Strip — 3-6 column grid at top of contentEvery dashboard
2Filters / Time Range — if the page has user-controlled filtersOptional
3Primary Content — chart, table, or card gridEvery dashboard
4Secondary Content — additional tables, detail cardsOptional
5Footer / Confidentiality — if page is printed or exportedPrint only
Header Bar Pattern
The header always has: title (left), controls (right). Controls include time range, data refresh, and action buttons.
Complete header with all standard controls
Inventory Dashboard
Updated 2 min ago
PositionElementRequired
LeftPage title (16px/600, #111, margin-right:auto)Always
Center-rightData refresh indicator (dot + timestamp)If data-connected
RightTime range pills (7d, 30d, 90d, YTD)If time-filterable
Far rightAction button (Export, Print, etc.)If exportable
Breadcrumbs
Use when navigating to detail views from a list
Dashboard / Inventory / Item Detail
PropertySpec
Font12px / 400
Link colorvar(--primary)
Current pagevar(--text-heading), font-weight: 500 — not a link
Separator/ in var(--text-faint)
PositionInside <main>, above KPI strip, padding: 8px 0
When to useDetail views only (Item Detail, Customer Detail). Not on top-level pages.
Page Loading Sequence
What the user sees from page load to data render.
StepWhat RendersDuration
1. ShellSidebar + header + empty main area — instant from HTML0ms
2. SkeletonsKPI skeletons + table skeleton in main area — CSS animation0ms
3. Iconslucide.createIcons() replaces <i> tags with SVGs~50ms
4. Data arrivesReplace skeletons with real KPI values + table rows~500-2000ms
5. CountUpKPI numbers animate from 0 to final value1.5s
6. ChartsChart.js renders after data is available~200ms after data
The sidebar and header must render instantly from static HTML — never wait for JS or data. Skeletons go in the content area only. This gives users instant orientation even on slow connections.
Mobile Sidebar Toggle
At <768px, sidebar becomes an overlay drawer. Header shows a hamburger button.
HTML
<!-- Add to header, visible only on mobile -->
<button class="menu-toggle" onclick="document.querySelector('.sidebar').classList.toggle('open')">
  <i data-lucide="menu" style="width:20px;height:20px"></i>
</button>
CSS
.menu-toggle { display:none; background:none; border:none; cursor:pointer; color:var(--text-secondary); }

@media (max-width: 768px) {
  .menu-toggle { display:block; }
  .sidebar {
    transform: translateX(-100%);
    transition: transform .3s ease;
    z-index: 200;
  }
  .sidebar.open {
    transform: translateX(0);
    box-shadow: 4px 0 20px rgba(0,0,0,.15);
  }
  .main-wrapper { margin-left: 0; }
  header { padding: 0 16px; }
  main { padding: 12px 16px 40px; }
}
Page Shell — Complete Template
Copy this entire block as your starting point for any sidebar dashboard. Includes header with controls, sidebar with nav groups, mobile toggle, and content area with KPI skeletons.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Page Title — GFS</title> <style> * { margin:0; padding:0; box-sizing:border-box; } body { font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif; background:#F7F7F8; color:#1F1F1F; font-size:15px; line-height:1.5; -webkit-font-smoothing:antialiased; } /* ═══ LAYOUT ═══ */ .app-layout { display:flex; min-height:100vh; } .sidebar { width:260px; background:#fff; border-right:1px solid #E5E5E5; position:fixed; top:0; left:0; bottom:0; display:flex; flex-direction:column; z-index:100; } .sidebar-header { height:56px; padding:0 16px; display:flex; align-items:center; border-bottom:1px solid #E5E5E5; flex-shrink:0; } .sidebar-logo { display:flex; align-items:center; gap:10px; } .sidebar-logo-text { font-size:13px; font-weight:700; color:#092F64; letter-spacing:-.2px; } .sidebar-logo-sub { font-size:9px; font-weight:500; color:#6B7280; text-transform:uppercase; letter-spacing:.5px; margin-top:1px; } .sidebar-nav { flex:1; padding:8px; overflow-y:auto; } .nav-group { margin-bottom:12px; } .nav-group-label { font-size:11px; font-weight:500; color:#8E8EA0; text-transform:uppercase; letter-spacing:.5px; padding:6px 12px 4px; } .nav-item { display:flex; align-items:center; padding:8px 12px; border-radius:8px; font-size:14px; font-weight:400; color:#4B5F7A; cursor:pointer; border:none; background:none; width:100%; text-align:left; min-height:36px; transition:background .2s; } .nav-item:hover { background:#F0F0F0; color:#1F1F1F; } .nav-item.active { background:#EBEBEB; color:#1F1F1F; font-weight:500; } .main-wrapper { margin-left:260px; flex:1; } header { background:#fff; height:56px; padding:0 32px; display:flex; align-items:center; gap:12px; border-bottom:1px solid #E5E5E5; position:sticky; top:0; z-index:90; } .header-title { font-size:16px; font-weight:600; color:#111; margin-right:auto; } main { max-width:1080px; margin:0 auto; padding:20px 32px 48px; } </style> </head> <body> <div class="app-layout"> <!-- ═══ SIDEBAR ═══ --> <aside class="sidebar"> <div class="sidebar-header"> <div class="sidebar-logo"> <!-- 24px Globe Icon Mark --> <svg width="24" height="24" viewBox="0 0 32 32" fill="none"> <rect width="32" height="32" rx="8" fill="#092F64"/> <circle cx="16" cy="16" r="8" stroke="#93BFEF" stroke-width="1.3"/> <ellipse cx="16" cy="16" rx="13" ry="4" transform="rotate(-20 16 16)" stroke="#FFFFFF" stroke-width="1.1" stroke-linecap="round"/> <ellipse cx="16" cy="16" rx="13" ry="4" transform="rotate(-50 16 16)" stroke="#468BE6" stroke-width="1.1" stroke-linecap="round"/> </svg> <div> <div class="sidebar-logo-text">Global Food Solutions</div> <div class="sidebar-logo-sub">Corporate Hub</div> </div> </div> </div> <div class="sidebar-nav"> <div class="nav-group"> <button class="nav-item active">Dashboard</button> </div> <div class="nav-group"> <div class="nav-group-label">Section</div> <button class="nav-item">Page Name</button> </div> </div> </aside> <!-- ═══ MAIN ═══ --> <div class="main-wrapper"> <header> <button class="menu-toggle" onclick="document.querySelector('.sidebar').classList.toggle('open')"><i data-lucide="menu"></i></button> <span class="header-title">Page Title</span> <!-- Data refresh + time range + action buttons go here --> </header> <main> <!-- Breadcrumbs (detail views only): Dashboard / Section / Page --> <!-- 1. KPI Strip --> <!-- 2. Filters (optional) --> <!-- 3. Primary content (table/chart) --> <!-- 4. Secondary content (optional) --> </main> </div> </div> </body> </html>
ElementSpec
Sidebar width260px fixed, full height
Sidebar + Header height56px each — borders must align
All borders1px solid #E5E5E5 — same color everywhere
Header padding0 32px — no vertical padding (height controls centering)
Sidebar header padding0 16px
Main contentmax-width: 1080px; padding: 20px 32px 48px
Logo icon24px globe mark — navy rect + Jordy Blue circle + 2 orbital ellipses
Logo text13px/700 navy + 9px/500 muted uppercase
Safe areas (mobile only)@media (max-width:768px) — never apply on desktop
GFS Utility Files
Two files give you every component pre-styled and every utility function ready to use.
HTML
<!-- GFS component classes -->
<link rel="stylesheet" href="css/gfs-components.css">

<!-- GFS utilities — auto-inits Lucide, Chart.js, copy buttons -->
<script src="js/gfs-init.js"></script>
JS
/* gfs-init.js auto-initializes. Use utilities like: */
GFS.format.currency(124500) // "$124,500"
GFS.format.currency(-12400) // "($12,400)"
GFS.format.percent(94) // "94%"
GFS.format.cases(1247) // "1,247 cs"
GFS.format.weight(68400) // "68,400 lbs"
GFS.format.date('2026-05-11') // "May 11, 2026"
GFS.badge('success', 'Active') // badge HTML with dot
GFS.badge('danger', 'Past Due') // danger badge HTML
FileSizeProvides
css/gfs-components.css~4KBCards, KPIs, tables, buttons, badges, alerts, inputs, filters, empty states, skeleton, progress, toast
js/gfs-init.js~5KBGFS.format, GFS.badge(), GFS.copyTable(), Chart.js defaults, [data-copyable], [data-countup], dark mode
CDN Dependencies
Load these CDN resources before the utility files.
HTML
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">

<!-- Icons -->
<script src="https://unpkg.com/lucide@latest"></script>

<!-- Charts (only if dashboard has charts) -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
ResourceCDNSizeRequired
Inter (font)Google Fonts~25KBAlways
JetBrains MonoGoogle Fonts~18KBAlways
Lucide Iconsunpkg~65KBAlways
Chart.jsjsDelivr~67KBOnly if charts
Build Checklist
Verify before shipping any new dashboard.
Pre-ship QA
  • All CSS variables from :root block — no hardcoded colors
  • Inter + JetBrains Mono loaded via Google Fonts CDN
  • Lucide CDN loaded, lucide.createIcons() at end of body
  • Icons use standard GFS icon map names — no freelancing
  • Grid columns use minmax(0,1fr) not plain 1fr
  • Cards: no box-shadow, 1px border, 10px radius
  • Numeric table columns right-aligned with mono font
  • Copy button on every data table (Dark variant, top-right)
  • Empty states handled — no blank screens when data is missing
  • KPI values use trend indicators where period comparison exists
  • Negative numbers in parentheses with danger color
  • Responsive at 768px — tested on mobile viewport
  • No promotional language — facts only, stated clearly
CSS Variables Reference
Complete list of CSS custom properties defined in :root of css/styles.css.
:root
/* Brand Colors */
--navy: #092F64; /* Cool Black */
--blue: #1A5799; /* Cobalt Blue — primary */
--blue-mid: #468BE6; /* Tufts Blue — focus rings */
--blue-light: #93BFEF; /* Jordy Blue — accents */
--blue-bg: #E9F5FF; /* Alice Blue — badges, tints */

/* Semantic — 8 statuses, 3 tokens each */
--success: #10B981; --success-text: #065F46; --success-bg: #ECFDF5;
--warning: #F59E0B; --warning-text: #92400E; --warning-bg: #FFFBEB;
--danger: #EF4444; --danger-text: #991B1B; --danger-bg: #FEF2F2;
--info: #468BE6; --info-text: #1A5799; --info-bg: #E9F5FF;
--purple: #8B5CF6; --purple-text: #7C3AED; --purple-bg: #F5F3FF;
--neutral: #6B7280; --neutral-text: #4B5563; --neutral-bg: #F3F4F6;
--teal: #14B8A6; --teal-text: #0D9488; --teal-bg: #F0FDFA;
--orange: #F97316; --orange-text: #EA580C; --orange-bg: #FFF7ED;

/* Text & Neutrals */
--black: #1F1F1F; /* Eerie Black — headings, body */
--gray-50: #FAFAFA; /* Sunken surfaces, table header */
--gray-100: #F0F0F0; /* Hover backgrounds */
--gray-200: #E5E5E5; /* Card borders, dividers */
--gray-300: #D0D0D0; /* Hover borders, input borders */
--gray-500: #6B7280; /* Slate Grey — labels */
--gray-600: #4B5F7A; /* Steel Blue Grey — subheadings */
--gray-800: #1F1F1F;
--gray-900: #092F64;
--white: #FFFFFF;

/* Shadows */
--shadow: none; /* cards — FLAT, no shadow */
--shadow-md: 0 4px 16px rgba(9,47,100,.08);

/* Layout */
--radius: 10px;
--sidebar-width: 260px;

/* Typography */
--font-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
--font-mono: 'JetBrains Mono', 'SF Mono', 'Fira Code', 'Consolas', monospace;
File Structure
Project
GFS Setup Packets 2026/
├── index.html /* HTML shell — ~3,580 lines, 26 tabs */
├── css/
│ └── styles.css /* All CSS — ~1,420 lines */
├── js/
│ ├── app.js /* Main JS — ~2,420 lines */
│ └── nav.js /* Navigation + org chart — 156 lines */
├── design-system.html /* This file */
├── getting-here.html /* Visitor directions */
├── who-to-call.html /* Phone contacts (production floor) */
├── Documents/ /* PDFs, floor plans, facility docs */
├── Customer Setup Packet/
└── Vendor Information Packet/

File Structure Standard
Standard folder layout for any GFS dashboard project.
Project
my-dashboard/
├── index.html /* Dashboard page */
├── css/
│ └── gfs-components.css /* Pre-built component classes */
├── js/
│ └── gfs-init.js /* Utilities, auto-init, formatters */
└── GFS-HEADER-STANDARD.md /* Header reference (do not deploy) */
RuleDetail
Root HTML fileAlways index.html or [name]-dashboard.html
CSS foldercss/ — only gfs-components.css + any page-specific styles
JS folderjs/ — only gfs-init.js + any page-specific scripts
No assets folderAll images are inline SVG. No raster image assets.
No node_modulesAll dependencies loaded via CDN. No npm, no build step.

Glossary
Standard GFS terminology. Always use these exact abbreviations and spellings.
Business Terms
AbbreviationFull NameUsage Note
SOSales OrderNever "sale order" or "sales orders" in labels
POPurchase Order
WOWork OrderProduction context
ARAccounts ReceivableMoney owed TO us
APAccounts PayableMoney WE owe
BOMBill of MaterialsAssembly/production context
NSNetSuiteERP system
SQFSafe Quality FoodFood safety certification
USDAU.S. Department of AgricultureCommodity program context
CMEChicago Mercantile ExchangeCheese pricing reference
QCQuality Control
Time & Measurement
AbbreviationMeaning
MTDMonth to Date
YTDYear to Date
QTDQuarter to Date
WoWWeek over Week
MoMMonth over Month
YoYYear over Year
csCases (unit)
lbsPounds (weight)
pltPallets
°FDegrees Fahrenheit

Changelog
Version history of the GFS Design System.
VersionDateChanges
v8.0May 2026Icon expansion: 100+ icons across 10 categories (Food Safety, Manufacturing, Logistics, Product, Sales, Reporting, KPI, Security, Finance, USDA). 10 new table patterns (totals, grouped, expandable, row highlighting, actions, pagination, density, striped, clickable, alignment). Dark mode for design system page.
v7.0May 2026Enterprise readiness: Voice & Tone, Naming Conventions, Imagery Guidelines, Glossary, Changelog, File Structure Standard.
v6.0May 2026Production kit: gfs-init.js + gfs-components.css, WCAG AAA contrast fix, 3C Double Ring globe, Buddy mascot, 480px breakpoint, dark mode toggle, CountUp.js + html2pdf.js, Recommended Stack, Browser-Native CSS.
v5.0May 2026Major expansion: 11 new sections (Charts, Formatting, Workflows, Empty States, Print, Maps, Favicon, Email, Confidentiality, Dashboard Patterns, Layouts). Lucide Icons standard, Inter + JetBrains Mono fonts, 8 semantic statuses with 3-token system, navy hero, dropdown nav, section auto-numbering, blue-family category tags, Chart.js branded config.
v4.0May 2026Initial design system: Colors, Typography, Spacing, Shadows, Core Components, KPI Cards, Data Tables, Timeline, Org Chart, Templates, Kanban, Micro Components, Sidebar, Patterns, Dark Mode, Responsive, Motion, CSS Variables.