Menu

Change language

GitHub repo

Seat Pricing Matrix

blockmarketing

Comprehensive enterprise pricing workbench with monthly/annual billing cycle toggle, currency selector (USD/EUR/GBP), team seat simulator slider, dynamic add-on calculators, and an expandable side-by-side feature comparison matrix.

Installation

$npx shadcn@latest add https://uipkge.dev/r/lit/pricing-01.json
Manifest:https://uipkge.dev/r/lit/pricing-01.jsonInstalls to:src/uip/blocks/pricing-01/

Variants

Loading interactive previews…

Schema

Type aliases exported from this item's source. Use these to shape the data you pass in.

HTMLElementTagNameMap
interface HTMLElementTagNameMap {
    'uip-pricing-01': UipPricing01
  }
}

Files installed (1)

  • src/uip/blocks/pricing-01/pricing-01.ts30.6 kB
    import { LitElement, css, html } from 'lit'
    import { ArrowRight, Check, ChevronDown, ChevronUp, ShieldCheck, Users, Zap } from 'lucide'
    import { cn } from '../../lib/utils'
    import { tailwind } from '../../lib/styles'
    import { ThemeController } from '../../lib/theme'
    import { icon } from '../../lib/icon'
    // Side-effect imports: register the composed elements for standalone use
    // (consumers who install only this block still get working primitives).
    import '../../components/badge/badge'
    import '../../components/button/button'
    import '../../components/card/card'
    import '../../components/separator/separator'
    import '../../components/slider/slider'
    import '../../components/switch/switch'
    import '../../components/toggle-group/toggle-group'
    import type { UipToggleGroup } from '../../components/toggle-group/toggle-group'
    
    type BillingCycle = 'monthly' | 'yearly'
    type Currency = 'USD' | 'EUR' | 'GBP'
    
    const currencySymbols: Record<Currency, string> = {
      USD: '$',
      EUR: '€',
      GBP: '£',
    }
    
    const currencyRates: Record<Currency, number> = {
      USD: 1.0,
      EUR: 0.92,
      GBP: 0.79,
    }
    
    const comparisonMatrix = [
      {
        category: 'Platform & Compute Core',
        features: [
          { name: 'Active Team Members', starter: 'Up to 10', team: 'Unlimited', enterprise: 'Unlimited + Org Units' },
          { name: 'Monthly API Requests', starter: '100,000 / mo', team: '2,500,000 / mo', enterprise: 'Custom Unlimited' },
          { name: 'Workflow Automations', starter: '10 active', team: '100 active', enterprise: 'Unlimited real-time' },
          { name: 'Data Retention History', starter: '30 days', team: '365 days', enterprise: '7 years immutable' },
        ],
      },
      {
        category: 'Security & Enterprise Governance',
        features: [
          {
            name: 'SOC 2 Type II & ISO 27001',
            starter: 'Standard',
            team: 'Included',
            enterprise: 'Included + Auditor Portal',
          },
          { name: 'SAML SSO & SCIM Provisioning', starter: '—', team: 'Google / Okta', enterprise: 'Custom IdP + SCIM v2' },
          {
            name: 'Role-Based Access (RBAC)',
            starter: '3 predefined roles',
            team: 'Granular permissions',
            enterprise: 'Custom policy engine',
          },
          {
            name: 'Immutable Audit Trail Logs',
            starter: '—',
            team: '90 days exportable',
            enterprise: 'Real-time SIEM streaming',
          },
        ],
      },
      {
        category: 'Support & Success SLAs',
        features: [
          {
            name: 'Support Channel',
            starter: 'Community & Email',
            team: 'Priority Email + Chat',
            enterprise: 'Dedicated Private Slack',
          },
          {
            name: 'First-Response SLA',
            starter: '24 business hours',
            team: '4 business hours',
            enterprise: '< 15 mins (24/7/365)',
          },
          { name: 'Uptime SLA Guarantee', starter: '99.9%', team: '99.95%', enterprise: '99.99% financially backed' },
          { name: 'Dedicated Solutions Architect', starter: '—', team: '—', enterprise: 'Assigned Principal Engineer' },
        ],
      },
    ]
    
    // Rendered class strings of the registry Table primitives verbatim
    // (packages/registry-react/components/table/table.tsx), composed with cn()
    // exactly like the React block does.
    const rowBase = 'hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors duration-150'
    const headBase =
      "text-foreground h-10 px-3 text-left align-middle text-sm font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]"
    const cellBase =
      "px-3 py-2 align-middle text-sm whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]"
    
    /**
     * <uip-pricing-01> — the registry Pricing01 block as a web component.
     *
     * Class strings are React's Pricing01 verbatim. React state (useState) becomes
     * @state fields; the billing/currency switchers become <uip-toggle-group>
     * (value + value-change, with React's `v && set` guard), the seat simulator
     * becomes <uip-slider> (value + value-change), the add-ons become
     * <uip-switch> (.checked + checked-change), and the comparison matrix is a
     * native table carrying the registry Table's rendered classes verbatim.
     */
    export class UipPricing01 extends LitElement {
      static shadowRootOptions = { ...LitElement.shadowRootOptions, delegatesFocus: true }
      // :host display can't be a utility class (the host has no template of its own).
      static styles = [tailwind, css`:host { display: block; }`]
    
      static properties = {
        billingCycle: { state: true },
        currency: { state: true },
        teamSeats: { state: true },
        addDedicatedSla: { state: true },
        addAuditVault: { state: true },
        showComparisonTable: { state: true },
      }
    
      private billingCycle: BillingCycle = 'yearly'
      private currency: Currency = 'USD'
      private teamSeats: number[] = [12]
      private addDedicatedSla = false
      private addAuditVault = false
      private showComparisonTable = false
    
      constructor() {
        super()
        new ThemeController(this)
      }
    
      connectedCallback() {
        super.connectedCallback()
        this.setAttribute('data-uipkge', '')
        this.setAttribute('data-slot', 'pricing-01')
      }
    
      // React guards onValueChange with `v && setBillingCycle(v)`: clicking the
      // pressed item must keep the old value. The group clears itself internally
      // first, so push the kept value back to stay in sync.
      private onSingleToggle(id: string, value: string | string[], apply: (v: string) => void) {
        if (typeof value === 'string' && value) {
          apply(value)
          return
        }
        const el = this.renderRoot.querySelector(id) as UipToggleGroup | null
        if (el) el.value = (el.value || value) as string
        this.requestUpdate()
      }
    
      render() {
        const rates = currencyRates[this.currency]
        const sym = currencySymbols[this.currency]
    
        const starterBase = this.billingCycle === 'yearly' ? 12 : 15
        const teamBase = this.billingCycle === 'yearly' ? 28 : 35
        const enterpriseBase = this.billingCycle === 'yearly' ? 68 : 85
    
        const slaCost = this.addDedicatedSla ? 99 : 0
        const vaultCost = this.addAuditVault ? 49 : 0
    
        const currentSeats = this.teamSeats[0] || 1
    
        const starterMonthlyTotal = Math.round((starterBase * currentSeats + (this.addAuditVault ? 29 : 0)) * rates)
        const teamMonthlyTotal = Math.round((teamBase * currentSeats + slaCost + vaultCost) * rates)
    
        const annualSavingsTeam = Math.round((35 * currentSeats * 12 - 28 * currentSeats * 12) * rates)
    
        return html`
          <section data-slot="pricing-01" class="bg-background w-full py-16 sm:py-24">
            <div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
              <div class="mx-auto max-w-3xl space-y-4 text-center">
                <div
                  class="border-primary/20 bg-primary/5 text-primary inline-flex items-center gap-2 rounded-full border px-3 py-1 text-xs font-medium shadow-2xs"
                >
                  ${icon(ShieldCheck, 'shield-check', 'size-3.5')}
                  <span>Predictable Enterprise Pricing</span>
                </div>
                <h2 class="text-foreground text-3xl font-bold tracking-tight sm:text-4xl lg:text-5xl">
                  Scale effortlessly without seat tax surprises
                </h2>
                <p class="text-muted-foreground text-base sm:text-lg">
                  Zero setup fees, transparent volume discounts, and instant self-serve provisioning. Switch or cancel
                  plans anytime.
                </p>
    
                <div class="mt-8 flex flex-wrap items-center justify-center gap-4 pt-2">
                  <div class="border-border bg-card inline-flex rounded-lg border p-1 shadow-2xs">
                    <uip-toggle-group
                      id="billing-toggle"
                      type="single"
                      .value=${this.billingCycle}
                      @value-change=${(e: CustomEvent<{ value: string | string[] }>) => {
                        this.onSingleToggle('#billing-toggle', e.detail.value, (v) => {
                          this.billingCycle = v as BillingCycle
                        })
                      }}
                    >
                      <uip-toggle-group-item value="monthly" class="px-3.5 py-1.5 text-xs font-medium">
                        Monthly
                      </uip-toggle-group-item>
                      <uip-toggle-group-item value="yearly" class="flex items-center gap-1.5 px-3.5 py-1.5 text-xs font-medium">
                        <span>Annual</span>
                        <uip-badge variant="secondary" class="bg-primary/10 text-primary border-primary/20 px-1.5 py-0 text-xs">
                          Save 20%
                        </uip-badge>
                      </uip-toggle-group-item>
                    </uip-toggle-group>
                  </div>
    
                  <div class="border-border bg-card inline-flex rounded-lg border p-1 shadow-2xs">
                    <uip-toggle-group
                      id="currency-toggle"
                      type="single"
                      .value=${this.currency}
                      @value-change=${(e: CustomEvent<{ value: string | string[] }>) => {
                        this.onSingleToggle('#currency-toggle', e.detail.value, (v) => {
                          this.currency = v as Currency
                        })
                      }}
                    >
                      <uip-toggle-group-item value="USD" class="px-2.5 py-1 font-mono text-xs font-medium">
                        USD ($)
                      </uip-toggle-group-item>
                      <uip-toggle-group-item value="EUR" class="px-2.5 py-1 font-mono text-xs font-medium">
                        EUR (€)
                      </uip-toggle-group-item>
                      <uip-toggle-group-item value="GBP" class="px-2.5 py-1 font-mono text-xs font-medium">
                        GBP (£)
                      </uip-toggle-group-item>
                    </uip-toggle-group>
                  </div>
                </div>
    
                <div class="border-border bg-card mx-auto mt-6 max-w-xl rounded-xl border p-4 shadow-2xs">
                  <div class="flex flex-wrap items-center justify-between gap-2 text-xs">
                    <div class="text-foreground flex items-center gap-2 font-medium">
                      ${icon(Users, 'users', 'text-primary size-4')}
                      <span>Simulate Team Size:</span>
                    </div>
                    <div class="flex items-center gap-2">
                      <span class="bg-muted text-foreground rounded px-2 py-0.5 font-mono text-xs font-semibold">
                        ${currentSeats} ${currentSeats === 1 ? 'seat' : 'seats'}
                      </span>
                      ${this.billingCycle === 'yearly' && annualSavingsTeam > 0
                        ? html`<span class="text-success text-xs font-medium">
                            (Saves ~${sym}${annualSavingsTeam.toLocaleString()}/yr on Team plan)
                          </span>`
                        : ''}
                    </div>
                  </div>
                  <div class="mt-3">
                    <uip-slider
                      class="cursor-pointer"
                      .value=${this.teamSeats}
                      min="1"
                      max="50"
                      step="1"
                      @value-change=${(e: CustomEvent<number[]>) => {
                        this.teamSeats = e.detail
                      }}
                    ></uip-slider>
                  </div>
                  <div class="text-muted-foreground mt-2 flex justify-between font-mono text-xs">
                    <span>1 seat</span>
                    <span>25 seats</span>
                    <span>50+ seats</span>
                  </div>
                </div>
              </div>
    
              <div class="mt-12 grid grid-cols-1 gap-8 lg:grid-cols-3 lg:items-stretch">
                <uip-card
                  class="border-border bg-card hover:border-primary/40 relative flex flex-col justify-between shadow-xs transition-colors duration-200 hover:shadow-md"
                >
                  <div>
                    <uip-card-header class="pb-4">
                      <div class="flex items-center justify-between">
                        <uip-badge variant="outline" class="font-mono text-xs">Bootstrap & Indie</uip-badge>
                      </div>
                      <uip-card-title class="text-foreground text-xl font-bold tracking-tight">
                        Starter Studio
                      </uip-card-title>
                      <uip-card-description class="text-muted-foreground text-xs">
                        For agile squads and early-stage product teams validating core workflows.
                      </uip-card-description>
    
                      <div class="mt-6 space-y-1">
                        <div class="flex items-baseline gap-1.5">
                          <span class="text-foreground text-4xl font-bold tracking-tight">
                            ${sym}${Math.round(starterBase * rates)}
                          </span>
                          <span class="text-muted-foreground text-xs font-medium">/ seat / month</span>
                        </div>
                        <div class="text-muted-foreground font-mono text-xs">
                          Est. ${sym}${starterMonthlyTotal.toLocaleString()}/mo for ${currentSeats}
                          ${currentSeats === 1 ? 'seat' : 'seats'}
                        </div>
                      </div>
                    </uip-card-header>
    
                    <uip-card-content class="space-y-4 pt-2">
                      <uip-separator></uip-separator>
                      <div class="space-y-2.5">
                        <p class="text-muted-foreground text-xs font-semibold tracking-wider uppercase">
                          Included features
                        </p>
                        <ul class="text-foreground space-y-2.5 text-xs">
                          <li class="flex items-start gap-2">
                            ${icon(Check, 'check', 'text-success mt-0.5 size-4 shrink-0')}
                            <span>Up to 10 team seats & unlimited guests</span>
                          </li>
                          <li class="flex items-start gap-2">
                            ${icon(Check, 'check', 'text-success mt-0.5 size-4 shrink-0')}
                            <span>100,000 monthly API event calls</span>
                          </li>
                          <li class="flex items-start gap-2">
                            ${icon(Check, 'check', 'text-success mt-0.5 size-4 shrink-0')}
                            <span>30-day continuous audit & revision history</span>
                          </li>
                          <li class="flex items-start gap-2">
                            ${icon(Check, 'check', 'text-success mt-0.5 size-4 shrink-0')}
                            <span>Standard Community & Email support (24h)</span>
                          </li>
                          <li class="text-muted-foreground flex items-start gap-2">
                            ${icon(Check, 'check', 'text-muted-foreground/50 mt-0.5 size-4 shrink-0')}
                            <span>Community Discord access & quickstarts</span>
                          </li>
                        </ul>
                      </div>
                    </uip-card-content>
                  </div>
    
                  <uip-card-footer class="border-border mt-auto border-t pt-4">
                    <uip-button variant="outline" class="h-10 w-full gap-1.5 text-xs font-semibold">
                      <span>Start Free 14-Day Trial</span>
                      ${icon(ArrowRight, 'arrow-right', 'size-3.5')}
                    </uip-button>
                  </uip-card-footer>
                </uip-card>
    
                <uip-card
                  class="border-primary bg-card ring-primary/20 relative flex flex-col justify-between shadow-lg ring-2 transition-colors duration-200 hover:shadow-xl lg:-translate-y-2"
                >
                  <div
                    class="absolute -top-3.5 left-1/2 -translate-x-1/2"
                  >
                    <uip-badge class="bg-primary text-primary-foreground gap-1.5 px-3 py-0.5 text-xs font-semibold shadow-sm">
                      ${icon(Zap, 'zap', 'size-3 fill-current')}
                      <span>Most Popular Choice</span>
                    </uip-badge>
                  </div>
    
                  <div>
                    <uip-card-header class="pt-7 pb-4">
                      <div class="flex items-center justify-between">
                        <uip-badge variant="secondary" class="bg-primary/10 text-primary border-primary/20 font-mono text-xs">
                          Scale & High-Growth
                        </uip-badge>
                      </div>
                      <uip-card-title class="text-foreground text-2xl font-bold tracking-tight">Team Scale</uip-card-title>
                      <uip-card-description class="text-muted-foreground text-xs">
                        For fast-scaling engineering and product organizations requiring deep automation.
                      </uip-card-description>
    
                      <div class="mt-6 space-y-1">
                        <div class="flex items-baseline gap-1.5">
                          <span class="text-foreground text-4xl font-bold tracking-tight">
                            ${sym}${Math.round(teamBase * rates)}
                          </span>
                          <span class="text-muted-foreground text-xs font-medium">/ seat / month</span>
                        </div>
                        <div class="text-primary font-mono text-xs font-medium">
                          Est. ${sym}${teamMonthlyTotal.toLocaleString()}/mo for ${currentSeats}
                          ${currentSeats === 1 ? 'seat' : 'seats'}
                        </div>
                      </div>
                    </uip-card-header>
    
                    <uip-card-content class="space-y-4 pt-2">
                      <uip-separator></uip-separator>
                      <div class="space-y-2.5">
                        <p class="text-muted-foreground text-xs font-semibold tracking-wider uppercase">
                          Everything in Starter, plus
                        </p>
                        <ul class="text-foreground space-y-2.5 text-xs">
                          <li class="flex items-start gap-2">
                            ${icon(Check, 'check', 'text-success mt-0.5 size-4 shrink-0')}
                            <span class="font-medium">Unlimited team seats & custom workspace roles</span>
                          </li>
                          <li class="flex items-start gap-2">
                            ${icon(Check, 'check', 'text-success mt-0.5 size-4 shrink-0')}
                            <span>2.5M monthly API calls & priority queue</span>
                          </li>
                          <li class="flex items-start gap-2">
                            ${icon(Check, 'check', 'text-success mt-0.5 size-4 shrink-0')}
                            <span>Google & Okta SAML SSO integration</span>
                          </li>
                          <li class="flex items-start gap-2">
                            ${icon(Check, 'check', 'text-success mt-0.5 size-4 shrink-0')}
                            <span>365-day immutable compliance logs</span>
                          </li>
                          <li class="flex items-start gap-2">
                            ${icon(Check, 'check', 'text-success mt-0.5 size-4 shrink-0')}
                            <span>Priority ticketing with 4h guaranteed SLA</span>
                          </li>
                        </ul>
                      </div>
    
                      <div class="border-border bg-muted/30 space-y-2.5 rounded-lg border p-3">
                        <p class="text-foreground text-xs font-semibold">Optional Power Add-ons</p>
                        <div class="flex items-center justify-between text-xs">
                          <label for="lit-sla-addon" class="text-muted-foreground cursor-pointer">
                            24/7 Dedicated SLA (+${sym}${Math.round(99 * rates)}/mo)
                          </label>
                          <uip-switch
                            id="lit-sla-addon"
                            .checked=${this.addDedicatedSla}
                            @checked-change=${(e: CustomEvent<boolean>) => {
                              this.addDedicatedSla = e.detail
                            }}
                          ></uip-switch>
                        </div>
                        <div class="flex items-center justify-between text-xs">
                          <label for="lit-vault-addon" class="text-muted-foreground cursor-pointer">
                            SOC 2 Vault Streaming (+${sym}${Math.round(49 * rates)}/mo)
                          </label>
                          <uip-switch
                            id="lit-vault-addon"
                            .checked=${this.addAuditVault}
                            @checked-change=${(e: CustomEvent<boolean>) => {
                              this.addAuditVault = e.detail
                            }}
                          ></uip-switch>
                        </div>
                      </div>
                    </uip-card-content>
                  </div>
    
                  <uip-card-footer class="border-border mt-auto border-t pt-4">
                    <uip-button class="h-10 w-full gap-1.5 text-xs font-semibold shadow-sm">
                      <span>Deploy Team Workspace</span>
                      ${icon(ArrowRight, 'arrow-right', 'size-3.5')}
                    </uip-button>
                  </uip-card-footer>
                </uip-card>
    
                <uip-card
                  class="border-border bg-card hover:border-primary/40 relative flex flex-col justify-between shadow-xs transition-colors duration-200 hover:shadow-md"
                >
                  <div>
                    <uip-card-header class="pb-4">
                      <div class="flex items-center justify-between">
                        <uip-badge variant="outline" class="font-mono text-xs">Enterprise & Security</uip-badge>
                      </div>
                      <uip-card-title class="text-foreground text-xl font-bold tracking-tight">
                        Enterprise Suite
                      </uip-card-title>
                      <uip-card-description class="text-muted-foreground text-xs">
                        Dedicated infrastructure, custom security controls, and bespoke compliance SLAs.
                      </uip-card-description>
    
                      <div class="mt-6 space-y-1">
                        <div class="flex items-baseline gap-1.5">
                          <span class="text-foreground text-4xl font-bold tracking-tight">
                            ${sym}${Math.round(enterpriseBase * rates)}
                          </span>
                          <span class="text-muted-foreground text-xs font-medium">/ seat / month</span>
                        </div>
                        <div class="text-muted-foreground font-mono text-xs">
                          Custom volume licensing available for 100+ seats
                        </div>
                      </div>
                    </uip-card-header>
    
                    <uip-card-content class="space-y-4 pt-2">
                      <uip-separator></uip-separator>
                      <div class="space-y-2.5">
                        <p class="text-muted-foreground text-xs font-semibold tracking-wider uppercase">
                          Everything in Team, plus
                        </p>
                        <ul class="text-foreground space-y-2.5 text-xs">
                          <li class="flex items-start gap-2">
                            ${icon(Check, 'check', 'text-success mt-0.5 size-4 shrink-0')}
                            <span>Custom SCIM v2 user provisioning & directory sync</span>
                          </li>
                          <li class="flex items-start gap-2">
                            ${icon(Check, 'check', 'text-success mt-0.5 size-4 shrink-0')}
                            <span>Dedicated VPC peering & custom data residency</span>
                          </li>
                          <li class="flex items-start gap-2">
                            ${icon(Check, 'check', 'text-success mt-0.5 size-4 shrink-0')}
                            <span>99.99% uptime SLA with financial penalty backing</span>
                          </li>
                          <li class="flex items-start gap-2">
                            ${icon(Check, 'check', 'text-success mt-0.5 size-4 shrink-0')}
                            <span>Assigned Principal Solutions Engineer & private Slack</span>
                          </li>
                          <li class="flex items-start gap-2">
                            ${icon(Check, 'check', 'text-success mt-0.5 size-4 shrink-0')}
                            <span>Custom Master Service Agreement (MSA) & DPA</span>
                          </li>
                        </ul>
                      </div>
                    </uip-card-content>
                  </div>
    
                  <uip-card-footer class="border-border mt-auto border-t pt-4">
                    <uip-button variant="outline" class="h-10 w-full gap-1.5 text-xs font-semibold">
                      ${icon(ShieldCheck, 'shield-check', 'text-primary size-3.5')}
                      <span>Contact Solutions Team</span>
                    </uip-button>
                  </uip-card-footer>
                </uip-card>
              </div>
    
              <div class="mt-12 text-center">
                <uip-button
                  variant="ghost"
                  size="sm"
                  class="text-foreground hover:bg-muted gap-2 text-xs font-semibold"
                  @click=${() => {
                    this.showComparisonTable = !this.showComparisonTable
                  }}
                >
                  <span>
                    ${this.showComparisonTable ? 'Hide Detailed Feature Comparison' : 'Compare All Features & Enterprise Limits'}
                  </span>
                  ${this.showComparisonTable
                    ? icon(ChevronUp, 'chevron-up', 'size-4')
                    : icon(ChevronDown, 'chevron-down', 'size-4')}
                </uip-button>
              </div>
    
              ${this.showComparisonTable
                ? html`
                    <div class="border-border bg-card mt-8 overflow-hidden rounded-xl border shadow-xs">
                      <div class="border-border bg-muted/20 flex flex-wrap items-center justify-between gap-4 border-b p-4 sm:p-6">
                        <div>
                          <h3 class="text-foreground text-base font-bold">Detailed Specification & Limits</h3>
                          <p class="text-muted-foreground text-xs">
                            Comprehensive side-by-side breakdown across every tier.
                          </p>
                        </div>
                        <uip-badge variant="outline" class="font-mono text-xs">
                          All plans include SSL & automated backups
                        </uip-badge>
                      </div>
    
                      <div class="overflow-x-auto">
                        <div data-uipkge="" data-slot="table-container" class="relative w-full overflow-auto">
                          <table data-uipkge="" data-slot="table" class="w-full caption-bottom text-sm">
                            <thead data-uipkge="" data-slot="table-header" class="bg-muted/50 [&_tr]:border-b">
                              <tr data-uipkge="" data-slot="table-row" class=${cn(rowBase, 'bg-muted/40')}>
                                <th
                                  data-uipkge=""
                                  data-slot="table-head"
                                  class=${cn(headBase, 'text-foreground w-[34%] text-xs font-semibold')}
                                >
                                  Capabilities
                                </th>
                                <th
                                  data-uipkge=""
                                  data-slot="table-head"
                                  class=${cn(headBase, 'text-foreground w-[22%] text-xs font-semibold')}
                                >
                                  Starter Studio
                                </th>
                                <th
                                  data-uipkge=""
                                  data-slot="table-head"
                                  class=${cn(headBase, 'text-primary w-[22%] text-xs font-bold font-semibold')}
                                >
                                  Team Scale
                                </th>
                                <th
                                  data-uipkge=""
                                  data-slot="table-head"
                                  class=${cn(headBase, 'text-foreground w-[22%] text-xs font-semibold')}
                                >
                                  Enterprise Suite
                                </th>
                              </tr>
                            </thead>
                            <tbody data-uipkge="" data-slot="table-body" class="[&_tr:last-child]:border-0">
                              ${comparisonMatrix.map(
                                (group) => html`
                                  <tr
                                    data-uipkge=""
                                    data-slot="table-row"
                                    class=${cn(rowBase, 'bg-muted/60 text-muted-foreground text-xs font-semibold')}
                                  >
                                    <td
                                      data-uipkge=""
                                      data-slot="table-cell"
                                      colSpan="4"
                                      class=${cn(cellBase, 'py-2.5 font-mono text-xs tracking-wider uppercase')}
                                    >
                                      ${group.category}
                                    </td>
                                  </tr>
                                  ${group.features.map(
                                    (feat) => html`
                                      <tr data-uipkge="" data-slot="table-row" class=${cn(rowBase, 'text-xs')}>
                                        <td
                                          data-uipkge=""
                                          data-slot="table-cell"
                                          class=${cn(cellBase, 'text-foreground py-3 font-medium')}
                                        >
                                          ${feat.name}
                                        </td>
                                        <td
                                          data-uipkge=""
                                          data-slot="table-cell"
                                          class=${cn(cellBase, 'text-muted-foreground py-3')}
                                        >
                                          ${feat.starter}
                                        </td>
                                        <td
                                          data-uipkge=""
                                          data-slot="table-cell"
                                          class=${cn(cellBase, 'text-foreground bg-primary/5 py-3 font-medium')}
                                        >
                                          ${feat.team}
                                        </td>
                                        <td
                                          data-uipkge=""
                                          data-slot="table-cell"
                                          class=${cn(cellBase, 'text-foreground py-3')}
                                        >
                                          ${feat.enterprise}
                                        </td>
                                      </tr>
                                    `,
                                  )}
                                `,
                              )}
                            </tbody>
                          </table>
                        </div>
                      </div>
                    </div>
                  `
                : ''}
            </div>
          </section>
        `
      }
    }
    
    customElements.get('uip-pricing-01') || customElements.define('uip-pricing-01', UipPricing01)
    
    declare global {
      interface HTMLElementTagNameMap {
        'uip-pricing-01': UipPricing01
      }
    }
    

Raw manifest:https://uipkge.dev/r/lit/pricing-01.json