conventions:
  data-bearing-props: >-
    Some components accept their data only via JS properties — not HTML attributes or slotted children. The catalog marks these as 'attr_map: <prop>: (js only)' and surfaces the shape under
    'prop_shapes'. Components in this family: vi-select / vi-combobox / vi-listbox / vi-listbox-popup / vi-radio-group / vi-checkbox-group (each takes 'options' as { value, label, ... }[]);
    vi-data-grid ('columns' + 'rows'); vi-matrix-table ('data'); and the chart family — vi-sparkline ('values'), vi-line-chart / vi-bar-chart ('series', plus 'categories'), vi-donut-chart
    ('segments'), vi-gauge-chart ('thresholds'), vi-funnel-chart ('stages'), vi-radar-chart ('axes' + 'series'). HTML <option> children of vi-select, attribute strings, and slotted markup are NOT read
    by these components. Assign the property after the element is connected to the DOM. See each component's 'usage' field for the working pattern.
  slots-vs-properties: >-
    Content goes in slots; data goes in JS properties. If a value is structured (an array of records, a time series, a tree), it is a JS property. If a value is visual children (a label, an icon, a
    card body), it is a slot.
  html-hidden-attribute: >-
    The standard HTML 'hidden' attribute works on every vi-* component. ViElement carries ':host([hidden]) { display: none !important }' so the attribute beats each component's ':host { display: ...
    }' rule on specificity. Use it directly: '<vi-alert hidden>' is sufficient; no wrapping <div hidden> needed. The standard 'aria-hidden', 'aria-busy', 'disabled' (where supported), and 'inert'
    attributes work as documented per component.
  overlays-top-layer: >-
    Floating overlay panels (vi-combobox listbox, vi-popover panel, vi-listbox-popup popup, vi-dropdown panel, chart hover tooltips) render in the browser's top layer via the Popover API. They escape
    ancestor 'overflow', 'transform', 'contain', clip-path, parent stacking-context tints, and shadow-DOM boundaries — so dropping any of these inside a vi-modal, vi-drawer, vi-card, or any scroll
    container Just Works. The popover-API element stays in its DOM position for events / focus / aria-controls; only its visual rendering is promoted. Browser support: Chrome 114+ / Safari 17+ /
    Firefox 125+; we feature-detect and gracefully no-op on older engines (the panel just doesn't render via popover, falls back to in-flow position: fixed).
vi-icon:
  summary: Scalable icon primitive with built-in, Font Awesome, and custom system support.
  props:
    iconRole: string
    name: string
    size: number
    system: IconSystem | ''
    faStyle: string
    iconClass: string
    label: string
  examples:
    - <vi-icon name="check"></vi-icon>
vi-alert:
  summary: >-
    Semantic status messages. Default is a full-width banner bar (sticky, saturated tone) for top-of-page system notices. Add variant="soft" for an inline page-body alert — soft tone fill, tone-700
    text, rounded, non-sticky — the better fit for messages that live within content.
  props:
    tone: "'info' | 'success' | 'warning' | 'danger'"
    variant: "'' | 'soft'"
    iconName: string
    iconSystem: string
    iconStyle: string
  slots:
    - icon
    - default
    - actions
  parts:
    - actions
    - base
    - content
    - icon
  css_vars:
    - "--vi-cmp-alert-bg"
    - "--vi-cmp-alert-danger-bg"
    - "--vi-cmp-alert-font-size"
    - "--vi-cmp-alert-font-weight"
    - "--vi-cmp-alert-icon-gap"
    - "--vi-cmp-alert-info-bg"
    - "--vi-cmp-alert-line-height"
    - "--vi-cmp-alert-padding"
    - "--vi-cmp-alert-radius"
    - "--vi-cmp-alert-soft-bg"
    - "--vi-cmp-alert-soft-border"
    - "--vi-cmp-alert-soft-danger-bg"
    - "--vi-cmp-alert-soft-danger-border"
    - "--vi-cmp-alert-soft-danger-text"
    - "--vi-cmp-alert-soft-info-bg"
    - "--vi-cmp-alert-soft-info-border"
    - "--vi-cmp-alert-soft-info-text"
    - "--vi-cmp-alert-soft-padding"
    - "--vi-cmp-alert-soft-radius"
    - "--vi-cmp-alert-soft-success-bg"
    - "--vi-cmp-alert-soft-success-border"
    - "--vi-cmp-alert-soft-success-text"
    - "--vi-cmp-alert-soft-text"
    - "--vi-cmp-alert-soft-warning-bg"
    - "--vi-cmp-alert-soft-warning-border"
    - "--vi-cmp-alert-soft-warning-text"
    - "--vi-cmp-alert-success-bg"
    - "--vi-cmp-alert-text"
    - "--vi-cmp-alert-warning-bg"
  examples:
    - <vi-alert></vi-alert>
vi-align-items:
  summary: Cross-axis alignment utility (vertical alignment in row layouts).
  props:
    variant: string
    value: "'start' | 'center' | 'end' | 'stretch' | 'baseline'"
    gap: string
  examples:
    - <vi-align-items></vi-align-items>
vi-animated-image:
  summary: Toggles between still and animated media.
  props:
    variant: string
    stillSrc: string
    animatedSrc: string
    alt: string
    playing: boolean
  parts:
    - base
    - image
    - toggle
  events:
    - vi-toggle
  css_vars:
    - "--vi-cmp-animated-image-radius"
  examples:
    - <vi-animated-image></vi-animated-image>
vi-avatar:
  summary: "Identity representation with fallback initials. Built-in variant: square (corner radius instead of circle)."
  props:
    variant: string
    src: string
    name: string
    size: number
    initials: number
  parts:
    - base
    - image
    - initials
  css_vars:
    - "--vi-cmp-avatar-bg"
  examples:
    - <vi-avatar></vi-avatar>
vi-avatar-group:
  summary: Stacked avatars with an overflow count.
  props:
    variant: string
    size: number
    overlap: number
    max: number
    overflowAriaLabel: string
  parts:
    - count
  examples:
    - <vi-avatar-group></vi-avatar-group>
vi-badge:
  summary: "Status indicator for inline contexts; supports icon slots and semantic tones. Built-in variants: outline (visible tone border), solid (filled background)."
  props:
    tone: "'neutral' | 'success' | 'warning' | 'danger' | 'info' | 'accent' | 'transparent'"
    variant: "'outline' | 'solid'"
  slots:
    - default
    - prefix
    - suffix
  css_vars:
    - "--vi-cmp-badge-gap"
    - "--vi-cmp-badge-padding-block"
    - "--vi-cmp-badge-padding-inline"
    - "--vi-cmp-badge-radius"
  examples:
    - <vi-badge></vi-badge>
    - <vi-badge><vi-icon slot="prefix" name="check"></vi-icon>In Review<vi-icon slot="suffix" name="external-link"></vi-icon></vi-badge>
    - <vi-badge tone="transparent">12</vi-badge>
vi-breadcrumb:
  summary: "Hierarchical path navigation container with configurable separators. Built-in variants: bar (pill container with hover), chevron (arrow-shaped segments with accent current item)."
  props:
    variant: string
    separator: string
  css_vars:
    - "--vi-cmp-breadcrumb-bar-bg"
    - "--vi-cmp-breadcrumb-bar-padding"
    - "--vi-cmp-breadcrumb-bar-radius"
    - "--vi-cmp-breadcrumb-chevron-depth"
    - "--vi-cmp-breadcrumb-gap"
  examples:
    - <vi-breadcrumb><vi-breadcrumb-item href="/clients">Clients</vi-breadcrumb-item><vi-breadcrumb-item current>Atlas</vi-breadcrumb-item></vi-breadcrumb>
    - <vi-breadcrumb variant="bar"><vi-breadcrumb-item href="/clients">Clients</vi-breadcrumb-item><vi-breadcrumb-item current>Overview</vi-breadcrumb-item></vi-breadcrumb>
    - <vi-breadcrumb variant="chevron"><vi-breadcrumb-item href="/clients">Clients</vi-breadcrumb-item><vi-breadcrumb-item current>Overview</vi-breadcrumb-item></vi-breadcrumb>
vi-breadcrumb-item:
  summary: Individual breadcrumb step with optional prefix icon, link, and current-page state.
  props:
    variant: string
    href: string
    current: boolean
    separator: string
    hideSeparator: boolean
  slots:
    - prefix
    - default
    - separator
  parts:
    - base
    - link
    - separator
  css_vars:
    - "--vi-cmp-breadcrumb-current-bg"
    - "--vi-cmp-breadcrumb-current-filter"
    - "--vi-cmp-breadcrumb-current-shadow"
    - "--vi-cmp-breadcrumb-current-text"
    - "--vi-cmp-breadcrumb-current-weight"
    - "--vi-cmp-breadcrumb-item-bg"
    - "--vi-cmp-breadcrumb-item-clip-path"
    - "--vi-cmp-breadcrumb-item-clip-path-first"
    - "--vi-cmp-breadcrumb-item-clip-path-last"
    - "--vi-cmp-breadcrumb-item-divider-filter"
    - "--vi-cmp-breadcrumb-item-filter"
    - "--vi-cmp-breadcrumb-item-hover-bg"
    - "--vi-cmp-breadcrumb-item-hover-text"
    - "--vi-cmp-breadcrumb-item-overlap"
    - "--vi-cmp-breadcrumb-item-overlap-last"
    - "--vi-cmp-breadcrumb-item-padding"
    - "--vi-cmp-breadcrumb-item-padding-first"
    - "--vi-cmp-breadcrumb-item-radius"
    - "--vi-cmp-breadcrumb-item-text"
    - "--vi-cmp-breadcrumb-separator-color"
    - "--vi-cmp-breadcrumb-separator-display"
  examples:
    - <vi-breadcrumb-item href="/clients">Clients</vi-breadcrumb-item>
    - <vi-breadcrumb-item current>Overview</vi-breadcrumb-item>
    - <vi-breadcrumb-item href="/clients"><vi-icon slot="prefix" name="folder" size="14"></vi-icon>Clients</vi-breadcrumb-item>
vi-button:
  summary: Represents an action available to users.
  props:
    variant: string
    tone: "'brand' | 'action' | 'secondary' | 'accent' | 'neutral' | 'danger' | 'success' | 'warning' | 'info'"
    size: "'sm' | 'md' | 'lg'"
    disabled: boolean
    type: "'button' | 'submit' | 'reset'"
    iconOnly: boolean
  slots:
    - default
    - prefix
    - suffix
  parts:
    - base
    - label
    - icon-start
    - icon-end
  events:
    - vi-click
  css_vars:
    - "--vi-cmp-button-bg"
    - "--vi-cmp-button-border"
    - "--vi-cmp-button-height-lg"
    - "--vi-cmp-button-height-md"
    - "--vi-cmp-button-height-sm"
    - "--vi-cmp-button-hover-bg"
    - "--vi-cmp-button-hover-border"
    - "--vi-cmp-button-hover-text"
    - "--vi-cmp-button-padding-inline"
    - "--vi-cmp-button-radius"
    - "--vi-cmp-button-text"
  examples:
    - <vi-button>Run</vi-button>
    - <vi-button variant="outline" tone="neutral"><vi-icon slot="prefix" name="check"></vi-icon>Run</vi-button>
    - |-
      <style>
        vi-button[variant='compact-square']::part(base) {
          border-radius: 0.25rem;
        }
      </style>
      <vi-button variant="compact-square" tone="info">Run</vi-button>
vi-button-group:
  summary: Groups related actions into a structured control.
  props:
    variant: string
    vertical: boolean
  examples:
    - <vi-button-group></vi-button-group>
vi-callout:
  summary: "Highlights important inline content with tone semantics. Variants: soft (opaque tone fill, uniform corners), tinted (translucent tone background, keeps accent border)."
  props:
    variant: string
    tone: "'info' | 'success' | 'warning' | 'danger'"
    title: string
  parts:
    - base
    - content
    - title
  css_vars:
    - "--vi-cmp-callout-border-width"
    - "--vi-cmp-callout-danger-border"
    - "--vi-cmp-callout-info-border"
    - "--vi-cmp-callout-leading-end-radius"
    - "--vi-cmp-callout-leading-start-radius"
    - "--vi-cmp-callout-radius"
    - "--vi-cmp-callout-success-border"
    - "--vi-cmp-callout-warning-border"
  examples:
    - <vi-callout></vi-callout>
vi-card:
  summary: "Flexible container for related content with header, body, and footer slots. Variants: tinted (translucent fill, no border/shadow), outlined (border only, no fill/shadow)."
  props:
    variant: string
  slots:
    - header
    - default
    - footer
  parts:
    - base
    - body
    - footer
    - header
  css_vars:
    - "--vi-cmp-card-border"
    - "--vi-cmp-card-gap"
    - "--vi-cmp-card-padding"
    - "--vi-cmp-card-radius"
    - "--vi-cmp-card-shadow"
    - "--vi-cmp-card-tinted-bg"
  examples:
    - <vi-card></vi-card>
vi-carousel:
  summary: Cycle between content slides.
  props:
    variant: string
    index: number
    prevLabel: string
    nextLabel: string
    prevIconName: string
    nextIconName: string
    prevAriaLabel: string
    nextAriaLabel: string
  slots:
    - default
    - prev-icon
    - prev-label
    - next-label
    - next-icon
  parts:
    - base
    - controls
    - live-region
    - next
    - prev
    - viewport
  events:
    - vi-change
  examples:
    - <vi-carousel></vi-carousel>
vi-carousel-item:
  summary: A single slide inside vi-carousel. Hidden unless it carries `active`.
  usage: |
    `:host` is `display: none` without the `active` attribute, so exactly
    one item must start with `active` or the carousel renders empty. After
    that the parent vi-carousel moves the attribute as `index` changes —
    do not move it yourself.
  props:
    variant: string
    active: boolean
  examples:
    - |
      <vi-carousel>
        <vi-carousel-item active><vi-card>Portfolio Snapshot</vi-card></vi-carousel-item>
        <vi-carousel-item><vi-card>Risk Changes</vi-card></vi-carousel-item>
      </vi-carousel>
vi-checkbox:
  summary: Checkbox with label and optional help text for descriptive form controls.
  props:
    variant: string
    checked: boolean
    disabled: boolean
    invalid: boolean
    label: string
    helpText: string
    value: string
  parts:
    - base
    - help-text
    - input
    - label
  events:
    - vi-change
  examples:
    - <vi-checkbox></vi-checkbox>
vi-checkbox-group:
  summary: Grouped checkbox choices with optional group help text and per-option descriptions.
  usage: |
    REQUIRED: assign `options` via JS property — it's `attribute: false`.
    No HTML <input type=checkbox> children are read. Set `value` to a
    string[] of selected option values. Option shape: { label, value, helpText? }.
  props:
    variant: string
    value: string[]
    invalid: boolean
    options: CheckboxOption[]
  prop_shapes:
    options: "CheckboxOption = { label: string; value: string; helpText?: string }"
  attr_map:
    value: (js only)
    options: (js only)
  events:
    - vi-change
  examples:
    - |
      <vi-checkbox-group id="cg" label="Notifications"></vi-checkbox-group>
      <script>
        const cg = document.getElementById('cg');
        cg.options = [
          { label: 'Comments',   value: 'comments',   helpText: 'When someone posts a comment.' },
          { label: 'Candidates', value: 'candidates', helpText: 'When a candidate applies.' },
          { label: 'Offers',     value: 'offers' }
        ];
        cg.value = ['comments'];
      </script>
vi-cluster:
  summary: Wrap items with consistent spacing.
  props:
    variant: string
    gap: string
    justify: string
  examples:
    - <vi-cluster></vi-cluster>
vi-color-button:
  summary: Compact color trigger that opens a picker popup with color history.
  props:
    variant: string
    value: string
    format: "'oklch' | 'hex' | 'rgb' | 'hsl' | 'hsv'"
    alpha: boolean
    open: boolean
    swatches: string[]
    triggerAriaLabel: string
  attr_map:
    swatches: (js only)
  parts:
    - panel
    - trigger
  events:
    - vi-change
  css_vars:
    - "--vi-cmp-color-button-border"
    - "--vi-cmp-color-button-color"
    - "--vi-cmp-color-button-radius"
    - "--vi-cmp-color-button-size"
  examples:
    - <vi-color-button></vi-color-button>
vi-color-picker:
  summary: OKLCH color picker with 2D gradient, hue slider, and format selector.
  props:
    variant: string
    value: string
    format: "'oklch' | 'hex' | 'rgb' | 'hsl' | 'hsv'"
    invalid: boolean
    swatches: string[]
    labels: ColorPickerLabels
    canvasAriaLabel: string
    hueAriaLabel: string
    swatchAriaLabel: string
    harmonyAriaLabel: string
    alpha: boolean
    alphaAriaLabel: string
  prop_shapes:
    labels: "ColorPickerLabels = { alpha: string; hex: string; red: string; green: string; blue: string; hue: string; saturation: string; lightness: string; value: string; chroma: string }"
  attr_map:
    swatches: (js only)
    labels: (js only)
  parts:
    - alpha-slider
    - base
    - canvas
    - harmonies
    - hue-slider
    - readout
    - swatch
    - swatches
  events:
    - vi-change
  css_vars:
    - "--vi-cmp-checkerboard-color"
    - "--vi-cmp-color-picker-canvas-height"
    - "--vi-cmp-color-picker-checkerboard"
    - "--vi-cmp-color-picker-thumb-border"
    - "--vi-cmp-color-picker-thumb-shadow"
    - "--vi-cmp-color-picker-width"
  examples:
    - <vi-color-picker></vi-color-picker>
vi-color-select:
  summary: Constrained color picker with group + swatch model. Supports reference palettes, semantic tokens, or a mix of both.
  props:
    variant: string
    value: string
    groups: ColorGroup[]
    open: boolean
    disabled: boolean
    invalid: boolean
    placeholder: string
    swatchDisplay: "'none' | 'plain' | 'badge'"
  prop_shapes:
    groups: "ColorGroup = { name: string; label: string; preview: string; swatches: ColorSwatch[] }"
  attr_map:
    groups: (js only)
  slots:
    - indicator-icon
  parts:
    - chevron
    - listbox
    - shades
    - trigger
  events:
    - vi-change
  css_vars:
    - "--vi-cmp-list-hover"
  examples:
    - <vi-color-select></vi-color-select>
vi-color-select-button:
  summary: Compact swatch trigger that opens a group + swatch popup.
  props:
    variant: string
    value: string
    groups: ColorGroup[]
    swatchDisplay: "'none' | 'plain' | 'badge'"
    open: boolean
    triggerAriaLabel: string
  attr_map:
    groups: (js only)
  parts:
    - panel
    - trigger
  events:
    - vi-change
  css_vars:
    - "--vi-cmp-color-select-button-border"
    - "--vi-cmp-color-select-button-color"
    - "--vi-cmp-color-select-button-radius"
    - "--vi-cmp-color-select-button-size"
  examples:
    - <vi-color-select-button></vi-color-select-button>
vi-combobox:
  summary: Editable combobox with typeahead filtering and optional label/help text.
  usage: |
    Assign `options` via JS property — it's `attribute: false`. Accepts:
      - string[]  — each string becomes both the value and the label
      - ComboboxOption[]  — { value, label?, search? }
        (label defaults to value; search defaults to label)
    The combobox ALSO supports slotted <vi-option slot="option"> children
    when rich HTML labels are needed; pick one mode per instance. Setting
    `value` selects (or pre-fills) the input. Filtering matches across
    `search`, `label`, and `value`.
  props:
    variant: string
    value: string
    options: (string | ComboboxOption)[]
    required: boolean
    invalid: boolean
    open: boolean
    placeholder: string
    clearable: boolean
    clearAriaLabel: string
    indicatorOpenAriaLabel: string
    indicatorCloseAriaLabel: string
  prop_shapes:
    options: "ComboboxOption = { value: string; label?: string; search?: string }"
  attr_map:
    options: (js only)
  slots:
    - clear-icon
    - indicator-icon
    - option
  parts:
    - chevron
    - clear
    - clear-icon
    - control
    - indicator
    - input
    - listbox
  events:
    - vi-change
    - vi-clear
    - vi-input
    - vi-select
  css_vars:
    - "--vi-cmp-check-mark"
    - "--vi-cmp-input-height"
    - "--vi-cmp-input-padding-inline"
    - "--vi-cmp-input-radius"
    - "--vi-cmp-list-check-bg"
    - "--vi-cmp-list-hover"
  examples:
    - |
      <vi-combobox id="cb" label="Sector"></vi-combobox>
      <script>
        const cb = document.getElementById('cb');
        cb.options = [
          { value: 'totp',     label: 'Authenticator (TOTP)',  search: 'otp app 2fa authy' },
          { value: 'sms',      label: 'SMS code' },
          { value: 'email',    label: 'Email OTP',             search: 'onetimepin code' }
        ];
        cb.value = 'totp';
      </script>
    - |
      <!-- string[] shorthand when value === label and no search synonyms -->
      <vi-combobox id="cb" label="Sector"></vi-combobox>
      <script>
        document.getElementById('cb').options = ['Energy', 'Financials', 'Healthcare'];
      </script>
    - |
      <!-- Slotted-option mode (rich HTML labels) -->
      <vi-combobox label="Sector">
        <vi-option slot="option" value="energy" search="oil gas utilities">Energy</vi-option>
        <vi-option slot="option" value="financials">Financials</vi-option>
      </vi-combobox>
vi-comparison:
  summary: "Before/after visual comparison with draggable split. Built-in variant: bar (full-height vertical divider line at the split point)."
  props:
    variant: string
    value: number
    sliderAriaLabel: string
  slots:
    - before
    - after
  parts:
    - after
    - base
    - before
    - handle
    - slider
  events:
    - vi-change
  css_vars:
    - "--vi-cmp-comparison-border"
    - "--vi-cmp-comparison-radius"
    - "--vi-cmp-comparison-ratio"
  examples:
    - <vi-comparison><img slot="before" src="before.png" alt="Before" /><img slot="after" src="after.png" alt="After" /></vi-comparison>
    - <vi-comparison variant="bar"><img slot="before" src="before.png" alt="Before" /><img slot="after" src="after.png" alt="After" /></vi-comparison>
vi-copy-button:
  summary: "Copies text to clipboard with feedback states. Built-in variant: ghost (transparent). Use icon-only attribute for icon-only rendering (typically paired with ghost variant)."
  props:
    variant: string
    value: string
    label: string
    copiedLabel: string
    copied: boolean
    disabled: boolean
    iconOnly: boolean
  events:
    - vi-copy
  css_vars:
    - "--vi-cmp-button-height-md"
  examples:
    - <vi-copy-button value="text" label="Copy" copied-label="Copied"></vi-copy-button>
    - <vi-copy-button variant="ghost" icon-only value="text"></vi-copy-button>
vi-data-grid:
  summary: >-
    Tabular data display. Set `columns` and `rows` as JS properties (not HTML attributes) — the grid renders nothing until both are assigned. Local filtering (default) hides rows that don't match the
    toolbar query and any per-column dropdown filters; set `filter-behavior="external"` to keep the input but receive `vi-filter` events and apply filtering yourself.
  usage: |
    REQUIRED: assign `columns` and `rows` as JS properties — they are
    `attribute: false` so HTML attributes for them are ignored. Setting
    `<vi-data-grid rows="...">` does nothing.

    Column shape (GridColumnInput, or a string shorthand that becomes
    { key: <string>, label: humanize(<string>) }):
      { key, label?, align?, headerAlign?, cellAlign?, verticalAlign?,
        wrap?, width?, sortable?, filterable?, filterOptions?,
        filterValue?, filterAllLabel? }

    Row shape (GridRow): Record<string, string | number>. Keys must
    match the columns' `key` values.

    Filter behavior:
      - `filter-behavior="local"` (default) — grid filters rows itself
        by substring match across all column keys, AND applies any
        per-column `filterValue` as exact-equality on that column's key.
      - `filter-behavior="external"` — grid emits `vi-filter` and
        `vi-column-filter-change` events; you filter and reassign rows.

    Common cause of "no matching rows": a stale `filterQuery` or a
    per-column `filterValue` is excluding everything. To clear ALL
    filters in local mode: set `grid.filterQuery = ''` and rebuild the
    `columns` array with `filterValue` removed from each column (or
    explicitly set each `column.filterValue = ''`). Re-assigning the
    same `rows` array reference will NOT trigger a re-filter on its
    own — change the array (or the filter state) to refresh.

    Events:
      - `vi-sort` — { column, direction }
      - `vi-filter` — { query } (free-text toolbar input)
      - `vi-column-filter-change` — { column, value }
      - `vi-filter-toggle` — { open }
      - `vi-row-select` — { row, selected, selectedRows }
  props:
    variant: string
    caption: string
    columns: GridColumnInput[]
    rows: GridRow[]
    rowKeyField: string
    dense: boolean
    sortable: boolean
    sortColumn: string
    sortDirection: "'none' | 'asc' | 'desc'"
    sortIconSystem: string
    sortIconStyle: string
    sortIconAscName: string
    sortIconDescName: string
    sortIconSize: number
    filterable: boolean
    filterQuery: string
    filterPlaceholder: string
    filterAriaLabel: string
    filterOpen: boolean
    filterBehavior: string
    filterIconSystem: string
    filterIconStyle: string
    filterIconName: string
    filterActiveIconName: string
    filterToggleOpenAriaLabel: string
    filterToggleCloseAriaLabel: string
    emptyStateText: string
    striped: boolean
    selectable: boolean
    selectedRows: string[]
    selectAllAriaLabel: string
    selectRowAriaLabel: string
    sortAscAriaLabel: string
    sortDescAriaLabel: string
    sortClearAriaLabel: string
  attr_map:
    columns: (js only)
    rows: (js only)
    selectedRows: (js only)
  slots:
    - empty-state
  parts:
    - base
    - empty-state
    - filter-input
    - filter-input-shell
    - filter-overlay
    - filter-toggle
    - table
  events:
    - vi-column-filter-change
    - vi-filter
    - vi-filter-toggle
    - vi-row-select
    - vi-sort
  css_vars:
    - "--vi-cmp-data-grid-filter-funnel-gap"
    - "--vi-cmp-data-grid-filter-icon-active-color"
    - "--vi-cmp-data-grid-filter-icon-color"
    - "--vi-cmp-data-grid-filter-radius"
    - "--vi-cmp-data-grid-filter-row-height"
    - "--vi-cmp-data-grid-filter-toggle-radius"
    - "--vi-cmp-data-grid-filter-top"
    - "--vi-cmp-data-grid-filter-width"
    - "--vi-cmp-data-grid-focus-radius"
    - "--vi-cmp-data-grid-sort-active"
  examples:
    - |
      <vi-data-grid id="users" sortable filterable></vi-data-grid>
      <script>
        const grid = document.getElementById('users');
        grid.columns = [
          { key: 'name', label: 'Name', sortable: true },
          { key: 'role', label: 'Role', filterable: true,
            filterOptions: [
              { value: 'admin',  label: 'Admin' },
              { value: 'editor', label: 'Editor' }
            ] }
        ];
        grid.rows = [
          { name: 'Ada Lovelace', role: 'admin' },
          { name: 'Grace Hopper', role: 'editor' }
        ];
      </script>
    - <vi-data-grid sortable filterable filter-placeholder="Search rows..."></vi-data-grid>
vi-data-grid-filter-popup:
  summary: Internal column-filter popup that vi-data-grid instantiates for itself. Not intended for direct use.
  usage: |
    vi-data-grid creates, positions, and destroys this element as part of
    its column-filter UI. Use `vi-data-grid`'s own filtering API instead;
    it is documented here only so the tag is not mistaken for an
    undocumented public component.
  props:
    variant: string
    options: GridColumnFilterOption[]
    value: string
    anchor: HTMLElement | null
  attr_map:
    options: (js only)
    anchor: (js only)
  parts:
    - listbox
  events:
    - vi-change
    - vi-close
  css_vars:
    - "--vi-cmp-data-grid-filter-active"
  examples:
    - <!-- created internally by vi-data-grid; do not instantiate directly -->
vi-calendar:
  summary: Locale-aware month calendar with keyboard navigation, single/range selection modes, min/max bounds, and selectable outside-month days.
  props:
    variant: string
    mode: "'single' | 'range'"
    value: Temporal.PlainDate | null
    start: Temporal.PlainDate | null
    end: Temporal.PlainDate | null
    min: Temporal.PlainDate | null
    max: Temporal.PlainDate | null
    locale: string
    weekStart: number
    disabled: boolean
    showOutsideDays: boolean
    showCurrentDate: boolean
    previousMonthAriaLabel: string
    nextMonthAriaLabel: string
  parts:
    - base
    - grid
    - header
    - nav-button
    - nav-next
    - nav-prev
    - title
    - week
    - weekday
    - weekday-row
  events:
    - vi-change
    - vi-clear
    - vi-input
  css_vars:
    - "--vi-cmp-calendar-bg"
    - "--vi-cmp-calendar-border"
    - "--vi-cmp-calendar-cell-gap"
    - "--vi-cmp-calendar-day-radius"
    - "--vi-cmp-calendar-gap"
    - "--vi-cmp-calendar-nav-bg"
    - "--vi-cmp-calendar-nav-border"
    - "--vi-cmp-calendar-nav-color"
    - "--vi-cmp-calendar-nav-hover-bg"
    - "--vi-cmp-calendar-nav-hover-color"
    - "--vi-cmp-calendar-nav-radius"
    - "--vi-cmp-calendar-padding"
    - "--vi-cmp-calendar-radius"
    - "--vi-cmp-calendar-range-chevron-size"
  keyboard: Arrow keys move by day, Up/Down move by week, Home/End jump to week bounds, PageUp/PageDown change month, Enter/Space select, Delete/Backspace clear.
  aria: Exposes grid semantics with row/column headers and selected-day state.
  examples:
    - <vi-calendar value="2026-02-12"></vi-calendar>
    - <vi-calendar mode="range" start="2026-02-12" end="2026-02-27"></vi-calendar>
    - <vi-calendar locale="en-GB" week-start="0" min="2026-02-01" max="2026-03-31"></vi-calendar>
vi-date-input:
  summary: "Locale-aware date input. Auto-detects format from browser settings. Variant: ghost (transparent at rest, surface on hover, full border on focus)."
  props:
    variant: string
    locale: string
    value: Temporal.PlainDate | null
    min: Temporal.PlainDate | null
    max: Temporal.PlainDate | null
    required: boolean
    disabled: boolean
    invalid: boolean
    clearable: boolean
    clearAriaLabel: string
    validators: Validator<Temporal.PlainDate | null>[]
  attr_map:
    validators: (js only)
  slots:
    - prefix
    - suffix
  parts:
    - error-text
  events:
    - vi-change
    - vi-clear
    - vi-input
  examples:
    - <vi-date-input></vi-date-input>
vi-date-range-input:
  summary: Input-like date picker with calendar trigger icon and popover panel that proxies vi-calendar options, including single/range mode.
  props:
    variant: string
    mode: "'single' | 'range'"
    value: Temporal.PlainDate | null
    start: Temporal.PlainDate | null
    end: Temporal.PlainDate | null
    min: Temporal.PlainDate | null
    max: Temporal.PlainDate | null
    locale: string
    weekStart: number
    required: boolean
    disabled: boolean
    invalid: boolean
    showOutsideDays: boolean
    showCurrentDate: boolean
    open: boolean
    placeholder: string
  parts:
    - error-text
    - icon
    - panel
    - trigger
    - value
  events:
    - vi-change
    - vi-clear
    - vi-input
  css_vars:
    - "--vi-cmp-date-range-input-bg"
    - "--vi-cmp-date-range-input-border"
    - "--vi-cmp-date-range-input-height"
    - "--vi-cmp-date-range-input-padding-inline"
    - "--vi-cmp-date-range-input-radius"
    - "--vi-cmp-input-height"
    - "--vi-cmp-input-padding-inline"
    - "--vi-cmp-input-radius"
  examples:
    - <vi-date-range-input></vi-date-range-input>
    - <vi-date-range-input start="2026-02-12" end="2026-02-27"></vi-date-range-input>
vi-time-input:
  summary: Locale-aware masked time input with optional seconds precision, min/max bounds, and hour-cycle override.
  props:
    variant: string
    locale: string
    value: Temporal.PlainTime | null
    min: Temporal.PlainTime | null
    max: Temporal.PlainTime | null
    hourCycle: "'auto' | '12' | '24'"
    showSeconds: boolean
    required: boolean
    disabled: boolean
    invalid: boolean
    clearable: boolean
    clearAriaLabel: string
    validators: Validator<Temporal.PlainTime | null>[]
  attr_map:
    validators: (js only)
  slots:
    - prefix
    - suffix
  parts:
    - error-text
  events:
    - vi-change
    - vi-clear
    - vi-input
  examples:
    - <vi-time-input></vi-time-input>
    - <vi-time-input show-seconds hour-cycle="24" min="09:30:15" max="17:00:45"></vi-time-input>
    - <vi-time-input hour-cycle="12"></vi-time-input>
vi-details:
  summary: Expand/collapse section with configurable chevron position and rich summary/body slot content.
  props:
    variant: string
    summary: string
    open: boolean
    chevronPosition: "'leading' | 'trailing'"
    collapsedIcon: string
    expandedIcon: string
    showSummary: boolean
    toggleAriaLabel: string
  slots:
    - collapsed-icon
    - summary
    - default
  parts:
    - base
    - chevron
    - content
    - summary
  events:
    - vi-toggle
  css_vars:
    - "--vi-cmp-details-border"
    - "--vi-cmp-details-radius"
  examples:
    - <vi-details chevron-position="trailing"><div slot="summary">Summary</div><p>Body</p></vi-details>
vi-divider:
  summary: Visual separator between regions (horizontal and vertical).
  props:
    variant: string
    orientation: "'horizontal' | 'vertical'"
    vertical: boolean
    length: string
    stretch: boolean
    weight: number
  examples:
    - <vi-divider></vi-divider>
vi-drawer:
  summary: Side panel for secondary tasks.
  props:
    variant: string
    open: boolean
    side: "'left' | 'right'"
    size: "'sm' | 'md' | 'lg' | 'xl'"
    label: string
  slots:
    - header
    - default
  parts:
    - base
    - body
    - header
    - overlay
  events:
    - vi-close
  css_vars:
    - "--vi-cmp-drawer-backdrop-filter"
    - "--vi-cmp-drawer-shadow"
    - "--vi-cmp-drawer-width"
  examples:
    - <vi-drawer open side="right">Drawer content</vi-drawer>
    - |-
      <vi-drawer open side="right">
        <vi-drawer-header slot="header" heading="Client Context"></vi-drawer-header>
        Drawer content
      </vi-drawer>
vi-drawer-header:
  summary: drawer header with title/actions and close request button.
  props:
    variant: string
    heading: string
    showClose: boolean
    closeLabel: string
    closeIconName: string
    closeIconSystem: string
    closeIconStyle: string
  slots:
    - default
    - actions
    - close-icon
  parts:
    - actions
    - base
    - close
    - title
  events:
    - vi-close-request
  css_vars:
    - "--vi-cmp-drawer-header-title-color"
    - "--vi-cmp-drawer-header-title-size"
  examples:
    - <vi-drawer-header></vi-drawer-header>
vi-dropdown:
  summary: "Displays additional content in a toggleable panel. Built-in variant: ghost (transparent trigger)."
  props:
    variant: string
    label: string
    icon: string
    open: boolean
    align: string
    placement: "'bottom-start' | 'bottom-end' | 'top-start' | 'top-end' | 'start-top' | 'start-bottom' | 'end-top' | 'end-bottom'"
    hasCustomTrigger: boolean
    staticIcon: boolean
  slots:
    - trigger
    - default
  parts:
    - chevron
    - panel
    - trigger
  events:
    - vi-toggle
  css_vars:
    - "--vi-cmp-dropdown-bg"
    - "--vi-cmp-dropdown-radius"
    - "--vi-cmp-dropdown-trigger-gap"
  examples:
    - <vi-dropdown label="Actions" icon="chevron-down"></vi-dropdown>
    - <vi-dropdown variant="ghost" icon="ellipsis-vertical" label=""></vi-dropdown>
vi-dropdown-item:
  summary: Selectable item for dropdown menus.
  props:
    variant: string
    value: string
    checked: boolean
    checkbox: boolean
    disabled: boolean
    checkIcon: string
    submenuIcon: string
  slots:
    - default
    - check-icon
    - submenu
    - submenu-icon
  parts:
    - base
    - check
  events:
    - vi-select
  css_vars:
    - "--vi-cmp-list-hover"
  examples:
    - <vi-dropdown-item value="open">Open</vi-dropdown-item>
vi-empty-state:
  summary: Empty/waiting state container with dashed border, icon slot, title, description, and actions.
  props:
    variant: string
    title: string
    description: string
    dashed: boolean
    waiting: boolean
    iconName: string
    iconSystem: string
    iconStyle: string
    waitingLabel: string
  slots:
    - icon
    - waiting-icon
    - title
    - description
    - default
  parts:
    - actions
    - base
    - description
    - icon
    - title
  css_vars:
    - "--vi-cmp-empty-state-min-height"
    - "--vi-cmp-empty-state-min-height-narrow"
    - "--vi-cmp-empty-state-radius"
    - "--vi-cmp-empty-state-title-size"
  aria: Built with semantic region/status patterns based on waiting state.
  examples:
    - <vi-empty-state icon-name="database-add" title="Create a new database" description="Get started by adding your first dataset."></vi-empty-state>
vi-field:
  summary: Standalone wrapper that provides a visible label, help text, and error text around any slotted form control.
  props:
    variant: string
    label: string
    helpText: string
    errorText: string
    invalid: boolean
    reserveHelpSpace: boolean
    autoValidate: boolean
  parts:
    - field
    - help-text
    - label
  css_vars:
    - "--vi-cmp-field-help-line-height"
  examples:
    - <vi-field></vi-field>
vi-file-input:
  summary: Upload via select or drag/drop.
  props:
    variant: string
    multiple: boolean
    accept: string
    invalid: boolean
    dragOver: boolean
    files: File[]
  attr_map:
    files: (js only)
  parts:
    - base
    - input
    - label
  events:
    - vi-change
  examples:
    - <vi-file-input></vi-file-input>
vi-flank:
  summary: Semantic two-slot layout (start/end). Best when content is naturally left-vs-right.
  props:
    variant: string
    align: string
  slots:
    - start
    - end
  parts:
    - base
    - end
    - start
  examples:
    - <vi-flank></vi-flank>
vi-flex-wrap:
  summary: Configure flex wrapping behavior.
  props:
    variant: string
    value: "'nowrap' | 'wrap' | 'wrap-reverse'"
    gap: string
  examples:
    - <vi-flex-wrap></vi-flex-wrap>
vi-footnote-link:
  summary: >-
    Trigger-only footnote marker (icon + references) that emits vi-activate with reference and footnote data for consumer-handled display. Built-in variants: tinted (background fill), underline (plain
    text). Use leading/trailing properties for bracket decoration.
  props:
    variant: string
    label: string
    footnotes: FootnoteItem[]
    iconName: string
    iconSystem: string
    iconStyle: string
    leading: string
    trailing: string
  prop_shapes:
    footnotes: "FootnoteItem = { id: string | number; text: string; href?: string }"
  slots:
    - label
    - icon
  parts:
    - trigger
  events:
    - vi-activate
  css_vars:
    - "--vi-cmp-footnote-link-color"
    - "--vi-cmp-footnote-link-label-color"
    - "--vi-cmp-footnote-link-tinted-bg"
  examples:
    - <vi-footnote-link></vi-footnote-link>
vi-frame:
  summary: Constrain content to aspect ratio.
  props:
    variant: string
    ratio: string
  examples:
    - <vi-frame></vi-frame>
vi-gap:
  summary: Apply spacing between children.
  props:
    variant: string
    value: string
    inline: boolean
  examples:
    - <vi-gap></vi-gap>
vi-grid:
  summary: Responsive grid layout utility.
  props:
    variant: string
    columns: string
    gap: string
  examples:
    - <vi-grid></vi-grid>
vi-indicator:
  summary: Overlays a small dot, count badge, or text label on any corner of its child content.
  props:
    variant: string
    content: string
    tone: "'neutral' | 'success' | 'warning' | 'danger' | 'info' | 'accent'"
    position: "'top-right' | 'top-left' | 'bottom-right' | 'bottom-left'"
    pulse: boolean
    max: number
  parts:
    - wrapper
    - indicator
    - base
  css_vars:
    - "--vi-cmp-indicator-accent-bg"
    - "--vi-cmp-indicator-accent-text"
    - "--vi-cmp-indicator-border-color"
    - "--vi-cmp-indicator-border-width"
    - "--vi-cmp-indicator-danger-bg"
    - "--vi-cmp-indicator-danger-text"
    - "--vi-cmp-indicator-dot-size"
    - "--vi-cmp-indicator-font-size"
    - "--vi-cmp-indicator-info-bg"
    - "--vi-cmp-indicator-info-text"
    - "--vi-cmp-indicator-inset"
    - "--vi-cmp-indicator-neutral-bg"
    - "--vi-cmp-indicator-neutral-text"
    - "--vi-cmp-indicator-pill-min-size"
    - "--vi-cmp-indicator-pill-padding"
    - "--vi-cmp-indicator-pill-radius"
    - "--vi-cmp-indicator-pulse-on"
    - "--vi-cmp-indicator-success-bg"
    - "--vi-cmp-indicator-success-text"
    - "--vi-cmp-indicator-warning-bg"
    - "--vi-cmp-indicator-warning-text"
  examples:
    - <vi-indicator tone="success" pulse><vi-avatar name="John"></vi-avatar></vi-indicator>
    - <vi-indicator content="12" max="99"><vi-button>Inbox</vi-button></vi-indicator>
    - <vi-indicator content="New" tone="accent"><vi-icon name="bell"></vi-icon></vi-indicator>
vi-input:
  summary: Single-line input with optional clear action plus prefix/suffix icon/content slots.
  props:
    variant: string
    type: string
    value: string
    placeholder: string
    required: boolean
    disabled: boolean
    invalid: boolean
    clearable: boolean
    clearAriaLabel: string
    prefixText: string
    suffixText: string
  slots:
    - prefix
    - clear-icon
    - suffix
  parts:
    - clear
    - clear-icon
    - control
    - input
    - prefix
    - prefix-text
    - suffix
    - suffix-text
  events:
    - vi-change
    - vi-clear
    - vi-input
  css_vars:
    - "--vi-cmp-input-height"
    - "--vi-cmp-input-padding-inline"
    - "--vi-cmp-input-radius"
  examples:
    - <vi-input label="Name"></vi-input>
vi-justify-content:
  summary: Generic flex utility for any number of children (no start/end slots).
  props:
    variant: string
    value: string
  examples:
    - <vi-justify-content></vi-justify-content>
vi-list:
  summary: Flexible row-list container for key/value style entries with optional striping, dividers, density, and responsive stacking.
  props:
    variant: string
    dividers: boolean
    striped: boolean
    dense: boolean
    stacked: boolean
    responsive: boolean
    framed: boolean
    labelWidth: string
  css_vars:
    - "--vi-cmp-list-radius"
    - "--vi-cmp-list-surface"
  examples:
    - <vi-list><vi-list-item label="Customer">Michael Foster</vi-list-item></vi-list>
vi-list-item:
  summary: Flexible list row item with label/value slots, prefix/suffix/meta regions, and optional link behavior.
  props:
    variant: string
    label: string
    value: string
    href: string
    target: string
    rel: string
    divider: boolean
    dense: boolean
    listOdd: boolean
    stacked: boolean
    responsive: boolean
    labelAlign: "'start' | 'center' | 'end'"
    valueAlign: "'start' | 'center' | 'end'"
    wrap: "'wrap' | 'nowrap' | 'ellipsis'"
    labelWidth: string
  slots:
    - label
    - prefix
    - default
    - suffix
    - meta
  parts:
    - base
    - label
    - main
    - meta
    - value
    - value-wrap
  events:
    - vi-select
  css_vars:
    - "--vi-cmp-list-column-gap"
    - "--vi-cmp-list-hover"
    - "--vi-cmp-list-item-padding"
    - "--vi-cmp-list-item-padding-dense"
    - "--vi-cmp-list-label-color"
    - "--vi-cmp-list-label-width"
    - "--vi-cmp-list-meta-color"
    - "--vi-cmp-list-row-alt"
    - "--vi-cmp-list-value-color"
  examples:
    - <vi-list-item label="Amount">US$150.00<span slot="meta">Using FX spot rate snapshot.</span></vi-list-item>
vi-listbox:
  summary: Selection-only listbox with single or multi-select and rich slotted HTML options.
  usage: |
    Two equivalent ways to provide options:
      1. Slotted <vi-option> children (rich HTML, the common case).
      2. `options` JS property — `(string | { value, label, ... })[]`.
    Pick one mode per instance. `value` (single) or `selected` (multi)
    drives selection. Listen for vi-select / vi-change events.
  props:
    variant: string
    value: string
    values: string[]
    options: Array<string | ListboxOption>
    required: boolean
    invalid: boolean
    multiple: boolean
    disabled: boolean
    emptyText: string
    maxHeight: string
  prop_shapes:
    options: "ListboxOption = { value: string; label: string }"
  attr_map:
    values: (js only)
    options: (js only)
  slots:
    - option
  parts:
    - listbox
  events:
    - vi-change
    - vi-select
  css_vars:
    - "--vi-cmp-check-mark"
    - "--vi-cmp-list-check-bg"
    - "--vi-cmp-list-hover"
  examples:
    - <vi-listbox><vi-option value="atlas">Atlas Capital</vi-option><vi-option value="vega">Vega Partners</vi-option></vi-listbox>
    - |
      <vi-listbox id="lb"></vi-listbox>
      <script>
        document.getElementById('lb').options = [
          { value: 'atlas', label: 'Atlas Capital' },
          { value: 'vega',  label: 'Vega Partners' }
        ];
      </script>
vi-listbox-popup:
  summary: Trigger + popup listbox for selection-only workflows (no input typing).
  usage: |
    Same option-source choice as vi-listbox — either slotted <vi-option>
    children or an `options` JS property. The trigger renders the
    currently-selected label; the popup opens on click/enter.
  props:
    variant: string
    value: string
    values: string[]
    options: Array<string | ListboxOption>
    invalid: boolean
    open: boolean
    placeholder: string
    multiple: boolean
    disabled: boolean
    closeOnSelect: boolean
    emptyText: string
    maxHeight: string
    placement: "'bottom-start' | 'bottom-end' | 'top-start' | 'top-end' | 'start-top' | 'start-bottom' | 'end-top' | 'end-bottom'"
  attr_map:
    values: (js only)
    options: (js only)
  slots:
    - indicator-icon
    - option
  parts:
    - chevron
    - listbox
    - trigger
  events:
    - vi-change
    - vi-select
  css_vars:
    - "--vi-cmp-check-mark"
    - "--vi-cmp-list-check-bg"
    - "--vi-cmp-list-hover"
  examples:
    - <vi-listbox-popup><vi-option value="atlas">Atlas Capital</vi-option><vi-option value="vega">Vega Partners</vi-option></vi-listbox-popup>
    - |
      <vi-listbox-popup id="lp"></vi-listbox-popup>
      <script>
        document.getElementById('lp').options = [
          { value: 'atlas', label: 'Atlas Capital' },
          { value: 'vega',  label: 'Vega Partners' }
        ];
      </script>
vi-masked-input:
  summary: Input with mask tokens and optional regex validation for structured values.
  props:
    variant: string
    value: string
    placeholder: string
    mask: string
    pattern: string
    required: boolean
    disabled: boolean
    invalid: boolean
    clearable: boolean
    clearAriaLabel: string
    prefixText: string
    suffixText: string
  slots:
    - prefix
    - clear-icon
    - suffix
  parts:
    - clear
    - clear-icon
    - control
    - input
    - prefix
    - prefix-text
    - suffix
    - suffix-text
  events:
    - vi-change
    - vi-clear
    - vi-input
  css_vars:
    - "--vi-cmp-input-height"
    - "--vi-cmp-input-padding-inline"
    - "--vi-cmp-input-radius"
    - "--vi-cmp-masked-input-placeholder-opacity"
  examples:
    - <vi-masked-input mask="9999 9999 9999 9999"></vi-masked-input>
vi-matrix-table:
  summary: >-
    Sticky-label matrix table with auto-fit columns and horizontal overflow beyond max visible columns. Built-in variants: scorecard (contained evaluation grid with bold values), heatmap (dense
    pattern-reading grid with compact padding). Supports striped rows.
  usage: |
    REQUIRED: assign `columns` and `rows` via JS — both are `attribute: false`.
    Re-assign the rows array (not a mutation) to refresh. See vi-data-grid's
    usage for the same convention.
  props:
    variant: string
    columns: MatrixColumn[]
    rows: MatrixRow[]
    labelWidth: string
    maxVisibleColumns: number
    fitColumns: boolean
    striped: boolean
  prop_shapes:
    columns: "MatrixColumn = { key: string; label?: string; highlight?: boolean; badge?: string; align?: 'left' | 'center' | 'right' }"
    rows: "MatrixRow = { key?: string; label?: string; values?: Record<string, string | number> }"
  attr_map:
    columns: (js only)
    rows: (js only)
  parts:
    - base
    - data-table
    - labels-table
    - table
    - viewport
  css_vars:
    - "--vi-cmp-matrix-cell-bg"
    - "--vi-cmp-matrix-highlight"
    - "--vi-cmp-matrix-table-border"
    - "--vi-cmp-matrix-table-radius"
  examples:
    - |
      <vi-matrix-table id="m" max-visible-columns="3"></vi-matrix-table>
      <script>
        const m = document.getElementById('m');
        m.columns = [
          { key: 'risk',   label: 'Risk' },
          { key: 'liquidity', label: 'Liquidity' }
        ];
        m.rows = [
          { label: 'Q1', risk: 'Low',    liquidity: 'High' },
          { label: 'Q2', risk: 'Medium', liquidity: 'High' }
        ];
      </script>
    - <vi-matrix-table variant="scorecard" max-visible-columns="3"></vi-matrix-table>
    - <vi-matrix-table variant="heatmap" fit-columns max-visible-columns="2"></vi-matrix-table>
vi-metric-card:
  summary: >-
    KPI-style card with value, label, icon slot, optional context chip, and trend slot. Built-in variants: flat (label-first, no accent bar/shadow, dark value text), compact (icon-left, smaller icon,
    denser padding, no chip).
  props:
    variant: string
    value: string
    label: string
    chip: string
    progress: number | undefined
    max: number
  slots:
    - value
    - label
    - trend
    - icon
  parts:
    - accent
    - base
    - chip
    - content
    - fill
    - icon
    - label
    - track
    - value
  css_vars:
    - "--vi-cmp-metric-card-accent"
    - "--vi-cmp-metric-card-chip-bg"
    - "--vi-cmp-metric-card-chip-color"
    - "--vi-cmp-metric-card-content-gap"
    - "--vi-cmp-metric-card-icon-bg"
    - "--vi-cmp-metric-card-icon-color"
    - "--vi-cmp-metric-card-padding"
    - "--vi-cmp-metric-card-progress"
    - "--vi-cmp-metric-card-radius"
    - "--vi-cmp-metric-card-surface"
    - "--vi-cmp-metric-card-trend-color"
    - "--vi-cmp-metric-card-trend-gap"
    - "--vi-cmp-metric-card-value"
    - "--vi-cmp-metric-card-value-family"
    - "--vi-cmp-metric-card-value-size"
    - "--vi-cmp-metric-card-value-weight"
  examples:
    - <vi-metric-card value="6" label="Total Assessments" chip="Wind Power"><vi-icon slot="icon" name="layer-group" size="24"></vi-icon></vi-metric-card>
    - <vi-metric-card variant="flat" value="$1.2M" label="Revenue"><vi-icon slot="icon" name="trending-up" size="24"></vi-icon><span slot="trend">+12.5% vs prior month</span></vi-metric-card>
    - <vi-metric-card variant="compact" value="142" label="Open Tasks"><vi-icon slot="icon" name="ticket" size="28"></vi-icon><span slot="trend">+8 today</span></vi-metric-card>
vi-modal:
  summary: Modal overlay with built-in body scroll lock and optional custom HTML header slot.
  props:
    variant: string
    open: boolean
    heading: string
    subheading: string
    label: string
    persistent: boolean
    closeButtonText: string
    closeAriaLabel: string
  slots:
    - header
    - subheading
    - default
    - footer
  parts:
    - backdrop
    - body
    - close
    - dialog
    - footer
    - header
    - subtitle
    - title
    - title-group
  events:
    - vi-close
  css_vars:
    - "--vi-cmp-modal-accent"
    - "--vi-cmp-modal-backdrop-filter"
    - "--vi-cmp-modal-body-padding-block"
    - "--vi-cmp-modal-close-icon-size"
    - "--vi-cmp-modal-close-radius"
    - "--vi-cmp-modal-close-size"
    - "--vi-cmp-modal-close-top"
    - "--vi-cmp-modal-close-trailing"
    - "--vi-cmp-modal-confirm-max-width"
    - "--vi-cmp-modal-header-title-family"
    - "--vi-cmp-modal-header-title-size"
    - "--vi-cmp-modal-header-title-spacing"
    - "--vi-cmp-modal-header-title-weight"
    - "--vi-cmp-modal-max-width"
    - "--vi-cmp-modal-radius"
    - "--vi-cmp-modal-subheading-color"
    - "--vi-cmp-modal-subheading-family"
    - "--vi-cmp-modal-subheading-gap"
    - "--vi-cmp-modal-subheading-size"
    - "--vi-cmp-modal-subheading-weight"
  examples:
    - >-
      <vi-modal open><vi-modal-header slot="header"><span>Pre-Closing Workstreams</span><button slot="actions" aria-label="Approve"><vi-icon name="check"></vi-icon></button><button slot="actions"
      aria-label="Open detail"><vi-icon name="external-link"></vi-icon></button></vi-modal-header>Approve this compliance override?<div slot="footer"><vi-button>Confirm</vi-button></div></vi-modal>
vi-modal-header:
  summary: Composable modal header with rich label content, action slot, and optional configurable close icon/control.
  props:
    variant: string
    heading: string
    showClose: boolean
    closeLabel: string
    tone: string
    closeIconName: string
    closeIconSystem: string
    closeIconStyle: string
  slots:
    - default
    - actions
    - close-icon
  parts:
    - actions
    - base
    - close
    - title
  events:
    - vi-close-request
  css_vars:
    - "--vi-cmp-modal-close-icon-size"
    - "--vi-cmp-modal-close-radius"
    - "--vi-cmp-modal-close-size"
    - "--vi-cmp-modal-header-title-color"
    - "--vi-cmp-modal-header-title-family"
    - "--vi-cmp-modal-header-title-size"
    - "--vi-cmp-modal-header-title-spacing"
    - "--vi-cmp-modal-header-title-weight"
  examples:
    - >-
      <vi-modal-header><span>Pre-Closing Workstreams</span><button slot="actions" aria-label="Approve"><vi-icon name="check"></vi-icon></button><button slot="actions" aria-label="Open detail"><vi-icon
      name="external-link"></vi-icon></button></vi-modal-header>
vi-number-input:
  summary: "Numeric input with steppers. Variant: ghost (transparent at rest, surface on hover, full border on focus)."
  props:
    variant: string
    value: number | null
    step: number
    min: number
    max: number
    required: boolean
    disabled: boolean
    invalid: boolean
    decrementAriaLabel: string
    incrementAriaLabel: string
    decrementText: string
    incrementText: string
  parts:
    - base
    - decrement
    - increment
    - input
  events:
    - vi-change
  css_vars:
    - "--vi-cmp-input-height"
    - "--vi-cmp-input-radius"
  examples:
    - <vi-number-input></vi-number-input>
vi-option:
  summary: Rich option row primitive for combobox/select-like lists; supports custom value, label, and search text.
  props:
    variant: string
    value: string
    label: string
    search: string
    selected: boolean
    disabled: boolean
    multiselect: boolean
  events:
    - vi-select
  css_vars:
    - "--vi-cmp-check-mark"
    - "--vi-cmp-list-check-bg"
    - "--vi-cmp-list-hover"
  examples:
    - <vi-option></vi-option>
vi-page:
  summary: >-
    Full-viewport application shell. A CSS grid that pins navigation, header, banner, aside, and footer around a single scrollable content region — the outermost layout element of an app, not a
    content container.
  usage: |
    Occupies the full viewport (height: 100dvh) and owns the only scroll
    container, so put it at the root of the app and let content scroll
    inside the default slot. Do not nest it or wrap it in a scrolling parent.

    `has-banner` and `has-aside` are recomputed from slotchange. Setting
    them in the initial markup to match the slots you actually fill is
    correct and avoids a first-paint reflow — but they cannot force a
    layout that contradicts the slots, because the next slotchange wins.

    Slots: banner (full width, above both the nav rail and the content
    column), navigation (left rail — pair with vi-vertical-nav), header
    (above the content column only, not full width), default (the
    scrolling body), aside (right rail), footer.
  props:
    variant: string
    headerInset: boolean
    hasBanner: boolean
    hasAside: boolean
  slots:
    - banner
    - navigation
    - aside
    - header
    - default
    - footer
  parts:
    - aside
    - banner
    - base
    - footer
    - header
    - main
    - nav
  css_vars:
    - "--vi-cmp-page-gap"
  examples:
    - |
      <vi-page>
        <vi-vertical-nav slot="navigation"></vi-vertical-nav>
        <h1 slot="header">Portfolio</h1>
        <vi-stack gap="1rem">Main content scrolls here.</vi-stack>
        <span slot="footer">© Vela Intelligence</span>
      </vi-page>
vi-pagination:
  summary: Pagination control with windowed pages, clickable ellipsis jump, optional min-width edge-pinned controls, and compact summary mode.
  props:
    variant: string
    page: number
    totalPages: number
    siblingCount: number
    boundaryCount: number
    ellipsisJump: number
    compact: boolean
    compactTextFormat: string
    minWidth: string
    disabled: boolean
    hideOnSinglePage: boolean
    openEnded: boolean
    ellipsis: string
    ellipsisPreviousAriaLabel: string
    ellipsisNextAriaLabel: string
    previousAriaLabel: string
    nextAriaLabel: string
    pageAriaLabelPrefix: string
  slots:
    - previous-icon
    - previous-label
    - ellipsis
    - next-label
    - next-icon
  parts:
    - base
    - compact-summary
    - ellipsis
    - next
    - next-icon
    - page-button
    - pages
    - previous
    - previous-icon
  events:
    - vi-change
  examples:
    - <vi-pagination page="3" total-pages="66"><span slot="previous-label">Previous</span><span slot="next-label">Next</span></vi-pagination>
    - <vi-pagination page="3" total-pages="66" compact compact-text-format="{page} / {total}" min-width="30rem"></vi-pagination>
vi-popover:
  summary: "Anchored interactive overlay with built-in trigger button, outside-click-to-close, Escape, and focus trap. Built-in variant: ghost (transparent trigger)."
  props:
    variant: string
    label: string
    icon: string
    open: boolean
    align: string
    placement: "'bottom-start' | 'bottom-end' | 'top-start' | 'top-end' | 'start-top' | 'start-bottom' | 'end-top' | 'end-bottom'"
  slots:
    - trigger
    - default
  parts:
    - panel
    - trigger
  css_vars:
    - "--vi-cmp-popover-radius"
    - "--vi-cmp-popover-trigger-gap"
  examples:
    - <vi-popover label="Open Popover">Popover content</vi-popover>
    - <vi-popover variant="ghost" icon="ellipsis-vertical" label="">Popover content</vi-popover>
vi-progress-bar:
  summary: Linear determinate progress indicator with configurable label placement (before, after, or below).
  props:
    variant: string
    value: number
    max: number
    label: string
    labelPosition: "'below' | 'before' | 'after'"
  parts:
    - base
    - fill
    - label
    - track
  examples:
    - <vi-progress-bar></vi-progress-bar>
vi-progress-ring:
  summary: Circular determinate progress indicator.
  props:
    variant: string
    value: number
    max: number
    size: number
    stroke: number
    showLabel: boolean
    labelFormat: string
  examples:
    - <vi-progress-ring></vi-progress-ring>
vi-qr-code:
  summary: Renders a real, scannable QR code (byte mode) to a canvas.
  props:
    variant: string
    value: string
    size: number
    level: "'L' | 'M' | 'Q' | 'H'"
    cells: number
    ariaLabel: string
  events:
    - vi-render
  css_vars:
    - "--vi-cmp-qr-code-border"
    - "--vi-cmp-qr-code-radius"
  examples:
    - <vi-qr-code></vi-qr-code>
vi-radio:
  summary: Single radio control with label and optional help text.
  props:
    variant: string
    checked: boolean
    disabled: boolean
    invalid: boolean
    value: string
    label: string
    helpText: string
  parts:
    - base
    - help-text
    - input
    - label
  events:
    - vi-change
  css_vars:
    - "--vi-cmp-radio-input-offset-y"
  examples:
    - <vi-radio></vi-radio>
vi-radio-group:
  summary: Grouped radio choices with optional group help text and per-option descriptions.
  usage: |
    REQUIRED: assign `options` via JS property — it's `attribute: false`.
    No HTML <input type=radio> children are read. Set `value` to the
    selected option's `value`. Option shape: { label, value, helpText? }.
  props:
    variant: string
    name: string
    value: string
    invalid: boolean
    options: RadioOption[]
  prop_shapes:
    options: "RadioOption = { label: string; value: string; helpText?: string }"
  attr_map:
    options: (js only)
  events:
    - vi-change
  examples:
    - |
      <vi-radio-group id="rg" label="Plan"></vi-radio-group>
      <script>
        const rg = document.getElementById('rg');
        rg.options = [
          { label: 'Free',  value: 'free',  helpText: 'Up to 3 projects.' },
          { label: 'Pro',   value: 'pro',   helpText: 'Unlimited projects.' },
          { label: 'Team',  value: 'team',  helpText: 'SSO + roles.' }
        ];
        rg.value = 'pro';
      </script>
vi-rating:
  summary: Configurable star rating input. Supports custom icons via icon-name, icon-system, and icon-style.
  props:
    variant: string
    value: number
    max: number
    precision: number
    invalid: boolean
    readonly: boolean
    iconName: string
    iconSystem: string
    iconStyle: string
    starAriaLabel: string
  parts:
    - base
    - star
  events:
    - vi-change
  examples:
    - <vi-rating></vi-rating>
vi-scroller:
  summary: Scrollable content with overflow cues on vertical and horizontal axes.
  props:
    variant: string
    overflowTop: boolean
    overflowBottom: boolean
    overflowLeft: boolean
    overflowRight: boolean
    maxHeight: string
    maxWidth: string
    direction: "'vertical' | 'horizontal' | 'both'"
  parts:
    - base
    - content
    - fade-bottom
    - fade-left
    - fade-right
    - fade-top
  css_vars:
    - "--vi-cmp-scroller-border"
    - "--vi-cmp-scroller-radius"
  examples:
    - <vi-scroller></vi-scroller>
vi-select:
  summary: Native select wrapper with optional label and help text.
  usage: |
    REQUIRED: assign `options` via JS property (it's `attribute: false`).
    HTML <option> children of <vi-select> are NOT rendered — the browser's
    native <select> only paints its own option children, and the slotted
    children don't get picked up. Setting `value` selects an option.
    Option shape: { value: string; label: string }.
  props:
    variant: string
    value: string
    options: SelectOption[]
    required: boolean
    disabled: boolean
    invalid: boolean
  prop_shapes:
    options: "SelectOption = { label: string; value: string }"
  attr_map:
    options: (js only)
  events:
    - vi-change
  css_vars:
    - "--vi-cmp-input-height"
    - "--vi-cmp-input-padding-inline"
    - "--vi-cmp-input-radius"
  examples:
    - |
      <vi-select id="sel" label="Tier"></vi-select>
      <script>
        const sel = document.getElementById('sel');
        sel.options = [
          { value: 'free',    label: 'Free' },
          { value: 'pro',     label: 'Pro' },
          { value: 'team',    label: 'Team' }
        ];
        sel.value = 'pro';
        sel.addEventListener('vi-change', (e) => console.log(e.detail.value));
      </script>
vi-segment:
  summary: Selectable segment item used within vi-segmented-control.
  props:
    variant: string
    value: string
    selected: boolean
    disabled: boolean
    edge: string
    segmentSize: "'sm' | 'md' | 'lg'"
    segmentVariant: string
    groupDisabled: boolean
    tabIndexValue: number
  attr_map:
    tabIndexValue: (js only)
  parts:
    - base
    - button
  events:
    - vi-segment-select
  css_vars:
    - "--vi-cmp-segment-active-indicator"
    - "--vi-cmp-segment-active-shadow"
    - "--vi-cmp-segment-edge-radius"
    - "--vi-cmp-segment-flex"
    - "--vi-cmp-segment-indicator"
    - "--vi-cmp-segment-radius"
    - "--vi-cmp-segmented-active-bg"
    - "--vi-cmp-segmented-active-divider"
    - "--vi-cmp-segmented-active-text"
    - "--vi-cmp-segmented-divider"
    - "--vi-cmp-segmented-hover-bg"
    - "--vi-cmp-segmented-pressed-bg"
    - "--vi-cmp-segmented-text"
  keyboard: Keyboard navigation is coordinated by parent segmented control.
  aria: Exposes radio semantics when used in segmented control.
  examples:
    - <vi-segment value="filter"><vi-icon name="funnel"></vi-icon>Filter</vi-segment>
vi-segmented-control:
  summary: "Single-select grouped state control for segmented actions. Built-in variants: tinted (pill with neutral bg and shadow), underline (transparent with bottom indicator)."
  props:
    variant: string
    value: string
    label: string
    size: "'sm' | 'md' | 'lg'"
    disabled: boolean
    fullWidth: boolean
  parts:
    - base
    - underline-indicator
  events:
    - vi-change
  css_vars:
    - "--vi-cmp-button-height-lg"
    - "--vi-cmp-button-height-md"
    - "--vi-cmp-button-height-sm"
    - "--vi-cmp-segment-active-indicator-color"
    - "--vi-cmp-segment-active-indicator-width"
    - "--vi-cmp-segmented-bg"
    - "--vi-cmp-segmented-border"
    - "--vi-cmp-segmented-border-width"
    - "--vi-cmp-segmented-control-height"
    - "--vi-cmp-segmented-padding"
    - "--vi-cmp-segmented-padding-bottom"
    - "--vi-cmp-segmented-padding-left"
    - "--vi-cmp-segmented-padding-right"
    - "--vi-cmp-segmented-padding-top"
    - "--vi-cmp-segmented-radius"
    - "--vi-cmp-tab-active-bg"
    - "--vi-cmp-tab-active-shadow"
    - "--vi-cmp-tab-active-text"
  keyboard: Arrow keys/Home/End move selection across enabled segments.
  aria: Exposes radiogroup semantics.
  examples:
    - <vi-segmented-control><vi-segment value="years">Years</vi-segment><vi-segment value="months">Months</vi-segment></vi-segmented-control>
    - <vi-segmented-control variant="tinted"><vi-segment value="years">Years</vi-segment><vi-segment value="months">Months</vi-segment></vi-segmented-control>
    - <vi-segmented-control variant="underline"><vi-segment value="years">Years</vi-segment><vi-segment value="months">Months</vi-segment></vi-segmented-control>
vi-skeleton:
  summary: Shimmer loading placeholder with configurable speed (slow, normal, fast).
  props:
    variant: string
    width: string
    height: string
    speed: string
  css_vars:
    - "--vi-cmp-skeleton-base"
    - "--vi-cmp-skeleton-highlight"
    - "--vi-cmp-skeleton-radius"
  examples:
    - <vi-skeleton width="100%" height="1rem"></vi-skeleton>
    - <vi-skeleton speed="fast" width="60%" height="0.75rem"></vi-skeleton>
vi-slider:
  summary: "Drag to set numeric value. Variant: thick (doubles the track height and enlarges the thumb)."
  props:
    variant: string
    value: number
    min: number
    max: number
    step: number
    disabled: boolean
    invalid: boolean
    ariaLabel: string
  parts:
    - base
    - input
    - output
  events:
    - vi-input
  examples:
    - <vi-slider></vi-slider>
vi-bar-chart:
  summary: >-
    Vertical or horizontal bars, single or multi-series, optionally stacked. Use vertical for time-series totals (tokens/day, cost/day); horizontal with categories for bucket lists (TTL remaining);
    stacked for multi-series totals on the same axis. Add show-legend for color swatches below the chart, or show-tooltip to surface the series label and value on hover.
  usage: |
    REQUIRED: assign `series` via JS — it's `attribute: false`. Optional
    `categories: string[]` (used for the x-axis in vertical mode and for
    row labels in `orientation="horizontal"`). Series shape: { label?,
    color?, values: number[] }. Use `stacked` for multi-series totals.
    Horizontal mode is row-oriented and pairs naturally with `show-values`.
  props:
    variant: string
    series: BarChartSeries[]
    categories: string[]
    orientation: "'vertical' | 'horizontal'"
    stacked: boolean
    showValues: boolean
    showLegend: boolean
    showTooltip: boolean
    height: number
    ariaLabel: string
  prop_shapes:
    series: "BarChartSeries = { label?: string; color?: string; values: number[] }"
  attr_map:
    series: (js only)
    categories: (js only)
  parts:
    - bar
    - base
    - chart
    - empty
    - label
    - legend
    - list
    - row
    - svg
    - tooltip
    - track
    - value
  css_vars:
    - "--vi-cmp-bar-chart-height"
  examples:
    - |
      <vi-bar-chart id="b" stacked show-legend show-tooltip></vi-bar-chart>
      <script>
        const b = document.getElementById('b');
        b.categories = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'];
        b.series = [
          { label: 'Input',  color: 'chart-4', values: [10, 12, 8, 15, 20] },
          { label: 'Output', color: 'chart-2', values: [22, 18, 14, 28, 32] }
        ];
      </script>
    - |
      <!-- Horizontal bucket list -->
      <vi-bar-chart id="h" orientation="horizontal" show-values></vi-bar-chart>
      <script>
        const h = document.getElementById('h');
        h.categories = ['Expired', '<7d', '7-30d', '30-60d', '60-90d'];
        h.series = [{ color: 'chart-5', values: [0, 0, 57, 5, 0] }];
      </script>
vi-donut-chart:
  summary: >-
    Proportional segment chart with center readout and legend. Center value + label communicate the total; segments show breakdown by category. Best for 3-6 categories — past that, switch to a
    horizontal bar list. Add show-tooltip to surface the label, value, and percentage of each segment on hover.
  usage: |
    REQUIRED: assign `segments` via JS — it's `attribute: false`. Segment
    shape: { label, value, color? }. The center readout is set via
    `center-value` / `center-label` HTML attributes.
  props:
    variant: string
    segments: DonutChartSegment[]
    centerValue: string
    centerLabel: string
    showLegend: boolean
    showTooltip: boolean
    thickness: number
    size: number
    ariaLabel: string
  prop_shapes:
    segments: "DonutChartSegment = { label: string; value: number; color?: string }"
  attr_map:
    segments: (js only)
  parts:
    - base
    - center
    - center-label
    - center-value
    - empty
    - legend
    - svg
    - tooltip
  css_vars:
    - "--vi-cmp-donut-center-value-size"
    - "--vi-cmp-donut-size"
  examples:
    - |
      <vi-donut-chart id="d" center-value="62" center-label="cached" show-tooltip></vi-donut-chart>
      <script>
        document.getElementById('d').segments = [
          { label: 'Book',    value: 35, color: 'chart-1' },
          { label: 'Movie',   value: 18, color: 'chart-2' },
          { label: 'Series',  value: 13, color: 'chart-3' },
          { label: 'Article', value:  7, color: 'chart-5' }
        ];
      </script>
vi-funnel-chart:
  summary: >-
    Stage-to-stage conversion / drop-off for pipeline data — Request → Cached → Processed → Billed, or Signup → First use → Paid. Centered bands narrow with each stage; the gap between bands shows the
    share retained from the previous stage (and of the start). Single-hue by default since it is one flow narrowing, not separate categories — set a per-stage color to vary it. Set stages ({ label,
    value, color? }[]) via JS.
  usage: |
    REQUIRED: assign `stages` via JS — it's `attribute: false`. Stage
    shape: { label, value, color? }. Single-hue by default (one flow
    narrowing); per-stage `color` overrides let you vary it.
  props:
    variant: string
    stages: FunnelStage[]
    color: string
    showValues: boolean
    showConversion: boolean
    ariaLabel: string
  prop_shapes:
    stages: "FunnelStage = { label: string; value: number; color?: string }"
  attr_map:
    stages: (js only)
  parts:
    - band
    - base
    - connector
    - conversion
    - empty
    - label
    - value
  css_vars:
    - "--vi-cmp-funnel-band-height"
    - "--vi-cmp-funnel-connector-height"
    - "--vi-cmp-funnel-radius"
    - "--vi-cmp-funnel-wall-alpha"
  examples:
    - |
      <vi-funnel-chart id="f"></vi-funnel-chart>
      <script>
        document.getElementById('f').stages = [
          { label: 'Requests',  value: 8200 },
          { label: 'Cache hit', value: 5100 },
          { label: 'Processed', value: 4800 },
          { label: 'Billed',    value: 4600 }
        ];
      </script>
vi-gauge-chart:
  summary: >-
    Single-metric radial gauge for capacity and health — cache utilization, quota usage, storage, load. A 270° arc (gap at the bottom) with a center readout. The fill recolors by threshold zone so the
    number reads as healthy / warning / critical at a glance, which is what distinguishes it from vi-progress-ring (full circle) and vi-donut-chart. Set value/min/max, unit, and thresholds (array of {
    upTo, color }) via JS.
  usage: |
    `value` / `min` / `max` / `unit` / `label` / `sweep` are HTML attributes.
    `thresholds` is JS-only — it carries the zone bands that recolor the
    fill (healthy / warning / critical). Threshold shape: { upTo: number;
    color: string }. The fill takes the color of the first zone whose
    upTo >= value (so order thresholds ascending).
  props:
    variant: string
    value: number
    min: number
    max: number
    sweep: number
    thickness: number
    size: number
    color: string
    unit: string
    label: string
    valueLabel: string
    showValue: boolean
    thresholds: GaugeThreshold[]
    ariaLabel: string
  prop_shapes:
    thresholds: "GaugeThreshold = { upTo: number; color: string }"
  attr_map:
    thresholds: (js only)
  parts:
    - base
    - center
    - empty
    - fill
    - label
    - svg
    - track
    - value
  css_vars:
    - "--vi-cmp-gauge-size"
    - "--vi-cmp-gauge-value-size"
  examples:
    - |
      <vi-gauge-chart id="g" label="cache hit" unit="%"></vi-gauge-chart>
      <script>
        const g = document.getElementById('g');
        g.value = 62;
        g.thresholds = [
          { upTo: 50,  color: 'danger'  },
          { upTo: 80,  color: 'warning' },
          { upTo: 100, color: 'success' }
        ];
      </script>
vi-line-chart:
  summary: >-
    Multi-series line chart for dashboard data. Variants: area (soft fill below the line), stacked (cumulative areas — implies area), and normalize (100% stacked — each point fills the full height to
    show share-of-total over time). Set series via JS for per-series labels and colors. Optional show-grid renders dashed gridlines; show-legend surfaces series labels; show-tooltip enables a hover
    crosshair with per-series values (percentages in normalized mode) at the nearest x.
  usage: |
    REQUIRED: assign `series` via JS — it's `attribute: false`. Optional
    `categories: string[]` provides x-axis labels for the hover tooltip.
    Series shape: { label?, color?, values: number[] }. Color accepts a
    chart palette token (chart-1..6), a --vi-* variable, or a raw color.
    Variants: `area`, `stacked`, `normalize` (100% stacked / share-of-total).
  props:
    variant: string
    series: LineChartSeries[]
    categories: string[]
    area: boolean
    stacked: boolean
    normalized: boolean
    height: number
    showGrid: boolean
    showLegend: boolean
    showTooltip: boolean
    ariaLabel: string
  prop_shapes:
    series: "LineChartSeries = { label?: string; color?: string; values: number[] }"
  attr_map:
    series: (js only)
    categories: (js only)
    normalized: normalize
  parts:
    - area
    - base
    - chart
    - crosshair
    - empty
    - focus-dot
    - legend
    - line
    - svg
    - tooltip
  css_vars:
    - "--vi-cmp-line-chart-height"
    - "--vi-cmp-line-chart-stroke"
  examples:
    - |
      <vi-line-chart id="lc" area show-tooltip></vi-line-chart>
      <script>
        const lc = document.getElementById('lc');
        lc.categories = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'];
        lc.series = [
          { label: 'Latency', color: 'chart-1', values: [12, 18, 9, 22, 14] }
        ];
      </script>
    - |
      <!-- Stacked area -->
      <vi-line-chart id="stk" stacked show-legend></vi-line-chart>
      <script>
        document.getElementById('stk').series = [
          { label: 'Hits',   color: 'chart-2', values: [3, 5, 4, 8, 12] },
          { label: 'Misses', color: 'chart-6', values: [7, 6, 8, 12, 16] }
        ];
      </script>
vi-radar-chart:
  summary: >-
    Multi-axis comparison across a shared scale — score vs. benchmark, this deal vs. the portfolio median, current vs. target. One closed polygon per series over N axes. Mark the reference series
    dashed and it drops its fill and renders as a dashed ring, so it reads as context rather than as a second measurement (and stays distinguishable without color). Set axes (string[]) and series ({
    label, color?, values, dashed?, fill? }[]) via JS. Optional max pins the outer ring, levels sets the number of grid rings, shape="circle" swaps polygon rings for circular ones, and show-tooltip
    snaps to the nearest axis with every series value on it. Needs at least three axes.
  usage: |
    REQUIRED: assign `axes` (string[]) and `series` via JS — both are
    `attribute: false`. Series shape: { label?, color?, values: number[],
    dashed?, fill? }. `values` is positional against `axes`; missing
    entries fall back to `min`.

    Needs at least three axes — with fewer it renders the empty state.

    For a value-against-baseline chart, put the measured series first and
    mark the reference `dashed: true`: it drops its fill and draws as a
    dashed ring, so it reads as context rather than a second measurement
    and stays distinguishable without color. `fill` overrides that default
    (it defaults to `!dashed`).

    `max` pins the outer ring (auto-scales to the largest value when
    unset); `min` defaults to 0. `levels` sets the number of grid rings,
    `shape="circle"` swaps polygon rings for circular ones, `size` is the
    square plot size in px.

    Axis labels sit outside the plot — keep them short. Their gutter is
    `--vi-cmp-radar-chart-gutter` (default 2.5rem).
  props:
    variant: string
    axes: string[]
    series: RadarChartSeries[]
    min: number
    max: number
    levels: number
    shape: "'polygon' | 'circle'"
    size: number
    showLabels: boolean
    showDots: boolean
    showLegend: boolean
    showTooltip: boolean
    ariaLabel: string
  prop_shapes:
    series: "RadarChartSeries = { label?: string; color?: string; values: number[]; dashed?: boolean; fill?: boolean }"
  attr_map:
    axes: (js only)
    series: (js only)
  parts:
    - area
    - axis-label
    - base
    - chart
    - dot
    - empty
    - grid
    - legend
    - outline
    - spoke
    - spoke-active
    - svg
    - tooltip
  css_vars:
    - "--vi-cmp-radar-chart-gutter"
    - "--vi-cmp-radar-label-size"
    - "--vi-cmp-radar-size"
    - "--vi-cmp-radar-stroke"
  examples:
    - |
      <vi-radar-chart id="r" max="100" show-tooltip></vi-radar-chart>
      <script>
        const r = document.getElementById('r');
        r.axes = ['Governance', 'Data', 'Risk', 'Controls', 'Reporting', 'People'];
        r.series = [
          { label: 'This deal', values: [82, 64, 71, 55, 90, 68] },
          { label: 'Portfolio baseline', color: 'chart-2', dashed: true,
            values: [60, 60, 60, 60, 60, 60] }
        ];
      </script>
vi-sparkline:
  summary: >-
    Minimal inline trend chart. No axes, no gridlines — just the line, optionally with a soft fill below. Slots cleanly into metric cards or any tight space. Set tone="chart-1".."chart-6" for the
    curated chart palette; stretches to fill its container width.
  usage: |
    `values: number[]` accepts a JSON-string HTML attribute OR a JS property
    assignment (it's the friendly exception). Use the attribute form for
    static inline trends in metric cards.
  props:
    variant: string
    values: number[]
    tone: string
    fill: boolean
    height: number
    ariaLabel: string
  parts:
    - area
    - dot
    - empty
    - line
    - svg
  css_vars:
    - "--vi-cmp-sparkline-height"
    - "--vi-cmp-sparkline-stroke"
  examples:
    - <vi-sparkline values="[12, 18, 9, 22, 30, 27, 35]" tone="chart-2"></vi-sparkline>
    - |
      <vi-sparkline id="sp" tone="chart-2"></vi-sparkline>
      <script>
        document.getElementById('sp').values = [12, 18, 9, 22, 30, 27, 35];
      </script>
vi-show-more-list:
  summary: Shows a limited number of rich slotted items with a dynamic "X more" reveal action.
  props:
    variant: string
    limit: number
    expanded: boolean
    moreLabel: string
    lessLabel: string
    heading: string
  slots:
    - heading
    - default
    - vi-overflow
  parts:
    - base
    - heading
    - items
    - toggle
  events:
    - vi-toggle
  css_vars:
    - "--vi-cmp-show-more-list-border"
    - "--vi-cmp-show-more-list-radius"
    - "--vi-cmp-show-more-list-surface"
  examples:
    - <vi-show-more-list limit="3"><div>Item</div><div>Item</div><div>Item</div><div>Item</div></vi-show-more-list>
vi-spinner:
  summary: "Indeterminate loading state. Variant: thick (doubles the border width)."
  props:
    variant: string
    size: number
    label: string
  examples:
    - <vi-spinner></vi-spinner>
vi-split:
  summary: Two-slot layout with an explicit flex spacer and configurable gap.
  props:
    variant: string
    gap: string
    align: string
  slots:
    - start
    - end
  parts:
    - base
    - end
    - start
  examples:
    - <vi-split></vi-split>
vi-split-panel:
  summary: "Resizable dual-pane container. Built-in variant: bar (full-height semi-transparent divider line with solid nub)."
  props:
    variant: string
    ratio: number
    orientation: "'horizontal' | 'vertical'"
  slots:
    - start
    - end
  parts:
    - base
    - handle
    - pane-end
    - pane-start
  events:
    - vi-resize
  examples:
    - <vi-split-panel ratio="50"><div slot="start">Left</div><div slot="end">Right</div></vi-split-panel>
    - <vi-split-panel variant="bar" ratio="50"><div slot="start">Left</div><div slot="end">Right</div></vi-split-panel>
vi-stack:
  summary: Vertical rhythm utility.
  props:
    variant: string
    gap: string
    align: string
  examples:
    - <vi-stack></vi-stack>
vi-step:
  summary: A single step inside vi-steps. Controlled entirely by its parent — it renders the label you slot into it and nothing else.
  usage: |
    Put the label in the default slot and set no properties. Index, current
    state, total, circle size, and clickability are pushed down by the
    parent vi-steps on slotchange; every property on vi-step is internal
    state and assigning to it is overwritten on the next parent render.

    Drive the flow from the parent instead: `current` on vi-steps is
    **1-based** (`current="2"` marks the second step active), and clicks
    are surfaced as `vi-change` on vi-steps, not on the individual step.
  props:
    variant: string
  parts:
    - circle
    - label
    - track
  events:
    - vi-step-click
  css_vars:
    - "--vi-cmp-steps-active-color"
    - "--vi-cmp-steps-active-text"
    - "--vi-cmp-steps-circle-bg"
    - "--vi-cmp-steps-circle-color"
    - "--vi-cmp-steps-connector-color"
    - "--vi-cmp-steps-connector-radius"
    - "--vi-cmp-steps-connector-thickness"
    - "--vi-cmp-steps-font-weight"
    - "--vi-cmp-steps-label-color"
    - "--vi-cmp-steps-label-gap"
    - "--vi-cmp-steps-label-size"
  examples:
    - |
      <vi-steps current="2">
        <vi-step>Register</vi-step>
        <vi-step>Choose plan</vi-step>
        <vi-step>Purchase</vi-step>
      </vi-steps>
vi-steps:
  summary: Horizontal step indicator with numbered circles, connector lines, and labels. Custom variants shown via CSS custom properties.
  props:
    variant: string
    current: number
    size: number
    clickable: boolean
  events:
    - vi-change
  examples:
    - <vi-steps></vi-steps>
vi-switch:
  summary: On/off toggle switch with optional label/help text and themeable track/thumb styling.
  props:
    variant: string
    checked: boolean
    disabled: boolean
    invalid: boolean
    label: string
    value: string
  parts:
    - base
    - label
    - thumb
  events:
    - vi-change
  css_vars:
    - "--vi-cmp-switch-height"
    - "--vi-cmp-switch-padding"
    - "--vi-cmp-switch-shift"
    - "--vi-cmp-switch-thumb-bg"
    - "--vi-cmp-switch-thumb-border"
    - "--vi-cmp-switch-thumb-shadow"
    - "--vi-cmp-switch-thumb-size"
    - "--vi-cmp-switch-track-bg-off"
    - "--vi-cmp-switch-track-bg-on"
    - "--vi-cmp-switch-track-border-off"
    - "--vi-cmp-switch-track-border-on"
    - "--vi-cmp-switch-width"
  examples:
    - <vi-switch></vi-switch>
vi-tab:
  summary: Individual tab trigger coordinated by vi-tab-group.
  props:
    variant: string
    value: string
    active: boolean
    disabled: boolean
    controls: string
  events:
    - vi-tab-select
  css_vars:
    - "--vi-cmp-tab-active-bg"
    - "--vi-cmp-tab-active-indicator"
    - "--vi-cmp-tab-active-shadow"
    - "--vi-cmp-tab-active-text"
    - "--vi-cmp-tab-bg"
    - "--vi-cmp-tab-font-weight"
    - "--vi-cmp-tab-gap"
    - "--vi-cmp-tab-indicator"
    - "--vi-cmp-tab-padding"
    - "--vi-cmp-tab-radius"
    - "--vi-cmp-tab-text"
  examples:
    - <vi-tab></vi-tab>
vi-tab-group:
  summary: Coordinates tabs with inline and/or external panels via value matching.
  props:
    variant: string
    value: string
    panelMode: "'inline' | 'external' | 'both'"
  slots:
    - tab
    - default
  parts:
    - base
    - panels
    - tabs
  events:
    - vi-change
  css_vars:
    - "--vi-cmp-tab-bar-bg"
    - "--vi-cmp-tab-bar-border"
    - "--vi-cmp-tab-bar-gap"
    - "--vi-cmp-tab-bar-padding"
    - "--vi-cmp-tab-bar-radius"
  examples:
    - <vi-tab-group></vi-tab-group>
vi-tab-panel:
  summary: Tab panel that can be inline or externally linked to a tab group by group id.
  props:
    variant: string
    value: string
    active: boolean
    group: string
  examples:
    - <vi-tab-panel></vi-tab-panel>
vi-tag:
  summary: "Compact label for categorization with tone colors (neutral, success, warning, danger, info, accent). Built-in variants: outline (visible tone border), solid (filled background with white text)."
  props:
    variant: string
    tone: "'neutral' | 'success' | 'warning' | 'danger' | 'info' | 'accent'"
    removable: boolean
    removeIcon: string
    removeAriaLabel: string
  slots:
    - default
    - remove-icon
  parts:
    - base
    - remove
  events:
    - vi-remove
  css_vars:
    - "--vi-cmp-tag-gap"
    - "--vi-cmp-tag-padding-block"
    - "--vi-cmp-tag-padding-inline"
    - "--vi-cmp-tag-radius"
  examples:
    - <vi-tag tone="info">Compliance</vi-tag>
    - <vi-tag variant="outline" tone="success">Approved</vi-tag>
    - <vi-tag variant="solid" tone="danger" removable>Overdue</vi-tag>
vi-textarea:
  summary: Multi-line textarea with optional label, help text, and custom footer slot content.
  props:
    variant: string
    value: string
    rows: number
    placeholder: string
    required: boolean
    disabled: boolean
    invalid: boolean
  slots:
    - footer
  parts:
    - base
    - control
    - footer
  events:
    - vi-change
    - vi-input
  css_vars:
    - "--vi-cmp-textarea-footer-min-height"
    - "--vi-cmp-textarea-footer-padding"
    - "--vi-cmp-textarea-radius"
  examples:
    - <vi-textarea></vi-textarea>
vi-theme-switcher:
  summary: Pill-shaped segmented control for selecting light, dark, or system color mode. Emits vi-change with mode and resolvedMode.
  props:
    variant: string
    mode: "'light' | 'dark' | 'system'"
  events:
    - vi-change
  examples:
    - <vi-theme-switcher></vi-theme-switcher>
vi-timeline:
  summary: Flexible activity timeline supporting dots, icons, custom markers, timestamps, rich body content, and action rows.
  props:
    variant: string
    connectors: boolean
    dense: boolean
    markerColumnWidth: string
    rowGap: string
  css_vars:
    - "--vi-cmp-timeline-row-gap"
  examples:
    - <vi-timeline></vi-timeline>
vi-timeline-item:
  summary: One entry in vi-timeline — a marker plus title, optional subtitle, timestamp, body content, and an actions row.
  usage: |
    `marker` selects the marker style: 'dot' (default), 'icon' (pair with
    `marker-icon-name`), 'custom' (slot any element into `slot="marker"` —
    an avatar, for example), or 'none'. `tone` colours the marker.

    Prefer `<span slot="title">` over the `title` attribute when the title
    contains markup — and note that this component declares a `title`
    property that shadows the native `HTMLElement.title`, so setting the
    attribute also gives the element a browser tooltip. The slot does not.

    Body content goes in the default slot; `slot="actions"` renders a
    trailing action row. Both are hidden when empty.
  props:
    variant: string
    title: string
    subtitle: string
    timestamp: string
    marker: "'dot' | 'icon' | 'custom' | 'none'"
    tone: "'neutral' | 'info' | 'success' | 'warning' | 'danger'"
    markerSize: "'sm' | 'md' | 'lg'"
    markerIconName: string
    markerIconSystem: string
    markerIconStyle: string
    markerIconSize: number
    connector: boolean
    dense: boolean
  slots:
    - marker
    - title
    - subtitle
    - timestamp
    - default
    - meta
    - actions
  parts:
    - actions
    - base
    - body
    - connector
    - content
    - head
    - marker
    - meta
    - rail
    - subtitle
    - timestamp
    - title
  css_vars:
    - "--vi-cmp-timeline-line-color"
    - "--vi-cmp-timeline-line-width"
    - "--vi-cmp-timeline-marker-bg"
    - "--vi-cmp-timeline-marker-border"
    - "--vi-cmp-timeline-marker-color"
    - "--vi-cmp-timeline-marker-column-width"
    - "--vi-cmp-timeline-marker-danger-bg"
    - "--vi-cmp-timeline-marker-danger-border"
    - "--vi-cmp-timeline-marker-danger-color"
    - "--vi-cmp-timeline-marker-info-bg"
    - "--vi-cmp-timeline-marker-info-border"
    - "--vi-cmp-timeline-marker-info-color"
    - "--vi-cmp-timeline-marker-neutral-bg"
    - "--vi-cmp-timeline-marker-neutral-border"
    - "--vi-cmp-timeline-marker-neutral-color"
    - "--vi-cmp-timeline-marker-success-bg"
    - "--vi-cmp-timeline-marker-success-border"
    - "--vi-cmp-timeline-marker-success-color"
    - "--vi-cmp-timeline-marker-warning-bg"
    - "--vi-cmp-timeline-marker-warning-border"
    - "--vi-cmp-timeline-marker-warning-color"
    - "--vi-cmp-timeline-row-gap"
    - "--vi-cmp-timeline-subtitle-color"
    - "--vi-cmp-timeline-timestamp-color"
    - "--vi-cmp-timeline-title-color"
  examples:
    - |
      <vi-timeline>
        <vi-timeline-item marker="icon" tone="success" marker-icon-name="check" timestamp="Sep 28">
          <span slot="title">Completed phone screening</span>
        </vi-timeline-item>
        <vi-timeline-item marker="custom" timestamp="3d ago">
          <vi-avatar slot="marker" name="Chelsea Hagon" size="34"></vi-avatar>
          <span slot="title"><strong>Chelsea Hagon</strong> commented</span>
          <vi-card>Client reassured me the invoice would be paid by the 25th.</vi-card>
        </vi-timeline-item>
      </vi-timeline>
vi-toast:
  summary: Individual toast notification with tone, icon, actions, and dismiss support.
  props:
    toastId: string
    heading: string
    message: string
    tone: "'neutral' | 'info' | 'success' | 'warning' | 'danger'"
    variant: string
    duration: number
    dismissible: boolean
    open: boolean
    leaving: boolean
    iconName: string
    iconSystem: string
    iconStyle: string
    closeAriaLabel: string
  slots:
    - icon
    - title
    - default
    - actions
    - close-icon
  parts:
    - actions
    - base
    - content
    - dismiss
    - icon
    - message
    - title
  events:
    - vi-toast-dismiss
  css_vars:
    - "--vi-cmp-toast-bg"
    - "--vi-cmp-toast-border"
    - "--vi-cmp-toast-danger-icon"
    - "--vi-cmp-toast-danger-icon-bg"
    - "--vi-cmp-toast-dismiss-color"
    - "--vi-cmp-toast-icon-bg"
    - "--vi-cmp-toast-icon-color"
    - "--vi-cmp-toast-icon-radius"
    - "--vi-cmp-toast-icon-size"
    - "--vi-cmp-toast-info-icon"
    - "--vi-cmp-toast-info-icon-bg"
    - "--vi-cmp-toast-message-color"
    - "--vi-cmp-toast-neutral-icon"
    - "--vi-cmp-toast-neutral-icon-bg"
    - "--vi-cmp-toast-radius"
    - "--vi-cmp-toast-success-icon"
    - "--vi-cmp-toast-success-icon-bg"
    - "--vi-cmp-toast-text"
    - "--vi-cmp-toast-warning-icon"
    - "--vi-cmp-toast-warning-icon-bg"
    - "--vi-cmp-toast-width"
  aria: Uses status/alert live region semantics based on tone.
  examples:
    - <vi-toast tone="success" title="Saved" message="Record updated."></vi-toast>
vi-toast-stack:
  summary: Positioned top-right toast queue/stack manager with max-visible and auto-dismiss behavior.
  props:
    variant: string
    position: "'top-right' | 'top-left' | 'bottom-right' | 'bottom-left'"
    maxVisible: number
    newestOnTop: boolean
    pauseOnHover: boolean
    inline: boolean
    gap: string
    defaultDuration: number
    animationDuration: number
  events:
    - vi-toast-close
    - vi-toast-open
  css_vars:
    - "--vi-cmp-toast-stack-inset"
    - "--vi-cmp-toast-stack-z-index"
  aria: Delegated to child vi-toast live regions.
  examples:
    - <vi-toast-stack position="top-right"></vi-toast-stack>
vi-tooltip:
  summary: Contextual tooltip with arrow, auto-flip placement, scroll tracking, and dark/light mode inverse colors. Supports text content via attribute or rich HTML via the content slot.
  props:
    variant: string
    content: string
    placement: "'top' | 'bottom' | 'left' | 'right'"
    delay: number
    open: boolean
    showArrow: boolean
  slots:
    - default
    - content
  parts:
    - trigger
    - content
  css_vars:
    - "--vi-cmp-tooltip-arrow"
    - "--vi-cmp-tooltip-arrow-display"
    - "--vi-cmp-tooltip-fade"
    - "--vi-cmp-tooltip-radius"
    - "--vi-cmp-tooltip-shadow"
  keyboard: Escape dismisses an open tooltip.
  aria: Bubble has role="tooltip"; trigger gets aria-describedby when open.
  examples:
    - <vi-tooltip content="Confidence score from model inference"><vi-button>Score</vi-button></vi-tooltip>
    - <vi-tooltip placement="right" content="Opens in a new tab"><vi-icon name="external-link"></vi-icon></vi-tooltip>
    - |-
      <vi-tooltip placement="bottom">
        <vi-button>Details</vi-button>
        <span slot="content"><strong>Pipeline status:</strong> 3 of 5 stages complete</span>
      </vi-tooltip>
vi-rich-tooltip:
  summary: Tooltip with the same placement/delay behavior as vi-tooltip but intended for free-form slotted content.
  props:
    variant: string
  slots:
    - default
    - content
  parts:
    - trigger
    - content
    - base
  keyboard: Escape dismisses an open tooltip.
  aria: Bubble has role="tooltip"; trigger gets aria-describedby when open.
  examples:
    - |-
      <vi-rich-tooltip placement="top" delay="200">
        <vi-button>Model Details</vi-button>
        <div slot="content">
          <strong>Inference Summary</strong><br />
          Confidence: 0.92
        </div>
      </vi-rich-tooltip>
vi-tree:
  summary: Hierarchical expandable content, including a selectable mode for driving detail panes.
  props:
    variant: string
    selectable: boolean
    value: string
  events:
    - vi-change
  examples:
    - <vi-tree></vi-tree>
vi-tree-item:
  summary: A node in vi-tree. Its own label goes in the default slot; nested nodes go in `slot="children"`.
  usage: |
    The nesting rule is the thing to get right: a child node must carry
    `slot="children"`, otherwise it lands in the default slot and renders
    as part of the parent's label instead of as a subtree.

    In a `selectable` tree every selectable node needs a `value` — that is
    what vi-tree reports on `vi-change`. `expanded` is a plain attribute you
    can set for the initial state.
  props:
    variant: string
    expanded: boolean
    selected: boolean
    label: string
    value: string
    collapsedIcon: string
    expandedIcon: string
  slots:
    - default
    - children
  parts:
    - base
    - chevron
    - children
    - label
  events:
    - vi-select
    - vi-toggle
  examples:
    - |
      <vi-tree selectable>
        <vi-tree-item value="fund-a" expanded>
          Fund A
          <vi-tree-item slot="children" value="memo">Entity Memo.pdf</vi-tree-item>
          <vi-tree-item slot="children" value="risk">Risk Summary</vi-tree-item>
        </vi-tree-item>
      </vi-tree>
vi-vertical-nav:
  summary: Vertical navigation container with optional auto-active behavior, collapsible icon-only mode, and built-in toggle button.
  props:
    variant: string
    manageActive: boolean
    collapsed: boolean
    collapsible: boolean
    toggleAriaLabel: string
    collapsedIcon: string
    expandedIcon: string
  slots:
    - header-icon
    - header
    - default
  parts:
    - base
    - header
    - header-content
    - header-icon
    - toggle
  events:
    - vi-change
    - vi-toggle
  css_vars:
    - "--vi-cmp-vertical-nav-collapsed-width"
    - "--vi-cmp-vertical-nav-width"
  examples:
    - <vi-vertical-nav><vi-vertical-nav-item value="home">Home</vi-vertical-nav-item></vi-vertical-nav>
    - |-
      <vi-vertical-nav collapsible>
        <vi-avatar slot="header-icon" name="Acme Corp" size="24"></vi-avatar>
        <strong slot="header">Acme Corp</strong>
        <vi-vertical-nav-item value="home">
          <vi-icon slot="leading" name="house"></vi-icon>Home
        </vi-vertical-nav-item>
        <vi-vertical-nav-item value="settings">
          <vi-icon slot="leading" name="gear"></vi-icon>Settings
        </vi-vertical-nav-item>
      </vi-vertical-nav>
vi-vertical-nav-item:
  summary: Vertical navigation row with leading/trailing slots, active/disabled states, and optional expandable children.
  props:
    variant: string
    value: string
    label: string
    href: string
    target: string
    rel: string
    active: boolean
    disabled: boolean
    expanded: boolean
    collapsed: boolean
    tooltip: string
    heading: boolean
    guide: boolean
    collapsible: boolean
    selectable: boolean
  slots:
    - trailing
    - children
    - default
    - leading
  parts:
    - base
    - chevron
    - children
    - content
    - leading
    - trailing
  events:
    - vi-select
    - vi-toggle
  css_vars:
    - "--vi-cmp-vertical-nav-heading-font-size"
    - "--vi-cmp-vertical-nav-item-active-border"
    - "--vi-cmp-vertical-nav-item-active-surface"
    - "--vi-cmp-vertical-nav-item-active-text"
    - "--vi-cmp-vertical-nav-item-active-weight"
    - "--vi-cmp-vertical-nav-item-font-size"
    - "--vi-cmp-vertical-nav-item-font-weight"
    - "--vi-cmp-vertical-nav-item-hover-border"
    - "--vi-cmp-vertical-nav-item-hover-surface"
    - "--vi-cmp-vertical-nav-item-hover-text"
    - "--vi-cmp-vertical-nav-item-radius"
  aria: Sets aria-expanded when children are present.
  examples:
    - <vi-vertical-nav-item value="dashboard">Dashboard</vi-vertical-nav-item>
    - <vi-vertical-nav-item value="dashboard"><vi-icon slot="leading" name="house"></vi-icon>Dashboard<vi-badge slot="trailing" tone="transparent">5</vi-badge></vi-vertical-nav-item>
    - |-
      <vi-vertical-nav-item value="team" expanded selectable="false">
        <vi-icon slot="leading" name="user"></vi-icon>
        Team
        <vi-vertical-nav-item slot="children" value="members"><vi-icon slot="leading" name="user"></vi-icon>Members</vi-vertical-nav-item>
        <vi-vertical-nav-item slot="children" value="roles"><vi-icon slot="leading" name="gear"></vi-icon>Roles</vi-vertical-nav-item>
      </vi-vertical-nav-item>
vi-zoomable-frame:
  summary: Iframe wrapper with zoom controls that can render outside or float inside a chosen corner.
  props:
    variant: string
    src: string
    srcdoc: string
    zoom: number
    toolbarInside: boolean
    toolbarPosition: "'top-right' | 'top-left' | 'bottom-right' | 'bottom-left'"
    zoomOutText: string
    zoomInText: string
    zoomOutAriaLabel: string
    zoomInAriaLabel: string
    frameTitle: string
    placeholderText: string
    sandbox: string
  slots:
    - zoom-out-icon
    - zoom-in-icon
  parts:
    - base
    - frame
    - placeholder
    - toolbar
    - zoom-in
    - zoom-out
  events:
    - vi-zoom
  css_vars:
    - "--vi-cmp-zoomable-frame-border"
    - "--vi-cmp-zoomable-frame-control-radius"
    - "--vi-cmp-zoomable-frame-control-size"
    - "--vi-cmp-zoomable-frame-radius"
  examples:
    - <vi-zoomable-frame toolbar-inside toolbar-position="top-right" style="--vi-cmp-zoomable-frame-control-radius:0.125rem;"></vi-zoomable-frame>
