Design Guide

Colors, typography, spacing, and component patterns for Graspful. Every brand gets its own theme — this documents the Graspful defaults and the system that drives all brands.

The Graspful favicon is a white “G” on a sky-blue rounded square. It ships as three formats for maximum compatibility.

SVG

src/app/icon.svg

Modern browsers. Auto-served by Next.js.

ICO

src/app/favicon.ico

Legacy browsers. 16px, 32px, 48px.

PNG

src/app/apple-icon.png

iOS home screen. 180x180.

Each brand sets faviconUrl in its brand YAML. The root layout injects it as <link rel="icon">. Next.js also auto-serves icon.svg and apple-icon.png from the app directory.

Colors

The Graspful brand uses a sky-blue primary with teal accents. All colors are defined as HSL values in the brand config and injected as CSS custom properties at runtime.

Core palette

Primary#0EA5E9hsl(199 89% 48%)

Buttons, links, active states, icons

Secondary#4A90D9hsl(210 80% 55%)

Supporting accents, secondary buttons

Accent#06B6B4hsl(186 94% 42%)

Highlights, badges, teal accents

Foreground#0F172Ahsl(222 47% 11%)

Headings, body text

Muted Foreground#6B7280hsl(200 5% 46%)

Secondary text, descriptions

Background#FFFFFFhsl(0 0% 100%)

Page background

Card#FFFFFFhsl(0 0% 100%)

Card surfaces, elevated content

Border#E5E7EBhsl(200 10% 90%)

Card borders, dividers

Muted#F5F5F5hsl(200 10% 96%)

Subtle backgrounds, code blocks inline

Destructive#EF4444hsl(0 84% 60%)

Errors, destructive actions

Gradient

Used for CTA buttons, hero text, and mesh background orbs on marketing pages.

Start

#0284C7

Mid

#0EA5E9

End

#38BDF8

Accent

#2DD4BF
CSS custom properties (injected by BrandThemeStyle)
:root {
  --primary: hsl(199 89% 48%);
  --secondary: hsl(210 80% 55%);
  --accent: hsl(186 94% 42%);
  --foreground: hsl(222 47% 11%);
  --background: hsl(0 0% 100%);
  --muted-foreground: hsl(200 5% 46%);
  --border: hsl(200 10% 90%);
  --radius: 0.625rem;
  --gradient-start: #0284C7;
  --gradient-mid: #0EA5E9;
  --gradient-end: #38BDF8;
  --gradient-accent: #2DD4BF;
}

Typography

Inter is the only typeface. Loaded via next/font/google with display: swap.

Heading scale

Page title

text-4xl font-bold tracking-[-0.04em]

Section heading

text-2xl font-bold

Subsection heading

text-lg font-semibold

Card title

text-base font-semibold

Body text

Intro paragraph — used below page titles

text-lg leading-relaxed text-muted-foreground

Body text — used in sections and descriptions

text-sm text-muted-foreground

Small text — captions, labels

text-xs text-muted-foreground

Spacing and Layout

Consistent spacing creates visual rhythm. These are the patterns used across all doc and marketing pages.

mt-12Between major sections
mt-6Between subsections (h3)
mt-4Content after a heading
mt-2Paragraph after a heading
gap-4Grid gaps (cards, items)
p-6Card padding
p-8Feature card / CTA padding
max-w-7xlPage max width (docs layout)
max-w-5xlMarketing section max width
rounded-xlCards and containers
rounded-lgButtons, inputs, smaller elements

Component Patterns

Reusable patterns across docs and marketing pages.

Card

Card Title

Card description text. Cards use rounded-xl, border-border/50, bg-card, and p-6. Hover state adds shadow-md and border-primary/20.

Card pattern
<div className="rounded-xl border border-border/50 bg-card p-6
     transition-all duration-200 hover:shadow-md hover:border-primary/20">
  <h3 className="text-base font-semibold text-foreground mb-1">Title</h3>
  <p className="text-sm text-muted-foreground">Description</p>
</div>

Code block

Dark background (#0A1628), slate-300 text, optional title bar, copy button on hover. Import from @/components/docs/code-block.

import { CodeBlock } from "@/components/docs/code-block";

<CodeBlock language="yaml" title="example.yaml">
  {`key: value`}
</CodeBlock>

Section label

Used in sidebar nav and card group headers.

Section Label

<p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
  Section Label
</p>

Next steps card

Every doc page ends with this. Links to related pages.

<section className="mt-16 rounded-xl border border-border/50 bg-card p-8">
  <h2 className="text-xl font-bold text-foreground mb-4">Next steps</h2>
  <div className="grid gap-3 sm:grid-cols-2">
    <Link href="/docs/page" className="group flex items-center gap-2 text-sm
      text-muted-foreground hover:text-foreground transition-colors">
      <ArrowRight className="h-3.5 w-3.5 text-primary" />
      <span>Link text</span>
    </Link>
  </div>
</section>

Multi-Brand Theme System

Graspful is white-label. Each brand defines its own colors, gradients, and radius in the brand config. The BrandThemeStyle component injects these as CSS custom properties at runtime, overriding the defaults in globals.css.

Available brand presets

Sky Blue(Graspful (default))
#0EA5E9
Red / Orange(FirefighterPrep)
#FF6600
Blue(ElectricianPrep)
#3B82F6
Yellow(JSPrep)
#EAB308
Orange(PostHog TAM)
#F97316

How theming works

brand.yaml — theme section
theme:
  preset: sky          # Not used at runtime — colors are explicit
  radius: "0.625rem"   # Border radius base

# Colors are defined in the TypeScript brand config (defaults.ts)
# as BrandThemeColors objects for light and dark modes.
# BrandThemeStyle converts them to CSS custom properties.
How BrandThemeStyle works
// In root layout.tsx:
<BrandThemeStyle brand={brand} />

// This injects a <style> tag:
// :root { --primary: hsl(199 89% 48%); ... }
// .dark { --primary: hsl(199 89% 58%); ... }

// All Tailwind classes (bg-primary, text-foreground, etc.)
// automatically pick up the brand's colors.

Dark Mode

Dark mode is supported via the .dark class on the HTML element. The ThemeProvider manages toggling. Marketing pages force light mode.

Each brand defines both theme.light and theme.dark color sets. The app layout (student dashboard, study flow) respects the user's preference. Marketing pages always render in light mode.

Next steps