# Store CTA (Moonarc)

The call to get the app: a panel of the app's colour block with the headline, the store buttons and, on a wide screen, a QR code to the app, and a phone rising out of the panel's lower edge as the panel comes into view, its lower third cut by the panel. The rise is a view timeline; where there is none, or with reduced motion, the phone stands where the rise ends. The store buttons invert on the panel, the block's text as their ground. Zero JavaScript.

- Pro block. Install: `npx shadcn@latest add @moonarc-pro/store-cta` (license key required)
- Tier B · category section · trigger scroll
- Readout: `<StoreCta stores={[{ href, name, note }]} screen={{ title, rows }} />`
- Browser support: widely (Chrome 105 · Firefox 110 · Safari 16); elsewhere: without view timelines the phone stands still where the rise ends
- Measured cost: 0 B JS of its own · uses Reveal + runtime (with dependencies 3.0 kB raw; CSS 29.7 kB raw)
- Page: https://moonarc.dev/components/store-cta/

## Props

| Prop | Type | Default | Description |
|---|---|---|---|
| `stores` | `{ href: string; name: string; note?: string }[]` | none | The stores as text buttons. Slot "actions" replaces them and the QR code. |
| `screen` | `AppScreen props` | none | The screen in the phone; a label names it for a screen reader. |
| `qr` | `{ value: string; caption?: string; label?: string }` | none | A QR code to the app, on a wide screen with a pointer. |
| `headline` | `string` | none | The heading. Slot "headline" wins and may hold an <em>. |
| `eyebrow` | `string` | none | A short line above the heading. |
| `copy` | `string` | none | A line under the heading. |
| `note` | `string` | none | A short line under the buttons. |
| `block` | `1 | 2 | 3 | 4 | 5` | `1` | The panel's colour block. |
| `model` | `'island' | 'notch' | 'punch'` | `'island'` | The phone's cut-out. |
| `level` | `2 | 3` | `2` | Heading level of the heading. |
| `tone` | `'surface' | 'muted' | 'ink' | 'brand'` | `unset (paints nothing)` | The ground around the panel. |
| `density` | `'compact' | 'cozy' | 'roomy'` | `'cozy'` | Block padding ×0.8 / ×1 / ×1.25 through --ma-density. |

## Usage

```astro
---
import StoreCta from '@/components/moonarc/pro/StoreCta.astro';
---
<StoreCta
  copy="Free for three habits. Every habit for $3.99 a month."
  stores={[
    { href: 'https://apps.apple.com/app/id000000000', note: 'Download on the', name: 'App Store' },
    { href: 'https://play.google.com/store/apps/details?id=com.example', note: 'Get it on', name: 'Google Play' },
  ]}
  qr={{ value: 'https://example.com/get', caption: 'Scan to get the app' }}
  screen={{ title: 'Today', label: 'The today screen', rows: [{ kind: 'ring', value: 0.75, text: '3 of 4', label: 'done' }] }}
>
  <span slot="headline">Start <em>tomorrow</em> morning</span>
</StoreCta>
```

## Reduced motion

The phone stands still where the rise ends.

## With ClientRouter

CSS and Reveal.

## Craft

- The phone is cut by the panel (overflow: clip on the panel), so it reads as standing behind the panel's edge, and the rise is a translate on the panel's own view timeline: it arrives as the reader arrives, and goes back down if they scroll back.
- On a wide screen the phone stands at the panel's end and the panel is at least as tall as the phone's visible part, so a short headline never lets the phone run out of the top.
- The store buttons are the block's text on the block's ground, inverted: the pair the palette already holds at 4.5 : 1.

## Replaces

- App download banners with store badges and a phone mockup

## Source

Pro block. The source is served by the license-gated registry: `npx shadcn@latest add @moonarc-pro/store-cta` with a key in components.json (https://moonarc.dev/account/). Everything it composes is free: phone-frame, app-screen, reveal.
