{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "waitlist-referral-position",
  "title": "Waitlist — Referral Position",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/waitlist-referral-position/WaitlistReferralPosition.vue",
      "content": "<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\nimport { Check, Copy, Users } from 'lucide-vue-next'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card, CardContent } from '@/components/ui/card'\nimport { Input } from '@/components/ui/input'\nimport { Progress } from '@/components/ui/progress'\nimport { Separator } from '@/components/ui/separator'\n\nconst props = withDefaults(defineProps<{ position?: number; nextTierAt?: number }>(), {\n  position: 1_284,\n  nextTierAt: 1_000,\n})\n\nconst email = ref('')\nconst joined = ref(false)\nconst copied = ref(false)\nconst referralLink = 'https://northwind.dev/w/8f2a41'\n\n// How far from the current position to the next access tier, as a percentage.\nconst progress = computed(() => {\n  const span = props.position - props.nextTierAt\n  if (span <= 0) return 100\n  return Math.round(((props.position - span) / props.position) * 100)\n})\n\nfunction join() {\n  if (!email.value.trim()) return\n  joined.value = true\n}\n\nasync function copyLink() {\n  try {\n    await navigator.clipboard.writeText(referralLink)\n    copied.value = true\n    setTimeout(() => (copied.value = false), 1600)\n  } catch {\n    // Clipboard blocked: the link stays visible and selectable.\n  }\n}\n</script>\n\n<template>\n  <section data-slot=\"waitlist-referral-position\" class=\"bg-background\">\n    <div class=\"mx-auto max-w-xl px-6 py-20 text-center lg:py-28\">\n      <Badge variant=\"secondary\" class=\"gap-1.5\">\n        <Users class=\"size-3\" aria-hidden=\"true\" />\n        8,400 waiting\n      </Badge>\n\n      <h2 class=\"mt-5 text-3xl font-semibold tracking-tight text-balance sm:text-4xl\">\n        Early access opens a cohort at a time\n      </h2>\n      <p class=\"text-muted-foreground mt-3 text-lg\">\n        Join the list, then move up it. Every person who joins through your link moves you forward.\n      </p>\n\n      <!-- One card that swaps contents rather than two stacked states, so the\n           section height barely changes between before and after. -->\n      <Card class=\"mt-8 text-left\">\n        <CardContent class=\"p-6\">\n          <form v-if=\"!joined\" @submit.prevent=\"join\">\n            <label for=\"waitlist-email\" class=\"text-sm font-medium\">Work email</label>\n            <div class=\"mt-2 flex gap-2\">\n              <Input\n                id=\"waitlist-email\"\n                v-model=\"email\"\n                type=\"email\"\n                required\n                placeholder=\"you@company.com\"\n                autocomplete=\"email\"\n              />\n              <Button type=\"submit\" class=\"shrink-0\">Join</Button>\n            </div>\n            <p class=\"text-muted-foreground mt-2 text-xs\">\n              No product emails while you wait — one message when your cohort opens.\n            </p>\n          </form>\n\n          <div v-else aria-live=\"polite\">\n            <div class=\"flex items-baseline justify-between gap-4\">\n              <div>\n                <p class=\"text-muted-foreground text-xs tracking-wide uppercase\">Your position</p>\n                <p class=\"font-display mt-1 text-3xl font-bold tracking-tight\">#{{ position.toLocaleString() }}</p>\n              </div>\n              <p class=\"text-muted-foreground text-right text-xs\">\n                Next cohort opens<br />at #{{ nextTierAt.toLocaleString() }}\n              </p>\n            </div>\n\n            <Progress :model-value=\"progress\" class=\"mt-4 h-1.5\" aria-label=\"Progress to the next cohort\" />\n\n            <Separator class=\"my-5\" />\n\n            <p class=\"text-sm font-medium\">Move up the list</p>\n            <p class=\"text-muted-foreground mt-1 text-xs\">Each signup through your link moves you forward 12 places.</p>\n            <div class=\"border-border bg-muted/30 mt-3 flex items-stretch overflow-hidden rounded-md border\">\n              <code class=\"min-w-0 flex-1 truncate px-3 py-2 font-mono text-xs\">{{ referralLink }}</code>\n              <Button\n                variant=\"ghost\"\n                class=\"border-border h-auto shrink-0 rounded-none border-l px-3\"\n                aria-label=\"Copy referral link\"\n                @click=\"copyLink\"\n              >\n                <Check v-if=\"copied\" class=\"text-success size-4\" aria-hidden=\"true\" />\n                <Copy v-else class=\"size-4\" aria-hidden=\"true\" />\n              </Button>\n            </div>\n          </div>\n        </CardContent>\n      </Card>\n    </div>\n  </section>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/WaitlistReferralPosition.vue"
    }
  ],
  "dependencies": [
    "lucide-vue-next"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/vue/badge.json",
    "https://uipkge.dev/r/vue/button.json",
    "https://uipkge.dev/r/vue/card.json",
    "https://uipkge.dev/r/vue/input.json",
    "https://uipkge.dev/r/vue/progress.json",
    "https://uipkge.dev/r/vue/separator.json"
  ],
  "description": "Waitlist capture that swaps on submit to show queue position, the referral link that moves it, and a progress meter to the next tier of early access.",
  "categories": [
    "marketing"
  ]
}