<!-- Source: https://motion.svelte.page/examples/armed-buttons -->

# Armed Buttons

> Production-style armed archive and delete wait button microinteractions built with Svelte Motion, AnimatePresence, and spring transitions.

**Source:** [https://motion.svelte.page/examples/armed-buttons](https://motion.svelte.page/examples/armed-buttons)

**Markdown mirror:** [https://motion.svelte.page/examples/armed-buttons.md](https://motion.svelte.page/examples/armed-buttons.md)

---

This mirror preserves the prose, implementation notes, and runnable Svelte source behind the live example page.

## FIG-001: archive armed button.

A quiet row action that becomes intentional on demand: hover exposes the archive icon, first click arms it, and `AnimatePresence` springs a compact confirm button into place. Arm another row to watch the previous one eject.

**Metadata:** tag: `ARMED` | wow: `icon blooms into confirm`

### Notes

- The WOW behavior is the small archive icon blooming into a labeled confirm button, keeping the row calm until the user shows intent. Archived rows flip the same slot into an armed unarchive action.
- `AnimatePresence` owns the confirm button mount and exit, while the row uses `whileHover` and spring transitions for tactile feedback.
- The armed state auto-disarms after a short timeout, so an abandoned destructive action never stays primed.

### Source

#### Archive.svelte

Source file: [src/lib/examples/armed-buttons/demos/Archive.svelte](https://github.com/humanspeak/svelte-motion/blob/main/docs/src/lib/examples/armed-buttons/demos/Archive.svelte)

```svelte
<script lang="ts">
    import { SvelteSet } from 'svelte/reactivity'
    import ArchiveArmedButton from '../ArchiveArmedButton.svelte'

    const rows = [
        { id: 'launch', title: 'Launch notes', eyebrow: 'Shared insight' },
        { id: 'pricing', title: 'Pricing objections', eyebrow: 'Saved thread' },
        { id: 'metrics', title: 'Retention metrics', eyebrow: 'Team highlight' }
    ]

    let armedId = $state<string | null>(null)
    const archivedIds = new SvelteSet<string>()

    const status = $derived(armedId ? `armed: ${armedId}` : 'idle')
    const archivedCount = $derived(archivedIds.size)

    $effect(() => {
        if (!armedId) return
        const timer = window.setTimeout(() => {
            armedId = null
        }, 4000)

        return () => window.clearTimeout(timer)
    })

    const toggleArchiveRow = (id: string) => {
        if (archivedIds.has(id)) {
            archivedIds.delete(id)
        } else {
            archivedIds.add(id)
        }
        armedId = null
    }
</script>

<!-- dk-strip: docs-kit positioning shell — stripped from the published code. -->
<div class="dk-demo-shell">
    <div class="strip">
        <div class="strip-head">
            <span class="micro">// archive queue</span>
            <span class="micro state">{status}</span>
        </div>

        <div class="stack">
            {#each rows as row (row.id)}
                <ArchiveArmedButton
                    id={row.id}
                    title={row.title}
                    eyebrow={row.eyebrow}
                    armed={armedId === row.id}
                    archived={archivedIds.has(row.id)}
                    onArm={() => (armedId = row.id)}
                    onDisarm={() => {
                        if (armedId === row.id) armedId = null
                    }}
                    onArchive={() => toggleArchiveRow(row.id)}
                />
            {/each}
        </div>

        <div class="strip-foot">
            <span class="micro">disarm: 4s / spring 520·32</span>
            <span class="micro">archived: {String(archivedCount).padStart(2, '0')} / 03</span>
        </div>
    </div>
</div>

<style>
    .dk-demo-shell {
        display: flex;
        min-height: 300px;
        align-items: center;
        justify-content: center;
        padding: 2rem;
    }

    .strip {
        display: flex;
        width: min(100%, 28rem);
        flex-direction: column;
        gap: 0.75rem;
    }

    .micro {
        font-family: var(--brut-mono, monospace);
        font-size: 0.6875rem;
        letter-spacing: 0.08em;
        text-transform: uppercase;
        color: var(--brut-ink-3, #9a9a9a);
    }

    .state {
        color: var(--brut-accent, #247768);
    }

    .strip-head,
    .strip-foot {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 1rem;
        border-bottom: 1px dashed var(--brut-rule-2, #bbc4c0);
        padding-bottom: 0.5rem;
    }

    .strip-foot {
        border-bottom: none;
        border-top: 1px dashed var(--brut-rule-2, #bbc4c0);
        padding-top: 0.75rem;
        padding-bottom: 0;
    }

    .stack {
        display: grid;
        gap: 0.75rem;

        --armed-danger: #b91c1c;
        --armed-danger-soft: rgba(185, 28, 28, 0.12);
    }

    :global(.dark) .stack {
        --armed-danger: #ef5350;
        --armed-danger-soft: rgba(239, 83, 80, 0.16);
    }
</style>
```

#### ArchiveArmedButton.svelte

Source file: [src/lib/examples/armed-buttons/ArchiveArmedButton.svelte](https://github.com/humanspeak/svelte-motion/blob/main/docs/src/lib/examples/armed-buttons/ArchiveArmedButton.svelte)

```svelte
<script lang="ts">
    import { AnimatePresence, motion, styleString } from '@humanspeak/svelte-motion'
    import { Archive, ArchiveRestore, FileText } from '@lucide/svelte'

    interface Props {
        id?: string
        title?: string
        eyebrow?: string
        armed?: boolean
        archived?: boolean
        timeoutMs?: number
        onArm?: () => void
        onDisarm?: () => void
        onArchive?: () => void
    }

    const {
        id = 'north-star',
        title = 'North star kickoff notes',
        eyebrow = 'Shared insight',
        armed: controlledArmed,
        archived: controlledArchived,
        timeoutMs = 4000,
        onArm,
        onDisarm,
        onArchive
    }: Props = $props()

    let armedId = $state<string | null>(null)
    let archivedState = $state(false)

    const isArmed = $derived(controlledArmed ?? armedId === id)
    const isArchived = $derived(controlledArchived ?? archivedState)
    let coverArchiveSlot = $state(false)

    $effect(() => {
        if (!isArmed) return
        const timer = window.setTimeout(() => {
            if (controlledArmed === undefined) {
                armedId = null
            } else {
                onDisarm?.()
            }
        }, timeoutMs)
        return () => window.clearTimeout(timer)
    })

    $effect(() => {
        if (isArmed) {
            coverArchiveSlot = true
            return
        }

        const timer = window.setTimeout(() => {
            coverArchiveSlot = false
        }, 160)
        return () => window.clearTimeout(timer)
    })

    const armArchive = () => {
        if (isArmed) {
            if (controlledArmed === undefined) {
                armedId = null
            } else {
                onDisarm?.()
            }
            return
        }
        if (controlledArmed === undefined) {
            armedId = id
        } else {
            onArm?.()
        }
    }

    const confirmArchive = () => {
        archivedState = !isArchived
        armedId = null
        onArchive?.()
    }
</script>

<motion.div
    class="armed-row"
    animate={isArchived ? { opacity: 0.55, x: 0 } : { opacity: 1, x: 0 }}
    whileHover={{ x: 2 }}
    transition={{ type: 'spring', stiffness: 520, damping: 32 }}
    style={styleString(() => ({
        position: 'relative',
        display: 'flex',
        width: '100%',
        maxWidth: '26rem',
        alignItems: 'center',
        gap: '0.75rem',
        border: '1px solid var(--brut-rule-2, #bbc4c0)',
        background: 'var(--brut-bg-2, #eef4f1)',
        padding: '0.75rem',
        boxShadow: '6px 6px 0 var(--brut-rule, #d6dedb)'
    }))}
    data-testid="archive-row"
    data-armed={isArmed}
    data-archived={isArchived}
>
    <div class="glyph">
        <FileText size={18} />
    </div>

    <div class="copy">
        <p class="eyebrow">{isArchived ? 'Archived' : eyebrow}</p>
        <p class="title">{title}</p>
    </div>

    <div class="slot">
        {#if coverArchiveSlot}
            <div class="cover" aria-hidden="true"></div>
        {/if}

        <motion.button
            type="button"
            aria-label={isArchived ? 'Unarchive insight' : 'Archive insight'}
            aria-hidden={coverArchiveSlot}
            tabindex={coverArchiveSlot ? -1 : 0}
            whileHover={{
                scale: 1.16,
                backgroundColor: 'var(--brut-accent-soft, rgba(36, 119, 104, 0.1))',
                color: 'var(--brut-ink, #0a0a0a)'
            }}
            whileTap={{ scale: 0.9 }}
            transition={{ type: 'spring', stiffness: 520, damping: 28 }}
            onclick={armArchive}
            data-testid="archive-arm"
            style={styleString(() => ({
                display: 'inline-flex',
                width: '2rem',
                height: '2rem',
                flex: 'none',
                alignItems: 'center',
                justifyContent: 'center',
                border: '1px solid transparent',
                background: 'transparent',
                color: 'var(--brut-ink-3, #9a9a9a)',
                cursor: 'pointer',
                opacity: coverArchiveSlot ? 0 : 1,
                pointerEvents: coverArchiveSlot ? 'none' : 'auto'
            }))}
        >
            {#if isArchived}
                <ArchiveRestore size={15} />
            {:else}
                <Archive size={15} />
            {/if}
        </motion.button>

        <AnimatePresence mode="popLayout">
            {#if isArmed}
                <motion.div
                    key="archive-confirm"
                    initial={{ opacity: 0, scale: 0.78, x: 10 }}
                    animate={{ opacity: 1, scale: 1, x: 0 }}
                    exit={{ opacity: 0, scale: 0.78, x: 10 }}
                    transition={{ duration: 0.12 }}
                    data-testid="archive-confirm-shell"
                    style={styleString(() => ({
                        position: 'absolute',
                        top: 0,
                        bottom: 0,
                        right: 0,
                        zIndex: 20,
                        display: 'flex',
                        alignItems: 'center',
                        justifyContent: 'flex-end'
                    }))}
                >
                    <motion.button
                        type="button"
                        onclick={confirmArchive}
                        data-testid="archive-confirm"
                        whileHover={{ opacity: 0.9 }}
                        whileTap={{ scale: 0.96 }}
                        transition={{ type: 'spring', stiffness: 520, damping: 28 }}
                        style={styleString(() => ({
                            position: 'relative',
                            display: 'inline-flex',
                            height: '2rem',
                            overflow: 'hidden',
                            alignItems: 'center',
                            justifyContent: 'center',
                            gap: '0.375rem',
                            border: '1px solid var(--brut-accent, #247768)',
                            background: 'var(--brut-accent, #247768)',
                            padding: '0 0.75rem',
                            fontFamily: 'var(--brut-mono, monospace)',
                            fontSize: '0.6875rem',
                            fontWeight: 700,
                            letterSpacing: '0.08em',
                            textTransform: 'uppercase',
                            whiteSpace: 'nowrap',
                            color: 'var(--brut-accent-ink, #f8fcfb)',
                            cursor: 'pointer'
                        }))}
                    >
                        <motion.span
                            key="archive-disarm-meter"
                            initial={{ scaleX: 1 }}
                            animate={{ scaleX: 0 }}
                            transition={{ duration: timeoutMs / 1000, ease: 'linear' }}
                            aria-hidden="true"
                            data-testid="archive-disarm-meter"
                            style={styleString(() => ({
                                position: 'absolute',
                                left: 0,
                                right: 0,
                                bottom: 0,
                                height: '2px',
                                transformOrigin: 'left',
                                background: 'var(--brut-accent-ink, #f8fcfb)',
                                opacity: 0.45,
                                pointerEvents: 'none'
                            }))}
                        />
                        {#if isArchived}
                            <ArchiveRestore size={13} />
                            Unarchive
                        {:else}
                            <Archive size={13} />
                            Archive
                        {/if}
                    </motion.button>
                </motion.div>
            {/if}
        </AnimatePresence>
    </div>
</motion.div>

<style>
    .glyph {
        display: grid;
        width: 2.5rem;
        height: 2.5rem;
        flex: none;
        place-items: center;
        border: 1px solid var(--brut-rule-2, #bbc4c0);
        background: var(--brut-accent-soft, rgba(36, 119, 104, 0.1));
        color: var(--brut-accent, #247768);
    }

    .copy {
        min-width: 0;
        flex: 1;
    }

    .eyebrow {
        margin: 0;
        font-family: var(--brut-mono, monospace);
        font-size: 0.625rem;
        font-weight: 700;
        letter-spacing: 0.16em;
        text-transform: uppercase;
        color: var(--brut-ink-3, #9a9a9a);
    }

    .title {
        margin: 0.125rem 0 0;
        overflow: hidden;
        font-size: 0.8125rem;
        font-weight: 600;
        text-overflow: ellipsis;
        white-space: nowrap;
        color: var(--brut-ink, #0a0a0a);
    }

    .slot {
        position: relative;
        display: flex;
        height: 2rem;
        width: 6rem;
        flex: none;
        align-items: center;
        justify-content: flex-end;
    }

    .cover {
        pointer-events: none;
        position: absolute;
        inset: 0 0 0 auto;
        z-index: 10;
        width: 6rem;
        background: var(--brut-bg-2, #eef4f1);
    }
</style>
```

## FIG-002: delete armed + wait.

Each delete row arms on first click, locks itself behind a visible countdown, then swaps into the final destructive confirm state without resizing the control. Arming a different row cancels the first countdown.

**Metadata:** tag: `WAIT` | wow: `safety timer without layout shift`

### Notes

- The WOW behavior is the row becoming its own safety mechanism: click once to arm, wait for the timer, then click again to confirm. Arming a second row cancels the first row's countdown.
- A keyed motion span swaps trash, spinner, and success states so each icon gets a crisp entrance instead of popping in place.
- Fixed height and reserved trailing space keep the button steady while countdown text changes.

### Source

#### DeleteWait.svelte

Source file: [src/lib/examples/armed-buttons/demos/DeleteWait.svelte](https://github.com/humanspeak/svelte-motion/blob/main/docs/src/lib/examples/armed-buttons/demos/DeleteWait.svelte)

```svelte
<script lang="ts">
    import { AnimatePresence, motion } from '@humanspeak/svelte-motion'
    import DeleteArmedWaitButton from '../DeleteArmedWaitButton.svelte'

    const rows = [
        { id: 'launch', title: 'Launch notes', eyebrow: 'Delete insight' },
        { id: 'pricing', title: 'Pricing objections', eyebrow: 'Delete thread' },
        { id: 'metrics', title: 'Retention metrics', eyebrow: 'Delete highlight' }
    ]

    let armedId = $state<string | null>(null)
    let removedIds = $state(new Set<string>())

    const visibleRows = $derived(rows.filter((row) => !removedIds.has(row.id)))
    const status = $derived(armedId ? `armed: ${armedId}` : 'idle')

    const removeAfterDeletedBeat = (id: string) => {
        window.setTimeout(() => {
            removedIds = new Set([...removedIds, id])
        }, 2000)
    }
</script>

<!-- dk-strip: docs-kit positioning shell — stripped from the published code. -->
<div class="dk-demo-shell">
    <div class="strip">
        <div class="strip-head">
            <span class="micro">// delete queue</span>
            <span class="micro state">{status}</span>
        </div>

        <div class="stack">
            <AnimatePresence mode="popLayout">
                {#each visibleRows as row (row.id)}
                    <motion.div
                        key={row.id}
                        layout
                        initial={{ opacity: 0, y: 12, scale: 0.98 }}
                        animate={{ opacity: 1, y: 0, scale: 1 }}
                        exit={{ opacity: 0, x: -28, scale: 0.96, filter: 'blur(3px)' }}
                        transition={{ type: 'spring', stiffness: 520, damping: 34 }}
                    >
                        <DeleteArmedWaitButton
                            title={row.title}
                            eyebrow={row.eyebrow}
                            armed={armedId === row.id}
                            onArm={() => (armedId = row.id)}
                            onDisarm={() => {
                                if (armedId === row.id) armedId = null
                            }}
                            onDelete={() => removeAfterDeletedBeat(row.id)}
                        />
                    </motion.div>
                {/each}
            </AnimatePresence>
        </div>

        <div class="strip-foot">
            <span class="micro">countdown: 3s / disarm 10s</span>
            <span class="micro">rows: {String(visibleRows.length).padStart(2, '0')} / 03</span>
        </div>
    </div>
</div>

<style>
    .dk-demo-shell {
        display: flex;
        min-height: 300px;
        align-items: center;
        justify-content: center;
        padding: 2rem;
    }

    .strip {
        display: flex;
        width: min(100%, 28rem);
        flex-direction: column;
        gap: 0.75rem;
    }

    .micro {
        font-family: var(--brut-mono, monospace);
        font-size: 0.6875rem;
        letter-spacing: 0.08em;
        text-transform: uppercase;
        color: var(--brut-ink-3, #9a9a9a);
    }

    .state {
        color: var(--brut-accent, #247768);
    }

    .strip-head,
    .strip-foot {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 1rem;
        border-bottom: 1px dashed var(--brut-rule-2, #bbc4c0);
        padding-bottom: 0.5rem;
    }

    .strip-foot {
        border-bottom: none;
        border-top: 1px dashed var(--brut-rule-2, #bbc4c0);
        padding-top: 0.75rem;
        padding-bottom: 0;
    }

    .stack {
        display: grid;
        gap: 0.75rem;

        --armed-danger: #b91c1c;
        --armed-danger-soft: rgba(185, 28, 28, 0.12);
    }

    :global(.dark) .stack {
        --armed-danger: #ef5350;
        --armed-danger-soft: rgba(239, 83, 80, 0.16);
    }
</style>
```

#### DeleteArmedWaitButton.svelte

Source file: [src/lib/examples/armed-buttons/DeleteArmedWaitButton.svelte](https://github.com/humanspeak/svelte-motion/blob/main/docs/src/lib/examples/armed-buttons/DeleteArmedWaitButton.svelte)

```svelte
<script lang="ts">
    import {
        motion,
        styleString,
        useAnimationFrame,
        useMotionValue,
        useSpring
    } from '@humanspeak/svelte-motion'
    import { Check, LoaderCircle, Trash2 } from '@lucide/svelte'

    interface Props {
        title?: string
        eyebrow?: string
        armed?: boolean
        countdownSeconds?: number
        disarmAfterMs?: number
        onArm?: () => void
        onDisarm?: () => void
        onDelete?: () => void
    }

    const {
        title = 'Delete workspace',
        eyebrow = 'Danger action',
        armed: controlledArmed,
        countdownSeconds = 3,
        disarmAfterMs = 10000,
        onArm,
        onDisarm,
        onDelete
    }: Props = $props()

    let armedState = $state(false)
    let secondsLeft = $state(0)
    let deleting = $state(false)
    let deleted = $state(false)

    const armed = $derived(controlledArmed ?? armedState)
    const locked = $derived((armed && secondsLeft > 0) || deleting)
    const disarmMeterSeconds = $derived(
        Math.max((disarmAfterMs - countdownSeconds * 1000) / 1000, 0.1)
    )
    const spinTarget = useMotionValue(0)
    const spinRotate = useSpring(spinTarget, { stiffness: 220, damping: 18, mass: 0.8 })

    let spinStartedAt: number | undefined
    let nextSpinAt = 0
    let spinTurns = 0

    // Motion-driven color state: idle / armed (danger) / deleted (accent).
    const rowColors = $derived(
        deleted
            ? {
                  backgroundColor: 'var(--brut-accent-soft, rgba(36, 119, 104, 0.1))',
                  borderColor: 'var(--brut-accent, #247768)',
                  color: 'var(--brut-accent, #247768)'
              }
            : armed
              ? {
                    backgroundColor: 'var(--armed-danger, #b91c1c)',
                    borderColor: 'var(--armed-danger, #b91c1c)',
                    color: 'var(--brut-accent-ink, #f8fcfb)'
                }
              : {
                    backgroundColor: 'var(--brut-bg-2, #eef4f1)',
                    borderColor: 'var(--brut-rule-2, #bbc4c0)',
                    color: 'var(--brut-ink, #0a0a0a)'
                }
    )

    useAnimationFrame((time) => {
        if (!locked) {
            spinStartedAt = undefined
            nextSpinAt = 0
            spinTurns = 0
            spinTarget.jump(0)
            return
        }

        spinStartedAt ??= time
        if (time < nextSpinAt) return

        spinTurns += 1
        spinTarget.set(spinTurns * 720)
        nextSpinAt = time + 1180
    })

    $effect(() => {
        if (!armed) return

        secondsLeft = countdownSeconds
        const ticker = window.setInterval(() => {
            secondsLeft = secondsLeft > 0 ? secondsLeft - 1 : 0
        }, 1000)
        const disarm = window.setTimeout(() => {
            if (!deleting && !deleted) {
                if (controlledArmed === undefined) {
                    armedState = false
                } else {
                    onDisarm?.()
                }
            }
        }, disarmAfterMs)

        return () => {
            window.clearInterval(ticker)
            window.clearTimeout(disarm)
        }
    })

    const handleClick = () => {
        if (deleted) return
        if (!armed) {
            if (controlledArmed === undefined) {
                armedState = true
            } else {
                onArm?.()
            }
            return
        }
        if (locked) return

        deleting = true
        window.setTimeout(() => {
            deleting = false
            deleted = true
            armedState = false
            onDisarm?.()
            onDelete?.()
        }, 520)
    }
</script>

<motion.div
    whileHover={armed || deleted ? undefined : { x: 2 }}
    transition={{ type: 'spring', stiffness: 520, damping: 32 }}
    style={styleString(() => ({
        width: '100%',
        maxWidth: '26rem'
    }))}
>
    <motion.button
        type="button"
        disabled={locked || deleted}
        onclick={handleClick}
        data-testid="delete-wait-button"
        data-armed={armed}
        data-locked={locked}
        data-deleted={deleted}
        animate={rowColors}
        whileHover={armed || deleted ? undefined : { backgroundColor: 'var(--brut-bg, #f8fcfb)' }}
        transition={{ type: 'spring', stiffness: 520, damping: 32 }}
        style={styleString(() => ({
            position: 'relative',
            display: 'flex',
            height: '3rem',
            width: '100%',
            overflow: 'hidden',
            alignItems: 'center',
            gap: '0.75rem',
            borderWidth: '1px',
            borderStyle: 'solid',
            padding: '0 1rem',
            fontSize: '0.8125rem',
            lineHeight: 1,
            fontWeight: 600,
            boxShadow: '6px 6px 0 var(--brut-rule, #d6dedb)',
            cursor: locked || deleted ? 'not-allowed' : 'pointer'
        }))}
    >
        {#if armed && !deleted && !deleting}
            <motion.span
                key={secondsLeft > 0 ? 'delete-disarm-meter-wait' : 'delete-disarm-meter-ready'}
                initial={{ scaleX: 1 }}
                animate={{ scaleX: secondsLeft > 0 ? 1 : 0 }}
                transition={{ duration: secondsLeft > 0 ? 0 : disarmMeterSeconds, ease: 'linear' }}
                aria-hidden="true"
                data-testid="delete-disarm-meter"
                style={styleString(() => ({
                    position: 'absolute',
                    left: 0,
                    right: 0,
                    bottom: 0,
                    height: '2px',
                    transformOrigin: 'left',
                    background: 'currentColor',
                    opacity: 0.45,
                    pointerEvents: 'none'
                }))}
            />
        {/if}

        {#key deleted ? 'done' : locked ? 'locked' : armed ? 'ready' : 'idle'}
            <motion.span
                initial={{ opacity: 0, scale: 0.6, rotate: locked ? -30 : 0 }}
                animate={{ opacity: 1, scale: locked ? [1, 1.12, 1] : 1 }}
                style={{
                    display: 'inline-flex',
                    width: '1.25rem',
                    height: '1.25rem',
                    flex: 'none',
                    alignItems: 'center',
                    justifyContent: 'center',
                    ...(!armed && !deleted ? { color: 'var(--armed-danger, #b91c1c)' } : {}),
                    ...(locked ? { rotate: spinRotate } : {})
                }}
                transition={{
                    type: locked ? 'tween' : 'spring',
                    duration: locked ? 0.42 : undefined,
                    ease: locked ? 'easeOut' : undefined,
                    stiffness: locked ? undefined : 520,
                    damping: locked ? undefined : 30
                }}
                data-testid="delete-icon-state"
            >
                {#if deleted}
                    <Check size={17} />
                {:else if locked}
                    <LoaderCircle size={17} />
                {:else}
                    <Trash2 size={17} />
                {/if}
            </motion.span>
        {/key}

        <span class="label">
            {#if deleted}
                Deleted
            {:else}
                <span class="eyebrow">{eyebrow}</span>
                <span class="title">{title}</span>
            {/if}
        </span>

        <span class="trail">
            {#if armed && secondsLeft > 0}
                {#key secondsLeft}
                    <motion.span
                        initial={{ y: -7, opacity: 0 }}
                        animate={{ y: 0, opacity: 1 }}
                        transition={{ type: 'spring', stiffness: 520, damping: 30 }}
                        data-testid="delete-countdown"
                        style={styleString(() => ({
                            display: 'inline-flex',
                            alignItems: 'center',
                            lineHeight: 1,
                            fontVariantNumeric: 'tabular-nums'
                        }))}
                    >
                        {secondsLeft}
                    </motion.span>
                {/key}
            {:else if armed && !deleted}
                <span class="ready" data-testid="delete-ready">Ready</span>
            {/if}
        </span>
    </motion.button>
</motion.div>

<style>
    .label {
        min-width: 0;
        flex: 1;
        text-align: left;
    }

    .eyebrow {
        display: block;
        font-family: var(--brut-mono, monospace);
        font-size: 0.625rem;
        line-height: 1.15;
        font-weight: 700;
        letter-spacing: 0.16em;
        text-transform: uppercase;
        opacity: 0.62;
    }

    .title {
        display: block;
        margin-top: 0.125rem;
        line-height: 1.25;
    }

    .trail {
        display: flex;
        width: 4rem;
        justify-content: flex-end;
    }

    .ready {
        position: relative;
        top: 1px;
        display: inline-flex;
        align-items: center;
        font-family: var(--brut-mono, monospace);
        font-size: 0.6875rem;
        line-height: 1;
        letter-spacing: 0.16em;
        text-transform: uppercase;
    }
</style>
```

## FIG-003: recording stage.

A merged shared-insight list for demos, posts, and short design videos: archive and delete live beside each other, with delete hiding archive while it is armed.

**Metadata:** tag: `VIDEO` | format: `video-ready`

### Notes

- The stage keeps the shared-insight row format while combining archive and delete into one stable action cluster.
- Archive arms in its own slot and leaves delete visible, so the safer secondary action never disappears during archive confirmation.
- Delete clears any armed archive state, hides the archive control, counts down, and then unlocks the final destructive click.

### Source

#### Default.svelte

Source file: [src/lib/examples/armed-buttons/demos/Default.svelte](https://github.com/humanspeak/svelte-motion/blob/main/docs/src/lib/examples/armed-buttons/demos/Default.svelte)

```svelte
<script lang="ts">
    import {
        AnimatePresence,
        motion,
        useAnimationFrame,
        useMotionValue,
        useSpring
    } from '@humanspeak/svelte-motion'
    import RecordingInsightRow from '../RecordingInsightRow.svelte'
    import { SvelteSet } from 'svelte/reactivity'

    const rows = [
        { id: 'launch', title: 'Launch notes', eyebrow: 'Shared insight' },
        { id: 'pricing', title: 'Pricing objections', eyebrow: 'Saved thread' },
        { id: 'metrics', title: 'Retention metrics', eyebrow: 'Team highlight' }
    ]

    const DELETE_COUNTDOWN_SECONDS = 3
    const ARCHIVE_DISARM_AFTER_MS = 4000
    const DELETE_DISARM_AFTER_MS = 10000

    let archiveArmedId = $state<string | null>(null)
    const archiveArchivedIds = new SvelteSet<string>()
    let deleteArmedId = $state<string | null>(null)
    let deleteSecondsLeft = $state(0)
    let deletingId = $state<string | null>(null)
    const deletedIds = new SvelteSet<string>()
    const removedIds = new SvelteSet<string>()
    const spinTarget = useMotionValue(0)
    const spinRotate = useSpring(spinTarget, { stiffness: 220, damping: 18, mass: 0.8 })

    let nextSpinAt = 0
    let spinTurns = 0

    const deleteLocked = $derived(
        Boolean(deleteArmedId && deleteSecondsLeft > 0) || Boolean(deletingId)
    )
    const visibleRows = $derived(rows.filter((row) => !removedIds.has(row.id)))

    const status = $derived(
        deletingId
            ? `deleting: ${deletingId}`
            : deleteArmedId
              ? `delete armed: ${deleteArmedId}`
              : archiveArmedId
                ? `archive armed: ${archiveArmedId}`
                : 'idle'
    )

    useAnimationFrame((time) => {
        if (!deleteLocked) {
            nextSpinAt = 0
            spinTurns = 0
            spinTarget.jump(0)
            return
        }

        if (time < nextSpinAt) return

        spinTurns += 1
        spinTarget.set(spinTurns * 720)
        nextSpinAt = time + 1180
    })

    $effect(() => {
        if (!deleteArmedId) return

        deleteSecondsLeft = DELETE_COUNTDOWN_SECONDS
        const ticker = window.setInterval(() => {
            deleteSecondsLeft = deleteSecondsLeft > 0 ? deleteSecondsLeft - 1 : 0
        }, 1000)
        const disarm = window.setTimeout(() => {
            if (!deletingId) deleteArmedId = null
        }, DELETE_DISARM_AFTER_MS)

        return () => {
            window.clearInterval(ticker)
            window.clearTimeout(disarm)
        }
    })

    $effect(() => {
        if (!archiveArmedId) return
        const timer = window.setTimeout(() => {
            archiveArmedId = null
        }, ARCHIVE_DISARM_AFTER_MS)

        return () => window.clearTimeout(timer)
    })

    const armArchive = (id: string) => {
        if (deletedIds.has(id) || deleteArmedId === id) return
        archiveArmedId = archiveArmedId === id ? null : id
    }

    const confirmArchive = (id: string) => {
        if (archiveArchivedIds.has(id)) {
            archiveArchivedIds.delete(id)
        } else {
            archiveArchivedIds.add(id)
        }
        archiveArmedId = null
    }

    const armDelete = (id: string) => {
        if (deletedIds.has(id) || archiveArchivedIds.has(id)) return
        if (deleteArmedId === id) {
            if (deleteSecondsLeft > 0 || deletingId) return

            deletingId = id
            window.setTimeout(() => {
                deletedIds.add(id)
                deletingId = null
                deleteArmedId = null
                window.setTimeout(() => {
                    removedIds.add(id)
                }, 2000)
            }, 520)
            return
        }

        archiveArmedId = null
        deleteArmedId = id
    }
</script>

<!-- dk-strip: docs-kit positioning shell — stripped from the published code. -->
<div class="dk-demo-shell">
    <div class="strip">
        <div class="strip-head">
            <span class="micro">// recording stage</span>
            <span class="micro state">{status}</span>
        </div>

        <div class="stage">
            <div class="stack">
                <AnimatePresence mode="popLayout">
                    {#each visibleRows as row (row.id)}
                        {@const archiveArmed = archiveArmedId === row.id}
                        {@const deleteArmed = deleteArmedId === row.id}
                        {@const deleting = deletingId === row.id}
                        {@const deleted = deletedIds.has(row.id)}
                        {@const archived = archiveArchivedIds.has(row.id)}
                        {@const locked = deleteArmed && deleteSecondsLeft > 0}
                        <motion.div
                            key={row.id}
                            layout
                            initial={{ opacity: 0, y: 12, scale: 0.98 }}
                            animate={{ opacity: 1, y: 0, scale: 1 }}
                            exit={{ opacity: 0, x: -28, scale: 0.96, filter: 'blur(3px)' }}
                            transition={{ type: 'spring', stiffness: 520, damping: 34 }}
                        >
                            <RecordingInsightRow
                                {row}
                                {archiveArmed}
                                {deleteArmed}
                                {deleting}
                                {deleted}
                                {archived}
                                {locked}
                                {deleteSecondsLeft}
                                archiveTimeoutMs={ARCHIVE_DISARM_AFTER_MS}
                                deleteDisarmAfterMs={DELETE_DISARM_AFTER_MS}
                                deleteCountdownSeconds={DELETE_COUNTDOWN_SECONDS}
                                {spinRotate}
                                onArmArchive={armArchive}
                                onConfirmArchive={confirmArchive}
                                onArmDelete={armDelete}
                            />
                        </motion.div>
                    {/each}
                </AnimatePresence>
            </div>
        </div>

        <div class="strip-foot">
            <span class="micro">mode: popLayout / spring 520·34</span>
            <span class="micro">rows: {String(visibleRows.length).padStart(2, '0')} / 03</span>
        </div>
    </div>
</div>

<style>
    .dk-demo-shell {
        display: flex;
        min-height: 360px;
        align-items: center;
        justify-content: center;
        padding: 2rem;
    }

    .strip {
        display: flex;
        width: min(100%, 32rem);
        flex-direction: column;
        gap: 0.75rem;
    }

    .micro {
        font-family: var(--brut-mono, monospace);
        font-size: 0.6875rem;
        letter-spacing: 0.08em;
        text-transform: uppercase;
        color: var(--brut-ink-3, #9a9a9a);
    }

    .state {
        color: var(--brut-accent, #247768);
    }

    .strip-head,
    .strip-foot {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 1rem;
        border-bottom: 1px dashed var(--brut-rule-2, #bbc4c0);
        padding-bottom: 0.5rem;
    }

    .strip-foot {
        border-bottom: none;
        border-top: 1px dashed var(--brut-rule-2, #bbc4c0);
        padding-top: 0.75rem;
        padding-bottom: 0;
    }

    .stage {
        border: 1px solid var(--brut-rule-2, #bbc4c0);
        background:
            linear-gradient(90deg, var(--brut-rule, #d6dedb) 1px, transparent 1px),
            linear-gradient(0deg, var(--brut-rule, #d6dedb) 1px, transparent 1px),
            var(--brut-bg-2, #eef4f1);
        background-size:
            54px 54px,
            54px 54px,
            auto;
        padding: 1.25rem;
    }

    .stack {
        display: grid;
        gap: 0.65rem;

        --armed-danger: #b91c1c;
        --armed-danger-soft: rgba(185, 28, 28, 0.12);
    }

    :global(.dark) .stack {
        --armed-danger: #ef5350;
        --armed-danger-soft: rgba(239, 83, 80, 0.16);
    }
</style>
```

#### RecordingInsightRow.svelte

Source file: [src/lib/examples/armed-buttons/RecordingInsightRow.svelte](https://github.com/humanspeak/svelte-motion/blob/main/docs/src/lib/examples/armed-buttons/RecordingInsightRow.svelte)

```svelte
<script lang="ts">
    import {
        AnimatePresence,
        motion,
        styleString,
        type SpringMotionValue
    } from '@humanspeak/svelte-motion'
    import { Archive, ArchiveRestore, Check, FileText, LoaderCircle, Trash2 } from '@lucide/svelte'

    interface InsightRow {
        id: string
        title: string
        eyebrow: string
    }

    interface Props {
        row: InsightRow
        archiveArmed: boolean
        deleteArmed: boolean
        deleting: boolean
        deleted: boolean
        archived: boolean
        locked: boolean
        deleteSecondsLeft: number
        archiveTimeoutMs?: number
        deleteDisarmAfterMs?: number
        deleteCountdownSeconds?: number
        spinRotate: SpringMotionValue<number>
        onArmArchive: (_id: string) => void
        onConfirmArchive: (_id: string) => void
        onArmDelete: (_id: string) => void
    }

    const {
        row,
        archiveArmed,
        deleteArmed,
        deleting,
        deleted,
        archived,
        locked,
        deleteSecondsLeft,
        archiveTimeoutMs = 4000,
        deleteDisarmAfterMs = 10000,
        deleteCountdownSeconds = 3,
        spinRotate,
        onArmArchive,
        onConfirmArchive,
        onArmDelete
    }: Props = $props()

    const deleteEyebrow = $derived(
        `Delete ${row.eyebrow.split(' ').at(-1)?.toLowerCase() ?? 'item'}`
    )
    const deleteActive = $derived(deleteArmed || deleting || deleted)
    const deleteMeterSeconds = $derived(
        Math.max((deleteDisarmAfterMs - deleteCountdownSeconds * 1000) / 1000, 0.1)
    )
    let coverArchiveSlot = $state(false)

    // Motion-driven color state for the armed/deleted delete row.
    const dangerRowColors = $derived(
        deleted
            ? {
                  backgroundColor: 'var(--brut-accent-soft, rgba(36, 119, 104, 0.1))',
                  borderColor: 'var(--brut-accent, #247768)',
                  color: 'var(--brut-accent, #247768)'
              }
            : {
                  backgroundColor: 'var(--armed-danger, #b91c1c)',
                  borderColor: 'var(--armed-danger, #b91c1c)',
                  color: 'var(--brut-accent-ink, #f8fcfb)'
              }
    )

    $effect(() => {
        if (archiveArmed) {
            coverArchiveSlot = true
            return
        }

        const timer = window.setTimeout(() => {
            coverArchiveSlot = false
        }, 160)
        return () => window.clearTimeout(timer)
    })
</script>

{#if deleteActive}
    <motion.button
        key="recording-delete-row"
        type="button"
        disabled={locked || deleting || deleted}
        initial={{ opacity: 0, x: 18, scale: 0.98 }}
        animate={{ opacity: 1, x: 0, scale: 1, ...dangerRowColors }}
        exit={{ opacity: 0, x: -18, scale: 0.98 }}
        transition={{ type: 'spring', stiffness: 520, damping: 34 }}
        onclick={() => onArmDelete(row.id)}
        data-testid="recording-armed-row"
        data-archive-armed={archiveArmed}
        data-delete-armed={deleteArmed}
        data-delete-row-active={deleteActive}
        style={styleString(() => ({
            position: 'relative',
            display: 'flex',
            height: '4rem',
            width: '100%',
            overflow: 'hidden',
            alignItems: 'center',
            gap: '0.75rem',
            borderWidth: '1px',
            borderStyle: 'solid',
            padding: '0 0.75rem',
            fontSize: '0.8125rem',
            lineHeight: 1,
            fontWeight: 600,
            boxShadow: '6px 6px 0 var(--brut-rule, #d6dedb)',
            cursor: locked || deleting || deleted ? 'not-allowed' : 'pointer'
        }))}
    >
        {#if deleteArmed && !deleted && !deleting}
            <motion.span
                key={locked
                    ? 'recording-delete-disarm-meter-wait'
                    : 'recording-delete-disarm-meter-ready'}
                initial={{ scaleX: 1 }}
                animate={{ scaleX: locked ? 1 : 0 }}
                transition={{ duration: locked ? 0 : deleteMeterSeconds, ease: 'linear' }}
                aria-hidden="true"
                data-testid="recording-delete-disarm-meter"
                style={styleString(() => ({
                    position: 'absolute',
                    left: 0,
                    right: 0,
                    bottom: 0,
                    height: '2px',
                    transformOrigin: 'left',
                    background: 'currentColor',
                    opacity: 0.45,
                    pointerEvents: 'none'
                }))}
            />
        {/if}

        {#key deleted ? 'done' : locked || deleting ? 'locked' : 'ready'}
            <motion.span
                initial={{ opacity: 0, scale: 0.6, rotate: locked || deleting ? -30 : 0 }}
                animate={{
                    opacity: 1,
                    scale: locked || deleting ? [1, 1.12, 1] : 1
                }}
                style={{
                    display: 'inline-flex',
                    width: '2.5rem',
                    height: '2.5rem',
                    flex: 'none',
                    alignItems: 'center',
                    justifyContent: 'center',
                    ...(!(locked || deleting) ? { background: 'rgba(255, 255, 255, 0.15)' } : {}),
                    ...(locked || deleting ? { rotate: spinRotate } : {})
                }}
                transition={{
                    type: locked || deleting ? 'tween' : 'spring',
                    duration: locked || deleting ? 0.42 : undefined,
                    ease: locked || deleting ? 'easeOut' : undefined,
                    stiffness: locked || deleting ? undefined : 520,
                    damping: locked || deleting ? undefined : 30
                }}
            >
                {#if deleted}
                    <Check size={18} />
                {:else if locked || deleting}
                    <LoaderCircle size={18} />
                {:else}
                    <Trash2 size={18} />
                {/if}
            </motion.span>
        {/key}

        <span class="label">
            {#if deleted}
                <span class="deleted-line">Deleted</span>
            {:else}
                <span class="eyebrow">{deleteEyebrow}</span>
                <span class="title">{row.title}</span>
            {/if}
        </span>

        <span class="trail">
            {#if locked}
                {#key deleteSecondsLeft}
                    <motion.span
                        initial={{ y: -7, opacity: 0 }}
                        animate={{ y: 0, opacity: 1 }}
                        transition={{ type: 'spring', stiffness: 520, damping: 30 }}
                        style={styleString(() => ({
                            display: 'inline-flex',
                            alignItems: 'center',
                            lineHeight: 1,
                            fontVariantNumeric: 'tabular-nums'
                        }))}
                    >
                        {deleteSecondsLeft}
                    </motion.span>
                {/key}
            {:else if deleteArmed && !deleted}
                <span class="ready">Ready</span>
            {/if}
        </span>
    </motion.button>
{:else}
    <motion.div
        key="recording-normal-row"
        animate={archived ? { opacity: 0.55, x: 0 } : { opacity: 1, x: 0 }}
        whileHover={{ x: 2 }}
        transition={{ type: 'spring', stiffness: 520, damping: 32 }}
        data-testid="recording-armed-row"
        data-archive-armed={archiveArmed}
        data-delete-armed={deleteArmed}
        data-delete-row-active={deleteActive}
        style={styleString(() => ({
            position: 'relative',
            display: 'flex',
            height: '4rem',
            width: '100%',
            alignItems: 'center',
            gap: '0.75rem',
            border: '1px solid var(--brut-rule-2, #bbc4c0)',
            background: 'var(--brut-bg-2, #eef4f1)',
            padding: '0.75rem',
            boxShadow: '6px 6px 0 var(--brut-rule, #d6dedb)'
        }))}
    >
        <div class="glyph">
            <FileText size={18} />
        </div>

        <div class="copy">
            <p class="eyebrow ink3">{archived ? 'Archived' : row.eyebrow}</p>
            <p class="title ink">{row.title}</p>
        </div>

        <div class="actions">
            <div class="archive-slot">
                {#if coverArchiveSlot}
                    <div class="cover" aria-hidden="true"></div>
                {/if}

                <motion.button
                    type="button"
                    aria-label={archived ? 'Unarchive insight' : 'Archive insight'}
                    aria-hidden={coverArchiveSlot}
                    tabindex={coverArchiveSlot ? -1 : 0}
                    whileHover={{
                        scale: 1.16,
                        backgroundColor: 'var(--brut-accent-soft, rgba(36, 119, 104, 0.1))',
                        color: 'var(--brut-ink, #0a0a0a)'
                    }}
                    whileTap={{ scale: 0.9 }}
                    transition={{ type: 'spring', stiffness: 520, damping: 28 }}
                    onclick={() => onArmArchive(row.id)}
                    style={styleString(() => ({
                        display: 'inline-flex',
                        width: '2rem',
                        height: '2rem',
                        flex: 'none',
                        alignItems: 'center',
                        justifyContent: 'center',
                        border: '1px solid transparent',
                        background: 'transparent',
                        color: 'var(--brut-ink-3, #9a9a9a)',
                        cursor: 'pointer',
                        opacity: coverArchiveSlot ? 0 : 1,
                        pointerEvents: coverArchiveSlot ? 'none' : 'auto'
                    }))}
                >
                    {#if archived}
                        <ArchiveRestore size={15} />
                    {:else}
                        <Archive size={15} />
                    {/if}
                </motion.button>

                <AnimatePresence mode="popLayout">
                    {#if archiveArmed}
                        <motion.div
                            key="recording-archive-confirm"
                            initial={{ opacity: 0, scale: 0.78, x: 10 }}
                            animate={{ opacity: 1, scale: 1, x: 0 }}
                            exit={{ opacity: 0, scale: 0.78, x: 10 }}
                            transition={{ duration: 0.12 }}
                            style={styleString(() => ({
                                position: 'absolute',
                                top: 0,
                                bottom: 0,
                                right: 0,
                                zIndex: 20,
                                display: 'flex',
                                alignItems: 'center',
                                justifyContent: 'flex-end'
                            }))}
                        >
                            <motion.button
                                type="button"
                                onclick={() => onConfirmArchive(row.id)}
                                whileHover={{ opacity: 0.9 }}
                                whileTap={{ scale: 0.96 }}
                                transition={{ type: 'spring', stiffness: 520, damping: 28 }}
                                style={styleString(() => ({
                                    position: 'relative',
                                    display: 'inline-flex',
                                    height: '2rem',
                                    overflow: 'hidden',
                                    alignItems: 'center',
                                    justifyContent: 'center',
                                    gap: '0.375rem',
                                    border: '1px solid var(--brut-accent, #247768)',
                                    background: 'var(--brut-accent, #247768)',
                                    padding: '0 0.75rem',
                                    fontFamily: 'var(--brut-mono, monospace)',
                                    fontSize: '0.6875rem',
                                    fontWeight: 700,
                                    letterSpacing: '0.08em',
                                    textTransform: 'uppercase',
                                    whiteSpace: 'nowrap',
                                    color: 'var(--brut-accent-ink, #f8fcfb)',
                                    cursor: 'pointer'
                                }))}
                            >
                                <motion.span
                                    key="recording-archive-disarm-meter"
                                    initial={{ scaleX: 1 }}
                                    animate={{ scaleX: 0 }}
                                    transition={{
                                        duration: archiveTimeoutMs / 1000,
                                        ease: 'linear'
                                    }}
                                    aria-hidden="true"
                                    data-testid="recording-archive-disarm-meter"
                                    style={styleString(() => ({
                                        position: 'absolute',
                                        left: 0,
                                        right: 0,
                                        bottom: 0,
                                        height: '2px',
                                        transformOrigin: 'left',
                                        background: 'var(--brut-accent-ink, #f8fcfb)',
                                        opacity: 0.45,
                                        pointerEvents: 'none'
                                    }))}
                                />
                                {#if archived}
                                    <ArchiveRestore size={13} />
                                    Unarchive
                                {:else}
                                    <Archive size={13} />
                                    Archive
                                {/if}
                            </motion.button>
                        </motion.div>
                    {/if}
                </AnimatePresence>
            </div>

            {#if !archived}
                <motion.button
                    type="button"
                    aria-label="Delete insight"
                    whileHover={{
                        scale: 1.16,
                        backgroundColor: 'var(--armed-danger-soft, rgba(185, 28, 28, 0.12))'
                    }}
                    whileTap={{ scale: 0.9 }}
                    transition={{ type: 'spring', stiffness: 520, damping: 28 }}
                    onclick={() => onArmDelete(row.id)}
                    style={styleString(() => ({
                        display: 'inline-flex',
                        width: '2rem',
                        height: '2rem',
                        flex: 'none',
                        alignItems: 'center',
                        justifyContent: 'center',
                        border: '1px solid transparent',
                        background: 'transparent',
                        color: 'var(--armed-danger, #b91c1c)',
                        cursor: 'pointer'
                    }))}
                >
                    <Trash2 size={15} />
                </motion.button>
            {/if}
        </div>
    </motion.div>
{/if}

<style>
    .glyph {
        display: grid;
        width: 2.5rem;
        height: 2.5rem;
        flex: none;
        place-items: center;
        border: 1px solid var(--brut-rule-2, #bbc4c0);
        background: var(--brut-accent-soft, rgba(36, 119, 104, 0.1));
        color: var(--brut-accent, #247768);
    }

    .copy {
        min-width: 0;
        flex: 1;
    }

    .label {
        min-width: 0;
        flex: 1;
        text-align: left;
    }

    .eyebrow {
        margin: 0;
        font-family: var(--brut-mono, monospace);
        font-size: 0.625rem;
        line-height: 1.25;
        font-weight: 700;
        letter-spacing: 0.16em;
        text-transform: uppercase;
    }

    .label .eyebrow {
        display: block;
        opacity: 0.62;
    }

    .eyebrow.ink3 {
        color: var(--brut-ink-3, #9a9a9a);
    }

    .title {
        margin: 0.125rem 0 0;
        overflow: hidden;
        font-size: 0.8125rem;
        font-weight: 600;
        line-height: 1.25;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .label .title {
        display: block;
    }

    .title.ink {
        color: var(--brut-ink, #0a0a0a);
    }

    .deleted-line {
        display: block;
        font-size: 0.8125rem;
        line-height: 1.25;
    }

    .trail {
        display: flex;
        width: 4rem;
        flex: none;
        justify-content: flex-end;
    }

    .ready {
        position: relative;
        top: 1px;
        display: inline-flex;
        align-items: center;
        font-family: var(--brut-mono, monospace);
        font-size: 0.6875rem;
        line-height: 1;
        letter-spacing: 0.16em;
        text-transform: uppercase;
    }

    .actions {
        display: flex;
        height: 2rem;
        flex: none;
        align-items: center;
        justify-content: flex-end;
        gap: 0.25rem;
    }

    .archive-slot {
        position: relative;
        display: flex;
        width: 2rem;
        height: 2rem;
        align-items: center;
        justify-content: flex-end;
    }

    .cover {
        pointer-events: none;
        position: absolute;
        inset: 0 0 0 auto;
        z-index: 10;
        width: 6.75rem;
        background: var(--brut-bg-2, #eef4f1);
    }
</style>
```
