{
  "name": "cookie-consent",
  "type": "registry:block",
  "registryDependencies": [
    "button",
    "dialog",
    "switch",
    "card",
    "label",
    "accordion"
  ],
  "files": [
    {
      "path": "components/cookie-consent/cookie-provider.tsx",
      "type": "registry:file",
      "target": "components/cookie-consent/cookie-provider.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { GoogleConsentMode } from \"./google-consent-mode\";\nimport {\n  hasGoogleScripts as checkHasGoogleScripts,\n  getLoadedScripts,\n  loadConsentedScripts,\n  registerScript as registerScriptInternal,\n  unloadRevokedScripts,\n  unregisterScript as unregisterScriptInternal,\n} from \"./script-manager\";\nimport { retryFailedRecords, trackConsent } from \"./tracker\";\nimport type {\n  CategoryConfig,\n  ConsentCategories,\n  ConsentCategory,\n  ConsentChangeEvent,\n  ConsentState,\n  CookieConsentConfig,\n  CookieConsentContextValue,\n  GoogleConsentModeConfig,\n  ScriptConfig,\n} from \"./types\";\nimport {\n  calculateExpirationDate,\n  clearConsentState,\n  getAllAcceptedCategories,\n  getDefaultCategories,\n  getExistingVisitorId,\n  getVisitorId,\n  isConsentExpired,\n  isGoogleScript,\n  loadConsentState,\n  saveConsentState,\n} from \"./utils\";\n\nconst CookieConsentContext =\n  React.createContext<CookieConsentContextValue | null>(null);\n\nexport const defaultCategories: CategoryConfig[] = [\n  {\n    key: \"necessary\",\n    title: \"Necessary\",\n    description:\n      \"Essential cookies required for the website to function properly. These cannot be disabled.\",\n    required: true,\n  },\n  {\n    key: \"analytics\",\n    title: \"Analytics\",\n    description:\n      \"Cookies that help us understand how visitors interact with our website.\",\n  },\n  {\n    key: \"marketing\",\n    title: \"Marketing\",\n    description: \"Cookies used for advertising and tracking across websites.\",\n  },\n  {\n    key: \"preferences\",\n    title: \"Preferences\",\n    description: \"Cookies that remember your settings and preferences.\",\n  },\n];\n\ninterface CookieConsentProviderProps {\n  children: React.ReactNode;\n  config: CookieConsentConfig;\n}\n\nexport function CookieConsentProvider({\n  children,\n  config,\n}: CookieConsentProviderProps) {\n  const [state, setState] = React.useState<ConsentState>(() => ({\n    hasConsented: false,\n    categories: getDefaultCategories(config.categories),\n    lastUpdated: null,\n    consentVersion: config.consentVersion,\n    visitorId: \"\",\n  }));\n  const [isBannerVisible, setIsBannerVisible] = React.useState(false);\n  const [isSettingsOpen, setIsSettingsOpen] = React.useState(false);\n  const [isInitialized, setIsInitialized] = React.useState(false);\n  const [hasGoogleScripts, setHasGoogleScripts] = React.useState(false);\n\n  const previousCategoriesRef = React.useRef<ConsentCategories>(\n    getDefaultCategories(config.categories)\n  );\n\n  // Auto-enable Google Consent Mode if Google scripts are detected\n  const effectiveGoogleConsentMode = React.useMemo(():\n    | GoogleConsentModeConfig\n    | undefined => {\n    // If user explicitly configured it, use their config\n    if (config.googleConsentMode) {\n      return config.googleConsentMode;\n    }\n    // If Google scripts are detected, auto-enable with defaults\n    if (hasGoogleScripts) {\n      return {\n        enabled: true,\n        mapping: {\n          analytics_storage: \"analytics\",\n          ad_storage: \"marketing\",\n          ad_user_data: \"marketing\",\n          ad_personalization: \"marketing\",\n          functionality_storage: \"preferences\",\n          personalization_storage: \"preferences\",\n          security_storage: \"necessary\",\n        },\n      };\n    }\n    return undefined;\n  }, [config.googleConsentMode, hasGoogleScripts]);\n\n  // Update Google Consent Mode v2 when consent changes\n  // Only updates if Google Consent Mode is enabled AND gtag exists (user is using Google services)\n  const updateGoogleConsentMode = React.useCallback(\n    (categories: ConsentCategories) => {\n      if (!effectiveGoogleConsentMode?.enabled) return;\n      if (typeof window === \"undefined\" || !window.gtag) return;\n      // Additional check: only update if dataLayer exists (Google services are actually loaded)\n      if (!window.dataLayer) return;\n\n      const mapping = effectiveGoogleConsentMode.mapping || {\n        analytics_storage: \"analytics\",\n        ad_storage: \"marketing\",\n        ad_user_data: \"marketing\",\n        ad_personalization: \"marketing\",\n        functionality_storage: \"preferences\",\n        personalization_storage: \"preferences\",\n        security_storage: \"necessary\",\n      };\n\n      const consentUpdate: Record<string, \"granted\" | \"denied\"> = {};\n\n      // Map consent categories to Google consent types\n      Object.entries(mapping).forEach(([googleType, category]) => {\n        if (category && categories[category]) {\n          consentUpdate[googleType] = \"granted\";\n        } else {\n          consentUpdate[googleType] = \"denied\";\n        }\n      });\n\n      // Update Google Consent Mode\n      window.gtag(\"consent\", \"update\", consentUpdate);\n    },\n    [effectiveGoogleConsentMode]\n  );\n\n  // Initialize state from localStorage\n  React.useEffect(() => {\n    const visitorId = getExistingVisitorId();\n    const stored = loadConsentState();\n\n    const isExpired = stored?.expiresAt\n      ? isConsentExpired(stored.expiresAt)\n      : stored?.lastUpdated\n        ? new Date(stored.lastUpdated).getTime() +\n            (config.expirationDays ?? 365) * 86400000 <\n          Date.now()\n        : false;\n\n    if (\n      stored &&\n      stored.consentVersion === config.consentVersion &&\n      !isExpired\n    ) {\n      setState({ ...stored, visitorId: stored.visitorId || visitorId || \"\" });\n      setIsBannerVisible(false);\n      previousCategoriesRef.current = stored.categories;\n\n      loadConsentedScripts(stored.categories);\n    } else {\n      setState((prev) => ({ ...prev, visitorId: visitorId || \"\" }));\n      setIsBannerVisible(true);\n    }\n\n    setIsInitialized(true);\n\n    if (config.traceability?.enabled) {\n      retryFailedRecords(config.traceability);\n    }\n  }, [config.consentVersion, config.expirationDays, config.traceability]);\n\n  // Check for existing Google scripts on mount\n  React.useEffect(() => {\n    // Check if any already registered scripts are Google scripts\n    if (checkHasGoogleScripts()) {\n      setHasGoogleScripts(true);\n    }\n  }, []);\n\n  const saveAndTrack = React.useCallback(\n    async (\n      categories: ConsentCategories,\n      action: \"accept_all\" | \"reject_all\" | \"custom\" | \"update\"\n    ) => {\n      const expirationDays = config.expirationDays ?? 365;\n      const expiresAt = calculateExpirationDate(expirationDays);\n      const visitorId = getVisitorId();\n\n      const previousCategories = previousCategoriesRef.current;\n\n      const newState: ConsentState = {\n        hasConsented: true,\n        categories,\n        lastUpdated: new Date().toISOString(),\n        consentVersion: config.consentVersion,\n        visitorId,\n        expiresAt,\n      };\n\n      setState(newState);\n      saveConsentState(newState);\n      setIsBannerVisible(false);\n\n      const revokedCategories = unloadRevokedScripts(\n        previousCategories,\n        categories\n      );\n      loadConsentedScripts(categories);\n\n      // Update Google Consent Mode v2\n      updateGoogleConsentMode(categories);\n\n      const grantedCategories: ConsentCategory[] = [];\n      (Object.keys(categories) as ConsentCategory[]).forEach((category) => {\n        if (!previousCategories[category] && categories[category]) {\n          grantedCategories.push(category);\n        }\n      });\n\n      if (config.onConsentChange) {\n        const event: ConsentChangeEvent = {\n          previousCategories,\n          currentCategories: categories,\n          action,\n          revokedCategories,\n          grantedCategories,\n        };\n        config.onConsentChange(event);\n      }\n\n      // Update previous categories ref\n      previousCategoriesRef.current = categories;\n\n      // Track consent if traceability is enabled\n      if (config.traceability?.enabled) {\n        const userId = await config.consentScope?.getUserId?.();\n        await trackConsent({\n          categories,\n          action,\n          consentVersion: config.consentVersion,\n          expiresAt,\n          config: config.traceability,\n          userId: userId ?? undefined,\n          scope: config.consentScope?.mode === \"global\" ? \"global\" : \"device\",\n        });\n      }\n    },\n    [config, updateGoogleConsentMode]\n  );\n\n  const acceptAll = React.useCallback(async () => {\n    await saveAndTrack(\n      getAllAcceptedCategories(config.categories ?? defaultCategories),\n      \"accept_all\"\n    );\n  }, [config.categories, saveAndTrack]);\n\n  const rejectAll = React.useCallback(async () => {\n    await saveAndTrack(\n      getDefaultCategories(config.categories),\n      \"reject_all\"\n    );\n  }, [config.categories, saveAndTrack]);\n\n  const updateConsent = React.useCallback(\n    async (categories: Partial<ConsentCategories>) => {\n      const newCategories: ConsentCategories = {\n        ...state.categories,\n        ...categories,\n        necessary: true,\n      };\n      const action = state.hasConsented ? \"update\" : \"custom\";\n      await saveAndTrack(newCategories, action);\n    },\n    [state.categories, state.hasConsented, saveAndTrack]\n  );\n\n  const openSettings = React.useCallback(() => {\n    setIsSettingsOpen(true);\n  }, []);\n\n  const closeSettings = React.useCallback(() => {\n    setIsSettingsOpen(false);\n  }, []);\n\n  const hideBanner = React.useCallback(() => {\n    setIsBannerVisible(false);\n  }, []);\n\n  const resetConsent = React.useCallback(() => {\n    const defaultCats = getDefaultCategories(config.categories);\n    unloadRevokedScripts(state.categories, defaultCats);\n\n    clearConsentState();\n    setState({\n      hasConsented: false,\n      categories: defaultCats,\n      lastUpdated: null,\n      consentVersion: config.consentVersion,\n      visitorId: \"\",\n    });\n    previousCategoriesRef.current = defaultCats;\n    setIsBannerVisible(true);\n  }, [config.categories, config.consentVersion, state.categories]);\n\n  const hasConsent = React.useCallback(\n    (category: \"necessary\" | \"analytics\" | \"marketing\" | \"preferences\") => {\n      return state.categories[category] ?? false;\n    },\n    [state.categories]\n  );\n\n  const registerScript = React.useCallback((script: ScriptConfig) => {\n    registerScriptInternal(script);\n\n    // Auto-detect Google scripts and enable Google Consent Mode\n    if (isGoogleScript(script)) {\n      setHasGoogleScripts(true);\n    }\n  }, []);\n\n  const unregisterScript = React.useCallback((id: string) => {\n    unregisterScriptInternal(id);\n  }, []);\n\n  const value: CookieConsentContextValue = React.useMemo(\n    () => ({\n      state,\n      isBannerVisible: isInitialized && isBannerVisible,\n      isSettingsOpen,\n      acceptAll,\n      rejectAll,\n      updateConsent,\n      openSettings,\n      closeSettings,\n      hideBanner,\n      resetConsent,\n      hasConsent,\n      config,\n      registerScript,\n      unregisterScript,\n      getLoadedScripts,\n    }),\n    [\n      state,\n      isInitialized,\n      isBannerVisible,\n      isSettingsOpen,\n      acceptAll,\n      rejectAll,\n      updateConsent,\n      openSettings,\n      closeSettings,\n      hideBanner,\n      resetConsent,\n      hasConsent,\n      config,\n      registerScript,\n      unregisterScript,\n    ]\n  );\n\n  return (\n    <CookieConsentContext.Provider value={value}>\n      {children}\n      {/* Automatically render GoogleConsentMode when Google scripts are detected */}\n      {hasGoogleScripts && effectiveGoogleConsentMode?.enabled && (\n        <GoogleConsentMode\n          defaults={{\n            analytics_storage: \"denied\",\n            ad_storage: \"denied\",\n            ad_user_data: \"denied\",\n            ad_personalization: \"denied\",\n          }}\n          regions={effectiveGoogleConsentMode?.regions}\n        />\n      )}\n    </CookieConsentContext.Provider>\n  );\n}\n\nexport function useCookieConsent(): CookieConsentContextValue {\n  const context = React.useContext(CookieConsentContext);\n  if (!context) {\n    throw new Error(\n      \"useCookieConsent must be used within a CookieConsentProvider\"\n    );\n  }\n  return context;\n}\n\nexport { CookieConsentContext };\n"
    },
    {
      "path": "components/cookie-consent/cookie-banner.tsx",
      "type": "registry:file",
      "target": "components/cookie-consent/cookie-banner.tsx",
      "content": "\"use client\";\nimport { Button } from \"@/components/ui/button\";\nimport { cn } from \"@/lib/utils\";\nimport { AnimatePresence, motion } from \"framer-motion\";\nimport { Cookie, Settings } from \"lucide-react\";\nimport { useCookieConsent } from \"./cookie-provider\";\nimport type { BannerPosition, BannerSize } from \"./types\";\n\nexport interface CookieBannerProps {\n  className?: string;\n  position?: BannerPosition;\n  size?: BannerSize;\n  buttonClassName?: string;\n  isEmbedded?: boolean;\n  forceVisible?: boolean;\n  isMobile?: boolean;\n  title?: string;\n  description?: string;\n  acceptAllText?: string;\n  rejectAllText?: string;\n  customizeText?: string;\n  learnMoreText?: string;\n}\n\nexport function CookieBanner({\n  className,\n  position: propPosition,\n  size: propSize,\n  buttonClassName,\n  isEmbedded = false,\n  forceVisible = false,\n  isMobile = false,\n  title = \"Cookie Preferences\",\n  description = \"We use cookies to enhance your experience. By continuing to visit this site you agree to our use of cookies.\",\n  acceptAllText = \"Accept All\",\n  rejectAllText = \"Reject All\",\n  customizeText = \"Customize\",\n  learnMoreText = \"Learn more\",\n}: CookieBannerProps) {\n  const { isBannerVisible, acceptAll, rejectAll, openSettings, config } =\n    useCookieConsent();\n\n  const showBanner = forceVisible || isBannerVisible;\n\n  const position = propPosition ?? config.position ?? \"bottom\";\n  const isFloating = position === \"bottom-left\" || position === \"bottom-right\";\n  const size = propSize ?? config.size ?? \"default\";\n\n  const positionClasses = {\n    bottom: isMobile ? \"inset-x-0 bottom-0 p-3\" : \"inset-x-0 bottom-0 p-3 sm:p-4\",\n    top: isMobile ? \"inset-x-0 top-0 p-3\" : \"inset-x-0 top-0 p-3 sm:p-4\",\n    \"bottom-left\": isMobile\n      ? \"inset-x-0 bottom-0 p-3\"\n      : \"inset-x-0 bottom-0 p-3 sm:p-0 sm:bottom-4 sm:left-4 sm:right-auto sm:w-full sm:max-w-md\",\n    \"bottom-right\": isMobile\n      ? \"inset-x-0 bottom-0 p-3\"\n      : \"inset-x-0 bottom-0 p-3 sm:p-0 sm:bottom-4 sm:right-4 sm:left-auto sm:w-full sm:max-w-md\",\n  };\n\n  // Prevent rounded-full from collapsing floating cards into distorted ovals\n  const safeCardClassName = isFloating && className?.includes(\"rounded-full\")\n    ? className.replace(/\\brounded-full\\b/g, \"rounded-3xl\")\n    : className;\n\n  // Derive matching button radius from banner className or explicit buttonClassName\n  const detectedRadius = className?.match(/\\brounded-(none|xs|sm|md|lg|xl|2xl|3xl|full)\\b/)?.[0];\n  const buttonRadiusClass = buttonClassName ?? detectedRadius ?? \"\";\n\n  const sizeStyles = {\n    sm: {\n      title: \"text-xs font-semibold\",\n      description: \"text-[11px] leading-relaxed\",\n      iconBox: \"h-7 w-7\",\n      icon: \"h-3.5 w-3.5\",\n      floatingPadding: \"p-3.5 space-y-2.5\",\n      barPadding: \"p-3.5 sm:px-6 sm:py-3.5\",\n      button: \"h-7 text-[11px] px-2.5\",\n    },\n    default: {\n      title: \"text-sm font-semibold\",\n      description: \"text-xs sm:text-sm leading-relaxed\",\n      iconBox: \"h-9 w-9 sm:h-10 sm:w-10\",\n      icon: \"h-4 w-4 sm:h-5 sm:w-5\",\n      floatingPadding: \"p-5 space-y-4\",\n      barPadding: \"p-5 sm:px-8 sm:py-5\",\n      button: \"h-8 text-xs px-3\",\n    },\n    lg: {\n      title: \"text-base font-bold\",\n      description: \"text-sm sm:text-base leading-relaxed\",\n      iconBox: \"h-11 w-11 sm:h-12 sm:w-12\",\n      icon: \"h-5 w-5 sm:h-6 sm:w-6\",\n      floatingPadding: \"p-6 space-y-5\",\n      barPadding: \"p-6 sm:px-10 sm:py-6\",\n      button: \"h-9 text-sm px-4\",\n    },\n  }[size];\n\n  return (\n    <AnimatePresence>\n      {showBanner && (\n        <motion.div\n          key={position}\n          initial={{ y: position.includes(\"top\") ? -100 : 100, opacity: 0 }}\n          animate={{ y: 0, opacity: 1 }}\n          exit={{ y: position.includes(\"top\") ? -100 : 100, opacity: 0 }}\n          transition={{ type: \"spring\", damping: 25, stiffness: 300 }}\n          className={cn(\n            isEmbedded ? \"absolute z-30\" : \"fixed z-50\",\n            positionClasses[position]\n          )}\n        >\n          <div\n            className={cn(\n              \"bg-card border border-border rounded-lg shadow-lg overflow-hidden\",\n              !isFloating ? \"@container mx-auto max-w-5xl\" : \"w-full mx-auto max-w-md\",\n              safeCardClassName\n            )}\n          >\n            {isFloating ? (\n              /* Floating Card Layout (bottom-left / bottom-right) */\n              <div className={sizeStyles.floatingPadding}>\n                <div className=\"flex items-center gap-3\">\n                  <div className={cn(\"shrink-0 flex items-center justify-center rounded-full bg-muted\", sizeStyles.iconBox)}>\n                    <Cookie className={cn(\"text-muted-foreground\", sizeStyles.icon)} />\n                  </div>\n                  <h3 className={cn(\"text-foreground\", sizeStyles.title)}>\n                    {title}\n                  </h3>\n                </div>\n\n                <p className={cn(\"text-muted-foreground\", sizeStyles.description)}>\n                  {description}{\" \"}\n                  {config.privacyPolicyUrl && (\n                    <a\n                      href={config.privacyPolicyUrl}\n                      className=\"underline underline-offset-4 hover:text-foreground transition-colors\"\n                      target=\"_blank\"\n                      rel=\"noopener noreferrer\"\n                    >\n                      {learnMoreText}\n                    </a>\n                  )}\n                </p>\n\n                <div className=\"flex flex-col gap-2 pt-1\">\n                  <div className=\"grid grid-cols-2 gap-2\">\n                    <Button\n                      variant=\"outline\"\n                      size=\"sm\"\n                      onClick={openSettings}\n                      className={cn(\"gap-1.5 bg-transparent w-full\", sizeStyles.button, buttonRadiusClass)}\n                    >\n                      <Settings className={cn(\"shrink-0\", sizeStyles.icon)} />\n                      {customizeText}\n                    </Button>\n                    <Button\n                      variant=\"outline\"\n                      size=\"sm\"\n                      onClick={rejectAll}\n                      className={cn(\"bg-transparent w-full\", sizeStyles.button, buttonRadiusClass)}\n                    >\n                      {rejectAllText}\n                    </Button>\n                  </div>\n                  <Button\n                    size=\"sm\"\n                    onClick={acceptAll}\n                    className={cn(\"w-full font-medium\", sizeStyles.button, buttonRadiusClass)}\n                  >\n                    {acceptAllText}\n                  </Button>\n                </div>\n              </div>\n            ) : (\n              /* Full-Width Bar Layout (bottom / top) */\n              <div className={sizeStyles.barPadding}>\n                <div className=\"flex flex-col gap-3.5 @3xl:flex-row @3xl:items-center @3xl:justify-between\">\n                  <div className=\"flex items-start gap-3 sm:gap-4\">\n                    <div className={cn(\"shrink-0 flex items-center justify-center rounded-full bg-muted mt-0.5\", sizeStyles.iconBox)}>\n                      <Cookie className={cn(\"text-muted-foreground\", sizeStyles.icon)} />\n                    </div>\n                    <div className=\"space-y-1\">\n                      <h3 className={cn(\"text-foreground\", sizeStyles.title)}>\n                        {title}\n                      </h3>\n                      <p className={cn(\"max-w-xl text-muted-foreground\", sizeStyles.description)}>\n                        {description}{\" \"}\n                        {config.privacyPolicyUrl && (\n                          <a\n                            href={config.privacyPolicyUrl}\n                            className=\"underline underline-offset-4 hover:text-foreground transition-colors\"\n                            target=\"_blank\"\n                            rel=\"noopener noreferrer\"\n                          >\n                            {learnMoreText}\n                          </a>\n                        )}\n                      </p>\n                    </div>\n                  </div>\n\n                  {/* Button cluster with container-aware responsive wrap */}\n                  <div className=\"grid grid-cols-2 gap-2 @sm:flex @sm:items-center @sm:flex-wrap @sm:justify-end shrink-0 pt-1 @3xl:pt-0\">\n                    <Button\n                      variant=\"outline\"\n                      size=\"sm\"\n                      onClick={openSettings}\n                      className={cn(\"gap-1.5 bg-transparent col-span-1 @sm:w-auto\", sizeStyles.button, buttonRadiusClass)}\n                    >\n                      <Settings className={cn(\"shrink-0\", sizeStyles.icon)} />\n                      {customizeText}\n                    </Button>\n                    <Button\n                      variant=\"outline\"\n                      size=\"sm\"\n                      onClick={rejectAll}\n                      className={cn(\"bg-transparent col-span-1 @sm:w-auto\", sizeStyles.button, buttonRadiusClass)}\n                    >\n                      {rejectAllText}\n                    </Button>\n                    <Button\n                      size=\"sm\"\n                      onClick={acceptAll}\n                      className={cn(\"font-medium col-span-2 @sm:w-auto\", sizeStyles.button, buttonRadiusClass)}\n                    >\n                      {acceptAllText}\n                    </Button>\n                  </div>\n                </div>\n              </div>\n            )}\n          </div>\n        </motion.div>\n      )}\n    </AnimatePresence>\n  );\n}\n"
    },
    {
      "path": "components/cookie-consent/cookie-settings.tsx",
      "type": "registry:file",
      "target": "components/cookie-consent/cookie-settings.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Check, Shield } from \"lucide-react\"\nimport {\n  Dialog,\n  DialogContent,\n  DialogDescription,\n  DialogFooter,\n  DialogHeader,\n  DialogTitle,\n} from \"@/components/ui/dialog\"\nimport { Button } from \"@/components/ui/button\"\nimport { Switch } from \"@/components/ui/switch\"\nimport { Label } from \"@/components/ui/label\"\nimport { Separator } from \"@/components/ui/separator\"\nimport { useCookieConsent, defaultCategories } from \"./cookie-provider\"\nimport type { ConsentCategories, ConsentCategory } from \"./types\"\nimport { getDefaultCategories, getAllAcceptedCategories } from \"./utils\"\nimport { cn } from \"@/lib/utils\"\n\nexport interface CookieSettingsProps {\n  className?: string\n  buttonClassName?: string\n  title?: string\n  description?: string\n}\n\nexport function CookieSettings({\n  className,\n  buttonClassName,\n  title = \"Cookie Settings\",\n  description = \"Manage your cookie preferences below.\",\n}: CookieSettingsProps) {\n  const { isSettingsOpen, closeSettings, state, updateConsent, config, acceptAll, rejectAll } = useCookieConsent()\n\n  const categories = config.categories ?? defaultCategories\n\n  const [localCategories, setLocalCategories] = React.useState<ConsentCategories>(state.categories)\n\n  // Derive matching button radius from modal className or explicit buttonClassName\n  const detectedRadius = className?.match(/\\brounded-(none|xs|sm|md|lg|xl|2xl|3xl|full)\\b/)?.[0];\n  const buttonRadiusClass = buttonClassName ?? detectedRadius ?? \"\";\n\n  // Sync local state when modal opens or when state changes\n  React.useEffect(() => {\n    if (isSettingsOpen) {\n      setLocalCategories(state.categories)\n    }\n  }, [isSettingsOpen, state.categories])\n\n  const handleToggle = (key: ConsentCategory, checked: boolean) => {\n    setLocalCategories((prev) => ({\n      ...prev,\n      [key]: checked,\n    }))\n  }\n\n  const handleSave = async () => {\n    await updateConsent(localCategories)\n    closeSettings()\n  }\n\n  const handleAcceptAll = async () => {\n    const allAccepted = getAllAcceptedCategories(categories)\n    // Update local state immediately for UI feedback\n    setLocalCategories(allAccepted)\n    await acceptAll()\n    closeSettings()\n  }\n\n  const handleRejectAll = async () => {\n    const defaultCats = getDefaultCategories(categories)\n    // Update local state immediately for UI feedback\n    setLocalCategories(defaultCats)\n    await rejectAll()\n    closeSettings()\n  }\n\n  return (\n    <Dialog open={isSettingsOpen} onOpenChange={(open) => !open && closeSettings()}>\n      <DialogContent className={cn(\"sm:max-w-lg\", className)}>\n        <DialogHeader>\n          <div className=\"flex items-center gap-3\">\n            <div className=\"flex h-10 w-10 items-center justify-center rounded-full bg-muted\">\n              <Shield className=\"h-5 w-5 text-muted-foreground\" />\n            </div>\n            <div>\n              <DialogTitle>{title}</DialogTitle>\n              <DialogDescription>{description}</DialogDescription>\n            </div>\n          </div>\n        </DialogHeader>\n\n        <Separator />\n\n        <div className=\"space-y-4 py-4 max-h-[60vh] overflow-y-auto\">\n          {categories.map((category) => {\n            const isEnabled = localCategories[category.key]\n            const isRequired = category.required\n\n            return (\n              <div\n                key={category.key}\n                className={cn(\n                  \"flex items-start justify-between gap-4 rounded-lg border p-4 transition-colors\",\n                  isEnabled ? \"border-primary/20 bg-primary/5\" : \"border-border\",\n                )}\n              >\n                <div className=\"space-y-1\">\n                  <div className=\"flex items-center gap-2\">\n                    <Label htmlFor={`cookie-${category.key}`} className=\"text-sm font-medium cursor-pointer\">\n                      {category.title}\n                    </Label>\n                    {isRequired && (\n                      <span className=\"text-xs text-muted-foreground bg-muted px-2 py-0.5 rounded\">Required</span>\n                    )}\n                  </div>\n                  <p className=\"text-sm text-muted-foreground leading-relaxed\">{category.description}</p>\n                </div>\n                <Switch\n                  id={`cookie-${category.key}`}\n                  checked={isEnabled}\n                  onCheckedChange={(checked) => handleToggle(category.key, checked)}\n                  disabled={isRequired}\n                  aria-label={`Toggle ${category.title} cookies`}\n                />\n              </div>\n            )\n          })}\n        </div>\n\n        <Separator />\n\n        <DialogFooter className=\"flex-col gap-2 sm:flex-row\">\n          <Button\n            variant=\"outline\"\n            size=\"sm\"\n            onClick={handleRejectAll}\n            className={cn(\"w-full sm:w-auto bg-transparent\", buttonRadiusClass)}\n          >\n            Reject All\n          </Button>\n          <Button\n            variant=\"outline\"\n            size=\"sm\"\n            onClick={handleAcceptAll}\n            className={cn(\"w-full sm:w-auto bg-transparent\", buttonRadiusClass)}\n          >\n            Accept All\n          </Button>\n          <Button\n            size=\"sm\"\n            onClick={handleSave}\n            className={cn(\"w-full sm:w-auto gap-2\", buttonRadiusClass)}\n          >\n            <Check className=\"h-4 w-4\" />\n            Save Preferences\n          </Button>\n        </DialogFooter>\n\n        {config.privacyPolicyUrl && (\n          <p className=\"text-xs text-center text-muted-foreground\">\n            Read our{\" \"}\n            <a\n              href={config.privacyPolicyUrl}\n              className=\"underline underline-offset-4 hover:text-foreground transition-colors\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n            >\n              Privacy Policy\n            </a>\n          </p>\n        )}\n      </DialogContent>\n    </Dialog>\n  )\n}\n"
    },
    {
      "path": "components/cookie-consent/cookie-trigger.tsx",
      "type": "registry:file",
      "target": "components/cookie-consent/cookie-trigger.tsx",
      "content": "\"use client\"\nimport { Cookie } from \"lucide-react\"\nimport { Button } from \"@/components/ui/button\"\nimport { useCookieConsent } from \"./cookie-provider\"\nimport { cn } from \"@/lib/utils\"\n\nexport interface CookieTriggerProps {\n  className?: string\n  variant?: \"icon\" | \"text\" | \"full\"\n  children?: React.ReactNode\n}\n\n/**\n * A trigger button to reopen cookie settings after initial consent\n */\nexport function CookieTrigger({ className, variant = \"text\", children }: CookieTriggerProps) {\n  const { openSettings, state } = useCookieConsent()\n\n  if (children) {\n    return (\n      <Button onClick={openSettings} className={className}>\n        {children}\n      </Button>\n    )\n  }\n\n  if (!state.hasConsented) {\n    return null\n  }\n\n  if (variant === \"icon\") {\n    return (\n      <Button\n        variant=\"ghost\"\n        size=\"icon\"\n        onClick={openSettings}\n        className={cn(\"h-8 w-8\", className)}\n        aria-label=\"Cookie settings\"\n      >\n        <Cookie className=\"h-4 w-4\" />\n      </Button>\n    )\n  }\n\n  if (variant === \"full\") {\n    return (\n      <Button variant=\"outline\" size=\"sm\" onClick={openSettings} className={cn(\"gap-2\", className)}>\n        <Cookie className=\"h-4 w-4\" />\n        Cookie Settings\n      </Button>\n    )\n  }\n\n  return (\n    <button\n      onClick={openSettings}\n      className={cn(\n        \"text-sm text-muted-foreground hover:text-foreground underline underline-offset-4 transition-colors\",\n        className,\n      )}\n    >\n      Cookie Settings\n    </button>\n  )\n}\n"
    },
    {
      "path": "components/cookie-consent/consent-script.tsx",
      "type": "registry:file",
      "target": "components/cookie-consent/consent-script.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { useCookieConsent } from \"./cookie-provider\"\nimport type { ConsentCategory, ScriptConfig } from \"./types\"\nimport { loadScript, registerCleanup, registerScript, unregisterScript } from \"./script-manager\"\n\nexport interface ConsentScriptProps {\n  /** Unique identifier for the script */\n  id: string\n  /** External script URL */\n  src?: string\n  /** Inline script content */\n  children?: string\n  /** Consent category required to load */\n  category: ConsentCategory\n  /** Script loading strategy */\n  strategy?: \"afterInteractive\" | \"lazyOnload\" | \"beforeInteractive\"\n  /** Additional script attributes */\n  attributes?: Record<string, string>\n  /** Callback when script loads */\n  onLoad?: () => void\n  /** Callback when script fails to load */\n  onError?: (error: Error) => void\n  /** Callback when consent is revoked - use for cleanup */\n  onRevoke?: () => void\n}\n\n/**\n * ConsentScript - A component that conditionally loads scripts based on user consent.\n *\n * Similar to Next.js Script component but with consent awareness.\n *\n * @example\n * // External script\n * <ConsentScript\n *   id=\"google-analytics\"\n *   src=\"https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID\"\n *   category=\"analytics\"\n *   onRevoke={() => {\n *     // Cleanup GA cookies and global\n *     window.ga = undefined\n *   }}\n * />\n *\n * @example\n * // Inline script\n * <ConsentScript id=\"analytics-init\" category=\"analytics\">\n *   {`window.dataLayer = window.dataLayer || [];`}\n * </ConsentScript>\n */\nexport function ConsentScript({\n  id,\n  src,\n  children,\n  category,\n  strategy = \"afterInteractive\",\n  attributes,\n  onLoad,\n  onError,\n  onRevoke,\n}: ConsentScriptProps) {\n  const { hasConsent, registerScript: ctxRegister } = useCookieConsent()\n  const hasConsentForCategory = hasConsent(category)\n  const [isLoaded, setIsLoaded] = React.useState(false)\n  const [error, setError] = React.useState<Error | null>(null)\n\n  // Register script on mount\n  React.useEffect(() => {\n    const config: ScriptConfig = {\n      id,\n      src,\n      content: children,\n      category,\n      strategy,\n      attributes,\n      onLoad: () => {\n        setIsLoaded(true)\n        onLoad?.()\n      },\n      onError: (err) => {\n        setError(err)\n        onError?.(err)\n      },\n      onRevoke: () => {\n        setIsLoaded(false)\n        onRevoke?.()\n      },\n    }\n\n    registerScript(config)\n    ctxRegister(config)\n\n    return () => {\n      unregisterScript(id)\n    }\n  }, [id, src, children, category, strategy, attributes, onLoad, onError, onRevoke, ctxRegister])\n\n  // Load script when consent is granted\n  React.useEffect(() => {\n    if (hasConsentForCategory && !isLoaded && !error) {\n      loadScript(id).catch((err) => {\n        setError(err)\n        onError?.(err)\n      })\n    }\n  }, [hasConsentForCategory, isLoaded, error, id, onError])\n\n  // Register cleanup if provided\n  React.useEffect(() => {\n    if (onRevoke) {\n      registerCleanup(id, onRevoke)\n    }\n  }, [id, onRevoke])\n\n  // This component doesn't render anything visible\n  return null\n}\n\nConsentScript.displayName = \"ConsentScript\"\n"
    },
    {
      "path": "components/cookie-consent/index.ts",
      "type": "registry:file",
      "target": "components/cookie-consent/index.ts",
      "content": "// Main exports for cookie consent components\nexport { ConsentScript } from \"./consent-script\";\nexport { CookieBanner } from \"./cookie-banner\";\nexport { CookieBannerBackdrop } from \"./cookie-banner-backdrop\";\nexport {\n  CookieConsentProvider,\n  defaultCategories,\n  useCookieConsent,\n} from \"./cookie-provider\";\nexport { CookieSettings } from \"./cookie-settings\";\nexport { CookieTrigger } from \"./cookie-trigger\";\nexport { GoogleConsentMode } from \"./google-consent-mode\";\nexport { useConsentScript } from \"./use-consent-script\";\nexport { useConsentGate, useConsentValue } from \"./use-cookie-consent\";\n\n// Types\nexport type {\n  BannerPosition,\n  BannerSize,\n  CategoryConfig,\n  ConsentAction,\n  ConsentCategories,\n  ConsentCategory,\n  ConsentChangeEvent,\n  ConsentRecord,\n  ConsentScope,\n  ConsentScopeConfig,\n  ConsentState,\n  CookieConsentConfig,\n  CookieConsentContextValue,\n  GoogleConsentModeConfig,\n  ScriptConfig,\n  TraceabilityConfig,\n} from \"./types\";\n\n// Utilities\nexport {\n  getLoadedScripts,\n  hasGoogleScripts,\n  loadScript,\n  registerCleanup,\n  registerScript,\n  scriptCleanupHelpers,\n  unloadScript,\n  unregisterScript,\n} from \"./script-manager\";\nexport { retryFailedRecords, trackConsent } from \"./tracker\";\nexport { generateUUID, getExistingVisitorId, getVisitorId, isGoogleScript } from \"./utils\";\n\n// Note: Test utilities are not exported from the main index to avoid\n// bundling test dependencies in production builds. Import them directly\n// from \"./test-utils\" in test files only.\n"
    },
    {
      "path": "components/cookie-consent/types.ts",
      "type": "registry:file",
      "target": "components/cookie-consent/types.ts",
      "content": "// Cookie consent types following shadcn patterns\n\nexport type ConsentCategory = \"necessary\" | \"analytics\" | \"marketing\" | \"preferences\"\n\nexport type ConsentAction = \"accept_all\" | \"reject_all\" | \"custom\" | \"update\"\n\nexport type ConsentScope = \"device\" | \"global\"\n\nexport type BannerPosition = \"bottom\" | \"top\" | \"bottom-left\" | \"bottom-right\"\n\nexport type BannerSize = \"sm\" | \"default\" | \"lg\"\n\nexport interface ConsentCategories {\n  necessary: boolean\n  analytics: boolean\n  marketing: boolean\n  preferences: boolean\n}\n\nexport interface ConsentRecord {\n  /** Unique device identifier */\n  visitorId: string\n  /** Unique consent action identifier */\n  consentId: string\n  /** Version of consent policy */\n  consentVersion: string\n  /** User account ID when authenticated */\n  userId?: string\n  /** Consent scope */\n  scope: ConsentScope\n  /** Category consent values */\n  categories: ConsentCategories\n  /** Type of action taken */\n  action: ConsentAction\n  /** ISO 8601 timestamp */\n  timestamp: string\n  /** When consent expires */\n  expiresAt: string\n  /** Page URL where consent was given */\n  url: string\n  /** Browser user agent */\n  userAgent: string\n  /** Browser language */\n  language: string\n  /** Device ID that was linked (for global scope) */\n  linkedFromDevice?: string\n}\n\nexport interface TraceabilityConfig {\n  /** Enable consent traceability */\n  enabled: boolean\n  /** API endpoint to send consent records */\n  endpoint: string\n  /** HTTP method */\n  method?: \"POST\" | \"PUT\"\n  /** Custom headers */\n  headers?: Record<string, string>\n  /** Custom visitor ID generator */\n  getVisitorId?: () => string | Promise<string>\n  /** Include user agent in record */\n  includeUserAgent?: boolean\n  /** Include URL in record */\n  includeUrl?: boolean\n  /** Retry on failure */\n  retryOnFailure?: boolean\n  /** Max retry attempts */\n  maxRetries?: number\n  /** Success callback */\n  onSuccess?: (record: ConsentRecord) => void\n  /** Error callback */\n  onError?: (error: Error, record: ConsentRecord) => void\n}\n\nexport interface ConsentScopeConfig {\n  /** Consent scope mode */\n  mode: \"device\" | \"global\" | \"hybrid\"\n  /** Sync endpoint for global/hybrid mode */\n  syncEndpoint?: string\n  /** Get user ID for global consent */\n  getUserId?: () => string | null | Promise<string | null>\n  /** Conflict resolution strategy */\n  conflictStrategy?: \"server-wins\" | \"device-wins\" | \"most-recent\"\n  /** Sync on authentication */\n  syncOnAuth?: boolean\n  /** Link device to user */\n  linkDeviceToUser?: boolean\n}\n\nexport interface CategoryConfig {\n  key: ConsentCategory\n  title: string\n  description: string\n  required?: boolean\n}\n\nexport interface ScriptConfig {\n  /** Unique identifier for the script */\n  id: string\n  /** Script source URL */\n  src?: string\n  /** Inline script content */\n  content?: string\n  /** Consent category required */\n  category: ConsentCategory\n  /** Script loading strategy */\n  strategy?: \"afterInteractive\" | \"lazyOnload\" | \"beforeInteractive\"\n  /** Additional script attributes */\n  attributes?: Record<string, string>\n  /** Callback when script loads */\n  onLoad?: () => void\n  /** Callback when script fails */\n  onError?: (error: Error) => void\n  /** Cleanup function when consent is revoked */\n  onRevoke?: () => void\n}\n\nexport interface ConsentChangeEvent {\n  previousCategories: ConsentCategories\n  currentCategories: ConsentCategories\n  action: ConsentAction\n  revokedCategories: ConsentCategory[]\n  grantedCategories: ConsentCategory[]\n}\n\nexport interface GoogleConsentModeConfig {\n  /** Enable Google Consent Mode v2 integration */\n  enabled: boolean\n  /** Custom mapping of consent categories to Google consent types */\n  mapping?: {\n    analytics_storage?: ConsentCategory\n    ad_storage?: ConsentCategory\n    ad_user_data?: ConsentCategory\n    ad_personalization?: ConsentCategory\n    functionality_storage?: ConsentCategory\n    personalization_storage?: ConsentCategory\n    security_storage?: ConsentCategory\n  }\n  /** Regions to apply consent mode to (empty = all regions) */\n  regions?: string[]\n}\n\nexport interface CookieConsentConfig {\n  consentVersion: string\n  expirationDays?: number\n  privacyPolicyUrl?: string\n  position?: BannerPosition\n  size?: BannerSize\n  categories?: CategoryConfig[]\n  traceability?: TraceabilityConfig\n  consentScope?: ConsentScopeConfig\n  googleConsentMode?: GoogleConsentModeConfig\n  onConsentChange?: (event: ConsentChangeEvent) => void\n}\n\nexport interface ConsentState {\n  /** Whether consent has been given */\n  hasConsented: boolean\n  /** Current consent categories */\n  categories: ConsentCategories\n  /** When consent was last updated */\n  lastUpdated: string | null\n  /** Consent version */\n  consentVersion: string\n  /** Visitor ID */\n  visitorId: string\n  /** When consent expires */\n  expiresAt?: string\n}\n\nexport interface CookieConsentContextValue {\n  state: ConsentState\n  isBannerVisible: boolean\n  isSettingsOpen: boolean\n  acceptAll: () => Promise<void>\n  rejectAll: () => Promise<void>\n  updateConsent: (categories: Partial<ConsentCategories>) => Promise<void>\n  openSettings: () => void\n  closeSettings: () => void\n  hideBanner: () => void\n  resetConsent: () => void\n  hasConsent: (category: ConsentCategory) => boolean\n  config: CookieConsentConfig\n  registerScript: (script: ScriptConfig) => void\n  unregisterScript: (id: string) => void\n  getLoadedScripts: () => string[]\n}\n"
    },
    {
      "path": "components/cookie-consent/utils.ts",
      "type": "registry:file",
      "target": "components/cookie-consent/utils.ts",
      "content": "import type { CategoryConfig, ConsentCategories, ConsentState } from \"./types\"\n\nconst STORAGE_KEY = \"cookie-consent\"\nconst VISITOR_ID_KEY = \"cookie-consent-visitor-id\"\n\n/**\n * Generate a UUID v4\n */\nexport function generateUUID(): string {\n  return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n    const r = (Math.random() * 16) | 0\n    const v = c === \"x\" ? r : (r & 0x3) | 0x8\n    return v.toString(16)\n  })\n}\n\n/**\n * Get existing visitor ID from localStorage without creating or persisting one\n */\nexport function getExistingVisitorId(): string | null {\n  if (typeof window === \"undefined\") return null\n  return localStorage.getItem(VISITOR_ID_KEY)\n}\n\n/**\n * Get or create a visitor ID\n */\nexport function getVisitorId(): string {\n  if (typeof window === \"undefined\") {\n    return generateUUID()\n  }\n\n  let visitorId = localStorage.getItem(VISITOR_ID_KEY)\n  if (!visitorId) {\n    visitorId = generateUUID()\n    localStorage.setItem(VISITOR_ID_KEY, visitorId)\n  }\n  return visitorId\n}\n\n/**\n * Get default consent categories (all false except necessary, or required categories from config)\n */\nexport function getDefaultCategories(categories?: CategoryConfig[]): ConsentCategories {\n  const result: ConsentCategories = {\n    necessary: true,\n    analytics: false,\n    marketing: false,\n    preferences: false,\n  }\n\n  if (categories) {\n    for (const category of categories) {\n      if (category.required) {\n        result[category.key] = true\n      }\n    }\n  }\n\n  return result\n}\n\n/**\n * Get all configured categories accepted (defaults to all categories if no config provided)\n */\nexport function getAllAcceptedCategories(categories?: CategoryConfig[]): ConsentCategories {\n  if (!categories || categories.length === 0) {\n    return {\n      necessary: true,\n      analytics: true,\n      marketing: true,\n      preferences: true,\n    }\n  }\n\n  const result: ConsentCategories = {\n    necessary: true,\n    analytics: false,\n    marketing: false,\n    preferences: false,\n  }\n\n  for (const category of categories) {\n    result[category.key] = true\n  }\n\n  return result\n}\n\n/**\n * Save consent state to localStorage\n */\nexport function saveConsentState(state: ConsentState): void {\n  if (typeof window === \"undefined\") return\n  localStorage.setItem(STORAGE_KEY, JSON.stringify(state))\n}\n\n/**\n * Load consent state from localStorage\n */\nexport function loadConsentState(): ConsentState | null {\n  if (typeof window === \"undefined\") return null\n\n  const stored = localStorage.getItem(STORAGE_KEY)\n  if (!stored) return null\n\n  try {\n    return JSON.parse(stored) as ConsentState\n  } catch {\n    return null\n  }\n}\n\n/**\n * Clear consent state from localStorage\n */\nexport function clearConsentState(): void {\n  if (typeof window === \"undefined\") return\n  localStorage.removeItem(STORAGE_KEY)\n}\n\n/**\n * Calculate expiration date\n */\nexport function calculateExpirationDate(days: number): string {\n  const date = new Date()\n  date.setDate(date.getDate() + days)\n  return date.toISOString()\n}\n\n/**\n * Check if consent has expired\n */\nexport function isConsentExpired(expiresAt: string): boolean {\n  return new Date(expiresAt) < new Date()\n}\n\n/**\n * Check if a script is a Google service script\n * Detects Google Analytics, Google Tag Manager, Google Ads, etc.\n */\nexport function isGoogleScript(script: { src?: string; content?: string }): boolean {\n  // Check if src URL contains Google domains (case-insensitive)\n  if (script.src) {\n    const srcLower = script.src.toLowerCase()\n    const googleDomains = [\n      \"googletagmanager.com\",\n      \"google-analytics.com\",\n      \"googleadservices.com\",\n      \"google.com/analytics\",\n      \"google.com/ads\",\n      \"doubleclick.net\",\n      \"googleapis.com/gtag\",\n    ]\n    \n    // Check if any Google domain is present in the URL\n    // Use better matching to avoid false positives (e.g., \"fakegoogletagmanager.com\")\n    const isGoogleDomain = googleDomains.some((domain) => {\n      const domainLower = domain.toLowerCase()\n      // For full domains, check for domain boundaries (preceded by . or // or start of string)\n      if (domainLower.includes(\"/\")) {\n        // For paths like \"google.com/analytics\", just check if it's included\n        return srcLower.includes(domainLower)\n      } else {\n        // For domains, check for proper domain boundaries\n        // Match: .googletagmanager.com or //googletagmanager.com or googletagmanager.com/\n        const domainPattern = new RegExp(\n          `(^|//|\\\\.)${domainLower.replace(/\\./g, \"\\\\.\")}(/|:|$|\\\\?)`,\n          \"i\"\n        )\n        return domainPattern.test(srcLower)\n      }\n    })\n    \n    if (isGoogleDomain) {\n      return true\n    }\n  }\n\n  // Check if inline content contains Google-specific code (case-insensitive)\n  // This is checked as a fallback if src doesn't match, or if no src is provided\n  if (script.content) {\n    const contentLower = script.content.toLowerCase()\n    const googlePatterns = [\n      \"googletagmanager.com\",\n      \"google-analytics.com\",\n      \"gtag(\",\n      \"datalayer\",\n      \"ga(\",\n      \"google-analytics\",\n    ]\n    return googlePatterns.some((pattern) => contentLower.includes(pattern.toLowerCase()))\n  }\n\n  return false\n}\n"
    },
    {
      "path": "components/cookie-consent/use-cookie-consent.ts",
      "type": "registry:file",
      "target": "components/cookie-consent/use-cookie-consent.ts",
      "content": "\"use client\"\n\nimport { useContext } from \"react\"\nimport { CookieConsentContext } from \"./cookie-provider\"\nimport type { ConsentCategory, CookieConsentContextValue } from \"./types\"\n\n/**\n * Hook to access cookie consent context\n */\nexport function useCookieConsent(): CookieConsentContextValue {\n  const context = useContext(CookieConsentContext)\n  if (!context) {\n    throw new Error(\"useCookieConsent must be used within a CookieConsentProvider\")\n  }\n  return context\n}\n\n/**\n * Hook to check if a specific category is consented\n */\nexport function useConsentValue(category: ConsentCategory): boolean {\n  const { hasConsent } = useCookieConsent()\n  return hasConsent(category)\n}\n\n/**\n * Hook to conditionally render based on consent\n */\nexport function useConsentGate(category: ConsentCategory): {\n  isAllowed: boolean\n  isLoading: boolean\n} {\n  const { state } = useCookieConsent()\n\n  return {\n    isAllowed: state.categories[category] ?? false,\n    isLoading: !state.hasConsented,\n  }\n}\n"
    },
    {
      "path": "components/cookie-consent/use-consent-script.ts",
      "type": "registry:file",
      "target": "components/cookie-consent/use-consent-script.ts",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { useCookieConsent } from \"./cookie-provider\";\nimport {\n  loadScript,\n  registerCleanup,\n  registerScript,\n  unloadScript,\n  unregisterScript,\n} from \"./script-manager\";\nimport type { ConsentCategory } from \"./types\";\n\ninterface UseConsentScriptOptions {\n  /** External script URL */\n  src?: string;\n  /** Inline script content */\n  content?: string;\n  /** Additional script attributes */\n  attributes?: Record<string, string>;\n  /** Script loading strategy */\n  strategy?: \"afterInteractive\" | \"lazyOnload\" | \"beforeInteractive\";\n  /** Cleanup function when consent is revoked */\n  onRevoke?: () => void;\n}\n\ninterface UseConsentScriptReturn {\n  /** Whether the script is loaded */\n  isLoaded: boolean;\n  /** Whether the script is currently loading */\n  isLoading: boolean;\n  /** Whether consent is granted for this category */\n  hasConsent: boolean;\n  /** Any error that occurred */\n  error: Error | null;\n  /** Manually trigger script load (if consent is granted) */\n  load: () => Promise<void>;\n  /** Manually unload the script */\n  unload: () => void;\n}\n\n/**\n * Hook for programmatic consent-aware script loading\n *\n * @example\n * const { isLoaded, hasConsent } = useConsentScript(\"analytics\", \"gtag\", {\n *   src: \"https://www.googletagmanager.com/gtag/js?id=GA_ID\",\n *   onRevoke: () => {\n *     window.gtag = undefined\n *   }\n * })\n *\n * useEffect(() => {\n *   if (isLoaded) {\n *     gtag('config', 'GA_ID')\n *   }\n * }, [isLoaded])\n */\nexport function useConsentScript(\n  category: ConsentCategory,\n  id: string,\n  options: UseConsentScriptOptions = {}\n): UseConsentScriptReturn {\n  const { hasConsent: checkConsent, registerScript: ctxRegister } =\n    useCookieConsent();\n  const consentGranted = checkConsent(category);\n\n  const [isLoaded, setIsLoaded] = React.useState(false);\n  const [isLoading, setIsLoading] = React.useState(false);\n  const [error, setError] = React.useState<Error | null>(null);\n\n  // Use refs to avoid re-registration on every render\n  const isRegisteredRef = React.useRef(false);\n  const onRevokeRef = React.useRef(options.onRevoke);\n\n  // Keep onRevoke ref up to date\n  React.useLayoutEffect(() => {\n    onRevokeRef.current = options.onRevoke;\n  }, [options.onRevoke]);\n\n  // Register script only once\n  React.useEffect(() => {\n    if (isRegisteredRef.current) return;\n    isRegisteredRef.current = true;\n\n    registerScript({\n      id,\n      src: options.src,\n      content: options.content,\n      category,\n      strategy: options.strategy,\n      attributes: options.attributes,\n      onLoad: () => setIsLoaded(true),\n      onError: setError,\n      onRevoke: () => {\n        setIsLoaded(false);\n        onRevokeRef.current?.();\n      },\n    });\n\n    ctxRegister({\n      id,\n      src: options.src,\n      content: options.content,\n      category,\n      strategy: options.strategy,\n      attributes: options.attributes,\n    });\n\n    if (onRevokeRef.current) {\n      registerCleanup(id, () => onRevokeRef.current?.());\n    }\n\n    return () => {\n      isRegisteredRef.current = false;\n      unregisterScript(id);\n    };\n    // Only re-register if id changes - other options are captured in initial registration\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [id]);\n\n  // Auto-load when consent is granted\n  React.useEffect(() => {\n    if (consentGranted && !isLoaded && !isLoading && !error) {\n      let cancelled = false;\n      setIsLoading(true);\n      loadScript(id)\n        .then(() => {\n          if (!cancelled) {\n            setIsLoaded(true);\n            setIsLoading(false);\n          }\n        })\n        .catch((err) => {\n          if (!cancelled) {\n            setError(err);\n            setIsLoading(false);\n          }\n        });\n      return () => {\n        cancelled = true;\n      };\n    }\n  }, [consentGranted, isLoaded, isLoading, error, id]);\n\n  const load = React.useCallback(async () => {\n    if (!consentGranted) {\n      throw new Error(\n        `Cannot load script \"${id}\": consent not granted for category \"${category}\"`\n      );\n    }\n    if (isLoaded) return;\n\n    setIsLoading(true);\n    try {\n      await loadScript(id);\n      setIsLoaded(true);\n    } catch (err) {\n      setError(err as Error);\n      throw err;\n    } finally {\n      setIsLoading(false);\n    }\n  }, [consentGranted, isLoaded, id, category]);\n\n  const unload = React.useCallback(() => {\n    unloadScript(id);\n    setIsLoaded(false);\n  }, [id]);\n\n  return {\n    isLoaded,\n    isLoading,\n    hasConsent: consentGranted,\n    error,\n    load,\n    unload,\n  };\n}\n"
    },
    {
      "path": "components/cookie-consent/script-manager.ts",
      "type": "registry:file",
      "target": "components/cookie-consent/script-manager.ts",
      "content": "// Script management utilities for consent-based script loading\n\nimport type { ConsentCategories, ConsentCategory, ScriptConfig } from \"./types\";\n\ninterface ManagedScript extends ScriptConfig {\n  element?: HTMLScriptElement;\n  loaded: boolean;\n}\n\n// Registry of all managed scripts\nconst scriptRegistry = new Map<string, ManagedScript>();\n\n// Track cleanup functions for each script\nconst cleanupRegistry = new Map<string, () => void>();\n\n/**\n * Register a script to be managed by the consent system\n */\nexport function registerScript(config: ScriptConfig): void {\n  if (scriptRegistry.has(config.id)) {\n    console.warn(\n      `[CookieConsent] Script with id \"${config.id}\" is already registered`\n    );\n    return;\n  }\n\n  scriptRegistry.set(config.id, {\n    ...config,\n    loaded: false,\n  });\n}\n\n/**\n * Unregister a script and clean it up\n */\nexport function unregisterScript(id: string): void {\n  const script = scriptRegistry.get(id);\n  if (script) {\n    unloadScript(id);\n    scriptRegistry.delete(id);\n  }\n}\n\n/**\n * Load a script into the DOM\n */\nexport function loadScript(id: string): Promise<void> {\n  return new Promise((resolve, reject) => {\n    const managed = scriptRegistry.get(id);\n    if (!managed) {\n      reject(new Error(`Script \"${id}\" is not registered`));\n      return;\n    }\n\n    if (managed.loaded && managed.element) {\n      resolve();\n      return;\n    }\n\n    const script = document.createElement(\"script\");\n    script.id = `consent-script-${id}`;\n    script.async = true;\n\n    if (managed.src) {\n      script.src = managed.src;\n    } else if (managed.content) {\n      script.textContent = managed.content;\n    } else {\n      reject(new Error(`Script \"${id}\" has no src or content`));\n      return;\n    }\n\n    // Apply custom attributes\n    if (managed.attributes) {\n      Object.entries(managed.attributes).forEach(([key, value]) => {\n        script.setAttribute(key, value);\n      });\n    }\n\n    // For inline scripts (content), resolve immediately after appending\n    // For external scripts (src), wait for onload\n    if (managed.content) {\n      // Inline scripts execute immediately when appended\n      if (managed.strategy === \"beforeInteractive\") {\n        document.head.appendChild(script);\n      } else {\n        document.body.appendChild(script);\n      }\n\n      // Use setTimeout to ensure script has executed\n      setTimeout(() => {\n        managed.loaded = true;\n        managed.element = script;\n        managed.onLoad?.();\n        resolve();\n      }, 0);\n    } else {\n      // External script - wait for load/error events\n      script.onload = () => {\n        managed.loaded = true;\n        managed.element = script;\n        managed.onLoad?.();\n        resolve();\n      };\n\n      script.onerror = () => {\n        const error = new Error(`Failed to load script \"${id}\"`);\n        managed.onError?.(error);\n        reject(error);\n      };\n\n      // Append based on strategy\n      if (managed.strategy === \"beforeInteractive\") {\n        document.head.appendChild(script);\n      } else {\n        document.body.appendChild(script);\n      }\n    }\n  });\n}\n\n/**\n * Unload a script from the DOM and run cleanup\n */\nexport function unloadScript(id: string): void {\n  const managed = scriptRegistry.get(id);\n  if (!managed) return;\n\n  // Remove the script element\n  if (managed.element) {\n    managed.element.remove();\n    managed.element = undefined;\n  }\n\n  // Also try to find by ID in case element reference is stale\n  const existingScript = document.getElementById(`consent-script-${id}`);\n  if (existingScript) {\n    existingScript.remove();\n  }\n\n  // Run the revoke callback\n  managed.onRevoke?.();\n\n  // Run any registered cleanup\n  const cleanup = cleanupRegistry.get(id);\n  if (cleanup) {\n    cleanup();\n    cleanupRegistry.delete(id);\n  }\n\n  managed.loaded = false;\n}\n\n/**\n * Register a cleanup function for a script\n */\nexport function registerCleanup(id: string, cleanup: () => void): void {\n  cleanupRegistry.set(id, cleanup);\n}\n\n/**\n * Load all scripts for consented categories\n */\nexport function loadConsentedScripts(categories: ConsentCategories): void {\n  scriptRegistry.forEach((script, id) => {\n    if (categories[script.category] && !script.loaded) {\n      loadScript(id).catch((error) => {\n        console.error(`[CookieConsent] Failed to load script \"${id}\":`, error);\n      });\n    }\n  });\n}\n\n/**\n * Unload all scripts for revoked categories\n */\nexport function unloadRevokedScripts(\n  previousCategories: ConsentCategories,\n  currentCategories: ConsentCategories\n): ConsentCategory[] {\n  const revokedCategories: ConsentCategory[] = [];\n\n  // Find revoked categories\n  (Object.keys(previousCategories) as ConsentCategory[]).forEach((category) => {\n    if (previousCategories[category] && !currentCategories[category]) {\n      revokedCategories.push(category);\n    }\n  });\n\n  // Unload scripts for revoked categories\n  scriptRegistry.forEach((script, id) => {\n    if (revokedCategories.includes(script.category) && script.loaded) {\n      unloadScript(id);\n    }\n  });\n\n  return revokedCategories;\n}\n\n/**\n * Get all loaded script IDs\n */\nexport function getLoadedScripts(): string[] {\n  const loaded: string[] = [];\n  scriptRegistry.forEach((script, id) => {\n    if (script.loaded) {\n      loaded.push(id);\n    }\n  });\n  return loaded;\n}\n\n/**\n * Get all registered scripts\n */\nexport function getRegisteredScripts(): Map<string, ManagedScript> {\n  return new Map(scriptRegistry);\n}\n\n/**\n * Check if any registered scripts are Google scripts\n */\nexport function hasGoogleScripts(): boolean {\n  for (const script of scriptRegistry.values()) {\n    if (\n      (script.src && (\n        script.src.includes(\"googletagmanager.com\") ||\n        script.src.includes(\"google-analytics.com\") ||\n        script.src.includes(\"googleadservices.com\") ||\n        script.src.includes(\"google.com/analytics\") ||\n        script.src.includes(\"google.com/ads\") ||\n        script.src.includes(\"doubleclick.net\") ||\n        script.src.includes(\"googleapis.com/gtag\")\n      )) ||\n      (script.content && (\n        script.content.includes(\"googletagmanager.com\") ||\n        script.content.includes(\"google-analytics.com\") ||\n        script.content.includes(\"gtag(\") ||\n        script.content.includes(\"dataLayer\") ||\n        script.content.includes(\"ga(\") ||\n        script.content.includes(\"google-analytics\")\n      ))\n    ) {\n      return true;\n    }\n  }\n  return false;\n}\n\n/**\n * Clear all scripts (useful for testing)\n */\nexport function clearAllScripts(): void {\n  scriptRegistry.forEach((_, id) => {\n    unloadScript(id);\n  });\n  scriptRegistry.clear();\n  cleanupRegistry.clear();\n}\n\n/**\n * Common third-party script cleanup helpers\n */\nexport const scriptCleanupHelpers = {\n  // Google Analytics cleanup\n  googleAnalytics: () => {\n    // Remove GA cookies\n    const cookies = document.cookie.split(\";\");\n    cookies.forEach((cookie) => {\n      const parts = cookie.split(\"=\");\n      const firstPart = parts[0];\n      if (firstPart !== undefined) {\n        const name = firstPart.trim();\n        if (\n          name.startsWith(\"_ga\") ||\n          name.startsWith(\"_gid\") ||\n          name.startsWith(\"_gat\")\n        ) {\n          document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=${window.location.hostname}`;\n          document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=.${window.location.hostname}`;\n        }\n      }\n    });\n    // Clear GA global\n    if (typeof window !== \"undefined\") {\n      (window as unknown as Record<string, unknown>).ga = undefined;\n      (window as unknown as Record<string, unknown>).gtag = undefined;\n      (window as unknown as Record<string, unknown>).dataLayer = undefined;\n    }\n  },\n\n  // Facebook Pixel cleanup\n  facebookPixel: () => {\n    const cookies = document.cookie.split(\";\");\n    cookies.forEach((cookie) => {\n      const parts = cookie.split(\"=\");\n      const firstPart = parts[0];\n      if (firstPart !== undefined) {\n        const name = firstPart.trim();\n        if (name.startsWith(\"_fbp\") || name.startsWith(\"_fbc\")) {\n          document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=${window.location.hostname}`;\n          document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=.${window.location.hostname}`;\n        }\n      }\n    });\n    if (typeof window !== \"undefined\") {\n      (window as unknown as Record<string, unknown>).fbq = undefined;\n    }\n  },\n\n  // Generic cookie cleanup by prefix\n  clearCookiesByPrefix: (prefix: string) => {\n    const cookies = document.cookie.split(\";\");\n    cookies.forEach((cookie) => {\n      const parts = cookie.split(\"=\");\n      const firstPart = parts[0];\n      if (firstPart !== undefined) {\n        const name = firstPart.trim();\n        if (name.startsWith(prefix)) {\n          document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=${window.location.hostname}`;\n          document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=.${window.location.hostname}`;\n        }\n      }\n    });\n  },\n};\n"
    },
    {
      "path": "components/cookie-consent/tracker.ts",
      "type": "registry:file",
      "target": "components/cookie-consent/tracker.ts",
      "content": "import type { ConsentAction, ConsentCategories, ConsentRecord, TraceabilityConfig } from \"./types\"\nimport { generateUUID, getVisitorId } from \"./utils\"\n\ninterface TrackConsentParams {\n  categories: ConsentCategories\n  action: ConsentAction\n  consentVersion: string\n  expiresAt: string\n  config: TraceabilityConfig\n  userId?: string\n  scope?: \"device\" | \"global\"\n}\n\n/**\n * Send consent record to the configured endpoint\n */\nexport async function trackConsent(params: TrackConsentParams): Promise<ConsentRecord | null> {\n  const { categories, action, consentVersion, expiresAt, config, userId, scope = \"device\" } = params\n\n  if (!config.enabled || !config.endpoint) {\n    return null\n  }\n\n  const visitorId = config.getVisitorId ? await config.getVisitorId() : getVisitorId()\n\n  const record: ConsentRecord = {\n    visitorId,\n    consentId: generateUUID(),\n    consentVersion,\n    userId,\n    scope,\n    categories,\n    action,\n    timestamp: new Date().toISOString(),\n    expiresAt,\n    url: config.includeUrl !== false && typeof window !== \"undefined\" ? window.location.href : \"\",\n    userAgent: config.includeUserAgent !== false && typeof navigator !== \"undefined\" ? navigator.userAgent : \"\",\n    language: typeof navigator !== \"undefined\" ? navigator.language : \"\",\n  }\n\n  const maxRetries = config.retryOnFailure !== false ? (config.maxRetries ?? 3) : 1\n\n  for (let attempt = 0; attempt < maxRetries; attempt++) {\n    try {\n      const response = await fetch(config.endpoint, {\n        method: config.method ?? \"POST\",\n        headers: {\n          \"Content-Type\": \"application/json\",\n          ...config.headers,\n        },\n        body: JSON.stringify(record),\n      })\n\n      if (!response.ok) {\n        throw new Error(`HTTP ${response.status}: ${response.statusText}`)\n      }\n\n      config.onSuccess?.(record)\n      return record\n    } catch (error) {\n      if (attempt === maxRetries - 1) {\n        const err = error instanceof Error ? error : new Error(String(error))\n        config.onError?.(err, record)\n\n        // Store in localStorage as fallback\n        storeFailedRecord(record)\n      }\n    }\n  }\n\n  return null\n}\n\n/**\n * Store failed record for later retry\n */\nfunction storeFailedRecord(record: ConsentRecord): void {\n  if (typeof window === \"undefined\") return\n\n  const key = \"cookie-consent-pending\"\n  const pending = JSON.parse(localStorage.getItem(key) ?? \"[]\") as ConsentRecord[]\n  pending.push(record)\n  localStorage.setItem(key, JSON.stringify(pending))\n}\n\n/**\n * Retry sending failed records\n */\nexport async function retryFailedRecords(config: TraceabilityConfig): Promise<void> {\n  if (typeof window === \"undefined\" || !config.enabled || !config.endpoint) return\n\n  const key = \"cookie-consent-pending\"\n  const pending = JSON.parse(localStorage.getItem(key) ?? \"[]\") as ConsentRecord[]\n\n  if (pending.length === 0) return\n\n  const stillPending: ConsentRecord[] = []\n\n  for (const record of pending) {\n    try {\n      const response = await fetch(config.endpoint, {\n        method: config.method ?? \"POST\",\n        headers: {\n          \"Content-Type\": \"application/json\",\n          ...config.headers,\n        },\n        body: JSON.stringify(record),\n      })\n\n      if (!response.ok) {\n        stillPending.push(record)\n      } else {\n        config.onSuccess?.(record)\n      }\n    } catch {\n      stillPending.push(record)\n    }\n  }\n\n  localStorage.setItem(key, JSON.stringify(stillPending))\n}\n"
    },
    {
      "path": "components/cookie-consent/google-consent-mode.tsx",
      "type": "registry:file",
      "target": "components/cookie-consent/google-consent-mode.tsx",
      "content": "\"use client\"\n\nimport { useEffect } from \"react\"\n\n/**\n * Google Consent Mode v2 default consent state\n * These values are set BEFORE gtag.js loads to ensure compliance\n */\nexport interface GoogleConsentModeDefaults {\n  /** Analytics storage consent */\n  analytics_storage?: \"granted\" | \"denied\"\n  /** Ad storage consent */\n  ad_storage?: \"granted\" | \"denied\"\n  /** Ad user data consent */\n  ad_user_data?: \"granted\" | \"denied\"\n  /** Ad personalization consent */\n  ad_personalization?: \"granted\" | \"denied\"\n  /** Functionality storage consent */\n  functionality_storage?: \"granted\" | \"denied\"\n  /** Personalization storage consent */\n  personalization_storage?: \"granted\" | \"denied\"\n  /** Security storage consent */\n  security_storage?: \"granted\" | \"denied\"\n}\n\nexport interface GoogleConsentModeProps {\n  /** Default consent state (must be \"denied\" for GDPR compliance) */\n  defaults?: GoogleConsentModeDefaults\n  /** Time (ms) to wait for CMP to load before using defaults */\n  waitForUpdate?: number\n  /** Regions to apply defaults to (empty = all regions) */\n  regions?: string[]\n}\n\n/**\n * GoogleConsentMode - Sets default consent state for Google Consent Mode v2\n *\n * **Only use this component if you're using Google Analytics, Google Ads, or other Google services.**\n * If your site doesn't use Google services, you don't need this component.\n *\n * This component MUST be placed in <head> BEFORE gtag.js loads.\n * It sets default consent to \"denied\" to ensure GDPR compliance.\n *\n * @example\n * ```tsx\n * // Only include if using Google Analytics/Ads\n * // In your root layout.tsx or _document.tsx\n * <head>\n *   <GoogleConsentMode />\n *   <script async src=\"https://www.googletagmanager.com/gtag/js?id=G-XXXXX\" />\n * </head>\n * ```\n */\nexport function GoogleConsentMode({\n  defaults = {\n    analytics_storage: \"denied\",\n    ad_storage: \"denied\",\n    ad_user_data: \"denied\",\n    ad_personalization: \"denied\",\n  },\n  waitForUpdate = 500,\n  regions,\n}: GoogleConsentModeProps) {\n  useEffect(() => {\n    // Only initialize if we're in the browser\n    if (typeof window === \"undefined\") return\n\n    // Initialize dataLayer if it doesn't exist\n    // This is safe to do even if Google services aren't used - it's just an empty array\n    window.dataLayer = window.dataLayer || []\n\n    // Define gtag function if it doesn't exist\n    // This allows consent mode to work even if gtag.js hasn't loaded yet\n    if (!window.gtag) {\n      window.gtag = function gtag(...args: unknown[]) {\n        if (window.dataLayer) {\n          window.dataLayer.push(args)\n        }\n      }\n    }\n\n    // Set default consent state\n    // This MUST run synchronously before gtag.js loads\n    // Note: If you don't use Google services, you don't need to include this component\n    // But if you do include it, we'll initialize consent mode (user's intent is clear)\n    if (window.gtag) {\n      window.gtag(\"consent\", \"default\", {\n        ...defaults,\n        wait_for_update: waitForUpdate,\n        ...(regions?.length ? { region: regions } : {}),\n      })\n    }\n  }, [defaults, waitForUpdate, regions])\n\n  // This component doesn't render anything\n  return null\n}\n\n// Extend Window interface for TypeScript\ndeclare global {\n  interface Window {\n    dataLayer?: unknown[]\n    gtag?: (...args: unknown[]) => void\n  }\n}\n"
    },
    {
      "path": "components/cookie-consent/cookie-banner-backdrop.tsx",
      "type": "registry:file",
      "target": "components/cookie-consent/cookie-banner-backdrop.tsx",
      "content": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\nimport { AnimatePresence, motion } from \"framer-motion\";\nimport { useCookieConsent } from \"./cookie-provider\";\n\nexport interface CookieBannerBackdropProps {\n  /** Custom class name for the backdrop */\n  className?: string;\n  /** Whether clicking the backdrop should close the banner by rejecting all cookies */\n  closeOnClick?: boolean;\n  /** Custom blur amount (e.g., \"4px\", \"8px\"). Defaults to \"4px\" */\n  blur?: string;\n  /** Custom opacity for the backdrop (0-1). Defaults to 0.5 */\n  opacity?: number;\n  /** Whether backdrop is contained inside an embedded container */\n  isEmbedded?: boolean;\n  /** Always keep visible for preview */\n  forceVisible?: boolean;\n}\n\nexport function CookieBannerBackdrop({\n  className,\n  closeOnClick = false,\n  blur = \"4px\",\n  opacity = 0.5,\n  isEmbedded = false,\n  forceVisible = false,\n}: CookieBannerBackdropProps) {\n  const { isBannerVisible, rejectAll } = useCookieConsent();\n  const showBackdrop = forceVisible || isBannerVisible;\n\n  const handleClick = () => {\n    if (closeOnClick) {\n      rejectAll();\n    }\n  };\n\n  return (\n    <AnimatePresence>\n      {showBackdrop && (\n        <motion.div\n          initial={{ opacity: 0 }}\n          animate={{ opacity: 1 }}\n          exit={{ opacity: 0 }}\n          transition={{ duration: 0.3, ease: \"easeInOut\" }}\n          onClick={handleClick}\n          className={cn(\n            isEmbedded ? \"absolute inset-0 z-20\" : \"fixed inset-0 z-40\",\n            \"bg-black/50\",\n            closeOnClick && \"cursor-pointer\",\n            className\n          )}\n          style={{\n            backgroundColor: `rgba(0, 0, 0, ${opacity})`,\n            backdropFilter: `blur(${blur})`,\n            WebkitBackdropFilter: `blur(${blur})`,\n          }}\n          aria-hidden=\"true\"\n        />\n      )}\n    </AnimatePresence>\n  );\n}\n"
    }
  ],
  "description": "A full-featured, GDPR-compliant cookie consent solution with traceability support, script management, and granular category control.",
  "category": "forms",
  "subcategory": "consent"
}