# @3dsource/source-ui-native

> All local file paths in this document are relative to the package root (`@3dsource/source-ui-native/`).


> Lightweight UI primitives with zero dependencies (only `tslib`). **No Angular peer dependency** — works without Angular entirely. Can be used in any project (React, Vue, plain HTML, Lovable, etc.) by importing just the compiled CSS stylesheet. Angular components use signals API (`input()`, `output()`), zoneless change detection, `ViewEncapsulation.None`, and CSS custom properties (`--src-*`) for theming.

For CDK/Material components (color-picker, popover, tabs, tooltip, CDK modal, styled Material form fields) see the companion library `@3dsource/source-ui`.

- [Live demo site](https://preview.3dsource.com/front-libraries/develop/): Interactive examples of all components with live code snippets (uses HashLocationStrategy — routes like `/#/components/SourceButtonComponent`). The `/develop/` branch always has the latest published version.

## Setup

Complete these steps when adding Source UI to a new app. Order matters — nothing renders correctly without steps 1 and 2.

1. **Import the stylesheet.** For Angular projects, add to `styles.scss`:
   ```scss
   @use '../node_modules/@3dsource/source-ui-native/styles/source.ui.native.scss' as source-ui-native;
   ```
   For non-Angular / CSS-only projects, link `node_modules/@3dsource/source-ui-native/styles/source-ui-native.min.css`. Full reference: see `## Stylesheet import paths` below.

2. **Add the `section_3dsourcecom` root class.** Put it on an element that wraps your whole app — inner `<app-root>` wrapper, a root `<section>`, or `<body>` as a last resort. NOT on `<html>`. Example:
   ```html
   <body class="section_3dsourcecom">...</body>
   ```
   Without this class, design tokens do not apply and components render unstyled.

3. **Place `<src-overlay-container>` inside the root element** if the app uses the native modal (`SourceModalNativeService`). Import `SourceOverlayContainerComponent` from `@3dsource/source-ui-native` and add the tag once, typically as a sibling of `<app-root>`:
   ```html
   <body class="section_3dsourcecom">
     <app-root></app-root>
     <src-overlay-container></src-overlay-container>
   </body>
   ```
   `SourceModalNativeService.open(...)` attaches into this container; without it, native modals throw at runtime. No other API currently uses this container (popovers, CDK Dialog, and ngx-toastr all bypass it).

4. **(Optional) Enable dark theme.** Add `section_3dsourcecom--dark` alongside `section_3dsourcecom` to switch to dark tokens. Both light and dark token sets are bundled — no extra import. Toggle by adding/removing the `--dark` class at runtime.

5. **(If using `@3dsource/source-ui`)** Install it as a peer of `@3dsource/source-ui-native` and follow the Setup section in its llms.txt for Angular Material / CDK prerequisites (providers, animations).

## Key concepts

- All components use the `src-` selector prefix (e.g. `<src-button>`, `<src-badge>`)
- Angular component imports: `import { SourceButtonComponent } from '@3dsource/source-ui-native'` or `import { SourcePopoverTriggerComponent } from '@3dsource/source-ui'`. All components are exported from the package root — no deep import paths.
- Inputs use Angular signals: `input()`, `input.required()`, `output()`
- Enum-like inputs are typed as union types derived from `as const` objects (e.g. `SourceButtonAppearanceKeys` = `"plain" | "inline" | "filled" | "default"`)
- Design tokens are SCSS CSS custom properties with `--src-` prefix, organized by category: color (light/dark themes), layout (responsive breakpoints), typeface, UI sizing
- The library provides TWO levels of styling: Angular Components (with `input()/output()` API) AND CSS-only Source Elements (BEM classes on native HTML tags — no Angular imports needed)
- Modals use native `<dialog>` element — opened via `SourceModalNativeService.open(component, config)` (no CDK dependency). The first argument is the component class to render: pass `SourceModalNativeComponent` for built-in chrome (header / body / footer driven by `config.data: SourceModalData` — `headerTitle`, `closeButton`, `closeButtonAriaLabel`, `context`, `content` (HTML string), `footerButtons`, `testID`), pass `SourceModalComponent` from `@3dsource/source-ui` for the same chrome backed by CDK button components (cross-context via dual DI), or pass any custom component for a fully custom layout. `config: SourceModalConfig<D>` carries `data` plus dialog-wrapper options (`width`, `panelClass`, `role`, `ariaLabel`/`ariaLabelledBy`/`ariaDescribedBy`, sizing). Returns `SourceModalNativeRef` — subscribe to `afterClosed()` for the result (or `closed` for a CDK-style observable). Custom components inject `SOURCE_MODAL_DATA` and `SOURCE_MODAL_REF` to read data and close. Old names `SourceModalElement*` remain available as deprecated aliases — prefer `*Native*` in new code. This native-`<dialog>` modal is the recommended choice over the CDK-based `SourceModalComponent` from `@3dsource/source-ui` for new code; the CDK version remains a supported alternative.
- The `section_3dsourcecom` class must be placed on the root app container element for Source UI styles to apply. Place it on `<app-root>` inner wrapper, the root `<section>`, or `<body>` as a last resort. Do NOT place it on `<html>`. Example: `<body class="section_3dsourcecom">` or `<div class="section_3dsourcecom">` as the first child of `<app-root>`.
- **Dark theme**: add `section_3dsourcecom--dark` class alongside `section_3dsourcecom` to activate the dark color scheme. Toggle between light and dark by adding/removing the `--dark` class. Both light and dark tokens are bundled — no extra import needed.
- **Scrollbar**: global scrollbar styling is applied automatically (`scrollbar-width: thin`). Override with `--srcScrollbarThumbColor` and `--srcScrollbarTrackColor` CSS custom properties on any ancestor element.
- STRICT RULE: Do NOT use Tailwind CSS or any utility-first CSS framework. All styling must use Source UI design tokens (`--src-*` CSS custom properties), Source Element BEM classes (`src-*`), and standard CSS/SCSS. Never generate Tailwind classes (`flex`, `p-4`, `bg-blue-500`, etc.).
- STRICT RULE: Do NOT use `all: unset` to reset browser defaults. It also unsets `box-sizing: border-box` and causes layout bugs. Reset defaults explicitly (e.g. `appearance: none; background: none; border: none; padding: 0; margin: 0; font: inherit; color: inherit; cursor: pointer;`).

## Components

- **Angular Components** (require Angular): badge, banner, button, copyright, divider, hint, icon-button, loading, logo-loading, modal-native, slider, tile
- **Source Elements (CSS-only, no Angular needed)**: badge, banner, breadcrumbs, button, button-group, checkbox, divider, hint, icon-button, input, label, list, modal, radio, select, textarea, tile, toggle, toolbar — pure CSS classes applied to standard HTML elements

## Component API reference (inline)

> Full API for every component inlined below. No external JSON links needed.

### SourceBadgeComponent (@3dsource/source-ui-native)
**Selector:** `src-badge` · **Kind:** Component

**Inputs:**

| Input | Type | Default | Values | Required | Description |
|-------|------|---------|--------|----------|-------------|
| backgroundColor | string | "var(--src-ui-accent-default, #017bffff)" | — | no | — |
| context | SourceBadgeContextKeys | — | default, info, success, warning, attention, error | no | — |
| size | SourceBadgeSizeKeys | "md" | sm, md, lg, xl | no | — |
| textColor | string | "var(--src-text-body-main-invert, #f9fafbff)" | — | no | — |
| customClass | string \| string[] | — | — | no | — |
| testID (alias: data-testid) | string | "" | — | no | — |
| role | string \| null | "status" | — | no | — |
| ariaLabel | string | — | — | no | — |

### SourceBannerComponent (@3dsource/source-ui-native)
**Selector:** `src-banner` · **Kind:** Component

**Inputs:**

| Input | Type | Default | Values | Required | Description |
|-------|------|---------|--------|----------|-------------|
| context | SourceBannerContextKeys | "default" | default, info, success, warning, critical, error | no | — |
| size | SourceBannerSizeKeys | "sm" | sm, md, lg, xl | no | — |
| isFullWidth | boolean | true | — | no | — |
| testID (alias: data-testid) | string | "" | — | no | — |
| role | string | — | — | no | — |
| ariaLive | 'polite' \| 'assertive' \| 'off' | — | — | no | — |

### SourceButtonComponent (@3dsource/source-ui-native)
**Selector:** `src-button` · **Kind:** Component

**Inputs:**

| Input | Type | Default | Values | Required | Description |
|-------|------|---------|--------|----------|-------------|
| type | SourceButtonTypeKeys | "button" | button, submit, reset | no | — |
| appearance | SourceButtonAppearanceKeys | "filled" | plain, inline, filled, default | no | — |
| weight | SourceButtonWeightKeys | "secondary" | primary, secondary, ghost | no | — |
| size | SourceButtonSizeKeys | "md" | sm, md, lg, xl | no | — |
| context | SourceButtonContextKeys | "default" | default, error, success, info | no | — |
| customClass | string \| string[] | "" | — | no | — |
| isFullWidth | boolean | false | — | no | — |
| isPressed | boolean | false | — | no | — |
| isDisabled | boolean | false | — | no | — |
| isLoading | boolean | false | — | no | — |
| isInverted | boolean | false | — | no | — |
| srcButtonConfig | SourceButton | — | — | no | — |
| formID | string | — | — | no | — |
| testID (alias: data-testid) | string | "" | — | no | — |
| ariaLabel | string | — | — | no | — |

**Outputs:**

| Output | Type | Description |
|--------|------|-------------|
| onClick | Event | — |
| onSubmit | Event | — |

### SourceCopyrightComponent (@3dsource/source-ui-native)
**Selector:** `src-copyright` · **Kind:** Component

**Inputs:**

| Input | Type | Default | Values | Required | Description |
|-------|------|---------|--------|----------|-------------|
| linkText | string | "Powered by 3D Source" | — | no | — |
| isCollapsible | boolean | false | — | no | — |
| testID (alias: data-testid) | string | "" | — | no | — |

### SourceDividerComponent (@3dsource/source-ui-native)
**Selector:** `src-divider` · **Kind:** Component

**Inputs:**

| Input | Type | Default | Values | Required | Description |
|-------|------|---------|--------|----------|-------------|
| orientation | SourceDividerOrientationKeys | "horizontal" | horizontal, vertical | no | — |
| testID (alias: data-testid) | string | "" | — | no | — |

### SourceHintComponent (@3dsource/source-ui-native)
**Selector:** `src-hint` · **Kind:** Component

**Inputs:**

| Input | Type | Default | Values | Required | Description |
|-------|------|---------|--------|----------|-------------|
| isError | boolean | false | — | no | — |
| context | SourceHintContextKeys | "default" | default, error, success, info | no | — |
| size | SourceHintSizeKeys | "md" | sm, md, lg, xl | no | — |
| testID (alias: data-testid) | string | "" | — | no | — |
| id | string | — | — | no | — |
| role | string | — | — | no | — |
| ariaLive | 'polite' \| 'assertive' \| 'off' | — | — | no | — |

### SourceIconButtonComponent (@3dsource/source-ui-native)
**Selector:** `src-icon-button` · **Kind:** Component

**Inputs:**

| Input | Type | Default | Values | Required | Description |
|-------|------|---------|--------|----------|-------------|
| name | unknown | — | — | no | — |
| type | SourceIconButtonTypeKeys | "button" | button, submit, reset | no | — |
| appearance | SourceIconButtonAppearanceKeys | "filled" | filled, plain, inline | no | — |
| weight | SourceIconButtonWeightKeys | "secondary" | primary, secondary, ghost | no | — |
| size | SourceIconButtonSizeKeys | "md" | sm, md, lg, xl | no | — |
| shape | SourceIconButtonShapeKeys | "square" | square, round | no | — |
| context | SourceIconButtonContextKeys | "default" | default, error, success, info, warning | no | — |
| counter | number \| undefined | "undefined" | — | no | — |
| isPressed | boolean | false | — | no | — |
| isInverted | boolean | false | — | no | — |
| isDisabled | boolean | false | — | no | — |
| testID (alias: data-testid) | string | "" | — | no | — |
| ariaLabel | string | — | — | no | — |

**Outputs:**

| Output | Type | Description |
|--------|------|-------------|
| onClick | Event | — |

### SourceLoadingComponent (@3dsource/source-ui-native)
**Selector:** `src-loading` · **Kind:** Component

**Inputs:**

| Input | Type | Default | Values | Required | Description |
|-------|------|---------|--------|----------|-------------|
| size | number | 32 | — | no | — |
| progress | number \| null | "null" | — | no | — |
| lineCap | SourceLoadingLineCapKeys | "round" | round, square, butt | no | — |
| backgroundStrokeColor | string | "transparent" | — | no | — |
| progressStrokeColor | string | "var(--src-ui-accent-default, #017bffff)" | — | no | — |
| strokeWidth | number | 3 | — | no | — |
| testID (alias: data-testid) | string | "" | — | no | — |
| role | string | — | — | no | — |
| ariaLabel | string | — | — | no | — |
| ariaValueNow | number | — | — | no | — |
| ariaValueMin | number | — | — | no | — |
| ariaValueMax | number | — | — | no | — |

### SourceLogoLoadingComponent (@3dsource/source-ui-native)
**Selector:** `src-logo-loading` · **Kind:** Component

**Inputs:**

| Input | Type | Default | Values | Required | Description |
|-------|------|---------|--------|----------|-------------|
| size | number | 32 | — | no | — |
| strokeColor | string | "var(--src-ui-accent-default, #017bffff)" | — | no | — |
| testID (alias: data-testid) | string | "" | — | no | — |
| role | string | "status" | — | no | — |
| ariaLabel | string | — | — | no | — |

### SourceModalNativeComponent (@3dsource/source-ui-native)
**Selector:** `src-modal-native` · **Kind:** Component

### SourceOverlayContainerComponent (@3dsource/source-ui-native)
**Selector:** `src-overlay-container` · **Kind:** Component

### SourceSliderComponent (@3dsource/source-ui-native)
**Selector:** `src-slider` · **Kind:** Component

**Inputs:**

| Input | Type | Default | Values | Required | Description |
|-------|------|---------|--------|----------|-------------|
| id | string | — | — | no | — |
| value | number | — | — | yes | — |
| min | number | — | — | yes | — |
| max | number | — | — | yes | — |
| thumbSize | number | 16 | — | no | — |
| trackHeight | number | 4 | — | no | — |
| step | number | 1 | — | no | — |
| showTicks | boolean | false | — | no | — |
| isDisabled | boolean | false | — | no | — |
| orientation | 'horizontal' \| 'vertical' | "horizontal" | — | no | — |
| testID (alias: data-testid) | string | "" | — | no | — |
| ariaLabel | string | — | — | no | — |
| ariaValueText | string | — | — | no | — |

**Outputs:**

| Output | Type | Description |
|--------|------|-------------|
| onChange | number | — |
| onInput | number | — |

### SourceTileComponent (@3dsource/source-ui-native)
**Selector:** `src-tile` · **Kind:** Component

**Inputs:**

| Input | Type | Default | Values | Required | Description |
|-------|------|---------|--------|----------|-------------|
| width | string | — | — | no | — |
| counter | string | — | — | no | — |
| counterPlacement | SourceTileCounterPlacementKeys | "center" | top-right, top-left, bottom-right, bottom-left, center | no | — |
| aspectRatio | string | "1/1" | — | no | — |
| titleLineClamp | number | — | — | no | — |
| isInteractive | boolean | true | — | no | — |
| isActive | boolean | — | — | no | — |
| isDisabled | boolean | — | — | no | — |
| isLoading | boolean | — | — | no | — |
| testID (alias: data-testid) | string | "" | — | no | — |
| ariaLabel | string | — | — | no | — |
| ariaValueText | string | — | — | no | — |

### SourceDialogContainerComponent (@3dsource/source-ui-native)
**Selector:** `src-dialog-container` · **Kind:** Component

**Inputs:**

| Input | Type | Default | Values | Required | Description |
|-------|------|---------|--------|----------|-------------|
| shell | ShellConfig | — | — | yes | — |

## Source Elements (CSS-only styling)

CSS-only Source Elements — BEM classes applied to native HTML tags. No Angular imports needed. Requires source.ui.native.scss stylesheet.

Stylesheet: `@3dsource/source-ui-native/styles/source-ui-native.min.css`

- [Source Elements API (JSON)](../api/source-elements.json): Machine-readable reference for all CSS-only elements with modifiers, sub-elements, and usage examples.

Use Source Elements when: you don't need Angular signal bindings, you want minimal overhead, or you're prototyping without Angular.

### Badge Element

Status badge. Use for labels, tags, and status indicators.

Apply `src-badge` class to any appropriate HTML tag.

**Usage:**
```html
<span class="src-badge src-badge--context-success">
  <span class="src-badge__icon">
    <svg viewBox="0 0 20 20" fill="currentColor"><!-- check icon --></svg>
  </span>
  Active
</span>

<span class="src-badge src-badge--context-error src-badge--size-sm">3</span>
```

**Context modifiers:**
- `src-badge--context-default` (default) — Neutral background, muted label colour.
- `src-badge--context-info` — Info-blue styling.
- `src-badge--context-success` — Success-green styling.
- `src-badge--context-warning` — Warning-amber styling.
- `src-badge--context-attention` — Attention-yellow styling.
- `src-badge--context-error` — Error-red styling.

**Sub-elements:**
- `src-badge__icon` — Prefix/postfix icon wrapper inside badge.

**Custom properties:** `--srcBadgeBackgroundColor`, `--srcBadgeTextColor`

### Banner Element

Notification banner. Use for page-level alerts.

Apply `src-banner` class to any appropriate HTML tag.

**Usage:**
```html
<div class="src-banner src-banner--context-info">
  <span class="src-banner__icon-prefix">
    <svg viewBox="0 0 20 20" fill="currentColor"><!-- info icon --></svg>
  </span>
  <div class="src-banner__content">
    <div class="src-banner__title">Information</div>
    Your changes have been saved successfully.
  </div>
  <span class="src-banner__icon-postfix">
    <button type="button" class="src-icon-button src-icon-button--inline">
      <svg viewBox="0 0 20 20" fill="currentColor"><!-- close icon --></svg>
    </button>
  </span>
</div>
```

**Context modifiers:**
- `src-banner--context-info` — Info-blue styling.
- `src-banner--context-success` — Success-green styling.
- `src-banner--context-warning` — Warning-amber styling.
- `src-banner--context-error` — Error-red styling.
- `src-banner--context-critical` — Critical-red styling (same as error).

**Size modifiers:**
- `src-banner--size-sm` — Small size (default). Tech-style uppercase title.
- `src-banner--size-md` — Medium size. Tech-style uppercase title.
- `src-banner--size-lg` — Large size. Capitalized title with larger font.
- `src-banner--size-xl` — Extra-large size. Capitalized title with larger font.

**Sub-elements:**
- `src-banner__icon-prefix` — Leading icon slot.
- `src-banner__icon-postfix` — Trailing icon slot (e.g. close button).
- `src-banner__title` — Uppercase bold title within the banner.
- `src-banner__content` — Main body content wrapper.

### Breadcrumbs Element

CSS-only breadcrumb navigation trail. Renders items in a horizontal list with "/" separators. Content inside each item is fully consumer-controlled (links, buttons, spans).

Apply `src-breadcrumbs` class to any appropriate HTML tag.

**Usage:**
```html
<nav aria-label="Breadcrumb" class="src-breadcrumbs">
  <ol class="src-breadcrumbs__list">
    <li class="src-breadcrumbs__item">
      <a class="src-label-md" href="/">Home</a>
    </li>
    <li class="src-breadcrumbs__item">
      <a class="src-label-md" href="/components">Components</a>
    </li>
    <li class="src-breadcrumbs__item" aria-current="page">
      <span class="src-label-md">Breadcrumbs</span>
    </li>
  </ol>
</nav>
```

**Sub-elements:**
- `src-breadcrumbs__list` — Flex container for breadcrumb items. Apply to an <ol> inside .src-breadcrumbs.
- `src-breadcrumbs__item` — Individual breadcrumb item. Apply to each <li>. Renders a "/" separator via ::after (hidden on last item).

**Custom properties:** `--srcBreadcrumbListGap`, `--srcBreadcrumbSeparatorOffset`

### Button Group Element

CSS-only wrapper that visually combines adjacent buttons or icon-buttons into a single unit. Flattens inner border-radii so the group appears as one continuous control.

Apply `src-button-group` class to any appropriate HTML tag.

**Usage:**
```html
<div class="src-button-group">
  <src-button appearance="plain">Label</src-button>
  <src-icon-button appearance="plain" size="sm">
    <src-icon name="arrow_drop_down" size="var(--src-icon-size)"></src-icon>
  </src-icon-button>
</div>
```

### Button Element

Interactive button. Use for actions and navigation.

Apply `src-button` class to any appropriate HTML tag.

**Usage:**
```html
<button type="button" class="src-button src-button--primary src-button--size-lg">
  Save changes
</button>

<button type="button" class="src-button src-button--plain src-button--ghost">
  Cancel
</button>

<button type="button" class="src-button src-button--primary src-button--context-error">
  Delete
</button>
```

**Weight modifiers:**
- `src-button--primary` — Change visual weight to more prominent.
- `src-button--secondary` (default) — Change visual weight to default button.
- `src-button--ghost` — Change visual weight for less prominent button.

**Appearance modifiers:**
- `src-button--plain` — Minimalistic button without background color and border.
- `src-button--inline` — Minimalistic button without background color, border and paddings around.

**Size modifiers:**
- `src-button--size-sm` — Small size for the button.
- `src-button--size-md` (default) — Default size for the button.
- `src-button--size-lg` — Large size for the button.
- `src-button--size-xl` — Extra large size for the button.
- `src-button--full-width` — Full width button.

**Context modifiers:**
- `src-button--context-info` — Visual context for button - used for informational purposes. Paint the button in blue color. For primary button does not exist.
- `src-button--context-success` — Visual context for a button indicating a successful action. The button is painted green.
- `src-button--context-error` — Visual context for a button indicating a failed action. Paint the button in red color.

**State modifiers:**
- `src-button--pressed` — Button pressed state.

[Demo](https://preview.3dsource.com/front-libraries/develop/#/components/SourceButtonElement)

### Checkbox Element

Styled native checkbox.

Apply `src-checkbox` class to any appropriate HTML tag.

**Usage:**
```html
<label class="src-checkbox">
  <input type="checkbox" checked />
  <span class="src-checkbox__label">I agree to the terms and conditions</span>
</label>

<label class="src-checkbox">
  <input type="checkbox" disabled />
  <span class="src-checkbox__label">Disabled option</span>
</label>
```

**Sub-elements:**
- `src-checkbox__label` — Text label beside the checkbox.

[Demo](https://preview.3dsource.com/front-libraries/develop/#/components/FormElements)

### Divider Element

Separator line. Horizontal by default.

Apply `src-divider` class to any appropriate HTML tag.

**Usage:**
```html
<hr class="src-divider" />

<!-- Vertical -->
<hr class="src-divider src-divider--vertical" />

<!-- Custom thickness and color -->
<hr class="src-divider" style="--srcDividerThickness: 2px; --srcDividerColor: #e1e4e8;" />

<!-- With inset (shortens the line on both ends) -->
<hr class="src-divider" style="--srcDividerInset: 12px;" />
```

**Modifier modifiers:**
- `src-divider--vertical` — Renders the divider as a vertical line.

**Custom properties:** `--srcDividerColor`, `--srcDividerThickness`, `--srcDividerInset`, `--srcDividerOffsetStart`, `--srcDividerOffsetEnd`, `--srcDividerOffsetTop`, `--srcDividerOffsetBottom`

### Hint Element

Contextual message below form fields or content.

Apply `src-hint` class to any appropriate HTML tag.

**Usage:**
```html
<p class="src-hint">Enter a value between 1 and 100.</p>

<p class="src-hint src-hint--context-error">
  <span class="src-hint__icon">
    <svg viewBox="0 0 20 20" fill="currentColor"><!-- error icon --></svg>
  </span>
  This field is required.
</p>

<p class="src-hint src-hint--context-success">Username is available.</p>
```

**Context modifiers:**
- `src-hint--context-error` — Red text for error messages.
- `src-hint--context-info` — Blue text for informational messages.
- `src-hint--context-success` — Green text for success messages.
- `src-hint--error` — Legacy alias for --context-error.

**Sub-elements:**
- `src-hint__icon` — Prefix icon slot.

### Icon Button Element

Icon-only action button. Use for toolbar actions and compact controls.

Apply `src-icon-button` class to any appropriate HTML tag.

**Usage:**
```html
<button type="button" class="src-icon-button src-icon-button--ghost src-icon-button--round">
  <svg viewBox="0 0 20 20" fill="currentColor"><!-- close icon --></svg>
</button>

<button type="button" class="src-icon-button src-icon-button--inline src-icon-button--size-sm">
  <svg viewBox="0 0 20 20" fill="currentColor"><!-- close icon --></svg>
</button>
```

**Appearance modifiers:**
- `src-icon-button--plain` — Represents a plain icon button.
- `src-icon-button--inline` — Represents an inline icon button without paddings around.

**Weight modifiers:**
- `src-icon-button--primary` — Change visual weight to more prominent.
- `src-icon-button--secondary` (default) — Change visual weight to default button.
- `src-icon-button--ghost` — Change visual weight for less prominent button.

**Size modifiers:**
- `src-icon-button--size-sm` — Small size for the button. Used for popovers and modals.
- `src-icon-button--size-md` (default) — Default size for the button.
- `src-icon-button--size-lg` — Large size for the button.
- `src-icon-button--size-xl` — Extra large size for the button.

**Shape modifiers:**
- `src-icon-button--round` — Shape modificator. You can use Size modificators with this class.

**Context modifiers:**
- `src-icon-button--context-info` — Visual context for button - used for informational purposes. Paint the button in blue color.
- `src-icon-button--context-success` — Visual context for a button indicating a successful action. Paint the button in green color.
- `src-icon-button--context-warning` — Visual context for a button indicating a warning. Paint the button in orange color. Works for inline appearance only.
- `src-icon-button--context-error` — Visual context for a button indicating a failed action. Paint the button in red color.

**State modifiers:**
- `src-icon-button--pressed` — Standard active state for button

[Demo](https://preview.3dsource.com/front-libraries/develop/#/components/SourceIconButtonElement)

### Input Element

Text input field. Use for single-line text entry.

Apply `src-input` class to any appropriate HTML tag.

**Usage:**
```html
<label class="src-label" for="email-input">Email</label>
<input
  id="email-input"
  type="email"
  class="src-input"
  placeholder="name@example.com"
/>

<label class="src-label" for="error-input">Username</label>
<input
  id="error-input"
  type="text"
  class="src-input src-input--context-error"
  placeholder="Enter username"
  value="ab"
/>
<p class="src-hint src-hint--context-error">Minimum 3 characters required.</p>
```

**Weight modifiers:**
- `src-input--primary` (default) — Default visual appearance of input - with visible border.
- `src-input--secondary` — Visual appearance for less prominent input - with visible background, but without border.
- `src-input--ghost` — Visual appearance for the least prominent input - without visible background and border.

**Size modifiers:**
- `src-input--size-sm` — Smallest size of input.
- `src-input--size-md` (default) — Default size of input.
- `src-input--size-lg` — Large size of input.
- `src-input--size-xl` — Extra large size of input.

**Context modifiers:**
- `src-input--context-success` — Green border for the input. Used for success context.
- `src-input--context-error` — Red border for the input. Used for error context.

**State modifiers:**
- `src-input--disabled` — Disabled state for the input. Also you can use [disabled] property instead of a class.

[Demo](https://preview.3dsource.com/front-libraries/develop/#/components/SourceInputElement)

### Label Element

Uppercase, small technical text label for form fields.

Apply `src-label` class to any appropriate HTML tag.

**Usage:**
```html
<label class="src-label" for="name-field">Full name</label>
<input id="name-field" type="text" class="src-input" placeholder="John Doe" />
```

### List Element

List container with styled items.

Apply `src-list` class to any appropriate HTML tag.

**Usage:**
```html
<ul class="src-list">
  <li class="src-list__item src-list__item--selected">Dashboard</li>
  <li class="src-list__item">Projects</li>
  <li class="src-list__item src-list__item--disabled">Archived</li>
  <li class="src-list__item src-list__item--flex src-list__item--context-error">
    <svg viewBox="0 0 20 20" fill="currentColor"><!-- delete icon --></svg>
    Delete workspace
  </li>
</ul>
```

**Size modifiers:**
- `src-list--compact` — Decreased padding around the list and between list items.

**Sub-elements:**
- `src-list__item` — The main class for the list item element.
- `src-list__item--flex` — Class modifier for a flex list item. Use this when your content includes an icon or has a more complex structure. You can still style it in your CSS.
- `src-list__item--disabled` — List item disabled state. The "disabled" attribute is also supported.
- `src-list__item--selected` — Selected state for the list item.
- `src-list__item--context-error` — Visually distinct appearance to emphasize a critical action.

[Demo](https://preview.3dsource.com/front-libraries/develop/#/components/SourceListElement)

### Modal Native Element

CSS structure for modal layout (header / body / footer). Used by the Angular `SourceModalNativeComponent` and by custom CDK Dialog modals.

Apply `src-modal` class to any appropriate HTML tag.

**Usage:**
```html
<dialog class="src-dialog">
  <div class="src-modal">
    <div class="src-modal__header">
      <button type="button" class="src-icon-button src-icon-button--plain src-icon-button--round src-icon-button--size-sm src-modal__close">
        <svg viewBox="0 0 20 20" fill="currentColor"><!-- close icon --></svg>
      </button>
    </div>
    <div class="src-modal__body">
      <h2 class="src-modal__title">Confirm deletion</h2>
      <div class="src-modal__scroll-box">
        <p>Are you sure you want to delete this item? This action cannot be undone.</p>
      </div>
    </div>
    <div class="src-modal__footer">
      <div class="src-modal__footer-group">
        <button type="button" class="src-button src-button--plain src-button--ghost">Cancel</button>
        <button type="button" class="src-button src-button--primary src-button--context-error">Delete</button>
      </div>
    </div>
  </div>
</dialog>
```

**Sub-elements:**
- `src-dialog` — Apply on a native `<dialog>` element to reset its padding/border/background and style its `::backdrop` with the design-system curtain color.
- `src-modal__header` — Header row. Hosts the close button; has bottom border.
- `src-modal__body` — Scrollable content area with padding. Grid-based; children `__title` and `__scroll-box` span the full width by default.
- `src-modal__body--icon` — Switches body grid to two columns (24px icon + content). Use together with `.src-modal__icon` when rendering a context icon (info/success/warning/error).
- `src-modal__icon` — Icon slot in the left column of `.src-modal__body--icon`. Spans all body rows.
- `src-modal__title` — Semibold title inside the body. Word-break on overflow.
- `src-modal__scroll-box` — Scrollable content wrapper spanning the full body grid width.
- `src-modal__footer` — Action buttons row. Right-aligned by default; when two `.src-modal__footer-group` children are present it switches to space-between via `:has()`. Top border. On narrow viewports (<=767px) stacks column-reverse.
- `src-modal__footer-group` — Button group inside `.src-modal__footer`. Use one group for right-aligned buttons, or two groups to split them between left and right.
- `src-modal__close` — Absolutely-positioned close button at top-right of the header. Typically applied to `.src-icon-button`.

**Custom properties:** `--srcModalWidth`, `--srcModalMaxWidth`, `--srcModalMaxHeight`, `--srcModalBg`, `--srcModalBoxShadow`, `--srcModalBorderRadius`, `--srcModalTitleSize`, `--srcModalTitleLineHeight`, `--srcModalTitleColor`, `--srcModalBodyPadding`, `--srcModalTitleBorder`, `--srcModalFooterBorder`

### Radio Group Element

Radio button group container.

Apply `src-radio-group` class to any appropriate HTML tag.

**Usage:**
```html
<div class="src-radio-group">
  <label class="src-radio">
    <input type="radio" name="plan" value="free" checked />
    <span class="src-radio__label">Free</span>
  </label>
  <label class="src-radio">
    <input type="radio" name="plan" value="pro" />
    <span class="src-radio__label">Professional</span>
  </label>
  <label class="src-radio">
    <input type="radio" name="plan" value="enterprise" disabled />
    <span class="src-radio__label">Enterprise (coming soon)</span>
  </label>
</div>
```

**Layout modifiers:**
- `src-radio-group--horizontal` — Switches to horizontal flex-row with wrapping.

**Sub-elements:**
- `src-radio` — Flex container for a single radio button. Wraps input[type="radio"] with custom appearance.
- `src-radio__label` — Text label beside the radio button.

[Demo](https://preview.3dsource.com/front-libraries/develop/#/components/FormElements)

### Select Element

Native dropdown select. Same modifiers as src-input.

Apply `src-select` class to any appropriate HTML tag.

**Usage:**
```html
<label class="src-label" for="country-select">Country</label>
<select id="country-select" class="src-select">
  <option value="">Select a country</option>
  <option value="us">United States</option>
  <option value="de">Germany</option>
  <option value="jp">Japan</option>
</select>
```

**Weight modifiers:**
- `src-select--primary` (default) — Default visual appearance of select - with visible border.
- `src-select--secondary` — Visual appearance for less prominent select - with visible background, but without border.
- `src-select--ghost` — Visual appearance for the least prominent select - without visible background and border.

**Size modifiers:**
- `src-select--size-sm` — Smallest size of select.
- `src-select--size-md` (default) — Default size of select.
- `src-select--size-lg` — Large size of select.
- `src-select--size-xl` — Extra large size of select.

**Context modifiers:**
- `src-select--context-success` — Green border for the select. Used for success context.
- `src-select--context-error` — Red border for the select. Used for error context.

**State modifiers:**
- `src-select--disabled` — Disabled state for the select. Also you can use [disabled] property instead of a class.

[Demo](https://preview.3dsource.com/front-libraries/develop/#/components/SourceSelectElement)

### Textarea Element

Multi-line text input.

Apply `src-textarea` class to any appropriate HTML tag.

**Usage:**
```html
<label class="src-label" for="comment-field">Comment</label>
<textarea
  id="comment-field"
  class="src-textarea src-textarea--size-lg"
  rows="4"
  placeholder="Write your comment..."
></textarea>

<textarea
  class="src-textarea src-textarea--context-error"
  rows="3"
  placeholder="Write your comment..."
>Invalid content</textarea>
<p class="src-hint src-hint--context-error">Comment exceeds maximum length.</p>
```

**Weight modifiers:**
- `src-textarea--secondary` — Visual appearance with background fill, no border.
- `src-textarea--ghost` — Transparent background, no border.

**Size modifiers:**
- `src-textarea--size-sm` — Smallest size (28px min-height).
- `src-textarea--size-md` (default) — Default size (36px min-height).
- `src-textarea--size-lg` — Large size (44px min-height).
- `src-textarea--size-xl` — Extra large size (56px min-height).

**Context modifiers:**
- `src-textarea--context-success` — Green border for success context.
- `src-textarea--context-error` — Red border for error context.

**State modifiers:**
- `src-textarea--disabled` — Disabled state. Also supports the native [disabled] attribute.

### Tile Element

Image thumbnail tile. Use for material previews, preset cards, and option selectors.

Apply `src-tile` class to any appropriate HTML tag.

**Usage:**
```html
<div class="src-tile src-tile--active">
  <div class="src-tile__image">
    <img src="material.avif" alt="Oak wood" />
    <div class="src-tile__counter src-tile__counter--top-right">3</div>
    <div class="src-tile__props">
      <svg viewBox="0 0 20 20" fill="currentColor"><!-- cube icon --></svg>
    </div>
  </div>
  <div class="src-tile__title">Oak wood</div>
  <button type="button" class="src-tile__delete src-icon-button src-icon-button--round src-icon-button--size-sm">
    <svg viewBox="0 0 20 20" fill="currentColor"><!-- close icon --></svg>
  </button>
</div>
```

**Modifier modifiers:**
- `src-tile--active` — Active/selected state with accent border and focus shadow.
- `src-tile--static` — Non-interactive tile — no hover/active feedback, default cursor.
- `src-tile--disabled` — Dimmed tile with reduced opacity and no pointer events.
- `src-tile--clamped` — Enables line-clamping on the title. Set --srcTileTitleLineClamp to control the number of visible lines.

**Sub-elements:**
- `src-tile__image` — Image area with border, border-radius, aspect-ratio, and hover/active states. Place an <img> or colored <span> inside.
- `src-tile__title` — Title text below the image area. Hidden when empty.
- `src-tile__delete` — Absolutely positioned delete button slot at top-right corner of the tile.
- `src-tile__props` — Icon strip at bottom-left of the image area. Child elements are sized via --srcTilePropsItemSize.
- `src-tile__counter` — Counter badge overlay on the image. Requires a placement modifier.
- `src-tile__counter--center` — Centers the counter in the image area.
- `src-tile__counter--top-right` — Places the counter at top-right of the image area.
- `src-tile__counter--top-left` — Places the counter at top-left of the image area.
- `src-tile__counter--bottom-right` — Places the counter at bottom-right of the image area.
- `src-tile__counter--bottom-left` — Places the counter at bottom-left of the image area.
- `src-tile__loading` — Full-overlay loading state covering the image area with a faded background.

**Custom properties:** `--srcTileWidth`, `--srcTileAspectRatio`, `--srcTileBorderColor`, `--srcTileBorderRadius`, `--srcTileBoxShadow`, `--srcTileTransition`, `--srcTileImagePadding`, `--srcTilePointerEvents`, `--srcTileHoverBorderColor`, `--srcTileHoverBoxShadow`, `--srcTileActiveBorderColor`, `--srcTileActiveBoxShadow`, `--srcTileDisabledOpacity`, `--srcTileTitleColor`, `--srcTileTitleFontSize`, `--srcTileTitleLineHeight`, `--srcTileTitleLineClamp`, `--srcTilePropsItemSize`, `--srcTilePropsColor`, `--srcTilePropsBg`, `--srcTileCounterBg`, `--srcTileCounterColor`

### Toggle Element

Toggle switch wrapping a native checkbox.

Apply `src-toggle` class to any appropriate HTML tag.

**Usage:**
```html
<label class="src-toggle">
  <input type="checkbox" checked />
  <span class="src-toggle__label">Enable notifications</span>
</label>

<label class="src-toggle">
  <input type="checkbox" disabled />
  <span class="src-toggle__label">Dark mode (unavailable)</span>
</label>
```

**Sub-elements:**
- `src-toggle__label` — Text label beside the toggle.

[Demo](https://preview.3dsource.com/front-libraries/develop/#/components/FormElements)

### Toolbar Element

Inline container for grouping buttons and icon-buttons with shadow and rounded corners.

Apply `src-toolbar` class to any appropriate HTML tag.

**Usage:**
```html
<div class="src-toolbar">
  <button type="button" class="src-icon-button">...</button>
  <hr class="src-divider src-divider--vertical" />
  <button type="button" class="src-button src-button--plain">Action</button>
</div>
```

**Modifier modifiers:**
- `src-toolbar--compact` — Removes inner paddings.
- `src-toolbar--vertical` — Stacks children vertically.
- `src-toolbar--disabled` — Disables pointer events and applies a muted background. Buttons inside should be disabled separately.

**Size modifiers:**
- `src-toolbar--size-sm` — Small toolbar.
- `src-toolbar--size-md` (default) — Medium toolbar (default).
- `src-toolbar--size-lg` — Large toolbar.
- `src-toolbar--size-xl` — Extra-large toolbar.

**Custom properties:** `--srcToolbarBgColor`, `--srcToolbarBorderColor`, `--srcToolbarBorder`, `--srcToolbarPaddings`, `--srcToolbarGap`, `--srcToolbarBorderRadius`, `--srcToolbarShadow`
## Common patterns

These patterns show how Source UI components and elements compose together in real-world UI.

### Form field

Every form field follows: label + control + hint (optional).

```html
<div class="src-form__item">
  <label class="src-label" for="email">Email</label>
  <input id="email" type="email" class="src-input" placeholder="name@example.com" />
  <p class="src-hint">We will never share your email.</p>
</div>
```

Error state:
```html
<div class="src-form__item">
  <label class="src-label" for="username">Username</label>
  <input id="username" type="text" class="src-input src-input--context-error" placeholder="Enter username" />
  <p class="src-hint src-hint--context-error">Minimum 3 characters required.</p>
</div>
```

Works the same with `src-select` and `src-textarea` instead of `src-input`.

### Form layout

`.src-form` is the **required wrapper** for any form. It provides a flex-column layout with consistent gaps. All form content goes inside it.

**Structure:** `.src-form` > `.src-form__row` > `.src-form__item` (label + control + hint).

Available children of `.src-form`:
- `.src-form__item` — flex-column container for one field (label + control + hint). Can be placed directly in `.src-form` or inside a `.src-form__row`
- `.src-form__row` — grid row, single column by default. Wraps one or more `.src-form__item`
- `.src-form__row--double` — modifier for two-column grid row
- `.src-form__row--triple` — modifier for three-column grid row
- `.src-form__row-group` — groups consecutive rows under a common title. Contains `.src-form__row-group-label` + one or more `.src-form__row`
- `.src-form__row-group-label` — title/label for a row group. No predefined styles — apply `.src-label` or your own class for styling
- `.src-form__button-row` — right-aligned row for action buttons at the bottom of the form

```html
<form class="src-form">
  <div class="src-form__row src-form__row--double">
    <div class="src-form__item">
      <label class="src-label" for="first">First name</label>
      <input id="first" type="text" class="src-input" placeholder="John" />
    </div>
    <div class="src-form__item">
      <label class="src-label" for="last">Last name</label>
      <input id="last" type="text" class="src-input" placeholder="Doe" />
    </div>
  </div>
  <div class="src-form__row">
    <div class="src-form__item">
      <label class="src-label" for="bio">Bio</label>
      <textarea id="bio" class="src-textarea" rows="3" placeholder="Tell us about yourself..."></textarea>
    </div>
  </div>
  <div class="src-form__button-row">
    <src-button appearance="plain" weight="ghost" (onClick)="cancel()">Cancel</src-button>
    <src-button weight="primary" (onClick)="save()">Save</src-button>
  </div>
</form>
```

Custom properties: `--srcFormRowGap` (gap between rows, default 16px), `--srcFormItemsGap` (gap between items in a row, default 12px), `--srcFormOffset` (padding for focus outlines).

### Checkbox, radio, and toggle in forms

```html
<div class="src-form__item">
  <label class="src-checkbox">
    <input type="checkbox" />
    <span class="src-checkbox__label">Subscribe to newsletter</span>
  </label>
</div>

<div class="src-form__item">
  <label class="src-label">Plan</label>
  <div class="src-radio-group">
    <label class="src-radio">
      <input type="radio" name="plan" value="free" checked />
      <span class="src-radio__label">Free</span>
    </label>
    <label class="src-radio">
      <input type="radio" name="plan" value="pro" />
      <span class="src-radio__label">Professional</span>
    </label>
  </div>
</div>

<div class="src-form__item">
  <label class="src-toggle">
    <input type="checkbox" />
    <span class="src-toggle__label">Enable notifications</span>
  </label>
</div>
```

### Action bar (button groups)

Confirm/cancel pattern — primary action last, cancel as ghost:
```html
<div class="src-form__button-row">
  <src-button appearance="plain" weight="ghost" (onClick)="cancel()">Cancel</src-button>
  <src-button weight="primary" (onClick)="confirm()">Confirm</src-button>
</div>
```

Destructive action:
```html
<div class="src-form__button-row">
  <src-button appearance="plain" weight="ghost" (onClick)="cancel()">Cancel</src-button>
  <src-button weight="primary" context="error" (onClick)="delete()">Delete</src-button>
</div>
```

### Banner with close action

```html
<src-banner context="warning">
  <src-icon size="var(--src-icon-size)" name="warning" srcIconPrefix></src-icon>
  <div srcBannerTitle>Attention</div>
  Your session will expire in 5 minutes.
  <src-icon-button appearance="inline" srcIconPostfix (onClick)="closeBanner()">
    <src-icon name="close-small"></src-icon>
  </src-icon-button>
</src-banner>
```

### List inside popover

```html
<src-popover-trigger [srcPopoverTpl]="optionsTpl" headerTitle="Options">
  <src-button [isPressed]="trigger.popoverShown()">Choose</src-button>
</src-popover-trigger>

<ng-template #optionsTpl>
  <ul class="src-list">
    <li class="src-list__item src-list__item--selected">Option A</li>
    <li class="src-list__item">Option B</li>
    <li class="src-list__item">Option C</li>
  </ul>
</ng-template>
```

### Tile grid

Use CSS grid to lay out tiles. The tile component handles its own sizing.
```html
<div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: var(--src-layout-gap-const-md, 12px);">
  <src-tile [counter]="3">
    <img src="oak.jpg" alt="Oak wood" srcTileImage />
    <div srcTileTitle>Oak wood</div>
  </src-tile>
  <src-tile>
    <img src="maple.jpg" alt="Maple" srcTileImage />
    <div srcTileTitle>Maple</div>
  </src-tile>
  <src-tile>
    <img src="walnut.jpg" alt="Walnut" srcTileImage />
    <div srcTileTitle>Walnut</div>
  </src-tile>
</div>
```

## Typography

Source UI provides CSS classes for consistent text styling. Apply them to any HTML element. Native heading tags (`h1`–`h6`) are also styled automatically.

Primary typeface: Inter (imported in the stylesheet).

### When to use what

- **Headings** (`src-headings-*`): Page-level titles only. These are large and should NOT be used for card titles, accordion headers, or panel labels.
- **Titles** (`src-title-*`): Card headers, accordion titles, sidebar sections, panel headers, group labels — any UI chrome that needs emphasis but is not a page-level heading.
- **Body** (`src-body-*`): Default reading text with compact line-height. Use for UI text, descriptions, paragraphs.
- **Body Relaxed** (`src-body-relaxed-*`): Same sizes as Body but with increased line-height. Use for long-form content, help text, articles.
- **Labels** (`src-label-*`): Medium-weight text for links, navigation items, UI controls. Not the same as the `src-label` form element class.

### Scale reference

Headings (semibold, header font):
- `src-headings-4xl` (= `h1`) — page title
- `src-headings-3xl` — large section header
- `src-headings-2xl` (= `h2`) — section header
- `src-headings-xl` (= `h3`) — subsection header
- `src-headings-lg` (= `h4`) — smallest heading, use sparingly

Titles (semibold):
- `src-title-md` (= `h5`) — card/panel header, dialog title
- `src-title-base` (= `h6`) — accordion title, sidebar section header
- `src-title-sm` — compact title, toolbar label
- `src-title-xs` — uppercase technical label (auto text-transform)

Body (regular weight):
- `src-body-md` — primary UI text (16px)
- `src-body-base` — default body text (14px)
- `src-body-sm` — secondary/small text (12px)

Body Relaxed (regular weight, taller line-height):
- `src-body-relaxed-md`, `src-body-relaxed-base`, `src-body-relaxed-sm`

Labels (medium weight):
- `src-label-xl`, `src-label-lg`, `src-label-md`, `src-label-sm`, `src-label-tech` (uppercase)

STRICT RULE: Do NOT use deprecated classes `src-heading-h1`..`src-heading-h6` or `src-heading-massive`.

### Text colors

Not all text should be the same color. Use semantic text tokens:

Body text (content areas):
- `--src-text-body-main` — primary text (headings, important content)
- `--src-text-body-secondary` — supporting text (descriptions, subtitles)
- `--src-text-body-grey` — muted text (placeholders, timestamps)
- `--src-text-body-lable` — form labels, captions
- `--src-text-body-disabled` — disabled state

Semantic body colors:
- `--src-text-body-accent` — links, interactive text
- `--src-text-body-success` — success messages
- `--src-text-body-destruct` — error messages, destructive text

UI text (buttons, controls, navigation on colored backgrounds):
- `--src-text-ui-secondary-main` — primary UI text on neutral background
- `--src-text-ui-secondary-secondary` — secondary UI text on neutral background
- `--src-text-ui-primary-main` — text on primary/accent-colored backgrounds
- `--src-text-ui-accent-main` / `--src-text-ui-success-main` / `--src-text-ui-distruct-main` / `--src-text-ui-warning-main` — colored interactive text

Inverted (for dark backgrounds in light theme, or vice versa):
- `--src-text-body-main-invert`, `--src-text-body-secondary-invert`
- `--src-text-ui-primary-main-invert`, `--src-text-ui-secondary-main-invert`

STRICT RULE: Do NOT use raw hex colors for text. Always use `--src-text-*` tokens. They adapt automatically to light/dark theme.

### Icon colors

Icons have their own color tokens. Do not reuse `--src-text-*` for icons — icon tokens have different values optimized for icon contrast.

- `--src-icon-default` — standard icon color (slightly lighter than body text)
- `--src-icon-label` — muted icon next to labels
- `--src-icon-hover` — icon on hover
- `--src-icon-grey` — decorative/disabled-looking icons
- `--src-icon-disabled` — disabled state

Semantic:
- `--src-icon-info` / `--src-icon-info-hover`
- `--src-icon-success` / `--src-icon-success-hover`
- `--src-icon-error` / `--src-icon-error-hover`
- `--src-icon-warning` / `--src-icon-warning-hover`
- `--src-icon-attention` / `--src-icon-attention-hover`

Inverted (for dark/colored backgrounds):
- `--src-icon-main-invert`, `--src-icon-secondary-invert`

Fallback: if a specific icon token doesn't exist for your case, `color: inherit` from the parent text color is acceptable. But prefer `--src-icon-*` tokens when available.

## Stylesheet import paths

STRICT RULE: Use ONLY the paths listed below. Do NOT fabricate paths like `@3dsource/source-ui-native/src/lib/styles/...` or `dist/...`.

**SCSS import (Angular projects with a builder) — add to your `styles.scss`:**
```
@use '../node_modules/@3dsource/source-ui-native/styles/source.ui.native.scss' as source-ui-native;
```

**Compiled CSS import (non-Angular / CSS-only / no builder) — add to `<head>` or import in your bundler:**
```
node_modules/@3dsource/source-ui-native/styles/source-ui-native.min.css
```

IMPORTANT: SCSS entry files use dots in the name (`source.ui.native.scss`), while compiled CSS uses dashes (`source-ui-native.min.css`). Do not confuse them.

## Icons

The library is icon-agnostic — no icon font is bundled. Icons are projected into components via `<ng-content>` (Angular) or placed directly inside elements (CSS-only).

STRICT RULE: Do NOT use the Material Icons font (`<link href="https://fonts.google.com/icon?family=Material+Icons">` or the `material-icons` CSS class). The font-based icon approach conflicts with Source UI styles. Use **SVG icons** instead.

Recommended icon source: [Material Symbols (Rounded)](https://fonts.google.com/icons?icon.style=Rounded) with settings: Style Rounded, Weight 400, Fill On, Optical size 20dp.

### SVG icon setup (Angular projects)

1. Create an `assets/icons/` folder in your project.
2. Download SVG icons from your design or from [Material Symbols](https://fonts.google.com/icons?icon.style=Rounded).
3. In each SVG file: set `fill="currentColor"` (for CSS color control), remove `width`/`height` attributes, keep `viewBox`.
4. Create an `SvgIconComponent` in your project (this component is NOT part of the library — copy it into your codebase):

```typescript
import { HttpClient } from '@angular/common/http';
import { Component, effect, inject, input, signal, untracked } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { first } from 'rxjs';

@Component({
  selector: 'src-icon',
  imports: [],
  template: `@if (svg()) {
    <div [innerHTML]="svg()" class="src-icon" [style.--srcIconSize]="size()"></div>
  }`,
  styles: [`
    .src-icon { width: var(--srcIconSize); height: var(--srcIconSize); color: inherit; }
    .src-icon svg { width: 100%; height: 100%; fill: currentColor; }
  `],
})
export class SvgIconComponent {
  name = input<string>('');
  size = input<string>('20px');
  PATH_TO_ICON_FOLDER = 'assets/icons';
  svg = signal<SafeHtml | null>(null);
  http = inject(HttpClient);
  sanitizer = inject(DomSanitizer);

  _ = effect(() => {
    const path = this.PATH_TO_ICON_FOLDER + '/' + this.name() + '.svg';
    untracked(() => {
      this.http.get(path, { responseType: 'text' }).pipe(first()).subscribe({
        next: (rawSvg) => this.svg.set(this.sanitizer.bypassSecurityTrustHtml(rawSvg)),
        error: () => console.warn('Icon "' + this.name() + '" not found at ' + path),
      });
    });
  });
}
```

5. Usage: `<src-icon name="close"></src-icon>`, `<src-icon name="chevron_left" size="32px"></src-icon>`
6. Default size: `20px`. Color inherits from parent element.

### SVG icon setup (non-Angular / CSS-only projects)

Inline the SVG directly in your HTML:
```html
<button class="src-icon-button">
  <svg viewBox="0 0 24 24" fill="currentColor"><path d="..."/></svg>
</button>
```

### Icon design tokens

- `--src-icon-size` — default icon size (16px)
- `--src-icon-default`, `--src-icon-info`, `--src-icon-success`, `--src-icon-error`, `--src-icon-warning` — contextual icon colors

- [Icons documentation](https://preview.3dsource.com/front-libraries/develop/#/icons)

## Component registry

- [Component Registry](../api/_registry.json): Index of all source-ui-native components with selectors, kinds, and JSON file references

## Design Tokens (inline)

> Auto-generated from 1029 total tokens. Below is a curated subset of semantic tokens most useful for development. Full token data: design-tokens.json.

### primitives (scope: global)
Source: `variables/primitives/primitives.scss`

| Token | Value |
|-------|-------|
| --src-space-0 | 0px |
| --src-space-px | 1px |
| --src-space-0-5 | 2px |
| --src-space-1 | 4px |
| --src-space-1-5 | 6px |
| --src-space-2 | 8px |
| --src-space-2-5 | 10px |
| --src-space-3 | 12px |
| --src-space-3-5 | 14px |
| --src-space-4 | 16px |
| --src-space-5 | 20px |
| --src-space-6 | 24px |
| --src-space-7 | 28px |
| --src-space-8 | 32px |
| --src-space-9 | 36px |
| --src-space-10 | 40px |
| --src-space-11 | 44px |
| --src-space-12 | 48px |
| --src-space-14 | 56px |
| --src-space-16 | 64px |
| --src-space-20 | 80px |
| --src-space-24 | 96px |
| --src-space-28 | 112px |
| --src-space-32 | 128px |
| --src-space-36 | 144px |
| --src-space-40 | 160px |
| --src-space-44 | 176px |
| --src-space-48 | 192px |
| --src-space-52 | 208px |
| --src-space-56 | 224px |
| --src-space-60 | 240px |
| --src-space-64 | 256px |
| --src-space-72 | 288px |
| --src-space-80 | 320px |
| --src-space-96 | 384px |
| --src-color-primary-50 | #f1f6ffff |
| --src-color-primary-100 | #d6e9ffff |
| --src-color-primary-200 | #add4ffff |
| --src-color-primary-300 | #7dbbffff |
| --src-color-primary-400 | #4ea4ffff |
| --src-color-primary-500 | #017bffff |
| --src-color-primary-600 | #016fe6ff |
| --src-color-primary-700 | #0162ccff |
| --src-color-primary-800 | #014ca3ff |
| --src-color-primary-900 | #003a7aff |
| --src-color-primary-950 | #00244dff |
| --src-color-alpha-accent-10 | #017bff14 |
| --src-color-alpha-accent-50 | #017bff1f |
| --src-color-alpha-accent-100 | #017bff29 |
| --src-color-alpha-accent-200 | #017bff3d |
| --src-color-alpha-accent-300 | #017bff52 |
| --src-color-alpha-accent-400 | #017bff5c |

### color-light (scope: global)
Source: `variables/color/light.scss`

| Token | Value |
|-------|-------|
| --src-surface-background | var(--src-color-grey-50) |
| --src-surface-background-inverse | var(--src-color-grey-800) |
| --src-ui-accent-default | var(--src-color-primary-500) |
| --src-ui-accent-default-hover | var(--src-color-primary-600) |
| --src-ui-accent-disabled | var(--src-color-alpha-test-200) |
| --src-ui-accent-success | var(--src-color-green-500) |
| --src-ui-accent-success-hover | var(--src-color-green-600) |
| --src-ui-accent-error | var(--src-color-red-500) |
| --src-ui-accent-error-hover | var(--src-color-red-600) |
| --src-ui-accent-active | var(--src-color-grey-700) |
| --src-ui-accent-active-hover | var(--src-color-grey-900) |
| --src-ui-secondary-default | var(--src-color-alpha-default-10) |
| --src-ui-secondary-default-hover | var(--src-color-alpha-default-50) |
| --src-ui-secondary-disabled | var(--src-color-alpha-white-10) |
| --src-ui-secondary-active | var(--src-color-alpha-accent-50) |
| --src-ui-secondary-info | var(--src-color-alpha-accent-10) |
| --src-ui-secondary-info-hover | var(--src-color-alpha-accent-50) |
| --src-ui-secondary-success | var(--src-color-alpha-success-10) |
| --src-ui-secondary-success-hover | var(--src-color-alpha-success-50) |
| --src-ui-secondary-error | var(--src-color-alpha-destruct-10) |
| --src-ui-secondary-error-hover | var(--src-color-alpha-destruct-100) |
| --src-ui-secondary-progress | var(--src-color-alpha-warning-10) |
| --src-ui-input-default | var(--src-color-alpha-white-10) |
| --src-ui-input-secondary | var(--src-color-alpha-default-10) |
| --src-ui-input-hover | var(--src-color-alpha-accent-10) |
| --src-ui-input-disabled | var(--src-color-alpha-default-50) |
| --src-ui-input-success | var(--src-color-alpha-white-10) |
| --src-ui-input-success-hover | var(--src-color-alpha-success-10) |
| --src-ui-input-error | var(--src-color-alpha-white-10) |
| --src-ui-input-error-hover | var(--src-color-alpha-destruct-10) |
| --src-surface-curtain | var(--src-color-alpha-default-600) |
| --src-surface-fade | var(--src-color-alpha-white-600) |
| --src-surface-bg | var(--src-color-alpha-default-200) |
| --src-ui-light | var(--src-light) |
| --src-border-control-default | var(--src-color-neutral-300) |
| --src-border-control-hover | var(--src-color-neutral-500) |
| --src-border-button-basic | var(--src-color-grey-200) |
| --src-border-button-basic-hover | var(--src-color-grey-400) |
| --src-border-button-info | var(--src-color-primary-300) |
| --src-border-button-info-hover | var(--src-color-primary-500) |
| --src-border-button-success | var(--src-color-green-400) |
| --src-border-button-success-hover | var(--src-color-green-500) |
| --src-border-button-error | var(--src-color-red-300) |
| --src-border-button-error-hover | var(--src-color-red-500) |
| --src-border-button-disabled | var(--src-color-grey-200) |
| --src-border-input-basic | var(--src-color-grey-300) |
| --src-border-input-hover | var(--src-color-grey-400) |
| --src-border-input-filled | var(--src-color-grey-300) |
| --src-border-input-active | var(--src-color-primary-500) |
| --src-border-input-success | var(--src-color-green-500) |
| --src-border-input-success-hover | var(--src-color-green-600) |
| --src-border-input-error | var(--src-color-red-500) |
| --src-border-input-error-hover | var(--src-color-red-500) |
| --src-border-container-basic | var(--src-color-grey-300) |
| --src-border-container-hover | var(--src-color-grey-400) |
| --src-border-container-light | var(--src-color-alpha-default-50) |
| --src-border-container-active | var(--src-color-primary-400) |
| --src-border-container-success | var(--src-color-green-200) |
| --src-border-container-error | var(--src-color-red-200) |
| --src-text-body-main | var(--src-color-grey-900) |
| --src-text-body-secondary | var(--src-color-grey-600) |
| --src-text-body-grey | var(--src-color-grey-400) |
| --src-text-body-lable | var(--src-color-grey-500) |
| --src-text-body-disabled | var(--src-color-grey-400) |
| --src-text-body-main-invert | var(--src-color-grey-50) |
| --src-text-body-secondary-invert | var(--src-color-grey-300) |
| --src-icon-default | var(--src-color-grey-700) |
| --src-icon-label | var(--src-color-grey-500) |
| --src-icon-hover | var(--src-color-grey-900) |
| --src-icon-grey | var(--src-color-grey-400) |
| --src-icon-disabled | var(--src-color-grey-400) |
| --src-icon-main-invert | var(--src-light) |
| --src-icon-secondary-invert | var(--src-color-grey-200) |
| --src-icon-info | var(--src-color-primary-500) |
| --src-icon-info-hover | var(--src-color-primary-600) |
| --src-icon-success | var(--src-color-green-600) |
| --src-icon-success-hover | var(--src-color-green-700) |
| --src-icon-error | var(--src-color-red-500) |
| --src-icon-error-hover | var(--src-color-red-600) |
| --src-icon-warning | var(--src-color-tertiary-600) |
| --src-icon-warning-hover | var(--src-color-tertiary-700) |
| --src-icon-attention | var(--src-color-yellow-800) |
| --src-icon-attention-hover | var(--src-color-yellow-900) |
| --src-graphics-positive | var(--src-color-green-500) |
| --src-graphics-negative | var(--src-color-red-500) |
| --src-graphics-accent | var(--src-color-primary-500) |
| --src-graphics-dark-grey | var(--src-color-grey-500) |
| --src-graphics-orange | #f5a80fff |
| --src-graphics-yellow | #f0e442ff |
| --src-graphics-turquoise | #00ced1ff |
| --src-graphics-brown | #8b4513ff |
| --src-graphics-black | var(--src-color-grey-700) |
| --src-text-body-accent | var(--src-color-primary-600) |
| --src-text-body-success | var(--src-color-green-600) |
| --src-text-body-destruct | var(--src-color-red-600) |
| --src-text-ui-primary-main | var(--src-light) |
| --src-text-ui-primary-secondary | var(--src-color-grey-200) |
| --src-text-ui-primary-disabled | var(--src-color-grey-400) |
| --src-text-ui-primary-main-invert | var(--src-color-grey-50) |
| --src-text-ui-primary-secondary-invert | var(--src-color-grey-200) |
| --src-text-ui-secondary-main | var(--src-color-grey-900) |
| --src-text-ui-secondary-secondary | var(--src-color-grey-600) |
| --src-text-ui-secondary-grey | var(--src-color-grey-400) |
| --src-text-ui-secondary-disabled | var(--src-color-grey-400) |
| --src-text-ui-secondary-main-invert | var(--src-color-grey-50) |
| --src-text-ui-secondary-secondary-invert | var(--src-color-grey-300) |
| --src-shadow-hard | var(--src-color-alpha-test-200) |
| --src-shadow-light | var(--src-color-alpha-default-50) |
| --src-shadow-accent-light | var(--src-color-alpha-accent-100) |
| --src-shadow-accent-hard | var(--src-color-alpha-accent-200) |
| --src-shadow-success | var(--src-color-alpha-success-50) |
| --src-shadow-success-hover | var(--src-color-alpha-success-200) |
| --src-shadow-error | var(--src-color-alpha-destruct-100) |
| --src-shadow-error-hover | var(--src-color-alpha-destruct-200) |
| --src-text-ui-accent-main | var(--src-color-primary-600) |
| --src-text-ui-accent-hover | var(--src-color-primary-700) |
| --src-text-ui-success-main | var(--src-color-green-600) |
| --src-text-ui-success-hover | var(--src-color-green-700) |
| --src-text-ui-distruct-main | var(--src-color-red-500) |
| --src-text-ui-distruct-hover | var(--src-color-red-600) |
| --src-surface-container-main | var(--src-light) |
| --src-surface-container-on-top | var(--src-color-alpha-default-10) |
| --src-surface-container-secondary | var(--src-color-grey-50) |
| --src-surface-container-info | var(--src-color-primary-50) |
| --src-surface-container-success | var(--src-color-green-50) |
| --src-surface-container-error | var(--src-color-red-50) |
| --src-surface-toast-basic | var(--src-color-alpha-default-50) |
| --src-surface-toast-info | var(--src-color-primary-600) |
| --src-surface-toast-success | var(--src-color-green-600) |
| --src-surface-toast-error | var(--src-color-red-500) |
| --src-border-infoPrompt-basic | var(--src-color-grey-300) |
| --src-border-infoPrompt-light | var(--src-color-alpha-default-50) |
| --src-border-infoPrompt-info | var(--src-color-primary-200) |
| --src-border-infoPrompt-success | var(--src-color-green-200) |
| --src-border-infoPrompt-error | var(--src-color-red-200) |
| --src-gradient-light-start | var(--src-color-alpha-test-100) |
| --src-gradient-light-end | var(--src-color-alpha-default-10) |
| --src-gradient-accent-light | var(--src-color-alpha-accent-10) |
| --src-gradient-accent-hard | var(--src-color-alpha-accent-50) |
| --src-gradient-success | var(--color-alpha-success-50) |
| --src-gradient-success-hover | var(--color-alpha-success-200) |
| --src-gradient-error | var(--color-alpha-destruct-100) |
| --src-gradient-error-hover | var(--color-alpha-destruct-200) |
| --src-tech-sticker | var(--src-color-tertiary-100) |
| --wireframe-main | var(--src-color-neutral-600) |
| --wireframe-secondary | var(--src-color-neutral-500) |
| --wireframe-light | var(--src-color-neutral-300) |
| --wireframe-surface-primary | var(--src-light) |
| --wireframe-surface-secondary | var(--src-color-alpha-default-50) |
| --wireframe-border | var(--src-color-alpha-default-200) |
| --wireframe-invert | var(--src-light) |
| --src-tech-description | var(--src-color-tertiary-900) |
| --src-light | #ffffffff |
| --src-dark | #000000ff |
| --src-ui-status-basic-neutral | var(--src-color-grey-500) |
| --src-ui-status-basic-neutral-hover | var(--src-color-grey-600) |
| --src-ui-status-basic-critical | var(--src-color-red-500) |
| --src-ui-status-basic-critical-hover | var(--src-color-red-600) |
| --src-ui-status-basic-info | var(--src-color-primary-500) |
| --src-ui-status-basic-info-hover | var(--src-color-primary-600) |
| --src-ui-status-basic-success | var(--src-color-green-500) |
| --src-ui-status-basic-success-hover | var(--src-color-green-500) |
| --src-ui-status-basic-warning | var(--src-color-tertiary-500) |
| --src-ui-status-basic-warning-hover | var(--src-color-tertiary-600) |
| --src-ui-status-basic-attention | var(--src-color-yellow-500) |
| --src-ui-status-basic-attention-hover | var(--src-color-yellow-600) |
| --src-ui-status-light-neutral | var(--src-color-alpha-default-100) |
| --src-ui-status-light-neutral-hover | var(--src-color-alpha-default-200) |
| --src-ui-status-light-critical | var(--src-color-alpha-destruct-100) |
| --src-ui-status-light-critical-hover | var(--src-color-alpha-destruct-200) |
| --src-ui-status-light-info | var(--src-color-alpha-accent-200) |
| --src-ui-status-light-info-hover | var(--src-color-alpha-accent-300) |
| --src-ui-status-light-success | var(--src-color-alpha-success-100) |
| --src-ui-status-light-success-hover | var(--src-color-alpha-success-200) |
| --src-ui-status-light-warning | var(--src-color-alpha-warning-200) |
| --src-ui-status-light-warning-hover | var(--src-color-alpha-warning-300) |
| --src-ui-status-light-attention | var(--src-color-alpha-attention-200) |
| --src-ui-status-light-attention-hover | var(--src-color-alpha-attention-300) |
| --src-text-ui-warning-main | var(--src-color-tertiary-600) |
| --src-text-ui-warning-hover | var(--src-color-tertiary-700) |
| --src-text-ui-attention-main | var(--src-color-yellow-800) |
| --src-text-ui-attention-hover | var(--src-color-yellow-900) |

### color-dark (scope: global)
Source: `variables/color/dark.scss`

| Token | Value |
|-------|-------|
| --src-surface-background | var(--src-color-grey-900) |
| --src-surface-background-inverse | var(--src-color-grey-50) |
| --src-ui-accent-default | var(--src-color-primary-400) |
| --src-ui-accent-default-hover | var(--src-color-primary-500) |
| --src-ui-accent-disabled | var(--src-color-alpha-white-100) |
| --src-ui-accent-success | var(--src-color-green-600) |
| --src-ui-accent-success-hover | var(--src-color-green-500) |
| --src-ui-accent-error | var(--src-color-red-600) |
| --src-ui-accent-error-hover | var(--src-color-red-500) |
| --src-ui-accent-active | var(--src-color-grey-200) |
| --src-ui-accent-active-hover | var(--src-color-grey-50) |
| --src-ui-secondary-default | var(--src-color-alpha-white-50) |
| --src-ui-secondary-default-hover | var(--src-color-alpha-default-100) |
| --src-ui-secondary-disabled | var(--src-color-alpha-default-100) |
| --src-ui-secondary-active | var(--src-color-alpha-accent-100) |
| --src-ui-secondary-info | var(--src-color-alpha-accent-200) |
| --src-ui-secondary-info-hover | var(--src-color-alpha-accent-100) |
| --src-ui-secondary-success | var(--src-color-alpha-success-200) |
| --src-ui-secondary-success-hover | var(--src-color-alpha-success-50) |
| --src-ui-secondary-error | var(--src-color-alpha-destruct-200) |
| --src-ui-secondary-error-hover | var(--src-color-alpha-destruct-100) |
| --src-ui-secondary-progress | var(--src-color-alpha-warning-10) |
| --src-ui-input-default | var(--src-color-alpha-white-10) |
| --src-ui-input-secondary | var(--src-color-alpha-default-200) |
| --src-ui-input-hover | var(--src-color-alpha-default-200) |
| --src-ui-input-disabled | var(--src-color-alpha-default-200) |
| --src-ui-input-success | var(--src-color-alpha-white-10) |
| --src-ui-input-success-hover | var(--src-color-alpha-success-50) |
| --src-ui-input-error | var(--src-color-alpha-white-10) |
| --src-ui-input-error-hover | var(--src-color-alpha-destruct-50) |
| --src-surface-curtain | var(--src-color-alpha-default-600) |
| --src-surface-fade | var(--src-color-alpha-default-200) |
| --src-surface-bg | var(--src-color-alpha-white-50) |
| --src-ui-light | var(--src-dark) |
| --src-border-control-default | var(--src-color-neutral-300) |
| --src-border-control-hover | var(--src-color-neutral-100) |
| --src-border-button-basic | var(--src-color-grey-600) |
| --src-border-button-basic-hover | var(--src-color-grey-500) |
| --src-border-button-info | var(--src-color-primary-500) |
| --src-border-button-info-hover | var(--src-color-primary-400) |
| --src-border-button-success | var(--src-color-green-700) |
| --src-border-button-success-hover | var(--src-color-green-600) |
| --src-border-button-error | var(--src-color-red-500) |
| --src-border-button-error-hover | var(--src-color-red-600) |
| --src-border-button-disabled | var(--src-color-grey-800) |
| --src-border-input-basic | var(--src-color-grey-700) |
| --src-border-input-hover | var(--src-color-grey-500) |
| --src-border-input-filled | var(--src-color-grey-700) |
| --src-border-input-active | var(--src-color-primary-500) |
| --src-border-input-success | var(--src-color-green-600) |
| --src-border-input-success-hover | var(--src-color-green-400) |
| --src-border-input-error | var(--src-color-red-700) |
| --src-border-input-error-hover | var(--src-color-red-700) |
| --src-border-container-basic | var(--src-color-grey-800) |
| --src-border-container-hover | var(--src-color-grey-600) |
| --src-border-container-light | var(--src-color-alpha-white-50) |
| --src-border-container-active | var(--src-color-primary-500) |
| --src-border-container-success | var(--src-color-green-800) |
| --src-border-container-error | var(--src-color-red-800) |
| --src-text-body-main | var(--src-color-grey-50) |
| --src-text-body-secondary | var(--src-color-grey-300) |
| --src-text-body-grey | var(--src-color-grey-400) |
| --src-text-body-lable | var(--src-color-grey-300) |
| --src-text-body-disabled | var(--src-color-grey-500) |
| --src-text-body-main-invert | var(--src-color-grey-900) |
| --src-text-body-secondary-invert | var(--src-color-grey-600) |
| --src-icon-default | var(--src-color-grey-200) |
| --src-icon-label | var(--src-color-grey-400) |
| --src-icon-hover | var(--src-color-grey-50) |
| --src-icon-grey | var(--src-color-grey-400) |
| --src-icon-disabled | var(--src-color-grey-600) |
| --src-icon-main-invert | var(--src-light) |
| --src-icon-secondary-invert | var(--src-color-grey-200) |
| --src-icon-info | var(--src-color-primary-500) |
| --src-icon-info-hover | var(--src-color-primary-400) |
| --src-icon-success | var(--src-color-green-500) |
| --src-icon-success-hover | var(--src-color-green-400) |
| --src-icon-error | var(--src-color-red-400) |
| --src-icon-error-hover | var(--src-color-red-300) |
| --src-icon-warning | var(--src-color-tertiary-400) |
| --src-icon-warning-hover | var(--src-color-tertiary-300) |
| --src-icon-attention | var(--src-color-yellow-400) |
| --src-icon-attention-hover | var(--src-color-yellow-600) |
| --src-graphics-positive | var(--color-green-400) |
| --src-graphics-negative | var(--src-color-red-400) |
| --src-graphics-accent | var(--src-color-primary-500) |
| --src-graphics-dark-grey | var(--src-color-grey-400) |
| --src-graphics-orange | #ffb92dff |
| --src-graphics-yellow | #f0e442ff |
| --src-graphics-turquoise | #00ced1ff |
| --src-graphics-brown | #8b4513ff |
| --src-graphics-black | var(--src-color-grey-200) |
| --src-text-body-accent | var(--src-color-primary-400) |
| --src-text-body-success | var(--src-color-green-400) |
| --src-text-body-destruct | var(--src-color-red-400) |
| --src-text-ui-primary-main | var(--src-light) |
| --src-text-ui-primary-secondary | var(--src-color-grey-200) |
| --src-text-ui-primary-disabled | var(--src-color-grey-400) |
| --src-text-ui-primary-main-invert | var(--src-color-grey-900) |
| --src-text-ui-primary-secondary-invert | var(--src-color-grey-700) |
| --src-text-ui-secondary-main | var(--src-color-grey-50) |
| --src-text-ui-secondary-secondary | var(--src-color-grey-200) |
| --src-text-ui-secondary-grey | var(--src-color-grey-400) |
| --src-text-ui-secondary-disabled | var(--src-color-grey-500) |
| --src-text-ui-secondary-main-invert | var(--src-color-grey-900) |
| --src-text-ui-secondary-secondary-invert | var(--src-color-grey-600) |
| --src-shadow-hard | var(--src-color-alpha-dark-100) |
| --src-shadow-light | var(--src-color-alpha-dark-50) |
| --src-shadow-accent-light | var(--src-color-alpha-accent-300) |
| --src-shadow-accent-hard | var(--src-color-alpha-accent-400) |
| --src-shadow-success | var(--src-color-alpha-success-200) |
| --src-shadow-success-hover | var(--src-color-alpha-success-50) |
| --src-shadow-error | var(--src-color-alpha-destruct-200) |
| --src-shadow-error-hover | var(--src-color-alpha-destruct-100) |
| --src-text-ui-accent-main | var(--src-color-primary-400) |
| --src-text-ui-accent-hover | var(--src-color-primary-300) |
| --src-text-ui-success-main | var(--src-color-green-400) |
| --src-text-ui-success-hover | var(--src-color-green-300) |
| --src-text-ui-distruct-main | var(--src-color-red-400) |
| --src-text-ui-distruct-hover | var(--src-color-red-300) |
| --src-surface-container-main | var(--src-color-grey-800) |
| --src-surface-container-on-top | var(--src-color-alpha-white-10) |
| --src-surface-container-secondary | var(--src-color-grey-950) |
| --src-surface-container-info | var(--src-color-blue-950) |
| --src-surface-container-success | var(--src-color-green-950) |
| --src-surface-container-error | var(--src-color-red-950) |
| --src-surface-toast-basic | var(--src-color-alpha-default-200) |
| --src-surface-toast-info | var(--src-color-primary-400) |
| --src-surface-toast-success | var(--src-color-green-400) |
| --src-surface-toast-error | var(--src-color-red-400) |
| --src-border-infoPrompt-basic | var(--src-color-grey-800) |
| --src-border-infoPrompt-light | var(--src-color-alpha-white-50) |
| --src-border-infoPrompt-info | var(--src-color-primary-800) |
| --src-border-infoPrompt-success | var(--src-color-green-800) |
| --src-border-infoPrompt-error | var(--src-color-red-800) |
| --src-gradient-light-start | var(--src-color-alpha-dark-200) |
| --src-gradient-light-end | var(--src-color-alpha-dark-100) |
| --src-gradient-accent-light | var(--src-color-alpha-accent-300) |
| --src-gradient-accent-hard | var(--src-color-alpha-accent-400) |
| --src-gradient-success | var(--src-color-alpha-success-200) |
| --src-gradient-success-hover | var(--src-color-alpha-success-50) |
| --src-gradient-error | var(--src-color-alpha-destruct-200) |
| --src-gradient-error-hover | var(--src-color-alpha-destruct-100) |
| --src-tech-sticker | var(--src-color-tertiary-800) |
| --wireframe-main | var(--src-color-neutral-300) |
| --wireframe-secondary | var(--src-color-neutral-400) |
| --wireframe-light | var(--src-color-neutral-500) |
| --wireframe-surface-primary | var(--src-dark) |
| --wireframe-surface-secondary | var(--src-color-alpha-white-50) |
| --wireframe-border | var(--src-color-alpha-white-100) |
| --wireframe-invert | var(--src-dark) |
| --src-tech-description | var(--src-color-tertiary-50) |
| --src-light | #ffffffff |
| --src-dark | #000000ff |
| --src-ui-status-basic-neutral | var(--src-color-alpha-white-100) |
| --src-ui-status-basic-neutral-hover | var(--src-color-alpha-white-600) |
| --src-ui-status-basic-critical | var(--src-color-alpha-success-100) |
| --src-ui-status-basic-critical-hover | var(--src-color-alpha-success-50) |
| --src-ui-status-basic-info | var(--src-color-alpha-accent-300) |
| --src-ui-status-basic-info-hover | var(--src-color-alpha-accent-200) |
| --src-ui-status-basic-success | var(--src-color-alpha-success-200) |
| --src-ui-status-basic-success-hover | var(--src-color-alpha-success-100) |
| --src-ui-status-basic-warning | var(--src-color-alpha-warning-300) |
| --src-ui-status-basic-warning-hover | var(--src-color-alpha-warning-200) |
| --src-ui-status-basic-attention | var(--src-color-alpha-attention-300) |
| --src-ui-status-basic-attention-hover | var(--src-color-alpha-attention-200) |
| --src-ui-status-light-neutral | var(--src-color-alpha-white-100) |
| --src-ui-status-light-neutral-hover | var(--src-color-alpha-white-600) |
| --src-ui-status-light-critical | var(--src-color-alpha-success-100) |
| --src-ui-status-light-critical-hover | var(--src-color-alpha-success-50) |
| --src-ui-status-light-info | var(--src-color-alpha-accent-300) |
| --src-ui-status-light-info-hover | var(--src-color-alpha-accent-200) |
| --src-ui-status-light-success | var(--src-color-alpha-success-200) |
| --src-ui-status-light-success-hover | var(--src-color-alpha-success-100) |
| --src-ui-status-light-warning | var(--src-color-alpha-warning-300) |
| --src-ui-status-light-warning-hover | var(--src-color-alpha-warning-200) |
| --src-ui-status-light-attention | var(--src-color-alpha-attention-300) |
| --src-ui-status-light-attention-hover | var(--src-color-alpha-attention-200) |
| --src-text-ui-warning-main | var(--src-color-tertiary-400) |
| --src-text-ui-warning-hover | var(--src-color-tertiary-500) |
| --src-text-ui-attention-main | var(--src-color-tertiary-200) |
| --src-text-ui-attention-hover | var(--src-color-tertiary-100) |

### typeface (scope: global)
Source: `variables/typeface/web.scss`

| Token | Value |
|-------|-------|
| --src-font-family-header | Inter |
| --src-font-family-body | Inter |
| --src-font-family-mono | PT Mono |
| --src-font-weight-bold | Bold |
| --src-font-weight-semiBold | SemiBold |
| --src-font-weight-medium | Medium |
| --src-font-weight-regular | Regular |
| --src-font-size-tech | 9px |
| --src-font-size-xs | 12px |
| --src-font-size-sm | 14px |
| --src-font-size-base | 16px |
| --src-font-size-md | 20px |
| --src-font-size-lg | 24px |
| --src-font-size-xl | 28px |
| --src-font-size-2xl | 32px |
| --src-font-size-3xl | 40px |
| --src-font-line-tech | 12px |
| --src-font-size-4xl | 48px |
| --src-font-line-xs | 16px |
| --src-font-line-sm | 20px |
| --src-font-line-base | 24px |
| --src-font-line-md | 28px |
| --src-font-line-lg | 32px |
| --src-font-line-xl | 36px |
| --src-font-line-2xl | 44px |
| --src-font-line-3xl | 52px |
| --src-font-line-4xl | 56px |
| --src-font-spacing-tech | 1.2000000476837158px |
| --src-font-spacing-xl | -0.20000000298023224px |
| --src-font-spacing-2xl | -0.30000001192092896px |
| --src-font-spacing-3xl | -0.5px |
| --src-font-spacing-4xl | -1px |

### ui-md (scope: global)
Source: `variables/ui/_md.scss`

| Token | Value |
|-------|-------|
| --src-media-thumbnail | 48px |
| --src-media-preview | 1024px |
| --src-padding-xs | var(--src-space-2) |
| --src-padding-sm | var(--src-space-3) |
| --src-padding-md | var(--src-space-4) |
| --src-padding-lg | var(--src-space-5) |
| --src-padding-xl | var(--src-space-7) |
| --src-height-xs | var(--src-space-4) |
| --src-icon-size | var(--src-space-5) |
| --src-icon-line-width | 1.440000057220459px |
| --src-height-sm | var(--src-space-5) |
| --src-border-border | 1px |
| --src-height-base | var(--src-space-9) |
| --src-border-rounded-none | 0px |
| --src-height-lg | 52px |
| --src-border-rounded-xs | var(--src-space-1) |
| --src-border-rounded | var(--src-space-1-5) |
| --src-border-rounded-parent | var(--src-space-2-5) |
| --src-border-rounded-lg | var(--src-space-4) |
| --src-border-rounded-full | 9999px |
| --src-gap-none | 0px |
| --src-gap-lg | var(--src-space-2-5) |
| --src-text-weight-base | var(--src-font-weight-medium) |
| --src-text-lineHeight | var(--src-font-line-sm) |
| --src-text-fontSize | var(--src-font-size-sm) |
| --src-gap-md | var(--src-space-1-5) |
| --src-gap-xl | var(--src-space-3-5) |
| --src-gap-sm | var(--src-space-1) |
| --src-text-weight-bold | var(--src-font-weight-bold) |
| --src-text-weight-medium | var(--src-font-weight-semiBold) |
| --src-shadow-focused | var(--src-space-1) |
| --src-shadow-ambient-inner | -1px |
| --src-shadow-ambient-inner-light | 1px |
| --src-shadow-ambient-outer | 1px |
| --src-shadow-blur | 1px |

### layout-md (scope: @media (min-width: 768px))
Source: `variables/layout/_md.scss`

| Token | Value |
|-------|-------|
| --src-layout-padding-const-xs | var(--src-space-1) |
| --src-layout-padding-const-sm | var(--src-space-2) |
| --src-layout-padding-const-md | var(--src-space-3) |
| --src-layout-padding-const-lg | var(--src-space-4) |
| --src-layout-padding-const-xl | var(--src-space-6) |
| --src-layout-padding-const-2xl | var(--src-space-8) |
| --src-layout-padding-var-xs | var(--src-space-2) |
| --src-layout-padding-table-sm | var(--src-space-3) |
| --src-layout-padding-var-sm | var(--src-space-3) |
| --src-layout-padding-var-md | var(--src-space-4) |
| --src-layout-padding-var-lg | var(--src-space-5) |
| --src-layout-padding-var-xl | var(--src-space-8) |
| --src-layout-padding-var-2xl | var(--src-space-11) |
| --src-layout-gap-const-none | 0px |
| --src-layout-gap-const-xs | var(--src-space-1) |
| --src-layout-gap-const-sm | var(--src-space-2) |
| --src-layout-gap-const-md | var(--src-space-3) |
| --src-layout-gap-const-lg | var(--src-space-4) |
| --src-layout-gap-const-xl | var(--src-space-6) |
| --src-layout-gap-const-2xl | var(--src-space-8) |
| --src-layout-gap-var-none | 0px |
| --src-layout-gap-var-sm | var(--src-space-2) |
| --src-layout-gap-var-md | var(--src-space-3) |
| --src-layout-gap-var-lg | var(--src-space-4) |
| --src-layout-gap-var-xl | var(--src-space-8) |
| --src-layout-height-const-sm | var(--src-space-7) |
| --src-layout-height-const-md | var(--src-space-8) |
| --src-layout-height-const-lg | var(--src-space-9) |
| --src-layout-height-const-h-xl | var(--src-space-10) |
| --src-layout-height-const-h-2xl | var(--src-space-16) |
| --src-layout-height-var-xs | var(--src-space-8) |
| --src-layout-height-var-sm | var(--src-space-10) |
| --src-layout-height-var-base | var(--src-space-20) |
| --src-layout-height-var-md | var(--src-space-28) |
| --src-layout-height-var-lg | var(--src-space-24) |
| --src-layout-height-var-xl | var(--src-space-36) |
| --src-layout-radius-var-rounded-kid | var(--src-space-2) |
| --src-layout-radius-var-rounded-parent | var(--src-space-3) |
| --src-layout-radius-rounded-none | 0px |
| --src-layout-border-border | 1px |
| --src-layout-table-height | var(--src-space-14) |
| --src-layout-radius-const-rounded-sm | var(--src-space-1-5) |
| --src-layout-radius-const-rounded | var(--src-space-2) |
| --src-layout-radius-const-rounded-md | var(--src-space-3) |
| --src-layout-radius-const-rounded-lg | var(--src-space-4) |
| --src-layout-radius-const-rounded-xl | var(--src-space-6) |
| --src-layout-radius-const-rounded-2xl | var(--src-space-8) |
| --src-layout-radius-rounded-ui-full | 9999px |
| --src-shadow-basic | var(--src-space-1-5) |
| --src-graphs-label | var(--src-space-2) |
| --src-graphs-label-var | var(--src-space-2-5) |
| --src-graphs-height-label-var | var(--src-space-7) |
| --src-graphs-height-label-const | var(--src-space-5) |
| --src-graphs-height-s | var(--src-space-8) |
| --screen-width | 768px |
| --card-width | 320px |
| --preview-width | 216px |
| --src-typography-var-p-sm-fontSize | var(--src-font-size-sm) |
| --src-typography-var-p-sm-weight | var(--src-font-weight-regular) |
| --src-typography-var-p-sm-lineHeight | var(--src-font-line-sm) |
| --src-typography-var-p-md-fontSize | var(--src-font-size-base) |
| --src-typography-var-p-md-weight | var(--src-font-weight-regular) |
| --src-typography-var-p-md-lineHeight | var(--src-font-line-base) |
| --src-typography-var-h-sm-fontSize | var(--src-font-size-md) |
| --src-typography-var-h-sm-weight | var(--src-font-weight-semiBold) |
| --src-typography-var-h-sm-lineHeight | var(--src-font-line-md) |
| --src-typography-var-h-md-fontSize | var(--src-font-size-lg) |
| --src-typography-var-h-md-weight | var(--src-font-weight-semiBold) |
| --src-typography-var-h-md-lineHeight | var(--src-font-line-lg) |
| --src-typography-var-h-lg-fontSize | var(--src-font-size-xl) |
| --src-typography-var-h-lg-weight | var(--src-font-weight-semiBold) |
| --src-typography-var-h-lg-lineHeight | var(--src-font-line-xl) |
| --src-typography-var-h-xl-fontSize | var(--src-font-size-3xl) |
| --src-typography-var-h-xl-weight | var(--src-font-weight-semiBold) |
| --src-typography-var-h-xl-lineHeight | var(--src-font-line-3xl) |
| --src-typography-var-p-lg-fontSize | var(--src-font-size-lg) |
| --src-typography-var-p-lg-weight | var(--src-font-weight-regular) |
| --src-typography-var-p-lg-lineHeight | var(--src-font-line-lg) |

## Design system rules

Before building custom UI, always search for an existing Source UI component or Source Element with the same semantic meaning. Only create new components as a last resort.

Full design system rules reference: [Design System Rules](../llms-design-rules.md)

### Token selection priority

When styling, follow this priority chain:
1. Use an existing semantic token from `design-tokens.json` (`--src-space-*`, `--src-padding-*`, etc.)
2. If no exact semantic token exists — use the closest primitive from `design-tokens.json`
3. If no primitive fits — use a raw value (px/rem). **A raw value is always better than an invented token.**

STRICT RULE: Never invent a token name that does not exist in `design-tokens.json`.

### Token groups cheat sheet

- **Spacing**: `--src-space-*` (0–96 scale, e.g. `--src-space-4` = 16px)
- **UI sizing**: `--src-padding-*`, `--src-height-*`, `--src-gap-*`, `--src-icon-size`
- **Border radius**: `--src-border-rounded-*` (component-level), `--src-layout-radius-*` (layout-level)
- **Layout**: `--src-layout-padding-(const|var)-*`, `--src-layout-gap-(const|var)-*`, `--src-layout-height-(const|var)-*`
- **Typography**: `--src-font-*` (primitives), `--src-typography-var-*` (responsive composites)

### Responsive: `var` vs `const` tokens

- `var` tokens change by breakpoint (sm/md/lg/xl) — use for adaptive/responsive UI
- `const` tokens stay the same across all screen sizes — use for fixed-size UI
- `layout-sm` tokens are the base (global) defaults — they apply at all viewport widths. `layout-md/lg/xl` override them at their respective breakpoints (768px / 1440px / 1920px)
- Example: `--src-layout-padding-var-*` scales with viewport; `--src-layout-padding-const-*` does not

### Semantic color layers

Always use semantic color tokens, not raw color primitives:
- Surfaces: `--src-surface-*` — backgrounds
- Text: `--src-text-*` — font colors
- Icons: `--src-icon-*` — icon fills
- Borders: `--src-border-*` — border colors
- Accents/status: `--src-ui-*` — interactive states, status indicators
- Shadows: `--src-shadow-*` — elevation
- Gradients: `--src-gradient-*`

**Alpha rule**: Alpha tokens (`--src-color-alpha-*`) may only be used as overlays on top of a solid surface layer. Never use alpha as the only background without a solid surface under it.

### Radius hierarchy

Border radius tokens follow a hierarchy: smaller level number = bigger radius. Parent containers must have a larger (or equal) radius than nested children. Use only `--src-border-rounded-*` and `--src-layout-radius-*` tokens.

### Anti-patterns

- Using primitive color tokens (`--src-color-red-500`) for UI instead of semantic tokens (`--src-ui-accent-error`)
- Alpha token as standalone background (no solid surface beneath)
- Mixing `const` and `var` layout tokens in the same adaptive context
- Breaking radius hierarchy (child radius > parent radius)

## Theming: Custom Accent Colors

The accent color palette drives all primary interactive elements (buttons, selections, focus rings, links). You can override the default blue (`#017BFF`) with any brand color.

### How accent colors work

1. **Primitives** define the raw palette in `primitives/primitives.scss`:
   - `--src-color-primary-50` through `--src-color-primary-950` (11 shades)
   - `--src-color-alpha-accent-10` through `--src-color-alpha-accent-400` (5 alpha variants)

2. **Semantic tokens** in `color/light.scss` and `color/dark.scss` reference the primitives:
   - `--src-ui-accent-default: var(--src-ui-accent-default, #017bffff)` (primary action color)
   - `--src-ui-accent-default-hover: var(--src-color-primary-600)` (hover state)
   - `--src-ui-secondary-active: var(--src-color-alpha-accent-50)` (selected backgrounds)
   - etc.

3. **You only override primitives** — semantic mappings stay intact, so all components update automatically.

### Agent instruction: Override accent color

To change the accent color to a custom brand color (e.g. `#FF5722`):

1. Create `_accent-override.scss` in the user's project (NOT in the library):

```scss
// _accent-override.scss
// Custom accent color palette — override Source UI default blue
// Generated from base color: #FF5722
:root {
  // ── primary shades (50=lightest, 950=darkest) ──
  --src-color-primary-50:  #FFF3E0ff;
  --src-color-primary-100: #FFE0B2ff;
  --src-color-primary-200: #FFCC80ff;
  --src-color-primary-300: #FFB74Dff;
  --src-color-primary-400: #FFA726ff;
  --src-color-primary-500: #FF5722ff;  // ← your base color
  --src-color-primary-600: #F4511Eff;
  --src-color-primary-700: #E64A19ff;
  --src-color-primary-800: #D84315ff;
  --src-color-primary-900: #BF360Cff;
  --src-color-primary-950: #7F1D04ff;

  // ── Alpha variants (for backgrounds, hover states) ──
  // Format: base color (#FF5722) + alpha hex suffix
  --src-color-alpha-accent-10:  #FF572214;
  --src-color-alpha-accent-50:  #FF57221f;
  --src-color-alpha-accent-100: #FF572229;
  --src-color-alpha-accent-200: #FF57223d;
  --src-color-alpha-accent-300: #FF572252;
  --src-color-alpha-accent-400: #FF57225c;
}
```

2. Import it in `styles.scss` AFTER the Source UI stylesheets:

```scss
@use '../node_modules/@3dsource/source-ui-native/styles/source.ui.native.scss' as source-ui-native;
@use './accent-override'; // ← after library styles
```

### Palette generation algorithm

From a single base hex color, generate the 50–950 scale using HSL lightness steps:

| Shade | Lightness target |
|-------|-----------------|
| 50    | 95% |
| 100   | 88% |
| 200   | 78% |
| 300   | 68% |
| 400   | 58% |
| 500   | Base color (keep original lightness) |
| 600   | Base lightness − 5% |
| 700   | Base lightness − 12% |
| 800   | Base lightness − 18% |
| 900   | Base lightness − 28% |
| 950   | Base lightness − 40% |

Alpha variants use the base 500 color with these hex alpha suffixes:
- `10` → `14` (8% opacity)
- `50` → `1f` (12% opacity)
- `100` → `29` (16% opacity)
- `200` → `3d` (24% opacity)
- `300` → `52` (32% opacity)
- `400` → `5c` (36% opacity)

### Rules

- **NEVER modify** `primitives.scss`, `light.scss`, or `dark.scss` in the library
- **NEVER modify** semantic tokens — they reference primitives automatically
- The override file MUST be loaded AFTER the library stylesheet
- All 11 shades (50–950) and 6 alpha variants must be defined for full coverage
- Suffix `ff` on hex colors = fully opaque; alpha variants use partial opacity suffixes

## Optional

- [Full documentation (self-contained)](../llms-full.txt): Comprehensive reference with all component APIs and design tokens inlined — no external links needed
- [Full component registry JSON](../api/_registry.json): Machine-readable index for programmatic discovery
