# Incline design reference
Version: 1.0
The foundations and real components behind Incline. A living reference for the people and agents building thoughtful tools for work.
Manifest: /style/guide.json
CSS tokens: /style/tokens.css
## Instructions for agents
- Use the documented components and their import paths before creating new primitives.
- Use semantic CSS tokens instead of hard-coded values.
- Treat example code as executable usage and follow the accessibility requirements.
- Preserve documented variants. Propose an addition when an existing component does not fit.
- This is Incline's production design contract. Read docs/frontend-style-guide.md before changing product UI.
- Use Söhne 400 and 500 only. Never request a Söhne weight above 500. Keep page, detail, and dialog headings at 400.
- Use the existing type-body, type-supporting, type-heading-component, type-heading-context, and type-heading-page classes. Body is 14px; supporting text is 13px; headings are 16, 22, and 36px.
- IBM Plex Mono is for code and structured data. Labels, metadata, identifiers, timestamps, and metrics stay in Söhne. Inter is reserved for numeric alignment through font-numeric.
- Use the documented Tailwind spacing, radius, and duration utilities. Utility-only foundations are not new global CSS variables.
- Use uppercase sparingly with at most 0.04em tracking. Favor white backgrounds and negative space; borders clarify essential structure only.
- Use blue for primary actions and focus. Status colors carry runtime state, not decoration. Avoid broad muted page backgrounds.
- Standard controls are 36px and compact controls 32px. Buttons, single-line inputs, selects, dropdown triggers, and badges use rounded-full; textareas use an 18px radius.
- Reuse the imports documented here. Add variants to primitives before introducing new one-off components. Do not override primitive corner radii outside compound interior joins.
- Dropdown ghost and outline share geometry; fullWidth is independent of variant. width sizes the popup, not the trigger. Use options/value/onValueChange for selection and DropdownItem for actions.
- Retain focus rings and accessible labels, including icon-only actions. Input and Textarea call sites must supply the documented focus-visible ring classes.
- Use Surface for shared material, GlassSurface only for functional floating layers, and DialogTitle for the 22px heading with its automatic close action.
- Samples use local state and never call the API. Their renderer wrappers are in web/src/style-guide/previews.tsx; implementation imports point to production components.
- Maintain web/src/style-guide/guide.ts and previews.tsx together. Run pnpm --dir web style:reference after edits; dev and build do this automatically. Never edit generated public/style files directly.
## Principles
- Information first: A professional control surface with a clear grid and Swiss editorial discipline.
- A little breathing room: White canvas, authored content, and deliberate negative space. Keep the chrome compact.
- One shared language: Production components, honest states, and accessible interactions. Extend before inventing.
## Typography
Font: Söhne; stack: "Soehne", "Helvetica Neue", Arial, sans-serif
- --font-size-heading-page: 2.25rem; line height 1.08; weight 400. Page.
- --font-size-heading-context: 1.375rem; line height 28px; weight 400. Context.
- --font-size-heading-component: 1rem; line height 1.5; weight 500. Component.
- --font-size-body: 0.875rem; line height 1.5; weight 400. Body.
- --font-size-supporting: 0.8125rem; line height 1.5; weight 400. Supporting.
## Color
- --foreground: #191917. Ink. Primary type and icons.
- --background: #ffffff. Canvas. The white workspace.
- --surface-subtle: #f9f9f8. Subtle. Quiet local grouping and hover.
- --border: #e8e8e3. Line. Essential structure only.
- --muted-foreground: #74736d. Supporting. Secondary attributes and context.
- --primary: #1546d8. Blue. Primary actions and focus.
- --surface-brand-subtle: #f3f5fb. Blue tint. A restrained interactive tint.
- --success: #37c991. Success. Positive runtime state.
- --success-foreground: #087653. Success text. Readable positive status text.
- --warning: #f4b33d. Warning. A state that needs attention.
- --warning-foreground: #8a4b08. Warning text. Readable caution labels.
- --destructive: #d83a4e. Destructive. Errors and destructive actions.
## Foundations
A 4px spacing rhythm. Semicircular controls. Softness reserved for surfaces that need it.
- class gap-1: 4px. 1.
- class gap-2: 8px. 2.
- class gap-3: 12px. 3.
- class gap-4: 16px. 4.
- class gap-6: 24px. 6.
- class gap-8: 32px. 8.
- class gap-12: 48px. 12.
- class gap-16: 64px. 16.
- class rounded-xl: 12px. Surface.
- class rounded-[18px]: 18px. Textarea.
- class rounded-full: 999px. Control.
- class duration-150: 150ms. Feedback.
- class duration-300: 300ms. Transition.
## Actions
One clear next step. The same familiar geometry, at every level of emphasis.
### Button
The shared shadcn-style action, with pill geometry and a visible focus ring.
Import: @/components/ui/button
Usage:
- Choose an existing variant; keep the primitive's radius.
- Use type="button" outside intentional form submission.
- Use asChild with a link for navigation.
Accessibility:
- Label every icon-only action.
- Preserve disabled, aria-busy, and keyboard-focus states.
Props:
- variant: 'default' | 'outline' | 'secondary' | 'ghost' | 'destructive' | 'link' (default: default). Action emphasis.
- size: 'default' | 'sm' | 'icon' | 'icon-sm' (default: default). 36px standard or 32px compact.
#### A useful hierarchy [button-variants]
Primary, outline, secondary, ghost, destructive, and link. Click an action to try its local loading state.
```tsx
```
#### Every state counts [button-states]
Compact, disabled, and busy. Loading feedback stays in place.
```tsx
```
#### A little less chrome [button-icons]
A labeled icon action with a pressed state. Try adding it to favorites.
```tsx
```
### SplitButton
An independent main action and an adjacent menu.
Import: @/components/ui/split-button
Usage:
- Keep the main action independent of its menu.
Accessibility:
- Supply menuLabel for the secondary trigger.
#### Two related choices [split-button-default]
Try opens a local dialog; the menu offers a separate continuous run.
```tsx
Try>} onAction={openRunDialog} menuLabel="More run options">
{(close) => { close(); openContinuousDialog(); }} />}
```
### EditorHeaderButton
A background-free action for access, history, and other header dialogs.
Import: @/components/editor-header
Usage:
- Keep header actions quiet and compact.
Accessibility:
- Open the related dialog and return focus to its trigger.
#### Quietly available [header-actions-default]
Access and version history, with real production dialogs.
```tsx
PrivateLive v3
```
## Inputs
A clear label, a comfortable target, and useful guidance. Native behavior comes first.
### Input
The production 36px pill-shaped text input.
Import: @/components/ui/input
Usage:
- Use a visible, associated label.
- Add the shared focus-visible ring at the call site.
Accessibility:
- Connect hints and errors with aria-describedby.
- Use aria-invalid for an invalid field and an appropriate input type.
#### Start with a name [input-default]
A persistent label and the shared focus treatment.
```tsx
```
#### Consider the edges [input-states]
Compact, disabled, and overflowing values.
```tsx
```
### Textarea
A multiline input with an 18px corner radius.
Import: @/components/ui/textarea
Usage:
- Use for freeform instructions; allow vertical resizing.
Accessibility:
- Provide a label and a visible focus ring.
#### Room for a thought [textarea-default]
Freeform instructions, with the production compound-control geometry.
```tsx
```
### NativeSelect
A native picker with the shared control shape and one chevron.
Import: @/components/ui/native-select
Usage:
- Keep the platform picker; do not add a second chevron.
Accessibility:
- Associate a label with the select.
#### A familiar choice [native-select-default]
Choose a date range using the native platform control.
```tsx
```
## Selection
Menus, values, and views. Consistent controls with the right semantics for each choice.
### Dropdown
The shared popup for action menus and single-value selection.
Import: @/components/ui/dropdown
Usage:
- Use DropdownItem children for actions; options/value/onValueChange for selection.
- ghost and outline share geometry. fullWidth controls the trigger; width controls the popup.
Accessibility:
- Provide a label. Keep built-in menu/listbox semantics and arrow-key behavior.
#### Actions in context [dropdown-menu]
The outline and ghost triggers share geometry. Choose an action to update the label.
```tsx
{(close) => { rename(); close(); }} />}
```
#### One selected value [dropdown-selection]
Grouped options, descriptions, a long label, and a disabled option.
```tsx
```
#### An intentional width [dropdown-full-width]
fullWidth affects the trigger independently of its visual variant.
```tsx
```
#### Even when nothing is ready [dropdown-states]
Disabled, loading, and an empty option list.
```tsx
undefined} options={modelOptions} />
undefined} options={[]} />
```
### SegmentedControl
The Assistant / Editor mode switch.
Import: @/components/ui/segmented-control
Usage:
- Use for closely related modes, not independent actions.
Accessibility:
- Supply ariaLabel and keep arrow, Home, and End navigation.
- Connect tab IDs and controls to corresponding panels.
#### A change of perspective [segmented-control-default]
Switch between Assistant and Editor using a click or the keyboard.
```tsx
```
### Tabs
Related views with an anchored active indicator.
Import: @/components/ui/tabs
Usage:
- Compose Tabs, TabsList, TabsTrigger, and TabsContent.
Accessibility:
- Label the tab list and retain Radix keyboard semantics.
#### A place for each view [tabs-default]
Change the selected view to show its local content.
```tsx
WorkflowTasksCustomer renewal3 tasks in progress
```
## Feedback
Small, readable signals that say what is happening. Color always comes with words.
### RunStatusBadge
The product's shared runtime status labels, built on Badge.
Import: @/components/status-badge
Usage:
- Use the real RunStatus value; do not invent display labels.
- Keep sentence case, Söhne 500, and no letter spacing.
Accessibility:
- Communicate status with text as well as color.
#### Keep people in the loop [run-status-default]
Starting, Working, Needs you, Done, and Needs attention.
```tsx
```
## Overlays
A focused moment, above the work. Translucent surfaces with familiar keyboard behavior.
### Dialog
The shared Radix dialog, with a 22px title and automatic close action.
Import: @/components/ui/dialog
Usage:
- Use for focused transient work. Put DialogTitle inside DialogHeader.
- Use the shared material and overlay rather than recreating them.
Accessibility:
- Include DialogTitle and DialogDescription.
- Keep focus trapping, Escape dismissal, and return focus intact.
#### Make one small change [dialog-default]
Rename a local sample workflow. Save and Cancel remain fully interactive.
```tsx
```
## Materials
A shared foundation for elevation. Glass is a functional floating layer, used with restraint.
### Surface
Shared rim lighting and cast shadows for raised, glass, and dialog surfaces.
Import: @/components/ui/surface
Usage:
- Surface owns material, not positioning, radius, spacing, or clipping.
Accessibility:
- Preserve a readable opaque fallback.
#### A simple foundation [surface-default]
A production raised surface with explicit spacing and geometry.
```tsx
Customer renewal
```
### BentoCard
A composed card using the shared Surface foundation.
Import: @/components/ui/bento-card
Usage:
- Use for local grouping; avoid framing every piece of content.
Accessibility:
- Keep metrics labeled with meaningful text.
#### A little context [bento-default]
An illustrative completion metric with the product's numeric font.
```tsx
Completion
98.6%
138 of 140 finished well
```
### GlassSurface
The floating material: translucent fill, blur, highlights, and a fallback.
Import: @/components/ui/glass-surface
Usage:
- Use only when content meaningfully passes beneath a floating surface.
Accessibility:
- Maintain legibility with and without backdrop-filter.
#### Clarity above the canvas [glass-default]
The production material over Incline's existing brand artwork.
```tsx
A little clarity.
```
## Data
Dense information, clearly arranged. Search, sort, and inspect without losing the thread.
### DataList
A shared table composition with explicit column geometry.
Import: @/components/ui/data-list
Usage:
- Compose DataListHeader, DataListBody, and DataListRow.
- Keep wide data scrollable within its owning region.
Accessibility:
- Keep columnheader, cell, and sorting semantics accurate.
- Label search and filter controls; keep the overflow region keyboard reachable.
#### The work, at a glance [data-list-default]
Filter the sample workflows, sort Runs, or search for an empty result.
```tsx
```
## Patterns
Primitives working together. Production compositions, with their behavior intact.
### ConversationComposer
The shared chat composer, shown here with local-only submission.
Import: @/components/conversation-composer
Usage:
- Reuse this composition rather than rebuilding chat controls.
- Use embedded placement inside an existing flow.
Accessibility:
- Provide ariaLabel. Preserve keyboard submission and disabled states.
#### Start a conversation [composer-default]
Write a message and submit it. This sample renders locally and never calls the API.
```tsx
undefined}
onRemoveAttachment={() => undefined} onSubmit={handleLocalSubmit} />
```
## Identity
The name, the mark, and the typefaces that make the system feel like Incline.
### InclineWordmark
The real wordmark and compact mark used by the product.
Import: @/components/incline-wordmark
Usage:
- Import the wordmark or mark; do not approximate them with plain text.
Accessibility:
- Provide an accessible name when the mark is a standalone navigation link.
#### A recognizable signature [wordmark-default]
The shared wordmark alongside the compact product mark.
```tsx
```
### Typefaces
The production font roles, loaded from the product's permanent local assets.
Import: @/index.css
Usage:
- Söhne for all interface text, IBM Plex Mono for code, Inter for numeric alignment.
Accessibility:
- Use text rather than an image of text; preserve the supplied fallback stacks.
#### A role for every family [typefaces-default]
Söhne 400 and 500, IBM Plex Mono, and aligned Inter numerals.
```tsx
Söhne · 400Söhne · 500IBM Plex Mono0123456789
```