{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "receipt-tiers",
  "title": "Receipt Tiers",
  "description": "Plans printed as thermal receipts with torn edges, dotted leaders, and a rubber stamp.",
  "files": [
    {
      "path": "components/spectrumui/blocks/pricing/receipt-tiers.tsx",
      "content": "'use client';\n\nimport { cn } from '@/lib/utils';\nimport { REVEAL_KEYFRAMES, revealClass, revealDelay, useReveal } from './reveal';\nimport type { Plan } from './types';\n\nexport type ReceiptTiersVariant = 'Tilted' | 'Straight';\n\nexport interface ReceiptTiersProps {\n  plans: Plan[];\n  eyebrow?: string;\n  heading?: string;\n  subheading?: string;\n  merchant?: string;\n  merchantLine?: string;\n  variant?: ReceiptTiersVariant;\n  className?: string;\n}\n\nconst TILTS = [\n  '@3xl:-rotate-1',\n  '@3xl:rotate-[0.5deg] @3xl:-translate-y-2',\n  '@3xl:rotate-[1.5deg]',\n];\n\nfunction Rule() {\n  return (\n    <span\n      aria-hidden\n      className=\"my-3 block border-t border-dashed border-[#b9b6ad] dark:border-[#3f3f45]\"\n    />\n  );\n}\n\nexport function ReceiptTiers({\n  plans,\n  eyebrow,\n  heading,\n  subheading,\n  merchant = 'PORTSIDE FREIGHT CO.',\n  merchantLine = 'TERMINAL 4 · DOCK 12 · ROTTERDAM',\n  variant = 'Tilted',\n  className,\n}: ReceiptTiersProps) {\n  const { ref, shown } = useReveal<HTMLElement>();\n\n  return (\n    <section\n      ref={ref}\n      className={cn(\n        '@container w-full rounded-2xl bg-[#e9e8e3] px-6 py-12 sm:px-10 dark:bg-[#111113]',\n        className,\n      )}\n    >\n      <style dangerouslySetInnerHTML={{ __html: REVEAL_KEYFRAMES }} />\n\n      {heading && (\n        <div className={cn('mx-auto mb-12 max-w-[52ch] text-center font-mono', revealClass(shown))}>\n          {eyebrow && (\n            <span className=\"text-[11px] tracking-[0.3em] text-[#7c7a72] dark:text-[#8f8f95]\">\n              ··· {eyebrow.toUpperCase()} ···\n            </span>\n          )}\n          <h2 className=\"mt-4 text-balance text-[24px] font-bold uppercase tracking-[0.12em] text-[#2a2a26] dark:text-[#d8d8d2] @lg:text-[27px]\">\n            {heading}\n          </h2>\n          {subheading && (\n            <p className=\"mt-3 text-pretty text-[11.5px] uppercase leading-[1.7] tracking-[0.08em] text-[#7c7a72] dark:text-[#8f8f95]\">\n              {subheading}\n            </p>\n          )}\n        </div>\n      )}\n\n      <div className=\"mx-auto grid max-w-[1040px] grid-cols-1 items-start gap-8 font-mono @3xl:grid-cols-3 @3xl:gap-7\">\n        {plans.map((plan, position) => (\n          <div\n            key={plan.id}\n            style={revealDelay(shown, position)}\n            className={cn(\n              'relative bg-[#fefdf8] px-6 pb-7 pt-8 text-[12.5px] leading-relaxed text-[#2a2a26] shadow-[0_12px_32px_-16px_rgba(0,0,0,0.35)]',\n              '[clip-path:polygon(0_0,100%_0,100%_calc(100%-8px),97%_100%,94%_calc(100%-8px),91%_100%,88%_calc(100%-8px),85%_100%,82%_calc(100%-8px),79%_100%,76%_calc(100%-8px),73%_100%,70%_calc(100%-8px),67%_100%,64%_calc(100%-8px),61%_100%,58%_calc(100%-8px),55%_100%,52%_calc(100%-8px),49%_100%,46%_calc(100%-8px),43%_100%,40%_calc(100%-8px),37%_100%,34%_calc(100%-8px),31%_100%,28%_calc(100%-8px),25%_100%,22%_calc(100%-8px),19%_100%,16%_calc(100%-8px),13%_100%,10%_calc(100%-8px),7%_100%,4%_calc(100%-8px),1%_100%,0_calc(100%-8px))]',\n              'dark:bg-[#1c1c1f] dark:text-[#d8d8d2]',\n              revealClass(shown),\n              variant === 'Tilted' && TILTS[position % TILTS.length],\n            )}\n          >\n            {plan.badge && (\n              <span\n                aria-hidden\n                className=\"absolute right-4 top-16 -rotate-12 rounded border-2 border-[#c93a28] px-2 py-1 text-[11px] font-bold tracking-[0.14em] text-[#c93a28] opacity-80 mix-blend-multiply dark:mix-blend-normal dark:opacity-90\"\n              >\n                {plan.badge.toUpperCase()}\n              </span>\n            )}\n\n            <p className=\"text-center text-[13.5px] font-bold tracking-[0.08em]\">{merchant}</p>\n            <p className=\"mt-1 text-center text-[10.5px] tracking-[0.06em] text-[#7c7a72] dark:text-[#8f8f95]\">\n              {merchantLine}\n            </p>\n\n            <Rule />\n\n            <div className=\"flex items-baseline justify-between\">\n              <span className=\"font-bold tracking-[0.08em]\">{plan.name.toUpperCase()} PLAN</span>\n              <span className=\"text-[#7c7a72] dark:text-[#8f8f95]\">×1</span>\n            </div>\n            <p className=\"mt-1 text-[11px] text-[#7c7a72] dark:text-[#8f8f95]\">{plan.tagline}</p>\n\n            <Rule />\n\n            <ul className=\"space-y-1.5\">\n              {plan.features.map((feature) => (\n                <li key={feature} className=\"flex items-baseline gap-2\">\n                  <span className=\"min-w-0 flex-shrink truncate\">{feature.toUpperCase()}</span>\n                  <span\n                    aria-hidden\n                    className=\"mb-1 min-w-3 flex-1 border-b border-dotted border-[#b9b6ad] dark:border-[#3f3f45]\"\n                  />\n                  <span className=\"shrink-0 text-[#7c7a72] dark:text-[#8f8f95]\">INCL</span>\n                </li>\n              ))}\n            </ul>\n\n            <Rule />\n\n            <div className=\"flex items-baseline justify-between text-[11.5px] text-[#7c7a72] dark:text-[#8f8f95]\">\n              <span>SUBTOTAL</span>\n              <span>{plan.price ? `$${plan.price.monthly}.00` : 'ON QUOTE'}</span>\n            </div>\n            <div className=\"flex items-baseline justify-between text-[11.5px] text-[#7c7a72] dark:text-[#8f8f95]\">\n              <span>SEAT DISCOUNT (YEARLY)</span>\n              <span>\n                {plan.price && plan.price.monthly > 0\n                  ? `-$${plan.price.monthly - plan.price.annual}.00`\n                  : '—'}\n              </span>\n            </div>\n\n            <div className=\"mt-2 flex items-baseline justify-between text-[17px] font-bold\">\n              <span>TOTAL /MO</span>\n              <span>{plan.price ? `$${plan.price.annual}.00` : 'CUSTOM'}</span>\n            </div>\n\n            <Rule />\n\n            <button\n              type=\"button\"\n              className={cn(\n                'w-full py-3 text-[12.5px] font-bold tracking-[0.1em]',\n                'transition-transform duration-150 active:scale-[0.98]',\n                'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-[#c93a28] focus-visible:ring-offset-2 dark:focus-visible:ring-offset-[#1c1c1f]',\n                'bg-[#2a2a26] text-[#fefdf8] hover:bg-black dark:bg-[#ecece6] dark:text-[#1c1c1f] dark:hover:bg-white',\n              )}\n            >\n              {plan.cta.toUpperCase()}\n            </button>\n\n            <div\n              aria-hidden\n              className=\"mx-auto mt-5 h-10 w-4/5 opacity-80 [background-image:repeating-linear-gradient(90deg,currentColor_0,currentColor_2px,transparent_2px,transparent_5px,currentColor_5px,currentColor_6px,transparent_6px,transparent_9px)]\"\n            />\n            <p className=\"mt-2 text-center text-[10px] tracking-[0.2em] text-[#7c7a72] dark:text-[#8f8f95]\">\n              {`NO. 00${28 + position} · THANK YOU`}\n            </p>\n          </div>\n        ))}\n      </div>\n    </section>\n  );\n}\n\nexport default ReceiptTiers;\n",
      "type": "registry:block",
      "target": "components/spectrumui/blocks/pricing/receipt-tiers.tsx"
    },
    {
      "path": "components/spectrumui/blocks/pricing/types.ts",
      "content": "export type BillingPeriod = 'monthly' | 'annual';\n\nexport interface PlanPrice {\n  monthly: number;\n  annual: number;\n}\n\nexport interface Plan {\n  id: string;\n  name: string;\n  tagline: string;\n  price: PlanPrice | null;\n  unit?: string;\n  cta: string;\n  featured?: boolean;\n  badge?: string;\n  inherits?: string;\n  features: string[];\n  footnote?: string;\n}\n\nexport type FeatureValue = string | boolean;\n\nexport interface FeatureRow {\n  label: string;\n  hint?: string;\n  values: FeatureValue[];\n}\n\nexport interface FeatureGroup {\n  label: string;\n  rows: FeatureRow[];\n}\n\nexport interface RateTier {\n  from: number;\n  to?: number;\n  unitPrice: number;\n}\n\nexport interface MeteredProduct {\n  id: string;\n  name: string;\n  description?: string;\n  unit: string;\n  unitPlural: string;\n  included: number;\n  tiers: RateTier[];\n}\n\nexport interface CreditPack {\n  id: string;\n  name: string;\n  credits: number;\n  bonus: number;\n  price: number;\n  featured?: boolean;\n  note?: string;\n}\n\nexport interface CreditRate {\n  id: string;\n  label: string;\n  credits: number;\n  per: number;\n  unitLabel: string;\n}\n\nexport interface AddOn {\n  id: string;\n  name: string;\n  description: string;\n  price: number;\n  unit?: string;\n  perSeat?: boolean;\n  defaultOn?: boolean;\n}\n\nexport interface ModelRate {\n  id: string;\n  name: string;\n  context: string;\n  input: number;\n  output: number;\n  cacheWrite: number;\n  cacheRead: number;\n  badge?: string;\n}\n\nexport interface UsageDimension {\n  id: string;\n  label: string;\n  unit: string;\n  min: number;\n  max: number;\n  step: number;\n  defaultValue: number;\n}\n\nexport interface ComplianceItem {\n  id: string;\n  label: string;\n  detail: string;\n}\n\nexport interface RecommenderOption {\n  id: string;\n  label: string;\n  scores: Record<string, number>;\n  reason?: string;\n}\n\nexport interface RecommenderQuestion {\n  id: string;\n  label: string;\n  hint?: string;\n  options: RecommenderOption[];\n}\n\nexport interface PlanFamily {\n  id: string;\n  label: string;\n  description: string;\n  plans: Plan[];\n  footnote?: string;\n}\n",
      "type": "registry:file",
      "target": "components/spectrumui/blocks/pricing/types.ts"
    },
    {
      "path": "components/spectrumui/blocks/pricing/reveal.ts",
      "content": "'use client';\n\nimport { useEffect, useRef, useState } from 'react';\n\nexport const REVEAL_KEYFRAMES = `\n@keyframes su-reveal { from { opacity: 0; transform: translateY(14px) } to { opacity: 1; transform: none } }\n@keyframes su-draw { from { stroke-dashoffset: 1 } to { stroke-dashoffset: 0 } }\n@keyframes su-sheen { 0%, 62% { transform: translateX(-110%) } 100% { transform: translateX(110%) } }\n`;\n\nexport function useReveal<T extends HTMLElement>() {\n  const ref = useRef<T>(null);\n  const [shown, setShown] = useState(false);\n\n  useEffect(() => {\n    const node = ref.current;\n    if (!node) return;\n    if (typeof IntersectionObserver === 'undefined') {\n      const frame = requestAnimationFrame(() => setShown(true));\n      return () => cancelAnimationFrame(frame);\n    }\n    const observer = new IntersectionObserver(\n      (entries) => {\n        if (entries.some((entry) => entry.isIntersecting)) {\n          setShown(true);\n          observer.disconnect();\n        }\n      },\n      { threshold: 0.18, rootMargin: '0px 0px -8% 0px' },\n    );\n    observer.observe(node);\n    return () => observer.disconnect();\n  }, []);\n\n  return { ref, shown };\n}\n\nexport function revealClass(shown: boolean) {\n  return shown\n    ? '[animation:su-reveal_480ms_cubic-bezier(0.23,1,0.32,1)_both] motion-reduce:animate-none'\n    : '';\n}\n\nexport function revealDelay(shown: boolean, index: number) {\n  return shown ? { animationDelay: `${index * 70}ms` } : undefined;\n}\n",
      "type": "registry:file",
      "target": "components/spectrumui/blocks/pricing/reveal.ts"
    }
  ],
  "type": "registry:block"
}
