Minor release covering eight new blueprint primitive components, an Artisan
command suite for scaffolding / diagnostics / asset publishing / AI-tooling
integration / machine-readable manifests, the Livewire sandbox primitives library,
and a security-hardening sweep across `target="_blank"` link rendering plus the
JSON-encoder layer.

No breaking changes — fully backward-compatible with v1.2.x.

### Added

- **Blueprint primitive components (8)** — `<x-wirekit::price>` (currency formatting with size variants), `<x-wirekit::date-separator>` (timeline / chat date divider), `<x-wirekit::reaction>` (emoji reaction button with count), `<x-wirekit::ticker>` (live data ticker with delta indicator), `<x-wirekit::toolbar>` (button group bar with slots), `<x-wirekit::message>` (chat / thread message bubble with alignment), `<x-wirekit::kanban>` and `<x-wirekit::kanban-column>` (kanban board with column composition). All use design tokens exclusively, support the Intent × Surface API where applicable, and follow WAI-ARIA patterns.
- **Sandbox primitives library** (`src/Sandbox/`) — reusable security-hardened render pipeline for any developer project that needs to render WireKit components from untrusted JSON props (live-preview iframes, prop-editor UIs, etc.):
  - **`SandboxRenderer::render($component, $props, $ip): RenderResult`** — main entry point. Validates → sanitizes → renders → audit-logs. Returns `RenderResult` (success or 422-shaped rejection); never throws.
  - **`PropsValidator`** — enforces per-component prop schema, type-checks, rejects strings >10 KB and arrays nested >5 deep (DoS defense), HTML-escapes every string defense-in-depth so even a slot using `{!! !!}` cannot surface raw payload content.
  - **`ComponentAllowlist`** — strict kebab-case regex + `ComponentRegistry` cross-check + sandbox-schema presence guard. Path-traversal characters, namespace separators, whitespace, uppercase — all rejected with 422-shape, never 500.
  - **`SandboxSchemaRegistry`** — in-memory registry of per-component prop allowlists with `allowed_values` enums. Initial coverage of 11 starter components (button, badge, callout, alert, card, code, code-block, kbd, heading, text, link); the renderer is functional with whatever schemas are seeded, full coverage will follow incrementally.
  - **`SandboxAuditLog`** — file-based daily-rotating log (`storage/logs/sandbox/YYYY-MM-DD.log`). IPs sha256-truncated to 16 chars so logs are useful for rate-pattern auditing but not for tracking individuals.
  - **`RenderResult` / `ValidationResult`** — immutable result objects with public-readable `ok` / `violations` / `html` / `schema` properties so developer-side prop-editor UIs can read them via `get_object_vars()`.

- **`<x-wirekit::ticker>` dark-mode contrast fix** — switched the delta text from the bare `--color-wk-success` / `--color-wk-danger` foundation tokens to the `*-text` variants (which are calibrated for ≥4.5:1 WCAG 1.4.3 contrast against surface tokens in BOTH light and dark mode).
- **`.cursor/rules/wirekit.mdc`** — single-file (~150-line) Cursor rules ruleset covering component invocation syntax, the Intent × Surface variant system, design tokens, icon usage, layout primitives, typography primitives, modal / drawer / dropdown trigger patterns, accessibility defaults, Livewire integration patterns, browser-support baseline, and the full CLI. Cursor / Codeium / other native `.mdc` editors pick up the rules automatically for every `*.blade.php` and `*.css` file in the project.
- **`php artisan wirekit:component {name}`** — scaffolds a custom Blade component derived from a WireKit base into `resources/views/components/custom/{name}.blade.php`. `--base` flag picks the source; `--force` allows overwriting an existing custom file. Resolves both flat (`button`) and dotted (`card.header`) base names. (The v2.0.0 default of `--base={name}` was superseded in v2.1.0 by a derived-parent default — `wirekit:component my-button` now derives `--base=button` automatically; see the v2.1.0 entry.)
- **`php artisan wirekit:publish-icons {preset}`** — targeted icon publishing. Copies a single preset's SVG directory from `vendor/{package}/resources/svg/` to `public/vendor/wirekit/icons/{preset}/`. Refuses with a precise `composer require ...` fix line when the underlying icon-set package is not installed. Supports `heroicons`, `heroicons-app`, `heroicons-marketing`, `lucide`, `phosphor`, `tabler`.
- **`php artisan wirekit:doctor`** — alias for `wirekit:verify` under the more conventional Laravel-ecosystem name. Existing CI scripts and docs that reference either name keep working. (The v2.0.0 shipped two parallel registrations; v2.1.0 collapses them to a single Symfony alias — see the v2.1.0 `### Changed` entry for the internal-import consequence.)
- **`php artisan wirekit:cursor-rules`** — copies the package's `.cursor/rules/wirekit.mdc` into the developer project's `.cursor/rules/` directory. `--force` to overwrite an existing copy.
- **`php artisan wirekit:export-api-map [--pretty]`** — emits an AI-friendly hierarchical sitemap covering eight groups: components, themes, fonts, icons, layouts, blueprints, recipes, and commands. Superset of `wirekit:export-json`. Output is XSS-safe via `JSON_HEX_TAG`. Designed for MCP servers and other AI tooling that need a single entry point to enumerate every WireKit surface.
- **`php artisan wirekit:export-blocks [--pretty]`** — emits a machine-readable JSON manifest of every layout + blueprint with frontmatter metadata (`category`, `tags`, `dependencies`, `responsive`, `dark_compatible`) plus generated `preview_url` and `source_url`. Consumable by gallery UIs and AI tooling for filterable browsing.
- **Password input accessibility** — toggle button has a static `aria-label` fallback for pre-Alpine-hydration accessibility scans.
- **Toggle auto-labeling** — component auto-generates an `aria-label` from the `name` prop when neither `label` nor `aria-label` is provided.
- **Config defaults** — `config/wirekit.php` ships size defaults for `<x-wirekit::price>` and `<x-wirekit::ticker>`.

### Changed

- **`Pushery\WireKit\Sandbox\RenderResult`** now carries a public-readable `?array $schema` property in addition to `ok` / `html` / `violations`. `SandboxRenderer::success()` echoes the per-component schema back so developer-side prop-editor UIs can render the editor without a second round-trip to the schema registry.
- **`target="_blank"` auto-protection hardened** — the `rel` attribute injection in all 13 link-rendering components (Button, Dropdown Item, Command Palette Item, Menubar Item, Navigation Menu Item, Navigation Menu Link, Navbar Item, Sidebar Item, Link, Brand, Card) now uses an explicit override pattern that prevents caller-supplied `rel` values from silently defeating the `noopener noreferrer` protection. Coverage extended to four additional components that were previously missing the pattern: Link, Navbar Item, Navigation Menu Link, and Sidebar Item.
- **Chart.js dark-mode refresh** — `chart.update()` replaces `chart.update('none')` in the MutationObserver callback. Chart.js v4's `'none'` mode skips the style-resolver pass when only color properties change, leaving stale colors rendered. The observer now watches both `<html>` and `<body>` for `.dark` class changes, supporting both mounting conventions.

### Fixed

- **WCAG 1.4.3 dark-mode contrast on `<x-wirekit::ticker>` delta text** — the `--color-wk-success` / `--color-wk-danger` foundation tokens previously yielded 3.66:1 / 4.05:1 against dark surface tokens (fails the 4.5:1 AA threshold for small text). Fix uses the `*-text` token variants which are calibrated for ≥4.5:1 in both modes.
- **CTA accent variant dark-mode contrast** — the accent variant used a hardcoded `text-white` class that fails when `--color-wk-accent` inverts in dark mode. Now uses `text-[var(--color-wk-accent-fg)]` which auto-switches correctly.
- **Section accent background token** — the accent background variant referenced a non-existent `--color-wk-primary` CSS variable. Replaced with `--color-wk-accent` background and `--color-wk-accent-fg` text color, matching the established pattern used by CTA and Badge.
- **Dropdown trigger ARIA** — `aria-haspopup`, `aria-expanded`, and `aria-controls` were placed on a non-interactive `<div>` wrapper. Moved to the inner interactive element via `x-init`.
- **Progress bar accessible name** — component only wired `aria-labeledby` when the `label` prop was set. Usages without labels now receive a sensible `"Progress"` default.
- **App-shell sidebar backdrop** — the mobile sidebar dim overlay was traversable by screen readers, defeating the focus-trap intent. Added `aria-hidden="true"`.
- **`dist/wirekit.css` parses correctly when loaded via `<link>`.** Previously the entire token palette lived inside a Tailwind v4 `@theme {}` compiler block. Browsers correctly skip unknown at-rules per the CSS spec, which meant the documented "fastest path" — using the `@wirekitStyles` Blade directive that embeds the file via `<link rel="stylesheet">` — left zero `--color-wk-*` variables defined in the CSSOM. Components rendered without color tokens. The file now emits a standard `:root {}` (light) and `.dark {}` (dark) block directly, so both consumption paths resolve identically: the `@wirekitStyles` directive AND `@import` from `app.css`. The `@custom-variant dark (&:where(.dark, .dark *));` directive is preserved at the top of the file (harmless under `<link>`, useful under `@import` for Tailwind `dark:` variant support).
- **WCAG 1.4.3 contrast — light-mode `*-text` and `text-muted` tokens recalibrated.** Three "soft-bg foreground" tokens were below the AA 4.5:1 threshold against the 12% `color-mix()` soft-tone backgrounds used by badge / alert / callout / feature / message / reaction / toast-region, and `text-muted` was below threshold on `bg-muted`:
  - `--color-wk-success-text`: green-700 → green-800. Was 4.33:1 on soft-success bg, now ~6.17:1.
  - `--color-wk-danger-text`: red-500 → red-700. Was 3.89:1 on soft-danger bg, now ~5.13:1.
  - `--color-wk-warning-text`: amber-700 → amber-800. Was 4.41:1 on soft-warning bg, now ~6.04:1.
  - `--color-wk-text-muted`: neutral-500 → neutral-550. Was 4.26:1 on `bg-muted` (#f7f7f7), now ~6.13:1. `text-subtle` and `text-placeholder` are unchanged (they only appear on white where neutral-500 already meets 4.74:1).

- **Bare `text-[var(--color-wk-{success,warning,danger})]` on text content swept to `*-text` variants.** Affected component-internal usages: `<x-wirekit::text>` semantic variants (`success` / `warning`), `<x-wirekit::stat>` `up` trend, `<x-wirekit::price>` delta intent (`success` / `danger`), `<x-wirekit::feature>` soft tones (`success` / `warning`). Decorative `aria-hidden` SVG icons inside alert / callout / toast-region / code-block / rating left at the bare tone (graphic-element semantics, 3:1 threshold via WCAG 1.4.11).
- **`<x-wirekit::calendar>` event chips no longer render white text on green-500 / amber-500.** Month-view and week-view event chips (`background: var(--color-wk-success); color: var(--color-wk-bg)`) yielded 3.21:1 / 2.13:1 — fail. Component now uses `color: var(--color-wk-success-fg)` / `color: var(--color-wk-warning-fg)` (zinc-900 on the tone bg — ~6.95:1 / ~9.03:1).
- **`<x-wirekit::calendar>` week-view chip subtexts collapsed.** Opacity-blended subtexts (`<span style="opacity: 0.8">…</span>`) dropped contrast below 4.5:1 in light mode (4.23:1 against the tone bg). Replaced the two-line `Primary` + opacity-dimmed subtext pattern with a single-line `Primary · Subtext` middle-dot label that passes both modes at the full token contrast.

### Security

- **`/components.json` JSON encoder hardened with `JSON_HEX_TAG`** — brings `wirekit:export-json` in line with the existing `wirekit:export-api-map` and `wirekit:export-blocks` contracts. Without `JSON_HEX_TAG`, a component description containing `</script>` could break out of a `<script type="application/ld+json">` block where the manifest is embedded.