{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "commerce-storefront",
  "type": "registry:block",
  "title": "Commerce storefront",
  "description": "Organizes product story, detail browsing, volume pricing, and cart confirmation into a complete purchase path.",
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [
    "https://motion-lexicon.pages.dev/r/add-to-cart-morph.json",
    "https://motion-lexicon.pages.dev/r/animated-combobox.json",
    "https://motion-lexicon.pages.dev/r/cinematic-hero.json",
    "https://motion-lexicon.pages.dev/r/media-carousel.json",
    "https://motion-lexicon.pages.dev/r/pricing-calculator.json"
  ],
  "categories": [
    "page-block"
  ],
  "docs": "https://motion-lexicon.pages.dev/en/blocks/commerce-storefront/",
  "meta": {
    "engines": [
      "motion"
    ],
    "runtimeCost": "medium",
    "signature": "Product browsing, price configuration, and cart state resolve along one purchase path.",
    "sceneFamily": "editorial-warm",
    "primaryState": "Hero product, material details, and a confirmable purchase panel",
    "componentIds": [
      "add-to-cart-morph",
      "animated-combobox",
      "cinematic-hero",
      "media-carousel",
      "pricing-calculator"
    ]
  },
  "files": [
    {
      "path": "src/registry/blocks/commerce-storefront.tsx",
      "type": "registry:component",
      "target": "components/motion-lexicon/blocks/commerce-storefront.tsx",
      "content": "\"use client\";\n\nimport { motion, useReducedMotion } from \"motion/react\";\nimport { useState } from \"react\";\nimport { AddToCartMorph } from \"@/components/motion-lexicon/add-to-cart-morph\";\nimport { AnimatedCombobox } from \"@/components/motion-lexicon/animated-combobox\";\nimport { CinematicHero } from \"@/components/motion-lexicon/cinematic-hero\";\nimport {\n  MediaCarousel,\n  type MediaCarouselItem,\n} from \"@/components/motion-lexicon/media-carousel\";\nimport { PricingCalculator } from \"@/components/motion-lexicon/pricing-calculator\";\n\ntype Locale = \"zh\" | \"en\";\nexport type CommerceStorefrontBlockProps = {\n  locale?: Locale;\n  className?: string;\n};\n\nfunction ProductArt({ shade, label }: { shade: string; label: string }) {\n  return (\n    <div className={`relative size-full overflow-hidden ${shade}`}>\n      <i className=\"absolute left-[15%] top-[10%] h-[76%] w-[39%] rounded-[48%_48%_18%_18%] bg-white/80 shadow-[20px_28px_30px_-24px_rgba(35,26,20,.65)]\" />\n      <i className=\"absolute right-[14%] top-[22%] size-[30%] rounded-full border-[10px] border-[#604939]/75\" />\n      <span className=\"absolute bottom-4 left-4 font-mono text-[9px] tracking-[.16em] text-[#543f30]/75\">\n        {label}\n      </span>\n    </div>\n  );\n}\n\nexport function CommerceStorefrontBlock({\n  locale = \"en\",\n  className = \"\",\n}: CommerceStorefrontBlockProps) {\n  const reduced = useReducedMotion() === true;\n  const [notice, setNotice] = useState(\"\");\n  const c = locale === \"zh\" ? zh : en;\n  const media: MediaCarouselItem[] = [\n    {\n      id: \"sand\",\n      eyebrow: c.material,\n      title: c.materialTitle,\n      description: c.materialBody,\n      meta: \"01\",\n      art: <ProductArt shade=\"bg-[#d9bd9a]\" label=\"SAND / 01\" />,\n    },\n    {\n      id: \"blue\",\n      eyebrow: c.detail,\n      title: c.detailTitle,\n      description: c.detailBody,\n      meta: \"02\",\n      art: <ProductArt shade=\"bg-[#9ab6c7]\" label=\"TIDE / 02\" />,\n    },\n    {\n      id: \"clay\",\n      eyebrow: c.care,\n      title: c.careTitle,\n      description: c.careBody,\n      meta: \"03\",\n      art: <ProductArt shade=\"bg-[#d49372]\" label=\"CLAY / 03\" />,\n    },\n  ];\n  return (\n    <section\n      data-page-block=\"commerce-storefront\"\n      className={`w-full overflow-hidden rounded-[18px] bg-[#f7f1e8] text-[#342820] shadow-[0_24px_60px_-45px_rgba(58,37,22,.6)] ${className}`}\n    >\n      <header className=\"flex min-h-16 items-center justify-between border-b border-[#785d49]/15 px-5 sm:px-8\">\n        <a\n          href=\"#store-top\"\n          className=\"min-h-11 py-3 font-serif text-[22px] tracking-[-.06em] outline-none focus-visible:ring-2 focus-visible:ring-[#4568ff]\"\n        >\n          Serein\n        </a>\n        <div className=\"flex items-center gap-4 font-mono text-[9px] uppercase tracking-[.14em] text-[#806a58]\">\n          <a className=\"hidden min-h-11 items-center sm:flex\" href=\"#details\">\n            {c.details}\n          </a>\n          <span>{notice || c.cart}</span>\n        </div>\n      </header>\n      <div id=\"store-top\">\n        <div className=\"grid gap-8 px-5 py-10 sm:px-8 lg:grid-cols-[1.02fr_.98fr] lg:items-center lg:px-12 lg:py-16\">\n          <div className=\"order-2 lg:order-1\">\n            <p className=\"font-mono text-[10px] uppercase tracking-[.16em] text-[#a17252]\">\n              {c.kicker}\n            </p>\n            <h1 className=\"mt-4 max-w-[8ch] font-serif text-[clamp(48px,7vw,82px)] leading-[.84] tracking-[-.075em]\">\n              {c.title}\n            </h1>\n            <p className=\"mt-6 max-w-md text-[14px] leading-6 text-[#765e4d]\">\n              {c.body}\n            </p>\n            <div className=\"mt-7 flex gap-4 text-[10px] text-[#765e4d]\">\n              <span>01 / 04</span>\n              <span>{c.ship}</span>\n            </div>\n          </div>\n          <div className=\"order-1 lg:order-2\">\n            <CinematicHero\n              eyebrow={c.edition}\n              title={c.product}\n              description={c.body}\n              actionLabel={c.details}\n              onAction={() =>\n                document\n                  .getElementById(\"details\")\n                  ?.scrollIntoView({ behavior: reduced ? \"auto\" : \"smooth\" })\n              }\n              art={<ProductArt shade=\"bg-[#c9a77e]\" label=\"SEREIN / 2026\" />}\n            />\n          </div>\n        </div>\n        <div\n          id=\"details\"\n          className=\"grid gap-6 border-y border-[#785d49]/15 px-5 py-10 sm:px-8 lg:grid-cols-[minmax(0,1.05fr)_minmax(280px,.95fr)] lg:px-12\"\n        >\n          <MediaCarousel\n            items={media}\n            label={c.details}\n            className=\"bg-[#fffaf3]\"\n          />\n          <aside className=\"grid content-start gap-5\">\n            <AddToCartMorph\n              product={c.product}\n              price=\"$128 · VAT included\"\n              image=\"/og-home-en.png\"\n              imageAlt={c.product}\n              label={c.edition}\n              onAdd={() => setNotice(c.added)}\n            />\n            <AnimatedCombobox\n              label={c.details}\n              placeholder={c.email}\n              options={[\n                {\n                  id: \"standard\",\n                  label: \"Standard delivery\",\n                  detail: \"2–4 days\",\n                },\n                {\n                  id: \"express\",\n                  label: \"Express delivery\",\n                  detail: \"Tomorrow\",\n                },\n                {\n                  id: \"studio\",\n                  label: \"Studio pickup\",\n                  detail: \"By appointment\",\n                },\n              ]}\n              onChange={(option) => setNotice(option ? option.label : \"\")}\n            />\n            <div className=\"rounded-[15px] border border-[#785d49]/15 bg-[#eee1d0] p-4\">\n              <p className=\"font-mono text-[9px] uppercase tracking-[.15em] text-[#806a58]\">\n                {c.formLabel}\n              </p>\n              <label className=\"mt-4 block text-[11px] font-medium\">\n                {c.email}\n                <input\n                  className=\"mt-2 min-h-11 w-full rounded-lg border border-[#785d49]/20 bg-white/70 px-3 text-[12px] outline-none focus-visible:ring-2 focus-visible:ring-[#4568ff]\"\n                  type=\"email\"\n                  placeholder=\"you@example.com\"\n                />\n              </label>\n              <button\n                type=\"button\"\n                onClick={() => setNotice(c.joined)}\n                className=\"mt-3 min-h-11 w-full rounded-lg bg-[#382920] text-[11px] font-medium text-white outline-none focus-visible:ring-2 focus-visible:ring-[#4568ff]\"\n              >\n                {c.join}\n              </button>\n            </div>\n          </aside>\n        </div>\n        <div className=\"px-5 py-10 sm:px-8 lg:px-12\">\n          <div className=\"mb-5 flex flex-wrap items-end justify-between gap-3\">\n            <div>\n              <p className=\"font-mono text-[9px] uppercase tracking-[.15em] text-[#a17252]\">\n                Studio program\n              </p>\n              <h2 className=\"mt-2 font-serif text-[31px] tracking-[-.055em]\">\n                {c.program}\n              </h2>\n            </div>\n            <p className=\"max-w-xs text-[11px] leading-5 text-[#765e4d]\">\n              {c.programBody}\n            </p>\n          </div>\n          <PricingCalculator\n            tiers={[\n              { id: \"studio\", label: c.tiers[0], unitPrice: 18 },\n              { id: \"atelier\", label: c.tiers[1], unitPrice: 32 },\n              { id: \"retail\", label: c.tiers[2], unitPrice: 54 },\n            ]}\n            currency=\"USD\"\n            label={c.calculator}\n            className=\"max-w-xl\"\n          />\n        </div>\n        <footer className=\"border-t border-[#785d49]/15 px-5 py-6 text-center font-serif text-[22px] tracking-[-.05em] sm:px-8\">\n          {c.footer}\n          <motion.span\n            animate={reduced ? undefined : { opacity: [1, 0.45, 1] }}\n            transition={{ duration: 2.2, repeat: Infinity }}\n            className=\"ml-2 text-[#bd7044]\"\n          >\n            ✦\n          </motion.span>\n        </footer>\n      </div>\n    </section>\n  );\n}\n\nconst en = {\n  cart: \"Cart / 0\",\n  added: \"Cart / 1\",\n  joined: \"You are on the list\",\n  kicker: \"Object 04 · a quiet daily tool\",\n  title: \"A vessel for the everyday.\",\n  body: \"Hand-finished stoneware designed to make ordinary rituals feel deliberately yours.\",\n  ship: \"Ships in 2–4 days\",\n  details: \"The object\",\n  material: \"Material\",\n  materialTitle: \"Pale stoneware\",\n  materialBody: \"A warm matte body with a hand-finished rim.\",\n  detail: \"Detail\",\n  detailTitle: \"Balanced by hand\",\n  detailBody: \"A low, weighted base keeps the pour steady.\",\n  care: \"Care\",\n  careTitle: \"Made for use\",\n  careBody: \"Dishwasher safe. Each glaze carries its own variation.\",\n  product: \"Tide carafe\",\n  edition: \"Small-batch edition\",\n  formLabel: \"Studio letters\",\n  email: \"Email address\",\n  join: \"Join the list\",\n  program: \"For places that pour with intention.\",\n  programBody:\n    \"Configure a studio order for cafés, restaurants, and considered retail spaces.\",\n  calculator: \"Trade pricing\",\n  tiers: [\"12 pieces\", \"24 pieces\", \"48 pieces\"],\n  footer: \"Made slowly, used daily.\",\n};\nconst zh: typeof en = {\n  cart: \"购物袋 / 0\",\n  added: \"购物袋 / 1\",\n  joined: \"已加入名单\",\n  kicker: \"物件 04 · 安静的日常工具\",\n  title: \"盛放日常的器物。\",\n  body: \"手工完成的炻器，让每天重复的仪式变得更贴近自己。\",\n  ship: \"2–4 天内发货\",\n  details: \"这件器物\",\n  material: \"材质\",\n  materialTitle: \"浅色炻器\",\n  materialBody: \"温暖的哑光器身，边缘由手工完成。\",\n  detail: \"细节\",\n  detailTitle: \"手感平衡\",\n  detailBody: \"低重心底座让每次倾倒保持稳定。\",\n  care: \"护理\",\n  careTitle: \"为使用而造\",\n  careBody: \"可放入洗碗机，每道釉色都保留自己的变化。\",\n  product: \"潮汐水壶\",\n  edition: \"小批量版\",\n  formLabel: \"工作室来信\",\n  email: \"邮箱地址\",\n  join: \"加入名单\",\n  program: \"为讲究倒酒的空间而做。\",\n  programBody: \"为咖啡馆、餐厅和审美零售空间配置工作室订单。\",\n  calculator: \"商用定价\",\n  tiers: [\"12 件\", \"24 件\", \"48 件\"],\n  footer: \"缓慢制作，天天使用。\",\n};\n"
    }
  ]
}
