A marquee is content that repeats without end: the customers on a logo wall, the rates on a
ticker, the payments settling in a column beside a dashboard. It is the one component here whose
purpose is motion, and it says so in its props: the axis to travel along, the direction, the
speed, the distance between items, and whether the loop runs at all.

What makes it a component rather than a `div` with an animation is the seam. The children are
rendered twice and the track travels by half its own length, so the loop returns to content rather
than to empty space; the second copy is hidden from assistive technology, so the content is read
once.

```tsx demo="data-display/marquee-preview"
```

## Usage

```tsx
import { Marquee } from "@asheeui/web";

<Marquee speed="slow" gap="3rem" pauseOnHover fadeEdges>
  {customers.map((customer) => (
    <Typography key={customer} role="heading-sm" as="span">
      {customer}
    </Typography>
  ))}
</Marquee>
```

`children` is an array, and it is the array that is repeated, so the list a page passes is the
list a reader sees, drawn twice rather than generated once. Each child needs its own `key` for the
same reason any list does.

`axis` is `x`, the registered value, or `y` for a column; a vertical marquee has no width to claim
and states `h-full`, so the frame it sits in supplies the height. `direction` is `forward`, the
registered one, which moves from right to left on the horizontal axis and from bottom to top on
the vertical, or `reverse`.

`gap` is a CSS length, registered as `1.5rem`, and it is applied both between the items of one
copy and between the two copies, so the loop's seam is spaced like everything else.

## Speed, and what the reader can read

`speed` is a preset, `slow` at 50 seconds a cycle, `normal` at 30, `fast` at 15, or a number of
seconds for one cycle, which is the same scale stated exactly. `normal` is the registered value.

```tsx demo="data-display/marquee-speed"
```

Speed is the one prop worth thinking about in seconds rather than in tokens, because the duration
is fixed and the distance is not: a cycle covers one copy of the content, so the same preset moves
faster when the copy is wide, a wall of long customer names, and more gently when it is short. A
ticker of short strings reads at `fast`, and a logo wall reads at `slow`, because a reader has to
recognise a word they were not expecting.

`pauseOnHover`, registered `false`, stops the track while a pointer rests on it *or while
anything inside it has keyboard focus*, so a reader who cannot use a pointer can still stop the
loop, the class covers `group-hover` and `group-focus-within`, so it needs no state and no
rerender. A marquee whose content holds nothing focusable therefore has only the reduced-motion
opt-out below. `fadeEdges`, registered `false`, paints a gradient over each end so the content
dissolves into the background instead of being cut off at the frame's edge.

## Motion a reader can decline

Two things stop the loop: the `isAnimated` prop, registered `true`, and the document's
`prefers-reduced-motion` preference. The component reads the preference through
`usePrefersReducedMotion` and renders the content once, at rest, when either says stop.

```tsx demo="data-display/marquee-still"
```

A stopped marquee is a different layout rather than a paused one: one copy is drawn in a frame
that scrolls along the axis and wraps on the cross axis, so nothing is clipped and nothing is
duplicated. That is also why the duplicate is `inert` while the track moves, a link inside a
moving marquee is one tab stop, announced once. The demo's own switch shows the difference between
the moving and the resting form.

## Props

```props Marquee
```

Every option is registered, so a product's marquee is stated once under `components.marquee`:
`axis` `x`, `direction` `forward`, `speed` `normal`, `gap` `1.5rem`, `pauseOnHover` `false`,
`fadeEdges` `false` and `isAnimated` `true`. There is no colour, size or radius to resolve, because
a marquee draws no surface of its own, what it draws is the consumer's nodes, in a consumer's
frame.

`children`, `itemClassName`, `className` and `style` are instance-only. What moves and how it is
dressed in one place is a statement about that place; how fast and which way is a statement about
the product.

## Accessibility

- The content is drawn twice for the seam, and the second copy is `aria-hidden`, so a reader hears
  each item once rather than twice in a row.
- The loop yields to `prefers-reduced-motion: reduce` and to `isAnimated`, so a reader who has
  asked their system for less motion gets a still frame without the page having to know.
- `pauseOnHover` is a pointer's gesture. There is no control in the page that stops the loop, so a
  keyboard or touch reader cannot pause it, and a screen that has to offer that states its own
  control over `isAnimated`, the demo in the previous section is the smallest version of it.
- `aria-hidden` hides a subtree from assistive technology without removing it from the tab order,
  so a link or button inside a marquee is a tab stop in both copies. A marquee is for content that
  is read, not pressed.

## Native

`@asheeui/native` renders a `Marquee` with the same props, driving an animated scroll view rather
than a stylesheet keyframe. It yields to the platform's own motion setting the way the web yields
to the media query, `pauseOnHover` has nothing to pause on because a touch screen has no pointer,
and `fadeEdges` is not painted: a gradient needs a drawing library the package does not depend on,
so the option resolves and changes nothing. `gap` is converted from a CSS length, `rem` at 16
units, `px` at one, and falls back to 24 when it names a unit the platform cannot state. See
[React Native](/platforms/native).

## Related

```related hero, card, testimonials
```
