# 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 Private Live 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