---
version: alpha
name: Fontshare
description: Warm cream type-browser by Indian Type Foundry — a flat, borderless utility interface in off-white and near-black, Passenger Sans variable at every scale, and pill geometry as the sole shape vocabulary.

colors:
  # Surface / canvas
  background: "#ffffe3"          # warm cream — the page's defining chromatic decision
  surface: "#ffffe3"             # same cream; no inner surface differentiation

  # Ink / text
  ink: "#10100e"                 # near-black CSS custom property --black-b-color
  ink-secondary: "#606055"       # muted labels, metadata, secondary filters
  on-primary: "#ffffe3"          # cream text on dark interactive fills

  # Brand accent — the inversion
  primary: "#10100e"             # near-black used as CTA fill (inverted button)
  primary-hover: "#30302b"       # slightly lifted dark hover state
  on-surface: "#10100e"          # text on cream surface

  # Borders / chrome
  border: "#c0c0ab"              # warm gray -- CSS variable --gray-b-color; resting card edges
  border-strong: "#30302b"       # darker 2px border, selected state
  border-subtle: "#e8e8cf"       # hairline inset — 1px bottom divider

  # Shadow / depth
  shadow-soft: "#e8e8cf"         # opaque approx of very subtle lift — no true shadow system

typography:
  display-hero:
    fontFamily: "Passenger Sans, system-ui, -apple-system, sans-serif"
    fontSize: 72px
    fontWeight: 700
    lineHeight: 1.0
    letterSpacing: -1.5px
  display:
    fontFamily: "Passenger Sans, system-ui, -apple-system, sans-serif"
    fontSize: 40px
    fontWeight: 700
    lineHeight: 1.05
    letterSpacing: -0.8px
  heading-section:
    fontFamily: "Passenger Sans, system-ui, -apple-system, sans-serif"
    fontSize: 24px
    fontWeight: 700
    lineHeight: 1.1
    letterSpacing: -0.3px
  heading-sub:
    fontFamily: "Passenger Sans, system-ui, -apple-system, sans-serif"
    fontSize: 18px
    fontWeight: 500
    lineHeight: 1.3
    letterSpacing: 0px
  body-large:
    fontFamily: "Passenger Sans, system-ui, -apple-system, sans-serif"
    fontSize: 16px
    fontWeight: 500
    lineHeight: 1.19
    letterSpacing: 0px
  body:
    fontFamily: "Passenger Sans, system-ui, -apple-system, sans-serif"
    fontSize: 16px
    fontWeight: 400
    lineHeight: 1.19
    letterSpacing: 0px
  nav-link:
    fontFamily: "Passenger Sans, system-ui, -apple-system, sans-serif"
    fontSize: 16px
    fontWeight: 500
    lineHeight: 1.0
    letterSpacing: 0px
  button-ui:
    fontFamily: "Passenger Sans, system-ui, -apple-system, sans-serif"
    fontSize: 16px
    fontWeight: 500
    lineHeight: 1.0
    letterSpacing: 0px
  caption:
    fontFamily: "Passenger Sans, system-ui, -apple-system, sans-serif"
    fontSize: 12px
    fontWeight: 500
    lineHeight: 1.17
    letterSpacing: 0px
  caption-bold:
    fontFamily: "Passenger Sans, system-ui, -apple-system, sans-serif"
    fontSize: 12px
    fontWeight: 700
    lineHeight: 1.17
    letterSpacing: 0px

spacing:
  xs: 5px
  sm: 10px
  md: 20px
  lg: 40px
  xl: 60px
  2xl: 100px
  3xl: 120px

rounded:
  none: 0px
  pill: 9999px

components:
  button-primary:
    backgroundColor: "{colors.primary}"
    textColor: "{colors.on-primary}"
    typography: "{typography.button-ui}"
    rounded: "{rounded.pill}"
    padding: 10px 20px
  button-primary-hover:
    backgroundColor: "{colors.primary-hover}"
    textColor: "{colors.on-primary}"
    typography: "{typography.button-ui}"
    rounded: "{rounded.pill}"
    padding: 10px 20px

  button-secondary:
    backgroundColor: "{colors.background}"
    textColor: "{colors.ink}"
    typography: "{typography.button-ui}"
    rounded: "{rounded.pill}"
    padding: 10px 20px
    borderColor: "{colors.border}"
  button-secondary-hover:
    backgroundColor: "{colors.background}"
    textColor: "{colors.ink}"
    typography: "{typography.button-ui}"
    rounded: "{rounded.pill}"
    padding: 10px 20px
    borderColor: "{colors.border-strong}"

  card:
    backgroundColor: "{colors.background}"
    rounded: "{rounded.none}"
    padding: 20px
    borderColor: "{colors.border}"
  card-selected:
    backgroundColor: "{colors.background}"
    rounded: "{rounded.none}"
    padding: 20px
    borderColor: "{colors.border-strong}"

  badge:
    backgroundColor: "{colors.background}"
    textColor: "{colors.ink-secondary}"
    typography: "{typography.caption}"
    rounded: "{rounded.pill}"
    padding: 4px 10px
    borderColor: "{colors.border}"
  badge-active:
    backgroundColor: "{colors.primary}"
    textColor: "{colors.on-primary}"
    typography: "{typography.caption}"
    rounded: "{rounded.pill}"
    padding: 4px 10px

  input:
    backgroundColor: "{colors.background}"
    textColor: "{colors.ink}"
    typography: "{typography.body}"
    rounded: "{rounded.none}"
    padding: 10px 40px
  input-focus:
    backgroundColor: "{colors.ink}"
    textColor: "{colors.on-primary}"
    typography: "{typography.body}"
    rounded: "{rounded.none}"
    padding: 10px 40px

  nav:
    backgroundColor: "{colors.background}"
    textColor: "{colors.ink}"
    typography: "{typography.nav-link}"
    rounded: "{rounded.none}"
    padding: 0px 20px
    borderColor: "{colors.border-subtle}"
---

# Fontshare Design System

## Overview

Fontshare arrives looking like the inside of a well-lit type specimen book that someone quietly turned into a website. The {colors.background} canvas — a warm cream that sits closer to an aged page than a clinical off-white — immediately separates it from the monochrome gray-on-white default of tech products. Nothing here is cold. The near-black {colors.ink} text, a shade so deep it barely distinguishes itself from true black, reads against that cream with the contrast of ink on a premium uncoated stock. The palette is, in effect, two colors and a handful of warm grays. All the chromatic work is done before a single font card loads.

The typography is Passenger Sans, Indian Type Foundry's own variable grotesque. Using your own product to build your product is an obvious but reliable move — every font card rendered in Satoshi or Clash Display implicitly argues for the library's range, but the interface itself stays consistent, structured, and out of the way in Passenger Sans. The font is warm where Helvetica is neutral, slightly condensed where Inter is relaxed. At UI scale (16px / 1.19 leading) it's unremarkable in the best sense — legible and quiet. The font preview area is where the typographic drama belongs; the chrome understands its supporting role.

Border-radius is entirely binary. Pill geometry at {rounded.pill} handles every interactive element — filter chips, category tags, search input, shortlist toggle — and hard squares at {rounded.none} govern every card frame and content container. There is no middle ground. No 8px radius softening the grid cells, no 16px rounding on panels. The result is a UI that reads as a precise instrument: interactive affordances are soft and approachable, structural containers are rectilinear and grid-strict. This shape discipline makes the browser fast to scan — if it's rounded, it filters or navigates; if it's square, it contains.

**Key Characteristics:**
- {colors.background} warm cream canvas — the entire site's chromatic identity rests on this single non-neutral decision
- {colors.ink} near-black from CSS `--black-b-color` — not pure #000000, a warmth that binds to the cream field
- Passenger Sans variable (ITF's own font) at 500–700 weight for all chrome type
- Exactly two radius values: {rounded.none} for cards/containers and {rounded.pill} for all interactive controls
- {colors.border} warm gray used as the resting border on 2px strokes throughout the grid
- {colors.border-strong} darker 2px border signals selected/active state with no color change needed
- Completely flat elevation model — zero shadows, zero gradients anywhere in the UI
- Font preview rendered at user-adjustable px size with a drag slider (10px–210px range)
- Dark inversion CTA: primary button is near-black {colors.primary} on cream — not a colored accent
- 0.15s `cubic-bezier(0.4, 0, 0.2, 1)` transition on all interactive element color changes
- Search input inverts to {colors.ink} background on focus — the only high-contrast shift in the system
- Filter chips display counts (categories show total fonts, styles show personality counts) in {typography.caption}

## Colors

### Primary

- **Warm Cream** (`{colors.background}`): The page canvas. Every UI element lives on this field. Not pure white, not beige — closer to the color of a warm fluorescent-lit paper. Immediately communicates "type culture" without a single word.
- **Near-Black** (`{colors.ink}`): Primary text, card font-name labels, nav items, all headings. The CSS variable is `--black-b-color`. The slight warmth prevents the interface from reading as stark.

### Brand Accent

- **Inverted Dark** (`{colors.primary}`): The system has no colored accent. Instead, the primary call-to-action is a near-black fill with cream text — an inversion of the surface. Used for primary CTA buttons and active toggle states. This design choice keeps the palette intact while providing a clear interactive signal.

### Text States

- **Warm Gray** (`{colors.ink-secondary}`): Caption metadata, foundry attribution lines, secondary filter labels. Readable but clearly de-emphasized. Sits mid-palette between the cream canvas and near-black text.
- **On-Primary** (`{colors.on-primary}`): The cream color reused as text on dark button fills — the palette loops back on itself.

### Borders and Dividers

- **Gray Warm** (`{colors.border}`): The dominant border value. Used as a 2px solid stroke on every font card in the grid at rest. CSS variable `--gray-b-color`. The warmth matches the canvas — no cold gray intrusions.
- **Border Strong** (`{colors.border-strong}`): Darker 2px border for selected, active, or hovered states. The only interaction signal is a border-color shift — no fill change, no shadow.
- **Border Subtle** (`{colors.border-subtle}`): A hairline inset-bottom divider on the header strip and table-like layouts. Barely perceptible, structural.

## Typography

### Font Family

- **Primary**: `Passenger Sans` (self-hosted variable woff2: `PassengerSans-Variable.woff2`), with fallbacks: `system-ui, -apple-system, sans-serif`
- Passenger Sans is a variable grotesque published by Indian Type Foundry — the same studio behind Fontshare. It ships as a waxis variable font with weights 400–700 accessible from a single file.
- **Monospace**: Not used. The system is entirely single-family.
- **OpenType Features**: Variable axis (`wght`) used throughout; no explicit `font-feature-settings` declarations observed.

### Hierarchy

The complete type scale is in the `typography:` token block above.

| Token | Use |
|---|---|
| `display-hero` | Specimen-scale font name previews at maximum slider size |
| `display` | Section headings, landing page font name at hero |
| `heading-section` | Sub-section titles, panel headers |
| `heading-sub` | Card metadata headings, modal section titles |
| `body-large` | Nav links, active filter labels, primary list items |
| `body` | Description text, license terms, secondary list items |
| `nav-link` | Top navigation bar links and tab labels |
| `button-ui` | All interactive control labels — filters, CTAs, toggles |
| `caption` | Style count badges, metadata, weight/style labels |
| `caption-bold` | Emphasis within caption-scale text, license type labels |

### Principles

- Passenger Sans is used at weight 500 for UI chrome and 700 for display-scale specimen labels — two working weights from a single variable font file.
- Letter-spacing is negative only at display scale (−1.5px at 72px, −0.8px at 40px); body and UI type use zero tracking throughout.
- Line height at UI scale is tight at 1.19 — closer to the line spacing of a printed specimen book than a typical web app.
- The font preview tiles render the specimen text in the highlighted font at the user's chosen slider value — a live variable-font axis demonstration built into the browse interface.
- No secondary typeface anywhere. The design stakes its identity entirely on showing a rotating cast of type in the preview tiles, keeping the surrounding chrome in one consistent voice.

## Layout

### Spacing System

The complete spacing scale is in the `spacing:` token block above. Base unit: 5px — an uncommon choice reflecting the ITF/South Asian type design sensibility (5px increments at the micro end, scaling to 10, 20, 40, 60, 100, 120).

The spacing personality is tight at the component level and generous at section scale. Filter chips and nav items breathe on 10–20px gaps; the specimen hero area and full-page browse canvas use 60–120px vertical breathing room.

### Grid & Container

- Max content width: approximately 1700px — wide container, designed for font-browser use at large displays
- Primary layout: full-width horizontal nav tabs, then a filter row, then a fluid-grid font list (1-up list view or variable-column grid view)
- Font cards in list view: single full-width card per row with font name left and metadata (style count, format, source) right
- Grid view: responsive masonry-like grid of specimen tiles
- The preview text area is full-width — the font name in the selected font at 210px default scale occupies the majority of the viewport

### Whitespace Philosophy

- Whitespace is functional, not decorative. The browse tool is information-dense by necessity — 100+ fonts browsed in a single scroll session.
- Cards use minimal padding ({spacing.md} internal) with 2px border doing the separation work instead of gaps between cells.
- The slim `{spacing.xs}` (5px) and `{spacing.sm}` (10px) values dominate interactive element internals — filters, badges, nav links are all compact.

## Elevation & Depth

| Level | Treatment | Use |
|---|---|---|
| Flat (Level 0) | No shadow | Entire system — page, nav, cards, modals |
| Border (Level 1) | `2px solid {colors.border}` | Resting card frames, unselected filter chips |
| Border Active (Level 2) | `2px solid {colors.border-strong}` | Selected/active card frames, nav tab active |
| Inset (Level 3) | `0 1px 1px solid {colors.border-subtle}` | Header bottom divider, table-row separators |
| Focus Ring | `box-shadow: 0 0 0 3000px {colors.ink} inset` | Search input: full inversion on focus |
| Modal | Not used | — |

**Shadow Philosophy**: Fontshare runs a shadow-free design. Depth is entirely structural — border-color shifts signal interaction, border presence signals containment. The only dramatic visual shift in the system is the search input's focus inversion, which floods the input background with {colors.ink} near-black using a 3000px inset shadow trick. This is the system's one piece of theater. Everything else is flat.

## Shapes

The complete radius scale is in the `rounded:` token block above. The system uses:

| Token | Value | Use |
|---|---|---|
| `none` | 0px | Font cards, image containers, panels, the search input box |
| `pill` | 9999px | Filter chips, category tags, style tags, CTA buttons, shortlist toggle, count badges |

Fontshare's shape system is the most disciplined binary in its peer set. There are precisely two options and no exceptions observed. Cards are strict squares. Buttons and tags are always pills. The shape is the affordance: pills filter, squares hold. A font designer's appreciation for the weight of a decision — make it, commit to it, don't hedge.

## Components

The complete component spec lives in the `components:` token block above.

### Button Variants

- **`button-primary`** — Near-black {colors.primary} fill on cream text, full pill radius. Used for primary actions like "Download All Styles." The system's single high-contrast UI moment.
- **`button-secondary`** — Cream background, {colors.border} 2px stroke, {colors.ink} text, pill radius. Used for secondary CTAs, alternative view modes, export options.

### Cards

Font list cards use `{rounded.none}` with a 2px `{colors.border}` resting border. The card is sparse — font name in `{typography.heading-section}`, designer attribution in `{typography.caption}`, style count + format metadata right-aligned. The entire card surface is clickable. Hover and selected states step up to `{colors.border-strong}` without fill change.

### Inputs

The search input uses `{rounded.none}` with no visible border at rest — a full-width underline style. On focus, the background floods to `{colors.ink}` via an aggressive inset box-shadow, and text color switches to `{colors.on-primary}` cream. This is the most visually striking interaction in the system: typing a search query inverts the input field to a dark window within the cream page.

### Badges and Tags

Filter chips and category/style badges use `{rounded.pill}` with `{colors.border}` outline and `{colors.ink-secondary}` text at rest. Active/selected state inverts to `{colors.primary}` fill and `{colors.on-primary}` text. Count numerals are `{typography.caption}` inline with the label.

### Navigation

The global nav is a flat `{colors.background}` strip with a `{colors.border-subtle}` bottom edge. Four primary tabs (Fonts, Pairs, Licenses, a hamburger toggle) with a count sub-label ("100", "59") beneath the active labels. The active tab uses a `{colors.border-strong}` indicator — a 2px bottom stroke. No pill container, no fill change on the nav itself.

## Do's and Don'ts

### Do

- Use `{colors.background}` warm cream as the only canvas color — never substitute cool white or gray surfaces in the same product context
- Apply `{rounded.pill}` to every interactive control (buttons, filter chips, tag badges, toggles) without exception
- Keep `{rounded.none}` for every container, card frame, and input field — the binary is the system's visual identity
- Use `{colors.border}` 2px solid as the resting border weight for cards; reserve `{colors.border-strong}` exclusively for selected or active states
- Set all UI chrome in Passenger Sans weight 500; reserve weight 700 for display-scale specimen text only
- Rely on border-color shifts alone for hover/active feedback — no fills, no shadows, no scale transforms
- Keep the search input flat at rest; the focus inversion to `{colors.ink}` is the system's deliberate dramatic moment — preserve it
- Use `{colors.ink-secondary}` for metadata and attribution copy to maintain legible hierarchy without introducing new colors

### Don't

- Don't introduce any colored accent into the UI chrome — the palette is cream, near-black, and warm grays; color lives only in the font specimens
- Don't apply box shadows or drop shadows to any element — the system is categorically flat
- Don't round cards or content containers with any non-zero border-radius — `{rounded.none}` on containers is non-negotiable
- Don't use weight 400 for interactive labels or nav items — weight 500 is the minimum for any UI text
- Don't introduce a second typeface; even code or numbers should use Passenger Sans
- Don't substitute cool or neutral gray tones for `{colors.border}` — the warmth of the gray must match the canvas
- Don't use fill changes to signal hover states on cards; the 2px border-color shift is the only permitted interaction signal
- Don't set positive letter-spacing on any token — the system uses zero or negative tracking throughout
- Don't place pill-radius shapes in structural/container roles — users will expect them to be interactive

---

## Responsive Behavior

### Breakpoints

| Name | Width | Key Changes |
|---|---|---|
| Mobile Small | <360px | Single column, compact filter row, font name wraps |
| Mobile | 360–576px | Filter strip scrolls horizontally, nav collapses |
| Mobile Large | 576–767px | 1-column browse list, slider hidden |
| Tablet | 767–1023px | 2-column grid view available, filter row expands |
| Desktop | 1023–1400px | Full filter row, 3-column grid view, slider visible |
| Wide Desktop | 1400–1700px | 4-column grid, specimen hero at full width |
| Ultra Wide | >1700px | Content constrains at ~1700px, canvas fills beyond |

### Touch Targets

Pill buttons and filter chips use `{spacing.sm}` (10px) vertical padding and `{spacing.md}` (20px) horizontal, giving a 36–40px tap height. Font list-view cards are full-width rows with adequate vertical padding. The preview text drag-slider is a wide-handle range input with visible hit area.

### Collapsing Strategy

The horizontal filter row collapses to a scrollable single-line strip below 767px; the full category/properties/personality filter UI moves to a modal drawer. The grid view converts to list-only on narrow viewports. The specimen font-size slider is hidden below 576px, defaulting to a fixed preview size. The top nav tabs condense: counts ("100", "59") may be hidden on the narrowest breakpoints, leaving the tab label only.

### Image Behavior

Font specimen previews are text-rendered (no raster images) — they reflow and rescale with the viewport naturally. The preview size slider directly controls `font-size` on a live text node; responsive reflow occurs in real time. The Fontshare wordmark in the nav is SVG/text and scales without degradation.

---

## Agent Prompt Guide

### Quick Color Reference

- Background: `{colors.background}`
- Text: `{colors.ink}`
- Secondary text: `{colors.ink-secondary}`
- Border (resting): `{colors.border}`
- Border (active): `{colors.border-strong}`
- CTA fill: `{colors.primary}`
- CTA text: `{colors.on-primary}`

### Example Component Prompts

- "Build a Fontshare-style font browser card: {colors.background} fill, `{rounded.none}` (0px radius), 2px solid `{colors.border}` resting border. Left: font name in `{typography.heading-section}` (Passenger Sans 24px 700) in `{colors.ink}`. Below the name: designer attribution in `{typography.caption}` (12px 500) in `{colors.ink-secondary}`. Right-aligned: style count + format badge in `{typography.caption}`. On hover, switch border to `{colors.border-strong}`. Flat — no shadow."
- "Create a Fontshare filter chip: `{rounded.pill}` (9999px), 2px solid `{colors.border}`, `{colors.background}` fill, `{colors.ink-secondary}` label in `{typography.button-ui}` (16px 500). Active state: fill `{colors.primary}`, text `{colors.on-primary}`, border `{colors.primary}`. Padding 4px 10px. 0.15s ease color transition."
- "Design a Fontshare search input: full width, `{rounded.none}`, no visible border at rest — only a 1px `{colors.border-subtle}` bottom edge. Placeholder in `{typography.body}` (16px 400) `{colors.ink-secondary}`. On focus, apply `box-shadow: 0 0 0 3000px {colors.ink} inset` to flood the background near-black; switch text and placeholder to `{colors.on-primary}`. 0.15s ease transition."
- "Build a Fontshare navigation bar: `{colors.background}` background, full-width, `{colors.border-subtle}` bottom 1px edge. Four tab items in `{typography.nav-link}` (16px 500): 'Fonts', 'Pairs', 'Licenses', and a hamburger icon. Active tab has a 2px solid `{colors.border-strong}` bottom indicator. Below the active tab label show a numeric count in `{typography.caption}` (12px 500) `{colors.ink-secondary}`. Right: shortlist toggle as a {rounded.pill} icon button in {colors.primary}."
- "Create a Fontshare specimen hero: `{colors.background}` canvas, full viewport width. Font name as live text in `{typography.display-hero}` (Passenger Sans 72px 700 letter-spacing −1.5px) in `{colors.ink}`. Below: designer credit in `{typography.caption}` (12px 500) `{colors.ink-secondary}` with 'Indian Type Foundry' right-aligned. Below that: a row of pill-shaped style tags using `{components.badge}`. No shadow, no gradient, no image."
- "Design a Fontshare-style font pairing card: two stacked specimen rows on a `{colors.background}` surface with `{rounded.none}` container and 2px `{colors.border}` outline. Top row: Passenger Sans body line; bottom row: paired font body line. Between rows: a 1px `{colors.border-subtle}` divider. Font names as pill chips `{components.badge-active}` at top-right of each row."

### Iteration Guide

1. Start with `{colors.background}` warm cream and `{colors.ink}` near-black — the palette is two colors; resist adding any third hue to the chrome
2. Assign shape by function: `{rounded.pill}` for everything interactive; `{rounded.none}` for everything structural — there is no middle case
3. Use 2px `{colors.border}` borders in place of shadows for all card containment; shift to `{colors.border-strong}` on active/selected state
4. Set all UI type at Passenger Sans weight 500; reserve weight 700 for specimen-scale display text only
5. The search input focus inversion (flooding the field with `{colors.ink}`) is the system's single moment of drama — keep it
6. All transitions at 0.15s `cubic-bezier(0.4, 0, 0.2, 1)` on color properties; never add scale or translate transforms to the browse chrome
7. Let the font specimens carry the visual color and personality — the UI chrome should remain a neutral warm stage

---

## Attribution

Independent design analysis from [Design Swatches](https://designmd.santiagoalonso.com) by [Santiago Alonso](https://santiagoalonso.com). Based on publicly observable interface patterns. Not affiliated with or endorsed by Fontshare. Brand names and trademarks belong to their respective owners.
