{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "event-card",
  "title": "Event Card",
  "author": "ilinxa",
  "description": "Event preview card with six status states and four layouts — capacity-aware badges, overlay links, and soft-failure item handling.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "button",
    "progress"
  ],
  "files": [
    {
      "path": "src/registry/components/data/event-card/event-card.tsx",
      "content": "\"use client\";\n\nimport { memo, useId, useMemo } from \"react\";\nimport {\n  DEFAULT_EVENT_CARD_LABELS,\n  type EventCardProps,\n  type EventCardLabels,\n} from \"./types\";\nimport { getEventStatus } from \"./lib/event-status\";\nimport {\n  getDaysUntilEvent,\n  formatEventDate,\n  defaultFormatDaysUntilSuffix,\n  defaultFormatSpotsLeftSuffix,\n} from \"./lib/format-default\";\nimport { EventCardGrid } from \"./parts/grid\";\nimport { EventCardFeed } from \"./parts/feed\";\nimport { EventCardList } from \"./parts/list\";\nimport { EventCardCompact } from \"./parts/compact\";\n\nfunction EventCardInner({\n  event,\n  variant,\n  href,\n  getHref,\n  onClick,\n  linkComponent = \"a\",\n  formatDate,\n  formatDaysUntilSuffix,\n  formatSpotsLeftSuffix,\n  now,\n  statusOverride,\n  labels: labelsProp,\n  typeStyles,\n  titleClassName,\n  imageClassName,\n  className,\n  ariaLabel,\n  actions,\n  loading = \"lazy\",\n}: EventCardProps) {\n  const titleId = useId();\n\n  const labels = useMemo<Required<EventCardLabels>>(\n    () => ({ ...DEFAULT_EVENT_CARD_LABELS, ...labelsProp }),\n    [labelsProp],\n  );\n\n  const daysUntilSuffixFormatter = useMemo<(count: number) => string>(() => {\n    if (formatDaysUntilSuffix) return formatDaysUntilSuffix;\n    if (labelsProp?.daysUntilSuffix !== undefined) {\n      const suffix = labelsProp.daysUntilSuffix;\n      return () => suffix;\n    }\n    return defaultFormatDaysUntilSuffix;\n  }, [formatDaysUntilSuffix, labelsProp]);\n\n  const spotsLeftSuffixFormatter = useMemo<(count: number) => string>(() => {\n    if (formatSpotsLeftSuffix) return formatSpotsLeftSuffix;\n    if (labelsProp?.spotsLeftSuffix !== undefined) {\n      const suffix = labelsProp.spotsLeftSuffix;\n      return () => suffix;\n    }\n    return defaultFormatSpotsLeftSuffix;\n  }, [formatSpotsLeftSuffix, labelsProp]);\n\n  const status = useMemo(\n    () => statusOverride ?? getEventStatus(event, now),\n    [event, now, statusOverride],\n  );\n\n  const daysUntil = useMemo(\n    () => getDaysUntilEvent(event.date, now),\n    [event.date, now],\n  );\n\n  const formattedDate = useMemo(\n    () => (formatDate ? formatDate(event.date) : formatEventDate(event.date)),\n    [event.date, formatDate],\n  );\n\n  const resolvedHref =\n    href ?? (getHref ? getHref(event) : undefined) ?? \"#\";\n\n  const typeStyle = typeStyles?.[event.type];\n  const featured = event.featured === true;\n\n  const sharedProps = {\n    event,\n    status,\n    daysUntil,\n    formattedDate,\n    featured,\n    labels,\n    formatDaysUntilSuffix: daysUntilSuffixFormatter,\n    formatSpotsLeftSuffix: spotsLeftSuffixFormatter,\n    href: resolvedHref,\n    linkComponent,\n    onClick,\n    ariaLabel,\n    titleId,\n    titleClassName,\n    imageClassName,\n    className,\n    actions,\n    loading,\n  };\n\n  if (variant === \"feed\") {\n    return <EventCardFeed {...sharedProps} />;\n  }\n\n  if (variant === \"list\") {\n    return <EventCardList {...sharedProps} typeStyle={typeStyle} />;\n  }\n\n  if (variant === \"compact\") {\n    return <EventCardCompact {...sharedProps} typeStyle={typeStyle} />;\n  }\n\n  return <EventCardGrid {...sharedProps} typeStyle={typeStyle} />;\n}\n\nexport const EventCard = memo(EventCardInner);\nEventCard.displayName = \"EventCard\";\n\nexport default EventCard;\n",
      "type": "registry:component",
      "target": "components/event-card/event-card.tsx"
    },
    {
      "path": "src/registry/components/data/event-card/index.ts",
      "content": "export { EventCard, default } from \"./event-card\";\n\nexport type {\n  EventCardItem,\n  EventCardLabels,\n  EventCardProps,\n  EventCardVariant,\n  EventStatus,\n} from \"./types\";\n\nexport { DEFAULT_EVENT_CARD_LABELS } from \"./types\";\n\nexport {\n  getEventStatus,\n  EVENT_STATUS_CONFIG,\n  type EventStatusConfigEntry,\n} from \"./lib/event-status\";\n\nexport { formatEventDate, getDaysUntilEvent } from \"./lib/format-default\";\n\n",
      "type": "registry:component",
      "target": "components/event-card/index.ts"
    },
    {
      "path": "src/registry/components/data/event-card/types.ts",
      "content": "import type { ElementType, MouseEvent, ReactNode } from \"react\";\nimport type { EventStatus } from \"./lib/event-status\";\n\nexport type { EventStatus };\n\nexport type EventCardVariant = \"grid\" | \"feed\" | \"list\" | \"compact\";\n\nexport interface EventCardItem {\n  /** Stable identifier. Used for React keys and the default ariaLabel. */\n  id: string;\n  /** Headline. Rendered as <h3>. Required. */\n  title: string;\n  /** Event-type label (e.g. \"Conference\", \"Webinar\"). Used as a key into `typeStyles`. Required. */\n  type: string;\n  /** Start date. ISO-8601 string parseable by `new Date()`. Required — drives status logic. */\n  date: string;\n  /** End date. ISO-8601 string. Optional — defaults to `date` (single-day event). */\n  endDate?: string;\n  /** Time string (\"09:00 - 18:00\"). Optional — meta line omitted if missing. */\n  time?: string;\n  /** Location string (\"Istanbul Conference Center\", \"Virtual\", etc). Optional. */\n  location?: string;\n  /** Image URL. Optional — placeholder rendered if missing. */\n  image?: string;\n  /** Image alt-text. Optional — falls back to `title`. */\n  imageAlt?: string;\n  /** Short summary. Optional — variant gracefully omits. */\n  description?: string;\n  /** Total seat count. Optional — capacity bar + capacity-derived states (full / lastSpots) skipped if absent. */\n  capacity?: number;\n  /** Currently-registered count. Optional — same as `capacity`. */\n  registered?: number;\n  /** Promotional flag. Optional — adds visual lift treatment. */\n  featured?: boolean;\n}\n\nexport interface EventCardLabels {\n  // ─── Status badges ──────────────────────────────────────────────\n  /** Default: 'Ended'. */\n  expired?: string;\n  /** Default: 'Live now'. */\n  ongoing?: string;\n  /** Default: 'Soon'. */\n  upcoming?: string;\n  /** Default: 'Registration open'. */\n  open?: string;\n  /** Default: 'Sold out'. */\n  full?: string;\n  /** Default: 'Last spots'. */\n  lastSpots?: string;\n  // ─── Image-area overlays ────────────────────────────────────────\n  /**\n   * Suffix on the days-until countdown. Default: 'days left'.\n   * @deprecated Use `formatDaysUntilSuffix` (callback) for plural-correct labels.\n   *   Setting this still works (used as a static suffix for all counts) but\n   *   produces ungrammatical output at count === 1 (\"1 days left\").\n   */\n  daysUntilSuffix?: string;\n  /** Pulsing-dot pill text on `ongoing` events. Default: 'Happening now'. */\n  ongoingIndicator?: string;\n  // ─── Capacity counter ───────────────────────────────────────────\n  /**\n   * Suffix on the spots-left counter. Default: 'spots left'.\n   * @deprecated Use `formatSpotsLeftSuffix` (callback) for plural-correct labels.\n   */\n  spotsLeftSuffix?: string;\n  /** Spots-left counter when capacity hit. Default: 'Sold out'. */\n  spotsLeftFull?: string;\n  /** aria-label prefix on the capacity progress bar. Default: 'Registered'. */\n  capacityAriaPrefix?: string;\n  /** Word between the registered + capacity numbers in the aria-label. Default: 'of'. */\n  capacityAriaSeparator?: string;\n  // ─── CTA ────────────────────────────────────────────────────────\n  /** Default: 'Register'. */\n  ctaRegister?: string;\n  /** Default: 'Join'. */\n  ctaJoin?: string;\n  /** Default: 'View details'. */\n  ctaViewDetails?: string;\n  /** Default: 'Sold out'. */\n  ctaSoldOut?: string;\n  // ─── A11y ───────────────────────────────────────────────────────\n  /** sr-only label on the featured-star icon. Default: 'Featured event'. */\n  featuredAriaLabel?: string;\n}\n\nexport interface EventCardProps {\n  /** The event to render. */\n  event: EventCardItem;\n\n  /** Visual variant. Required — no default; explicit per render site. */\n  variant: EventCardVariant;\n\n  // ─── Navigation ──────────────────────────────────────────────────\n  /** URL the card links to. Mutually exclusive with `getHref`. */\n  href?: string;\n  /** Alternative href derivation. Receives the event, returns a URL. */\n  getHref?: (event: EventCardItem) => string;\n  /** Click handler, fired before navigation if href is also set. */\n  onClick?: (event: EventCardItem, mouseEvent: MouseEvent) => void;\n  /** Element used for the link. Default: 'a'. Pass NextLink / RemixLink / etc. */\n  linkComponent?: ElementType;\n\n  // ─── Time / formatting ───────────────────────────────────────────\n  /** Custom date formatter. Default: browser locale long format. */\n  formatDate?: (dateString: string) => string;\n  /**\n   * Format the days-until suffix as a function of count. Default uses\n   * `Intl.PluralRules` (\"day left\" at 1, \"days left\" otherwise). Receives the\n   * integer day-count, returns a string. Takes precedence over `labels.daysUntilSuffix`.\n   */\n  formatDaysUntilSuffix?: (count: number) => string;\n  /**\n   * Format the spots-left suffix as a function of count. Default uses\n   * `Intl.PluralRules` (\"spot left\" at 1, \"spots left\" otherwise). Takes\n   * precedence over `labels.spotsLeftSuffix`.\n   */\n  formatSpotsLeftSuffix?: (count: number) => string;\n  /** Inject a \"now\" reference for deterministic status (tests, live clocks). Default: new Date() at render. */\n  now?: Date;\n  /** Override the derived status. Rare — for preview / what-if states. */\n  statusOverride?: EventStatus;\n  /** Localized labels. Defaults are English. */\n  labels?: EventCardLabels;\n\n  // ─── Theming ─────────────────────────────────────────────────────\n  /** Map of event-type → Tailwind class string. Default: empty (falls to bg-muted). */\n  typeStyles?: Record<string, { className: string }>;\n  /** Override classes for the title. */\n  titleClassName?: string;\n  /** Override classes for the image. */\n  imageClassName?: string;\n  /** Override classes for the root <article>. */\n  className?: string;\n\n  // ─── Accessibility ───────────────────────────────────────────────\n  /** Override the link's accessible name. Default: title. */\n  ariaLabel?: string;\n\n  // ─── Nested interactives (overlay-link pattern) ──────────────────\n  /** Optional cluster of buttons/links that sit ABOVE the link overlay (z-10). */\n  actions?: ReactNode;\n\n  // ─── Performance ─────────────────────────────────────────────────\n  /** Image loading strategy. Default: 'lazy'. */\n  loading?: \"lazy\" | \"eager\";\n}\n\n/** Default English labels — exported for consumer composition. */\nexport const DEFAULT_EVENT_CARD_LABELS: Required<EventCardLabels> = {\n  expired: \"Ended\",\n  ongoing: \"Live now\",\n  upcoming: \"Soon\",\n  open: \"Registration open\",\n  full: \"Sold out\",\n  lastSpots: \"Last spots\",\n  daysUntilSuffix: \"days left\",\n  ongoingIndicator: \"Happening now\",\n  spotsLeftSuffix: \"spots left\",\n  spotsLeftFull: \"Sold out\",\n  capacityAriaPrefix: \"Registered\",\n  capacityAriaSeparator: \"of\",\n  ctaRegister: \"Register\",\n  ctaJoin: \"Join\",\n  ctaViewDetails: \"View details\",\n  ctaSoldOut: \"Sold out\",\n  featuredAriaLabel: \"Featured event\",\n};\n",
      "type": "registry:component",
      "target": "components/event-card/types.ts"
    },
    {
      "path": "src/registry/components/data/event-card/parts/grid.tsx",
      "content": "\"use client\";\n\nimport type { ElementType, MouseEvent, ReactNode } from \"react\";\nimport { Calendar, Clock, MapPin, Star, Users } from \"lucide-react\";\nimport { Progress } from \"@/components/ui/progress\";\nimport { buttonVariants } from \"@/components/ui/button\";\nimport { cn } from \"@/lib/utils\";\nimport type {\n  EventCardLabels,\n  EventCardItem,\n} from \"../types\";\nimport {\n  EVENT_STATUS_CONFIG,\n  type EventStatus,\n} from \"../lib/event-status\";\nimport { ImageFallback } from \"../lib/image-fallback\";\n\ninterface GridPartProps {\n  event: EventCardItem;\n  status: EventStatus;\n  daysUntil: number;\n  formattedDate: string;\n  typeStyle: { className: string } | undefined;\n  featured: boolean;\n  labels: Required<EventCardLabels>;\n  formatDaysUntilSuffix: (count: number) => string;\n  formatSpotsLeftSuffix: (count: number) => string;\n  href: string;\n  linkComponent: ElementType;\n  onClick?: (event: EventCardItem, mouseEvent: MouseEvent) => void;\n  ariaLabel?: string;\n  titleId: string;\n  titleClassName?: string;\n  imageClassName?: string;\n  className?: string;\n  actions?: ReactNode;\n  loading: \"lazy\" | \"eager\";\n}\n\nfunction resolveCta(\n  status: EventStatus,\n  labels: Required<EventCardLabels>,\n): { label: string; variant: \"default\" | \"secondary\" | \"outline\" } {\n  switch (status) {\n    case \"ongoing\":\n      return { label: labels.ctaJoin, variant: \"default\" };\n    case \"full\":\n      return { label: labels.ctaSoldOut, variant: \"secondary\" };\n    case \"expired\":\n      return { label: labels.ctaViewDetails, variant: \"outline\" };\n    case \"open\":\n    case \"upcoming\":\n    case \"lastSpots\":\n    default:\n      return { label: labels.ctaRegister, variant: \"default\" };\n  }\n}\n\nexport function EventCardGrid({\n  event,\n  status,\n  daysUntil,\n  formattedDate,\n  typeStyle,\n  featured,\n  labels,\n  formatDaysUntilSuffix,\n  formatSpotsLeftSuffix,\n  href,\n  linkComponent: LinkComponent,\n  onClick,\n  ariaLabel,\n  titleId,\n  titleClassName,\n  imageClassName,\n  className,\n  actions,\n  loading,\n}: GridPartProps) {\n  const statusEntry = EVENT_STATUS_CONFIG[status];\n  const StatusIcon = statusEntry.icon;\n  const showCapacity = event.capacity != null && event.registered != null;\n  const spotsLeft = showCapacity\n    ? (event.capacity ?? 0) - (event.registered ?? 0)\n    : 0;\n  const percentFull = showCapacity\n    ? event.capacity === 0\n      ? 100\n      : ((event.registered ?? 0) / (event.capacity ?? 1)) * 100\n    : 0;\n  const cta = resolveCta(status, labels);\n  const hasActions = actions != null;\n\n  const handleClick = onClick\n    ? (e: MouseEvent<HTMLAnchorElement>) => onClick(event, e)\n    : undefined;\n\n  return (\n    <article\n      className={cn(\n        \"relative group bg-card rounded-2xl overflow-hidden shadow-sm motion-safe:hover:shadow-xl transition-all duration-500 border border-border/50 h-full flex flex-col\",\n        statusEntry.cardClassName,\n        featured && \"border-t-4 border-t-primary\",\n        className,\n      )}\n    >\n      {/* Image area */}\n      <div className=\"relative h-48 overflow-hidden\">\n        {event.image ? (\n          <img\n            src={event.image}\n            alt={event.imageAlt ?? event.title}\n            loading={loading}\n            className={cn(\n              \"w-full h-full object-cover motion-safe:group-hover:scale-110 transition-transform duration-700\",\n              imageClassName,\n            )}\n          />\n        ) : (\n          <ImageFallback className={imageClassName} />\n        )}\n\n        {/* Gradient overlay for legibility */}\n        <div\n          aria-hidden=\"true\"\n          className=\"absolute inset-0 bg-linear-to-t from-black/60 via-transparent to-transparent\"\n        />\n\n        {/* Status badge — top-left */}\n        <span\n          className={cn(\n            \"absolute top-4 left-4 inline-flex items-center gap-1.5 px-3 py-1 rounded-md text-xs font-medium\",\n            statusEntry.className,\n          )}\n        >\n          <StatusIcon aria-hidden=\"true\" className=\"w-3.5 h-3.5\" />\n          {labels[status]}\n        </span>\n\n        {/* Type badge — top-right OR bottom-right when actions yields top */}\n        <span\n          className={cn(\n            \"absolute backdrop-blur-sm border rounded-md text-xs px-2.5 py-0.5\",\n            hasActions ? \"bottom-4 right-4\" : \"top-4 right-4\",\n            typeStyle?.className ?? \"bg-muted text-muted-foreground border-border\",\n          )}\n        >\n          {event.type}\n        </span>\n\n        {/* Actions slot — top-right, above link overlay */}\n        {hasActions && (\n          <div className=\"absolute top-4 right-4 z-10 flex gap-1.5\">\n            {actions}\n          </div>\n        )}\n\n        {/* Days-until OR ongoing pill — bottom-left */}\n        {status !== \"expired\" && status !== \"ongoing\" && (\n          <div className=\"absolute bottom-4 left-4 bg-black/70 backdrop-blur-sm rounded-lg px-3 py-2 text-white\">\n            <div className=\"text-2xl font-bold leading-none\">{daysUntil}</div>\n            <div className=\"text-xs text-white/70\">{formatDaysUntilSuffix(daysUntil)}</div>\n          </div>\n        )}\n        {status === \"ongoing\" && (\n          <div className=\"absolute bottom-4 left-4 bg-accent/90 backdrop-blur-sm rounded-lg px-3 py-2 text-accent-foreground inline-flex items-center gap-2\">\n            <span\n              aria-hidden=\"true\"\n              className=\"w-2 h-2 rounded-full bg-current motion-safe:animate-pulse\"\n            />\n            <span className=\"text-sm font-medium\">{labels.ongoingIndicator}</span>\n          </div>\n        )}\n      </div>\n\n      {/* Link overlay — covers whole article, transparent, on top of content */}\n      <LinkComponent\n        href={href}\n        aria-labelledby={ariaLabel ? undefined : titleId}\n        aria-label={ariaLabel}\n        onClick={handleClick}\n        className=\"absolute inset-0 z-0 rounded-2xl focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 outline-none\"\n      />\n\n      {/* Content */}\n      <div className=\"p-6 flex-1 flex flex-col\">\n        <h3\n          id={titleId}\n          className={cn(\n            \"text-xl font-bold text-foreground mb-2 motion-safe:group-hover:text-primary transition-colors line-clamp-2\",\n            titleClassName,\n          )}\n        >\n          {featured && (\n            <Star\n              aria-hidden=\"true\"\n              className=\"inline w-4 h-4 fill-primary text-primary mr-1.5 align-baseline\"\n            />\n          )}\n          {event.title}\n          {featured && (\n            <span className=\"sr-only\"> ({labels.featuredAriaLabel})</span>\n          )}\n        </h3>\n\n        {event.description && (\n          <p className=\"text-muted-foreground text-sm mb-4 line-clamp-2\">\n            {event.description}\n          </p>\n        )}\n\n        {/* Meta lines */}\n        <ul role=\"list\" className=\"space-y-2 mb-4\">\n          <li className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n            <Calendar\n              aria-hidden=\"true\"\n              className=\"w-4 h-4 text-primary shrink-0\"\n            />\n            <span>{formattedDate}</span>\n          </li>\n          {event.time && (\n            <li className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n              <Clock\n                aria-hidden=\"true\"\n                className=\"w-4 h-4 text-primary shrink-0\"\n              />\n              <span>{event.time}</span>\n            </li>\n          )}\n          {event.location && (\n            <li className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n              <MapPin\n                aria-hidden=\"true\"\n                className=\"w-4 h-4 text-primary shrink-0\"\n              />\n              <span className=\"truncate\">{event.location}</span>\n            </li>\n          )}\n        </ul>\n\n        {/* Capacity bar */}\n        {showCapacity && (\n          <div className=\"mt-auto\">\n            <div className=\"flex items-center justify-between text-sm mb-2\">\n              <span className=\"inline-flex items-center gap-1.5 text-muted-foreground\">\n                <Users aria-hidden=\"true\" className=\"w-4 h-4\" />\n                {event.registered} / {event.capacity}\n              </span>\n              {status !== \"expired\" && (\n                <span\n                  className={cn(\n                    \"text-xs font-medium\",\n                    spotsLeft <= 5 && spotsLeft > 0\n                      ? \"text-destructive\"\n                      : \"text-muted-foreground\",\n                  )}\n                >\n                  {spotsLeft > 0\n                    ? `${spotsLeft} ${formatSpotsLeftSuffix(spotsLeft)}`\n                    : labels.spotsLeftFull}\n                </span>\n              )}\n            </div>\n            <Progress\n              value={percentFull}\n              className={cn(\"h-2\", status === \"expired\" && \"opacity-50\")}\n              aria-label={`${labels.capacityAriaPrefix}: ${event.registered} ${labels.capacityAriaSeparator} ${event.capacity}`}\n            />\n          </div>\n        )}\n\n        {/* Decorative CTA — visual only; click passes through to link overlay */}\n        <div\n          aria-hidden=\"true\"\n          className={cn(\n            buttonVariants({ variant: cta.variant }),\n            \"w-full mt-4 pointer-events-none\",\n            !showCapacity && \"mt-auto\",\n          )}\n        >\n          {cta.label}\n        </div>\n      </div>\n    </article>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/event-card/parts/grid.tsx"
    },
    {
      "path": "src/registry/components/data/event-card/parts/feed.tsx",
      "content": "\"use client\";\n\nimport type { ElementType, MouseEvent, ReactNode } from \"react\";\nimport {\n  ArrowRight,\n  Calendar,\n  Clock,\n  MapPin,\n  Star,\n  Users,\n} from \"lucide-react\";\nimport { buttonVariants } from \"@/components/ui/button\";\nimport { cn } from \"@/lib/utils\";\nimport type {\n  EventCardLabels,\n  EventCardItem,\n} from \"../types\";\nimport {\n  EVENT_STATUS_CONFIG,\n  type EventStatus,\n} from \"../lib/event-status\";\nimport { ImageFallback } from \"../lib/image-fallback\";\n\ninterface FeedPartProps {\n  event: EventCardItem;\n  status: EventStatus;\n  daysUntil: number;\n  formattedDate: string;\n  featured: boolean;\n  labels: Required<EventCardLabels>;\n  formatDaysUntilSuffix: (count: number) => string;\n  formatSpotsLeftSuffix: (count: number) => string;\n  href: string;\n  linkComponent: ElementType;\n  onClick?: (event: EventCardItem, mouseEvent: MouseEvent) => void;\n  ariaLabel?: string;\n  titleId: string;\n  titleClassName?: string;\n  imageClassName?: string;\n  className?: string;\n  actions?: ReactNode;\n  loading: \"lazy\" | \"eager\";\n}\n\nfunction resolveCta(\n  status: EventStatus,\n  labels: Required<EventCardLabels>,\n): { label: string; variant: \"default\" | \"secondary\" | \"outline\" } {\n  switch (status) {\n    case \"ongoing\":\n      return { label: labels.ctaJoin, variant: \"default\" };\n    case \"full\":\n      return { label: labels.ctaSoldOut, variant: \"secondary\" };\n    case \"expired\":\n      return { label: labels.ctaViewDetails, variant: \"outline\" };\n    case \"open\":\n    case \"upcoming\":\n    case \"lastSpots\":\n    default:\n      return { label: labels.ctaRegister, variant: \"default\" };\n  }\n}\n\nexport function EventCardFeed({\n  event,\n  status,\n  daysUntil,\n  formattedDate,\n  featured,\n  labels,\n  formatDaysUntilSuffix,\n  formatSpotsLeftSuffix,\n  href,\n  linkComponent: LinkComponent,\n  onClick,\n  ariaLabel,\n  titleId,\n  titleClassName,\n  imageClassName,\n  className,\n  actions,\n  loading,\n}: FeedPartProps) {\n  const statusEntry = EVENT_STATUS_CONFIG[status];\n  const StatusIcon = statusEntry.icon;\n  const showCapacity = event.capacity != null && event.registered != null;\n  const spotsLeft = showCapacity\n    ? (event.capacity ?? 0) - (event.registered ?? 0)\n    : null;\n  const cta = resolveCta(status, labels);\n  const hasActions = actions != null;\n\n  const handleClick = onClick\n    ? (e: MouseEvent<HTMLAnchorElement>) => onClick(event, e)\n    : undefined;\n\n  return (\n    <article\n      className={cn(\n        \"relative group h-64 md:h-72 overflow-hidden lg:rounded-xl shadow-[inset_0_80px_60px_-40px_rgba(0,0,0,0.4)]\",\n        statusEntry.cardClassName,\n        featured && \"ring-2 ring-primary ring-inset\",\n        className,\n      )}\n    >\n      {/* Background image */}\n      {event.image ? (\n        <img\n          src={event.image}\n          alt={event.imageAlt ?? event.title}\n          loading={loading}\n          className={cn(\n            \"absolute inset-0 w-full h-full object-cover motion-safe:group-hover:scale-105 transition-transform duration-700\",\n            imageClassName,\n          )}\n        />\n      ) : (\n        <ImageFallback className={cn(\"absolute inset-0\", imageClassName)} />\n      )}\n\n      {/* Two layered gradients for depth + legibility */}\n      <div\n        aria-hidden=\"true\"\n        className=\"absolute inset-0 bg-linear-to-t from-black/90 via-black/50 to-black/30\"\n      />\n      <div\n        aria-hidden=\"true\"\n        className=\"absolute inset-0 shadow-[inset_0_60px_80px_-20px_rgba(0,0,0,0.6)]\"\n      />\n\n      {/* Link overlay — covers whole card */}\n      <LinkComponent\n        href={href}\n        aria-labelledby={ariaLabel ? undefined : titleId}\n        aria-label={ariaLabel}\n        onClick={handleClick}\n        className=\"absolute inset-0 z-0 lg:rounded-xl focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 outline-none\"\n      />\n\n      {/* Content */}\n      <div className=\"absolute inset-0 flex flex-col justify-between p-6\">\n        {/* Top row */}\n        <div className=\"flex items-start justify-between\">\n          <div className=\"flex items-center gap-2\">\n            <span\n              className={cn(\n                \"inline-flex items-center gap-1.5 px-3 py-1 rounded-md text-xs font-medium\",\n                statusEntry.className,\n              )}\n            >\n              <StatusIcon aria-hidden=\"true\" className=\"w-3.5 h-3.5\" />\n              {labels[status]}\n            </span>\n            <span className=\"bg-white/10 text-white border border-white/20 backdrop-blur-sm rounded-md text-xs px-2.5 py-0.5\">\n              {event.type}\n            </span>\n          </div>\n\n          {hasActions ? (\n            <div className=\"z-10 flex gap-1.5\">{actions}</div>\n          ) : status === \"ongoing\" ? (\n            <div className=\"bg-accent/90 backdrop-blur-sm rounded-full px-3 py-1.5 text-accent-foreground inline-flex items-center gap-2\">\n              <span\n                aria-hidden=\"true\"\n                className=\"w-2 h-2 rounded-full bg-current motion-safe:animate-pulse\"\n              />\n              <span className=\"text-xs font-medium\">\n                {labels.ongoingIndicator}\n              </span>\n            </div>\n          ) : status !== \"expired\" ? (\n            <div className=\"bg-white/10 backdrop-blur-md rounded-lg px-3 py-2 text-center\">\n              <div className=\"text-2xl font-bold text-white leading-none\">\n                {daysUntil}\n              </div>\n              <div className=\"text-xs text-white/70\">\n                {formatDaysUntilSuffix(daysUntil)}\n              </div>\n            </div>\n          ) : null}\n        </div>\n\n        {/* Bottom block */}\n        <div>\n          <h3\n            id={titleId}\n            className={cn(\n              \"text-xl md:text-2xl font-bold text-white mb-3 line-clamp-2 motion-safe:group-hover:text-accent transition-colors\",\n              titleClassName,\n            )}\n          >\n            {featured && (\n              <Star\n                aria-hidden=\"true\"\n                className=\"inline w-4 h-4 fill-primary text-primary mr-1.5 align-baseline\"\n              />\n            )}\n            {event.title}\n            {featured && (\n              <span className=\"sr-only\"> ({labels.featuredAriaLabel})</span>\n            )}\n          </h3>\n\n          {/* Inline meta row */}\n          <ul\n            role=\"list\"\n            className=\"flex flex-wrap items-center gap-x-4 gap-y-2 text-sm text-white/80 mb-4\"\n          >\n            <li className=\"flex items-center gap-1.5\">\n              <Calendar aria-hidden=\"true\" className=\"w-4 h-4\" />\n              <span>{formattedDate}</span>\n            </li>\n            {event.time && (\n              <li className=\"flex items-center gap-1.5\">\n                <Clock aria-hidden=\"true\" className=\"w-4 h-4\" />\n                <span>{event.time}</span>\n              </li>\n            )}\n            {event.location && (\n              <li className=\"flex items-center gap-1.5\">\n                <MapPin aria-hidden=\"true\" className=\"w-4 h-4\" />\n                <span className=\"truncate max-w-[150px]\">{event.location}</span>\n              </li>\n            )}\n            {showCapacity && (\n              <li className=\"flex items-center gap-1.5\">\n                <Users aria-hidden=\"true\" className=\"w-4 h-4\" />\n                <span>\n                  {spotsLeft != null && spotsLeft > 0\n                    ? `${spotsLeft} ${formatSpotsLeftSuffix(spotsLeft)}`\n                    : labels.spotsLeftFull}\n                </span>\n              </li>\n            )}\n          </ul>\n\n          {/* CTA + chevron */}\n          <div className=\"flex items-center justify-between\">\n            <div\n              aria-hidden=\"true\"\n              className={cn(\n                buttonVariants({ variant: cta.variant, size: \"sm\" }),\n                \"pointer-events-none\",\n                status === \"expired\" &&\n                  \"bg-white/10 border-white/20 text-white hover:bg-white/10\",\n              )}\n            >\n              {cta.label}\n            </div>\n            <span className=\"flex items-center gap-1 text-white/60 text-sm motion-safe:group-hover:text-accent transition-colors\">\n              <ArrowRight\n                aria-hidden=\"true\"\n                className=\"w-4 h-4 motion-safe:group-hover:translate-x-1 transition-transform rtl:rotate-180\"\n              />\n            </span>\n          </div>\n        </div>\n      </div>\n    </article>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/event-card/parts/feed.tsx"
    },
    {
      "path": "src/registry/components/data/event-card/parts/list.tsx",
      "content": "\"use client\";\n\nimport type { ElementType, MouseEvent, ReactNode } from \"react\";\nimport {\n  ArrowRight,\n  Calendar,\n  Clock,\n  MapPin,\n  Star,\n  Users,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\nimport type {\n  EventCardLabels,\n  EventCardItem,\n} from \"../types\";\nimport {\n  EVENT_STATUS_CONFIG,\n  type EventStatus,\n} from \"../lib/event-status\";\nimport { ImageFallback } from \"../lib/image-fallback\";\n\ninterface ListPartProps {\n  event: EventCardItem;\n  status: EventStatus;\n  daysUntil: number;\n  formattedDate: string;\n  typeStyle: { className: string } | undefined;\n  featured: boolean;\n  labels: Required<EventCardLabels>;\n  formatDaysUntilSuffix: (count: number) => string;\n  formatSpotsLeftSuffix: (count: number) => string;\n  href: string;\n  linkComponent: ElementType;\n  onClick?: (event: EventCardItem, mouseEvent: MouseEvent) => void;\n  ariaLabel?: string;\n  titleId: string;\n  titleClassName?: string;\n  imageClassName?: string;\n  className?: string;\n  actions?: ReactNode;\n  loading: \"lazy\" | \"eager\";\n}\n\nexport function EventCardList({\n  event,\n  status,\n  daysUntil,\n  formattedDate,\n  typeStyle,\n  featured,\n  labels,\n  formatDaysUntilSuffix,\n  formatSpotsLeftSuffix,\n  href,\n  linkComponent: LinkComponent,\n  onClick,\n  ariaLabel,\n  titleId,\n  titleClassName,\n  imageClassName,\n  className,\n  actions,\n  loading,\n}: ListPartProps) {\n  const statusEntry = EVENT_STATUS_CONFIG[status];\n  const StatusIcon = statusEntry.icon;\n  const showCapacity = event.capacity != null && event.registered != null;\n  const spotsLeft = showCapacity\n    ? (event.capacity ?? 0) - (event.registered ?? 0)\n    : null;\n  const hasActions = actions != null;\n\n  const handleClick = onClick\n    ? (e: MouseEvent<HTMLAnchorElement>) => onClick(event, e)\n    : undefined;\n\n  return (\n    <article\n      className={cn(\n        \"relative group grid grid-cols-[auto_1fr_auto] gap-3 sm:gap-4 py-3 px-3 border-b border-border/50 last:border-0 motion-safe:hover:bg-muted/30 transition-colors rounded-lg items-center\",\n        statusEntry.cardClassName,\n        featured && \"border-l-4 border-l-primary\",\n        className,\n      )}\n    >\n      {/* Thumbnail left — square */}\n      <div className=\"relative w-16 h-16 sm:w-20 sm:h-20 rounded-lg overflow-hidden shrink-0\">\n        {event.image ? (\n          <img\n            src={event.image}\n            alt={event.imageAlt ?? event.title}\n            loading={loading}\n            className={cn(\n              \"w-full h-full object-cover\",\n              imageClassName,\n            )}\n          />\n        ) : (\n          <ImageFallback className={imageClassName} />\n        )}\n      </div>\n\n      {/* Content middle */}\n      <div className=\"flex flex-col justify-center min-w-0\">\n        {/* Top row: status + type badges */}\n        <div className=\"flex items-center gap-1.5 mb-1 flex-wrap\">\n          <span\n            className={cn(\n              \"inline-flex items-center gap-1 px-2 py-0.5 rounded text-[10px] font-medium\",\n              statusEntry.className,\n            )}\n          >\n            <StatusIcon aria-hidden=\"true\" className=\"w-3 h-3\" />\n            {labels[status]}\n          </span>\n          <span\n            className={cn(\n              \"border rounded text-[10px] px-1.5 py-0.5 truncate max-w-[120px]\",\n              typeStyle?.className ??\n                \"bg-muted text-muted-foreground border-border\",\n            )}\n          >\n            {event.type}\n          </span>\n        </div>\n\n        {/* Title */}\n        <h4\n          id={titleId}\n          className={cn(\n            \"text-sm font-semibold line-clamp-1 mb-1 motion-safe:group-hover:text-primary transition-colors\",\n            titleClassName,\n          )}\n        >\n          {featured && (\n            <Star\n              aria-hidden=\"true\"\n              className=\"inline w-3.5 h-3.5 fill-primary text-primary mr-1 align-baseline\"\n            />\n          )}\n          {event.title}\n          {featured && (\n            <span className=\"sr-only\"> ({labels.featuredAriaLabel})</span>\n          )}\n        </h4>\n\n        {/* Inline event-specific meta row — date / time / location / spots */}\n        <ul\n          role=\"list\"\n          className=\"flex flex-wrap items-center gap-x-3 gap-y-0.5 text-xs text-muted-foreground\"\n        >\n          <li className=\"flex items-center gap-1\">\n            <Calendar\n              aria-hidden=\"true\"\n              className=\"w-3 h-3 text-primary shrink-0\"\n            />\n            <span>{formattedDate}</span>\n          </li>\n          {event.time && (\n            <li className=\"flex items-center gap-1\">\n              <Clock\n                aria-hidden=\"true\"\n                className=\"w-3 h-3 text-primary shrink-0\"\n              />\n              <span>{event.time}</span>\n            </li>\n          )}\n          {event.location && (\n            <li className=\"flex items-center gap-1 min-w-0\">\n              <MapPin\n                aria-hidden=\"true\"\n                className=\"w-3 h-3 text-primary shrink-0\"\n              />\n              <span className=\"truncate max-w-[140px]\">{event.location}</span>\n            </li>\n          )}\n          {showCapacity && (\n            <li\n              className={cn(\n                \"flex items-center gap-1 font-medium\",\n                spotsLeft != null && spotsLeft <= 5 && spotsLeft > 0\n                  ? \"text-destructive\"\n                  : \"text-muted-foreground\",\n              )}\n            >\n              <Users aria-hidden=\"true\" className=\"w-3 h-3 shrink-0\" />\n              <span>\n                {spotsLeft != null && spotsLeft > 0\n                  ? `${spotsLeft} ${formatSpotsLeftSuffix(spotsLeft)}`\n                  : labels.spotsLeftFull}\n              </span>\n            </li>\n          )}\n        </ul>\n      </div>\n\n      {/* Right slot — actions OR status-aware indicator OR days-until OR chevron */}\n      <div className=\"flex items-center justify-end self-center shrink-0\">\n        {hasActions ? (\n          <div className=\"z-10 flex gap-1.5\">{actions}</div>\n        ) : status === \"ongoing\" ? (\n          <span className=\"bg-accent/20 text-accent-foreground rounded-full px-2.5 py-1 text-[10px] font-semibold inline-flex items-center gap-1\">\n            <span\n              aria-hidden=\"true\"\n              className=\"w-1.5 h-1.5 rounded-full bg-accent-foreground motion-safe:animate-pulse\"\n            />\n            {labels.ongoingIndicator}\n          </span>\n        ) : status === \"expired\" ? (\n          <ArrowRight\n            aria-hidden=\"true\"\n            className=\"w-4 h-4 text-muted-foreground motion-safe:group-hover:text-primary motion-safe:group-hover:translate-x-1 transition-all rtl:rotate-180\"\n          />\n        ) : (\n          <div className=\"text-center px-2 min-w-12\">\n            <div className=\"text-base font-bold leading-none text-foreground\">\n              {daysUntil}\n            </div>\n            <div className=\"text-[10px] text-muted-foreground mt-0.5\">\n              {formatDaysUntilSuffix(daysUntil)}\n            </div>\n          </div>\n        )}\n      </div>\n\n      {/* Link overlay covers whole row */}\n      <LinkComponent\n        href={href}\n        aria-labelledby={ariaLabel ? undefined : titleId}\n        aria-label={ariaLabel}\n        onClick={handleClick}\n        className=\"absolute inset-0 z-0 rounded-lg focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 outline-none\"\n      />\n    </article>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/event-card/parts/list.tsx"
    },
    {
      "path": "src/registry/components/data/event-card/parts/compact.tsx",
      "content": "\"use client\";\n\nimport type { ElementType, MouseEvent, ReactNode } from \"react\";\nimport { Calendar, Clock, MapPin, Star } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\nimport type {\n  EventCardLabels,\n  EventCardItem,\n} from \"../types\";\nimport {\n  EVENT_STATUS_CONFIG,\n  type EventStatus,\n} from \"../lib/event-status\";\n\ninterface CompactPartProps {\n  event: EventCardItem;\n  status: EventStatus;\n  formattedDate: string;\n  typeStyle: { className: string } | undefined;\n  featured: boolean;\n  labels: Required<EventCardLabels>;\n  href: string;\n  linkComponent: ElementType;\n  onClick?: (event: EventCardItem, mouseEvent: MouseEvent) => void;\n  ariaLabel?: string;\n  titleId: string;\n  titleClassName?: string;\n  className?: string;\n  actions?: ReactNode;\n}\n\nexport function EventCardCompact({\n  event,\n  status,\n  formattedDate,\n  typeStyle,\n  featured,\n  labels,\n  href,\n  linkComponent: LinkComponent,\n  onClick,\n  ariaLabel,\n  titleId,\n  titleClassName,\n  className,\n  actions,\n}: CompactPartProps) {\n  const statusEntry = EVENT_STATUS_CONFIG[status];\n  const hasActions = actions != null;\n\n  const handleClick = onClick\n    ? (e: MouseEvent<HTMLAnchorElement>) => onClick(event, e)\n    : undefined;\n\n  return (\n    <article\n      className={cn(\n        \"relative group py-4 px-2 border-b border-border/50 last:border-0 motion-safe:hover:bg-muted/30 transition-colors rounded-md\",\n        statusEntry.cardClassName,\n        className,\n      )}\n    >\n      {/* Top row: title + type badge (or actions) */}\n      <div className=\"flex items-start justify-between gap-3 mb-2\">\n        <h4\n          id={titleId}\n          className={cn(\n            \"text-sm font-semibold line-clamp-2 motion-safe:group-hover:text-primary transition-colors flex-1 min-w-0\",\n            titleClassName,\n          )}\n        >\n          {featured && (\n            <Star\n              aria-hidden=\"true\"\n              className=\"inline w-3.5 h-3.5 fill-primary text-primary mr-1 align-baseline\"\n            />\n          )}\n          {event.title}\n          {featured && (\n            <span className=\"sr-only\"> ({labels.featuredAriaLabel})</span>\n          )}\n        </h4>\n\n        {hasActions ? (\n          <div className=\"z-10 flex gap-1 shrink-0\">{actions}</div>\n        ) : (\n          <span\n            className={cn(\n              \"text-xs px-2 py-0.5 rounded shrink-0\",\n              typeStyle?.className ??\n                \"bg-muted text-muted-foreground\",\n            )}\n          >\n            {event.type}\n          </span>\n        )}\n      </div>\n\n      {/* Inline meta — vertical stack */}\n      <ul\n        role=\"list\"\n        className=\"space-y-1 text-xs text-muted-foreground\"\n      >\n        {hasActions && (\n          <li className=\"flex items-center gap-1.5\">\n            <span\n              className={cn(\n                \"inline-block px-1.5 py-0.5 rounded text-[10px]\",\n                typeStyle?.className ??\n                  \"bg-muted text-muted-foreground\",\n              )}\n            >\n              {event.type}\n            </span>\n          </li>\n        )}\n        <li className=\"flex items-center gap-1.5\">\n          <Calendar aria-hidden=\"true\" className=\"w-3 h-3 shrink-0\" />\n          <span>{formattedDate}</span>\n        </li>\n        {event.time && (\n          <li className=\"flex items-center gap-1.5\">\n            <Clock aria-hidden=\"true\" className=\"w-3 h-3 shrink-0\" />\n            <span>{event.time}</span>\n          </li>\n        )}\n        {event.location && (\n          <li className=\"flex items-center gap-1.5 min-w-0\">\n            <MapPin aria-hidden=\"true\" className=\"w-3 h-3 shrink-0\" />\n            <span className=\"truncate\">{event.location}</span>\n          </li>\n        )}\n      </ul>\n\n      {/* Link overlay covers whole row */}\n      <LinkComponent\n        href={href}\n        aria-labelledby={ariaLabel ? undefined : titleId}\n        aria-label={ariaLabel}\n        onClick={handleClick}\n        className=\"absolute inset-0 z-0 rounded-md focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 outline-none\"\n      />\n    </article>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/event-card/parts/compact.tsx"
    },
    {
      "path": "src/registry/components/data/event-card/lib/event-status.ts",
      "content": "import { AlertCircle, CheckCircle, Timer, XCircle } from \"lucide-react\";\nimport type { ComponentType } from \"react\";\nimport type { EventCardItem } from \"../types\";\n\nexport type EventStatus =\n  | \"expired\"\n  | \"ongoing\"\n  | \"upcoming\"\n  | \"open\"\n  | \"full\"\n  | \"lastSpots\";\n\nexport interface EventStatusConfigEntry {\n  label: string;\n  icon: ComponentType<{ className?: string; \"aria-hidden\"?: boolean | \"true\" | \"false\" }>;\n  className: string;\n  cardClassName?: string;\n}\n\nexport const EVENT_STATUS_CONFIG: Record<EventStatus, EventStatusConfigEntry> = {\n  expired: {\n    label: \"Ended\",\n    icon: XCircle,\n    className: \"bg-muted text-muted-foreground\",\n    cardClassName: \"opacity-60 grayscale-30\",\n  },\n  ongoing: {\n    label: \"Live now\",\n    icon: Timer,\n    className: \"bg-accent text-accent-foreground motion-safe:animate-pulse\",\n  },\n  upcoming: {\n    label: \"Soon\",\n    icon: AlertCircle,\n    className: \"bg-warning text-warning-foreground\",\n  },\n  open: {\n    label: \"Registration open\",\n    icon: CheckCircle,\n    className: \"bg-primary text-primary-foreground\",\n  },\n  full: {\n    label: \"Sold out\",\n    icon: XCircle,\n    className: \"bg-destructive text-destructive-foreground\",\n  },\n  lastSpots: {\n    label: \"Last spots\",\n    icon: AlertCircle,\n    className: \"bg-warning text-warning-foreground\",\n  },\n};\n\nexport function getEventStatus(\n  event: EventCardItem,\n  now: Date = new Date(),\n): EventStatus {\n  const eventDate = new Date(event.date);\n  const endDate = event.endDate ? new Date(event.endDate) : new Date(event.date);\n  eventDate.setHours(0, 0, 0, 0);\n  endDate.setHours(23, 59, 59, 999);\n\n  if (now > endDate) return \"expired\";\n  if (now >= eventDate && now <= endDate) return \"ongoing\";\n\n  if (event.capacity != null && event.registered != null) {\n    const spotsLeft = event.capacity - event.registered;\n    const percentFull =\n      event.capacity === 0 ? 100 : (event.registered / event.capacity) * 100;\n    if (spotsLeft <= 0) return \"full\";\n    if (percentFull >= 80) return \"lastSpots\";\n  }\n\n  const today = new Date(now);\n  today.setHours(0, 0, 0, 0);\n  const daysUntil = Math.ceil(\n    (eventDate.getTime() - today.getTime()) / (1000 * 60 * 60 * 24),\n  );\n  if (daysUntil <= 7) return \"upcoming\";\n\n  return \"open\";\n}\n",
      "type": "registry:component",
      "target": "components/event-card/lib/event-status.ts"
    },
    {
      "path": "src/registry/components/data/event-card/lib/format-default.ts",
      "content": "export function formatEventDate(dateString: string, locale?: string): string {\n  return new Date(dateString).toLocaleDateString(locale, {\n    day: \"numeric\",\n    month: \"long\",\n    year: \"numeric\",\n  });\n}\n\nexport function getDaysUntilEvent(\n  dateString: string,\n  now: Date = new Date(),\n): number {\n  const today = new Date(now);\n  today.setHours(0, 0, 0, 0);\n  const eventDate = new Date(dateString);\n  eventDate.setHours(0, 0, 0, 0);\n  return Math.ceil(\n    (eventDate.getTime() - today.getTime()) / (1000 * 60 * 60 * 24),\n  );\n}\n\nconst enPluralRules = new Intl.PluralRules(\"en\");\n\n/** Default English plural-correct days-until suffix. \"day left\" / \"days left\". */\nexport function defaultFormatDaysUntilSuffix(count: number): string {\n  return enPluralRules.select(count) === \"one\" ? \"day left\" : \"days left\";\n}\n\n/** Default English plural-correct spots-left suffix. \"spot left\" / \"spots left\". */\nexport function defaultFormatSpotsLeftSuffix(count: number): string {\n  return enPluralRules.select(count) === \"one\" ? \"spot left\" : \"spots left\";\n}\n",
      "type": "registry:component",
      "target": "components/event-card/lib/format-default.ts"
    },
    {
      "path": "src/registry/components/data/event-card/lib/image-fallback.tsx",
      "content": "import { Calendar } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport function ImageFallback({ className }: { className?: string }) {\n  return (\n    <div\n      className={cn(\n        \"flex h-full w-full items-center justify-center bg-muted\",\n        className,\n      )}\n    >\n      <Calendar\n        aria-hidden=\"true\"\n        className=\"h-8 w-8 text-muted-foreground/40\"\n      />\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/event-card/lib/image-fallback.tsx"
    }
  ],
  "categories": [
    "data",
    "events"
  ],
  "type": "registry:block"
}