# @zendir/ui

## 0.7.1

### Patch Changes

- b361ac4a: Keep the `HexViewer` ASCII column readable in a narrow panel.

  Hex rows are a fixed-width grid, but the row and its cells were flex items with the default shrink factor, and the virtual-row wrapper was pinned to the visible width with `right: 0`. In a narrow container the ASCII column was squeezed to a single character and clipped, with no way to scroll to it. Rows now size to their content and the cells hold their width, so the hex grid scrolls horizontally instead of losing the ASCII column.

- bcd82390: Replace the CARTO dark and light basemaps with Esri Gray Canvas.

  CARTO now watermarks tiles served without an API key and returns them as HTTP 200, so the map rendered "API KEY REQUIRED" across the dark style and the tile-error fallback never triggered. Esri Gray Canvas needs no key and matches the existing satellite provider.

  Canvas ships place names as a separate reference layer, so `GroundTrackMap` now draws a matching label overlay above the base tiles. Adds the `CANVAS_LABEL_TILES` and `ESRI_CANVAS_ATTRIBUTION` exports; `getBasemapAttribution` resolves Canvas URLs to the Esri Canvas terms, which credit different sources than World Imagery.

## 0.7.0

### Minor Changes

- 339957c: New `@zendir/ui/react/icons` entry point: the full Lucide icon set (ISC license), plus six custom space-status glyphs Lucide has no equivalent for (`SatelliteTransmit`/`SatelliteReceive`/`SatelliteOff`, `AntennaTransmit`/`AntennaReceive`/`AntennaOff`). Named exports throughout — bundlers tree-shake to only the icons actually imported.

  New `Logo` component (`@zendir/ui/react/core`): the Zendir brand mark, primary wordmark lockup, and sub-brand lockups for Docs, Studio, Editor, and API. Ink color is a prop, so one asset covers every surface.

  Both are additive — no existing exports changed.

- c4b2bc0: Export the card, chart and visualization components from `@zendir/ui/react`.

  The top-level React barrel re-exported some sub-barrels but never wired in
  `cards` or `visualizations`, and cherry-picked from `charts` rather than
  re-exporting it. Around sixty components and their prop/data types were
  therefore public one level down while being unreachable from the entry point
  consumers actually import — among them the chart family (`LineChart`,
  `AreaChart`, `BarChart`, `ScatterChart`, `PieChart`, `GaugeChart`, the 3D and
  mission-analysis charts), the cards (`SpacecraftCard`, `TelemetryCard`,
  `OrbitCard`) and the visualization cards (`NavBallCard`, `LinkBudgetCard`,
  `PropulsionCard`, `EclipseTimerCard`, `ThermalHeatmapCard`,
  `SensorFootprintCard`), plus the data types their props require.

  The three sub-barrels are now re-exported wholesale rather than through another
  hand-maintained list, since a curated barrel drifts silently every time a
  component is added — which is how this arose.

  Additive only: nothing was renamed or removed, so existing imports are
  unaffected.

- cc5084b: `ChatPanel` accepts `renderMessageContent` to render message text with a renderer
  the host supplies.

  The built-in renderer covers `**bold**`, `` `code` `` and fenced code blocks, but
  not lists, tables or links — so an assistant instructed to answer in numbered
  steps has every one of them shown as literal text. A markdown renderer is a
  dependency this package does not carry, so the prop hands that choice, and its
  bundle cost, to the consumer.

  Omitted, the built-in renderer is used exactly as before. Blocks are unaffected
  and still render beneath the returned content.

### Patch Changes

- 949dee3: Dependency and tooling maintenance, no public API or behavior change:

  - Resolved all open Dependabot alerts by bumping transitive dev-toolchain dependencies (undici, brace-expansion, postcss, js-yaml, fast-uri, dompurify, protobufjs) via `npm audit fix`. Lockfile-only — no `package.json` ranges changed. Production dependency audit was already clean.
  - Fixed the `css-vars.ts` token generator (`scripts/build-tokens.ts`) to run its output through Prettier, so the generated file stays format-clean regardless of future token-name lengths.

## 0.6.3

### Patch Changes

- **HexViewer**: partial final rows keep full column alignment — the
  two-space pad cells no longer collapse, so the ASCII column lines up on
  the last line of any byte length.
- **Checkbox**: unchecked boxes use `border.default` instead of
  `border.muted`; themes may define the muted hairline equal to an elevated
  surface colour (nebula does), which made unchecked boxes invisible inside
  panels and dropdowns.

## 0.6.2

### Patch Changes

- **GroundTrackMap**: vector layers (tracks, footprints, terminator) render
  to canvas instead of SVG, removing the DOM churn that destabilised Safari
  on the map view.

## 0.6.1

### Patch Changes

- **ThemeProvider**: set the theme variant on `data-theme` and the mode on
  `data-mode` (previously `data-theme` carried the mode and the variant went
  to the unused `data-variant`). The generated `tokens.css` keys its blocks on
  `[data-theme="<variant>"]` / `[data-mode="light"]`, so the mismatch meant the
  static `--zendir-*` CSS variables always resolved to the default (hybrid)
  block — non-hybrid variants (nebula, astro, purple-hue) only themed via
  `useThemeTokens()`, not via CSS variables. CSS-variable consumers now get the
  selected variant. `data-variant` is retained for backward compatibility.

## 0.6.0

### Minor Changes

- **ImageGallery**: new optional `badge` field on `GalleryImage` renders an
  overlay pill on thumbnails (e.g. flagging newly downlinked images).
- **ThemeProvider**: explicit `theme`/`mode` props are now authoritative and
  no longer overridden by persisted preferences; use `defaultVariant`/
  `defaultMode` to opt into localStorage restore.
- New opt-in `nebula` theme (Prussian Slate / Ultraviolet).
- Primitive color scales are now importable from `@zendir/ui/tokens` (Zendir
  brand, Astro UXDS status, Tailwind v4.2) and emitted as `--zendir-*` CSS
  variables, so product code and charts can reference endorsed palette stops
  directly.
- Theme types and palettes extracted into dedicated modules
  (`react/theme/types`, `tokens/palettes`, `tokens/core`); public API
  unchanged.
- Toolchain security refresh: Vitest 4, Vite 8, Storybook 10 — clears every
  outstanding dependency audit advisory (production deps were already clean).

## 0.5.0

### Minor Changes

- Add a `stat` variant to `DataValue` for compact top-bar telemetry chips
  (value over a small uppercase label, status-tinted).
- Refresh `SideNav` styling and layout.

### Patch Changes

- Harden Popover first-open positioning: seed the panel's position state as
  `fixed` and gate visibility on a `positioned` flag that resets on close, so
  neither the first open nor any reopen flashes at stale coordinates.

## 0.4.1

### Patch Changes

- Fix Popover first-open positioning flash: panel now renders with
  `visibility: hidden` until the initial `requestAnimationFrame` resolves
  real coordinates, preventing the one-frame misposition on first open.

## 0.4.0

### Minor Changes

- Add `ImageFrame` widget: renders a single-channel sensor/CCD data frame
  (`number[]` of samples) as a false-colour image on a canvas, with
  fixed-ceiling normalisation, `cividis`/`gray` colormaps, an optional raw
  value grid, and loading/empty states. Purely presentational — callers
  pass the frame data in. Also exports the pure `decodeImage` helper.

### Patch Changes

- Scope the Dialog focus trap to the open transition so typing in a dialog
  input isn't interrupted when the surrounding parent re-renders.

## 0.3.0

**Upgrade from npm:** The latest public release on the registry is
[0.2.21](https://www.npmjs.com/package/@zendir/ui). This **0.3.0** release
is the next version on npm and combines the hook / 3D integration work
with the token / `react/core/` architecture pass below.

This release reframes the React hook layer around a single, well-defined
bridge from `zendir-ts` to the live `<ZenSpace3D />` surface, and
replaces three legacy SDK-coupled hooks with smaller, REST-aligned
primitives. The Cesium backend gains proper sub-satellite ground-track
alignment, and the `ZenSpace3DUtils` helper module is slimmed to only
what the live backends actually consume. It also eliminates token drift
hazards by consolidating literals, auto-generating `tokens.css`, and
reorganising `react/core/` into thematic subfolders.

### Features

- **`useSimulationScene`** — primary integration hook
  (`@zendir/ui/react/hooks` and `@zendir/ui/react/3d`). Bridges a
  `zendir-ts` `ZendirClient` to `ZenSpace3D` props: fetches
  `GetSimulationStructure` once, buckets spacecraft / ground stations /
  planets, and polls `Position_BN_N` / `Velocity_BN_N` on a configurable
  interval (default 2 s). Exports `SimulationSceneClient`,
  `SimulationSceneObject`, `StructureDiag`, `PositionTickDiag`, and
  `UseSimulationSceneResult` for typed app integration.
- **Operator 3D surface** — the hook is intended to drive a full-screen
  `ZenSpace3D` in host apps (e.g. `space-range-operator`
  `/admin/3d/:containerId/:simulationId`). Feed
  `useSimulationScene` with `containerId`, `simulationId`, and the
  session `client`.
- **`ZenSpace3DProps.referenceTime`** — new `Date` prop used by the
  Cesium backend to convert ECI/J2000 positions into the Earth-Fixed
  (ECEF) frame Cesium renders. Passing the simulation clock (sim epoch
  - sim seconds) lines the sub-satellite point on Earth up with the
    true ground track; omitting it falls back to wall-clock time and the
    ground track will drift.
- **Top-level re-exports** — `ZenSpace3D`, `useSimulationScene`, and
  their types are now available from the main `@zendir/ui/react`
  entry in addition to the `react/3d` and `react/hooks` subpaths.

### Breaking Changes

- **Removed legacy SDK hooks**: `useTelemetry`, `useSpacecraftPosition`,
  and `useSimulationTime` no longer exist. Their
  responsibilities are covered by `useSimulationScene` (live position /
  velocity bucketed onto scene objects) and by the `referenceDate` /
  `positionTickDiag` fields on its result.
- **`useAccessWindows` is now pure client-side math**. The Zendir REST
  API does not expose a server-side access-prediction endpoint, so the
  hook no longer attempts to load `zendir-ts` or fetch passes. It now
  accepts a `windows: AccessPass[]` input (compute these with your own
  propagator / SGP4 / demo data) and returns `TimerConfig` objects for
  `<MissionClock />`. Removed options: `spacecraftId`, `groundStationId`,
  `passCount`. Removed result fields: `isConnected`, `isSdkAvailable`,
  `error`. The `manualWindows` option is kept as a deprecated alias
  for `windows` for one minor.
- **Renames in `useAccessWindows`**: the `AccessWindow` type is now
  `AccessPass`, and `createDemoAccessWindows` is now
  `createDemoAccessPasses`. Update imports accordingly.
- **`ZenSpace3DUtils` pruned to the live surface**. Unused helpers were
  removed: `cartesianToLatLonAlt`, `cartesianToSpherical`,
  `sphericalToCartesian`, `eciToEcef`, `calculateGMST`,
  `dateToJulianDate`, `parseTLE`, `propagateSGP4Simple`,
  `propagateSatellite`, `generateOrbitPath`, `isVisible`,
  `calculateVisibilityConeGeometry`, `calculateFootprint`,
  `generateHexGrid`, `updateHexGridCoverage`, all vector-math helpers
  (`dot`, `cross`, `magnitude`, `normalize`, `subtract`, `add`,
  `scale`, `distance`, `lerp`), `easeInOutCubic`, `smoothstep`,
  `lerpColor`, `hexToRgb`, `getGradientColor`, `formatDuration`,
  `formatDistance`, `formatVelocity`, `formatDateTime`, and the
  constants `EARTH_MU`, `AU_KM`, `J2000_EPOCH`. Retained:
  `EARTH_RADIUS_KM`, `DEG_TO_RAD`, `RAD_TO_DEG`, `SCENE_EARTH_RADIUS`,
  `KM_TO_SCENE`, `latLonAltToCartesian`, `easeOutCubic`. For orbital
  mechanics, use a dedicated library (`satellite.js` for SGP4) or
  Cesium's built-in transforms; the Three.js path already draws
  coverage from the explicit `SatelliteCoverage` props.

### Improvements

- **`useZendirSession`** — reworked container + simulation lifecycle
  (provision container, poll until `RUNNING`, then create a simulation),
  with a new `SessionInfo` export and `preloadZendirSdk` /
  `isZendirSdkAvailable` utilities.
- **`ZenSpace3D` Cesium backend** — substantial rework
  (`ZenSpace3DCesium.tsx`) so positions streamed in J2000/ECI are
  correctly rotated into ECEF each frame using the simulation clock,
  keeping the orbit and its ground track visually consistent.
- **`ZenSpace3DTypes` docs** — updated SDK-compatibility example to the
  new `useSimulationScene` pattern and clarified that coverage geometry
  is either explicit (`footprintPolygon` / `halfAngle`) or computed
  locally by the viewer.
- **`types.ts`** — clarified that UI-domain types (`Quaternion`,
  `Vector3D`, `PointingMode`, etc.) ship with `@zendir/ui` and are not
  provided by `zendir-ts` (which is REST-only and intentionally
  minimal). Helpers like `estimateOrbitalPeriod` /
  `estimateOrbitalVelocity` are documented as client-side approximations.
- **Docs refresh** — `SDKIntegration.mdx`, `ComponentsOverview.mdx`,
  and `Introduction.mdx` updated to reflect the `zendir-ts` rename
  (previously `@zendir/sdk`) and the new hook surface.

### Migration

```tsx
// Before (0.2.x)
import {
  useTelemetry,
  useSpacecraftPosition,
  useSimulationTime,
} from "@zendir/ui/react/hooks";

// After (0.3.0)
import { useSimulationScene } from "@zendir/ui/react/hooks";

const scene = useSimulationScene({ client, containerId, simulationId });
// scene.satellites, scene.groundStations, scene.referenceDate, scene.positionTickDiag
```

```tsx
// Before (0.2.x)
import {
  useAccessWindows,
  createDemoAccessWindows,
  AccessWindow,
} from "@zendir/ui/react/hooks";

const { aosTimer, losTimer } = useAccessWindows({
  spacecraftId: "my-sat",
  groundStationId: "gs-1",
});

// After (0.3.0)
import {
  useAccessWindows,
  createDemoAccessPasses,
  AccessPass,
} from "@zendir/ui/react/hooks";

const passes: AccessPass[] = computePasses(satellite, groundStation); // your propagator
const { aosTimer, losTimer } = useAccessWindows({ windows: passes });
```

### Notes

- Consumer apps that use a published tarball should depend on
  `"@zendir/ui": "^0.3.0"`. Monorepo/local development can keep
  `"@zendir/ui": "file:../zendir-ui"`.
- After `npm publish` in this package, run `npm install` in consuming
  apps to pick up 0.3.0 (no automatic push; release is manual).

### Architecture — `core/` reorganised

The 42-file flat `react/core/` folder is split into thematic subfolders:
`inputs/`, `feedback/`, `overlays/`, `navigation/`, `data/`, `display/`,
`widgets/` (alongside the existing `layout/`).

- The `core/index.ts` barrel still exports everything by name. Consumers
  using `import { Button } from '@zendir/ui'` or `from '@zendir/ui/react/core'`
  are unaffected.
- Deep imports like `from '@zendir/ui/react/core/Button'` now resolve via
  the new path; if you have these, switch to the barrel for stability.

### Theme + a11y

- **JS-side `tokens.animation.*` honours `prefers-reduced-motion`.**
  The global CSS @media rule already stripped CSS animations; this
  extends the same behaviour to the JS-side tokens surface so animation
  libraries (Framer Motion etc.) reading `tokens.animation.fast` get
  collapsed values too.

### Removed

- Legacy `EarthViewer` and `SolarSystemViewer` 3D components (~1.6k LOC
  of dead code; superseded by `ZenSpace3D`).
- Deprecated `ChatGPTCard` alias (use `AppCard`) and `useIntrinsicHeight`
  no-op hook (use `useMaxHeight`).
- `scripts/build-tokens.js` (had its own duplicate token literal —
  replaced by `build-tokens.ts` that imports from `tokens/index.ts`).

### Internal

- `src/react/core/` reorganised — see "Architecture" above.
- Operator and dashboard verified working with new structure.
- **Toolchain** — ESLint 9 flat config (`eslint.config.js`), `typescript-eslint` v8,
  Vitest 2.1 + Vite 5.4; `npm audit fix -w @zendir/ui --legacy-peer-deps` at monorepo
  root to clear hoisted dev CVEs without `--force` onto Vite 8. Storybook 8
  `eslint-plugin-storybook` rules removed until Storybook 10+ (plugin v0.8 uses
  APIs dropped in ESLint 9).
- 284/284 tests pass; typecheck clean; build clean.

---

## 0.2.21

### Improvements

- **SidePanel**: Fixed sudden layout shift when opening/closing — width animates from `0px` smoothly during the `opening` phase (previously snapped to full width instantly, causing the flex layout to jump). Closing transition no longer drops width to `0px` instantly while the panel is still sliding out.
- **SidePanel**: Slowed transitions from `0.5s` to `0.6s` and switched to a calmer `cubic-bezier(0.2, 0.8, 0.2, 1)` ease curve for a smoother, less jarring feel — based on UX research showing 500–600ms with deceleration easing reads as "calm" without feeling sluggish.

---

## 0.2.20

### Improvements

- **SidePanel**: Smoother open/close animation — CSS transitions increased from 0.3s to 0.5s with matched JavaScript timing (550ms closing timeout) to prevent premature unmount during slide-out.

---

## 0.2.5

### Bug Fixes

- **Container**: Fixed `[object Object]` rendering when `subtitle` is a React element. Non-string subtitles (JSX) are now rendered directly below the `CardHeader` instead of being coerced via `String()`.

---

## 0.2.4

### Features

#### GroundTrackMap — Layers Panel

- **Layers icon + dropdown panel** — the top-right control bar now shows a stacked-diamond icon that opens a clean dropdown panel with two sections: **Base Map** (Dark/Satellite radio) and **Overlays** (toggle switches for Day/Night terminator, Grid Lines, and custom layers).
- **Custom layers API** — pass `customLayers: MapLayerDef[]` to add your own toggle items to the Overlays section. The map provides the toggle UI; the consumer app renders its own overlay content via `onLayerChange(layerId, enabled)`.
- **Persistent tile style** — Dark/Satellite choice is saved to `localStorage` and restored across tabs and page reloads.
- **Unified control bar** — Recenter, Layers, and Zoom (+/−) are now a single horizontal row at top-right, replacing both the old separate controls and Leaflet's native zoom.
- **Runtime overlay toggling** — built-in overlays (Terminator, Grid) can now be toggled on/off at runtime from the Layers panel without remounting the map.

### Breaking Changes

- `showMapStyleToggle` prop is still accepted but now controls whether the "Base Map" section appears in the Layers panel (default `true`).
- Leaflet's native zoom controls have been replaced by custom-styled buttons matching the Astro UXDS dark ops aesthetic.

### Documentation

- **LayersPanel** story — demonstrates the full layers panel with base map toggle and overlay switches.
- **CustomLayers** story — shows how to add developer-defined overlay toggles with `MapLayerDef[]` and respond via `onLayerChange`.

---

## 0.2.3

### Features

#### GroundTrackMap — Map Style Toggle

- **Built-in Dark / Satellite tile switcher** — when no explicit `tileUrl` is passed, a compact toggle appears below the Leaflet zoom controls allowing operators to switch between Dark (CartoDB) and Satellite (Esri World Imagery) tile layers.
- **No-flash tile swap** — toggling swaps only the tile layer without recreating the Leaflet map, preserving the current zoom, pan, and overlay state.
- **`showMapStyleToggle` prop** — defaults to `true`. Set to `false` to hide the toggle. Automatically hidden when an explicit `tileUrl` is provided (backward compatible).
- **`TILE_PRESETS`** — exported preset URLs (`dark`, `satellite`, `light`) for quick tile configuration.

#### GroundTrackMap — Terminator Boundary Line

- **Geometric terminator line** — a subtle dashed line at the 0° solar depression boundary (geometric sunset/sunrise) is now drawn on both Canvas and Leaflet backends, giving a clear visual reference for the day/night edge while the graduated fade provides the realistic transition.

#### UnifiedTimeline — Playhead Auto-Follow

- **Auto-scroll to playhead** — when the playhead marker moves near the edge of the visible chart viewport, the view auto-scrolls to keep it centered. Throttled at 300ms to avoid fighting user scrolling.
- **Smooth playhead animation** — the playhead line now uses a CSS transition (`left 0.4s linear`) for glide-smooth movement between position updates.

### Documentation

- **Map Style Toggle** story — demonstrates the built-in tile switcher with a satellite track and terminator, including opt-out patterns.
- Updated component description with Map Style Toggle feature.

### Internal

- Refactored tile layer lifecycle in `GroundTrackMapLeaflet` — tile creation is now a separate effect from map initialization, enabling smooth in-place tile swaps.
- **Fixed duplicate tile layer on mount** — the initial mount effect no longer creates a tile layer; the dedicated tile-swap effect is solely responsible, eliminating z-order conflicts that caused the terminator overlay to render behind tiles.
- **Attribution management** — tile swap effect now properly adds/removes Carto vs OSM attribution when switching tile styles.
- Map controls repositioned to bottom-left for reliable visibility across container sizes.

---

## 0.2.2

### Features

#### GroundTrackMap — Night Visualization

- **Seamless night polygon** — completely rewritten terminator geometry: sunset/sunrise curves are now computed as continuous longitude pairs, producing a single closed polygon with no antimeridian artifacts. Eliminates all "jerk" lines and rendering glitches at the poles.
- **`nightTileUrl` prop** — optional second tile layer (e.g. NASA Black Marble, VIIRS city lights) rendered beneath the terminator overlay. The graduated twilight gradient naturally masks the day-to-night tile transition. Leaflet backend only.
- **`lightSources` prop** — array of point light sources (`LightSource` interface) rendered as soft glow dots on the night side of the map. Each light is masked by the terminator: invisible in daylight, fading in through twilight, full brightness at night. Supports custom colors, radii, intensity, and labels.
- **Solar elevation masking** — light source visibility is computed per-point using the exact solar elevation angle (not polygon containment), giving a smooth and physically correct twilight fade for each individual light.

### Documentation

- **City Lights at Night** story — 35+ world cities as `lightSources`, demonstrating realistic nighttime glow.
- **City Lights Time Travel** story — interactive UTC hour slider showing lights switching on/off as the terminator sweeps.
- **Custom Light Sources** story — mission scenario with colored RF emitters, bases, and relay nodes.
- **Night Tile Layer** story — demonstrates `nightTileUrl` combined with `lightSources`.
- Updated component description with Night Tile Layer and Dynamic Light Sources sections.

### Bug Fixes

- Fixed terminator night polygon antimeridian wrapping — sunset and sunrise curves are now generated as continuous coordinate pairs (no `lon ± 180` mirroring), preventing the polygon from crossing the day side.
- Removed unused `buildBandPolygon` function from Leaflet backend.

---

## 0.2.0

### Features

#### SDK Category System (New)

- **`CategoryDef`** — shared interface for a named, colored data category (`id`, `color`, `label?`), used across Timeline, GroundTrackMap, and any future component.
- **`CategoryPalette`** — utility class that maps category IDs to stable colors and labels, with built-in fallback palettes for auto-assignment.
- **`CategoryProvider` / `useCategoryPalette`** — optional React Context for sharing a `CategoryPalette` and a custom display label (e.g. "Squad", "Division") across an entire dashboard. Fully opt-in; components work standalone without it.
- New Storybook documentation page (`SDK Category Concept`) with interactive examples, architecture diagrams, and integration guidance.

#### UnifiedTimeline

- **Team / category-aware events** — events now carry structured team identity (`id`, `color`, `label?`), enabling category-colored event bars and badges.
- **Multi-select team filter** — replaces the former boolean `teamColoredOnly` toggle; users can filter by specific teams via pill-style checkboxes.
- **`teamLabel` prop** — devs can rename "Team" to any domain-specific term (e.g. "Squad", "Division"); also readable from `CategoryProvider` context.
- **Day markers** — `showDayMarkers` draws labeled day boundaries on multi-day timelines.
- **Redesigned filter bar** — collapsible panel with Astro UX filter icon, search field moved to top header row, responsive breakpoints.
- **Performance** — bounding-box culling for `ChartView` events outside the visible viewport.

#### GroundTrackMap

- **Twilight terminator with gradient zones** — realistic Civil / Nautical / Astronomical / Full Night shading derived from solar depression angle, replacing the former hard-edge day/night line. Uses `depressionDeg` for precise boundaries.
- **Collaborative pins** — new `MapPin` interface and `pins` / `pinsEditable` / `onPinAdd` / `onPinUpdate` / `onPinRemove` props for placing colored points-of-interest synced across terminals.
- **Enhanced satellite visualization** — `showFootprint` / `footprintRadius` for sensor coverage circles, `futureTrackIndex` for solid-past / dashed-future track split, `passMarkers` for AOS/LOS diamonds.
- **Ground station antenna icons** — `dish`, `phased-array`, `omni`, and `relay` icon types with coverage circles and Astro status colors.
- **Legend overlay** — auto-generated satellite + ground station legend with status indicators.
- Category-aware pin colors via `CategoryProvider` integration.

#### SimulationControls

- Increased control-button background opacities for better visibility on dark themes.

### Documentation

- Comprehensive Storybook updates for Timeline (`WithCategoryProvider`, `MultiDayWithCategories` stories) and GroundTrackMap (`SDK Category Integration` section).
- New `CategoryConcept` Storybook page with `PaletteBasics`, `ProviderAndHook`, and `DynamicCategories` interactive stories.

### Breaking Changes

- `TimelineEvent.color` replaced by `TimelineEvent.team` (`TimelineTeam` / `CategoryDef`). Plain string colors are still accepted for backward compatibility but are treated as legacy entries.
- `TimelineFilter.teamColoredOnly` replaced by `TimelineFilter.teams` (multi-select `string[]`).

---

## 0.1.0

Initial public release.

### Features

- 60+ React components for space, air, land, and maritime operations
- Built on Astro UX Design System
- Themeable (Zen, Hybrid, Astro, Glass) with dark/light mode
- ECharts-based charting (line, area, bar, radar, treemap, sankey, and more)
- 3D viewers (Earth, Solar System, ZenSpace3D) via Three.js
- Ground track maps (Leaflet and canvas backends)
- Mission control widgets (MissionClock, SimulationControls, UnifiedTimeline)
- Layout primitives (Box, Flex, Grid, Stack, Container, SideNav, SidePanel)
- Accessibility-first (WCAG 2.2 AA oriented)
- Design tokens as JS objects and CSS custom properties
- Optional `zendir-ts` (Zendir TypeScript SDK) integration with graceful fallback
