MotirBuilding in public
MOTIR · moooon
onMotir
You’re viewing a public project. Anyone can view it — no account needed. Sign in to submit, upvote, or comment on requests.View-only — you can’t edit work items
MOTIR-2335

The own-box PADDING / HEIGHT axis of the shape swap — decide the density scale, then route the 447 escapes onto it

To Do
Description

Repo: motir-core. Carved out of MOTIR-2306 by THE REPLAN ACTION on 2026-08-07, which had bundled this axis with the RADIUS axis and sized both from a one-directory sample. The radius axis stays on MOTIR-2306 (62 sites, an exact token mapping, ~1h); this one is a different animal and this story is its home.

Why it is a story and not a card

CLAUDE.md's shape rule covers three things: a surface's own radius, its own padding, and its own height. Radius routes mechanically — every raw radius has exactly one semantic role and the substitution is value-preserving. Padding and height do not, and the measurement is the reason.

Scanning every tracked components/**, app/**, lib/** and packages/design-system/src/** source for a string literal that names a radius utility AND a raw own-box p*-N / h-N (measured on origin/main @ 7ffa2ba4, comments stripped):

literals carrying a raw own-box value447 in 190 files
of those, on a non-circular (token-radius) surface273 padding · 135 height, in 174 files
on a rounded-full surface (a dot, a switch, an avatar)1 padding · 52 height

That is not a sweep a single card can hold, and gate 4 (≤ 1h of agent run per coding_agent card) forbids pretending otherwise. It needs its own subtask set, planned once the decision below lands.

The blocker underneath it — the tokens cannot receive the sweep yet

The instruction "route each raw value to the element-semantic token CLAUDE.md maps its surface to" is unsatisfiable today, because each surface role has exactly ONE padding value and the code uses a scale. Measured, per radius role, on origin/main:

rolethe token sayswhat the code actually uses
--radius-card--spacing-card-padding: 24px12px ×61 · 16px ×18 · 14px ×12 · 8px ×19 · 10px ×9 · 4px ×7 · 20px ×4 · 24px ×5 · 32/40/56px ×9
--radius-control--spacing-control-x: 10px / -y: 6px2px ×23 · 4px ×21 · 6px ×17 · 8px ×27 · 10px ×11 · 12px ×11 · 16px ×4
--radius-control (height)--height-control: 36px12px ×12 · 16px ×13 · 28px ×16 · 36px ×8 · 8/10/14/20/24/26/32/48px ×30
--radius-badge--spacing-chip-x: 10px / -y: 2px1px ×8 · 2px ×12 · 6px ×14 · 8px ×3 · 4/10/12px ×3
--radius-btn--spacing-btn-x: 18px / -y: 10px (sm 12/8)2px ×6 · 12px ×15 · 24px ×5 · 10px ×1
--radius-input--spacing-input-x: 16px / -y: 12px2px ×2 · 8px ×3 · 10px ×3 · 12px ×2 · 16px ×3 · 28/32px ×4

Five of 145 card-padded surfaces are actually at the card token's 24px. Routing the other 140 to it would re-pad the entire application — a redesign nobody asked for, shipped as a "token substitution". The honest reading is that the padding/height vocabulary is INCOMPLETE: there is no token for an inner panel's 12px, for a dense list row's 4px, or for a 28px compact control, so components reached for the raw value because there was nothing to reach for.

So the first subtask is a DECISION about the token set, and the sweep can only be planned after it.

Acceptance criteria (story level — expand into subtasks after the decision lands)

  • The density-scale decision is recorded (its own subtask, below) and CLAUDE.md's padding-by-surface and sizing-by-surface tables name every token the sweep will route to.
  • Every own-box padding / height escape in components/**, app/** and packages/design-system/src/** names a token from that scale, or sits in shapeSwapLint's allowlist with the reason it is legitimate.
  • tests/theme/shapeSwapLint.test.ts — created by MOTIR-2306 with the radius check — carries a SECOND check for the own-box axis, in the same exactly-asserted-allowlist shape, and its comment states the own-box ↔ layout distinction it applies.
  • The default style renders unchanged where the migration was value-preserving, and every value that DID change is named in the PR body with the reason.

Context refs

  • MOTIR-2306 — the radius axis + the guard file this story extends. This story is blocked_by it.
  • motir-core/CLAUDE.md — "Shape (radius + spacing + sizing) flows through element-semantic shape tokens", the padding-by-surface and sizing-by-surface tables the decision amends.
  • packages/design-system/theme.css:198-223 — the @theme padding / height tokens as they stand; :360+ — the ten [data-style] blocks that must carry every new token or it will not flip.
  • tests/theme/swapLayerLint.test.ts — the colour-axis guard whose exact-allowlist discipline both checks mirror.
Status
To Do
Type
Story