# Foundations
> What the general @sdxc/ui components are for, the rules every one follows, and every non-color variable they read.

The general catalogue: forms, overlays, navigation, feedback, layout and type, rendered as server HTML. Every namespace builds on it.

Colors come from the roles on Theming and shape from the variables below, so you retune a component by setting a variable.

Import the components from `@sdxc/ui` and the theme once from `@sdxc/ui/theme.css`.

## When to reach for it

- Any page, app or marketing: these are the parts every other namespace composes.
- Forms, dialogs, menus, popovers, tabs and the other controls a product needs.
- A component you want to own: sdxc ui add copies one into your project to edit.

## Shared ideas

- **Ambient headings.** `Heading` takes its level from the nearest `HeadingScope`; `size` sets the look apart from the level.
- **Platform first.** Overlays use `<dialog>`, the Popover API and Invoker Commands; only `DialogDismiss` is an island.
- **Color by role.** `color` takes `brand`, `neutral`, `success`, `warning` or `danger`; no component hard-codes a hue.
- **Targets.** Small controls grow an invisible hit area to `--ui-target-size`, 44px on a coarse pointer.
- **Names checked.** Icon-only controls and landmarks warn in development without an accessible name.
- **Motion.** `spin`, `pulse` and `shimmer` are CSS keyframes that soften under `prefers-reduced-motion`.
- **Both directions.** Logical properties and `:dir(rtl)` mirroring keep one markup for both writing directions.

## CSS variables

Every custom property the namespace reads or declares. Reads every role, brand, neutral, success, warning and danger; the Theming page lists them with their light and dark values. The roles are documented on Theming.

### Scales

`@sdxc/u`'s `theme.css` declares spacing, fonts, type and container sizes; radius and shadow are read with these defaults, and declaring one restyles every component.

| Variable | Default | What it controls |
| --- | --- | --- |
| `--ui-spacing` | `0.25rem` | Unit of every numeric gap, padding and size step. |
| `--ui-font-sans` | `ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif` | Body face. |
| `--ui-font-serif` | `ui-serif, Georgia, Cambria, "Times New Roman", serif` | Serif face. |
| `--ui-font-mono` | `ui-monospace, SFMono-Regular, Menlo, Consolas, monospace` | Code face. |
| `--ui-font-display` | `var(--ui-font-sans)` | Face of `Heading`'s `display` and `chapter` sizes. |
| `--ui-text-xs … --ui-text-9xl` | `0.75rem, 0.875rem, 1rem, 1.125rem, 1.25rem … 8rem` | The type size scale. |
| `--ui-container-xs … --ui-container-2xl` | `20rem, 24rem, 36rem, 48rem, 64rem, 80rem` | The container widths components step at. |
| `--ui-radius-none … --ui-radius-full` | `0px, 0.25rem, 0.375rem, 0.5rem, 0.75rem, 9999px (none, sm, md, lg, xl, full)` | The corner radius scale. |
| `--ui-shadow-sm … --ui-shadow-xl` | `from 0 1px 2px 0 rgb(0 0 0 / 0.05) to 0 20px 25px -5px rgb(0 0 0 / 0.1)` | The elevation scale. |

### Surfaces

Declared in `theme.css`, with dark values under `.dark` and `prefers-color-scheme: dark` and solid lines under `prefers-contrast: more`.

| Variable | Default | What it controls |
| --- | --- | --- |
| `--ui-target-size` | `1.5rem; 2.75rem on a coarse pointer` | Smallest pointer target a small control grows to. |
| `--ui-shadow-ring` | `a 1px ring at 6% black with a soft lift; 8% white in dark` | Edge of cards, dialogs and floating surfaces. |
| `--ui-shadow-ring-hover` | `the same ring a step stronger` | The ring's hover state, for a surface that responds to the pointer. |
| `--ui-surface-raised` | `white; a neutral 900–950 mix in dark` | Fill of a `variant="surface"` button. |
| `--ui-shadow-control` | `a 1px drop with an inset highlight and ring` | Tactile edge of a `variant="surface"` button. |
| `--ui-shadow-surface, --ui-shadow-stage` | `a ring with a small drop; a ring with a deep drop` | Edges of raised cards and staged frames, which the landing parts read. |
| `--ui-image-outline` | `rgb(0 0 0 / 0.1); rgb(255 255 255 / 0.1) in dark` | Inset line that keeps an image's edge visible on a same-tone fill. |

### Component tuning

Each falls back to its default in the component; set it on the element, an ancestor or `:root`.

| Variable | Default | What it controls |
| --- | --- | --- |
| `--ui-button-radius` | `var(--ui-radius-md); 9999px on an icon-only button` | Corners of `Button` and `LinkButton`. |
| `--ui-button-weight` | `500` | Weight of a button's label. |
| `--ui-button-icon-size-sm, -md, -lg` | `2rem, 2.5rem, 3rem` | Edge of an icon-only button at each size. |
| `--ui-popover-offset` | `0.5rem` | Gap between a popover or hover card and its trigger. |
| `--ui-overlay-arrow-offset` | `0.5rem` | How far an `OverlayArrow` reaches past its surface. |
| `--ui-surface-padding` | `0.25rem` | Inner padding of floating surfaces; their inner radius follows it. |
| `--ui-hover-card-open-delay, --ui-hover-card-close-delay` | `0.4s, 0.2s` | How long a hover card waits to open and to close. |
| `--ui-hover-card-z` | `50` | Stacking order of a hover card. |
| `--ui-slider-thumb-size, --ui-slider-thumb-border-width` | `1.25rem, 2px` | A slider thumb's size and border. |
| `--ui-slider-track-thickness` | `0.5rem` | Thickness of a slider's track and fill. |
| `--ui-switch-track-inline-size, --ui-switch-track-block-size` | `2.75rem, 1.5rem` | Width and height of a `Switch`'s track. |
| `--ui-switch-thumb-size, --ui-switch-thumb-inset` | `1.25rem, 0.125rem` | A `Switch` thumb's size and its gap to the track's edge. |
| `--ui-checkbox-size` | `1.25rem` | Edge of a Checkbox. |
| `--ui-radio-size, --ui-radio-mark-size` | `1.25rem, 0.625rem` | A radio's circle and its checked dot. |
| `--ui-selection-indicator-size` | `1rem` | Edge of the check mark box in menus and lists. |
| `--ui-carousel-gap, --ui-carousel-slide-size, --ui-carousel-padding` | `1rem, 18rem, 0px` | A `Carousel`'s gap, slide size and track padding. |
| `--ui-spinner-icon-size-sm, -md, -lg` | `1rem, 1.25rem, 1.75rem` | A `Spinner`'s glyph at each size, also inside a pending Button. |
| `--ui-image-placeholder-size-sm, -md, -lg` | `2rem, 2.5rem, 3rem` | An `ImagePlaceholder`'s edge at each size; md is also an `Avatar`'s size. |
| `--ui-avatar-group-ring` | `var(--ui-bg, Canvas)` | Ring between overlapping avatars in Avatar.Group. |
| `--ui-item-gap, --ui-item-actions-gap` | `0.75rem, 0.5rem` | Gaps between an `Item`'s media and content, and between its actions. |
| `--ui-item-padding-block, --ui-item-padding-inline` | `0.625rem, 0.75rem` | An `Item`'s padding. |
| `--ui-item-media-size` | `2rem` | Edge of an Item's media box. |
| `--ui-sheet-size` | `24rem, at most 90vw` | Width of a Sheet. |
| `--ui-separator-thickness, --ui-separator-min-size` | `1px, 1rem` | A `Separator`'s thickness and a vertical one's shortest length. |
| `--ui-meter-track-block-size, --ui-progress-bar-block-size` | `0.5rem, 0.5rem` | Height of a `Meter`'s and a `ProgressBar`'s track. |
| `--ui-pagination-control-size` | `2.25rem` | Edge of each `Pagination` control. |
| `--ui-tag-remove-size` | `1rem` | Edge of a tag's remove button. |
| `--ui-navigation-menu-viewport-inline-size, -block-size` | `auto` | Size of `NavigationMenu`'s shared viewport, which transitions between panels. |
| `--ui-typeset-size, --ui-typeset-leading, --ui-typeset-flow` | `set by Typeset's preset; docs is 1.125rem, 1.75, 1.25em` | Body size, line height and space between blocks of rendered prose. |
| `--ui-aspect-ratio` | `set by AspectRatio from ratio; 1` | The box's aspect ratio. |

### Animations

Each animation from `@sdxc/ui/animations` reads its options through these, so a variable overrides the option it names.

| Variable | Default | What it controls |
| --- | --- | --- |
| `--ui-spin-duration, --ui-spin-easing, --ui-spin-fade-duration` | `1s, linear, 150ms` | One turn of `spin()`, its easing and its fade in and out. |
| `--ui-pulse-duration, --ui-pulse-easing, --ui-pulse-fade-duration` | `1.6s, ease-in-out, 150ms` | One breath of `pulse()`, its easing and its fade in and out. |
| `--ui-pulse-min-opacity, --ui-pulse-max-opacity` | `0.5, 1` | The dimmest and brightest points of `pulse()`. |
| `--ui-shimmer-duration, --ui-shimmer-easing, --ui-shimmer-band-size, --ui-shimmer-fade-duration` | `1.6s, ease-in-out, 50%, 150ms` | One sweep of `shimmer()`, its easing, its band's width and its fade. |
| `--ui-text-shimmer-duration, -easing, -band-size, -angle` | `2s, linear, 30%, 90deg` | One sweep of `textShimmer()` through the glyphs, and its band. |
| `--ui-text-shimmer-color, --ui-text-shimmer-fade-duration` | `currentColor, 150ms` | The band's peak color and the shimmer's fade. |
| `--ui-scroll-shadow` | `0 4px 12px -4px rgb(0 0 0 / 0.18)` | Shadow `scrollShadow()` ramps in under a sticky header. |

### Set by the components

Written by a component from its props or by a mixin, and read back by its own parts. Leave them unset.

| Variable | Default | What it controls |
| --- | --- | --- |
| `--ui-tab-indicator-inline-start, -inline-size, -block-start, -block-size, -opacity` | `set by Tabs.List from activeIndex and tabSize` | Where the active tab's indicator sits and whether it shows. |
| `--ui-slider-fill` | `set by Slider.Track from value` | How much of the track is filled. |
| `--ui-drawer-enter-offset, --ui-drawer-exit-offset` | `set by Drawer from placement` | Where a drawer slides in from and out to. |
| `--ui-sheet-enter-offset, --ui-sheet-exit-offset` | `set by Sheet from side` | Where a sheet slides in from and out to. |
| `--ui-box-shadow-ring` | `var(--ui-shadow-ring)` | The ring slot of a surface's composite shadow. |
| `--ui-view-reveal-translate, --ui-scroll-fade-direction` | `set by viewReveal() and scrollFade()` | A reveal's starting offset and a scroll fade's direction, mirrored in RTL. |
