PRIZM 4.0DSTA

Foundations

Icons

Icons in PRIZM use lucide-react — a wide, well-maintained, MIT-licensed set bundled as React components. No remote fetches, air-gap safe out of the box. PRIZM overrides the stroke-width site-wide for a lighter, more precise aesthetic.

Stroke width

Lucide's default stroke-width is 2. PRIZM overrides to 1.5 via a single rule in app/globals.css:

css
@layer base {
  svg {
    stroke-width: 1.5;
  }
}

Default (lucide stock)

stroke-width: 2

PRIZM site-wide

stroke-width: 1.5

The lighter stroke reads as more precise and pairs better with PRIZM's typography weights. The override applies to ALL svg elements site-wide. To deviate on a single icon, use the Tailwind arbitrary modifier ([stroke-width:2]) or inline style. The lucide strokeWidth prop is overridden by the CSS rule, so prop-level changes have no effect.

Size scale

Five sizes cover essentially every use case. Apply via Tailwind class on the icon element. Sizes are not enforced by tokens — the goal is to keep choices small and predictable, not to gate them.

ClassPixelsUse caseSample
h-3 w-312pxInside Badge, dense status indicators, kbd glyphs
h-3.5 w-3.514pxSmall buttons (size sm), breadcrumb separators
h-4 w-416px (default)Most buttons, inline with body text, command palette
h-5 w-520pxSection headers, icon rail items, foundation cards
h-6 w-624pxEmpty states, hero placements, oversized affordances

Pairing with text

Use inline-flex items-center and an explicit gap that scales with the text. Vertical centering is rarely correct by default — let flex align them.

Continue

h-4 w-4 + text-sm + gap-2

Default for buttons and inline calls to action

Helper text

h-3.5 w-3.5 + text-xs + gap-1.5

Captions, hints, status chips

Dashboard

h-5 w-5 + text-base + gap-3

Section headers, nav rail tooltips when expanded

Accessibility

The two rules that cover 95% of cases:

Decorative (alongside a visible label)

Add aria-hidden so screen readers skip the icon. The label conveys the meaning.

tsx
<Button>
  <Check className="h-4 w-4" aria-hidden />
  Save changes
</Button>

Meaningful (icon-only control)

Put aria-label on the container, not the icon. The icon stays decorative.

tsx
<Button variant="ghost" size="icon" aria-label="Settings">
  <Settings className="h-4 w-4" aria-hidden />
</Button>

Common icons

The 30 icons PRIZM uses most across components and templates. Not a full catalogue — lucide ships ~1,500 icons; any of them can be imported the same way.

Actions

Check
X
Plus
Copy
Search
Settings
ArrowRight
ArrowLeft

Chevrons

ChevronDown
ChevronUp
ChevronRight
ChevronLeft

Status & feedback

Info
AlertTriangle
AlertCircle
CheckCircle
Bell

People & containers

User
Users
Home
FileText
LayoutDashboard
LayoutGrid
MessageSquare
Eye

Theme & state

Sun
Moon
Droplet

Misc

Github
ExternalLink

Import any of these by name from lucide-react:

tsx
import { Check, Search, Settings } from "lucide-react";

Custom SVGs

For brand marks and product-specific glyphs lucide doesn't cover, write the SVG inline. Set stroke-width on each <path> directly — the site-wide svg { stroke-width: 1.5 } only affects elements that don't have an explicit per-path value. Include a <title> for accessibility.

PRIZM brand mark

Used in the site header and C3 App Shell

tsx
<svg
  viewBox="0 0 24 24"
  fill="none"
  className="h-5 w-5 text-accent"
  aria-hidden
>
  <title>PRIZM</title>
  <path
    d="M12 2L22 20H2L12 2Z"
    stroke="currentColor"
    strokeWidth="2"
    strokeLinejoin="round"
  />
  <path
    d="M12 2L12 20"
    stroke="currentColor"
    strokeWidth="2"
    strokeLinejoin="round"
  />
</svg>

Air-gap

lucide-react ships every icon as a React component bundled into your build — no remote fetches. PRIZM's air-gap audit (pnpm audit:airgap) does not flag lucide. Custom SVGs vendored inline are also safe. The only thing that would break air-gap discipline is referencing a remote icon font or external SVG URL — don't do that.