{
  "schemaVersion": "1.0.0",
  "package": "@ds-mo/ui",
  "packageVersion": "14.17.0",
  "kind": "components",
  "entries": [
    {
      "id": "component:ds-agent-activity",
      "tag": "ds-agent-activity",
      "name": "agent-activity",
      "title": "AgentActivity",
      "summary": "Collapsible, user-safe summary of agent work steps without private reasoning.",
      "intentStatus": "complete",
      "intent": {
        "audience": "specialized",
        "status": "experimental",
        "summary": "Collapsible, user-safe summary of agent work steps without private reasoning.",
        "useWhen": [
          "An agent response benefits from concise progress or completion summaries."
        ],
        "avoidWhen": [
          "The content would reveal private chain-of-thought, hidden prompts, secrets, or raw internal traces."
        ],
        "commonlyComposedWith": [
          "component:ds-agent-response",
          "component:ds-loader"
        ],
        "patterns": [
          "pattern:agent-chat"
        ],
        "accessibility": [
          "Each step has textual state and description; animation and color are supplementary.",
          "The disclosure uses native keyboard and expanded-state semantics."
        ],
        "states": [
          "While collapsed, the summary follows the current user-safe activity and shimmers only while active; while expanded, the heading becomes Activity and the ordered list exposes every step.",
          "Pending, active, complete, and error describe user-safe workflow progress."
        ],
        "responsiveBehavior": [
          "Steps wrap within the response width."
        ],
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/MessageScroller/MessageScroller.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "heading": {
            "type": "string",
            "required": false
          },
          "items": {
            "type": "AgentActivityItem[]",
            "required": false
          },
          "open": {
            "type": "boolean",
            "required": false
          }
        },
        "events": [],
        "slots": []
      },
      "exports": {
        "customElement": "ds-agent-activity",
        "react": "DsAgentActivity",
        "vue": "DsAgentActivity",
        "angular": "DsAgentActivity"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens",
        "@ds-mo/icons"
      ],
      "componentDependencies": [
        "icon",
        "loader",
        "text"
      ]
    },
    {
      "id": "component:ds-agent-questionnaire",
      "tag": "ds-agent-questionnaire",
      "name": "agent-questionnaire",
      "title": "AgentQuestionnaire",
      "summary": "Temporary multi-step work surface for provider-neutral agent clarification questions and durable read-only answer records.",
      "intentStatus": "complete",
      "intent": {
        "audience": "specialized",
        "status": "experimental",
        "summary": "Temporary multi-step work surface for provider-neutral agent clarification questions and durable read-only answer records.",
        "useWhen": [
          "An agent turn pauses for one or more structured single-choice, multiple-choice, or free-text answers."
        ],
        "avoidWhen": [
          "The interaction is a conventional application form, a tool authorization policy, or an application-owned approval with consequences beyond collecting answers."
        ],
        "commonlyComposedWith": [
          "component:ds-message-scroller",
          "component:ds-message-composer",
          "component:ds-agent-response",
          "component:ds-radio",
          "component:ds-checkbox",
          "component:ds-button-filled",
          "component:ds-button-unfilled"
        ],
        "patterns": [
          "pattern:agent-chat"
        ],
        "accessibility": [
          "Radio and checkbox primitives own choice semantics, target density, keyboard interaction, and selected or disabled presentation; progress, validation relationships, static answered summaries, and every action remain available without relying on color or visual position.",
          "The component never takes focus when it mounts; the application calls setFocus only when shifting focus is appropriate.",
          "Choice rows use large Radio and Checkbox targets, while every navigation action uses a small Button primitive and Cancel is an icon-only Cross with localized tooltip and accessible name.",
          "Selection primitives preserve focus, selected, invalid, and disabled distinctions in forced colors."
        ],
        "states": [
          "The component owns only the current step, validation, and unsaved in-progress draft; the application owns the request, submission, transport, resume operation, persistence, and transcript replacement.",
          "Preparing communicates that questions are being assembled, submitting locks editing without clearing the draft, error retains it with application feedback, and answered is a quiet noninteractive record.",
          "A changed request identifier resets to the first question and seeds a fresh local draft from the supplied answers.",
          "Questionnaire selection primitives are isolated from ancestor forms; only dsAnswer emits the normalized ordered answer collection."
        ],
        "responsiveBehavior": [
          "Descriptive choices remain full-row targets, while actions collapse into a single-column layout at narrow widths."
        ],
        "references": [
          {
            "label": "Questionnaire state stories",
            "path": "src/wc/components/AgentQuestionnaire/AgentQuestionnaire.stories.ts"
          },
          {
            "label": "Agent chat composition",
            "path": "agent/patterns/agent-chat/pattern.agent.json"
          }
        ]
      },
      "api": {
        "props": {
          "allowCancel": {
            "type": "boolean",
            "required": false
          },
          "answers": {
            "type": "AgentQuestionAnswer[]",
            "required": false
          },
          "errorMessage": {
            "type": "string",
            "required": false
          },
          "labels": {
            "type": "Partial<AgentQuestionnaireLabels>",
            "required": false
          },
          "questions": {
            "type": "AgentQuestion[]",
            "required": true
          },
          "requestId": {
            "type": "string",
            "required": true
          },
          "status": {
            "type": "AgentQuestionnaireStatus",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsAnswer",
            "detail": "AgentQuestionnaireAnswerEventDetail"
          },
          {
            "name": "dsCancel",
            "detail": "AgentQuestionnaireCancelEventDetail"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-agent-questionnaire",
        "react": "DsAgentQuestionnaire",
        "vue": "DsAgentQuestionnaire",
        "angular": "DsAgentQuestionnaire"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens",
        "@ds-mo/icons"
      ],
      "componentDependencies": [
        "button-filled",
        "button-unfilled",
        "checkbox",
        "icon",
        "loader",
        "radio",
        "text",
        "tooltip"
      ]
    },
    {
      "id": "component:ds-agent-response",
      "tag": "ds-agent-response",
      "name": "agent-response",
      "title": "AgentResponse",
      "summary": "Ordered renderer for normalized immutable agent response parts or an application-composed response body inside a generic incoming message.",
      "intentStatus": "complete",
      "intent": {
        "audience": "specialized",
        "status": "experimental",
        "summary": "Ordered renderer for normalized immutable agent response parts or an application-composed response body inside a generic incoming message.",
        "useWhen": [
          "An agent response combines Markdown, user-safe activity, display-only tools, attachments, answered questionnaires, sources, or application-specific content in authored order."
        ],
        "avoidWhen": [
          "The component would be expected to own a model, transport, persistence, title generation, approval policy, or private reasoning."
        ],
        "commonlyComposedWith": [
          "component:ds-message",
          "component:ds-message-actions",
          "component:ds-markdown",
          "component:ds-agent-activity",
          "component:ds-agent-tool-call",
          "component:ds-agent-source-list",
          "component:ds-agent-questionnaire"
        ],
        "patterns": [
          "pattern:agent-chat"
        ],
        "accessibility": [
          "Part or composed-slot order matches authored reading order and remains inside generic message semantics.",
          "Streaming state supplements rather than replaces meaningful textual status.",
          "Forwarded metadata actions retain Message ordering, keyboard reveal, and touch visibility."
        ],
        "states": [
          "The owner replaces immutable part arrays as scripted or live output changes.",
          "Parts mode remains the compatibility default for serializable content; composed mode ignores parts and gives the default slot ownership of the complete ordered response body.",
          "AgentResponse renders directly in Message without borrowing a plain MessageBubble surface.",
          "Markdown parts use the optional safe renderer; the response sets the public prose text measure while code, tables, tools, sources, attachments, and other structured parts retain the full lane.",
          "The application may compose MessageActions for completed-response Copy and controlled feedback while retaining persistent retry or recovery controls in the separate actions slot."
        ],
        "responsiveBehavior": [
          "Direct prose blocks use a readable text measure within the available transcript width, while narrow lanes and structured content retain their available width and local overflow constraints."
        ],
        "references": [
          {
            "label": "Response modes and representative flow",
            "path": "src/wc/components/AgentResponse/AgentResponse.stories.ts"
          },
          {
            "label": "Prose distribution decision",
            "path": "docs/prose-foundation.md"
          }
        ]
      },
      "api": {
        "props": {
          "author": {
            "type": "string",
            "required": false
          },
          "messageId": {
            "type": "string",
            "required": false
          },
          "metadataVisibility": {
            "type": "MessageMetadataVisibility",
            "required": false
          },
          "parts": {
            "type": "AgentResponsePart[]",
            "required": false
          },
          "renderMode": {
            "type": "AgentResponseRenderMode",
            "required": false
          },
          "showAuthor": {
            "type": "boolean",
            "required": false
          },
          "streaming": {
            "type": "boolean",
            "required": false
          },
          "timestamp": {
            "type": "string",
            "required": false
          }
        },
        "events": [],
        "slots": []
      },
      "exports": {
        "customElement": "ds-agent-response",
        "react": "DsAgentResponse",
        "vue": "DsAgentResponse",
        "angular": "DsAgentResponse"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "agent-activity",
        "agent-questionnaire",
        "agent-source-list",
        "agent-tool-call",
        "attachment-list",
        "markdown",
        "message"
      ]
    },
    {
      "id": "component:ds-agent-source-list",
      "tag": "ds-agent-source-list",
      "name": "agent-source-list",
      "title": "AgentSourceList",
      "summary": "Inline collapsible agent-source list with safe external links, derived hostnames, optional descriptions, and observable disclosure state.",
      "intentStatus": "complete",
      "intent": {
        "audience": "specialized",
        "status": "experimental",
        "summary": "Inline collapsible agent-source list with safe external links, derived hostnames, optional descriptions, and observable disclosure state.",
        "useWhen": [
          "A stable agent response cites external material readers may inspect inline."
        ],
        "avoidWhen": [
          "The links are ordinary body links, source discovery is still active, or the application expects a source drawer or deduplication behavior."
        ],
        "commonlyComposedWith": [
          "component:ds-agent-response",
          "component:ds-markdown"
        ],
        "patterns": [
          "pattern:agent-chat"
        ],
        "accessibility": [
          "Each interactive source uses descriptive linked text, a visible hostname, supporting context, and an external-link indication.",
          "Malformed and unsafe schemes remain non-interactive text rather than producing executable links.",
          "The native disclosure exposes keyboard and expanded-state semantics, while open-change events let applications observe participant intent."
        ],
        "states": [
          "Applications collect and deduplicate sources, then append the stable list once; active discovery remains an activity or tool state."
        ],
        "responsiveBehavior": [
          "Source titles, hostnames, and descriptions wrap within the response width."
        ],
        "references": [
          {
            "label": "Source safety and disclosure stories",
            "path": "src/wc/components/AgentSourceList/AgentSourceList.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "heading": {
            "type": "string",
            "required": false
          },
          "items": {
            "type": "AgentSource[]",
            "required": false
          },
          "open": {
            "type": "boolean",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsOpenChange",
            "detail": "{ open: boolean }"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-agent-source-list",
        "react": "DsAgentSourceList",
        "vue": "DsAgentSourceList",
        "angular": "DsAgentSourceList"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens",
        "@ds-mo/icons"
      ],
      "componentDependencies": [
        "icon",
        "text"
      ]
    },
    {
      "id": "component:ds-agent-tool-call",
      "tag": "ds-agent-tool-call",
      "name": "agent-tool-call",
      "title": "AgentToolCall",
      "summary": "Compact display-only status row for a provider-neutral agent tool lifecycle with optional custom result and diagnostic disclosure surfaces.",
      "intentStatus": "complete",
      "intent": {
        "audience": "specialized",
        "status": "experimental",
        "summary": "Compact display-only status row for a provider-neutral agent tool lifecycle with optional custom result and diagnostic disclosure surfaces.",
        "useWhen": [
          "An agent product needs to expose user-safe tool preparation, queueing, execution, participant wait, completion, failure, denial, or cancellation state."
        ],
        "avoidWhen": [
          "A participant must approve, deny, edit, retry, or execute the tool call; those product controls and consequences remain outside this component."
        ],
        "commonlyComposedWith": [
          "component:ds-agent-response",
          "component:ds-code-block",
          "component:ds-text"
        ],
        "patterns": [
          "pattern:agent-chat"
        ],
        "accessibility": [
          "Every lifecycle state remains visible as text and error or denied meaning does not depend on color.",
          "A disclosure is rendered only when details exist and uses native keyboard and expanded-state semantics.",
          "Structured input, output, and error details use the semantic code-family fallback and optional ligature override."
        ],
        "states": [
          "Applications normalize provider-specific tool states and may localize the visible status label before rendering.",
          "A custom summary replaces the generated name, a custom result owns the primary result surface, and custom details replace generic input, output, and error diagnostics.",
          "An ordinary text-only custom result inherits the body-medium interface-text baseline; structured result components retain ownership of their own layout and typography.",
          "Compose semantic links around ds-text when a custom result is navigational so anchor semantics and design-system typography each have one owner.",
          "Applications load font assets once at their root; tool details and results never fetch or package a font.",
          "This component presents state but never executes a tool or owns approval, retry, authorization, transport, or consequence policy."
        ],
        "responsiveBehavior": [
          "Long names and state labels wrap inside the compact row while custom results and structured diagnostics remain within the transcript lane without widening it."
        ],
        "references": [
          {
            "label": "Lifecycle and slot stories",
            "path": "src/wc/components/AgentToolCall/AgentToolCall.stories.ts"
          },
          {
            "label": "Font ownership and loading",
            "path": "docs/font-ownership.md"
          }
        ]
      },
      "api": {
        "props": {
          "error": {
            "type": "string",
            "required": false
          },
          "input": {
            "type": "unknown",
            "required": false
          },
          "label": {
            "type": "string",
            "required": false
          },
          "name": {
            "type": "string",
            "required": false
          },
          "open": {
            "type": "boolean",
            "required": false
          },
          "output": {
            "type": "unknown",
            "required": false
          },
          "state": {
            "type": "AgentToolState",
            "required": false
          },
          "statusLabel": {
            "type": "string",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsOpenChange",
            "detail": "{ open: boolean }"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-agent-tool-call",
        "react": "DsAgentToolCall",
        "vue": "DsAgentToolCall",
        "angular": "DsAgentToolCall"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens",
        "@ds-mo/icons"
      ],
      "componentDependencies": [
        "icon",
        "loader",
        "text"
      ]
    },
    {
      "id": "component:ds-attachment-list",
      "tag": "ds-attachment-list",
      "name": "attachment-list",
      "title": "AttachmentList",
      "summary": "Channel-neutral list of message attachments with name, media type, size, and optional safe link.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "experimental",
        "summary": "Channel-neutral list of message attachments with name, media type, size, and optional safe link.",
        "useWhen": [
          "A conversation message needs to display already-known attachment metadata."
        ],
        "avoidWhen": [
          "Users need to choose, upload, remove, or edit files; those controls belong to the product workflow."
        ],
        "commonlyComposedWith": [
          "component:ds-message",
          "component:ds-message-bubble"
        ],
        "patterns": [
          "pattern:conversation"
        ],
        "accessibility": [
          "Attachment name remains visible and is the link text when a safe URL is available.",
          "Media type and size are supporting metadata, never the only identifier."
        ],
        "responsiveBehavior": [
          "Long names wrap or truncate without overflowing the message surface."
        ],
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/MessageScroller/MessageScroller.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "items": {
            "type": "ConversationAttachment[]",
            "required": false
          },
          "label": {
            "type": "string",
            "required": false
          }
        },
        "events": [],
        "slots": []
      },
      "exports": {
        "customElement": "ds-attachment-list",
        "react": "DsAttachmentList",
        "vue": "DsAttachmentList",
        "angular": "DsAttachmentList"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens",
        "@ds-mo/icons"
      ],
      "componentDependencies": [
        "icon",
        "text"
      ]
    },
    {
      "id": "component:ds-avatar",
      "tag": "ds-avatar",
      "name": "avatar",
      "title": "Avatar",
      "summary": "Compact icon avatar for visually identifying a person, group, channel, or conversation type.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Compact icon avatar for visually identifying a person, group, channel, or conversation type.",
        "useWhen": [
          "A list or message composition needs a consistent circular identity marker represented by an icon at md, sm, or xs control density."
        ],
        "avoidWhen": [
          "The identity has a supplied photograph, initials, presence state, or editable profile behavior; those variants are not part of this primitive."
        ],
        "commonlyComposedWith": [
          "component:ds-conversation-list-item",
          "component:ds-message"
        ],
        "accessibility": [
          "Provide label only when the icon communicates meaning that surrounding text does not already convey.",
          "Omit label when the owning row or message already provides an equivalent accessible name.",
          "Treat primary and secondary as general icon hierarchy; an owning product may map that hierarchy to states such as unread and read, but Avatar does not own those states."
        ],
        "responsiveBehavior": [
          "The selected size stays fixed across viewports: md is a 32px circle with a 20px icon, sm is 24px with 16px, and xs is 16px with 12px."
        ],
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/Avatar/Avatar.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "icon": {
            "type": "string",
            "required": false
          },
          "iconColor": {
            "type": "IconColor",
            "required": false
          },
          "label": {
            "type": "string | undefined",
            "required": false
          },
          "size": {
            "type": "AvatarSize",
            "required": false
          }
        },
        "events": [],
        "slots": []
      },
      "exports": {
        "customElement": "ds-avatar",
        "react": "DsAvatar",
        "vue": "DsAvatar",
        "angular": "DsAvatar"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens",
        "@ds-mo/icons"
      ],
      "componentDependencies": [
        "icon"
      ]
    },
    {
      "id": "component:ds-badge",
      "tag": "ds-badge",
      "name": "badge",
      "title": "Badge",
      "summary": "Non-interactive brand counter or dot that supplements an owning control or label with unread notification information.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Non-interactive brand counter or dot that supplements an owning control or label with unread notification information.",
        "useWhen": [
          "An existing control, navigation item, or label needs a compact unread notification count.",
          "An owning element needs a small visual dot indicating that supplemental notification information exists.",
          "When the badge overlaps an icon or content, the immediate backing surface can be identified so its separation ring matches."
        ],
        "avoidWhen": [
          "The status must stand alone without an owning label or control.",
          "The mark needs semantic positive, caution, negative, or neutral color; Badge intentionally uses one brand treatment.",
          "The compact content is metadata or taxonomy; use Tag or Chip according to whether it is removable.",
          "The badge itself would receive pointer or keyboard interaction; put interaction on the owning control."
        ],
        "alternatives": [
          {
            "when": "A compact static label communicates taxonomy or a semantic status.",
            "component": "component:ds-tag",
            "reason": "Tag owns static metadata labels and semantic intent coloring."
          },
          {
            "when": "A metadata value must be individually removable.",
            "component": "component:ds-chip",
            "reason": "Chip owns dismissible metadata values."
          },
          {
            "when": "The count is primary content rather than supplemental notification chrome.",
            "component": "component:ds-text",
            "reason": "Text preserves the quantity as normal readable content."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-button-unfilled",
          "component:ds-bar-nav",
          "component:ds-panel-nav",
          "component:ds-menu"
        ],
        "accessibility": [
          "The owning control or content provides the primary accessible name; Badge contributes only supplemental unread or notification meaning.",
          "When a dot is announced, provide contextual text that explains its meaning. Otherwise mark it aria-hidden from the owning composition.",
          "When a counter is announced, provide contextual text such as “5 unread notifications”; a bare number is insufficient.",
          "Avoid duplicating information already included in the owning control's accessible name.",
          "Badge never receives focus and never owns an interaction."
        ],
        "states": [
          "Counter represents an unread or notification count, while dot communicates presence without quantity.",
          "Non-positive counter values hide the badge.",
          "Counts above the configured compact limit display the limit with a plus suffix while accessible text retains meaningful context.",
          "Badge keeps one brand treatment; semantic severity belongs to another component or adjacent content.",
          "Use the ring only when Badge overlaps an icon or other content. Disable it in a reserved safe-area slot.",
          "When enabled, the ring matches the immediate backing surface for both variants. Use a direct ring override only for a component-local fill that no surface preset represents.",
          "Enabled shell gradient rings align automatically inside active ShellApp gradient chrome and may be explicitly enabled or disabled when composition requires it."
        ],
        "responsiveBehavior": [
          "The owning control or layout positions Badge and decides whether notification indicators remain visible, condense, or move at responsive breakpoints.",
          "Badge does not anchor itself or automatically switch between counter and dot variants."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Position Badge from the owning element's layout and synchronize its contextual accessibility text with the owner."
          ],
          "react": [
            "Keep count, visibility, and contextual accessibility text derived from the same unread-notification state as the owning control."
          ],
          "angular": [
            "Keep count, visibility, and contextual accessibility text derived from the same unread-notification state as the owning control."
          ]
        },
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/Badge/Badge.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "background": {
            "type": "string | undefined",
            "required": false
          },
          "count": {
            "type": "number",
            "required": false
          },
          "gradientBackground": {
            "type": "boolean",
            "required": false
          },
          "hasRing": {
            "type": "boolean",
            "required": false
          },
          "label": {
            "type": "string | undefined",
            "required": false
          },
          "max": {
            "type": "number",
            "required": false
          },
          "surface": {
            "type": "BadgeSurface",
            "required": false
          },
          "variant": {
            "type": "BadgeVariant",
            "required": false
          }
        },
        "events": [],
        "slots": []
      },
      "exports": {
        "customElement": "ds-badge",
        "react": "DsBadge",
        "vue": "DsBadge",
        "angular": "DsBadge"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "text"
      ]
    },
    {
      "id": "component:ds-banner",
      "tag": "ds-banner",
      "name": "banner",
      "title": "Banner",
      "summary": "Persistent in-flow application banner with semantic color intent, explicit announcement urgency, horizontal actions, and controlled dismissal motion.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Persistent in-flow application banner with semantic color intent, explicit announcement urgency, horizontal actions, and controlled dismissal motion.",
        "useWhen": [
          "A persistent application-wide condition or announcement must remain visible while the user works.",
          "A shell-level message needs optional actions and dismissal while reflowing the application rather than floating over it.",
          "Message urgency and color intent must be selected independently."
        ],
        "avoidWhen": [
          "Feedback is transient, queued, promise-driven, or anchored to a control; use Toast.",
          "The message belongs inside a field, card, or bounded content section; use the future inline banner rather than shrinking the application shell.",
          "Several global messages must be prioritized or queued; the application must resolve them to one active banner before rendering."
        ],
        "alternatives": [
          {
            "when": "Feedback is transient or follows a completed action.",
            "component": "component:ds-toast",
            "reason": "Toast owns queues, timers, stacking, swipe dismissal, and anchored feedback."
          },
          {
            "when": "A bounded region has no content to show.",
            "component": "component:ds-empty-state",
            "reason": "EmptyState explains an empty result without creating global application urgency."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-shell-app",
          "component:ds-button-unfilled"
        ],
        "patterns": [
          "pattern:application-shell"
        ],
        "accessibility": [
          "Choose announcement=none for content present at page load, polite for non-urgent dynamic changes, and assertive only when immediate interruption is necessary.",
          "Visual intent never chooses live-region urgency; a negative banner can be persistent and non-urgent, while a neutral banner can require prompt attention.",
          "The close control is always available. Localize dismissLabel and keep the banner mounted until dsAfterClose before removing it.",
          "Slotted actions retain their own accessible names, keyboard behavior, and outcome messaging."
        ],
        "states": [
          "The application owns open. The always-present close control emits dsClose, and the application sets open=false to begin exit motion.",
          "dsAfterClose fires once after the closing banner is inert, hidden from assistive technology, and no longer occupies layout space.",
          "The opaque surface slides by its complete block size while occupied-shell space expands with the same short-3 duration. Opening uses the shell tool panel's ease-out curve; dismissal reverses with its ease-in curve, keeping the Banner boundary flush with the shell throughout.",
          "Heading is optional and description is required. With orientation=horizontal they share one inline copy flow, so description begins after the heading and continuation lines use the complete text width beneath it. With orientation=vertical, description starts on the next line with a 4px gap.",
          "The actions slot accepts at most two ds-button-unfilled controls. They stay in one horizontal trailing lane, align to the top of the dismiss control when sharing the copy row, and must receive the matching parent-surface background context.",
          "Intent selects neutral, brand, positive, warning, caution, or negative hue. Contrast independently selects faint, medium, strong, or bold fill.",
          "Banner has a real bottom boundary, no radius, no elevation, no icon, no timeout, and no internal queue."
        ],
        "responsiveBehavior": [
          "Applications select orientation explicitly. Horizontal keeps copy and actions in one row, with actions top-aligned to dismissal. Vertical puts actions below copy on the 16px text boundary and keeps controls 16px above the bottom boundary; without actions it reserves no trailing row and keeps the copy visually balanced between the top and bottom edges.",
          "When placed in ShellApp's banner slot, the banner spans the complete application above navigation, workspace, and tools.",
          "ShellApp reserves the mobile top safe area once above the banner and keeps the banner visible while mobile tools or navigation surfaces replace the routed stage."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Listen for dsClose, set open=false, and wait for dsAfterClose before conditionally removing the element.",
            "Place at most one ds-banner in ShellApp's banner slot, choose horizontal or vertical orientation for the available shell capacity, and assign no more than two ds-button-unfilled elements slot=actions."
          ],
          "react": [
            "Keep the component mounted while open changes from true to false; remove it in onDsAfterClose when unmounting is required.",
            "Project no more than two ds-button-unfilled actions and pass each the matching background context."
          ],
          "angular": [
            "Bind open as controlled application state, handle dsClose to update it, and wait for dsAfterClose before removing an ngIf owner.",
            "Import and project no more than two DsButtonUnfilled actions with slot=actions and their matching background input."
          ]
        },
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/Banner/Banner.stories.ts"
          },
          {
            "label": "Rendered behavior coverage",
            "path": "tests/e2e/banner.spec.ts"
          },
          {
            "label": "Application shell contract",
            "path": "agent/patterns/application-shell/pattern.agent.json"
          }
        ]
      },
      "api": {
        "props": {
          "announcement": {
            "type": "BannerAnnouncement",
            "required": false
          },
          "contrast": {
            "type": "BannerContrast",
            "required": false
          },
          "description": {
            "type": "string",
            "required": true
          },
          "dismissLabel": {
            "type": "string",
            "required": false
          },
          "heading": {
            "type": "string",
            "required": false
          },
          "intent": {
            "type": "BannerIntent",
            "required": false
          },
          "open": {
            "type": "boolean",
            "required": false
          },
          "orientation": {
            "type": "BannerOrientation",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsAfterClose",
            "detail": "void"
          },
          {
            "name": "dsClose",
            "detail": "MouseEvent"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-banner",
        "react": "DsBanner",
        "vue": "DsBanner",
        "angular": "DsBanner"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "button-unfilled",
        "text",
        "tooltip"
      ]
    },
    {
      "id": "component:ds-bar-action",
      "tag": "ds-bar-action",
      "name": "bar-action",
      "title": "BarAction",
      "summary": "Compact bold-brand selection-action chrome that reports a selected count, offers Clear, and hosts application commands on a medium-elevation surface.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Compact bold-brand selection-action chrome that reports a selected count, offers Clear, and hosts application commands on a medium-elevation surface.",
        "useWhen": [
          "A multi-select table or similar collection needs a persistent bar of commands for the current selected set.",
          "The application owns selected identities and must keep bulk actions visually consistent across surfaces."
        ],
        "avoidWhen": [
          "The message is an application-wide announcement rather than a selected-set command surface; use Banner.",
          "A single row or card needs local overflow commands; use ButtonUnfilled with Menu.",
          "The chrome is a table result summary or footer; compose Table's footer instead."
        ],
        "alternatives": [
          {
            "when": "The message is a persistent application announcement.",
            "component": "component:ds-banner",
            "reason": "Banner owns shell-level messaging and does not represent a selected set."
          },
          {
            "when": "A single row or card needs local overflow commands.",
            "component": "component:ds-button-unfilled",
            "reason": "ButtonUnfilled with Menu owns local item commands rather than selected-set bulk actions."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-table",
          "component:ds-button-unfilled",
          "component:ds-button-filled",
          "component:ds-menu",
          "component:ds-text"
        ],
        "patterns": [],
        "accessibility": [
          "Provide a group accessible name that describes the selected-set commands.",
          "Keep Clear as a real button. A persistent polite live region announces valid selected-count updates without stealing focus.",
          "Name every slotted action. Icon-only commands still need an explicit accessible name.",
          "The application updates the selected identities after dsClear, then moves focus to a stable collection control before the empty bar disappears; the bar never mutates selection or guesses a focus target."
        ],
        "states": [
          "The bar is hidden while the selected count is below one and appears as the compact bold-brand elevated surface once at least one item is selected.",
          "Clear reports intent only. The application replaces the controlled selected identities.",
          "Slotted actions stay application-owned. Pass background matching the bold parent surface so those controls remain readable.",
          "The component-owned visible surface owns medium control-elevation and removes the empty actions lane. Overlay inset, footer clearance, and stacking remain application layout."
        ],
        "responsiveBehavior": [
          "The count truncates before Clear or trailing actions lose their complete hit targets.",
          "The bar fills its owner's inline size. Overlay inset, footer clearance, and stacking against a table remain the consuming layout."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Bind count from the current selected set, replace that set after dsClear, and return focus to a stable collection control.",
            "Project command controls through slot=actions with background matching the bold parent surface."
          ],
          "react": [
            "Pass count from selected row or item state, clear that state from onDsClear, and return focus to a stable collection control.",
            "Place DsBarAction in the same positioned owner as the table when overlaying the table footer."
          ],
          "angular": [
            "Bind count from the controlled selected identities, handle dsClear in the collection owner, and return focus to a stable collection control.",
            "Project ds-button-unfilled or ds-button-filled into slot=actions with background matching the bold parent surface."
          ]
        },
        "references": [
          {
            "label": "Storybook review matrix",
            "path": "src/wc/components/BarAction/BarAction.stories.ts"
          },
          {
            "label": "Rendered behavior coverage",
            "path": "tests/e2e/bar-action.spec.ts"
          }
        ]
      },
      "api": {
        "props": {
          "clearLabel": {
            "type": "string",
            "required": false
          },
          "count": {
            "type": "number",
            "required": false
          },
          "label": {
            "type": "string",
            "required": false
          },
          "selectedLabel": {
            "type": "string",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsClear",
            "detail": "MouseEvent"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-bar-action",
        "react": "DsBarAction",
        "vue": "DsBarAction",
        "angular": "DsBarAction"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "text"
      ]
    },
    {
      "id": "component:ds-bar-nav",
      "tag": "ds-bar-nav",
      "name": "bar-nav",
      "title": "BarNav",
      "summary": "Required secondary route navigation within ShellApp, showing peer sections of the active PanelNav destination or its destination label when no section tabs apply.",
      "intentStatus": "complete",
      "intent": {
        "audience": "specialized",
        "status": "stable",
        "summary": "Required secondary route navigation within ShellApp, showing peer sections of the active PanelNav destination or its destination label when no section tabs apply.",
        "useWhen": [
          "Rendering the required secondary navigation region inside ShellApp.",
          "The active primary destination has peer route sections that users can navigate between.",
          "The active primary destination has no route sections or is showing a detail route and its destination label must preserve the BarNav region."
        ],
        "avoidWhen": [
          "Primary application destinations are being rendered; use PanelNav instead.",
          "A third navigation level is needed; BarNav is never tertiary navigation.",
          "The choices switch local content without navigating routes; use TabGroup instead.",
          "Document-style tabs need reordering, pinning, closing, or user customization.",
          "BarNav would be mounted outside the application's single ShellApp."
        ],
        "alternatives": [
          {
            "when": "The choices are the application's top-level destinations.",
            "component": "component:ds-panel-nav",
            "reason": "PanelNav exclusively owns primary application navigation."
          },
          {
            "when": "The choices switch local content without changing routes.",
            "component": "component:ds-tab-group",
            "reason": "TabGroup owns local view selection and tab semantics."
          },
          {
            "when": "The choices are temporary commands or contextual options.",
            "component": "component:ds-menu",
            "reason": "Menu owns transient action and option collections."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-shell-app",
          "component:ds-panel-nav",
          "component:ds-panel-tools"
        ],
        "patterns": [
          "pattern:application-shell"
        ],
        "accessibility": [
          "Use concise localized labels for every route section.",
          "Keep section navigation keyboard accessible through BarNav's built-in horizontal roving focus and overflow menu.",
          "Preserve the selected route state when sections move between the visible row and overflow menu.",
          "Use notification dots only as supplemental status and not as the sole indication of important information.",
          "Pass the active PanelNav destination label through heading whenever section tabs are absent or hidden."
        ],
        "states": [
          "BarNav is the second and final application navigation level; it never replaces PanelNav and never becomes tertiary navigation.",
          "The host router owns the current route; prefer currentUrl with basePath so BarNav derives the selected section.",
          "Use value only when URL-derived selection is unavailable.",
          "The consuming application supplies heading from the active PanelNav destination; BarNav does not inspect PanelNav to derive it.",
          "When no sections apply, retain the BarNav region and show heading rather than shifting the main content upward.",
          "On non-tab detail routes, show the parent PanelNav destination label in BarNav while the detail-page title remains in page content.",
          "Dividers and groups visually organize peer route sections only and do not create hierarchy.",
          "The application filters unauthorized sections before passing tabs to BarNav.",
          "Dashboard and Settings route state updates PanelNav groups, BarNav tabs, heading, basePath, currentUrl, and navStyle as one coordinated change."
        ],
        "responsiveBehavior": [
          "Keep the BarNav region present so shell height and main-content origin remain stable across routes.",
          "Allow the built-in overflow behavior to move trailing sections into Menu when the available width is insufficient.",
          "The active section does not need to remain visible in the tab row when it moves into overflow because page content supplies the page title.",
          "Do not infer mobile navigation behavior from desktop BarNav; future ShellApp mobile composition may use a different navigation design."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Assign tabs as a JavaScript property and replace the array reference when the collection changes.",
            "Update tabs, heading, basePath, currentUrl, and navStyle from the same resolved route state."
          ],
          "react": [
            "Pass tabs as an array through the generated React wrapper and synchronize currentUrl and basePath with the host router."
          ],
          "angular": [
            "Import DsBarNav from @ds-mo/ui/angular/ds-bar-nav and bind tabs as a property.",
            "Bind heading to the active PanelNav destination label and update route inputs atomically."
          ]
        },
        "references": [
          {
            "label": "Executable Storybook examples",
            "path": "src/wc/components/BarNav/BarNav.stories.ts"
          },
          {
            "label": "Framework and routing integration",
            "path": "docs/framework-integration.md"
          },
          {
            "label": "Application shell composition",
            "path": "agent/patterns/application-shell/pattern.agent.json"
          }
        ]
      },
      "api": {
        "props": {
          "basePath": {
            "type": "string",
            "required": false
          },
          "currentUrl": {
            "type": "string",
            "required": false
          },
          "heading": {
            "type": "string | undefined",
            "required": false
          },
          "moreTabsLabel": {
            "type": "string",
            "required": false
          },
          "navStyle": {
            "type": "NavChromeStyle",
            "required": false
          },
          "tabs": {
            "type": "BarNavTab[]",
            "required": false
          },
          "value": {
            "type": "string",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsTabChange",
            "detail": "string"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-bar-nav",
        "react": "DsBarNav",
        "vue": "DsBarNav",
        "angular": "DsBarNav"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "badge",
        "button-unfilled",
        "menu",
        "text"
      ]
    },
    {
      "id": "component:ds-bar-title",
      "tag": "ds-bar-title",
      "name": "bar-title",
      "title": "BarTitle",
      "summary": "Page-level title chrome with an optional expanded route breadcrumb, compact Back action, supporting description, inline active-section menu, one primary action, grouped overflow actions, and explicit expanded, compact, or constrained variants.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Page-level title chrome with an optional expanded route breadcrumb, compact Back action, supporting description, inline active-section menu, one primary action, grouped overflow actions, and explicit expanded, compact, or constrained variants.",
        "useWhen": [
          "A top-level page needs one h1 above its content.",
          "A list or detail page has multiple route-level sections that belong in the inline active-section menu.",
          "A detail page needs route ancestors in expanded presentation and a page-level Back action in compact chrome.",
          "A page needs one primary action plus optional secondary or destructive overflow commands."
        ],
        "avoidWhen": [
          "The title belongs to a PanelTools drawer or fullscreen pane; use PanelToolHeader through PanelTools instead.",
          "The choices are primary application destinations or BarNav destinations rather than sections within the current page.",
          "The heading belongs to a card, modal, or other bounded region rather than the page.",
          "Local panels inside page content should remain directly selectable; use TabGroup instead.",
          "Automatic sticky or responsive page orchestration is required; compose BarTitle in ShellPage rather than implementing it in the header."
        ],
        "alternatives": [
          {
            "when": "A create or edit workflow needs Exit, persistent step navigation, and a final Save or Submit action.",
            "component": "component:ds-bar-workflow",
            "reason": "BarWorkflow owns compact-only workflow progression rather than responsive page identity."
          },
          {
            "when": "The header belongs to a PanelTools product view.",
            "component": "component:ds-panel-tool-header",
            "reason": "PanelToolHeader owns pane-level Back and actions without creating page chrome."
          },
          {
            "when": "A small set of inner-page panels should remain visible as tabs.",
            "component": "component:ds-tab-group",
            "reason": "TabGroup is the local content-view control rather than route-level page title chrome."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-shell-page",
          "component:ds-button-filled",
          "component:ds-button-unfilled",
          "component:ds-breadcrumb",
          "component:ds-menu",
          "component:ds-text"
        ],
        "patterns": [
          "pattern:shell-page"
        ],
        "accessibility": [
          "Provide one concise heading; BarTitle renders exactly one h1 and changes only its visual recipe between variants.",
          "Give compact Back a destination-specific accessible name such as Back to Drivers and handle dsBack in the route owner.",
          "Provide ordered breadcrumb items for deeper expanded paths and handle dsBreadcrumbSelect when native href navigation is not used; backLabel remains the single-parent expanded fallback.",
          "Keep value synchronized with the current child route; dsSectionChange returns the selected section id.",
          "Section and overflow triggers expose menu relationships and restore focus after selection or dismissal.",
          "Use one filled primary action in the page decision area and mark destructive overflow actions explicitly."
        ],
        "states": [
          "Omitting Back, sections, primaryAction, and actions produces the top-level title-only header.",
          "Two or more selectable sections add the inline section trigger; one section does not render a redundant menu.",
          "Dividers in sections or actions create separate Menu groups without becoming selectable rows.",
          "The overflow trigger uses its bordered treatment whenever the primary action is visible beside it; overflow-only and auto-collapsed-primary presentations keep the trigger borderless.",
          "expanded renders the larger heading, optional description, inset divider, and a full-width caption breadcrumb row above the title. The breadcrumb begins after 32px top padding; the following title and right-side actions share one top alignment. Compact renders 48px chrome with the existing icon Back action; constrained uses compact chrome and moves an auto-collapse primary action into overflow.",
          "primaryAction collapse defaults to auto. Use never for exceptional actions whose hierarchy must remain visible in constrained layouts.",
          "showDivider=false removes the bottom divider when the surrounding page composition supplies the boundary; showCompactDivider can independently restore or remove that boundary in compact and constrained variants."
        ],
        "responsiveBehavior": [
          "BarTitle does not observe viewport, shell, scroll, or container state. Its owner selects an explicit variant.",
          "ShellPage is the standard owner for automatic expanded, compact, and constrained selection.",
          "When ShellPage owns BarTitle on a secondary desktop or tablet page, its expanded, compact, and constrained presentations all match that canvas; the separate MobileHeader component remains primary.",
          "Compact titles use the shared compact-header geometry and md control inset so top-level headings align with BarNav and inline Back geometry aligns with PanelToolHeader. Long headings and section labels truncate independently while Back and action controls retain complete hit targets and accessible names.",
          "A never-collapse primary action remains visible in constrained mode; the title and section label yield space first."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Assign breadcrumbs, sections, primaryAction, and actions as JavaScript properties and replace array or object identities when controlled state changes.",
            "Handle dsBack for compact navigation and dsBreadcrumbSelect for application-owned expanded breadcrumb navigation, update value after dsSectionChange, and execute product commands from dsAction."
          ],
          "react": [
            "Pass breadcrumb, section, and action arrays directly to DsBarTitle and keep value controlled from route state.",
            "Place DsBarTitle in DsShellPage with slot=header when automatic page behavior is required."
          ],
          "angular": [
            "Bind complex values on the standalone DsBarTitle adapter and handle Back, breadcrumb, section, and action intent events in the route shell.",
            "Place ds-bar-title in ds-shell-page with slot=header; do not render router-outlet inside BarTitle."
          ]
        },
        "references": [
          {
            "label": "Explicit variant examples",
            "path": "src/wc/components/BarTitle/BarTitle.stories.ts"
          },
          {
            "label": "ShellPage composition and responsive examples",
            "path": "src/wc/components/ShellPage/ShellPage.stories.ts"
          },
          {
            "label": "Cross-browser shell-page and header coverage",
            "path": "tests/e2e/bar-title.spec.ts"
          }
        ]
      },
      "api": {
        "props": {
          "actions": {
            "type": "BarTitleActionItem[]",
            "required": false
          },
          "actionsAriaLabel": {
            "type": "string",
            "required": false
          },
          "backAriaLabel": {
            "type": "string",
            "required": false
          },
          "backLabel": {
            "type": "string",
            "required": false
          },
          "breadcrumbAriaLabel": {
            "type": "string",
            "required": false
          },
          "breadcrumbs": {
            "type": "BreadcrumbItem[]",
            "required": false
          },
          "description": {
            "type": "string",
            "required": false
          },
          "heading": {
            "type": "string",
            "required": true
          },
          "primaryAction": {
            "type": "BarTitlePrimaryAction | null",
            "required": false
          },
          "sections": {
            "type": "BarTitleSectionItem[]",
            "required": false
          },
          "sectionsAriaLabel": {
            "type": "string",
            "required": false
          },
          "showBack": {
            "type": "boolean",
            "required": false
          },
          "showCompactDivider": {
            "type": "boolean",
            "required": false
          },
          "showDivider": {
            "type": "boolean",
            "required": false
          },
          "value": {
            "type": "string",
            "required": false
          },
          "variant": {
            "type": "BarTitleVariant",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsAction",
            "detail": "string"
          },
          {
            "name": "dsBack",
            "detail": "MouseEvent"
          },
          {
            "name": "dsBreadcrumbSelect",
            "detail": "BreadcrumbSelectDetail"
          },
          {
            "name": "dsSectionChange",
            "detail": "string"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-bar-title",
        "react": "DsBarTitle",
        "vue": "DsBarTitle",
        "angular": "DsBarTitle"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens",
        "@ds-mo/icons"
      ],
      "componentDependencies": [
        "breadcrumb",
        "button-filled",
        "button-unfilled",
        "icon",
        "menu",
        "text",
        "tooltip"
      ]
    },
    {
      "id": "component:ds-bar-workflow",
      "tag": "ds-bar-workflow",
      "name": "bar-workflow",
      "title": "BarWorkflow",
      "summary": "Compact bold-brand create/edit workflow chrome with Exit, controlled previous and next step navigation, and a final Save or Submit action.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Compact bold-brand create/edit workflow chrome with Exit, controlled previous and next step navigation, and a final Save or Submit action.",
        "useWhen": [
          "A create or edit flow needs persistent page-level Exit and step navigation.",
          "A single-step form needs the same compact workflow chrome and final Save or Submit action.",
          "Next or Submit must remain visible while the application owns validation and the current step."
        ],
        "avoidWhen": [
          "The header identifies a routed page, list, or detail view; use BarTitle instead.",
          "The steps must be visibly enumerated or expose progress; BarWorkflow uses steps only to resolve its navigation controls.",
          "The header belongs to a PanelTools drawer or fullscreen pane; use PanelToolHeader through PanelTools instead.",
          "The interaction is a local wizard inside page content rather than page-level workflow chrome."
        ],
        "alternatives": [
          {
            "when": "A routed page needs responsive title, section, Back, and page-action presentations.",
            "component": "component:ds-bar-title",
            "reason": "BarTitle owns page identity and capacity variants rather than workflow progression."
          },
          {
            "when": "The workflow belongs to a tool drawer or fullscreen tool pane.",
            "component": "component:ds-panel-tool-header",
            "reason": "PanelToolHeader owns tool-pane navigation and actions within PanelTools."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-shell-page",
          "component:ds-mobile-header",
          "component:ds-button-filled",
          "component:ds-button-unfilled",
          "component:ds-text",
          "component:ds-tooltip"
        ],
        "patterns": [],
        "accessibility": [
          "Provide one concise workflow heading; BarWorkflow renders exactly one h1 and appends the controlled current-step count as heading · X/N only for multi-step workflows.",
          "Provide a workflow-specific Exit accessible name that describes the consequence or destination.",
          "Give every step a stable id and concise label even though step labels are not rendered as visible progress.",
          "Previous is omitted on the first step; it appears from step two onward. Next remains visible on intermediate steps and becomes the final labeled Check action on the last step.",
          "Use submitAction.type=submit inside a form so the final action preserves native submission semantics."
        ],
        "states": [
          "BarWorkflow always renders compact 48px bold-brand chrome; responsiveMode changes only the action geometry, never workflow state or hierarchy.",
          "An unrecognized value resolves navigation from the first step without mutating the controlled value.",
          "The first step omits Previous. Intermediate steps show Previous and Next. The last step replaces Next with the Check Save or Submit action.",
          "The default empty steps array is a single-step flow with the plain heading, no Previous control, and the final action visible. An explicit one-step array behaves the same way.",
          "isNextInactive blocks forward navigation while preserving the Next control; the target step's isInactive state also blocks entry.",
          "submitAction owns the final label, native button type, inactive state, and loading state."
        ],
        "responsiveBehavior": [
          "Desktop and tablet keep the established left-aligned identity and trailing actions.",
          "Mobile uses symmetric MobileHeader geometry with Exit leading, the title and step count centered, and Previous plus Next or Submit trailing.",
          "The heading truncates before Exit, Previous, and Next or Submit lose their complete hit targets.",
          "When slotted into ShellPage, BarWorkflow remains compact while ShellPage continues to provide sticky placement."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Assign steps and submitAction as JavaScript properties and replace their identities when controlled state changes.",
            "Update value after dsStepChange, handle dsExit in the workflow owner, and use dsSubmit only when product behavior supplements native form submission."
          ],
          "react": [
            "Pass steps and submitAction directly to DsBarWorkflow and keep value controlled in the workflow route.",
            "Place DsBarWorkflow in DsShellPage with slot=header when sticky page placement is required."
          ],
          "angular": [
            "Bind steps and submitAction on the standalone DsBarWorkflow adapter and update value from dsStepChange.",
            "Place ds-bar-workflow in ds-shell-page with slot=header and keep the form or router outlet in ShellPage content."
          ]
        },
        "references": [
          {
            "label": "Workflow states and controlled navigation",
            "path": "src/wc/components/BarWorkflow/BarWorkflow.stories.ts"
          },
          {
            "label": "Cross-browser workflow behavior",
            "path": "tests/e2e/bar-workflow.spec.ts"
          }
        ]
      },
      "api": {
        "props": {
          "exitAriaLabel": {
            "type": "string",
            "required": false
          },
          "exitLabel": {
            "type": "string",
            "required": false
          },
          "heading": {
            "type": "string",
            "required": true
          },
          "isNextInactive": {
            "type": "boolean",
            "required": false
          },
          "nextLabel": {
            "type": "string",
            "required": false
          },
          "previousLabel": {
            "type": "string",
            "required": false
          },
          "responsiveMode": {
            "type": "ShellResponsiveMode",
            "required": false
          },
          "steps": {
            "type": "BarWorkflowStep[]",
            "required": false
          },
          "submitAction": {
            "type": "BarWorkflowSubmitAction",
            "required": false
          },
          "value": {
            "type": "string",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsExit",
            "detail": "MouseEvent"
          },
          {
            "name": "dsStepChange",
            "detail": "string"
          },
          {
            "name": "dsSubmit",
            "detail": "MouseEvent"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-bar-workflow",
        "react": "DsBarWorkflow",
        "vue": "DsBarWorkflow",
        "angular": "DsBarWorkflow"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "button-filled",
        "button-unfilled",
        "mobile-header",
        "text",
        "tooltip"
      ]
    },
    {
      "id": "component:ds-breadcrumb",
      "tag": "ds-breadcrumb",
      "name": "breadcrumb",
      "title": "Breadcrumb",
      "summary": "Compact hierarchical page navigation with native links or application-owned selection, optional current-page semantics, and slash separators.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Compact hierarchical page navigation with native links or application-owned selection, optional current-page semantics, and slash separators.",
        "useWhen": [
          "A page needs to expose its hierarchical ancestors above the current page title.",
          "Users need to move directly to a broader page in the current route hierarchy.",
          "BarTitle expanded presentation needs an ancestor path instead of a directional Back button."
        ],
        "avoidWhen": [
          "The navigation represents primary application destinations; use PanelNav or BarNav.",
          "The choices switch peer views within the current page; use TabGroup or the BarTitle section selector.",
          "Only a directional return command is needed in compact chrome; use the owning header's Back action.",
          "The path would repeat the same current-page label already communicated by a nearby h1 without adding useful ancestors."
        ],
        "alternatives": [
          {
            "when": "The title and breadcrumb belong to responsive page chrome with page-level actions.",
            "component": "component:ds-bar-title",
            "reason": "BarTitle composes Breadcrumb in expanded mode and preserves compact Back behavior."
          },
          {
            "when": "A small set of peer content views should remain directly selectable.",
            "component": "component:ds-tab-group",
            "reason": "TabGroup communicates peer selection rather than route ancestry."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-bar-title",
          "component:ds-text",
          "component:ds-shell-page"
        ],
        "accessibility": [
          "The component renders a named navigation landmark containing an ordered list.",
          "Provide href for native navigation or handle dsSelect when the application router owns navigation.",
          "Mark at most one item current; it renders without interaction and exposes aria-current=page.",
          "Visible caption labels use secondary foreground and slash separators are decorative and hidden from assistive technology.",
          "Every interactive item remains keyboard reachable and receives the shared focus ring."
        ],
        "states": [
          "Items with href render native anchors; items without href render buttons and emit the same dsSelect detail.",
          "Preventing dsSelect cancels native anchor navigation.",
          "A current item is static text and never emits selection.",
          "Links have no resting underline and add a quaternary-foreground solid underline on hover; focus remains communicated by the shared focus ring."
        ],
        "responsiveBehavior": [
          "The path stays on one caption line and truncates long labels within the available width.",
          "Width is protected newest-to-oldest: the oldest ancestor collapses to a literal ellipsis before the next ancestor yields width, and the current location truncates only after every ancestor reaches its minimum.",
          "A fully collapsed item keeps its complete label available to assistive technology while rendering only the literal ellipsis visually.",
          "Separators remain visible while labels yield width."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Assign items as a JavaScript property and replace its array identity when the route changes.",
            "Use relative or absolute href values for native navigation; omit href when the host router handles dsSelect."
          ],
          "react": [
            "Pass items to DsBreadcrumb and handle onDsSelect when navigation is application-owned."
          ],
          "angular": [
            "Bind items on the standalone DsBreadcrumb adapter and handle dsSelect when navigation is application-owned."
          ]
        },
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/Breadcrumb/Breadcrumb.stories.ts"
          },
          {
            "label": "Expanded page-header composition",
            "path": "src/wc/components/BarTitle/BarTitle.tsx"
          }
        ]
      },
      "api": {
        "props": {
          "ariaLabel": {
            "type": "string",
            "required": false
          },
          "items": {
            "type": "BreadcrumbItem[]",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsSelect",
            "detail": "BreadcrumbSelectDetail"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-breadcrumb",
        "react": "DsBreadcrumb",
        "vue": "DsBreadcrumb",
        "angular": "DsBreadcrumb"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "text"
      ]
    },
    {
      "id": "component:ds-button-filled",
      "tag": "ds-button-filled",
      "name": "button-filled",
      "title": "ButtonFilled",
      "summary": "Highest-emphasis command button for the single primary action in a local decision area, with semantic consequence and async progress treatments.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Highest-emphasis command button for the single primary action in a local decision area, with semantic consequence and async progress treatments.",
        "useWhen": [
          "The user initiates the single primary command in a local decision area.",
          "An action's consequence requires a matching semantic treatment.",
          "A standalone compact primary action needs an icon-only presentation with an explicit accessible name."
        ],
        "avoidWhen": [
          "Another filled action already exists in the same local decision area.",
          "The action is unfilled icon-only shell or navigation chrome.",
          "The element represents navigation rather than a command.",
          "The content is a persistent selected state rather than an action.",
          "A semantic color would be decorative or merely match the surrounding product area.",
          "The control is an overflow or more-options menu whose only content is an Ellipses glyph; that role is never filled."
        ],
        "alternatives": [
          {
            "when": "The action is icon-only shell, navigation, overflow, or tool-rail chrome.",
            "component": "component:ds-button-unfilled",
            "reason": "Unfilled buttons provide the correct active, border, and surface-aware interaction states for chrome."
          },
          {
            "when": "The user is choosing a destination in application navigation.",
            "component": "component:ds-panel-nav",
            "reason": "Navigation components own destination selection, active state, and navigation semantics."
          },
          {
            "when": "The control is the overflow or more-options menu for a row, card, or toolbar.",
            "component": "component:ds-button-unfilled",
            "reason": "An icon-only Ellipses trigger is chrome, and its glyph conveys the menu without a chevron; a filled button never carries that role."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-modal",
          "component:ds-field",
          "component:ds-menu"
        ],
        "patterns": [
          "pattern:menu-trigger"
        ],
        "accessibility": [
          "Provide an explicit accessible name for icon-only buttons.",
          "Set hasMenu when the action opens a Menu; it implies aria-haspopup of menu and renders the trailing chevron. Pass controls with the Menu id and expanded from the same open state given to Menu.",
          "Use haspopup directly for a non-menu popup such as a dialog; that case gets no chevron.",
          "Use inactive state only when the action must remain visible but unavailable.",
          "Do not encode the action meaning through color alone.",
          "Loading keeps the action focused and named, exposes busy and disabled state, and blocks activation; announce broader operation progress from the owning workflow when users need confirmation.",
          "Use native submit behavior for form submission and handle the form submit event rather than submitting from the button click event."
        ],
        "states": [
          "Every size applies one complete control-density recipe across frame height, inline padding, icon zone, text-container inset, gap, and radius.",
          "Set isInset only when the button is nested inside a same-size control. The default single inset removes 4px overall; insetDepth double removes 8px overall so the parent can add 4px per edge while preserving its outer alignment box. Double inset falls back to single at xs to protect minimum icon geometry.",
          "Use only one filled action per local decision area; render all secondary actions with ButtonUnfilled.",
          "Choose brand or neutral for general commands. Reserve positive, negative, warning, and caution for matching action consequences, and AI, guide, or walkthrough for actions that enter those feature experiences.",
          "Contrast serves both surface adaptation and hierarchy, but never permits a second filled action in the same decision area.",
          "The optional inset border is off by default. Enable it only when the filled action needs an explicit edge against its parent surface.",
          "Parent surface context changes only the optional inset border color. Contrast continues to own the button fill, foreground, hover, pressed, and focus treatments; never use surface context to change action hierarchy.",
          "Rounded changes only the control radius to the half-radius treatment; it does not change hierarchy, size, variant, intent, or interaction semantics.",
          "Loading prevents duplicate activation without applying inactive opacity or removing the current keyboard focus.",
          "Icon and icon-label loading replace the icon in place. Label-only loading centers the loader while preserving the button's measured width.",
          "Physical press scaling is on by default. Disable it only when an owning composite must keep child or background geometry fixed; hover and pressed interaction washes remain available.",
          "ButtonFilled has no active, pressed, or selected state; a filled action is a command, not a toggle or a persistent selection.",
          "An open popup is a transient pressed state instead. While expanded is true the pressed wash is held for the popup's complete rendered lifecycle and survives hover, so the trigger reads as held open without introducing a selected treatment.",
          "hasMenu supports only the label and icon-label variants. The chevron is what communicates that a menu will open, so an icon-only filled menu button would leave the affordance unstated."
        ],
        "responsiveBehavior": [
          "Use fill width only when the parent layout calls for a full-width action, commonly on narrow form layouts."
        ],
        "frameworkCaveats": {
          "customElements": [
            "For form submission, use the native submit type and listen to the form submit event; use dsClick for non-submit commands."
          ],
          "react": [
            "Keep async state in the owner and pass it to the loading state until the command settles."
          ],
          "angular": [
            "Keep async state in the owner and pass it to the loading state until the command settles."
          ]
        },
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/ButtonFilled/ButtonFilled.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "ariaLabel": {
            "type": "string | null",
            "required": false
          },
          "background": {
            "type": "ButtonFilledBackground | undefined",
            "required": false
          },
          "contrast": {
            "type": "ButtonFilledContrast",
            "required": false
          },
          "controls": {
            "type": "string | undefined",
            "required": false
          },
          "expanded": {
            "type": "boolean | undefined",
            "required": false
          },
          "hasBorder": {
            "type": "boolean",
            "required": false
          },
          "hasMenu": {
            "type": "boolean",
            "required": false
          },
          "haspopup": {
            "type": "ButtonFilledPopup | undefined",
            "required": false
          },
          "icon": {
            "type": "string",
            "required": false
          },
          "insetDepth": {
            "type": "ControlInsetDepth",
            "required": false
          },
          "intent": {
            "type": "ButtonFilledIntent",
            "required": false
          },
          "isInactive": {
            "type": "boolean",
            "required": false
          },
          "isInset": {
            "type": "boolean",
            "required": false
          },
          "isLoading": {
            "type": "boolean",
            "required": false
          },
          "label": {
            "type": "string",
            "required": false
          },
          "pressScale": {
            "type": "boolean",
            "required": false
          },
          "rounded": {
            "type": "boolean",
            "required": false
          },
          "size": {
            "type": "ButtonFilledSize",
            "required": false
          },
          "type": {
            "type": "'button' | 'submit' | 'reset'",
            "required": false
          },
          "variant": {
            "type": "ButtonFilledVariant",
            "required": false
          },
          "width": {
            "type": "ButtonFilledWidth",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsClick",
            "detail": "MouseEvent"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-button-filled",
        "react": "DsButtonFilled",
        "vue": "DsButtonFilled",
        "angular": "DsButtonFilled"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens",
        "@ds-mo/icons"
      ],
      "componentDependencies": [
        "badge",
        "icon",
        "loader",
        "text"
      ]
    },
    {
      "id": "component:ds-button-unfilled",
      "tag": "ds-button-unfilled",
      "name": "button-unfilled",
      "title": "ButtonUnfilled",
      "summary": "Secondary command and compact chrome button with optional persistent toggle state, surface-aware interaction treatment, and async progress.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Secondary command and compact chrome button with optional persistent toggle state, surface-aware interaction treatment, and async progress.",
        "useWhen": [
          "A secondary command accompanies the single filled primary action in a local decision area.",
          "A toolbar, tool rail, overflow area, or shell region needs a compact icon action.",
          "A command represents a persistent toggle or mode whose active state remains meaningful after activation.",
          "A row, card, or toolbar needs an overflow or more-options menu; this is the only component that carries that role."
        ],
        "avoidWhen": [
          "The command is the single primary action in a local decision area; use ButtonFilled instead.",
          "The control selects an application destination or local content panel; use the matching navigation component.",
          "Active styling would only indicate the most recently invoked command or add decorative emphasis.",
          "Surface context would be used to make the action louder or quieter rather than describe its actual parent surface."
        ],
        "alternatives": [
          {
            "when": "The command is the single primary action in the decision area.",
            "component": "component:ds-button-filled",
            "reason": "ButtonFilled owns highest-emphasis commands."
          },
          {
            "when": "The choices are persistent application destinations.",
            "component": "component:ds-panel-nav",
            "reason": "PanelNav owns primary route selection and navigation semantics."
          },
          {
            "when": "The choices are transient commands or contextual options.",
            "component": "component:ds-menu",
            "reason": "Menu owns temporary popup collections and their keyboard model."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-button-filled",
          "component:ds-menu",
          "component:ds-panel-tools"
        ],
        "patterns": [
          "pattern:menu-trigger"
        ],
        "accessibility": [
          "Provide an explicit accessible name for every icon-only action.",
          "Set hasMenu when the button triggers a Menu; it implies aria-haspopup of menu. Pass controls with the Menu id and expanded from the same open state given to Menu. Expanded popup triggers hold only the pressed wash while open, without changing their resting foreground; expanded disclosure controls without popup semantics retain the normal resting appearance.",
          "Give an icon-only menu button an accessible name that states the role, such as More options or Customize table, because no visible label or chevron carries it.",
          "Use haspopup directly for a non-menu popup such as a listbox or dialog; those cases get no chevron.",
          "Use pressed only for a genuine toggle button; it supplies aria-pressed and dsChange intent. Use isActive only for owner-controlled visual emphasis inside a composite whose selection semantics live on the owner.",
          "Treat notification dots as supplemental unread or status information; never use a dot as the sole state, meaning, or accessible name.",
          "Loading keeps the action focused and named, exposes busy and disabled state, and blocks activation; announce broader operation progress from the owning workflow when needed.",
          "Use inactive state only when an unavailable action must remain visible.",
          "For form submission, use native submit behavior and handle the form submit event rather than submitting from the button click event."
        ],
        "states": [
          "Every size applies one complete control-density recipe across frame height, inline padding, icon zone, text-container inset, gap, and radius.",
          "Set isInset only when the button is nested inside a same-size control. The default single inset removes 4px overall; insetDepth double removes 8px overall so the parent can add 4px per edge while preserving its outer alignment box. Double inset falls back to single at xs to protect minimum icon geometry.",
          "A true pressed toggle and owner-controlled isActive emphasis share the selected visual treatment, but only pressed supplies toggle semantics and dsChange.",
          "General content UI keeps the selected interaction fill and border for pressed or active emphasis.",
          "Shell, navigation, and tool-rail composites use isActive with primary foreground across the complete control and no selected fill or border.",
          "The omitted default surface treatment is for primary and secondary parent surfaces and uses the brand-active selected fill; pass faint explicitly on faint surfaces to use the neutral active fill.",
          "Surface context must match the actual parent surface; translucent, inverted, media, and always-dark treatments are reserved for those surfaces.",
          "Loading prevents duplicate activation without applying inactive opacity or removing the current keyboard focus.",
          "Rounded changes only the control radius to the half-radius treatment; it does not change hierarchy, size, variant, or interaction semantics.",
          "Physical press scaling is on by default. Disable it only when an owning composite must keep child or background geometry fixed; hover and pressed interaction washes remain available.",
          "Icon and icon-label loading replace the icon in place. Label-only loading centers the loader while preserving the button's measured width.",
          "hasMenu covers two distinct menu-button shapes and the variant selects between them. With label or icon-label the action has a menu, and a trailing chevron carries the affordance. With icon the button is a menu and no chevron is added.",
          "Because the icon-only shape has no chevron, its glyph must convey the menu on its own. Use Ellipses for a generic more-options or overflow control. Use a specific icon when the menu has a named purpose, such as Table for Customize table.",
          "An open popup is a transient pressed state rather than a selected one. While expanded is true and haspopup or hasMenu identifies a popup, the pressed wash is held for the popup's complete rendered lifecycle and survives hover without promoting foreground or selected fill, including when chrome opts out of selected fills with activeFill set to false. Expanded disclosure buttons without popup semantics remain visually neutral."
        ],
        "responsiveBehavior": [
          "The consuming layout decides when an icon-label action becomes icon-only and must provide an explicit accessible name after changing variants. Table caption Customize is one such layout: below 900px it uses the icon shape, and a customized catalog promotes the Table icon to primary.",
          "When collapseLabel is set inside a named ds-table container narrower than 900px, an icon-label caption action omits its label and chevron and becomes icon-only while keeping its accessible name. An active control then promotes the icon to primary.",
          "Use fill width only when the parent layout requires a full-width secondary action."
        ],
        "frameworkCaveats": {
          "customElements": [
            "For form submission, use the native submit type and listen to the form submit event; use dsClick for non-submit commands.",
            "Roving-focus composites own the button's tab-stop placement and selection semantics."
          ],
          "react": [
            "Use pressed for controlled toggles and isActive for composite-owned emphasis; keep async state synchronized from the owner."
          ],
          "angular": [
            "Use pressed for controlled toggles and isActive for composite-owned emphasis; keep async state synchronized from the owner."
          ]
        },
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/ButtonUnfilled/ButtonUnfilled.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "activeFill": {
            "type": "boolean",
            "required": false
          },
          "ariaLabel": {
            "type": "string | null",
            "required": false
          },
          "background": {
            "type": "ButtonUnfilledBackground | undefined",
            "required": false
          },
          "collapseLabel": {
            "type": "boolean",
            "required": false
          },
          "controls": {
            "type": "string | undefined",
            "required": false
          },
          "dot": {
            "type": "boolean",
            "required": false
          },
          "expanded": {
            "type": "boolean | undefined",
            "required": false
          },
          "focusTabIndex": {
            "type": "number",
            "required": false
          },
          "hasBorder": {
            "type": "boolean",
            "required": false
          },
          "hasMenu": {
            "type": "boolean",
            "required": false
          },
          "haspopup": {
            "type": "ButtonUnfilledPopup | undefined",
            "required": false
          },
          "icon": {
            "type": "string",
            "required": false
          },
          "insetDepth": {
            "type": "ControlInsetDepth",
            "required": false
          },
          "isActive": {
            "type": "boolean",
            "required": false
          },
          "isInactive": {
            "type": "boolean",
            "required": false
          },
          "isInset": {
            "type": "boolean",
            "required": false
          },
          "isLoading": {
            "type": "boolean",
            "required": false
          },
          "label": {
            "type": "string",
            "required": false
          },
          "pressScale": {
            "type": "boolean",
            "required": false
          },
          "pressed": {
            "type": "boolean | undefined",
            "required": false
          },
          "rounded": {
            "type": "boolean",
            "required": false
          },
          "size": {
            "type": "ButtonUnfilledSize",
            "required": false
          },
          "type": {
            "type": "'button' | 'submit' | 'reset'",
            "required": false
          },
          "variant": {
            "type": "ButtonUnfilledVariant",
            "required": false
          },
          "width": {
            "type": "ButtonUnfilledWidth",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsChange",
            "detail": "boolean"
          },
          {
            "name": "dsClick",
            "detail": "MouseEvent"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-button-unfilled",
        "react": "DsButtonUnfilled",
        "vue": "DsButtonUnfilled",
        "angular": "DsButtonUnfilled"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens",
        "@ds-mo/icons"
      ],
      "componentDependencies": [
        "badge",
        "icon",
        "loader",
        "text"
      ]
    },
    {
      "id": "component:ds-card-chart",
      "tag": "ds-card-chart",
      "name": "card-chart",
      "title": "CardChart",
      "summary": "Standard chart card chrome with variant-owned chart and legend composition.",
      "intentStatus": "complete",
      "intent": {
        "audience": "specialized",
        "status": "stable",
        "summary": "Standard chart card chrome with variant-owned chart and legend composition.",
        "useWhen": [
          "A chart, legend, metric visualization, or custom chart composition needs standard card chrome.",
          "A chart and static external legend need one standard card layout.",
          "A chart card needs a visible heading, optional filter action, and application-owned chart data."
        ],
        "avoidWhen": [
          "The card contains editable settings; use CardSetting.",
          "The surface contains ordinary non-visualization content.",
          "The application needs to replace the card chrome rather than compose its chart and actions."
        ],
        "alternatives": [
          {
            "when": "The surface contains editable settings.",
            "component": "component:ds-card-setting",
            "reason": "CardSetting owns the controlled settings-section workflow."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-chart",
          "component:ds-chart-legend",
          "component:ds-button-unfilled"
        ],
        "accessibility": [
          "Provide a concise visible heading; the component renders it as a section heading.",
          "Slotted actions must provide accessible names and controlled-state semantics.",
          "Charts retain their own image names and data summaries.",
          "A visible legend provides persistent labels while the chart retains its own accessible name and focus behavior."
        ],
        "states": [
          "Custom mode provides flexible body chrome and does not mutate chart or legend interaction.",
          "Chart mode keeps a slotted external legend static by disabling hover emphasis.",
          "showFilter adds the standard filter action and emits dsFilterClick without owning filter state."
        ],
        "responsiveBehavior": [
          "The sm, md, or lg width sets a matching token-based minimum height and remains constrained by its parent.",
          "The body allocates remaining height to an unconfigured ds-chart while legends retain content height; authored chart height and aspectRatio remain authoritative.",
          "Parent layouts own wrapping, stacking, and breakpoint-dependent card width."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Set variant to chart for the standard chart and static legend layout; slot chart, legend, actions, and supporting content by name."
          ],
          "react": [
            "Keep chart data in React and pass chart, legend, and action elements through named slots."
          ],
          "angular": [
            "Keep chart data in Angular and project chart, legend, and action elements through named slots."
          ]
        },
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/CardChart/CardChart.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "cardWidth": {
            "type": "CardChartWidth",
            "required": false
          },
          "filterLabel": {
            "type": "string",
            "required": false
          },
          "heading": {
            "type": "string",
            "required": true
          },
          "showFilter": {
            "type": "boolean",
            "required": false
          },
          "variant": {
            "type": "CardChartVariant",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsFilterClick",
            "detail": "void"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-card-chart",
        "react": "DsCardChart",
        "vue": "DsCardChart",
        "angular": "DsCardChart"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "button-unfilled",
        "text"
      ]
    },
    {
      "id": "component:ds-card-overview",
      "tag": "ds-card-overview",
      "name": "card-overview",
      "title": "CardOverview",
      "summary": "Page-level summary with a persistent 48px reporting bar above an equal-track grid of an optional safety score and comparable measures, plus an elevated page-controlled collapse surface.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Page-level summary with a persistent 48px reporting bar above an equal-track grid of an optional safety score and comparable measures, plus an elevated page-controlled collapse surface.",
        "useWhen": [
          "A page opens with one headline figure that the surrounding measures explain.",
          "Every measure is compared against the same period, so one caption describes the comparison for all of them.",
          "The measures are read together at a glance rather than explored individually."
        ],
        "avoidWhen": [
          "There is no headline figure and the measures are unrelated; use the matching card surface for each one.",
          "A measure needs a chart, sparkline, or other visualization; the grid presents values and change only.",
          "The measures each require their own comparison period or their own filter control.",
          "The content is a settings section or a general read-only card."
        ],
        "alternatives": [
          {
            "when": "A measure needs a chart or other data visualization.",
            "component": "component:ds-card-chart",
            "reason": "CardChart owns the data-visualization card contract; the overview grid presents values and change only."
          },
          {
            "when": "The surface is a settings section with an edit workflow.",
            "component": "component:ds-card-setting",
            "reason": "CardSetting owns the controlled view and edit chrome."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-select",
          "component:ds-button-unfilled",
          "component:ds-text",
          "component:ds-tooltip"
        ],
        "accessibility": [
          "The bar is a labelled region; set overviewLabel to name what is being summarised, such as Safety summary.",
          "Colour never carries trend meaning alone; the arrow direction and formatted change value are both included in the accessible text.",
          "Measures become selectable only when they are not inactive. Selectable measures form one roving tab stop, so the grid is a single stop and arrow keys move between measures.",
          "Set labelTooltip when a measure's label needs qualifying rather than shortening the label into something ambiguous.",
          "While loading, the region exposes a busy state and renders skeletons whose type metrics match the resolved content."
        ],
        "states": [
          "Score and measures are supplied as data; the component owns their type treatment so summary bars stay consistent across pages.",
          "Trend is supplied already resolved as a direction, a formatted value, and a tone. Whether a rise reads well is a product decision, so the component never infers tone from the numbers. Derive it with resolveMetricTrend.",
          "Omit a trend when there is nothing to report; resolveMetricTrend returns null in that case so no zero change is rendered.",
          "Omit score to render a centered Score unavailable cell with a tertiary border and no score fill. Set scoreErrorMessage to replace that copy while the measures remain readable.",
          "Loading replaces the score and measures with skeletons and does not alter the slotted period control. When measures are already supplied, their count preserves the resolved grid shape; otherwise five measure placeholders join the score in the standard six-cell grid.",
          "At most seven measures are shown. Keep larger collections outside the summary bar rather than turning it into a dense dashboard.",
          "The period and filter controls are slotted rather than owned. Use the period slot when the current range is selectable; otherwise periodLabel supplies fixed current copy in the same md control-frame and label-inset anatomy. Use the filter slot for the application-owned comparison-window control. Slotted Selects use hasBorder false so the 48px bar owns their surrounding boundary and allowClear false because both controls always require one selected reporting period.",
          "A numeric safety score infers fair from 0–50, good from 51–80, and excellent from 81–100. The level can be supplied explicitly when the displayed value is not numeric. The deprecated band field is ignored.",
          "The safety score is the first grid cell and uses the same track, 8px outer inset, 6px inner padding, dividers, and responsive behavior as metric cells. The display value removes 8px from both block edges of its line box so it does not increase the shared row height. Score remains nonselectable and excluded from metric roving focus.",
          "During page-controlled scroll collapse, the component preserves its expanded flow height and stationary reporting bar while the metric grid moves and clips beneath it. Elevation remains fitted to the visible surface.",
          "compact is exactly 48px high and renders only the reporting bar. It omits Score, measures, and footer."
        ],
        "responsiveBehavior": [
          "The measure grid reflows to fewer columns and finally stacks without horizontal scrolling. Even cell totals prefer complete rows; odd totals retain the densest fitting layout and may leave an orphan in the final row.",
          "Every occupied grid track has the same width. When a final row is incomplete, its measures keep the same width as the row above and the unused tracks remain empty.",
          "Set metricMinWidth to change the width a measure may shrink to before the grid drops a column.",
          "The safety score participates in the same equal-width tracks as measures rather than occupying a separate rail.",
          "The reporting bar owns an exact 8px inset on every edge. Fixed current copy and slotted controls begin at that inset; their labels share md control-frame geometry and truncate before changing the 48px height.",
          "Every measure occupies a full-width row in the stacked state.",
          "Set layout to stacked when the owning page shell enters a responsive mode before the card's own container reaches its narrow threshold.",
          "CardOverview does not observe scroll, choose sticky offsets, or switch its own presentation. The page owner supplies collapse progress, keeps the card sticky at the appropriate shell inset, and swaps to compact at the 48px endpoint.",
          "Leave scroll collapse inactive on page modes that do not support sticky compact summary chrome."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Assign score and metrics as JavaScript properties; both are objects and cannot be expressed as HTML attributes.",
            "Place an optional current-range control in the period slot and the comparison-window control in the filter slot; the component reserves their layout but never computes or renders controls.",
            "When driving scroll collapse, update scrollCollapseProgress from page-owned geometry and swap to a separate compact presentation at the endpoint."
          ],
          "react": [
            "Pass score and metrics as props and read the selected measure from the onDsMetricSelect event detail.",
            "Derive each trend with resolveMetricTrend so tone stays an explicit product decision.",
            "Keep sticky geometry and scrollCollapseProgress in the page owner; CardOverview only renders the visual collapse."
          ],
          "angular": [
            "Bind [score] and [metrics] as properties and read the selected measure from $event.detail on (dsMetricSelect).",
            "Derive each trend with resolveMetricTrend so tone stays an explicit product decision.",
            "Keep date math, sticky geometry, and [scrollCollapseProgress] in the page owner; CardOverview only renders the supplied composition and visual collapse."
          ]
        },
        "references": [
          {
            "label": "Storybook structural examples",
            "path": "src/wc/components/CardOverview/CardOverview.stories.ts"
          },
          {
            "label": "Trend resolution unit coverage",
            "path": "tests/metric-change.test.ts"
          }
        ]
      },
      "api": {
        "props": {
          "comparisonLabel": {
            "type": "string",
            "required": false
          },
          "isLoading": {
            "type": "boolean",
            "required": false
          },
          "layout": {
            "type": "CardOverviewLayout",
            "required": false
          },
          "metricMinWidth": {
            "type": "string",
            "required": false
          },
          "metrics": {
            "type": "OverviewMetric[]",
            "required": false
          },
          "overviewLabel": {
            "type": "string",
            "required": false
          },
          "periodLabel": {
            "type": "string",
            "required": false
          },
          "score": {
            "type": "OverviewScore | undefined",
            "required": false
          },
          "scoreErrorMessage": {
            "type": "string | undefined",
            "required": false
          },
          "scrollCollapseProgress": {
            "type": "number",
            "required": false
          },
          "variant": {
            "type": "CardOverviewVariant",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsMetricSelect",
            "detail": "OverviewMetric"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-card-overview",
        "react": "DsCardOverview",
        "vue": "DsCardOverview",
        "angular": "DsCardOverview"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "skeleton",
        "text",
        "tooltip"
      ]
    },
    {
      "id": "component:ds-card-setting",
      "tag": "ds-card-setting",
      "name": "card-setting",
      "title": "CardSetting",
      "summary": "Persistent settings-section surface with a heading, controlled view/edit chrome, fixed edit-save-cancel actions, and application-owned body content.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Persistent settings-section surface with a heading, controlled view/edit chrome, fixed edit-save-cancel actions, and application-owned body content.",
        "useWhen": [
          "A settings page needs a persistent section that switches between read-only and editable content.",
          "The parent can control one active editing section and owns validation, persistence, cancellation, and body content.",
          "The section uses the standard Pencil, Save, and Cancel header workflow."
        ],
        "avoidWhen": [
          "The surface contains a chart, legend, metric visualization, or other data-visualization composition.",
          "The content is a general-purpose read-only card with no settings edit workflow.",
          "The task must block the rest of the interface or requires confirmation in a modal.",
          "Several sections must remain editable at the same time.",
          "The header requires custom actions beyond the fixed edit-save-cancel workflow."
        ],
        "alternatives": [
          {
            "when": "The surface contains a chart or specialized data-visualization composition.",
            "component": "component:ds-card-chart",
            "reason": "CardChart owns the independently evolving chart-card contract."
          },
          {
            "when": "The task must block the interface for one focused decision or short workflow.",
            "component": "component:ds-modal",
            "reason": "Modal provides top-layer focus containment and explicit blocking-task dismissal."
          },
          {
            "when": "Only one labeled form control is needed without a section surface.",
            "component": "component:ds-field",
            "reason": "Field provides the control label, supporting copy, and validation relationship without card chrome."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-field",
          "component:ds-input",
          "component:ds-select",
          "component:ds-switch",
          "component:ds-text"
        ],
        "accessibility": [
          "Provide a concise heading that identifies the settings section; CardSetting renders it as an h2.",
          "Edit, Save, and Cancel are icon-only controls with localized accessible labels supplied by the matching label props. When several sections share a page, include the section name in each label.",
          "The owner must expose persistent field labels, descriptions, and validation messages inside the body.",
          "Save must not remove validation errors or exit editing until the parent accepts the action and updates the controlled editing state.",
          "Cancel must restore or retain the last persisted values according to product policy before the parent exits editing.",
          "Keep only one CardSetting in edit mode so keyboard and screen-reader users have one unambiguous set of Save and Cancel actions.",
          "When another section requests editing, resolve dirty changes in the current section before switching; never silently discard user input."
        ],
        "states": [
          "The editing property is controlled; CardSetting never changes it internally.",
          "dsAction emits edit, save, or cancel with the original pointer event. The parent decides whether and when editing changes.",
          "When another section requests edit, the parent keeps one active section and resolves any dirty current section before switching.",
          "The parent owns read-only versus editable body composition, dirty state, validation, persistence, loading, success, and error consequences.",
          "A save request keeps the section editing while validation or persistence is pending; the parent exits only after success.",
          "A cancel request does not persist changes; the parent restores its chosen value snapshot and exits editing."
        ],
        "responsiveBehavior": [
          "Choose sm, md, or lg from the parent layout; each width uses its matching token-based minimum height.",
          "The surface never exceeds its parent width, while the parent owns wrapping, columns, stacking, and breakpoint changes.",
          "At narrow widths, keep the fixed header actions visible and let application-owned body layouts collapse before allowing horizontal overflow."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Set editing as a JavaScript property and inspect dsAction.detail.action before updating the controlled state.",
            "When one section emits edit, update every sibling CardSetting so only the requested section remains editing."
          ],
          "react": [
            "Pass editing from parent state and inspect onDsAction event detail; do not treat Save as successful until validation and persistence complete.",
            "Store one active section id and derive each CardSetting editing prop from that id."
          ],
          "angular": [
            "Bind [editing] and inspect $event.detail.action from (dsAction); do not treat Save as successful until validation and persistence complete.",
            "Store one active section id and derive each CardSetting editing binding from that id."
          ]
        },
        "references": [
          {
            "label": "Storybook controlled and single-edit examples",
            "path": "src/wc/components/CardSetting/CardSetting.stories.ts"
          },
          {
            "label": "Cross-browser shell and action coverage",
            "path": "tests/e2e/card-setting.spec.ts"
          }
        ]
      },
      "api": {
        "props": {
          "cancelLabel": {
            "type": "string",
            "required": false
          },
          "cardWidth": {
            "type": "CardSettingWidth",
            "required": false
          },
          "editLabel": {
            "type": "string",
            "required": false
          },
          "editing": {
            "type": "boolean",
            "required": false
          },
          "heading": {
            "type": "string",
            "required": true
          },
          "saveLabel": {
            "type": "string",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsAction",
            "detail": "CardSettingActionDetail"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-card-setting",
        "react": "DsCardSetting",
        "vue": "DsCardSetting",
        "angular": "DsCardSetting"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "button-filled",
        "button-unfilled",
        "text"
      ]
    },
    {
      "id": "component:ds-chart",
      "tag": "ds-chart",
      "name": "chart",
      "title": "Chart",
      "summary": "Responsive chart grammar for Cartesian, polar, heatmap, and distribution compositions with one keyed scene and centralized focus.",
      "intentStatus": "complete",
      "intent": {
        "audience": "specialized",
        "status": "stable",
        "summary": "Responsive chart grammar for Cartesian, polar, heatmap, and distribution compositions with one keyed scene and centralized focus.",
        "useWhen": [
          "A product needs a responsive line, area, bar, scatter, pie, donut, gauge, radar, heatmap, histogram, density, or boxplot visualization.",
          "Several mark layers must share scales and semantic interaction points."
        ],
        "avoidWhen": [
          "The visualization needs maps, networks, brushing, zooming, selection, or Canvas."
        ],
        "alternatives": [],
        "commonlyComposedWith": [
          "component:ds-chart-legend",
          "component:ds-card-chart",
          "component:ds-tooltip-chart"
        ],
        "accessibility": [
          "Provide the required label and an adjacent exact-value summary when exact values are essential.",
          "The SVG is one tab stop; arrow keys, Home, End, and Escape control semantic focus.",
          "Pointer and keyboard input resolve through the same interaction points and polite status output."
        ],
        "states": [
          "Definition compilation is renderer-independent and regenerates when data, locale, width, or height changes.",
          "Stable mark and datum keys preserve focus across responsive recompilation and reordered data.",
          "Tooltip rows are chart-owned while legends remain external and static.",
          "Pie and donut pointer tooltips require direct slice containment and follow the pointer; keyboard tooltips remain anchored to the semantic slice.",
          "Polar center content defaults to its authored total and may opt into focused content."
        ],
        "responsiveBehavior": [
          "The chart observes its container unless width is fixed and recompiles geometry at CSS pixel dimensions.",
          "Height uses an authored height or aspectRatio, fills the chart region supplied by CardChart, and otherwise defaults to 320px.",
          "Measured guide labels reserve margins and thin colliding ticks while retaining boundary ticks."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Assign definition as a JavaScript property and import D3 scale factories from granular D3 packages."
          ],
          "react": [
            "Pass the typed definition object as a property; do not serialize it to an attribute."
          ],
          "angular": [
            "Bind definition as a property so accessors and D3 factories remain intact."
          ]
        },
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/Chart/Chart.stories.ts"
          },
          {
            "label": "Chart guide",
            "path": "src/docs/Charts.mdx"
          }
        ]
      },
      "api": {
        "props": {
          "aspectRatio": {
            "type": "number",
            "required": false
          },
          "definition": {
            "type": "ChartDefinition",
            "required": true
          },
          "description": {
            "type": "string",
            "required": false
          },
          "height": {
            "type": "number",
            "required": false
          },
          "label": {
            "type": "string",
            "required": true
          },
          "locale": {
            "type": "string",
            "required": false
          },
          "width": {
            "type": "number",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsChartFocusChange",
            "detail": "ChartFocusChangeDetail"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-chart",
        "react": "DsChart",
        "vue": "DsChart",
        "angular": "DsChart"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "tooltip-chart"
      ]
    },
    {
      "id": "component:ds-chart-legend",
      "tag": "ds-chart-legend",
      "name": "chart-legend",
      "title": "ChartLegend",
      "summary": "External chart legend with swatches, labels, optional values and percentages, and explicit deep links.",
      "intentStatus": "complete",
      "intent": {
        "audience": "specialized",
        "status": "stable",
        "summary": "External chart legend with swatches, labels, optional values and percentages, and explicit deep links.",
        "useWhen": [
          "A chart needs the standard swatch, label, and optional numeric-detail legend.",
          "Polar slices or Cartesian series need a continuously visible key beside or below the visualization.",
          "A category has an explicit deep-link destination and should render as an accessible link."
        ],
        "avoidWhen": [
          "The design calls for chips, bare swatches, external stat callouts, or another custom legend treatment.",
          "Rows need to toggle visibility, filter data, or represent selection.",
          "The content is a command menu or navigation list unrelated to chart data."
        ],
        "alternatives": [
          {
            "when": "The product needs a nonstandard legend treatment.",
            "component": "component:ds-text",
            "reason": "Compose product-owned semantic markup from the same chart data rather than forcing it into this row recipe."
          },
          {
            "when": "A chart and static series key belong in the canonical dashboard card.",
            "component": "component:ds-card-chart",
            "reason": "The chart variant places the external legend and disables decorative local hover highlighting."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-chart",
          "component:ds-card-chart"
        ],
        "accessibility": [
          "Rows remain non-interactive unless the item supplies an actual link destination.",
          "Optional highlight changes opacity only and never moves focus or announces selection.",
          "Keep full labels available when visible text truncates, and retain stable tabular numeric columns.",
          "Do not rely on swatch color alone; every entry requires a meaningful visible label."
        ],
        "states": [
          "Local pointer or focus interaction and external chart highlight remain separate; both may dim peers, but only a real link row receives navigation affordances.",
          "Disable local hover highlighting for static keys such as a line-chart legend; externally controlled activeLabel highlighting and genuine link affordances remain available.",
          "Hover synchronization is temporary emphasis, never filtering, toggling, or selected state.",
          "Percentage values use one consistent precision across the complete legend.",
          "The list owns pointer leave so moving across row gaps does not clear and reapply highlight."
        ],
        "responsiveBehavior": [
          "Vertical legends let the label yield width and truncate before right-aligned value and percentage columns.",
          "Horizontal legends wrap complete entries and suit compact series keys below a chart.",
          "The parent constrains width and decides when a custom condensed treatment is necessary."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Assign items as a JavaScript property and set href only for genuine navigation."
          ],
          "react": [
            "Intercept the item-click event only when application routing must replace native link navigation."
          ],
          "angular": [
            "Intercept the item-click event only when application routing must replace native link navigation."
          ]
        },
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/ChartLegend/ChartLegend.stories.ts"
          },
          {
            "label": "Rendered interaction tests",
            "path": "tests/e2e/chart-legend.spec.ts"
          }
        ]
      },
      "api": {
        "props": {
          "activeLabel": {
            "type": "string | null",
            "required": false
          },
          "direction": {
            "type": "ChartLegendDirection",
            "required": false
          },
          "highlightOnHover": {
            "type": "boolean",
            "required": false
          },
          "items": {
            "type": "ChartLegendItem[]",
            "required": false
          },
          "locale": {
            "type": "string | undefined",
            "required": false
          },
          "percentageDecimals": {
            "type": "ChartLegendPercentageDecimals",
            "required": false
          },
          "showPercentage": {
            "type": "boolean",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsItemClick",
            "detail": "{ item: ChartLegendItem; originalEvent: MouseEvent }"
          },
          {
            "name": "dsItemHover",
            "detail": "ChartLegendItem | null"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-chart-legend",
        "react": "DsChartLegend",
        "vue": "DsChartLegend",
        "angular": "DsChartLegend"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "text"
      ]
    },
    {
      "id": "component:ds-checkbox",
      "tag": "ds-checkbox",
      "name": "checkbox",
      "title": "Checkbox",
      "summary": "Form-associated checkbox for independent choices, acknowledgment, or consent, with optional supporting description, checked, unchecked, mixed, and four density states.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Form-associated checkbox for independent choices, acknowledgment, or consent, with optional supporting description, checked, unchecked, mixed, and four density states.",
        "useWhen": [
          "A user may independently select zero or more choices.",
          "A form requires acknowledgment, consent, or an opt-in value before submission.",
          "A composite multi-select option needs a presentation-only checkbox indicator."
        ],
        "avoidWhen": [
          "Exactly one option must be chosen from a mutually exclusive set.",
          "A binary setting takes effect immediately rather than being submitted or confirmed.",
          "The control triggers a one-time command instead of maintaining selection state."
        ],
        "alternatives": [
          {
            "when": "Exactly one option must be chosen from a mutually exclusive set.",
            "component": "component:ds-radio",
            "reason": "Radio communicates one-of-many selection."
          },
          {
            "when": "A binary setting takes effect immediately.",
            "component": "component:ds-switch",
            "reason": "Switch communicates an immediately applied on/off setting."
          },
          {
            "when": "The interaction triggers a one-time command.",
            "component": "component:ds-button-filled",
            "reason": "Button semantics communicate an action rather than persistent selection."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-field",
          "component:ds-select",
          "component:ds-text"
        ],
        "accessibility": [
          "Every interactive checkbox requires a visible label that provides its accessible name; an optional visible description is associated as supporting context.",
          "Enter and Space activate the checkbox; checked and mixed state are exposed through aria-checked.",
          "Disabled and inactive checkboxes leave the tab order and are omitted from form submission.",
          "Use presentation mode only inside a composite option that owns selection semantics, focus, and interaction."
        ],
        "states": [
          "Unchecked boxes use a tertiary-foreground inset stroke: 1.5px at lg, 1.25px at md, 1px at sm, and 0.75px at xs. Selected and mixed boxes remove the border, use a brand fill, and draw a component-owned filled check or subtract outline that scales with the box.",
          "Activating an indeterminate checkbox clears the mixed state, toggles checked, and emits dsChange with the resulting boolean.",
          "The initial checked and indeterminate values are restored by native form reset; checked values submit under name and unchecked values submit nothing.",
          "Sizes are lg with a 20px box in a 24px placement, md with a 16px box in a 20px placement, sm with a 12px box in a 16px placement, and xs with an 8px box in a 12px placement.",
          "Presentation mode removes checkbox semantics, focus, interaction, label rendering, description rendering, and form submission while preserving the visual state.",
          "Description-rich checkboxes grow beyond the fixed density height while retaining its minimum target size and primitive-owned selection anatomy."
        ],
        "responsiveBehavior": [
          "Choose size from the density of the containing row; labels and descriptions may wrap while the placement box stays fixed.",
          "Use the same density as the shared option icon zone in multi-select rows."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Bind checked and indeterminate as properties for application state updates and listen for dsChange.",
            "Use the form attribute on the host when associating a checkbox rendered outside its owning form or isolating it from an ancestor form."
          ],
          "react": [
            "Use DsCheckbox and handle onDsChange; checked and indeterminate are mutable and update after user activation."
          ],
          "vue": [
            "Use DsCheckbox with v-model for checked, bind indeterminate as a property, and listen for dsChange."
          ],
          "angular": [
            "Use DsCheckbox with checked binding and dsChange, or the generated boolean value accessor in Angular forms."
          ]
        },
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/Checkbox/Checkbox.stories.ts"
          },
          {
            "label": "Cross-browser form and accessibility coverage",
            "path": "tests/e2e/forms.spec.ts"
          }
        ]
      },
      "api": {
        "props": {
          "checked": {
            "type": "boolean",
            "required": false
          },
          "description": {
            "type": "string",
            "required": false
          },
          "disabled": {
            "type": "boolean",
            "required": false
          },
          "indeterminate": {
            "type": "boolean",
            "required": false
          },
          "isInactive": {
            "type": "boolean",
            "required": false
          },
          "label": {
            "type": "string",
            "required": true
          },
          "name": {
            "type": "string | undefined",
            "required": false
          },
          "presentation": {
            "type": "boolean",
            "required": false
          },
          "required": {
            "type": "boolean",
            "required": false
          },
          "requiredMessage": {
            "type": "string",
            "required": false
          },
          "size": {
            "type": "CheckboxSize",
            "required": false
          },
          "value": {
            "type": "string",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsChange",
            "detail": "boolean"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-checkbox",
        "react": "DsCheckbox",
        "vue": "DsCheckbox",
        "angular": "DsCheckbox"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "text"
      ]
    },
    {
      "id": "component:ds-chip",
      "tag": "ds-chip",
      "name": "chip",
      "title": "Chip",
      "summary": "Always-removable metadata value for primary surfaces, with semantic value status and parent-owned removal.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Always-removable metadata value for primary surfaces, with semantic value status and parent-owned removal.",
        "useWhen": [
          "A user-applied value such as a filter, recipient, or tokenized input entry must remain visible and individually removable.",
          "A compact metadata value needs a semantic neutral, active, error, or caution status before removal.",
          "A collection owner can remove the represented value and restore focus after the dismiss action."
        ],
        "avoidWhen": [
          "The label is static or not individually removable; use Tag instead.",
          "The control selects, toggles, or navigates; use the matching button or navigation component.",
          "The information is a persistent status, count, or unread indicator; use Badge or an appropriate status composition instead.",
          "The chip would be placed on any surface other than a primary surface."
        ],
        "alternatives": [
          {
            "when": "The metadata label is static and has no dismiss action.",
            "component": "component:ds-tag",
            "reason": "Tag owns non-interactive taxonomy and metadata labels."
          },
          {
            "when": "The compact mark communicates a count, status, or unread indicator.",
            "component": "component:ds-badge",
            "reason": "Badge owns supplemental counters and status marks without a dismiss action."
          },
          {
            "when": "The value is a selectable or persistent toggle.",
            "component": "component:ds-button-unfilled",
            "reason": "ButtonUnfilled owns command and toggle semantics."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-input",
          "component:ds-select"
        ],
        "accessibility": [
          "Keep the visible label meaningful without relying on semantic color alone.",
          "Give the dismiss action a name that identifies the represented value.",
          "After removal, the parent moves focus to the next chip, then the previous chip, or the owning collection or input trigger when no chips remain.",
          "Inactive chips remain visible while their dismiss action is disabled and removed from keyboard interaction."
        ],
        "states": [
          "Semantic state describes the represented value; active does not mean selected or pressed.",
          "The dismiss action is the chip's only interaction, and the parent owns data mutation after dsRemove.",
          "Long labels remain on one line and truncate only when the consuming layout supplies a maximum width; otherwise the chip sizes to its content.",
          "Rounded shape is a visual choice and does not change semantics or interaction.",
          "Chip is designed only for primary surfaces and has no surface-context API."
        ],
        "responsiveBehavior": [
          "The parent chooses chip size and owns wrapping, overflow, and collection condensation.",
          "Chip does not automatically resize, hide, or collapse its label at responsive breakpoints."
        ],
        "frameworkCaveats": {
          "customElements": [
            "dsRemove has no payload; associate each rendered chip with its owning value and remove that value from the event handler."
          ],
          "react": [
            "Use the rendered chip's bound item context in the dsRemove handler, then restore focus after the collection rerenders."
          ],
          "angular": [
            "Use the rendered chip's bound item context in the dsRemove handler, then restore focus after the collection rerenders."
          ]
        },
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/Chip/Chip.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "isInactive": {
            "type": "boolean",
            "required": false
          },
          "label": {
            "type": "string",
            "required": true
          },
          "maxWidth": {
            "type": "string | number | undefined",
            "required": false
          },
          "removeLabel": {
            "type": "string",
            "required": false
          },
          "rounded": {
            "type": "boolean",
            "required": false
          },
          "size": {
            "type": "ChipSize",
            "required": false
          },
          "state": {
            "type": "ChipState",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsRemove",
            "detail": "void"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-chip",
        "react": "DsChip",
        "vue": "DsChip",
        "angular": "DsChip"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens",
        "@ds-mo/icons"
      ],
      "componentDependencies": [
        "icon",
        "text"
      ]
    },
    {
      "id": "component:ds-code-block",
      "tag": "ds-code-block",
      "name": "code-block",
      "title": "CodeBlock",
      "summary": "Scrollable code surface with optional language or filename context and copy action.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "experimental",
        "summary": "Scrollable code surface with optional language or filename context and copy action.",
        "useWhen": [
          "A message or document displays fenced code that readers may copy."
        ],
        "avoidWhen": [
          "A live editor, terminal, diff viewer, or syntax-highlighting environment is required."
        ],
        "commonlyComposedWith": [
          "component:ds-markdown",
          "component:ds-button-unfilled"
        ],
        "accessibility": [
          "The copy action has matching accessible-name and visible-tooltip status wording, and the code remains selectable text.",
          "Language and filename labels supplement rather than replace the code content.",
          "The semantic code-family token retains a system-monospace fallback when an application does not load Fira Code; applications may disable programming ligatures through the shared code-surface custom property."
        ],
        "states": [
          "Applications load font assets once at their root. The component consumes --typography-font-family-code and never fetches or packages a font."
        ],
        "responsiveBehavior": [
          "Long lines scroll horizontally and do not widen the owning transcript."
        ],
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/CodeBlock/CodeBlock.stories.ts"
          },
          {
            "label": "Font ownership and loading",
            "path": "docs/font-ownership.md"
          }
        ]
      },
      "api": {
        "props": {
          "code": {
            "type": "string",
            "required": false
          },
          "filename": {
            "type": "string",
            "required": false
          },
          "language": {
            "type": "string",
            "required": false
          }
        },
        "events": [],
        "slots": []
      },
      "exports": {
        "customElement": "ds-code-block",
        "react": "DsCodeBlock",
        "vue": "DsCodeBlock",
        "angular": "DsCodeBlock"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "button-unfilled",
        "text",
        "tooltip"
      ]
    },
    {
      "id": "component:ds-conversation-list",
      "tag": "ds-conversation-list",
      "name": "conversation-list",
      "title": "ConversationList",
      "summary": "Scrollable conversation-list region with dedicated empty and persistent action placement.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "experimental",
        "summary": "Scrollable conversation-list region with dedicated empty and persistent action placement.",
        "useWhen": [
          "A messaging-like surface needs a reusable history list with empty and action regions."
        ],
        "avoidWhen": [
          "The content is not a collection of conversations or threads."
        ],
        "commonlyComposedWith": [
          "component:ds-conversation-list-section",
          "component:ds-conversation-list-item",
          "component:ds-empty-state",
          "component:ds-scroll-overlay"
        ],
        "patterns": [
          "pattern:conversation"
        ],
        "accessibility": [
          "Provide an accessible list label through the surrounding heading or region.",
          "Keep the empty message descriptive and every persistent action explicitly named."
        ],
        "states": [
          "The default floating action stays at the lower end corner.",
          "actionLayout footer stretches a long action between 8px side and bottom insets.",
          "Both action layouts share the always-active scroll-overlay fade controller, reserve measured end clearance, and begin fading 8px before the visible action.",
          "ConversationList paints its measured fade on a separate surface-aware layer so contextual row actions retain a real backdrop for blur; hovered, focused, and menu-open rows rise above that decorative fade.",
          "The persistent action wrapper splits its md outer shadow from a top inset-highlight overlay so opaque filled actions keep the complete TokoMo elevation; slotted buttons disable optional resting borders and the press-scale modifier moves the button and elevated surface as one unit."
        ],
        "responsiveBehavior": [
          "The list fills its owner, scrolls independently, and keeps its persistent action above scrolling rows."
        ],
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/ConversationList/ConversationList.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "actionLayout": {
            "type": "ConversationListActionLayout",
            "required": false
          }
        },
        "events": [],
        "slots": []
      },
      "exports": {
        "customElement": "ds-conversation-list",
        "react": "DsConversationList",
        "vue": "DsConversationList",
        "angular": "DsConversationList"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": []
    },
    {
      "id": "component:ds-conversation-list-item",
      "tag": "ds-conversation-list-item",
      "name": "conversation-list-item",
      "title": "ConversationListItem",
      "summary": "Selectable conversation row with one-line preview, recency, unread presence, generic busy or error status, and channel-owned accessory slots.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "experimental",
        "summary": "Selectable conversation row with one-line preview, recency, unread presence, generic busy or error status, and channel-owned accessory slots.",
        "useWhen": [
          "A conversation history needs a compact row that opens one thread."
        ],
        "avoidWhen": [
          "The row represents a command rather than a persisted conversation."
        ],
        "commonlyComposedWith": [
          "component:ds-conversation-list-section",
          "component:ds-avatar",
          "component:ds-badge",
          "component:ds-loader"
        ],
        "patterns": [
          "pattern:conversation"
        ],
        "accessibility": [
          "The conversation surface is one button with its title as the primary accessible name; actions are sibling controls so buttons are never nested.",
          "An action in the actions slot remains keyboard-focusable and appears on row focus as well as pointer hover; touch layouts keep it visible.",
          "Status copy must make busy or error meaning available without relying on motion or color."
        ],
        "states": [
          "Rows reuse the md choice-item label/subtext recipe used by Menu, including 6px row padding, 2px text inset, and the shared content gap. The enclosing conversation-list scroll region supplies the larger 8px outer container padding.",
          "Busy and error are generic channel-neutral states; the owning product supplies suitable status wording. A busy row pairs its body-small status with the sm 16px Loader at a 4px gap.",
          "Any positive unreadCount renders one dot on the title row rather than a visible counter; the accessible row name may still announce the exact unread quantity.",
          "Hover and press use the shared interaction hover and pressed overlays. Only the selected conversation uses the persistent active fill.",
          "The title uses body-medium, not title-small, and the body-small preview truncates after one line. Unread titles use emphasis with primary foreground; read titles use regular weight with secondary foreground.",
          "The actions slot overlays the row at an 8px right inset without changing title or preview measure, and paints above the row interaction wash while that wash remains active.",
          "Contextual actions use the shared md control-elevation wrapper so their transparent backdrop blur is unchanged while the split inset highlight remains above the borderless slotted action and the press-scale modifier moves the complete elevated surface."
        ],
        "responsiveBehavior": [
          "Long titles and previews truncate without displacing trailing status."
        ],
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/ConversationList/ConversationList.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "actionsOpen": {
            "type": "boolean",
            "required": false
          },
          "conversationId": {
            "type": "string",
            "required": false
          },
          "conversationTitle": {
            "type": "string",
            "required": false
          },
          "preview": {
            "type": "string",
            "required": false
          },
          "selected": {
            "type": "boolean",
            "required": false
          },
          "state": {
            "type": "ConversationItemState",
            "required": false
          },
          "statusLabel": {
            "type": "string",
            "required": false
          },
          "unreadCount": {
            "type": "number",
            "required": false
          },
          "updatedAt": {
            "type": "string",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsSelect",
            "detail": "{ id: string }"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-conversation-list-item",
        "react": "DsConversationListItem",
        "vue": "DsConversationListItem",
        "angular": "DsConversationListItem"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "badge",
        "loader",
        "text"
      ]
    },
    {
      "id": "component:ds-conversation-list-section",
      "tag": "ds-conversation-list-section",
      "name": "conversation-list-section",
      "title": "ConversationListSection",
      "summary": "Semantically labelled section for grouping conversation rows by meaningful chronology or category.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "experimental",
        "summary": "Semantically labelled section for grouping conversation rows by meaningful chronology or category.",
        "useWhen": [
          "A conversation list needs visible groups such as Today, Yesterday, or Older."
        ],
        "avoidWhen": [
          "A flat list is clearer or the proposed grouping has no meaning to readers."
        ],
        "commonlyComposedWith": [
          "component:ds-conversation-list",
          "component:ds-conversation-list-item"
        ],
        "patterns": [
          "pattern:conversation"
        ],
        "accessibility": [
          "The visible heading labels the section and must describe the relationship shared by its rows."
        ],
        "responsiveBehavior": [
          "Rows remain full width with a 4px gap between adjacent items while the heading stays visible in document order."
        ],
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/ConversationList/ConversationList.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "heading": {
            "type": "string",
            "required": false
          },
          "sectionId": {
            "type": "string",
            "required": false
          }
        },
        "events": [],
        "slots": []
      },
      "exports": {
        "customElement": "ds-conversation-list-section",
        "react": "DsConversationListSection",
        "vue": "DsConversationListSection",
        "angular": "DsConversationListSection"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "text"
      ]
    },
    {
      "id": "component:ds-divider",
      "tag": "ds-divider",
      "name": "divider",
      "title": "Divider",
      "summary": "Horizontal or vertical separator between sibling content groups, decorative by default with optional structural semantics.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Horizontal or vertical separator between sibling content groups, decorative by default with optional structural semantics.",
        "useWhen": [
          "Related sibling content groups on one surface need stronger visual separation than spacing alone provides.",
          "A list or panel needs an inset separator that does not define the outer edge of its container.",
          "Meaningful document or group structure requires an explicit horizontal or vertical separator."
        ],
        "avoidWhen": [
          "Spacing alone communicates the grouping clearly.",
          "The line defines a container edge, control outline, or selected state; use the owning component's border treatment.",
          "The divider would compensate for weak headings or unclear information hierarchy.",
          "A decorative flourish does not clarify grouping."
        ],
        "alternatives": [
          {
            "when": "Editable settings need an enclosing section surface and outer boundary.",
            "component": "component:ds-card-setting",
            "reason": "CardSetting owns settings-section chrome, structure, and edge treatment."
          },
          {
            "when": "A static compact label is being used to name a group.",
            "component": "component:ds-text",
            "reason": "Text communicates hierarchy directly instead of relying on a line."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-card-setting",
          "component:ds-menu",
          "component:ds-panel-sub-nav"
        ],
        "accessibility": [
          "Keep purely visual dividers hidden from assistive technology.",
          "Expose separator semantics only when the line represents meaningful document or group structure.",
          "Semantic orientation must match the divider's visual orientation.",
          "Do not use a semantic divider as a substitute for headings, landmarks, or explicit group labels."
        ],
        "states": [
          "Horizontal and vertical variants separate sibling groups along the parent's layout axis.",
          "The omitted background context is for primary and secondary surfaces. Explicit faint documents a faint surface while using the same standard divider token.",
          "Other background contexts select their matching divider token, including navigation where Divider is composed inside app chrome.",
          "Inset is symmetric along the line axis. Explicit length is reserved for layout-specific separators; otherwise the line fills the available axis."
        ],
        "responsiveBehavior": [
          "The parent layout decides whether to change orientation, visibility, inset, or length at responsive breakpoints.",
          "Divider does not infer layout direction or hide itself responsively."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Set semantic mode only from known document structure; presentation alone should remain hidden from assistive technology."
          ],
          "react": [
            "Derive orientation and visibility from the parent layout rather than viewport logic inside Divider."
          ],
          "angular": [
            "Derive orientation and visibility from the parent layout rather than viewport logic inside Divider."
          ]
        },
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/Divider/Divider.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "background": {
            "type": "DividerBackground | undefined",
            "required": false
          },
          "inset": {
            "type": "DividerInset",
            "required": false
          },
          "length": {
            "type": "DividerLength",
            "required": false
          },
          "orientation": {
            "type": "DividerOrientation",
            "required": false
          },
          "semantic": {
            "type": "boolean",
            "required": false
          }
        },
        "events": [],
        "slots": []
      },
      "exports": {
        "customElement": "ds-divider",
        "react": "DsDivider",
        "vue": "DsDivider",
        "angular": "DsDivider"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": []
    },
    {
      "id": "component:ds-empty-state",
      "tag": "ds-empty-state",
      "name": "empty-state",
      "title": "EmptyState",
      "summary": "Centered empty-content message composed as icon plus title plus body, title plus body, or compact body-only content.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Centered empty-content message composed as icon plus title plus body, title plus body, or compact body-only content.",
        "useWhen": [
          "A bounded content area is in a first-use, no-content, filtered no-results, or no-access state and needs a calm explanatory message tailored to that cause.",
          "A prominent empty region benefits from a decorative icon, visual title, and supporting body copy.",
          "A compact owner such as a Select popup needs only centered body copy."
        ],
        "avoidWhen": [
          "Content is still loading; use Skeleton for predictable structure or Loader for an indeterminate operation.",
          "The state is an error, warning, or confirmation that needs semantic intent and announcement from the owning workflow.",
          "The state needs a recovery action, link, or other interactive content; the current EmptyState pattern is intentionally message-only.",
          "A decorative illustration, arbitrary rich content, or custom layout is required."
        ],
        "alternatives": [
          {
            "when": "A content region is waiting for structured data.",
            "component": "component:ds-skeleton",
            "reason": "Skeleton preserves expected geometry while content is pending."
          },
          {
            "when": "An operation is progressing without predictable content structure.",
            "component": "component:ds-loader",
            "reason": "Loader owns indeterminate progress rather than an empty outcome."
          },
          {
            "when": "Only ordinary prose is needed without empty-state layout.",
            "component": "component:ds-text",
            "reason": "Text owns typography without adding centered empty-state composition."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-table",
          "component:ds-select",
          "component:ds-text",
          "component:ds-icon"
        ],
        "accessibility": [
          "The optional icon is decorative; the title and body provide all meaning in text.",
          "EmptyState does not create a live region or alert automatically. The owner decides whether a dynamic transition requires announcement.",
          "The visual title does not impose a document heading level because the correct hierarchy belongs to the consuming page or region.",
          "Keep localized body copy concise and sufficient when using the body-only variant."
        ],
        "states": [
          "Supported compositions are icon plus title plus body, title plus body, and body only; body copy is present in every supported composition.",
          "The decorative icon renders at xl in the primary foreground with an 8px gap before the text group and only when a title is also provided.",
          "The visual title uses title-small primary text; body uses body-medium secondary text with a 4px title-to-body gap.",
          "All content is centered. The owner supplies container size and surrounding padding; repeated panel and master-detail owners should share one empty-region geometry instead of wrapping each EmptyState differently. Do not compose actions into or immediately alongside the current EmptyState pattern.",
          "First-use, no-content, no-results, and no-access states reuse this primitive with cause-specific localized messages rather than visual variants."
        ],
        "responsiveBehavior": [
          "The owner controls available width and height; text wraps naturally while remaining centered.",
          "EmptyState does not infer breakpoints or change composition automatically."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Pass canonical IcoMo icon names and localized heading/body strings through properties or attributes."
          ],
          "react": [
            "Choose one supported composition by passing body with optional heading and icon props."
          ],
          "angular": [
            "Choose one supported composition by binding body with optional heading and icon inputs."
          ]
        },
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/EmptyState/EmptyState.stories.ts"
          },
          {
            "label": "Shared layout recipe foundation",
            "path": "docs/layout-recipe-foundation.md"
          }
        ]
      },
      "api": {
        "props": {
          "body": {
            "type": "string",
            "required": false
          },
          "heading": {
            "type": "string | undefined",
            "required": false
          },
          "icon": {
            "type": "string | undefined",
            "required": false
          }
        },
        "events": [],
        "slots": []
      },
      "exports": {
        "customElement": "ds-empty-state",
        "react": "DsEmptyState",
        "vue": "DsEmptyState",
        "angular": "DsEmptyState"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens",
        "@ds-mo/icons"
      ],
      "componentDependencies": [
        "icon",
        "text"
      ]
    },
    {
      "id": "component:ds-field",
      "tag": "ds-field",
      "name": "field",
      "title": "Field",
      "summary": "Accessible form-field composition that gives one Input or Select a persistent label, optional guidance, shared error presentation, stable IDs, and observable interaction state.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Accessible form-field composition that gives one Input or Select a persistent label, optional guidance, shared error presentation, stable IDs, and observable interaction state.",
        "useWhen": [
          "An Input or Select needs a persistent visible label in a form.",
          "Help text or an error message must be programmatically associated with one control.",
          "A form layout needs one consistent label-control-message rhythm."
        ],
        "avoidWhen": [
          "The component already owns its visible label and complete selection semantics, such as Checkbox, Radio, or Switch.",
          "Several controls belong to one question; use a semantic fieldset and legend instead.",
          "Text describes a region or group rather than one form control."
        ],
        "alternatives": [
          {
            "when": "Several related controls answer one question.",
            "component": "component:ds-text",
            "reason": "Use native fieldset and legend semantics, then compose Text only for supporting content."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-input",
          "component:ds-select",
          "component:ds-text"
        ],
        "accessibility": [
          "Slot exactly one form control. Field assigns its stable control ID and connects the visible label automatically.",
          "The visible description or error ID is merged with any authored aria-describedby references; a rendered error replaces the description.",
          "The error prop forwards aria-invalid and supported design-system control error styling; put visible error text on Field, not again on the child control.",
          "Clicking the label focuses the slotted design-system control without opening a Select popup.",
          "Do not use placeholder text as the only label. Keep label text concise and put format or consequence guidance in description."
        ],
        "states": [
          "Label, control, description, and error content follow the shared 4px vertical field flow without changing the slotted control's width or semantics.",
          "Field exposes data-focused, data-filled, data-dirty, data-touched, data-invalid, data-disabled, and data-required hooks while the slotted control remains the source of value and interaction behavior.",
          "A rendered error replaces the description; preserve essential guidance in the error message so users retain what they need to correct the field.",
          "Field owns validation presentation but not validation timing; the form decides when to set error and errorMessage.",
          "The label uses primary body-small emphasis, description uses secondary body-small text, and error uses negative body-small text."
        ],
        "responsiveBehavior": [
          "Field fills the width supplied by its parent and makes the slotted control fill that field width.",
          "The form layout owns column count, wrapping, and responsive placement; Field keeps the vertical label-control-message composition intact."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Set fieldId only when another element must reference a predictable control ID; otherwise use the generated association.",
            "Assign child component values and option arrays through their normal JavaScript properties."
          ],
          "react": [
            "Compose one DsInput or DsSelect child and control validation timing in the form owner."
          ],
          "angular": [
            "Compose the generated Field adapter around the control adapter and its matching Angular value accessor."
          ]
        },
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/Field/Field.stories.ts"
          },
          {
            "label": "Cross-browser form and accessibility coverage",
            "path": "tests/e2e/forms.spec.ts"
          }
        ]
      },
      "api": {
        "props": {
          "description": {
            "type": "string | undefined",
            "required": false
          },
          "error": {
            "type": "boolean",
            "required": false
          },
          "errorMessage": {
            "type": "string | undefined",
            "required": false
          },
          "fieldId": {
            "type": "string | undefined",
            "required": false
          },
          "label": {
            "type": "string",
            "required": true
          }
        },
        "events": [],
        "slots": []
      },
      "exports": {
        "customElement": "ds-field",
        "react": "DsField",
        "vue": "DsField",
        "angular": "DsField"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "text"
      ]
    },
    {
      "id": "component:ds-filter-menu",
      "tag": "ds-filter-menu",
      "name": "filter-menu",
      "title": "FilterMenu",
      "summary": "Controlled two-pane filter select with menu-recipe category navigation, single- and multiple-choice, boolean, and date filters, selected counts, and a clear action.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Controlled two-pane filter select with menu-recipe category navigation, single- and multiple-choice, boolean, and date filters, selected counts, and a clear action.",
        "useWhen": [
          "A compact trigger must expose several filter families without turning the toolbar into many separate controls.",
          "Users need to move between persistent filter categories while editing the selected category in a second pane."
        ],
        "avoidWhen": [
          "The user is selecting one form value; use Select.",
          "The popup contains contextual commands rather than filtering controls; use Menu.",
          "The workflow requires confirmation or several ordered steps; use Modal."
        ],
        "alternatives": [
          {
            "when": "One known value is selected for a form field.",
            "component": "component:ds-select",
            "reason": "Select owns compact form-value and listbox semantics."
          },
          {
            "when": "A trigger reveals commands or row actions.",
            "component": "component:ds-menu",
            "reason": "Menu provides the appropriate action-menu semantics and keyboard model."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-select",
          "component:ds-table",
          "component:ds-checkbox"
        ],
        "accessibility": [
          "The built-in select trigger exposes combobox semantics with a dialog popup, synchronizes expanded state, holds the pressed interaction wash without changing resting foreground while open, and restores focus after dismissal.",
          "The category pane is a vertical tab list. Arrow Up and Arrow Down wrap, Home and End jump, Arrow Right enters the option pane, and Arrow Left returns to the active category.",
          "Escape and outside activation close the popup and restore trigger focus. Tab moves through option controls and closes only when it leaves the popup boundary.",
          "The trigger count reports active filter categories. Category counts and the footer report individual selected criteria; none replace visible selected-state indication."
        ],
        "states": [
          "The application owns filters, values, activeFilterId, and open. Replace controlled objects and arrays after dsChange, dsActiveFilterChange, dsClear, or dsClose.",
          "Single filters return a string, multiple filters return ordered string arrays, boolean filters return a boolean, and date filters return a YYYY-MM-DD string.",
          "Selection applies immediately and does not close the popup.",
          "Changing category replaces the option-pane subtree so checkbox and other option visuals mount in their new state instead of transitioning from the previous category's row state.",
          "The trigger reports how many filter categories have selections, while the footer appears when values are selected and reports the total selected criteria."
        ],
        "responsiveBehavior": [
          "The popup defaults to the large menu-width token and clamps to the viewport.",
          "When collapseLabel is set inside a named ds-table container narrower than 900px, the trigger omits its label and chevron and becomes icon-only. Active criteria promote the prefix icon to primary.",
          "Both panes remain visible at narrow widths, with a smaller category minimum and reduced option-pane padding.",
          "Treat side as preferred placement; the popup flips and clamps when viewport collision requires it."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Assign filters and values as JavaScript properties after the element is defined."
          ],
          "react": [
            "Pass filters and values as controlled props and handle onDsChange, onDsActiveFilterChange, onDsClear, and onDsClose."
          ],
          "angular": [
            "Use property bindings for filters and values and event bindings for dsChange, dsActiveFilterChange, dsClear, and dsClose."
          ]
        },
        "references": [
          {
            "label": "Storybook example",
            "path": "src/wc/components/FilterMenu/FilterMenu.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "activeFill": {
            "type": "boolean",
            "required": false
          },
          "activeFilterId": {
            "type": "string | undefined",
            "required": false
          },
          "align": {
            "type": "AnchoredAlign",
            "required": false
          },
          "alignOffset": {
            "type": "number | string",
            "required": false
          },
          "anchor": {
            "type": "HTMLElement | undefined",
            "required": false
          },
          "anchorId": {
            "type": "string | undefined",
            "required": false
          },
          "ariaLabel": {
            "type": "string | null",
            "required": false
          },
          "categoriesLabel": {
            "type": "string",
            "required": false
          },
          "clearLabel": {
            "type": "string",
            "required": false
          },
          "collapseLabel": {
            "type": "boolean",
            "required": false
          },
          "filters": {
            "type": "FilterMenuFilter[]",
            "required": false
          },
          "hasBorder": {
            "type": "boolean",
            "required": false
          },
          "icon": {
            "type": "string | undefined",
            "required": false
          },
          "initialFocusVisible": {
            "type": "boolean",
            "required": false
          },
          "inputId": {
            "type": "string | undefined",
            "required": false
          },
          "menuLabel": {
            "type": "string",
            "required": false
          },
          "menuWidth": {
            "type": "string",
            "required": false
          },
          "open": {
            "type": "boolean",
            "required": false
          },
          "side": {
            "type": "AnchoredSide",
            "required": false
          },
          "sideOffset": {
            "type": "number | string",
            "required": false
          },
          "size": {
            "type": "FilterMenuSize",
            "required": false
          },
          "triggerLabel": {
            "type": "string",
            "required": false
          },
          "values": {
            "type": "FilterMenuValues",
            "required": false
          },
          "width": {
            "type": "FilterMenuWidth",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsActiveFilterChange",
            "detail": "string"
          },
          {
            "name": "dsAfterClose",
            "detail": "void"
          },
          {
            "name": "dsChange",
            "detail": "FilterMenuChangeDetail"
          },
          {
            "name": "dsClear",
            "detail": "void"
          },
          {
            "name": "dsClose",
            "detail": "void"
          },
          {
            "name": "dsOpenChange",
            "detail": "boolean"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-filter-menu",
        "react": "DsFilterMenu",
        "vue": "DsFilterMenu",
        "angular": "DsFilterMenu"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens",
        "@ds-mo/icons"
      ],
      "componentDependencies": [
        "button-unfilled",
        "checkbox",
        "icon",
        "tag",
        "text",
        "tooltip"
      ]
    },
    {
      "id": "component:ds-icon",
      "tag": "ds-icon",
      "name": "icon",
      "title": "Icon",
      "summary": "Secure, lazily loaded renderer for canonical IcoMo system and flag glyphs, decorative by default with optional graphic semantics.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Secure, lazily loaded renderer for canonical IcoMo system and flag glyphs, decorative by default with optional graphic semantics.",
        "useWhen": [
          "An approved IcoMo system glyph supplements visible text or control chrome.",
          "A canonical flag glyph communicates a country or region with adjacent text or an explicit localized label.",
          "A standalone non-interactive symbol conveys meaning that is unavailable from nearby text."
        ],
        "avoidWhen": [
          "The glyph itself must be clickable or keyboard interactive; use an appropriate button or link and compose Icon inside it.",
          "The visual is an illustration, logo, chart, or arbitrary SVG artwork rather than a canonical IcoMo glyph.",
          "An alias, guessed name, or case-insensitive lookup would be required; runtime lookup uses exact canonical export names.",
          "A fallback glyph would be required when loading fails; Icon intentionally preserves an empty fixed-size box."
        ],
        "alternatives": [
          {
            "when": "The icon initiates an action or persistent toggle.",
            "component": "component:ds-button-unfilled",
            "reason": "ButtonUnfilled owns interaction, focus, naming, and toggle semantics."
          },
          {
            "when": "The visual communicates indeterminate loading progress.",
            "component": "component:ds-loader",
            "reason": "Loader owns progress status and motion behavior."
          },
          {
            "when": "The compact visual is an unread count or notification dot.",
            "component": "component:ds-badge",
            "reason": "Badge owns supplemental notification semantics."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-button-filled",
          "component:ds-button-unfilled",
          "component:ds-menu",
          "component:ds-panel-nav"
        ],
        "accessibility": [
          "Icons are decorative by default and remain hidden from assistive technology when visible text or an owning control already communicates the meaning.",
          "The owning button, link, or composite control provides the accessible name; do not repeat that name on its nested Icon.",
          "Provide an explicit label only when the non-interactive icon itself communicates otherwise unavailable meaning.",
          "Tertiary and quaternary foregrounds are restricted to icons inside genuinely inactive or disabled UI, or to purely decorative icons; quaternary is the fainter tier, and informative icons and meaningful status graphics retain sufficient rendered contrast even when aria-hidden.",
          "Informative flags require an explicit localized country or region label; never derive accessible text from the export name.",
          "Icon never receives focus or owns interaction."
        ],
        "states": [
          "Omitted color inherits currentColor from the owning context. Explicit semantic aliases and CSS-variable references are available when the icon has an independent color role.",
          "Prefer the owning control's isInactive or native disabled state over manually selecting tertiary or quaternary so visual treatment and inactive semantics remain synchronized.",
          "Built-in glyph lookup accepts exact canonical IcoMo export names only. Names beginning with Flag select the flag catalog automatically.",
          "A cache miss lazy-loads into a fixed-size box without layout shift. Unknown names, failed loads, and rejected markup leave that box empty.",
          "Critical first-paint glyphs may be pre-registered before rendering; all resolved glyphs share a global cache.",
          "Every SVG is validated at the render boundary and injected as parsed DOM nodes so app-registered markup cannot bypass executable-content or external-reference checks."
        ],
        "responsiveBehavior": [
          "The owning component or layout chooses icon size and any responsive changes.",
          "Icon does not scale from viewport width or change glyphs automatically."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Import each canonical glyph as an SVG string and call registerIcons before first render when synchronous critical-icon paint is required."
          ],
          "react": [
            "Keep nested control icons decorative and place the accessible name on the owning React control."
          ],
          "angular": [
            "Keep nested control icons decorative and place the accessible name on the owning Angular control."
          ]
        },
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/Icon/Icon.stories.ts"
          },
          {
            "label": "Preload API guidance",
            "path": "src/wc/components/Icon/icon-cache.ts"
          }
        ]
      },
      "api": {
        "props": {
          "color": {
            "type": "IconColor",
            "required": false
          },
          "label": {
            "type": "string | undefined",
            "required": false
          },
          "name": {
            "type": "string",
            "required": false
          },
          "size": {
            "type": "IconSize",
            "required": false
          }
        },
        "events": [],
        "slots": []
      },
      "exports": {
        "customElement": "ds-icon",
        "react": "DsIcon",
        "vue": "DsIcon",
        "angular": "DsIcon"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens",
        "@ds-mo/icons"
      ],
      "componentDependencies": []
    },
    {
      "id": "component:ds-input",
      "tag": "ds-input",
      "name": "input",
      "title": "Input",
      "summary": "Form-associated single-line text and number field for primary and secondary application backgrounds, with native input behavior, four control densities, optional leading and trailing content, search clearing, and validation.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Form-associated single-line text and number field for primary and secondary application backgrounds, with native input behavior, four control densities, optional leading and trailing content, search clearing, and validation.",
        "useWhen": [
          "A user must enter or edit one line of text, an email address, telephone number, URL, search query, password, or exact number.",
          "The value must participate in native, Angular, React, or Vue form state.",
          "A compact filter or toolbar needs a single-line search field that follows the shared control-density recipe."
        ],
        "avoidWhen": [
          "The user chooses from a finite set of known values.",
          "The user must enter multiple paragraphs or formatted content.",
          "The value is adjusted primarily by dragging within a numeric range."
        ],
        "alternatives": [
          {
            "when": "The value comes from a finite set of known choices.",
            "component": "component:ds-select",
            "reason": "Select exposes the available values and owns listbox selection behavior."
          },
          {
            "when": "The value is an immediate on/off setting.",
            "component": "component:ds-switch",
            "reason": "Switch communicates a binary setting instead of free text entry."
          },
          {
            "when": "The value is chosen from a bounded numeric range.",
            "component": "component:ds-slider",
            "reason": "Slider supports direct range adjustment and communicates the current position."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-field",
          "component:ds-icon",
          "component:ds-text"
        ],
        "accessibility": [
          "Provide a persistent visible label through the owning field or an external native label; placeholder text is guidance and must not be the field's only label.",
          "Choose the native input type that matches the value so browsers and assistive technology can provide appropriate semantics and keyboards.",
          "Error text is associated with the native input and announced as an alert when the invalid state is rendered.",
          "Read-only fields remain focusable and submittable while preventing edits; inactive or disabled fields leave the tab order and are omitted from form submission.",
          "Suffix content must not carry information that is otherwise absent from the field's visible label, value, or description."
        ],
        "states": [
          "Every size applies one complete control-density recipe across frame height, inline padding, icon zones, text-container inset, gap, and radius; supporting error content follows the shared 4px field flow.",
          "The normal field boundary uses the shared secondary inset border. Focus promotes it to the thicker bold-brand inset stroke, while error uses the thicker bold-negative inset stroke without changing geometry. Set hasBorder to false only in chrome that supplies enough surrounding structure; the control then remains borderless at rest, while focused, and while invalid, with semantics and supporting error copy unchanged.",
          "Placeholder text is secondary at rest and quaternary while the editable field is focused because it becomes decorative once typing begins.",
          "Entered values use the parent surface's primary foreground; prefix icons, suffix content, and resting placeholder text use its secondary foreground.",
          "Search fields show a standard borderless CrossCircle icon action only while they contain a value. Clearing emits the empty value and restores focus to the native field.",
          "The suffix slot is for compact units or decorations. The optional leading icon is decorative and does not replace the field label.",
          "Use autoComplete, inputMode, and enterKeyHint to provide browser and virtual-keyboard hints without changing the value's semantic type.",
          "Number fields preserve native spinbutton semantics, stepping, and min/max constraint behavior while dsChange continues to report the native string value.",
          "The host exposes focused, filled, dirty, touched, invalid, disabled, read-only, and required data attributes for Field integration and diagnostics.",
          "Use Input only on primary or secondary application backgrounds. It intentionally does not expose alternate surface contexts."
        ],
        "responsiveBehavior": [
          "Form fields normally fill their parent; use hug width only in a compact toolbar or filter layout with an explicit width constraint.",
          "Choose density from the containing layout: md for ordinary forms, lg for a touch-primary layout, and sm or xs only where surrounding controls use the same compact recipe.",
          "The owner supplies layout constraints and decides when a compact field moves to its own row."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Listen for dsChange for user edits and dsClear for the search clear action.",
            "Use the form attribute on the host when associating an input rendered outside its owning form."
          ],
          "react": [
            "Use DsInput, bind value for controlled application state, and handle onDsChange and onDsClear."
          ],
          "vue": [
            "Use DsInput with v-model for the value, and listen for dsChange and dsClear."
          ],
          "angular": [
            "Import DsInput with TextValueAccessor when integrating with Angular Forms."
          ]
        },
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/Input/Input.stories.ts"
          },
          {
            "label": "Cross-browser form and accessibility coverage",
            "path": "tests/e2e/forms.spec.ts"
          }
        ]
      },
      "api": {
        "props": {
          "ariaDescribedby": {
            "type": "string | undefined",
            "required": false
          },
          "ariaLabel": {
            "type": "string | null",
            "required": false
          },
          "ariaLabelledby": {
            "type": "string | undefined",
            "required": false
          },
          "autoComplete": {
            "type": "string | undefined",
            "required": false
          },
          "autoFocus": {
            "type": "boolean",
            "required": false
          },
          "clearLabel": {
            "type": "string",
            "required": false
          },
          "disabled": {
            "type": "boolean",
            "required": false
          },
          "enterKeyHint": {
            "type": "string",
            "required": false
          },
          "error": {
            "type": "boolean",
            "required": false
          },
          "errorMessage": {
            "type": "string | undefined",
            "required": false
          },
          "form": {
            "type": "string | undefined",
            "required": false
          },
          "hasBorder": {
            "type": "boolean",
            "required": false
          },
          "icon": {
            "type": "string | undefined",
            "required": false
          },
          "inputId": {
            "type": "string | undefined",
            "required": false
          },
          "inputMode": {
            "type": "string",
            "required": false
          },
          "isInactive": {
            "type": "boolean",
            "required": false
          },
          "max": {
            "type": "number | undefined",
            "required": false
          },
          "min": {
            "type": "number | undefined",
            "required": false
          },
          "name": {
            "type": "string | undefined",
            "required": false
          },
          "placeholder": {
            "type": "string | undefined",
            "required": false
          },
          "readOnly": {
            "type": "boolean",
            "required": false
          },
          "required": {
            "type": "boolean",
            "required": false
          },
          "requiredMessage": {
            "type": "string",
            "required": false
          },
          "size": {
            "type": "InputSize",
            "required": false
          },
          "step": {
            "type": "number | undefined",
            "required": false
          },
          "type": {
            "type": "InputType",
            "required": false
          },
          "value": {
            "type": "string",
            "required": false
          },
          "width": {
            "type": "InputWidth",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsChange",
            "detail": "string"
          },
          {
            "name": "dsClear",
            "detail": "void"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-input",
        "react": "DsInput",
        "vue": "DsInput",
        "angular": "DsInput"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens",
        "@ds-mo/icons"
      ],
      "componentDependencies": [
        "button-unfilled",
        "icon",
        "text"
      ]
    },
    {
      "id": "component:ds-loader",
      "tag": "ds-loader",
      "name": "loader",
      "title": "Loader",
      "summary": "Indeterminate progress glyph for ongoing operations, inheriting owner color and optionally exposing standalone polite status text.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Indeterminate progress glyph for ongoing operations, inheriting owner color and optionally exposing standalone polite status text.",
        "useWhen": [
          "An action or operation is in progress and its remaining duration cannot be quantified.",
          "A button, field, or bounded workflow needs a compact visual busy indicator owned by that control or region.",
          "A standalone operation needs a visible spinner with contextual polite status text."
        ],
        "avoidWhen": [
          "Pending content has a predictable structure; use Skeleton to preserve that layout.",
          "Progress is measurable; use an appropriate determinate progress pattern.",
          "The UI needs a blocking overlay or automatic centering; the owning layout must provide that structure.",
          "Success, failure, retry, or completion must be communicated; the owning workflow handles outcomes."
        ],
        "alternatives": [
          {
            "when": "A content region is waiting for structured data.",
            "component": "component:ds-skeleton",
            "reason": "Skeleton preserves the expected content geometry while data loads."
          },
          {
            "when": "A static visual symbol is needed without progress semantics.",
            "component": "component:ds-icon",
            "reason": "Icon owns non-progress system and flag glyphs."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-button-filled",
          "component:ds-button-unfilled",
          "component:ds-input",
          "component:ds-select"
        ],
        "accessibility": [
          "When Loader is nested in a busy button, field, or region, keep it unnamed and expose busy state from the owner.",
          "Standalone Loader requires contextual status text that explains what is loading; do not rely on a generic visual spinner alone.",
          "Loader is an informative progress graphic and must retain sufficient rendered contrast; tertiary and quaternary are not supported standalone or informative Loader treatments.",
          "Avoid duplicate announcements from both Loader and its owning busy region.",
          "Reduced motion stops rotation while keeping the glyph and status semantics visible."
        ],
        "states": [
          "Loader communicates indeterminate progress only and does not emit completion or failure events.",
          "The segmented glyph rotates clockwise, with its opacity ramp trailing the leading arc.",
          "Omitted color inherits currentColor. Explicit semantic aliases and CSS-variable references match Icon when an independent progress color is required.",
          "Nested Loader inherits a readable color from its owning busy control or region rather than selecting tertiary or quaternary directly.",
          "The owner decides whether to delay Loader visibility for short operations and removes it when the operation settles.",
          "The owner reserves space and supplies centering or overlay layout so Loader never causes unexpected layout movement."
        ],
        "responsiveBehavior": [
          "The owning component or layout chooses Loader size, placement, and any responsive changes.",
          "Loader does not infer container size or viewport breakpoints."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Use the label only for standalone status; nested usage should synchronize aria-busy on the owning element."
          ],
          "react": [
            "Derive Loader visibility and the owner's busy state from the same operation state."
          ],
          "angular": [
            "Derive Loader visibility and the owner's busy state from the same operation state."
          ]
        },
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/Loader/Loader.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "color": {
            "type": "LoaderColor",
            "required": false
          },
          "label": {
            "type": "string | undefined",
            "required": false
          },
          "size": {
            "type": "LoaderSize",
            "required": false
          }
        },
        "events": [],
        "slots": []
      },
      "exports": {
        "customElement": "ds-loader",
        "react": "DsLoader",
        "vue": "DsLoader",
        "angular": "DsLoader"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": []
    },
    {
      "id": "component:ds-markdown",
      "tag": "ds-markdown",
      "name": "markdown",
      "title": "Markdown",
      "summary": "Optional safe CommonMark and GFM renderer that emits semantic nodes without raw HTML injection and consumes the shared prose CSS contract.",
      "intentStatus": "complete",
      "intent": {
        "audience": "specialized",
        "status": "experimental",
        "summary": "Optional safe CommonMark and GFM renderer that emits semantic nodes without raw HTML injection and consumes the shared prose CSS contract.",
        "useWhen": [
          "A serializable Markdown string needs the design system's safe, opinionated renderer for headings, lists, links, tables, tasks, quotes, and code."
        ],
        "avoidWhen": [
          "The application already owns a safe semantic-DOM renderer and only needs @ds-mo/ui/prose.css.",
          "The application needs arbitrary HTML, custom plugins, or a full document CMS renderer."
        ],
        "commonlyComposedWith": [
          "component:ds-agent-response",
          "component:ds-code-block"
        ],
        "patterns": [
          "pattern:agent-chat"
        ],
        "accessibility": [
          "Semantic parsed elements preserve heading, list, table, quote, and code relationships.",
          "Raw HTML is ignored and unsafe link schemes are not made interactive.",
          "Link text must remain descriptive in authored content."
        ],
        "states": [
          "Streaming updates are coalesced to one parse and render per animation frame.",
          "Typography, rhythm, opt-out, and overflow styling come from the renderer-neutral .ds-prose source rather than a Markdown-only recipe."
        ],
        "responsiveBehavior": [
          "Tables and code scroll horizontally instead of forcing the transcript wider."
        ],
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/AgentResponse/AgentResponse.stories.ts"
          },
          {
            "label": "Prose distribution decision",
            "path": "docs/prose-foundation.md"
          }
        ]
      },
      "api": {
        "props": {
          "content": {
            "type": "string",
            "required": false
          },
          "streaming": {
            "type": "boolean",
            "required": false
          }
        },
        "events": [],
        "slots": []
      },
      "exports": {
        "customElement": "ds-markdown",
        "react": "DsMarkdown",
        "vue": "DsMarkdown",
        "angular": "DsMarkdown"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "code-block"
      ]
    },
    {
      "id": "component:ds-menu",
      "tag": "ds-menu",
      "name": "menu",
      "title": "Menu",
      "summary": "Anchored action menu with flat commands, grouped sections, single-selection choices, supplemental notification dots or trailing tags, prefix icons, reorderable rows, switches, and destructive actions.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Anchored action menu with flat commands, grouped sections, single-selection choices, supplemental notification dots or trailing tags, prefix icons, reorderable rows, switches, and destructive actions.",
        "useWhen": [
          "A trigger reveals a short contextual list of commands or state-changing actions.",
          "Actions need grouping, mutually exclusive selected state, supplemental notification dots or trailing tags, prefix icons, reorderable switch or command rows, or destructive treatment."
        ],
        "avoidWhen": [
          "The user is selecting a value for a form field.",
          "The content requires rich dialog interaction or a multi-step workflow.",
          "The actions should remain persistently visible."
        ],
        "alternatives": [
          {
            "when": "The choice is a form value with a label, validation, and submitted value.",
            "component": "component:ds-select",
            "reason": "Select provides form-control semantics and value ownership."
          },
          {
            "when": "Several form values may be selected.",
            "component": "component:ds-select",
            "reason": "Select multiple provides multi-select listbox semantics, array value ownership, and count presentation."
          },
          {
            "when": "The interaction needs substantial content, confirmation, or a form.",
            "component": "component:ds-modal",
            "reason": "Modal owns focus containment and dialog-level interaction."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-button-unfilled",
          "component:ds-panel-nav",
          "component:ds-switch",
          "component:ds-swatch-picker"
        ],
        "patterns": [
          "pattern:menu-trigger"
        ],
        "accessibility": [
          "Anchor the menu to the control that opens it and return focus to that control when the menu closes.",
          "Open with visible initial focus only when the trigger was activated from the keyboard.",
          "Keep disabled items discoverable only when their unavailable state is meaningful.",
          "Switch rows use menuitemcheckbox semantics on the row; the nested ds-switch is an aria-hidden presentation indicator at the same density as the menu.",
          "Single-selection menus use menuitemradio semantics and aria-checked on each row, but render no nested radio control; selected interaction fill and primary foreground provide the visual state.",
          "A swatch-picker section changes the popup to a non-modal dialog so its radio group and ordinary preference buttons keep valid nested semantics; Tab moves between its controls, then leaves and closes at the popup boundary.",
          "Use notification dots only as supplemental status and not as the sole indication of important information.",
          "Trailing tags are non-interactive supplemental content; their visible label remains part of the menu item's accessible name.",
          "Reorderable rows keep a presentation Drag handle. Pointer drag on the handle and Alt+Arrow Up or Down emit dsReorder without closing. Pointer cancellation abandons the pending move. Hide-locked reorderable rows expose aria-disabled for the unavailable toggle but stay focusable so they can move; fully locked rows stay out of the contiguous reorderable run.",
          "Announce the new position through a polite live region that is a sibling of the role=menu popup, so the menu retains only permitted descendants."
        ],
        "states": [
          "The host owns open state and responds to selection and close events.",
          "Use either flat items or sections, not both.",
          "After dsSelect from a switch row, replace the items or sections array with updated switchValue data so the controlled indicator reflects the new state.",
          "After dsReorder, replace items or the affected section with the emitted items array. Menu never mutates order and does not close.",
          "For selectionMode single, keep exactly one item isSelected and replace the items or sections array after dsSelect; Menu never mutates consumer-owned selection data.",
          "Arrays, objects, and element anchors must be assigned as JavaScript properties.",
          "Use a swatch-picker section for a small curated visual preference and apply dsSwatchSelect immediately without closing the popup.",
          "Ordinary rows, section headings, and supporting text consume the Menu size. At xs, both the primary label and supporting text use caption metrics.",
          "A trailing tag resolves one density smaller than its menu row and uses the inset recipe so it nests without changing row height. Do not combine tag, dot, and switch suffixes on one item.",
          "Reorderable rows use the Drag prefix and ignore icon. Prefix and drag-handle icons inherit the choice-popup secondary foreground, matching Select. When any row in a section has an icon or is reorderable, the remaining rows get a spacer so labels align."
        ],
        "responsiveBehavior": [
          "Keep the default choice-cell anchor alignment so the first or last interactive row edge aligns with its trigger, matching Select; use popup-frame only for deliberate custom frame geometry.",
          "Treat side as the preferred placement. When the popup cannot fit there and the opposite side offers more room, Menu flips on that main axis before clamping the final position to the viewport.",
          "Avoid fixed widths that exceed narrow viewports."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Assign items, sections, and HTMLElement anchors as properties after the element is defined.",
            "Handle dsReorder by replacing the items or section items with the emitted items array; Menu never mutates order."
          ],
          "react": [
            "Pass arrays and objects as wrapper props and handle generated onDsSelect, onDsReorder, and onDsClose event props."
          ],
          "angular": [
            "Use property bindings for arrays, objects, and anchors and event bindings for dsSelect, dsReorder, and dsClose."
          ]
        },
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/Menu/Menu.stories.ts"
          },
          {
            "label": "Framework integration",
            "path": "docs/framework-integration.md"
          }
        ]
      },
      "api": {
        "props": {
          "align": {
            "type": "MenuAlign",
            "required": false
          },
          "alignOffset": {
            "type": "number | string",
            "required": false
          },
          "anchor": {
            "type": "HTMLElement | undefined",
            "required": false
          },
          "anchorAlignment": {
            "type": "ChoicePopupAnchorAlignment",
            "required": false
          },
          "anchorId": {
            "type": "string | undefined",
            "required": false
          },
          "initialFocusVisible": {
            "type": "boolean",
            "required": false
          },
          "items": {
            "type": "MenuItemData[]",
            "required": false
          },
          "menuLabel": {
            "type": "string",
            "required": false
          },
          "menuWidth": {
            "type": "string | undefined",
            "required": false
          },
          "minWidth": {
            "type": "string | undefined",
            "required": false
          },
          "open": {
            "type": "boolean",
            "required": false
          },
          "sections": {
            "type": "MenuSection[]",
            "required": false
          },
          "selectionMode": {
            "type": "MenuSelectionMode",
            "required": false
          },
          "side": {
            "type": "MenuSide",
            "required": false
          },
          "sideOffset": {
            "type": "number | string",
            "required": false
          },
          "size": {
            "type": "MenuSize",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsAfterClose",
            "detail": "void"
          },
          {
            "name": "dsClose",
            "detail": "void"
          },
          {
            "name": "dsReorder",
            "detail": "MenuReorderDetail"
          },
          {
            "name": "dsSelect",
            "detail": "MenuItemData"
          },
          {
            "name": "dsSwatchSelect",
            "detail": "string"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-menu",
        "react": "DsMenu",
        "vue": "DsMenu",
        "angular": "DsMenu"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens",
        "@ds-mo/icons"
      ],
      "componentDependencies": [
        "badge",
        "icon",
        "swatch-picker",
        "switch",
        "tag",
        "text"
      ]
    },
    {
      "id": "component:ds-message",
      "tag": "ds-message",
      "name": "message",
      "title": "Message",
      "summary": "Channel-neutral message row owning direction, grouping, author, time, delivery metadata, and persistent or metadata action regions.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "experimental",
        "summary": "Channel-neutral message row owning direction, grouping, author, time, delivery metadata, and persistent or metadata action regions.",
        "useWhen": [
          "A transcript contains messages that need consistent incoming, outgoing, or system layout."
        ],
        "avoidWhen": [
          "Content is not an authored message in a conversation."
        ],
        "commonlyComposedWith": [
          "component:ds-message-bubble",
          "component:ds-message-actions",
          "component:ds-message-scroller"
        ],
        "patterns": [
          "pattern:conversation"
        ],
        "accessibility": [
          "Author and time metadata remain textual when they are necessary to interpret the transcript.",
          "Delivery failure uses negative Failed to send text in the footer while the message bubble keeps its normal outgoing treatment; when time is also visible, a tertiary middle dot separates the failure label and timestamp.",
          "Hover-only metadata rows remain keyboard reachable, reveal on focus, and stay visible for touch and coarse-pointer input."
        ],
        "states": [
          "Pass an ISO timestamp. Message keeps the full value in dateTime and formats the visible value as a localized time; applications must not render a raw ISO string as visible transcript metadata.",
          "A visible incoming author uses body-small emphasis with primary foreground; timestamp and delivery metadata remain caption text.",
          "Visible author, bubble content, and timestamp or delivery footer use consistent 4px vertical gaps.",
          "Grouping joins adjacent bubble corners, shows the incoming author only at the start, and shows delivery/time metadata only at the end. Outgoing author remains in the accessible message label without repeating a visible You label.",
          "Set showAuthor false only when the product makes participant and assistant roles visually self-evident; continue passing author so the accessible message label remains specific.",
          "Metadata actions precede incoming timestamps and follow outgoing timestamps. In hover mode the complete reserved footer—delivery, timestamp, and actions—fades as one unit without changing geometry; the persistent actions slot retains separate message-level controls."
        ],
        "responsiveBehavior": [
          "Outgoing and incoming rows adapt to available width while preserving their directional alignment."
        ],
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/MessageScroller/MessageScroller.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "author": {
            "type": "string",
            "required": false
          },
          "deliveryState": {
            "type": "MessageDeliveryState | undefined",
            "required": false
          },
          "direction": {
            "type": "MessageDirection",
            "required": false
          },
          "groupPosition": {
            "type": "MessageGroupPosition",
            "required": false
          },
          "messageId": {
            "type": "string",
            "required": false
          },
          "metadataVisibility": {
            "type": "MessageMetadataVisibility",
            "required": false
          },
          "scrollAnchor": {
            "type": "boolean",
            "required": false
          },
          "showAuthor": {
            "type": "boolean",
            "required": false
          },
          "streaming": {
            "type": "boolean",
            "required": false
          },
          "timestamp": {
            "type": "string",
            "required": false
          }
        },
        "events": [],
        "slots": []
      },
      "exports": {
        "customElement": "ds-message",
        "react": "DsMessage",
        "vue": "DsMessage",
        "angular": "DsMessage"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "text"
      ]
    },
    {
      "id": "component:ds-message-actions",
      "tag": "ds-message-actions",
      "name": "message-actions",
      "title": "MessageActions",
      "summary": "Reusable message-level Copy and controlled response-feedback actions with consistent compact presentation and browser clipboard feedback.",
      "intentStatus": "complete",
      "intent": {
        "audience": "specialized",
        "status": "experimental",
        "summary": "Reusable message-level Copy and controlled response-feedback actions with consistent compact presentation and browser clipboard feedback.",
        "useWhen": [
          "A message metadata row needs Copy alone or Copy with mutually exclusive positive and negative response feedback."
        ],
        "avoidWhen": [
          "The action executes, retries, regenerates, approves, edits, or otherwise changes message content."
        ],
        "commonlyComposedWith": [
          "component:ds-message",
          "component:ds-agent-response",
          "component:ds-button-unfilled"
        ],
        "patterns": [
          "pattern:conversation",
          "pattern:agent-chat"
        ],
        "accessibility": [
          "Every icon action has a matching tooltip and accessible name.",
          "Feedback uses genuine pressed toggle semantics and Copy announces its temporary Copied state through the control name."
        ],
        "states": [
          "The component owns clipboard execution and temporary copied feedback while the application supplies the exact copyable text.",
          "Feedback is controlled: the component emits the requested positive, negative, or cleared value while the application owns persistence and consequences.",
          "Selected feedback changes to the filled thumb icon without adding a persistent selected fill; hover and press feedback remain available.",
          "Copy, positive feedback, and negative feedback retain one stable order."
        ],
        "responsiveBehavior": [
          "The compact action group follows the visibility and metadata placement policy of its owning Message."
        ],
        "references": [
          {
            "label": "Message metadata composition",
            "path": "src/wc/components/Message/Message.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "copyText": {
            "type": "string | undefined",
            "required": false
          },
          "feedback": {
            "type": "MessageFeedback | undefined",
            "required": false
          },
          "feedbackEnabled": {
            "type": "boolean",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsCopyResult",
            "detail": "MessageCopyResultEventDetail"
          },
          {
            "name": "dsFeedbackChange",
            "detail": "MessageFeedback | undefined"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-message-actions",
        "react": "DsMessageActions",
        "vue": "DsMessageActions",
        "angular": "DsMessageActions"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "button-unfilled",
        "tooltip"
      ]
    },
    {
      "id": "component:ds-message-bubble",
      "tag": "ds-message-bubble",
      "name": "message-bubble",
      "title": "MessageBubble",
      "summary": "Visible plain-message surface with a body-medium default, separated from message-row direction and metadata.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "experimental",
        "summary": "Visible plain-message surface with a body-medium default, separated from message-row direction and metadata.",
        "useWhen": [
          "Plain user-sent or received person-to-person message copy needs a visible surface within a Message row.",
          "Plain conversation copy should use the shared body-medium regular typography recipe without application styling."
        ],
        "avoidWhen": [
          "The surface is a general card, callout, or form container.",
          "The content is a rich agent response; compose AgentResponse directly in Message.",
          "The state only indicates that another participant is typing; use TypingIndicator."
        ],
        "commonlyComposedWith": [
          "component:ds-message"
        ],
        "patterns": [
          "pattern:conversation"
        ],
        "accessibility": [
          "Surface styling does not add semantics; failed delivery belongs in Message metadata below the unchanged bubble rather than in an error bubble treatment."
        ],
        "states": [
          "The user variant represents user-sent copy in agent and person-to-person channels and uses secondary foreground.",
          "The received variant represents ordinary incoming person-to-person copy.",
          "Typing and rich agent output are not MessageBubble variants."
        ],
        "responsiveBehavior": [
          "The bubble wraps plain message copy within the transcript width."
        ],
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/MessageScroller/MessageScroller.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "variant": {
            "type": "MessageBubbleVariant",
            "required": false
          }
        },
        "events": [],
        "slots": []
      },
      "exports": {
        "customElement": "ds-message-bubble",
        "react": "DsMessageBubble",
        "vue": "DsMessageBubble",
        "angular": "DsMessageBubble"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": []
    },
    {
      "id": "component:ds-message-composer",
      "tag": "ds-message-composer",
      "name": "message-composer",
      "title": "MessageComposer",
      "summary": "Two-line auto-growing conversation textarea with submit, stop, an attached submission-error support surface, and extensible tool, action, and error-recovery regions.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "experimental",
        "summary": "Two-line auto-growing conversation textarea with submit, stop, an attached submission-error support surface, and extensible tool, action, and error-recovery regions.",
        "useWhen": [
          "A conversation accepts multi-line text and needs Enter-to-submit with a streaming stop action."
        ],
        "avoidWhen": [
          "The text is a conventional form field submitted with unrelated fields."
        ],
        "commonlyComposedWith": [
          "component:ds-message-scroller",
          "component:ds-button-filled",
          "component:ds-button-unfilled"
        ],
        "patterns": [
          "pattern:conversation"
        ],
        "accessibility": [
          "Always provide a localized textarea label and submit or stop action names; the built-in icon action exposes the same name in its tooltip.",
          "Shift plus Enter inserts a newline while Enter submits non-empty content.",
          "Submission errors remain visible and announced above the editable box as part of one attached composer unit, and the editable control references their text while the error state is active.",
          "Streaming and error states remain perceivable without relying on icon shape or color alone."
        ],
        "states": [
          "The owner controls draft value and transport state; the composer emits intent without performing transport.",
          "Error status never clears or disables the draft; the application supplies recovery actions through error-actions and owns retry semantics. The negative support surface appears above and attached to the composer box, within the component's measured ownership.",
          "Use the tools slot for leading actions such as add and the actions slot for trailing actions such as dictation; the built-in submit or stop action remains last with an 8px gap from the preceding action. These icon buttons use the standard non-rounded control radius, and the application supplies tooltips for slotted icon actions.",
          "The composer surface uses the 10px --dimension-radius-125 token.",
          "Mouse or keyboard focus on the textarea gives the complete composer surface the same bold-brand inset stroke width and color as an active Input; the native textarea never draws a separate outline.",
          "The empty or otherwise inactive submit action is a disabled bordered ButtonUnfilled. Ready submit actions use submitIntent, while the streaming stop action remains a bold-brand ButtonFilled.",
          "The attached error unit keeps a real boundary in forced colors and lets message text and application-owned recovery actions wrap at narrow widths."
        ],
        "responsiveBehavior": [
          "The textarea begins at two body-medium lines, grows one line at a time through six lines, and then scrolls internally."
        ],
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/MessageComposer/MessageComposer.stories.ts"
          },
          {
            "label": "Scroller overlay composition",
            "path": "src/wc/components/MessageScroller/MessageScroller.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "errorMessage": {
            "type": "string",
            "required": false
          },
          "isInactive": {
            "type": "boolean",
            "required": false
          },
          "label": {
            "type": "string",
            "required": false
          },
          "placeholder": {
            "type": "string",
            "required": false
          },
          "status": {
            "type": "MessageComposerStatus",
            "required": false
          },
          "submitIntent": {
            "type": "ButtonFilledIntent",
            "required": false
          },
          "value": {
            "type": "string",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsInput",
            "detail": "string"
          },
          {
            "name": "dsStop",
            "detail": "void"
          },
          {
            "name": "dsSubmit",
            "detail": "{ text: string }"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-message-composer",
        "react": "DsMessageComposer",
        "vue": "DsMessageComposer",
        "angular": "DsMessageComposer"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens",
        "@ds-mo/icons"
      ],
      "componentDependencies": [
        "button-filled",
        "button-unfilled",
        "icon",
        "text",
        "tooltip"
      ]
    },
    {
      "id": "component:ds-message-scroller",
      "tag": "ds-message-scroller",
      "name": "message-scroller",
      "title": "MessageScroller",
      "summary": "Focusable transcript scroller with turn anchoring, reader-controlled live-edge following, and a measured interaction-plus-composer overlay stack.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "experimental",
        "summary": "Focusable transcript scroller with turn anchoring, reader-controlled live-edge following, and a measured interaction-plus-composer overlay stack.",
        "useWhen": [
          "Messages can append or stream and transcript position must remain respectful of reader intent."
        ],
        "avoidWhen": [
          "Content is static prose without message navigation or live updates."
        ],
        "commonlyComposedWith": [
          "component:ds-message",
          "component:ds-message-composer",
          "component:ds-agent-questionnaire"
        ],
        "patterns": [
          "pattern:conversation",
          "pattern:agent-chat"
        ],
        "accessibility": [
          "Give each transcript a concise localized label.",
          "New content is exposed through log semantics without stealing focus.",
          "The scroll-to-latest control remains keyboard accessible when follow behavior is released and exposes its action name in a tooltip."
        ],
        "states": [
          "Wheel, touch, keyboard navigation, selection, and transcript interaction release automatic following; Scroll to latest explicitly restores it.",
          "A newly appended outgoing Message marked scroll-anchor starts a turn near the top with the configurable previous-turn peek; mutations inside existing messages and prepended history do not re-anchor.",
          "Opening saved history, message jumps, and prepended history preserve deliberate position.",
          "The scroll-to-latest action is absent at the live edge, appears only after the reader moves away, and disappears again after returning to the newest message.",
          "Scroll to latest uses the shared md control-elevation wrapper with a pointer-transparent top highlight, preserving its transparent backdrop blur and borderless unfilled action while the press-scale modifier moves the complete elevated surface.",
          "Place a pending human-input surface in interaction and a composer container with 8px padding on every side in overlay; the shared scroll-overlay controller measures them as one stack, tracks every growth step, reserves matching transcript clearance, begins the fade before the stack, and keeps scroll-to-latest above it."
        ],
        "responsiveBehavior": [
          "Transcript width is readable while the scroll region fills available height.",
          "For a narrower fullscreen conversation lane, set --ds-message-scroller-content-max-width on the host instead of constraining the host; the full-width viewport then keeps its scrollbar at the outer edge while the transcript remains centered.",
          "The custom property sizes the padded transcript box. If the target is the usable conversation width, add the transcript's two 16px inline paddings and size the centered overlay container to the same target plus its two 8px paddings so messages and the visible composer align."
        ],
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/MessageScroller/MessageScroller.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "autoFollow": {
            "type": "boolean",
            "required": false
          },
          "busy": {
            "type": "boolean",
            "required": false
          },
          "defaultPosition": {
            "type": "MessageScrollerPosition",
            "required": false
          },
          "messagesLabel": {
            "type": "string",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsReachStart",
            "detail": "void"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-message-scroller",
        "react": "DsMessageScroller",
        "vue": "DsMessageScroller",
        "angular": "DsMessageScroller"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "button-unfilled",
        "tooltip"
      ]
    },
    {
      "id": "component:ds-mobile-bar-nav",
      "tag": "ds-mobile-bar-nav",
      "name": "mobile-bar-nav",
      "title": "MobileBarNav",
      "summary": "Persistent mobile shell navigation for Menu, the router-derived current area, Search, Inbox, Messages, and Agents.",
      "intentStatus": "complete",
      "intent": {
        "audience": "specialized",
        "status": "experimental",
        "summary": "Persistent mobile shell navigation for Menu, the router-derived current area, Search, Inbox, Messages, and Agents.",
        "useWhen": [
          "ShellApp is rendering its dedicated below-768px application composition."
        ],
        "avoidWhen": [
          "Rendering desktop or tablet shell chrome.",
          "An arbitrary set of product tabs is required."
        ],
        "commonlyComposedWith": [
          "component:ds-shell-app"
        ],
        "patterns": [
          "pattern:application-shell"
        ],
        "accessibility": [
          "Every icon-only item keeps a localized accessible name.",
          "Only the active destination exposes aria-current; Menu exposes its controlled pane through aria-expanded."
        ],
        "states": [
          "The fixed groups are Menu plus current area, followed by Search, Inbox, Messages, and Agents.",
          "Selection promotes foreground to primary without painting a selected fill; unselected destinations use tertiary foreground.",
          "Opening Mobile Sheet Nav replaces the Menu glyph with Cross while preserving its accessible name.",
          "Reselecting an active destination does not reset its nested state.",
          "Direct touch paints the pressed overlay immediately, keeps a quick tap visible for one short frame, and clears it after release or cancellation without relying on Safari's latch-prone active state."
        ],
        "responsiveBehavior": [
          "Render only below the mobile breakpoint; its primary surface extends through the bottom safe-area inset when the application enables viewport-fit=cover.",
          "The primary-background bar keeps an 8px outer inset; its two icon-only groups anchor to opposite edges while retaining fixed 40px targets and a divider between Menu and current area.",
          "Bar chrome and its divider are not text-selectable and suppress the iOS touch callout."
        ],
        "references": [
          {
            "label": "Storybook",
            "path": "src/wc/components/MobileBarNav/MobileBarNav.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "activeDestination": {
            "type": "MobileDestination",
            "required": false
          },
          "agentsDot": {
            "type": "boolean",
            "required": false
          },
          "agentsLabel": {
            "type": "string",
            "required": false
          },
          "currentArea": {
            "type": "PanelNavItem",
            "required": false
          },
          "helpLabel": {
            "type": "string",
            "required": false
          },
          "inboxDot": {
            "type": "boolean",
            "required": false
          },
          "inboxLabel": {
            "type": "string",
            "required": false
          },
          "menuLabel": {
            "type": "string",
            "required": false
          },
          "messagesDot": {
            "type": "boolean",
            "required": false
          },
          "messagesLabel": {
            "type": "string",
            "required": false
          },
          "searchDot": {
            "type": "boolean",
            "required": false
          },
          "searchLabel": {
            "type": "string",
            "required": false
          },
          "sheetNavExpanded": {
            "type": "boolean",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsDestinationChange",
            "detail": "MobileBarNavDestinationDetail"
          },
          {
            "name": "dsSheetNavToggle",
            "detail": "boolean"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-mobile-bar-nav",
        "react": "DsMobileBarNav",
        "vue": "DsMobileBarNav",
        "angular": "DsMobileBarNav"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens",
        "@ds-mo/icons"
      ],
      "componentDependencies": [
        "badge",
        "icon"
      ]
    },
    {
      "id": "component:ds-mobile-header",
      "tag": "ds-mobile-header",
      "name": "mobile-header",
      "title": "MobileHeader",
      "summary": "Consistent mobile top chrome with symmetric action lanes, a centered page identity or peer-section chooser, and an optional subordinate page-section row.",
      "intentStatus": "complete",
      "intent": {
        "audience": "specialized",
        "status": "experimental",
        "summary": "Consistent mobile top chrome with symmetric action lanes, a centered page identity or peer-section chooser, and an optional subordinate page-section row.",
        "useWhen": [
          "A routed page, persistent tool, account surface, or workflow needs the canonical mobile header presentation."
        ],
        "avoidWhen": [
          "Rendering desktop BarTitle, BarNav, or PanelToolHeader.",
          "Rendering the Mobile Sheet Nav utility lane."
        ],
        "commonlyComposedWith": [
          "component:ds-mobile-section-switcher",
          "component:ds-tab-group",
          "component:ds-shell-page",
          "component:ds-shell-tools"
        ],
        "patterns": [
          "pattern:application-shell"
        ],
        "accessibility": [
          "Static screens render a real h1 or h2 according to headingLevel.",
          "Section-switching screens expose an equivalent semantic heading alongside the accessible popup trigger or named segmented TabGroup.",
          "Subsections use a separately named navigation landmark and never replace the semantic page identity.",
          "Leading and trailing slotted icon actions retain their own accessible names and tooltips."
        ],
        "states": [
          "Without multiple sections the center renders heading.",
          "With multiple sections the center renders the controlled MobileSectionSwitcher by default or an explicitly requested segmented TabGroup.",
          "The segmented presentation uses the shared fill-width TabGroup contract and divides its centered two-thirds top-bar lane equally between options.",
          "Optional subsections render in a second row and emit dsSubsectionChange without changing the primary section.",
          "Sections represent peer destinations at the current navigation level; subsections represent local views beneath the selected page or detail identity.",
          "Brand tone changes surface and foreground without changing geometry or interaction ownership."
        ],
        "responsiveBehavior": [
          "The primary 56px lane matches the Mobile Sheet Nav header and Mobile Bar Nav; optional subsections add one subordinate 48px lane.",
          "Equal flexible side lanes keep the center mathematically aligned when actions are asymmetric; segmented headers allocate the usable lane in a 1:4:1 ratio."
        ],
        "references": [
          {
            "label": "Storybook",
            "path": "src/wc/components/MobileHeader/MobileHeader.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "heading": {
            "type": "string",
            "required": false
          },
          "headingLevel": {
            "type": "MobileHeaderHeadingLevel",
            "required": false
          },
          "sections": {
            "type": "TabGroupItem[]",
            "required": false
          },
          "sectionsAriaLabel": {
            "type": "string",
            "required": false
          },
          "sectionsPresentation": {
            "type": "MobileHeaderSectionsPresentation",
            "required": false
          },
          "sectionsSize": {
            "type": "TabGroupSize",
            "required": false
          },
          "subsections": {
            "type": "TabItem[]",
            "required": false
          },
          "subsectionsAriaLabel": {
            "type": "string",
            "required": false
          },
          "subvalue": {
            "type": "string",
            "required": false
          },
          "tone": {
            "type": "MobileHeaderTone",
            "required": false
          },
          "value": {
            "type": "string",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsSectionChange",
            "detail": "string"
          },
          {
            "name": "dsSubsectionChange",
            "detail": "string"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-mobile-header",
        "react": "DsMobileHeader",
        "vue": "DsMobileHeader",
        "angular": "DsMobileHeader"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "mobile-section-switcher",
        "tab-group",
        "text"
      ]
    },
    {
      "id": "component:ds-mobile-section-switcher",
      "tag": "ds-mobile-section-switcher",
      "name": "mobile-section-switcher",
      "title": "MobileSectionSwitcher",
      "summary": "Controlled mobile section chooser showing the current section, adjacent-position hints, and a complete tap menu.",
      "intentStatus": "complete",
      "intent": {
        "audience": "specialized",
        "status": "experimental",
        "summary": "Controlled mobile section chooser showing the current section, adjacent-position hints, and a complete tap menu.",
        "useWhen": [
          "A mobile page or tool header must combine current-page identity with ordered peer-section navigation."
        ],
        "avoidWhen": [
          "Rendering desktop BarNav.",
          "The destination collection is primary application navigation."
        ],
        "commonlyComposedWith": [
          "component:ds-mobile-header"
        ],
        "patterns": [
          "pattern:application-shell"
        ],
        "accessibility": [
          "The trigger exposes the current section, popup relationship, and expanded state.",
          "Decorative previous and next position hints are hidden from assistive technology.",
          "The menu is always available so a future swipe gesture is never the only navigation mechanism.",
          "Peer destinations use menuitem semantics with aria-current on the active page; they do not present a radio-control affordance."
        ],
        "states": [
          "Selection is controlled and dsChange reports intent without mutating value.",
          "Dividers group menu items but never participate in previous or next resolution.",
          "The first and last selectable sections expose only the available neighboring direction."
        ],
        "responsiveBehavior": [
          "Use only in the dedicated mobile header presentation."
        ],
        "references": [
          {
            "label": "Storybook",
            "path": "src/wc/components/MobileSectionSwitcher/MobileSectionSwitcher.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "navigationLabel": {
            "type": "string",
            "required": false
          },
          "sections": {
            "type": "TabItem[]",
            "required": false
          },
          "value": {
            "type": "string",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsChange",
            "detail": "string"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-mobile-section-switcher",
        "react": "DsMobileSectionSwitcher",
        "vue": "DsMobileSectionSwitcher",
        "angular": "DsMobileSectionSwitcher"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "menu",
        "text"
      ]
    },
    {
      "id": "component:ds-mobile-sheet-nav",
      "tag": "ds-mobile-sheet-nav",
      "name": "mobile-sheet-nav",
      "title": "MobileSheetNav",
      "summary": "Full-height mobile navigation sheet with a single brand, context, and utility header above large primary destinations.",
      "intentStatus": "complete",
      "intent": {
        "audience": "specialized",
        "status": "experimental",
        "summary": "Full-height mobile navigation sheet with a single brand, context, and utility header above large primary destinations.",
        "useWhen": [
          "The mobile ShellApp Menu control needs to expose the complete primary navigation collection."
        ],
        "avoidWhen": [
          "Rendering desktop PanelNav.",
          "Switching local page content."
        ],
        "commonlyComposedWith": [
          "component:ds-shell-app",
          "component:ds-mobile-bar-nav"
        ],
        "patterns": [
          "pattern:application-shell"
        ],
        "accessibility": [
          "The sheet is a named navigation landmark and retains visible labels for every primary destination.",
          "Dashboard and Settings use icon-only tabs with localized accessible names; Help and the optional Account shortcut use icon-only actions with matching tooltips.",
          "Escape requests dismissal and opening moves focus to the selected or first available area."
        ],
        "states": [
          "Dashboard and Settings change only the flat destination collection being browsed.",
          "Area, Help, and Account events express intent while the application owns navigation and product behavior.",
          "Set routeSelectionActive to false while a global tool owns the mobile stage so the underlying router URL remains available without marking its area current.",
          "Set showAccount to false when account and user preferences already live in the supplied Settings navigation."
        ],
        "responsiveBehavior": [
          "The pane fills the mobile content stage while the bottom bar remains available.",
          "The sheet header and scrollable navigation body each use the shared 8px chrome inset; the context TabGroup and primary controls share a 40px height and 24px icon scale.",
          "When the optional Account shortcut is hidden, the Dashboard and Settings TabGroup fills the centered two-thirds top-bar lane and gives both context options equal width.",
          "Dashboard and Settings preserve their supplied visual groups with an 8px gap between destinations inside a section and a 32px gap between sections."
        ],
        "references": [
          {
            "label": "Storybook",
            "path": "src/wc/components/MobileSheetNav/MobileSheetNav.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "accountLabel": {
            "type": "string",
            "required": false
          },
          "browseContext": {
            "type": "NavChromeStyle",
            "required": false
          },
          "currentUrl": {
            "type": "string",
            "required": false
          },
          "dashboardGroups": {
            "type": "PanelNavGroup[]",
            "required": false
          },
          "dashboardLabel": {
            "type": "string",
            "required": false
          },
          "helpLabel": {
            "type": "string",
            "required": false
          },
          "navigationLabel": {
            "type": "string",
            "required": false
          },
          "open": {
            "type": "boolean",
            "required": false
          },
          "routeSelectionActive": {
            "type": "boolean",
            "required": false
          },
          "settingsGroups": {
            "type": "PanelNavGroup[]",
            "required": false
          },
          "settingsLabel": {
            "type": "string",
            "required": false
          },
          "showAccount": {
            "type": "boolean",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsAreaSelect",
            "detail": "string"
          },
          {
            "name": "dsBrowseContextChange",
            "detail": "NavChromeStyle"
          },
          {
            "name": "dsClose",
            "detail": "void"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-mobile-sheet-nav",
        "react": "DsMobileSheetNav",
        "vue": "DsMobileSheetNav",
        "angular": "DsMobileSheetNav"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens",
        "@ds-mo/icons"
      ],
      "componentDependencies": [
        "badge",
        "button-unfilled",
        "icon",
        "tab-group",
        "text",
        "tooltip"
      ]
    },
    {
      "id": "component:ds-modal",
      "tag": "ds-modal",
      "name": "modal",
      "title": "Modal",
      "summary": "Dismissible native top-layer dialog for a focused confirmation or short blocking task, with a compact title-and-close header, optional supporting description, composable content, and an optional two-action footer.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Dismissible native top-layer dialog for a focused confirmation or short blocking task, with a compact title-and-close header, optional supporting description, composable content, and an optional two-action footer.",
        "useWhen": [
          "The user must confirm or cancel one focused decision before returning to the underlying interface.",
          "A short blocking task or compact form needs dialog semantics, focus containment, and explicit completion actions.",
          "The content can be safely dismissed through Close, Escape, or the backdrop."
        ],
        "avoidWhen": [
          "The message is non-blocking feedback or a transient status update.",
          "The interaction is a contextual list of commands anchored to a trigger.",
          "The workflow is multi-step, long-form, or requires substantial navigation.",
          "Dismissal would lose work or leave an irreversible operation in an unsafe state.",
          "A second modal would be opened over an existing modal."
        ],
        "alternatives": [
          {
            "when": "The user needs non-blocking feedback or a transient status message.",
            "component": "component:ds-toast",
            "reason": "Toast communicates transient status without trapping focus or blocking the page."
          },
          {
            "when": "A trigger reveals a short contextual list of commands.",
            "component": "component:ds-menu",
            "reason": "Menu provides anchored command semantics without creating a blocking dialog."
          },
          {
            "when": "Editable settings should remain visible without blocking the rest of the interface.",
            "component": "component:ds-card-setting",
            "reason": "CardSetting provides a persistent controlled settings workflow without modal focus containment."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-button-filled",
          "component:ds-button-unfilled",
          "component:ds-field",
          "component:ds-text"
        ],
        "accessibility": [
          "Provide a concise visible heading; the component uses it as the dialog's accessible name.",
          "When concise supporting context belongs in the header, provide description; it stays below the title and is included in the dialog's accessible description.",
          "Give the primary explanatory copy a stable id and pass it through aria-describedby so assistive technology receives the decision context.",
          "Opening the native modal dialog moves focus to the header Close action, whose visible tooltip matches its accessible name, traps Tab navigation inside the top layer, and makes outside content inert.",
          "Close, Escape, and backdrop activation emit dsClose with close-button, escape, or backdrop reason before beginning dismissal; use the component only when every dismissal path is safe.",
          "After exit motion completes, the native dialog leaves the top layer, focus returns to the previously focused element, and dsAfterClose emits.",
          "Use visible label-only footer buttons. Keep at most two actions: one bold filled primary action followed by one bordered unfilled action, or two bordered unfilled actions.",
          "Use negative intent for a filled destructive action and state the irreversible consequence in the content.",
          "Do not open a modal from another modal; keep one blocking decision in focus at a time."
        ],
        "states": [
          "The owner opens the modal through the open property and responds to the typed dsClose detail for application state synchronization or dismissal analytics.",
          "The component mutates open to false for Close, Escape, and backdrop dismissal while retaining its rendered surface through exit motion. The close timer begins only after the closing class has rendered, so the dialog surface and backdrop enter together and exit together before the native top layer closes across browsers.",
          "The default slot owns task content; the named footer slot is optional and is hidden when no actions are assigned.",
          "The optional header description remains stacked beneath the title with the shared compact-header rhythm; longer task content belongs in the default slot.",
          "Primary actions use a bold filled button with semantic intent. Secondary and cancel actions use bordered label-only unfilled buttons.",
          "The owner performs save, delete, cancel, and other product consequences before or while closing the modal."
        ],
        "responsiveBehavior": [
          "Choose the smallest sm, md, or lg width that fits the focused task; the top-layer dialog clamps to the viewport with token-based outer space.",
          "Content scrolls independently when needed while the header and optional 64px footer remain fixed. The title-only header uses the shared 48px compact geometry and grows when its optional description wraps.",
          "Avoid layouts whose minimum content width exceeds the narrow viewport clamp.",
          "The native top layer escapes transformed ancestors, clipping containers, and application stacking contexts without moving slotted content."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Set open as a JavaScript property when controlling the modal; inspect dsClose.detail.reason and use dsAfterClose for cleanup that must wait for exit motion and focus restoration.",
            "Connect the most relevant slotted explanatory text through aria-describedby.",
            "Footer actions are slotted application-owned controls and must implement their own product consequence."
          ],
          "react": [
            "Pass open to DsModal, inspect onDsClose event detail, and use onDsAfterClose only for cleanup after exit motion and focus restoration.",
            "Connect the most relevant slotted explanatory text through aria-describedby.",
            "Assign footer controls with slot=\"footer\" and handle each action before updating open."
          ],
          "angular": [
            "Bind [open], inspect $event.detail from (dsClose), and use (dsAfterClose) only for cleanup after exit motion and focus restoration.",
            "Connect the most relevant slotted explanatory text through aria-describedby.",
            "Assign footer controls with slot=\"footer\" and handle each action before updating open."
          ]
        },
        "references": [
          {
            "label": "Storybook confirmation and footer examples",
            "path": "src/wc/components/Modal/Modal.stories.ts"
          },
          {
            "label": "Cross-browser focus, dismissal, geometry, and accessibility coverage",
            "path": "tests/e2e/accessibility-overlays.spec.ts"
          },
          {
            "label": "Reduced-motion overlay coverage",
            "path": "tests/e2e/reduced-motion.spec.ts"
          }
        ]
      },
      "api": {
        "props": {
          "ariaDescribedby": {
            "type": "string | undefined",
            "required": false
          },
          "closeAriaLabel": {
            "type": "string",
            "required": false
          },
          "description": {
            "type": "string",
            "required": false
          },
          "heading": {
            "type": "string",
            "required": true
          },
          "modalWidth": {
            "type": "ModalWidth | string",
            "required": false
          },
          "open": {
            "type": "boolean",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsAfterClose",
            "detail": "void"
          },
          {
            "name": "dsClose",
            "detail": "ModalCloseDetail"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-modal",
        "react": "DsModal",
        "vue": "DsModal",
        "angular": "DsModal"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "button-unfilled",
        "text",
        "tooltip"
      ]
    },
    {
      "id": "component:ds-pagination",
      "tag": "ds-pagination",
      "name": "pagination",
      "title": "Pagination",
      "summary": "Controlled fixed or fitted page-size, compact range, and first/previous/next/last navigation for application-owned data windows.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Controlled fixed or fitted page-size, compact range, and first/previous/next/last navigation for application-owned data windows.",
        "useWhen": [
          "A result set is divided into discrete pages and the application owns fetching or slicing each page.",
          "A table or list needs a compact page-size selector, result range, and boundary-aware navigation."
        ],
        "avoidWhen": [
          "More results append to one continuous list; use the owning component's incremental-loading behavior instead.",
          "Only previous and next navigation is meaningful and the total result count is unknown."
        ],
        "commonlyComposedWith": [
          "component:ds-table",
          "component:ds-select",
          "component:ds-button-unfilled"
        ],
        "accessibility": [
          "The component renders a named navigation region, gives its compact page-size noun a complete accessible label, and gives every icon-only boundary control an explicit page action name.",
          "The visible page-size cluster states the localized noun, selected size, and total, for example Rows: 25 of 500. The page position uses compact ‘of’ phrasing, for example 1 of 20. A polite atomic status update retains the complete current range and ‘Page’ phrasing with the localized item noun.",
          "Left and Right Arrow request the adjacent page while focus is within pagination navigation controls. The page-size combobox retains its own arrow-key behavior.",
          "Inactive boundary controls and every control during loading remain non-interactive while retaining their accessible names."
        ],
        "states": [
          "pageIndex, numeric effective pageSize, pageSizeMode, totalItems, and pageSizeOptions are controlled inputs. dsChange reports the complete next pagination state, previous index, size, and mode, and whether the request changed the page, page size, or fitted capacity; it never mutates controlled inputs.",
          "Page-size changes request the first page. Out-of-range page indexes and invalid numeric inputs normalize only for presentation; the owner remains authoritative.",
          "Zero results display 0–0 of 0 and Page 1 of 1. A partial final page caps the visible range at totalItems.",
          "loading preserves the full pagination surface, applies aria-busy to the navigation region, and prevents page or page-size requests.",
          "fitToPage appends a Fit to page choice. fitPageSize supplies its effective whole-item capacity; the closed trigger says Fit while the range continues to expose the resulting count. fitToPageInactive keeps that choice visible but unavailable when fitting is not meaningful for the current data shape. Pagination does not measure layouts itself."
        ],
        "responsiveBehavior": [
          "The compact controls remain on one line with noun, selected size, total, a vertical divider, and page position. When inline space is still insufficient, the pagination surface scrolls horizontally rather than wrapping labels away from their controls."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Assign pageSizeOptions through the JavaScript property and replace controlled values in response to dsChange."
          ],
          "react": [
            "Replace pageIndex and pageSize from the emitted detail before supplying the requested data window."
          ],
          "angular": [
            "Bind numeric inputs as properties and update the owning signals from the dsChange output."
          ]
        },
        "references": [
          {
            "label": "Storybook review states",
            "path": "src/wc/components/Pagination/Pagination.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "fitPageSize": {
            "type": "number | undefined",
            "required": false
          },
          "fitPageSizeLabel": {
            "type": "string",
            "required": false
          },
          "fitPageSizeTriggerLabel": {
            "type": "string",
            "required": false
          },
          "fitToPage": {
            "type": "boolean",
            "required": false
          },
          "fitToPageInactive": {
            "type": "boolean",
            "required": false
          },
          "itemLabel": {
            "type": "string",
            "required": false
          },
          "label": {
            "type": "string",
            "required": false
          },
          "loading": {
            "type": "boolean",
            "required": false
          },
          "pageIndex": {
            "type": "number",
            "required": false
          },
          "pageSize": {
            "type": "number",
            "required": false
          },
          "pageSizeAriaLabel": {
            "type": "string | undefined",
            "required": false
          },
          "pageSizeLabel": {
            "type": "string",
            "required": false
          },
          "pageSizeMode": {
            "type": "PaginationPageSizeMode",
            "required": false
          },
          "pageSizeOptions": {
            "type": "number[]",
            "required": false
          },
          "totalItems": {
            "type": "number",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsChange",
            "detail": "PaginationChangeDetail"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-pagination",
        "react": "DsPagination",
        "vue": "DsPagination",
        "angular": "DsPagination"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "button-unfilled",
        "divider",
        "select",
        "text"
      ]
    },
    {
      "id": "component:ds-panel-nav",
      "tag": "ds-panel-nav",
      "name": "panel-nav",
      "title": "PanelNav",
      "summary": "The single persistent primary navigation for an application, providing grouped top-level destinations, active-route state, standard dashboard/settings switching, user access, and collapsible desktop and tablet presentation.",
      "intentStatus": "complete",
      "intent": {
        "audience": "specialized",
        "status": "stable",
        "summary": "The single persistent primary navigation for an application, providing grouped top-level destinations, active-route state, standard dashboard/settings switching, user access, and collapsible desktop and tablet presentation.",
        "useWhen": [
          "Building the one primary navigation surface for an application that uses the CompoMo system.",
          "Top-level destinations must remain consistently available while the application's page content changes.",
          "Primary destinations need visual grouping, icons, notification indicators, active-route state, and expanded or collapsed presentation."
        ],
        "avoidWhen": [
          "A second navigation surface is needed within the same application; an application must have only one PanelNav.",
          "The choices represent sections within the active primary destination; use BarNav instead.",
          "The choices switch local content without changing the application's primary destination; use TabGroup instead.",
          "The interaction performs a command or presents temporary contextual choices; use a button or Menu instead.",
          "Building navigation below the mobile breakpoint; use the application's dedicated mobile navigation component instead."
        ],
        "alternatives": [
          {
            "when": "The choices represent route sections within the active primary destination.",
            "component": "component:ds-bar-nav",
            "reason": "BarNav owns secondary section navigation within the destination selected by PanelNav."
          },
          {
            "when": "The choices switch local content without changing the application's primary destination.",
            "component": "component:ds-tab-group",
            "reason": "TabGroup owns local view selection and tab semantics."
          },
          {
            "when": "The choices are commands or temporary contextual actions.",
            "component": "component:ds-menu",
            "reason": "Menu owns transient action and option collections rather than persistent destinations."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-shell-app",
          "component:ds-bar-nav",
          "component:ds-panel-tools",
          "component:ds-menu"
        ],
        "patterns": [
          "pattern:application-shell"
        ],
        "accessibility": [
          "Give every primary destination a concise visible label and an icon that supports rather than replaces that label.",
          "Provide localized dashboard, settings, account, navigation, collapse, and expand labels.",
          "Preserve accessible destination names when the panel is collapsed to icon-only presentation.",
          "Use notification dots as supplemental status and never as the only indication of important information.",
          "When the destination body overflows, it becomes a localized keyboard-focusable scroll region in addition to the roving destination controls.",
          "Keep the standard dashboard/settings switch and user/account entry available in the footer."
        ],
        "states": [
          "Render exactly one PanelNav per application; it owns primary application destinations and no other navigation role.",
          "The host router owns the current route; prefer currentUrl for active destination matching and use activeId only when route matching is unavailable.",
          "Use anchor mode for native links or routers that intercept anchors; use event mode when the host performs navigation from dsNavSelect.",
          "Groups visually organize top-level destinations only and must not be interpreted as nested or expandable navigation.",
          "Dashboard presents day-to-day operational destinations; Settings presents administrative and configuration destinations.",
          "The standard footer switches the entire destination collection and navStyle between Dashboard and Settings and exposes the user/account entry.",
          "The host owns the external user menu opened from dsNavUserAction.",
          "While the external user menu is open or closing, accountMenuExpanded keeps its trigger visibly pressed without applying selected-destination foreground treatment in either expanded or collapsed presentation.",
          "Item and header controls inherit the shared md control radius while local shell geometry continues to own collapsed layout and footer animation positioning.",
          "On desktop, allow user-controlled expand and collapse and persist the preference with storageKey when cross-session persistence is appropriate."
        ],
        "responsiveBehavior": [
          "At 1200px and wider, default to expanded, allow the user to expand or collapse, and restore the locally persisted desktop preference when available.",
          "From 768px through 1199px, present PanelNav permanently collapsed and do not allow user expansion.",
          "Below 768px, the consuming application replaces PanelNav with a dedicated mobile navigation component; PanelNav does not own mobile navigation.",
          "Managed ShellApp permanently owns responsive composition: it determines shell mode, enforces tablet collapse, and presents MobileSheetNav below 768px.",
          "When the viewport is below breakpoint, PanelNav locks collapsed, disables its header toggle affordance, and preserves the persisted desktop collapse preference.",
          "Collapsed presentation must preserve destination ordering, active state, notification status, and accessible names."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Assign groups as a JavaScript property for structured data; a JSON string attribute is also supported.",
            "Set nav-style before the element connects when first-paint style must match the current route."
          ],
          "react": [
            "Pass groups as an array through the generated React wrapper and synchronize currentUrl with the host router.",
            "ShellApp owns mobile replacement; PanelNav enforces its configured breakpoint expansion lock."
          ],
          "angular": [
            "Import DsPanelNav from @ds-mo/ui/angular/ds-panel-nav and bind groups as a property.",
            "Bind both the nav-style attribute and navStyle property when first-paint route styling must be deterministic.",
            "ShellApp owns mobile replacement; PanelNav enforces its configured breakpoint expansion lock."
          ]
        },
        "references": [
          {
            "label": "Executable Storybook examples",
            "path": "src/wc/components/PanelNav/PanelNav.stories.ts"
          },
          {
            "label": "Framework and routing integration",
            "path": "docs/framework-integration.md"
          },
          {
            "label": "Application shell composition",
            "path": "agent/patterns/application-shell/pattern.agent.json"
          }
        ]
      },
      "api": {
        "props": {
          "accountLabel": {
            "type": "string",
            "required": false
          },
          "accountMenuExpanded": {
            "type": "boolean",
            "required": false
          },
          "activeId": {
            "type": "string",
            "required": false
          },
          "breakpoint": {
            "type": "number",
            "required": false
          },
          "collapseNavigationLabel": {
            "type": "string",
            "required": false
          },
          "collapsed": {
            "type": "boolean",
            "required": false
          },
          "currentUrl": {
            "type": "string",
            "required": false
          },
          "dashboardLabel": {
            "type": "string",
            "required": false
          },
          "dashboardNavigationLabel": {
            "type": "string",
            "required": false
          },
          "disableViewTransition": {
            "type": "boolean",
            "required": false
          },
          "expandNavigationLabel": {
            "type": "string",
            "required": false
          },
          "groups": {
            "type": "string | PanelNavGroup[]",
            "required": false
          },
          "navStyle": {
            "type": "NavChromeStyle",
            "required": false
          },
          "navigationItemsLabel": {
            "type": "string",
            "required": false
          },
          "routerMode": {
            "type": "PanelNavRouterMode",
            "required": false
          },
          "settingsLabel": {
            "type": "string",
            "required": false
          },
          "settingsNavigationLabel": {
            "type": "string",
            "required": false
          },
          "storageKey": {
            "type": "string",
            "required": false
          },
          "userInitial": {
            "type": "string",
            "required": false
          },
          "userName": {
            "type": "string",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsChromeTransitionEnd",
            "detail": "ChromeTransitionDetail"
          },
          {
            "name": "dsChromeTransitionStart",
            "detail": "ChromeTransitionDetail"
          },
          {
            "name": "dsNavFooterAction",
            "detail": "void"
          },
          {
            "name": "dsNavSelect",
            "detail": "string"
          },
          {
            "name": "dsNavToggle",
            "detail": "boolean"
          },
          {
            "name": "dsNavUserAction",
            "detail": "PanelNavUserActionDetail"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-panel-nav",
        "react": "DsPanelNav",
        "vue": "DsPanelNav",
        "angular": "DsPanelNav"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens",
        "@ds-mo/icons"
      ],
      "componentDependencies": [
        "badge",
        "button-unfilled",
        "icon",
        "text",
        "tooltip"
      ]
    },
    {
      "id": "component:ds-panel-sub-nav",
      "tag": "ds-panel-sub-nav",
      "name": "panel-sub-nav",
      "title": "PanelSubNav",
      "summary": "Persistent vertical tab navigation for a panel or card side rail, switching adjacent local content with menu-like selected fill and stable text weight.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Persistent vertical tab navigation for a panel or card side rail, switching adjacent local content with menu-like selected fill and stable text weight.",
        "useWhen": [
          "A panel or card side rail needs a persistent vertical list that switches adjacent local content.",
          "Each concise text label controls an immediately available tabpanel without changing application routes."
        ],
        "avoidWhen": [
          "The navigation is not contained in a panel or card side rail.",
          "Local views should be arranged horizontally; use TabGroup instead.",
          "The choices navigate routes in application shell chrome; use PanelNav or BarNav instead.",
          "The choices are temporary commands or contextual options; use Menu instead.",
          "Rows need icons, subtext, notification dots, nested levels, or section headers."
        ],
        "alternatives": [
          {
            "when": "Local panel choices fit a horizontal tab row.",
            "component": "component:ds-tab-group",
            "reason": "TabGroup is the horizontal local-view counterpart."
          },
          {
            "when": "The choices are primary application destinations.",
            "component": "component:ds-panel-nav",
            "reason": "PanelNav owns primary application navigation."
          },
          {
            "when": "The choices are secondary application routes.",
            "component": "component:ds-bar-nav",
            "reason": "BarNav owns route sections inside ShellApp."
          },
          {
            "when": "The choices are transient actions or options.",
            "component": "component:ds-menu",
            "reason": "Menu owns temporary popup collections."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-card-setting",
          "component:ds-text"
        ],
        "accessibility": [
          "Provide an accessible name with aria-label or aria-labelledby.",
          "Give every item a unique id and the id of its controlled tabpanel.",
          "Keep each controlled tabpanel labelled by its matching item id.",
          "Always provide a valid selected item when enabled items exist so exactly one tab and panel are active.",
          "ArrowUp and ArrowDown move and activate selection; Home and End select the first and last available items.",
          "Do not use selected text weight as the selection cue; active fill and primary foreground communicate selection."
        ],
        "states": [
          "The parent owns the canonical selected value and panel visibility, and should update both from dsChange.",
          "A missing, empty, or unknown selected value is invalid when enabled items exist; the component does not choose a fallback selection.",
          "Inactive items remain visible but cannot be focused or selected.",
          "Selection is singular and follows keyboard focus.",
          "The omitted default surface treatment is for primary and secondary parent surfaces and uses the brand-active selected fill; pass faint explicitly on faint surfaces to use the neutral active fill.",
          "Rows contain one text label only and do not express nested navigation or grouped hierarchy."
        ],
        "responsiveBehavior": [
          "The component remains vertical at every width.",
          "The consuming panel owns responsive adaptation and decides whether to reposition or replace the side rail."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Assign items as a JavaScript property because structured arrays are not represented by HTML attributes.",
            "Keep value synchronized to a valid enabled item and update the controlled panel from dsChange."
          ],
          "react": [
            "Pass items as an array through the generated wrapper, keep value controlled, and use onDsChange to synchronize the visible panel."
          ],
          "angular": [
            "Bind items and a valid value as properties, and handle dsChange to synchronize the visible panel."
          ]
        }
      },
      "api": {
        "props": {
          "ariaLabel": {
            "type": "string | null",
            "required": false
          },
          "ariaLabelledby": {
            "type": "string | undefined",
            "required": false
          },
          "background": {
            "type": "PanelSubNavBackground | undefined",
            "required": false
          },
          "items": {
            "type": "PanelSubNavItem[]",
            "required": false
          },
          "value": {
            "type": "string",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsChange",
            "detail": "string"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-panel-sub-nav",
        "react": "DsPanelSubNav",
        "vue": "DsPanelSubNav",
        "angular": "DsPanelSubNav"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "text"
      ]
    },
    {
      "id": "component:ds-panel-tool-header",
      "tag": "ds-panel-tool-header",
      "name": "panel-tool-header",
      "title": "PanelToolHeader",
      "summary": "Canonical left-aligned PanelTools header with an optional leading navigation or dismiss action and application-owned trailing icon actions.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "experimental",
        "summary": "Canonical left-aligned PanelTools header with an optional leading navigation or dismiss action and application-owned trailing icon actions.",
        "useWhen": [
          "PanelTools needs its one shared root or detail header.",
          "A tool header needs a title with optional Back or Close navigation, menu, fullscreen, or other compact icon actions."
        ],
        "avoidWhen": [
          "Rendering inside a PanelTools tool body; PanelTools already composes this canonical header above the body.",
          "The header belongs to page content."
        ],
        "commonlyComposedWith": [
          "component:ds-button-unfilled"
        ],
        "accessibility": [
          "Leading navigation or dismiss actions and trailing icon actions require concise localized names; the header reuses each name as the action tooltip.",
          "The visible heading names the active panel or subview."
        ],
        "states": [
          "The title remains left aligned whether the header has no actions, Back, one trailing action, or several trailing actions.",
          "Leading and trailing control zones never shrink; only the title consumes and truncates within the remaining width. The header uses the shared 8px compact-header zone gap, while adjacent trailing actions retain their 4px control gap.",
          "Header chrome text is not selectable; actions remain keyboard focusable and interactive.",
          "Adjacent trailing actions keep the shared 4px control gap in drawer and fullscreen presentations.",
          "When fullscreen and overflow actions appear together, author fullscreen before overflow so Ellipses remains the rightmost action.",
          "PanelTools supplies application-owned actions and relays their ids through its shared dsHeaderAction event."
        ],
        "responsiveBehavior": [
          "The title truncates between optional leading navigation and trailing action zones."
        ],
        "references": [
          {
            "label": "Standalone examples",
            "path": "src/wc/components/PanelToolHeader/PanelToolHeader.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "actions": {
            "type": "PanelToolsHeaderAction[]",
            "required": false
          },
          "backAriaLabel": {
            "type": "string",
            "required": false
          },
          "backIcon": {
            "type": "string",
            "required": false
          },
          "heading": {
            "type": "string",
            "required": false
          },
          "menuAriaLabel": {
            "type": "string",
            "required": false
          },
          "menuControls": {
            "type": "string | undefined",
            "required": false
          },
          "menuExpanded": {
            "type": "boolean",
            "required": false
          },
          "menuTriggerId": {
            "type": "string",
            "required": false
          },
          "showBack": {
            "type": "boolean",
            "required": false
          },
          "showMenu": {
            "type": "boolean",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsAction",
            "detail": "{ id: string; originalEvent: MouseEvent }"
          },
          {
            "name": "dsBack",
            "detail": "MouseEvent"
          },
          {
            "name": "dsMenuToggle",
            "detail": "MouseEvent"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-panel-tool-header",
        "react": "DsPanelToolHeader",
        "vue": "DsPanelToolHeader",
        "angular": "DsPanelToolHeader"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "button-unfilled",
        "text",
        "tooltip"
      ]
    },
    {
      "id": "component:ds-panel-tool-search",
      "tag": "ds-panel-tool-search",
      "name": "panel-tool-search",
      "title": "PanelToolSearch",
      "summary": "Transparent search row for the top of a PanelTools product view, with a fixed 48px allocation around the standard md search control and an optional filter-menu trigger.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "experimental",
        "summary": "Transparent search row for the top of a PanelTools product view, with a fixed 48px allocation around the standard md search control and an optional filter-menu trigger.",
        "useWhen": [
          "A PanelTools base view filters or searches the tool's own content.",
          "Several tool products need the same search-row geometry directly below the shared PanelTools header.",
          "The product needs a compact filter menu next to search while keeping its filter choices and matching policy application-owned."
        ],
        "avoidWhen": [
          "The search belongs inside a Select popup; use that component's searchable behavior in either cardinality mode.",
          "A form needs a labelled standalone field; compose ds-input inside ds-field instead."
        ],
        "commonlyComposedWith": [
          "component:ds-panel-tools",
          "component:ds-conversation-list",
          "component:ds-input"
        ],
        "accessibility": [
          "Provide an aria-label that names the searched domain, such as Search agent chats or Search messages.",
          "The standard search clear action restores focus, uses the concise localized clearLabel by itself for both its tooltip and accessible name, and emits both the empty query and dsClear.",
          "When showFilter is enabled, provide stable filterTriggerId and filterControls values, synchronize filterExpanded with the controlled menu, and restore focus after selection; filterAriaLabel also labels its tooltip."
        ],
        "states": [
          "The row is always 48px high with 8px outer padding and a complete md search recipe: 32px control, text-body-medium at 14px/20px, and a 20px md search icon.",
          "The search icon stays foreground-secondary at rest, hover, focus, active, and while the query is filled.",
          "The row and control surface remain transparent so the ShellApp chrome wash is visible behind them.",
          "The row divider remains the same tertiary 1px boundary while the input is focused because it belongs to the 48px container rather than the input control.",
          "With filtering enabled, the md search control, decorative vertical divider, and borderless md Filter action are separated by 8px; filterActive promotes only the trigger foreground without adding a selected fill."
        ],
        "responsiveBehavior": [
          "The row fills the available drawer or fullscreen width, allows its search region to shrink inside a 300px drawer without pushing the filter trigger under the tool rail, and does not reduce its control below md density."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Listen for dsChange to receive the current string query and dsClear when the clear action is used.",
            "Listen for dsFilterToggle and pair the trigger with an externally controlled ds-menu; product-specific filter labels and filtering remain outside this component."
          ],
          "react": [
            "Use DsPanelToolSearch, bind value for controlled state, and handle onDsChange.",
            "Bind the optional filter trigger state and connect onDsFilterToggle to a controlled DsMenu."
          ],
          "angular": [
            "Import DsPanelToolSearch and bind value as a property; this search composition is not a form value accessor.",
            "Bind showFilter, filterExpanded, and filterActive, then connect dsFilterToggle to a product-owned ds-menu."
          ]
        },
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/PanelToolSearch/PanelToolSearch.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "ariaLabel": {
            "type": "string",
            "required": false
          },
          "controls": {
            "type": "string | undefined",
            "required": false
          },
          "filterActive": {
            "type": "boolean",
            "required": false
          },
          "filterAriaLabel": {
            "type": "string",
            "required": false
          },
          "filterControls": {
            "type": "string | undefined",
            "required": false
          },
          "filterExpanded": {
            "type": "boolean",
            "required": false
          },
          "filterTriggerId": {
            "type": "string",
            "required": false
          },
          "isInactive": {
            "type": "boolean",
            "required": false
          },
          "placeholder": {
            "type": "string",
            "required": false
          },
          "showFilter": {
            "type": "boolean",
            "required": false
          },
          "value": {
            "type": "string",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsChange",
            "detail": "string"
          },
          {
            "name": "dsClear",
            "detail": "void"
          },
          {
            "name": "dsFilterToggle",
            "detail": "MouseEvent"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-panel-tool-search",
        "react": "DsPanelToolSearch",
        "vue": "DsPanelToolSearch",
        "angular": "DsPanelToolSearch"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens",
        "@ds-mo/icons"
      ],
      "componentDependencies": [
        "button-unfilled",
        "divider",
        "icon",
        "text",
        "tooltip"
      ]
    },
    {
      "id": "component:ds-panel-tools",
      "tag": "ds-panel-tools",
      "name": "panel-tools",
      "title": "PanelTools",
      "summary": "Desktop and tablet utility rail-and-drawer primitive for explicitly defined application-wide tools, normally assembled by managed ShellApp through ShellTools.",
      "intentStatus": "complete",
      "intent": {
        "audience": "specialized",
        "status": "stable",
        "summary": "Desktop and tablet utility rail-and-drawer primitive for explicitly defined application-wide tools, normally assembled by managed ShellApp through ShellTools.",
        "useWhen": [
          "An advanced slotted ShellApp needs the desktop and tablet global-tools primitive directly.",
          "Users need to move between application-wide utilities without losing each tool's in-progress state.",
          "Search, AI conversations, user messages, review stacks, notifications, or help content must remain available alongside route content."
        ],
        "avoidWhen": [
          "The action is specific to the current page or selected content rather than globally available across the application.",
          "The item navigates to a primary or secondary route; use PanelNav or BarNav instead.",
          "Tool definitions lack stable ids, visible labels, explicit rail placement, or application-owned view content.",
          "Building the mobile tools experience; use ShellTools or managed ShellApp.",
          "PanelTools would be mounted outside the application's single ShellApp."
        ],
        "alternatives": [
          {
            "when": "The action navigates to a top-level application destination.",
            "component": "component:ds-panel-nav",
            "reason": "PanelNav exclusively owns primary application navigation."
          },
          {
            "when": "The action navigates between route sections of the active destination.",
            "component": "component:ds-bar-nav",
            "reason": "BarNav exclusively owns secondary route navigation."
          },
          {
            "when": "Temporary contextual actions or options are needed.",
            "component": "component:ds-menu",
            "reason": "Menu owns transient contextual choices rather than persistent global products."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-shell-app",
          "component:ds-panel-nav",
          "component:ds-bar-nav"
        ],
        "patterns": [
          "pattern:application-shell"
        ],
        "accessibility": [
          "Provide localized accessible labels for the rail, shortcut group, and every rendered tool.",
          "Use the canonical default recipe when the product needs Search first and Help last; custom recipes must preserve a deliberate keyboard and visual order.",
          "Keep focus on the selected rail action when opening a drawer and allow normal Tab navigation into its content.",
          "When the shortcut rail overflows, its labeled body becomes a keyboard-focusable scroll region without changing the rail action order.",
          "Do not trigger global shortcuts while focus is in an editable control.",
          "Use notification dots only as supplemental unread or new-content status and never as the sole status indication.",
          "Explain temporarily inactive tools through an accessible label or adjacent product guidance; omit unauthorized tools entirely."
        ],
        "states": [
          "Every tool has a stable explicit id and accessible label. The application filters definitions for authorization and entitlement.",
          "Tool order, header or footer rail placement, shortcut, and mobile grouping come from explicit item metadata rather than id-based layout assumptions.",
          "PANEL_TOOLS_DEFAULT_ITEMS is the canonical Lab recipe: Search pinned first, Messages before Agents, Help pinned last, current shortcuts, and only Stacks and Activity grouped under mobile Inbox.",
          "Only one drawer is open at a time; selecting another tool switches directly and selecting the active tool closes to rail-only mode.",
          "The drawer starts closed, remains open across ordinary route changes, and retains every mounted tool's independent conversation, query, scroll, and work state.",
          "When storageKey is set, persist only the last active tool in this browser and still restore the drawer closed after reload.",
          "The application owns unread state; opening Messages, Agents, Stacks, or Activity does not automatically clear its notification dot.",
          "PanelTools owns the one visible header above every drawer tool view and above fullscreen views using the default shared header mode. Slotted tool content must not render a second header unless the conversation product explicitly opts into split fullscreen headers.",
          "PanelTools composes ds-panel-tool-header as its canonical left-aligned header implementation so standalone header stories and shell rendering cannot diverge.",
          "Each tool supplies its current header title, base-versus-detail Back state, and right-side actions through the headers property. Base views omit Back; deeper views expose Back and update the same header in place.",
          "Header Back and action events express intent only; the owning tool changes product navigation, menus, and data state. PanelTools keeps the final header action exactly 8px from the drawer edge.",
          "Menus opened from a right-side header action use PANEL_TOOLS_HEADER_MENU_PLACEMENT: bottom/end choice-cell alignment and a 12px side offset, placing the popup 4px below the 48px header while aligning the final menu item edge with the trigger.",
          "Tool view roots stay transparent so ShellApp's chrome wash remains visible; only explicitly designed child surfaces introduce a fill.",
          "Tools with search compose ds-panel-tool-search immediately below the shared header. Its 48px row always contains the md search control and must not be reduced to sm or xs.",
          "If an active optional tool becomes unavailable, PanelTools closes the drawer, clears activeTool, and emits its deselection.",
          "Use isInactive only for a temporarily unavailable visible tool; omit tools the user is not authorized to access.",
          "Rail actions disable physical press scaling so notification-dot halos remain aligned to the shell gradient; hover and pressed washes continue to paint above the dot and halo.",
          "The application owns slotted tool products and data while PanelTools owns rail ordering, drawer selection, open state, motion, and shell events.",
          "Opening and closing clip an already-rendered fixed-width surface. Header and tool content remain fully opaque and retained during width motion; transition completion is accepted only at the measured terminal clip width, after which the closed surface becomes inert and paint-skipped.",
          "Entering and exiting fullscreen snaps without borrowing the drawer open or close animation.",
          "When fullscreenHeaderMode is split, PanelTools suppresses only its fullscreen shared header. The application renders exactly two canonical ds-panel-tool-header instances: a tool-title/list-actions header over the 300px history pane and a chat-title/Exit-fullscreen/chat-actions header over the detail pane. The detail header omits Back because the list remains visible."
        ],
        "responsiveBehavior": [
          "The open drawer reduces main-content width and uses --dimension-panel-width-xs (300px) on every supported desktop and tablet viewport.",
          "ShellApp owns the fixed drawer-width variable; consumers must not hardcode alternate drawer widths.",
          "Below 768px, do not reuse PanelTools directly; ShellTools and managed ShellApp present the same persistent tool owners through mobile chrome.",
          "Keep named-slot content mounted while tools switch or the drawer closes so users can return to in-progress global work.",
          "Conversation products may use fullscreenHeaderMode split for a 300px history rail beside a flexible detail pane, each with its own canonical header; the application owns that internal split layout.",
          "Use fixed drawer widths for now; do not add user resizing or width persistence."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Assign items and headers as JavaScript properties and replace their references when collections change.",
            "Assign headers as a JavaScript property and replace its object identity whenever an active tool changes title, depth, or actions.",
            "Keep PanelTools mounted at ShellApp scope across route changes and provide each product through its matching named slot."
          ],
          "react": [
            "Pass a stable explicitly ordered item collection through the generated React wrapper and keep named-slot product content mounted at ShellApp scope.",
            "Use storageKey only for same-browser last-tool continuity; do not persist the open drawer."
          ],
          "angular": [
            "Import DsPanelTools from @ds-mo/ui/angular/ds-panel-tools and bind items as a property.",
            "Bind headers as a replaced object and route dsHeaderBack and dsHeaderAction to the active tool owner.",
            "Keep the component in the persistent shell layout rather than recreating it in routed page components."
          ]
        },
        "references": [
          {
            "label": "Executable Storybook examples",
            "path": "src/wc/components/PanelTools/PanelTools.stories.ts"
          },
          {
            "label": "Framework and shell integration",
            "path": "docs/framework-integration.md"
          },
          {
            "label": "Application shell composition",
            "path": "agent/patterns/application-shell/pattern.agent.json"
          }
        ]
      },
      "api": {
        "props": {
          "activeTool": {
            "type": "PanelToolsToolId | ''",
            "required": false
          },
          "fullscreenHeaderMode": {
            "type": "'shared' | 'split'",
            "required": false
          },
          "headers": {
            "type": "PanelToolsHeaders",
            "required": false
          },
          "items": {
            "type": "PanelToolsItem[]",
            "required": false
          },
          "open": {
            "type": "boolean",
            "required": false
          },
          "presentation": {
            "type": "'drawer' | 'fullscreen'",
            "required": false
          },
          "storageKey": {
            "type": "string",
            "required": false
          },
          "toolShortcutsLabel": {
            "type": "string",
            "required": false
          },
          "toolsLabel": {
            "type": "string",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsChromeTransitionEnd",
            "detail": "ChromeTransitionDetail"
          },
          {
            "name": "dsChromeTransitionStart",
            "detail": "ChromeTransitionDetail"
          },
          {
            "name": "dsHeaderAction",
            "detail": "{\n    tool: PanelToolsToolId;\n    id: string;\n  }"
          },
          {
            "name": "dsHeaderBack",
            "detail": "{\n    tool: PanelToolsToolId;\n  }"
          },
          {
            "name": "dsPresentationChange",
            "detail": "{\n    presentation: 'drawer' | 'fullscreen';\n  }"
          },
          {
            "name": "dsToolChange",
            "detail": "{\n    id: PanelToolsToolId;\n    selected: boolean;\n  }"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-panel-tools",
        "react": "DsPanelTools",
        "vue": "DsPanelTools",
        "angular": "DsPanelTools"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "button-unfilled",
        "panel-tool-header",
        "tooltip"
      ]
    },
    {
      "id": "component:ds-paper-texture",
      "tag": "ds-paper-texture",
      "name": "paper-texture",
      "title": "PaperTexture",
      "summary": "A decorative Paper Design WebGL2 paper texture surface with Storybook-tunable literal shader parameters and a static default frame.",
      "intentStatus": "complete",
      "intent": {
        "audience": "specialized",
        "status": "experimental",
        "summary": "A decorative Paper Design WebGL2 paper texture surface with Storybook-tunable literal shader parameters and a static default frame.",
        "useWhen": [
          "A shell or other visual surface needs a paper or cardboard texture layered above an existing background.",
          "Designers need to tune paper texture parameters interactively before choosing a baked static asset."
        ],
        "avoidWhen": [
          "The surface needs semantic content, interaction, or accessible information.",
          "The target environment cannot provide WebGL2 and no pre-baked fallback asset is available.",
          "A token-driven color treatment is required; this component accepts literal shader colors only."
        ],
        "alternatives": [],
        "commonlyComposedWith": [
          "component:ds-shell-app"
        ],
        "accessibility": [
          "The texture is decorative and is hidden from assistive technology.",
          "Keep all meaningful content in the owning surface above or beside the texture."
        ],
        "states": [
          "The default speed is zero, so a texture renders one deterministic frame without a recurring animation loop.",
          "Paper shader colors are literal CSS color strings and are not resolved from TokoMo tokens.",
          "If WebGL2 or the noise texture is unavailable, the decorative layer removes itself without blocking the owning surface."
        ],
        "responsiveBehavior": [
          "The shader observes its host dimensions and follows the owning surface through resize changes.",
          "minPixelRatio and maxPixelCount are available for explicit quality/performance tuning."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Assign config as a JavaScript property; nested shader values are not intended for serialized HTML attributes."
          ],
          "react": [
            "Use the generated wrapper and pass the config object as a property."
          ],
          "angular": [
            "Bind the config object as a property so nested shader values are preserved."
          ]
        },
        "references": [
          {
            "label": "Storybook parameter playground",
            "path": "src/wc/components/PaperTexture/PaperTexture.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "config": {
            "type": "PaperTextureConfig",
            "required": false
          }
        },
        "events": [],
        "slots": []
      },
      "exports": {
        "customElement": "ds-paper-texture",
        "react": "DsPaperTexture",
        "vue": "DsPaperTexture",
        "angular": "DsPaperTexture"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": []
    },
    {
      "id": "component:ds-radio",
      "tag": "ds-radio",
      "name": "radio",
      "title": "Radio",
      "summary": "Form-associated one-of-many radio selection set with vertical or horizontal layout, optional per-option descriptions, four densities, per-option inactive state, and roving keyboard focus.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Form-associated one-of-many radio selection set with vertical or horizontal layout, optional per-option descriptions, four densities, per-option inactive state, and roving keyboard focus.",
        "useWhen": [
          "A user must select exactly one visible option from a small set.",
          "All available choices should remain visible for comparison.",
          "A form needs one selected string value with native validation, reset, or external form association."
        ],
        "avoidWhen": [
          "A user may select zero or multiple independent choices.",
          "A binary setting applies immediately rather than selecting from a set.",
          "The option list is too long or space-constrained to remain visible."
        ],
        "alternatives": [
          {
            "when": "A user may select zero or multiple independent choices.",
            "component": "component:ds-checkbox",
            "reason": "Checkbox communicates independent selection rather than one-of-many choice."
          },
          {
            "when": "A binary setting applies immediately.",
            "component": "component:ds-switch",
            "reason": "Switch communicates an immediately applied on/off setting."
          },
          {
            "when": "The option list is long or the available space is constrained.",
            "component": "component:ds-select",
            "reason": "Select keeps a larger one-of-many choice set compact."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-field",
          "component:ds-text"
        ],
        "accessibility": [
          "The host exposes radiogroup semantics and requires an accessible group name from aria-label or aria-labelledby.",
          "Each visible option exposes radio semantics, its checked state, its label text, optional supporting description, and any inactive state.",
          "Arrow keys move and select through active options; Home and End select the first and last active options; Space and Enter select the focused option.",
          "Roving tabindex keeps one active option in the tab order, preferring the selected option; setFocus uses that same public focus target."
        ],
        "states": [
          "Unchecked circles use a tertiary-foreground inset stroke: 1.5px at lg, 1.25px at md, 1px at sm, and 0.75px at xs.",
          "Selected circles remove the border, use a brand fill, and draw a centered on-bold foreground dot sized 10px at lg, 8px at md, 6px at sm, and 4px at xs.",
          "Sizes are lg with a 20px circle in a 24px placement, md with a 16px circle in a 20px placement, sm with a 12px circle in a 16px placement, and xs with an 8px circle in a 12px placement.",
          "The initial value is restored by native form reset; the selected value submits under name and a required set is invalid until one active option is selected.",
          "Description-rich options grow beyond the fixed density height while retaining its minimum target size and primitive-owned selection anatomy."
        ],
        "responsiveBehavior": [
          "Choose size from the density of the containing form or settings row.",
          "Prefer vertical layout when labels or descriptions may wrap or horizontal space is constrained; horizontal layout is appropriate for short labels in a small set."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Assign options as a JavaScript property, set value as a property for application state updates, and listen for dsChange.",
            "Use the form attribute on the host when associating a radio set rendered outside its owning form."
          ],
          "react": [
            "Use DsRadio, pass options as an array, and handle onDsChange; value is mutable and updates after user selection."
          ],
          "vue": [
            "Use DsRadio with v-model for the selected value, bind options as a property, and listen for dsChange."
          ],
          "angular": [
            "Use DsRadio with options and value bindings plus dsChange, or import the generated radio value accessor with the component adapter."
          ]
        },
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/Radio/Radio.stories.ts"
          },
          {
            "label": "Cross-browser form and accessibility coverage",
            "path": "tests/e2e/forms.spec.ts"
          }
        ]
      },
      "api": {
        "props": {
          "ariaLabel": {
            "type": "string | null",
            "required": false
          },
          "ariaLabelledby": {
            "type": "string | undefined",
            "required": false
          },
          "direction": {
            "type": "'vertical' | 'horizontal'",
            "required": false
          },
          "disabled": {
            "type": "boolean",
            "required": false
          },
          "form": {
            "type": "string | undefined",
            "required": false
          },
          "isInactive": {
            "type": "boolean",
            "required": false
          },
          "name": {
            "type": "string | undefined",
            "required": false
          },
          "options": {
            "type": "RadioOption[]",
            "required": false
          },
          "required": {
            "type": "boolean",
            "required": false
          },
          "requiredMessage": {
            "type": "string",
            "required": false
          },
          "size": {
            "type": "RadioSize",
            "required": false
          },
          "value": {
            "type": "string",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsChange",
            "detail": "string"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-radio",
        "react": "DsRadio",
        "vue": "DsRadio",
        "angular": "DsRadio"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "text"
      ]
    },
    {
      "id": "component:ds-scroll-overlay",
      "tag": "ds-scroll-overlay",
      "name": "scroll-overlay",
      "title": "ScrollOverlay",
      "summary": "Generic scroll owner for content that moves behind a persistent footer action or composer with an always-active alpha fade.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Generic scroll owner for content that moves behind a persistent footer action or composer with an always-active alpha fade.",
        "useWhen": [
          "A bounded region owns scrolling while footer actions remain overlaid and continuously visible.",
          "The final content must clear a live-height footer while earlier content can move behind it."
        ],
        "avoidWhen": [
          "The footer belongs in normal document flow rather than overlaying content.",
          "Another component already owns scrolling and cannot delegate its scrollport to this component."
        ],
        "commonlyComposedWith": [
          "component:ds-button-filled",
          "component:ds-message-composer"
        ],
        "accessibility": [
          "Provide scrollLabel when the scrollport needs its own named, keyboard-focusable region.",
          "Keep footer actions keyboard accessible and explicitly named; the fade is decorative and never intercepts pointer input."
        ],
        "states": [
          "The alpha mask remains active at every scroll position and moves in content coordinates so it stays pinned behind the footer without masking native scrollbars.",
          "The component measures the complete overlay for end clearance, measures its visible child for fade depth, and begins the fade 8px before that visible content.",
          "An md 32px footer action with 8px bottom inset therefore produces a 48px fade; variable-height composers produce a correspondingly taller measured fade."
        ],
        "responsiveBehavior": [
          "The scrollport and overlay fill the available width and height; the owner supplies responsive sizing and overlay insets."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Place scrollable content in the default slot and one footer wrapper in the overlay slot; use dsScroll only when the application needs position data."
          ],
          "react": [
            "Use DsScrollOverlay with ordinary children plus an element carrying slot=\"overlay\"."
          ],
          "angular": [
            "Import DsScrollOverlay and project the persistent footer wrapper with slot=\"overlay\"."
          ]
        },
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/ScrollOverlay/ScrollOverlay.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "scrollLabel": {
            "type": "string | undefined",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsScroll",
            "detail": "ScrollOverlayScrollDetail"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-scroll-overlay",
        "react": "DsScrollOverlay",
        "vue": "DsScrollOverlay",
        "angular": "DsScrollOverlay"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": []
    },
    {
      "id": "component:ds-select",
      "tag": "ds-select",
      "name": "select",
      "title": "Select",
      "summary": "Form-associated select for one value or several independent values through the multiple mode, with listbox semantics for ordinary choices, grid semantics for choices with contextual actions, local search, grouped sections, loading, clearing, and surface-aware trigger chrome.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Form-associated select for one value or several independent values through the multiple mode, with listbox semantics for ordinary choices, grid semantics for choices with contextual actions, local search, grouped sections, loading, clearing, and surface-aware trigger chrome.",
        "useWhen": [
          "The user must choose one value from a finite set.",
          "The user may choose several independent values when multiple is enabled.",
          "The option set benefits from local search, subtext, prefix icons, grouping, or disabled choices.",
          "The choice set has more than roughly 20 options, comes from a user-managed listing, or represents a large domain such as addresses where search materially improves retrieval.",
          "The selected value must participate in native, Angular, React, or Vue form state."
        ],
        "avoidWhen": [
          "The rows perform commands rather than choosing a form value.",
          "The choices form a hierarchy with expandable parents."
        ],
        "alternatives": [
          {
            "when": "The popup contains commands or state-changing actions.",
            "component": "component:ds-menu",
            "reason": "Menu uses action-menu roles and command-focused keyboard behavior."
          },
          {
            "when": "A small set of choices should remain visible.",
            "component": "component:ds-radio",
            "reason": "Prefer Radio for roughly two to five mutually exclusive choices when the available space allows all choices to remain visible."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-text",
          "component:ds-icon",
          "component:ds-empty-state",
          "component:ds-loader"
        ],
        "accessibility": [
          "In forms, provide a persistent visible external field label; placeholder text is guidance and must not be the field's only label. In a compact filter bar, the trigger's visible text may supply the accessible name.",
          "The trigger uses combobox semantics. Ordinary choices use a listbox with options; when any choice has a contextual action, the popup promotes to a grid with selectable rows, a choice cell, and an action cell. Do not replace either popup with menu roles.",
          "Multiple mode adds aria-multiselectable, exposes independent aria-selected state, and uses presentation-only checkbox indicators while each option remains the sole interaction target.",
          "Disabled options remain visible, expose aria-disabled, and are skipped by keyboard navigation and typeahead.",
          "Keyboard navigation keeps the aria-activedescendant option scrolled into the visible listbox viewport.",
          "Selected options rely on active fill and foreground treatment without a redundant trailing check icon.",
          "A contextual option action is a sibling gridcell rather than an interactive descendant of the selectable choice cell. Pointer hover, focus, ArrowRight, and Shift+F10 make the ellipsis action reachable without changing the selected value.",
          "Local search moves focus into the search field while preserving the active option through aria-activedescendant.",
          "Use errorMessage with error so the trigger is described by the rendered alert."
        ],
        "states": [
          "The multiple property changes cardinality without changing the component family: scalar mode selects and closes, while multiple mode toggles array values and keeps the popup open.",
          "Every size applies one complete control-density recipe across trigger height, inline padding, icon zones, text-container inset, gap, and radius; error content follows the shared 4px field flow.",
          "Value is controlled through the mutable value property as a string in scalar mode or a string array in multiple mode; dsChange reports the matching shape.",
          "Multiple mode keeps the persistent placeholder label visible, appends the selected count, and submits one repeated form entry per selected value.",
          "Required Selects begin without an automatic selection and require the user to make an explicit choice; do not preselect the first option merely to satisfy validity.",
          "When allowClear is enabled, the clear affordance appears only after a value exists. Clearing is valid for optional and required fields; a required field becomes invalid until the user selects again.",
          "Clearing emits dsChange with an empty string or empty array according to mode plus dsClear, keeps the popup open, and restores useful focus.",
          "Loading keeps the trigger visible, replaces its prefix icon, marks the control busy, and makes selection interaction temporarily unavailable without presenting the control as inactive. When the popup is open, its single loader is centered vertically and horizontally within the loading region.",
          "The trigger label stays left-aligned at every width. The default size is md in both forms and filter bars; smaller sizes require an explicit density need.",
          "In scalar mode, triggerLabel may provide compact trigger-only copy while the popup continues to show the selected option's full label. Set triggerLabelPlaceholder when that copy represents the default or browse state and should retain secondary placeholder emphasis despite a real selected value. Use dot for a supplemental changed or attention state without appending status prose to the label.",
          "Use option icons only when they help users differentiate choices. Icons render only when every option in the complete list provides one; mixed icon data falls back to the text-only row layout.",
          "Create sections only for categories that are meaningful to customers, not merely to break a long list into arbitrary chunks.",
          "When any option supplies subtext, every row uses the same subtext structure and missing values render an em dash. Subtext should disambiguate or add decision-helpful information.",
          "Option labels and the selected trigger label stay on one line and truncate when constrained. Option subtext may wrap to at most two lines.",
          "Use an option action only for a contextual menu about that user-managed option. The fixed ellipsis action appears on hover, keyboard activity, focus, and touch; expanded keeps it visible while its controlled menu is open. Activating it emits dsOptionAction without selecting the option or closing the Select popup.",
          "Use option subtextActions for a compact set of immediate actions that belong to one option. They render beneath only that option's label using the standard supporting-text inset and rhythm, use action or negative semantic color, and emit dsOptionSubtextAction without selecting the option or closing the popup. Unlike descriptive subtext, they do not reserve a blank supporting line on neighboring options.",
          "The optional prefix icon and trailing indicator always use the parent surface's secondary foreground color, including when a selected value promotes the label to primary. When collapseLabel compact icon-only chrome is active, a selected value promotes the prefix icon to primary instead. The default down indicator communicates disclosure; up-down is reserved for compact value steppers such as pagination page size.",
          "While the popup is open, the trigger holds the pressed interaction wash without changing its resting foreground or selected-value treatment.",
          "The shared popup search control follows the Select density, using the same text, icon, and internal spacing as a borderless trigger. Its container uses menu-item padding on every side and owns a 1px bottom divider that becomes a 1.5px bold-brand stroke while search has focus. Search placeholder text is secondary at rest and quaternary while focused because it becomes decorative once the editable field is active.",
          "When search contains text, the shared control shows a rounded icon-only ButtonUnfilled with the CrossCircle icon and no border, sized to remain inset within the current row density. It clears the local term, stays hidden for an empty term, and returns focus to search.",
          "The shared clear footer mirrors the owning density: menu-item padding surrounds a borderless density row, and the Clear label uses the same row and label insets as option text. The clear action never wraps. In multiple mode, the selected summary stays on one line and collapses to its numeric count when the full localized phrase would compete with the clear action. The outer footer owns a 1px top divider.",
          "Use footerActionLabel for one product-owned text action beneath the option list. It replaces the clear affordance, stays aligned with option labels, uses the shared brand text-action treatment with a matching brand underline on hover, emits dsFooterAction, and closes the popup when activated.",
          "An empty filtered list composes the message-only body variant of EmptyState. Keep the default neutral no-results message unless localized product guidance makes the outcome clearer.",
          "Enable searchable for more than roughly 20 options, user-managed listings, large domains such as addresses, or sets users cannot efficiently scan. Local matching includes option labels, subtext, and section headings; the owner resolves remote data before assigning options.",
          "Validation timing belongs to the form owner and may be immediate or deferred until blur or submit; the Select exposes validity and error presentation without imposing that policy.",
          "The error trigger uses a 1.5px bold-negative inset stroke so invalid state remains distinguishable from the normal 1px border without changing control geometry. Set hasBorder to false for chrome where the trigger must remain borderless at rest, when selected or focused, and when invalid; error semantics and supporting copy remain available.",
          "An initially empty option set is not an expected Select use case. The no-results state describes a search with no matches, not a source with no choices.",
          "Use options for a flat list or sections for grouped choices; when sections are present they take precedence.",
          "The background prop describes the actual parent surface and uses the same surface set as ButtonUnfilled."
        ],
        "responsiveBehavior": [
          "Use width fill for form fields and width hug for compact filter bars. Override those defaults only when the owning layout has a clear constraint.",
          "When collapseLabel is set inside a named ds-table container narrower than 900px, the trigger omits its label and chevron and becomes icon-only. A selected value promotes the prefix icon to primary.",
          "The popup matches the trigger minimum width, may grow for content, and clamps to the viewport.",
          "Keep popupAlign at start for ordinary fields and filters. Use end when a control sits against a right layout edge and the popup should grow inward.",
          "Long option collections scroll inside the popup; virtualization and remote search are not part of this component."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Assign options, sections, and multiple-mode array values through JavaScript properties because arrays and objects cannot be represented safely as attributes."
          ],
          "react": [
            "Pass options or sections as wrapper props, set multiple for array values, and handle onDsChange, onDsClear, onDsOpenChange, onDsFooterAction, onDsOptionAction, and onDsOptionSubtextAction."
          ],
          "vue": [
            "Use DsSelect with v-model for the selected value, bind options or sections as properties, and listen for dsChange, dsClear, dsOpenChange, dsFooterAction, dsOptionAction, and dsOptionSubtextAction."
          ],
          "angular": [
            "Import DsSelect and SelectValueAccessor when integrating with Angular Forms; bind options and sections as properties."
          ]
        },
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/Select/Select.stories.ts"
          },
          {
            "label": "Selection patterns",
            "path": "src/docs/SelectionPatterns.mdx"
          }
        ]
      },
      "api": {
        "props": {
          "activeFill": {
            "type": "boolean",
            "required": false
          },
          "allowClear": {
            "type": "boolean",
            "required": false
          },
          "ariaDescribedby": {
            "type": "string | undefined",
            "required": false
          },
          "ariaLabel": {
            "type": "string | null",
            "required": false
          },
          "ariaLabelledby": {
            "type": "string | undefined",
            "required": false
          },
          "background": {
            "type": "SelectBackground | undefined",
            "required": false
          },
          "clearLabel": {
            "type": "string",
            "required": false
          },
          "collapseLabel": {
            "type": "boolean",
            "required": false
          },
          "disabled": {
            "type": "boolean",
            "required": false
          },
          "dot": {
            "type": "boolean",
            "required": false
          },
          "error": {
            "type": "boolean",
            "required": false
          },
          "errorMessage": {
            "type": "string | undefined",
            "required": false
          },
          "footerActionLabel": {
            "type": "string | undefined",
            "required": false
          },
          "hasBorder": {
            "type": "boolean",
            "required": false
          },
          "icon": {
            "type": "string | undefined",
            "required": false
          },
          "indicator": {
            "type": "SelectIndicator",
            "required": false
          },
          "inputId": {
            "type": "string | undefined",
            "required": false
          },
          "isInactive": {
            "type": "boolean",
            "required": false
          },
          "isLoading": {
            "type": "boolean",
            "required": false
          },
          "loadingLabel": {
            "type": "string",
            "required": false
          },
          "multiple": {
            "type": "boolean",
            "required": false
          },
          "name": {
            "type": "string | undefined",
            "required": false
          },
          "noResultsText": {
            "type": "string",
            "required": false
          },
          "open": {
            "type": "boolean",
            "required": false
          },
          "options": {
            "type": "SelectOption[]",
            "required": false
          },
          "placeholder": {
            "type": "string",
            "required": false
          },
          "popupAlign": {
            "type": "SelectPopupAlign",
            "required": false
          },
          "required": {
            "type": "boolean",
            "required": false
          },
          "requiredMessage": {
            "type": "string",
            "required": false
          },
          "searchPlaceholder": {
            "type": "string",
            "required": false
          },
          "searchable": {
            "type": "boolean",
            "required": false
          },
          "sections": {
            "type": "SelectSection[]",
            "required": false
          },
          "selectedLabel": {
            "type": "string",
            "required": false
          },
          "size": {
            "type": "SelectSize",
            "required": false
          },
          "triggerLabel": {
            "type": "string | undefined",
            "required": false
          },
          "triggerLabelPlaceholder": {
            "type": "boolean",
            "required": false
          },
          "value": {
            "type": "SelectValue",
            "required": false
          },
          "width": {
            "type": "SelectWidth",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsChange",
            "detail": "SelectValue"
          },
          {
            "name": "dsClear",
            "detail": "void"
          },
          {
            "name": "dsFooterAction",
            "detail": "void"
          },
          {
            "name": "dsOpenChange",
            "detail": "boolean"
          },
          {
            "name": "dsOptionAction",
            "detail": "SelectOptionActionDetail"
          },
          {
            "name": "dsOptionSubtextAction",
            "detail": "SelectOptionSubtextActionDetail"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-select",
        "react": "DsSelect",
        "vue": "DsSelect",
        "angular": "DsSelect"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens",
        "@ds-mo/icons"
      ],
      "componentDependencies": [
        "badge",
        "button-unfilled",
        "checkbox",
        "empty-state",
        "icon",
        "loader",
        "text",
        "tooltip"
      ]
    },
    {
      "id": "component:ds-shell-app",
      "tag": "ds-shell-app",
      "name": "shell-app",
      "title": "ShellApp",
      "summary": "The standard managed workspace root for authenticated applications, assembling responsive navigation, page chrome, global tools, and stable application-owned content from typed data.",
      "intentStatus": "complete",
      "intent": {
        "audience": "specialized",
        "status": "stable",
        "summary": "The standard managed workspace root for authenticated applications, assembling responsive navigation, page chrome, global tools, and stable application-owned content from typed data.",
        "useWhen": [
          "Building any standard authenticated product or workspace page with CompoMo.",
          "Navigation, page chrome, global tools, responsive behavior, and shell shortcuts must be composed as one application frame without parallel desktop and mobile owners.",
          "Future application templates need the supported base-page composition boundary."
        ],
        "avoidWhen": [
          "Building authentication, onboarding, public, marketing, print, error, or intentionally focused full-screen experiences that require a different layout.",
          "Another ShellApp already exists in the page; applications must render exactly one and must never nest ShellApps.",
          "Building content inside an existing ShellApp; render the page content rather than another shell."
        ],
        "commonlyComposedWith": [
          "component:ds-panel-nav",
          "component:ds-bar-nav",
          "component:ds-panel-tools",
          "component:ds-shell-tools",
          "component:ds-mobile-sheet-nav",
          "component:ds-mobile-header",
          "component:ds-mobile-bar-nav",
          "component:ds-shell-page",
          "component:ds-banner",
          "component:ds-swatch-picker",
          "component:ds-paper-texture"
        ],
        "patterns": [
          "pattern:application-shell",
          "pattern:shell-page"
        ],
        "accessibility": [
          "Supply primary destinations through navigation and secondary route sections through pageChrome so managed ShellApp preserves their correct semantics.",
          "Ensure the default content region contains the page's single main landmark.",
          "Keep the shell-owned routed-content scroller keyboard-focusable while its page landmark retains content semantics. Do not paint a control focus ring around that scroller; it is a layout region, and a page-column outline looks like a selected card.",
          "Keep the managed desktop/tablet and mobile presentations available without conditionally recreating routed or tool content.",
          "Do not override browser keyboard chords when enabling shell shortcuts.",
          "Require Search and Help as the minimum PanelTools actions and provide accessible labels for every tool.",
          "Preserve focus and accessible names across navigation, collapse, overflow, and responsive presentation changes."
        ],
        "states": [
          "Render exactly one ShellApp as the workspace root and never nest it.",
          "Managed composition is the standard. Supply navigation, pageChrome, and tools objects plus named tool-view and default page-content slots.",
          "The application router owns the current route, authorization filtering, Dashboard or Settings context, destination collections, section collections, and localized content labels.",
          "ShellApp renders the lower-level desktop, tablet, and mobile chrome, coordinates layout, gradient alignment, transitions, shortcuts, global surfaces, Inbox state, focus restoration, and mobile-stage visibility.",
          "The application router owns authorization, current URLs, history, and route execution; ShellApp forwards navigation and page intent events without routing.",
          "The application supplies each routed content owner and tool view once. ShellApp changes visibility, inert state, and presentation without recreating those nodes.",
          "The optional banner slot accepts one application-owned ds-banner above the complete shell row. The application owns its open state, orientation for the current shell capacity, action consequences, dismissal persistence, and resolution when several messages compete.",
          "Use composition=slotted only for advanced application architectures that intentionally own all lower-level chrome wiring.",
          "Set gradientPreset to the single resolved global chrome preference: neutral by default, none for solid chrome, or cool, neutral, warm, and fresh for token-based washes.",
          "The application owns gradient preference persistence, cross-tab synchronization, and server or account precedence; ShellApp owns rendering the resolved preset across authenticated routes.",
          "The optional paperTexture property adds a decorative Paper Design texture layer above the gradient or solid chrome frame; its color values are literal shader inputs rather than design tokens.",
          "Dashboard represents day-to-day operational work while Settings represents administrative and configuration work; route state selects the context.",
          "Replace navigation and pageChrome together from one completed route state.",
          "When pageChrome.showBack marks a detail depth, mobile chrome keeps the page heading as its identity and presents only local subsections; peer route tabs remain in desktop BarNav rather than replacing the detail heading.",
          "Managed ShellApp keeps BarNav and ShellPage presentations present and owns page header stickiness and the content scroller.",
          "Route-owned pageChrome independently selects ShellPage contentInset, roomy and compact top seams, scroll compaction, expanded and compact header-divider visibility, and contentSurface; ShellApp forwards them without making page-specific layout or surface decisions.",
          "The application filters unauthorized destinations, sections, and tools before passing them into shell components."
        ],
        "responsiveBehavior": [
          "ShellApp owns the fixed system breakpoints and resolves desktop at 1200px and wider, tablet from 768px through 1199px, and mobile below 768px.",
          "On desktop, PanelNav defaults expanded, permits user collapse or expansion, and respects the locally persisted desktop preference.",
          "On tablet, ShellApp keeps PanelNav permanently collapsed and prevents user expansion without overwriting the desktop preference.",
          "On mobile, ShellApp hides and inerts desktop chrome, uses a solid primary stage, and composes MobileHeader, MobileSheetNav, ShellTools, and the persistent MobileBarNav around the same application-owned content.",
          "Opening MobileSheetNav temporarily overlays the active routed page or global tool; closing it without selecting an area restores that same destination and its nested state. The sheet exposes the router-derived current area only while the routed area owns the mobile stage, so a global tool never leaves an underlying route highlighted.",
          "Selecting Help from the managed mobile sheet activates the configured Help tool and promotes Help to the primary mobile destination instead of forwarding it as route navigation.",
          "Set navigation.showMobileAccount to false when the Settings destination collection already includes account and user preferences.",
          "When a suspended mobile document returns to the foreground, ShellApp refreshes the complete stage paint layer without remounting routed content or tool owners.",
          "When the application enables viewport-fit=cover, ShellApp reserves the shared top safe-area inset once for the complete mobile stage; nested routed, sheet, and tool headers must not add a second top inset.",
          "A slotted Banner remains below the top safe-area inset and above routed, navigation, fullscreen-tool, and mobile global-surface presentations.",
          "Mobile global surfaces conceal and inert the routed workspace without unmounting it, preserving nested routes and scroll state.",
          "Keep PanelNav width, BarNav height, PanelTools chrome, and main-content origin stable except during intentional responsive or collapse transitions.",
          "Paper texture chrome is desktop/tablet-only and follows the fixed viewport phase of the shell chrome; mobile remains a solid primary stage.",
          "Managed page-header capacity follows only the fixed shell breakpoint: roomy on desktop and compact on tablet. Opening PanelTools does not compact or constrain BarTitle.",
          "The bottom bar remains visible at all route and tool depths in the foundation release."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Assign navigation, pageChrome, and tools as JavaScript properties on the managed ShellApp.",
            "Assign paperTexture as a JavaScript property when enabling the optional decorative layer.",
            "Stamp route-derived nav-style before components connect when deterministic first paint is required."
          ],
          "react": [
            "Use the generated ShellApp wrapper, structured object props, named tool-view slots, and stable routed children.",
            "Pass paperTexture as a structured property when the shell needs the optional texture layer.",
            "Resolve all shell inputs from one router state before rendering the composition."
          ],
          "angular": [
            "Use the generated standalone ShellApp adapter, bind structured object props, and preserve named tool-view slots.",
            "Bind paperTexture as a property so nested shader parameters are preserved.",
            "Bind complex inputs as properties and update navigation inputs atomically from one resolved router state.",
            "Bind both nav-style attributes and properties when deterministic first paint is required."
          ]
        },
        "references": [
          {
            "label": "Component guide",
            "path": "src/wc/components/ShellApp/ShellApp.mdx"
          },
          {
            "label": "Executable Storybook composition",
            "path": "src/wc/components/ShellApp/ShellApp.stories.ts"
          },
          {
            "label": "Framework integration",
            "path": "docs/framework-integration.md"
          },
          {
            "label": "Application shell contract",
            "path": "agent/patterns/application-shell/pattern.agent.json"
          }
        ]
      },
      "api": {
        "props": {
          "composition": {
            "type": "ShellAppComposition",
            "required": false
          },
          "gradientPreset": {
            "type": "ShellGradientPreset",
            "required": false
          },
          "mobileDestination": {
            "type": "MobileDestination",
            "required": false
          },
          "mobileSheetNavOpen": {
            "type": "boolean",
            "required": false
          },
          "navStyle": {
            "type": "NavChromeStyle",
            "required": false
          },
          "navigation": {
            "type": "ShellNavigationConfig",
            "required": false
          },
          "pageChrome": {
            "type": "ShellPageChromeConfig",
            "required": false
          },
          "paperTexture": {
            "type": "PaperTextureConfig",
            "required": false
          },
          "shortcutsEnabled": {
            "type": "boolean",
            "required": false
          },
          "tools": {
            "type": "ShellToolsConfig",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsBreadcrumbSelect",
            "detail": "BreadcrumbSelectDetail"
          },
          {
            "name": "dsBrowseContextChange",
            "detail": "NavChromeStyle"
          },
          {
            "name": "dsHeaderAction",
            "detail": "{ tool: PanelToolsToolId; id: string }"
          },
          {
            "name": "dsHeaderBack",
            "detail": "{ tool: PanelToolsToolId }"
          },
          {
            "name": "dsNavFooterAction",
            "detail": "void"
          },
          {
            "name": "dsNavSelect",
            "detail": "string"
          },
          {
            "name": "dsNavUserAction",
            "detail": "PanelNavUserActionDetail"
          },
          {
            "name": "dsPageAction",
            "detail": "string"
          },
          {
            "name": "dsPageBack",
            "detail": "MouseEvent"
          },
          {
            "name": "dsPresentationChange",
            "detail": "{ presentation: 'drawer' | 'fullscreen' }"
          },
          {
            "name": "dsResponsiveModeChange",
            "detail": "{ mode: ShellResponsiveMode }"
          },
          {
            "name": "dsSubsectionChange",
            "detail": "string"
          },
          {
            "name": "dsTabChange",
            "detail": "string"
          },
          {
            "name": "dsToolChange",
            "detail": "{ id: PanelToolsToolId; selected: boolean }"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-shell-app",
        "react": "DsShellApp",
        "vue": "DsShellApp",
        "angular": "DsShellApp"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "bar-nav",
        "bar-title",
        "button-unfilled",
        "mobile-bar-nav",
        "mobile-header",
        "mobile-sheet-nav",
        "panel-nav",
        "paper-texture",
        "shell-page",
        "shell-tools",
        "tooltip"
      ]
    },
    {
      "id": "component:ds-shell-page",
      "tag": "ds-shell-page",
      "name": "shell-page",
      "title": "ShellPage",
      "summary": "The standard routed-page boundary inside ShellApp, owning sticky BarTitle or BarWorkflow placement, application-supplied BarTitle capacity, optional scroll compaction, and independent page-content inset and canvas surface without creating a nested scroll container.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "The standard routed-page boundary inside ShellApp, owning sticky BarTitle or BarWorkflow placement, application-supplied BarTitle capacity, optional scroll compaction, and independent page-content inset and canvas surface without creating a nested scroll container.",
        "useWhen": [
          "Rendering a standard routed page inside ShellApp's default content region.",
          "BarTitle should expand at a roomy page top, compact after scroll, or use constrained action layout when the application shell reports reduced capacity.",
          "BarWorkflow needs sticky page-level placement while remaining compact.",
          "Pages need consistent content gutters with an explicit full-bleed option.",
          "The page canvas surrounding routed content must use either the primary or secondary application surface."
        ],
        "avoidWhen": [
          "Building authentication, onboarding, public, modal, drawer, or intentionally focused fullscreen layouts outside the standard ShellApp page region.",
          "Another ShellPage already owns the routed page; never nest ShellPages.",
          "A bounded card or pane needs its own header rather than a page-level main landmark."
        ],
        "alternatives": [
          {
            "when": "The composition is a persistent application-wide workspace frame.",
            "component": "component:ds-shell-app",
            "reason": "ShellApp owns global navigation, tools, and the content scroll region; ShellPage belongs inside it."
          },
          {
            "when": "Only static page title chrome is required without sticky or responsive orchestration.",
            "component": "component:ds-bar-title",
            "reason": "BarTitle can be used standalone with an explicit variant."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-shell-app",
          "component:ds-bar-title",
          "component:ds-bar-workflow",
          "component:ds-tab-group"
        ],
        "patterns": [
          "pattern:shell-page"
        ],
        "accessibility": [
          "ShellPage exposes the routed page as the main landmark; render exactly one active ShellPage inside ShellApp.",
          "Provide one BarTitle or BarWorkflow through the desktop header slot and one MobileHeader through mobile-header when the page participates in the mobile shell.",
          "Keep loading, empty, validation, error, progress, success, and failure communication in the default product-content slot.",
          "Responsive variant changes preserve the same heading, controls, accessible names, and keyboard focus targets."
        ],
        "states": [
          "headerCapacity=roomy, compact, or constrained is supplied before paint by the owning application shell and describes the page-header space available after viewport and shell-chrome policy are applied.",
          "headerPresentation=auto selects the matching header variant from headerCapacity and scroll position.",
          "expanded, compact, and constrained are explicit overrides for exceptional layouts and deterministic examples.",
          "contentInset=default supplies standard page gutters; none permits maps, canvases, and other full-bleed content.",
          "contentInsetBlockStart=none removes only the gutter adjacent to the page header while retaining the responsive inline and bottom gutters.",
          "contentInsetBlockStartSize can provide an exact roomy top seam, while compactContentInsetBlockStartSize independently defines the compact and constrained seam. ShellPage exposes their resolved sticky-header offset through --ds-shell-page-content-block-start-offset for viewport-fitted descendants.",
          "scrollCompaction=false keeps a roomy header expanded and pinned during page scrolling; capacity changes still select compact or constrained variants.",
          "contentSurface=primary keeps the standard page canvas; secondary paints both the inset gutter and the canvas beneath routed content. Desktop and tablet BarTitle chrome matches that canvas in expanded, compact, and constrained presentations; MobileHeader remains primary.",
          "contentInset and contentSurface are independent: either surface supports standard responsive gutters or a full-bleed page-owned layout.",
          "The header slot accepts one desktop BarTitle or BarWorkflow; mobile-header accepts the corresponding MobileHeader presentation. The default slot owns router output and all page product content."
        ],
        "responsiveBehavior": [
          "The owning application shell resolves viewport and persistent-chrome state into the explicit headerCapacity prop; ShellPage never guesses the cause of reduced width from its own rendered size.",
          "Roomy capacity expands at the top and compacts after scroll; compact capacity stays compact; constrained capacity uses the constrained action layout.",
          "Pages with scrollCompaction=false keep roomy headers expanded while still responding to compact or constrained capacity from tools and breakpoints.",
          "A ShellPage-managed BarTitle remains concealed until headerCapacity is available and its rendered variant matches the resolved presentation, preventing a default-variant flash during route activation.",
          "responsiveMode=mobile hides and inerts the desktop header, exposes mobile-header, and disables desktop scroll-compaction geometry.",
          "Update headerCapacity synchronously with shell layout state so opening tools or crossing application breakpoints cannot briefly render the wrong presentation.",
          "The default content inset is balanced on every side: 32px in desktop mode and 16px in tablet and mobile modes.",
          "contentInsetBlockStart can independently remove the top gutter for table and canvas pages that should meet the sticky header; exact roomy and compact block-start sizes support pages whose seam changes with header capacity.",
          "The selected content surface persists unchanged across desktop, tablet, and mobile modes.",
          "On a secondary desktop or tablet page, BarTitle matches the page canvas across capacity and scroll-driven variant changes; the separate mobile-header presentation remains primary.",
          "The flow-preservation spacer follows contentSurface so compacting a secondary page cannot expose a primary strip before its content.",
          "On roomy pages, the expanded header scrolls upward until its title and action row reaches the compact row position, while its bottom divider progressively extends from the expanded inset to edge-to-edge; it then snaps variants without moving that shared visual anchor.",
          "Scroll compaction preserves the expanded page flow offset so content never jumps beneath the sticky header.",
          "ShellPage relies on ShellApp's content scroller and never introduces nested scrolling.",
          "BarWorkflow remains compact and is not assigned BarTitle's capacity or scroll variants."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Import ShellPage with BarTitle or BarWorkflow in slot=header and MobileHeader in slot=mobile-header, then render route content as default children.",
            "Do not set BarTitle.variant while ShellPage owns headerPresentation."
          ],
          "react": [
            "Render the desktop header with slot=header and DsMobileHeader with slot=mobile-header inside DsShellPage.",
            "Use contentInset none only for deliberately full-bleed page products, and choose contentSurface independently from the page's spacing model."
          ],
          "angular": [
            "Import the generated standalone DsShellPage adapter with the desktop header and DsMobileHeader, preserve both header slots, and place router-outlet in the default slot.",
            "Do not add another overflow auto wrapper around the routed page."
          ]
        },
        "references": [
          {
            "label": "Page-family and responsive examples",
            "path": "src/wc/components/ShellPage/ShellPage.stories.ts"
          },
          {
            "label": "Cross-browser geometry and interaction coverage",
            "path": "tests/e2e/bar-title.spec.ts"
          },
          {
            "label": "Reusable framework composition",
            "path": "agent/patterns/shell-page/pattern.agent.json"
          }
        ]
      },
      "api": {
        "props": {
          "compactContentInsetBlockStartSize": {
            "type": "string",
            "required": false
          },
          "contentInset": {
            "type": "ShellPageContentInset",
            "required": false
          },
          "contentInsetBlockStart": {
            "type": "ShellPageContentInset",
            "required": false
          },
          "contentInsetBlockStartSize": {
            "type": "string",
            "required": false
          },
          "contentSurface": {
            "type": "ShellPageContentSurface",
            "required": false
          },
          "headerCapacity": {
            "type": "ShellPageCapacity",
            "required": false
          },
          "headerPresentation": {
            "type": "ShellPageHeaderPresentation",
            "required": false
          },
          "responsiveMode": {
            "type": "ShellResponsiveMode",
            "required": false
          },
          "scrollCompaction": {
            "type": "boolean",
            "required": false
          }
        },
        "events": [],
        "slots": []
      },
      "exports": {
        "customElement": "ds-shell-page",
        "react": "DsShellPage",
        "vue": "DsShellPage",
        "angular": "DsShellPage"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": []
    },
    {
      "id": "component:ds-shell-tools",
      "tag": "ds-shell-tools",
      "name": "shell-tools",
      "title": "ShellTools",
      "summary": "Responsive persistent host for explicitly defined global tools, adapting PanelTools desktop/tablet chrome to configured mobile destinations and groups.",
      "intentStatus": "complete",
      "intent": {
        "audience": "specialized",
        "status": "stable",
        "summary": "Responsive persistent host for explicitly defined global tools, adapting PanelTools desktop/tablet chrome to configured mobile destinations and groups.",
        "useWhen": [
          "A ShellApp must preserve the same product-owned global tool views across desktop, tablet, and mobile."
        ],
        "avoidWhen": [
          "The tools exist only in desktop and tablet chrome; PanelTools remains supported for that case.",
          "The content is a routed primary application area."
        ],
        "alternatives": [
          {
            "when": "Only legacy rail and drawer behavior is required.",
            "component": "component:ds-panel-tools",
            "reason": "PanelTools is the direct desktop and tablet rail-and-drawer primitive."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-shell-app",
          "component:ds-panel-tool-header",
          "component:ds-mobile-header",
          "component:ds-tab-group",
          "component:ds-mobile-bar-nav"
        ],
        "patterns": [
          "pattern:application-shell"
        ],
        "accessibility": [
          "Only the active mobile tool view participates in focus or the accessibility tree.",
          "Header Back and application-owned header actions preserve the PanelTools event contract.",
          "Mobile Inbox uses a named label-only TabGroup for Stacks and Activity; Messages remains a direct mobile destination."
        ],
        "states": [
          "The application owns open and activeTool and replaces headers when tool depth changes.",
          "Items with mobileDestination inbox map to one mobile Inbox destination while retaining the actual active tool id; the canonical recipe groups Stacks and Activity, while Messages remains a separate destination.",
          "Stable tool ids own named slots; label, order, rail placement, shortcut, and mobile destination are explicit item data.",
          "Switching responsive mode must not recreate application-owned slotted product elements."
        ],
        "responsiveBehavior": [
          "Desktop and tablet compose PanelTools-compatible rail and drawer chrome.",
          "Mobile renders one centered MobileHeader for every tool; Stacks and Activity use the large segmented Inbox control, while Messages remains a direct tool destination."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Assign items and headers as JavaScript properties and place each persistent owner in its named *-view slot."
          ],
          "react": [
            "Keep stable keyed product owner elements in the generated wrapper's named slots."
          ],
          "angular": [
            "Bind structured items and headers as properties and keep each tool owner mounted under a named *-view slot."
          ]
        },
        "references": [
          {
            "label": "Storybook",
            "path": "src/wc/components/ShellTools/ShellTools.stories.ts"
          },
          {
            "label": "PanelTools contract",
            "path": "src/wc/components/PanelTools/PanelTools.agent.json"
          }
        ]
      },
      "api": {
        "props": {
          "activeTool": {
            "type": "PanelToolsToolId | ''",
            "required": false
          },
          "fullscreenHeaderMode": {
            "type": "'shared' | 'split'",
            "required": false
          },
          "headers": {
            "type": "PanelToolsHeaders",
            "required": false
          },
          "inboxLabel": {
            "type": "string",
            "required": false
          },
          "inboxNavigationLabel": {
            "type": "string",
            "required": false
          },
          "items": {
            "type": "PanelToolsItem[]",
            "required": false
          },
          "open": {
            "type": "boolean",
            "required": false
          },
          "presentation": {
            "type": "'drawer' | 'fullscreen'",
            "required": false
          },
          "responsiveMode": {
            "type": "ShellResponsiveMode",
            "required": false
          },
          "storageKey": {
            "type": "string",
            "required": false
          },
          "toolShortcutsLabel": {
            "type": "string",
            "required": false
          },
          "toolsLabel": {
            "type": "string",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsHeaderAction",
            "detail": "{\n    tool: PanelToolsToolId;\n    id: string;\n  }"
          },
          {
            "name": "dsHeaderBack",
            "detail": "{\n    tool: PanelToolsToolId;\n  }"
          },
          {
            "name": "dsPresentationChange",
            "detail": "{\n    presentation: 'drawer' | 'fullscreen';\n  }"
          },
          {
            "name": "dsToolChange",
            "detail": "{\n    id: PanelToolsToolId;\n    selected: boolean;\n  }"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-shell-tools",
        "react": "DsShellTools",
        "vue": "DsShellTools",
        "angular": "DsShellTools"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "button-unfilled",
        "mobile-header",
        "panel-tools",
        "tooltip"
      ]
    },
    {
      "id": "component:ds-skeleton",
      "tag": "ds-skeleton",
      "name": "skeleton",
      "title": "Skeleton",
      "summary": "Aria-hidden atomic placeholder for preserving expected text, icon, or control geometry while structured content is pending.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Aria-hidden atomic placeholder for preserving expected text, icon, or control geometry while structured content is pending.",
        "useWhen": [
          "A pending content region has a predictable structure whose geometry should remain stable while data loads.",
          "Text, icon, and control placeholder atoms can be composed to approximate the final hierarchy and arrangement.",
          "The owning region can expose busy state and contextual loading status independently."
        ],
        "avoidWhen": [
          "An action or operation is progressing without predictable content structure; use Loader.",
          "The final layout is unknown or likely to differ substantially from the placeholder composition.",
          "A complete card, list, or table preset is expected from one Skeleton; compose atomic shapes in the owner.",
          "The shimmer would be used as decoration after content is available."
        ],
        "alternatives": [
          {
            "when": "An indeterminate action or operation is in progress.",
            "component": "component:ds-loader",
            "reason": "Loader owns operation-level indeterminate progress."
          },
          {
            "when": "Real text content is already available.",
            "component": "component:ds-text",
            "reason": "Text should replace its placeholder as soon as content is ready."
          },
          {
            "when": "A real system glyph is available.",
            "component": "component:ds-icon",
            "reason": "Icon renders actual glyph content rather than loading geometry."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-card-setting",
          "component:ds-text",
          "component:ds-icon"
        ],
        "accessibility": [
          "Skeleton remains hidden from assistive technology because its shapes do not represent content.",
          "The owning content region exposes busy state and a contextual loading status when an announcement is needed.",
          "Do not announce every placeholder atom or duplicate status text across a composed skeleton layout.",
          "The owner preserves focus and meaningful reading order when replacing placeholders with real content."
        ],
        "states": [
          "Text, icon, and control variants are atomic metric canvases aligned to their corresponding design-system recipes. Text bars occupy 75% of their line-height canvas, while icon shapes occupy 75% of their square canvas; both remain centered with a proportional 12.5% inset per applicable edge. Control atoms inherit the selected control density's default radius.",
          "Compose approximate line count, hierarchy, widths, and control placement without simulating actual values.",
          "Shimmer is on by default and may be disabled for a static placeholder. Reduced motion always produces the static final shape.",
          "Rounded is an optional visual treatment for icon and control atoms rather than a semantic state.",
          "Omitted background is for primary and secondary surfaces. Explicit faint documents a faint parent while using the same standard base and shimmer tokens; other contexts use matching surface tokens.",
          "The owner decides whether to delay initial visibility and when to replace the complete composition."
        ],
        "responsiveBehavior": [
          "The owning layout changes placeholder count, width, visibility, and arrangement to match its real responsive content.",
          "Skeleton does not infer breakpoints or rearrange sibling atoms."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Compose one element per placeholder atom and set aria-busy or loading status on the containing content region."
          ],
          "react": [
            "Render Skeleton and real content from one loading branch so placeholder geometry and region busy state settle together."
          ],
          "angular": [
            "Render Skeleton and real content from one loading branch so placeholder geometry and region busy state settle together."
          ]
        },
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/Skeleton/Skeleton.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "background": {
            "type": "SkeletonBackground | undefined",
            "required": false
          },
          "controlSize": {
            "type": "ControlSize",
            "required": false
          },
          "iconSize": {
            "type": "IconSize",
            "required": false
          },
          "rounded": {
            "type": "boolean",
            "required": false
          },
          "shimmer": {
            "type": "boolean",
            "required": false
          },
          "textVariant": {
            "type": "TextVariant",
            "required": false
          },
          "variant": {
            "type": "SkeletonVariant",
            "required": false
          },
          "width": {
            "type": "string | number | undefined",
            "required": false
          }
        },
        "events": [],
        "slots": []
      },
      "exports": {
        "customElement": "ds-skeleton",
        "react": "DsSkeleton",
        "vue": "DsSkeleton",
        "angular": "DsSkeleton"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": []
    },
    {
      "id": "component:ds-slider",
      "tag": "ds-slider",
      "name": "slider",
      "title": "Slider",
      "summary": "Form-associated single or two-thumb range input with native slider semantics, pointer dragging, keyboard operation, formatting, density, and orientation controls.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Form-associated single or two-thumb range input with native slider semantics, pointer dragging, keyboard operation, formatting, density, and orientation controls.",
        "useWhen": [
          "A person should choose or tune an approximate numeric value within known bounds.",
          "A bounded minimum and maximum range needs two independently focusable thumbs.",
          "A value benefits from direct manipulation, immediate preview, and native form submission."
        ],
        "avoidWhen": [
          "The exact numeric value is more important than direct spatial adjustment.",
          "The choices are categorical rather than ordered numeric values.",
          "The value is progress, measurement, or read-only status rather than user input."
        ],
        "alternatives": [
          {
            "when": "People must enter or verify a precise numeric value.",
            "component": "component:ds-input",
            "reason": "A typed field supports exact entry and review more efficiently than spatial adjustment."
          },
          {
            "when": "The available values are a short finite set with meaningful labels.",
            "component": "component:ds-radio",
            "reason": "Visible named choices communicate categorical meaning more clearly."
          },
          {
            "when": "The setting is binary and applies immediately.",
            "component": "component:ds-switch",
            "reason": "Switch communicates an immediate on/off state without implying intermediate values."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-text",
          "component:ds-input"
        ],
        "accessibility": [
          "Each thumb contains a native range input and must have an accessible name; a visible label names a single thumb, while startLabel and endLabel distinguish a two-thumb range.",
          "Arrow keys adjust one step, Home and End reach the allowed bounds, and browser-supported Page Up and Page Down make larger changes.",
          "Every range thumb remains in a constant tab order and exposes dynamic minimum and maximum values when the other thumb constrains it.",
          "Use valueText for one authored description or valueTexts for per-thumb range descriptions when numeric values are not understandable on their own, such as named levels, dates, durations, or units.",
          "Read-only sliders remain focusable and submittable; inactive or disabled sliders leave the tab order and form submission."
        ],
        "states": [
          "The label, slider control, value display, and supporting content follow the shared 4px vertical field flow.",
          "value is mutable: user pointer, keyboard, or assistive-technology input updates it and emits dsChange continuously.",
          "dsCommit emits once a pointer interaction completes or the native range input commits a keyboard or assistive-technology change.",
          "Assign a two-number array through the JavaScript value property to create a range; values are ordered, clamped, stepped, and prevented from crossing.",
          "minStepsBetweenValues reserves a minimum stepped distance between range thumbs.",
          "The initial normalized value is the native form-reset baseline and range values submit as repeated entries under the same name.",
          "Focused, filled, dirty, touched, dragging, valid, disabled, read-only, and orientation data hooks expose interaction state without changing the value contract."
        ],
        "responsiveBehavior": [
          "The visible label uses the same primary emphasized text-body-small recipe as Field at every density; the value uses the same primary metric without emphasis.",
          "Horizontal Slider fills the width supplied by its parent; the parent chooses an appropriate readable track length.",
          "Vertical Slider owns a token-based default length that may be overridden with --ds-slider-vertical-length in layout-specific compositions.",
          "Use md in ordinary forms and sm or xs only when the surrounding control density uses the same recipe.",
          "Track thickness scales with density: 8px at md, 6px at sm, and 4px at xs. The unfilled track is transparent with a tertiary-foreground inset outline, the filled range is brand, and the square thumb uses a 2px radius with a 1.5px brand inset ring.",
          "Horizontal value direction is left-to-right; the design system does not author RTL-specific component behavior."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Assign range arrays and formatOptions through JavaScript properties, not string attributes.",
            "Listen for dsChange during adjustment and dsCommit for expensive work that should run after the interaction settles."
          ],
          "react": [
            "Use DsSlider with a number or two-number value array and handle onDsChange and onDsCommit custom events."
          ],
          "angular": [
            "Use DsSlider with property binding for range arrays; the generated number value accessor is appropriate only for a single numeric value."
          ]
        },
        "references": [
          {
            "label": "Storybook design review",
            "path": "src/wc/components/Slider/Slider.stories.ts"
          },
          {
            "label": "Cross-browser form and interaction coverage",
            "path": "tests/e2e/forms.spec.ts"
          }
        ]
      },
      "api": {
        "props": {
          "ariaDescribedby": {
            "type": "string | undefined",
            "required": false
          },
          "ariaLabel": {
            "type": "string | null",
            "required": false
          },
          "ariaLabelledby": {
            "type": "string | undefined",
            "required": false
          },
          "disabled": {
            "type": "boolean",
            "required": false
          },
          "endLabel": {
            "type": "string",
            "required": false
          },
          "form": {
            "type": "string | undefined",
            "required": false
          },
          "formatOptions": {
            "type": "Intl.NumberFormatOptions | undefined",
            "required": false
          },
          "inputId": {
            "type": "string | undefined",
            "required": false
          },
          "isInactive": {
            "type": "boolean",
            "required": false
          },
          "label": {
            "type": "string | undefined",
            "required": false
          },
          "locale": {
            "type": "string | undefined",
            "required": false
          },
          "max": {
            "type": "number",
            "required": false
          },
          "min": {
            "type": "number",
            "required": false
          },
          "minStepsBetweenValues": {
            "type": "number",
            "required": false
          },
          "name": {
            "type": "string | undefined",
            "required": false
          },
          "orientation": {
            "type": "SliderOrientation",
            "required": false
          },
          "rangeSeparator": {
            "type": "string",
            "required": false
          },
          "readOnly": {
            "type": "boolean",
            "required": false
          },
          "showValue": {
            "type": "boolean",
            "required": false
          },
          "size": {
            "type": "SliderSize",
            "required": false
          },
          "startLabel": {
            "type": "string",
            "required": false
          },
          "step": {
            "type": "number",
            "required": false
          },
          "thumbAlignment": {
            "type": "SliderThumbAlignment",
            "required": false
          },
          "value": {
            "type": "SliderValue",
            "required": false
          },
          "valuePrefix": {
            "type": "string",
            "required": false
          },
          "valueSuffix": {
            "type": "string",
            "required": false
          },
          "valueText": {
            "type": "string | undefined",
            "required": false
          },
          "valueTexts": {
            "type": "string[]",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsChange",
            "detail": "SliderValue"
          },
          {
            "name": "dsCommit",
            "detail": "SliderValue"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-slider",
        "react": "DsSlider",
        "vue": "DsSlider",
        "angular": "DsSlider"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "text"
      ]
    },
    {
      "id": "component:ds-swatch-picker",
      "tag": "ds-swatch-picker",
      "name": "swatch-picker",
      "title": "SwatchPicker",
      "summary": "Compact one-of-many picker for curated flat-color, gradient, or visually absent presets with optional section separators and roving radio-group interaction.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Compact one-of-many picker for curated flat-color, gradient, or visually absent presets with optional section separators and roving radio-group interaction.",
        "useWhen": [
          "Users choose exactly one visual preset from a small curated set.",
          "Options are best compared through compact flat-color or gradient previews.",
          "A settings surface or richer menu needs an immediately applied visual preference."
        ],
        "avoidWhen": [
          "Users need an unrestricted spectrum, numeric channels, opacity editing, or custom CSS gradient construction.",
          "Text labels are the primary distinction between choices; use Radio instead.",
          "The choice is a submitted form value with validation or a long compact list; use Radio or Select.",
          "Color or gradient is the only indication of status, meaning, or required action."
        ],
        "alternatives": [
          {
            "when": "The user needs an arbitrary color rather than a curated preset.",
            "component": "component:ds-input",
            "reason": "SwatchPicker intentionally does not provide spectrum, channel, or free-form value editing."
          },
          {
            "when": "Visible text labels are more important than visual previews.",
            "component": "component:ds-radio",
            "reason": "Radio presents explicit one-of-many option labels and native form behavior."
          },
          {
            "when": "The option set is long or must remain compact.",
            "component": "component:ds-select",
            "reason": "Select scales a larger named choice set into an anchored listbox."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-menu",
          "component:ds-shell-app"
        ],
        "accessibility": [
          "Provide a localized groupLabel describing the complete choice.",
          "Give every option a meaningful label because its visual preview is never its accessible name.",
          "The options form one radio group with one Tab stop; Arrow keys wrap across active options while Home and End select the boundaries.",
          "Inactive options remain named and disabled, and keyboard movement skips them."
        ],
        "states": [
          "value is the selected option value and updates when the user chooses an active option.",
          "options provides one flat list; sections takes precedence and adds visual separators while preserving one radio group.",
          "A preview may use a token-based backgroundColor, a CSS gradient backgroundImage, and an optional opacity from zero through one.",
          "The parent owns persistence and application of the selected value; SwatchPicker owns only choice interaction and dsChange."
        ],
        "responsiveBehavior": [
          "Options wrap within the width supplied by the parent while retaining compact fixed swatch geometry.",
          "Keep the set small enough for direct visual comparison; switch to a named list when wrapping harms comprehension."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Assign options or sections as JavaScript properties, bind value, and listen for dsChange."
          ],
          "react": [
            "Use DsSwatchPicker, pass option arrays as props, and handle onDsChange."
          ],
          "angular": [
            "Use property bindings for options or sections and handle dsChange to update application state."
          ]
        },
        "references": [
          {
            "label": "Executable stories",
            "path": "src/wc/components/SwatchPicker/SwatchPicker.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "groupLabel": {
            "type": "string",
            "required": false
          },
          "options": {
            "type": "SwatchPickerOption[]",
            "required": false
          },
          "sections": {
            "type": "SwatchPickerSection[]",
            "required": false
          },
          "value": {
            "type": "string",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsChange",
            "detail": "string"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-swatch-picker",
        "react": "DsSwatchPicker",
        "vue": "DsSwatchPicker",
        "angular": "DsSwatchPicker"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": []
    },
    {
      "id": "component:ds-switch",
      "tag": "ds-switch",
      "name": "switch",
      "title": "Switch",
      "summary": "Compact on/off setting control for changes that take effect immediately, with four sizes and form-associated behavior.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Compact on/off setting control for changes that take effect immediately, with four sizes and form-associated behavior.",
        "useWhen": [
          "A binary setting takes effect immediately when the user turns it on or off.",
          "A settings, form, or menu row needs a compact on/off control.",
          "The checked value needs native form submission, required validation, reset, or external form association."
        ],
        "avoidWhen": [
          "The user is providing consent, acknowledging a statement, or selecting multiple independent choices.",
          "The user must choose one option from a mutually exclusive set.",
          "The interaction triggers a one-time action instead of maintaining an on/off state."
        ],
        "alternatives": [
          {
            "when": "The interaction represents consent, acknowledgment, or multi-select choices.",
            "component": "component:ds-checkbox",
            "reason": "Checkbox semantics communicate selection or agreement rather than an immediately applied setting."
          },
          {
            "when": "The user must choose one option from a mutually exclusive group.",
            "component": "component:ds-radio",
            "reason": "Radio communicates one-of-many selection."
          },
          {
            "when": "The control triggers a one-time command or submission.",
            "component": "component:ds-button-filled",
            "reason": "Button semantics communicate an action rather than persistent state."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-field",
          "component:ds-menu",
          "component:ds-text"
        ],
        "accessibility": [
          "Every standalone switch requires an accessible name from a native label, aria-label, or aria-labelledby.",
          "Checked state is exposed through switch semantics and thumb position, so state does not rely on color alone.",
          "Read-only switches remain focusable and submitted but cannot change; inactive or disabled switches leave the tab order and are omitted from form submission.",
          "Required and invalid state are exposed explicitly on the switch role; focused, filled, dirty, touched, valid, and invalid data hooks support form diagnostics without imposing visual validation timing.",
          "Use presentation mode only when a composite owner such as a menuitemcheckbox provides the interaction and accessible state."
        ],
        "states": [
          "Activation updates checked immediately and emits dsChange with the new boolean value.",
          "The initial checked value is the form-reset baseline; unchecked switches submit nothing unless uncheckedValue is provided.",
          "Sizes are lg 40×24 with a 16px thumb and 4px body inset, md 32×20 with a 12px thumb and 4px inset, sm 24×16 with a 10px thumb and 3px inset, and xs 20×12 with an 8px thumb and 2px inset.",
          "Unchecked uses a transparent track with a density-specific tertiary-foreground inset stroke and a solid tertiary-foreground thumb without a border. Checked uses a brand track and primary-background thumb with no strokes.",
          "Presentation mode removes switch semantics, focus, interaction, and form submission while retaining the checked visual."
        ],
        "responsiveBehavior": [
          "Choose size from the density of the containing row; do not enlarge the switch to the full control height.",
          "Keep the switch from shrinking when adjacent labels wrap.",
          "Thumb movement is left-to-right; the design system does not author RTL-specific component behavior."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Set checked as a property for application state updates and listen for dsChange.",
            "Use the form attribute to associate a switch rendered outside its owning form."
          ],
          "react": [
            "Use DsSwitch and handle onDsChange; checked is mutable and updates immediately when the component is activated."
          ],
          "vue": [
            "Use DsSwitch with v-model for checked, and listen for dsChange."
          ],
          "angular": [
            "Use DsSwitch with checked binding and dsChange, or the generated boolean value accessor in Angular forms."
          ]
        },
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/Switch/Switch.stories.ts"
          },
          {
            "label": "Cross-browser form and accessibility coverage",
            "path": "tests/e2e/forms.spec.ts"
          }
        ]
      },
      "api": {
        "props": {
          "checked": {
            "type": "boolean",
            "required": false
          },
          "disabled": {
            "type": "boolean",
            "required": false
          },
          "form": {
            "type": "string | undefined",
            "required": false
          },
          "isInactive": {
            "type": "boolean",
            "required": false
          },
          "name": {
            "type": "string | undefined",
            "required": false
          },
          "presentation": {
            "type": "boolean",
            "required": false
          },
          "readOnly": {
            "type": "boolean",
            "required": false
          },
          "required": {
            "type": "boolean",
            "required": false
          },
          "requiredMessage": {
            "type": "string",
            "required": false
          },
          "size": {
            "type": "SwitchSize",
            "required": false
          },
          "uncheckedValue": {
            "type": "string | undefined",
            "required": false
          },
          "value": {
            "type": "string",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsChange",
            "detail": "boolean"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-switch",
        "react": "DsSwitch",
        "vue": "DsSwitch",
        "angular": "DsSwitch"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": []
    },
    {
      "id": "component:ds-tab-group",
      "tag": "ds-tab-group",
      "name": "tab-group",
      "title": "TabGroup",
      "summary": "Horizontal single-selection tabs for switching adjacent local views or view modes, with uniform label, icon, or icon-label presentation and surface-aware selection.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Horizontal single-selection tabs for switching adjacent local views or view modes, with uniform label, icon, or icon-label presentation and surface-aware selection.",
        "useWhen": [
          "Adjacent local content views or panels fit in a horizontal tab row.",
          "A compact horizontal selector switches between equivalent local view modes such as list and grid.",
          "A tab set needs concise labels, icons, or icon-label content with optional supplemental notification dots."
        ],
        "avoidWhen": [
          "The choices navigate application routes; use PanelNav or BarNav instead.",
          "The choices belong in a vertical panel or card side rail; use PanelSubNav instead.",
          "The choices are temporary commands or contextual options; use Menu instead.",
          "The row requires mixed content variants, subtext, nested levels, or multi-row wrapping.",
          "No enabled tab can remain selected while enabled choices exist."
        ],
        "alternatives": [
          {
            "when": "Local views need persistent vertical side-rail navigation.",
            "component": "component:ds-panel-sub-nav",
            "reason": "PanelSubNav owns the vertical local-view keyboard and selection model."
          },
          {
            "when": "The choices are primary application destinations.",
            "component": "component:ds-panel-nav",
            "reason": "PanelNav owns application route selection in shell navigation."
          },
          {
            "when": "The choices are secondary application route sections.",
            "component": "component:ds-bar-nav",
            "reason": "BarNav owns route sections, overflow, and shell coordination."
          },
          {
            "when": "The choices are transient actions or options.",
            "component": "component:ds-menu",
            "reason": "Menu owns temporary popup collections rather than persistent local views."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-text",
          "component:ds-icon"
        ],
        "accessibility": [
          "Provide an accessible tab-list name with aria-label or aria-labelledby.",
          "Keep exactly one valid enabled tab selected whenever enabled tabs exist, and keep its controlled view synchronized.",
          "When tabs control tabpanels, give each tab the id of its panel and label each panel from its tab.",
          "ArrowLeft and ArrowRight move and activate selection; Home and End select the first and last available tabs.",
          "Icon-only tabs retain their required text label as the accessible name even though the label is not visible.",
          "Notification dots are supplemental status only and must never replace a label, state, or accessible name.",
          "Inactive tabs remain visible but cannot be focused or selected."
        ],
        "states": [
          "The parent owns the canonical selected value and adjacent view visibility, and should update both from dsChange.",
          "A missing, empty, inactive, or unknown selected value is invalid when enabled tabs exist; the component does not choose a fallback selection.",
          "Selection is singular and follows keyboard focus.",
          "Width follows the shared control contract: hug keeps the track content-sized, while fill occupies the parent width and distributes available space equally across selectable segments; dividers remain fixed-width separators.",
          "Small, medium, and large use the shared 24px, 32px, and 40px control-density recipes for the outer track. Each segment uses the same-size inset recipe at 20px, 28px, and 36px while preserving that density's typography, icon, gap, and label metrics.",
          "Use one consistent content variant across every selectable tab in a group.",
          "Omitted background is for primary and secondary surfaces; pass the faint context explicitly on faint surfaces.",
          "Only the omitted default context emphasizes visible selected label text and keeps the filled track; every explicit surface context uses a transparent track, stable text weight, surface border, and its context-matched neutral active fill rather than a brand active fill.",
          "Dividers visually separate related subsets inside one tab list but do not create nested navigation or independent selection groups."
        ],
        "responsiveBehavior": [
          "The component remains a single horizontal row and does not become vertical or wrap.",
          "Use the large size when a mobile composition aligns the group with 40px shell controls; size does not change automatically at a breakpoint.",
          "The consuming layout owns the available width; use fill only inside a definite bounded width and replace the row with a more suitable navigation pattern when labels cannot remain usable."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Assign tabs as a JavaScript property because structured arrays are not represented by HTML attributes.",
            "Use one item variant consistently, keep value synchronized to an enabled item, and update controlled content from dsChange."
          ],
          "react": [
            "Pass tabs as an array through the generated wrapper, keep value controlled, and use onDsChange to synchronize the visible view."
          ],
          "angular": [
            "Bind tabs and a valid value as properties, and handle dsChange to synchronize the visible view."
          ]
        },
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/TabGroup/TabGroup.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "ariaLabel": {
            "type": "string | null",
            "required": false
          },
          "ariaLabelledby": {
            "type": "string | undefined",
            "required": false
          },
          "background": {
            "type": "TabBackground | undefined",
            "required": false
          },
          "size": {
            "type": "TabGroupSize",
            "required": false
          },
          "tabs": {
            "type": "TabGroupItem[]",
            "required": false
          },
          "value": {
            "type": "string",
            "required": false
          },
          "width": {
            "type": "TabGroupWidth",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsChange",
            "detail": "string"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-tab-group",
        "react": "DsTabGroup",
        "vue": "DsTabGroup",
        "angular": "DsTabGroup"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens",
        "@ds-mo/icons"
      ],
      "componentDependencies": [
        "badge",
        "icon",
        "text"
      ]
    },
    {
      "id": "component:ds-table",
      "tag": "ds-table",
      "name": "table",
      "title": "Table",
      "summary": "Semantic, controlled data table with durable visual primitives for cell geometry, grouping, sorting, multi-selection, sticky overflow, incremental loading, top-level pagination, and optional row virtualization.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Semantic, controlled data table with durable visual primitives for cell geometry, grouping, sorting, multi-selection, sticky overflow, incremental loading, top-level pagination, and optional row virtualization.",
        "useWhen": [
          "A structured dataset needs native row and column relationships, optional one-level grouping, or comparable values across records.",
          "An application needs controlled sorting, loaded-row selection, infinite loading, pagination, virtual row recycling, or opted-in table-owned data-mode and column controls while retaining ownership of the data query, catalog, and persistence.",
          "A product table needs a token-backed recipe whose individual header, group, row, cell, selection, state, and load-more layers remain easy to restyle."
        ],
        "avoidWhen": [
          "Content is primarily editorial prose; use semantic product-owned markup with the prose recipe instead.",
          "A small label/value set reads more clearly as a list, description list, or card.",
          "The interface requires tree-grid behavior, nested grouping, inline cell editing, row reordering, multiple pinned columns per edge, or column virtualization; those remain outside the contract.",
          "The application expects the component to fetch, slice pages, sort, group, or mutate records internally."
        ],
        "commonlyComposedWith": [
          "component:ds-empty-state",
          "component:ds-skeleton",
          "component:ds-loader",
          "component:ds-pagination",
          "component:ds-table-toolbar",
          "component:ds-table-saved-views",
          "component:ds-table-filter",
          "component:ds-table-sort",
          "component:ds-bar-action",
          "component:ds-button-unfilled",
          "component:ds-menu",
          "component:ds-tooltip",
          "component:ds-tag",
          "component:ds-icon"
        ],
        "patterns": [
          "pattern:menu-trigger"
        ],
        "accessibility": [
          "The rendered structure uses a native table, caption, column headers, row groups, and data cells; keep the caption non-empty. The native caption remains visually hidden as the table's accessible name. When caption visibility is enabled, a 48px header bar renders as component chrome outside the horizontal scrollport. It defaults to a presentational caption title that does not duplicate the accessible name. Application-owned labeled controls supplied through the single named header slot replace that fallback and occupy the leading content width inside the component-owned 8px inset. When columnCustomizer is enabled, the table adds a trailing Customize control named Customize table; the label becomes Customized table when hidden or reordered columns differ from the catalog default. The control is icon-label at typical widths and the icon-only Table menu button below 900px. Otherwise the header slot receives the complete content width.",
          "The data-mode switcher is the shared Menu of the table's supported infinite, pagination, and virtual modes. It uses an Ellipses trigger. The switcher is the final caption-bar action; when the column customizer is also present, a decorative vertical divider separates the two controls. dataMode remains controlled, and the application responds to change intent by supplying the matching records, pagination state, loading behavior, and query consequences. Escape, dismissal, and selection return focus to the trigger.",
          "The column customizer is the shared Menu of switch rows, not a table-owned dialog. Data columns can be shown, hidden, and reordered. Action columns and the selection checkbox never appear in the menu. The last remaining visible data column cannot be hidden, but it stays focusable so it can still be reordered. Escape and outside click restore focus to the trigger. Persistence stays in the application.",
          "Sorting controls remain buttons inside column headers and expose the table's one controlled member-row sort through aria-sort. ds-table-sort in the toolbar trailing cluster is the matching menu of Data and Direction sections; it emits the same dsSortChange shape so header clicks and menu choices stay in sync. Grouping never adds a second sort indicator or header control; the application supplies groups in its fixed product order. Optional column help underlines the header label with the shared dotted decoration and shows ds-tooltip from that label; it does not add a second header control or replace the column name.",
          "Selection controls expose checkbox semantics and explicit row names; select-all affects selectable loaded rows only and preserves selected identities outside the loaded window. In virtual mode the supplied in-memory rows are that loaded set, including rows whose DOM is recycled. When grouping is active with multi-selection, each group section header also exposes a checkbox that selects or clears that group's selectable loaded rows.",
          "Interactive rows are focusable as native rows, activate with Enter or Space, and do not steal activation from their nested selection, action, overflow-menu, or primary-text link controls.",
          "Scrollable table regions become keyboard focusable and named only when overflow exists.",
          "Incremental loading, newly appended row counts, failures, and end-of-results transitions are announced through a polite status region without replacing visible state. In grouped tables, announcements name the independently loading group.",
          "Static and infinite tables may show an optional result summary footer when displayedCount and totalCount are finite. Virtual mode shows a total-only summary and ignores displayedCount. Pagination mode instead renders a named Pagination control with a compact selected-size total, vertical divider, and page position; range changes are announced independently with complete phrasing. Unmodified Left and Right Arrow request the adjacent page while focus is inside a paginated table or on a containing page scroller that owns it; editable fields, choice controls, sliders, open menus, and modified key combinations retain their own keyboard behavior. A table-owned footer slot can replace summary copy, while footer-leading and footer-trailing remain available in the same compact-bar anatomy. Nested dialog footers are ignored."
        ],
        "states": [
          "Columns, rows, groups, grouping, sorting, selected row IDs, collapsed group IDs, hiddenColumnIds, columnOrder, dataMode, pagination, displayedCount, totalCount, and incremental-loading state are controlled inputs. Events communicate intent and never mutate those inputs. The optional header is one composable table-local surface: the component owns its 48px chrome, 8px inset on every side, and sticky placement while the application owns the leading slot's internal layout, controls, labels, filtering behavior, and action handling. Opting into dataModeSwitcher and columnCustomizer adds their trailing Menu triggers and requires caption visibility. When both are present, Customize precedes a decorative divider and the data-mode trigger remains the final action. The Customize label becomes Customized when hidden or reordered columns differ from the catalog default. That state is foreground-only: the label goes primary on the icon-label shape, and the Table icon goes primary on the compact icon shape. The table closes one trailing Menu before opening the other. The footer retains its compact-bar composition: application-owned leading status sits left while a controlled result summary or Pagination aligns right, before any trailing action. Content-sized tables remain natural for sparse or fixed-count results. height bounds the complete header, frame, and footer composition. fitViewport reserves the compact-state composition height in the nearest vertical scrollport while growing the visible table into that reservation as surrounding page chrome collapses.",
          "Grouping supports one level. The application supplies groups in a fixed product-defined order and supplies ordered member rows independently. Group section headers show an emphasized text-body-medium label followed by a middle dot and plain secondary loaded progress, for example Critical · 50 of 166. The loaded value comes from the supplied member rows and the total comes from totalCount. A localized countLabel total phrase remains available for the complete assistive progress announcement. Virtual mode shows totals only, for example Critical · 166, because there is no loaded window. Groups may declare an optional intent (brand, neutral, negative, warning, caution, positive) that paints an LTR gradient from the faint intent surface at the label edge into faint neutral at the trailing edge, plus a bold intent title color. Neutral groups remain solid faint neutral. Section separators are painted inside that viewport-width surface so translucent border tokens composite with each intent background. Internal sections keep their separators; a collapsed or empty section header yields its separator only when it is the table's final rendered item. A trailing visually neutral icon-only ButtonUnfilled uses the 24px md double-inset action recipe and toggles controlled collapsedGroupIds, showing ChevronUp while expanded and ChevronDown while collapsed. While any group is expanded, a ChevronDownUp action uses the xs sort-control recipe widened to a table-owned 24px lane and collapses every group. It appears at the inline-end edge of the trailing column declared with kind action when one exists; otherwise a button-hugging 24px by 16px medium-elevation surface floats at the visible scrollport's header edge so the action remains reachable while member columns scroll beneath it. With stickyHeader enabled, each contained section uses its one real section row as a native sticky header inside its real row-group boundary. The browser therefore owns pinning, push-off, scrolling, and resize layout in one pass without a duplicated lane, active-section state, transforms, or scroll-time geometry. Shared grid tracks retain exact header and member-cell alignment. The section surface also stays pinned to the visible horizontal scrollport and spans the smaller of the visible viewport or table width. Virtual grouped tables flatten headers and members into that same scrollport; expanding a section never introduces an inner scroller.",
          "When columnCustomizer is false, columns render in catalog order. When it is true, columns remains the catalog: hiddenColumnIds and columnOrder control visibility and data-column sequence, action columns stay last, cannot be hidden, and remain absent from the customizer Menu, and dsColumnsConfigChange reports the next hidden ids and data-column order without mutating those inputs. The customizer Menu live-applies show/hide and data-column reorder. The table does not persist preferences.",
          "An active member sort toggles only between ascending and descending; activating a different sortable label moves the one sorting state to that key. Applications may still clear the controlled sort state explicitly. Grouping does not introduce another interactive direction.",
          "Compound headers can expose multiple related labels with independent sort keys. Each label owns only its content-width interaction target while the active direction remains in the column's alignment-aware sort lane.",
          "Initial loading defaults to ten row-shaped skeletons and preserves row dividers, column dividers, selection lanes, and sticky boundaries. A selectable table renders a checkbox-sized control skeleton in its selection lane so loading geometry matches the real checkbox instead of a generic icon. Each column may declare representative text, multiline text, image, Tag, icon, icon-and-text, action, or intentionally blank loading geometry; the table applies the matching resolved-cell padding and track anatomy so the placeholder row has the same height and rhythm as its data row. Columns without a declaration use one text line, while action columns infer an icon action placeholder. chromeLoading replaces opted-in table-owned caption controls with non-interactive control skeletons in the same slots and at the same dimensions, without changing dataMode or the surrounding caption geometry. Empty and initial error replace only the body with ds-empty-state, using Inbox or ErrorTriangle plus the table heading and body copy. In height-bounded and maxHeight tables that region fills the remaining viewport below the column header; content-sized tables keep a minimum empty-region height. Empty, initial error, load-more, retry, loading-more, and terminal bands remain fixed to the visible table width while data columns scroll horizontally beneath them. Incremental loading retains existing rows and supports automatic sentinel, manual load-more, retry, and terminal states. When grouping is active, each expanded group owns its load band at the end of its member rows; internal group load bands keep their bottom divider, while a terminal group load band yields it to the table edge or footer. The global bottom-of-table loader is not rendered.",
          "dataMode selects the top-level window: infinite appends ungrouped rows through dsLoadMore when hasMore is true, pagination renders the controlled page supplied by the application and emits dsPaginationChange, and virtual recycles row DOM over the full in-memory rows or groups the application already supplied. Infinite mode also covers fixed result sets by leaving hasMore false. In a grouped paginated table, pagination counts and windows only parent groups; each expanded parent can still append its own members through dsGroupLoadMore. Virtual mode does not fetch, ignores hasMore and load bands, and requires a bounded viewport (height, maxHeight, or fitViewport with a definite block size). Without that height it fails visibly instead of mounting every row. The application owns requests, cancellation, cursors, deduplication, slicing, and query identity.",
          "When pagination enables Fit to page on a bounded table, the table proposes the number of complete top-level rows that fit below its column header. Grouped tables count group headers only; member rows never affect capacity. Selecting Fit captures that numeric snapshot. A changed fitIdentity requests one fresh snapshot for a new query shape, while viewport resizing alone does not change the active controlled page size.",
          "Rows opt into complete-row activation with interactive and emit dsRowActivate without owning navigation. Selection paints through the shared selected ::before layer; interactive hover and press paint through the shared ::after layer.",
          "Row selection owns the single sticky start lane. One explicitly sized application column can own the sticky end lane, or the start lane when selection is absent. Each sticky boundary owns one fixed divider and a row-clipped directional shadow that paints into the adjacent scrolling columns only while more inline content remains beyond that edge.",
          "Cells accept scalar content, standard primary-and-secondary or dual-primary text primitives, declarative Tag, icon-only, icon-and-text, 16:9 Image, or ButtonUnfilled Action content, or explicit Empty and Blank absence values. Text objects may declare an optional href (and target) on the primary track only; the table renders a native anchor with the shared brand text-action treatment when the URL is safe, and leaves scalars unlinked. Standard secondary copy defaults to the secondary foreground and may declare a semantic Text color when the application data carries intent; an optional tertiary track uses the same subdued body-small recipe as secondary. Secondary and tertiary may also be a short list of colorable runs, rendered on one line with the table's middle-dot separator. Dual-primary copy keeps both tracks primary unless explicitly colored and does not gain a tertiary track. Body data cells share 8px outer padding; header and group rows keep their own geometry. Text tracks, including Empty, keep 4px inline padding so copy lines up with column-header labels; Tag and icon-only tracks stay on the 8px cell chrome alone. Icon-and-text cells (`kind: 'icon-text'`) place one md prefix icon beside the same copy stack as a text cell. The icon slot takes 2px padding on every side, then a 2px flex gap before the copy; text-track padding stays on the copy. Omit iconLabel when the glyph is decorative. 20px content (body-medium text, md icon, and the row checkbox) sits in a 24px track so it stays optically aligned with 24px Tag and Action content. Single-track text, selection, tag-only, icon-only, icon-and-text, Action, Empty, Blank, and 1-track Image cells resolve a 40px base contract while two-track cells grow to 62px and three-track cells grow to 84px. Tracks stack with a 2px gap. Wrapping primary on a 1-track cell uses that same rhythm: two wrapped lines share the 62px row and three wrapped lines share the 84px row. Wrapping secondary keeps primary on the first track and consumes later tracks: two secondary lines share the 84px row and three secondary lines share a 106px fourth track. Keep the same track count in every row of a table or group when those rows should share one height. Tag cells use the inset Tag recipe: md double-inset is a 24px control for tag-only and tag-with-text, while text-with-tag uses sm single-inset at 20px so the second-track pill fills the body-small slot. Action cells primarily use an icon-only Ellipses treatment, render a 24px small ButtonUnfilled, default to unbordered, and emit row, column, and action identities through dsCellAction. When an action cell declares items, that Ellipses trigger opens the shared ds-menu for commands, dividers, inactive rows, and destructive rows instead of emitting on click; choosing a command emits dsCellAction with that item's actionId. Omit items to keep a single-shot control. Image cells declare tracks 1, 2, or 3 so the 16:9 bordered preview fills that body-row content box (cell height minus 8px padding) and the column hugs the resulting width; omit tracks for the 1-track recipe, and keep image tracks aligned with the other cells in the table or group. Image cells fall back to an accessible placeholder when no source is supplied. Empty means the data applies but has no value and renders an em dash with localized assistive text; Blank means the data is not applicable and renders no content. Nullish values remain backward-compatible Empty values. Stable type and variant hooks keep every cell family independently styleable.",
          "The public @ds-mo/ui/table.css export is the authoritative zero-specificity visual recipe. Override its --ds-table-* properties or target its stable element classes for product-specific styling."
        ],
        "responsiveBehavior": [
          "The table keeps native semantics at narrow widths and scrolls horizontally instead of transforming into cards.",
          "Inside the named ds-table container, caption Filter, Group, and Sort controls that opt into collapseLabel become icon-only below 900px by omitting their labels and chevrons. Active filtering or grouping promotes the visible icon to primary. Sort keeps resting secondary chrome because its selection lives in the menu and headers. Customize switches to the icon-only Table menu button below 900px; a customized catalog then promotes that icon to primary.",
          "stickyHeader follows the active vertical scroll owner: a maxHeight, height, or fitViewport table keeps its native header and group sections inside one bounded table scrollport, while a document-flow table retains a semantic native header and renders a sticky control header whose columns follow the body's native inline scroll timeline. Consumers set --ds-table-sticky-header-offset when page chrome occupies an unbounded document scrollport edge. When the 48px table header bar is visible, it sticks at that external offset and the column header stacks immediately below it.",
          "fitViewport uses viewportInsetBlockStart and viewportInsetBlockEnd to describe compact surrounding chrome and page gutters relative to the nearest vertical scroll owner. Before the table reaches that compact position, its host reserves the eventual height while the visible composition grows and vertical input remains owned by the outer page. Once settled, the internal table viewport becomes the vertical scroll owner. Bounded grouped tables use browser-native sticky section rows inside real block row-group boundaries, so scroll and resize do not run component JavaScript or trigger reactive section swaps. Document-flow tables retain the synchronized visual lane required by their separate horizontal scrollport.",
          "Without maxHeight the table grows the document and automatic lazy loading observes the browser viewport. Horizontal scrolling chains vertical wheel and trackpad movement to the page instead of trapping it.",
          "Explicit column sizes establish the horizontal overflow width; unsized columns share remaining space. Set imageTracks on an image column to derive its fixed width from the matching 1-, 2-, or 3-track 16:9 image geometry plus table cell padding instead of copying a numeric width.",
          "Prefer the named xs through xl column sizes, which resolve through TokoMo's table-column width tokens; numeric pixel sizes remain an escape hatch for exceptional application-owned widths.",
          "Column headers use one 32px geometry. Body rows use a 40px single-track minimum with shared 8px cell padding; additional tracks grow downward. Image previews fill the same content box as their declared track count. The second text track and the third text track share one subdued body-small recipe so line 3 lines up with line 2.",
          "Long content truncates to one line by default. Hover (or keyboard-focus a primary link) shows the omitted value in one table-owned tooltip when that track overflows. maxLines 2 or 3 wrap onto the named 2-track and 3-track row heights, then ellipsize with the same tooltip. wrap: true remains unlimited and does not show a truncation tooltip. Wrapping 1-track primary occupies the named 2-track and 3-track row heights instead of a private line-height scale. Wrapping secondary on a 2-track cell occupies the named 3-track row and a 106px fourth track for three lines."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Assign columns, rows, groups, grouping, sort, selectedRowIds, collapsedGroupIds, hiddenColumnIds, columnOrder, pagination, displayedCount, and totalCount through JavaScript properties rather than HTML attribute strings.",
            "dataMode=virtual recycles row DOM over the supplied in-memory rows or groups and requires height, maxHeight, or fitViewport. It does not fetch or paginate.",
            "When an action cell supplies items, the table opens one shared ds-menu from the Ellipses trigger; dsCellAction fires for the selected command, not for opening or closing the menu.",
            "When columnCustomizer is enabled, the Table trigger opens the same shared ds-menu of reorderable switch rows; toggling a switch or reordering a row emits dsColumnsConfigChange and does not close the menu.",
            "Overflowing text tracks present one shared ds-tooltip with the omitted value. Unlimited wrapping tracks and disabled rows never show it. The tooltip is not linked with aria-describedby because the full string remains in the cell.",
            "Replace controlled property values in response to dsSortChange, dsGroupCollapseChange, dsSelectionChange, dsLoadMore, dsGroupLoadMore, dsPaginationChange, and dsColumnsConfigChange; route dsRowActivate in the application owner. When columnCustomizer is enabled, keep columns as the full catalog and replace hiddenColumnIds and columnOrder from that event."
          ],
          "react": [
            "Pass new array and state-object references when the controlled data or query state changes.",
            "Apply emitted sort, collapse, selection, action, pagination, column-customizer, or global/group loading detail to application state and perform data transformations in the owning layer."
          ],
          "angular": [
            "Bind complex table inputs as properties and update the controlled values from the corresponding output events.",
            "Keep server cursor, page slicing, query lifecycle, and cell-action handling in the owning service or container."
          ]
        },
        "references": [
          {
            "label": "Storybook review matrix",
            "path": "src/wc/components/Table/Table.stories.ts"
          },
          {
            "label": "Public visual recipe",
            "path": "src/wc/styles/table.css"
          },
          {
            "label": "Menu trigger composition",
            "path": "agent/patterns/menu-trigger/pattern.agent.json"
          }
        ]
      },
      "api": {
        "props": {
          "caption": {
            "type": "string",
            "required": true
          },
          "captionVisibility": {
            "type": "TableCaptionVisibility",
            "required": false
          },
          "chromeLoading": {
            "type": "boolean",
            "required": false
          },
          "collapsedGroupIds": {
            "type": "string[]",
            "required": false
          },
          "columnCustomizer": {
            "type": "boolean",
            "required": false
          },
          "columnOrder": {
            "type": "string[]",
            "required": false
          },
          "columns": {
            "type": "TableColumn[]",
            "required": false
          },
          "dataMode": {
            "type": "TableDataMode",
            "required": false
          },
          "dataModeMenuLabel": {
            "type": "string",
            "required": false
          },
          "dataModeSwitcher": {
            "type": "boolean",
            "required": false
          },
          "dataModeSwitcherLabel": {
            "type": "string",
            "required": false
          },
          "displayedCount": {
            "type": "number | undefined",
            "required": false
          },
          "emptyBody": {
            "type": "string",
            "required": false
          },
          "emptyCellLabel": {
            "type": "string",
            "required": false
          },
          "emptyHeading": {
            "type": "string",
            "required": false
          },
          "endOfResultsLabel": {
            "type": "string",
            "required": false
          },
          "error": {
            "type": "boolean",
            "required": false
          },
          "errorBody": {
            "type": "string",
            "required": false
          },
          "errorHeading": {
            "type": "string",
            "required": false
          },
          "fitViewport": {
            "type": "boolean",
            "required": false
          },
          "groupEndOfResultsLabel": {
            "type": "string",
            "required": false
          },
          "groupLoadMoreAriaLabel": {
            "type": "string",
            "required": false
          },
          "groupLoadMoreLabel": {
            "type": "string",
            "required": false
          },
          "groupLoadingMoreLabel": {
            "type": "string",
            "required": false
          },
          "groupRetryLabel": {
            "type": "string",
            "required": false
          },
          "groupRowsLoadedLabel": {
            "type": "string",
            "required": false
          },
          "grouping": {
            "type": "TableGroupingState | null",
            "required": false
          },
          "groups": {
            "type": "TableGroup[]",
            "required": false
          },
          "hasMore": {
            "type": "boolean",
            "required": false
          },
          "height": {
            "type": "string | number | undefined",
            "required": false
          },
          "hiddenColumnIds": {
            "type": "string[]",
            "required": false
          },
          "infiniteModeLabel": {
            "type": "string",
            "required": false
          },
          "loadIdentity": {
            "type": "string | number",
            "required": false
          },
          "loadMoreError": {
            "type": "string | undefined",
            "required": false
          },
          "loadMoreLabel": {
            "type": "string",
            "required": false
          },
          "loadMoreMode": {
            "type": "TableLoadMoreMode",
            "required": false
          },
          "loadMoreThreshold": {
            "type": "number",
            "required": false
          },
          "loading": {
            "type": "boolean",
            "required": false
          },
          "loadingMore": {
            "type": "boolean",
            "required": false
          },
          "loadingMoreLabel": {
            "type": "string",
            "required": false
          },
          "maxHeight": {
            "type": "string | number | undefined",
            "required": false
          },
          "pagination": {
            "type": "TablePaginationState | null",
            "required": false
          },
          "paginationModeLabel": {
            "type": "string",
            "required": false
          },
          "resultSummaryLabel": {
            "type": "string",
            "required": false
          },
          "resultTotalSummaryLabel": {
            "type": "string",
            "required": false
          },
          "retryLabel": {
            "type": "string",
            "required": false
          },
          "rows": {
            "type": "TableRow[]",
            "required": false
          },
          "rowsLoadedLabel": {
            "type": "string",
            "required": false
          },
          "scrollLabel": {
            "type": "string | undefined",
            "required": false
          },
          "selectedRowIds": {
            "type": "string[]",
            "required": false
          },
          "selectionMode": {
            "type": "TableSelectionMode",
            "required": false
          },
          "skeletonRows": {
            "type": "number",
            "required": false
          },
          "sort": {
            "type": "TableSortState | null",
            "required": false
          },
          "stickyHeader": {
            "type": "boolean",
            "required": false
          },
          "totalCount": {
            "type": "number | undefined",
            "required": false
          },
          "viewportInsetBlockEnd": {
            "type": "string | number",
            "required": false
          },
          "viewportInsetBlockStart": {
            "type": "string | number",
            "required": false
          },
          "virtualModeLabel": {
            "type": "string",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsCellAction",
            "detail": "TableCellActionDetail"
          },
          {
            "name": "dsColumnsConfigChange",
            "detail": "TableColumnsConfigChangeDetail"
          },
          {
            "name": "dsDataModeChange",
            "detail": "TableDataModeChangeDetail"
          },
          {
            "name": "dsGroupCollapseChange",
            "detail": "TableGroupCollapseChangeDetail"
          },
          {
            "name": "dsGroupLoadMore",
            "detail": "TableGroupLoadMoreDetail"
          },
          {
            "name": "dsLoadMore",
            "detail": "TableLoadMoreDetail"
          },
          {
            "name": "dsPaginationChange",
            "detail": "PaginationChangeDetail"
          },
          {
            "name": "dsRowActivate",
            "detail": "TableRowActivateDetail"
          },
          {
            "name": "dsSelectionChange",
            "detail": "TableSelectionChangeDetail"
          },
          {
            "name": "dsSortChange",
            "detail": "TableSortChangeDetail"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-table",
        "react": "DsTable",
        "vue": "DsTable",
        "angular": "DsTable"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens",
        "@ds-mo/icons"
      ],
      "componentDependencies": [
        "button-unfilled",
        "checkbox",
        "divider",
        "empty-state",
        "icon",
        "loader",
        "menu",
        "pagination",
        "skeleton",
        "tag",
        "text",
        "tooltip"
      ]
    },
    {
      "id": "component:ds-table-filter",
      "tag": "ds-table-filter",
      "name": "table-filter",
      "title": "TableFilter",
      "summary": "Standard table-toolbar Filter control that owns the shared trigger, filter menu UI, accessible defaults, and compact-caption behavior while the application controls data and values.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Standard table-toolbar Filter control that owns the shared trigger, filter menu UI, accessible defaults, and compact-caption behavior while the application controls data and values.",
        "useWhen": [
          "A table toolbar should expose the standard singular Filter control and shared filter-menu interaction.",
          "A product supplies filter definitions and controlled values but should not recreate the toolbar trigger, selected count, category navigation, or responsive treatment."
        ],
        "avoidWhen": [
          "Filtering is unrelated to a table or structured result set; use ds-filter-menu directly.",
          "The application expects the component to filter, fetch, persist, or otherwise transform rows.",
          "A filter requires a product-specific editor that the shared filter category kinds cannot represent."
        ],
        "alternatives": [
          {
            "when": "A non-table surface needs the generic filter interaction or custom trigger recipe.",
            "component": "component:ds-filter-menu",
            "reason": "FilterMenu exposes generic trigger geometry and popup positioning rather than the fixed table-toolbar recipe."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-table",
          "component:ds-table-toolbar",
          "component:ds-table-saved-views",
          "component:ds-table-sort",
          "component:ds-filter-menu"
        ],
        "patterns": [
          "pattern:menu-trigger"
        ],
        "accessibility": [
          "The trigger is an icon-label combobox named Filter table unless a product aria-label supplies the table context. Compact caption widths preserve that accessible name after the visible label and chevron are omitted.",
          "The popup retains ds-filter-menu category navigation, option semantics, focus entry, dismissal, and focus return.",
          "Localize label, menuLabel, categoriesLabel, and clearLabel together so visible and accessible wording remains consistent."
        ],
        "states": [
          "filters, values, and activeFilterId are controlled. dsChange, dsClear, and dsActiveFilterChange report intent without changing those inputs; the application applies query consequences and returns replacement values.",
          "The visible trigger label defaults to singular Filter and appends the selected criterion count. The trigger uses resting secondary chrome at typical widths; active criteria promote only the visible label, without redefining generic button active semantics.",
          "Popup visibility follows the same mutable open and dsOpenChange contract as ds-filter-menu."
        ],
        "responsiveBehavior": [
          "Place the control in the trailing region of ds-table-toolbar.",
          "Inside a named ds-table container narrower than 900px, the trigger becomes icon-only and active criteria promote the Filters icon to primary."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Assign filters, values, and activeFilterId as JavaScript properties. Replace controlled values in response to dsChange and dsClear."
          ],
          "react": [
            "Keep filters and values in application state and replace values from the typed dsChange and dsClear events."
          ],
          "angular": [
            "Import the generated DsTableFilter adapter, bind filters and values, and handle dsChange, dsClear, and dsActiveFilterChange."
          ]
        },
        "references": [
          {
            "label": "Storybook review states",
            "path": "src/wc/components/TableFilter/TableFilter.stories.ts"
          },
          {
            "label": "Toolbar composition owner",
            "path": "src/wc/components/TableToolbar/TableToolbar.agent.json"
          }
        ]
      },
      "api": {
        "props": {
          "activeFilterId": {
            "type": "string | undefined",
            "required": false
          },
          "ariaLabel": {
            "type": "string | null",
            "required": false
          },
          "categoriesLabel": {
            "type": "string",
            "required": false
          },
          "clearLabel": {
            "type": "string",
            "required": false
          },
          "filters": {
            "type": "FilterMenuFilter[]",
            "required": false
          },
          "label": {
            "type": "string",
            "required": false
          },
          "menuLabel": {
            "type": "string | null",
            "required": false
          },
          "open": {
            "type": "boolean",
            "required": false
          },
          "values": {
            "type": "FilterMenuValues",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsActiveFilterChange",
            "detail": "string"
          },
          {
            "name": "dsAfterClose",
            "detail": "void"
          },
          {
            "name": "dsChange",
            "detail": "FilterMenuChangeDetail"
          },
          {
            "name": "dsClear",
            "detail": "void"
          },
          {
            "name": "dsClose",
            "detail": "void"
          },
          {
            "name": "dsOpenChange",
            "detail": "boolean"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-table-filter",
        "react": "DsTableFilter",
        "vue": "DsTableFilter",
        "angular": "DsTableFilter"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "filter-menu"
      ]
    },
    {
      "id": "component:ds-table-saved-views",
      "tag": "ds-table-saved-views",
      "name": "table-saved-views",
      "title": "TableSavedViews",
      "summary": "Controlled saved-views UI for table toolbars, including selection, dirty state, create, save, discard, rename, remove, validation, and focus behavior without owning table configuration or persistence.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Controlled saved-views UI for table toolbars, including selection, dirty state, create, save, discard, rename, remove, validation, and focus behavior without owning table configuration or persistence.",
        "useWhen": [
          "A table workspace lets people recall and manage named combinations of table controls.",
          "Several products need the same saved-view interaction while retaining different view payloads and storage systems."
        ],
        "avoidWhen": [
          "The choices do not represent restorable table configurations.",
          "The application expects the component to serialize filters, grouping, sorting, columns, pagination, or product-specific state."
        ],
        "commonlyComposedWith": [
          "component:ds-table-toolbar",
          "component:ds-table",
          "component:ds-select",
          "component:ds-menu",
          "component:ds-modal"
        ],
        "patterns": [
          "pattern:menu-trigger"
        ],
        "accessibility": [
          "The primary control retains combobox semantics and exposes a direct accessible name.",
          "Each custom view exposes a separately named options trigger. The options menu supports keyboard navigation and returns focus through the shared Select and Menu behavior.",
          "The naming dialog traps focus through Modal behavior, associates validation text with the input through Field, and restores focus to the saved-views control after closing."
        ],
        "states": [
          "views, value, and dirty are controlled. Dirty state is presented only for a selected custom view; the default template never shows the trigger dot or save/discard actions even if dirty is supplied. Selection, create, save, discard, rename, and remove events communicate intent and never mutate application records.",
          "The component owns only transient interaction state: the contextual menu, naming dialog, draft name, duplicate-name validation, and focus restoration.",
          "The default view is a non-editable template. Application-owned custom views appear in a separate section with Rename and Remove actions. New view opens the naming dialog. When an editable selected view is dirty, that view row shows Save and negative Discard supporting actions while the footer remains dedicated to New view. The application decides which table state to capture, restore, and persist."
        ],
        "responsiveBehavior": [
          "The control remains a single toolbar item and relies on Select, Menu, and Modal collision and viewport behavior. Its trigger hugs short view names and is capped at the compact menu-width token so long names truncate while the dirty dot stays visible. Its choice popup keeps that same token as the minimum width.",
          "Place it in the start region of ds-table-toolbar so the middle region can keep left-side and right-side controls on one spanning cluster."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Assign views through the JavaScript property and update value after handling dsViewChange."
          ],
          "react": [
            "Keep view records and serialized table configuration in application state; update controlled props in response to the component events."
          ],
          "angular": [
            "Import the generated DsTableSavedViews adapter and bind views, value, and dirty; handle event.detail for selection and mutations."
          ]
        },
        "references": [
          {
            "label": "Storybook review states",
            "path": "src/wc/components/TableSavedViews/TableSavedViews.stories.ts"
          },
          {
            "label": "Toolbar composition owner",
            "path": "src/wc/components/TableToolbar/TableToolbar.agent.json"
          }
        ]
      },
      "api": {
        "props": {
          "createLabel": {
            "type": "string",
            "required": false
          },
          "defaultViewId": {
            "type": "string",
            "required": false
          },
          "defaultViewLabel": {
            "type": "string",
            "required": false
          },
          "dirty": {
            "type": "boolean",
            "required": false
          },
          "label": {
            "type": "string",
            "required": false
          },
          "triggerLabel": {
            "type": "string",
            "required": false
          },
          "value": {
            "type": "string",
            "required": false
          },
          "views": {
            "type": "TableSavedView[]",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsViewChange",
            "detail": "TableSavedViewChangeDetail"
          },
          {
            "name": "dsViewCreate",
            "detail": "TableSavedViewCreateDetail"
          },
          {
            "name": "dsViewDiscard",
            "detail": "TableSavedViewDiscardDetail"
          },
          {
            "name": "dsViewRemove",
            "detail": "TableSavedViewRemoveDetail"
          },
          {
            "name": "dsViewRename",
            "detail": "TableSavedViewRenameDetail"
          },
          {
            "name": "dsViewSave",
            "detail": "TableSavedViewSaveDetail"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-table-saved-views",
        "react": "DsTableSavedViews",
        "vue": "DsTableSavedViews",
        "angular": "DsTableSavedViews"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "button-filled",
        "button-unfilled",
        "field",
        "input",
        "menu",
        "modal",
        "select"
      ]
    },
    {
      "id": "component:ds-table-sort",
      "tag": "ds-table-sort",
      "name": "table-sort",
      "title": "TableSort",
      "summary": "Toolbar companion for the table's one controlled member-row sort, with a two-section menu for the sort field and direction that mirrors header sorting.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Toolbar companion for the table's one controlled member-row sort, with a two-section menu for the sort field and direction that mirrors header sorting.",
        "useWhen": [
          "A table toolbar needs an explicit Sort control alongside Filter and Group.",
          "Sortable columns or compound header segments should be choosable without relying only on column-header clicks."
        ],
        "avoidWhen": [
          "The table has no sortable columns; the control hides itself.",
          "The application expects the control to sort rows internally or persist preferences.",
          "The popup should submit a form value; use Select."
        ],
        "alternatives": [
          {
            "when": "The choice is one submitted form value.",
            "component": "component:ds-select",
            "reason": "Select owns form-value and listbox semantics, not table sort state."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-table",
          "component:ds-table-toolbar",
          "component:ds-table-filter",
          "component:ds-select",
          "component:ds-button-unfilled",
          "component:ds-menu"
        ],
        "patterns": [
          "pattern:menu-trigger"
        ],
        "accessibility": [
          "The trigger is an icon-label menu button named Sort table unless a product aria-label is supplied. Compact caption widths keep that accessible name after the visible label is omitted.",
          "The menu has two sections, Data and Direction. Each section presents one selected row through isSelected; the menu is not a single radio group because field and direction are independent.",
          "Choosing a row applies immediately and keeps the menu open so the other section can be changed. Escape and outside activation close the menu and restore trigger focus."
        ],
        "states": [
          "columns and sort are controlled. dsSortChange reports the next TableSortState and never mutates those inputs. The same sort object is what column headers emit through the table.",
          "Selecting a different data field keeps the current direction, or starts ascending when no sort exists. Selecting a direction applies it to the current field, or to the first sortable field when no sort exists. Selecting the already-active field or direction is a no-op and does not toggle the way a header click does.",
          "The trigger stays Sort in resting secondary chrome. Field and direction selection live in the menu and on column headers, so the trigger never uses active primary emphasis.",
          "Compound sortable headers contribute one Data row per segment. Action columns never appear."
        ],
        "responsiveBehavior": [
          "Place the control in the trailing region of ds-table-toolbar with Filter and Group.",
          "Inside a named ds-table container narrower than 900px, the trigger omits its label and chevron and becomes icon-only. The icon keeps the resting secondary foreground."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Assign columns and sort as JavaScript properties. Replace sort from both dsSortChange on this control and dsSortChange on the table."
          ],
          "react": [
            "Keep one sort state and pass it to both ds-table and ds-table-sort; update it from either event."
          ],
          "angular": [
            "Import the generated DsTableSort adapter, bind columns and sort, and handle dsSortChange with the same owner that handles table header sorting."
          ]
        },
        "references": [
          {
            "label": "Storybook review states",
            "path": "src/wc/components/TableSort/TableSort.stories.ts"
          },
          {
            "label": "Toolbar composition owner",
            "path": "src/wc/components/TableToolbar/TableToolbar.agent.json"
          }
        ]
      },
      "api": {
        "props": {
          "ariaLabel": {
            "type": "string | null",
            "required": false
          },
          "columns": {
            "type": "TableColumn[]",
            "required": false
          },
          "sort": {
            "type": "TableSortState | null",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsSortChange",
            "detail": "TableSortChangeDetail"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-table-sort",
        "react": "DsTableSort",
        "vue": "DsTableSort",
        "angular": "DsTableSort"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "button-unfilled",
        "menu"
      ]
    },
    {
      "id": "component:ds-table-toolbar",
      "tag": "ds-table-toolbar",
      "name": "table-toolbar",
      "title": "TableToolbar",
      "summary": "Data-agnostic companion layout for application-owned table caption controls, with a start cluster, optional search, trailing Filter/Group/Sort, and narrow-width horizontal overflow.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Data-agnostic companion layout for application-owned table caption controls, with a start cluster, optional search, trailing Filter/Group/Sort, and narrow-width horizontal overflow.",
        "useWhen": [
          "Several table pages repeat the same saved-view cluster, middle discovery and result-shaping controls, and table-owned caption actions.",
          "A ds-table header slot needs consistent control spacing, alignment, grouping, and narrow-width overflow without moving product behavior into the table."
        ],
        "avoidWhen": [
          "The controls do not operate on a table or structured result set.",
          "The application expects the toolbar to define filters, saved views, grouping choices, persistence, or data transformations.",
          "Only one standalone control is present and needs no grouped toolbar semantics."
        ],
        "commonlyComposedWith": [
          "component:ds-table",
          "component:ds-table-saved-views",
          "component:ds-divider",
          "component:ds-input",
          "component:ds-table-filter",
          "component:ds-select",
          "component:ds-table-sort",
          "component:ds-button-unfilled"
        ],
        "patterns": [],
        "accessibility": [
          "The component exposes a named toolbar while each slotted control retains its own accessible name and native keyboard behavior.",
          "Use the start slot for saved views. Use search for the optional discovery field, leading for any additional left-side middle controls, and trailing for Filter, Group, and Sort. Table-owned column customizer and data-mode actions remain in the table caption trailing cluster.",
          "Tab order follows authored DOM order. The toolbar does not add roving focus because it may contain heterogeneous form and popup controls."
        ],
        "states": [
          "The component owns layout only. It never mutates slotted control props, values, menus, loading, persistence, or consequences. Use ds-table-saved-views and ds-table-filter when those interactions need the shared CompoMo behavior while application data and persistence remain external.",
          "The start cluster is followed by a decorative vertical divider, then the spanning middle region. The start cluster and divider hide when nothing is projected. Search is a dedicated slot that hides when nothing is projected. Empty leading or trailing clusters add no placeholder chrome. The middle region occupies remaining width so trailing controls stay at its inline end.",
          "Column customizer and data-mode switching stay table-owned caption actions. Do not recreate those menus in the toolbar."
        ],
        "responsiveBehavior": [
          "The start cluster, search, trailing Filter/Group/Sort, and table caption trailing actions stay on one line. Saved views hug their current trigger content up to the compact menu-width token rather than reserving that full width; long names truncate while the dirty dot stays visible. Filter, Group, and Sort triggers cap at the same token, and Group and Sort popups keep that compact menu-width floor. The toolbar horizontally scrolls when its complete controls no longer fit.",
          "Inside a named ds-table container narrower than 900px, ds-table-filter and ds-table-sort omit their labels and chevrons and become icon-only. Group controls explicitly opt into the same treatment with collapseLabel. Active filtering or grouping promotes the prefix icon to primary. Sort keeps resting secondary chrome. Table-owned Customize also becomes the icon-only Table menu button at that width.",
          "The scrollbar is visually suppressed without removing touch, trackpad, mouse-wheel, or keyboard scrolling from the overflow container.",
          "Trailing controls remain grouped after leading controls; the toolbar does not collapse controls into an application-specific overflow menu."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Project saved views through slot=start, search through slot=search, additional left-side middle controls through slot=leading, and ds-table-filter, Group, and ds-table-sort through slot=trailing. Set collapseLabel on the Group control and provide contextual accessible names when Table controls is insufficient."
          ],
          "react": [
            "Set slot=start, slot=search, slot=leading, or slot=trailing on each child control. Use ds-table-filter for the standard Filter recipe, opt Group into collapseLabel, and keep values and event handlers in the application."
          ],
          "angular": [
            "Set slot=start, slot=search, slot=leading, or slot=trailing on each child control, use DsTableFilter for the standard Filter recipe, opt Group into collapseLabel, and import the generated adapters."
          ]
        },
        "references": [
          {
            "label": "Storybook review states",
            "path": "src/wc/components/TableToolbar/TableToolbar.stories.ts"
          },
          {
            "label": "Table composition owner",
            "path": "src/wc/components/Table/Table.agent.json"
          }
        ]
      },
      "api": {
        "props": {
          "label": {
            "type": "string",
            "required": false
          }
        },
        "events": [],
        "slots": []
      },
      "exports": {
        "customElement": "ds-table-toolbar",
        "react": "DsTableToolbar",
        "vue": "DsTableToolbar",
        "angular": "DsTableToolbar"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "divider"
      ]
    },
    {
      "id": "component:ds-tag",
      "tag": "ds-tag",
      "name": "tag",
      "title": "Tag",
      "summary": "Compact metadata or semantic-status label on primary surfaces, optionally rendered as a controlled menu trigger with leading and fixed suffix icons.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Compact metadata or semantic-status label on primary surfaces, optionally rendered as a controlled menu trigger with leading and fixed suffix icons.",
        "useWhen": [
          "A value needs a compact static metadata or category label.",
          "A status needs persistent semantic color and visible text without interaction.",
          "Product affiliation or AI-generated content needs an explicit labelled marker.",
          "A compact metadata value opens a related menu and needs a native button with controlled popup state."
        ],
        "avoidWhen": [
          "The value must be individually removable; use Chip.",
          "The element triggers an action other than opening a related menu; use the appropriate button or link.",
          "The element represents persistent selection or a toggle; use a control whose active state owns that meaning.",
          "A count or notification dot supplements another control; use Badge.",
          "The tag would be placed on a non-primary parent surface."
        ],
        "alternatives": [
          {
            "when": "A metadata value is individually removable.",
            "component": "component:ds-chip",
            "reason": "Chip owns dismiss interaction and parent-managed removal."
          },
          {
            "when": "A compact mark communicates unread count or notification presence.",
            "component": "component:ds-badge",
            "reason": "Badge owns supplemental notification indicators."
          },
          {
            "when": "The compact element triggers a non-menu action or toggle.",
            "component": "component:ds-button-unfilled",
            "reason": "ButtonUnfilled owns general actions, focus, and active state."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-card-setting",
          "component:ds-text",
          "component:ds-icon",
          "component:ds-menu"
        ],
        "accessibility": [
          "The visible label provides Tag's accessible name; a separate aria-label is normally unnecessary.",
          "Leading icons reinforce the visible label and remain decorative. The fixed ChevronUpDown suffix is always decorative.",
          "Static Tag stays outside the tab order. Interactive Tag renders a native button with menu popup semantics.",
          "The owner controls expanded state, associates the menu with aria-controls when available, and moves focus according to the Menu contract.",
          "Do not communicate semantic intent by color alone; the label must remain understandable without color."
        ],
        "states": [
          "Intent describes the represented value's semantic meaning, never selection or interaction state.",
          "Neutral is ordinary metadata; brand marks Motive or product affiliation; AI marks AI-generated or AI-assisted content; positive, caution, warning, and negative communicate increasingly specific status meaning.",
          "Warning signals higher urgency or risk than caution, which asks for attention before a possible issue.",
          "Contrast changes visual prominence without changing semantic intent or parent surface context.",
          "Rounded is an optional visual style with no semantic difference. Every size and inset depth keeps a minimum inline size equal to its resolved height, so short labels such as a one-digit count render as circles instead of vertically elongated pills.",
          "isInset opts into reduced outer geometry only when Tag is nested inside a control of the same density. The default single inset removes 4px overall; insetDepth double removes 8px overall and falls back to single at xs to protect minimum icon geometry. Semantic styling, typography, icons, gaps, radius, and interaction remain unchanged.",
          "Labels stay on one line and truncate only when the owner supplies a maximum width.",
          "Omitted interactive renders static metadata with no focus, event, or suffix. Interactive adds the fixed ChevronUpDown suffix and emits dsClick without toggling expanded internally.",
          "isInactive disables only the interactive button and applies the shared inactive treatment."
        ],
        "responsiveBehavior": [
          "The owner selects md, sm, or xs density to match its local layout and owns collection wrapping, overflow, and condensation. Use isInset only for same-density control nesting.",
          "Tag does not change size or behavior automatically at breakpoints."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Listen for dsClick to open the associated menu, then update expanded as controlled state. Use the Tag host ID as the menu anchor when required."
          ],
          "react": [
            "Use a stable key and parent-owned layout for Tag collections. For interactive Tag, synchronize expanded and the associated menu from the same state."
          ],
          "angular": [
            "Use parent-owned layout for Tag collections. For interactive Tag, synchronize expanded and the associated menu from the same state."
          ]
        },
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/Tag/Tag.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "ariaControls": {
            "type": "string | undefined",
            "required": false
          },
          "contrast": {
            "type": "TagContrast",
            "required": false
          },
          "expanded": {
            "type": "boolean",
            "required": false
          },
          "icon": {
            "type": "string",
            "required": false
          },
          "insetDepth": {
            "type": "ControlInsetDepth",
            "required": false
          },
          "intent": {
            "type": "TagIntent",
            "required": false
          },
          "interactive": {
            "type": "boolean",
            "required": false
          },
          "isInactive": {
            "type": "boolean",
            "required": false
          },
          "isInset": {
            "type": "boolean",
            "required": false
          },
          "label": {
            "type": "string",
            "required": true
          },
          "maxWidth": {
            "type": "string | number | undefined",
            "required": false
          },
          "rounded": {
            "type": "boolean",
            "required": false
          },
          "size": {
            "type": "TagSize",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsClick",
            "detail": "MouseEvent"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-tag",
        "react": "DsTag",
        "vue": "DsTag",
        "angular": "DsTag"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens",
        "@ds-mo/icons"
      ],
      "componentDependencies": [
        "icon",
        "text"
      ]
    },
    {
      "id": "component:ds-text",
      "tag": "ds-text",
      "name": "text",
      "title": "Text",
      "summary": "Semantic plain UI text with atomic tokenized typography recipes, measurable line boxes, and composition-owned wrapping and truncation.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Semantic plain UI text with atomic tokenized typography recipes, measurable line boxes, and composition-owned wrapping and truncation.",
        "useWhen": [
          "Plain UI text needs a complete design-system typography recipe.",
          "Headings, paragraphs, labels, or inline phrasing need native HTML semantics independent from their visual scale.",
          "A component needs a stable measurable text box aligned to shared typography metrics.",
          "Changing numeric values need tabular glyph widths."
        ],
        "avoidWhen": [
          "Content is markdown, rich prose, or an arbitrary nested document structure.",
          "The element is interactive; use the correct native or design-system control and compose Text only for its label.",
          "Individual font metrics must be overridden instead of selecting an existing complete variant.",
          "Typography alone would be used to repair an incorrect heading hierarchy."
        ],
        "alternatives": [
          {
            "when": "Predictable text geometry is pending while content loads.",
            "component": "component:ds-skeleton",
            "reason": "Skeleton owns aria-hidden loading geometry aligned to Text line metrics."
          },
          {
            "when": "Compact static metadata or semantic status needs a contained treatment.",
            "component": "component:ds-tag",
            "reason": "Tag owns compact labelled metadata and intent surfaces."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-icon",
          "component:ds-card-setting",
          "component:ds-field",
          "component:ds-button-filled"
        ],
        "accessibility": [
          "Choose the native element from document meaning and hierarchy; choose the visual variant independently.",
          "Composition authors preserve logical h1–h6 order regardless of visual size.",
          "Visible content and the selected native element provide accessible meaning; avoid redundant roles and labels.",
          "Use label semantics and its for association only for a real form control.",
          "When truncating essential content, the owner provides an accessible way to obtain the omitted text.",
          "Tertiary and quaternary foregrounds are restricted to text inside genuinely inactive or disabled UI, or to purely decorative content whose removal would not change meaning; quaternary is the fainter tier, and aria-hidden alone does not exempt meaningful visible text from contrast requirements.",
          "Underline link text by default. Brand-blue links may omit the resting underline when color already supplies the affordance.",
          "Use dotted underline for hidden or supplemental interaction such as a tooltip; the owning trigger must provide focus, keyboard interaction, and accessible tooltip semantics."
        ],
        "states": [
          "A variant is atomic: font size, line height, weight, and letter spacing stay together and are not overridden by consumers.",
          "Emphasis selects the supported stronger recipe for local hierarchy; it does not independently mean selected or active.",
          "Omitted color inherits currentColor without imposing a host color declaration, so an owning component may apply its semantic foreground directly without depending on stylesheet order. Explicit semantic aliases or CSS-variable references are used when Text has an independent color role.",
          "Prefer the owning control's isInactive or native disabled state over manually selecting tertiary or quaternary so visual treatment and inactive semantics remain synchronized.",
          "Line truncation and wrapping require an owner-supplied width constraint and content-aware composition decision.",
          "Solid underline is the default link affordance; brand-blue links may omit it at rest. Solid and dotted underlines share the tokenized decoration thickness and offset. Dotted underline communicates hidden or supplemental interaction such as a tooltip. Decoration does not make Text interactive by itself.",
          "Tabular numbers are for changing numeric values or aligned numeric columns where stable glyph width matters.",
          "Shimmer is reserved for visible generating/loading status text whose owner provides status semantics; reduced motion keeps static readable text."
        ],
        "responsiveBehavior": [
          "The composition owns width, wrapping, truncation, alignment, and any responsive variant change.",
          "Text preserves complete token recipes and does not scale fluidly or infer breakpoints."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Set as explicitly for inline text, headings, and labels; omitted as renders a paragraph."
          ],
          "react": [
            "Keep semantic as choices aligned with the rendered document hierarchy rather than component styling."
          ],
          "angular": [
            "Use the for prop only when Text renders a label associated with a real control ID."
          ]
        },
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/Text/Text.stories.ts"
          },
          {
            "label": "Typography contract",
            "path": "AGENTS.md"
          }
        ]
      },
      "api": {
        "props": {
          "align": {
            "type": "TextAlign | undefined",
            "required": false
          },
          "as": {
            "type": "TextElement",
            "required": false
          },
          "color": {
            "type": "TextColor",
            "required": false
          },
          "decoration": {
            "type": "TextDecoration | undefined",
            "required": false
          },
          "emphasis": {
            "type": "boolean",
            "required": false
          },
          "fontFeature": {
            "type": "TextFontFeature",
            "required": false
          },
          "for": {
            "type": "string | undefined",
            "required": false
          },
          "italic": {
            "type": "boolean",
            "required": false
          },
          "lineTruncation": {
            "type": "LineTruncation",
            "required": false
          },
          "shimmer": {
            "type": "boolean",
            "required": false
          },
          "textId": {
            "type": "string | undefined",
            "required": false
          },
          "variant": {
            "type": "TextVariant",
            "required": false
          },
          "wrap": {
            "type": "TextWrap | undefined",
            "required": false
          }
        },
        "events": [],
        "slots": []
      },
      "exports": {
        "customElement": "ds-text",
        "react": "DsText",
        "vue": "DsText",
        "angular": "DsText"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": []
    },
    {
      "id": "component:ds-toast",
      "tag": "ds-toast",
      "name": "toast",
      "title": "Toast",
      "summary": "Application-level floating notification system with a global manager, queued bottom-end stack, anchored feedback, actions, promise states, priority announcements, pauseable timers, keyboard access, and swipe dismissal.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Application-level floating notification system with a global manager, queued bottom-end stack, anchored feedback, actions, promise states, priority announcements, pauseable timers, keyboard access, and swipe dismissal.",
        "useWhen": [
          "A completed or failed operation needs brief non-blocking feedback without moving page content.",
          "An application needs one coordinated notification queue that can be triggered outside the current component tree.",
          "A short-lived undo or recovery action belongs directly with transient feedback.",
          "Contextual feedback such as Copy confirmation should appear near the control that caused it."
        ],
        "avoidWhen": [
          "The message must remain visible as part of page content or contains information users need later.",
          "The user must make a decision before continuing; use Modal for a blocking workflow.",
          "Validation belongs to a specific field or form section; keep the error adjacent to that content.",
          "The notification would contain long prose, several actions, navigation, or a complete workflow.",
          "Repeated background events would create a noisy stream instead of one updated or deduplicated toast."
        ],
        "alternatives": [
          {
            "when": "The user must respond before continuing or an irreversible action needs confirmation.",
            "component": "component:ds-modal",
            "reason": "Modal owns blocking focus containment and explicit decision actions."
          },
          {
            "when": "A form control needs persistent validation or supporting guidance.",
            "component": "component:ds-field",
            "reason": "Field keeps actionable feedback associated with the control that needs correction."
          },
          {
            "when": "A compact status must remain visible in the page hierarchy.",
            "component": "component:ds-tag",
            "reason": "Tag represents persistent static metadata rather than transient feedback."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-button-filled",
          "component:ds-button-unfilled",
          "component:ds-modal",
          "component:ds-field"
        ],
        "accessibility": [
          "Mount one ds-toast near the application root. New notifications never move focus.",
          "Provide a concise title, description, or both. Do not place the only recovery instructions in an automatically expiring toast.",
          "Use low priority for ordinary feedback. Reserve high priority for urgent interruptions that warrant assertive announcement.",
          "F6 moves focus into the Notifications region; Escape dismisses the focused toast and focus returns to a surviving toast or the previous control.",
          "Timers pause while users hover, focus, swipe, or leave the document, preserving the remaining reading time.",
          "Use timeout 0 for feedback that must remain until explicitly dismissed. Keep action labels concise and uniquely understandable.",
          "Anchored feedback supplements the triggering control but does not replace its accessible name, state, or persistent result.",
          "Do not include secrets, customer PII, or sensitive operational details in transient notification text."
        ],
        "states": [
          "The manager owns add, ID-based upsert, update, close, closeAll, and promise transitions. The component renders the manager snapshot.",
          "Loading promise records remain persistent until the same id updates to success or error and begins its resulting timeout.",
          "Only the newest records up to the limit are visible in the global stack. The collapsed trail insets each successive toast by 8px per side; hover or keyboard focus expands all visible records to full width. Older records remain mounted and inert until promoted.",
          "All timers pause together on hover, focus, touch swipe, window blur, or hidden-document state and resume from their exact remainder.",
          "Closing records remain rendered through exit motion before removal callbacks and dsToastRemove.",
          "One optional bordered unfilled action sits below the text at bottom-left, emits dsToastAction, and runs the supplied callback without dismissing automatically.",
          "Swipe state exposes movement and direction hooks; down and right are the default dismissal directions.",
          "Anchored records use trigger-relative positioning and do not consume the global stack limit."
        ],
        "responsiveBehavior": [
          "The global stack stays at the viewport bottom-end with token-based inset and never exceeds the available viewport width.",
          "Set avoid-mobile-shell-bar when the application uses the persistent shell bottom bar. Below 768px the global stack clears the complete safe-area-aware bar container by 16px; tablet and desktop positioning remain unchanged.",
          "Anchored toasts flip on their placement axis and clamp to viewport padding when the preferred side does not fit.",
          "The owner does not create separate mobile and desktop managers; one queue preserves ordering across responsive layouts.",
          "Pointer swipe remains optional input. Close and action controls retain keyboard access through the notification region."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Import ds-toast once and call toastManager from @ds-mo/ui/toast. Assign a custom manager and swipeDirections through JavaScript properties.",
            "Mount one ds-toast per manager; a second connected viewport for the same manager remains inactive."
          ],
          "react": [
            "Render one DsToast near the application root and import toastManager or createToastManager from @ds-mo/ui/toast.",
            "Pass custom manager, action callbacks, data, positioner anchors, and swipe directions as properties rather than string attributes."
          ],
          "angular": [
            "Import DsToast once near the application root and import toastManager or createToastManager from @ds-mo/ui/toast.",
            "Use property binding for manager, action callbacks, data, positioner anchors, and swipeDirections."
          ]
        },
        "references": [
          {
            "label": "Storybook examples",
            "path": "src/wc/components/Toast/Toast.stories.ts"
          },
          {
            "label": "Manager unit coverage",
            "path": "tests/toast-manager.test.ts"
          },
          {
            "label": "Cross-browser behavior coverage",
            "path": "tests/e2e/toast.spec.ts"
          }
        ]
      },
      "api": {
        "props": {
          "avoidMobileShellBar": {
            "type": "boolean",
            "required": false
          },
          "closeLabel": {
            "type": "string",
            "required": false
          },
          "label": {
            "type": "string",
            "required": false
          },
          "limit": {
            "type": "number",
            "required": false
          },
          "manager": {
            "type": "ToastManager",
            "required": false
          },
          "swipeDirections": {
            "type": "ToastSwipeDirection[]",
            "required": false
          },
          "timeout": {
            "type": "number | string",
            "required": false
          }
        },
        "events": [
          {
            "name": "dsToastAction",
            "detail": "ToastActionEventDetail"
          },
          {
            "name": "dsToastClose",
            "detail": "ToastCloseEventDetail"
          },
          {
            "name": "dsToastRemove",
            "detail": "ToastEventDetail"
          }
        ],
        "slots": []
      },
      "exports": {
        "customElement": "ds-toast",
        "react": "DsToast",
        "vue": "DsToast",
        "angular": "DsToast"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "button-unfilled",
        "text"
      ]
    },
    {
      "id": "component:ds-tooltip",
      "tag": "ds-tooltip",
      "name": "tooltip",
      "title": "Tooltip",
      "summary": "Supplementary, non-interactive visual label for an already named action, shown on mouse or hover-capable pen and keyboard focus.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "stable",
        "summary": "Supplementary, non-interactive visual label for an already named action, shown on mouse or hover-capable pen and keyboard focus.",
        "useWhen": [
          "An icon-only or dense control benefits from a short visual label for sighted mouse, pen, and keyboard users.",
          "A non-essential keyboard shortcut should appear beside a concise visual label.",
          "Adjacent chrome actions need delayed first disclosure with instant warm handoff between tooltips."
        ],
        "avoidWhen": [
          "The tooltip would be the trigger's only accessible name or contain information required to complete the task.",
          "The popup needs links, buttons, rich content, a close action, click-to-open behavior, or touch access.",
          "The callout follows a chart cursor or data point rather than a slotted control."
        ],
        "alternatives": [
          {
            "when": "The popup contains a contextual list of actions or options.",
            "component": "component:ds-menu",
            "reason": "Menu provides interactive content, keyboard navigation, selection, and close behavior."
          },
          {
            "when": "The content requires focus management, substantial explanation, confirmation, or a form.",
            "component": "component:ds-modal",
            "reason": "Modal provides dialog semantics and focus containment."
          },
          {
            "when": "A chart needs a cursor- or data-point-positioned value callout.",
            "component": "component:ds-tooltip-chart",
            "reason": "TooltipChart accepts chart coordinates and is designed for data visualization hover feedback."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-button-filled",
          "component:ds-button-unfilled",
          "component:ds-panel-nav",
          "component:ds-panel-tools",
          "component:ds-table"
        ],
        "accessibility": [
          "The slotted trigger must have its own accessible name, usually an aria-label that closely matches the visual tooltip label.",
          "Tooltip content is supplementary and non-essential; touch input intentionally does not open it.",
          "While open, the trigger is linked to the role=tooltip popup with aria-describedby by default; the relationship is removed when the popup leaves the DOM without disturbing consumer description IDs. Hosts that already expose the full string, such as a truncated table cell, disable that relationship.",
          "Keyboard focus opens the tooltip and Escape dismisses it without moving focus."
        ],
        "states": [
          "The first hover or keyboard focus waits for delay; moving to another tooltip shortly after dismissal opens it immediately.",
          "An empty or whitespace-only label suppresses the popup while preserving the wrapper.",
          "Only one tooltip remains active globally; warm handoff removes the previous popup before showing the next.",
          "Disconnecting and reinserting the tooltip host rebinds the current slotted trigger.",
          "A host may present the popup against an external anchor it already owns, without wrapping that trigger or binding hover on it.",
          "The preferred side flips when it cannot fit, then alignment is clamped to viewport padding.",
          "Reduced motion removes enter and exit fades while retaining the final visible or hidden state."
        ],
        "responsiveBehavior": [
          "The portaled popup follows trigger and popup resize, viewport resize, and nested scrolling while open.",
          "Touch users rely on the trigger's accessible and visible context rather than tooltip disclosure.",
          "Keep labels concise and non-wrapping by default; omitted table cell values may wrap at panel-xs."
        ],
        "frameworkCaveats": {
          "customElements": [
            "Place exactly one trigger element as the component's light-DOM child.",
            "Replacing the slotted trigger rebinds pointer and focus behavior automatically.",
            "A table or similar host can present the popup against an overflowing text node instead of wrapping that node.",
            "sideOffset, alignOffset, and delay accept numbers or TokoMo CSS values."
          ],
          "react": [
            "Wrap one focusable trigger with DsTooltip; keep the trigger's aria-label independent from the tooltip label."
          ],
          "angular": [
            "Wrap one focusable trigger with DsTooltip and use property binding when offset or delay values are not plain strings."
          ]
        },
        "references": [
          {
            "label": "Storybook behavior examples",
            "path": "src/wc/components/Tooltip/Tooltip.stories.ts"
          },
          {
            "label": "Cross-browser behavior and accessibility coverage",
            "path": "tests/e2e/tooltip.spec.ts"
          },
          {
            "label": "Positioning unit coverage",
            "path": "tests/anchored-position.test.ts"
          }
        ]
      },
      "api": {
        "props": {
          "align": {
            "type": "TooltipAlign",
            "required": false
          },
          "alignOffset": {
            "type": "number | string",
            "required": false
          },
          "delay": {
            "type": "number | string",
            "required": false
          },
          "describedBy": {
            "type": "boolean",
            "required": false
          },
          "label": {
            "type": "string",
            "required": true
          },
          "shortcutKey": {
            "type": "string | undefined",
            "required": false
          },
          "shortcutKeyPosition": {
            "type": "'start' | 'end'",
            "required": false
          },
          "side": {
            "type": "TooltipSide",
            "required": false
          },
          "sideOffset": {
            "type": "number | string",
            "required": false
          },
          "size": {
            "type": "TooltipSize",
            "required": false
          },
          "wrapLabel": {
            "type": "boolean",
            "required": false
          }
        },
        "events": [],
        "slots": []
      },
      "exports": {
        "customElement": "ds-tooltip",
        "react": "DsTooltip",
        "vue": "DsTooltip",
        "angular": "DsTooltip"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "text"
      ]
    },
    {
      "id": "component:ds-tooltip-chart",
      "tag": "ds-tooltip-chart",
      "name": "tooltip-chart",
      "title": "TooltipChart",
      "summary": "Chart-owned, non-interactive label and value callout positioned from pointer or focused-mark coordinates inside a visualization wrapper.",
      "intentStatus": "complete",
      "intent": {
        "audience": "specialized",
        "status": "stable",
        "summary": "Chart-owned, non-interactive label and value callout positioned from pointer or focused-mark coordinates inside a visualization wrapper.",
        "useWhen": [
          "A chart needs immediate visual value feedback for a genuinely hovered or keyboard-focused mark.",
          "The anchor lives inside SVG or chart coordinates rather than on a slotted HTML trigger.",
          "The owning chart can mount the callout for one interaction session and update its coordinates while tracking."
        ],
        "avoidWhen": [
          "A normal control or text trigger needs supplemental explanation; use Tooltip.",
          "The content needs links, actions, focus, or touch-primary disclosure.",
          "An externally synchronized highlight has no genuine local pointer or keyboard interaction.",
          "The callout would be the only accessible source of an essential value."
        ],
        "alternatives": [
          {
            "when": "A slotted control or text trigger needs a conventional tooltip.",
            "component": "component:ds-tooltip",
            "reason": "Tooltip owns trigger semantics, focus behavior, and anchored overlay lifecycle."
          },
          {
            "when": "Donut details should remain continuously visible beside the chart.",
            "component": "component:ds-chart-legend",
            "reason": "A visible legend avoids redundant transient slice callouts."
          }
        ],
        "commonlyComposedWith": [
          "component:ds-chart"
        ],
        "accessibility": [
          "The callout is presentation-only and never replaces the owning chart mark's accessible label or an adjacent data summary.",
          "Keyboard-focused marks receive the same visual feedback as pointer-hovered marks.",
          "The callout never receives focus or contains interactive descendants."
        ],
        "states": [
          "The owning chart mounts the callout when a local interaction starts and unmounts it when that interaction ends.",
          "Coordinate updates track within one mounted interaction session without restarting the show delay.",
          "Placement flips horizontally or vertically when the rendered callout approaches a viewport edge.",
          "The heading and rows use the same medium-density section-heading and control-frame anatomy as menu-style choice content.",
          "When any grouped row supplies a swatch, every row reserves the shared leading icon zone so mixed-swatch labels and trailing values stay aligned.",
          "Placement is chosen as a quadrant rather than computed as coordinates: the component measures its own rendered rect and flips its side and align props, which CSS consumes. It therefore does not use the shared anchored-position utilities, which resolve an anchor element into x and y.",
          "This separation is deliberate. The callout follows the pointer instead of an element, so it has no anchor rect to resolve; adopting the shared geometry would mean rewriting its CSS to consume coordinates for no behavioral gain.",
          "Reduced motion preserves the final visible state without an opacity transition."
        ],
        "responsiveBehavior": [
          "Render inside a positioned chart wrapper and pass coordinates relative to that wrapper.",
          "Keep labels concise enough for the single-line callout; persistent or long explanations belong outside the chart."
        ],
        "frameworkCaveats": {
          "customElements": [
            "The owning chart computes coordinates and conditionally mounts the component; applications should not use it as a standalone overlay."
          ],
          "react": [
            "Keep callout lifecycle and coordinates inside the chart wrapper rather than application-global tooltip state."
          ],
          "angular": [
            "Keep callout lifecycle and coordinates inside the chart wrapper rather than application-global tooltip state."
          ]
        },
        "references": [
          {
            "label": "Storybook example",
            "path": "src/wc/components/TooltipChart/TooltipChart.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "delay": {
            "type": "number | string",
            "required": false
          },
          "heading": {
            "type": "string",
            "required": false
          },
          "items": {
            "type": "TooltipChartItem[]",
            "required": false
          },
          "label": {
            "type": "string",
            "required": false
          },
          "value": {
            "type": "string | number",
            "required": false
          },
          "x": {
            "type": "number",
            "required": false
          },
          "y": {
            "type": "number",
            "required": false
          }
        },
        "events": [],
        "slots": []
      },
      "exports": {
        "customElement": "ds-tooltip-chart",
        "react": "DsTooltipChart",
        "vue": "DsTooltipChart",
        "angular": "DsTooltipChart"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "text"
      ]
    },
    {
      "id": "component:ds-typing-indicator",
      "tag": "ds-typing-indicator",
      "name": "typing-indicator",
      "title": "TypingIndicator",
      "summary": "Dedicated transient status for another participant actively composing a message.",
      "intentStatus": "complete",
      "intent": {
        "audience": "general",
        "status": "experimental",
        "summary": "Dedicated transient status for another participant actively composing a message.",
        "useWhen": [
          "An agent or person-to-person conversation needs to show that another participant is currently typing."
        ],
        "avoidWhen": [
          "An operation is loading or streaming a response; use Loader or the owning region's busy state.",
          "The status represents persisted message content; use Message and MessageBubble."
        ],
        "commonlyComposedWith": [
          "component:ds-message",
          "component:ds-message-scroller"
        ],
        "patterns": [
          "pattern:conversation"
        ],
        "accessibility": [
          "Provide concise localized status text; the standard label is Typing followed by a three-dot ellipsis.",
          "The polite atomic status announces typing without representing it as a message bubble."
        ],
        "states": [
          "TypingIndicator is transient conversation status, never persisted message content.",
          "Its body-medium secondary text may shimmer, while reduced-motion preferences retain a static readable status."
        ],
        "responsiveBehavior": [
          "The indicator fills the message content width and wraps only when localized status text requires it."
        ],
        "references": [
          {
            "label": "Storybook example",
            "path": "src/wc/components/TypingIndicator/TypingIndicator.stories.ts"
          }
        ]
      },
      "api": {
        "props": {
          "label": {
            "type": "string",
            "required": false
          }
        },
        "events": [],
        "slots": []
      },
      "exports": {
        "customElement": "ds-typing-indicator",
        "react": "DsTypingIndicator",
        "vue": "DsTypingIndicator",
        "angular": "DsTypingIndicator"
      },
      "dependencies": [
        "@ds-mo/ui",
        "@ds-mo/tokens"
      ],
      "componentDependencies": [
        "text"
      ]
    }
  ]
}
