{
  "version": "0.2.0-preview.1",
  "content_digest": "70ac710f4d22dce040e7ac593379ba8aca9dcb59a0b9c0f839819cae0e2bb721",
  "status": "preview",
  "authority": {
    "repository": "cloakedinc/design",
    "path": "packages/design-system",
    "catalog": "packages/design-system/catalog.json",
    "status": "preview"
  },
  "provenance": {
    "repo": "cloakedinc/automation",
    "commit": "f96f416e1c3bfbfaffcd155a88b87b18b8bb25f1",
    "path": "packages/design-system",
    "imported_spec_status": "approved"
  },
  "adaptations": [
    {
      "id": "button-content-gap",
      "status": "preview",
      "description": "Use the specification's 4px content gap instead of the inherited 8px implementation gap."
    },
    {
      "id": "keyboard-focus",
      "status": "preview",
      "description": "Add visible Button and Input keyboard focus and an overridable inset focus default for shared button resets, including FAQ cards and ListItem rows."
    },
    {
      "id": "supporting-text-contrast",
      "status": "preview",
      "description": "Map light secondary text to the existing grey-04-strong primitive for readable helper text on white and cream."
    },
    {
      "id": "danger-text-contrast",
      "status": "preview",
      "description": "Separate readable danger text/borders from destructive fills; preserve the primary danger-button fill and label pair."
    },
    {
      "id": "preview-status",
      "status": "preview",
      "description": "Local components, specs and token adaptations await human sign-off; upstream approved status is provenance only."
    },
    {
      "id": "motion-comparison-accessibility",
      "status": "preview",
      "description": "Preserve the original MotionShowcase comparisons while requiring explicit replay, responding to live reduced-motion changes, and keeping duration tracks usable on small screens."
    },
    {
      "id": "list-item-ownership",
      "status": "preview",
      "description": "List owns listitem wrappers for its content rows, while section labels stay outside the row count and standalone rows retain their existing semantics."
    },
    {
      "id": "card-delta-text-contrast",
      "status": "preview",
      "description": "Mix Card.Delta foregrounds from 60% existing tone solid and 40% primary text for readable contrast in both themes; preserve the four original tone fills."
    },
    {
      "id": "carousel-keyboard-access",
      "status": "preview",
      "description": "Keep all native-scrolling carousel slide controls exposed to assistive technology and keyboard navigation; pause autoplay while focus is inside the carousel."
    }
  ],
  "id": "button",
  "name": "Button",
  "category": "Primitives",
  "summary": "Make the next action clear with one primary button and quieter supporting actions.",
  "documentation": {
    "summary": "Make the next action clear with one primary button and quieter supporting actions.",
    "when_to_use": [
      "Initiate an action that changes the current state.",
      "Show one primary action per view.",
      "Use danger tone when the action is destructive."
    ],
    "avoid": [
      "Using a button to navigate to another URL; use a link.",
      "Treating the link variant as an anchor.",
      "Disabling an action without explaining what is needed."
    ],
    "accessibility": [
      "Use a descriptive visible label, or ariaLabel for icon-only buttons.",
      "Loading preserves the label, sets aria-busy, and blocks duplicate presses.",
      "Keyboard focus is visible in both themes."
    ],
    "constraints": [
      "Text buttons use children and optional leading/trailing content.",
      "Icon-only buttons require icon and ariaLabel and cannot have children or leading/trailing.",
      "Always renders type=button. A form must explicitly request submission."
    ]
  },
  "source": {
    "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
    "code": "import React from 'react';\nimport { cn } from '../../../utilities';\nimport { useHaptic } from '../../../hooks/useHaptic';\nimport type { HapticFeedback } from '../../../tokens/CdsHaptic';\nimport { Spinner } from '../../status/Spinner/Spinner';\nimport styles from './Button.module.scss';\n\nexport type ButtonVariant = 'primary' | 'secondary' | 'tertiary' | 'link';\nexport type ButtonSize = 'sm' | 'md';\nexport type ButtonTone = 'default' | 'danger';\n\n/**\n * The props both button shapes share. Not exported on its own: a button is either text or\n * icon-only, so consumers reach for `ButtonProps`.\n */\ninterface ButtonBaseProps {\n    /** Visual treatment by action hierarchy. */\n    variant: ButtonVariant;\n    /** Semantic action tone, independent of hierarchy. */\n    tone?: ButtonTone;\n    /** Height and padding tier; icon-only buttons use their own square size for each tier. */\n    size: ButtonSize;\n    /** Fires on tap. Omitted, the button renders inert without looking disabled. */\n    onPress?: () => void;\n    /** Blocks presses and dims the button. Use `loading` when the block is an in-flight action. */\n    disabled?: boolean;\n    /** Shows the loading treatment and prevents interaction. */\n    loading?: boolean;\n    /** Stretches the button to the width of its parent. */\n    fullWidth?: boolean;\n    /** Accessible label for icon-only buttons. */\n    ariaLabel?: string;\n    className?: string;\n    style?: React.CSSProperties;\n    /** Haptic feedback for successful presses. Defaults to `true` (`light`). */\n    haptic?: HapticFeedback;\n    /** Selector on the `<button>` itself; nothing inside derives from it. */\n    testId?: string;\n}\n\n/**\n * The shape whose visible text is its accessible name, optionally flanked by `leading`/`trailing`\n * visuals.\n */\ninterface TextButtonProps extends ButtonBaseProps {\n    children: React.ReactNode;\n    /** Optional leading visual, usually an Icon. */\n    leading?: React.ReactNode;\n    /** Optional trailing visual, usually an Icon. */\n    trailing?: React.ReactNode;\n    /** Text buttons use leading/trailing slots instead of icon-only glyphs. */\n    icon?: never;\n}\n\n/**\n * The shape with no visible text, so `ariaLabel` is required and becomes the accessible name.\n */\ninterface IconButtonProps extends ButtonBaseProps {\n    /** The button's only content; its presence is what selects this shape. */\n    icon: React.ReactNode;\n    /** Accessible label for the icon-only button. */\n    ariaLabel: string;\n    /** Icon buttons do not render visible text. */\n    children?: never;\n    /** Icon-only buttons do not support a separate leading slot. */\n    leading?: never;\n    /** Icon-only buttons do not support a separate trailing slot. */\n    trailing?: never;\n}\n\n/**\n * What a consumer passes: supplying `icon` selects the icon-only shape, omitting it the text shape.\n */\nexport type ButtonProps = TextButtonProps | IconButtonProps;\n\n/**\n * The action primitive. Always a `<button type='button'>`, so it never submits a form and\n * `variant='link'` is a text treatment rather than an anchor.\n */\nexport function Button({\n    variant,\n    tone = 'default',\n    size,\n    onPress,\n    disabled,\n    loading,\n    fullWidth,\n    ariaLabel,\n    className,\n    style,\n    haptic = true,\n    testId,\n    children,\n    icon,\n    leading,\n    trailing,\n}: ButtonProps) {\n    const isIconOnly = icon !== undefined;\n    const isDisabled = disabled || loading;\n    const fireHaptic = useHaptic('light');\n\n    const handlePress = () => {\n        fireHaptic(haptic);\n        onPress?.();\n    };\n\n    return (\n        <button\n            type='button'\n            className={cn(\n                styles.button,\n                styles[`variant-${variant}`],\n                tone === 'danger' && styles['tone-danger'],\n                styles[`size-${size}`],\n                isIconOnly && styles.iconOnly,\n                isIconOnly && variant === 'secondary' && styles.iconSecondary,\n                isIconOnly && variant === 'secondary' && tone === 'danger' && styles.iconSecondaryDanger,\n                fullWidth && styles.fullWidth,\n                loading && styles.loading,\n                className\n            )}\n            style={style}\n            onClick={isDisabled || !onPress ? undefined : handlePress}\n            disabled={isDisabled}\n            data-testid={testId}\n            aria-label={isIconOnly ? ariaLabel : undefined}\n            aria-busy={loading || undefined}\n        >\n            {/* Hidden at opacity 0 rather than unmounted, so the button holds its width under the overlaid Spinner. */}\n            <span className={cn(styles.content, loading && styles.contentHidden)}>\n                {isIconOnly ? (\n                    icon\n                ) : (\n                    <>\n                        {leading && <span className={styles.slot}>{leading}</span>}\n                        <span>{children}</span>\n                        {trailing && <span className={styles.slot}>{trailing}</span>}\n                    </>\n                )}\n            </span>\n            {loading && (\n                <span className={styles.loadingIndicator}>\n                    <Spinner size={size} tone={variant === 'primary' ? 'inverse' : 'primary'} />\n                </span>\n            )}\n        </button>\n    );\n}\n"
  },
  "spec": {
    "$schema": "../../../specs/component-spec.schema.json",
    "identity": {
      "name": "Button",
      "status": "preview",
      "version": "1.0.0",
      "summary": "A pressable action primitive with text, optional leading or trailing content, or an icon-only presentation."
    },
    "parts": [
      {
        "id": "container",
        "label": "Container",
        "description": "Owns the tap target, action hierarchy treatment, size, and state."
      },
      {
        "id": "label",
        "label": "Label",
        "description": "Names the action for text buttons."
      },
      {
        "id": "leading",
        "label": "Leading visual",
        "description": "Optional visual placed before a text label."
      },
      {
        "id": "trailing",
        "label": "Trailing visual",
        "description": "Optional visual placed after a text label."
      },
      {
        "id": "icon",
        "label": "Icon",
        "description": "The sole visible part of an icon-only button."
      },
      {
        "id": "loading-indicator",
        "label": "Loading indicator",
        "description": "Replaces visible content while preserving the button geometry during loading."
      }
    ],
    "allowedDesignChoices": {
      "variants": {
        "primary": {
          "label": "Primary"
        },
        "secondary": {
          "label": "Secondary"
        },
        "tertiary": {
          "label": "Tertiary",
          "description": "A deliberate web-only extension."
        },
        "link": {
          "label": "Link"
        }
      },
      "sizes": {
        "sm": {
          "label": "Small"
        },
        "md": {
          "label": "Medium"
        }
      }
    },
    "variants": [
      {
        "id": "primary",
        "label": "Primary",
        "description": "Filled treatment for the highest-priority action in a group.",
        "platforms": [
          "ios",
          "android",
          "web"
        ]
      },
      {
        "id": "secondary",
        "label": "Secondary",
        "description": "Outlined text treatment; icon-only secondary buttons use the filled secondary container.",
        "platforms": [
          "ios",
          "android",
          "web"
        ]
      },
      {
        "id": "tertiary",
        "label": "Tertiary",
        "description": "Chrome-free text treatment that retains the full text-button tap target.",
        "platforms": [
          "web"
        ]
      },
      {
        "id": "link",
        "label": "Link",
        "description": "Inline, lowest-emphasis action without button padding.",
        "platforms": [
          "ios",
          "android",
          "web"
        ]
      }
    ],
    "sizes": [
      {
        "id": "sm",
        "label": "Small",
        "description": "Compact text or icon action for dense layouts."
      },
      {
        "id": "md",
        "label": "Medium",
        "description": "Default standalone text or icon action."
      }
    ],
    "measurements": [
      {
        "id": "text-md-height",
        "label": "Medium text button height",
        "kind": "exact",
        "token": "--cds-size-56",
        "value": 56,
        "unit": "px",
        "appliesTo": [
          "text",
          "md"
        ]
      },
      {
        "id": "text-md-horizontal-padding",
        "label": "Medium text button horizontal padding",
        "kind": "exact",
        "token": "--cds-space-32",
        "value": 32,
        "unit": "px",
        "appliesTo": [
          "text",
          "md"
        ]
      },
      {
        "id": "text-md-vertical-spacing",
        "label": "Medium text button vertical spacing",
        "kind": "automatic",
        "appliesTo": [
          "text",
          "md"
        ],
        "notes": "The exact 56px height centers the label and owns the vertical inset."
      },
      {
        "id": "text-sm-vertical-padding",
        "label": "Small text button vertical padding",
        "kind": "exact",
        "token": "--cds-space-8",
        "value": 8,
        "unit": "px",
        "appliesTo": [
          "text",
          "sm"
        ]
      },
      {
        "id": "text-sm-horizontal-padding",
        "label": "Small text button horizontal padding",
        "kind": "exact",
        "token": "--cds-space-20",
        "value": 20,
        "unit": "px",
        "appliesTo": [
          "text",
          "sm"
        ]
      },
      {
        "id": "content-gap",
        "label": "Content gap",
        "kind": "exact",
        "token": "--cds-space-4",
        "value": 4,
        "unit": "px",
        "appliesTo": [
          "text",
          "leading",
          "trailing"
        ],
        "notes": "Reconciles the design gap of 4px with the prior web implementation gap of 8px."
      },
      {
        "id": "icon-md-size",
        "label": "Medium icon-only button size",
        "kind": "exact",
        "token": "--cds-size-40",
        "value": 40,
        "unit": "px",
        "appliesTo": [
          "icon",
          "md"
        ]
      },
      {
        "id": "icon-sm-size",
        "label": "Small icon-only button size",
        "kind": "exact",
        "token": "--cds-size-24",
        "value": 24,
        "unit": "px",
        "appliesTo": [
          "icon",
          "sm"
        ]
      },
      {
        "id": "large-pill-radius",
        "label": "Large primary and secondary radius",
        "kind": "exact",
        "token": "--cds-radius-full",
        "value": "full",
        "unit": "none",
        "appliesTo": [
          "text",
          "md",
          "primary",
          "secondary"
        ]
      }
    ],
    "layout": {
      "alignment": "Label, slots, icon, and loading indicator are centered in both axes.",
      "flow": "Text buttons lay out leading visual, label, and trailing visual in one row; icon-only buttons render one icon.",
      "notes": [
        "Full-width text buttons stretch to their parent while preserving centered content.",
        "Icon-only secondary buttons use the filled secondary container rather than the text-button outline."
      ]
    },
    "typographyAndColor": {
      "typography": [
        {
          "label": "Medium text",
          "description": "Uses the 16px body style.",
          "token": "--cds-type-body-size"
        },
        {
          "label": "Small text",
          "description": "Uses the 14px body-small style.",
          "token": "--cds-type-body-small-size"
        },
        {
          "label": "Link text",
          "description": "Uses the compact link style.",
          "token": "--cds-type-link-size"
        }
      ],
      "colors": [
        {
          "label": "Primary container",
          "description": "Theme-aware primary action fill.",
          "token": "--cds-button-primary-container"
        },
        {
          "label": "Primary text",
          "description": "Theme-aware foreground on the primary fill.",
          "token": "--cds-button-primary-text"
        },
        {
          "label": "Secondary container",
          "description": "Theme-aware fill for icon-only secondary buttons.",
          "token": "--cds-button-secondary-container"
        },
        {
          "label": "Secondary text",
          "description": "Theme-aware foreground for secondary and tertiary text.",
          "token": "--cds-button-secondary-text"
        }
      ]
    },
    "states": [
      {
        "id": "active",
        "label": "Active",
        "description": "Available for press and uses the selected variant treatment."
      },
      {
        "id": "disabled",
        "label": "Disabled",
        "description": "Blocks presses and applies --cds-opacity-disabled."
      },
      {
        "id": "loading",
        "label": "Loading",
        "description": "Blocks presses, hides the visible content, and centers a Spinner without changing geometry."
      }
    ],
    "behavior": [
      {
        "label": "Press",
        "description": "Calls onPress once for an enabled, non-loading button."
      },
      {
        "label": "Loading",
        "description": "Treats loading as disabled and exposes the busy state to assistive technology."
      },
      {
        "label": "Haptic",
        "description": "Requests the light semantic haptic after a successful press unless haptics are disabled."
      }
    ],
    "accessibility": [
      {
        "label": "Icon-only label",
        "description": "Every icon-only button requires an accessible ariaLabel that names the action."
      },
      {
        "label": "Native semantics",
        "description": "Renders a native button element and forwards disabled and aria-busy state."
      },
      {
        "label": "Loading name",
        "description": "Keeps the original visible label in the accessibility tree while the Spinner is shown."
      }
    ],
    "contentAdaptation": [
      {
        "label": "Action labels",
        "description": "Use short verb-led labels; full-width layouts absorb longer localized text."
      },
      {
        "label": "Slots",
        "description": "Use leading and trailing visuals only when they clarify the action; icon-only buttons do not accept text slots."
      }
    ],
    "motionHaptics": {
      "motion": [
        {
          "label": "Press feedback",
          "description": "Uses the shared button press treatment and respects reduced-motion preferences."
        }
      ],
      "haptics": [
        {
          "label": "Default feedback",
          "description": "Uses a light haptic for successful presses when a native bridge is available."
        }
      ]
    },
    "platformDifferences": [
      {
        "platforms": [
          "web"
        ],
        "description": "The tertiary variant is web-only; it is not part of the shared cross-platform component set.",
        "rationale": "Commit e85ed8f16 added the intentional chrome-free app treatment, so the difference remains documented instead of being removed during design reconciliation."
      }
    ]
  },
  "spec_source": "packages/design-system/src/components/primitives/Button/Button.spec.json",
  "guidance_source": {
    "path": "packages/design-system/src/components/primitives/Button/Button.mdx",
    "code": "import { Meta, Canvas, Controls } from '@storybook/addon-docs/blocks';\nimport { ComponentSpec, UsageTable, Do, Dont, Compare } from '../../../../.storybook/blocks';\nimport * as ButtonStories from './Button.stories';\nimport buttonSpec from './Button.spec.json';\n\n<Meta of={ButtonStories} />\n\n# Button\n\nThe primary tap target for actions. `variant` encodes action hierarchy. For a\nnon-tappable label, use `Tag`.\n\n<Canvas of={ButtonStories.Playground} />\n\n## Use when\n\nEmphasis runs `primary` → `secondary` → `tertiary` → `link`. Pick by how much you want\nthe action tapped, not by label order.\n\n<UsageTable\n    rows={[\n        {\n            variant: 'primary',\n            use: 'The one action you most want tapped in a view or step — Continue, Submit, Done, Try Again. Usually the full-width footer CTA.',\n            avoid: 'More than one in the same group — two filled buttons flatten the hierarchy.',\n        },\n        {\n            variant: 'secondary',\n            use: 'The workhorse variant: the companion beside a primary (Cancel, Back, Skip), a standalone medium-emphasis action (Try Again, reply chips), or an icon-only soft circle for close / dismiss.',\n            avoid: 'The single decisive CTA of a full-screen step — let a primary lead there.',\n        },\n        {\n            variant: 'tertiary',\n            use: 'A low-emphasis action that still wants a full button-sized tap target but no fill or border, so it reads as plain text.',\n            avoid: 'The main CTA (use primary); an inline, baseline-aligned text action (use link).',\n        },\n        {\n            variant: 'link',\n            use: 'The lowest-emphasis action: text deferrals (Maybe later, See full terms) and chromeless icon-only affordances (info, chevron, more). Inline baseline text, no padding.',\n            avoid: 'A footer CTA or anything needing a button-sized tap target — use primary or tertiary.',\n        },\n    ]}\n/>\n\n`tertiary` is the newest variant and the least reached-for — `secondary` and `link` cover\nmost low-emphasis needs today. Choose it only when you specifically want a full-size,\nchrome-free text button.\n\n## Tone\n\n`tone` is independent of hierarchy. Use `danger` only for destructive actions whose\nconsequences are clearly explained nearby.\n\n<Canvas of={ButtonStories.Danger} />\n\n## Do / Don't\n\n<Compare>\n    <Do caption='One primary sets the priority; step other actions down to secondary.'>\n        <Canvas of={ButtonStories.OnePrimary} sourceState='none' />\n    </Do>\n    <Dont caption='Two saturated buttons compete — neither reads as the priority.'>\n        <Canvas of={ButtonStories.TwoPrimaries} sourceState='none' />\n    </Dont>\n</Compare>\n\n## Content\n\nPass `icon` + a required `ariaLabel` for an icon-only button, **or** `leading` /\n`trailing` slots alongside text — the two are mutually exclusive.\n\n<Canvas of={ButtonStories.IconOnly} />\n<Canvas of={ButtonStories.WithSlots} />\n\n`fullWidth` stretches the button to its container — the standard footer CTA.\n\n<Canvas of={ButtonStories.FullWidth} />\n\n## States\n\nEvery `variant` × `size` × state. `loading` shows a Spinner and blocks presses.\n\n<Canvas of={ButtonStories.StateMatrix} />\n\n## Dark theme\n\n<Canvas of={ButtonStories.DarkTheme} />\n\n## Design Guidelines\n\n<ComponentSpec spec={buttonSpec} />\n\n## Props\n\n<Controls of={ButtonStories.Playground} />\n"
  },
  "props": [
    {
      "name": "variant",
      "type": "ButtonVariant",
      "required": true,
      "description": "Visual treatment by action hierarchy."
    },
    {
      "name": "tone",
      "type": "ButtonTone",
      "required": false,
      "description": "Semantic action tone, independent of hierarchy."
    },
    {
      "name": "size",
      "type": "ButtonSize",
      "required": true,
      "description": "Height and padding tier; icon-only buttons use their own square size for each tier."
    },
    {
      "name": "onPress",
      "type": "() => void",
      "required": false,
      "description": "Fires on tap. Omitted, the button renders inert without looking disabled."
    },
    {
      "name": "disabled",
      "type": "boolean",
      "required": false,
      "description": "Blocks presses and dims the button. Use `loading` when the block is an in-flight action."
    },
    {
      "name": "loading",
      "type": "boolean",
      "required": false,
      "description": "Shows the loading treatment and prevents interaction."
    },
    {
      "name": "fullWidth",
      "type": "boolean",
      "required": false,
      "description": "Stretches the button to the width of its parent."
    },
    {
      "name": "ariaLabel",
      "type": "string",
      "required": false,
      "description": "Accessible label for icon-only buttons."
    },
    {
      "name": "className",
      "type": "string",
      "required": false,
      "description": ""
    },
    {
      "name": "style",
      "type": "React.CSSProperties",
      "required": false,
      "description": ""
    },
    {
      "name": "haptic",
      "type": "HapticFeedback",
      "required": false,
      "description": "Haptic feedback for successful presses. Defaults to `true` (`light`)."
    },
    {
      "name": "testId",
      "type": "string",
      "required": false,
      "description": "Selector on the `<button>` itself; nothing inside derives from it."
    }
  ],
  "prop_shapes": {
    "text": [
      {
        "name": "children",
        "type": "React.ReactNode",
        "required": true,
        "description": ""
      },
      {
        "name": "leading",
        "type": "React.ReactNode",
        "required": false,
        "description": "Optional leading visual, usually an Icon."
      },
      {
        "name": "trailing",
        "type": "React.ReactNode",
        "required": false,
        "description": "Optional trailing visual, usually an Icon."
      },
      {
        "name": "icon",
        "type": "never",
        "required": false,
        "description": "Text buttons use leading/trailing slots instead of icon-only glyphs."
      }
    ],
    "icon": [
      {
        "name": "icon",
        "type": "React.ReactNode",
        "required": true,
        "description": "The button's only content; its presence is what selects this shape."
      },
      {
        "name": "ariaLabel",
        "type": "string",
        "required": true,
        "description": "Accessible label for the icon-only button."
      },
      {
        "name": "children",
        "type": "never",
        "required": false,
        "description": "Icon buttons do not render visible text."
      },
      {
        "name": "leading",
        "type": "never",
        "required": false,
        "description": "Icon-only buttons do not support a separate leading slot."
      },
      {
        "name": "trailing",
        "type": "never",
        "required": false,
        "description": "Icon-only buttons do not support a separate trailing slot."
      }
    ]
  },
  "examples": [
    {
      "id": "button-playground",
      "title": "Button playground",
      "source": "packages/design-system/examples/ButtonPlayground.tsx",
      "export": "ButtonPlayground",
      "components": [
        "button"
      ],
      "description": "Explore hierarchy, tone, size, disabled and loading states with code generated from the rendered props.",
      "synthetic_data": false,
      "storybook_id": "components-button--playground",
      "code": "import { useState } from 'react';\nimport { Button, type ButtonVariant, type ButtonTone, type ButtonSize } from '../src';\nimport { DemoFrame, SelectControl } from './DemoFrame';\nimport { buttonExampleCode, initialButtonProps, type ButtonExampleProps } from './code';\n\nexport function ButtonPlayground() {\n  const [props, setProps] = useState<ButtonExampleProps>(initialButtonProps);\n  const [presses, setPresses] = useState(0);\n  const change = (value: Partial<ButtonExampleProps>) => { setProps(previous => ({ ...previous, ...value })); setPresses(0); };\n  return <DemoFrame code={buttonExampleCode(props)} controls={<ButtonControls props={props} change={change} />}>\n    <div className=\"demo-button-stage\">\n      <Button variant={props.variant} tone={props.tone} size={props.size}\n        disabled={props.disabled} loading={props.loading} onPress={() => setPresses(value => value + 1)}>\n        {props.label}\n      </Button>\n      <p className=\"demo-feedback\" role=\"status\">{presses ? `Pressed ${presses} ${presses === 1 ? 'time' : 'times'}.` : 'Try the button, then explore its states.'}</p>\n    </div>\n  </DemoFrame>;\n}\n\nfunction ButtonControls({ props, change }: { props: ButtonExampleProps; change: (value: Partial<ButtonExampleProps>) => void }) {\n  const state = props.loading ? 'loading' : props.disabled ? 'disabled' : 'default';\n  return <>\n    <SelectControl label=\"Hierarchy\" value={props.variant} options={['primary', 'secondary', 'tertiary', 'link']}\n      onChange={value => change({ variant: value as ButtonVariant })} />\n    <SelectControl label=\"Tone\" value={props.tone} options={['default', 'danger']}\n      onChange={value => change({ tone: value as ButtonTone })} />\n    <SelectControl label=\"Size\" value={props.size} options={['md', 'sm']}\n      onChange={value => change({ size: value as ButtonSize })} />\n    <SelectControl label=\"State\" value={state} options={['default', 'loading', 'disabled']}\n      onChange={value => change({ disabled: value === 'disabled', loading: value === 'loading' })} />\n  </>;\n}\n\nexport function ButtonHierarchy() {\n  const [message, setMessage] = useState('Choose one primary action. Let supporting actions step back.');\n  return <DemoFrame>\n    <div className=\"demo-decision-card\">\n      <span className=\"demo-eyebrow\">A clear next step</span>\n      <h2>Keep your personal email private.</h2>\n      <p>Create an address you can turn off when you no longer need it.</p>\n      <div className=\"demo-actions\">\n        <Button variant=\"secondary\" size=\"sm\" onPress={() => setMessage('Secondary action selected. This example stays on the page.')}>Maybe later</Button>\n        <Button variant=\"primary\" size=\"sm\" onPress={() => setMessage('Primary action selected. See the complete flow below.')}>Create an address</Button>\n      </div>\n      <p className=\"demo-feedback\" role=\"status\">{message}</p>\n    </div>\n  </DemoFrame>;\n}\n"
    },
    {
      "id": "button-hierarchy",
      "title": "One clear next step",
      "source": "packages/design-system/examples/ButtonPlayground.tsx",
      "export": "ButtonHierarchy",
      "components": [
        "button"
      ],
      "description": "A primary and secondary action working together in a realistic decision.",
      "synthetic_data": true,
      "storybook_id": "components-button--hierarchy",
      "code": "import { useState } from 'react';\nimport { Button, type ButtonVariant, type ButtonTone, type ButtonSize } from '../src';\nimport { DemoFrame, SelectControl } from './DemoFrame';\nimport { buttonExampleCode, initialButtonProps, type ButtonExampleProps } from './code';\n\nexport function ButtonPlayground() {\n  const [props, setProps] = useState<ButtonExampleProps>(initialButtonProps);\n  const [presses, setPresses] = useState(0);\n  const change = (value: Partial<ButtonExampleProps>) => { setProps(previous => ({ ...previous, ...value })); setPresses(0); };\n  return <DemoFrame code={buttonExampleCode(props)} controls={<ButtonControls props={props} change={change} />}>\n    <div className=\"demo-button-stage\">\n      <Button variant={props.variant} tone={props.tone} size={props.size}\n        disabled={props.disabled} loading={props.loading} onPress={() => setPresses(value => value + 1)}>\n        {props.label}\n      </Button>\n      <p className=\"demo-feedback\" role=\"status\">{presses ? `Pressed ${presses} ${presses === 1 ? 'time' : 'times'}.` : 'Try the button, then explore its states.'}</p>\n    </div>\n  </DemoFrame>;\n}\n\nfunction ButtonControls({ props, change }: { props: ButtonExampleProps; change: (value: Partial<ButtonExampleProps>) => void }) {\n  const state = props.loading ? 'loading' : props.disabled ? 'disabled' : 'default';\n  return <>\n    <SelectControl label=\"Hierarchy\" value={props.variant} options={['primary', 'secondary', 'tertiary', 'link']}\n      onChange={value => change({ variant: value as ButtonVariant })} />\n    <SelectControl label=\"Tone\" value={props.tone} options={['default', 'danger']}\n      onChange={value => change({ tone: value as ButtonTone })} />\n    <SelectControl label=\"Size\" value={props.size} options={['md', 'sm']}\n      onChange={value => change({ size: value as ButtonSize })} />\n    <SelectControl label=\"State\" value={state} options={['default', 'loading', 'disabled']}\n      onChange={value => change({ disabled: value === 'disabled', loading: value === 'loading' })} />\n  </>;\n}\n\nexport function ButtonHierarchy() {\n  const [message, setMessage] = useState('Choose one primary action. Let supporting actions step back.');\n  return <DemoFrame>\n    <div className=\"demo-decision-card\">\n      <span className=\"demo-eyebrow\">A clear next step</span>\n      <h2>Keep your personal email private.</h2>\n      <p>Create an address you can turn off when you no longer need it.</p>\n      <div className=\"demo-actions\">\n        <Button variant=\"secondary\" size=\"sm\" onPress={() => setMessage('Secondary action selected. This example stays on the page.')}>Maybe later</Button>\n        <Button variant=\"primary\" size=\"sm\" onPress={() => setMessage('Primary action selected. See the complete flow below.')}>Create an address</Button>\n      </div>\n      <p className=\"demo-feedback\" role=\"status\">{message}</p>\n    </div>\n  </DemoFrame>;\n}\n"
    },
    {
      "id": "protected-email-flow",
      "title": "Create a protected email",
      "source": "packages/design-system/examples/ProtectedEmailFlow.tsx",
      "export": "ProtectedEmailFlow",
      "components": [
        "button",
        "field",
        "input"
      ],
      "description": "A local-only sample flow with validation, loading, success and restart. No data is sent or saved.",
      "synthetic_data": true,
      "storybook_id": "patterns-protected-email--create",
      "code": "import { useEffect, useLayoutEffect, useRef, useState, type FormEvent } from 'react';\nimport { Button, Field, Input } from '../src';\nimport { DemoFrame } from './DemoFrame';\nimport { createSampleIdentity, validateIdentity, type IdentityDraft, type IdentityErrors } from './protected-email';\n\nconst EMPTY_DRAFT: IdentityDraft = { name: '', website: '' };\n\nexport function ProtectedEmailFlow() {\n  const [draft, setDraft] = useState<IdentityDraft>(EMPTY_DRAFT);\n  const [errors, setErrors] = useState<IdentityErrors>({});\n  const [stage, setStage] = useState<'editing' | 'loading' | 'success'>('editing');\n  const form = useRef<HTMLFormElement>(null);\n  const success = useRef<HTMLHeadingElement>(null);\n  useEffect(() => {\n    if (stage !== 'loading') return;\n    const timer = window.setTimeout(() => setStage('success'), 700);\n    return () => window.clearTimeout(timer);\n  }, [stage]);\n  useEffect(() => { if (stage === 'success') success.current?.focus(); }, [stage]);\n  useLayoutEffect(() => {\n    if (Object.keys(errors).length) form.current?.querySelector<HTMLInputElement>('[aria-invalid=\"true\"]')?.focus();\n  }, [errors]);\n  const restart = () => {\n    setDraft(EMPTY_DRAFT); setErrors({}); setStage('editing');\n    requestAnimationFrame(() => form.current?.querySelector<HTMLInputElement>('input')?.focus());\n  };\n  const submit = (event: FormEvent) => {\n    event.preventDefault();\n    if (stage !== 'editing') return;\n    const nextErrors = validateIdentity(draft);\n    setErrors(nextErrors);\n    if (Object.keys(nextErrors).length) return;\n    setStage('loading');\n  };\n  return <DemoFrame><section className=\"demo-flow\" aria-label=\"Create a protected email example\">\n    <p className=\"demo-sample-note\">Interactive example · Sample data only. Nothing is sent or saved.</p>\n    {stage === 'success' ? <FlowSuccess draft={draft} headingRef={success} restart={restart} /> :\n      <form ref={form} noValidate onSubmit={submit} aria-busy={stage === 'loading'}>\n        <FlowHeading />\n        <FlowFields draft={draft} errors={errors} loading={stage === 'loading'} change={setDraft} submit={() => form.current?.requestSubmit()} />\n        <Button variant=\"primary\" size=\"md\" fullWidth loading={stage === 'loading'} onPress={() => form.current?.requestSubmit()}>Create protected email</Button>\n        <p className=\"demo-feedback\" role=\"status\">{stage === 'loading' ? 'Creating your sample address…' : 'Your personal email stays yours.'}</p>\n      </form>}\n  </section></DemoFrame>;\n}\n\nfunction FlowHeading() {\n  return <div className=\"demo-flow-heading\">\n    <span className=\"demo-symbol\" aria-hidden=\"true\">@</span>\n    <span className=\"demo-eyebrow\">A little more privacy</span>\n    <h2>An email for this part of your life.</h2>\n    <p>Give it a name so you know where you used it.</p>\n  </div>;\n}\n\nfunction FlowFields({ draft, errors, loading, change, submit }: {\n  draft: IdentityDraft; errors: IdentityErrors; loading: boolean;\n  change: (draft: IdentityDraft) => void; submit: () => void;\n}) {\n  return <div className=\"demo-flow-fields\">\n    <Field label=\"Name\" helperText=\"For example, shopping or a newsletter.\" error={errors.name} required disabled={loading}>\n      <Input value={draft.name} onChange={name => change({ ...draft, name })} placeholder=\"Shopping\"\n        name=\"identity-name\" autoComplete=\"off\" maxLength={80} enterKeyHint=\"next\" />\n    </Field>\n    <Field label=\"Website (optional)\" helperText=\"A reminder of where you'll use this address.\" error={errors.website} disabled={loading}>\n      <Input value={draft.website} onChange={website => change({ ...draft, website })} placeholder=\"example.com\"\n        name=\"identity-website\" autoComplete=\"off\" inputMode=\"url\" autoCapitalize=\"none\" maxLength={200}\n        enterKeyHint=\"done\" enterBehavior=\"callback\" onEnter={submit} />\n    </Field>\n  </div>;\n}\n\nfunction FlowSuccess({ draft, headingRef, restart }: {\n  draft: IdentityDraft; headingRef: React.RefObject<HTMLHeadingElement>; restart: () => void;\n}) {\n  const identity = createSampleIdentity(draft);\n  return <div className=\"demo-flow-success\">\n    <span className=\"demo-symbol demo-symbol-success\" aria-hidden=\"true\">✓</span>\n    <span className=\"demo-eyebrow\">Ready to use</span>\n    <h2 ref={headingRef} tabIndex={-1}>A fresh address for {identity.name}.</h2>\n    <p>This sample address demonstrates the result. It cannot receive email.</p>\n    <div className=\"demo-email-result\"><span>Protected email</span><strong>{identity.email}</strong></div>\n    <Button variant=\"secondary\" size=\"md\" fullWidth onPress={restart}>Try the flow again</Button>\n  </div>;\n}\n"
    },
    {
      "id": "foundation-overview",
      "title": "Tokens together",
      "source": "packages/design-system/examples/foundations/FoundationOverview.tsx",
      "export": "FoundationOverview",
      "components": [
        "button"
      ],
      "description": "A real component composition with editable container spacing and corner radius.",
      "synthetic_data": true,
      "storybook_id": "foundations-tokens-together--explore",
      "code": "import { useState } from 'react';\nimport { Button } from '../../src';\nimport { ContextCard, FoundationFrame, FoundationSelect } from './FoundationShared';\nimport { radiusSteps, spacingSteps } from './foundation-data';\n\nexport function FoundationOverview() {\n  const [radius, setRadius] = useState('--cds-radius-xl');\n  const [inset, setInset] = useState('--cds-space-24');\n  const [selected, setSelected] = useState(false);\n  return <FoundationFrame controls={<>\n    <FoundationSelect label=\"Corner radius\" value={radius} options={radiusSteps} onChange={setRadius} />\n    <FoundationSelect label=\"Container spacing\" value={inset} options={spacingSteps.filter(token => ['16px', '24px', '32px'].includes(token.value))} onChange={setInset} />\n  </>} code={`const cardStyle = {\\n  padding: 'var(${inset})',\\n  borderRadius: 'var(${radius})',\\n  background: 'var(--cds-bg-surface)',\\n  boxShadow: 'var(--cds-shadow-card)',\\n};\\n// Text and Button consume their own semantic tokens.`}>\n    <div className=\"foundation-overview-stage\">\n      <span className=\"demo-eyebrow\">Small decisions. One coherent experience.</span>\n      <ContextCard testId=\"overview-card\" style={{ padding: `var(${inset})`, borderRadius: `var(${radius})` }}>\n        <Button variant=\"primary\" size=\"sm\" onPress={() => setSelected(true)}>Create an address</Button>\n      </ContextCard>\n      <p className=\"foundation-caption\" role=\"status\">{selected ? 'Action selected. This is a local composition example.' : 'Change the container tokens. The real components keep their own behavior.'}</p>\n    </div>\n    <div className=\"foundation-token-connections\">\n      <span><b>Typography</b><code>--cds-type-h3-serif-*</code></span>\n      <span><b>Surface</b><code>--cds-bg-surface</code></span>\n      <span><b>Action</b><code>--cds-button-primary-*</code></span>\n    </div>\n  </FoundationFrame>;\n}\n"
    },
    {
      "id": "foundation-motion",
      "title": "Motion",
      "source": "packages/design-system/examples/foundations/FoundationMotion.tsx",
      "export": "FoundationMotion",
      "components": [
        "button"
      ],
      "description": "Original Storybook motion comparisons: three easing graphs raced against linear references and three duration tracks, with explicit replay and live reduced-motion support.",
      "synthetic_data": true,
      "storybook_id": "foundations-motion--explore",
      "code": "import { MotionShowcase } from '../../src/foundations/MotionShowcase';\nimport { FoundationFrame } from './FoundationShared';\n\n/** The website and original Foundations Motion story render this same showcase. */\nexport function FoundationMotion() {\n  return <FoundationFrame><MotionShowcase /></FoundationFrame>;\n}\n"
    }
  ],
  "tokens": [
    {
      "name": "--cds-size-56",
      "light": "56px",
      "dark": "56px"
    },
    {
      "name": "--cds-space-32",
      "light": "32px",
      "dark": "32px"
    },
    {
      "name": "--cds-space-8",
      "light": "8px",
      "dark": "8px"
    },
    {
      "name": "--cds-space-20",
      "light": "20px",
      "dark": "20px"
    },
    {
      "name": "--cds-space-4",
      "light": "4px",
      "dark": "4px"
    },
    {
      "name": "--cds-size-40",
      "light": "40px",
      "dark": "40px"
    },
    {
      "name": "--cds-size-24",
      "light": "24px",
      "dark": "24px"
    },
    {
      "name": "--cds-radius-full",
      "light": "9999px",
      "dark": "9999px"
    },
    {
      "name": "--cds-type-body-size",
      "light": "1rem",
      "dark": "1rem"
    },
    {
      "name": "--cds-type-body-small-size",
      "light": "0.875rem",
      "dark": "0.875rem"
    },
    {
      "name": "--cds-type-link-size",
      "light": "0.75rem",
      "dark": "0.75rem"
    },
    {
      "name": "--cds-button-primary-container",
      "light": "#0b0b0a",
      "dark": "#ffffff"
    },
    {
      "name": "--cds-button-primary-text",
      "light": "#ffffff",
      "dark": "#141410"
    },
    {
      "name": "--cds-button-secondary-container",
      "light": "#f3f1ed",
      "dark": "#ffffff0d"
    },
    {
      "name": "--cds-button-secondary-text",
      "light": "#141410",
      "dark": "#f3f1ed"
    },
    {
      "name": "--cds-opacity-disabled",
      "light": "0.3",
      "dark": "0.3"
    }
  ],
  "visual_reference": {
    "stories": [
      {
        "id": "cloaked-design-system-primitives-button--playground",
        "name": "Playground",
        "title": "Cloaked Design System/Primitives/Button",
        "exportName": "Playground",
        "source_path": "packages/design-system/src/components/primitives/Button/Button.stories.tsx",
        "source_digest": "4c471332d6da310075e36b2c3ff9b1b4f17c74cc60a3bc9079400f9db51c98cc",
        "status": "preview",
        "local_url": "/storybook/iframe.html?id=cloaked-design-system-primitives-button--playground&viewMode=story"
      },
      {
        "id": "cloaked-design-system-primitives-button--icon-only",
        "name": "Icon Only",
        "title": "Cloaked Design System/Primitives/Button",
        "exportName": "IconOnly",
        "source_path": "packages/design-system/src/components/primitives/Button/Button.stories.tsx",
        "source_digest": "4c471332d6da310075e36b2c3ff9b1b4f17c74cc60a3bc9079400f9db51c98cc",
        "status": "preview",
        "local_url": "/storybook/iframe.html?id=cloaked-design-system-primitives-button--icon-only&viewMode=story"
      },
      {
        "id": "cloaked-design-system-primitives-button--with-slots",
        "name": "With Slots",
        "title": "Cloaked Design System/Primitives/Button",
        "exportName": "WithSlots",
        "source_path": "packages/design-system/src/components/primitives/Button/Button.stories.tsx",
        "source_digest": "4c471332d6da310075e36b2c3ff9b1b4f17c74cc60a3bc9079400f9db51c98cc",
        "status": "preview",
        "local_url": "/storybook/iframe.html?id=cloaked-design-system-primitives-button--with-slots&viewMode=story"
      },
      {
        "id": "cloaked-design-system-primitives-button--danger",
        "name": "Danger",
        "title": "Cloaked Design System/Primitives/Button",
        "exportName": "Danger",
        "source_path": "packages/design-system/src/components/primitives/Button/Button.stories.tsx",
        "source_digest": "4c471332d6da310075e36b2c3ff9b1b4f17c74cc60a3bc9079400f9db51c98cc",
        "status": "preview",
        "local_url": "/storybook/iframe.html?id=cloaked-design-system-primitives-button--danger&viewMode=story"
      },
      {
        "id": "cloaked-design-system-primitives-button--full-width",
        "name": "Full Width",
        "title": "Cloaked Design System/Primitives/Button",
        "exportName": "FullWidth",
        "source_path": "packages/design-system/src/components/primitives/Button/Button.stories.tsx",
        "source_digest": "4c471332d6da310075e36b2c3ff9b1b4f17c74cc60a3bc9079400f9db51c98cc",
        "status": "preview",
        "local_url": "/storybook/iframe.html?id=cloaked-design-system-primitives-button--full-width&viewMode=story"
      },
      {
        "id": "cloaked-design-system-primitives-button--one-primary",
        "name": "One Primary",
        "title": "Cloaked Design System/Primitives/Button",
        "exportName": "OnePrimary",
        "source_path": "packages/design-system/src/components/primitives/Button/Button.stories.tsx",
        "source_digest": "4c471332d6da310075e36b2c3ff9b1b4f17c74cc60a3bc9079400f9db51c98cc",
        "status": "preview",
        "local_url": "/storybook/iframe.html?id=cloaked-design-system-primitives-button--one-primary&viewMode=story"
      },
      {
        "id": "cloaked-design-system-primitives-button--two-primaries",
        "name": "Two Primaries",
        "title": "Cloaked Design System/Primitives/Button",
        "exportName": "TwoPrimaries",
        "source_path": "packages/design-system/src/components/primitives/Button/Button.stories.tsx",
        "source_digest": "4c471332d6da310075e36b2c3ff9b1b4f17c74cc60a3bc9079400f9db51c98cc",
        "status": "preview",
        "local_url": "/storybook/iframe.html?id=cloaked-design-system-primitives-button--two-primaries&viewMode=story"
      },
      {
        "id": "cloaked-design-system-primitives-button--state-matrix",
        "name": "State Matrix",
        "title": "Cloaked Design System/Primitives/Button",
        "exportName": "StateMatrix",
        "source_path": "packages/design-system/src/components/primitives/Button/Button.stories.tsx",
        "source_digest": "4c471332d6da310075e36b2c3ff9b1b4f17c74cc60a3bc9079400f9db51c98cc",
        "status": "preview",
        "local_url": "/storybook/iframe.html?id=cloaked-design-system-primitives-button--state-matrix&viewMode=story"
      },
      {
        "id": "cloaked-design-system-primitives-button--dark-theme",
        "name": "Dark Theme",
        "title": "Cloaked Design System/Primitives/Button",
        "exportName": "DarkTheme",
        "source_path": "packages/design-system/src/components/primitives/Button/Button.stories.tsx",
        "source_digest": "4c471332d6da310075e36b2c3ff9b1b4f17c74cc60a3bc9079400f9db51c98cc",
        "status": "preview",
        "local_url": "/storybook/iframe.html?id=cloaked-design-system-primitives-button--dark-theme&viewMode=story"
      }
    ],
    "name": "Button",
    "id": "button",
    "category": "Primitives"
  },
  "stories": [
    {
      "id": "cloaked-design-system-primitives-button--playground",
      "name": "Playground",
      "title": "Cloaked Design System/Primitives/Button",
      "exportName": "Playground",
      "source_path": "packages/design-system/src/components/primitives/Button/Button.stories.tsx",
      "source_digest": "4c471332d6da310075e36b2c3ff9b1b4f17c74cc60a3bc9079400f9db51c98cc",
      "status": "preview",
      "local_url": "/storybook/iframe.html?id=cloaked-design-system-primitives-button--playground&viewMode=story"
    },
    {
      "id": "cloaked-design-system-primitives-button--icon-only",
      "name": "Icon Only",
      "title": "Cloaked Design System/Primitives/Button",
      "exportName": "IconOnly",
      "source_path": "packages/design-system/src/components/primitives/Button/Button.stories.tsx",
      "source_digest": "4c471332d6da310075e36b2c3ff9b1b4f17c74cc60a3bc9079400f9db51c98cc",
      "status": "preview",
      "local_url": "/storybook/iframe.html?id=cloaked-design-system-primitives-button--icon-only&viewMode=story"
    },
    {
      "id": "cloaked-design-system-primitives-button--with-slots",
      "name": "With Slots",
      "title": "Cloaked Design System/Primitives/Button",
      "exportName": "WithSlots",
      "source_path": "packages/design-system/src/components/primitives/Button/Button.stories.tsx",
      "source_digest": "4c471332d6da310075e36b2c3ff9b1b4f17c74cc60a3bc9079400f9db51c98cc",
      "status": "preview",
      "local_url": "/storybook/iframe.html?id=cloaked-design-system-primitives-button--with-slots&viewMode=story"
    },
    {
      "id": "cloaked-design-system-primitives-button--danger",
      "name": "Danger",
      "title": "Cloaked Design System/Primitives/Button",
      "exportName": "Danger",
      "source_path": "packages/design-system/src/components/primitives/Button/Button.stories.tsx",
      "source_digest": "4c471332d6da310075e36b2c3ff9b1b4f17c74cc60a3bc9079400f9db51c98cc",
      "status": "preview",
      "local_url": "/storybook/iframe.html?id=cloaked-design-system-primitives-button--danger&viewMode=story"
    },
    {
      "id": "cloaked-design-system-primitives-button--full-width",
      "name": "Full Width",
      "title": "Cloaked Design System/Primitives/Button",
      "exportName": "FullWidth",
      "source_path": "packages/design-system/src/components/primitives/Button/Button.stories.tsx",
      "source_digest": "4c471332d6da310075e36b2c3ff9b1b4f17c74cc60a3bc9079400f9db51c98cc",
      "status": "preview",
      "local_url": "/storybook/iframe.html?id=cloaked-design-system-primitives-button--full-width&viewMode=story"
    },
    {
      "id": "cloaked-design-system-primitives-button--one-primary",
      "name": "One Primary",
      "title": "Cloaked Design System/Primitives/Button",
      "exportName": "OnePrimary",
      "source_path": "packages/design-system/src/components/primitives/Button/Button.stories.tsx",
      "source_digest": "4c471332d6da310075e36b2c3ff9b1b4f17c74cc60a3bc9079400f9db51c98cc",
      "status": "preview",
      "local_url": "/storybook/iframe.html?id=cloaked-design-system-primitives-button--one-primary&viewMode=story"
    },
    {
      "id": "cloaked-design-system-primitives-button--two-primaries",
      "name": "Two Primaries",
      "title": "Cloaked Design System/Primitives/Button",
      "exportName": "TwoPrimaries",
      "source_path": "packages/design-system/src/components/primitives/Button/Button.stories.tsx",
      "source_digest": "4c471332d6da310075e36b2c3ff9b1b4f17c74cc60a3bc9079400f9db51c98cc",
      "status": "preview",
      "local_url": "/storybook/iframe.html?id=cloaked-design-system-primitives-button--two-primaries&viewMode=story"
    },
    {
      "id": "cloaked-design-system-primitives-button--state-matrix",
      "name": "State Matrix",
      "title": "Cloaked Design System/Primitives/Button",
      "exportName": "StateMatrix",
      "source_path": "packages/design-system/src/components/primitives/Button/Button.stories.tsx",
      "source_digest": "4c471332d6da310075e36b2c3ff9b1b4f17c74cc60a3bc9079400f9db51c98cc",
      "status": "preview",
      "local_url": "/storybook/iframe.html?id=cloaked-design-system-primitives-button--state-matrix&viewMode=story"
    },
    {
      "id": "cloaked-design-system-primitives-button--dark-theme",
      "name": "Dark Theme",
      "title": "Cloaked Design System/Primitives/Button",
      "exportName": "DarkTheme",
      "source_path": "packages/design-system/src/components/primitives/Button/Button.stories.tsx",
      "source_digest": "4c471332d6da310075e36b2c3ff9b1b4f17c74cc60a3bc9079400f9db51c98cc",
      "status": "preview",
      "local_url": "/storybook/iframe.html?id=cloaked-design-system-primitives-button--dark-theme&viewMode=story"
    }
  ],
  "stories_source": {
    "path": "packages/design-system/src/components/primitives/Button/Button.stories.tsx",
    "code": "import React from 'react';\nimport type { Meta, StoryObj } from '@storybook/react-vite';\nimport { HStack } from '../../layout/HStack/HStack';\nimport { VStack } from '../../layout/VStack/VStack';\nimport { disabledControl, hapticArgType, selectArgType } from '../../../storybook/controlOptions';\nimport { Text } from '../Text/Text';\nimport { Icon } from '../Icon/Icon';\nimport { Button, type ButtonSize, type ButtonTone, type ButtonVariant } from './Button';\n\nconst BUTTON_VARIANTS = ['primary', 'secondary', 'tertiary', 'link'] as const satisfies readonly ButtonVariant[];\nconst BUTTON_TONES = ['default', 'danger'] as const satisfies readonly ButtonTone[];\nconst BUTTON_SIZES = ['sm', 'md'] as const satisfies readonly ButtonSize[];\nconst SIZE_LABELS: Record<ButtonSize, string> = { sm: 'Small', md: 'Medium' };\n\ninterface ButtonState {\n    key: string;\n    label: string;\n    props: { disabled?: boolean; loading?: boolean };\n}\nconst BUTTON_STATES: ButtonState[] = [\n    { key: 'default', label: 'Default', props: {} },\n    { key: 'disabled', label: 'Disabled', props: { disabled: true } },\n    { key: 'loading', label: 'Loading', props: { loading: true } },\n];\n\n// A bounded stand-in for a phone footer so `fullWidth` has real width to stretch into\n// (the centered story canvas would otherwise shrink-wrap the button to its label).\nconst FOOTER_CONTAINER: React.CSSProperties = {\n    width: 320,\n    padding: 'var(--cds-space-16)',\n    border: 'var(--cds-border-width-default) dashed var(--cds-divider)',\n    borderRadius: 'var(--cds-radius-lg)',\n};\n\nconst meta: Meta<typeof Button> = {\n    parameters: { a11y: { test: 'error' } },\n    title: 'Cloaked Design System/Primitives/Button',\n    component: Button,\n    args: {\n        variant: 'primary',\n        tone: 'default',\n        size: 'md',\n        children: 'Continue',\n    },\n    argTypes: {\n        variant: {\n            ...selectArgType(BUTTON_VARIANTS),\n            description:\n                'Action hierarchy: `primary` (one per view) · `secondary` · `tertiary` (borderless full-size text) · `link` (inline).',\n        },\n        tone: {\n            ...selectArgType(BUTTON_TONES),\n            description: 'Semantic action tone, independent of hierarchy. Use `danger` for destructive actions.',\n        },\n        size: {\n            ...selectArgType(BUTTON_SIZES),\n            description: 'Height/padding tier — `md` for standalone CTAs, `sm` for dense rows and inline groups.',\n        },\n        icon: {\n            ...disabledControl,\n            description: 'Glyph for an icon-only button; requires `ariaLabel` and excludes text/slots.',\n        },\n        leading: { ...disabledControl, description: 'Visual before the label (usually an `Icon`); text buttons only.' },\n        trailing: { ...disabledControl, description: 'Visual after the label (usually an `Icon`); text buttons only.' },\n        onPress: { ...disabledControl, description: 'Press handler; a button with no handler renders inert.' },\n        haptic: {\n            ...hapticArgType,\n            description: 'Haptic fired on a successful press. Defaults to `true` (a light tap).',\n        },\n        testId: { ...disabledControl, description: 'Kebab-case selector hook for tests and engine-mcp targeting.' },\n    },\n};\nexport default meta;\ntype Story = StoryObj<typeof Button>;\n\nexport const Playground: Story = {};\n\nexport const IconOnly: Story = {\n    parameters: {\n        docs: {\n            description: {\n                story:\n                    '`icon` + required `ariaLabel` and no children — a compact glyph-only tap target. Icon-only ' +\n                    '`secondary` renders as a soft-filled circle (the DS 4.5 close/dismiss affordance).',\n            },\n        },\n    },\n    args: { variant: 'primary', icon: <Icon name='arrow-right' size='medium' />, ariaLabel: 'Next' },\n};\n\nexport const WithSlots: Story = {\n    parameters: {\n        docs: {\n            description: {\n                story: '`leading`/`trailing` slots frame the label — use for affordance cues, not icon-only.',\n            },\n        },\n    },\n    args: {\n        variant: 'secondary',\n        leading: <Icon name='check' size='small' />,\n        trailing: <Icon name='arrow-right' size='small' />,\n        children: 'Review item',\n    },\n};\n\nexport const Danger: Story = {\n    parameters: {\n        docs: {\n            description: {\n                story: '`tone=\"danger\"` communicates a destructive action without changing its hierarchy.',\n            },\n        },\n    },\n    args: {\n        tone: 'danger',\n        children: 'Delete identity',\n        testId: 'button-danger',\n    },\n};\n\nexport const FullWidth: Story = {\n    parameters: {\n        docs: {\n            description: {\n                story: '`fullWidth` stretches the button to fill its container — the standard footer CTA. Shown in a phone-width footer.',\n            },\n        },\n    },\n    render: () => (\n        <div style={FOOTER_CONTAINER}>\n            <Button variant='primary' size='md' fullWidth onPress={() => undefined} testId='button-full-width'>\n                Continue\n            </Button>\n        </div>\n    ),\n};\n\nexport const OnePrimary: Story = {\n    parameters: {\n        docs: {\n            description: { story: 'One `primary` sets the priority; supporting actions step down to `secondary`.' },\n        },\n    },\n    render: () => (\n        <HStack gap={12} align='center'>\n            <Button variant='secondary' size='md' onPress={() => undefined} testId='button-do-cancel'>\n                Cancel\n            </Button>\n            <Button variant='primary' size='md' onPress={() => undefined} testId='button-do-save'>\n                Save changes\n            </Button>\n        </HStack>\n    ),\n};\n\nexport const TwoPrimaries: Story = {\n    parameters: {\n        docs: {\n            description: {\n                story: 'Two saturated `primary` buttons compete — neither reads as the priority.',\n            },\n        },\n    },\n    render: () => (\n        <HStack gap={12} align='center'>\n            <Button variant='primary' size='md' onPress={() => undefined} testId='button-dont-cancel'>\n                Cancel\n            </Button>\n            <Button variant='primary' size='md' onPress={() => undefined} testId='button-dont-save'>\n                Save changes\n            </Button>\n        </HStack>\n    ),\n};\n\nexport const StateMatrix: Story = {\n    parameters: {\n        docs: {\n            description: {\n                story:\n                    'Every `variant` × `size` × state, for both text and icon-only buttons. Rows are variants; ' +\n                    'columns are default / disabled / loading.',\n            },\n        },\n    },\n    render: () => (\n        <VStack gap={24}>\n            <MatrixSection kind='text' />\n            <MatrixSection kind='icon' />\n        </VStack>\n    ),\n};\n\nexport const DarkTheme: Story = {\n    globals: { theme: 'dark' },\n    parameters: {\n        docs: { description: { story: 'Every `variant` on the dark surface, text and icon-only.' } },\n    },\n    render: () => (\n        <VStack gap={16}>\n            <HStack gap={12} align='center'>\n                {BUTTON_VARIANTS.map(variant => (\n                    <Button\n                        key={variant}\n                        variant={variant}\n                        size='md'\n                        onPress={() => undefined}\n                        testId={`button-dark-${variant}`}\n                    >\n                        {variant}\n                    </Button>\n                ))}\n            </HStack>\n            <HStack gap={12} align='center'>\n                {BUTTON_VARIANTS.map(variant => (\n                    <Button\n                        key={variant}\n                        variant={variant}\n                        size='md'\n                        icon={<Icon name='arrow-right' size='small' />}\n                        ariaLabel={`${variant} icon`}\n                        onPress={() => undefined}\n                        testId={`button-dark-icon-${variant}`}\n                    />\n                ))}\n            </HStack>\n        </VStack>\n    ),\n};\n\nfunction MatrixSection({ kind }: { kind: 'text' | 'icon' }) {\n    return (\n        <VStack gap={16}>\n            <Text variant='h5'>{kind === 'text' ? 'Text buttons' : 'Icon buttons'}</Text>\n            {BUTTON_SIZES.map(size => (\n                <VStack key={size} gap={8}>\n                    <Text variant='body-small' color='secondary'>\n                        {SIZE_LABELS[size]}\n                    </Text>\n                    {BUTTON_VARIANTS.map(variant => (\n                        <HStack key={variant} gap={12} align='center'>\n                            <Text variant='body-small' color='secondary'>\n                                {variant}\n                            </Text>\n                            {BUTTON_STATES.map(state => (\n                                <MatrixButton key={state.key} kind={kind} variant={variant} size={size} state={state} />\n                            ))}\n                        </HStack>\n                    ))}\n                </VStack>\n            ))}\n        </VStack>\n    );\n}\n\nfunction MatrixButton({\n    kind,\n    variant,\n    size,\n    state,\n}: {\n    kind: 'text' | 'icon';\n    variant: ButtonVariant;\n    size: ButtonSize;\n    state: ButtonState;\n}) {\n    const testId = `button-${kind}-${variant}-${size}-${state.key}`;\n\n    if (kind === 'icon') {\n        return (\n            <Button\n                variant={variant}\n                size={size}\n                icon={<Icon name='arrow-right' size='small' />}\n                ariaLabel={`${variant} ${size} ${state.label}`}\n                onPress={() => undefined}\n                testId={testId}\n                {...state.props}\n            />\n        );\n    }\n\n    return (\n        <Button variant={variant} size={size} onPress={() => undefined} testId={testId} {...state.props}>\n            {state.label}\n        </Button>\n    );\n}\n"
  },
  "platforms": {
    "implemented": [
      "web"
    ],
    "native": "Imported design guidance only; no native implementation or parity verification in this preview.",
    "react": {
      "implementation": "local",
      "status": "preview",
      "parity": "web-reference"
    },
    "vue": {
      "implementation": "absent",
      "parity": "not-verified",
      "status": "reference-only"
    },
    "swift": {
      "implementation": "absent",
      "parity": "not-verified",
      "status": "reference-only"
    },
    "kotlin": {
      "implementation": "absent",
      "parity": "not-verified",
      "status": "reference-only"
    }
  },
  "links": {
    "human": "/component-button",
    "json": "/data/components/button.json",
    "markdown": "/data/components/button.md",
    "storybook": "/storybook/?path=/story/cloaked-design-system-primitives-button--playground"
  },
  "contract_status": "preview",
  "contract_kind": "curated",
  "approval": "required",
  "api": {
    "method": "typescript-type-checker",
    "typescript_version": "5.9.3",
    "public_export": "Button",
    "public_path": "Button",
    "import_path": "@cloakedinc/design-system",
    "root_kind": "component",
    "entrypoints": [
      {
        "name": "Button",
        "signature": 1,
        "visibility": "public",
        "source": {
          "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
          "line": 80
        },
        "props_type": "ButtonProps",
        "props": [
          {
            "name": "children",
            "type": "React.ReactNode",
            "declared_type": "React.ReactNode",
            "required": false,
            "description": "Icon buttons do not render visible text.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 46
            }
          },
          {
            "name": "leading",
            "type": "React.ReactNode",
            "declared_type": "React.ReactNode",
            "required": false,
            "description": "Optional leading visual, usually an Icon.\nIcon-only buttons do not support a separate leading slot.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 48
            }
          },
          {
            "name": "trailing",
            "type": "React.ReactNode",
            "declared_type": "React.ReactNode",
            "required": false,
            "description": "Optional trailing visual, usually an Icon.\nIcon-only buttons do not support a separate trailing slot.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 50
            }
          },
          {
            "name": "icon",
            "type": "never",
            "declared_type": "never",
            "required": false,
            "description": "Text buttons use leading/trailing slots instead of icon-only glyphs.\nThe button's only content; its presence is what selects this shape.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 52
            },
            "forbidden": true
          },
          {
            "name": "variant",
            "type": "ButtonVariant",
            "declared_type": "ButtonVariant",
            "required": true,
            "description": "Visual treatment by action hierarchy.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 18
            },
            "values": [
              "link",
              "primary",
              "secondary",
              "tertiary"
            ],
            "values_complete": true
          },
          {
            "name": "tone",
            "type": "ButtonTone | undefined",
            "declared_type": "ButtonTone",
            "required": false,
            "description": "Semantic action tone, independent of hierarchy.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 20
            },
            "values": [
              "danger",
              "default"
            ],
            "values_complete": true,
            "default": "'default'",
            "default_kind": "source-expression"
          },
          {
            "name": "size",
            "type": "ButtonSize",
            "declared_type": "ButtonSize",
            "required": true,
            "description": "Height and padding tier; icon-only buttons use their own square size for each tier.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 22
            },
            "values": [
              "md",
              "sm"
            ],
            "values_complete": true
          },
          {
            "name": "onPress",
            "type": "(() => void) | undefined",
            "declared_type": "() => void",
            "required": false,
            "description": "Fires on tap. Omitted, the button renders inert without looking disabled.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 24
            }
          },
          {
            "name": "disabled",
            "type": "boolean | undefined",
            "declared_type": "boolean",
            "required": false,
            "description": "Blocks presses and dims the button. Use `loading` when the block is an in-flight action.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 26
            },
            "values": [
              false,
              true
            ],
            "values_complete": true
          },
          {
            "name": "loading",
            "type": "boolean | undefined",
            "declared_type": "boolean",
            "required": false,
            "description": "Shows the loading treatment and prevents interaction.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 28
            },
            "values": [
              false,
              true
            ],
            "values_complete": true
          },
          {
            "name": "fullWidth",
            "type": "boolean | undefined",
            "declared_type": "boolean",
            "required": false,
            "description": "Stretches the button to the width of its parent.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 30
            },
            "values": [
              false,
              true
            ],
            "values_complete": true
          },
          {
            "name": "ariaLabel",
            "type": "string | undefined",
            "declared_type": "string",
            "required": false,
            "description": "Accessible label for icon-only buttons.\nAccessible label for the icon-only button.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 32
            }
          },
          {
            "name": "className",
            "type": "string | undefined",
            "declared_type": "string",
            "required": false,
            "description": "",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 33
            }
          },
          {
            "name": "style",
            "type": "React.CSSProperties | undefined",
            "declared_type": "React.CSSProperties",
            "required": false,
            "description": "",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 34
            }
          },
          {
            "name": "haptic",
            "type": "HapticFeedback | undefined",
            "declared_type": "HapticFeedback",
            "required": false,
            "description": "Haptic feedback for successful presses. Defaults to `true` (`light`).",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 36
            },
            "values": [
              "error",
              "heavy",
              "light",
              "medium",
              "selection",
              "success",
              "warning",
              false,
              true
            ],
            "values_complete": true,
            "default": "true",
            "default_kind": "source-expression"
          },
          {
            "name": "testId",
            "type": "string | undefined",
            "declared_type": "string",
            "required": false,
            "description": "Selector on the `<button>` itself; nothing inside derives from it.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
              "line": 38
            }
          }
        ],
        "branches": [
          {
            "name": "TextButtonProps",
            "props": [
              {
                "name": "children",
                "type": "React.ReactNode",
                "declared_type": "React.ReactNode",
                "required": true,
                "description": "",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 46
                }
              },
              {
                "name": "leading",
                "type": "React.ReactNode",
                "declared_type": "React.ReactNode",
                "required": false,
                "description": "Optional leading visual, usually an Icon.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 48
                }
              },
              {
                "name": "trailing",
                "type": "React.ReactNode",
                "declared_type": "React.ReactNode",
                "required": false,
                "description": "Optional trailing visual, usually an Icon.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 50
                }
              },
              {
                "name": "icon",
                "type": "never",
                "declared_type": "never",
                "required": false,
                "description": "Text buttons use leading/trailing slots instead of icon-only glyphs.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 52
                },
                "forbidden": true
              },
              {
                "name": "variant",
                "type": "ButtonVariant",
                "declared_type": "ButtonVariant",
                "required": true,
                "description": "Visual treatment by action hierarchy.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 18
                },
                "values": [
                  "link",
                  "primary",
                  "secondary",
                  "tertiary"
                ],
                "values_complete": true
              },
              {
                "name": "tone",
                "type": "ButtonTone | undefined",
                "declared_type": "ButtonTone",
                "required": false,
                "description": "Semantic action tone, independent of hierarchy.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 20
                },
                "values": [
                  "danger",
                  "default"
                ],
                "values_complete": true,
                "default": "'default'",
                "default_kind": "source-expression"
              },
              {
                "name": "size",
                "type": "ButtonSize",
                "declared_type": "ButtonSize",
                "required": true,
                "description": "Height and padding tier; icon-only buttons use their own square size for each tier.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 22
                },
                "values": [
                  "md",
                  "sm"
                ],
                "values_complete": true
              },
              {
                "name": "onPress",
                "type": "(() => void) | undefined",
                "declared_type": "() => void",
                "required": false,
                "description": "Fires on tap. Omitted, the button renders inert without looking disabled.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 24
                }
              },
              {
                "name": "disabled",
                "type": "boolean | undefined",
                "declared_type": "boolean",
                "required": false,
                "description": "Blocks presses and dims the button. Use `loading` when the block is an in-flight action.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 26
                },
                "values": [
                  false,
                  true
                ],
                "values_complete": true
              },
              {
                "name": "loading",
                "type": "boolean | undefined",
                "declared_type": "boolean",
                "required": false,
                "description": "Shows the loading treatment and prevents interaction.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 28
                },
                "values": [
                  false,
                  true
                ],
                "values_complete": true
              },
              {
                "name": "fullWidth",
                "type": "boolean | undefined",
                "declared_type": "boolean",
                "required": false,
                "description": "Stretches the button to the width of its parent.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 30
                },
                "values": [
                  false,
                  true
                ],
                "values_complete": true
              },
              {
                "name": "ariaLabel",
                "type": "string | undefined",
                "declared_type": "string",
                "required": false,
                "description": "Accessible label for icon-only buttons.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 32
                }
              },
              {
                "name": "className",
                "type": "string | undefined",
                "declared_type": "string",
                "required": false,
                "description": "",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 33
                }
              },
              {
                "name": "style",
                "type": "React.CSSProperties | undefined",
                "declared_type": "React.CSSProperties",
                "required": false,
                "description": "",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 34
                }
              },
              {
                "name": "haptic",
                "type": "HapticFeedback | undefined",
                "declared_type": "HapticFeedback",
                "required": false,
                "description": "Haptic feedback for successful presses. Defaults to `true` (`light`).",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 36
                },
                "values": [
                  "error",
                  "heavy",
                  "light",
                  "medium",
                  "selection",
                  "success",
                  "warning",
                  false,
                  true
                ],
                "values_complete": true,
                "default": "true",
                "default_kind": "source-expression"
              },
              {
                "name": "testId",
                "type": "string | undefined",
                "declared_type": "string",
                "required": false,
                "description": "Selector on the `<button>` itself; nothing inside derives from it.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 38
                }
              }
            ]
          },
          {
            "name": "IconButtonProps",
            "props": [
              {
                "name": "icon",
                "type": "React.ReactNode",
                "declared_type": "React.ReactNode",
                "required": true,
                "description": "The button's only content; its presence is what selects this shape.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 60
                }
              },
              {
                "name": "ariaLabel",
                "type": "string",
                "declared_type": "string",
                "required": true,
                "description": "Accessible label for the icon-only button.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 62
                }
              },
              {
                "name": "children",
                "type": "never",
                "declared_type": "never",
                "required": false,
                "description": "Icon buttons do not render visible text.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 64
                },
                "forbidden": true
              },
              {
                "name": "leading",
                "type": "never",
                "declared_type": "never",
                "required": false,
                "description": "Icon-only buttons do not support a separate leading slot.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 66
                },
                "forbidden": true
              },
              {
                "name": "trailing",
                "type": "never",
                "declared_type": "never",
                "required": false,
                "description": "Icon-only buttons do not support a separate trailing slot.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 68
                },
                "forbidden": true
              },
              {
                "name": "variant",
                "type": "ButtonVariant",
                "declared_type": "ButtonVariant",
                "required": true,
                "description": "Visual treatment by action hierarchy.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 18
                },
                "values": [
                  "link",
                  "primary",
                  "secondary",
                  "tertiary"
                ],
                "values_complete": true
              },
              {
                "name": "tone",
                "type": "ButtonTone | undefined",
                "declared_type": "ButtonTone",
                "required": false,
                "description": "Semantic action tone, independent of hierarchy.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 20
                },
                "values": [
                  "danger",
                  "default"
                ],
                "values_complete": true,
                "default": "'default'",
                "default_kind": "source-expression"
              },
              {
                "name": "size",
                "type": "ButtonSize",
                "declared_type": "ButtonSize",
                "required": true,
                "description": "Height and padding tier; icon-only buttons use their own square size for each tier.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 22
                },
                "values": [
                  "md",
                  "sm"
                ],
                "values_complete": true
              },
              {
                "name": "onPress",
                "type": "(() => void) | undefined",
                "declared_type": "() => void",
                "required": false,
                "description": "Fires on tap. Omitted, the button renders inert without looking disabled.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 24
                }
              },
              {
                "name": "disabled",
                "type": "boolean | undefined",
                "declared_type": "boolean",
                "required": false,
                "description": "Blocks presses and dims the button. Use `loading` when the block is an in-flight action.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 26
                },
                "values": [
                  false,
                  true
                ],
                "values_complete": true
              },
              {
                "name": "loading",
                "type": "boolean | undefined",
                "declared_type": "boolean",
                "required": false,
                "description": "Shows the loading treatment and prevents interaction.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 28
                },
                "values": [
                  false,
                  true
                ],
                "values_complete": true
              },
              {
                "name": "fullWidth",
                "type": "boolean | undefined",
                "declared_type": "boolean",
                "required": false,
                "description": "Stretches the button to the width of its parent.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 30
                },
                "values": [
                  false,
                  true
                ],
                "values_complete": true
              },
              {
                "name": "className",
                "type": "string | undefined",
                "declared_type": "string",
                "required": false,
                "description": "",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 33
                }
              },
              {
                "name": "style",
                "type": "React.CSSProperties | undefined",
                "declared_type": "React.CSSProperties",
                "required": false,
                "description": "",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 34
                }
              },
              {
                "name": "haptic",
                "type": "HapticFeedback | undefined",
                "declared_type": "HapticFeedback",
                "required": false,
                "description": "Haptic feedback for successful presses. Defaults to `true` (`light`).",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 36
                },
                "values": [
                  "error",
                  "heavy",
                  "light",
                  "medium",
                  "selection",
                  "success",
                  "warning",
                  false,
                  true
                ],
                "values_complete": true,
                "default": "true",
                "default_kind": "source-expression"
              },
              {
                "name": "testId",
                "type": "string | undefined",
                "declared_type": "string",
                "required": false,
                "description": "Selector on the `<button>` itself; nothing inside derives from it.",
                "source": {
                  "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
                  "line": 38
                }
              }
            ]
          }
        ],
        "constraints": [
          {
            "kind": "union",
            "rule": "Props must satisfy one complete branch; a forbidden prop cannot be supplied.",
            "branches": [
              "TextButtonProps",
              "IconButtonProps"
            ]
          }
        ],
        "extraction_status": "extracted"
      }
    ],
    "type_sources": [
      {
        "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
        "line": 8,
        "name": "ButtonVariant",
        "code": "export type ButtonVariant = 'primary' | 'secondary' | 'tertiary' | 'link';"
      },
      {
        "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
        "line": 9,
        "name": "ButtonSize",
        "code": "export type ButtonSize = 'sm' | 'md';"
      },
      {
        "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
        "line": 10,
        "name": "ButtonTone",
        "code": "export type ButtonTone = 'default' | 'danger';"
      },
      {
        "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
        "line": 16,
        "name": "ButtonBaseProps",
        "code": "interface ButtonBaseProps {\n    /** Visual treatment by action hierarchy. */\n    variant: ButtonVariant;\n    /** Semantic action tone, independent of hierarchy. */\n    tone?: ButtonTone;\n    /** Height and padding tier; icon-only buttons use their own square size for each tier. */\n    size: ButtonSize;\n    /** Fires on tap. Omitted, the button renders inert without looking disabled. */\n    onPress?: () => void;\n    /** Blocks presses and dims the button. Use `loading` when the block is an in-flight action. */\n    disabled?: boolean;\n    /** Shows the loading treatment and prevents interaction. */\n    loading?: boolean;\n    /** Stretches the button to the width of its parent. */\n    fullWidth?: boolean;\n    /** Accessible label for icon-only buttons. */\n    ariaLabel?: string;\n    className?: string;\n    style?: React.CSSProperties;\n    /** Haptic feedback for successful presses. Defaults to `true` (`light`). */\n    haptic?: HapticFeedback;\n    /** Selector on the `<button>` itself; nothing inside derives from it. */\n    testId?: string;\n}"
      },
      {
        "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
        "line": 45,
        "name": "TextButtonProps",
        "code": "interface TextButtonProps extends ButtonBaseProps {\n    children: React.ReactNode;\n    /** Optional leading visual, usually an Icon. */\n    leading?: React.ReactNode;\n    /** Optional trailing visual, usually an Icon. */\n    trailing?: React.ReactNode;\n    /** Text buttons use leading/trailing slots instead of icon-only glyphs. */\n    icon?: never;\n}"
      },
      {
        "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
        "line": 58,
        "name": "IconButtonProps",
        "code": "interface IconButtonProps extends ButtonBaseProps {\n    /** The button's only content; its presence is what selects this shape. */\n    icon: React.ReactNode;\n    /** Accessible label for the icon-only button. */\n    ariaLabel: string;\n    /** Icon buttons do not render visible text. */\n    children?: never;\n    /** Icon-only buttons do not support a separate leading slot. */\n    leading?: never;\n    /** Icon-only buttons do not support a separate trailing slot. */\n    trailing?: never;\n}"
      },
      {
        "path": "packages/design-system/src/components/primitives/Button/Button.tsx",
        "line": 74,
        "name": "ButtonProps",
        "code": "export type ButtonProps = TextButtonProps | IconButtonProps;"
      },
      {
        "path": "packages/design-system/src/tokens/CdsHaptic.ts",
        "line": 6,
        "name": "HapticFeedback",
        "code": "export type HapticFeedback = boolean | HapticType;"
      },
      {
        "path": "packages/design-system/src/tokens/HapticType.ts",
        "line": 2,
        "name": "HapticType",
        "code": "export type HapticType = 'light' | 'medium' | 'heavy' | 'success' | 'warning' | 'error' | 'selection';"
      }
    ],
    "defaults_policy": "Only explicit destructured parameter initializers are extracted. Other runtime defaults remain in implementation source."
  },
  "missing_facts": [
    {
      "code": "human-review-pending",
      "detail": "This local preview has no recorded human design or engineering sign-off."
    },
    {
      "code": "platform-parity-unverified",
      "detail": "Vue, Swift and Kotlin implementations are absent from this package; platform parity has not been verified."
    },
    {
      "code": "figma-mapping-unverified",
      "detail": "No current component-level Figma node and immutable revision have been verified for this contract."
    }
  ],
  "review": {
    "local_status": "not-reviewed",
    "source_approval": null,
    "imported_spec_status": "approved",
    "spec_origin": "imported-adapted",
    "local_spec_source_status": "preview",
    "imported_source_revision": "f96f416e1c3bfbfaffcd155a88b87b18b8bb25f1",
    "note": "Inherited specification status is provenance, not approval of the current local implementation or extracted contract."
  }
}
