{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "product-detail-page",
  "title": "Product Detail Page",
  "type": "registry:page",
  "files": [
    {
      "path": "packages/registry-angular/blocks/product-detail-page/product-detail-page.component.ts",
      "content": "// Flagship e-commerce product detail page: breadcrumb, multi-angle gallery with finish &\n// cable selectors, stock urgency, warranty upsell, flash-sale strip, bundle, specs,\n// reviews, and Q&A. Self-contained single-file port of the Vue ProductDetailPage +\n// ProductGalleryBuyBox 1:1 (sibling sections are inlined so the block installs alone).\nimport { ChangeDetectionStrategy, Component, Input, computed, signal } from '@angular/core'\nimport {\n  BadgeCheck,\n  ChevronRight,\n  Cpu,\n  Flame,\n  Heart,\n  HelpCircle,\n  LucideAngularModule,\n  MessagesSquare,\n  Minus,\n  Package,\n  Plus,\n  RotateCcw,\n  Share2,\n  ShieldCheck,\n  ShoppingCart,\n  Star,\n  ThumbsUp,\n  Truck,\n  Zap,\n} from 'lucide-angular'\nimport { cn } from '@/lib/utils'\nimport { UiBadgeComponent } from '@/ui/badge/badge.component'\nimport { UiButtonComponent } from '@/ui/button/button.component'\nimport { UiInputComponent } from '@/ui/input/input.component'\nimport { UiSeparatorComponent } from '@/ui/separator/separator.component'\n\nexport interface ProductVariant {\n  id: string\n  name: string\n  colorHex: string\n  sku: string\n  inStock: boolean\n  stockCount: number\n  price: number\n  originalPrice: number\n  images: { id: string; url: string; alt: string }[]\n}\n\nexport const variants: ProductVariant[] = [\n  {\n    id: 'var-black',\n    name: 'Obsidian Matte Black',\n    colorHex: '#18181b',\n    sku: 'APX-950-BLK',\n    inStock: true,\n    stockCount: 14,\n    price: 599,\n    originalPrice: 749,\n    images: [\n      {\n        id: 'img-1',\n        url: 'https://images.unsplash.com/photo-1546435770-a3e426bf472b?w=900&auto=format&fit=crop&q=80',\n        alt: 'Apex Pro Reference Studio Headphones on Wood Desk',\n      },\n      {\n        id: 'img-2',\n        url: 'https://images.unsplash.com/photo-1505740420928-5e560c06d30e?w=900&auto=format&fit=crop&q=80',\n        alt: 'Apex Pro CNC Aluminum Driver Open Back View',\n      },\n      {\n        id: 'img-3',\n        url: 'https://images.unsplash.com/photo-1583394838336-acd977736f90?w=900&auto=format&fit=crop&q=80',\n        alt: 'Apex Pro Lambskin Magnetic Earpads Angle',\n      },\n      {\n        id: 'img-4',\n        url: 'https://images.unsplash.com/photo-1484704849700-f032a568e944?w=900&auto=format&fit=crop&q=80',\n        alt: 'Apex Pro Studio Audio Cable Interconnects',\n      },\n    ],\n  },\n  {\n    id: 'var-silver',\n    name: 'Lunar Silver Aluminum',\n    colorHex: '#94a3b8',\n    sku: 'APX-950-SLV',\n    inStock: true,\n    stockCount: 6,\n    price: 599,\n    originalPrice: 749,\n    images: [\n      {\n        id: 'img-2',\n        url: 'https://images.unsplash.com/photo-1505740420928-5e560c06d30e?w=900&auto=format&fit=crop&q=80',\n        alt: 'Apex Pro Lunar Silver Open Back View',\n      },\n      {\n        id: 'img-1',\n        url: 'https://images.unsplash.com/photo-1546435770-a3e426bf472b?w=900&auto=format&fit=crop&q=80',\n        alt: 'Apex Pro Silver Edition Desk Shot',\n      },\n      {\n        id: 'img-3',\n        url: 'https://images.unsplash.com/photo-1583394838336-acd977736f90?w=900&auto=format&fit=crop&q=80',\n        alt: 'Apex Pro Earpads Detail',\n      },\n    ],\n  },\n  {\n    id: 'var-navy',\n    name: 'Midnight Studio Navy',\n    colorHex: '#1e293b',\n    sku: 'APX-950-NVY',\n    inStock: true,\n    stockCount: 3,\n    price: 629,\n    originalPrice: 779,\n    images: [\n      {\n        id: 'img-3',\n        url: 'https://images.unsplash.com/photo-1583394838336-acd977736f90?w=900&auto=format&fit=crop&q=80',\n        alt: 'Apex Pro Midnight Navy Studio Edition',\n      },\n      {\n        id: 'img-1',\n        url: 'https://images.unsplash.com/photo-1546435770-a3e426bf472b?w=900&auto=format&fit=crop&q=80',\n        alt: 'Apex Pro Navy Perspective',\n      },\n      {\n        id: 'img-2',\n        url: 'https://images.unsplash.com/photo-1505740420928-5e560c06d30e?w=900&auto=format&fit=crop&q=80',\n        alt: 'Apex Pro Navy Driver Housing',\n      },\n    ],\n  },\n]\n\ntype CableKey = '4.4mm' | '3.5mm' | 'xlr'\n\ninterface BundleItem {\n  id: string\n  name: string\n  detail: string\n  price: number\n}\n\nconst BUNDLE_ITEMS: BundleItem[] = [\n  { id: 'bundle-cable', name: 'Apex Balanced 4.4mm Upgrade Cable', detail: 'OCC copper, 1.5m', price: 89 },\n  { id: 'bundle-case', name: 'Studio Hard Travel Case', detail: 'Molded, humidity control', price: 129 },\n  { id: 'bundle-pads', name: 'Replacement Lambskin Earpads', detail: 'Magnetic mount pair', price: 59 },\n]\n\ninterface SpecRow {\n  label: string\n  value: string\n}\n\nconst SPEC_ROWS: SpecRow[] = [\n  { label: 'Driver', value: '106mm planar magnetic, 32Ω impedance' },\n  { label: 'Frequency Response', value: '8Hz – 55kHz (±3dB)' },\n  { label: 'THD', value: '< 0.05% @ 1kHz, 100dB SPL' },\n  { label: 'Weight', value: '420g without cable' },\n  { label: 'Cable', value: 'Detachable dual 3.5mm, 2m balanced' },\n  { label: 'Model', value: 'APX-950-PRO · Studio Edition 2026' },\n]\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-product-detail-page, [ui-product-detail-page]',\n  standalone: true,\n  // React renders the root <div> itself: the host stays out of layout and `class` goes to the root.\n  host: { '[attr.class]': '\"contents\"' },\n  imports: [LucideAngularModule, UiBadgeComponent, UiButtonComponent, UiInputComponent, UiSeparatorComponent],\n  template: `\n    <div data-slot=\"product-detail-page\" [class]=\"rootClass\">\n      <!-- Breadcrumb Navigation Bar -->\n      <nav class=\"text-muted-foreground flex items-center gap-1.5 text-xs\" aria-label=\"Breadcrumb\">\n        <span class=\"hover:text-foreground cursor-pointer\">Storefront</span>\n        <lucide-icon [img]=\"ChevronRight\" class=\"size-3.5\" />\n        <span class=\"hover:text-foreground cursor-pointer\">Pro Audio & Reference</span>\n        <lucide-icon [img]=\"ChevronRight\" class=\"size-3.5\" />\n        <span class=\"hover:text-foreground cursor-pointer\">Planar Magnetic</span>\n        <lucide-icon [img]=\"ChevronRight\" class=\"size-3.5\" />\n        <span class=\"text-foreground font-medium\">APX-950-PRO Reference Monitor</span>\n      </nav>\n\n      <!-- Main Hero Split: Gallery & Buy Box -->\n      <div class=\"grid grid-cols-1 gap-8 lg:grid-cols-12 lg:gap-12\">\n        <!-- Left Column: Interactive Image Gallery -->\n        <div class=\"space-y-4 lg:col-span-7\">\n          <div class=\"border-border bg-muted/30 relative aspect-4/3 w-full overflow-hidden rounded-xl border shadow-xs\">\n            <img\n              [src]=\"activeImageUrl()\"\n              [alt]=\"currentVariant().name\"\n              class=\"size-full object-cover transition-transform duration-300 hover:scale-105\"\n            />\n\n            <div class=\"absolute top-3 left-3 flex flex-wrap gap-1.5\">\n              <span ui-badge variant=\"default\" class=\"h-6 font-mono text-xs font-semibold uppercase\">\n                2026 Flagship\n              </span>\n              <span ui-badge variant=\"secondary\" class=\"text-success h-6 font-mono text-xs\">\n                Laboratory Calibrated\n              </span>\n            </div>\n\n            <div class=\"absolute top-3 right-3 flex flex-col gap-2\">\n              <button\n                type=\"button\"\n                [class]=\"wishlistBtnClass()\"\n                (click)=\"isWishlisted.set(!isWishlisted())\"\n                aria-label=\"Toggle wishlist\"\n              >\n                <lucide-icon [img]=\"Heart\" class=\"size-4\" [class.fill-current]=\"isWishlisted()\" />\n              </button>\n              <button\n                type=\"button\"\n                class=\"border-border bg-background/90 text-muted-foreground hover:text-foreground flex size-8 items-center justify-center rounded-full border shadow-2xs backdrop-blur-xs transition-colors\"\n                (click)=\"shareLink()\"\n                aria-label=\"Share product\"\n              >\n                <lucide-icon [img]=\"Share2\" class=\"size-4\" />\n              </button>\n            </div>\n          </div>\n\n          <div class=\"grid grid-cols-4 gap-3\">\n            @for (img of currentVariant().images; track img.id; let idx = $index) {\n              <button type=\"button\" [class]=\"thumbClass(idx)\" (click)=\"activeImageIndex.set(idx)\">\n                <img [src]=\"img.url\" [alt]=\"img.alt\" class=\"size-full object-cover\" />\n              </button>\n            }\n          </div>\n\n          <div class=\"border-border bg-muted/20 grid grid-cols-3 gap-3 rounded-lg border p-3 text-center text-xs\">\n            <div class=\"flex flex-col items-center gap-1\">\n              <lucide-icon [img]=\"Truck\" class=\"text-primary size-4\" />\n              <span class=\"text-foreground font-medium\">Free 2-Day Air</span>\n              <span class=\"text-muted-foreground text-xs\">Orders over $150</span>\n            </div>\n            <div class=\"border-border/80 flex flex-col items-center gap-1 border-x px-2\">\n              <lucide-icon [img]=\"RotateCcw\" class=\"text-success size-4\" />\n              <span class=\"text-foreground font-medium\">45-Day Trial</span>\n              <span class=\"text-muted-foreground text-xs\">Zero-risk return</span>\n            </div>\n            <div class=\"flex flex-col items-center gap-1\">\n              <lucide-icon [img]=\"ShieldCheck\" class=\"text-info size-4\" />\n              <span class=\"text-foreground font-medium\">3-Yr Warranty</span>\n              <span class=\"text-muted-foreground text-xs\">Direct factory support</span>\n            </div>\n          </div>\n        </div>\n\n        <!-- Right Column: Buy Box & Product Configuration -->\n        <div class=\"space-y-6 lg:col-span-5\">\n          <div class=\"space-y-2\">\n            <div class=\"text-muted-foreground flex items-center gap-2 font-mono text-xs\">\n              <span>SKU: {{ currentVariant().sku }}</span>\n              <span>·</span>\n              <span>Made in Germany</span>\n            </div>\n\n            <h1 class=\"text-foreground text-2xl font-bold tracking-tight sm:text-3xl\">\n              Apex Pro Reference Planar Studio Headphones\n            </h1>\n\n            <div class=\"flex items-center gap-2 pt-1 text-xs\">\n              <div class=\"text-warning flex items-center gap-1\">\n                <lucide-icon [img]=\"Star\" class=\"fill-warning size-3.5\" />\n                <lucide-icon [img]=\"Star\" class=\"fill-warning size-3.5\" />\n                <lucide-icon [img]=\"Star\" class=\"fill-warning size-3.5\" />\n                <lucide-icon [img]=\"Star\" class=\"fill-warning size-3.5\" />\n                <lucide-icon [img]=\"Star\" class=\"fill-warning size-3.5\" />\n              </div>\n              <span class=\"text-foreground font-semibold\">4.9</span>\n              <span class=\"text-muted-foreground\">(342 Verified Mastering Reviews)</span>\n            </div>\n          </div>\n\n          <ui-separator />\n\n          <div class=\"space-y-1.5\">\n            <div class=\"flex items-baseline gap-3\">\n              <span class=\"text-foreground text-3xl font-extrabold tracking-tight\">\n                \\${{ currentVariant().price }}\n              </span>\n              <span class=\"text-muted-foreground text-base line-through\"> \\${{ currentVariant().originalPrice }} </span>\n              <span ui-badge variant=\"secondary\" class=\"text-success font-mono text-xs font-bold\">\n                Save \\${{ currentVariant().originalPrice - currentVariant().price }} (20% OFF)\n              </span>\n            </div>\n            <p class=\"text-muted-foreground text-xs\">\n              Interest-free installments of \\${{ (currentVariant().price / 4).toFixed(2) }}/mo with Affirm or Klarna.\n            </p>\n          </div>\n\n          <div class=\"space-y-2.5\">\n            <div class=\"flex items-center justify-between text-xs\">\n              <span class=\"text-foreground font-medium\">Finish / Enclosure:</span>\n              <span class=\"text-muted-foreground font-mono font-semibold\">{{ currentVariant().name }}</span>\n            </div>\n\n            <div class=\"flex items-center gap-3\">\n              @for (v of finishVariants; track v.id) {\n                <button type=\"button\" [class]=\"swatchClass(v.id)\" (click)=\"selectVariant(v)\" [attr.aria-label]=\"v.name\">\n                  <span\n                    class=\"size-6 rounded-full border border-black/10 shadow-2xs\"\n                    [style.backgroundColor]=\"v.colorHex\"\n                  ></span>\n                </button>\n              }\n            </div>\n          </div>\n\n          <div class=\"space-y-2.5\">\n            <div class=\"flex items-center justify-between text-xs\">\n              <span class=\"text-foreground font-medium\">Primary Studio Cable Termination:</span>\n              <span class=\"text-primary font-mono text-xs\">Included in package</span>\n            </div>\n\n            <div class=\"grid grid-cols-3 gap-2 text-xs\">\n              <button type=\"button\" [class]=\"cableClass('4.4mm')\" (click)=\"selectedCable.set('4.4mm')\">\n                <div class=\"font-mono text-xs font-semibold\">4.4mm Balanced</div>\n                <div class=\"text-muted-foreground text-xs\">Pentaconn TRRRS</div>\n              </button>\n\n              <button type=\"button\" [class]=\"cableClass('3.5mm')\" (click)=\"selectedCable.set('3.5mm')\">\n                <div class=\"font-mono text-xs font-semibold\">3.5mm SE + 6.35mm</div>\n                <div class=\"text-muted-foreground text-xs\">Screw Adapter</div>\n              </button>\n\n              <button type=\"button\" [class]=\"cableClass('xlr')\" (click)=\"selectedCable.set('xlr')\">\n                <div class=\"font-mono text-xs font-semibold\">4-Pin XLR Pro</div>\n                <div class=\"text-muted-foreground text-xs\">Neutrik Studio</div>\n              </button>\n            </div>\n          </div>\n\n          <label\n            class=\"border-border bg-muted/20 hover:bg-muted/30 flex cursor-pointer items-start gap-3 rounded-lg border p-3 text-xs transition-colors\"\n          >\n            <input\n              type=\"checkbox\"\n              [checked]=\"addExtendedWarranty()\"\n              (change)=\"addExtendedWarranty.set($any($event.target).checked)\"\n              class=\"border-border text-primary focus:ring-primary mt-0.5 size-4 rounded\"\n            />\n            <span class=\"space-y-0.5\">\n              <span class=\"flex items-center justify-between\">\n                <span class=\"text-foreground font-semibold\">Add 3-Year Apex Care+ Accidental Protection</span>\n                <span class=\"text-foreground font-mono font-bold\">+$49.00</span>\n              </span>\n              <span class=\"text-muted-foreground block text-xs\">\n                Covers accidental drops, driver voice-coil failure, and free earpad replacement.\n              </span>\n            </span>\n          </label>\n\n          <div class=\"space-y-1.5 rounded-lg border border-orange-500/30 bg-orange-500/5 p-3 text-xs\">\n            <div class=\"flex items-center justify-between\">\n              <div class=\"flex items-center gap-1.5 font-semibold text-orange-600 dark:text-orange-400\">\n                <lucide-icon [img]=\"Flame\" class=\"size-3.5 fill-current\" />\n                <span>Fulfillment Hub Stock Level</span>\n              </div>\n              <span class=\"text-foreground font-mono font-bold\">{{ currentVariant().stockCount }} units remaining</span>\n            </div>\n            <p class=\"text-muted-foreground text-xs\">\n              High demand: 18 sound engineers have this item in their active checkout carts.\n            </p>\n          </div>\n\n          <div class=\"space-y-3 pt-2\">\n            <div class=\"flex items-center gap-3\">\n              <div class=\"border-border bg-background flex h-10 items-center rounded-lg border shadow-2xs\">\n                <button\n                  type=\"button\"\n                  class=\"text-muted-foreground hover:text-foreground flex size-9 items-center justify-center\"\n                  (click)=\"decrementQty()\"\n                  aria-label=\"Decrease quantity\"\n                >\n                  <lucide-icon [img]=\"Minus\" class=\"size-3.5\" />\n                </button>\n                <span class=\"text-foreground w-8 text-center font-mono text-xs font-semibold\">{{ quantity() }}</span>\n                <button\n                  type=\"button\"\n                  class=\"text-muted-foreground hover:text-foreground flex size-9 items-center justify-center\"\n                  (click)=\"incrementQty()\"\n                  aria-label=\"Increase quantity\"\n                >\n                  <lucide-icon [img]=\"Plus\" class=\"size-3.5\" />\n                </button>\n              </div>\n\n              <button ui-button class=\"h-10 flex-1 gap-2 font-medium shadow-xs\" (click)=\"handleAddToCart()\">\n                <lucide-icon [img]=\"ShoppingCart\" class=\"size-4\" />\n                <span>Add to Cart · \\${{ finalPrice() }}</span>\n              </button>\n            </div>\n\n            <button\n              ui-button\n              variant=\"secondary\"\n              class=\"border-border h-10 w-full gap-2 border font-semibold shadow-2xs\"\n              (click)=\"handleExpressBuy()\"\n            >\n              <lucide-icon [img]=\"Zap\" class=\"fill-warning text-warning size-4\" />\n              <span>Instant 1-Click Checkout (Apple Pay / G-Pay)</span>\n            </button>\n\n            @if (cartNotice(); as notice) {\n              <p class=\"border-success/30 bg-success/10 text-success rounded-lg border px-3 py-2 text-xs font-medium\">\n                {{ notice }}\n              </p>\n            }\n          </div>\n\n          <div class=\"border-border bg-muted/20 flex items-center gap-2 rounded-lg border p-2.5 text-xs\">\n            <lucide-icon [img]=\"Truck\" class=\"text-muted-foreground size-4 shrink-0\" />\n            <span class=\"text-muted-foreground\">Deliver to:</span>\n            <ui-input\n              [value]=\"zipCode()\"\n              (valueChange)=\"zipCode.set($event)\"\n              maxlength=\"5\"\n              class=\"h-7 w-20 text-center font-mono text-xs\"\n            />\n            <span class=\"text-foreground font-medium\">Fast Delivery: <strong>Tomorrow, 2:00 PM</strong></span>\n          </div>\n        </div>\n      </div>\n\n      <!-- Section 2: Flash Sale & Multi-Buy Tier Deal Bar -->\n      <div class=\"space-y-3\">\n        <div class=\"border-destructive/30 bg-destructive/5 rounded-xl border p-4 sm:p-5\">\n          <div class=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n            <div class=\"flex items-center gap-2\">\n              <lucide-icon [img]=\"Flame\" class=\"text-destructive size-4 fill-current\" />\n              <p class=\"text-foreground text-sm font-semibold\">Audio Pro Week: Limited Master Batch 04</p>\n            </div>\n            <p class=\"text-muted-foreground font-mono text-xs\">\n              {{ claimedPercent }}% claimed · Only {{ currentVariant().stockCount }} left at this price\n            </p>\n          </div>\n          <div class=\"bg-destructive/20 mt-3 h-2 overflow-hidden rounded-full\">\n            <div class=\"bg-destructive h-full rounded-full\" [style.width]=\"claimedPercent + '%'\"></div>\n          </div>\n        </div>\n      </div>\n\n      <!-- Section 3: Frequently Bought Together Bundle -->\n      <div class=\"space-y-4\">\n        <div class=\"flex items-center gap-2\">\n          <lucide-icon [img]=\"Package\" class=\"text-primary size-4\" />\n          <h2 class=\"text-foreground text-lg font-semibold tracking-tight\">Frequently Bought Together</h2>\n        </div>\n        <div class=\"border-border bg-card grid grid-cols-1 gap-3 rounded-xl border p-4 sm:grid-cols-3\">\n          @for (item of bundleItems; track item.id) {\n            <div class=\"border-border bg-muted/20 rounded-lg border p-3\">\n              <p class=\"text-foreground text-xs font-semibold\">{{ item.name }}</p>\n              <p class=\"text-muted-foreground mt-0.5 text-xs\">{{ item.detail }}</p>\n              <p class=\"text-foreground mt-1.5 font-mono text-xs font-bold\">+\\${{ item.price }}</p>\n            </div>\n          }\n        </div>\n        <button ui-button size=\"sm\" class=\"gap-1.5 text-xs shadow-xs\" (click)=\"addBundleToCart()\">\n          <lucide-icon [img]=\"ShoppingCart\" class=\"size-3.5\" />\n          <span>Add 3 Items to Cart · \\${{ bundleTotal }}</span>\n        </button>\n      </div>\n\n      <!-- Section 4: Engineering & Technical Specifications Sheet -->\n      <div class=\"space-y-4\">\n        <div class=\"flex items-center gap-2\">\n          <lucide-icon [img]=\"Cpu\" class=\"text-primary size-4\" />\n          <h2 class=\"text-foreground text-lg font-semibold tracking-tight\">Engineering & Technical Specifications</h2>\n          <span ui-badge variant=\"outline\" class=\"font-mono text-xs\">APX-950-PRO</span>\n        </div>\n        <div class=\"border-border overflow-hidden rounded-xl border\">\n          @for (row of specRows; track row.label; let last = $last) {\n            <div\n              class=\"grid grid-cols-[160px_1fr] gap-3 px-4 py-2.5 text-xs\"\n              [class.border-b]=\"!last\"\n              [class.border-border]=\"!last\"\n            >\n              <span class=\"text-muted-foreground font-medium\">{{ row.label }}</span>\n              <span class=\"text-foreground\">{{ row.value }}</span>\n            </div>\n          }\n        </div>\n      </div>\n\n      <!-- Section 5: Verified Customer Reviews & Photo Breakdown -->\n      <div class=\"space-y-4\">\n        <div class=\"flex items-center gap-2\">\n          <lucide-icon [img]=\"Star\" class=\"text-warning fill-warning size-4\" />\n          <h2 class=\"text-foreground text-lg font-semibold tracking-tight\">Verified Customer Reviews</h2>\n          <span ui-badge variant=\"secondary\" class=\"font-mono text-xs\">4.9 · 342 reviews</span>\n        </div>\n        <div class=\"grid grid-cols-1 gap-3 md:grid-cols-2\">\n          <div class=\"border-border bg-card rounded-xl border p-4\">\n            <div class=\"flex items-center justify-between\">\n              <p class=\"text-foreground text-xs font-semibold\">Marcus T. · Mix Engineer, Berlin</p>\n              <span ui-badge variant=\"outline\" class=\"border-success/30 bg-success/10 text-success gap-1 text-xs\">\n                <lucide-icon [img]=\"BadgeCheck\" class=\"size-3\" />\n                Verified buyer\n              </span>\n            </div>\n            <div class=\"text-warning mt-2 flex items-center gap-0.5\">\n              <lucide-icon [img]=\"Star\" class=\"fill-warning size-3\" />\n              <lucide-icon [img]=\"Star\" class=\"fill-warning size-3\" />\n              <lucide-icon [img]=\"Star\" class=\"fill-warning size-3\" />\n              <lucide-icon [img]=\"Star\" class=\"fill-warning size-3\" />\n              <lucide-icon [img]=\"Star\" class=\"fill-warning size-3\" />\n            </div>\n            <p class=\"text-muted-foreground mt-2 text-xs leading-relaxed\">\n              Translation is scary good — mixes move to monitors with zero surprises. The 4.4mm balanced drive has\n              headroom for days.\n            </p>\n            <button\n              ui-button\n              variant=\"ghost\"\n              size=\"sm\"\n              class=\"text-muted-foreground mt-2 h-auto gap-1 p-0 text-xs\"\n              (click)=\"markHelpful('review-1')\"\n            >\n              <lucide-icon [img]=\"ThumbsUp\" class=\"size-3\" />\n              <span>Helpful ({{ helpfulCount('review-1') }})</span>\n            </button>\n          </div>\n          <div class=\"border-border bg-card rounded-xl border p-4\">\n            <div class=\"flex items-center justify-between\">\n              <p class=\"text-foreground text-xs font-semibold\">Yuki S. · Mastering, Tokyo</p>\n              <span ui-badge variant=\"outline\" class=\"border-success/30 bg-success/10 text-success gap-1 text-xs\">\n                <lucide-icon [img]=\"BadgeCheck\" class=\"size-3\" />\n                Verified buyer\n              </span>\n            </div>\n            <div class=\"text-warning mt-2 flex items-center gap-0.5\">\n              <lucide-icon [img]=\"Star\" class=\"fill-warning size-3\" />\n              <lucide-icon [img]=\"Star\" class=\"fill-warning size-3\" />\n              <lucide-icon [img]=\"Star\" class=\"fill-warning size-3\" />\n              <lucide-icon [img]=\"Star\" class=\"fill-warning size-3\" />\n              <lucide-icon [img]=\"Star\" class=\"fill-warning size-3\" />\n            </div>\n            <p class=\"text-muted-foreground mt-2 text-xs leading-relaxed\">\n              Wore them for a 9-hour session with no fatigue. Earpads and clamping force are the best I have tested at\n              any price.\n            </p>\n            <button\n              ui-button\n              variant=\"ghost\"\n              size=\"sm\"\n              class=\"text-muted-foreground mt-2 h-auto gap-1 p-0 text-xs\"\n              (click)=\"markHelpful('review-2')\"\n            >\n              <lucide-icon [img]=\"ThumbsUp\" class=\"size-3\" />\n              <span>Helpful ({{ helpfulCount('review-2') }})</span>\n            </button>\n          </div>\n        </div>\n      </div>\n\n      <!-- Section 6: Customer & Staff Q&A Community -->\n      <div class=\"space-y-4\">\n        <div class=\"flex items-center gap-2\">\n          <lucide-icon [img]=\"MessagesSquare\" class=\"text-primary size-4\" />\n          <h2 class=\"text-foreground text-lg font-semibold tracking-tight\">Customer & Staff Q&A</h2>\n        </div>\n        <p class=\"text-muted-foreground text-xs\">\n          Questions about the Apex Pro Reference Planar Headphones, answered by owners and factory staff.\n        </p>\n        <div class=\"space-y-3\">\n          <div class=\"border-border bg-card rounded-xl border p-4\">\n            <p class=\"text-foreground flex items-start gap-2 text-xs font-semibold\">\n              <lucide-icon [img]=\"HelpCircle\" class=\"text-primary mt-0.5 size-3.5 shrink-0\" />\n              Does the APX-950-PRO need a dedicated headphone amp?\n            </p>\n            <p class=\"text-muted-foreground mt-2 pl-5.5 text-xs leading-relaxed\">\n              <span class=\"text-success font-semibold\">Staff answer:</span> At 32Ω it runs fine from a modern interface,\n              but a balanced 4.4mm output tightens sub-bass control noticeably.\n            </p>\n          </div>\n          <div class=\"border-border bg-card rounded-xl border p-4\">\n            <p class=\"text-foreground flex items-start gap-2 text-xs font-semibold\">\n              <lucide-icon [img]=\"HelpCircle\" class=\"text-primary mt-0.5 size-3.5 shrink-0\" />\n              Are the earpads user-replaceable?\n            </p>\n            <p class=\"text-muted-foreground mt-2 pl-5.5 text-xs leading-relaxed\">\n              <span class=\"text-success font-semibold\">Staff answer:</span> Yes — magnetic mounts swap in seconds, and\n              Apex Care+ covers one free replacement pair.\n            </p>\n          </div>\n        </div>\n        <div class=\"flex flex-col gap-2 sm:flex-row\">\n          <ui-input\n            [value]=\"question()\"\n            (valueChange)=\"question.set($event)\"\n            placeholder=\"Ask about fit, drivability, or warranty...\"\n            class=\"flex-1 text-xs\"\n          />\n          <button ui-button size=\"sm\" class=\"gap-1.5 text-xs\" (click)=\"askQuestion()\">\n            <lucide-icon [img]=\"MessagesSquare\" class=\"size-3.5\" />\n            Ask a Question\n          </button>\n        </div>\n      </div>\n    </div>\n  `,\n})\nexport class UiProductDetailPageComponent {\n  protected readonly BadgeCheck = BadgeCheck\n  protected readonly ChevronRight = ChevronRight\n  protected readonly Cpu = Cpu\n  protected readonly Flame = Flame\n  protected readonly Heart = Heart\n  protected readonly HelpCircle = HelpCircle\n  protected readonly MessagesSquare = MessagesSquare\n  protected readonly Minus = Minus\n  protected readonly Package = Package\n  protected readonly Plus = Plus\n  protected readonly RotateCcw = RotateCcw\n  protected readonly Share2 = Share2\n  protected readonly ShieldCheck = ShieldCheck\n  protected readonly ShoppingCart = ShoppingCart\n  protected readonly Star = Star\n  protected readonly ThumbsUp = ThumbsUp\n  protected readonly Truck = Truck\n  protected readonly Zap = Zap\n\n  protected readonly finishVariants = variants\n  protected readonly bundleItems = BUNDLE_ITEMS\n  protected readonly bundleTotal = BUNDLE_ITEMS.reduce((acc, item) => acc + item.price, 0)\n  protected readonly specRows = SPEC_ROWS\n  protected readonly claimedPercent = 82\n\n  @Input() set initialVariantId(v: string | undefined) {\n    if (v) this.selectedVariantId.set(v)\n  }\n  @Input('class') className?: string\n\n  readonly selectedVariantId = signal(variants[0].id)\n  readonly activeImageIndex = signal(0)\n  readonly quantity = signal(1)\n  readonly selectedCable = signal<CableKey>('4.4mm')\n  readonly isWishlisted = signal(false)\n  readonly addExtendedWarranty = signal(true)\n  readonly zipCode = signal('94103')\n  readonly cartNotice = signal<string | null>(null)\n  readonly question = signal('')\n  readonly helpfulVotes = signal<Record<string, number>>({ 'review-1': 24, 'review-2': 11 })\n\n  readonly currentVariant = computed(() => variants.find((v) => v.id === this.selectedVariantId()) ?? variants[0])\n\n  readonly activeImageUrl = computed(() => {\n    const variant = this.currentVariant()\n    return variant.images[this.activeImageIndex()]?.url ?? variant.images[0].url\n  })\n\n  readonly finalPrice = computed(() => {\n    let base = this.currentVariant().price * this.quantity()\n    if (this.addExtendedWarranty()) base += 49\n    return base\n  })\n\n  get rootClass(): string {\n    return cn('bg-background text-foreground w-full space-y-10', this.className)\n  }\n\n  wishlistBtnClass(): string {\n    return cn(\n      'flex size-8 items-center justify-center rounded-full border shadow-2xs backdrop-blur-xs transition-colors border-border bg-background/90',\n      this.isWishlisted() ? 'text-destructive' : 'text-muted-foreground hover:text-foreground',\n    )\n  }\n\n  thumbClass(idx: number): string {\n    return cn(\n      'bg-muted/20 relative aspect-4/3 overflow-hidden rounded-lg border transition-colors',\n      this.activeImageIndex() === idx\n        ? 'border-primary ring-primary/40 ring-2'\n        : 'border-border opacity-70 hover:opacity-100',\n    )\n  }\n\n  swatchClass(id: string): string {\n    return cn(\n      'group relative flex size-9 items-center justify-center rounded-full border transition-colors',\n      this.selectedVariantId() === id\n        ? 'border-primary ring-primary ring-offset-background ring-2 ring-offset-2'\n        : 'border-border hover:border-muted-foreground',\n    )\n  }\n\n  cableClass(key: CableKey): string {\n    return cn(\n      'rounded-lg border p-2.5 text-center transition-colors',\n      this.selectedCable() === key\n        ? 'border-primary bg-primary/5 text-primary ring-primary font-semibold ring-1'\n        : 'border-border bg-card text-foreground hover:bg-muted/40',\n    )\n  }\n\n  helpfulCount(id: string): number {\n    return this.helpfulVotes()[id] ?? 0\n  }\n\n  markHelpful(id: string): void {\n    this.helpfulVotes.update((prev) => ({ ...prev, [id]: (prev[id] ?? 0) + 1 }))\n  }\n\n  selectVariant(v: ProductVariant): void {\n    this.selectedVariantId.set(v.id)\n    this.activeImageIndex.set(0)\n  }\n\n  incrementQty(): void {\n    if (this.quantity() < this.currentVariant().stockCount) {\n      this.quantity.update((q) => q + 1)\n    }\n  }\n\n  decrementQty(): void {\n    if (this.quantity() > 1) {\n      this.quantity.update((q) => q - 1)\n    }\n  }\n\n  handleAddToCart(): void {\n    // The Vue/React blocks use window.alert here; Angular renders the same confirmation\n    // copy inline so it stays testable under jsdom and never blocks the event loop.\n    this.cartNotice.set(\n      `Added ${this.quantity()}x ${this.currentVariant().name} (${this.selectedCable()}) to cart. Total: $${this.finalPrice()}`,\n    )\n  }\n\n  shareLink(): void {\n    this.cartNotice.set('Share link copied to clipboard!')\n  }\n\n  handleExpressBuy(): void {\n    this.cartNotice.set(`Initiating Express Apple Pay checkout for $${this.finalPrice()}...`)\n  }\n\n  addBundleToCart(): void {\n    this.cartNotice.set(`Added bundle (3 items) to cart. Total: $${this.bundleTotal}`)\n  }\n\n  askQuestion(): void {\n    const q = this.question().trim()\n    if (!q) return\n    this.cartNotice.set('Question posted — factory staff typically reply within 24 hours.')\n    this.question.set('')\n  }\n}\n",
      "type": "registry:page",
      "target": "~/src/app/components/blocks/product-detail-page/product-detail-page.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/product-detail-page/index.ts",
      "content": "export { UiProductDetailPageComponent, variants, type ProductVariant } from './product-detail-page.component'\n",
      "type": "registry:page",
      "target": "~/src/app/components/blocks/product-detail-page/index.ts"
    }
  ],
  "dependencies": [
    "lucide-angular"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/angular/badge.json",
    "https://uipkge.dev/r/angular/button.json",
    "https://uipkge.dev/r/angular/input.json",
    "https://uipkge.dev/r/angular/separator.json"
  ],
  "description": "Flagship e-commerce product detail page with multi-angle gallery, finish & cable selectors, stock urgency counter, warranty upsell, flash sale countdown bar, frequently bought together bundle, technical specs sheet, customer reviews breakdown, and community Q&A.",
  "categories": [
    "commerce",
    "ecommerce"
  ]
}