> ## Oymyakon DS index
> Fetch the full index at: https://super-dollop-pzmo65r.pages.github.io/llms.txt
> HTML preview: https://super-dollop-pzmo65r.pages.github.io/destination-button.html
> Source: specs/components/destination-button/destination-button.md, specs/components/destination-button/destination-button-a11y.md, specs/components/destination-button/capabilities.json

---

# DestinationButton · Oymyakon DS 3

> The screen-level entry into an order: a search icon, the destination prompt in two centred lines,
> and the service image — one full-width row assembled from customButton.

**Version:** 3.0.4 · **Status:** Draft · **Figma line:** `[DestinationButton] 3.0` — component set
(node `30339:368`), `State=Standard` (node `30333:357`), `State=Skeleton` (node `30339:349`)

> **Figma source note.** The component set lives on the branch `ruoGXrpbw0vbfgl8bdfPcj` of the
> Oymyakon 3.29.1 components file and is not merged into the main file yet, so the node-ids above are
> branch ids. They are recorded here so the web build is traceable; the manifest binds them once the
> branch merges (see § 11).

---

## 1. Description

DestinationButton is the control a rider taps to start an order. It sits at the top of the ride flow as a
full-width row: the search icon on the left, the question in two centred lines in the middle, and
the service image on the right.

It differs from [Button](https://super-dollop-pzmo65r.pages.github.io/button.md) in what it is for rather than in how it is built. A
Button commits to an action the wording already names — Accept, Confirm, Pay. DestinationButton opens a flow
whose subject is the destination, so the label is a question rather than a verb, and the row carries
an image of the service instead of an icon.

The component is a locked configuration of **customButton**, the same relationship
[Floating Button](https://super-dollop-pzmo65r.pages.github.io/floating-button.md) has to it: the base stays open, this preset
fixes the height, the fill, the typography and the two side slots so a product team consumes it
as-is. What stays open is slot content — the start glyph and the service image are swap slots, and
the two text rows carry defaults rather than fixed strings.

---

## 2. Anatomy

DestinationButton is built out of slots named with the DS-wide **StartSlot / StartText / EndSlot** semantics.
Both side slots are swap slots that hold a default component and accept another in its place.

```
DestinationButton                .destination-button                   100% x s64 — required
├── StartSlot           .destination-button__start-slot        s64 x s56, swap slot, default modified-size IconContainer (s24 glyph) — required
├── StartText           .destination-button__start-text        row column, s2 gap — required
│   ├── Title row       .destination-button__title-row         Heading 2 — required
│   └── Subtitle row    .destination-button__subtitle-row      Compact Body — optional, on by default
└── EndSlot             .destination-button__end-slot          s64 x s56, swap slot, default 3D service image, mirrored — required
```

The three parts sit on one row with `space-between`, so the icon is flush to the leading edge, the
image to the trailing edge, and the text column takes the space between them, centred.

The default start-slot content is a **modified-size IconContainer**: the box is stretched to
`s64` x `s56` while the glyph keeps its `s32` box, centred in it — Figma calls the
instance `modified-size-icon`, and the default glyph is
`icons/outlined/actions/search.svg` in `TextAndIcon/Primary`. The default end-slot content is the
`economy-white` service image in its `tariff` crop (`illu/3D/vehicle/tariff/economy-white.png`),
filling its box.

The illustration is **mirrored, in every variation** — the Figma illustration container ships with its
RTL toggle on, which turns the vehicle to face the text column instead of the row's trailing edge. As
with a directional glyph the asset file is never edited: the mirror is a `scaleX(-1)` on the consuming
component. It belongs to the artwork rather than to the document's direction, so it does not flip a
second time under `dir="rtl"` — the row mirrors as a whole and the vehicle keeps facing the text.

---

## 3. Variants and sizes

| Axis | Values | Default | Note |
|---|---|---|---|
| `State` | `Standard`, `Skeleton` | `Standard` | Rest vs loading |
| `RTL` | `Off`, `On` | `Off` | Mirrors the row as a whole; on the web it comes from the document's `dir`, no class |

**One size.** DestinationButton has a single size — `s64` tall, full width of its container — because it
occupies a fixed place in the screen rather than scaling with the content around it. There is no
`L` / `M` / `S` ladder and no `Style` axis: the fill is always `Surface/OnWhite`.

---

## 4. States

| State | Description |
|---|---|
| **Standard** | The rest state. `Surface/OnWhite` fill, both text rows and both side slots shown. |
| **Pressed** | While the row is held. Scale steps to 95% on `pushButton`; the fill and the label keep their tokens. |
| **Skeleton** | The shape alone while the order data loads. The content is dropped and the row is filled by the [Skeleton](https://super-dollop-pzmo65r.pages.github.io/skeleton.md) component at radius `s20`. |

`Disabled` is not part of this component. The Figma set's `State` axis carries `Standard | Skeleton` only —
a screen that cannot start an order does not show the row in a dimmed form, it shows the Skeleton
while the data is missing.

---

## 5. Animation and behavior

Motion follows [`motion-rules.md`](https://super-dollop-pzmo65r.pages.github.io/motion.md) § 6.1, which names the
button family as the consumer of `pushButton` — scale and colour moving together on press.

| Event | Pattern | Token | CSS |
|---|---|---|---|
| Press | `pushButton` | `--component-push-button-press` | `transform` (100% → 95%) |
| Release | `pushButton` | `--component-push-button-release` | `transform` (95% → 100%) |
| Skeleton → Standard | — | — | Owned by the Skeleton component: the row is replaced, not transitioned |

```css
.destination-button {
  transition: transform var(--component-push-button-release);
}
.destination-button:active {
  transform: scale(0.95);
  transition: transform var(--component-push-button-press);
}
```

Only `transform` participates, so the press stays on the compositor. Reduced motion is handled at
the token — `motion.css` zeroes every `--component-*` under
`@media (prefers-reduced-motion: reduce)`, so the press becomes instant and this component carries no
override of its own.

The skeleton sweep is the Skeleton component's own animation, not DestinationButton's.

---

## 6. Color tokens

| Element | Token | Figma variable |
|---|---|---|
| Row fill | `var(--surface-on-white)` | `Surface/OnWhite` |
| Title row | `var(--text-and-icon-primary)` | `TextAndIcon/Primary` |
| Subtitle row | `var(--text-and-icon-secondary)` | `TextAndIcon/Secondary` |
| Start-slot glyph | `var(--text-and-icon-primary)` | `TextAndIcon/Primary` |
| Focus ring | `var(--text-and-icon-primary)` | `TextAndIcon/Primary` |
| Skeleton fill | `var(--skeleton-on-white)` via `.skeleton` | `Additional/Skeleton/Start` |

The end-slot image is a raster illustration and carries no colour token; it changes with the
service, not with the theme. Light and dark substitute by token name — the row has no theme branch of
its own.

---

## 7. Typography

| Element | Style | Tokens |
|---|---|---|
| Title row | Heading 2 | `var(--text-heading-heading2-*)` — PP Agrandir, 24px |
| Subtitle row | Compact Body | `var(--text-body-compact-body-*)` — Suisse Intl, 14px |

Heading 2 is the one place the button family reaches for PP Agrandir, and it is the same style
`Main CTA` uses: the prompt is the loudest text on the screen it opens. Both rows are **centred** on
each other and in the space between the two slots, so the pair reads as one block whichever row is
wider.

Both rows are **single-line**: text that overflows its row truncates to an ellipsis rather than
wrapping, so the row's `s64` height never grows with content. The full string still reaches assistive
technology — the accessible name comes from the text content, not from the rendered line (see
[`destination-button-a11y.md`](https://super-dollop-pzmo65r.pages.github.io/destination-button.md)).

---

## 8. Spacing

| Property | Token | Value |
|---|---|---|
| Height | `var(--sp-s64)` | 64 |
| Width | — | `100%` of the container |
| Corner radius | `var(--sp-s20)` | 20 |
| Padding | — | none — the row declares no padding on any side |
| Gap, row | `var(--sp-s12)` | 12 |
| Gap, text rows | `var(--sp-s2)` | 2 |
| StartSlot | `var(--sp-s64)` x `var(--sp-s56)` | 64 x 56 — modified-size IconContainer box |
| EndSlot | `var(--sp-s64)` x `var(--sp-s56)` | 64 x 56 — ImgContainer box |
| Start glyph | `var(--sp-s32)` | 32 — the IconContainer scale step the design uses |

Three consequences of those numbers are worth stating, because each looks like a mistake and is not:

- **The slots centre in the row.** The row declares no padding: both side slots are `s56` tall in the
  `s64` row, and the 4 of air above and below each is centring arithmetic (64 − 56), not an inset.
  Nothing extends past the row's bounds — unlike the `s8`-padded 3.0.0 arrangement, where the image
  bled through.
- **No horizontal padding either.** The inset comes from the slots themselves: the `s32` glyph is
  centred in its `s64` box, which is where the leading air comes from, and the image fills its box to
  the trailing edge.
- **The glyph keeps the IconContainer default.** `modified-size` names the BOX, not the icon: the
  container is stretched to `s64` x `s56` while the glyph stays `s32`. Scaling the glyph instead would
  take it off the IconContainer size scale (16 / 20 / 24 / 32).

---

## 9. Usage context

**Use it** for the destination prompt that opens an order — one per screen, at the top of the flow.

**Do not use it** for:

- an in-page action whose label names a verb — that is [Button](https://super-dollop-pzmo65r.pages.github.io/button.md);
- a row in a list of places or settings — that is [Cell](https://super-dollop-pzmo65r.pages.github.io/cell.md);
- an action floating above scrolling content — that is
  [Floating Button](https://super-dollop-pzmo65r.pages.github.io/floating-button.md);
- a second prompt on the same screen. The row is sized and coloured to be the only one of its kind in
  view.

Related: [Button](https://super-dollop-pzmo65r.pages.github.io/button.md) (the base and the family), [Cell](https://super-dollop-pzmo65r.pages.github.io/cell.md) (the list
row it is often mistaken for), [Skeleton](https://super-dollop-pzmo65r.pages.github.io/skeleton.md) (the loading state).

---

## 10. Accessibility

Full spec: [`destination-button-a11y.md`](https://super-dollop-pzmo65r.pages.github.io/destination-button.md).

The row is one tap target and one accessible name — the two text rows joined by the name computation, "{title} {subtitle}".
The start glyph and the service image are decorative and carry `aria-hidden="true"`: neither adds
information the name does not already give. The focus ring is `s2` in
`var(--text-and-icon-primary)` at radius `s20`, offset inward so a full-width row cannot push the ring
past its container. The Skeleton state is not focusable and announces nothing.

---

## 11. Analytics and coverage contract

Contract per [`docs/prototype-analytics-and-coverage.md`](https://github.com/inDriver/oymyakon-ds/blob/main/docs/prototype-analytics-and-coverage.md).

| Field | Value |
|---|---|
| `data-ds-component` | `destination-button` |
| Coverage unit | Yes |
| Tap target model | Root — one target |
| Supported actions | `tap` |
| Internal targets | None — the image and the glyph are decorative |
| Emits a value | No |

Required prototype markup:

```html
<button type="button" class="destination-button"
        data-ds-component="destination-button"
        data-ds-component-id="ride-destination-button"
        data-ds-state="standard"
        data-ds-action="tap">
  <span class="destination-button__start-slot" aria-hidden="true"><!-- search icon (modified-size IconContainer) --></span>
  <span class="destination-button__start-text">
    <span class="destination-button__title-row">Where to?</span>
    <span class="destination-button__subtitle-row">And for how much?</span>
  </span>
  <span class="destination-button__end-slot" aria-hidden="true"><!-- 3D service image --></span>
</button>
```

`data-ds-preset` is omitted: the component has one size and one style, so there is no preset axis to
report. The Skeleton state carries `data-ds-state="skeleton"` and no `data-ds-action`.

**Manifest binding.** The web build ships with this spec, so `manifest/web-nodes.json` carries the
entry as the owner rule requires. The Figma node-ids are branch ids until `[DestinationButton]` merges
into the main components file — recorded in the entry's `$note` rather than silently bound as if they
were main-file ids.

---

## Changelog

The version tracks the Figma line `[DestinationButton] 3.0` (owner, 2026-08-24). The slot swap and the
mirror below briefly shipped as 3.1.0 / 3.1.1 — an over-eager `X` bump on the repo side while Figma
stayed on 3.0; renumbered to 3.0.1 / 3.0.2, same content.

| Version | Date | Change |
|---|---|---|
| 3.0.4 | 2026-08-26 | Two design drifts reconciled from the live Figma set (found while porting the spec frame). **The set now carries an `RTL` axis** (`State × RTL`; RTL=On mirrors the row as a whole) — §3 gains the axis, the a11y RTL section and the roadmap drop the «not a variant yet» known gap; on the web nothing changes, mirroring still comes from `dir`. **The start glyph box is `s32`, not `s24`** (`modified:forward-arrow-right` 32×32) — §2/§8 corrected and the web build's glyph size updated to match the design. |
| 3.0.3 | 2026-08-26 | **Renamed: Where-To → DestinationButton** (owner; the content-name became a role-name after coder feedback — the destination semantics stay in the name, the family stays Button). Classes `.where-to*` → `.destination-button*`, id/page/paths/`data-ds-component` renamed, Figma set `[Button:Where-To]` → `[DestinationButton]`. No visual or behavioural change. Earlier rows read the new name. |
| 3.0.2 | 2026-08-24 | The end-slot illustration is **mirrored in every variation** (owner, from the Figma container's RTL toggle): `scaleX(-1)` on the image, the asset file untouched, so the vehicle faces the text column instead of the trailing edge. The mirror is part of the artwork, not of the document direction — it does not flip again under `dir="rtl"`. Three sentences left over from 3.0.0 are corrected with it: § 1 put the service on the leading edge and called the glyph the end one, § 6 still named an `End-slot glyph` and a `start-slot image`, § 10 called the icon the end glyph, and the § 11 markup comment still put the service image in the start slot. `capabilities.json` gets the same sweep — its `anatomy`, `rtl`, `analytics` and description blocks still described the 3.0.0 composition. § 7 now states the single-line ellipsis truncation the CSS already carried, and § 10's accessible-name example drops its comma — the name is computed from content, joined with a space. |
| 3.0.1 | 2026-08-24 | **Side slots swapped and both grown to `s64` x `s56`** (owner, from the Figma set on branch `ruoGXrpbw0vbfgl8bdfPcj`). StartSlot now holds a **modified-size IconContainer** — the box stretched to the slot while the glyph stays at the IconContainer default `s24`, `search` in `TextAndIcon/Primary`; EndSlot holds the 3D service image, which is why the artwork now reaches the trailing edge. The `s8` vertical padding is gone — the row declares none; both `s56` slots centre in the `s64` row and the 4 of air per side is centring arithmetic, not an inset. The text rows are **centred** instead of leading-aligned. The RTL glyph mirror is gone with the arrow: `search` is not on the `icon-container.md` § 3.5 directional list, so the row mirrors as a whole and nothing flips in place. |
| 3.0.0 | 2026-08-24 | Initial spec — one size (`s64`, full width), `State: Standard \| Skeleton`, Heading 2 + Compact Body rows, `s64 x s56` service image and `s64 x s40` arrow slot, `pushButton` press. Built as a locked customButton configuration from Figma `[DestinationButton]` |

---

# DestinationButton — Accessibility

**Component:** DestinationButton
**Version:** 3.0.4
**Spec:** [`destination-button.md`](https://super-dollop-pzmo65r.pages.github.io/destination-button.md)

---

## Role and ARIA

| Attribute | Value | Where |
|---|---|---|
| `type` | `"button"` | The root — a bare `<button>` inside a form defaults to `submit` |
| `role` | `"button"` | Native on `<button>`; a custom element needs it explicitly |
| `aria-hidden` | `"true"` | The StartSlot icon and the EndSlot service image — both decorative |
| `aria-hidden` | `"true"` | The whole row in the `Skeleton` state |

The row is **one** control, not a composition of tappable parts. The name comes from the text that is
already on screen — the title row and the subtitle row, read in that order — so no `aria-label` is
needed in the Standard state. Where a product replaces the rows with its own strings, the name
follows the visible text rather than being pinned by a label.

The join is the name computation's own: the two rows are block-level, so the algorithm separates them
with a space — "Where to? And for how much?". No punctuation is inserted between them; the title's
question mark is what supplies the pause. A comma would only exist if an `aria-label` put it there,
and this component does not carry one.

Both side slots are decorative. The service image says the same thing the prompt says, and the icon
says "this opens something", which the `button` trait already carries. Exposing either one adds a
second announcement for the same fact.

**The subtitle is part of the name, not a description.** "And for how much?" changes what the control
promises — a rider who hears only "Where to?" does not know the next screen also quotes a price. It
belongs in the name, which is why the two rows are joined rather than split across
`aria-describedby`.

---

## Focus

The root is the only focusable element. Neither text row, nor the icon, nor the image takes focus,
so one Tab moves past the whole row.

| Property | Value |
|---|---|
| Ring | `var(--sp-s2)` solid `var(--text-and-icon-primary)` |
| Radius | `var(--sp-s20)` — follows the row's own corner |
| Offset | `calc(var(--sp-s2) * -1)` — inward |

The offset is inward for the reason a full-width control needs it: the row spans its container, so an
outward ring would be drawn past the container's edge and clipped. This is the same inward-ring
decision Button and Checkbox already carry.

The `Skeleton` state is not focusable and takes no `tabindex` — there is no action behind a shape
that is still loading.

---

## Keyboard

| Key | Action |
|---|---|
| `Tab` / `Shift+Tab` | Moves onto and off the row |
| `Enter` | Activates |
| `Space` | Activates |

A native `<button>` carries both activation keys, the focus behaviour and the role on its own, which
is why it is the DS markup for this component.

**The implementation trap.** Standing a `<div>` in for the row — tempting, because the row holds an
image and two lines of text and reads like a card — loses all three at once: no role, no focus stop,
no keys. A `<div>` needs `role="button"`, `tabindex="0"` and a handler for both `Enter` and `Space`.
The second trap sits inside: neither text row may become interactive. A nested `<button>` or a link in
the title makes two controls where the design has one, and screen-reader focus then stops twice on the
same row.

---

## Contrast

Measured on the component's own pairings, `Surface/OnWhite` as the background in both themes.

| Pairing | Light | Dark | Bar |
|---|---|---|---|
| Title row — `TextAndIcon/Primary` | **15.69:1** | **13.20:1** | AA 4.5 · AAA 7 — passes both |
| Subtitle row — `TextAndIcon/Secondary` | **4.64:1** | **6.13:1** | AA 4.5 — passes; AAA 7 — does not |

The subtitle clears AA in light theme by 0.14, which is the narrowest margin on the component. It
holds because Compact Body at 14px is normal text, where the bar is 4.5:1 — but it leaves no room for
a product to darken the row's fill or lighten the subtitle. A subtitle that needs more headroom moves
to `TextAndIcon/Primary` rather than to a new colour.

The start icon carries `TextAndIcon/Primary`, so it sits at the title's ratio, above the 3:1
non-text bar.

---

## Android · TalkBack

### Tap target · the row

| Element | Label | Value | Trait | Hint |
|---|---|---|---|---|
| DestinationButton row | "{title} {subtitle}" — "Where to? And for how much?" | — | `BUTTON` | "Double-tap to activate" |
| Start icon | not announced | — | — | — |
| Service image | not announced | — | — | — |

### Edge states

- **Skeleton:** the row is out of the swipe order entirely — `aria-hidden` removes it from the
  accessibility tree, so TalkBack moves from the element before it to the element after it. The screen
  announces its own loading through the region's `aria-busy`, not through this row.
- **Long strings:** the label is read in full even when the visible text truncates, since the name comes
  from the text content rather than from the rendered line.

---

## iOS · VoiceOver

### Tap target · the row

| Element | Label | Value | Trait | Hint |
|---|---|---|---|---|
| DestinationButton row | "{title} {subtitle}" — "Where to? And for how much?" | — | `.button` | "Double-tap to activate" |
| Start icon | not announced | — | — | — |
| Service image | not announced | — | — | — |

### Edge states

- **Skeleton:** the row is not in the rotor and not reachable by swipe. This is where the two platforms
  agree and the `Disabled` convention does not apply — DestinationButton has no disabled form, so there is no
  `.dimmed` announcement for it on either platform.
- **Rotor by heading:** the title row is Heading 2 by *style*, not by semantics. It is a `<span>` inside a
  button, so it does not enter the heading rotor — which is correct: the control is an action, not a
  section title.

---

## Target size

| Property | Value | Bar |
|---|---|---|
| Height | `var(--sp-s64)` — 64 | 44 x 44 (WCAG 2.5.5 AAA, Apple HIG) — passes |
| Width | `100%` of the container | — |

The whole row is the target, icon and image included; there is no smaller hit area inside it. Nothing
about either side slot invites a separate tap, and neither has one.

---

## RTL

The row mirrors as a whole: the icon moves to the trailing edge and the service image to the leading
one, and the centred text column needs no change. Nothing flips in place — the default `search` glyph
is not on the DS list of directional glyphs
that mirror (see `icon-container.md § 3.5`).

The illustration is the one thing that carries a mirror of its own, and it carries it in every
variation: the artwork ships `scaleX(-1)` so the vehicle faces the text column. That mirror belongs to
the artwork, not to the direction, so it stays as it is under `dir="rtl"` — nothing about it is
announced either way, since the image is `aria-hidden`.

The mirrored composition is a **variant of the Figma set** (`RTL: Off | On`). On the web the
mirroring comes from the document's `dir` and logical properties, so no second class is needed.

---

## Testing checklist

- [ ] One Tab stop for the whole row; the icon, both text rows and the image are skipped
- [ ] `Enter` and `Space` both activate
- [ ] TalkBack and VoiceOver both read title and subtitle as one name, in that order
- [ ] The icon and the service image are announced by neither
- [ ] Focus ring visible in both themes, `s2`, inward, following the `s20` corner
- [ ] Skeleton row is unreachable by swipe, rotor and Tab
- [ ] Subtitle contrast re-measured if the row fill or the subtitle token changes — the light-theme
      margin over AA is 0.14
- [ ] `dir="rtl"`: row mirrored, no glyph flipped (the default icon is not directional), the
      illustration keeps the mirror it ships with

---

## Changelog

| Version | Date | Change |
|---|---|---|
| 3.0.4 | 2026-08-26 | The RTL note follows the Figma set: the mirrored composition is now a variant (`RTL: Off | On`), no longer a known gap. No behavioural change on the web — mirroring still comes from `dir`. |
| 3.0.3 | 2026-08-26 | Follows the component's rename Where-To → DestinationButton. No a11y change — the accessible name still comes from the visible text rows, not from the component's name. |
| 3.0.2 | 2026-08-24 | Follows the component's 3.0.2: the end-slot illustration ships mirrored in every variation, and the RTL section records that this mirror belongs to the artwork rather than to the document direction — it does not flip again under `dir="rtl"`. No effect on the tree or the contrast numbers: the image is `aria-hidden`. The documented Label is corrected from "{title}, {subtitle}" to the space-joined "{title} {subtitle}" — the name is computed from content, and the algorithm inserts a space between the block-level rows, never a comma. |
| 3.0.1 | 2026-08-24 | Follows the component's 3.0.1 slot swap: the decorative pair is now the StartSlot **icon** and the EndSlot **service image**. The RTL note drops the glyph flip — the default `search` is not directional, so the row mirrors as a whole and nothing flips in place. Contrast row renamed to the start icon; the ratios are unchanged, both slots still carry `TextAndIcon/Primary` on `Surface/OnWhite`. |
| 3.0.0 | 2026-08-24 | Initial a11y spec — one tap target, name from both text rows, decorative image and arrow, inward `s2` focus ring, measured contrast (subtitle 4.64:1 light / 6.13:1 dark), Skeleton out of the tree, RTL mirroring |

---

## Machine contract — `specs/components/destination-button/capabilities.json`

Axes, allowed values, defaults, constraints and CSS/Figma bindings. Read this instead of guessing what the component can do.

```json
{
  "$schema": "../component-capabilities.schema.json",
  "id": "destination-button",
  "name": "DestinationButton",
  "version": "3.0.4",
  "description": "The screen-level entry into an order: a search icon, a two-line destination prompt and the service image, in one full-width row. A locked configuration of customButton — the base stays open, this preset fixes the height, the fill, the typography and both side slots. Figma: [DestinationButton] — component set 30339:368, variants State=Standard 30333:357 and State=Skeleton 30339:349 — on the branch ruoGXrpbw0vbfgl8bdfPcj, not yet in the main file. componentKeys are NOT captured (KNOWN GAP): a branch set is unpublished, so it has no stable library key until the branch merges and the library publishes.",
  "files": {
    "spec": "specs/components/destination-button/destination-button.md",
    "a11y": "specs/components/destination-button/destination-button-a11y.md",
    "preview": "src/destination-button.njk",
    "css": "src/shared/shared.css"
  },
  "figma": {
    "library": "Oymyakon 3.29.1 — components"
  },
  "root": {
    "class": "destination-button",
    "dataDsComponent": "destination-button"
  },
  "anatomy": {
    "startSlot": {
      "class": "destination-button__start-slot",
      "notes": "var(--sp-s64) x var(--sp-s56) swap slot — a modified-size IconContainer: the BOX is stretched to the slot while the glyph keeps its var(--sp-s32) box, centred on both axes. The row declares no padding — the slot centres in the var(--sp-s64) row, and the 4 of air above and below is centring arithmetic (64 − 56), not an inset."
    },
    "startText": {
      "class": "destination-button__start-text",
      "notes": "The two rows in a column, var(--sp-s2) gap, centred. min-width: 0, so the rows truncate instead of pushing a side slot out of the row."
    },
    "titleRow": {
      "class": "destination-button__title-row",
      "notes": "Heading 2. Single line, truncates."
    },
    "subtitleRow": {
      "class": "destination-button__subtitle-row",
      "optional": true,
      "notes": "Compact Body in var(--text-and-icon-secondary). On by default. Single line, truncates."
    },
    "endSlot": {
      "class": "destination-button__end-slot",
      "notes": "var(--sp-s64) x var(--sp-s56) swap slot. The 3D service image fills the box and is mirrored with scaleX(-1) in every variation — the mirror belongs to the artwork (the Figma illustration container ships its RTL toggle on), the asset file is never edited."
    }
  },
  "axes": {
    "subtitle": {
      "title": "Subtitle row",
      "type": "boolean",
      "default": true,
      "customizable": "Presence of the second text row. No modifier class — the row is either in the markup or it is not."
    },
    "startSlotContent": {
      "title": "Start slot content",
      "type": "enum",
      "values": [
        "search-icon"
      ],
      "default": "search-icon",
      "customizable": "Any DS icon may be swapped in. The slot is a modified-size IconContainer: the BOX is var(--sp-s64) x var(--sp-s56) while the glyph keeps its var(--sp-s32) box. A glyph on the icon-container.md § 3.5 directional list must opt INTO the RTL mirror at the instance — the default `search` is not directional, so the glyph ships no mirror of its own."
    },
    "endSlotContent": {
      "title": "End slot content",
      "type": "enum",
      "values": [
        "service-image"
      ],
      "default": "service-image",
      "customizable": "Any DS illustration or image may be swapped in; the slot box stays var(--sp-s64) x var(--sp-s56) and the content fills it, mirrored with scaleX(-1) like the default service image."
    },
    "titleText": {
      "title": "Title",
      "type": "text",
      "default": "Where to?",
      "customizable": "A question about the destination. A verb belongs to Button."
    },
    "subtitleText": {
      "title": "Subtitle",
      "type": "text",
      "default": "And for how much?",
      "customizable": "Any string; it is part of the accessible name, so it carries meaning rather than decoration."
    }
  },
  "states": {
    "default": [
      "standard",
      "pressed",
      "skeleton"
    ]
  },
  "constraints": [
    "One size: height var(--sp-s64), width 100% of the container. There is no size ladder and no hug form.",
    "No Style axis — the fill is always var(--surface-on-white).",
    "No Disabled state. The Figma set's State axis carries Standard | Skeleton only; a screen that cannot start an order shows the Skeleton, not a dimmed row.",
    "One instance per screen. A second row of the same weight leaves nothing to say which prompt the screen is for.",
    "The root is the only tap target. Neither text row nor either side slot may become interactive.",
    "Both text rows are single-line and truncate; the row's height never grows with content.",
    "The row declares no padding on any side. Both side slots are var(--sp-s56) tall and centre in the var(--sp-s64) row; nothing extends past the row's bounds.",
    "The end-slot illustration is mirrored with scaleX(-1) in every variation; the mirror belongs to the artwork and does not flip again under dir=\"rtl\".",
    "Skeleton drops the content and hands the whole shape to the Skeleton component; the row never draws a placeholder of its own.",
    "Title is Heading 2, subtitle is Compact Body. Neither row carries another text style.",
    "Only transform animates. Press is var(--component-push-button-press), release var(--component-push-button-release); reduced motion is zeroed at the token, never overridden here."
  ],
  "analytics": {
    "dataDsComponent": "destination-button",
    "action": "tap",
    "notes": "The root is the only target — the start glyph and the service image are decorative and are not separately trackable. No value is emitted. data-ds-preset is omitted deliberately: one size and one style mean there is no preset axis to report. The Skeleton state carries data-ds-state=\"skeleton\" and no data-ds-action."
  },
  "rtl": {
    "supported": true,
    "notes": "The row mirrors from the document's dir — the flex row reverses on its own and the row is symmetric (it declares no padding), so no class is needed. Nothing flips in place: the default search glyph is not on the icon-container.md § 3.5 directional list, and the end-slot illustration keeps the scaleX(-1) it ships with in every variation — that mirror belongs to the artwork, not to the direction. In Figma the mirrored composition is a variant of the set (RTL: Off | On)."
  }
}
```
