{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "trust-center-footer",
  "title": "Trust Center Footer",
  "description": "Compliance marks that expand to scope, over a logo row and link columns.",
  "registryDependencies": [
    "button",
    "tooltip"
  ],
  "files": [
    {
      "path": "components/spectrumui/blocks/footers/trust-center-footer.tsx",
      "content": "'use client';\n\nimport { Button } from '@/components/ui/button';\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';\nimport { cn } from '@/lib/utils';\nimport { IconArrowUpRight, IconShield, FooterBar, type FooterSocial } from './footer-kit';\n\ntype IconProps = React.SVGProps<SVGSVGElement>;\n\n/**\n * Six customer marks. Invented, not real companies — a logo row that ships with\n * somebody else's trademarks in it is wrong in every install. Straight lines,\n * rectangles and circles on a 24px grid, so the set stays crisp at 20px.\n */\nfunction MarkNorthwind(props: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\" {...props}>\n      <path d=\"M12 2 22 21.5 12 16.6 2 21.5 12 2Z\" />\n    </svg>\n  );\n}\n\nfunction MarkCobalt(props: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\" {...props}>\n      <path\n        fillRule=\"evenodd\"\n        clipRule=\"evenodd\"\n        d=\"M12 2 22 12 12 22 2 12 12 2Zm0 5.3L7.3 12l4.7 4.7 4.7-4.7L12 7.3Z\"\n      />\n    </svg>\n  );\n}\n\nfunction MarkMeridian(props: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\" {...props}>\n      <circle cx=\"12\" cy=\"12\" r=\"9\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.2\" />\n      <path d=\"M3.4 9h17.2M3.4 15h17.2\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.2\" />\n    </svg>\n  );\n}\n\nfunction MarkTessellate(props: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\" {...props}>\n      <path d=\"M3 3h8.4v8.4H3V3Z\" />\n      <path d=\"M12.6 3H21v8.4h-8.4V3Z\" opacity=\"0.45\" />\n      <path d=\"M3 12.6h8.4V21H3v-8.4Z\" opacity=\"0.45\" />\n      <path d=\"M12.6 12.6H21V21h-8.4v-8.4Z\" />\n    </svg>\n  );\n}\n\nfunction MarkLinework(props: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\" {...props}>\n      <rect x=\"3\" y=\"9\" width=\"4\" height=\"12\" rx=\"2\" opacity=\"0.45\" />\n      <rect x=\"10\" y=\"3.5\" width=\"4\" height=\"17.5\" rx=\"2\" />\n      <rect x=\"17\" y=\"12.5\" width=\"4\" height=\"8.5\" rx=\"2\" opacity=\"0.45\" />\n    </svg>\n  );\n}\n\nfunction MarkHollowCreek(props: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\" {...props}>\n      <circle cx=\"12\" cy=\"12\" r=\"8\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" />\n      <circle cx=\"12\" cy=\"12\" r=\"2.5\" />\n    </svg>\n  );\n}\n\n/* One word each. Two-word names truncate to an ellipsis in the two-column\n   mobile grid, and a logo row of half-names reads as broken rather than tight. */\n/**\n * Certification marks, drawn rather than imported as images.\n *\n * The badges were five identical green dots, which told a procurement reader\n * nothing — the whole point of a compliance row is that the marks are\n * recognisable before you read the label. These are silhouettes in each\n * standard's own colours: the EU ring of twelve stars for GDPR, an audit seal\n * for SOC 2, a certification rosette for ISO, a shield and cross for HIPAA, a\n * locked card for PCI. Trademarks belong to their respective bodies; swap in\n * the official artwork you are licensed to display before shipping.\n */\nfunction MarkSoc2(props: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\" {...props}>\n      <circle cx=\"12\" cy=\"12\" r=\"10\" fill=\"#1F4E79\" />\n      <circle\n        cx=\"12\"\n        cy=\"12\"\n        r=\"7\"\n        fill=\"none\"\n        stroke=\"#fff\"\n        strokeOpacity=\"0.55\"\n        strokeWidth=\"1.1\"\n      />\n      <path\n        d=\"m8.6 12.2 2.4 2.4 4.4-5\"\n        fill=\"none\"\n        stroke=\"#fff\"\n        strokeWidth=\"1.9\"\n        strokeLinecap=\"round\"\n        strokeLinejoin=\"round\"\n      />\n    </svg>\n  );\n}\n\nfunction MarkIso(props: IconProps) {\n  /* A certification rosette: twelve points around a disc. */\n  const points = Array.from({ length: 12 }, (_, i) => {\n    const a = (i / 12) * Math.PI * 2;\n    return `${(12 + Math.cos(a) * 10).toFixed(2)},${(12 + Math.sin(a) * 10).toFixed(2)}`;\n  }).join(' ');\n  return (\n    <svg viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\" {...props}>\n      <polygon points={points} fill=\"#4338CA\" />\n      <circle cx=\"12\" cy=\"12\" r=\"7.2\" fill=\"#fff\" fillOpacity=\"0.18\" />\n      <path d=\"M7 12h10\" stroke=\"#fff\" strokeWidth=\"1.9\" strokeLinecap=\"round\" />\n      <path\n        d=\"M9 9h6M9 15h6\"\n        stroke=\"#fff\"\n        strokeOpacity=\"0.6\"\n        strokeWidth=\"1.4\"\n        strokeLinecap=\"round\"\n      />\n    </svg>\n  );\n}\n\nfunction MarkGdpr(props: IconProps) {\n  /* The EU ring: twelve gold stars on reflex blue. Reading it as stars at 22px\n     needs discs, not five-point stars — the ring is what carries recognition. */\n  const stars = Array.from({ length: 12 }, (_, i) => {\n    const a = (i / 12) * Math.PI * 2 - Math.PI / 2;\n    return { x: 12 + Math.cos(a) * 7.2, y: 12 + Math.sin(a) * 7.2 };\n  });\n  return (\n    <svg viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\" {...props}>\n      <circle cx=\"12\" cy=\"12\" r=\"10\" fill=\"#003399\" />\n      {stars.map((star, i) => (\n        <circle key={i} cx={star.x.toFixed(2)} cy={star.y.toFixed(2)} r=\"1.15\" fill=\"#FFCC00\" />\n      ))}\n    </svg>\n  );\n}\n\nfunction MarkHipaa(props: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\" {...props}>\n      <path\n        d=\"M12 2.4 20 5.4v5.9c0 5-3.4 8.7-8 10.5-4.6-1.8-8-5.5-8-10.5V5.4l8-3Z\"\n        fill=\"#0F766E\"\n      />\n      <path d=\"M12 8v8M8 12h8\" stroke=\"#fff\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n    </svg>\n  );\n}\n\nfunction MarkPci(props: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\" {...props}>\n      <rect x=\"2\" y=\"5\" width=\"20\" height=\"14\" rx=\"3\" fill=\"#B01116\" />\n      <path d=\"M2 9.5h20\" stroke=\"#fff\" strokeOpacity=\"0.55\" strokeWidth=\"1.6\" />\n      <path\n        d=\"M10.6 14.4v-1.2a1.4 1.4 0 0 1 2.8 0v1.2\"\n        stroke=\"#fff\"\n        strokeWidth=\"1.3\"\n        strokeLinecap=\"round\"\n      />\n      <rect x=\"9.6\" y=\"14.2\" width=\"4.8\" height=\"3.6\" rx=\"1\" fill=\"#fff\" />\n    </svg>\n  );\n}\n\n/** Keyed on the badge id the fixture uses; anything unknown falls back to the shield. */\nconst BADGE_MARKS: Record<string, React.ComponentType<IconProps>> = {\n  soc2: MarkSoc2,\n  iso27001: MarkIso,\n  gdpr: MarkGdpr,\n  hipaa: MarkHipaa,\n  pci: MarkPci,\n};\n\nconst DEFAULT_CUSTOMERS = [\n  { name: 'Northwind', mark: MarkNorthwind },\n  { name: 'Cobalt', mark: MarkCobalt },\n  { name: 'Meridian', mark: MarkMeridian },\n  { name: 'Tessellate', mark: MarkTessellate },\n  { name: 'Linework', mark: MarkLinework },\n  { name: 'Hollow', mark: MarkHollowCreek },\n];\n\nconst KEYFRAMES = `\n@keyframes su-trust-in { from { opacity: 0; transform: translateY(3px) } to { opacity: 1; transform: none } }\n`;\n\nexport type TrustCenterFooterVariant = 'Badges' | 'Detailed';\n\nexport interface TrustBadge {\n  id: string;\n  label: string;\n  scope: string;\n  issued: string;\n  href: string;\n}\n\nexport interface CustomerMark {\n  name: string;\n  mark: React.ComponentType<IconProps>;\n}\n\nexport interface TrustCenterFooterProps {\n  socials?: FooterSocial[];\n  brand: string;\n  headline?: string;\n  badges: TrustBadge[];\n  /** Logos for the \"deployed inside\" row. Defaults to the bundled set. */\n  customers?: CustomerMark[];\n  customersLabel?: string;\n  /** Link columns. A trust page is still a footer; without them it reads as a banner. */\n  groups?: { title: string; links: { label: string; href: string }[] }[];\n  requestLabel?: string;\n  onRequestReport?: () => void;\n  links?: { label: string; href: string }[];\n  copyright?: string;\n  variant?: TrustCenterFooterVariant;\n  className?: string;\n}\n\nexport function TrustCenterFooter({\n  socials,\n  brand,\n  headline = 'Audited, documented, and available for review.',\n  badges,\n  customers = DEFAULT_CUSTOMERS,\n  customersLabel = 'Deployed inside',\n  groups = [],\n  requestLabel = 'Request full report',\n  onRequestReport,\n  links,\n  copyright,\n  variant = 'Badges',\n  className,\n}: TrustCenterFooterProps) {\n  const detailed = variant === 'Detailed';\n\n  return (\n    <footer\n      className={cn(\n        'w-full border-t border-black/[0.08] bg-white text-neutral-900 dark:border-white/[0.09] dark:bg-[#0A0A0B] dark:text-neutral-100',\n        className,\n      )}\n    >\n      <style dangerouslySetInnerHTML={{ __html: KEYFRAMES }} />\n\n      <div className=\"mx-auto w-full max-w-[1180px] px-6 py-12\">\n        <div className=\"flex flex-col gap-6 md:flex-row md:items-start md:justify-between\">\n          <div className=\"max-w-[38ch]\">\n            <span className=\"inline-flex items-center gap-1.5 font-mono text-[10.5px] font-medium uppercase tracking-[0.09em] text-neutral-500 dark:text-neutral-400\">\n              <IconShield className=\"size-3.5\" />\n              Trust center\n            </span>\n            <h2 className=\"mt-2.5 text-balance text-[19px] font-semibold leading-[1.25] tracking-[-0.35px]\">\n              {headline}\n            </h2>\n          </div>\n\n          <Button\n            type=\"button\"\n            onClick={onRequestReport}\n            className=\"group h-9 shrink-0 cursor-pointer gap-1.5 rounded-full px-4 text-[13px] transition-transform duration-150 ease-out active:scale-[0.96]\"\n          >\n            {requestLabel}\n            <IconArrowUpRight className=\"size-3.5 transition-transform duration-200 ease-[cubic-bezier(0.2,0,0,1)] group-hover:-translate-y-0.5 group-hover:translate-x-0.5 motion-reduce:transition-none\" />\n          </Button>\n        </div>\n\n        <TooltipProvider delayDuration={120} skipDelayDuration={300}>\n          <ul\n            className={cn(\n              'mt-8 grid gap-2.5',\n              detailed ? 'sm:grid-cols-2 lg:grid-cols-3' : 'sm:grid-cols-3 lg:grid-cols-5',\n            )}\n          >\n            {badges.map((badge) => {\n              const Glyph = BADGE_MARKS[badge.id] ?? IconShield;\n              const card = (\n                <a\n                  href={badge.href}\n                  className={cn(\n                    'flex h-full cursor-pointer flex-col rounded-xl border px-3.5 py-3 transition-[border-color,box-shadow] duration-200 ease-[cubic-bezier(0.2,0,0,1)] focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-neutral-400 motion-reduce:transition-none',\n                    'border-black/[0.08] bg-white shadow-[0_1px_2px_rgba(0,0,0,0.03)] hover:border-black/[0.14] hover:shadow-[0_2px_10px_rgba(0,0,0,0.06)]',\n                    'dark:border-white/[0.09] dark:bg-white/[0.03] dark:shadow-none dark:hover:border-white/[0.18]',\n                  )}\n                >\n                  <span className=\"flex items-center gap-2.5\">\n                    <Glyph className=\"size-[22px] shrink-0\" />\n                    <span className=\"text-[13px] font-medium tracking-[-0.1px]\">{badge.label}</span>\n                  </span>\n                  {detailed && (\n                    <span className=\"mt-1.5\">\n                      <span className=\"block text-pretty text-[11.5px] leading-[1.5] text-neutral-500 dark:text-neutral-400\">\n                        {badge.scope}\n                      </span>\n                      <span className=\"mt-1 block font-mono text-[10px] tabular-nums text-neutral-500 dark:text-neutral-400\">\n                        {badge.issued}\n                      </span>\n                    </span>\n                  )}\n                </a>\n              );\n\n              return (\n                <li key={badge.id}>\n                  {detailed ? (\n                    card\n                  ) : (\n                    /* The scope and date float in a tooltip rather than expanding\n                     the card. Expanding grew the row by 60px on hover, so the\n                     grid reflowed and every badge you were about to reach for\n                     jumped out from under the pointer. A tooltip is the same\n                     information with no layout involved. */\n                    <Tooltip>\n                      <TooltipTrigger asChild>{card}</TooltipTrigger>\n                      <TooltipContent side=\"bottom\" sideOffset={8} className=\"max-w-[260px]\">\n                        <p className=\"text-pretty text-[12px] leading-[1.5]\">{badge.scope}</p>\n                        <p className=\"mt-1 font-mono text-[10.5px] tabular-nums opacity-70\">\n                          {badge.issued}\n                        </p>\n                      </TooltipContent>\n                    </Tooltip>\n                  )}\n                </li>\n              );\n            })}\n          </ul>\n        </TooltipProvider>\n\n        {!detailed && (\n          <p className=\"mt-3 text-[11.5px] text-neutral-500 dark:text-neutral-400\">\n            Hover or focus a certification for its scope and report date.\n          </p>\n        )}\n\n        {customers.length > 0 && (\n          <div className=\"mt-10 border-t border-black/[0.07] pt-7 dark:border-white/[0.08]\">\n            <p className=\"font-mono text-[10.5px] font-medium uppercase tracking-[0.09em] text-neutral-500 dark:text-neutral-400\">\n              {customersLabel}\n            </p>\n            {/* A grid, not a wrapping flex row: six names of uneven length left a\n                single orphan on the second line at most widths. */}\n            <ul className=\"mt-5 grid grid-cols-2 gap-x-4 gap-y-5 sm:grid-cols-3 sm:gap-x-6 lg:grid-cols-6\">\n              {customers.map((customer) => {\n                const Glyph = customer.mark;\n                return (\n                  <li\n                    key={customer.name}\n                    className=\"flex min-w-0 items-center gap-2.5 text-neutral-400 transition-colors duration-150 hover:text-neutral-900 dark:text-neutral-500 dark:hover:text-neutral-100\"\n                  >\n                    <Glyph className=\"size-[22px] shrink-0\" />\n                    <span className=\"truncate text-[13px] font-semibold tracking-[-0.3px] sm:text-[14.5px] sm:tracking-[-0.35px]\">\n                      {customer.name}\n                    </span>\n                  </li>\n                );\n              })}\n            </ul>\n          </div>\n        )}\n\n        {groups.length > 0 && (\n          <nav\n            aria-label=\"Footer\"\n            className=\"mt-10 grid gap-8 border-t border-black/[0.07] pt-8 dark:border-white/[0.08] sm:grid-cols-2 lg:grid-cols-4\"\n          >\n            {groups.map((group) => (\n              <div key={group.title} className=\"min-w-0\">\n                <p className=\"font-mono text-[10.5px] font-medium uppercase tracking-[0.09em] text-neutral-500 dark:text-neutral-400\">\n                  {group.title}\n                </p>\n                <ul className=\"mt-4 space-y-2.5\">\n                  {group.links.map((link) => (\n                    <li key={link.label}>\n                      <a\n                        href={link.href}\n                        className=\"text-[13.5px] text-neutral-600 transition-colors duration-150 hover:text-neutral-950 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-neutral-400 dark:text-neutral-400 dark:hover:text-neutral-50\"\n                      >\n                        {link.label}\n                      </a>\n                    </li>\n                  ))}\n                </ul>\n              </div>\n            ))}\n          </nav>\n        )}\n\n        <FooterBar\n          brand={brand}\n          copyright={copyright}\n          links={links}\n          socials={socials}\n          className=\"mt-10\"\n        />\n      </div>\n    </footer>\n  );\n}\n\nexport default TrustCenterFooter;\n",
      "type": "registry:block",
      "target": "components/spectrumui/blocks/footers/trust-center-footer.tsx"
    },
    {
      "path": "components/spectrumui/blocks/footers/footer-kit.tsx",
      "content": "/**\n * Everything the footer blocks share: the icon set, the brand lockup, the\n * social row and the bottom bar.\n *\n * The earlier blocks inlined their own glyphs so each file copied out whole.\n * That stopped scaling once every footer needed the same wordmark, the same\n * three social marks and the same bottom bar — eighteen copies of the same\n * markup drift within a week. This ships alongside each block instead: the\n * registry item for `x-footer` lists this file too, so `npx shadcn add` writes\n * both and the block still installs in one command.\n *\n * Two icon styles live here on purpose:\n *\n *   - Utility icons — arrows, search, check, the rest — are **outline**. A\n *     filled arrow beside 13px text reads as a blob, and a filled chevron in a\n *     select looks like a warning triangle.\n *   - Social and brand marks are **solid**, because a logo drawn in outline is\n *     not that logo. These are the same paths the live site uses.\n */\n\nimport { cn } from '@/lib/utils';\n\ntype IconProps = React.SVGProps<SVGSVGElement>;\n\n/* ── Outline utility icons ──────────────────────────────────\n   One family, one grid, one stroke weight. 1.75 sits between the\n   1.5 that reads correctly next to regular text and the 2 that a\n   semibold label wants, which is the mix these footers run. */\n\nfunction Outline({ children, ...props }: IconProps & { children: React.ReactNode }) {\n  return (\n    <svg\n      viewBox=\"0 0 24 24\"\n      fill=\"none\"\n      stroke=\"currentColor\"\n      strokeWidth={1.75}\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      aria-hidden=\"true\"\n      {...props}\n    >\n      {children}\n    </svg>\n  );\n}\n\nexport function IconArrowRight(props: IconProps) {\n  return (\n    <Outline {...props}>\n      <path d=\"M4.5 12h15M13 5.5l6.5 6.5L13 18.5\" />\n    </Outline>\n  );\n}\n\nexport function IconArrowUpRight(props: IconProps) {\n  return (\n    <Outline {...props}>\n      <path d=\"M7 17 17 7M8.5 7H17v8.5\" />\n    </Outline>\n  );\n}\n\nexport function IconArrowUp(props: IconProps) {\n  return (\n    <Outline {...props}>\n      <path d=\"M12 19.5v-15M5.5 11 12 4.5l6.5 6.5\" />\n    </Outline>\n  );\n}\n\nexport function IconChevronDown(props: IconProps) {\n  return (\n    <Outline {...props}>\n      <path d=\"m6 9.5 6 6 6-6\" />\n    </Outline>\n  );\n}\n\nexport function IconChevronRight(props: IconProps) {\n  return (\n    <Outline {...props}>\n      <path d=\"m9.5 6 6 6-6 6\" />\n    </Outline>\n  );\n}\n\nexport function IconSearch(props: IconProps) {\n  return (\n    <Outline {...props}>\n      <circle cx=\"11\" cy=\"11\" r=\"6.75\" />\n      <path d=\"m20 20-3.9-3.9\" />\n    </Outline>\n  );\n}\n\nexport function IconCheck(props: IconProps) {\n  return (\n    <Outline {...props}>\n      <path d=\"m5 12.5 4.5 4.5L19 7\" />\n    </Outline>\n  );\n}\n\nexport function IconCopy(props: IconProps) {\n  return (\n    <Outline {...props}>\n      <rect x=\"8.5\" y=\"8.5\" width=\"12\" height=\"12\" rx=\"2.5\" />\n      <path d=\"M15.5 5.5A2 2 0 0 0 13.5 3.5h-8a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2\" />\n    </Outline>\n  );\n}\n\nexport function IconLocation(props: IconProps) {\n  return (\n    <Outline {...props}>\n      <path d=\"M19.5 10.5c0 5.5-7.5 11-7.5 11s-7.5-5.5-7.5-11a7.5 7.5 0 0 1 15 0Z\" />\n      <circle cx=\"12\" cy=\"10.3\" r=\"2.6\" />\n    </Outline>\n  );\n}\n\nexport function IconMail(props: IconProps) {\n  return (\n    <Outline {...props}>\n      <rect x=\"2.75\" y=\"4.75\" width=\"18.5\" height=\"14.5\" rx=\"2.5\" />\n      <path d=\"m3.5 8 7.4 4.6a2 2 0 0 0 2.2 0L20.5 8\" />\n    </Outline>\n  );\n}\n\nexport function IconPhone(props: IconProps) {\n  return (\n    <Outline {...props}>\n      <path d=\"M21 16.9v2.6a2 2 0 0 1-2.2 2 19.5 19.5 0 0 1-8.5-3A19.2 19.2 0 0 1 4.4 13 19.5 19.5 0 0 1 1.4 4.4 2 2 0 0 1 3.4 2.2H6a2 2 0 0 1 2 1.7c.1 1 .3 1.9.6 2.8a2 2 0 0 1-.4 2.1L7 10a16 16 0 0 0 6 6l1.2-1.2a2 2 0 0 1 2.1-.4c.9.3 1.8.5 2.8.6a2 2 0 0 1 1.7 2Z\" />\n    </Outline>\n  );\n}\n\nexport function IconClock(props: IconProps) {\n  return (\n    <Outline {...props}>\n      <circle cx=\"12\" cy=\"12\" r=\"8.75\" />\n      <path d=\"M12 6.8V12l3.4 2\" />\n    </Outline>\n  );\n}\n\nexport function IconShield(props: IconProps) {\n  return (\n    <Outline {...props}>\n      <path d=\"M12 2.75 19.75 5.6v5.8c0 4.9-3.3 8.5-7.75 10.4C7.55 19.9 4.25 16.3 4.25 11.4V5.6L12 2.75Z\" />\n      <path d=\"m8.8 11.8 2.4 2.4 4.4-4.8\" />\n    </Outline>\n  );\n}\n\nexport function IconStar(props: IconProps) {\n  return (\n    <Outline {...props}>\n      <path d=\"m12 3.5 2.72 5.5 6.08.89-4.4 4.28 1.04 6.05L12 17.36 6.56 20.22l1.04-6.05L3.2 9.89 9.28 9 12 3.5Z\" />\n    </Outline>\n  );\n}\n\nexport function IconSparkle(props: IconProps) {\n  return (\n    <Outline {...props}>\n      <path d=\"M12 3.2 13.9 9 19.7 10.9 13.9 12.8 12 18.6 10.1 12.8 4.3 10.9 10.1 9 12 3.2Z\" />\n    </Outline>\n  );\n}\n\nexport function IconEnter(props: IconProps) {\n  return (\n    <Outline {...props}>\n      <path d=\"M9 10.5 5 14.5l4 4\" />\n      <path d=\"M5 14.5h10a4.5 4.5 0 0 0 4.5-4.5V5.5\" />\n    </Outline>\n  );\n}\n\n/* ── Brand and social marks ─────────────────────────────────\n   Solid, because a logo drawn in outline is not that logo. */\n\n/** The Spectrum UI flag. Same two paths the site header uses. */\nexport function SpectrumLogo(props: IconProps) {\n  return (\n    <svg viewBox=\"0 0 36 41\" fill=\"currentColor\" aria-hidden=\"true\" {...props}>\n      <path d=\"M17.641 33.4291L11.563 27.3511C7.26395 23.052 0 26.091 0 32.169V40.1001H35.2821V15.7881L17.641 33.4291Z\" />\n      <path d=\"M17.641 6.67098L23.719 12.749C28.0181 17.0481 35.2821 14.0091 35.2821 7.93105V0H0V24.312L17.641 6.67098Z\" />\n    </svg>\n  );\n}\n\nexport function IconGitHub(props: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\" {...props}>\n      <path d=\"M12 .5C5.73.5.98 5.24.98 11.5c0 4.86 3.15 8.98 7.52 10.44.55.1.75-.24.75-.53v-1.86c-3.06.67-3.71-1.48-3.71-1.48-.5-1.28-1.22-1.62-1.22-1.62-1-.68.08-.67.08-.67 1.1.08 1.69 1.14 1.69 1.14.98 1.69 2.58 1.2 3.21.92.1-.72.38-1.2.7-1.48-2.44-.28-5.01-1.22-5.01-5.45 0-1.2.43-2.19 1.14-2.96-.12-.28-.5-1.4.1-2.92 0 0 .93-.3 3.04 1.13a10.5 10.5 0 0 1 5.54 0c2.1-1.43 3.03-1.13 3.03-1.13.6 1.52.22 2.64.11 2.92.71.77 1.13 1.76 1.13 2.96 0 4.24-2.57 5.17-5.02 5.44.39.34.74 1.01.74 2.04v3.03c0 .29.2.64.76.53A11.03 11.03 0 0 0 23.02 11.5C23.02 5.24 18.27.5 12 .5Z\" />\n    </svg>\n  );\n}\n\nexport function IconX(props: IconProps) {\n  return (\n    <svg viewBox=\"0 0 1200 1227\" fill=\"currentColor\" aria-hidden=\"true\" {...props}>\n      <path d=\"M714.163 519.284 1160.89 0H1055.03L667.137 450.887 357.328 0H0l468.492 681.821L0 1226.37h105.866l409.625-476.152 327.181 476.152H1200L714.137 519.284h.026Zm-145 168.544-47.468-67.894L144.011 79.694h162.604l304.797 435.991 47.468 67.894 396.2 566.721H892.476L569.165 687.854v-.026Z\" />\n    </svg>\n  );\n}\n\nexport function IconLinkedIn(props: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\" {...props}>\n      <path d=\"M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 01-2.063-2.065 2.064 2.064 0 112.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.225 0z\" />\n    </svg>\n  );\n}\n\n/* ── Brand data ─────────────────────────────────────────────\n   Real routes, so the previews link somewhere rather than to `#`. */\n\nexport const SPECTRUM = {\n  name: 'Spectrum UI',\n  tagline: 'Animation-ready React components and blocks, with the source on the page.',\n  url: 'https://ui.spectrumhq.in',\n  copyright: `© ${new Date().getFullYear()} Spectrum UI`,\n};\n\nexport interface FooterSocial {\n  label: string;\n  href: string;\n  icon: React.ComponentType<IconProps>;\n}\n\nexport const SPECTRUM_SOCIALS: FooterSocial[] = [\n  { label: 'GitHub', href: 'https://github.com/arihantcodes/spectrum-ui', icon: IconGitHub },\n  { label: 'X', href: 'https://x.com/arihantcodes', icon: IconX },\n  { label: 'LinkedIn', href: 'https://www.linkedin.com/in/arihantcodes', icon: IconLinkedIn },\n];\n\nexport interface FooterLinkGroup {\n  title: string;\n  links: { label: string; href: string; badge?: string }[];\n}\n\nexport const SPECTRUM_GROUPS: FooterLinkGroup[] = [\n  {\n    title: 'Library',\n    links: [\n      { label: 'Components', href: '/docs/components' },\n      { label: 'Blocks', href: '/blocks' },\n      { label: 'Charts', href: '/blocks/charts' },\n      { label: 'Tables', href: '/blocks/tables' },\n      { label: 'Footers', href: '/blocks/footers', badge: 'New' },\n      { label: 'Colors', href: '/colors' },\n    ],\n  },\n  {\n    title: 'Docs',\n    links: [\n      { label: 'Introduction', href: '/docs' },\n      { label: 'Installation', href: '/docs/installation' },\n      { label: 'CLI', href: '/docs/cli' },\n      { label: 'MCP server', href: '/docs/mcp' },\n      { label: 'Theming', href: '/docs/theming' },\n      { label: 'Changelog', href: '/changelog' },\n    ],\n  },\n  {\n    title: 'Resources',\n    links: [\n      { label: 'Blog', href: '/blog' },\n      { label: 'Guides', href: '/docs/guides' },\n      { label: 'Comparisons', href: '/compare' },\n      { label: 'Templates', href: '/templates' },\n      { label: 'Brand kit', href: '/brandkit' },\n      { label: 'llms.txt', href: '/llm-info' },\n    ],\n  },\n  {\n    title: 'Project',\n    links: [\n      { label: 'GitHub', href: 'https://github.com/arihantcodes/spectrum-ui' },\n      { label: 'Sponsor', href: '/sponsor' },\n      { label: 'Pricing', href: '/pricing' },\n      { label: 'FAQs', href: '/faqs' },\n      { label: 'Founder story', href: '/founder-story' },\n      { label: 'Contact', href: 'https://x.com/arihantcodes' },\n    ],\n  },\n];\n\nexport const SPECTRUM_LEGAL = [\n  { label: 'Privacy', href: '/privacy-policy' },\n  { label: 'Terms', href: '/tos' },\n  { label: 'License', href: '/docs/license' },\n  { label: 'Status', href: '/blocks/footers' },\n];\n\n/* ── Shared pieces ──────────────────────────────────────────\n   `tone=\"dark\"` is for the blocks that are dark in both themes, where\n   `dark:` variants never fire and the light palette would be unreadable. */\n\nexport type FooterTone = 'auto' | 'dark';\n\n/** The mark and the wordmark, locked up. */\nexport function BrandLockup({\n  brand = SPECTRUM.name,\n  href = '/',\n  tone = 'auto',\n  className,\n}: {\n  brand?: string;\n  href?: string;\n  tone?: FooterTone;\n  className?: string;\n}) {\n  return (\n    <a\n      href={href}\n      className={cn(\n        'inline-flex items-center gap-2.5 rounded-md transition-opacity duration-150 hover:opacity-70 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-neutral-400',\n        className,\n      )}\n    >\n      <span\n        className={cn(\n          'grid size-7 shrink-0 place-items-center rounded-[7px]',\n          tone === 'dark'\n            ? 'bg-neutral-100 text-neutral-900'\n            : 'bg-neutral-900 text-white dark:bg-neutral-100 dark:text-neutral-900',\n        )}\n      >\n        <SpectrumLogo className=\"h-3.5 w-auto\" />\n      </span>\n      <span className=\"whitespace-nowrap text-[14.5px] font-semibold tracking-[-0.3px]\">\n        {brand}\n      </span>\n    </a>\n  );\n}\n\n/** The social row. Solid marks, 32px hit area, one hover transition. */\nexport function FooterSocials({\n  socials = SPECTRUM_SOCIALS,\n  tone = 'auto',\n  className,\n}: {\n  socials?: FooterSocial[];\n  tone?: FooterTone;\n  className?: string;\n}) {\n  if (socials.length === 0) return null;\n  return (\n    <ul className={cn('flex items-center gap-0.5', className)}>\n      {socials.map(({ label, href, icon: Glyph }) => (\n        <li key={label}>\n          <a\n            href={href}\n            target=\"_blank\"\n            rel=\"noreferrer\"\n            aria-label={label}\n            className={cn(\n              'grid size-8 place-items-center rounded-lg transition-[color,background-color] duration-150 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-neutral-400',\n              tone === 'dark'\n                ? 'text-neutral-400 hover:bg-white/[0.07] hover:text-neutral-100'\n                : 'text-neutral-400 hover:bg-black/[0.05] hover:text-neutral-900 dark:text-neutral-500 dark:hover:bg-white/[0.07] dark:hover:text-neutral-100',\n            )}\n          >\n            <Glyph className=\"size-[15px]\" />\n          </a>\n        </li>\n      ))}\n    </ul>\n  );\n}\n\n/**\n * The bottom bar every footer ends on: lockup and copyright left, utility links\n * and social marks right. One component rather than eighteen hand-rolled\n * copies, which is the only way they stay identical.\n */\nexport function FooterBar({\n  brand = SPECTRUM.name,\n  copyright,\n  links = SPECTRUM_LEGAL,\n  socials = SPECTRUM_SOCIALS,\n  tone = 'auto',\n  showLockup = true,\n  className,\n}: {\n  brand?: string;\n  copyright?: string;\n  links?: { label: string; href: string }[];\n  socials?: FooterSocial[];\n  tone?: FooterTone;\n  showLockup?: boolean;\n  className?: string;\n}) {\n  const muted = tone === 'dark' ? 'text-neutral-400' : 'text-neutral-500 dark:text-neutral-400';\n  const hover =\n    tone === 'dark'\n      ? 'hover:text-neutral-100'\n      : 'hover:text-neutral-900 dark:hover:text-neutral-100';\n  const rule =\n    tone === 'dark' ? 'border-white/[0.08]' : 'border-black/[0.07] dark:border-white/[0.08]';\n\n  return (\n    <div className={cn('border-t pt-6', rule, className)}>\n      <div className=\"flex flex-col gap-5 lg:flex-row lg:items-center lg:justify-between\">\n        <div className=\"flex flex-wrap items-center gap-x-5 gap-y-2\">\n          {showLockup && <BrandLockup brand={brand} tone={tone} />}\n          <p className={cn('text-[12px] tabular-nums', muted)}>{copyright ?? SPECTRUM.copyright}</p>\n        </div>\n\n        <div className=\"flex flex-wrap items-center gap-x-6 gap-y-3\">\n          <ul className={cn('flex flex-wrap items-center gap-x-5 gap-y-2 text-[12px]', muted)}>\n            {links.map((link) => (\n              <li key={link.label}>\n                <a\n                  href={link.href}\n                  className={cn(\n                    'transition-colors duration-150 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-neutral-400',\n                    hover,\n                  )}\n                >\n                  {link.label}\n                </a>\n              </li>\n            ))}\n          </ul>\n          <FooterSocials socials={socials} tone={tone} className=\"-mr-2\" />\n        </div>\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:block",
      "target": "components/spectrumui/blocks/footers/footer-kit.tsx"
    }
  ],
  "type": "registry:block"
}
