# Rolling label

A button whose word turns over on hover — the current label swinging away
as the next arrives, on the same wheel mechanic as a card deck, at a
different scale.

## Three copies in one cell

```jsx
<span className="roll">
  {[0, 1, 2].map((c) => (
    <span key={c} style={{ '--c': c }} aria-hidden={c > 0}>{text}</span>
  ))}
</span>
```

```css
.roll { display: grid; place-items: center; }
.roll > span {
  grid-area: 1 / 1;
  transform-origin: 50% 4200%;
  transform: rotate(calc(var(--c) * -20deg));
  transition: transform .55s cubic-bezier(.22,.61,.36,1);
}
button:hover .roll > span { transform: rotate(calc((var(--c) - 1) * -20deg)); }
```

All three share one grid cell, so the button is sized by the word and not
by three of them. The button needs `overflow: hidden` — the spare copies
travel sideways out of it, and without the crop they simply sit beside the
word.

**Three copies, not two.** With two, the word that leaves and the word that
arrives are the same element, so it has to jump back and the roll stutters
on a fast re-hover.

## The number that does not transfer

The origin distance is the one value you cannot copy from another
implementation. It is a *percentage of the label's own height*, so the same
figure produces a different travel at a different type size.

Work it from the travel you need: one 20-degree step must carry a copy
clear of the button's width.

```
travel ≈ originDistance × sin(20°)
originDistance = labelHeight × (percentage / 100)
```

A 10px word in a 66px-wide pill needs roughly 4200%. Lift 1720% from a
design with an 18px word in a 130px pill and the spare copies land *inside*
your button — the label reads as doubled text.

## Prompt

> Build a rolling label for buttons. Render the word three times inside one
> CSS grid cell, each copy rotated a further -20 degrees about an origin far
> below it, and on hover rotate the whole set one step so the next copy
> arrives upright. Mark copies after the first `aria-hidden`. The button
> crops the overflow. Choose the origin distance so that one step carries a
> copy clear of the button's width — it is a percentage of the label height,
> so it must be recalculated for the type size rather than copied.
