diff --git a/.specs/banner.md b/.specs/banner.md
new file mode 100644
index 000000000..be17d7dfe
--- /dev/null
+++ b/.specs/banner.md
@@ -0,0 +1,154 @@
+---
+name: banner
+category: marketing
+structure: monolithic
+status: implemented
+spec_version: 2
+checksum: aa5819dc3d093d74004588fd8276547f0e79d431c2a081b4fe6997f20fcb08ab
+created: 2026-09-22
+last_updated: 2026-09-26
+---
+
+# Banner — Component Spec
+
+## Purpose
+
+A split promotional band: the announcement and its actions in the wide leading column, a short supporting note on a raised surface in the narrow trailing one. It is the page's one loud interruption between sections — wider and more assertive than `call-to-action`, which is a single-column closing ask.
+
+## When to use
+
+- To announce a launch, programme or offer part-way down a marketing page.
+- Whenever an announcement needs both a primary action and a short piece of supporting context beside it.
+- Once per page. A second banner turns the first into furniture.
+
+## When NOT to use
+
+- For the closing ask at the end of a page or section → use `call-to-action`, a single-column panel.
+- For the page's leading statement → use `hero`, whose `Hero.Title` owns the `h1`.
+- For a dismissible or status-bearing notice inside the product → use `message`.
+- For a feature tile in a grid → use `topic` in a `card-grid`.
+
+## Related
+
+- `call-to-action` — the single-column closing ask; this is the wider mid-page announcement.
+- `hero` — the page's leading band; its `Hero.Title` owns the page's statement and `h1`.
+- `message` — the in-product notice, which can be dismissed and carries severity.
+
+## Best practices
+
+- The band draws no frame of its own: the rule and the corner marks belong to the `section-module` or `frame-box` that the page assembles it into, so a band placed in a framed column never lands a second hairline on the column's own.
+
+- Put the announcement in `title` and keep the trailing column to one supporting sentence — it is context, not a second pitch.
+- Lead with one primary action in the `actions` slot; the band's whole job is that one target.
+- Use `eyebrow` to name the programme the banner belongs to, so the band reads in context when a reader lands mid-page.
+- Keep the trailing note short enough not to set the band's height; it sits beside the announcement, not under it.
+
+## Usage
+
+```vue
+
+
+
+
+
+
+
+
+
+```
+
+## Props
+
+| Prop | Type | Default | Required | JSDoc |
+|---|---|---|---|---|
+| `title` | `string` | `—` | true | The announcement, rendered as the band's `h2` in the leading column. |
+| `description` | `string` | `''` | false | Supporting note set on the raised trailing column; overridden by the `aside` slot. |
+| `eyebrow` | `string` | `''` | false | Short uppercase overline naming the programme, above the announcement. |
+
+## Events
+
+| _none_ | — | — |
+
+## Slots
+
+| Slot | Scope | Notes |
+|---|---|---|
+| `actions` | — | The controls the band exists to offer, under the announcement. |
+| `aside` | — | Trailing column content; replaces the `description` prop when provided. |
+
+## States
+
+- Visual states: `default`
+- The band holds no state of its own; controls composed into `actions` keep theirs
+- Below `md` the two columns stack, announcement first, so reading order matches visual order
+
+## Motion & Animations
+
+_none_
+
+## Tokens
+
+| Region | Token (DESIGN.md) |
+|---|---|
+| typography (announcement) | `.text-heading-xl` |
+| typography (trailing note) | `.text-heading-sm` |
+| announcement text | `var(--text-default)` |
+| trailing note text | `var(--text-muted)` |
+| leading surface | `var(--bg-surface)` |
+| trailing surface | `var(--bg-surface-raised)` |
+| band rules and marks | `var(--border-default)` |
+| spacing (column padding) | `var(--spacing-xxl)` |
+| spacing (copy stack) | `var(--spacing-lg)` |
+| spacing (copy to actions) | `var(--spacing-xl)` |
+
+## Theme gaps
+
+| Figma variable | Temporary primitive | Follow-up |
+|---|---|---|
+| _none_ | — | — |
+
+## Accessibility (WCAG 2.1 AA)
+
+- Visible focus: not applicable to the band itself; controls composed into `actions` keep their own `focus-visible:ring-2 focus-visible:ring-(--ring-color) focus-visible:ring-offset-2 focus-visible:ring-offset-(--bg-canvas)` ring.
+- Keyboard map: none of its own — `Tab` reaches only the controls placed in the `actions` slot, in DOM order.
+- ARIA: the announcement is a real `h2` rendered by the composed `section-title`, and the band is a `` named by its `title`, so it is reachable as a named landmark; no `role` is added.
+- Contrast ≥4.5:1 (text) / ≥3:1 (large + icons): the announcement is `var(--text-default)` on `var(--bg-surface)`; the trailing note uses `var(--text-muted)` on `var(--bg-surface-raised)`, which clears AA on the dark canvas and is a known theme-level shortfall on the light one (see `big-numbers`).
+- `motion-reduce:transition-none motion-reduce:transform-none` — not applicable, the band is static.
+- Touch target ≥40×40 px — the `actions` row stretches its children to full width below `md`, so slotted buttons keep their own target size.
+
+## Stories (Storybook)
+
+- Default
+- WithAside — the trailing column filled through the `aside` slot rather than the `description` prop (justified: the slot replaces the prop and is the only way to put richer content in that column)
+
+## 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 `