diff --git a/.specs/copy-button.md b/.specs/copy-button.md
new file mode 100644
index 00000000..8b80b008
--- /dev/null
+++ b/.specs/copy-button.md
@@ -0,0 +1,114 @@
+---
+name: copy-button
+category: actions
+structure: monolithic
+status: approved
+spec_version: 1
+checksum: f3173c1d9c26f7a94e7c053f1a5fca826724244384859ff48fe263badbf6b0f0
+created: 2026-06-02
+last_updated: 2026-06-02
+---
+# Copy Button — Component Spec
+
+## Purpose
+
+Icon-only control that copies a string to the clipboard and briefly confirms success. Composes `IconButton` for visuals and interaction tokens.
+
+## Props
+
+| Prop | Type | Default | Required | JSDoc |
+|---|---|---|---|---|
+| `value` | `string` | `—` | yes | Text copied to the clipboard on activation. |
+| `ariaLabel` | `string` | `'Copy'` | no | Accessible name while idle. |
+| `copiedLabel` | `string` | `'Copied'` | no | Accessible name while the copied state is shown. |
+| `kind` | `'primary' \| 'secondary' \| 'outlined' \| 'transparent' \| 'danger'` | `'transparent'` | no | Visual variant forwarded to `IconButton`. |
+| `size` | `'small' \| 'medium' \| 'large'` | `'small'` | no | Size token forwarded to `IconButton`. |
+| `disabled` | `boolean` | `false` | no | Disables interaction and applies disabled tokens. |
+
+## Events
+
+| Event | Payload | Notes |
+|---|---|---|
+| `copy` | `string` | Emitted after a successful clipboard write with the copied value. |
+
+## Slots
+
+| _none_ | — | — |
+
+## States
+
+- Visual states: `default`, `copied`, `disabled`
+- `data-state` mirrors `default` or `copied`
+- `data-disabled` mirrors the `disabled` prop
+
+## Motion & Animations
+
+| Trigger | Animation / Transition | Token | Reduced-motion fallback |
+|---|---|---|---|
+| state change | `transition-colors duration-150 ease-out` (via `IconButton`) | inline | `motion-reduce:transition-none` |
+
+## Tokens
+
+| Region | Token (DESIGN.md) |
+|---|---|
+| typography | .text-button-lg |
+| surface | `var(--bg-surface)` |
+| text | `var(--text-default)` |
+| spacing | `var(--spacing-3)` |
+| shape | `var(--shape-elements)` |
+| ring | `var(--ring-color)` |
+
+## Theme gaps
+
+| Figma variable | Temporary primitive | Follow-up |
+|---|---|---|
+| _none_ | — | — |
+
+## Accessibility (WCAG 2.1 AA)
+
+- Visible focus: inherited from `IconButton` (`focus-visible:ring-2 focus-visible:ring-[var(--ring-color)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--bg-canvas)]`)
+- Keyboard map: `Tab` focuses; `Enter`/`Space` activates copy.
+- ARIA: `aria-label` toggles between `ariaLabel` and `copiedLabel` when copied.
+- Contrast ≥4.5:1 (text) / ≥3:1 (large + icons), including disabled state.
+- `motion-reduce:transition-none motion-reduce:transform-none` on animated states.
+- Touch target ≥40×40 px where the control is interactive.
+
+## Usage
+
+```vue
+
+
+
+
+
+```
+
+## Stories (Storybook)
+
+- Default
+- Disabled
+
+## Constraints — DO NOT
+
+
+
+- Do not add props beyond the Props table above. If you need a prop that is not listed, emit `BLOCKED: missing prop ` and stop — do not invent.
+- Do not add events beyond the Events table above. Same rule for slots and sub-components.
+- Do not invent imports. Every `@aziontech/webkit/*` path must exist in `packages/webkit/package.json#exports`. Every relative import must resolve to a real file. Every npm package must be installed.
+- Do not use HEX/RGB/HSL colors, Tailwind palette names (e.g. `bg-blue-500`), raw typography classes (e.g. `text-sm`), `any`, `@ts-ignore`, or `class` inside `defineProps`.
+- Do not install or import positioning/animation libraries (`@floating-ui/*`, `popper.js`, `tippy.js`, `gsap`, `framer-motion`, `motion`, `@vueuse/motion`, `@formkit/auto-animate`, drag-drop runtimes, scroll virtualization libs). Use CSS + Vue primitives (``, ``). See `.claude/rules/dependencies.md`.
+- Do not improvise animations. Every `animate-*` / `transition-*` class must come from `packages/theme/src/tokens/semantic/animations.js`; every motion-bearing class pairs with `motion-reduce:*` on the same class string; no component-local `@keyframes`.
+- Do not create class presets in JavaScript (`const kindClasses = {...}`, `const sharedClasses = [...]`, `const sizeClasses = {...}`, `const rootClasses = computed(...)`). Variants live on `data-*` attributes consumed by Tailwind `data-[attr=value]:`. All utilities live inline on the root element's `class` attribute. No `