{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "cta92",
  "title": "Tailored Subscription",
  "description": "A newsletter CTA that asks before it asks for an address: subjects, then cadence, then the email, and the column swaps itself for a confirmation that reads back exactly what was chosen.",
  "dependencies": [
    "clsx",
    "tailwind-merge",
    "lucide-react"
  ],
  "registryDependencies": [
    "questionnaire",
    "button"
  ],
  "files": [
    {
      "path": "registry/cta92/cta92.tsx",
      "content": "\"use client\";\n\nimport { Check, MailCheck } from \"lucide-react\";\nimport Link from \"next/link\";\nimport { type FormEvent, useState } from \"react\";\nimport { Badge6 } from \"@/components/beste/component/badge6\";\nimport { Button1 } from \"@/components/beste/component/button1\";\nimport {\n  Questionnaire,\n  QuestionnaireActions,\n  QuestionnaireChoice,\n  QuestionnaireChoiceDescription,\n  QuestionnaireChoices,\n  QuestionnaireDescription,\n  QuestionnaireError,\n  QuestionnaireInput,\n  QuestionnaireItem,\n  QuestionnaireNext,\n  QuestionnairePrevious,\n  QuestionnaireProgress,\n  QuestionnaireSubmit,\n  QuestionnaireTitle,\n} from \"@/components/ui/questionnaire\";\nimport { cn } from \"@/lib/utils\";\n\ninterface Badge {\n  label: string;\n}\n\ninterface ActionButton {\n  label: string;\n  href: string;\n}\n\ninterface CoverImage {\n  src: string;\n  alt: string;\n}\n\ninterface Option {\n  value: string;\n  label: string;\n  description?: string;\n}\n\ninterface Step {\n  title: string;\n  description?: string;\n}\n\ninterface EmailStep extends Step {\n  label: string;\n  placeholder?: string;\n}\n\ninterface PromiseItem {\n  title: string;\n  description: string;\n}\n\ninterface Cta92Labels {\n  previous?: string;\n  next?: string;\n  submit?: string;\n  restart?: string;\n  confirmationTitle?: string;\n  confirmationDescription?: string;\n  topicsSummary?: string;\n  cadenceSummary?: string;\n  emailSummary?: string;\n}\n\ninterface Cta92Props {\n  badge?: Badge;\n  /** Short line beside the eyebrow, across the hairline divider */\n  meta?: string;\n  heading?: string;\n  description?: string;\n  /** Standing photograph in the left column */\n  image?: CoverImage;\n  caption?: string;\n  /** Bordered cells under the photograph: what the subscription is and is not */\n  promises?: PromiseItem[];\n  note?: string;\n  topicsStep?: Step;\n  topics?: Option[];\n  cadenceStep?: Step;\n  cadences?: Option[];\n  emailStep?: EmailStep;\n  /** Prints a scoped shortcut on every choice and binds it while the step is active */\n  shortcuts?: \"letters\" | \"numbers\";\n  /** Seal CTA under the confirmation */\n  button?: ActionButton;\n  labels?: Cta92Labels;\n  className?: string;\n}\n\nexport const cta92Demo: Cta92Props = {\n  badge: { label: \"Newsletter\" },\n  meta: \"4,100 readers\",\n  heading: \"Subscribe to the parts you actually read\",\n  description:\n    \"One list, three subjects, and a cadence you choose. Nothing arrives that you did not ask for, and the first email tells you exactly what you signed up to.\",\n  image: {\n    src: \"https://images.unsplash.com/photo-1781819062931-57ea2c12deb4?q=80&w=1887&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D\",\n    alt: \"Printed newsletter issues stacked on a desk\",\n  },\n  caption: \"Every issue is written, edited, and sent by the same two people.\",\n  promises: [\n    {\n      title: \"You pick the subjects\",\n      description:\n        \"Choose one or all three. Anything you leave out is never sent, not even as a footer.\",\n    },\n    {\n      title: \"You pick the rhythm\",\n      description: \"Weekly on a Thursday, monthly on the first, or only when something is released.\",\n    },\n    {\n      title: \"Leaving is one click\",\n      description: \"The unsubscribe link sits at the top of every email, not buried under a footer.\",\n    },\n  ],\n  note: \"No sponsorships, and the list is never shared with anyone.\",\n  shortcuts: \"numbers\",\n  topicsStep: {\n    title: \"What should we send you?\",\n    description: \"Pick as many as you like.\",\n  },\n  topics: [\n    {\n      value: \"notes\",\n      label: \"Engineering notes\",\n      description: \"What we changed, and the version that broke first.\",\n    },\n    {\n      value: \"design\",\n      label: \"Design teardowns\",\n      description: \"One interface a month, read closely and drawn over.\",\n    },\n    {\n      value: \"releases\",\n      label: \"Release announcements\",\n      description: \"New versions, migrations, and anything being retired.\",\n    },\n  ],\n  cadenceStep: {\n    title: \"How often is welcome?\",\n  },\n  cadences: [\n    { value: \"weekly\", label: \"Weekly\", description: \"Thursday mornings, around 400 words.\" },\n    { value: \"monthly\", label: \"Monthly\", description: \"The first of the month, a longer read.\" },\n    { value: \"releases\", label: \"Only when something ships\", description: \"Roughly six a year.\" },\n  ],\n  emailStep: {\n    title: \"Where should it arrive?\",\n    description: \"We confirm the address before anything is sent to it.\",\n    label: \"Email address\",\n    placeholder: \"you@company.com\",\n  },\n  button: { label: \"Read the last issue\", href: \"https://beste.co\" },\n  labels: {\n    submit: \"Confirm my subscription\",\n    restart: \"Change my answers\",\n    confirmationTitle: \"Check your inbox\",\n    confirmationDescription:\n      \"A confirmation link is on its way. Nothing is sent until you open it, and this is what it will set up.\",\n    topicsSummary: \"Subjects\",\n    cadenceSummary: \"How often\",\n    emailSummary: \"Sent to\",\n  },\n};\n\nexport function Cta92({\n  badge,\n  meta,\n  heading,\n  description,\n  image,\n  caption,\n  promises = [],\n  note,\n  topicsStep,\n  topics = [],\n  cadenceStep,\n  cadences = [],\n  emailStep,\n  shortcuts,\n  button,\n  labels = {},\n  className,\n}: Cta92Props) {\n  const {\n    previous: previousLabel,\n    next: nextLabel,\n    submit: submitLabel,\n    restart: restartLabel,\n    confirmationTitle,\n    confirmationDescription,\n    topicsSummary,\n    cadenceSummary,\n    emailSummary,\n  } = labels;\n\n  const [signup, setSignup] = useState<{\n    topics: string[];\n    cadence: string;\n    email: string;\n  } | null>(null);\n\n  const handleSubmit = (event: FormEvent<HTMLFormElement>) => {\n    event.preventDefault();\n    const data = new FormData(event.currentTarget);\n    setSignup({\n      topics: data.getAll(\"topics\").map((entry) => String(entry)),\n      cadence: String(data.get(\"cadence\") ?? \"\"),\n      email: String(data.get(\"email\") ?? \"\").trim(),\n    });\n  };\n\n  const restart = () => setSignup(null);\n\n  const labelFor = (options: Option[], value: string) =>\n    options.find((option) => option.value === value)?.label ?? value;\n\n  return (\n    <section className={cn(\"w-full py-16 md:py-24\", className)}>\n      <div className=\"mx-auto max-w-6xl px-4 md:px-6\">\n        <div className=\"flex flex-wrap items-center gap-5\">\n          {badge && <Badge6 label={badge.label} />}\n          {badge && meta && <span className=\"h-9 w-px bg-border\" />}\n          {meta && (\n            <span className=\"text-base font-bold uppercase tracking-widest text-muted-foreground\">\n              {meta}\n            </span>\n          )}\n        </div>\n\n        <div className=\"mt-6 border-b\" />\n\n        {heading && (\n          <h2 className=\"mt-10 max-w-3xl text-balance text-3xl font-bold leading-[1.05] tracking-tight text-foreground md:text-5xl\">\n            {heading}\n          </h2>\n        )}\n        {description && (\n          <p className=\"mt-6 max-w-2xl text-lg text-muted-foreground md:text-xl\">{description}</p>\n        )}\n\n        <div className=\"mt-12 grid gap-8 lg:grid-cols-[1fr_1.1fr] lg:gap-12\">\n          <div>\n            {/* Fixed height on purpose: the plate never resizes with the step beside it. */}\n            <div className=\"relative h-72 overflow-hidden rounded-md border bg-muted lg:h-96\">\n              {image && (\n                <img\n                  className=\"absolute inset-0 size-full object-cover\"\n                  src={image.src}\n                  alt={image.alt}\n                />\n              )}\n            </div>\n            {caption && <p className=\"mt-4 text-base text-muted-foreground\">{caption}</p>}\n          </div>\n\n          <div>\n            {signup ? (\n              <>\n                <div className=\"flex items-start gap-4\">\n                  <span className=\"flex size-10 shrink-0 items-center justify-center rounded-md bg-primary text-primary-foreground\">\n                    <MailCheck className=\"size-5\" aria-hidden=\"true\" />\n                  </span>\n                  <div className=\"min-w-0\">\n                    <p className=\"text-2xl font-bold tracking-tight text-foreground\">\n                      {confirmationTitle ?? \"Check your inbox\"}\n                    </p>\n                    {confirmationDescription && (\n                      <p className=\"mt-3 text-base text-muted-foreground md:text-lg\">\n                        {confirmationDescription}\n                      </p>\n                    )}\n                  </div>\n                </div>\n\n                <dl className=\"mt-8 grid gap-4\">\n                  <div className=\"rounded-md border bg-muted p-5\">\n                    <dt className=\"text-base font-bold uppercase tracking-widest text-muted-foreground\">\n                      {topicsSummary ?? \"Subjects\"}\n                    </dt>\n                    <dd className=\"mt-3 flex flex-wrap gap-2\">\n                      {signup.topics.length > 0 ? (\n                        signup.topics.map((value, index) => (\n                          <span\n                            key={index}\n                            className=\"inline-flex items-center gap-2 rounded-md bg-background px-3 py-1.5 text-base font-bold text-foreground\"\n                          >\n                            <Check className=\"size-4 text-primary\" aria-hidden=\"true\" />\n                            {labelFor(topics, value)}\n                          </span>\n                        ))\n                      ) : (\n                        <span className=\"text-base font-bold text-foreground\">\n                          Nothing selected\n                        </span>\n                      )}\n                    </dd>\n                  </div>\n\n                  <div className=\"grid gap-4 sm:grid-cols-2\">\n                    <div className=\"rounded-md border bg-muted p-5\">\n                      <dt className=\"text-base font-bold uppercase tracking-widest text-muted-foreground\">\n                        {cadenceSummary ?? \"How often\"}\n                      </dt>\n                      <dd className=\"mt-2 text-lg font-bold tracking-tight text-foreground\">\n                        {labelFor(cadences, signup.cadence)}\n                      </dd>\n                    </div>\n                    <div className=\"rounded-md border bg-muted p-5\">\n                      <dt className=\"text-base font-bold uppercase tracking-widest text-muted-foreground\">\n                        {emailSummary ?? \"Sent to\"}\n                      </dt>\n                      <dd className=\"mt-2 text-lg font-bold break-all tracking-tight text-foreground\">\n                        {signup.email}\n                      </dd>\n                    </div>\n                  </div>\n                </dl>\n\n                <div className=\"mt-8 flex flex-wrap items-center gap-5\">\n                  {button && (\n                    <Button1 asChild label={button.label}>\n                      <Link href={button.href} />\n                    </Button1>\n                  )}\n                  <button\n                    type=\"button\"\n                    onClick={restart}\n                    className=\"cursor-pointer text-lg font-bold text-foreground underline underline-offset-4 hover:text-primary\"\n                  >\n                    {restartLabel ?? \"Change my answers\"}\n                  </button>\n                </div>\n              </>\n            ) : (\n              <Questionnaire\n                defaultItem={topicsStep ? \"topics\" : cadenceStep ? \"cadence\" : \"email\"}\n                shortcuts={shortcuts}\n                onSubmit={handleSubmit}\n                className=\"gap-6\"\n              >\n                <QuestionnaireProgress className=\"text-base\" />\n\n                {topicsStep && (\n                  <QuestionnaireItem name=\"topics\" required multiple>\n                    <QuestionnaireTitle className=\"text-xl font-bold tracking-tight text-foreground md:text-2xl\">\n                      {topicsStep.title}\n                    </QuestionnaireTitle>\n                    {topicsStep.description && (\n                      <QuestionnaireDescription className=\"text-base text-muted-foreground md:text-lg\">\n                        {topicsStep.description}\n                      </QuestionnaireDescription>\n                    )}\n                    <QuestionnaireChoices>\n                      {topics.map((topic, index) => (\n                        <QuestionnaireChoice\n                          key={index}\n                          value={topic.value}\n                          className=\"rounded-md p-4 text-base data-checked:border-primary\"\n                        >\n                          <span className=\"font-bold text-foreground\">{topic.label}</span>\n                          {topic.description && (\n                            <QuestionnaireChoiceDescription className=\"text-base\">\n                              {topic.description}\n                            </QuestionnaireChoiceDescription>\n                          )}\n                        </QuestionnaireChoice>\n                      ))}\n                    </QuestionnaireChoices>\n                    <QuestionnaireError className=\"text-base\" />\n                  </QuestionnaireItem>\n                )}\n\n                {cadenceStep && (\n                  <QuestionnaireItem name=\"cadence\" required>\n                    <QuestionnaireTitle className=\"text-xl font-bold tracking-tight text-foreground md:text-2xl\">\n                      {cadenceStep.title}\n                    </QuestionnaireTitle>\n                    {cadenceStep.description && (\n                      <QuestionnaireDescription className=\"text-base text-muted-foreground md:text-lg\">\n                        {cadenceStep.description}\n                      </QuestionnaireDescription>\n                    )}\n                    <QuestionnaireChoices>\n                      {cadences.map((cadence, index) => (\n                        <QuestionnaireChoice\n                          key={index}\n                          value={cadence.value}\n                          className=\"rounded-md p-4 text-base data-checked:border-primary\"\n                        >\n                          <span className=\"font-bold text-foreground\">{cadence.label}</span>\n                          {cadence.description && (\n                            <QuestionnaireChoiceDescription className=\"text-base\">\n                              {cadence.description}\n                            </QuestionnaireChoiceDescription>\n                          )}\n                        </QuestionnaireChoice>\n                      ))}\n                    </QuestionnaireChoices>\n                    <QuestionnaireError className=\"text-base\" />\n                  </QuestionnaireItem>\n                )}\n\n                {emailStep && (\n                  <QuestionnaireItem name=\"email\" required>\n                    <QuestionnaireTitle className=\"text-xl font-bold tracking-tight text-foreground md:text-2xl\">\n                      {emailStep.title}\n                    </QuestionnaireTitle>\n                    {emailStep.description && (\n                      <QuestionnaireDescription className=\"text-base text-muted-foreground md:text-lg\">\n                        {emailStep.description}\n                      </QuestionnaireDescription>\n                    )}\n                    <QuestionnaireChoices>\n                      <QuestionnaireInput\n                        type=\"email\"\n                        aria-label={emailStep.label}\n                        placeholder={emailStep.placeholder}\n                        className=\"h-11 rounded-md px-4 text-base md:text-base\"\n                      />\n                    </QuestionnaireChoices>\n                    <QuestionnaireError className=\"text-base\" />\n                  </QuestionnaireItem>\n                )}\n\n                <QuestionnaireActions>\n                  <QuestionnairePrevious className=\"cursor-pointer rounded-md text-base\">\n                    {previousLabel}\n                  </QuestionnairePrevious>\n                  <QuestionnaireNext className=\"cursor-pointer rounded-md text-base\">\n                    {nextLabel}\n                  </QuestionnaireNext>\n                  <QuestionnaireSubmit className=\"cursor-pointer rounded-md text-base\">\n                    {submitLabel}\n                  </QuestionnaireSubmit>\n                </QuestionnaireActions>\n              </Questionnaire>\n            )}\n          </div>\n        </div>\n\n        {promises.length > 0 && (\n          <div className=\"mt-10 grid gap-4 sm:grid-cols-3\">\n            {promises.map((promise, index) => (\n              <div key={index} className=\"rounded-md border bg-muted p-5\">\n                <p className=\"text-lg font-bold tracking-tight text-foreground\">{promise.title}</p>\n                <p className=\"mt-2 text-base text-muted-foreground\">{promise.description}</p>\n              </div>\n            ))}\n          </div>\n        )}\n\n        {note && <p className=\"mt-6 text-base text-muted-foreground\">{note}</p>}\n      </div>\n    </section>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/beste/block/cta92.tsx"
    },
    {
      "path": "registry-components/badge6/badge6.tsx",
      "content": "import { cn } from \"@/lib/utils\";\n\ntype Tone = \"primary\" | \"foreground\" | \"muted\";\ntype Badge6Orientation = \"horizontal\" | \"vertical\";\n\ninterface Badge6Props {\n  /** Eyebrow label (rendered uppercase) */\n  label: string;\n  /** Accent square color */\n  tone?: Tone;\n  /** Layout: square beside the label (default) or stacked above it */\n  orientation?: Badge6Orientation;\n  /** Override the label classes, e.g. \"text-background/70\" on dark surfaces */\n  labelClassName?: string;\n  /** Additional classes merged onto the root */\n  className?: string;\n}\n\nconst toneStyles: Record<Tone, string> = {\n  primary: \"bg-primary\",\n  foreground: \"bg-foreground\",\n  muted: \"bg-muted-foreground\",\n};\n\nexport const badge6Demo: Badge6Props = {\n  label: \"About Us\",\n};\n\nexport function Badge6({\n  label,\n  tone = \"primary\",\n  orientation = \"horizontal\",\n  labelClassName,\n  className,\n}: Badge6Props) {\n  const vertical = orientation === \"vertical\";\n\n  return (\n    <div className={cn(\"flex\", vertical ? \"flex-col gap-3\" : \"items-center gap-2.5\", className)}>\n      <span className={cn(\"size-2.5 shrink-0\", toneStyles[tone])} />\n      <span\n        className={cn(\n          \"text-base font-bold uppercase tracking-widest text-muted-foreground\",\n          vertical && \"leading-tight\",\n          labelClassName\n        )}\n      >\n        {label}\n      </span>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/beste/component/badge6.tsx"
    },
    {
      "path": "registry-components/button1/button1.tsx",
      "content": "\"use client\";\n\nimport { ArrowRight, type LucideIcon } from \"lucide-react\";\nimport * as React from \"react\";\nimport { Button } from \"@/components/ui/button\";\nimport { cn } from \"@/lib/utils\";\n\ntype Tone = \"dark\" | \"primary\";\n\ninterface Button1Props {\n  /** Button label */\n  label: string;\n  /**\n   * Compose the rendered element shadcn-style (radix asChild):\n   * `<Button1 asChild label=\"Read More\"><Link href=\"/x\" /></Button1>`\n   * The child element receives the pill content (label + seal) as its\n   * children, so pass it without children of its own.\n   */\n  asChild?: boolean;\n  /** The element to render when `asChild` is set (e.g. your router's Link) */\n  children?: React.ReactElement;\n  /**\n   * Fallback link: renders a plain `<a>`. Prefer `asChild` with your\n   * framework's Link component for client-side navigation.\n   */\n  href?: string;\n  /** Trailing seal icon (defaults to ArrowRight) */\n  icon?: LucideIcon;\n  /** Surface tone: dark pill (default) or primary pill (for dark backgrounds) */\n  tone?: Tone;\n  /** Fully round the pill and seal (shorthand for className=\"rounded-full\") */\n  roundedFull?: boolean;\n  /** Click handler (used when there is no href and no asChild) */\n  onClick?: React.MouseEventHandler<HTMLButtonElement>;\n  /** Additional classes merged onto the button */\n  className?: string;\n}\n\nconst toneStyles: Record<Tone, { pill: string; seal: string }> = {\n  dark: {\n    pill: \"bg-foreground text-background hover:bg-foreground/90\",\n    seal: \"bg-primary text-primary-foreground\",\n  },\n  primary: {\n    pill: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n    seal: \"bg-primary-foreground text-primary\",\n  },\n};\n\nexport const button1Demo: Button1Props = {\n  label: \"Read More\",\n};\n\nexport function Button1({\n  label,\n  asChild = false,\n  children,\n  href,\n  icon: Icon = ArrowRight,\n  tone = \"dark\",\n  roundedFull = false,\n  onClick,\n  className,\n}: Button1Props) {\n  const styles = toneStyles[tone];\n\n  // Mirror the pill's border radius onto the seal so the arrow chip always\n  // matches the pill. Priority: an explicit `rounded-*` in className wins,\n  // then the `roundedFull` shorthand, otherwise the default rounded-md.\n  const explicitRadius = className?.match(/\\brounded-(?:none|sm|md|lg|xl|2xl|3xl|full)\\b/)?.[0];\n  const sealRadius = explicitRadius ?? (roundedFull ? \"rounded-full\" : \"rounded-md\");\n\n  const inner = (\n    <>\n      {label}\n      <span\n        className={cn(\n          \"flex size-8 items-center justify-center transition-transform motion-safe:group-hover/button1:translate-x-0.5\",\n          sealRadius,\n          styles.seal\n        )}\n      >\n        <Icon className=\"size-4\" />\n      </span>\n    </>\n  );\n\n  const classes = cn(\n    // justify-between keeps the label left and the seal pinned right when the\n    // pill is full-width; at w-fit there's no free space so they stay together.\n    \"group/button1 h-auto w-fit justify-between gap-3 rounded-md py-3 pl-6 pr-3 text-base font-bold transition-colors\",\n    roundedFull && \"rounded-full\",\n    styles.pill,\n    className\n  );\n\n  if (asChild && React.isValidElement(children)) {\n    // The consumer's element (e.g. next/link's <Link href>) becomes the\n    // rendered element; the pill content is injected as its children.\n    return (\n      <Button asChild className={classes}>\n        {React.cloneElement(children, undefined, inner)}\n      </Button>\n    );\n  }\n\n  if (href) {\n    return (\n      <Button asChild className={classes}>\n        <a href={href}>{inner}</a>\n      </Button>\n    );\n  }\n\n  return (\n    <Button type=\"button\" className={classes} onClick={onClick}>\n      {inner}\n    </Button>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/beste/component/button1.tsx"
    }
  ],
  "type": "registry:block"
}