> ## 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/squircle.html
> Source: specs/components/squircle/squircle.md, specs/components/squircle/squircle-a11y.md, specs/components/squircle/capabilities.json

---

# Squircle · Oymyakon DS 3

> The superellipse container — an avatar, category icon, or text badge inside composite
> components.

**Version:** 3.4.2 · **Status:** Draft · **Figma:** `[Squircle] 3.4` (page `3375:4028`, wrapper `3508:30471`)

---

## 1. Description

Squircle is a fixed square container shaped as a superellipse (Figma corner smoothing 60% — iOS
draws continuous corners natively; the web approximates with the plain corner radius, a recorded
platform deviation). It hosts one piece of content — an icon, a short text, or an image — and
never stretches: every size is a locked square.

The Figma line ships the `[Squircle] 3.4` wrapper with one `Size` instance-swap over six sets:

| Set | Contract |
|---|---|
| `Mini-Squircle` · `XS-Squircle` · `S-Squircle` · `M-Squircle` · `L-Squircle` | `Type` (Icon \| Text \| Img — Mini: Illu) × `State` (Default \| Inverse \| Color \| Disabled \| Skeleton) + a `Border` boolean (off) |
| `Custom-Squircle` | `State` (Default \| Skeleton) + `Border` boolean (**on**); every colour and layout value is unlocked |

On the web the family is one root class: `.squircle` is the Default state on the Custom geometry
(= the M box), sizes and states are modifiers, and the three `--squircle-*` custom properties are
the colour contract. Interactivity is not this component's job — the tappable form is the
separate `[SquircleButton] 3.0` line (not in the DS yet).

---

## 2. Anatomy

```
Squircle (.squircle)                fixed square · per-size radius · overflow hidden
├── slotContainer (.squircle__slot)   fills the box, centres the content
│     ├── icon        an IconContainer glyph (Type=Icon)
│     ├── text        a short string — initials, ID (Type=Text)
│     └── img         an avatar / picture, object-fit cover (Type=Img; Mini: an illustration)
└── Border (.squircle--border)        inset 1dp stroke — off by default
```

| Part | Required | Description |
|---|---|---|
| **container** | Required | The fixed square; clips content to the radius (`overflow: hidden`) |
| **slotContainer** | Required | Fills the box, centres whatever it hosts |
| **Border** | Off | A 1dp inside stroke (`.squircle--border`); the Custom-Squircle set alone defaults it on |

The root passes its content colour via `currentColor`; the label and glyph never declare their
own.

### RTL layout

Symmetric container — the shape, radius, and centred content do not change with direction.
Directional glyphs inside (arrow, chevron) mirror per the icon's own RTL variant; nothing else
flips.

---

## 3. Variants and sizes

| Axis | Values | Default | Web mechanism |
|---|---|---|---|
| **Size** | `mini` · `xs` · `s` · `m` · `l` | — (the wrapper's swap defaults to S) | `.squircle--{size}`; the bare `.squircle` is the Custom geometry (M box) |
| **Type** | `icon` · `text` · `img` | `icon` | The slot's content; `.squircle--text` adds the Text part's own padding, `.squircle--img` drops the fill (the picture is the surface). On Mini the image form is an illustration (`Illu`). The Figma Img slot default is the `indrive-money-color` illustration — captured at `illu/placeholder/indrive-money-color.png` |
| **State** | `standard` · `inverse` · `color` · `disabled` · `skeleton` | `standard` | `.squircle` is Standard (Figma: `Default`); others are `.squircle--{state}` |
| **Border** | off · on | **off** (Custom: on) | `.squircle--border` |
| **Fill / Content / Border colour** | any DS semantic token | see § 6 | `--squircle-fill` / `--squircle-content` / `--squircle-border`, re-pointed on a Custom instance |

Per-size geometry:

| Size | Box | Radius | Icon glyph | Text style | Text padding (ver / hor) |
|---|---|---|---|---|---|
| **Mini** | `var(--sp-s24)` (max ×150%) | `var(--sp-s8)` (max ×150%) | 16 | Body/Compact Body | `s4` / `s2` |
| **XS** | `var(--sp-s32)` (max ×150%) | `var(--sp-s12)` (max ×150%) | 16 | Body/Compact Body | `s4` / `s2` |
| **S** | `var(--sp-s40)` (max ×130%) | `var(--sp-s16)` (max ×130%) | 24 | Body/Main Body | `s4` / `s2` |
| **M** | `var(--sp-s48)` (max ×130%) | `var(--sp-s16)` (max ×130%) | 24 | Body/Promo Body | `s4` / `s2` |
| **L** | `var(--sp-s56)` | `var(--sp-s20)` | 24 | Heading/Heading 2 | `s4` / `s4` |

Values carry the Figma spec's own coefficient notation: `(max ×150%)` / `(max ×130%)` grows with
the SP mode up to that cap; a value with no coefficient — L's box and radius, the `s1` border,
the text paddings — never scales.

---

## 4. States

Squircle is non-interactive — **Standard** is the only rest form; States are design-time styles.

| State | Purpose |
|---|---|
| **Standard** | The rest form — the neutral container, the base (Figma names it `Default`) |
| **Inverse** | Dark pill on light, light on dark — for inverse surfaces. Icon/Text only by contract (the spec offers Img three states: Standard, Disabled, Skeleton; the set's Img/Inverse variant renders identically to Standard) |
| **Color** | A pastel + accent pairing (blue is the staged default; any same-group `--pastel-*` + `--accent-*` pair is allowed). Icon/Text only by contract, like Inverse |
| **Disabled** | Visual only: dimmed content, same fill; an image desaturates (luminosity blend) and dims to 0.3. Web trap: `mix-blend-mode` blends against the backdrop within the nearest stacking context — a transformed/opacity/z-indexed ancestor isolates it and the desaturation silently disappears |
| **Skeleton** | Loading placeholder: fill swaps, content hides, the DS shimmer sweeps |

---

## 5. Animation and behavior

Squircle itself is static — it declares no motion tokens and plays nothing of its own.

| Event | Token | Notes |
|---|---|---|
| Skeleton sweep | `var(--pattern-shimmer)` | The DS shimmer: `var(--skeleton-wave)` over the skeleton fill |
| Press, enter/exit | — | Belong to the host (Cell, DecorateContainer) or to the future SquircleButton — never to the container |

Reduced motion is handled at the token: `motion.css` zeroes `--pattern-shimmer` inside
`prefers-reduced-motion: reduce`; the component carries no override.

---

## 6. Color tokens

The three `--squircle-*` custom properties are the whole colour contract:

| State | `--squircle-fill` | `--squircle-content` | `--squircle-border` |
|---|---|---|---|
| **Standard** (Figma: Default) | `var(--surface-on-white)` | `var(--text-and-icon-primary)` | `var(--border-default)` |
| **Inverse** | `var(--background-inverse-primary)` | `var(--text-and-icon-inverse-primary)` | `var(--border-default)` |
| **Color** | `var(--pastel-blue1)` | `var(--accent-blue1)` | `var(--border-default)` |
| **Disabled** | `var(--surface-on-white)` | `var(--text-and-icon-disabled)` | `var(--border-default)` |
| **Skeleton** | `var(--skeleton-on-white)` | — (content hidden) | — |
| **Img type** | transparent — the picture is the surface | — | `var(--border-default)` |

- The border token is consumed only while `.squircle--border` is present.
- **Color state rule:** any `--pastel-*` fill with the matching `--accent-*` content from the
  same colour group.
- **Custom-Squircle** unlocks all three (its Figma default fill is `var(--background-secondary)`
  with the border on); on the web a Custom instance re-points the custom properties inline.
  The spec's staged geometry example: `var(--sp-s12)` paddings · `var(--sp-s28)` radius ·
  `var(--sp-s2)` border.

---

## 7. Typography

The text form wears the size's own style — fixed per size, never chosen per instance:

| Size | Style | Tokens |
|---|---|---|
| Mini / XS | Body/Compact Body | `var(--text-body-compact-body-*)` — set together |
| S | Body/Main Body | `var(--text-body-main-body-*)` |
| M | Body/Promo Body | `var(--text-body-promo-body-*)` |
| L | Heading/Heading 2 | `var(--text-heading-heading2-*)` — PP Agrandir, per the H2 role |

Single line, one to two characters by design (initials, an ID); the colour is `currentColor`
from `--squircle-content`. The Text part carries its own padding — `var(--sp-s4)` vertical /
`var(--sp-s2)` horizontal on every size except L, which pads `var(--sp-s4)` all round
(`.squircle--text` on the web).

---

## 8. Spacing

| Property | Token | Value @100% | Notes |
|---|---|---|---|
| Box (per size) | `var(--sp-s24/s32/s40/s48/s56)` | 24–56 | Fixed squares — width never hugs; Mini/XS (max ×150%), S/M (max ×130%), L uncoefficented (never scales) |
| Radius (per size) | `var(--sp-s8/s12/s16/s16/s20)` | 8–20 | Same coefficients as the box; plain radius on the web, 60%-smoothed in Figma/iOS |
| Container padding | `var(--sp-s0)` | 0 | The slot fills the box; content centres |
| Text padding | `var(--sp-s4)` / `var(--sp-s2)` | 4 / 2 | The Text part's own, ver/hor; L pads `var(--sp-s4)` all round. No coefficient — does not scale |
| Icon glyph | — | 16 (Mini/XS) / 24 (S/M/L) | The SVG size inside the slot |
| Img inner box | `var(--sp-s0)` | 0 | The picture's own paddings and corner radius — both open to any SP value per design; a fill may back a transparent picture |
| Border | — | 1dp | The Figma spec names it `s1`, no coefficient (never scales); the web SP scale has no `s1` token yet, so the build draws 1dp inside — owner call: add `s1` to the scale or keep the exception |

---

## 9. Usage context

### When to use Squircle

- A driver avatar or category image in a Cell start slot.
- A category or info icon on cards and lists.
- Initials or an ID as a text badge.
- The host tile of a DecorateContainer composition.

### When not to use Squircle

- As a tappable control — that is the `[SquircleButton] 3.0` line (not in the DS yet); a
  prototype that must tap one today wraps it in its own `<button>`.
- For a status count or dot — that is an Indicator.
- For a text label in a flow of content — that is a Tag.
- As a Custom-Squircle whose visuals deviate only slightly from a preset (a touch more radius or
  padding) — the spec prohibits it; take the ready preset.

### Related components

| Component | Relation |
|---|---|
| IconContainer | The glyph primitive the Icon type hosts |
| Cell | The most common host (start/end slots) |
| DecorateContainer | Wraps a Squircle to seat Indicator/Tag decorations |
| Floating Button | Opens from a Squircle form (its own component) |

---

## 10. Accessibility

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

- A meaning-bearing Squircle (an avatar, a category icon) takes `role="img"` + `aria-label` on
  the root; the inner glyph or picture is `aria-hidden="true"` / carries an empty `alt`.
- Decorative or redundant with the host's name (inside a Cell): `aria-hidden="true"` on the
  root — the Cell speaks.
- A text Squircle whose string is the meaning (initials) reads as plain text — no role needed.
- Disabled is a visual style on a non-interactive element: no `aria-disabled`.
- Skeleton: `aria-hidden="true"`; the loading container carries `aria-busy="true"`.
- No touch target: non-interactive. The tappable form is SquircleButton's contract.

---

## 11. Analytics and coverage contract

Reference: the `prototype-analytics` skill.

| Field | Value |
|---|---|
| `data-ds-component` | `squircle` |
| Coverage unit | Yes when standalone or a meaningful visible child; no when purely decorative inside another component |
| Tap target | None — non-interactive. A prototype that wraps one in its own `<button>` puts `data-ds-action` on that button |
| Root actions | none |

Attribute model: `data-ds-preset` = the size (`mini`…`l`, or `custom`), `data-ds-variant` = the
type (`icon` \| `text` \| `img`), `data-ds-state` = the State value (`standard` for Figma's `Default`, per spec-conventions).

```html
<div
  class="squircle squircle--m"
  data-ds-component="squircle"
  data-ds-component-id="profile.category"
  data-ds-preset="m"
  data-ds-variant="icon"
  data-ds-state="standard"
  role="img" aria-label="Delivery category">
  <span class="squircle__slot" aria-hidden="true"><!-- icon --></span>
</div>
```

A Custom instance re-points the custom properties and marks the preset:

```html
<div class="squircle squircle--border" data-ds-component="squircle" data-ds-preset="custom"
     style="--squircle-fill: var(--background-secondary);">
  <span class="squircle__slot" aria-hidden="true"><!-- content --></span>
</div>
```

When Squircle sits inside a Cell, the Cell owns tap analytics; the Squircle never defines
`data-ds-action`.

---

## Changelog

| Version | Date | Change |
|---|---|---|
| 3.4.2 | 2026-09-22 | Accessibility deep-audit (owner ask). Contrast table corrected to the measured reality: the Color state's Day pair (`--accent-blue1` on `--pastel-blue1`) measures ≈ 2.5:1 — under the 3:1 non-text floor and the 4.5:1 text floor — so Color is decorative in Day and a Text Squircle does not use it there (a DS-wide pastel/accent fact, flagged to the owner); the Night `--pastel-blue1` is a 28 % alpha overlay, so Night contrast is verified per placement. The Disabled dim named as the only perceivable signal of the state in all three platform sections, with the §4 stacking-context trap cross-referenced from the Web section. The Skeleton / Img contrast row split to match the three-state Img contract. Page: the two skeleton specimens that lacked the documented `aria-busy` container pattern now carry it; Color-in-Day and the Disabled-dim points added to the Accessibility section. |
| 3.4.1 | 2026-09-21 | The Img type documented across every State the Figma set carries: Standard/Inverse/Color render identically on Img (the picture is the surface — nothing to invert or tint), Skeleton replaces the box. Disabled Img corrected (owner catch): the picture carries the LUMINOSITY layer blend AND opacity 0.3 in every size set — the 3.4.0 row's "luminosity blend dropped" claim was a mis-read of the paint-level blend; the layer-level blend was there all along, and `mix-blend-mode: luminosity` is restored. The Figma Specification frame ingested (owner catch): per-size values now carry the spec's coefficient notation; the Text part's own padding restored (`s4`/`s2`, L `s4`/`s4` — `.squircle--text`); border named `s1` (no web token yet — flagged); Img contract = Standard/Disabled/Skeleton; the Custom staged example (`s12`/`s28`/`s2`) and the no-near-preset-customs prohibition recorded. The Figma Img slot default — the `indrive-money-color` illustration — captured to `illu/placeholder/indrive-money-color.png` and used as the web demo placeholder; a dedicated Img-across-states block added to the page. |
| 3.4.0 | 2026-09-17 | Aligned to Figma `[Squircle] 3.4` (version joins the Figma line; was an independent 2.0.0). **Border off by default** — `squircle--border` opt-in inset 1dp (only Custom-Squircle defaults it on in Figma); the always-on `1px solid` dropped from every state. `squircle--surface` retired — the base `.squircle` is the Default state via the new `--squircle-fill/content/border` custom properties. Per-size text styles now set in CSS (Mini/XS Compact Body · S Main Body · M Promo Body · L Heading 2); S icon glyph corrected 20 → 24. Disabled Img treatment aligned to Figma: plain `opacity: 0.3`, the luminosity blend dropped; `pointer-events: none` dropped (non-interactive by contract). Skeleton gains the DS shimmer sweep (`--pattern-shimmer`). Superellipse recorded as a platform deviation (Figma smoothing 60% ≈ iOS continuous corners; web = plain radius). Per-size scaling gradient documented (Mini/XS ×150 · S/M ×130 · L fixed). Analytics attrs moved to the Figma-axis model (preset=size, variant=type, state=State); interactivity re-pointed at the coming `[SquircleButton] 3.0`. |
| 2.0.0 | 2026-06-03 | **Breaking:** size scale synced to Figma 3.22.0. Containers Mini s24 / XS s28→**s32** / S s32→**s40** / M s40→**s48** / L s56. Radii XS s10→**s12** / M s12→**s16**. Icon sizes Mini s12→**s16** / L s28→**s24**. Text styles updated per size (Mini/XS CompactBody, S MainBody, M PromoBody, L Heading2). Added per-size locked border-radius and padding (s4 ver / s2 hor). Added `.squircle--xs` / `.squircle--mini` CSS. |
| 1.2.0 | 2026-04-30 | Added RTL section: symmetric container, no RTL impact on shape. IconContainer rtl:false by default; rtl:true only for directional icons. |
| 1.1.0 | 2026-04-29 | Added prototype analytics and DS coverage contract. |
| 1.0.0 | 2026-04-28 | Initial version. Sizes Mini/XS/S/M/L, configs Icon/Text/Img, styles Surface/Inverse/Color/Disabled/Skeleton, Custom Squircle. CSS implementation. |

---

# Squircle — Accessibility

Static container: the core accessibility question is what the content **means**. A Squircle that
carries meaning (an avatar, a category icon) is an image with a name; one that repeats what its
host already says is invisible; a text Squircle whose string is the meaning reads as plain text.
The container itself is never a control — the tappable form is the separate
`[SquircleButton] 3.0` line.

Label rule: describe the meaning, never the look — ✅ "Delivery category", ❌ "Grey square with
a box icon".

## Android · TalkBack

| Element | Label | Value | Trait | Hint |
|---|---|---|---|---|
| Squircle (meaning-bearing: avatar, category) | `contentDescription` with the meaning | — | Image | — |
| Squircle (decorative / redundant with the host) | — | — | Not important for accessibility (`importantForAccessibility="no"`) | — |
| Squircle (text form, string is the meaning) | The text, read in content order | — | — | — |
| Inner glyph / picture | — | — | Never its own element — the root speaks | — |

- Inside a focusable Cell the Cell takes the focus and the name; the Squircle joins the Cell's
  description or is excluded when redundant.
- A prototype that makes one tappable wraps it in its own button — the button then carries the
  action name and the 48dp target; the container contract stays untouched.

### Edge states

- **Disabled:** a visual style, not a state — **no** `disabled` semantics: the container owns no
  interaction to disable. The dimmed content (and the 0.3 image) changes no announcement — the
  visual dim is the only signal that the state differs.
- **Skeleton:** not announced (`importantForAccessibility="no"` — an empty box); the loading
  container carries the busy semantics.
- **Color / Inverse / Border:** purely visual — no announcement change.
- **RTL:** the symmetric container does not mirror; directional glyphs inside mirror per the
  icon's own RTL variant. Announcements unchanged.
- **Reduced motion:** the skeleton sweep zeroes at the token; nothing else moves.

---

## iOS · VoiceOver

| Element | Label | Value | Trait | Hint |
|---|---|---|---|---|
| Squircle (meaning-bearing) | `accessibilityLabel` with the meaning | — | Image | — |
| Squircle (decorative / redundant) | — | — | Excluded (`isAccessibilityElement = false`) | — |
| Squircle (text form) | The text, read in content order | — | Static text | — |
| Inner glyph / picture | — | — | Never its own element | — |

- Inside a Cell: the Cell is the accessibility element; the Squircle contributes to its label or
  is excluded.
- The tappable form is `DsSquircleButton`'s contract (the `[SquircleButton] 3.0` line), not this
  container's.

### Edge states

- **Dimmed / disabled:** not applicable — no interaction to disable; the dimmed look changes no
  announcement and adds no trait — the dim is the only signal that the state differs.
- **Skeleton:** excluded from the accessibility tree; the loading container reports busy.
- **Color / Inverse / Border / RTL / Reduced motion:** visual and motion only — announcements
  unchanged.

---

## Web preview (reference)

The preview page and prototypes mark the container up so the same contract holds:

- **Meaning-bearing** (avatar, category icon):

  ```html
  <div class="squircle squircle--m" role="img" aria-label="Delivery category">
    <span class="squircle__slot" aria-hidden="true"><!-- icon or img --></span>
  </div>
  ```

  The inner glyph is `aria-hidden="true"`; an `<img>` inside carries an empty `alt` — the root's
  label is the one name.
- **Decorative or redundant with the host** (inside a labelled Cell): `aria-hidden="true"` on the
  root; the Cell speaks.
- **Text form** whose string is the meaning (initials, an ID): plain text, no role, no label —
  it reads in content order.
- **Disabled:** no `aria-disabled` — announcing "disabled" on a static container promises
  something to enable, which is false. With no semantic signal, the luminosity + 0.3 dim is the
  **only** channel that makes the state perceivable — and a transformed / opacity / z-indexed
  ancestor silently kills the blend (the stacking-context trap, `squircle.md` §4); verify the dim
  actually renders in the real host.
- **Skeleton:** `aria-hidden="true"` on the box; the loading **container** carries
  `aria-busy="true"`:

  ```html
  <div aria-busy="true">
    <div class="squircle squircle--m squircle--skeleton" aria-hidden="true"></div>
  </div>
  ```

- **Never focusable:** no `tabindex`, no role beyond `img` where earned. A prototype's ad-hoc
  tappable Squircle is a real `<button>` wrapping the container, named for the **action**
  ("Open driver profile", not "Avatar"), with the 44×44 minimum target padded out at the small
  sizes — and that pattern graduates to SquircleButton when the component ships.
- **Reduced motion:** handled at the token — `motion.css` zeroes `--pattern-shimmer` inside
  `prefers-reduced-motion: reduce`; the component ships no override.

### Colour and contrast

| Pairing | Tokens | Requirement |
|---|---|---|
| Icon on the Default fill | `--text-and-icon-primary` on `--surface-on-white` | ≥ 3:1 (non-text UI) |
| Icon on the Inverse fill | `--text-and-icon-inverse-primary` on `--background-inverse-primary` | ≥ 3:1 |
| Icon on the Color fill | `--accent-blue1` on `--pastel-blue1` (any same-group pastel + accent pair) | ≥ 3:1 — the blue pair **measures ≈ 2.5:1 in the Day theme** (≈ 6.9:1 in Night over the reference canvas), so a meaning-bearing icon on the Color fill does not meet non-text contrast in Day; keep Color decorative, or carry the meaning in the label and the host — a DS-wide pastel/accent fact, flagged to the owner |
| Text on any fill | The size's text style on the state fill | 4.5:1 (text) — 3:1 for L's 24px Heading 2. The Color fill's Day pair (≈ 2.5:1) meets neither, so a Text Squircle does not use the Color state in Day (see the Color row) |
| Disabled content | `--text-and-icon-disabled` | None — dimmed, non-interactive |
| Skeleton | — | None — an empty box |
| Img type | — | None — the picture is the content; Disabled dims it via luminosity + 0.3 opacity, a decorative effect with no contrast requirement |

In the Night theme `--pastel-blue1` resolves to a 28 % alpha overlay
(`--p-transparent-blue-700-28`), not a solid tint — the Color pairing's rendered contrast there
depends on the backdrop, so it is verified per placement, not from the token pair alone.

A Custom instance re-pointing `--squircle-fill` / `--squircle-content` carries the same duty for
its new pairing. Never rely on the fill alone to convey meaning — the label (or the host's name)
carries it.

---

## Machine contract — `specs/components/squircle/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": "squircle",
  "name": "Squircle",
  "version": "3.4.2",
  "description": "The superellipse container — an avatar, category icon, or text badge. Five locked square sizes, three content types, five design-time states; non-interactive (the tappable form is the separate SquircleButton line).",
  "files": {
    "spec": "specs/components/squircle/squircle.md",
    "a11y": "specs/components/squircle/squircle-a11y.md",
    "preview": "src/squircle.njk",
    "css": "src/shared/shared.css"
  },
  "figma": {
    "library": "🕹️ Oymyakon 3.30.1 (components)",
    "fileKey": "7vdl5YkZFDWvh9QvSmydsH",
    "componentSets": {
      "[Squircle] 3.4": {
        "key": "5d6eb767f307b0745df9b5bf486023fca336f904",
        "note": "The wrapper component (node 3508:30471): one INSTANCE_SWAP prop `Size` choosing a size set; its default is S / Icon / Default."
      },
      "Mini-Squircle": {
        "key": "becf17cb1896f5a3813bd2341c238fe033b73cef",
        "note": "node 12922:7437 — the image type is an illustration (Type=Illu)."
      },
      "XS-Squircle": {
        "key": "5693825bdd01e9be5bca9b252b9c61d46f8c99a9",
        "note": "node 12922:7246."
      },
      "S-Squircle": {
        "key": "c75dc201f26140579e74447245a740274aa52b80",
        "note": "node 3375:9932 — the wrapper's Size swap default."
      },
      "M-Squircle": {
        "key": "f4f4de7a658716ef295caf5e02bb5120e1d18cb2",
        "note": "node 3375:9982."
      },
      "L-Squircle": {
        "key": "aa5c96a39f49b105f36143ed8e68bfa80ca64e0c",
        "note": "node 3375:10032."
      },
      "Custom-Squircle": {
        "key": "5aafef610736cb8cb97f9e02ecd8b37ebd24f10c",
        "note": "node 3508:30446 — State (Default | Skeleton) + Border (default ON); every colour and layout value unlocked."
      }
    },
    "capturedAt": "2026-09-17"
  },
  "root": {
    "class": "squircle",
    "dataDsComponent": "squircle"
  },
  "anatomy": {
    "slot": {
      "class": "squircle__slot",
      "notes": "Fills the box and centres the content: an IconContainer glyph, a short text, or an object-fit-cover image."
    }
  },
  "axes": {
    "size": {
      "title": "Size",
      "type": "enum",
      "values": [
        "mini",
        "xs",
        "s",
        "m",
        "l"
      ],
      "default": "s",
      "css": {
        "modifierTemplate": ".squircle--{value}",
        "mechanism": "the bare .squircle is the Custom geometry (the M box); each size locks box + radius + the size's own text style"
      },
      "figma": {
        "kind": "component-set",
        "values": {
          "mini": "Mini-Squircle",
          "xs": "XS-Squircle",
          "s": "S-Squircle",
          "m": "M-Squircle",
          "l": "L-Squircle"
        },
        "notes": "The wrapper's `Size` INSTANCE_SWAP picks the set; its default is S."
      },
      "notes": "The wrapper's `Size` INSTANCE_SWAP picks the set; its default is S. Spec coefficient notation: Mini/XS values (max ×150%), S/M (max ×130%), L uncoefficented — never scales."
    },
    "type": {
      "title": "Type",
      "type": "enum",
      "values": [
        "icon",
        "text",
        "img"
      ],
      "default": "icon",
      "css": {
        "modifier": ".squircle--img",
        "mechanism": "the slot's content is the type; .squircle--text adds the Text part's own padding (s4/s2, L: s4/s4), .squircle--img drops the fill (the picture is the surface). On Mini the image form is an illustration (Figma Type=Illu)."
      },
      "figma": {
        "kind": "variant-property",
        "property": "Type",
        "notes": "The Img slot's Figma default is the indrive-money-color illustration (captured at illu/placeholder/indrive-money-color.png)."
      }
    },
    "state": {
      "title": "State",
      "type": "enum",
      "values": [
        "standard",
        "inverse",
        "color",
        "disabled",
        "skeleton"
      ],
      "default": "standard",
      "css": {
        "modifierTemplate": ".squircle--{value}",
        "mechanism": "standard is the bare .squircle; each modifier re-points the --squircle-* custom properties. On the Img type the fill never shows, so Inverse/Color render identically to Standard."
      },
      "figma": {
        "kind": "variant-property",
        "property": "State",
        "values": {
          "standard": "Default"
        },
        "notes": "Figma names the rest state Default; the DS names it Standard (spec-conventions)."
      }
    },
    "border": {
      "title": "Border",
      "type": "boolean",
      "default": false,
      "css": {
        "modifier": ".squircle--border"
      },
      "figma": {
        "kind": "variant-property",
        "property": "Border",
        "notes": "A boolean component property; off on every size set, ON by default on Custom-Squircle alone. An inset 1dp stroke — no layout shift."
      }
    },
    "fill": {
      "title": "Fill (Custom / Color)",
      "type": "token",
      "customizable": "any DS semantic colour token; the Color state takes any --pastel-* with the matching --accent-* content",
      "default": "--surface-on-white",
      "tokens": [
        "--surface-on-white",
        "--background-inverse-primary",
        "--pastel-blue1",
        "--skeleton-on-white",
        "--background-secondary"
      ],
      "css": {
        "customProperty": "--squircle-fill"
      },
      "figma": {
        "kind": "none",
        "notes": "Custom-Squircle unlocks the fill (its Figma default is Background/Secondary); on the sized sets the Color state's pastel is an instance-level choice."
      }
    },
    "content": {
      "title": "Content colour",
      "type": "token",
      "customizable": "any DS semantic colour token; on the Color state, the --accent-* from the same group as the pastel fill",
      "default": "--text-and-icon-primary",
      "tokens": [
        "--text-and-icon-primary",
        "--text-and-icon-inverse-primary",
        "--accent-blue1",
        "--text-and-icon-disabled"
      ],
      "css": {
        "customProperty": "--squircle-content"
      },
      "figma": {
        "kind": "none",
        "notes": "Glyph and text take it via currentColor."
      }
    },
    "borderColor": {
      "title": "Border colour",
      "type": "token",
      "customizable": "any DS semantic colour token",
      "default": "--border-default",
      "tokens": [
        "--border-default"
      ],
      "css": {
        "customProperty": "--squircle-border"
      },
      "figma": {
        "kind": "none",
        "notes": "Consumed only while border=true."
      }
    }
  },
  "states": {
    "static": [
      "standard"
    ]
  },
  "constraints": [
    "Non-interactive: no press, hover, focus, or touch target — the host owns the tap, and the tappable form is the separate [SquircleButton] 3.0 line (not in the DS yet).",
    "Every size is a locked square — the box never hugs or stretches; the bare .squircle is the Custom geometry (the M box).",
    "The text style is the size's own (Mini/XS Compact Body · S Main Body · M Promo Body · L Heading 2) — never chosen per instance; single line, one-to-two characters; the Text part pads s4 ver / s2 hor (L: s4 all round) via .squircle--text.",
    "The documented Img contract is three states — Standard, Disabled, Skeleton; the set's Img Inverse/Color variants are technical and render identically to Standard (the picture is the surface). Disabled desaturates the picture through mix-blend-mode: luminosity AND dims it to opacity 0.3 (the Figma layer blend + opacity — image content has no token to re-point); Skeleton replaces the box.",
    "The Color state pairs any --pastel-* fill with the matching --accent-* content from the same colour group.",
    "The border is an inset stroke named s1 in the Figma spec, no coefficient — never moves the layout, never scales; the web SP scale has no s1 token yet, so the build draws 1dp (owner flag). Off by default (Custom-Squircle alone defaults it on).",
    "Scaling gradient per the Figma bindings: Mini/XS full ×150 · S/M cap ×130 · L fixed.",
    "The web corner is a plain radius — Figma draws 60%-smoothed superellipse corners and iOS uses continuous corners; a recorded platform deviation.",
    "No motion tokens are declared on the component; the skeleton sweep consumes the DS-wide --pattern-shimmer, and every other move belongs to the host.",
    "A Custom-Squircle whose visuals deviate only slightly from a preset is prohibited — take the ready preset (Figma spec, 'It is prohibited!')."
  ],
  "analytics": {
    "dataDsComponent": "squircle",
    "targets": [
      "none — non-interactive; a prototype's ad-hoc tappable Squircle is its own <button> wrapper carrying data-ds-action"
    ],
    "notes": "data-ds-preset = the size (mini…l, custom); data-ds-variant = the type (icon | text | img); data-ds-state = the State value — mirroring the Figma axes. Inside a Cell the Cell owns tap analytics."
  },
  "rtl": {
    "supported": true,
    "notes": "Symmetric container — the shape and centred content do not mirror; directional glyphs inside mirror per the icon's own RTL variant."
  }
}
```
