{
  "schemaVersion": "1.0",
  "name": "Incline",
  "version": "1.0",
  "description": "The foundations and real components behind Incline. A living reference for the people and agents building thoughtful tools for work.",
  "presentation": {
    "headline": "Built with\nintention",
    "kicker": "The Incline design language."
  },
  "instructions": [
    "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.",
    "Use ConversationUserMessage for sent bubbles and PendingConversationMessage for optimistic submissions. Assistant prose uses MarkdownMessage; progress uses its muted tone without changing the 14px body size.",
    "Use RunDetails for collapsible thinking blocks. Prefer the existing tool catalog name and workflow name over raw identifiers; do not maintain another label table. Keep exact tool and model details inspectable.",
    "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": [
    {
      "title": "Information first",
      "description": "A professional control surface with a clear grid and Swiss editorial discipline."
    },
    {
      "title": "A little breathing room",
      "description": "White canvas, authored content, and deliberate negative space. Keep the chrome compact."
    },
    {
      "title": "One shared language",
      "description": "Production components, honest states, and accessible interactions. Extend before inventing."
    }
  ],
  "typography": {
    "family": "Söhne",
    "stack": "\"Soehne\", \"Helvetica Neue\", Arial, sans-serif",
    "styles": [
      {
        "name": "Page",
        "token": "--font-size-heading-page",
        "size": "2.25rem",
        "lineHeight": "1.08",
        "weight": 400,
        "sample": "Space for the work."
      },
      {
        "name": "Context",
        "token": "--font-size-heading-context",
        "size": "1.375rem",
        "lineHeight": "28px",
        "weight": 400,
        "sample": "A clearer point of view."
      },
      {
        "name": "Component",
        "token": "--font-size-heading-component",
        "size": "1rem",
        "lineHeight": "1.5",
        "weight": 500,
        "sample": "The details, considered."
      },
      {
        "name": "Body",
        "token": "--font-size-body",
        "size": "0.875rem",
        "lineHeight": "1.5",
        "weight": 400,
        "sample": "Good tools make room for thoughtful work."
      },
      {
        "name": "Supporting",
        "token": "--font-size-supporting",
        "size": "0.8125rem",
        "lineHeight": "1.5",
        "weight": 400,
        "sample": "Useful context, when you need it."
      }
    ]
  },
  "colors": [
    {
      "name": "Ink",
      "token": "--foreground",
      "value": "#191917",
      "role": "Primary type and icons."
    },
    {
      "name": "Canvas",
      "token": "--background",
      "value": "#ffffff",
      "role": "The white workspace."
    },
    {
      "name": "Subtle",
      "token": "--surface-subtle",
      "value": "#f9f9f8",
      "role": "Quiet local grouping and hover."
    },
    {
      "name": "Line",
      "token": "--border",
      "value": "#e8e8e3",
      "role": "Essential structure only."
    },
    {
      "name": "Supporting",
      "token": "--muted-foreground",
      "value": "#74736d",
      "role": "Secondary attributes and context."
    },
    {
      "name": "Blue",
      "token": "--primary",
      "value": "#1546d8",
      "role": "Primary actions and focus."
    },
    {
      "name": "Blue tint",
      "token": "--surface-brand-subtle",
      "value": "#f3f5fb",
      "role": "A restrained interactive tint."
    },
    {
      "name": "Success",
      "token": "--success",
      "value": "#37c991",
      "role": "Positive runtime state."
    },
    {
      "name": "Success text",
      "token": "--success-foreground",
      "value": "#087653",
      "role": "Readable positive status text."
    },
    {
      "name": "Warning",
      "token": "--warning",
      "value": "#f4b33d",
      "role": "A state that needs attention."
    },
    {
      "name": "Warning text",
      "token": "--warning-foreground",
      "value": "#8a4b08",
      "role": "Readable caution labels."
    },
    {
      "name": "Destructive",
      "token": "--destructive",
      "value": "#d83a4e",
      "role": "Errors and destructive actions."
    },
    {
      "name": "Unseen results",
      "token": "--notification-unread",
      "value": "color-mix(in srgb, #1546d8 50%, #ffffff)",
      "role": "Pastel blue for unseen conversation results."
    },
    {
      "name": "Needs you",
      "token": "--notification-warning",
      "value": "color-mix(in srgb, #f4b33d 50%, #ffffff)",
      "role": "Pastel yellow for conversations awaiting input."
    },
    {
      "name": "Needs attention",
      "token": "--notification-error",
      "value": "color-mix(in srgb, #d83a4e 50%, #ffffff)",
      "role": "Pastel red for conversation errors."
    }
  ],
  "foundations": {
    "description": "A 4px spacing rhythm. Semicircular controls. Softness reserved for surfaces that need it.",
    "spacing": [
      {
        "name": "1",
        "utility": "gap-1",
        "value": "4px"
      },
      {
        "name": "2",
        "utility": "gap-2",
        "value": "8px"
      },
      {
        "name": "3",
        "utility": "gap-3",
        "value": "12px"
      },
      {
        "name": "4",
        "utility": "gap-4",
        "value": "16px"
      },
      {
        "name": "6",
        "utility": "gap-6",
        "value": "24px"
      },
      {
        "name": "8",
        "utility": "gap-8",
        "value": "32px"
      },
      {
        "name": "12",
        "utility": "gap-12",
        "value": "48px"
      },
      {
        "name": "16",
        "utility": "gap-16",
        "value": "64px"
      }
    ],
    "radii": [
      {
        "name": "Surface",
        "utility": "rounded-xl",
        "value": "12px"
      },
      {
        "name": "Textarea",
        "utility": "rounded-[18px]",
        "value": "18px"
      },
      {
        "name": "Control",
        "utility": "rounded-full",
        "value": "999px"
      }
    ],
    "motion": [
      {
        "name": "Feedback",
        "utility": "duration-150",
        "value": "150ms"
      },
      {
        "name": "Transition",
        "utility": "duration-300",
        "value": "300ms"
      }
    ]
  },
  "sections": [
    {
      "id": "actions",
      "title": "Actions",
      "description": "One clear next step. The same familiar geometry, at every level of emphasis.",
      "components": [
        {
          "id": "button",
          "name": "Button",
          "importPath": "@/components/ui/button",
          "description": "The shared shadcn-style action, with pill geometry and a visible focus ring.",
          "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": [
            {
              "name": "variant",
              "type": "'default' | 'outline' | 'secondary' | 'ghost' | 'destructive' | 'link'",
              "default": "default",
              "description": "Action emphasis."
            },
            {
              "name": "size",
              "type": "'default' | 'sm' | 'icon' | 'icon-sm'",
              "default": "default",
              "description": "36px standard or 32px compact."
            }
          ],
          "examples": [
            {
              "id": "button-variants",
              "name": "A useful hierarchy",
              "description": "Primary, outline, secondary, ghost, destructive, and link. Click an action to try its local loading state.",
              "code": "<Button type=\"button\">Continue</Button>\n<Button type=\"button\" variant=\"outline\">Outline</Button>\n<Button type=\"button\" variant=\"secondary\">Secondary</Button>\n<Button type=\"button\" variant=\"ghost\">Ghost</Button>\n<Button type=\"button\" variant=\"destructive\">Delete</Button>\n<Button variant=\"link\" asChild><a href=\"/\">Go home</a></Button>"
            },
            {
              "id": "button-states",
              "name": "Every state counts",
              "description": "Compact, disabled, and busy. Loading feedback stays in place.",
              "code": "<Button type=\"button\" size=\"sm\">Save</Button>\n<Button type=\"button\" disabled>Disabled</Button>\n<Button type=\"button\" variant=\"outline\" disabled aria-busy=\"true\">\n  <Loader2 className=\"animate-spin motion-reduce:animate-none\" /> Loading\n</Button>"
            },
            {
              "id": "button-icons",
              "name": "A little less chrome",
              "description": "A labeled icon action with a pressed state. Try adding it to favorites.",
              "code": "<Button type=\"button\" variant=\"ghost\" size=\"icon-sm\"\n  aria-label=\"Favorite\" aria-pressed={favorite}\n  onClick={() => setFavorite(!favorite)}>\n  <Star className={favorite ? \"fill-current text-primary\" : \"\"} />\n</Button>"
            }
          ]
        },
        {
          "id": "split-button",
          "name": "SplitButton",
          "importPath": "@/components/ui/split-button",
          "description": "An independent main action and an adjacent menu.",
          "usage": [
            "Keep the main action independent of its menu."
          ],
          "accessibility": [
            "Supply menuLabel for the secondary trigger."
          ],
          "examples": [
            {
              "id": "split-button-default",
              "name": "Two related choices",
              "description": "Try opens a local dialog; the menu offers a separate continuous run.",
              "code": "<SplitButton action={<>Try</>} onAction={openRunDialog} menuLabel=\"More run options\">\n  {(close) => <DropdownItem label=\"Run continuously\" onClick={() => { close(); openContinuousDialog(); }} />}\n</SplitButton>"
            }
          ]
        },
        {
          "id": "header-actions",
          "name": "EditorHeaderButton",
          "importPath": "@/components/editor-header",
          "description": "A background-free action for access, history, and other header dialogs.",
          "usage": [
            "Keep header actions quiet and compact."
          ],
          "accessibility": [
            "Open the related dialog and return focus to its trigger."
          ],
          "examples": [
            {
              "id": "header-actions-default",
              "name": "Quietly available",
              "description": "Access and version history, with real production dialogs.",
              "code": "<EditorHeaderButton onClick={openAccess}>Private</EditorHeaderButton>\n<EditorHeaderButton onClick={openHistory}><History />Live v3</EditorHeaderButton>"
            }
          ]
        }
      ]
    },
    {
      "id": "inputs",
      "title": "Inputs",
      "description": "A clear label, a comfortable target, and useful guidance. Native behavior comes first.",
      "components": [
        {
          "id": "input",
          "name": "Input",
          "importPath": "@/components/ui/input",
          "description": "The production 36px pill-shaped text 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."
          ],
          "examples": [
            {
              "id": "input-default",
              "name": "Start with a name",
              "description": "A persistent label and the shared focus treatment.",
              "code": "<label htmlFor=\"workflow-name\">Workflow name</label>\n<Input id=\"workflow-name\" placeholder=\"Customer renewal\"\n  className=\"focus-visible:ring-2 focus-visible:ring-ring/30\" />"
            },
            {
              "id": "input-states",
              "name": "Consider the edges",
              "description": "Compact, disabled, and overflowing values.",
              "code": "<Input aria-label=\"Compact name\" className=\"h-8 focus-visible:ring-2 focus-visible:ring-ring/30\" defaultValue=\"Customer renewal\" />\n<Input aria-label=\"Disabled name\" disabled placeholder=\"Disabled\" />\n<Input aria-label=\"Long name\" readOnly value=\"Customer renewal workflow for accounts approaching their annual renewal date\" />"
            }
          ]
        },
        {
          "id": "textarea",
          "name": "Textarea",
          "importPath": "@/components/ui/textarea",
          "description": "A multiline input with an 18px corner radius.",
          "usage": [
            "Use for freeform instructions; allow vertical resizing."
          ],
          "accessibility": [
            "Provide a label and a visible focus ring."
          ],
          "examples": [
            {
              "id": "textarea-default",
              "name": "Room for a thought",
              "description": "Freeform instructions, with the production compound-control geometry.",
              "code": "<label htmlFor=\"instructions\">Instructions</label>\n<Textarea id=\"instructions\" placeholder=\"Describe the work to be done…\"\n  className=\"focus-visible:ring-2 focus-visible:ring-ring/30\" />"
            }
          ]
        },
        {
          "id": "native-select",
          "name": "NativeSelect",
          "importPath": "@/components/ui/native-select",
          "description": "A native picker with the shared control shape and one chevron.",
          "usage": [
            "Keep the platform picker; do not add a second chevron."
          ],
          "accessibility": [
            "Associate a label with the select."
          ],
          "examples": [
            {
              "id": "native-select-default",
              "name": "A familiar choice",
              "description": "Choose a date range using the native platform control.",
              "code": "<NativeSelect aria-label=\"Date range\" defaultValue=\"30\">\n  <option value=\"7\">Last 7 days</option>\n  <option value=\"30\">Last 30 days</option>\n  <option value=\"90\">Last 90 days</option>\n</NativeSelect>"
            }
          ]
        }
      ]
    },
    {
      "id": "selection",
      "title": "Selection",
      "description": "Menus, values, and views. Consistent controls with the right semantics for each choice.",
      "components": [
        {
          "id": "dropdown",
          "name": "Dropdown",
          "importPath": "@/components/ui/dropdown",
          "description": "The shared popup for action menus and single-value selection.",
          "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."
          ],
          "examples": [
            {
              "id": "dropdown-menu",
              "name": "Actions in context",
              "description": "The outline and ghost triggers share geometry. Choose an action to update the label.",
              "code": "<Dropdown label=\"Workflow actions\" triggerLabel=\"Actions\">\n  {(close) => <DropdownItem label=\"Rename\" onClick={() => { rename(); close(); }} />}\n</Dropdown>"
            },
            {
              "id": "dropdown-selection",
              "name": "One selected value",
              "description": "Grouped options, descriptions, a long label, and a disabled option.",
              "code": "<Dropdown label=\"Model\" value={model} onValueChange={setModel}\n  options={modelOptions} />\n<Dropdown label=\"Model\" variant=\"ghost\" value={model}\n  onValueChange={setModel} options={modelOptions} />"
            },
            {
              "id": "dropdown-full-width",
              "name": "An intentional width",
              "description": "fullWidth affects the trigger independently of its visual variant.",
              "code": "<Dropdown label=\"Model\" fullWidth value={model}\n  onValueChange={setModel} options={modelOptions} />"
            },
            {
              "id": "dropdown-states",
              "name": "Even when nothing is ready",
              "description": "Disabled, loading, and an empty option list.",
              "code": "<Dropdown label=\"Disabled model\" disabled value={null}\n  onValueChange={() => undefined} options={modelOptions} />\n<Dropdown label=\"Empty model\" placeholder=\"Choose a model\"\n  value={null} onValueChange={() => undefined} options={[]} />"
            }
          ]
        },
        {
          "id": "segmented-control",
          "name": "SegmentedControl",
          "importPath": "@/components/ui/segmented-control",
          "description": "The Assistant / Editor mode switch.",
          "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."
          ],
          "examples": [
            {
              "id": "segmented-control-default",
              "name": "A change of perspective",
              "description": "Switch between Assistant and Editor using a click or the keyboard.",
              "code": "<SegmentedControl value={mode} onValueChange={setMode}\n  ariaLabel=\"Editing mode\" options={[\n    { value: \"assistant\", label: \"Assistant\" },\n    { value: \"editor\", label: \"Editor\" },\n  ]} />"
            }
          ]
        },
        {
          "id": "tabs",
          "name": "Tabs",
          "importPath": "@/components/ui/tabs",
          "description": "Related views with an anchored active indicator.",
          "usage": [
            "Compose Tabs, TabsList, TabsTrigger, and TabsContent."
          ],
          "accessibility": [
            "Label the tab list and retain Radix keyboard semantics."
          ],
          "examples": [
            {
              "id": "tabs-default",
              "name": "A place for each view",
              "description": "Change the selected view to show its local content.",
              "code": "<Tabs defaultValue=\"workflow\">\n  <TabsList aria-label=\"Workflow views\">\n    <TabsTrigger value=\"workflow\">Workflow</TabsTrigger>\n    <TabsTrigger value=\"tasks\">Tasks</TabsTrigger>\n  </TabsList>\n  <TabsContent value=\"workflow\">Customer renewal</TabsContent>\n  <TabsContent value=\"tasks\">3 tasks in progress</TabsContent>\n</Tabs>"
            }
          ]
        }
      ]
    },
    {
      "id": "feedback",
      "title": "Feedback",
      "description": "Small, readable signals that say what is happening. Color always comes with words.",
      "components": [
        {
          "id": "conversation-indicators",
          "name": "ConversationSidebarList",
          "importPath": "@/components/conversation-sidebar-list",
          "description": "Chat and resource builder navigation with quiet attention indicators.",
          "usage": [
            "Use 8px pastel dots derived equally from the core hue and surface: blue for unseen results, yellow for needed input, and red for errors.",
            "Opening a healthy conversation clears its dot and remembers the viewed update. New results can become unseen again.",
            "Needs you and error dots persist after viewing until their condition changes. Working states use a neutral spinner."
          ],
          "accessibility": [
            "Give every indicator a text label and tooltip; preserve keyboard focus on conversation buttons."
          ],
          "examples": [
            {
              "id": "conversation-indicators-default",
              "name": "Only when there is something to see",
              "description": "Select a chat to clear its unseen result. Errors and requests for input retain their dots.",
              "code": "<ConversationSidebarList conversations={conversations} selectedId={selectedId} loading={false} onSelect={selectChat} onNew={startChat} />"
            }
          ]
        },
        {
          "id": "run-status",
          "name": "RunStatusBadge",
          "importPath": "@/components/status-badge",
          "description": "The product's shared runtime status labels, built on 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."
          ],
          "examples": [
            {
              "id": "run-status-default",
              "name": "Keep people in the loop",
              "description": "Starting, Working, Needs you, Done, and Needs attention.",
              "code": "<RunStatusBadge status=\"QUEUED\" />\n<RunStatusBadge status=\"RUNNING\" />\n<RunStatusBadge status=\"WAITING_FOR_HUMAN\" />\n<RunStatusBadge status=\"SUCCEEDED\" />\n<RunStatusBadge status=\"FAILED\" />"
            }
          ]
        }
      ]
    },
    {
      "id": "overlays",
      "title": "Overlays",
      "description": "A focused moment, above the work. Translucent surfaces with familiar keyboard behavior.",
      "components": [
        {
          "id": "dialog",
          "name": "Dialog",
          "importPath": "@/components/ui/dialog",
          "description": "The shared Radix dialog, with a 22px title and automatic close action.",
          "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."
          ],
          "examples": [
            {
              "id": "dialog-default",
              "name": "Make one small change",
              "description": "Rename a local sample workflow. Save and Cancel remain fully interactive.",
              "code": "<Dialog>\n  <DialogTrigger asChild><Button variant=\"outline\">Rename workflow</Button></DialogTrigger>\n  <DialogContent>\n    <DialogHeader>\n      <DialogTitle>Rename workflow</DialogTitle>\n      <DialogDescription>Edit the workflow name.</DialogDescription>\n    </DialogHeader>\n    {/* Form content */}\n  </DialogContent>\n</Dialog>"
            }
          ]
        }
      ]
    },
    {
      "id": "materials",
      "title": "Materials",
      "description": "A shared foundation for elevation. Glass is a functional floating layer, used with restraint.",
      "components": [
        {
          "id": "surface",
          "name": "Surface",
          "importPath": "@/components/ui/surface",
          "description": "Shared rim lighting and cast shadows for raised, glass, and dialog surfaces.",
          "usage": [
            "Surface owns material, not positioning, radius, spacing, or clipping."
          ],
          "accessibility": [
            "Preserve a readable opaque fallback."
          ],
          "examples": [
            {
              "id": "surface-default",
              "name": "A simple foundation",
              "description": "A production raised surface with explicit spacing and geometry.",
              "code": "<Surface className=\"rounded-xl p-6\">Customer renewal</Surface>"
            }
          ]
        },
        {
          "id": "bento",
          "name": "BentoCard",
          "importPath": "@/components/ui/bento-card",
          "description": "A composed card using the shared Surface foundation.",
          "usage": [
            "Use for local grouping; avoid framing every piece of content."
          ],
          "accessibility": [
            "Keep metrics labeled with meaningful text."
          ],
          "examples": [
            {
              "id": "bento-default",
              "name": "A little context",
              "description": "An illustrative completion metric with the product's numeric font.",
              "code": "<BentoCard className=\"workflow-success-card rounded-xl p-6\">\n  <p>Completion</p>\n  <p className=\"font-numeric tabular-nums\">98.6%</p>\n  <p>138 of 140 finished well</p>\n</BentoCard>"
            }
          ]
        },
        {
          "id": "glass",
          "name": "GlassSurface",
          "importPath": "@/components/ui/glass-surface",
          "description": "The floating material: translucent fill, blur, highlights, and a fallback.",
          "usage": [
            "Use only when content meaningfully passes beneath a floating surface."
          ],
          "accessibility": [
            "Maintain legibility with and without backdrop-filter."
          ],
          "examples": [
            {
              "id": "glass-default",
              "name": "Clarity above the canvas",
              "description": "The production material over Incline's existing brand artwork.",
              "code": "<GlassSurface className=\"rounded-xl p-6\">\n  <p>A little clarity.</p>\n</GlassSurface>"
            }
          ]
        }
      ]
    },
    {
      "id": "data",
      "title": "Data",
      "category": "patterns",
      "description": "Dense information, clearly arranged. Search, sort, and inspect without losing the thread.",
      "components": [
        {
          "id": "data-list",
          "name": "DataList",
          "importPath": "@/components/ui/data-list",
          "description": "A shared table composition with explicit column geometry.",
          "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."
          ],
          "examples": [
            {
              "id": "data-list-default",
              "name": "The work, at a glance",
              "description": "Filter the sample workflows, sort Runs, or search for an empty result.",
              "code": "<DataList aria-label=\"Workflows\">\n  <DataListHeader>{/* column headers, including aria-sort */}</DataListHeader>\n  <DataListBody>\n    {rows.map(row => <DataListRow key={row.name}>\n      <div role=\"cell\">{row.name}</div>\n      <div role=\"cell\"><RunStatusBadge status={row.status} /></div>\n    </DataListRow>)}\n  </DataListBody>\n</DataList>"
            }
          ]
        }
      ]
    },
    {
      "id": "conversations",
      "title": "Conversations",
      "category": "patterns",
      "description": "Shared chat bubbles, assistant replies, and quiet thinking blocks for chat and resource conversations.",
      "components": [
        {
          "id": "chat-bubbles",
          "name": "Chat bubbles",
          "importPath": "@/components/conversation-user-message",
          "description": "The production ConversationUserMessage bubble, paired with assistant prose and local message actions.",
          "usage": [
            "Use ConversationUserMessage for sent user text and PendingConversationMessage from @/components/pending-conversation-message for optimistic submissions. Both share the same geometry on delivery.",
            "User bubbles align right, occupy at most 78% of the column, and use Surface with rounded-3xl, subtle fill, a quiet border, and px-4 py-3. Preserve line breaks and wrap long unbroken content.",
            "Assistant replies remain left-aligned MarkdownMessage prose from @/components/markdown-message. User and assistant text use type-body at 14px; progress changes tone to muted, not size. Identify progress from message metadata with isProgressMessage from @/lib/chat.",
            "Use ConversationMessageActions from @/components/conversation-message-actions for reply actions. Copy, optional Share, and the message timestamp live in the context menu instead of a permanent action row."
          ],
          "accessibility": [
            "Preserve the Your message and Sending message group labels and visible keyboard focus on assistant message actions.",
            "Support right-click, touch long-press, Context Menu, and Shift+F10. Keep menu arrow keys, Escape dismissal, focus return, and copy-result announcements.",
            "Keep text selectable, preserve multiline content, and constrain long links and attachments to the conversation column at compact widths."
          ],
          "examples": [
            {
              "id": "chat-bubbles-default",
              "name": "Messages in conversation",
              "description": "A user bubble, muted progress, and a final reply. Open the final reply’s context menu to try Copy and the local Share action.",
              "code": "<ConversationUserMessage text=\"Gather this week’s project updates and prepare a summary draft.\" />\n<MarkdownMessage tone=\"muted\">I’m gathering the updates and checking the delivery risks.</MarkdownMessage>\n<ConversationMessageActions text={reply} createdAt=\"2026-10-16T12:00:00Z\" onShare={shareLocally}>\n  <MarkdownMessage>{reply}</MarkdownMessage>\n</ConversationMessageActions>"
            },
            {
              "id": "chat-bubbles-delivery",
              "name": "Sending to sent",
              "description": "Toggle delivery state to compare the shared bubble shape, text size, padding, and alignment.",
              "code": "{pending\n  ? <PendingConversationMessage text={text} attachments={[]} />\n  : <ConversationUserMessage text={text} />}\n<Button variant=\"outline\" size=\"sm\" onClick={() => setPending(value => !value)}>\n  {pending ? \"Mark as sent\" : \"Show sending state\"}\n</Button>"
            },
            {
              "id": "chat-bubbles-overflow",
              "name": "Long links and line breaks",
              "description": "The real user bubble preserves multiline text and wraps an unbroken URL within its maximum width.",
              "code": "<ConversationUserMessage text={`Review this reference:\nhttps://example.test/reports/${\"weekly-project-update-\".repeat(9)}`} />\n<MarkdownMessage>Long links wrap inside the bubble. Multiline messages preserve their line breaks.</MarkdownMessage>"
            }
          ]
        },
        {
          "id": "thinking-blocks",
          "name": "Thinking blocks",
          "importPath": "@/components/run-details",
          "description": "The production RunDetails disclosure for current activity, elapsed thinking time, and inspectable execution steps.",
          "usage": [
            "Use RunDetails rather than rebuilding the thinking label or execution list. Keep the collapsed summary quiet, in supporting text, without framing borders or a separate card.",
            "Let latestRunActivity and runCompletionLabel choose the live activity and completed duration labels. Keep activity groups interleaved chronologically with messages and retain stable group identities as results stream.",
            "Display the existing tool catalog name through toolDisplayName and the resolved workflow name. Humanize identifiers only as a fallback; do not add a second label catalog.",
            "Expanded blocks retain distinct model, tool, workflow, and review steps. Exact model input/output and tool names, arguments, result, error, and timing remain inspectable.",
            "Production uses the default API detail source. Public reference samples supply local getToolCall and getModelCall functions through detailSource; never fetch real run data in a specimen."
          ],
          "accessibility": [
            "Keep aria-expanded, aria-controls, and the hidden/inert collapsed content. Enter and Space toggle the summary without leaving hidden steps in the tab order.",
            "Announce changing activity politely, preserve focus rings and dialog focus return, and retain reduced-motion behavior.",
            "Show failures with words as well as status color. Truncate long activity names with a full-text title and stack summary metadata at compact widths."
          ],
          "examples": [
            {
              "id": "thinking-blocks-default",
              "name": "From thinking to details",
              "description": "Expand the completed 23-second block and inspect the fictional tool, workflow, and model calls. Details load locally.",
              "code": "const run = useMemo(() => conversationSampleRun(\"SUCCEEDED\"), []);\nconst detailSource = useMemo(() => conversationSampleDetails(run), [run]);\n<RunDetails run={run} detailSource={detailSource} />\n// Fixtures: @/style-guide/conversation-fixtures. Production omits detailSource."
            },
            {
              "id": "thinking-blocks-states",
              "name": "Working, waiting, and stopped",
              "description": "Choose completed, thinking, queued with no steps, or failed. Each is a separate local snapshot with the same production disclosure.",
              "code": "const [status, setStatus] = useState<RunStatus>(\"SUCCEEDED\");\nconst run = useMemo(() => conversationSampleRun(status), [status]);\nconst detailSource = useMemo(() => conversationSampleDetails(run), [run]);\n<NativeSelect aria-label=\"Example state\" value={status}\n  onChange={event => setStatus(event.target.value as RunStatus)}>\n  <option value=\"SUCCEEDED\">Completed</option>\n  <option value=\"RUNNING\">Thinking</option>\n  <option value=\"QUEUED\">Queued with no steps</option>\n  <option value=\"FAILED\">Failed</option>\n</NativeSelect>\n<RunDetails key={status} run={run} detailSource={detailSource} />"
            }
          ]
        }
      ]
    },
    {
      "id": "patterns",
      "title": "Patterns",
      "category": "patterns",
      "description": "Primitives working together. Production compositions, with their behavior intact.",
      "components": [
        {
          "id": "composer",
          "name": "ConversationComposer",
          "importPath": "@/components/conversation-composer",
          "description": "The shared chat composer, shown here with local-only submission.",
          "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."
          ],
          "examples": [
            {
              "id": "composer-default",
              "name": "Start a conversation",
              "description": "Write a message and submit it. This sample renders locally and never calls the API.",
              "code": "<ConversationComposer placement=\"embedded\" value={value}\n  attachments={[]} attachmentsEnabled={false} disabled={false}\n  ariaLabel=\"Chat message\" placeholder=\"How can I help?\"\n  onChange={setValue} onAddAttachments={() => undefined}\n  onRemoveAttachment={() => undefined} onSubmit={handleLocalSubmit} />"
            }
          ]
        }
      ]
    },
    {
      "id": "identity",
      "title": "Identity",
      "description": "The name, the mark, and the typefaces that make the system feel like Incline.",
      "components": [
        {
          "id": "wordmark",
          "name": "InclineWordmark",
          "importPath": "@/components/incline-wordmark",
          "description": "The real wordmark and compact mark used by the product.",
          "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."
          ],
          "examples": [
            {
              "id": "wordmark-default",
              "name": "A recognizable signature",
              "description": "The shared wordmark alongside the compact product mark.",
              "code": "<InclineWordmark className=\"text-[36px]\" />\n<InclineMark className=\"grid size-10\" />"
            }
          ]
        },
        {
          "id": "typefaces",
          "name": "Typefaces",
          "importPath": "@/index.css",
          "description": "The production font roles, loaded from the product's permanent local assets.",
          "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."
          ],
          "examples": [
            {
              "id": "typefaces-default",
              "name": "A role for every family",
              "description": "Söhne 400 and 500, IBM Plex Mono, and aligned Inter numerals.",
              "code": "<span className=\"type-body\">Söhne · 400</span>\n<span className=\"type-body font-medium\">Söhne · 500</span>\n<code className=\"font-mono\">IBM Plex Mono</code>\n<span className=\"font-numeric tabular-nums\">0123456789</span>"
            }
          ]
        }
      ]
    }
  ],
  "routes": {
    "presenter": "/style",
    "manifest": "/style/guide.json",
    "agentReference": "/style/llms.txt",
    "tokens": "/style/tokens.css"
  },
  "agentInstructions": [
    "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.",
    "Use ConversationUserMessage for sent bubbles and PendingConversationMessage for optimistic submissions. Assistant prose uses MarkdownMessage; progress uses its muted tone without changing the 14px body size.",
    "Use RunDetails for collapsible thinking blocks. Prefer the existing tool catalog name and workflow name over raw identifiers; do not maintain another label table. Keep exact tool and model details inspectable.",
    "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."
  ]
}
