{"packageName":"@cedros/gallery","packageRoot":"workspace/react","entryPath":"workspace/react/dist/web/register.js","surfaceEntryPaths":{"web":"workspace/react/dist/web/register.js"},"surfaceFilePaths":{"web":["workspace/react/dist/web/register.js","workspace/react/dist/web/styles.css"]},"files":[{"path":"workspace/react/dist/web/register.js","kind":"module","text":"// src/web/register.ts\nimport React17 from \"react\";\n\n// src/albums.ts\nvar albumLayouts = /* @__PURE__ */ new Set([\"grid\", \"masonry\", \"carousel\", \"list\", \"featured\"]);\nvar galleryStatuses = /* @__PURE__ */ new Set([\"draft\", \"published\", \"archived\"]);\nfunction normalizeAlbumBlockProps(input) {\n  const value = record(input);\n  return {\n    albumId: stringValue(value.albumId),\n    title: stringValue(value.title),\n    description: stringValue(value.description),\n    headingLevel: integerValue(value.headingLevel, 2, 6, 2),\n    layout: albumLayouts.has(value.layout) ? value.layout : \"grid\",\n    showCounts: value.showCounts !== false,\n    showDescription: value.showDescription === true,\n    galleries: normalizeGalleryRefs(value.galleries),\n    childAlbums: normalizeChildAlbums(value.childAlbums)\n  };\n}\nfunction validateAlbumBlockProps(input) {\n  const props = normalizeAlbumBlockProps(input);\n  const errors = props.albumId || props.title || props.galleries.length || props.childAlbums.length ? [] : [\"Add an album title or gallery links\"];\n  return { valid: errors.length === 0, errors };\n}\nfunction buildAlbumView(input) {\n  const props = normalizeAlbumBlockProps(input);\n  const publishedGalleries = props.galleries.filter((gallery) => gallery.status === \"published\");\n  const childImageCount = props.childAlbums.reduce((sum, album) => sum + album.imageCount, 0);\n  const imageCount = publishedGalleries.reduce((sum, gallery) => sum + gallery.imageCount, childImageCount);\n  return {\n    albumId: props.albumId,\n    title: props.title || \"Gallery Album\",\n    description: props.description,\n    headingLevel: props.headingLevel,\n    layout: props.layout,\n    showCounts: props.showCounts,\n    showDescription: props.showDescription,\n    galleryCount: publishedGalleries.length,\n    childAlbumCount: props.childAlbums.length,\n    imageCount,\n    galleries: publishedGalleries,\n    childAlbums: props.childAlbums\n  };\n}\nfunction normalizeGalleryRefs(input) {\n  if (!Array.isArray(input)) return [];\n  return input.map(normalizeGalleryRef).filter((gallery) => gallery.id);\n}\nfunction normalizeGalleryRef(input) {\n  const value = record(input);\n  return {\n    id: stringValue(value.id),\n    title: stringValue(value.title),\n    description: stringValue(value.description),\n    href: stringValue(value.href ?? value.url ?? value.routePath),\n    coverImageId: stringValue(value.coverImageId),\n    coverImageUrl: stringValue(value.coverImageUrl ?? value.coverUrl),\n    coverAltText: stringValue(value.coverAltText),\n    imageCount: integerValue(value.imageCount, 0, 1e5, 0),\n    status: galleryStatuses.has(value.status) ? value.status : \"draft\"\n  };\n}\nfunction normalizeChildAlbums(input) {\n  if (!Array.isArray(input)) return [];\n  return input.map(normalizeAlbumSummary).filter((album) => album.id);\n}\nfunction normalizeAlbumSummary(input) {\n  const value = record(input);\n  return {\n    id: stringValue(value.id),\n    title: stringValue(value.title),\n    description: stringValue(value.description),\n    href: stringValue(value.href ?? value.url ?? value.routePath),\n    coverImageId: stringValue(value.coverImageId),\n    coverImageUrl: stringValue(value.coverImageUrl ?? value.coverUrl),\n    coverAltText: stringValue(value.coverAltText),\n    galleryCount: integerValue(value.galleryCount, 0, 1e5, 0),\n    imageCount: integerValue(value.imageCount, 0, 1e5, 0)\n  };\n}\nfunction integerValue(input, min, max, fallback) {\n  if (typeof input !== \"number\" || !Number.isInteger(input)) return fallback;\n  return Math.max(min, Math.min(max, input));\n}\nfunction stringValue(input) {\n  return typeof input === \"string\" ? input.trim() : \"\";\n}\nfunction record(input) {\n  return typeof input === \"object\" && input !== null && !Array.isArray(input) ? input : {};\n}\n\n// src/generated-manifest.ts\nvar generatedManifest = { \"schemaVersion\": 1, \"extensionId\": \"cedros-gallery\", \"displayName\": \"Cedros Gallery\", \"version\": \"3.3.1\", \"description\": \"Publish image-led Cedros pages, collect complete client proofing responses, and review authenticated image submissions.\", \"platformApiVersion\": \"1\", \"compatibility\": { \"platformApiVersion\": \"1\", \"minCedrosDataVersion\": \"0.1.96\", \"witChecksum\": \"2bb16879743cfd2748b7deefefcb82204c16b55a1c1a70385f4e9707a83d48f9\" }, \"packageFamily\": { \"server\": { \"packageName\": \"cedros-gallery-server\", \"version\": \"3.3.1\", \"required\": true }, \"react\": { \"packageName\": \"@cedros/gallery\", \"version\": \"3.3.1\", \"required\": true }, \"reactNative\": { \"packageName\": \"@cedros/gallery-native\", \"version\": \"3.3.1\", \"required\": true } }, \"dependencies\": { \"extensions\": [{ \"extensionId\": \"cedros-login\", \"minVersion\": \"0.0.58\", \"required\": true, \"reason\": \"Owns customer sessions verified by the Core visitor contract; Gallery never treats management identity as a customer.\" }, { \"extensionId\": \"cedros-pay\", \"minVersion\": \"2.0.0\", \"required\": false, \"reason\": \"Enables checkout handoff and entitlement-backed locked media states through published Pay contracts.\" }, { \"extensionId\": \"cedros-notifications\", \"minVersion\": \"0.1.9\", \"required\": false, \"reason\": \"Provisions owner notification routes for proofing submissions, comments, expirations, and broken media.\" }], \"capabilities\": [{ \"capabilityId\": \"cedros-data:extension-storage-cas-v1\", \"required\": true, \"reason\": \"Provides typed compare-and-set for shared Gallery and settings records so concurrent saves fail closed without lost updates.\" }, { \"capabilityId\": \"cedros-data:extension-visitor-v1\", \"required\": true, \"reason\": \"Core verifies Login sessions and supplies only extension-scoped visitor identity; cookie mutations require a trusted site Origin.\" }, { \"capabilityId\": \"cedros-pay:checkout\", \"required\": false, \"reason\": \"Used only for Shop/Pay purchase CTA handoff.\" }, { \"capabilityId\": \"cedros-pay:entitlement-read\", \"required\": false, \"reason\": \"Owned by Cedros Data gated media for paid media checks; Gallery renders resulting lock state.\" }, { \"capabilityId\": \"cedros-notifications:route-write\", \"required\": false, \"reason\": \"Allows notification seeds to appear in Settings > Notifications.\" }] }, \"requiredCapabilities\": [\"cedros-data:extension-storage-cas-v1\", \"cedros-data:extension-visitor-v1\"], \"routePolicies\": [{ \"routeId\": \"cedros-gallery:submission-create\", \"endUserAuth\": \"required\" }, { \"routeId\": \"cedros-gallery:submission-mine\", \"endUserAuth\": \"required\" }, { \"routeId\": \"cedros-gallery:access-validate\", \"endUserAuth\": \"optional\" }, { \"routeId\": \"cedros-gallery:proofing-feedback\", \"endUserAuth\": \"optional\" }, { \"routeId\": \"cedros-gallery:proofing-submit\", \"endUserAuth\": \"optional\" }, { \"routeId\": \"cedros-gallery:download-request\", \"endUserAuth\": \"optional\" }], \"surfaces\": { \"server\": { \"packageRef\": \"server\", \"required\": true, \"contentModels\": [\"cedros-gallery:galleries\", \"cedros-gallery:gallery-items\", \"cedros-gallery:albums\", \"cedros-gallery:proofing-sessions\", \"cedros-gallery:proofing-feedback\", \"cedros-gallery:templates\", \"cedros-gallery:derivatives\", \"cedros-gallery:settings\", \"cedros-gallery:autosave-idempotency\", \"cedros-gallery:submissions\"], \"routes\": [\"cedros-gallery:gallery-list\", \"cedros-gallery:gallery-create\", \"cedros-gallery:gallery-read\", \"cedros-gallery:gallery-update\", \"cedros-gallery:gallery-delete\", \"cedros-gallery:item-list\", \"cedros-gallery:item-upsert\", \"cedros-gallery:item-delete\", \"cedros-gallery:submission-create\", \"cedros-gallery:submission-mine\", \"cedros-gallery:submission-list\", \"cedros-gallery:submission-content-read\", \"cedros-gallery:submission-review\", \"cedros-gallery:album-list\", \"cedros-gallery:album-read\", \"cedros-gallery:album-upsert\", \"cedros-gallery:template-list\", \"cedros-gallery:template-upsert\", \"cedros-gallery:proofing-session-list\", \"cedros-gallery:proofing-session-read\", \"cedros-gallery:proofing-session-upsert\", \"cedros-gallery:proofing-feedback-list\", \"cedros-gallery:proofing-feedback\", \"cedros-gallery:proofing-submit\", \"cedros-gallery:derivative-list\", \"cedros-gallery:derivative-upsert\", \"cedros-gallery:derivative-delete\", \"cedros-gallery:access-validate\", \"cedros-gallery:download-request\", \"cedros-gallery:integration-status\", \"cedros-gallery:settings-read\", \"cedros-gallery:settings-update\", \"cedros-gallery:admin-summary\"], \"jobs\": [\"cedros-gallery:rebuild-index\", \"cedros-gallery:rebuild-derivatives\", \"cedros-gallery:scan-media\", \"cedros-gallery:expire-galleries\", \"cedros-gallery:cleanup-exports\"], \"events\": [\"cedros-gallery:gallery-saved\", \"cedros-gallery:image-submitted\", \"cedros-gallery:image-submission-reviewed\", \"cedros-gallery:proofing-submitted\", \"cedros-gallery:gallery-expired\", \"cedros-gallery:broken-media-detected\", \"autosave_started\", \"autosave_succeeded\", \"autosave_failed\", \"autosave_conflict\"] }, \"admin\": { \"packageRef\": \"react\", \"required\": true, \"moduleIds\": [\"cedros-gallery:admin\"] }, \"web\": { \"packageRef\": \"react\", \"required\": true, \"routeIds\": [\"cedros-gallery:portfolio\", \"cedros-gallery:proofing\", \"cedros-gallery:submit-artwork\"], \"blockTypes\": [\"cedros-gallery:gallery\", \"cedros-gallery:album\", \"cedros-gallery:before-after\", \"cedros-gallery:submission-form\"], \"templateIds\": [\"cedros-gallery:portfolio-page\", \"cedros-gallery:proofing-page\", \"cedros-gallery:submission-page\", \"cedros-gallery:artist-series-page\", \"cedros-gallery:editorial-story-page\", \"cedros-gallery:product-showcase-page\"], \"authoredSurfaceIds\": [\"cedros-gallery:gallery-surface\"], \"templateUtilityIds\": [\"cedros-gallery:gallery-presets\"] }, \"native\": { \"packageRef\": \"reactNative\", \"required\": true }, \"ai\": { \"packageRef\": \"server\", \"skills\": [{ \"id\": \"cedros-gallery:submit-image-guide\", \"name\": \"Submit an image\", \"description\": \"Submit one image to the Gallery review queue for the authenticated account.\", \"category\": \"gallery\", \"tags\": [\"gallery\", \"submission\", \"image\"], \"visibility\": \"authenticated\", \"docs\": { \"markdown\": \"# Submit an image\\n\\nUse `cedros-gallery:submit-image` only with the authenticated user's approval. Send a JPEG, PNG, WebP, or GIF as base64, up to 1 MB, with a stable idempotency key, title, and useful alt text. Successful submissions remain private and pending until a Gallery administrator reviews them. A bearer token must resolve to Cedros Login user context; missing host-verified visitor identity or storage fails closed. Core checks Origin on cookie-authenticated submissions; administrator authority is required only to review them.\" } }], \"capabilities\": [{ \"id\": \"cedros-gallery:submit-image\", \"name\": \"Submit image for review\", \"description\": \"Stores an authenticated user's image privately and creates a pending Gallery submission record.\", \"kind\": \"action\", \"tags\": [\"gallery\", \"submission\", \"storage\"], \"visibility\": \"authenticated\", \"endpoint\": { \"method\": \"POST\", \"path\": \"/extensions/cedros-gallery/v1/submissions\" }, \"auth\": { \"schemes\": [\"bearer-token\"] }, \"inputSchema\": { \"type\": \"object\", \"properties\": { \"idempotencyKey\": { \"type\": \"string\", \"minLength\": 1, \"maxLength\": 128 }, \"title\": { \"type\": \"string\", \"minLength\": 1, \"maxLength\": 160 }, \"altText\": { \"type\": \"string\", \"minLength\": 1, \"maxLength\": 500 }, \"caption\": { \"type\": \"string\", \"maxLength\": 2e3 }, \"fileName\": { \"type\": \"string\", \"minLength\": 1, \"maxLength\": 255 }, \"contentType\": { \"type\": \"string\", \"enum\": [\"image/jpeg\", \"image/png\", \"image/webp\", \"image/gif\"] }, \"contentBase64\": { \"type\": \"string\", \"minLength\": 1, \"maxLength\": 15e5 }, \"galleryId\": { \"type\": \"string\", \"maxLength\": 128 }, \"generation\": { \"type\": \"object\", \"properties\": { \"prompt\": { \"type\": \"string\", \"minLength\": 1, \"maxLength\": 12e3 }, \"provider\": { \"type\": \"string\", \"minLength\": 1, \"maxLength\": 80 }, \"model\": { \"type\": \"string\", \"minLength\": 1, \"maxLength\": 160 }, \"negativePrompt\": { \"type\": \"string\", \"maxLength\": 4e3 }, \"seed\": { \"type\": \"string\", \"maxLength\": 160 }, \"promptVersion\": { \"type\": \"string\", \"maxLength\": 80 } }, \"required\": [\"prompt\", \"provider\", \"model\"], \"additionalProperties\": false } }, \"required\": [\"idempotencyKey\", \"title\", \"altText\", \"fileName\", \"contentType\", \"contentBase64\"], \"additionalProperties\": false }, \"outputSchema\": { \"type\": \"object\", \"properties\": { \"ok\": { \"type\": \"boolean\" }, \"replayed\": { \"type\": \"boolean\" }, \"submission\": { \"type\": \"object\", \"properties\": { \"id\": { \"type\": \"string\" }, \"title\": { \"type\": \"string\" }, \"status\": { \"type\": \"string\", \"enum\": [\"pending\", \"approved\", \"rejected\"] }, \"contentType\": { \"type\": \"string\" }, \"sizeBytes\": { \"type\": \"number\" }, \"createdAt\": { \"type\": \"string\" } }, \"required\": [\"id\", \"title\", \"status\", \"contentType\", \"sizeBytes\", \"createdAt\"], \"additionalProperties\": false } }, \"required\": [\"ok\", \"replayed\", \"submission\"], \"additionalProperties\": false } }] } }, \"registration\": { \"server\": { \"entrypoint\": \"cedros_gallery_server::register_extension_family\" }, \"admin\": { \"entrypoint\": \"@cedros/gallery/admin/register\" }, \"web\": { \"entrypoint\": \"@cedros/gallery/web/register\" }, \"native\": { \"entrypoint\": \"@cedros/gallery-native/register\" } }, \"capabilities\": [{ \"id\": \"cedros-gallery:gallery-management\", \"displayName\": \"Gallery management\", \"description\": \"Manages extension-owned gallery records and writes redacted submission audit entries.\", \"category\": \"content\", \"requestedScopes\": [{ \"verb\": \"read\", \"resource\": \"gallery records\", \"summary\": \"Reads extension-owned gallery content for admin and public rendering.\" }, { \"verb\": \"write\", \"resource\": \"gallery records\", \"summary\": \"Writes extension-owned gallery, album, proofing, submission, and template records.\" }, { \"verb\": \"write\", \"resource\": \"site-brain-record:gallery-submission\", \"summary\": \"Writes redacted operational records when image submissions are created or reviewed.\" }] }], \"adminModules\": [{ \"moduleId\": \"cedros-gallery:admin\", \"extensionId\": \"cedros-gallery\", \"displayName\": \"Gallery\", \"version\": \"3.3.1\", \"packageName\": \"@cedros/gallery\", \"sectionIds\": [\"cedros-gallery:galleries\", \"cedros-gallery:submissions\", \"cedros-gallery:settings\"], \"sectionIcons\": { \"cedros-gallery:galleries\": \"media\", \"cedros-gallery:submissions\": \"media\", \"cedros-gallery:settings\": \"siteSettings\" }, \"navigation\": { \"sections\": [{ \"id\": \"cedros-gallery:galleries\", \"label\": \"Client reviews\", \"group\": \"Site\", \"order\": 45 }, { \"id\": \"cedros-gallery:submissions\", \"label\": \"Submissions\", \"group\": \"Site\", \"order\": 46 }, { \"id\": \"cedros-gallery:settings\", \"label\": \"Legacy Gallery preferences\", \"group\": \"Extension Settings\", \"order\": 45, \"hideFromNavigation\": true }] }, \"contributions\": { \"dashboardCards\": [{ \"id\": \"cedros-gallery:activity-card\", \"displayName\": \"Gallery activity\", \"description\": \"Shows pending client responses and image submissions with source freshness.\", \"requiredPermission\": \"cedros-gallery:gallery-management\", \"order\": 35 }] } }], \"contentBlocks\": [{ \"type\": \"cedros-gallery:gallery\", \"displayName\": \"Gallery\", \"description\": \"Displays a configured image gallery with layout, filters, lightbox, and optional CTA state.\", \"category\": \"media\", \"order\": 10 }, { \"type\": \"cedros-gallery:album\", \"displayName\": \"Gallery Album\", \"description\": \"Displays an album of galleries as covers, lists, masonry, or carousel.\", \"category\": \"media\", \"order\": 20 }, { \"type\": \"cedros-gallery:before-after\", \"displayName\": \"Before / After\", \"description\": \"Compares two related media assets or gallery items.\", \"category\": \"media\", \"order\": 30 }, { \"type\": \"cedros-gallery:submission-form\", \"displayName\": \"Image Submission Form\", \"description\": \"Lets a signed-in Cedros Login user submit one private image for administrator review.\", \"category\": \"forms\", \"order\": 40 }], \"contentTemplates\": [{ \"id\": \"cedros-gallery:portfolio-page\", \"displayName\": \"Portfolio Gallery\", \"description\": \"Clean portfolio gallery page.\", \"order\": 10, \"contentTypes\": [\"page\"], \"surfaceId\": \"cedros-gallery:gallery-surface\" }, { \"id\": \"cedros-gallery:proofing-page\", \"displayName\": \"Client Proofing Gallery\", \"description\": \"Private proofing starter page.\", \"order\": 20, \"contentTypes\": [\"page\"], \"surfaceId\": \"cedros-gallery:gallery-surface\" }, { \"id\": \"cedros-gallery:submission-page\", \"displayName\": \"Submit Artwork\", \"description\": \"Account-required image submission page with private review queue handoff.\", \"order\": 25, \"contentTypes\": [\"page\"], \"surfaceId\": \"cedros-gallery:gallery-surface\" }, { \"id\": \"cedros-gallery:artist-series-page\", \"displayName\": \"Artist Series\", \"description\": \"Artwork series page with metadata and availability handoff.\", \"order\": 30, \"contentTypes\": [\"page\"], \"surfaceId\": \"cedros-gallery:gallery-surface\" }, { \"id\": \"cedros-gallery:editorial-story-page\", \"displayName\": \"Editorial Image Story\", \"description\": \"Caption-forward image story page.\", \"order\": 40, \"contentTypes\": [\"page\", \"blog\"], \"surfaceId\": \"cedros-gallery:gallery-surface\" }, { \"id\": \"cedros-gallery:product-showcase-page\", \"displayName\": \"Product Showcase Gallery\", \"description\": \"Gallery page with optional Shop/Pay CTA handoff.\", \"order\": 50, \"contentTypes\": [\"page\"], \"surfaceId\": \"cedros-gallery:gallery-surface\" }], \"authoredSurfaces\": [{ \"id\": \"cedros-gallery:gallery-surface\", \"displayName\": \"Gallery\", \"description\": \"Owner-editable gallery and album pages.\", \"eyebrow\": \"Media\", \"templateIds\": [\"cedros-gallery:portfolio-page\", \"cedros-gallery:proofing-page\", \"cedros-gallery:submission-page\", \"cedros-gallery:artist-series-page\", \"cedros-gallery:editorial-story-page\", \"cedros-gallery:product-showcase-page\"] }], \"authoredTemplateUtilities\": [{ \"id\": \"cedros-gallery:gallery-presets\", \"displayName\": \"Gallery presets\", \"description\": \"Suggested gallery blocks for portfolio, proofing, artist, editorial, and product-showcase pages.\", \"order\": 10, \"templateIds\": [\"cedros-gallery:portfolio-page\", \"cedros-gallery:proofing-page\", \"cedros-gallery:submission-page\", \"cedros-gallery:artist-series-page\", \"cedros-gallery:editorial-story-page\", \"cedros-gallery:product-showcase-page\"], \"contentTypes\": [\"page\", \"blog\"], \"surfaceIds\": [\"cedros-gallery:gallery-surface\"], \"suggestedBlockTypes\": [\"cedros-gallery:gallery\", \"cedros-gallery:album\", \"cedros-gallery:before-after\", \"cedros-gallery:submission-form\"] }], \"pageSeeds\": [{ \"id\": \"cedros-gallery:portfolio\", \"displayName\": \"Portfolio\", \"title\": \"Portfolio\", \"routePath\": \"/portfolio\", \"description\": \"Owner-editable portfolio page seeded with a Cedros Gallery block.\", \"slug\": \"portfolio\", \"templateId\": \"cedros-gallery:portfolio-page\", \"seo\": { \"title\": \"Portfolio\", \"description\": \"Browse selected work.\", \"canonicalPath\": \"/portfolio\", \"ogTitle\": \"Portfolio\", \"ogDescription\": \"Browse selected work.\" }, \"autoCreateOnEnable\": false, \"publishOnEnable\": false }, { \"id\": \"cedros-gallery:proofing\", \"displayName\": \"Client Proofing\", \"title\": \"Client Proofing\", \"routePath\": \"/proofing\", \"description\": \"Owner-editable private proofing page seeded with a proofing gallery block.\", \"slug\": \"proofing\", \"templateId\": \"cedros-gallery:proofing-page\", \"seo\": { \"title\": \"Client Proofing\", \"description\": \"Review private gallery selections.\", \"noindex\": true }, \"autoCreateOnEnable\": false, \"publishOnEnable\": false }, { \"id\": \"cedros-gallery:submit-artwork\", \"displayName\": \"Submit Artwork\", \"title\": \"Submit Artwork\", \"routePath\": \"/submit-artwork\", \"access\": \"signed-in\", \"description\": \"Account-required page for submitting one private image to the Gallery review queue.\", \"slug\": \"submit-artwork\", \"templateId\": \"cedros-gallery:submission-page\", \"seo\": { \"title\": \"Submit Artwork\", \"description\": \"Submit artwork for private review.\", \"noindex\": true }, \"autoCreateOnEnable\": true, \"publishOnEnable\": false }], \"docsArticles\": [{ \"id\": \"cedros-gallery:authoring-guide\", \"displayName\": \"Gallery authoring guide\", \"title\": \"Gallery authoring guide\", \"slug\": \"gallery-authoring\", \"routePath\": \"/docs/gallery-authoring\", \"excerpt\": \"How to use Cedros Gallery without duplicating Shop, Pay, or Media responsibilities.\", \"bodyMarkdown\": \"# Gallery authoring guide\\n\\nUse Cedros Gallery for presentation, proofing, and visible media metadata. Cedros Core owns page titles, descriptions, robots directives, canonical URLs, hreflang, structured data, and sitemap output through the containing page's SEO settings. Gallery blocks never emit competing crawler metadata.\\n\\nPlace password, login, role, client-link, unlisted, and proofing galleries only on pages marked noindex in the Cedros page SEO editor. The seeded Client Proofing page is noindex by default. Hidden or access-restricted media is excluded from server-rendered gallery markup.\\n\\nProvide a descriptive gallery title and summary, truthful alt text, dimensions, and responsive image sources. Use Cedros Data gated media for protected originals, Cedros Pay for payments and entitlements, and Cedros Shop for product catalog truth when published.\\n\\n## Client reviews\\n\\nCreate a review in Client reviews and keep its generated password. Add stable preview links, names, and alt text under Review images. In Pages, use the Client Proofing template and paste the review reference into Gallery ID; publish at the review page path. The verified client block loads the saved images directly. Check the published page before sharing. Clients can save progress and submit; owners can mark a response handled, close an open review while retaining saved progress, or reopen it. Edit preserves image IDs; removal needs confirmation. Legacy Page-authored reviews continue to use their existing images.\\n\\nPreview links retain their existing media access rules: a review password does not protect a publicly accessible image URL. Use gated Media delivery for confidential originals. Account-backed reviews and contributor submissions use Core-verified, extension-scoped visitor identity from Cedros Login. Cookie mutations require a trusted site Origin. Management context cannot substitute for a contributor, and visitor identity cannot authorize owner actions. Private previews and submission decisions require Gallery management permission. Role-based access remains unavailable; use a review password instead.\\n\", \"category\": \"media\", \"tags\": [\"gallery\", \"proofing\", \"media\"], \"productSlug\": \"gallery\", \"productLabel\": \"Gallery\", \"sectionKey\": \"setup\", \"sectionLabel\": \"Setup\", \"internal\": true, \"readingMinutes\": 3, \"order\": 10, \"seo\": { \"description\": \"Cedros Gallery setup, search-readiness, and ownership boundaries.\", \"noindex\": true } }], \"analytics\": { \"events\": [{ \"id\": \"cedros-gallery:gallery-viewed\", \"displayName\": \"Gallery viewed\", \"description\": \"A public gallery was viewed.\", \"category\": \"gallery\", \"visibility\": \"public\" }, { \"id\": \"cedros-gallery:image-viewed\", \"displayName\": \"Image viewed\", \"description\": \"A gallery image was viewed.\", \"category\": \"gallery\", \"visibility\": \"public\" }, { \"id\": \"cedros-gallery:lightbox-opened\", \"displayName\": \"Lightbox opened\", \"description\": \"A visitor opened the gallery viewer.\", \"category\": \"gallery\", \"visibility\": \"public\" }, { \"id\": \"cedros-gallery:image-downloaded\", \"displayName\": \"Image downloaded\", \"description\": \"A Gallery-controlled image download was requested.\", \"category\": \"gallery\", \"visibility\": \"authenticated\" }, { \"id\": \"cedros-gallery:gallery-shared\", \"displayName\": \"Gallery shared\", \"description\": \"A visitor used a gallery share control.\", \"category\": \"gallery\", \"visibility\": \"public\" }, { \"id\": \"cedros-gallery:image-favorited\", \"displayName\": \"Image favorited\", \"description\": \"A proofing visitor favorited an image.\", \"category\": \"proofing\", \"visibility\": \"authenticated\" }, { \"id\": \"cedros-gallery:image-selected\", \"displayName\": \"Image selected\", \"description\": \"A proofing visitor selected an image.\", \"category\": \"proofing\", \"visibility\": \"authenticated\" }, { \"id\": \"cedros-gallery:image-submitted\", \"displayName\": \"Image submitted\", \"description\": \"An authenticated user submitted an image for review.\", \"category\": \"submission\", \"visibility\": \"authenticated\" }, { \"id\": \"cedros-gallery:proofing-submitted\", \"displayName\": \"Proofing submitted\", \"description\": \"A client submitted final proofing selections.\", \"category\": \"proofing\", \"visibility\": \"authenticated\" }, { \"id\": \"cedros-gallery:gallery-filter-changed\", \"displayName\": \"Gallery filter changed\", \"description\": \"A visitor changed gallery filters.\", \"category\": \"gallery\", \"visibility\": \"public\" }, { \"id\": \"cedros-gallery:gallery-search-performed\", \"displayName\": \"Gallery search performed\", \"description\": \"A visitor searched a gallery.\", \"category\": \"gallery\", \"visibility\": \"public\" }, { \"id\": \"cedros-gallery:linked-product-clicked\", \"displayName\": \"Linked product clicked\", \"description\": \"A visitor clicked a Gallery item product CTA.\", \"category\": \"commerce-handoff\", \"visibility\": \"public\" }] }, \"setupSeeds\": { \"notifications\": [{ \"id\": \"cedros-gallery:image-submitted-notification\", \"displayName\": \"Image submitted\", \"title\": \"Image submitted\", \"description\": \"Notifies the team when an authenticated user submits an image for review.\", \"eventId\": \"cedros-gallery:image-submitted\", \"audience\": \"team\", \"severity\": \"info\", \"defaultChannels\": [\"email\"], \"subjectTemplate\": \"New Gallery image submission\", \"bodyTemplate\": \"A new image submission {{submissionId}} is ready for review.\", \"tags\": [\"gallery\", \"submission\"] }, { \"id\": \"cedros-gallery:proofing-submitted-notification\", \"displayName\": \"Proofing submitted\", \"title\": \"Proofing submitted\", \"description\": \"Notifies the team when a client submits final proofing selections.\", \"eventId\": \"cedros-gallery:proofing-submitted\", \"audience\": \"team\", \"severity\": \"info\", \"defaultChannels\": [\"email\"], \"subjectTemplate\": \"Proofing selections submitted\", \"bodyTemplate\": \"A client submitted selections for gallery {{galleryId}}.\", \"tags\": [\"gallery\", \"proofing\"] }, { \"id\": \"cedros-gallery:gallery-expired-notification\", \"displayName\": \"Gallery expired\", \"title\": \"Gallery expired\", \"description\": \"Notifies the team when a gallery expiration job archives or locks a gallery.\", \"eventId\": \"cedros-gallery:gallery-expired\", \"audience\": \"team\", \"severity\": \"info\", \"defaultChannels\": [\"email\"], \"subjectTemplate\": \"Gallery expired\", \"bodyTemplate\": \"Gallery {{galleryId}} reached its expiration policy.\", \"tags\": [\"gallery\", \"access\"] }, { \"id\": \"cedros-gallery:broken-media-notification\", \"displayName\": \"Broken gallery media\", \"title\": \"Broken gallery media\", \"description\": \"Notifies the team when the media scan finds broken references.\", \"eventId\": \"cedros-gallery:broken-media-detected\", \"audience\": \"team\", \"severity\": \"warning\", \"defaultChannels\": [\"email\"], \"subjectTemplate\": \"Broken gallery media detected\", \"bodyTemplate\": \"Gallery scan found broken media references.\", \"tags\": [\"gallery\", \"media\"] }] }, \"jobSchedules\": [{ \"id\": \"cedros-gallery:rebuild-index-nightly\", \"jobId\": \"cedros-gallery:rebuild-index\", \"label\": \"Rebuild gallery index\", \"cron\": \"15 2 * * *\", \"timezone\": \"America/Los_Angeles\", \"enabled\": false, \"timeoutSeconds\": 300, \"maxRetries\": 2, \"autoCreateOnEnable\": false }, { \"id\": \"cedros-gallery:scan-media-weekly\", \"jobId\": \"cedros-gallery:scan-media\", \"label\": \"Scan gallery media\", \"cron\": \"30 3 * * 1\", \"timezone\": \"America/Los_Angeles\", \"enabled\": false, \"timeoutSeconds\": 300, \"maxRetries\": 2, \"autoCreateOnEnable\": false }, { \"id\": \"cedros-gallery:expire-galleries-daily\", \"jobId\": \"cedros-gallery:expire-galleries\", \"label\": \"Close expired Gallery reviews\", \"cron\": \"0 4 * * *\", \"timezone\": \"America/Los_Angeles\", \"enabled\": true, \"timeoutSeconds\": 180, \"maxRetries\": 2, \"autoCreateOnEnable\": true }, { \"id\": \"cedros-gallery:cleanup-exports-daily\", \"jobId\": \"cedros-gallery:cleanup-exports\", \"label\": \"Cleanup gallery exports\", \"cron\": \"45 4 * * *\", \"timezone\": \"America/Los_Angeles\", \"enabled\": false, \"timeoutSeconds\": 180, \"maxRetries\": 2, \"autoCreateOnEnable\": false }], \"providerAccess\": [{ \"id\": \"cedros-gallery:submission-storage\", \"provider\": \"storage\", \"displayName\": \"Private image submission storage\", \"description\": \"Stores and retrieves authenticated user image submissions for explicit administrator review.\", \"scopes\": [\"storage.read\", \"storage.write\"], \"tags\": [\"gallery\", \"submissions\"] }, { \"id\": \"cedros-gallery:derivative-storage\", \"provider\": \"storage\", \"displayName\": \"Gallery derivative storage\", \"description\": \"Stores Gallery-owned watermarked derivatives and temporary export artifacts. Originals stay in Cedros Data media.\", \"scopes\": [\"storage.write\"], \"tags\": [\"gallery\", \"derivatives\"] }], \"databaseAccess\": [{ \"id\": \"cedros-gallery:gallery-db\", \"displayName\": \"Gallery database\", \"description\": \"Reads and writes extension-owned gallery, album, proofing, submission, template, and derivative records.\", \"contentModels\": [\"cedros-gallery:galleries\", \"cedros-gallery:gallery-items\", \"cedros-gallery:albums\", \"cedros-gallery:proofing-sessions\", \"cedros-gallery:proofing-feedback\", \"cedros-gallery:templates\", \"cedros-gallery:derivatives\", \"cedros-gallery:settings\", \"cedros-gallery:autosave-idempotency\", \"cedros-gallery:submissions\"], \"scopes\": [{ \"verb\": \"read\", \"resource\": \"gallery records\", \"summary\": \"Reads Gallery records for public rendering, admin summaries, and jobs.\" }, { \"verb\": \"count\", \"resource\": \"gallery records\", \"summary\": \"Counts Gallery records for admin summaries and scheduled audits.\" }, { \"verb\": \"write\", \"resource\": \"gallery records\", \"summary\": \"Writes Gallery records from admin, proofing, and authenticated submission routes.\" }, { \"verb\": \"delete\", \"resource\": \"gallery records\", \"summary\": \"Deletes obsolete derivative/export and owner-requested Gallery records.\" }], \"tags\": [\"gallery\", \"content\"] }], \"onboardingPages\": [{ \"id\": \"cedros-gallery:setup\", \"displayName\": \"Set up Gallery\", \"moduleId\": \"cedros-gallery:admin\", \"sectionId\": \"cedros-gallery:galleries\", \"description\": \"Set up and follow client reviews here; publish Gallery and Submit Artwork pages from Cedros Pages.\" }] };\nvar generatedContentTemplates = [{ \"id\": \"cedros-gallery:portfolio-page\", \"label\": \"Portfolio Gallery\", \"contentTypes\": [\"page\"], \"zones\": [{ \"id\": \"main\", \"label\": \"Main\", \"order\": 0 }], \"blocks\": [{ \"type\": \"cedros-gallery:gallery\", \"zoneId\": \"main\", \"props\": { \"galleryId\": \"\", \"layout\": \"masonry\", \"columns\": 3, \"gap\": 16, \"headingLevel\": 2, \"lightbox\": true, \"showFilters\": false, \"showCaptions\": true, \"commerceMode\": \"none\", \"sort\": \"manual\", \"filters\": { \"category\": \"\", \"tag\": \"\", \"artist\": \"\", \"orientation\": \"\", \"productStatus\": \"\", \"accessState\": \"\", \"query\": \"\", \"selectedOnly\": false, \"featuredOnly\": false }, \"items\": [], \"config\": { \"presetId\": \"portfolio\", \"layout\": { \"style\": \"masonry\", \"columns\": 3, \"gap\": 16, \"minColumnWidth\": 240, \"aspectRatio\": \"original\", \"fit\": \"cover\", \"featuredItems\": false }, \"viewer\": { \"enabled\": true, \"mode\": \"minimal\", \"zoom\": true, \"thumbnails\": true, \"metadataPanel\": false, \"keyboard\": true, \"swipe\": true, \"share\": false }, \"filters\": { \"enabled\": false, \"display\": \"buttons\", \"categories\": true, \"tags\": true, \"search\": false, \"deepLinks\": false }, \"access\": { \"mode\": \"public\", \"requiredClaim\": \"\", \"scheduled\": false, \"expires\": false }, \"proofing\": { \"enabled\": false, \"favorites\": true, \"selections\": true, \"comments\": false, \"selectionLimit\": 0, \"lockAfterSubmit\": true }, \"downloads\": { \"mode\": \"none\", \"requireLogin\": false, \"requireEntitlement\": false, \"zipExports\": false }, \"protection\": { \"watermark\": false, \"watermarkPreset\": \"\", \"disableRightClick\": false, \"protectedDerivatives\": false, \"copyrightNotice\": true }, \"shop\": { \"mode\": \"none\", \"readOnlyStatus\": true, \"readOnlyPrice\": true, \"entitlementState\": false, \"hideWhenUnavailable\": false }, \"seo\": { \"imageAltRequired\": true, \"shareLinks\": false }, \"performance\": { \"lazyLoad\": true, \"preloadLightboxNeighbor\": true, \"pagination\": \"load-more\", \"virtualization\": false }, \"accessibility\": { \"focusTrap\": true, \"reducedMotion\": true, \"pauseAutoplay\": true, \"missingAltWarning\": true } }, \"presentation\": { \"layout\": { \"style\": \"grid\", \"container\": \"content\", \"gap\": 16, \"rowGap\": 16, \"randomize\": false }, \"grid\": { \"columns\": 3, \"responsiveColumns\": { \"mobile\": 1, \"tablet\": 2, \"desktop\": 3 }, \"minColumnWidth\": 240, \"aspectRatio\": \"original\", \"fit\": \"cover\", \"focalPoint\": \"center center\", \"equalHeightCards\": false, \"featuredLargerItems\": false }, \"masonry\": { \"columns\": 3, \"columnWidth\": 260, \"gutter\": 16, \"preserveAspectRatio\": true, \"balanceColumns\": true, \"animateLayoutShift\": true }, \"justified\": { \"targetRowHeight\": 220, \"maxRowHeight\": 360, \"gap\": 16, \"lastRow\": \"left\", \"preserveAspectRatio\": true, \"responsiveTargetRowHeight\": { \"mobile\": 160, \"tablet\": 220, \"desktop\": 220 } }, \"carousel\": { \"slidesPerView\": 1, \"responsiveSlidesPerView\": { \"mobile\": 1, \"tablet\": 2, \"desktop\": 1 }, \"autoplay\": false, \"autoplaySpeedMs\": 5e3, \"pauseOnHover\": true, \"pauseOnInteraction\": true, \"arrows\": true, \"dots\": false, \"thumbnailNav\": false, \"infiniteLoop\": false, \"centerMode\": false, \"transition\": \"slide\", \"transitionSpeedMs\": 350 }, \"viewer\": { \"mode\": \"standard\", \"closeOnEscape\": true, \"closeOnBackdrop\": true, \"fullscreen\": false, \"zoom\": true, \"pan\": true, \"pinchZoom\": true, \"thumbnailStrip\": false, \"counter\": true, \"caption\": true, \"metadata\": false, \"share\": false, \"download\": false, \"favorite\": false, \"comment\": false, \"productCta\": false, \"keyboard\": true, \"swipe\": true }, \"captions\": { \"display\": \"title-caption\", \"alignment\": \"left\", \"showArtist\": false, \"showCopyright\": true, \"showCustomFields\": false, \"showCta\": false }, \"card\": { \"hoverEffect\": \"none\", \"transitionMs\": 180, \"disableHoverOnMobile\": true, \"padding\": 0, \"radius\": 8, \"border\": \"none\", \"shadow\": \"none\" }, \"style\": { \"theme\": \"system\", \"backgroundToken\": \"--c1gb4l3-runtime-bg\", \"textToken\": \"--c1gb4l3-runtime-text\", \"overlayToken\": \"--c1gb4l3-runtime-panel\", \"buttonStyle\": \"solid\", \"iconStyle\": \"line\", \"customStyleId\": \"\", \"rawCssAccepted\": false } } } }] }, { \"id\": \"cedros-gallery:proofing-page\", \"label\": \"Client Proofing Gallery\", \"contentTypes\": [\"page\"], \"zones\": [{ \"id\": \"main\", \"label\": \"Main\", \"order\": 0 }], \"blocks\": [{ \"type\": \"cedros-gallery:gallery\", \"zoneId\": \"main\", \"props\": { \"galleryId\": \"\", \"layout\": \"grid\", \"columns\": 3, \"gap\": 16, \"headingLevel\": 2, \"lightbox\": true, \"showFilters\": false, \"showCaptions\": true, \"commerceMode\": \"none\", \"sort\": \"manual\", \"filters\": { \"category\": \"\", \"tag\": \"\", \"artist\": \"\", \"orientation\": \"\", \"productStatus\": \"\", \"accessState\": \"\", \"query\": \"\", \"selectedOnly\": false, \"featuredOnly\": false }, \"items\": [], \"config\": { \"presetId\": \"photographer\", \"layout\": { \"style\": \"grid\", \"columns\": 3, \"gap\": 16, \"minColumnWidth\": 240, \"aspectRatio\": \"original\", \"fit\": \"cover\", \"featuredItems\": false }, \"viewer\": { \"enabled\": true, \"mode\": \"proofing\", \"zoom\": true, \"thumbnails\": true, \"metadataPanel\": true, \"keyboard\": true, \"swipe\": true, \"share\": false }, \"filters\": { \"enabled\": false, \"display\": \"buttons\", \"categories\": true, \"tags\": true, \"search\": false, \"deepLinks\": false }, \"access\": { \"mode\": \"password\", \"requiredClaim\": \"\", \"scheduled\": false, \"expires\": false }, \"proofing\": { \"enabled\": true, \"favorites\": true, \"selections\": true, \"comments\": true, \"selectionLimit\": 0, \"lockAfterSubmit\": true }, \"downloads\": { \"mode\": \"selected\", \"requireLogin\": true, \"requireEntitlement\": false, \"zipExports\": false }, \"protection\": { \"watermark\": true, \"watermarkPreset\": \"\", \"disableRightClick\": false, \"protectedDerivatives\": true, \"copyrightNotice\": true }, \"shop\": { \"mode\": \"none\", \"readOnlyStatus\": true, \"readOnlyPrice\": true, \"entitlementState\": false, \"hideWhenUnavailable\": false }, \"seo\": { \"imageAltRequired\": true, \"shareLinks\": false }, \"performance\": { \"lazyLoad\": true, \"preloadLightboxNeighbor\": true, \"pagination\": \"load-more\", \"virtualization\": false }, \"accessibility\": { \"focusTrap\": true, \"reducedMotion\": true, \"pauseAutoplay\": true, \"missingAltWarning\": true } }, \"presentation\": { \"layout\": { \"style\": \"grid\", \"container\": \"content\", \"gap\": 16, \"rowGap\": 16, \"randomize\": false }, \"grid\": { \"columns\": 3, \"responsiveColumns\": { \"mobile\": 1, \"tablet\": 2, \"desktop\": 3 }, \"minColumnWidth\": 240, \"aspectRatio\": \"original\", \"fit\": \"cover\", \"focalPoint\": \"center center\", \"equalHeightCards\": false, \"featuredLargerItems\": false }, \"masonry\": { \"columns\": 3, \"columnWidth\": 260, \"gutter\": 16, \"preserveAspectRatio\": true, \"balanceColumns\": true, \"animateLayoutShift\": true }, \"justified\": { \"targetRowHeight\": 220, \"maxRowHeight\": 360, \"gap\": 16, \"lastRow\": \"left\", \"preserveAspectRatio\": true, \"responsiveTargetRowHeight\": { \"mobile\": 160, \"tablet\": 220, \"desktop\": 220 } }, \"carousel\": { \"slidesPerView\": 1, \"responsiveSlidesPerView\": { \"mobile\": 1, \"tablet\": 2, \"desktop\": 1 }, \"autoplay\": false, \"autoplaySpeedMs\": 5e3, \"pauseOnHover\": true, \"pauseOnInteraction\": true, \"arrows\": true, \"dots\": false, \"thumbnailNav\": false, \"infiniteLoop\": false, \"centerMode\": false, \"transition\": \"slide\", \"transitionSpeedMs\": 350 }, \"viewer\": { \"mode\": \"standard\", \"closeOnEscape\": true, \"closeOnBackdrop\": true, \"fullscreen\": false, \"zoom\": true, \"pan\": true, \"pinchZoom\": true, \"thumbnailStrip\": false, \"counter\": true, \"caption\": true, \"metadata\": false, \"share\": false, \"download\": false, \"favorite\": false, \"comment\": false, \"productCta\": false, \"keyboard\": true, \"swipe\": true }, \"captions\": { \"display\": \"title-caption\", \"alignment\": \"left\", \"showArtist\": false, \"showCopyright\": true, \"showCustomFields\": false, \"showCta\": false }, \"card\": { \"hoverEffect\": \"none\", \"transitionMs\": 180, \"disableHoverOnMobile\": true, \"padding\": 0, \"radius\": 8, \"border\": \"none\", \"shadow\": \"none\" }, \"style\": { \"theme\": \"system\", \"backgroundToken\": \"--c1gb4l3-runtime-bg\", \"textToken\": \"--c1gb4l3-runtime-text\", \"overlayToken\": \"--c1gb4l3-runtime-panel\", \"buttonStyle\": \"solid\", \"iconStyle\": \"line\", \"customStyleId\": \"\", \"rawCssAccepted\": false } } } }] }, { \"id\": \"cedros-gallery:submission-page\", \"label\": \"Submit Artwork\", \"contentTypes\": [\"page\"], \"zones\": [{ \"id\": \"main\", \"label\": \"Main\", \"order\": 0 }], \"blocks\": [{ \"type\": \"cedros-gallery:submission-form\", \"zoneId\": \"main\", \"props\": { \"title\": \"Submit your artwork\", \"description\": \"Sign in with your Cedros account and upload one image for private review.\" } }] }, { \"id\": \"cedros-gallery:artist-series-page\", \"label\": \"Artist Series\", \"contentTypes\": [\"page\"], \"zones\": [{ \"id\": \"main\", \"label\": \"Main\", \"order\": 0 }], \"blocks\": [{ \"type\": \"cedros-gallery:gallery\", \"zoneId\": \"main\", \"props\": { \"galleryId\": \"\", \"layout\": \"masonry\", \"columns\": 3, \"gap\": 16, \"headingLevel\": 2, \"lightbox\": true, \"showFilters\": false, \"showCaptions\": true, \"commerceMode\": \"none\", \"sort\": \"manual\", \"filters\": { \"category\": \"\", \"tag\": \"\", \"artist\": \"\", \"orientation\": \"\", \"productStatus\": \"\", \"accessState\": \"\", \"query\": \"\", \"selectedOnly\": false, \"featuredOnly\": false }, \"items\": [], \"config\": { \"presetId\": \"physical-artist\", \"layout\": { \"style\": \"masonry\", \"columns\": 3, \"gap\": 16, \"minColumnWidth\": 240, \"aspectRatio\": \"original\", \"fit\": \"cover\", \"featuredItems\": false }, \"viewer\": { \"enabled\": true, \"mode\": \"standard\", \"zoom\": true, \"thumbnails\": true, \"metadataPanel\": true, \"keyboard\": true, \"swipe\": true, \"share\": false }, \"filters\": { \"enabled\": false, \"display\": \"buttons\", \"categories\": true, \"tags\": true, \"search\": false, \"deepLinks\": false }, \"access\": { \"mode\": \"public\", \"requiredClaim\": \"\", \"scheduled\": false, \"expires\": false }, \"proofing\": { \"enabled\": false, \"favorites\": true, \"selections\": true, \"comments\": false, \"selectionLimit\": 0, \"lockAfterSubmit\": true }, \"downloads\": { \"mode\": \"none\", \"requireLogin\": false, \"requireEntitlement\": false, \"zipExports\": false }, \"protection\": { \"watermark\": false, \"watermarkPreset\": \"\", \"disableRightClick\": false, \"protectedDerivatives\": false, \"copyrightNotice\": true }, \"shop\": { \"mode\": \"view-product\", \"readOnlyStatus\": true, \"readOnlyPrice\": true, \"entitlementState\": false, \"hideWhenUnavailable\": false }, \"seo\": { \"imageAltRequired\": true, \"shareLinks\": false }, \"performance\": { \"lazyLoad\": true, \"preloadLightboxNeighbor\": true, \"pagination\": \"load-more\", \"virtualization\": false }, \"accessibility\": { \"focusTrap\": true, \"reducedMotion\": true, \"pauseAutoplay\": true, \"missingAltWarning\": true } }, \"presentation\": { \"layout\": { \"style\": \"grid\", \"container\": \"content\", \"gap\": 16, \"rowGap\": 16, \"randomize\": false }, \"grid\": { \"columns\": 3, \"responsiveColumns\": { \"mobile\": 1, \"tablet\": 2, \"desktop\": 3 }, \"minColumnWidth\": 240, \"aspectRatio\": \"original\", \"fit\": \"cover\", \"focalPoint\": \"center center\", \"equalHeightCards\": false, \"featuredLargerItems\": false }, \"masonry\": { \"columns\": 3, \"columnWidth\": 260, \"gutter\": 16, \"preserveAspectRatio\": true, \"balanceColumns\": true, \"animateLayoutShift\": true }, \"justified\": { \"targetRowHeight\": 220, \"maxRowHeight\": 360, \"gap\": 16, \"lastRow\": \"left\", \"preserveAspectRatio\": true, \"responsiveTargetRowHeight\": { \"mobile\": 160, \"tablet\": 220, \"desktop\": 220 } }, \"carousel\": { \"slidesPerView\": 1, \"responsiveSlidesPerView\": { \"mobile\": 1, \"tablet\": 2, \"desktop\": 1 }, \"autoplay\": false, \"autoplaySpeedMs\": 5e3, \"pauseOnHover\": true, \"pauseOnInteraction\": true, \"arrows\": true, \"dots\": false, \"thumbnailNav\": false, \"infiniteLoop\": false, \"centerMode\": false, \"transition\": \"slide\", \"transitionSpeedMs\": 350 }, \"viewer\": { \"mode\": \"standard\", \"closeOnEscape\": true, \"closeOnBackdrop\": true, \"fullscreen\": false, \"zoom\": true, \"pan\": true, \"pinchZoom\": true, \"thumbnailStrip\": false, \"counter\": true, \"caption\": true, \"metadata\": false, \"share\": false, \"download\": false, \"favorite\": false, \"comment\": false, \"productCta\": false, \"keyboard\": true, \"swipe\": true }, \"captions\": { \"display\": \"title-caption\", \"alignment\": \"left\", \"showArtist\": false, \"showCopyright\": true, \"showCustomFields\": false, \"showCta\": false }, \"card\": { \"hoverEffect\": \"none\", \"transitionMs\": 180, \"disableHoverOnMobile\": true, \"padding\": 0, \"radius\": 8, \"border\": \"none\", \"shadow\": \"none\" }, \"style\": { \"theme\": \"system\", \"backgroundToken\": \"--c1gb4l3-runtime-bg\", \"textToken\": \"--c1gb4l3-runtime-text\", \"overlayToken\": \"--c1gb4l3-runtime-panel\", \"buttonStyle\": \"solid\", \"iconStyle\": \"line\", \"customStyleId\": \"\", \"rawCssAccepted\": false } } } }] }, { \"id\": \"cedros-gallery:editorial-story-page\", \"label\": \"Editorial Image Story\", \"contentTypes\": [\"page\", \"blog\"], \"zones\": [{ \"id\": \"main\", \"label\": \"Main\", \"order\": 0 }], \"blocks\": [{ \"type\": \"cedros-gallery:gallery\", \"zoneId\": \"main\", \"props\": { \"galleryId\": \"\", \"layout\": \"story\", \"columns\": 3, \"gap\": 16, \"headingLevel\": 2, \"lightbox\": true, \"showFilters\": false, \"showCaptions\": true, \"commerceMode\": \"none\", \"sort\": \"manual\", \"filters\": { \"category\": \"\", \"tag\": \"\", \"artist\": \"\", \"orientation\": \"\", \"productStatus\": \"\", \"accessState\": \"\", \"query\": \"\", \"selectedOnly\": false, \"featuredOnly\": false }, \"items\": [], \"config\": { \"presetId\": \"editorial\", \"layout\": { \"style\": \"story\", \"columns\": 3, \"gap\": 16, \"minColumnWidth\": 240, \"aspectRatio\": \"original\", \"fit\": \"cover\", \"featuredItems\": false }, \"viewer\": { \"enabled\": true, \"mode\": \"details-side-panel\", \"zoom\": true, \"thumbnails\": true, \"metadataPanel\": false, \"keyboard\": true, \"swipe\": true, \"share\": true }, \"filters\": { \"enabled\": true, \"display\": \"buttons\", \"categories\": true, \"tags\": true, \"search\": true, \"deepLinks\": false }, \"access\": { \"mode\": \"public\", \"requiredClaim\": \"\", \"scheduled\": false, \"expires\": false }, \"proofing\": { \"enabled\": false, \"favorites\": true, \"selections\": true, \"comments\": false, \"selectionLimit\": 0, \"lockAfterSubmit\": true }, \"downloads\": { \"mode\": \"none\", \"requireLogin\": false, \"requireEntitlement\": false, \"zipExports\": false }, \"protection\": { \"watermark\": false, \"watermarkPreset\": \"\", \"disableRightClick\": false, \"protectedDerivatives\": false, \"copyrightNotice\": true }, \"shop\": { \"mode\": \"none\", \"readOnlyStatus\": true, \"readOnlyPrice\": true, \"entitlementState\": false, \"hideWhenUnavailable\": false }, \"seo\": { \"imageAltRequired\": true, \"shareLinks\": true }, \"performance\": { \"lazyLoad\": true, \"preloadLightboxNeighbor\": true, \"pagination\": \"load-more\", \"virtualization\": false }, \"accessibility\": { \"focusTrap\": true, \"reducedMotion\": true, \"pauseAutoplay\": true, \"missingAltWarning\": true } }, \"presentation\": { \"layout\": { \"style\": \"grid\", \"container\": \"content\", \"gap\": 16, \"rowGap\": 16, \"randomize\": false }, \"grid\": { \"columns\": 3, \"responsiveColumns\": { \"mobile\": 1, \"tablet\": 2, \"desktop\": 3 }, \"minColumnWidth\": 240, \"aspectRatio\": \"original\", \"fit\": \"cover\", \"focalPoint\": \"center center\", \"equalHeightCards\": false, \"featuredLargerItems\": false }, \"masonry\": { \"columns\": 3, \"columnWidth\": 260, \"gutter\": 16, \"preserveAspectRatio\": true, \"balanceColumns\": true, \"animateLayoutShift\": true }, \"justified\": { \"targetRowHeight\": 220, \"maxRowHeight\": 360, \"gap\": 16, \"lastRow\": \"left\", \"preserveAspectRatio\": true, \"responsiveTargetRowHeight\": { \"mobile\": 160, \"tablet\": 220, \"desktop\": 220 } }, \"carousel\": { \"slidesPerView\": 1, \"responsiveSlidesPerView\": { \"mobile\": 1, \"tablet\": 2, \"desktop\": 1 }, \"autoplay\": false, \"autoplaySpeedMs\": 5e3, \"pauseOnHover\": true, \"pauseOnInteraction\": true, \"arrows\": true, \"dots\": false, \"thumbnailNav\": false, \"infiniteLoop\": false, \"centerMode\": false, \"transition\": \"slide\", \"transitionSpeedMs\": 350 }, \"viewer\": { \"mode\": \"standard\", \"closeOnEscape\": true, \"closeOnBackdrop\": true, \"fullscreen\": false, \"zoom\": true, \"pan\": true, \"pinchZoom\": true, \"thumbnailStrip\": false, \"counter\": true, \"caption\": true, \"metadata\": false, \"share\": false, \"download\": false, \"favorite\": false, \"comment\": false, \"productCta\": false, \"keyboard\": true, \"swipe\": true }, \"captions\": { \"display\": \"title-caption\", \"alignment\": \"left\", \"showArtist\": false, \"showCopyright\": true, \"showCustomFields\": false, \"showCta\": false }, \"card\": { \"hoverEffect\": \"none\", \"transitionMs\": 180, \"disableHoverOnMobile\": true, \"padding\": 0, \"radius\": 8, \"border\": \"none\", \"shadow\": \"none\" }, \"style\": { \"theme\": \"system\", \"backgroundToken\": \"--c1gb4l3-runtime-bg\", \"textToken\": \"--c1gb4l3-runtime-text\", \"overlayToken\": \"--c1gb4l3-runtime-panel\", \"buttonStyle\": \"solid\", \"iconStyle\": \"line\", \"customStyleId\": \"\", \"rawCssAccepted\": false } } } }] }, { \"id\": \"cedros-gallery:product-showcase-page\", \"label\": \"Product Showcase Gallery\", \"contentTypes\": [\"page\"], \"zones\": [{ \"id\": \"main\", \"label\": \"Main\", \"order\": 0 }], \"blocks\": [{ \"type\": \"cedros-gallery:gallery\", \"zoneId\": \"main\", \"props\": { \"galleryId\": \"\", \"layout\": \"product\", \"columns\": 3, \"gap\": 16, \"headingLevel\": 2, \"lightbox\": true, \"showFilters\": false, \"showCaptions\": true, \"commerceMode\": \"none\", \"sort\": \"manual\", \"filters\": { \"category\": \"\", \"tag\": \"\", \"artist\": \"\", \"orientation\": \"\", \"productStatus\": \"\", \"accessState\": \"\", \"query\": \"\", \"selectedOnly\": false, \"featuredOnly\": false }, \"items\": [], \"config\": { \"presetId\": \"digital-artist\", \"layout\": { \"style\": \"product\", \"columns\": 3, \"gap\": 16, \"minColumnWidth\": 240, \"aspectRatio\": \"original\", \"fit\": \"cover\", \"featuredItems\": false }, \"viewer\": { \"enabled\": true, \"mode\": \"standard\", \"zoom\": true, \"thumbnails\": true, \"metadataPanel\": false, \"keyboard\": true, \"swipe\": true, \"share\": false }, \"filters\": { \"enabled\": false, \"display\": \"buttons\", \"categories\": true, \"tags\": true, \"search\": false, \"deepLinks\": false }, \"access\": { \"mode\": \"public\", \"requiredClaim\": \"\", \"scheduled\": false, \"expires\": false }, \"proofing\": { \"enabled\": false, \"favorites\": true, \"selections\": true, \"comments\": false, \"selectionLimit\": 0, \"lockAfterSubmit\": true }, \"downloads\": { \"mode\": \"preview\", \"requireLogin\": false, \"requireEntitlement\": true, \"zipExports\": false }, \"protection\": { \"watermark\": true, \"watermarkPreset\": \"\", \"disableRightClick\": false, \"protectedDerivatives\": true, \"copyrightNotice\": true }, \"shop\": { \"mode\": \"view-product\", \"readOnlyStatus\": true, \"readOnlyPrice\": true, \"entitlementState\": true, \"hideWhenUnavailable\": false }, \"seo\": { \"imageAltRequired\": true, \"shareLinks\": false }, \"performance\": { \"lazyLoad\": true, \"preloadLightboxNeighbor\": true, \"pagination\": \"load-more\", \"virtualization\": false }, \"accessibility\": { \"focusTrap\": true, \"reducedMotion\": true, \"pauseAutoplay\": true, \"missingAltWarning\": true } }, \"presentation\": { \"layout\": { \"style\": \"grid\", \"container\": \"content\", \"gap\": 16, \"rowGap\": 16, \"randomize\": false }, \"grid\": { \"columns\": 3, \"responsiveColumns\": { \"mobile\": 1, \"tablet\": 2, \"desktop\": 3 }, \"minColumnWidth\": 240, \"aspectRatio\": \"original\", \"fit\": \"cover\", \"focalPoint\": \"center center\", \"equalHeightCards\": false, \"featuredLargerItems\": false }, \"masonry\": { \"columns\": 3, \"columnWidth\": 260, \"gutter\": 16, \"preserveAspectRatio\": true, \"balanceColumns\": true, \"animateLayoutShift\": true }, \"justified\": { \"targetRowHeight\": 220, \"maxRowHeight\": 360, \"gap\": 16, \"lastRow\": \"left\", \"preserveAspectRatio\": true, \"responsiveTargetRowHeight\": { \"mobile\": 160, \"tablet\": 220, \"desktop\": 220 } }, \"carousel\": { \"slidesPerView\": 1, \"responsiveSlidesPerView\": { \"mobile\": 1, \"tablet\": 2, \"desktop\": 1 }, \"autoplay\": false, \"autoplaySpeedMs\": 5e3, \"pauseOnHover\": true, \"pauseOnInteraction\": true, \"arrows\": true, \"dots\": false, \"thumbnailNav\": false, \"infiniteLoop\": false, \"centerMode\": false, \"transition\": \"slide\", \"transitionSpeedMs\": 350 }, \"viewer\": { \"mode\": \"standard\", \"closeOnEscape\": true, \"closeOnBackdrop\": true, \"fullscreen\": false, \"zoom\": true, \"pan\": true, \"pinchZoom\": true, \"thumbnailStrip\": false, \"counter\": true, \"caption\": true, \"metadata\": false, \"share\": false, \"download\": false, \"favorite\": false, \"comment\": false, \"productCta\": false, \"keyboard\": true, \"swipe\": true }, \"captions\": { \"display\": \"title-caption\", \"alignment\": \"left\", \"showArtist\": false, \"showCopyright\": true, \"showCustomFields\": false, \"showCta\": false }, \"card\": { \"hoverEffect\": \"none\", \"transitionMs\": 180, \"disableHoverOnMobile\": true, \"padding\": 0, \"radius\": 8, \"border\": \"none\", \"shadow\": \"none\" }, \"style\": { \"theme\": \"system\", \"backgroundToken\": \"--c1gb4l3-runtime-bg\", \"textToken\": \"--c1gb4l3-runtime-text\", \"overlayToken\": \"--c1gb4l3-runtime-panel\", \"buttonStyle\": \"solid\", \"iconStyle\": \"line\", \"customStyleId\": \"\", \"rawCssAccepted\": false } } } }] }];\n\n// src/manifest.ts\nvar extensionManifest = generatedManifest;\n\n// src/bootstrap.ts\nvar extensionBootstrap = {\n  manifest: extensionManifest\n};\n\n// src/downloads.ts\nfunction buildGalleryDownloadDecision(item, policy, context = {}) {\n  const href = safeGalleryMediaSrc(item.imageUrl || item.thumbnailUrl);\n  if (policy.mode === \"none\") return hidden(\"disabled-by-config\", policy.mode);\n  if (!href) return hidden(\"missing-media\", policy.mode);\n  if (item.accessState === \"locked\") return disabled(\"locked\", policy.mode);\n  if (item.requiresPurchase && !item.entitlementGranted) {\n    return disabled(\"entitlement-required\", policy.mode);\n  }\n  if (policy.requireEntitlement && !item.entitlementGranted) {\n    return disabled(\"entitlement-required\", policy.mode);\n  }\n  if (policy.requireLogin && context.authenticated !== true) {\n    return disabled(\"login-required\", policy.mode);\n  }\n  if (policy.mode !== \"preview\") return disabled(\"gated-delivery-required\", policy.mode);\n  return {\n    visible: true,\n    enabled: true,\n    href,\n    kind: \"preview\",\n    label: \"Download preview\",\n    reason: \"ready\"\n  };\n}\nfunction safeGalleryMediaSrc(input) {\n  const value = input.trim();\n  if (!value || value.startsWith(\"//\") || value.includes(\"\\\\\")) return \"\";\n  if (value.startsWith(\"/\") && !/[\\s\"'<>]/.test(value)) return value;\n  if (/^[a-z0-9][^\\s\"'<>:]*$/i.test(value)) return value;\n  if (/^data:image\\/(avif|gif|jpeg|jpg|png|webp);base64,/i.test(value)) return value;\n  try {\n    const url = new URL(value);\n    return url.protocol === \"http:\" || url.protocol === \"https:\" || url.protocol === \"blob:\" ? value : \"\";\n  } catch {\n    return \"\";\n  }\n}\nfunction hidden(reason2, kind) {\n  return { visible: false, enabled: false, href: \"\", kind, label: \"\", reason: reason2 };\n}\nfunction disabled(reason2, kind) {\n  return {\n    visible: true,\n    enabled: false,\n    href: \"\",\n    kind,\n    label: reason2 === \"gated-delivery-required\" ? \"Request download\" : \"Download unavailable\",\n    reason: reason2\n  };\n}\n\n// src/comparison.ts\nfunction normalizeBeforeAfterProps(input) {\n  const value = record2(input);\n  return {\n    beforeMediaId: stringValue2(value.beforeMediaId),\n    afterMediaId: stringValue2(value.afterMediaId),\n    beforeLabel: stringValue2(value.beforeLabel) || \"Before\",\n    afterLabel: stringValue2(value.afterLabel) || \"After\",\n    orientation: value.orientation === \"vertical\" ? \"vertical\" : \"horizontal\",\n    sliderPosition: integerValue2(value.sliderPosition, 0, 100, 50),\n    showLabels: value.showLabels !== false\n  };\n}\nfunction validateBeforeAfterProps(input) {\n  const props = normalizeBeforeAfterProps(input);\n  const value = record2(input);\n  const errors = [];\n  if (!props.beforeMediaId && !safeGalleryMediaSrc(stringValue2(value.beforeImageUrl))) errors.push(\"A before image is required\");\n  if (!props.afterMediaId && !safeGalleryMediaSrc(stringValue2(value.afterImageUrl))) errors.push(\"An after image is required\");\n  return { valid: errors.length === 0, errors };\n}\nfunction buildBeforeAfterView(input) {\n  const props = normalizeBeforeAfterProps(input);\n  return {\n    beforeMediaId: props.beforeMediaId,\n    afterMediaId: props.afterMediaId,\n    beforeLabel: props.beforeLabel,\n    afterLabel: props.afterLabel,\n    orientation: props.orientation,\n    sliderPosition: props.sliderPosition,\n    showLabels: props.showLabels,\n    configured: validateBeforeAfterProps(input).valid\n  };\n}\nfunction integerValue2(input, min, max, fallback) {\n  if (typeof input !== \"number\" || !Number.isInteger(input)) return fallback;\n  return Math.max(min, Math.min(max, input));\n}\nfunction stringValue2(input) {\n  return typeof input === \"string\" ? input.trim() : \"\";\n}\nfunction record2(input) {\n  return typeof input === \"object\" && input !== null && !Array.isArray(input) ? input : {};\n}\n\n// src/gallery-items.ts\nvar gallerySorts = /* @__PURE__ */ new Set([\n  \"manual\",\n  \"newest\",\n  \"oldest\",\n  \"title-az\",\n  \"title-za\",\n  \"featured\",\n  \"category\",\n  \"artist\",\n  \"product-status\"\n]);\nfunction normalizeFilters(input) {\n  const value = isRecord(input) ? input : {};\n  return {\n    category: stringValue3(value.category),\n    tag: stringValue3(value.tag),\n    artist: stringValue3(value.artist),\n    orientation: stringValue3(value.orientation),\n    productStatus: stringValue3(value.productStatus),\n    accessState: stringValue3(value.accessState),\n    query: stringValue3(value.query),\n    selectedOnly: value.selectedOnly === true,\n    featuredOnly: value.featuredOnly === true\n  };\n}\nfunction normalizeGalleryItems(input) {\n  if (!Array.isArray(input)) return [];\n  return input.map(normalizeItem).filter((item) => item.id);\n}\nfunction filterGalleryItems(items, filters) {\n  const query = filters.query.toLocaleLowerCase();\n  return items.filter((item) => {\n    if (filters.selectedOnly && !item.selected) return false;\n    if (filters.featuredOnly && !item.featured) return false;\n    if (filters.category && item.category !== filters.category) return false;\n    if (filters.tag && !item.tags.includes(filters.tag)) return false;\n    if (filters.artist && item.artist !== filters.artist) return false;\n    if (filters.orientation && item.orientation !== filters.orientation) return false;\n    if (filters.productStatus && item.productStatus !== filters.productStatus) return false;\n    if (filters.accessState && item.accessState !== filters.accessState) return false;\n    return query ? searchableText(item).includes(query) : true;\n  });\n}\nfunction sortGalleryItems(items, sort) {\n  const copy = [...items];\n  if (sort === \"featured\") return copy.sort(featuredOrder);\n  if (sort === \"newest\") return copy.sort((a, b) => b.createdAt.localeCompare(a.createdAt));\n  if (sort === \"oldest\") return copy.sort((a, b) => a.createdAt.localeCompare(b.createdAt));\n  if (sort === \"title-az\") return copy.sort((a, b) => a.title.localeCompare(b.title));\n  if (sort === \"title-za\") return copy.sort((a, b) => b.title.localeCompare(a.title));\n  if (sort === \"category\") return copy.sort(byField(\"category\"));\n  if (sort === \"artist\") return copy.sort(byField(\"artist\"));\n  if (sort === \"product-status\") return copy.sort(byField(\"productStatus\"));\n  return copy.sort((a, b) => a.order - b.order);\n}\nfunction normalizeItem(input) {\n  const value = isRecord(input) ? input : {};\n  const entitlementGranted = value.entitlementGranted === true;\n  const requiresPurchase = value.requiresPurchase === true || value.requireEntitlement === true;\n  return {\n    id: stringValue3(value.id),\n    mediaAssetId: stringValue3(value.mediaAssetId ?? value.sourceMediaAssetId),\n    title: stringValue3(value.title),\n    caption: stringValue3(value.caption),\n    description: stringValue3(value.description),\n    altText: stringValue3(value.altText),\n    artist: stringValue3(value.artist),\n    credit: stringValue3(value.credit),\n    category: stringValue3(value.category),\n    tags: stringArray(value.tags),\n    imageUrl: stringValue3(value.imageUrl ?? value.url),\n    thumbnailUrl: stringValue3(value.thumbnailUrl),\n    detailUrl: stringValue3(value.detailUrl),\n    width: clampInteger(value.width, 0, 1e5, 0),\n    height: clampInteger(value.height, 0, 1e5, 0),\n    responsiveSources: normalizeResponsiveSources(value.responsiveSources ?? value.imageSources),\n    orientation: normalizeOrientation(value.orientation, value.width, value.height),\n    order: clampInteger(value.order, 0, 1e5, 0),\n    featured: value.featured === true,\n    favorite: value.favorite === true || value.favorited === true,\n    selected: value.selected === true,\n    createdAt: stringValue3(value.createdAt) || \"1970-01-01T00:00:00Z\",\n    accessState: effectiveAccessState(\n      normalizeAccessState(value.accessState),\n      entitlementGranted,\n      requiresPurchase\n    ),\n    productStatus: normalizeProductStatus(value.productStatus),\n    linkedProductId: stringValue3(value.linkedProductId ?? value.productId),\n    linkedVariantId: stringValue3(value.linkedVariantId ?? value.variantId),\n    productUrl: stringValue3(value.productUrl),\n    checkoutUrl: stringValue3(value.checkoutUrl),\n    priceLabel: stringValue3(value.priceLabel),\n    availabilityLabel: stringValue3(value.availabilityLabel),\n    entitlementGranted,\n    requiresPurchase,\n    hidden: value.hidden === true || value.visible === false,\n    private: value.private === true,\n    requiredRole: stringValue3(value.requiredRole ?? value.requiredClaim),\n    hideWhenProductUnavailable: value.hideWhenProductUnavailable === true\n  };\n}\nfunction normalizeResponsiveSources(input) {\n  if (!Array.isArray(input)) return [];\n  const sources = input.map((entry) => {\n    const value = isRecord(entry) ? entry : {};\n    return {\n      url: stringValue3(value.url ?? value.src),\n      width: clampInteger(value.width, 1, 1e5, 0)\n    };\n  }).filter((source) => source.url && source.width > 0);\n  return [...new Map(sources.map((source) => [source.width, source])).values()].sort((a, b) => a.width - b.width);\n}\nfunction effectiveAccessState(input, entitlementGranted, requiresPurchase) {\n  if (entitlementGranted) return \"unlocked\";\n  if (requiresPurchase) return \"locked\";\n  return input;\n}\nfunction featuredOrder(a, b) {\n  return Number(b.featured) - Number(a.featured) || a.order - b.order;\n}\nfunction byField(key) {\n  return (a, b) => {\n    return a[key].localeCompare(b[key]) || a.order - b.order;\n  };\n}\nfunction normalizeOrientation(input, width, height) {\n  if (input === \"landscape\" || input === \"portrait\" || input === \"square\" || input === \"panorama\") {\n    return input;\n  }\n  const imageWidth = clampInteger(width, 0, 1e5, 0);\n  const imageHeight = clampInteger(height, 0, 1e5, 0);\n  if (imageWidth && imageHeight) {\n    return imageWidth === imageHeight ? \"square\" : imageWidth > imageHeight ? \"landscape\" : \"portrait\";\n  }\n  return \"unknown\";\n}\nfunction normalizeAccessState(input) {\n  if (input === \"preview\" || input === \"locked\" || input === \"unlocked\") return input;\n  return \"public\";\n}\nfunction normalizeProductStatus(input) {\n  if (input === \"available\" || input === \"sold\" || input === \"unavailable\") return input;\n  return \"none\";\n}\nfunction searchableText(item) {\n  return [\n    item.title,\n    item.caption,\n    item.description,\n    item.altText,\n    item.artist,\n    item.credit,\n    item.category,\n    item.orientation,\n    item.productStatus,\n    item.accessState,\n    item.linkedProductId,\n    item.availabilityLabel,\n    ...item.tags\n  ].join(\" \").toLocaleLowerCase();\n}\nfunction stringArray(input) {\n  if (!Array.isArray(input)) return [];\n  return input.map(stringValue3).filter(Boolean);\n}\nfunction stringValue3(input) {\n  return typeof input === \"string\" ? input.trim() : \"\";\n}\nfunction clampInteger(input, min, max, fallback) {\n  if (typeof input !== \"number\" || !Number.isInteger(input)) return fallback;\n  return Math.max(min, Math.min(max, input));\n}\nfunction isRecord(input) {\n  return typeof input === \"object\" && input !== null && !Array.isArray(input);\n}\n\n// src/commerce.ts\nvar commerceModes = /* @__PURE__ */ new Set([\n  \"none\",\n  \"view-product\",\n  \"buy\",\n  \"add-to-cart\",\n  \"request-info\",\n  \"custom\"\n]);\nvar commerceSources = /* @__PURE__ */ new Set([\n  \"none\",\n  \"cedros-pay\",\n  \"cedros-shop\",\n  \"host-projection\"\n]);\nvar productStatuses = /* @__PURE__ */ new Set([\n  \"none\",\n  \"available\",\n  \"sold\",\n  \"unavailable\"\n]);\nfunction normalizeCommerceHandoff(input) {\n  const value = record3(input);\n  const mode = enumValue(value.mode ?? value.commerceMode, commerceModes, \"none\");\n  const linkedProductId = stringValue4(value.linkedProductId ?? value.productId);\n  const status2 = enumValue(value.productStatus ?? value.status, productStatuses, \"none\");\n  const purchased = value.purchased === true || value.entitlementGranted === true;\n  const requiresPurchase = value.requiresPurchase === true || value.requireEntitlement === true;\n  const action = decideAction(mode, value);\n  const url = actionUrl(action, value);\n  const visible = isVisible(mode, linkedProductId, status2, value.hideWhenUnavailable === true);\n  const enabled = isEnabled(visible, status2, action, mode) && !!url;\n  return {\n    itemId: stringValue4(value.itemId ?? value.id),\n    linkedProductId,\n    linkedVariantId: stringValue4(value.linkedVariantId ?? value.variantId),\n    source: enumValue(value.source, commerceSources, linkedProductId ? \"host-projection\" : \"none\"),\n    mode,\n    status: status2,\n    priceLabel: labelValue(value.priceLabel),\n    availabilityLabel: labelValue(value.availabilityLabel),\n    purchased,\n    requiresPurchase,\n    accessState: accessState(value.accessState, purchased, requiresPurchase),\n    cta: {\n      visible,\n      enabled,\n      label: ctaLabel(value.ctaLabel, mode, status2, purchased),\n      url,\n      action,\n      reason: reason(visible, enabled, action, status2)\n    },\n    boundary: commerceBoundary()\n  };\n}\nfunction buildCommerceHandoffs(items, options = {}) {\n  const shared = record3(options);\n  return items.map((item) => normalizeCommerceHandoff({ ...shared, ...item }));\n}\nfunction summarizeCommerceHandoffs(handoffs) {\n  return {\n    linkedCount: handoffs.filter((item) => item.linkedProductId).length,\n    visibleCtaCount: handoffs.filter((item) => item.cta.visible).length,\n    lockedCount: handoffs.filter((item) => item.accessState === \"locked\").length,\n    purchasedCount: handoffs.filter((item) => item.purchased).length,\n    hostCoordinatedCount: handoffs.filter((item) => item.cta.action.startsWith(\"host-coordinated\")).length,\n    boundary: \"Gallery displays read-only Shop/Pay projections and delegates checkout, cart, orders, inventory, tax, and fulfillment.\"\n  };\n}\nfunction decideAction(mode, value) {\n  if (mode === \"none\") return \"none\";\n  if (mode === \"request-info\") return \"request-info\";\n  if (mode === \"custom\") return \"custom\";\n  if (mode === \"add-to-cart\") return \"host-coordinated-shop-add-to-cart\";\n  if (mode === \"buy\") {\n    return safeUrl(value.checkoutUrl) ? \"cedros-pay-checkout\" : \"host-coordinated-checkout\";\n  }\n  if (mode === \"view-product\") {\n    if (safeUrl(value.productUrl)) return \"open-product-page\";\n    return value.quickView === true ? \"host-coordinated-shop-quick-view\" : \"host-coordinated-checkout\";\n  }\n  return \"none\";\n}\nfunction isVisible(mode, linkedProductId, status2, hideWhenUnavailable) {\n  if (mode === \"none\" || !linkedProductId) return false;\n  if (hideWhenUnavailable && (status2 === \"sold\" || status2 === \"unavailable\")) return false;\n  return true;\n}\nfunction isEnabled(visible, status2, action, mode) {\n  if (!visible) return false;\n  if ((status2 === \"sold\" || status2 === \"unavailable\") && mode !== \"view-product\") return false;\n  return !action.startsWith(\"host-coordinated\");\n}\nfunction accessState(input, purchased, requiresPurchase) {\n  if (purchased) return \"unlocked\";\n  if (requiresPurchase) return \"locked\";\n  if (input === \"preview\" || input === \"locked\" || input === \"unlocked\") return input;\n  return \"public\";\n}\nfunction actionUrl(action, value) {\n  if (action === \"cedros-pay-checkout\") return safeUrl(value.checkoutUrl);\n  if (action === \"open-product-page\") return safeUrl(value.productUrl);\n  if (action === \"request-info\" || action === \"custom\") return safeUrl(value.detailUrl || value.productUrl);\n  return \"\";\n}\nfunction ctaLabel(input, mode, status2, purchased) {\n  const label = labelValue(input);\n  if (label) return label;\n  if (mode === \"view-product\") return \"View product\";\n  if (purchased) return \"Purchased\";\n  if (status2 === \"sold\") return \"Sold\";\n  if (status2 === \"unavailable\") return \"Unavailable\";\n  if (mode === \"buy\") return \"Buy\";\n  if (mode === \"add-to-cart\") return \"Add to cart\";\n  if (mode === \"request-info\") return \"Request info\";\n  if (mode === \"custom\") return \"Learn more\";\n  return \"View product\";\n}\nfunction reason(visible, enabled, action, status2) {\n  if (!visible) return \"hidden\";\n  if (enabled) return \"ready\";\n  if (status2 === \"sold\" || status2 === \"unavailable\") return status2;\n  if (action.startsWith(\"host-coordinated\")) return \"host handoff required\";\n  return \"disabled\";\n}\nfunction commerceBoundary() {\n  return {\n    readOnlyProjection: true,\n    ownsCheckout: false,\n    ownsInventory: false,\n    ownsOrders: false,\n    shopContractStatus: \"host-coordinated\"\n  };\n}\nfunction safeUrl(input) {\n  const value = stringValue4(input);\n  if (!value || /[\\s\\u0000-\\u001f\\u007f\\\\]/.test(value)) return \"\";\n  if (value.startsWith(\"/\") && !value.startsWith(\"//\")) return value;\n  try {\n    const url = new URL(value);\n    return url.protocol === \"https:\" || url.protocol === \"http:\" ? value : \"\";\n  } catch {\n    return \"\";\n  }\n}\nfunction labelValue(input) {\n  return stringValue4(input).slice(0, 120);\n}\nfunction enumValue(input, options, fallback) {\n  return typeof input === \"string\" && options.has(input) ? input : fallback;\n}\nfunction stringValue4(input) {\n  return typeof input === \"string\" ? input.trim() : \"\";\n}\nfunction record3(input) {\n  return typeof input === \"object\" && input !== null && !Array.isArray(input) ? input : {};\n}\n\n// src/gallery-presets.ts\nvar presetOverrides = {\n  portfolio: { presetId: \"portfolio\", layout: \"masonry\", viewer: { mode: \"minimal\" } },\n  photographer: {\n    presetId: \"photographer\",\n    layout: \"grid\",\n    access: { mode: \"password\" },\n    viewer: { mode: \"proofing\", metadataPanel: true },\n    proofing: { enabled: true, comments: true },\n    protection: { watermark: true, protectedDerivatives: true },\n    downloads: { mode: \"selected\", requireLogin: true }\n  },\n  \"digital-artist\": {\n    presetId: \"digital-artist\",\n    layout: \"product\",\n    shop: { mode: \"view-product\", entitlementState: true },\n    downloads: { mode: \"preview\", requireEntitlement: true },\n    protection: { watermark: true, protectedDerivatives: true }\n  },\n  \"physical-artist\": {\n    presetId: \"physical-artist\",\n    layout: \"masonry\",\n    shop: { mode: \"view-product\", hideWhenUnavailable: false },\n    viewer: { metadataPanel: true }\n  },\n  editorial: {\n    presetId: \"editorial\",\n    layout: \"story\",\n    viewer: { mode: \"details-side-panel\", share: true },\n    filters: { enabled: true, search: true },\n    seo: { shareLinks: true }\n  }\n};\n\n// src/gallery-config.ts\nvar layoutValues = /* @__PURE__ */ new Set([\n  \"grid\",\n  \"masonry\",\n  \"justified\",\n  \"mosaic\",\n  \"carousel\",\n  \"slider\",\n  \"filmstrip\",\n  \"horizontal-scroll\",\n  \"vertical-stack\",\n  \"fullscreen-slideshow\",\n  \"album-cover-grid\",\n  \"featured-thumbnails\",\n  \"story\",\n  \"product\",\n  \"before-after\"\n]);\nvar viewerModes = /* @__PURE__ */ new Set([\n  \"standard\",\n  \"fullscreen\",\n  \"minimal\",\n  \"details-side-panel\",\n  \"slideshow\",\n  \"proofing\",\n  \"product\",\n  \"before-after\"\n]);\nvar commerceModes2 = /* @__PURE__ */ new Set([\n  \"none\",\n  \"view-product\",\n  \"buy\",\n  \"add-to-cart\",\n  \"request-info\",\n  \"custom\"\n]);\nvar accessModes = /* @__PURE__ */ new Set([\n  \"public\",\n  \"private\",\n  \"password\",\n  \"logged-in\",\n  \"role\",\n  \"client-link\",\n  \"unlisted\"\n]);\nvar presetIds = /* @__PURE__ */ new Set([\n  \"portfolio\",\n  \"photographer\",\n  \"digital-artist\",\n  \"physical-artist\",\n  \"editorial\"\n]);\nvar galleryLayoutOptions = [...layoutValues];\nfunction normalizeGalleryFeatureConfig(input) {\n  const value = record4(input);\n  return {\n    presetId: enumValue2(value.presetId, presetIds, \"portfolio\"),\n    layout: normalizeLayout(value),\n    viewer: normalizeViewer(value),\n    filters: normalizeFilters2(value),\n    access: normalizeAccess(value),\n    proofing: normalizeProofing(value),\n    downloads: normalizeDownloads(value),\n    protection: normalizeProtection(value),\n    shop: normalizeShop(value),\n    seo: normalizeSeo(value),\n    performance: normalizePerformance(value),\n    accessibility: normalizeAccessibility(value)\n  };\n}\nfunction buildPresetGalleryConfig(presetId) {\n  return normalizeGalleryFeatureConfig(presetOverrides[presetId]);\n}\nfunction summarizeFeatureConfig(config) {\n  const modules = [\n    config.filters.enabled && \"filters\",\n    config.viewer.enabled && \"viewer\",\n    config.proofing.enabled && \"proofing\",\n    config.downloads.mode !== \"none\" && \"downloads\",\n    config.protection.watermark && \"watermark\",\n    config.shop.mode !== \"none\" && \"shop-handoff\",\n    config.seo.shareLinks && \"sharing\",\n    config.performance.lazyLoad && \"performance\",\n    config.accessibility.focusTrap && \"accessibility\"\n  ].filter(Boolean);\n  return {\n    presetId: config.presetId,\n    layout: config.layout.style,\n    viewer: config.viewer.enabled ? config.viewer.mode : \"disabled\",\n    access: config.access.mode,\n    commerceMode: config.shop.mode,\n    modules,\n    commerceBoundary: \"Cedros Gallery displays Shop/Pay state but never owns checkout truth.\"\n  };\n}\nfunction normalizeLayout(input) {\n  const value = nested(input, \"layout\");\n  const styleInput = typeof input.layout === \"string\" ? input.layout : value.style;\n  return {\n    style: enumValue2(styleInput, layoutValues, \"grid\"),\n    columns: integerValue3(input.columns ?? value.columns, 1, 8, 3),\n    gap: integerValue3(input.gap ?? value.gap, 0, 64, 16),\n    minColumnWidth: integerValue3(value.minColumnWidth, 120, 800, 240),\n    aspectRatio: enumValue2(value.aspectRatio, aspectRatios, \"original\"),\n    fit: enumValue2(value.fit, fitModes, \"cover\"),\n    featuredItems: booleanValue(value.featuredItems, false)\n  };\n}\nfunction normalizeViewer(input) {\n  const value = nested(input, \"viewer\");\n  const enabled = input.lightbox === false ? false : booleanValue(value.enabled, true);\n  return {\n    enabled,\n    mode: enumValue2(value.mode, viewerModes, \"standard\"),\n    zoom: booleanValue(value.zoom, true),\n    thumbnails: booleanValue(value.thumbnails, true),\n    metadataPanel: booleanValue(value.metadataPanel, false),\n    keyboard: booleanValue(value.keyboard, true),\n    swipe: booleanValue(value.swipe, true),\n    share: booleanValue(value.share, false)\n  };\n}\nfunction normalizeFilters2(input) {\n  const value = nested(input, \"filters\");\n  return {\n    enabled: booleanValue(input.showFilters ?? value.enabled, false),\n    display: enumValue2(value.display, filterDisplays, \"buttons\"),\n    categories: booleanValue(value.categories, true),\n    tags: booleanValue(value.tags, true),\n    search: booleanValue(value.search, false),\n    deepLinks: booleanValue(value.deepLinks, false)\n  };\n}\nfunction normalizeAccess(input) {\n  const value = nested(input, \"access\");\n  return {\n    mode: enumValue2(value.mode, accessModes, \"public\"),\n    requiredClaim: stringValue5(value.requiredClaim),\n    scheduled: booleanValue(value.scheduled, false),\n    expires: booleanValue(value.expires, false)\n  };\n}\nfunction normalizeProofing(input) {\n  const value = nested(input, \"proofing\");\n  return {\n    enabled: booleanValue(value.enabled, false),\n    favorites: booleanValue(value.favorites, true),\n    selections: booleanValue(value.selections, true),\n    comments: booleanValue(value.comments, false),\n    selectionLimit: integerValue3(value.selectionLimit, 0, 1e4, 0),\n    lockAfterSubmit: booleanValue(value.lockAfterSubmit, true)\n  };\n}\nfunction normalizeDownloads(input) {\n  const value = nested(input, \"downloads\");\n  return {\n    mode: enumValue2(value.mode, downloadModes, \"none\"),\n    requireLogin: booleanValue(value.requireLogin, false),\n    requireEntitlement: booleanValue(value.requireEntitlement, false),\n    zipExports: booleanValue(value.zipExports, false)\n  };\n}\nfunction normalizeProtection(input) {\n  const value = nested(input, \"protection\");\n  return {\n    watermark: booleanValue(value.watermark, false),\n    watermarkPreset: stringValue5(value.watermarkPreset),\n    disableRightClick: booleanValue(value.disableRightClick, false),\n    protectedDerivatives: booleanValue(value.protectedDerivatives, false),\n    copyrightNotice: booleanValue(value.copyrightNotice, true)\n  };\n}\nfunction normalizeShop(input) {\n  const value = nested(input, \"shop\");\n  return {\n    mode: enumValue2(input.commerceMode ?? value.mode, commerceModes2, \"none\"),\n    readOnlyStatus: booleanValue(value.readOnlyStatus, true),\n    readOnlyPrice: booleanValue(value.readOnlyPrice, true),\n    entitlementState: booleanValue(value.entitlementState, false),\n    hideWhenUnavailable: booleanValue(value.hideWhenUnavailable, false)\n  };\n}\nfunction normalizeSeo(input) {\n  const value = nested(input, \"seo\");\n  return {\n    imageAltRequired: booleanValue(value.imageAltRequired, true),\n    shareLinks: booleanValue(value.shareLinks, false)\n  };\n}\nfunction normalizePerformance(input) {\n  const value = nested(input, \"performance\");\n  return {\n    lazyLoad: booleanValue(value.lazyLoad, true),\n    preloadLightboxNeighbor: booleanValue(value.preloadLightboxNeighbor, true),\n    pagination: enumValue2(value.pagination, paginationModes, \"load-more\"),\n    virtualization: booleanValue(value.virtualization, false)\n  };\n}\nfunction normalizeAccessibility(input) {\n  const value = nested(input, \"accessibility\");\n  return {\n    focusTrap: booleanValue(value.focusTrap, true),\n    reducedMotion: booleanValue(value.reducedMotion, true),\n    pauseAutoplay: booleanValue(value.pauseAutoplay, true),\n    missingAltWarning: booleanValue(value.missingAltWarning, true)\n  };\n}\nvar aspectRatios = /* @__PURE__ */ new Set([\"original\", \"square\", \"portrait\", \"landscape\", \"custom\"]);\nvar fitModes = /* @__PURE__ */ new Set([\"cover\", \"contain\", \"fill\"]);\nvar filterDisplays = /* @__PURE__ */ new Set([\"buttons\", \"dropdown\", \"tabs\", \"checkboxes\", \"sidebar\", \"drawer\"]);\nvar downloadModes = /* @__PURE__ */ new Set([\"none\", \"preview\", \"original\", \"selected\", \"zip\"]);\nvar paginationModes = /* @__PURE__ */ new Set([\"none\", \"load-more\", \"infinite\", \"paged\"]);\nfunction enumValue2(input, options, fallback) {\n  return typeof input === \"string\" && options.has(input) ? input : fallback;\n}\nfunction integerValue3(input, min, max, fallback) {\n  if (typeof input !== \"number\" || !Number.isInteger(input)) return fallback;\n  return Math.max(min, Math.min(max, input));\n}\nfunction booleanValue(input, fallback) {\n  return typeof input === \"boolean\" ? input : fallback;\n}\nfunction stringValue5(input) {\n  return typeof input === \"string\" ? input.trim() : \"\";\n}\nfunction nested(input, key) {\n  return record4(input[key]);\n}\nfunction record4(input) {\n  return typeof input === \"object\" && input !== null && !Array.isArray(input) ? input : {};\n}\n\n// src/presentation.ts\nvar layoutStyles = /* @__PURE__ */ new Set([\n  \"grid\",\n  \"masonry\",\n  \"justified\",\n  \"mosaic\",\n  \"carousel\",\n  \"slider\",\n  \"filmstrip\",\n  \"horizontal-scroll\",\n  \"vertical-stack\",\n  \"fullscreen-slideshow\",\n  \"album-cover-grid\",\n  \"featured-thumbnails\",\n  \"story\",\n  \"product\",\n  \"before-after\"\n]);\nvar viewerModes2 = /* @__PURE__ */ new Set([\n  \"standard\",\n  \"fullscreen\",\n  \"minimal\",\n  \"details-side-panel\",\n  \"slideshow\",\n  \"proofing\",\n  \"product\",\n  \"before-after\"\n]);\nvar captionDisplays = /* @__PURE__ */ new Set([\n  \"none\",\n  \"title\",\n  \"caption\",\n  \"title-caption\",\n  \"description\",\n  \"metadata\",\n  \"credit\",\n  \"custom-fields\",\n  \"cta\"\n]);\nvar hoverEffects = /* @__PURE__ */ new Set([\n  \"none\",\n  \"fade-overlay\",\n  \"zoom\",\n  \"slide-caption\",\n  \"reveal-title\",\n  \"reveal-metadata\",\n  \"reveal-buttons\",\n  \"grayscale-to-color\",\n  \"color-to-grayscale\",\n  \"blur\",\n  \"tilt\",\n  \"lift\"\n]);\nfunction normalizeGalleryPresentation(input) {\n  const value = record5(input);\n  const layout2 = record5(value.layout);\n  const grid = record5(value.grid);\n  const gap = integerValue4(value.gap ?? layout2.gap, 0, 64, 16);\n  const layoutStyle = typeof value.layout === \"string\" ? value.layout : layout2.style;\n  const legacyStyle = typeof value.style === \"string\" ? value.style : void 0;\n  return {\n    layout: {\n      style: enumValue3(value.layoutStyle ?? legacyStyle ?? layoutStyle, layoutStyles, \"grid\"),\n      container: enumValue3(value.container ?? layout2.container, containerModes, \"content\"),\n      gap,\n      rowGap: integerValue4(value.rowGap ?? layout2.rowGap, 0, 96, gap),\n      randomize: value.randomize === true || layout2.randomize === true\n    },\n    grid: normalizeGrid(grid, value),\n    masonry: normalizeMasonry(record5(value.masonry), gap),\n    justified: normalizeJustified(record5(value.justified), gap),\n    carousel: normalizeCarousel(record5(value.carousel)),\n    viewer: normalizeViewer2(record5(value.viewer), value),\n    captions: normalizeCaptions(record5(value.captions), value),\n    card: normalizeCard(record5(value.card), value),\n    style: normalizeStyle(record5(value.style))\n  };\n}\nfunction summarizePresentationPlan(plan) {\n  const controls = [\n    plan.viewer.zoom && \"zoom\",\n    plan.viewer.share && \"share\",\n    plan.viewer.download && \"download\",\n    plan.viewer.favorite && \"favorite\",\n    plan.viewer.productCta && \"product\"\n  ].filter(Boolean);\n  return {\n    layout: plan.layout.style,\n    container: plan.layout.container,\n    viewer: plan.viewer.mode,\n    captions: plan.captions.display,\n    hover: plan.card.hoverEffect,\n    controls,\n    cssBoundary: \"Uses Cedros runtime theme tokens; raw CSS/class payloads stay host-coordinated.\"\n  };\n}\nfunction normalizeGrid(input, root) {\n  const columns = integerValue4(root.columns ?? input.columns, 1, 8, 3);\n  return {\n    columns,\n    responsiveColumns: responsiveNumbers(input.responsiveColumns, 1, 8, { mobile: 1, tablet: 2, desktop: columns }),\n    minColumnWidth: integerValue4(input.minColumnWidth, 120, 800, 240),\n    aspectRatio: enumValue3(input.aspectRatio, aspectRatios2, \"original\"),\n    fit: enumValue3(input.fit, fitModes2, \"cover\"),\n    focalPoint: stringValue6(input.focalPoint) || \"center center\",\n    equalHeightCards: input.equalHeightCards === true,\n    featuredLargerItems: input.featuredLargerItems === true\n  };\n}\nfunction normalizeMasonry(input, gap) {\n  return {\n    columns: integerValue4(input.columns, 1, 8, 3),\n    columnWidth: integerValue4(input.columnWidth, 120, 800, 260),\n    gutter: integerValue4(input.gutter, 0, 64, gap),\n    preserveAspectRatio: input.preserveAspectRatio !== false,\n    balanceColumns: input.balanceColumns !== false,\n    animateLayoutShift: input.animateLayoutShift !== false\n  };\n}\nfunction normalizeJustified(input, gap) {\n  const target = integerValue4(input.targetRowHeight, 80, 600, 220);\n  return {\n    targetRowHeight: target,\n    maxRowHeight: integerValue4(input.maxRowHeight, target, 900, Math.max(target, 360)),\n    gap: integerValue4(input.gap, 0, 64, gap),\n    lastRow: enumValue3(input.lastRow, lastRows, \"left\"),\n    preserveAspectRatio: input.preserveAspectRatio !== false,\n    responsiveTargetRowHeight: responsiveNumbers(input.responsiveTargetRowHeight, 80, 600, {\n      mobile: 160,\n      tablet: target,\n      desktop: target\n    })\n  };\n}\nfunction normalizeCarousel(input) {\n  const slides = integerValue4(input.slidesPerView, 1, 8, 1);\n  return {\n    slidesPerView: slides,\n    responsiveSlidesPerView: responsiveNumbers(input.responsiveSlidesPerView, 1, 8, { mobile: 1, tablet: 2, desktop: slides }),\n    autoplay: input.autoplay === true,\n    autoplaySpeedMs: integerValue4(input.autoplaySpeedMs, 1e3, 3e4, 5e3),\n    pauseOnHover: input.pauseOnHover !== false,\n    pauseOnInteraction: input.pauseOnInteraction !== false,\n    arrows: input.arrows !== false,\n    dots: input.dots === true,\n    thumbnailNav: input.thumbnailNav === true,\n    infiniteLoop: input.infiniteLoop === true,\n    centerMode: input.centerMode === true,\n    transition: enumValue3(input.transition, slideTransitions, \"slide\"),\n    transitionSpeedMs: integerValue4(input.transitionSpeedMs, 100, 3e3, 350)\n  };\n}\nfunction normalizeViewer2(input, root) {\n  return {\n    mode: enumValue3(input.mode, viewerModes2, \"standard\"),\n    closeOnEscape: input.closeOnEscape !== false,\n    closeOnBackdrop: input.closeOnBackdrop !== false,\n    fullscreen: input.fullscreen === true,\n    zoom: input.zoom !== false,\n    pan: input.pan !== false,\n    pinchZoom: input.pinchZoom !== false,\n    thumbnailStrip: input.thumbnailStrip === true,\n    counter: input.counter !== false,\n    caption: input.caption !== false,\n    metadata: input.metadata === true,\n    share: root.share === true || input.share === true,\n    download: input.download === true,\n    favorite: input.favorite === true,\n    comment: input.comment === true,\n    productCta: input.productCta === true,\n    keyboard: input.keyboard !== false,\n    swipe: input.swipe !== false\n  };\n}\nfunction normalizeCaptions(input, root) {\n  return {\n    display: enumValue3(input.display, captionDisplays, root.showCaptions === false ? \"none\" : \"title-caption\"),\n    alignment: enumValue3(input.alignment, alignments, \"left\"),\n    showArtist: input.showArtist === true,\n    showCopyright: input.showCopyright !== false,\n    showCustomFields: input.showCustomFields === true,\n    showCta: input.showCta === true\n  };\n}\nfunction normalizeCard(input, root) {\n  return {\n    hoverEffect: enumValue3(input.hoverEffect ?? root.hoverEffect, hoverEffects, \"none\"),\n    transitionMs: integerValue4(input.transitionMs, 0, 3e3, 180),\n    disableHoverOnMobile: input.disableHoverOnMobile !== false,\n    padding: integerValue4(input.padding, 0, 48, 0),\n    radius: integerValue4(input.radius, 0, 32, 8),\n    border: enumValue3(input.border, borders, \"none\"),\n    shadow: enumValue3(input.shadow, shadows, \"none\")\n  };\n}\nfunction normalizeStyle(input) {\n  return {\n    theme: enumValue3(input.theme, themes, \"system\"),\n    backgroundToken: tokenValue(input.backgroundToken, \"--c1gb4l3-runtime-bg\"),\n    textToken: tokenValue(input.textToken, \"--c1gb4l3-runtime-text\"),\n    overlayToken: tokenValue(input.overlayToken, \"--c1gb4l3-runtime-panel\"),\n    buttonStyle: enumValue3(input.buttonStyle, buttonStyles, \"solid\"),\n    iconStyle: enumValue3(input.iconStyle, iconStyles, \"line\"),\n    customStyleId: identifierValue(input.customStyleId),\n    rawCssAccepted: false\n  };\n}\nfunction responsiveNumbers(input, min, max, fallback) {\n  const value = record5(input);\n  return {\n    mobile: integerValue4(value.mobile, min, max, fallback.mobile),\n    tablet: integerValue4(value.tablet, min, max, fallback.tablet),\n    desktop: integerValue4(value.desktop, min, max, fallback.desktop)\n  };\n}\nvar containerModes = /* @__PURE__ */ new Set([\"content\", \"wide\", \"full\"]);\nvar lastRows = /* @__PURE__ */ new Set([\"stretch\", \"left\", \"center\", \"hide\"]);\nvar slideTransitions = /* @__PURE__ */ new Set([\"slide\", \"fade\", \"zoom\", \"coverflow\"]);\nvar aspectRatios2 = /* @__PURE__ */ new Set([\"original\", \"square\", \"portrait\", \"landscape\", \"custom\"]);\nvar fitModes2 = /* @__PURE__ */ new Set([\"cover\", \"contain\", \"fill\"]);\nvar alignments = /* @__PURE__ */ new Set([\"left\", \"center\", \"right\"]);\nvar borders = /* @__PURE__ */ new Set([\"none\", \"hairline\", \"solid\"]);\nvar shadows = /* @__PURE__ */ new Set([\"none\", \"subtle\", \"raised\"]);\nvar themes = /* @__PURE__ */ new Set([\"system\", \"light\", \"dark\"]);\nvar buttonStyles = /* @__PURE__ */ new Set([\"solid\", \"outline\", \"ghost\"]);\nvar iconStyles = /* @__PURE__ */ new Set([\"line\", \"filled\"]);\nfunction enumValue3(input, options, fallback) {\n  return typeof input === \"string\" && options.has(input) ? input : fallback;\n}\nfunction integerValue4(input, min, max, fallback) {\n  if (typeof input !== \"number\" || !Number.isInteger(input)) return fallback;\n  return Math.max(min, Math.min(max, input));\n}\nfunction stringValue6(input) {\n  return typeof input === \"string\" ? input.trim() : \"\";\n}\nfunction tokenValue(input, fallback) {\n  const value = stringValue6(input);\n  return value.startsWith(\"--c1gb4l3-runtime-\") ? value : fallback;\n}\nfunction identifierValue(input) {\n  return stringValue6(input).replace(/[^a-zA-Z0-9:_-]/g, \"\").slice(0, 80);\n}\nfunction record5(input) {\n  return typeof input === \"object\" && input !== null && !Array.isArray(input) ? input : {};\n}\n\n// src/seo.ts\nfunction normalizeGallerySeo(input) {\n  const value = record6(input);\n  const title = plainText(value.title) || \"Gallery\";\n  const description = plainText(value.description);\n  const images = imageArray(value.items);\n  return {\n    galleryId: stringValue7(value.galleryId),\n    title,\n    description,\n    shareUrl: safePageUrl(value.shareUrl ?? value.pageUrl),\n    sharePreview: {\n      title: plainText(value.ogTitle ?? value.shareTitle) || title,\n      description: plainText(value.ogDescription ?? value.shareDescription) || description,\n      image: safeMediaUrl(value.ogImage) || firstImage(images)\n    },\n    images\n  };\n}\nfunction summarizeSeoPlan(plan) {\n  return {\n    title: plan.title,\n    description: plan.description,\n    shareUrl: plan.shareUrl,\n    imageCount: plan.images.length,\n    crawlerOutputOwner: \"cedros-core\",\n    sharing: plan.shareUrl ? \"ready\" : \"needs page share URL\"\n  };\n}\nfunction imageArray(input) {\n  if (!Array.isArray(input)) return [];\n  return input.map(seoImage).filter((item) => item.itemId);\n}\nfunction seoImage(input) {\n  const value = record6(input);\n  return {\n    itemId: stringValue7(value.id ?? value.itemId),\n    url: safeMediaUrl(value.imageUrl ?? value.url),\n    thumbnailUrl: safeMediaUrl(value.thumbnailUrl),\n    detailUrl: safePageUrl(value.detailUrl),\n    altText: plainText(value.altText),\n    title: plainText(value.title),\n    caption: plainText(value.caption),\n    credit: plainText(value.credit ?? value.artist)\n  };\n}\nfunction firstImage(images) {\n  const image = images.find((item) => item.url || item.thumbnailUrl);\n  return image?.url || image?.thumbnailUrl || \"\";\n}\nfunction safePageUrl(input) {\n  const value = stringValue7(input);\n  if (!value || value.startsWith(\"//\") || /[\\u0000-\\u0020\\u007f\\\\]/.test(value)) return \"\";\n  if (value.startsWith(\"/\")) return value;\n  try {\n    const url = new URL(value);\n    return url.protocol === \"https:\" || url.protocol === \"http:\" ? value : \"\";\n  } catch {\n    return \"\";\n  }\n}\nfunction safeMediaUrl(input) {\n  return safePageUrl(input);\n}\nfunction plainText(input) {\n  return stringValue7(input).replace(/[<>]/g, \"\").slice(0, 240);\n}\nfunction stringValue7(input) {\n  return typeof input === \"string\" ? input.trim() : \"\";\n}\nfunction record6(input) {\n  return typeof input === \"object\" && input !== null && !Array.isArray(input) ? input : {};\n}\n\n// src/proofing.ts\nfunction buildProofingSession(input) {\n  const value = record7(input);\n  const items = normalizeGalleryItems(value.items);\n  const feedback = feedbackByItem(value.feedback);\n  const states = items.map((item) => proofingItem(item, feedback.get(item.id)));\n  const selectedCount = states.filter((item) => item.selected).length;\n  const selectionLimit = integerValue5(value.selectionLimit, 0, 1e4, 0);\n  const requiredSelections = integerValue5(value.requiredSelections, 0, 1e4, 0);\n  const enabled = value.enabled === true;\n  const submitted = value.submitted === true;\n  const lockAfterSubmit = value.lockAfterSubmit !== false;\n  const locked = value.locked === true || submitted && lockAfterSubmit;\n  const deadline = stringValue8(value.deadline ?? value.expiresAt);\n  const expired = value.expired === true || isExpired(deadline, stringValue8(value.now));\n  return {\n    sessionId: stringValue8(value.sessionId ?? value.galleryId),\n    enabled,\n    locked,\n    submitted,\n    lockAfterSubmit,\n    expired,\n    deadline,\n    selectionLimit,\n    requiredSelections,\n    selectedCount,\n    remainingSelections: remaining(selectionLimit, selectedCount),\n    canSubmit: canSubmit(enabled, locked, expired, selectedCount, selectionLimit, requiredSelections),\n    status: status(enabled, locked, expired, selectedCount, selectionLimit, requiredSelections),\n    items: states\n  };\n}\nfunction summarizeProofingSession(plan) {\n  return {\n    status: plan.status,\n    selectedCount: plan.selectedCount,\n    remainingSelections: plan.remainingSelections,\n    canSubmit: plan.canSubmit,\n    comments: plan.items.filter((item) => item.comment).length\n  };\n}\nfunction proofingItem(item, feedback) {\n  return {\n    itemId: item.id,\n    favorite: item.favorite === true || feedback?.favorite === true,\n    selected: item.selected === true || feedback?.selected === true,\n    approval: approvalValue(feedback?.approval ?? feedback?.status),\n    comment: plainText2(feedback?.comment)\n  };\n}\nfunction feedbackByItem(input) {\n  const map = /* @__PURE__ */ new Map();\n  if (!Array.isArray(input)) return map;\n  for (const item of input) {\n    const value = record7(item);\n    const itemId = stringValue8(value.itemId ?? value.id);\n    if (itemId) map.set(itemId, value);\n  }\n  return map;\n}\nfunction status(enabled, locked, expired, selectedCount, selectionLimit, requiredSelections) {\n  if (!enabled) return \"disabled\";\n  if (expired) return \"expired\";\n  if (locked) return \"locked\";\n  if (selectionLimit > 0 && selectedCount > selectionLimit) return \"over-limit\";\n  if (selectedCount < requiredSelections) return \"incomplete\";\n  return selectedCount > 0 ? \"ready\" : \"open\";\n}\nfunction canSubmit(enabled, locked, expired, selectedCount, selectionLimit, requiredSelections) {\n  if (!enabled || locked || expired) return false;\n  if (selectionLimit > 0 && selectedCount > selectionLimit) return false;\n  return selectedCount >= requiredSelections;\n}\nfunction remaining(selectionLimit, selectedCount) {\n  return selectionLimit > 0 ? Math.max(0, selectionLimit - selectedCount) : 0;\n}\nfunction isExpired(deadline, now2) {\n  if (!deadline) return false;\n  const deadlineTime = Date.parse(/^\\d{4}-\\d{2}-\\d{2}$/.test(deadline) ? `${deadline}T23:59:59.999Z` : deadline);\n  const nowTime = now2 ? Date.parse(now2) : Date.now();\n  if (!Number.isFinite(deadlineTime) || !Number.isFinite(nowTime)) return false;\n  return nowTime > deadlineTime;\n}\nfunction approvalValue(input) {\n  if (input === \"approved\" || input === \"rejected\" || input === \"maybe\") return input;\n  return \"unreviewed\";\n}\nfunction plainText2(input) {\n  return stringValue8(input).replace(/[<>]/g, \"\").slice(0, 1e3);\n}\nfunction integerValue5(input, min, max, fallback) {\n  if (typeof input !== \"number\" || !Number.isInteger(input)) return fallback;\n  return Math.max(min, Math.min(max, input));\n}\nfunction stringValue8(input) {\n  return typeof input === \"string\" ? input.trim() : \"\";\n}\nfunction record7(input) {\n  return typeof input === \"object\" && input !== null && !Array.isArray(input) ? input : {};\n}\n\n// src/visibility.ts\nvar accessModes2 = /* @__PURE__ */ new Set([\n  \"public\",\n  \"private\",\n  \"password\",\n  \"logged-in\",\n  \"role\",\n  \"client-link\",\n  \"unlisted\"\n]);\nfunction normalizeVisibilityPolicy(input) {\n  const value = record8(input);\n  const mode = enumValue4(value.mode, accessModes2, \"public\");\n  const accessRestricted = mode !== \"public\";\n  return {\n    mode,\n    requiredRole: stringValue9(value.requiredRole ?? value.requiredClaim),\n    publishAt: stringValue9(value.publishAt ?? value.scheduledAt),\n    expiresAt: stringValue9(value.expiresAt ?? value.expirationDate),\n    hideFromIndexes: accessRestricted || value.hideFromIndexes === true || value.noindex === true,\n    hideFromSearch: accessRestricted || value.hideFromSearch === true || value.noindex === true,\n    archiveAfterExpiration: value.archiveAfterExpiration === true\n  };\n}\nfunction normalizeVisibilityContext(input) {\n  const value = record8(input);\n  return {\n    authenticated: value.authenticated === true,\n    credentialVerified: value.credentialVerified === true,\n    roles: stringArray2(value.roles ?? value.permissionClaims),\n    now: stringValue9(value.now)\n  };\n}\nfunction decideGalleryVisibility(policy, context = normalizeVisibilityContext({})) {\n  const timeState = timedState(policy, context.now);\n  if (timeState) return decision(false, timeState, policy, reasonFor(timeState));\n  if (policy.mode === \"private\") return decision(false, \"private\", policy, \"private gallery\");\n  if (policy.mode === \"logged-in\" && !context.authenticated) {\n    return decision(false, \"login-required\", policy, \"login required\");\n  }\n  if (policy.mode === \"password\" && !context.credentialVerified) {\n    return decision(false, \"credential-required\", policy, \"password required\");\n  }\n  if (policy.mode === \"client-link\" && !context.credentialVerified) {\n    return decision(false, \"credential-required\", policy, \"client link required\");\n  }\n  if (policy.mode === \"role\" && !hasRole(context.roles, policy.requiredRole)) {\n    return decision(false, \"role-required\", policy, \"required role missing\");\n  }\n  return decision(true, \"visible\", policy, policy.mode === \"unlisted\" ? \"unlisted\" : \"public\");\n}\nfunction decideItemVisibility(item, context) {\n  if (item.hidden) return itemDecision(item, false, \"hidden\");\n  if (item.private && !context.authenticated) return itemDecision(item, false, \"login required\");\n  if (item.requiredRole && !hasRole(context.roles, item.requiredRole)) {\n    return itemDecision(item, false, \"required role missing\");\n  }\n  if (item.hideWhenProductUnavailable && (item.productStatus === \"sold\" || item.productStatus === \"unavailable\")) {\n    return itemDecision(item, false, \"product unavailable\");\n  }\n  return itemDecision(item, true, \"visible\");\n}\nfunction filterVisibleGalleryItems(items, context) {\n  return items.filter((item) => decideItemVisibility(item, context).visible);\n}\nfunction summarizeVisibility(decision2) {\n  return {\n    state: decision2.state,\n    visible: decision2.visible,\n    indexable: decision2.indexable,\n    searchable: decision2.searchable,\n    archived: decision2.archived\n  };\n}\nfunction timedState(policy, nowInput) {\n  const now2 = nowInput ? Date.parse(nowInput) : Date.now();\n  const publishAt = policy.publishAt ? Date.parse(policy.publishAt) : Number.NaN;\n  const expiresAt = policy.expiresAt ? Date.parse(policy.expiresAt) : Number.NaN;\n  if (Number.isFinite(publishAt) && now2 < publishAt) return \"scheduled\";\n  if (Number.isFinite(expiresAt) && now2 > expiresAt) return \"expired\";\n  return null;\n}\nfunction decision(visible, state, policy, reason2) {\n  return {\n    visible,\n    state,\n    indexable: visible && policy.mode === \"public\" && !policy.hideFromIndexes && state !== \"expired\",\n    searchable: visible && policy.mode === \"public\" && !policy.hideFromSearch && state !== \"expired\",\n    archived: state === \"expired\" && policy.archiveAfterExpiration,\n    reason: reason2\n  };\n}\nfunction itemDecision(item, visible, reason2) {\n  return { itemId: item.id, visible, reason: reason2 };\n}\nfunction reasonFor(state) {\n  if (state === \"scheduled\") return \"scheduled publish date is in the future\";\n  if (state === \"expired\") return \"gallery expired\";\n  return state;\n}\nfunction hasRole(roles, requiredRole) {\n  if (!requiredRole) return false;\n  return roles.includes(\"*\") || roles.includes(requiredRole);\n}\nfunction stringArray2(input) {\n  if (!Array.isArray(input)) return [];\n  return input.map(stringValue9).filter(Boolean);\n}\nfunction enumValue4(input, options, fallback) {\n  return typeof input === \"string\" && options.has(input) ? input : fallback;\n}\nfunction stringValue9(input) {\n  return typeof input === \"string\" ? input.trim() : \"\";\n}\nfunction record8(input) {\n  return typeof input === \"object\" && input !== null && !Array.isArray(input) ? input : {};\n}\n\n// src/protection.ts\nfunction normalizeProtectionPlan(input) {\n  const value = record9(input);\n  const watermark = record9(value.watermark);\n  return {\n    watermark: normalizeWatermark(watermark, value),\n    disableRightClick: value.disableRightClick === true,\n    disableDragging: value.disableDragging === true,\n    hideOriginalUrl: value.hideOriginalUrl !== false,\n    protectedDerivatives: value.protectedDerivatives === true || value.watermark === true,\n    stripLocationExif: value.stripLocationExif === true,\n    preserveCopyrightMetadata: value.preserveCopyrightMetadata !== false,\n    copyrightNotice: plainText3(value.copyrightNotice),\n    licenseNotice: plainText3(value.licenseNotice),\n    creditLine: plainText3(value.creditLine)\n  };\n}\nfunction planProtectedDerivatives(galleryId, items, plan) {\n  if (!plan.protectedDerivatives && !plan.watermark.enabled) return [];\n  return items.filter((item) => item.mediaAssetId).flatMap((item) => derivativeRequests(galleryId, item, plan));\n}\nfunction summarizeProtectionPlan(plan) {\n  const modules = [\n    plan.watermark.enabled && \"watermark\",\n    plan.disableRightClick && \"right-click\",\n    plan.disableDragging && \"dragging\",\n    plan.hideOriginalUrl && \"hide-original-url\",\n    plan.protectedDerivatives && \"protected-derivatives\",\n    plan.stripLocationExif && \"strip-location-exif\"\n  ].filter(Boolean);\n  return {\n    watermark: plan.watermark.enabled ? plan.watermark.kind : \"none\",\n    modules,\n    copyrightNotice: Boolean(plan.copyrightNotice),\n    derivativeBoundary: \"Derivative previews are Gallery-owned; originals and protected delivery remain Cedros Data media.\"\n  };\n}\nfunction derivativeRequests(galleryId, item, plan) {\n  const requests = [\n    derivative(galleryId, item, \"preview\", \"protected preview\")\n  ];\n  if (plan.watermark.enabled) {\n    requests.push(derivative(galleryId, item, \"watermarked\", \"watermarked display\"));\n  }\n  if (plan.watermark.applyToThumbnails) {\n    requests.push(derivative(galleryId, item, \"thumbnail\", \"watermarked thumbnail\"));\n  }\n  return requests;\n}\nfunction derivative(galleryId, item, kind, reason2) {\n  return {\n    itemId: item.id,\n    sourceMediaAssetId: item.mediaAssetId,\n    kind,\n    contentType: \"image/webp\",\n    storageKey: `derivatives/${cleanSegment(galleryId || \"global\")}/${kind}/${cleanSegment(item.id)}`,\n    reason: reason2\n  };\n}\nfunction normalizeWatermark(watermark, root) {\n  const kind = enumValue5(watermark.kind, watermarkKinds, root.watermark === true ? \"text\" : \"none\");\n  return {\n    enabled: root.watermark === true || watermark.enabled === true || kind !== \"none\",\n    kind,\n    text: plainText3(watermark.text),\n    imageMediaAssetId: stringValue10(watermark.imageMediaAssetId),\n    position: enumValue5(watermark.position, watermarkPositions, \"bottom-right\"),\n    opacity: numberValue(watermark.opacity, 0, 1, 0.35),\n    scale: numberValue(watermark.scale, 0.05, 2, 0.2),\n    rotation: integerValue6(watermark.rotation, -180, 180, 0),\n    tiled: watermark.tiled === true || watermark.position === \"tiled\",\n    dynamicText: plainText3(watermark.dynamicText),\n    applyToThumbnails: watermark.applyToThumbnails === true,\n    applyToLightbox: watermark.applyToLightbox !== false,\n    applyToDownloads: watermark.applyToDownloads === true,\n    excludeOriginals: watermark.excludeOriginals !== false\n  };\n}\nvar watermarkKinds = /* @__PURE__ */ new Set([\"none\", \"text\", \"image\"]);\nvar watermarkPositions = /* @__PURE__ */ new Set([\n  \"center\",\n  \"top-left\",\n  \"top-right\",\n  \"bottom-left\",\n  \"bottom-right\",\n  \"tiled\"\n]);\nfunction cleanSegment(input) {\n  const cleaned = input.replace(/[^a-zA-Z0-9_-]+/g, \"-\").replace(/^-+|-+$/g, \"\");\n  return cleaned || \"item\";\n}\nfunction plainText3(input) {\n  return stringValue10(input).replace(/[<>]/g, \"\").slice(0, 240);\n}\nfunction enumValue5(input, options, fallback) {\n  return typeof input === \"string\" && options.has(input) ? input : fallback;\n}\nfunction integerValue6(input, min, max, fallback) {\n  if (typeof input !== \"number\" || !Number.isInteger(input)) return fallback;\n  return Math.max(min, Math.min(max, input));\n}\nfunction numberValue(input, min, max, fallback) {\n  if (typeof input !== \"number\" || !Number.isFinite(input)) return fallback;\n  return Math.max(min, Math.min(max, input));\n}\nfunction stringValue10(input) {\n  return typeof input === \"string\" ? input.trim() : \"\";\n}\nfunction record9(input) {\n  return typeof input === \"object\" && input !== null && !Array.isArray(input) ? input : {};\n}\n\n// src/performance.ts\nvar placeholders = /* @__PURE__ */ new Set([\"none\", \"blur-up\", \"dominant-color\", \"skeleton\"]);\nvar formats = /* @__PURE__ */ new Set([\"source\", \"webp\", \"avif\"]);\nvar paginationModes2 = /* @__PURE__ */ new Set([\"none\", \"load-more\", \"infinite\", \"paged\"]);\nfunction normalizePerformancePlan(input) {\n  const value = record10(input);\n  return {\n    lazyLoad: value.lazyLoad !== false,\n    eagerLoadCount: integerValue7(value.eagerLoadCount, 0, 24, 4),\n    srcset: value.srcset !== false,\n    responsiveSizes: stringValue11(value.responsiveSizes) || \"(min-width: 900px) 33vw, 100vw\",\n    optimizedThumbnails: value.optimizedThumbnails !== false,\n    formatPreference: enumValue6(value.formatPreference, formats, \"webp\"),\n    compressionQuality: integerValue7(value.compressionQuality, 1, 100, 82),\n    placeholder: enumValue6(value.placeholder, placeholders, \"blur-up\"),\n    pagination: enumValue6(value.pagination, paginationModes2, \"load-more\"),\n    pageSize: integerValue7(value.pageSize, 1, 500, 48),\n    virtualization: value.virtualization === true,\n    preloadLightboxNeighbor: value.preloadLightboxNeighbor !== false,\n    cacheGalleryQueries: value.cacheGalleryQueries !== false,\n    cacheLayoutData: value.cacheLayoutData !== false,\n    cdnCompatibleUrls: value.cdnCompatibleUrls !== false\n  };\n}\nfunction planImageLoading(items, plan) {\n  return items.map((item, index) => ({\n    itemId: item.id,\n    mediaAssetId: item.mediaAssetId,\n    loading: !plan.lazyLoad || index < plan.eagerLoadCount ? \"eager\" : \"lazy\",\n    decoding: \"async\",\n    fetchPriority: index === 0 ? \"high\" : \"auto\",\n    sizes: plan.responsiveSizes,\n    srcset: plan.srcset,\n    placeholder: plan.placeholder,\n    preferredFormat: plan.formatPreference\n  }));\n}\nfunction auditPerformancePlan(items, plan) {\n  const warnings = [];\n  if (items.length > 24 && !plan.lazyLoad) {\n    warnings.push(warning(\"lazy-load-disabled\", \"Lazy loading should stay enabled for image-heavy galleries.\"));\n  }\n  if (items.length > 200 && plan.pagination === \"none\") {\n    warnings.push(warning(\"large-gallery-no-pagination\", \"Large galleries need pagination, load-more, or infinite scroll.\"));\n  }\n  if (items.length > 500 && !plan.virtualization) {\n    warnings.push(info(\"large-gallery-no-virtualization\", \"Very large galleries should enable virtualization.\"));\n  }\n  if (!plan.srcset) {\n    warnings.push(warning(\"srcset-disabled\", \"Responsive image srcset should stay enabled.\"));\n  }\n  return warnings;\n}\nfunction summarizePerformancePlan(items, plan) {\n  const warnings = auditPerformancePlan(items, plan);\n  return {\n    lazyLoad: plan.lazyLoad,\n    pagination: plan.pagination,\n    pageSize: plan.pageSize,\n    virtualization: plan.virtualization,\n    imageCount: items.length,\n    warningCount: warnings.length,\n    firstImageLoading: plan.lazyLoad ? \"eager\" : \"all-eager\"\n  };\n}\nfunction warning(code, message) {\n  return { code, severity: \"warning\", message };\n}\nfunction info(code, message) {\n  return { code, severity: \"info\", message };\n}\nfunction enumValue6(input, options, fallback) {\n  return typeof input === \"string\" && options.has(input) ? input : fallback;\n}\nfunction integerValue7(input, min, max, fallback) {\n  if (typeof input !== \"number\" || !Number.isInteger(input)) return fallback;\n  return Math.max(min, Math.min(max, input));\n}\nfunction stringValue11(input) {\n  return typeof input === \"string\" ? input.trim() : \"\";\n}\nfunction record10(input) {\n  return typeof input === \"object\" && input !== null && !Array.isArray(input) ? input : {};\n}\n\n// src/domain.ts\nfunction normalizeGalleryBlockProps(input) {\n  const value = isRecord2(input) ? input : {};\n  const config = normalizeGalleryFeatureConfig(featureConfigInput(value));\n  const galleryId = typeof value.galleryId === \"string\" ? value.galleryId : \"\";\n  const items = normalizeGalleryItems(value.items);\n  const proofing = proofingInput(value);\n  const visibility = visibilityInput(value);\n  const visibilityPolicy = normalizeVisibilityPolicy({\n    mode: config.access.mode,\n    requiredClaim: config.access.requiredClaim,\n    ...visibility,\n    noindex: visibility.noindex === true\n  });\n  return {\n    galleryId,\n    layout: config.layout.style,\n    columns: config.layout.columns,\n    gap: config.layout.gap,\n    headingLevel: integerValue8(value.headingLevel, 2, 6, 2),\n    lightbox: config.viewer.enabled,\n    showFilters: config.filters.enabled,\n    showCaptions: value.showCaptions !== false,\n    commerceMode: config.shop.mode,\n    sort: gallerySorts.has(value.sort) ? value.sort : \"manual\",\n    filters: normalizeFilters(value.filters),\n    items,\n    config,\n    presentation: normalizeGalleryPresentation(value.presentation ?? value),\n    seo: normalizeGallerySeo({ ...seoInput(value), galleryId }),\n    proofing: buildProofingSession({\n      ...proofing,\n      sessionId: proofing.sessionId ?? galleryId,\n      enabled: typeof proofing.enabled === \"boolean\" ? proofing.enabled : config.proofing.enabled,\n      selectionLimit: proofing.selectionLimit ?? config.proofing.selectionLimit,\n      items\n    }),\n    visibilityPolicy,\n    visibilityContext: normalizeVisibilityContext(value.viewerContext),\n    protection: normalizeProtectionPlan({\n      ...config.protection,\n      ...protectionInput(value)\n    }),\n    performance: normalizePerformancePlan({\n      ...config.performance,\n      ...performanceInput(value)\n    })\n  };\n}\nfunction validateGalleryBlockProps(input) {\n  const props = normalizeGalleryBlockProps(input);\n  const requiresGalleryId = props.proofing.enabled || props.visibilityPolicy.mode === \"password\" || props.visibilityPolicy.mode === \"client-link\" || props.visibilityPolicy.mode === \"role\";\n  const errors = requiresGalleryId && !props.galleryId.trim() ? [\"galleryId is required for proofing and record-backed access modes\"] : [];\n  return { valid: errors.length === 0, errors };\n}\nfunction buildGalleryView(input) {\n  const props = normalizeGalleryBlockProps(input);\n  const visibilityDecision = decideGalleryVisibility(props.visibilityPolicy, props.visibilityContext);\n  const accessItems = visibilityDecision.visible ? filterVisibleGalleryItems(props.items, props.visibilityContext) : [];\n  const visibleItems = sortGalleryItems(filterGalleryItems(accessItems, props.filters), props.sort);\n  const visibleSeo = normalizeGallerySeo({ ...props.seo, items: visibleItems });\n  const commerceHandoffs = buildCommerceHandoffs(visibleItems, {\n    mode: props.commerceMode,\n    hideWhenUnavailable: props.config.shop.hideWhenUnavailable\n  });\n  const commerceSummary = summarizeCommerceHandoffs(commerceHandoffs);\n  const derivativeRequests2 = planProtectedDerivatives(props.galleryId, visibleItems, props.protection);\n  const imageLoading = planImageLoading(visibleItems, props.performance);\n  const lockedCount = visibleItems.filter((item) => item.accessState === \"locked\").length;\n  const productCount = visibleItems.filter(hasProductProjection).length;\n  return {\n    galleryId: props.galleryId,\n    layout: props.layout,\n    columns: props.columns,\n    gap: props.gap,\n    headingLevel: props.headingLevel,\n    controls: {\n      filters: props.showFilters,\n      lightbox: props.lightbox,\n      captions: props.showCaptions,\n      commerceMode: props.commerceMode\n    },\n    featureSummary: summarizeFeatureConfig(props.config),\n    presentationSummary: summarizePresentationPlan(props.presentation),\n    commerceSummary,\n    downloadPolicy: props.config.downloads,\n    seoSummary: summarizeSeoPlan(visibleSeo),\n    proofingSummary: summarizeProofingSession(props.proofing),\n    visibilitySummary: summarizeVisibility(visibilityDecision),\n    visibilityContext: props.visibilityContext,\n    protectionSummary: summarizeProtectionPlan(props.protection),\n    derivativeRequests: derivativeRequests2,\n    performanceSummary: summarizePerformancePlan(visibleItems, props.performance),\n    imageLoading,\n    itemCount: visibleItems.length,\n    lockedCount,\n    productCount,\n    items: visibleItems,\n    commerceHandoffs\n  };\n}\nfunction featureConfigInput(value) {\n  const config = isRecord2(value.config) ? value.config : {};\n  return {\n    ...config,\n    layout: value.layout ?? config.layout,\n    columns: value.columns ?? config.columns,\n    gap: value.gap ?? config.gap,\n    lightbox: value.lightbox ?? config.lightbox,\n    showFilters: value.showFilters ?? config.showFilters,\n    commerceMode: value.commerceMode ?? config.commerceMode\n  };\n}\nfunction seoInput(value) {\n  return isRecord2(value.seo) ? value.seo : {};\n}\nfunction proofingInput(value) {\n  return isRecord2(value.proofingSession) ? value.proofingSession : {};\n}\nfunction visibilityInput(value) {\n  return isRecord2(value.visibility) ? value.visibility : {};\n}\nfunction protectionInput(value) {\n  return isRecord2(value.protection) ? value.protection : {};\n}\nfunction performanceInput(value) {\n  return isRecord2(value.performance) ? value.performance : {};\n}\nfunction hasProductProjection(item) {\n  return item.productStatus !== \"none\" || Boolean(item.linkedProductId);\n}\nfunction integerValue8(input, min, max, fallback) {\n  if (typeof input !== \"number\" || !Number.isInteger(input)) return fallback;\n  return Math.max(min, Math.min(max, input));\n}\nfunction isRecord2(input) {\n  return typeof input === \"object\" && input !== null && !Array.isArray(input);\n}\n\n// src/styles.ts\nvar styleId = \"cedros-gallery-runtime-styles\";\nvar baselineRadius = `\n      --c1gb4l3-gallery-stage: #0a0a0a;\n      --c1gb4l3-gallery-radius-control: 6px;\n      --c1gb4l3-gallery-radius-card: 8px;\n      --c1gb4l3-gallery-radius-panel: 12px;`;\nvar galleryRoots = [\n  \".cedros-gallery-block\",\n  \".cedros-gallery-album\",\n  \".cedros-gallery-comparison\"\n];\nvar reducedMotionSelectors = galleryRoots.flatMap((root) => [root, `${root} *`, `${root} *::before`, `${root} *::after`]).join(\",\\n      \");\nfunction installGalleryStyles() {\n  if (typeof document === \"undefined\" || document.getElementById(styleId)) return;\n  const style = document.createElement(\"style\");\n  style.id = styleId;\n  style.setAttribute(\"data-c1gb4l3-extension-style\", \"@cedros/gallery::workspace/react/dist/web/styles.css\");\n  style.textContent = `\n    .cedros-gallery-block {\n${baselineRadius}\n      box-sizing: border-box;\n      color: var(--c1gb4l3-runtime-text, inherit);\n      display: grid;\n      gap: 24px;\n      max-width: 100%;\n      min-width: 0;\n      container-type: inline-size;\n      overflow-wrap: anywhere;\n    }\n    .cedros-gallery-block [hidden],\n    .cedros-gallery-album [hidden] { display: none; }\n    .cedros-gallery-block *,\n    .cedros-gallery-album *,\n    .cedros-gallery-comparison * {\n      box-sizing: border-box;\n      min-width: 0;\n    }\n    .cedros-gallery-header {\n      align-items: end;\n      display: flex;\n      gap: 16px;\n      justify-content: space-between;\n    }\n    .cedros-gallery-collection-context {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      font-size: .875rem;\n      margin: 8px 0 0;\n    }\n    .cedros-gallery-title-button {\n      background: transparent;\n      border: 0;\n      color: inherit;\n      cursor: pointer;\n      font: inherit;\n      padding: 0;\n      text-align: start;\n    }\n    .cedros-gallery-title-button:hover { text-decoration: underline; text-underline-offset: .2em; }\n    .cedros-gallery-submission__image-preview {\n      background: var(--c1gb4l3-runtime-bg, transparent);\n      border: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      border-radius: var(--c1gb4l3-gallery-radius-card, 8px);\n      margin: 0;\n      overflow: hidden;\n    }\n    .cedros-gallery-submission__image-preview img {\n      display: block;\n      height: min(36vh, 280px);\n      object-fit: contain;\n      width: 100%;\n    }\n    .cedros-gallery-submission__image-preview figcaption,\n    .cedros-gallery-submission__image-preview > p {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      font-size: .8125rem;\n      margin: 0;\n      overflow-wrap: anywhere;\n      padding: 12px;\n    }\n    .cedros-gallery-submission__caption summary {\n      cursor: pointer;\n      min-height: 44px;\n      padding-block: 12px;\n    }\n    .cedros-gallery-submission__caption summary:focus-visible {\n      outline: 2px solid var(--c1gb4l3-runtime-accent, currentColor);\n      outline-offset: 4px;\n    }\n    .cedros-gallery-submission--returning > .cedros-gallery-submission__history {\n      border-top: 0;\n      margin-top: 0;\n      padding-top: 0;\n    }\n    .cedros-gallery-submission > .cedros-gallery-header > .cedros-gallery-button {\n      align-self: flex-start;\n      flex-shrink: 0;\n    }\n    .cedros-gallery-submission > .cedros-gallery-header {\n      align-items: flex-start;\n      flex-direction: row;\n      flex-wrap: wrap;\n    }\n    .cedros-gallery-submission > .cedros-gallery-header > div { flex: 1 1 320px; }\n    .cedros-gallery-field--upload input[type=\"file\"] {\n      background: var(--c1gb4l3-runtime-panel, transparent);\n      padding: 12px;\n    }\n    .cedros-gallery-field--upload input::file-selector-button {\n      background: var(--c1gb4l3-runtime-bg, #fff);\n      border: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      border-radius: var(--c1gb4l3-gallery-radius-control, 6px);\n      color: var(--c1gb4l3-runtime-text, #111);\n      cursor: pointer;\n      font: inherit;\n      margin-inline-end: 12px;\n      min-height: 44px;\n      padding: 8px 12px;\n    }\n    .cedros-gallery-field--upload input::file-selector-button:hover { background: var(--c1gb4l3-runtime-accent-soft, transparent); }\n    .cedros-gallery-title-button:focus-visible {\n      outline: 2px solid var(--c1gb4l3-runtime-accent, currentColor);\n      outline-offset: 4px;\n      border-radius: var(--c1gb4l3-gallery-radius-control, 6px);\n    }\n    .cedros-gallery-block--proofing > .cedros-gallery-proofing {\n      position: sticky;\n      top: 12px;\n      z-index: 2;\n    }\n    .cedros-gallery-block--proofing > .cedros-gallery-proofing--static { position: static; }\n    .cedros-gallery-proofing,\n    .cedros-gallery-proofing__confirm { scroll-margin-block-start: 16px; }\n    @media (max-height: 480px) {\n      .cedros-gallery-block--proofing > .cedros-gallery-proofing { position: static; }\n    }\n    .cedros-gallery-heading {\n      font: inherit;\n      font-size: 1.5rem;\n      font-weight: 700;\n      line-height: 1.25;\n      margin: 0;\n    }\n    .cedros-gallery-kicker {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      font-size: .8125rem;\n      font-weight: 600;\n      letter-spacing: 0;\n      margin: 0 0 8px;\n      text-transform: none;\n    }\n    .cedros-gallery-description {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      margin: 8px 0 0;\n      max-width: 70ch;\n    }\n    .cedros-gallery-stats {\n      display: flex;\n      flex-wrap: wrap;\n      gap: 12px;\n      justify-content: flex-end;\n      margin: 0;\n    }\n    .cedros-gallery-stats div,\n    .cedros-gallery-access,\n    .cedros-gallery-proofing,\n    .cedros-gallery-toolbar {\n      border: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      background: var(--c1gb4l3-runtime-panel, transparent);\n      border-radius: var(--c1gb4l3-gallery-radius-control, 6px);\n    }\n    .cedros-gallery-stats div {\n      min-width: 88px;\n      padding: 8px 12px;\n    }\n    .cedros-gallery-stats dt {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      font-size: .75rem;\n      margin: 0;\n    }\n    .cedros-gallery-stats dd {\n      font-weight: 700;\n      margin: 4px 0 0;\n    }\n    .cedros-gallery-toolbar {\n      border: 0;\n      background: transparent;\n      display: grid;\n      gap: 0;\n      padding: 0;\n    }\n    .cedros-gallery-toolbar__primary,\n    .cedros-gallery-toolbar__advanced {\n      align-items: end;\n      display: flex;\n      flex-wrap: wrap;\n      gap: 12px;\n    }\n    .cedros-gallery-toolbar__primary > .cedros-gallery-field {\n      flex: 0 1 180px;\n    }\n    .cedros-gallery-toolbar__primary > .cedros-gallery-field--search {\n      flex: 1 1 240px;\n    }\n    .cedros-gallery-toolbar__disclosure {\n      display: grid;\n      grid-template-rows: 0fr;\n      transition: grid-template-rows var(--motion-duration-standard, 220ms) var(--motion-ease-standard, cubic-bezier(0.16, 1, 0.3, 1));\n    }\n    .cedros-gallery-toolbar.is-expanded .cedros-gallery-toolbar__disclosure {\n      grid-template-rows: 1fr;\n    }\n    .cedros-gallery-toolbar__advanced {\n      min-height: 0;\n      overflow: hidden;\n    }\n    .cedros-gallery-toolbar.is-expanded .cedros-gallery-toolbar__advanced {\n      padding-top: 12px;\n    }\n    .cedros-gallery-toolbar .cedros-gallery-toolbar__toggle {\n      display: inline-flex;\n    }\n    .cedros-gallery-field {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      display: grid;\n      font-size: .875rem;\n      gap: 8px;\n    }\n    .cedros-gallery-field input,\n    .cedros-gallery-field select,\n    .cedros-gallery-field textarea {\n      background: var(--c1gb4l3-runtime-bg, #fff);\n      border: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      border-radius: var(--c1gb4l3-gallery-radius-control, 6px);\n      color: var(--c1gb4l3-runtime-text, #111);\n      font: inherit;\n      margin: 0;\n      min-height: 44px;\n      padding: 8px 12px;\n      width: 100%;\n    }\n    .cedros-gallery-field--comment textarea {\n      min-height: 92px;\n      resize: vertical;\n    }\n    .cedros-gallery-submission {\n      margin-inline: auto;\n      max-width: 720px;\n      width: 100%;\n    }\n    .cedros-gallery-submission__access {\n      background: var(--c1gb4l3-runtime-panel, transparent);\n      border: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      border-radius: var(--c1gb4l3-gallery-radius-control, 6px);\n      display: grid;\n      gap: 12px;\n      padding: 24px;\n    }\n    .cedros-gallery-submission__access p { margin: 0; }\n    .cedros-gallery-submission__access .cedros-gallery-button { justify-self: start; }\n    .cedros-gallery-visually-hidden {\n      clip-path: inset(50%);\n      height: 1px;\n      overflow: hidden;\n      position: absolute;\n      white-space: nowrap;\n      width: 1px;\n    }\n    .cedros-gallery-submission__form {\n      background: var(--c1gb4l3-runtime-panel, transparent);\n      border: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      border-radius: var(--c1gb4l3-gallery-radius-panel, 12px);\n      display: grid;\n      gap: 16px;\n      padding: clamp(16px, 4vw, 24px);\n    }\n    .cedros-gallery-submission__form[hidden] { display: none; }\n    .cedros-gallery-submission__form fieldset {\n      border: 0;\n      display: grid;\n      gap: 16px;\n      margin: 0;\n      min-width: 0;\n      padding: 0;\n    }\n    .cedros-gallery-submission__form fieldset:disabled {\n      opacity: .72;\n    }\n    .cedros-gallery-submission__help,\n    .cedros-gallery-submission__status {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n    }\n    .cedros-gallery-submission__field input[type=\"file\"] {\n      max-width: 100%;\n      padding-block: 7px;\n    }\n    .cedros-gallery-submission__field input[type=\"file\"]::file-selector-button {\n      background: var(--c1gb4l3-runtime-panel, transparent);\n      border: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      border-radius: var(--c1gb4l3-gallery-radius-control, 6px);\n      color: var(--c1gb4l3-runtime-text, inherit);\n      cursor: pointer;\n      font: inherit;\n      font-weight: 600;\n      margin-inline-end: 12px;\n      padding: 8px 12px;\n    }\n    .cedros-gallery-submission__actions {\n      display: flex;\n      flex-wrap: wrap;\n      gap: 12px;\n    }\n    .cedros-gallery-submission__status {\n      margin: 0;\n    }\n    .cedros-gallery-submission__status--error,\n    .cedros-gallery-submission__status--auth {\n      color: var(--c1gb4l3-runtime-error, #b42318);\n    }\n    .cedros-gallery-submission__status--success {\n      color: var(--c1gb4l3-runtime-text, inherit);\n    }\n    .cedros-gallery-submission__history {\n      border-top: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      display: grid;\n      gap: 16px;\n      margin-top: 24px;\n      padding-top: 24px;\n    }\n    .cedros-gallery-submission__history-heading {\n      align-items: start;\n      display: flex;\n      gap: 16px;\n      justify-content: space-between;\n    }\n    .cedros-gallery-submission__history-heading .cedros-gallery-button { flex: none; }\n    .cedros-gallery-submission__history-heading > div { max-width: 44ch; }\n    @container (max-width: 480px) {\n      .cedros-gallery-submission__history-heading { align-items: flex-start; flex-direction: column; }\n    }\n    @media (max-width: 480px) {\n      .cedros-gallery-submission__history-heading { align-items: flex-start; flex-direction: column; }\n    }\n    .cedros-gallery-submission__history-heading h3,\n    .cedros-gallery-submission__history-heading p {\n      margin: 0;\n    }\n    .cedros-gallery-submission__history-heading p,\n    .cedros-gallery-submission__history-item > div > span {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n    }\n    .cedros-gallery-submission__history-list {\n      display: grid;\n      gap: 0;\n      list-style: none;\n      margin: 0;\n      padding: 0;\n    }\n    .cedros-gallery-submission__history-item {\n      align-items: start;\n      border-bottom: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      display: grid;\n      gap: 8px 16px;\n      grid-template-columns: minmax(0, 1fr) auto;\n      padding: 16px 0;\n    }\n    .cedros-gallery-submission__history-item:last-child { border-bottom: 0; }\n    .cedros-gallery-submission__history-item > div > span { font-size: .8125rem; }\n    .cedros-gallery-submission__history-item > div {\n      display: grid;\n      gap: 4px;\n      overflow-wrap: anywhere;\n    }\n    .cedros-gallery-submission__history-item > p {\n      grid-column: 1 / -1;\n      margin: 0;\n    }\n    .cedros-gallery-submission__reference {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      font-size: .8125rem;\n      grid-column: 1 / -1;\n    }\n    .cedros-gallery-submission__reference summary { cursor: pointer; padding-block: 8px; }\n    .cedros-gallery-submission__reference code { display: block; overflow-wrap: anywhere; padding-block: 8px; }\n    .cedros-gallery-submission__reference summary:focus-visible {\n      outline: 2px solid var(--c1gb4l3-runtime-accent, currentColor);\n      outline-offset: 3px;\n    }\n    .cedros-gallery-submission__decision {\n      justify-self: start;\n      border: 1px solid currentColor;\n      border-radius: 999px;\n      font-size: .75rem;\n      font-weight: 700;\n      padding: 4px 8px;\n    }\n    .cedros-gallery-submission__decision--approved {\n      color: var(--c1gb4l3-runtime-text, inherit);\n    }\n    .cedros-gallery-submission__decision--rejected {\n      color: var(--c1gb4l3-runtime-error, #b42318);\n    }\n    .cedros-gallery-submission__decision--pending {\n      background: color-mix(in srgb, var(--c1gb4l3-runtime-warning, #9a6700) 12%, var(--c1gb4l3-runtime-panel, #fff));\n      border-color: var(--c1gb4l3-runtime-warning, #9a6700);\n      color: var(--c1gb4l3-runtime-text, inherit);\n    }\n    .cedros-gallery-proofing {\n      align-items: center;\n      display: flex;\n      flex-wrap: wrap;\n      gap: 12px;\n      padding: 16px;\n    }\n    .cedros-gallery-proofing__summary {\n      display: grid;\n      flex: 1 1 240px;\n      gap: 4px;\n    }\n    .cedros-gallery-proofing__summary > span {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      font-size: .8125rem;\n    }\n    .cedros-gallery-proofing__state {\n      flex: 1 1 100%;\n    }\n    .cedros-gallery-proofing__summary + .cedros-gallery-proofing__state {\n      flex: 1 1 240px;\n    }\n    .cedros-gallery-access {\n      align-items: end;\n      display: grid;\n      gap: 12px;\n      grid-template-columns: minmax(180px, 1fr) auto;\n      padding: 12px;\n    }\n    .cedros-gallery-access--credential {\n      max-width: min(100%, 36rem);\n    }\n    .cedros-gallery-access__intro {\n      grid-column: 1 / -1;\n    }\n    .cedros-gallery-access p {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      margin: 0;\n    }\n    .cedros-gallery-proofing__state {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n    }\n    .cedros-gallery-proofing__confirm {\n      align-items: flex-start;\n      background: var(--c1gb4l3-runtime-panel, transparent);\n      border: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      border-radius: var(--c1gb4l3-gallery-radius-control, 6px);\n      display: grid;\n      flex: 1 1 100%;\n      gap: 8px;\n      padding: 12px;\n    }\n    .cedros-gallery-proofing__selected {\n      display: grid;\n      gap: 8px 16px;\n      grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));\n      list-style: none;\n      margin: 0;\n      max-height: 280px;\n      overflow-y: auto;\n      padding: 0;\n    }\n    .cedros-gallery-proofing__selected li {\n      align-items: center;\n      display: grid;\n      gap: 12px;\n      grid-template-columns: 64px minmax(0, 1fr);\n    }\n    .cedros-gallery-proofing__selected .cedros-gallery-image {\n      aspect-ratio: 1;\n      height: 64px;\n      min-height: 0;\n      padding: 0;\n    }\n    .cedros-gallery-proofing__selected .cedros-gallery-image--empty {\n      font-size: .625rem;\n      line-height: 1.2;\n    }\n    .cedros-gallery-proofing__selected .cedros-gallery-image--empty small { display: none; }\n    .cedros-gallery-proofing__confirm-actions {\n      display: flex;\n      flex-wrap: wrap;\n      gap: 8px;\n    }\n    .cedros-gallery-button,\n    .cedros-gallery-commerce {\n      align-items: center;\n      background: var(--c1gb4l3-runtime-action-bg, #111);\n      border: 1px solid var(--c1gb4l3-runtime-action-bg, #111);\n      border-radius: var(--c1gb4l3-gallery-radius-control, 6px);\n      color: var(--c1gb4l3-runtime-action-fg, #fff);\n      cursor: pointer;\n      display: inline-flex;\n      font: inherit;\n      font-size: .875rem;\n      font-weight: 600;\n      justify-content: center;\n      min-height: 44px;\n      padding: 8px 12px;\n      text-decoration: none;\n      transition: background-color var(--motion-duration-fast, 160ms) var(--motion-ease-standard, cubic-bezier(0.16, 1, 0.3, 1)),\n        border-color var(--motion-duration-fast, 160ms) var(--motion-ease-standard, cubic-bezier(0.16, 1, 0.3, 1)),\n        color var(--motion-duration-fast, 160ms) var(--motion-ease-standard, cubic-bezier(0.16, 1, 0.3, 1));\n    }\n    .cedros-gallery-button:not(:disabled):hover,\n    .cedros-gallery-commerce:not(.cedros-gallery-commerce--disabled):hover {\n      background: color-mix(in srgb, var(--c1gb4l3-runtime-action-bg, #111) 88%, var(--c1gb4l3-runtime-action-fg, #fff));\n    }\n    .cedros-gallery-button:not(:disabled):active,\n    .cedros-gallery-commerce:not(.cedros-gallery-commerce--disabled):active,\n    .cedros-gallery-icon-button:not(:disabled):active {\n      transform: scale(.98);\n    }\n    .cedros-gallery-field :disabled { cursor: not-allowed; opacity: .55; }\n    .cedros-gallery-button--ghost:not(:disabled):hover,\n    .cedros-gallery-icon-button:not(:disabled):hover {\n      background: var(--c1gb4l3-runtime-accent-soft, rgba(127,127,127,.12));\n    }\n    .cedros-gallery-icon-button:disabled,\n    .cedros-gallery-button:disabled,\n    .cedros-gallery-commerce--disabled {\n      cursor: not-allowed;\n      opacity: .55;\n    }\n    .cedros-gallery-button--ghost {\n      background: transparent;\n      border-color: var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      color: var(--c1gb4l3-runtime-text, inherit);\n    }\n    .cedros-gallery-button--active,\n    .cedros-gallery-button--active:not(:disabled):hover {\n      background: var(--c1gb4l3-runtime-accent-soft, rgba(127,127,127,.18));\n      border-color: var(--c1gb4l3-runtime-accent, currentColor);\n      color: var(--c1gb4l3-runtime-text, inherit);\n    }\n    .cedros-gallery-field input:focus-visible,\n    .cedros-gallery-field select:focus-visible,\n    .cedros-gallery-field textarea:focus-visible,\n    .cedros-gallery-album-card > a:focus-visible,\n    .cedros-gallery-button:focus-visible,\n    .cedros-gallery-commerce:focus-visible,\n    .cedros-gallery-icon-button:focus-visible,\n    .cedros-gallery-media-button:focus-visible,\n    .cedros-gallery-carousel__dot:focus-visible,\n    .cedros-gallery-lightbox__thumbnail:focus-visible,\n    .cedros-gallery-lightbox__panel:focus-visible,\n    .cedros-gallery-proofing__confirm:focus-visible {\n      outline: 2px solid var(--c1gb4l3-runtime-accent, currentColor);\n      outline-offset: 3px;\n    }\n    .cedros-gallery-button.cedros-gallery-button--quiet {\n      background: transparent;\n      border-color: transparent;\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n    }\n    .cedros-gallery-button--quiet:not(:disabled):hover,\n    .cedros-gallery-button--quiet:not(:disabled)[aria-pressed=\"true\"] {\n      background: var(--c1gb4l3-runtime-accent-soft, transparent);\n      color: var(--c1gb4l3-runtime-text, inherit);\n    }\n    .cedros-gallery-media-button:focus-visible,\n    .cedros-gallery-album-card > a:focus-visible,\n    .cedros-gallery-lightbox__thumbnail:focus-visible {\n      outline-offset: -3px;\n    }\n    .cedros-gallery-lightbox__thumbnails:has(:focus-visible) { mask-image: none; }\n    .cedros-gallery-pages {\n      display: grid;\n    }\n    .cedros-gallery-pages__page {\n      grid-area: 1 / 1;\n      min-width: 0;\n    }\n    .cedros-gallery-items {\n      display: grid;\n      gap: var(--c1gb4l3-gallery-gap, 16px);\n    }\n    .cedros-gallery-block--virtualized .cedros-gallery-items:not(.cedros-gallery-items--masonry) > .cedros-gallery-item {\n      contain-intrinsic-size: auto var(--c1gb4l3-gallery-intrinsic-height, 320px);\n      content-visibility: auto;\n    }\n    .cedros-gallery-items--grid,\n    .cedros-gallery-items--mosaic,\n    .cedros-gallery-items--featured-thumbnails,\n    .cedros-gallery-items--product,\n    .cedros-gallery-items--album-cover-grid {\n      grid-template-columns: repeat(var(--c1gb4l3-gallery-columns, 3), minmax(0, 1fr));\n    }\n    .cedros-gallery-items--mosaic > .cedros-gallery-item:first-child {\n      display: flex;\n      flex-direction: column;\n      grid-column: span var(--c1gb4l3-gallery-mosaic-span, 2);\n      grid-row: span 2;\n    }\n    .cedros-gallery-items--mosaic > .cedros-gallery-item:first-child > .cedros-gallery-media-button {\n      aspect-ratio: auto;\n      flex: 1;\n      min-height: 240px;\n    }\n    .cedros-gallery-items--masonry {\n      column-count: var(--c1gb4l3-gallery-columns, 3);\n      column-gap: var(--c1gb4l3-gallery-gap, 16px);\n      display: block;\n    }\n    .cedros-gallery-items--masonry .cedros-gallery-item {\n      break-inside: avoid;\n      margin: 0 0 var(--c1gb4l3-gallery-gap, 16px);\n    }\n    .cedros-gallery-items--masonry:has(> .cedros-gallery-item:only-child) {\n      column-count: 1;\n      max-width: min(100%, 640px);\n    }\n    .cedros-gallery-items--grid:has(> .cedros-gallery-item:only-child),\n    .cedros-gallery-items--product:has(> .cedros-gallery-item:only-child),\n    .cedros-gallery-items--album-cover-grid:has(> .cedros-gallery-item:only-child) {\n      grid-template-columns: minmax(0, 1fr);\n      max-width: min(100%, 640px);\n    }\n    .cedros-gallery-carousel {\n      --c1gb4l3-gallery-slides-current: var(--c1gb4l3-gallery-slides-desktop, 1);\n      container-type: inline-size;\n      display: grid;\n      gap: 12px;\n      min-width: 0;\n      position: relative;\n    }\n    .cedros-gallery-carousel__viewport {\n      min-width: 0;\n      overflow-x: auto;\n      overscroll-behavior-inline: contain;\n      scrollbar-width: thin;\n      scroll-snap-type: x mandatory;\n    }\n    .cedros-gallery-carousel::before,\n    .cedros-gallery-carousel::after {\n      content: \"\";\n      inset: 0 auto 64px;\n      opacity: 0;\n      pointer-events: none;\n      position: absolute;\n      transition: opacity var(--motion-duration-fast, 160ms) var(--motion-ease-standard, cubic-bezier(0.16, 1, 0.3, 1));\n      width: 36px;\n      z-index: 2;\n    }\n    .cedros-gallery-carousel::before {\n      background: linear-gradient(90deg, var(--c1gb4l3-runtime-bg, #fff), transparent);\n      left: 0;\n    }\n    .cedros-gallery-carousel::after {\n      background: linear-gradient(270deg, var(--c1gb4l3-runtime-bg, #fff), transparent);\n      right: 0;\n    }\n    .cedros-gallery-carousel:has(.cedros-gallery-carousel__viewport:not(.is-at-start))::before,\n    .cedros-gallery-carousel:has(.cedros-gallery-carousel__viewport:not(.is-at-end))::after {\n      opacity: 1;\n    }\n    .cedros-gallery-carousel__viewport:focus-visible {\n      border-radius: var(--c1gb4l3-gallery-radius-control, 6px);\n      outline: 2px solid var(--c1gb4l3-runtime-accent, currentColor);\n      outline-offset: 3px;\n    }\n    .cedros-gallery-items--justified,\n    .cedros-gallery-items--filmstrip,\n    .cedros-gallery-items--horizontal-scroll,\n    .cedros-gallery-items--carousel,\n    .cedros-gallery-items--fullscreen-slideshow,\n    .cedros-gallery-items--slider {\n      display: flex;\n      padding-bottom: 8px;\n      width: max-content;\n    }\n    .cedros-gallery-items--justified .cedros-gallery-item,\n    .cedros-gallery-items--filmstrip .cedros-gallery-item,\n    .cedros-gallery-items--horizontal-scroll .cedros-gallery-item,\n    .cedros-gallery-items--carousel .cedros-gallery-item,\n    .cedros-gallery-items--fullscreen-slideshow .cedros-gallery-item,\n    .cedros-gallery-items--slider .cedros-gallery-item {\n      flex: 0 0 min(82cqw, calc((100cqw - (var(--c1gb4l3-gallery-gap, 16px) * (var(--c1gb4l3-gallery-slides-current) - 1))) / var(--c1gb4l3-gallery-slides-current)));\n      scroll-snap-align: start;\n      scroll-snap-stop: always;\n      transition: opacity var(--c1gb4l3-gallery-carousel-duration, 350ms) var(--motion-ease-standard, cubic-bezier(0.16, 1, 0.3, 1)),\n        filter var(--c1gb4l3-gallery-carousel-duration, 350ms) var(--motion-ease-standard, cubic-bezier(0.16, 1, 0.3, 1)),\n        transform var(--c1gb4l3-gallery-carousel-duration, 350ms) var(--motion-ease-standard, cubic-bezier(0.16, 1, 0.3, 1));\n    }\n    .cedros-gallery-items--fullscreen-slideshow .cedros-gallery-item {\n      flex-basis: 100cqw;\n    }\n    .cedros-gallery-items--fullscreen-slideshow .cedros-gallery-media-button {\n      aspect-ratio: auto;\n      height: clamp(240px, 60svh, 720px);\n    }\n    @container (max-width: 760px) {\n      .cedros-gallery-items--fullscreen-slideshow .cedros-gallery-media-button { height: clamp(240px, 35svh, 400px); }\n    }\n    @media (max-width: 760px) {\n      .cedros-gallery-items--fullscreen-slideshow .cedros-gallery-media-button { height: clamp(240px, 35svh, 400px); }\n    }\n    .cedros-gallery-carousel--center .cedros-gallery-carousel__viewport {\n      scroll-padding-inline: max(0px, calc((100% - min(82vw, 360px)) / 2));\n    }\n    .cedros-gallery-carousel--fade .cedros-gallery-item.is-carousel-inactive {\n      opacity: .55;\n    }\n    .cedros-gallery-carousel--zoom .cedros-gallery-item.is-carousel-inactive {\n      opacity: .72;\n      transform: scale(.96);\n    }\n    .cedros-gallery-carousel--coverflow .cedros-gallery-item.is-carousel-inactive {\n      filter: saturate(.78);\n      opacity: .68;\n      transform: perspective(900px) rotateY(-4deg) scale(.94);\n    }\n    .cedros-gallery-carousel__arrows {\n      display: flex;\n      gap: 8px;\n      justify-content: flex-end;\n    }\n    .cedros-gallery-carousel__nav {\n      display: flex;\n      flex-wrap: wrap;\n      gap: 8px;\n      justify-content: center;\n    }\n    .cedros-gallery-carousel__dot {\n      background: transparent;\n      border: 0;\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      cursor: pointer;\n      display: grid;\n      height: 44px;\n      padding: 0;\n      place-items: center;\n      width: 44px;\n    }\n    .cedros-gallery-carousel__dot::before {\n      background: currentColor;\n      border-radius: 999px;\n      content: \"\";\n      height: 8px;\n      width: 8px;\n    }\n    .cedros-gallery-carousel__dot[aria-pressed=\"true\"] {\n      color: var(--c1gb4l3-runtime-text, inherit);\n    }\n    .cedros-gallery-carousel__dot[aria-pressed=\"true\"]::before {\n      transform: scale(1.25);\n    }\n    .cedros-gallery-carousel__nav--thumbnails .cedros-gallery-carousel__dot {\n      align-items: center;\n      display: inline-flex;\n      font-size: .75rem;\n      height: 44px;\n      justify-content: center;\n      width: 44px;\n    }\n    .cedros-gallery-carousel__nav--thumbnails .cedros-gallery-carousel__dot::before {\n      display: none;\n    }\n    .cedros-gallery-items--vertical-stack,\n    .cedros-gallery-items--story {\n      grid-template-columns: 1fr;\n    }\n    .cedros-gallery-items--story {\n      margin-inline: auto;\n      max-width: 48rem;\n      width: 100%;\n    }\n    .cedros-gallery-items--featured-thumbnails > .cedros-gallery-item:first-child {\n      grid-column: 1 / -1;\n    }\n    .cedros-gallery-items--featured-thumbnails > .cedros-gallery-item:first-child > .cedros-gallery-media-button {\n      aspect-ratio: auto;\n      height: clamp(240px, 45svh, 560px);\n    }\n    .cedros-gallery-items--before-after {\n      grid-template-columns: repeat(2, minmax(0, 1fr));\n    }\n    .cedros-gallery-item,\n    .cedros-gallery-album-card {\n      background: var(--c1gb4l3-runtime-panel, transparent);\n      border: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      border-radius: var(--c1gb4l3-gallery-radius-card, 8px);\n      overflow: hidden;\n      transform-origin: center bottom;\n    }\n    .cedros-gallery-item--border-none {\n      border-color: transparent;\n    }\n    .cedros-gallery-item--border-hairline {\n      border-color: color-mix(in srgb, var(--c1gb4l3-runtime-border, currentColor) 58%, transparent);\n    }\n    .cedros-gallery-item--border-solid {\n      border-color: var(--c1gb4l3-runtime-border, rgba(127,127,127,.4));\n    }\n    .cedros-gallery-item--shadow-subtle {\n      box-shadow: 0 8px 24px color-mix(in srgb, var(--c1gb4l3-runtime-text, #111) 8%, transparent);\n    }\n    .cedros-gallery-item--shadow-raised {\n      box-shadow: 0 18px 44px color-mix(in srgb, var(--c1gb4l3-runtime-text, #111) 14%, transparent);\n    }\n    .cedros-gallery-media-button {\n      aspect-ratio: 4 / 3;\n      background: var(--c1gb4l3-runtime-accent-soft, rgba(127,127,127,.12));\n      border: 0;\n      color: inherit;\n      cursor: zoom-in;\n      display: block;\n      font: inherit;\n      padding: 0;\n      position: relative;\n      width: 100%;\n    }\n    .cedros-gallery-image {\n      display: block;\n      height: 100%;\n      object-fit: cover;\n      transition: filter var(--c1gb4l3-gallery-hover-duration, 180ms) var(--motion-ease-standard, cubic-bezier(0.16, 1, 0.3, 1)),\n        transform var(--c1gb4l3-gallery-hover-duration, 180ms) var(--motion-ease-standard, cubic-bezier(0.16, 1, 0.3, 1));\n      width: 100%;\n    }\n    .cedros-gallery-image--empty,\n    .cedros-gallery-comparison__empty,\n    .cedros-gallery-album-card__cover {\n      align-items: center;\n      background: var(--c1gb4l3-runtime-panel, #fff);\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      display: flex;\n      flex-direction: column;\n      gap: 8px;\n      justify-content: center;\n      min-height: 180px;\n      padding: 16px;\n      text-align: center;\n    }\n    .cedros-gallery-missing-media-icon {\n      flex: none;\n      height: 28px;\n      opacity: .6;\n      width: 28px;\n    }\n    .cedros-gallery-proofing__selected .cedros-gallery-missing-media-icon { display: none; }\n    .cedros-gallery-item__body,\n    .cedros-gallery-album-card__body {\n      display: grid;\n      gap: 12px;\n      padding: var(--c1gb4l3-gallery-card-padding, 14px);\n    }\n    .cedros-gallery-item__body,\n    .cedros-gallery-item__title,\n    .cedros-gallery-caption,\n    .cedros-gallery-badges {\n      transition: opacity var(--c1gb4l3-gallery-hover-duration, 180ms) var(--motion-ease-standard, cubic-bezier(0.16, 1, 0.3, 1)),\n        transform var(--c1gb4l3-gallery-hover-duration, 180ms) var(--motion-ease-standard, cubic-bezier(0.16, 1, 0.3, 1));\n    }\n    .cedros-gallery-item__title-row {\n      align-items: stretch;\n      display: flex;\n      flex-direction: column;\n      gap: 8px;\n    }\n    .cedros-gallery-item__title,\n    .cedros-gallery-album-card__title {\n      font: inherit;\n      font-size: 1rem;\n      font-weight: 600;\n      line-height: 1.2;\n      margin: 0;\n    }\n    .cedros-gallery-item__title--preview > a,\n    .cedros-gallery-item__title--preview > button,\n    .cedros-gallery-album-card__title--preview {\n      display: -webkit-box;\n      -webkit-box-orient: vertical;\n      -webkit-line-clamp: 3;\n      overflow: hidden;\n    }\n    .cedros-gallery-item__title a {\n      color: inherit;\n    }\n    .cedros-gallery-caption,\n    .cedros-gallery-album-card p {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      margin: 0;\n    }\n    .cedros-gallery-empty {\n      align-items: start;\n      border-block: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      display: grid;\n      gap: 8px;\n      margin: 0;\n      padding: 32px 0;\n    }\n    .cedros-gallery-empty strong {\n      color: var(--c1gb4l3-runtime-text, inherit);\n    }\n    .cedros-gallery-empty p { margin: 0; }\n    .cedros-gallery-empty .cedros-gallery-button { justify-self: start; }\n    .cedros-gallery-pagination {\n      align-items: center;\n      display: flex;\n      gap: 12px;\n      justify-content: center;\n      flex-wrap: wrap;\n    }\n    .cedros-gallery-pagination p {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      margin: 0;\n    }\n    .cedros-gallery-badges,\n    .cedros-gallery-item__actions,\n    .cedros-gallery-lightbox__nav {\n      display: flex;\n      flex-wrap: wrap;\n      gap: 8px;\n    }\n    .cedros-gallery-item__actions {\n      transition: opacity var(--c1gb4l3-gallery-hover-duration, 180ms) var(--motion-ease-standard, cubic-bezier(0.16, 1, 0.3, 1)),\n        transform var(--c1gb4l3-gallery-hover-duration, 180ms) var(--motion-ease-standard, cubic-bezier(0.16, 1, 0.3, 1));\n    }\n    @media (hover: hover) and (pointer: fine) {\n      .cedros-gallery-item--hover-slide-caption:not(:hover):not(:focus-within) .cedros-gallery-item__body {\n        transform: translateY(5px);\n      }\n      .cedros-gallery-item--hover-reveal-title:not(:hover):not(:focus-within) .cedros-gallery-item__title,\n      .cedros-gallery-item--hover-reveal-metadata:not(:hover):not(:focus-within) .cedros-gallery-caption,\n      .cedros-gallery-item--hover-reveal-metadata:not(:hover):not(:focus-within) .cedros-gallery-badges {\n        opacity: .45;\n        transform: translateY(3px);\n      }\n    }\n    .cedros-gallery-item--hover-grayscale-to-color:not(:hover):not(:focus-within) .cedros-gallery-image {\n      filter: grayscale(1);\n    }\n    .cedros-gallery-item--hover-color-to-grayscale:hover .cedros-gallery-image,\n    .cedros-gallery-item--hover-color-to-grayscale:focus-within .cedros-gallery-image {\n      filter: grayscale(1);\n    }\n    .cedros-gallery-item--hover-blur:hover .cedros-gallery-image,\n    .cedros-gallery-item--hover-blur:focus-within .cedros-gallery-image {\n      filter: blur(1.5px);\n      transform: scale(1.015);\n    }\n    .cedros-gallery-item--hover-fade-overlay:hover .cedros-gallery-image,\n    .cedros-gallery-item--hover-fade-overlay:focus-within .cedros-gallery-image {\n      filter: brightness(.82);\n    }\n    .cedros-gallery-item__title-row > .cedros-gallery-badges {\n      flex: 0 0 auto;\n      justify-content: flex-start;\n      max-width: 100%;\n    }\n    .cedros-gallery-badges span {\n      background: var(--c1gb4l3-runtime-accent-soft, rgba(127,127,127,.12));\n      border-radius: 999px;\n      font-variant-numeric: tabular-nums;\n      max-width: 100%;\n      overflow-wrap: anywhere;\n      white-space: normal;\n      color: var(--c1gb4l3-runtime-text, inherit);\n      font-size: .75rem;\n      padding: 4px 8px;\n    }\n    .cedros-gallery-lightbox {\n      inset: 0;\n      position: fixed;\n      z-index: var(--z-modal, 1000);\n    }\n    .cedros-gallery-lightbox__backdrop {\n      background: rgba(0,0,0,.72);\n      border: 0;\n      inset: 0;\n      position: absolute;\n      width: 100%;\n    }\n    .cedros-gallery-lightbox__panel {\n      background: var(--c1gb4l3-runtime-panel, #fff);\n      border: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      border-radius: var(--c1gb4l3-gallery-radius-panel, 12px);\n      color: var(--c1gb4l3-runtime-text, #111);\n      display: grid;\n      grid-template-columns: minmax(0, 1fr) minmax(280px, 360px);\n      grid-template-rows: minmax(0, 1fr) auto;\n      inset: 24px;\n      overflow: hidden;\n      position: absolute;\n    }\n    .cedros-gallery-lightbox__panel.is-fullscreen {\n      border-radius: 0;\n      inset: 0;\n    }\n    .cedros-gallery-lightbox__media {\n      background: var(--c1gb4l3-gallery-stage, #0a0a0a);\n      min-height: 320px;\n      overflow: hidden;\n      position: relative;\n    }\n    .cedros-gallery-lightbox__media .cedros-gallery-image--empty {\n      background: var(--c1gb4l3-runtime-panel, #fff);\n      color: var(--c1gb4l3-runtime-muted, #525252);\n    }\n    .cedros-gallery-lightbox__media-step {\n      height: 100%;\n      inset: 0;\n      position: absolute;\n      width: 100%;\n    }\n    .cedros-gallery-lightbox__media-step > div {\n      height: 100%;\n      width: 100%;\n    }\n    .cedros-gallery-lightbox__media-step .is-zoomed {\n      cursor: grab;\n      touch-action: none;\n    }\n    .cedros-gallery-lightbox__media-step .is-zoomed:active {\n      cursor: grabbing;\n    }\n    .cedros-gallery-lightbox__media .cedros-gallery-image {\n      object-fit: contain;\n    }\n    .cedros-gallery-lightbox__details {\n      align-content: start;\n      display: grid;\n      gap: 16px;\n      overflow: auto;\n      overflow-wrap: anywhere;\n      padding: 16px;\n    }\n    .cedros-gallery-icon-button.cedros-gallery-lightbox__close {\n      background: var(--c1gb4l3-runtime-panel, #fff);\n      position: absolute;\n      right: 12px;\n      top: 12px;\n      z-index: 3;\n    }\n    .cedros-gallery-lightbox__toolbar {\n      align-items: center;\n      display: flex;\n      flex-wrap: wrap;\n      gap: 8px 12px;\n      padding-right: 48px;\n    }\n    .cedros-gallery-caption-region { display: grid; gap: 8px; }\n    .cedros-gallery-caption--summary {\n      display: -webkit-box;\n      -webkit-box-orient: vertical;\n      -webkit-line-clamp: 3;\n      overflow: hidden;\n    }\n    .cedros-gallery-caption-region__toggle { justify-self: start; }\n    .cedros-gallery-album-card__count { font-size: .8125rem; font-variant-numeric: tabular-nums; }\n    .cedros-gallery-lightbox__details p { margin: 0; }\n    .cedros-gallery-lightbox__details h2 {\n      font: inherit;\n      font-size: 1.25rem;\n      font-weight: 700;\n      margin: 0;\n    }\n    .cedros-gallery-lightbox__identity { padding-inline-end: 48px; }\n    .cedros-gallery-lightbox__utilities { border-top: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28)); padding-top: 12px; }\n    .cedros-gallery-lightbox__utilities:empty { display: none; }\n    .cedros-gallery-lightbox__more summary {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      cursor: pointer;\n      min-height: 44px;\n      padding-block: 12px;\n    }\n    .cedros-gallery-lightbox__more summary:focus-visible {\n      outline: 2px solid var(--c1gb4l3-runtime-accent, currentColor);\n      outline-offset: 3px;\n    }\n    .cedros-gallery-lightbox__counter {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      font-size: .8125rem;\n      margin: 0;\n    }\n    .cedros-gallery-lightbox__metadata {\n      display: grid;\n      gap: 8px;\n      margin: 0;\n    }\n    .cedros-gallery-lightbox__metadata div {\n      display: flex;\n      gap: 12px;\n      justify-content: space-between;\n    }\n    .cedros-gallery-lightbox__metadata dt {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n    }\n    .cedros-gallery-lightbox__metadata dd {\n      margin: 0;\n      text-align: right;\n    }\n    .cedros-gallery-lightbox__thumbnails {\n      grid-column: 1 / -1;\n      mask-image: linear-gradient(\n        90deg,\n        transparent 0,\n        #000 var(--c1gb4l3-gallery-thumbnail-fade-start, 32px),\n        #000 calc(100% - var(--c1gb4l3-gallery-thumbnail-fade-end, 32px)),\n        transparent 100%\n      );\n      overflow-x: auto;\n      overscroll-behavior-inline: contain;\n      padding: 8px;\n      scroll-snap-type: x mandatory;\n    }\n    .cedros-gallery-lightbox__thumbnails.is-at-start {\n      --c1gb4l3-gallery-thumbnail-fade-start: 0px;\n    }\n    .cedros-gallery-lightbox__thumbnails.is-at-end {\n      --c1gb4l3-gallery-thumbnail-fade-end: 0px;\n    }\n    .cedros-gallery-lightbox__thumbnail-track {\n      display: flex;\n      gap: 8px;\n      width: max-content;\n    }\n    .cedros-gallery-lightbox__thumbnail {\n      background: var(--c1gb4l3-gallery-stage, #0a0a0a);\n      border: 2px solid transparent;\n      border-radius: var(--c1gb4l3-gallery-radius-control, 6px);\n      height: 54px;\n      overflow: hidden;\n      padding: 0;\n      scroll-snap-align: center;\n      width: 72px;\n    }\n    .cedros-gallery-lightbox__thumbnail[aria-current=\"true\"] {\n      border-color: var(--c1gb4l3-runtime-accent, currentColor);\n    }\n    .cedros-gallery-lightbox__thumbnail .cedros-gallery-image {\n      object-fit: cover;\n    }\n    .cedros-gallery-icon-button {\n      align-items: center;\n      display: inline-flex;\n      justify-content: center;\n      font: inherit;\n      background: transparent;\n      border: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      border-radius: var(--c1gb4l3-gallery-radius-control, 6px);\n      color: inherit;\n      justify-self: end;\n      cursor: pointer;\n      min-height: 44px;\n      min-width: 44px;\n    }\n    .cedros-gallery-album {\n      --c1gb4l3-gallery-card-padding: 16px;\n${baselineRadius}\n      box-sizing: border-box;\n      color: var(--c1gb4l3-runtime-text, inherit);\n      display: grid;\n      gap: 24px;\n      max-width: 100%;\n      min-width: 0;\n      container-type: inline-size;\n      overflow-wrap: anywhere;\n    }\n    .cedros-gallery-album__grid {\n      display: grid;\n      gap: 16px;\n      grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));\n    }\n    .cedros-gallery-album__grid:has(> .cedros-gallery-album-card:only-child) {\n      grid-template-columns: minmax(0, 1fr);\n      max-width: min(100%, 640px);\n    }\n    .cedros-gallery-album--masonry .cedros-gallery-album__grid {\n      columns: 300px;\n      display: block;\n    }\n    .cedros-gallery-album--masonry .cedros-gallery-album-card {\n      break-inside: avoid;\n      margin-bottom: 16px;\n    }\n    .cedros-gallery-album--featured .cedros-gallery-album-card:first-child { grid-column: 1 / -1; }\n    .cedros-gallery-album--featured .cedros-gallery-album-card:first-child .cedros-gallery-album-card__cover {\n      aspect-ratio: auto;\n      height: clamp(240px, 40svh, 480px);\n    }\n    .cedros-gallery-album--list .cedros-gallery-album__grid {\n      grid-template-columns: minmax(0, 1fr);\n      max-width: 100%;\n    }\n    .cedros-gallery-album--list .cedros-gallery-album-card { min-height: 9rem; position: relative; }\n    .cedros-gallery-album--list .cedros-gallery-album-card__main { padding-inline-start: 12rem; }\n    .cedros-gallery-album--list .cedros-gallery-album-card__cover {\n      aspect-ratio: auto;\n      bottom: 0;\n      height: 100%;\n      inset-inline-start: 0;\n      position: absolute;\n      top: 0;\n      width: 12rem;\n    }\n    .cedros-gallery-album--list .cedros-gallery-album-card__description {\n      padding-inline-start: calc(12rem + var(--c1gb4l3-gallery-card-padding, 16px));\n    }\n    .cedros-gallery-album__carousel { display: grid; gap: 12px; min-width: 0; }\n    .cedros-gallery-album--carousel .cedros-gallery-album__grid {\n      align-items: start;\n      display: grid;\n      grid-auto-columns: min(85%, 400px);\n      grid-auto-flow: column;\n      grid-template-columns: none;\n      max-width: 100%;\n      overflow-x: auto;\n      overscroll-behavior-inline: contain;\n      padding-bottom: 8px;\n      scroll-snap-type: x mandatory;\n    }\n    .cedros-gallery-album--carousel .cedros-gallery-album-card { scroll-snap-align: start; }\n    .cedros-gallery-album__navigation { display: flex; flex-wrap: wrap; gap: 8px; justify-content: flex-end; }\n    @container (max-width: 32rem) {\n      .cedros-gallery-album--list .cedros-gallery-album-card__main { padding-inline-start: 0; }\n      .cedros-gallery-album--list .cedros-gallery-album-card__cover { aspect-ratio: 4 / 3; height: auto; position: static; width: auto; }\n      .cedros-gallery-album--list .cedros-gallery-album-card__description { padding-inline-start: var(--c1gb4l3-gallery-card-padding, 16px); }\n    }\n    .cedros-gallery-album-card__main {\n      color: inherit;\n      display: block;\n      text-decoration: none;\n    }\n    .cedros-gallery-album-card__description {\n      padding: 0 var(--c1gb4l3-gallery-card-padding, 16px) var(--c1gb4l3-gallery-card-padding, 16px);\n    }\n    .cedros-gallery-album-card__cover {\n      aspect-ratio: 4 / 3;\n      min-height: 0;\n      padding: 0;\n      overflow: hidden;\n    }\n    .cedros-gallery-album-card__cover img {\n      display: block;\n      height: 100%;\n      object-fit: cover;\n      width: 100%;\n    }\n    .cedros-gallery-comparison {\n${baselineRadius}\n      box-sizing: border-box;\n      color: var(--c1gb4l3-runtime-text, inherit);\n      display: grid;\n      gap: 16px;\n      max-width: 100%;\n      min-width: 0;\n      container-type: inline-size;\n      overflow-wrap: anywhere;\n    }\n    .cedros-gallery-comparison__stage {\n      aspect-ratio: 16 / 9;\n      background: var(--c1gb4l3-runtime-accent-soft, rgba(127,127,127,.12));\n      border: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      border-radius: var(--c1gb4l3-gallery-radius-card, 8px);\n      cursor: ew-resize;\n      overflow: hidden;\n      position: relative;\n      touch-action: none;\n    }\n    .cedros-gallery-comparison__stage img {\n      display: block;\n      height: 100%;\n      object-fit: cover;\n      width: 100%;\n    }\n    .cedros-gallery-comparison__after {\n      clip-path: inset(0 0 0 var(--c1gb4l3-gallery-split, 50%));\n      inset: 0;\n      position: absolute;\n    }\n    .cedros-gallery-comparison--vertical .cedros-gallery-comparison__stage {\n      cursor: ns-resize;\n    }\n    .cedros-gallery-comparison--vertical .cedros-gallery-comparison__after {\n      clip-path: inset(var(--c1gb4l3-gallery-split, 50%) 0 0 0);\n    }\n    .cedros-gallery-comparison__divider {\n      background: var(--c1gb4l3-runtime-panel, #fff);\n      box-shadow: 0 0 0 1px color-mix(in srgb, var(--c1gb4l3-runtime-text, #111) 16%, transparent);\n      bottom: 0;\n      left: var(--c1gb4l3-gallery-split, 50%);\n      pointer-events: none;\n      position: absolute;\n      top: 0;\n      width: 2px;\n      z-index: 2;\n    }\n    .cedros-gallery-comparison__divider::after {\n      background: var(--c1gb4l3-runtime-action-bg, #111);\n      border: 1px solid var(--c1gb4l3-runtime-action-fg, #fff);\n      border-radius: 999px;\n      content: \"\\u2194\";\n      color: var(--c1gb4l3-runtime-action-fg, #fff);\n      display: grid;\n      font-size: 12px;\n      height: 32px;\n      left: 50%;\n      place-items: center;\n      position: absolute;\n      top: 50%;\n      transform: translate(-50%, -50%);\n      width: 32px;\n    }\n    .cedros-gallery-comparison--vertical .cedros-gallery-comparison__divider {\n      bottom: auto;\n      height: 2px;\n      left: 0;\n      right: 0;\n      top: var(--c1gb4l3-gallery-split, 50%);\n      width: auto;\n    }\n    .cedros-gallery-comparison--vertical .cedros-gallery-comparison__divider::after {\n      content: \"\\u2195\";\n      left: 50%;\n      top: 50%;\n    }\n    .cedros-gallery-comparison__labels {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      display: grid;\n      font-size: .875em;\n      gap: 16px;\n      grid-template-columns: repeat(2, minmax(0, 1fr));\n    }\n    .cedros-gallery-comparison__labels span {\n      overflow-wrap: anywhere;\n    }\n    .cedros-gallery-comparison__labels span:last-child {\n      text-align: right;\n    }\n    .cedros-gallery-field--range input {\n      accent-color: var(--c1gb4l3-runtime-accent, currentColor);\n      padding-left: 0;\n      padding-right: 0;\n    }\n    @media (max-width: 760px) {\n      .cedros-gallery-block,\n      .cedros-gallery-album,\n      .cedros-gallery-comparison {\n        width: 100%;\n      }\n      .cedros-gallery-button,\n      .cedros-gallery-commerce,\n      .cedros-gallery-icon-button {\n        min-height: 44px;\n      }\n      .cedros-gallery-carousel {\n        --c1gb4l3-gallery-slides-current: var(--c1gb4l3-gallery-slides-mobile, 1);\n      }\n      .cedros-gallery-header,\n      .cedros-gallery-item__title-row {\n        align-items: stretch;\n        flex-direction: column;\n      }\n      .cedros-gallery-item__title-row > .cedros-gallery-badges {\n        justify-content: flex-start;\n        max-width: none;\n      }\n      .cedros-gallery-submission__history-item {\n        grid-template-columns: 1fr;\n      }\n      .cedros-gallery-submission__history-item > p {\n        grid-column: auto;\n      }\n      .cedros-gallery-stats {\n        justify-content: flex-start;\n      }\n      .cedros-gallery-access {\n        align-items: stretch;\n        grid-template-columns: 1fr;\n      }\n      .cedros-gallery-toolbar__primary {\n        display: grid;\n        grid-template-columns: repeat(2, minmax(0, 1fr));\n      }\n      .cedros-gallery-field--search {\n        grid-column: 1 / -1;\n      }\n      .cedros-gallery-toolbar .cedros-gallery-toolbar__toggle {\n        display: inline-flex;\n      }\n      .cedros-gallery-toolbar__disclosure {\n        grid-template-rows: 0fr;\n      }\n      .cedros-gallery-toolbar.is-expanded .cedros-gallery-toolbar__disclosure {\n        grid-template-rows: 1fr;\n      }\n      .cedros-gallery-toolbar__advanced {\n        grid-template-columns: 1fr;\n      }\n      .cedros-gallery-items--before-after,\n      .cedros-gallery-items--grid,\n      .cedros-gallery-items--mosaic,\n      .cedros-gallery-items--featured-thumbnails,\n      .cedros-gallery-items--product,\n      .cedros-gallery-items--album-cover-grid {\n        grid-template-columns: 1fr;\n      }\n      .cedros-gallery-items--masonry {\n        column-count: 1;\n      }\n      .cedros-gallery-items--mosaic > .cedros-gallery-item:first-child {\n        grid-column: auto;\n        grid-row: auto;\n      }\n      .cedros-gallery-items--mosaic > .cedros-gallery-item:first-child > .cedros-gallery-media-button {\n        aspect-ratio: 4 / 3;\n        min-height: 0;\n      }\n      .cedros-gallery-lightbox__panel {\n        grid-template-columns: 1fr;\n        grid-template-rows: minmax(0, 45dvh) minmax(0, 1fr) auto;\n        inset: 8px;\n      }\n      .cedros-gallery-lightbox__panel.is-fullscreen {\n        inset: 0;\n      }\n      .cedros-gallery-lightbox__media {\n        min-height: 0;\n      }\n      .cedros-gallery-lightbox__details {\n        padding: 12px;\n      }\n      .cedros-gallery-lightbox__toolbar { padding-right: 0; }\n      .cedros-gallery-lightbox__metadata div {\n        flex-wrap: wrap;\n      }\n      .cedros-gallery-lightbox__thumbnails {\n        max-width: 100%;\n      }\n    }\n    @media (max-width: 380px) {\n      .cedros-gallery-submission__actions > *,\n      .cedros-gallery-proofing__confirm-actions > * {\n        width: 100%;\n      }\n    }\n    @media (min-width: 761px) and (max-width: 1024px) {\n      .cedros-gallery-carousel {\n        --c1gb4l3-gallery-slides-current: var(--c1gb4l3-gallery-slides-tablet, 2);\n      }\n    }\n    @container (max-width: 760px) {\n      .cedros-gallery-block,\n      .cedros-gallery-album,\n      .cedros-gallery-comparison {\n        width: 100%;\n      }\n      .cedros-gallery-button,\n      .cedros-gallery-commerce,\n      .cedros-gallery-icon-button {\n        min-height: 44px;\n      }\n      .cedros-gallery-carousel {\n        --c1gb4l3-gallery-slides-current: var(--c1gb4l3-gallery-slides-mobile, 1);\n      }\n      .cedros-gallery-header,\n      .cedros-gallery-item__title-row {\n        align-items: stretch;\n        flex-direction: column;\n      }\n      .cedros-gallery-item__title-row > .cedros-gallery-badges {\n        justify-content: flex-start;\n        max-width: none;\n      }\n      .cedros-gallery-submission__history-item {\n        grid-template-columns: 1fr;\n      }\n      .cedros-gallery-submission__history-item > p {\n        grid-column: auto;\n      }\n      .cedros-gallery-stats {\n        justify-content: flex-start;\n      }\n      .cedros-gallery-access {\n        align-items: stretch;\n        grid-template-columns: 1fr;\n      }\n      .cedros-gallery-toolbar__primary {\n        display: grid;\n        grid-template-columns: repeat(2, minmax(0, 1fr));\n      }\n      .cedros-gallery-field--search {\n        grid-column: 1 / -1;\n      }\n      .cedros-gallery-toolbar .cedros-gallery-toolbar__toggle {\n        display: inline-flex;\n      }\n      .cedros-gallery-toolbar__disclosure {\n        grid-template-rows: 0fr;\n      }\n      .cedros-gallery-toolbar.is-expanded .cedros-gallery-toolbar__disclosure {\n        grid-template-rows: 1fr;\n      }\n      .cedros-gallery-toolbar__advanced {\n        grid-template-columns: 1fr;\n      }\n      .cedros-gallery-items--before-after,\n      .cedros-gallery-items--grid,\n      .cedros-gallery-items--mosaic,\n      .cedros-gallery-items--featured-thumbnails,\n      .cedros-gallery-items--product,\n      .cedros-gallery-items--album-cover-grid {\n        grid-template-columns: 1fr;\n      }\n      .cedros-gallery-items--masonry {\n        column-count: 1;\n      }\n      .cedros-gallery-items--mosaic > .cedros-gallery-item:first-child {\n        grid-column: auto;\n        grid-row: auto;\n      }\n      .cedros-gallery-items--mosaic > .cedros-gallery-item:first-child > .cedros-gallery-media-button {\n        aspect-ratio: 4 / 3;\n        min-height: 0;\n      }\n    }\n    @container (max-width: 380px) {\n      .cedros-gallery-submission__actions > *,\n      .cedros-gallery-proofing__confirm-actions > * {\n        width: 100%;\n      }\n    }\n    @container (min-width: 761px) and (max-width: 1024px) {\n      .cedros-gallery-carousel {\n        --c1gb4l3-gallery-slides-current: var(--c1gb4l3-gallery-slides-tablet, 2);\n      }\n    }\n    @media (prefers-reduced-motion: reduce) {\n      ${reducedMotionSelectors} {\n        animation-delay: 0ms !important;\n        animation-duration: .01ms !important;\n        animation-iteration-count: 1 !important;\n        scroll-behavior: auto !important;\n        transition-delay: 0ms !important;\n        transition-duration: .01ms !important;\n      }\n    }\n  `;\n  document.head.appendChild(style);\n}\n\n// src/web/album-block.ts\nimport React7 from \"react\";\n\n// ../../node_modules/framer-motion/dist/es/components/AnimatePresence/index.mjs\nimport { jsx as jsx3, Fragment } from \"react/jsx-runtime\";\nimport { useMemo as useMemo2, useRef as useRef4, useState, useContext as useContext3 } from \"react\";\n\n// ../../node_modules/framer-motion/dist/es/context/LayoutGroupContext.mjs\nimport { createContext } from \"react\";\nvar LayoutGroupContext = createContext({});\n\n// ../../node_modules/framer-motion/dist/es/utils/use-constant.mjs\nimport { useRef } from \"react\";\nfunction useConstant(init) {\n  const ref = useRef(null);\n  if (ref.current === null) {\n    ref.current = init();\n  }\n  return ref.current;\n}\n\n// ../../node_modules/framer-motion/dist/es/utils/use-isomorphic-effect.mjs\nimport { useLayoutEffect, useEffect } from \"react\";\n\n// ../../node_modules/framer-motion/dist/es/utils/is-browser.mjs\nvar isBrowser = typeof window !== \"undefined\";\n\n// ../../node_modules/framer-motion/dist/es/utils/use-isomorphic-effect.mjs\nvar useIsomorphicLayoutEffect = isBrowser ? useLayoutEffect : useEffect;\n\n// ../../node_modules/framer-motion/dist/es/components/AnimatePresence/PresenceChild.mjs\nimport { jsx as jsx2 } from \"react/jsx-runtime\";\nimport * as React3 from \"react\";\nimport { useId as useId2, useRef as useRef3, useMemo } from \"react\";\n\n// ../../node_modules/framer-motion/dist/es/context/PresenceContext.mjs\nimport { createContext as createContext2 } from \"react\";\nvar PresenceContext = /* @__PURE__ */ createContext2(null);\n\n// ../../node_modules/framer-motion/dist/es/components/AnimatePresence/PopChild.mjs\nimport { jsx } from \"react/jsx-runtime\";\n\n// ../../node_modules/motion-utils/dist/es/array.mjs\nfunction addUniqueItem(arr, item) {\n  if (arr.indexOf(item) === -1)\n    arr.push(item);\n}\nfunction removeItem(arr, item) {\n  const index = arr.indexOf(item);\n  if (index > -1)\n    arr.splice(index, 1);\n}\n\n// ../../node_modules/motion-utils/dist/es/clamp.mjs\nvar clamp = (min, max, v) => {\n  if (v > max)\n    return max;\n  if (v < min)\n    return min;\n  return v;\n};\n\n// ../../node_modules/motion-utils/dist/es/errors.mjs\nvar warning2 = () => {\n};\nvar invariant = () => {\n};\nif (false) {\n  warning2 = (check, message, errorCode) => {\n    if (!check && typeof console !== \"undefined\") {\n      console.warn(formatErrorMessage(message, errorCode));\n    }\n  };\n  invariant = (check, message, errorCode) => {\n    if (!check) {\n      throw new Error(formatErrorMessage(message, errorCode));\n    }\n  };\n}\n\n// ../../node_modules/motion-utils/dist/es/global-config.mjs\nvar MotionGlobalConfig = {};\n\n// ../../node_modules/motion-utils/dist/es/is-numerical-string.mjs\nvar isNumericalString = (v) => /^-?(?:\\d+(?:\\.\\d+)?|\\.\\d+)$/u.test(v);\n\n// ../../node_modules/motion-utils/dist/es/is-object.mjs\nvar isObject = (value) => typeof value === \"object\" && value !== null;\n\n// ../../node_modules/motion-utils/dist/es/is-zero-value-string.mjs\nvar isZeroValueString = (v) => /^0[^.\\s]+$/u.test(v);\n\n// ../../node_modules/motion-utils/dist/es/memo.mjs\n// @__NO_SIDE_EFFECTS__\nfunction memo(callback) {\n  let result;\n  return () => {\n    if (result === void 0)\n      result = callback();\n    return result;\n  };\n}\n\n// ../../node_modules/motion-utils/dist/es/noop.mjs\nvar noop = /* @__NO_SIDE_EFFECTS__ */ (any) => any;\n\n// ../../node_modules/motion-utils/dist/es/pipe.mjs\nvar pipe = (...transformers) => transformers.reduce((a, b) => (v) => b(a(v)));\n\n// ../../node_modules/motion-utils/dist/es/progress.mjs\nvar progress = /* @__NO_SIDE_EFFECTS__ */ (from, to, value) => {\n  const range = to - from;\n  return range ? (value - from) / range : 1;\n};\n\n// ../../node_modules/motion-utils/dist/es/subscription-manager.mjs\nvar SubscriptionManager = class {\n  constructor() {\n    this.subscriptions = [];\n  }\n  add(handler) {\n    addUniqueItem(this.subscriptions, handler);\n    return () => removeItem(this.subscriptions, handler);\n  }\n  notify(a, b, c) {\n    const numSubscriptions = this.subscriptions.length;\n    if (!numSubscriptions)\n      return;\n    if (numSubscriptions === 1) {\n      this.subscriptions[0](a, b, c);\n    } else {\n      for (let i = 0; i < numSubscriptions; i++) {\n        const handler = this.subscriptions[i];\n        handler && handler(a, b, c);\n      }\n    }\n  }\n  getSize() {\n    return this.subscriptions.length;\n  }\n  clear() {\n    this.subscriptions.length = 0;\n  }\n};\n\n// ../../node_modules/motion-utils/dist/es/time-conversion.mjs\nvar secondsToMilliseconds = /* @__NO_SIDE_EFFECTS__ */ (seconds) => seconds * 1e3;\nvar millisecondsToSeconds = /* @__NO_SIDE_EFFECTS__ */ (milliseconds) => milliseconds / 1e3;\n\n// ../../node_modules/motion-utils/dist/es/velocity-per-second.mjs\nvar velocityPerSecond = /* @__NO_SIDE_EFFECTS__ */ (velocity, frameDuration) => frameDuration ? velocity * (1e3 / frameDuration) : 0;\n\n// ../../node_modules/motion-utils/dist/es/wrap.mjs\nvar wrap = (min, max, v) => {\n  const rangeSize = max - min;\n  return ((v - min) % rangeSize + rangeSize) % rangeSize + min;\n};\n\n// ../../node_modules/motion-utils/dist/es/easing/cubic-bezier.mjs\nvar calcBezier = (t, a1, a2) => (((1 - 3 * a2 + 3 * a1) * t + (3 * a2 - 6 * a1)) * t + 3 * a1) * t;\nvar subdivisionPrecision = 1e-7;\nvar subdivisionMaxIterations = 12;\nfunction binarySubdivide(x, lowerBound, upperBound, mX1, mX2) {\n  let currentX;\n  let currentT;\n  let i = 0;\n  do {\n    currentT = lowerBound + (upperBound - lowerBound) / 2;\n    currentX = calcBezier(currentT, mX1, mX2) - x;\n    if (currentX > 0) {\n      upperBound = currentT;\n    } else {\n      lowerBound = currentT;\n    }\n  } while (Math.abs(currentX) > subdivisionPrecision && ++i < subdivisionMaxIterations);\n  return currentT;\n}\n// @__NO_SIDE_EFFECTS__\nfunction cubicBezier(mX1, mY1, mX2, mY2) {\n  if (mX1 === mY1 && mX2 === mY2)\n    return noop;\n  const getTForX = (aX) => binarySubdivide(aX, 0, 1, mX1, mX2);\n  return (t) => t === 0 || t === 1 ? t : calcBezier(getTForX(t), mY1, mY2);\n}\n\n// ../../node_modules/motion-utils/dist/es/easing/modifiers/mirror.mjs\nvar mirrorEasing = /* @__NO_SIDE_EFFECTS__ */ (easing) => (p) => p <= 0.5 ? easing(2 * p) / 2 : (2 - easing(2 * (1 - p))) / 2;\n\n// ../../node_modules/motion-utils/dist/es/easing/modifiers/reverse.mjs\nvar reverseEasing = /* @__NO_SIDE_EFFECTS__ */ (easing) => (p) => 1 - easing(1 - p);\n\n// ../../node_modules/motion-utils/dist/es/easing/back.mjs\nvar backOut = /* @__PURE__ */ cubicBezier(0.33, 1.53, 0.69, 0.99);\nvar backIn = /* @__PURE__ */ reverseEasing(backOut);\nvar backInOut = /* @__PURE__ */ mirrorEasing(backIn);\n\n// ../../node_modules/motion-utils/dist/es/easing/anticipate.mjs\nvar anticipate = (p) => p >= 1 ? 1 : (p *= 2) < 1 ? 0.5 * backIn(p) : 0.5 * (2 - Math.pow(2, -10 * (p - 1)));\n\n// ../../node_modules/motion-utils/dist/es/easing/circ.mjs\nvar circIn = (p) => 1 - Math.sin(Math.acos(p));\nvar circOut = reverseEasing(circIn);\nvar circInOut = mirrorEasing(circIn);\n\n// ../../node_modules/motion-utils/dist/es/easing/ease.mjs\nvar easeIn = /* @__PURE__ */ cubicBezier(0.42, 0, 1, 1);\nvar easeOut = /* @__PURE__ */ cubicBezier(0, 0, 0.58, 1);\nvar easeInOut = /* @__PURE__ */ cubicBezier(0.42, 0, 0.58, 1);\n\n// ../../node_modules/motion-utils/dist/es/easing/utils/is-easing-array.mjs\nvar isEasingArray = /* @__NO_SIDE_EFFECTS__ */ (ease2) => {\n  return Array.isArray(ease2) && typeof ease2[0] !== \"number\";\n};\n\n// ../../node_modules/motion-utils/dist/es/easing/utils/get-easing-for-segment.mjs\n// @__NO_SIDE_EFFECTS__\nfunction getEasingForSegment(easing, i) {\n  return isEasingArray(easing) ? easing[wrap(0, easing.length, i)] : easing;\n}\n\n// ../../node_modules/motion-utils/dist/es/easing/utils/is-bezier-definition.mjs\nvar isBezierDefinition = /* @__NO_SIDE_EFFECTS__ */ (easing) => Array.isArray(easing) && typeof easing[0] === \"number\";\n\n// ../../node_modules/motion-utils/dist/es/easing/utils/map.mjs\nvar easingLookup = {\n  linear: noop,\n  easeIn,\n  easeInOut,\n  easeOut,\n  circIn,\n  circInOut,\n  circOut,\n  backIn,\n  backInOut,\n  backOut,\n  anticipate\n};\nvar isValidEasing = (easing) => {\n  return typeof easing === \"string\";\n};\nvar easingDefinitionToFunction = (definition) => {\n  if (isBezierDefinition(definition)) {\n    invariant(definition.length === 4, `Cubic bezier arrays must contain four numerical values.`, \"cubic-bezier-length\");\n    const [x1, y1, x2, y2] = definition;\n    return cubicBezier(x1, y1, x2, y2);\n  } else if (isValidEasing(definition)) {\n    invariant(easingLookup[definition] !== void 0, `Invalid easing type '${definition}'`, \"invalid-easing-type\");\n    return easingLookup[definition];\n  }\n  return definition;\n};\n\n// ../../node_modules/motion-dom/dist/es/frameloop/order.mjs\nvar stepsOrder = [\n  \"setup\",\n  // Compute\n  \"read\",\n  // Read\n  \"resolveKeyframes\",\n  // Write/Read/Write/Read\n  \"preUpdate\",\n  // Compute\n  \"update\",\n  // Compute\n  \"preRender\",\n  // Compute\n  \"render\",\n  // Write\n  \"postRender\"\n  // Compute\n];\n\n// ../../node_modules/motion-dom/dist/es/frameloop/render-step.mjs\nfunction createRenderStep(runNextFrame) {\n  let thisFrame = /* @__PURE__ */ new Set();\n  let nextFrame = /* @__PURE__ */ new Set();\n  let isProcessing = false;\n  let flushNextFrame = false;\n  const toKeepAlive = /* @__PURE__ */ new WeakSet();\n  let latestFrameData = {\n    delta: 0,\n    timestamp: 0,\n    isProcessing: false\n  };\n  function triggerCallback(callback) {\n    if (toKeepAlive.has(callback)) {\n      step.schedule(callback);\n      runNextFrame();\n    }\n    callback(latestFrameData);\n  }\n  const step = {\n    /**\n     * Schedule a process to run on the next frame.\n     */\n    schedule: (callback, keepAlive = false, immediate = false) => {\n      const addToCurrentFrame = immediate && isProcessing;\n      const queue = addToCurrentFrame ? thisFrame : nextFrame;\n      if (keepAlive)\n        toKeepAlive.add(callback);\n      queue.add(callback);\n      return callback;\n    },\n    /**\n     * Cancel the provided callback from running on the next frame.\n     */\n    cancel: (callback) => {\n      nextFrame.delete(callback);\n      toKeepAlive.delete(callback);\n    },\n    /**\n     * Execute all schedule callbacks.\n     */\n    process: (frameData2) => {\n      latestFrameData = frameData2;\n      if (isProcessing) {\n        flushNextFrame = true;\n        return;\n      }\n      isProcessing = true;\n      const prevFrame = thisFrame;\n      thisFrame = nextFrame;\n      nextFrame = prevFrame;\n      thisFrame.forEach(triggerCallback);\n      thisFrame.clear();\n      isProcessing = false;\n      if (flushNextFrame) {\n        flushNextFrame = false;\n        step.process(frameData2);\n      }\n    }\n  };\n  return step;\n}\n\n// ../../node_modules/motion-dom/dist/es/frameloop/batcher.mjs\nvar maxElapsed = 40;\nfunction createRenderBatcher(scheduleNextBatch, allowKeepAlive) {\n  let runNextFrame = false;\n  let useDefaultElapsed = true;\n  const state = {\n    delta: 0,\n    timestamp: 0,\n    isProcessing: false\n  };\n  const flagRunNextFrame = () => runNextFrame = true;\n  const steps = stepsOrder.reduce((acc, key) => {\n    acc[key] = createRenderStep(flagRunNextFrame);\n    return acc;\n  }, {});\n  const { setup, read, resolveKeyframes, preUpdate, update, preRender, render, postRender } = steps;\n  const processBatch = () => {\n    const useManualTiming = MotionGlobalConfig.useManualTiming;\n    const timestamp = useManualTiming ? state.timestamp : performance.now();\n    runNextFrame = false;\n    if (!useManualTiming) {\n      state.delta = useDefaultElapsed ? 1e3 / 60 : Math.max(Math.min(timestamp - state.timestamp, maxElapsed), 1);\n    }\n    state.timestamp = timestamp;\n    state.isProcessing = true;\n    setup.process(state);\n    read.process(state);\n    resolveKeyframes.process(state);\n    preUpdate.process(state);\n    update.process(state);\n    preRender.process(state);\n    render.process(state);\n    postRender.process(state);\n    state.isProcessing = false;\n    if (runNextFrame && allowKeepAlive) {\n      useDefaultElapsed = false;\n      scheduleNextBatch(processBatch);\n    }\n  };\n  const wake = () => {\n    runNextFrame = true;\n    useDefaultElapsed = true;\n    if (!state.isProcessing) {\n      scheduleNextBatch(processBatch);\n    }\n  };\n  const schedule = stepsOrder.reduce((acc, key) => {\n    const step = steps[key];\n    acc[key] = (process2, keepAlive = false, immediate = false) => {\n      if (!runNextFrame)\n        wake();\n      return step.schedule(process2, keepAlive, immediate);\n    };\n    return acc;\n  }, {});\n  const cancel = (process2) => {\n    for (let i = 0; i < stepsOrder.length; i++) {\n      steps[stepsOrder[i]].cancel(process2);\n    }\n  };\n  return { schedule, cancel, state, steps };\n}\n\n// ../../node_modules/motion-dom/dist/es/frameloop/frame.mjs\nvar { schedule: frame, cancel: cancelFrame, state: frameData, steps: frameSteps } = /* @__PURE__ */ createRenderBatcher(typeof requestAnimationFrame !== \"undefined\" ? requestAnimationFrame : noop, true);\n\n// ../../node_modules/motion-dom/dist/es/frameloop/sync-time.mjs\nvar now;\nfunction clearTime() {\n  now = void 0;\n}\nvar time = {\n  now: () => {\n    if (now === void 0) {\n      time.set(frameData.isProcessing || MotionGlobalConfig.useManualTiming ? frameData.timestamp : performance.now());\n    }\n    return now;\n  },\n  set: (newTime) => {\n    now = newTime;\n    queueMicrotask(clearTime);\n  }\n};\n\n// ../../node_modules/motion-dom/dist/es/animation/utils/is-css-variable.mjs\nvar checkStringStartsWith = (token) => (key) => typeof key === \"string\" && key.startsWith(token);\nvar isCSSVariableName = /* @__PURE__ */ checkStringStartsWith(\"--\");\nvar startsAsVariableToken = /* @__PURE__ */ checkStringStartsWith(\"var(--\");\nvar isCSSVariableToken = (value) => {\n  const startsWithToken = startsAsVariableToken(value);\n  if (!startsWithToken)\n    return false;\n  return singleCssVariableRegex.test(value.split(\"/*\")[0].trim());\n};\nvar singleCssVariableRegex = /var\\(--(?:[\\w-]+\\s*|[\\w-]+\\s*,(?:\\s*[^)(\\s]|\\s*\\((?:[^)(]|\\([^)(]*\\))*\\))+\\s*)\\)$/iu;\nfunction containsCSSVariable(value) {\n  if (typeof value !== \"string\")\n    return false;\n  return value.split(\"/*\")[0].includes(\"var(--\");\n}\n\n// ../../node_modules/motion-dom/dist/es/value/types/numbers/index.mjs\nvar number = {\n  test: (v) => typeof v === \"number\",\n  parse: parseFloat,\n  transform: (v) => v\n};\nvar alpha = {\n  ...number,\n  transform: (v) => clamp(0, 1, v)\n};\nvar scale = {\n  ...number,\n  default: 1\n};\n\n// ../../node_modules/motion-dom/dist/es/value/types/utils/sanitize.mjs\nvar sanitize = (v) => Math.round(v * 1e5) / 1e5;\n\n// ../../node_modules/motion-dom/dist/es/value/types/utils/float-regex.mjs\nvar floatRegex = /-?(?:\\d+(?:\\.\\d+)?|\\.\\d+)/gu;\n\n// ../../node_modules/motion-dom/dist/es/value/types/utils/is-nullish.mjs\nfunction isNullish(v) {\n  return v == null;\n}\n\n// ../../node_modules/motion-dom/dist/es/value/types/utils/single-color-regex.mjs\nvar singleColorRegex = /^(?:#[\\da-f]{3,8}|(?:rgb|hsl)a?\\((?:-?[\\d.]+%?[,\\s]+){2}-?[\\d.]+%?\\s*(?:[,/]\\s*)?(?:\\b\\d+(?:\\.\\d+)?|\\.\\d+)?%?\\))$/iu;\n\n// ../../node_modules/motion-dom/dist/es/value/types/color/utils.mjs\nvar isColorString = (type, testProp) => (v) => {\n  return Boolean(typeof v === \"string\" && singleColorRegex.test(v) && v.startsWith(type) || testProp && !isNullish(v) && Object.prototype.hasOwnProperty.call(v, testProp));\n};\nvar splitColor = (aName, bName, cName) => (v) => {\n  if (typeof v !== \"string\")\n    return v;\n  const [a, b, c, alpha2] = v.match(floatRegex);\n  return {\n    [aName]: parseFloat(a),\n    [bName]: parseFloat(b),\n    [cName]: parseFloat(c),\n    alpha: alpha2 !== void 0 ? parseFloat(alpha2) : 1\n  };\n};\n\n// ../../node_modules/motion-dom/dist/es/value/types/color/rgba.mjs\nvar clampRgbUnit = (v) => clamp(0, 255, v);\nvar rgbUnit = {\n  ...number,\n  transform: (v) => Math.round(clampRgbUnit(v))\n};\nvar rgba = {\n  test: /* @__PURE__ */ isColorString(\"rgb\", \"red\"),\n  parse: /* @__PURE__ */ splitColor(\"red\", \"green\", \"blue\"),\n  transform: ({ red, green, blue, alpha: alpha$1 = 1 }) => \"rgba(\" + rgbUnit.transform(red) + \", \" + rgbUnit.transform(green) + \", \" + rgbUnit.transform(blue) + \", \" + sanitize(alpha.transform(alpha$1)) + \")\"\n};\n\n// ../../node_modules/motion-dom/dist/es/value/types/color/hex.mjs\nfunction parseHex(v) {\n  let r = \"\";\n  let g = \"\";\n  let b = \"\";\n  let a = \"\";\n  if (v.length > 5) {\n    r = v.substring(1, 3);\n    g = v.substring(3, 5);\n    b = v.substring(5, 7);\n    a = v.substring(7, 9);\n  } else {\n    r = v.substring(1, 2);\n    g = v.substring(2, 3);\n    b = v.substring(3, 4);\n    a = v.substring(4, 5);\n    r += r;\n    g += g;\n    b += b;\n    a += a;\n  }\n  return {\n    red: parseInt(r, 16),\n    green: parseInt(g, 16),\n    blue: parseInt(b, 16),\n    alpha: a ? parseInt(a, 16) / 255 : 1\n  };\n}\nvar hex = {\n  test: /* @__PURE__ */ isColorString(\"#\"),\n  parse: parseHex,\n  transform: rgba.transform\n};\n\n// ../../node_modules/motion-dom/dist/es/value/types/numbers/units.mjs\nvar createUnitType = /* @__NO_SIDE_EFFECTS__ */ (unit) => ({\n  test: (v) => typeof v === \"string\" && v.endsWith(unit) && v.split(\" \").length === 1,\n  parse: parseFloat,\n  transform: (v) => `${v}${unit}`\n});\nvar degrees = /* @__PURE__ */ createUnitType(\"deg\");\nvar percent = /* @__PURE__ */ createUnitType(\"%\");\nvar px = /* @__PURE__ */ createUnitType(\"px\");\nvar vh = /* @__PURE__ */ createUnitType(\"vh\");\nvar vw = /* @__PURE__ */ createUnitType(\"vw\");\nvar progressPercentage = /* @__PURE__ */ (() => ({\n  ...percent,\n  parse: (v) => percent.parse(v) / 100,\n  transform: (v) => percent.transform(v * 100)\n}))();\n\n// ../../node_modules/motion-dom/dist/es/value/types/color/hsla.mjs\nvar hsla = {\n  test: /* @__PURE__ */ isColorString(\"hsl\", \"hue\"),\n  parse: /* @__PURE__ */ splitColor(\"hue\", \"saturation\", \"lightness\"),\n  transform: ({ hue, saturation, lightness, alpha: alpha$1 = 1 }) => {\n    return \"hsla(\" + Math.round(hue) + \", \" + percent.transform(sanitize(saturation)) + \", \" + percent.transform(sanitize(lightness)) + \", \" + sanitize(alpha.transform(alpha$1)) + \")\";\n  }\n};\n\n// ../../node_modules/motion-dom/dist/es/value/types/color/index.mjs\nvar color = {\n  test: (v) => rgba.test(v) || hex.test(v) || hsla.test(v),\n  parse: (v) => {\n    if (rgba.test(v)) {\n      return rgba.parse(v);\n    } else if (hsla.test(v)) {\n      return hsla.parse(v);\n    } else {\n      return hex.parse(v);\n    }\n  },\n  transform: (v) => {\n    return typeof v === \"string\" ? v : v.hasOwnProperty(\"red\") ? rgba.transform(v) : hsla.transform(v);\n  },\n  getAnimatableNone: (v) => {\n    const parsed = color.parse(v);\n    parsed.alpha = 0;\n    return color.transform(parsed);\n  }\n};\n\n// ../../node_modules/motion-dom/dist/es/value/types/utils/color-regex.mjs\nvar colorRegex = /(?:#[\\da-f]{3,8}|(?:rgb|hsl)a?\\((?:-?[\\d.]+%?[,\\s]+){2}-?[\\d.]+%?\\s*(?:[,/]\\s*)?(?:\\b\\d+(?:\\.\\d+)?|\\.\\d+)?%?\\))/giu;\n\n// ../../node_modules/motion-dom/dist/es/value/types/complex/index.mjs\nfunction test(v) {\n  return isNaN(v) && typeof v === \"string\" && (v.match(floatRegex)?.length || 0) + (v.match(colorRegex)?.length || 0) > 0;\n}\nvar NUMBER_TOKEN = \"number\";\nvar COLOR_TOKEN = \"color\";\nvar VAR_TOKEN = \"var\";\nvar VAR_FUNCTION_TOKEN = \"var(\";\nvar SPLIT_TOKEN = \"${}\";\nvar complexRegex = /var\\s*\\(\\s*--(?:[\\w-]+\\s*|[\\w-]+\\s*,(?:\\s*[^)(\\s]|\\s*\\((?:[^)(]|\\([^)(]*\\))*\\))+\\s*)\\)|#[\\da-f]{3,8}|(?:rgb|hsl)a?\\((?:-?[\\d.]+%?[,\\s]+){2}-?[\\d.]+%?\\s*(?:[,/]\\s*)?(?:\\b\\d+(?:\\.\\d+)?|\\.\\d+)?%?\\)|-?(?:\\d+(?:\\.\\d+)?|\\.\\d+)/giu;\nfunction analyseComplexValue(value) {\n  const originalValue = value.toString();\n  const values = [];\n  const indexes = {\n    color: [],\n    number: [],\n    var: []\n  };\n  const types = [];\n  let i = 0;\n  const tokenised = originalValue.replace(complexRegex, (parsedValue) => {\n    if (color.test(parsedValue)) {\n      indexes.color.push(i);\n      types.push(COLOR_TOKEN);\n      values.push(color.parse(parsedValue));\n    } else if (parsedValue.startsWith(VAR_FUNCTION_TOKEN)) {\n      indexes.var.push(i);\n      types.push(VAR_TOKEN);\n      values.push(parsedValue);\n    } else {\n      indexes.number.push(i);\n      types.push(NUMBER_TOKEN);\n      values.push(parseFloat(parsedValue));\n    }\n    ++i;\n    return SPLIT_TOKEN;\n  });\n  const split = tokenised.split(SPLIT_TOKEN);\n  return { values, split, indexes, types };\n}\nfunction parseComplexValue(v) {\n  return analyseComplexValue(v).values;\n}\nfunction buildTransformer({ split, types }) {\n  const numSections = split.length;\n  return (v) => {\n    let output = \"\";\n    for (let i = 0; i < numSections; i++) {\n      output += split[i];\n      if (v[i] !== void 0) {\n        const type = types[i];\n        if (type === NUMBER_TOKEN) {\n          output += sanitize(v[i]);\n        } else if (type === COLOR_TOKEN) {\n          output += color.transform(v[i]);\n        } else {\n          output += v[i];\n        }\n      }\n    }\n    return output;\n  };\n}\nfunction createTransformer(source) {\n  return buildTransformer(analyseComplexValue(source));\n}\nvar convertNumbersToZero = (v) => typeof v === \"number\" ? 0 : color.test(v) ? color.getAnimatableNone(v) : v;\nvar convertToZero = (value, splitBefore) => {\n  if (typeof value === \"number\") {\n    return splitBefore?.trim().endsWith(\"/\") ? value : 0;\n  }\n  return convertNumbersToZero(value);\n};\nfunction getAnimatableNone(v) {\n  const info2 = analyseComplexValue(v);\n  const transformer = buildTransformer(info2);\n  return transformer(info2.values.map((value, i) => convertToZero(value, info2.split[i])));\n}\nvar complex = {\n  test,\n  parse: parseComplexValue,\n  createTransformer,\n  getAnimatableNone\n};\n\n// ../../node_modules/motion-dom/dist/es/value/types/color/hsla-to-rgba.mjs\nfunction hueToRgb(p, q, t) {\n  if (t < 0)\n    t += 1;\n  if (t > 1)\n    t -= 1;\n  if (t < 1 / 6)\n    return p + (q - p) * 6 * t;\n  if (t < 1 / 2)\n    return q;\n  if (t < 2 / 3)\n    return p + (q - p) * (2 / 3 - t) * 6;\n  return p;\n}\nfunction hslaToRgba({ hue, saturation, lightness, alpha: alpha2 }) {\n  hue /= 360;\n  saturation /= 100;\n  lightness /= 100;\n  let red = 0;\n  let green = 0;\n  let blue = 0;\n  if (!saturation) {\n    red = green = blue = lightness;\n  } else {\n    const q = lightness < 0.5 ? lightness * (1 + saturation) : lightness + saturation - lightness * saturation;\n    const p = 2 * lightness - q;\n    red = hueToRgb(p, q, hue + 1 / 3);\n    green = hueToRgb(p, q, hue);\n    blue = hueToRgb(p, q, hue - 1 / 3);\n  }\n  return {\n    red: Math.round(red * 255),\n    green: Math.round(green * 255),\n    blue: Math.round(blue * 255),\n    alpha: alpha2\n  };\n}\n\n// ../../node_modules/motion-dom/dist/es/utils/mix/immediate.mjs\nfunction mixImmediate(a, b) {\n  return (p) => p > 0 ? b : a;\n}\n\n// ../../node_modules/motion-dom/dist/es/utils/mix/number.mjs\nvar mixNumber = (from, to, progress2) => {\n  return from + (to - from) * progress2;\n};\n\n// ../../node_modules/motion-dom/dist/es/utils/mix/color.mjs\nvar mixLinearColor = (from, to, v) => {\n  const fromExpo = from * from;\n  const expo = v * (to * to - fromExpo) + fromExpo;\n  return expo < 0 ? 0 : Math.sqrt(expo);\n};\nvar colorTypes = [hex, rgba, hsla];\nvar getColorType = (v) => colorTypes.find((type) => type.test(v));\nfunction asRGBA(color2) {\n  const type = getColorType(color2);\n  warning2(Boolean(type), `'${color2}' is not an animatable color. Use the equivalent color code instead.`, \"color-not-animatable\");\n  if (!Boolean(type))\n    return false;\n  let model = type.parse(color2);\n  if (type === hsla) {\n    model = hslaToRgba(model);\n  }\n  return model;\n}\nvar mixColor = (from, to) => {\n  const fromRGBA = asRGBA(from);\n  const toRGBA = asRGBA(to);\n  if (!fromRGBA || !toRGBA) {\n    return mixImmediate(from, to);\n  }\n  const blended = { ...fromRGBA };\n  return (v) => {\n    blended.red = mixLinearColor(fromRGBA.red, toRGBA.red, v);\n    blended.green = mixLinearColor(fromRGBA.green, toRGBA.green, v);\n    blended.blue = mixLinearColor(fromRGBA.blue, toRGBA.blue, v);\n    blended.alpha = mixNumber(fromRGBA.alpha, toRGBA.alpha, v);\n    return rgba.transform(blended);\n  };\n};\n\n// ../../node_modules/motion-dom/dist/es/utils/mix/visibility.mjs\nvar invisibleValues = /* @__PURE__ */ new Set([\"none\", \"hidden\"]);\nfunction mixVisibility(origin, target) {\n  if (invisibleValues.has(origin)) {\n    return (p) => p <= 0 ? origin : target;\n  } else {\n    return (p) => p >= 1 ? target : origin;\n  }\n}\n\n// ../../node_modules/motion-dom/dist/es/utils/mix/complex.mjs\nfunction mixNumber2(a, b) {\n  return (p) => mixNumber(a, b, p);\n}\nfunction getMixer(a) {\n  if (typeof a === \"number\") {\n    return mixNumber2;\n  } else if (typeof a === \"string\") {\n    return isCSSVariableToken(a) ? mixImmediate : color.test(a) ? mixColor : mixComplex;\n  } else if (Array.isArray(a)) {\n    return mixArray;\n  } else if (typeof a === \"object\") {\n    return color.test(a) ? mixColor : mixObject;\n  }\n  return mixImmediate;\n}\nfunction mixArray(a, b) {\n  const output = [...a];\n  const numValues = output.length;\n  const blendValue = a.map((v, i) => getMixer(v)(v, b[i]));\n  return (p) => {\n    for (let i = 0; i < numValues; i++) {\n      output[i] = blendValue[i](p);\n    }\n    return output;\n  };\n}\nfunction mixObject(a, b) {\n  const output = { ...a, ...b };\n  const blendValue = {};\n  for (const key in output) {\n    if (a[key] !== void 0 && b[key] !== void 0) {\n      blendValue[key] = getMixer(a[key])(a[key], b[key]);\n    }\n  }\n  return (v) => {\n    for (const key in blendValue) {\n      output[key] = blendValue[key](v);\n    }\n    return output;\n  };\n}\nfunction matchOrder(origin, target) {\n  const orderedOrigin = [];\n  const pointers = { color: 0, var: 0, number: 0 };\n  for (let i = 0; i < target.values.length; i++) {\n    const type = target.types[i];\n    const originIndex = origin.indexes[type][pointers[type]];\n    const originValue = origin.values[originIndex] ?? 0;\n    orderedOrigin[i] = originValue;\n    pointers[type]++;\n  }\n  return orderedOrigin;\n}\nvar mixComplex = (origin, target) => {\n  const template = complex.createTransformer(target);\n  const originStats = analyseComplexValue(origin);\n  const targetStats = analyseComplexValue(target);\n  const canInterpolate = originStats.indexes.var.length === targetStats.indexes.var.length && originStats.indexes.color.length === targetStats.indexes.color.length && originStats.indexes.number.length >= targetStats.indexes.number.length;\n  if (canInterpolate) {\n    if (invisibleValues.has(origin) && !targetStats.values.length || invisibleValues.has(target) && !originStats.values.length) {\n      return mixVisibility(origin, target);\n    }\n    return pipe(mixArray(matchOrder(originStats, targetStats), targetStats.values), template);\n  } else {\n    warning2(true, `Complex values '${origin}' and '${target}' too different to mix. Ensure all colors are of the same type, and that each contains the same quantity of number and color values. Falling back to instant transition.`, \"complex-values-different\");\n    return mixImmediate(origin, target);\n  }\n};\n\n// ../../node_modules/motion-dom/dist/es/utils/mix/index.mjs\nfunction mix(from, to, p) {\n  if (typeof from === \"number\" && typeof to === \"number\" && typeof p === \"number\") {\n    return mixNumber(from, to, p);\n  }\n  const mixer = getMixer(from);\n  return mixer(from, to);\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/drivers/frame.mjs\nvar frameloopDriver = (update) => {\n  const passTimestamp = ({ timestamp }) => update(timestamp);\n  return {\n    start: (keepAlive = true) => frame.update(passTimestamp, keepAlive),\n    stop: () => cancelFrame(passTimestamp),\n    /**\n     * If we're processing this frame we can use the\n     * framelocked timestamp to keep things in sync.\n     */\n    now: () => frameData.isProcessing ? frameData.timestamp : time.now()\n  };\n};\n\n// ../../node_modules/motion-dom/dist/es/animation/waapi/utils/linear.mjs\nvar generateLinearEasing = (easing, duration, resolution = 10) => {\n  let points = \"\";\n  const numPoints = Math.max(Math.round(duration / resolution), 2);\n  for (let i = 0; i < numPoints; i++) {\n    points += Math.round(easing(i / (numPoints - 1)) * 1e4) / 1e4 + \", \";\n  }\n  return `linear(${points.substring(0, points.length - 2)})`;\n};\n\n// ../../node_modules/motion-dom/dist/es/animation/generators/utils/calc-duration.mjs\nvar maxGeneratorDuration = 2e4;\nfunction calcGeneratorDuration(generator) {\n  let duration = 0;\n  const timeStep = 50;\n  let state = generator.next(duration);\n  while (!state.done && duration < maxGeneratorDuration) {\n    duration += timeStep;\n    state = generator.next(duration);\n  }\n  return duration >= maxGeneratorDuration ? Infinity : duration;\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/generators/utils/create-generator-easing.mjs\nfunction createGeneratorEasing(options, scale2 = 100, createGenerator) {\n  const generator = createGenerator({ ...options, keyframes: [0, scale2] });\n  const duration = Math.min(calcGeneratorDuration(generator), maxGeneratorDuration);\n  return {\n    type: \"keyframes\",\n    ease: (progress2) => {\n      return generator.next(duration * progress2).value / scale2;\n    },\n    duration: millisecondsToSeconds(duration)\n  };\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/generators/spring.mjs\nvar springDefaults = {\n  // Default spring physics\n  stiffness: 100,\n  damping: 10,\n  mass: 1,\n  velocity: 0,\n  // Default duration/bounce-based options\n  duration: 800,\n  // in ms\n  bounce: 0.3,\n  visualDuration: 0.3,\n  // in seconds\n  // Rest thresholds\n  restSpeed: {\n    granular: 0.01,\n    default: 2\n  },\n  restDelta: {\n    granular: 5e-3,\n    default: 0.5\n  },\n  // Limits\n  minDuration: 0.01,\n  // in seconds\n  maxDuration: 10,\n  // in seconds\n  minDamping: 0.05,\n  maxDamping: 1\n};\nfunction calcAngularFreq(undampedFreq, dampingRatio) {\n  return undampedFreq * Math.sqrt(1 - dampingRatio * dampingRatio);\n}\nvar rootIterations = 12;\nfunction approximateRoot(envelope, derivative2, initialGuess) {\n  let result = initialGuess;\n  for (let i = 1; i < rootIterations; i++) {\n    result = result - envelope(result) / derivative2(result);\n  }\n  return result;\n}\nvar safeMin = 1e-3;\nfunction findSpring({ duration = springDefaults.duration, bounce = springDefaults.bounce, velocity = springDefaults.velocity, mass = springDefaults.mass }) {\n  let envelope;\n  let derivative2;\n  warning2(duration <= secondsToMilliseconds(springDefaults.maxDuration), \"Spring duration must be 10 seconds or less\", \"spring-duration-limit\");\n  let dampingRatio = 1 - bounce;\n  dampingRatio = clamp(springDefaults.minDamping, springDefaults.maxDamping, dampingRatio);\n  duration = clamp(springDefaults.minDuration, springDefaults.maxDuration, millisecondsToSeconds(duration));\n  if (dampingRatio < 1) {\n    envelope = (undampedFreq2) => {\n      const exponentialDecay = undampedFreq2 * dampingRatio;\n      const delta = exponentialDecay * duration;\n      const a = exponentialDecay - velocity;\n      const b = calcAngularFreq(undampedFreq2, dampingRatio);\n      const c = Math.exp(-delta);\n      return safeMin - a / b * c;\n    };\n    derivative2 = (undampedFreq2) => {\n      const exponentialDecay = undampedFreq2 * dampingRatio;\n      const delta = exponentialDecay * duration;\n      const d = delta * velocity + velocity;\n      const e10 = Math.pow(dampingRatio, 2) * Math.pow(undampedFreq2, 2) * duration;\n      const f = Math.exp(-delta);\n      const g = calcAngularFreq(Math.pow(undampedFreq2, 2), dampingRatio);\n      const factor = -envelope(undampedFreq2) + safeMin > 0 ? -1 : 1;\n      return factor * ((d - e10) * f) / g;\n    };\n  } else {\n    envelope = (undampedFreq2) => {\n      const a = Math.exp(-undampedFreq2 * duration);\n      const b = (undampedFreq2 - velocity) * duration + 1;\n      return -safeMin + a * b;\n    };\n    derivative2 = (undampedFreq2) => {\n      const a = Math.exp(-undampedFreq2 * duration);\n      const b = (velocity - undampedFreq2) * (duration * duration);\n      return a * b;\n    };\n  }\n  const initialGuess = 5 / duration;\n  const undampedFreq = approximateRoot(envelope, derivative2, initialGuess);\n  duration = secondsToMilliseconds(duration);\n  if (isNaN(undampedFreq)) {\n    return {\n      stiffness: springDefaults.stiffness,\n      damping: springDefaults.damping,\n      duration\n    };\n  } else {\n    const stiffness = Math.pow(undampedFreq, 2) * mass;\n    return {\n      stiffness,\n      damping: dampingRatio * 2 * Math.sqrt(mass * stiffness),\n      duration\n    };\n  }\n}\nvar durationKeys = [\"duration\", \"bounce\"];\nvar physicsKeys = [\"stiffness\", \"damping\", \"mass\"];\nfunction isSpringType(options, keys) {\n  return keys.some((key) => options[key] !== void 0);\n}\nfunction getSpringOptions(options) {\n  let springOptions = {\n    velocity: springDefaults.velocity,\n    stiffness: springDefaults.stiffness,\n    damping: springDefaults.damping,\n    mass: springDefaults.mass,\n    isResolvedFromDuration: false,\n    ...options\n  };\n  if (!isSpringType(options, physicsKeys) && isSpringType(options, durationKeys)) {\n    springOptions.velocity = 0;\n    if (options.visualDuration) {\n      const visualDuration = options.visualDuration;\n      const root = 2 * Math.PI / (visualDuration * 1.2);\n      const stiffness = root * root;\n      const damping = 2 * clamp(0.05, 1, 1 - (options.bounce || 0)) * Math.sqrt(stiffness);\n      springOptions = {\n        ...springOptions,\n        mass: springDefaults.mass,\n        stiffness,\n        damping\n      };\n    } else {\n      const derived = findSpring({ ...options, velocity: 0 });\n      springOptions = {\n        ...springOptions,\n        ...derived,\n        mass: springDefaults.mass\n      };\n      springOptions.isResolvedFromDuration = true;\n    }\n  }\n  return springOptions;\n}\nfunction spring(optionsOrVisualDuration = springDefaults.visualDuration, bounce = springDefaults.bounce) {\n  const options = typeof optionsOrVisualDuration !== \"object\" ? {\n    visualDuration: optionsOrVisualDuration,\n    keyframes: [0, 1],\n    bounce\n  } : optionsOrVisualDuration;\n  let { restSpeed, restDelta } = options;\n  const origin = options.keyframes[0];\n  const target = options.keyframes[options.keyframes.length - 1];\n  const state = { done: false, value: origin };\n  const { stiffness, damping, mass, duration, velocity, isResolvedFromDuration } = getSpringOptions({\n    ...options,\n    velocity: -millisecondsToSeconds(options.velocity || 0)\n  });\n  const initialVelocity = velocity || 0;\n  const dampingRatio = damping / (2 * Math.sqrt(stiffness * mass));\n  const initialDelta = target - origin;\n  const undampedAngularFreq = millisecondsToSeconds(Math.sqrt(stiffness / mass));\n  const isGranularScale = Math.abs(initialDelta) < 5;\n  restSpeed || (restSpeed = isGranularScale ? springDefaults.restSpeed.granular : springDefaults.restSpeed.default);\n  restDelta || (restDelta = isGranularScale ? springDefaults.restDelta.granular : springDefaults.restDelta.default);\n  let resolveSpring;\n  let resolveVelocity;\n  let angularFreq;\n  let A;\n  let sinCoeff;\n  let cosCoeff;\n  if (dampingRatio < 1) {\n    angularFreq = calcAngularFreq(undampedAngularFreq, dampingRatio);\n    A = (initialVelocity + dampingRatio * undampedAngularFreq * initialDelta) / angularFreq;\n    resolveSpring = (t) => {\n      const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);\n      return target - envelope * (A * Math.sin(angularFreq * t) + initialDelta * Math.cos(angularFreq * t));\n    };\n    sinCoeff = dampingRatio * undampedAngularFreq * A + initialDelta * angularFreq;\n    cosCoeff = dampingRatio * undampedAngularFreq * initialDelta - A * angularFreq;\n    resolveVelocity = (t) => {\n      const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);\n      return envelope * (sinCoeff * Math.sin(angularFreq * t) + cosCoeff * Math.cos(angularFreq * t));\n    };\n  } else if (dampingRatio === 1) {\n    resolveSpring = (t) => target - Math.exp(-undampedAngularFreq * t) * (initialDelta + (initialVelocity + undampedAngularFreq * initialDelta) * t);\n    const C = initialVelocity + undampedAngularFreq * initialDelta;\n    resolveVelocity = (t) => Math.exp(-undampedAngularFreq * t) * (undampedAngularFreq * C * t - initialVelocity);\n  } else {\n    const dampedAngularFreq = undampedAngularFreq * Math.sqrt(dampingRatio * dampingRatio - 1);\n    resolveSpring = (t) => {\n      const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);\n      const freqForT = Math.min(dampedAngularFreq * t, 300);\n      return target - envelope * ((initialVelocity + dampingRatio * undampedAngularFreq * initialDelta) * Math.sinh(freqForT) + dampedAngularFreq * initialDelta * Math.cosh(freqForT)) / dampedAngularFreq;\n    };\n    const P = (initialVelocity + dampingRatio * undampedAngularFreq * initialDelta) / dampedAngularFreq;\n    const sinhCoeff = dampingRatio * undampedAngularFreq * P - initialDelta * dampedAngularFreq;\n    const coshCoeff = dampingRatio * undampedAngularFreq * initialDelta - P * dampedAngularFreq;\n    resolveVelocity = (t) => {\n      const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);\n      const freqForT = Math.min(dampedAngularFreq * t, 300);\n      return envelope * (sinhCoeff * Math.sinh(freqForT) + coshCoeff * Math.cosh(freqForT));\n    };\n  }\n  const generator = {\n    calculatedDuration: isResolvedFromDuration ? duration || null : null,\n    velocity: (t) => secondsToMilliseconds(resolveVelocity(t)),\n    next: (t) => {\n      if (!isResolvedFromDuration && dampingRatio < 1) {\n        const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);\n        const sin = Math.sin(angularFreq * t);\n        const cos = Math.cos(angularFreq * t);\n        const current2 = target - envelope * (A * sin + initialDelta * cos);\n        const currentVelocity = secondsToMilliseconds(envelope * (sinCoeff * sin + cosCoeff * cos));\n        state.done = Math.abs(currentVelocity) <= restSpeed && Math.abs(target - current2) <= restDelta;\n        state.value = state.done ? target : current2;\n        return state;\n      }\n      const current = resolveSpring(t);\n      if (!isResolvedFromDuration) {\n        const currentVelocity = secondsToMilliseconds(resolveVelocity(t));\n        state.done = Math.abs(currentVelocity) <= restSpeed && Math.abs(target - current) <= restDelta;\n      } else {\n        state.done = t >= duration;\n      }\n      state.value = state.done ? target : current;\n      return state;\n    },\n    toString: () => {\n      const calculatedDuration = Math.min(calcGeneratorDuration(generator), maxGeneratorDuration);\n      const easing = generateLinearEasing((progress2) => generator.next(calculatedDuration * progress2).value, calculatedDuration, 30);\n      return calculatedDuration + \"ms \" + easing;\n    },\n    toTransition: () => {\n    }\n  };\n  return generator;\n}\nspring.applyToOptions = (options) => {\n  const generatorOptions = createGeneratorEasing(options, 100, spring);\n  options.ease = generatorOptions.ease;\n  options.duration = secondsToMilliseconds(generatorOptions.duration);\n  options.type = \"keyframes\";\n  return options;\n};\n\n// ../../node_modules/motion-dom/dist/es/animation/generators/utils/velocity.mjs\nvar velocitySampleDuration = 5;\nfunction getGeneratorVelocity(resolveValue, t, current) {\n  const prevT = Math.max(t - velocitySampleDuration, 0);\n  return velocityPerSecond(current - resolveValue(prevT), t - prevT);\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/generators/inertia.mjs\nfunction inertia({ keyframes: keyframes2, velocity = 0, power = 0.8, timeConstant = 325, bounceDamping = 10, bounceStiffness = 500, modifyTarget, min, max, restDelta = 0.5, restSpeed }) {\n  const origin = keyframes2[0];\n  const state = {\n    done: false,\n    value: origin\n  };\n  const isOutOfBounds = (v) => min !== void 0 && v < min || max !== void 0 && v > max;\n  const nearestBoundary = (v) => {\n    if (min === void 0)\n      return max;\n    if (max === void 0)\n      return min;\n    return Math.abs(min - v) < Math.abs(max - v) ? min : max;\n  };\n  let amplitude = power * velocity;\n  const ideal = origin + amplitude;\n  const target = modifyTarget === void 0 ? ideal : modifyTarget(ideal);\n  if (target !== ideal)\n    amplitude = target - origin;\n  const calcDelta = (t) => -amplitude * Math.exp(-t / timeConstant);\n  const calcLatest = (t) => target + calcDelta(t);\n  const applyFriction = (t) => {\n    const delta = calcDelta(t);\n    const latest = calcLatest(t);\n    state.done = Math.abs(delta) <= restDelta;\n    state.value = state.done ? target : latest;\n  };\n  let timeReachedBoundary;\n  let spring$1;\n  const checkCatchBoundary = (t) => {\n    if (!isOutOfBounds(state.value))\n      return;\n    timeReachedBoundary = t;\n    spring$1 = spring({\n      keyframes: [state.value, nearestBoundary(state.value)],\n      velocity: getGeneratorVelocity(calcLatest, t, state.value),\n      // TODO: This should be passing * 1000\n      damping: bounceDamping,\n      stiffness: bounceStiffness,\n      restDelta,\n      restSpeed\n    });\n  };\n  checkCatchBoundary(0);\n  return {\n    calculatedDuration: null,\n    next: (t) => {\n      let hasUpdatedFrame = false;\n      if (!spring$1 && timeReachedBoundary === void 0) {\n        hasUpdatedFrame = true;\n        applyFriction(t);\n        checkCatchBoundary(t);\n      }\n      if (timeReachedBoundary !== void 0 && t >= timeReachedBoundary) {\n        return spring$1.next(t - timeReachedBoundary);\n      } else {\n        !hasUpdatedFrame && applyFriction(t);\n        return state;\n      }\n    }\n  };\n}\n\n// ../../node_modules/motion-dom/dist/es/utils/interpolate.mjs\nfunction createMixers(output, ease2, customMixer) {\n  const mixers = [];\n  const mixerFactory = customMixer || MotionGlobalConfig.mix || mix;\n  const numMixers = output.length - 1;\n  for (let i = 0; i < numMixers; i++) {\n    let mixer = mixerFactory(output[i], output[i + 1]);\n    if (ease2) {\n      const easingFunction = Array.isArray(ease2) ? ease2[i] || noop : ease2;\n      mixer = pipe(easingFunction, mixer);\n    }\n    mixers.push(mixer);\n  }\n  return mixers;\n}\nfunction interpolate(input, output, { clamp: isClamp = true, ease: ease2, mixer } = {}) {\n  const inputLength = input.length;\n  invariant(inputLength === output.length, \"Both input and output ranges must be the same length\", \"range-length\");\n  if (inputLength === 1)\n    return () => output[0];\n  if (inputLength === 2 && output[0] === output[1])\n    return () => output[1];\n  const isZeroDeltaRange = input[0] === input[1];\n  if (input[0] > input[inputLength - 1]) {\n    input = [...input].reverse();\n    output = [...output].reverse();\n  }\n  const mixers = createMixers(output, ease2, mixer);\n  const numMixers = mixers.length;\n  const interpolator = (v) => {\n    if (isZeroDeltaRange && v < input[0])\n      return output[0];\n    let i = 0;\n    if (numMixers > 1) {\n      for (; i < input.length - 2; i++) {\n        if (v < input[i + 1])\n          break;\n      }\n    }\n    const progressInRange = progress(input[i], input[i + 1], v);\n    return mixers[i](progressInRange);\n  };\n  return isClamp ? (v) => interpolator(clamp(input[0], input[inputLength - 1], v)) : interpolator;\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/keyframes/offsets/fill.mjs\nfunction fillOffset(offset, remaining2) {\n  const min = offset[offset.length - 1];\n  for (let i = 1; i <= remaining2; i++) {\n    const offsetProgress = progress(0, remaining2, i);\n    offset.push(mixNumber(min, 1, offsetProgress));\n  }\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/keyframes/offsets/default.mjs\nfunction defaultOffset(arr) {\n  const offset = [0];\n  fillOffset(offset, arr.length - 1);\n  return offset;\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/keyframes/offsets/time.mjs\nfunction convertOffsetToTimes(offset, duration) {\n  return offset.map((o) => o * duration);\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/generators/keyframes.mjs\nfunction defaultEasing(values, easing) {\n  return values.map(() => easing || easeInOut).splice(0, values.length - 1);\n}\nfunction keyframes({ duration = 300, keyframes: keyframeValues, times, ease: ease2 = \"easeInOut\" }) {\n  const easingFunctions = isEasingArray(ease2) ? ease2.map(easingDefinitionToFunction) : easingDefinitionToFunction(ease2);\n  const state = {\n    done: false,\n    value: keyframeValues[0]\n  };\n  const absoluteTimes = convertOffsetToTimes(\n    // Only use the provided offsets if they're the correct length\n    // TODO Maybe we should warn here if there's a length mismatch\n    times && times.length === keyframeValues.length ? times : defaultOffset(keyframeValues),\n    duration\n  );\n  const mapTimeToKeyframe = interpolate(absoluteTimes, keyframeValues, {\n    ease: Array.isArray(easingFunctions) ? easingFunctions : defaultEasing(keyframeValues, easingFunctions)\n  });\n  return {\n    calculatedDuration: duration,\n    next: (t) => {\n      state.value = mapTimeToKeyframe(t);\n      state.done = t >= duration;\n      return state;\n    }\n  };\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/keyframes/get-final.mjs\nvar isNotNull = (value) => value !== null;\nfunction getFinalKeyframe(keyframes2, { repeat, repeatType = \"loop\" }, finalKeyframe, speed = 1) {\n  const resolvedKeyframes = keyframes2.filter(isNotNull);\n  const useFirstKeyframe = speed < 0 || repeat && repeatType !== \"loop\" && repeat % 2 === 1;\n  const index = useFirstKeyframe ? 0 : resolvedKeyframes.length - 1;\n  return !index || finalKeyframe === void 0 ? resolvedKeyframes[index] : finalKeyframe;\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/utils/replace-transition-type.mjs\nvar transitionTypeMap = {\n  decay: inertia,\n  inertia,\n  tween: keyframes,\n  keyframes,\n  spring\n};\nfunction replaceTransitionType(transition) {\n  if (typeof transition.type === \"string\") {\n    transition.type = transitionTypeMap[transition.type];\n  }\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/utils/WithPromise.mjs\nvar WithPromise = class {\n  constructor() {\n    this.updateFinished();\n  }\n  get finished() {\n    return this._finished;\n  }\n  updateFinished() {\n    this._finished = new Promise((resolve) => {\n      this.resolve = resolve;\n    });\n  }\n  notifyFinished() {\n    this.resolve();\n  }\n  /**\n   * Allows the animation to be awaited.\n   *\n   * @deprecated Use `finished` instead.\n   */\n  then(onResolve, onReject) {\n    return this.finished.then(onResolve, onReject);\n  }\n};\n\n// ../../node_modules/motion-dom/dist/es/animation/JSAnimation.mjs\nvar percentToProgress = (percent2) => percent2 / 100;\nvar JSAnimation = class extends WithPromise {\n  constructor(options) {\n    super();\n    this.state = \"idle\";\n    this.startTime = null;\n    this.isStopped = false;\n    this.currentTime = 0;\n    this.holdTime = null;\n    this.playbackSpeed = 1;\n    this.delayState = {\n      done: false,\n      value: void 0\n    };\n    this.stop = () => {\n      const { motionValue: motionValue2 } = this.options;\n      if (motionValue2 && motionValue2.updatedAt !== time.now()) {\n        this.tick(time.now());\n      }\n      this.isStopped = true;\n      if (this.state === \"idle\")\n        return;\n      this.teardown();\n      this.options.onStop?.();\n    };\n    this.options = options;\n    this.initAnimation();\n    this.play();\n    if (options.autoplay === false)\n      this.pause();\n  }\n  initAnimation() {\n    const { options } = this;\n    replaceTransitionType(options);\n    const { type = keyframes, repeat = 0, repeatDelay = 0, repeatType, velocity = 0 } = options;\n    let { keyframes: keyframes$1 } = options;\n    const generatorFactory = type || keyframes;\n    if (false) {\n      invariant(keyframes$1.length <= 2, `Only two keyframes currently supported with spring and inertia animations. Trying to animate ${keyframes$1}`, \"spring-two-frames\");\n    }\n    if (generatorFactory !== keyframes && typeof keyframes$1[0] !== \"number\") {\n      this.mixKeyframes = pipe(percentToProgress, mix(keyframes$1[0], keyframes$1[1]));\n      keyframes$1 = [0, 100];\n    }\n    const generator = generatorFactory({ ...options, keyframes: keyframes$1 });\n    if (repeatType === \"mirror\") {\n      this.mirroredGenerator = generatorFactory({\n        ...options,\n        keyframes: [...keyframes$1].reverse(),\n        velocity: -velocity\n      });\n    }\n    if (generator.calculatedDuration === null) {\n      generator.calculatedDuration = calcGeneratorDuration(generator);\n    }\n    const { calculatedDuration } = generator;\n    this.calculatedDuration = calculatedDuration;\n    this.resolvedDuration = calculatedDuration + repeatDelay;\n    this.totalDuration = this.resolvedDuration * (repeat + 1) - repeatDelay;\n    this.generator = generator;\n  }\n  updateTime(timestamp) {\n    const animationTime = Math.round(timestamp - this.startTime) * this.playbackSpeed;\n    if (this.holdTime !== null) {\n      this.currentTime = this.holdTime;\n    } else {\n      this.currentTime = animationTime;\n    }\n  }\n  tick(timestamp, sample = false) {\n    const { generator, totalDuration, mixKeyframes, mirroredGenerator, resolvedDuration, calculatedDuration } = this;\n    if (this.startTime === null)\n      return generator.next(0);\n    const { delay: delay2 = 0, keyframes: keyframes2, repeat, repeatType, repeatDelay, type, onUpdate, finalKeyframe } = this.options;\n    if (this.speed > 0) {\n      this.startTime = Math.min(this.startTime, timestamp);\n    } else if (this.speed < 0) {\n      this.startTime = Math.min(timestamp - totalDuration / this.speed, this.startTime);\n    }\n    if (sample) {\n      this.currentTime = timestamp;\n    } else {\n      this.updateTime(timestamp);\n    }\n    const timeWithoutDelay = this.currentTime - delay2 * (this.playbackSpeed >= 0 ? 1 : -1);\n    const isInDelayPhase = this.playbackSpeed >= 0 ? timeWithoutDelay < 0 : timeWithoutDelay > totalDuration;\n    this.currentTime = Math.max(timeWithoutDelay, 0);\n    if (this.state === \"finished\" && this.holdTime === null) {\n      this.currentTime = totalDuration;\n    }\n    let elapsed = this.currentTime;\n    let frameGenerator = generator;\n    if (repeat) {\n      const progress2 = Math.min(this.currentTime, totalDuration) / resolvedDuration;\n      let currentIteration = Math.floor(progress2);\n      let iterationProgress = progress2 % 1;\n      if (!iterationProgress && progress2 >= 1) {\n        iterationProgress = 1;\n      }\n      iterationProgress === 1 && currentIteration--;\n      currentIteration = Math.min(currentIteration, repeat + 1);\n      const isOddIteration = Boolean(currentIteration % 2);\n      if (isOddIteration) {\n        if (repeatType === \"reverse\") {\n          iterationProgress = 1 - iterationProgress;\n          if (repeatDelay) {\n            iterationProgress -= repeatDelay / resolvedDuration;\n          }\n        } else if (repeatType === \"mirror\") {\n          frameGenerator = mirroredGenerator;\n        }\n      }\n      elapsed = clamp(0, 1, iterationProgress) * resolvedDuration;\n    }\n    let state;\n    if (isInDelayPhase) {\n      this.delayState.value = keyframes2[0];\n      state = this.delayState;\n    } else {\n      state = frameGenerator.next(elapsed);\n    }\n    if (mixKeyframes && !isInDelayPhase) {\n      state.value = mixKeyframes(state.value);\n    }\n    let { done } = state;\n    if (!isInDelayPhase && calculatedDuration !== null) {\n      done = this.playbackSpeed >= 0 ? this.currentTime >= totalDuration : this.currentTime <= 0;\n    }\n    const isAnimationFinished = this.holdTime === null && (this.state === \"finished\" || this.state === \"running\" && done);\n    if (isAnimationFinished && type !== inertia) {\n      state.value = getFinalKeyframe(keyframes2, this.options, finalKeyframe, this.speed);\n    }\n    if (onUpdate) {\n      onUpdate(state.value);\n    }\n    if (isAnimationFinished) {\n      this.finish();\n    }\n    return state;\n  }\n  /**\n   * Allows the returned animation to be awaited or promise-chained. Currently\n   * resolves when the animation finishes at all but in a future update could/should\n   * reject if its cancels.\n   */\n  then(resolve, reject) {\n    return this.finished.then(resolve, reject);\n  }\n  get duration() {\n    return millisecondsToSeconds(this.calculatedDuration);\n  }\n  get iterationDuration() {\n    const { delay: delay2 = 0 } = this.options || {};\n    return this.duration + millisecondsToSeconds(delay2);\n  }\n  get time() {\n    return millisecondsToSeconds(this.currentTime);\n  }\n  set time(newTime) {\n    newTime = secondsToMilliseconds(newTime);\n    this.currentTime = newTime;\n    if (this.startTime === null || this.holdTime !== null || this.playbackSpeed === 0) {\n      this.holdTime = newTime;\n    } else if (this.driver) {\n      this.startTime = this.driver.now() - newTime / this.playbackSpeed;\n    }\n    if (this.driver) {\n      this.driver.start(false);\n    } else {\n      this.startTime = 0;\n      this.state = \"paused\";\n      this.holdTime = newTime;\n      this.tick(newTime);\n    }\n  }\n  /**\n   * Returns the generator's velocity at the current time in units/second.\n   * Uses the analytical derivative when available (springs), avoiding\n   * the MotionValue's frame-dependent velocity estimation.\n   */\n  getGeneratorVelocity() {\n    const t = this.currentTime;\n    if (t <= 0)\n      return this.options.velocity || 0;\n    if (this.generator.velocity) {\n      return this.generator.velocity(t);\n    }\n    const current = this.generator.next(t).value;\n    return getGeneratorVelocity((s) => this.generator.next(s).value, t, current);\n  }\n  get speed() {\n    return this.playbackSpeed;\n  }\n  set speed(newSpeed) {\n    const hasChanged = this.playbackSpeed !== newSpeed;\n    if (hasChanged && this.driver) {\n      this.updateTime(time.now());\n    }\n    this.playbackSpeed = newSpeed;\n    if (hasChanged && this.driver) {\n      this.time = millisecondsToSeconds(this.currentTime);\n    }\n  }\n  play() {\n    if (this.isStopped)\n      return;\n    const { driver = frameloopDriver, startTime } = this.options;\n    if (!this.driver) {\n      this.driver = driver((timestamp) => this.tick(timestamp));\n    }\n    this.options.onPlay?.();\n    const now2 = this.driver.now();\n    if (this.state === \"finished\") {\n      this.updateFinished();\n      this.startTime = now2;\n    } else if (this.holdTime !== null) {\n      this.startTime = now2 - this.holdTime;\n    } else if (!this.startTime) {\n      this.startTime = startTime ?? now2;\n    }\n    if (this.state === \"finished\" && this.speed < 0) {\n      this.startTime += this.calculatedDuration;\n    }\n    this.holdTime = null;\n    this.state = \"running\";\n    this.driver.start();\n  }\n  pause() {\n    this.state = \"paused\";\n    this.updateTime(time.now());\n    this.holdTime = this.currentTime;\n  }\n  complete() {\n    if (this.state !== \"running\") {\n      this.play();\n    }\n    this.state = \"finished\";\n    this.holdTime = null;\n  }\n  finish() {\n    this.notifyFinished();\n    this.teardown();\n    this.state = \"finished\";\n    this.options.onComplete?.();\n  }\n  cancel() {\n    this.holdTime = null;\n    this.startTime = 0;\n    this.tick(0);\n    this.teardown();\n    this.options.onCancel?.();\n  }\n  teardown() {\n    this.state = \"idle\";\n    this.stopDriver();\n    this.startTime = this.holdTime = null;\n  }\n  stopDriver() {\n    if (!this.driver)\n      return;\n    this.driver.stop();\n    this.driver = void 0;\n  }\n  sample(sampleTime) {\n    this.startTime = 0;\n    return this.tick(sampleTime, true);\n  }\n  attachTimeline(timeline) {\n    if (this.options.allowFlatten) {\n      this.options.type = \"keyframes\";\n      this.options.ease = \"linear\";\n      this.initAnimation();\n    }\n    this.driver?.stop();\n    return timeline.observe(this);\n  }\n};\n\n// ../../node_modules/motion-dom/dist/es/animation/keyframes/utils/fill-wildcards.mjs\nfunction fillWildcards(keyframes2) {\n  for (let i = 1; i < keyframes2.length; i++) {\n    keyframes2[i] ?? (keyframes2[i] = keyframes2[i - 1]);\n  }\n}\n\n// ../../node_modules/motion-dom/dist/es/render/dom/parse-transform.mjs\nvar radToDeg = (rad) => rad * 180 / Math.PI;\nvar rotate = (v) => {\n  const angle = radToDeg(Math.atan2(v[1], v[0]));\n  return rebaseAngle(angle);\n};\nvar matrix2dParsers = {\n  x: 4,\n  y: 5,\n  translateX: 4,\n  translateY: 5,\n  scaleX: 0,\n  scaleY: 3,\n  scale: (v) => (Math.abs(v[0]) + Math.abs(v[3])) / 2,\n  rotate,\n  rotateZ: rotate,\n  skewX: (v) => radToDeg(Math.atan(v[1])),\n  skewY: (v) => radToDeg(Math.atan(v[2])),\n  skew: (v) => (Math.abs(v[1]) + Math.abs(v[2])) / 2\n};\nvar rebaseAngle = (angle) => {\n  angle = angle % 360;\n  if (angle < 0)\n    angle += 360;\n  return angle;\n};\nvar rotateZ = rotate;\nvar scaleX = (v) => Math.sqrt(v[0] * v[0] + v[1] * v[1]);\nvar scaleY = (v) => Math.sqrt(v[4] * v[4] + v[5] * v[5]);\nvar matrix3dParsers = {\n  x: 12,\n  y: 13,\n  z: 14,\n  translateX: 12,\n  translateY: 13,\n  translateZ: 14,\n  scaleX,\n  scaleY,\n  scale: (v) => (scaleX(v) + scaleY(v)) / 2,\n  rotateX: (v) => rebaseAngle(radToDeg(Math.atan2(v[6], v[5]))),\n  rotateY: (v) => rebaseAngle(radToDeg(Math.atan2(-v[2], v[0]))),\n  rotateZ,\n  rotate: rotateZ,\n  skewX: (v) => radToDeg(Math.atan(v[4])),\n  skewY: (v) => radToDeg(Math.atan(v[1])),\n  skew: (v) => (Math.abs(v[1]) + Math.abs(v[4])) / 2\n};\nfunction defaultTransformValue(name) {\n  return name.includes(\"scale\") ? 1 : 0;\n}\nfunction parseValueFromTransform(transform2, name) {\n  if (!transform2 || transform2 === \"none\") {\n    return defaultTransformValue(name);\n  }\n  const matrix3dMatch = transform2.match(/^matrix3d\\(([-\\d.e\\s,]+)\\)$/u);\n  let parsers;\n  let match;\n  if (matrix3dMatch) {\n    parsers = matrix3dParsers;\n    match = matrix3dMatch;\n  } else {\n    const matrix2dMatch = transform2.match(/^matrix\\(([-\\d.e\\s,]+)\\)$/u);\n    parsers = matrix2dParsers;\n    match = matrix2dMatch;\n  }\n  if (!match) {\n    return defaultTransformValue(name);\n  }\n  const valueParser = parsers[name];\n  const values = match[1].split(\",\").map(convertTransformToNumber);\n  return typeof valueParser === \"function\" ? valueParser(values) : values[valueParser];\n}\nvar readTransformValue = (instance, name) => {\n  const { transform: transform2 = \"none\" } = getComputedStyle(instance);\n  return parseValueFromTransform(transform2, name);\n};\nfunction convertTransformToNumber(value) {\n  return parseFloat(value.trim());\n}\n\n// ../../node_modules/motion-dom/dist/es/render/utils/keys-transform.mjs\nvar transformPropOrder = [\n  \"transformPerspective\",\n  \"x\",\n  \"y\",\n  \"z\",\n  \"translateX\",\n  \"translateY\",\n  \"translateZ\",\n  \"scale\",\n  \"scaleX\",\n  \"scaleY\",\n  \"rotate\",\n  \"rotateX\",\n  \"rotateY\",\n  \"rotateZ\",\n  \"skew\",\n  \"skewX\",\n  \"skewY\"\n];\nvar transformProps = /* @__PURE__ */ (() => /* @__PURE__ */ new Set([...transformPropOrder, \"pathRotation\"]))();\n\n// ../../node_modules/motion-dom/dist/es/animation/keyframes/utils/unit-conversion.mjs\nvar isNumOrPxType = (v) => v === number || v === px;\nvar transformKeys = /* @__PURE__ */ new Set([\"x\", \"y\", \"z\"]);\nvar nonTranslationalTransformKeys = transformPropOrder.filter((key) => !transformKeys.has(key));\nfunction removeNonTranslationalTransform(visualElement) {\n  const removedTransforms = [];\n  nonTranslationalTransformKeys.forEach((key) => {\n    const value = visualElement.getValue(key);\n    if (value !== void 0) {\n      removedTransforms.push([key, value.get()]);\n      value.set(key.startsWith(\"scale\") ? 1 : 0);\n    }\n  });\n  return removedTransforms;\n}\nvar positionalValues = {\n  // Dimensions\n  width: ({ x }, { paddingLeft = \"0\", paddingRight = \"0\", boxSizing }) => {\n    const width = x.max - x.min;\n    return boxSizing === \"border-box\" ? width : width - parseFloat(paddingLeft) - parseFloat(paddingRight);\n  },\n  height: ({ y }, { paddingTop = \"0\", paddingBottom = \"0\", boxSizing }) => {\n    const height = y.max - y.min;\n    return boxSizing === \"border-box\" ? height : height - parseFloat(paddingTop) - parseFloat(paddingBottom);\n  },\n  top: (_bbox, { top }) => parseFloat(top),\n  left: (_bbox, { left }) => parseFloat(left),\n  bottom: ({ y }, { top }) => parseFloat(top) + (y.max - y.min),\n  right: ({ x }, { left }) => parseFloat(left) + (x.max - x.min),\n  // Transform\n  x: (_bbox, { transform: transform2 }) => parseValueFromTransform(transform2, \"x\"),\n  y: (_bbox, { transform: transform2 }) => parseValueFromTransform(transform2, \"y\")\n};\npositionalValues.translateX = positionalValues.x;\npositionalValues.translateY = positionalValues.y;\n\n// ../../node_modules/motion-dom/dist/es/animation/keyframes/KeyframesResolver.mjs\nvar toResolve = /* @__PURE__ */ new Set();\nvar isScheduled = false;\nvar anyNeedsMeasurement = false;\nvar isForced = false;\nfunction measureAllKeyframes() {\n  if (anyNeedsMeasurement) {\n    const resolversToMeasure = Array.from(toResolve).filter((resolver) => resolver.needsMeasurement);\n    const elementsToMeasure = new Set(resolversToMeasure.map((resolver) => resolver.element));\n    const transformsToRestore = /* @__PURE__ */ new Map();\n    elementsToMeasure.forEach((element) => {\n      const removedTransforms = removeNonTranslationalTransform(element);\n      if (!removedTransforms.length)\n        return;\n      transformsToRestore.set(element, removedTransforms);\n      element.render();\n    });\n    resolversToMeasure.forEach((resolver) => resolver.measureInitialState());\n    elementsToMeasure.forEach((element) => {\n      element.render();\n      const restore = transformsToRestore.get(element);\n      if (restore) {\n        restore.forEach(([key, value]) => {\n          element.getValue(key)?.set(value);\n        });\n      }\n    });\n    resolversToMeasure.forEach((resolver) => resolver.measureEndState());\n    resolversToMeasure.forEach((resolver) => {\n      if (resolver.suspendedScrollY !== void 0) {\n        window.scrollTo(0, resolver.suspendedScrollY);\n      }\n    });\n  }\n  anyNeedsMeasurement = false;\n  isScheduled = false;\n  toResolve.forEach((resolver) => resolver.complete(isForced));\n  toResolve.clear();\n}\nfunction readAllKeyframes() {\n  toResolve.forEach((resolver) => {\n    resolver.readKeyframes();\n    if (resolver.needsMeasurement) {\n      anyNeedsMeasurement = true;\n    }\n  });\n}\nfunction flushKeyframeResolvers() {\n  isForced = true;\n  readAllKeyframes();\n  measureAllKeyframes();\n  isForced = false;\n}\nvar KeyframeResolver = class {\n  constructor(unresolvedKeyframes, onComplete, name, motionValue2, element, isAsync = false) {\n    this.state = \"pending\";\n    this.isAsync = false;\n    this.needsMeasurement = false;\n    this.unresolvedKeyframes = [...unresolvedKeyframes];\n    this.onComplete = onComplete;\n    this.name = name;\n    this.motionValue = motionValue2;\n    this.element = element;\n    this.isAsync = isAsync;\n  }\n  scheduleResolve() {\n    this.state = \"scheduled\";\n    if (this.isAsync) {\n      toResolve.add(this);\n      if (!isScheduled) {\n        isScheduled = true;\n        frame.read(readAllKeyframes);\n        frame.resolveKeyframes(measureAllKeyframes);\n      }\n    } else {\n      this.readKeyframes();\n      this.complete();\n    }\n  }\n  readKeyframes() {\n    const { unresolvedKeyframes, name, element, motionValue: motionValue2 } = this;\n    if (unresolvedKeyframes[0] === null) {\n      const currentValue = motionValue2?.get();\n      const finalKeyframe = unresolvedKeyframes[unresolvedKeyframes.length - 1];\n      if (currentValue !== void 0) {\n        unresolvedKeyframes[0] = currentValue;\n      } else if (element && name) {\n        const valueAsRead = element.readValue(name, finalKeyframe);\n        if (valueAsRead !== void 0 && valueAsRead !== null) {\n          unresolvedKeyframes[0] = valueAsRead;\n        }\n      }\n      if (unresolvedKeyframes[0] === void 0) {\n        unresolvedKeyframes[0] = finalKeyframe;\n      }\n      if (motionValue2 && currentValue === void 0) {\n        motionValue2.set(unresolvedKeyframes[0]);\n      }\n    }\n    fillWildcards(unresolvedKeyframes);\n  }\n  setFinalKeyframe() {\n  }\n  measureInitialState() {\n  }\n  renderEndStyles() {\n  }\n  measureEndState() {\n  }\n  complete(isForcedComplete = false) {\n    this.state = \"complete\";\n    this.onComplete(this.unresolvedKeyframes, this.finalKeyframe, isForcedComplete);\n    toResolve.delete(this);\n  }\n  cancel() {\n    if (this.state === \"scheduled\") {\n      toResolve.delete(this);\n      this.state = \"pending\";\n    }\n  }\n  resume() {\n    if (this.state === \"pending\")\n      this.scheduleResolve();\n  }\n};\n\n// ../../node_modules/motion-dom/dist/es/render/dom/is-css-var.mjs\nvar isCSSVar = (name) => name.startsWith(\"--\");\n\n// ../../node_modules/motion-dom/dist/es/render/dom/style-set.mjs\nfunction setStyle(element, name, value) {\n  isCSSVar(name) ? element.style.setProperty(name, value) : element.style[name] = value;\n}\n\n// ../../node_modules/motion-dom/dist/es/utils/supports/flags.mjs\nvar supportsFlags = {};\n\n// ../../node_modules/motion-dom/dist/es/utils/supports/memo.mjs\nfunction memoSupports(callback, supportsFlag) {\n  const memoized = memo(callback);\n  return () => supportsFlags[supportsFlag] ?? memoized();\n}\n\n// ../../node_modules/motion-dom/dist/es/utils/supports/scroll-timeline.mjs\nvar supportsScrollTimeline = /* @__PURE__ */ memoSupports(() => window.ScrollTimeline !== void 0, \"scrollTimeline\");\n\n// ../../node_modules/motion-dom/dist/es/utils/supports/linear-easing.mjs\nvar supportsLinearEasing = /* @__PURE__ */ memoSupports(() => {\n  try {\n    document.createElement(\"div\").animate({ opacity: 0 }, { easing: \"linear(0, 1)\" });\n  } catch (e10) {\n    return false;\n  }\n  return true;\n}, \"linearEasing\");\n\n// ../../node_modules/motion-dom/dist/es/animation/waapi/easing/cubic-bezier.mjs\nvar cubicBezierAsString = ([a, b, c, d]) => `cubic-bezier(${a}, ${b}, ${c}, ${d})`;\n\n// ../../node_modules/motion-dom/dist/es/animation/waapi/easing/supported.mjs\nvar supportedWaapiEasing = {\n  linear: \"linear\",\n  ease: \"ease\",\n  easeIn: \"ease-in\",\n  easeOut: \"ease-out\",\n  easeInOut: \"ease-in-out\",\n  circIn: /* @__PURE__ */ cubicBezierAsString([0, 0.65, 0.55, 1]),\n  circOut: /* @__PURE__ */ cubicBezierAsString([0.55, 0, 1, 0.45]),\n  backIn: /* @__PURE__ */ cubicBezierAsString([0.31, 0.01, 0.66, -0.59]),\n  backOut: /* @__PURE__ */ cubicBezierAsString([0.33, 1.53, 0.69, 0.99])\n};\n\n// ../../node_modules/motion-dom/dist/es/animation/waapi/easing/map-easing.mjs\nfunction mapEasingToNativeEasing(easing, duration) {\n  if (!easing) {\n    return void 0;\n  } else if (typeof easing === \"function\") {\n    return supportsLinearEasing() ? generateLinearEasing(easing, duration) : \"ease-out\";\n  } else if (isBezierDefinition(easing)) {\n    return cubicBezierAsString(easing);\n  } else if (Array.isArray(easing)) {\n    return easing.map((segmentEasing) => mapEasingToNativeEasing(segmentEasing, duration) || supportedWaapiEasing.easeOut);\n  } else {\n    return supportedWaapiEasing[easing];\n  }\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/waapi/start-waapi-animation.mjs\nfunction startWaapiAnimation(element, valueName, keyframes2, { delay: delay2 = 0, duration = 300, repeat = 0, repeatType = \"loop\", ease: ease2 = \"easeOut\", times } = {}, pseudoElement = void 0) {\n  const keyframeOptions = {\n    [valueName]: keyframes2\n  };\n  if (times)\n    keyframeOptions.offset = times;\n  const easing = mapEasingToNativeEasing(ease2, duration);\n  if (Array.isArray(easing))\n    keyframeOptions.easing = easing;\n  const options = {\n    delay: delay2,\n    duration,\n    easing: !Array.isArray(easing) ? easing : \"linear\",\n    fill: \"both\",\n    iterations: repeat + 1,\n    direction: repeatType === \"reverse\" ? \"alternate\" : \"normal\"\n  };\n  if (pseudoElement)\n    options.pseudoElement = pseudoElement;\n  return element.animate(keyframeOptions, options);\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/generators/utils/is-generator.mjs\nfunction isGenerator(type) {\n  return typeof type === \"function\" && \"applyToOptions\" in type;\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/waapi/utils/apply-generator.mjs\nfunction applyGeneratorOptions({ type, ...options }) {\n  if (isGenerator(type) && supportsLinearEasing()) {\n    return type.applyToOptions(options);\n  } else {\n    options.duration ?? (options.duration = 300);\n    options.ease ?? (options.ease = \"easeOut\");\n  }\n  return options;\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/NativeAnimation.mjs\nvar NativeAnimation = class extends WithPromise {\n  constructor(options) {\n    super();\n    this.finishedTime = null;\n    this.isStopped = false;\n    this.manualStartTime = null;\n    if (!options)\n      return;\n    const { element, name, keyframes: keyframes2, pseudoElement, allowFlatten = false, finalKeyframe, onComplete } = options;\n    this.isPseudoElement = Boolean(pseudoElement);\n    this.allowFlatten = allowFlatten;\n    this.options = options;\n    invariant(typeof options.type !== \"string\", `Mini animate() doesn't support \"type\" as a string.`, \"mini-spring\");\n    const transition = applyGeneratorOptions(options);\n    this.animation = startWaapiAnimation(element, name, keyframes2, transition, pseudoElement);\n    if (transition.autoplay === false) {\n      this.animation.pause();\n    }\n    this.animation.onfinish = () => {\n      this.finishedTime = this.time;\n      if (!pseudoElement) {\n        const keyframe = getFinalKeyframe(keyframes2, this.options, finalKeyframe, this.speed);\n        if (this.updateMotionValue) {\n          this.updateMotionValue(keyframe);\n        }\n        setStyle(element, name, keyframe);\n        this.animation.cancel();\n      }\n      onComplete?.();\n      this.notifyFinished();\n    };\n  }\n  play() {\n    if (this.isStopped)\n      return;\n    this.manualStartTime = null;\n    this.animation.play();\n    if (this.state === \"finished\") {\n      this.updateFinished();\n    }\n  }\n  pause() {\n    this.animation.pause();\n  }\n  complete() {\n    this.animation.finish?.();\n  }\n  cancel() {\n    try {\n      this.animation.cancel();\n    } catch (e10) {\n    }\n  }\n  stop() {\n    if (this.isStopped)\n      return;\n    this.isStopped = true;\n    const { state } = this;\n    if (state === \"idle\" || state === \"finished\") {\n      return;\n    }\n    if (this.updateMotionValue) {\n      this.updateMotionValue();\n    } else {\n      this.commitStyles();\n    }\n    if (!this.isPseudoElement)\n      this.cancel();\n  }\n  /**\n   * WAAPI doesn't natively have any interruption capabilities.\n   *\n   * In this method, we commit styles back to the DOM before cancelling\n   * the animation.\n   *\n   * This is designed to be overridden by NativeAnimationExtended, which\n   * will create a renderless JS animation and sample it twice to calculate\n   * its current value, \"previous\" value, and therefore allow\n   * Motion to also correctly calculate velocity for any subsequent animation\n   * while deferring the commit until the next animation frame.\n   */\n  commitStyles() {\n    const element = this.options?.element;\n    if (!this.isPseudoElement && element?.isConnected) {\n      this.animation.commitStyles?.();\n    }\n  }\n  get duration() {\n    const duration = this.animation.effect?.getComputedTiming?.().duration || 0;\n    return millisecondsToSeconds(Number(duration));\n  }\n  get iterationDuration() {\n    const { delay: delay2 = 0 } = this.options || {};\n    return this.duration + millisecondsToSeconds(delay2);\n  }\n  get time() {\n    return millisecondsToSeconds(Number(this.animation.currentTime) || 0);\n  }\n  set time(newTime) {\n    const wasFinished = this.finishedTime !== null;\n    this.manualStartTime = null;\n    this.finishedTime = null;\n    this.animation.currentTime = secondsToMilliseconds(newTime);\n    if (wasFinished) {\n      this.animation.pause();\n    }\n  }\n  /**\n   * The playback speed of the animation.\n   * 1 = normal speed, 2 = double speed, 0.5 = half speed.\n   */\n  get speed() {\n    return this.animation.playbackRate;\n  }\n  set speed(newSpeed) {\n    if (newSpeed < 0)\n      this.finishedTime = null;\n    this.animation.playbackRate = newSpeed;\n  }\n  get state() {\n    return this.finishedTime !== null ? \"finished\" : this.animation.playState;\n  }\n  get startTime() {\n    return this.manualStartTime ?? Number(this.animation.startTime);\n  }\n  set startTime(newStartTime) {\n    this.manualStartTime = this.animation.startTime = newStartTime;\n  }\n  /**\n   * Attaches a timeline to the animation, for instance the `ScrollTimeline`.\n   */\n  attachTimeline({ timeline, rangeStart, rangeEnd, observe }) {\n    if (this.allowFlatten) {\n      this.animation.effect?.updateTiming({ easing: \"linear\" });\n    }\n    this.animation.onfinish = null;\n    if (timeline && supportsScrollTimeline()) {\n      this.animation.timeline = timeline;\n      if (rangeStart)\n        this.animation.rangeStart = rangeStart;\n      if (rangeEnd)\n        this.animation.rangeEnd = rangeEnd;\n      return noop;\n    } else {\n      return observe(this);\n    }\n  }\n};\n\n// ../../node_modules/motion-dom/dist/es/animation/waapi/utils/unsupported-easing.mjs\nvar unsupportedEasingFunctions = {\n  anticipate,\n  backInOut,\n  circInOut\n};\nfunction isUnsupportedEase(key) {\n  return key in unsupportedEasingFunctions;\n}\nfunction replaceStringEasing(transition) {\n  if (typeof transition.ease === \"string\" && isUnsupportedEase(transition.ease)) {\n    transition.ease = unsupportedEasingFunctions[transition.ease];\n  }\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/NativeAnimationExtended.mjs\nvar sampleDelta = 10;\nvar NativeAnimationExtended = class extends NativeAnimation {\n  constructor(options) {\n    replaceStringEasing(options);\n    replaceTransitionType(options);\n    super(options);\n    if (options.startTime !== void 0 && options.autoplay !== false) {\n      this.startTime = options.startTime;\n    }\n    this.options = options;\n  }\n  /**\n   * WAAPI doesn't natively have any interruption capabilities.\n   *\n   * Rather than read committed styles back out of the DOM, we can\n   * create a renderless JS animation and sample it twice to calculate\n   * its current value, \"previous\" value, and therefore allow\n   * Motion to calculate velocity for any subsequent animation.\n   */\n  updateMotionValue(value) {\n    const { motionValue: motionValue2, onUpdate, onComplete, element, ...options } = this.options;\n    if (!motionValue2)\n      return;\n    if (value !== void 0) {\n      motionValue2.set(value);\n      return;\n    }\n    const sampleAnimation = new JSAnimation({\n      ...options,\n      autoplay: false\n    });\n    const sampleTime = Math.max(sampleDelta, time.now() - this.startTime);\n    const delta = clamp(0, sampleDelta, sampleTime - sampleDelta);\n    const current = sampleAnimation.sample(sampleTime).value;\n    const { name } = this.options;\n    if (element && name)\n      setStyle(element, name, current);\n    motionValue2.setWithVelocity(sampleAnimation.sample(Math.max(0, sampleTime - delta)).value, current, delta);\n    sampleAnimation.stop();\n  }\n};\n\n// ../../node_modules/motion-dom/dist/es/animation/utils/is-animatable.mjs\nvar isAnimatable = (value, name) => {\n  if (name === \"zIndex\")\n    return false;\n  if (typeof value === \"number\" || Array.isArray(value))\n    return true;\n  if (typeof value === \"string\" && // It's animatable if we have a string\n  (complex.test(value) || value === \"0\") && // And it contains numbers and/or colors\n  !value.startsWith(\"url(\")) {\n    return true;\n  }\n  return false;\n};\n\n// ../../node_modules/motion-dom/dist/es/animation/utils/can-animate.mjs\nfunction hasKeyframesChanged(keyframes2) {\n  const current = keyframes2[0];\n  if (keyframes2.length === 1)\n    return true;\n  for (let i = 0; i < keyframes2.length; i++) {\n    if (keyframes2[i] !== current)\n      return true;\n  }\n}\nfunction canAnimate(keyframes2, name, type, velocity) {\n  const originKeyframe = keyframes2[0];\n  if (originKeyframe === null) {\n    return false;\n  }\n  if (name === \"display\" || name === \"visibility\")\n    return true;\n  const targetKeyframe = keyframes2[keyframes2.length - 1];\n  const isOriginAnimatable = isAnimatable(originKeyframe, name);\n  const isTargetAnimatable = isAnimatable(targetKeyframe, name);\n  warning2(isOriginAnimatable === isTargetAnimatable, `You are trying to animate ${name} from \"${originKeyframe}\" to \"${targetKeyframe}\". \"${isOriginAnimatable ? targetKeyframe : originKeyframe}\" is not an animatable value.`, \"value-not-animatable\");\n  if (!isOriginAnimatable || !isTargetAnimatable) {\n    return false;\n  }\n  return hasKeyframesChanged(keyframes2) || (type === \"spring\" || isGenerator(type)) && velocity;\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/utils/make-animation-instant.mjs\nfunction makeAnimationInstant(options) {\n  options.duration = 0;\n  options.type = \"keyframes\";\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/waapi/utils/accelerated-values.mjs\nvar acceleratedValues = /* @__PURE__ */ new Set([\n  \"opacity\",\n  \"clipPath\",\n  \"filter\",\n  \"transform\",\n  \"backgroundColor\"\n]);\n\n// ../../node_modules/motion-dom/dist/es/animation/waapi/utils/is-browser-color.mjs\nvar browserColorFunctions = /^(?:oklch|oklab|lab|lch|color|color-mix|light-dark)\\(/;\nfunction hasBrowserOnlyColors(keyframes2) {\n  for (let i = 0; i < keyframes2.length; i++) {\n    if (typeof keyframes2[i] === \"string\" && browserColorFunctions.test(keyframes2[i])) {\n      return true;\n    }\n  }\n  return false;\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/waapi/supports/waapi.mjs\nvar colorProperties = /* @__PURE__ */ new Set([\n  \"color\",\n  \"backgroundColor\",\n  \"outlineColor\",\n  \"fill\",\n  \"stroke\",\n  \"borderColor\",\n  \"borderTopColor\",\n  \"borderRightColor\",\n  \"borderBottomColor\",\n  \"borderLeftColor\"\n]);\nvar supportsWaapi = /* @__PURE__ */ memo(() => Object.hasOwnProperty.call(Element.prototype, \"animate\"));\nfunction supportsBrowserAnimation(options) {\n  const { motionValue: motionValue2, name, repeatDelay, repeatType, damping, type, keyframes: keyframes2 } = options;\n  const subject = motionValue2?.owner?.current;\n  if (!(subject instanceof HTMLElement) && !(subject instanceof SVGElement)) {\n    return false;\n  }\n  const { onUpdate, transformTemplate } = motionValue2.owner.getProps();\n  return supportsWaapi() && name && /**\n   * Force WAAPI for color properties with browser-only color formats\n   * (oklch, oklab, lab, lch, etc.) that the JS animation path can't parse.\n   */\n  (acceleratedValues.has(name) || colorProperties.has(name) && hasBrowserOnlyColors(keyframes2)) && (name !== \"transform\" || !transformTemplate) && /**\n   * If we're outputting values to onUpdate then we can't use WAAPI as there's\n   * no way to read the value from WAAPI every frame.\n   */\n  !onUpdate && !repeatDelay && repeatType !== \"mirror\" && damping !== 0 && type !== \"inertia\";\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/AsyncMotionValueAnimation.mjs\nvar MAX_RESOLVE_DELAY = 40;\nvar AsyncMotionValueAnimation = class extends WithPromise {\n  constructor({ autoplay = true, delay: delay2 = 0, type = \"keyframes\", repeat = 0, repeatDelay = 0, repeatType = \"loop\", keyframes: keyframes2, name, motionValue: motionValue2, element, ...options }) {\n    super();\n    this.stop = () => {\n      if (this._animation) {\n        this._animation.stop();\n        this.stopTimeline?.();\n      }\n      this.keyframeResolver?.cancel();\n    };\n    this.createdAt = time.now();\n    const optionsWithDefaults = {\n      autoplay,\n      delay: delay2,\n      type,\n      repeat,\n      repeatDelay,\n      repeatType,\n      name,\n      motionValue: motionValue2,\n      element,\n      ...options\n    };\n    const KeyframeResolver$1 = element?.KeyframeResolver || KeyframeResolver;\n    this.keyframeResolver = new KeyframeResolver$1(keyframes2, (resolvedKeyframes, finalKeyframe, forced) => this.onKeyframesResolved(resolvedKeyframes, finalKeyframe, optionsWithDefaults, !forced), name, motionValue2, element);\n    this.keyframeResolver?.scheduleResolve();\n  }\n  onKeyframesResolved(keyframes2, finalKeyframe, options, sync) {\n    this.keyframeResolver = void 0;\n    const { name, type, velocity, delay: delay2, isHandoff, onUpdate } = options;\n    this.resolvedAt = time.now();\n    let canAnimateValue = true;\n    if (!canAnimate(keyframes2, name, type, velocity)) {\n      canAnimateValue = false;\n      if (MotionGlobalConfig.instantAnimations || !delay2) {\n        onUpdate?.(getFinalKeyframe(keyframes2, options, finalKeyframe));\n      }\n      keyframes2[0] = keyframes2[keyframes2.length - 1];\n      makeAnimationInstant(options);\n      options.repeat = 0;\n    }\n    const startTime = sync ? !this.resolvedAt ? this.createdAt : this.resolvedAt - this.createdAt > MAX_RESOLVE_DELAY ? this.resolvedAt : this.createdAt : void 0;\n    const resolvedOptions = {\n      startTime,\n      finalKeyframe,\n      ...options,\n      keyframes: keyframes2\n    };\n    const useWaapi = canAnimateValue && !isHandoff && supportsBrowserAnimation(resolvedOptions);\n    const element = resolvedOptions.motionValue?.owner?.current;\n    let animation;\n    if (useWaapi) {\n      try {\n        animation = new NativeAnimationExtended({\n          ...resolvedOptions,\n          element\n        });\n      } catch {\n        animation = new JSAnimation(resolvedOptions);\n      }\n    } else {\n      animation = new JSAnimation(resolvedOptions);\n    }\n    animation.finished.then(() => {\n      this.notifyFinished();\n    }).catch(noop);\n    if (this.pendingTimeline) {\n      this.stopTimeline = animation.attachTimeline(this.pendingTimeline);\n      this.pendingTimeline = void 0;\n    }\n    this._animation = animation;\n  }\n  get finished() {\n    if (!this._animation) {\n      return this._finished;\n    } else {\n      return this.animation.finished;\n    }\n  }\n  then(onResolve, _onReject) {\n    return this.finished.finally(onResolve).then(() => {\n    });\n  }\n  get animation() {\n    if (!this._animation) {\n      this.keyframeResolver?.resume();\n      flushKeyframeResolvers();\n    }\n    return this._animation;\n  }\n  get duration() {\n    return this.animation.duration;\n  }\n  get iterationDuration() {\n    return this.animation.iterationDuration;\n  }\n  get time() {\n    return this.animation.time;\n  }\n  set time(newTime) {\n    this.animation.time = newTime;\n  }\n  get speed() {\n    return this.animation.speed;\n  }\n  get state() {\n    return this.animation.state;\n  }\n  set speed(newSpeed) {\n    this.animation.speed = newSpeed;\n  }\n  get startTime() {\n    return this.animation.startTime;\n  }\n  attachTimeline(timeline) {\n    if (this._animation) {\n      this.stopTimeline = this.animation.attachTimeline(timeline);\n    } else {\n      this.pendingTimeline = timeline;\n    }\n    return () => this.stop();\n  }\n  play() {\n    this.animation.play();\n  }\n  pause() {\n    this.animation.pause();\n  }\n  complete() {\n    this.animation.complete();\n  }\n  cancel() {\n    if (this._animation) {\n      this.animation.cancel();\n    }\n    this.keyframeResolver?.cancel();\n  }\n};\n\n// ../../node_modules/motion-dom/dist/es/animation/GroupAnimation.mjs\nvar GroupAnimation = class {\n  constructor(animations2) {\n    this.stop = () => this.runAll(\"stop\");\n    this.animations = animations2.filter(Boolean);\n  }\n  get finished() {\n    return Promise.all(this.animations.map((animation) => animation.finished));\n  }\n  /**\n   * TODO: Filter out cancelled or stopped animations before returning\n   */\n  getAll(propName) {\n    return this.animations[0][propName];\n  }\n  setAll(propName, newValue) {\n    for (let i = 0; i < this.animations.length; i++) {\n      this.animations[i][propName] = newValue;\n    }\n  }\n  attachTimeline(timeline) {\n    const subscriptions = this.animations.map((animation) => animation.attachTimeline(timeline));\n    return () => {\n      subscriptions.forEach((cancel, i) => {\n        cancel && cancel();\n        this.animations[i].stop();\n      });\n    };\n  }\n  get time() {\n    return this.getAll(\"time\");\n  }\n  set time(time2) {\n    this.setAll(\"time\", time2);\n  }\n  get speed() {\n    return this.getAll(\"speed\");\n  }\n  set speed(speed) {\n    this.setAll(\"speed\", speed);\n  }\n  get state() {\n    return this.getAll(\"state\");\n  }\n  get startTime() {\n    return this.getAll(\"startTime\");\n  }\n  get duration() {\n    return getMax(this.animations, \"duration\");\n  }\n  get iterationDuration() {\n    return getMax(this.animations, \"iterationDuration\");\n  }\n  runAll(methodName) {\n    this.animations.forEach((controls) => controls[methodName]());\n  }\n  play() {\n    this.runAll(\"play\");\n  }\n  pause() {\n    this.runAll(\"pause\");\n  }\n  cancel() {\n    this.runAll(\"cancel\");\n  }\n  complete() {\n    this.runAll(\"complete\");\n  }\n};\nfunction getMax(animations2, propName) {\n  let max = 0;\n  for (let i = 0; i < animations2.length; i++) {\n    const value = animations2[i][propName];\n    if (value !== null && value > max) {\n      max = value;\n    }\n  }\n  return max;\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/GroupAnimationWithThen.mjs\nvar GroupAnimationWithThen = class extends GroupAnimation {\n  then(onResolve, _onReject) {\n    return this.finished.finally(onResolve).then(() => {\n    });\n  }\n};\n\n// ../../node_modules/motion-dom/dist/es/animation/utils/calc-child-stagger.mjs\nfunction calcChildStagger(children, child, delayChildren, staggerChildren = 0, staggerDirection = 1) {\n  const index = Array.from(children).sort((a, b) => a.sortNodePosition(b)).indexOf(child);\n  const numChildren = children.size;\n  const maxStaggerDuration = (numChildren - 1) * staggerChildren;\n  const delayIsFunction = typeof delayChildren === \"function\";\n  return delayIsFunction ? delayChildren(index, numChildren) : staggerDirection === 1 ? index * staggerChildren : maxStaggerDuration - index * staggerChildren;\n}\n\n// ../../node_modules/motion-dom/dist/es/value/index.mjs\nvar MAX_VELOCITY_DELTA = 30;\nvar isFloat = (value) => {\n  return !isNaN(parseFloat(value));\n};\nvar collectMotionValues = {\n  current: void 0\n};\nvar MotionValue = class {\n  /**\n   * @param init - The initiating value\n   * @param config - Optional configuration options\n   *\n   * -  `transformer`: A function to transform incoming values with.\n   */\n  constructor(init, options = {}) {\n    this.canTrackVelocity = null;\n    this.events = {};\n    this.updateAndNotify = (v) => {\n      const currentTime = time.now();\n      if (this.updatedAt !== currentTime) {\n        this.setPrevFrameValue();\n      }\n      this.prev = this.current;\n      this.setCurrent(v);\n      if (this.current !== this.prev) {\n        this.events.change?.notify(this.current);\n        if (this.dependents) {\n          for (const dependent of this.dependents) {\n            dependent.dirty();\n          }\n        }\n      }\n    };\n    this.hasAnimated = false;\n    this.setCurrent(init);\n    this.owner = options.owner;\n  }\n  setCurrent(current) {\n    this.current = current;\n    this.updatedAt = time.now();\n    if (this.canTrackVelocity === null && current !== void 0) {\n      this.canTrackVelocity = isFloat(this.current);\n    }\n  }\n  setPrevFrameValue(prevFrameValue = this.current) {\n    this.prevFrameValue = prevFrameValue;\n    this.prevUpdatedAt = this.updatedAt;\n  }\n  /**\n   * Adds a function that will be notified when the `MotionValue` is updated.\n   *\n   * It returns a function that, when called, will cancel the subscription.\n   *\n   * When calling `onChange` inside a React component, it should be wrapped with the\n   * `useEffect` hook. As it returns an unsubscribe function, this should be returned\n   * from the `useEffect` function to ensure you don't add duplicate subscribers..\n   *\n   * ```jsx\n   * export const MyComponent = () => {\n   *   const x = useMotionValue(0)\n   *   const y = useMotionValue(0)\n   *   const opacity = useMotionValue(1)\n   *\n   *   useEffect(() => {\n   *     function updateOpacity() {\n   *       const maxXY = Math.max(x.get(), y.get())\n   *       const newOpacity = transform(maxXY, [0, 100], [1, 0])\n   *       opacity.set(newOpacity)\n   *     }\n   *\n   *     const unsubscribeX = x.on(\"change\", updateOpacity)\n   *     const unsubscribeY = y.on(\"change\", updateOpacity)\n   *\n   *     return () => {\n   *       unsubscribeX()\n   *       unsubscribeY()\n   *     }\n   *   }, [])\n   *\n   *   return <motion.div style={{ x }} />\n   * }\n   * ```\n   *\n   * @param subscriber - A function that receives the latest value.\n   * @returns A function that, when called, will cancel this subscription.\n   *\n   * @deprecated\n   */\n  onChange(subscription) {\n    if (false) {\n      warnOnce(false, `value.onChange(callback) is deprecated. Switch to value.on(\"change\", callback).`);\n    }\n    return this.on(\"change\", subscription);\n  }\n  on(eventName, callback) {\n    if (!this.events[eventName]) {\n      this.events[eventName] = new SubscriptionManager();\n    }\n    const unsubscribe = this.events[eventName].add(callback);\n    if (eventName === \"change\") {\n      return () => {\n        unsubscribe();\n        frame.read(() => {\n          if (!this.events.change.getSize()) {\n            this.stop();\n          }\n        });\n      };\n    }\n    return unsubscribe;\n  }\n  clearListeners() {\n    for (const eventManagers in this.events) {\n      this.events[eventManagers].clear();\n    }\n  }\n  /**\n   * Attaches a passive effect to the `MotionValue`.\n   */\n  attach(passiveEffect, stopPassiveEffect) {\n    this.passiveEffect = passiveEffect;\n    this.stopPassiveEffect = stopPassiveEffect;\n  }\n  /**\n   * Sets the state of the `MotionValue`.\n   *\n   * @remarks\n   *\n   * ```jsx\n   * const x = useMotionValue(0)\n   * x.set(10)\n   * ```\n   *\n   * @param latest - Latest value to set.\n   * @param render - Whether to notify render subscribers. Defaults to `true`\n   *\n   * @public\n   */\n  set(v) {\n    if (!this.passiveEffect) {\n      this.updateAndNotify(v);\n    } else {\n      this.passiveEffect(v, this.updateAndNotify);\n    }\n  }\n  setWithVelocity(prev, current, delta) {\n    this.set(current);\n    this.prev = void 0;\n    this.prevFrameValue = prev;\n    this.prevUpdatedAt = this.updatedAt - delta;\n  }\n  /**\n   * Set the state of the `MotionValue`, stopping any active animations,\n   * effects, and resets velocity to `0`.\n   */\n  jump(v, endAnimation = true) {\n    this.updateAndNotify(v);\n    this.prev = v;\n    this.prevUpdatedAt = this.prevFrameValue = void 0;\n    endAnimation && this.stop();\n    if (this.stopPassiveEffect)\n      this.stopPassiveEffect();\n  }\n  dirty() {\n    this.events.change?.notify(this.current);\n  }\n  addDependent(dependent) {\n    if (!this.dependents) {\n      this.dependents = /* @__PURE__ */ new Set();\n    }\n    this.dependents.add(dependent);\n  }\n  removeDependent(dependent) {\n    if (this.dependents) {\n      this.dependents.delete(dependent);\n    }\n  }\n  /**\n   * Returns the latest state of `MotionValue`\n   *\n   * @returns - The latest state of `MotionValue`\n   *\n   * @public\n   */\n  get() {\n    if (collectMotionValues.current) {\n      collectMotionValues.current.push(this);\n    }\n    return this.current;\n  }\n  /**\n   * @public\n   */\n  getPrevious() {\n    return this.prev;\n  }\n  /**\n   * Returns the latest velocity of `MotionValue`\n   *\n   * @returns - The latest velocity of `MotionValue`. Returns `0` if the state is non-numerical.\n   *\n   * @public\n   */\n  getVelocity() {\n    const currentTime = time.now();\n    if (!this.canTrackVelocity || this.prevFrameValue === void 0 || currentTime - this.updatedAt > MAX_VELOCITY_DELTA) {\n      return 0;\n    }\n    const delta = Math.min(this.updatedAt - this.prevUpdatedAt, MAX_VELOCITY_DELTA);\n    return velocityPerSecond(parseFloat(this.current) - parseFloat(this.prevFrameValue), delta);\n  }\n  /**\n   * Registers a new animation to control this `MotionValue`. Only one\n   * animation can drive a `MotionValue` at one time.\n   *\n   * ```jsx\n   * value.start()\n   * ```\n   *\n   * @param animation - A function that starts the provided animation\n   */\n  start(startAnimation) {\n    this.stop();\n    return new Promise((resolve) => {\n      this.hasAnimated = true;\n      this.animation = startAnimation(resolve);\n      if (this.events.animationStart) {\n        this.events.animationStart.notify();\n      }\n    }).then(() => {\n      if (this.events.animationComplete) {\n        this.events.animationComplete.notify();\n      }\n      this.clearAnimation();\n    });\n  }\n  /**\n   * Stop the currently active animation.\n   *\n   * @public\n   */\n  stop() {\n    if (this.animation) {\n      this.animation.stop();\n      if (this.events.animationCancel) {\n        this.events.animationCancel.notify();\n      }\n    }\n    this.clearAnimation();\n  }\n  /**\n   * Returns `true` if this value is currently animating.\n   *\n   * @public\n   */\n  isAnimating() {\n    return !!this.animation;\n  }\n  clearAnimation() {\n    delete this.animation;\n  }\n  /**\n   * Destroy and clean up subscribers to this `MotionValue`.\n   *\n   * The `MotionValue` hooks like `useMotionValue` and `useTransform` automatically\n   * handle the lifecycle of the returned `MotionValue`, so this method is only necessary if you've manually\n   * created a `MotionValue` via the `motionValue` function.\n   *\n   * @public\n   */\n  destroy() {\n    this.dependents?.clear();\n    this.events.destroy?.notify();\n    this.clearListeners();\n    this.stop();\n    if (this.stopPassiveEffect) {\n      this.stopPassiveEffect();\n    }\n  }\n};\nfunction motionValue(init, options) {\n  return new MotionValue(init, options);\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/utils/resolve-transition.mjs\nfunction resolveTransition(transition, parentTransition) {\n  if (transition?.inherit && parentTransition) {\n    const { inherit: _, ...rest } = transition;\n    return { ...parentTransition, ...rest };\n  }\n  return transition;\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/utils/get-value-transition.mjs\nfunction getValueTransition(transition, key) {\n  const valueTransition = transition?.[key] ?? transition?.[\"default\"] ?? transition;\n  if (valueTransition !== transition) {\n    return resolveTransition(valueTransition, transition);\n  }\n  return valueTransition;\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/utils/default-transitions.mjs\nvar underDampedSpring = {\n  type: \"spring\",\n  stiffness: 500,\n  damping: 25,\n  restSpeed: 10\n};\nvar criticallyDampedSpring = (target) => ({\n  type: \"spring\",\n  stiffness: 550,\n  damping: target === 0 ? 2 * Math.sqrt(550) : 30,\n  restSpeed: 10\n});\nvar keyframesTransition = {\n  type: \"keyframes\",\n  duration: 0.8\n};\nvar ease = {\n  type: \"keyframes\",\n  ease: [0.25, 0.1, 0.35, 1],\n  duration: 0.3\n};\nvar getDefaultTransition = (valueKey, { keyframes: keyframes2 }) => {\n  if (keyframes2.length > 2) {\n    return keyframesTransition;\n  } else if (transformProps.has(valueKey)) {\n    return valueKey.startsWith(\"scale\") ? criticallyDampedSpring(keyframes2[1]) : underDampedSpring;\n  }\n  return ease;\n};\n\n// ../../node_modules/motion-dom/dist/es/animation/utils/is-transition-defined.mjs\nvar orchestrationKeys = /* @__PURE__ */ new Set([\n  \"when\",\n  \"delay\",\n  \"delayChildren\",\n  \"staggerChildren\",\n  \"staggerDirection\",\n  \"repeat\",\n  \"repeatType\",\n  \"repeatDelay\",\n  \"from\",\n  \"elapsed\"\n]);\nfunction isTransitionDefined(transition) {\n  for (const key in transition) {\n    if (!orchestrationKeys.has(key))\n      return true;\n  }\n  return false;\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/interfaces/motion-value.mjs\nvar animateMotionValue = (name, value, target, transition = {}, element, isHandoff) => (onComplete) => {\n  const valueTransition = getValueTransition(transition, name) || {};\n  const delay2 = valueTransition.delay || transition.delay || 0;\n  let { elapsed = 0 } = transition;\n  elapsed = elapsed - secondsToMilliseconds(delay2);\n  const options = {\n    keyframes: Array.isArray(target) ? target : [null, target],\n    ease: \"easeOut\",\n    velocity: value.getVelocity(),\n    ...valueTransition,\n    delay: -elapsed,\n    onUpdate: (v) => {\n      value.set(v);\n      valueTransition.onUpdate && valueTransition.onUpdate(v);\n    },\n    onComplete: () => {\n      onComplete();\n      valueTransition.onComplete && valueTransition.onComplete();\n    },\n    name,\n    motionValue: value,\n    element: isHandoff ? void 0 : element\n  };\n  if (!isTransitionDefined(valueTransition)) {\n    Object.assign(options, getDefaultTransition(name, options));\n  }\n  options.duration && (options.duration = secondsToMilliseconds(options.duration));\n  options.repeatDelay && (options.repeatDelay = secondsToMilliseconds(options.repeatDelay));\n  if (options.from !== void 0) {\n    options.keyframes[0] = options.from;\n  }\n  let shouldSkip = false;\n  if (options.type === false || options.duration === 0 && !options.repeatDelay) {\n    makeAnimationInstant(options);\n    if (options.delay === 0) {\n      shouldSkip = true;\n    }\n  }\n  if (MotionGlobalConfig.instantAnimations || MotionGlobalConfig.skipAnimations || element?.shouldSkipAnimations || valueTransition.skipAnimations) {\n    shouldSkip = true;\n    makeAnimationInstant(options);\n    options.delay = 0;\n  }\n  options.allowFlatten = !valueTransition.type && !valueTransition.ease;\n  if (shouldSkip && !isHandoff && value.get() !== void 0) {\n    const finalKeyframe = getFinalKeyframe(options.keyframes, valueTransition);\n    if (finalKeyframe !== void 0) {\n      frame.update(() => {\n        options.onUpdate(finalKeyframe);\n        options.onComplete();\n      });\n      return;\n    }\n  }\n  return valueTransition.isSync ? new JSAnimation(options) : new AsyncMotionValueAnimation(options);\n};\n\n// ../../node_modules/motion-dom/dist/es/animation/utils/css-variables-conversion.mjs\nvar splitCSSVariableRegex = (\n  // eslint-disable-next-line redos-detector/no-unsafe-regex -- false positive, as it can match a lot of words\n  /^var\\(--(?:([\\w-]+)|([\\w-]+), ?([a-zA-Z\\d ()%#.,-]+))\\)/u\n);\nfunction parseCSSVariable(current) {\n  const match = splitCSSVariableRegex.exec(current);\n  if (!match)\n    return [,];\n  const [, token1, token2, fallback] = match;\n  return [`--${token1 ?? token2}`, fallback];\n}\nvar maxDepth = 4;\nfunction getVariableValue(current, element, depth = 1) {\n  invariant(depth <= maxDepth, `Max CSS variable fallback depth detected in property \"${current}\". This may indicate a circular fallback dependency.`, \"max-css-var-depth\");\n  const [token, fallback] = parseCSSVariable(current);\n  if (!token)\n    return;\n  const resolved = window.getComputedStyle(element).getPropertyValue(token);\n  if (resolved) {\n    const trimmed = resolved.trim();\n    return isNumericalString(trimmed) ? parseFloat(trimmed) : trimmed;\n  }\n  return isCSSVariableToken(fallback) ? getVariableValue(fallback, element, depth + 1) : fallback;\n}\n\n// ../../node_modules/motion-dom/dist/es/render/utils/resolve-variants.mjs\nfunction getValueState(visualElement) {\n  const state = [{}, {}];\n  visualElement?.values.forEach((value, key) => {\n    state[0][key] = value.get();\n    state[1][key] = value.getVelocity();\n  });\n  return state;\n}\nfunction resolveVariantFromProps(props, definition, custom, visualElement) {\n  if (typeof definition === \"function\") {\n    const [current, velocity] = getValueState(visualElement);\n    definition = definition(custom !== void 0 ? custom : props.custom, current, velocity);\n  }\n  if (typeof definition === \"string\") {\n    definition = props.variants && props.variants[definition];\n  }\n  if (typeof definition === \"function\") {\n    const [current, velocity] = getValueState(visualElement);\n    definition = definition(custom !== void 0 ? custom : props.custom, current, velocity);\n  }\n  return definition;\n}\n\n// ../../node_modules/motion-dom/dist/es/render/utils/resolve-dynamic-variants.mjs\nfunction resolveVariant(visualElement, definition, custom) {\n  const props = visualElement.getProps();\n  return resolveVariantFromProps(props, definition, custom !== void 0 ? custom : props.custom, visualElement);\n}\n\n// ../../node_modules/motion-dom/dist/es/render/utils/keys-position.mjs\nvar positionalKeys = /* @__PURE__ */ new Set([\n  \"width\",\n  \"height\",\n  \"top\",\n  \"left\",\n  \"right\",\n  \"bottom\",\n  ...transformPropOrder\n]);\n\n// ../../node_modules/motion-dom/dist/es/render/utils/is-keyframes-target.mjs\nvar isKeyframesTarget = (v) => {\n  return Array.isArray(v);\n};\n\n// ../../node_modules/motion-dom/dist/es/render/utils/setters.mjs\nfunction setMotionValue(visualElement, key, value) {\n  if (visualElement.hasValue(key)) {\n    visualElement.getValue(key).set(value);\n  } else {\n    visualElement.addValue(key, motionValue(value));\n  }\n}\nfunction resolveFinalValueInKeyframes(v) {\n  return isKeyframesTarget(v) ? v[v.length - 1] || 0 : v;\n}\nfunction setTarget(visualElement, definition) {\n  const resolved = resolveVariant(visualElement, definition);\n  let { transitionEnd = {}, transition = {}, ...target } = resolved || {};\n  target = { ...target, ...transitionEnd };\n  for (const key in target) {\n    const value = resolveFinalValueInKeyframes(target[key]);\n    setMotionValue(visualElement, key, value);\n  }\n}\n\n// ../../node_modules/motion-dom/dist/es/value/utils/is-motion-value.mjs\nvar isMotionValue = (value) => Boolean(value && value.getVelocity);\n\n// ../../node_modules/motion-dom/dist/es/value/will-change/is.mjs\nfunction isWillChangeMotionValue(value) {\n  return Boolean(isMotionValue(value) && value.add);\n}\n\n// ../../node_modules/motion-dom/dist/es/value/will-change/add-will-change.mjs\nfunction addValueToWillChange(visualElement, key) {\n  const willChange = visualElement.getValue(\"willChange\");\n  if (isWillChangeMotionValue(willChange)) {\n    return willChange.add(key);\n  } else if (!willChange && MotionGlobalConfig.WillChange) {\n    const newWillChange = new MotionGlobalConfig.WillChange(\"auto\");\n    visualElement.addValue(\"willChange\", newWillChange);\n    newWillChange.add(key);\n  }\n}\n\n// ../../node_modules/motion-dom/dist/es/render/dom/utils/camel-to-dash.mjs\nfunction camelToDash(str) {\n  return str.replace(/([A-Z])/g, (match) => `-${match.toLowerCase()}`);\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/optimized-appear/data-id.mjs\nvar optimizedAppearDataId = \"framerAppearId\";\nvar optimizedAppearDataAttribute = \"data-\" + camelToDash(optimizedAppearDataId);\n\n// ../../node_modules/motion-dom/dist/es/animation/optimized-appear/get-appear-id.mjs\nfunction getOptimisedAppearId(visualElement) {\n  return visualElement.props[optimizedAppearDataAttribute];\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/interfaces/visual-element-target.mjs\nfunction shouldBlockAnimation({ protectedKeys, needsAnimating }, key) {\n  const shouldBlock = protectedKeys.hasOwnProperty(key) && needsAnimating[key] !== true;\n  needsAnimating[key] = false;\n  return shouldBlock;\n}\nfunction animateTarget(visualElement, targetAndTransition, { delay: delay2 = 0, transitionOverride, type } = {}) {\n  let { transition, transitionEnd, ...target } = targetAndTransition;\n  const defaultTransition = visualElement.getDefaultTransition();\n  transition = transition ? resolveTransition(transition, defaultTransition) : defaultTransition;\n  const reduceMotion = transition?.reduceMotion;\n  const skipAnimations = transition?.skipAnimations;\n  if (transitionOverride)\n    transition = transitionOverride;\n  const animations2 = [];\n  const animationTypeState = type && visualElement.animationState && visualElement.animationState.getState()[type];\n  const path = transition?.path;\n  if (path) {\n    path.animateVisualElement(visualElement, target, transition, delay2, animations2);\n  }\n  for (const key in target) {\n    const value = visualElement.getValue(key, visualElement.latestValues[key] ?? null);\n    const valueTarget = target[key];\n    if (valueTarget === void 0 || animationTypeState && shouldBlockAnimation(animationTypeState, key)) {\n      continue;\n    }\n    const valueTransition = {\n      delay: delay2,\n      ...getValueTransition(transition || {}, key)\n    };\n    if (skipAnimations)\n      valueTransition.skipAnimations = true;\n    const currentValue = value.get();\n    if (currentValue !== void 0 && !value.isAnimating() && !Array.isArray(valueTarget) && valueTarget === currentValue && !valueTransition.velocity) {\n      frame.update(() => value.set(valueTarget));\n      continue;\n    }\n    let isHandoff = false;\n    if (window.MotionHandoffAnimation) {\n      const appearId = getOptimisedAppearId(visualElement);\n      if (appearId) {\n        const startTime = window.MotionHandoffAnimation(appearId, key, frame);\n        if (startTime !== null) {\n          valueTransition.startTime = startTime;\n          isHandoff = true;\n        }\n      }\n    }\n    addValueToWillChange(visualElement, key);\n    const shouldReduceMotion = reduceMotion ?? visualElement.shouldReduceMotion;\n    value.start(animateMotionValue(key, value, valueTarget, shouldReduceMotion && positionalKeys.has(key) ? { type: false } : valueTransition, visualElement, isHandoff));\n    const animation = value.animation;\n    if (animation) {\n      animations2.push(animation);\n    }\n  }\n  if (transitionEnd) {\n    const applyTransitionEnd = () => frame.update(() => {\n      transitionEnd && setTarget(visualElement, transitionEnd);\n    });\n    if (animations2.length) {\n      Promise.all(animations2).then(applyTransitionEnd);\n    } else {\n      applyTransitionEnd();\n    }\n  }\n  return animations2;\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/interfaces/visual-element-variant.mjs\nfunction animateVariant(visualElement, variant, options = {}) {\n  const resolved = resolveVariant(visualElement, variant, options.type === \"exit\" ? visualElement.presenceContext?.custom : void 0);\n  let { transition = visualElement.getDefaultTransition() || {} } = resolved || {};\n  if (options.transitionOverride) {\n    transition = options.transitionOverride;\n  }\n  const getAnimation = resolved ? () => Promise.all(animateTarget(visualElement, resolved, options)) : () => Promise.resolve();\n  const getChildAnimations = visualElement.variantChildren && visualElement.variantChildren.size ? (forwardDelay = 0) => {\n    const { delayChildren = 0, staggerChildren, staggerDirection } = transition;\n    return animateChildren(visualElement, variant, forwardDelay, delayChildren, staggerChildren, staggerDirection, options);\n  } : () => Promise.resolve();\n  const { when } = transition;\n  if (when) {\n    const [first, last] = when === \"beforeChildren\" ? [getAnimation, getChildAnimations] : [getChildAnimations, getAnimation];\n    return first().then(() => last());\n  } else {\n    return Promise.all([getAnimation(), getChildAnimations(options.delay)]);\n  }\n}\nfunction animateChildren(visualElement, variant, delay2 = 0, delayChildren = 0, staggerChildren = 0, staggerDirection = 1, options) {\n  const animations2 = [];\n  for (const child of visualElement.variantChildren) {\n    child.notify(\"AnimationStart\", variant);\n    animations2.push(animateVariant(child, variant, {\n      ...options,\n      delay: delay2 + (typeof delayChildren === \"function\" ? 0 : delayChildren) + calcChildStagger(visualElement.variantChildren, child, delayChildren, staggerChildren, staggerDirection)\n    }).then(() => child.notify(\"AnimationComplete\", variant)));\n  }\n  return Promise.all(animations2);\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/interfaces/visual-element.mjs\nfunction animateVisualElement(visualElement, definition, options = {}) {\n  visualElement.notify(\"AnimationStart\", definition);\n  let animation;\n  if (Array.isArray(definition)) {\n    const animations2 = definition.map((variant) => animateVariant(visualElement, variant, options));\n    animation = Promise.all(animations2);\n  } else if (typeof definition === \"string\") {\n    animation = animateVariant(visualElement, definition, options);\n  } else {\n    const resolvedDefinition = typeof definition === \"function\" ? resolveVariant(visualElement, definition, options.custom) : definition;\n    animation = Promise.all(animateTarget(visualElement, resolvedDefinition, options));\n  }\n  return animation.then(() => {\n    visualElement.notify(\"AnimationComplete\", definition);\n  });\n}\n\n// ../../node_modules/motion-dom/dist/es/value/types/auto.mjs\nvar auto = {\n  test: (v) => v === \"auto\",\n  parse: (v) => v\n};\n\n// ../../node_modules/motion-dom/dist/es/value/types/test.mjs\nvar testValueType = (v) => (type) => type.test(v);\n\n// ../../node_modules/motion-dom/dist/es/value/types/dimensions.mjs\nvar dimensionValueTypes = [number, px, percent, degrees, vw, vh, auto];\nvar findDimensionValueType = (v) => dimensionValueTypes.find(testValueType(v));\n\n// ../../node_modules/motion-dom/dist/es/animation/keyframes/utils/is-none.mjs\nfunction isNone(value) {\n  if (typeof value === \"number\") {\n    return value === 0;\n  } else if (value !== null) {\n    return value === \"none\" || value === \"0\" || isZeroValueString(value);\n  } else {\n    return true;\n  }\n}\n\n// ../../node_modules/motion-dom/dist/es/value/types/complex/filter.mjs\nvar maxDefaults = /* @__PURE__ */ new Set([\"brightness\", \"contrast\", \"saturate\", \"opacity\"]);\nfunction applyDefaultFilter(v) {\n  const [name, value] = v.slice(0, -1).split(\"(\");\n  if (name === \"drop-shadow\")\n    return v;\n  const [number2] = value.match(floatRegex) || [];\n  if (!number2)\n    return v;\n  const unit = value.replace(number2, \"\");\n  let defaultValue = maxDefaults.has(name) ? 1 : 0;\n  if (number2 !== value)\n    defaultValue *= 100;\n  return name + \"(\" + defaultValue + unit + \")\";\n}\nvar functionRegex = /\\b([a-z-]*)\\(.*?\\)/gu;\nvar filter = {\n  ...complex,\n  getAnimatableNone: (v) => {\n    const functions = v.match(functionRegex);\n    return functions ? functions.map(applyDefaultFilter).join(\" \") : v;\n  }\n};\n\n// ../../node_modules/motion-dom/dist/es/value/types/complex/mask.mjs\nvar mask = {\n  ...complex,\n  getAnimatableNone: (v) => {\n    const parsed = complex.parse(v);\n    const transformer = complex.createTransformer(v);\n    return transformer(parsed.map((v2) => typeof v2 === \"number\" ? 0 : typeof v2 === \"object\" ? { ...v2, alpha: 1 } : v2));\n  }\n};\n\n// ../../node_modules/motion-dom/dist/es/value/types/int.mjs\nvar int = {\n  ...number,\n  transform: Math.round\n};\n\n// ../../node_modules/motion-dom/dist/es/value/types/maps/transform.mjs\nvar transformValueTypes = {\n  rotate: degrees,\n  /**\n   * Internal channel for `transition.path` orientToPath. Composed onto\n   * `rotate` at the transform-build sites so the user's `rotate` is\n   * never read or overwritten. Not part of `transformPropOrder`.\n   */\n  pathRotation: degrees,\n  rotateX: degrees,\n  rotateY: degrees,\n  rotateZ: degrees,\n  scale,\n  scaleX: scale,\n  scaleY: scale,\n  scaleZ: scale,\n  skew: degrees,\n  skewX: degrees,\n  skewY: degrees,\n  distance: px,\n  translateX: px,\n  translateY: px,\n  translateZ: px,\n  x: px,\n  y: px,\n  z: px,\n  perspective: px,\n  transformPerspective: px,\n  opacity: alpha,\n  originX: progressPercentage,\n  originY: progressPercentage,\n  originZ: px\n};\n\n// ../../node_modules/motion-dom/dist/es/value/types/maps/number.mjs\nvar numberValueTypes = {\n  // Border props\n  borderWidth: px,\n  borderTopWidth: px,\n  borderRightWidth: px,\n  borderBottomWidth: px,\n  borderLeftWidth: px,\n  borderRadius: px,\n  borderTopLeftRadius: px,\n  borderTopRightRadius: px,\n  borderBottomRightRadius: px,\n  borderBottomLeftRadius: px,\n  // Positioning props\n  width: px,\n  maxWidth: px,\n  height: px,\n  maxHeight: px,\n  top: px,\n  right: px,\n  bottom: px,\n  left: px,\n  inset: px,\n  insetBlock: px,\n  insetBlockStart: px,\n  insetBlockEnd: px,\n  insetInline: px,\n  insetInlineStart: px,\n  insetInlineEnd: px,\n  // Spacing props\n  padding: px,\n  paddingTop: px,\n  paddingRight: px,\n  paddingBottom: px,\n  paddingLeft: px,\n  paddingBlock: px,\n  paddingBlockStart: px,\n  paddingBlockEnd: px,\n  paddingInline: px,\n  paddingInlineStart: px,\n  paddingInlineEnd: px,\n  margin: px,\n  marginTop: px,\n  marginRight: px,\n  marginBottom: px,\n  marginLeft: px,\n  marginBlock: px,\n  marginBlockStart: px,\n  marginBlockEnd: px,\n  marginInline: px,\n  marginInlineStart: px,\n  marginInlineEnd: px,\n  // Typography\n  fontSize: px,\n  // Misc\n  backgroundPositionX: px,\n  backgroundPositionY: px,\n  ...transformValueTypes,\n  zIndex: int,\n  // SVG\n  fillOpacity: alpha,\n  strokeOpacity: alpha,\n  numOctaves: int\n};\n\n// ../../node_modules/motion-dom/dist/es/value/types/maps/defaults.mjs\nvar defaultValueTypes = {\n  ...numberValueTypes,\n  // Color props\n  color,\n  backgroundColor: color,\n  outlineColor: color,\n  fill: color,\n  stroke: color,\n  // Border props\n  borderColor: color,\n  borderTopColor: color,\n  borderRightColor: color,\n  borderBottomColor: color,\n  borderLeftColor: color,\n  filter,\n  WebkitFilter: filter,\n  mask,\n  WebkitMask: mask\n};\nvar getDefaultValueType = (key) => defaultValueTypes[key];\n\n// ../../node_modules/motion-dom/dist/es/value/types/utils/animatable-none.mjs\nvar customTypes = /* @__PURE__ */ new Set([filter, mask]);\nfunction getAnimatableNone2(key, value) {\n  let defaultValueType = getDefaultValueType(key);\n  if (!customTypes.has(defaultValueType))\n    defaultValueType = complex;\n  return defaultValueType.getAnimatableNone ? defaultValueType.getAnimatableNone(value) : void 0;\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/keyframes/utils/make-none-animatable.mjs\nvar invalidTemplates = /* @__PURE__ */ new Set([\"auto\", \"none\", \"0\"]);\nfunction makeNoneKeyframesAnimatable(unresolvedKeyframes, noneKeyframeIndexes, name) {\n  let i = 0;\n  let animatableTemplate = void 0;\n  while (i < unresolvedKeyframes.length && !animatableTemplate) {\n    const keyframe = unresolvedKeyframes[i];\n    if (typeof keyframe === \"string\" && !invalidTemplates.has(keyframe) && analyseComplexValue(keyframe).values.length) {\n      animatableTemplate = unresolvedKeyframes[i];\n    }\n    i++;\n  }\n  if (animatableTemplate && name) {\n    for (const noneIndex of noneKeyframeIndexes) {\n      unresolvedKeyframes[noneIndex] = getAnimatableNone2(name, animatableTemplate);\n    }\n  }\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/keyframes/DOMKeyframesResolver.mjs\nvar DOMKeyframesResolver = class extends KeyframeResolver {\n  constructor(unresolvedKeyframes, onComplete, name, motionValue2, element) {\n    super(unresolvedKeyframes, onComplete, name, motionValue2, element, true);\n  }\n  readKeyframes() {\n    const { unresolvedKeyframes, element, name } = this;\n    if (!element || !element.current)\n      return;\n    super.readKeyframes();\n    for (let i = 0; i < unresolvedKeyframes.length; i++) {\n      let keyframe = unresolvedKeyframes[i];\n      if (typeof keyframe === \"string\") {\n        keyframe = keyframe.trim();\n        if (isCSSVariableToken(keyframe)) {\n          const resolved = getVariableValue(keyframe, element.current);\n          if (resolved !== void 0) {\n            unresolvedKeyframes[i] = resolved;\n          }\n          if (i === unresolvedKeyframes.length - 1) {\n            this.finalKeyframe = keyframe;\n          }\n        }\n      }\n    }\n    this.resolveNoneKeyframes();\n    if (!positionalKeys.has(name) || unresolvedKeyframes.length !== 2) {\n      return;\n    }\n    const [origin, target] = unresolvedKeyframes;\n    const originType = findDimensionValueType(origin);\n    const targetType = findDimensionValueType(target);\n    const originHasVar = containsCSSVariable(origin);\n    const targetHasVar = containsCSSVariable(target);\n    if (originHasVar !== targetHasVar && positionalValues[name]) {\n      this.needsMeasurement = true;\n      return;\n    }\n    if (originType === targetType)\n      return;\n    if (isNumOrPxType(originType) && isNumOrPxType(targetType)) {\n      for (let i = 0; i < unresolvedKeyframes.length; i++) {\n        const value = unresolvedKeyframes[i];\n        if (typeof value === \"string\") {\n          unresolvedKeyframes[i] = parseFloat(value);\n        }\n      }\n    } else if (positionalValues[name]) {\n      this.needsMeasurement = true;\n    }\n  }\n  resolveNoneKeyframes() {\n    const { unresolvedKeyframes, name } = this;\n    const noneKeyframeIndexes = [];\n    for (let i = 0; i < unresolvedKeyframes.length; i++) {\n      if (unresolvedKeyframes[i] === null || isNone(unresolvedKeyframes[i])) {\n        noneKeyframeIndexes.push(i);\n      }\n    }\n    if (noneKeyframeIndexes.length) {\n      makeNoneKeyframesAnimatable(unresolvedKeyframes, noneKeyframeIndexes, name);\n    }\n  }\n  measureInitialState() {\n    const { element, unresolvedKeyframes, name } = this;\n    if (!element || !element.current)\n      return;\n    if (name === \"height\") {\n      this.suspendedScrollY = window.pageYOffset;\n    }\n    this.measuredOrigin = positionalValues[name](element.measureViewportBox(), window.getComputedStyle(element.current));\n    unresolvedKeyframes[0] = this.measuredOrigin;\n    const measureKeyframe = unresolvedKeyframes[unresolvedKeyframes.length - 1];\n    if (measureKeyframe !== void 0) {\n      element.getValue(name, measureKeyframe).jump(measureKeyframe, false);\n    }\n  }\n  measureEndState() {\n    const { element, name, unresolvedKeyframes } = this;\n    if (!element || !element.current)\n      return;\n    const value = element.getValue(name);\n    value && value.jump(this.measuredOrigin, false);\n    const finalKeyframeIndex = unresolvedKeyframes.length - 1;\n    const finalKeyframe = unresolvedKeyframes[finalKeyframeIndex];\n    unresolvedKeyframes[finalKeyframeIndex] = positionalValues[name](element.measureViewportBox(), window.getComputedStyle(element.current));\n    if (finalKeyframe !== null && this.finalKeyframe === void 0) {\n      this.finalKeyframe = finalKeyframe;\n    }\n    if (this.removedTransforms?.length) {\n      this.removedTransforms.forEach(([unsetTransformName, unsetTransformValue]) => {\n        element.getValue(unsetTransformName).set(unsetTransformValue);\n      });\n    }\n    this.resolveNoneKeyframes();\n  }\n};\n\n// ../../node_modules/motion-dom/dist/es/utils/border-radius.mjs\nvar cornerRadiusProps = [\n  \"borderTopLeftRadius\",\n  \"borderTopRightRadius\",\n  \"borderBottomRightRadius\",\n  \"borderBottomLeftRadius\"\n];\n\n// ../../node_modules/motion-dom/dist/es/utils/resolve-elements.mjs\nfunction resolveElements(elementOrSelector, scope, selectorCache) {\n  if (elementOrSelector == null) {\n    return [];\n  }\n  if (elementOrSelector instanceof EventTarget) {\n    return [elementOrSelector];\n  } else if (typeof elementOrSelector === \"string\") {\n    let root = document;\n    if (scope) {\n      root = scope.current;\n    }\n    const elements = selectorCache?.[elementOrSelector] ?? root.querySelectorAll(elementOrSelector);\n    return elements ? Array.from(elements) : [];\n  }\n  return Array.from(elementOrSelector).filter((element) => element != null);\n}\n\n// ../../node_modules/motion-dom/dist/es/value/types/utils/get-as-type.mjs\nvar getValueAsType = (value, type) => {\n  return type && typeof value === \"number\" ? type.transform(value) : value;\n};\n\n// ../../node_modules/motion-dom/dist/es/utils/is-html-element.mjs\nfunction isHTMLElement(element) {\n  return isObject(element) && \"offsetHeight\" in element && !(\"ownerSVGElement\" in element);\n}\n\n// ../../node_modules/motion-dom/dist/es/frameloop/microtask.mjs\nvar { schedule: microtask, cancel: cancelMicrotask } = /* @__PURE__ */ createRenderBatcher(queueMicrotask, false);\n\n// ../../node_modules/motion-dom/dist/es/gestures/drag/state/is-active.mjs\nvar isDragging = {\n  x: false,\n  y: false\n};\nfunction isDragActive() {\n  return isDragging.x || isDragging.y;\n}\n\n// ../../node_modules/motion-dom/dist/es/gestures/drag/state/set-active.mjs\nfunction setDragLock(axis) {\n  if (axis === \"x\" || axis === \"y\") {\n    if (isDragging[axis]) {\n      return null;\n    } else {\n      isDragging[axis] = true;\n      return () => {\n        isDragging[axis] = false;\n      };\n    }\n  } else {\n    if (isDragging.x || isDragging.y) {\n      return null;\n    } else {\n      isDragging.x = isDragging.y = true;\n      return () => {\n        isDragging.x = isDragging.y = false;\n      };\n    }\n  }\n}\n\n// ../../node_modules/motion-dom/dist/es/gestures/utils/setup.mjs\nfunction setupGesture(elementOrSelector, options) {\n  const elements = resolveElements(elementOrSelector);\n  const gestureAbortController = new AbortController();\n  const eventOptions = {\n    passive: true,\n    ...options,\n    signal: gestureAbortController.signal\n  };\n  const cancel = () => gestureAbortController.abort();\n  return [elements, eventOptions, cancel];\n}\n\n// ../../node_modules/motion-dom/dist/es/gestures/hover.mjs\nfunction isValidHover(event) {\n  return !(event.pointerType === \"touch\" || isDragActive());\n}\nfunction hover(elementOrSelector, onHoverStart, options = {}) {\n  const [elements, eventOptions, cancel] = setupGesture(elementOrSelector, options);\n  elements.forEach((element) => {\n    let isPressed = false;\n    let deferredHoverEnd = false;\n    let hoverEndCallback;\n    const removePointerLeave = () => {\n      element.removeEventListener(\"pointerleave\", onPointerLeave);\n    };\n    const endHover = (event) => {\n      if (hoverEndCallback) {\n        hoverEndCallback(event);\n        hoverEndCallback = void 0;\n      }\n      removePointerLeave();\n    };\n    const onPointerUp = (event) => {\n      isPressed = false;\n      window.removeEventListener(\"pointerup\", onPointerUp);\n      window.removeEventListener(\"pointercancel\", onPointerUp);\n      if (deferredHoverEnd) {\n        deferredHoverEnd = false;\n        endHover(event);\n      }\n    };\n    const onPointerDown = () => {\n      isPressed = true;\n      window.addEventListener(\"pointerup\", onPointerUp, eventOptions);\n      window.addEventListener(\"pointercancel\", onPointerUp, eventOptions);\n    };\n    const onPointerLeave = (leaveEvent) => {\n      if (leaveEvent.pointerType === \"touch\")\n        return;\n      if (isPressed) {\n        deferredHoverEnd = true;\n        return;\n      }\n      endHover(leaveEvent);\n    };\n    const onPointerEnter = (enterEvent) => {\n      if (!isValidHover(enterEvent))\n        return;\n      deferredHoverEnd = false;\n      const onHoverEnd = onHoverStart(element, enterEvent);\n      if (typeof onHoverEnd !== \"function\")\n        return;\n      hoverEndCallback = onHoverEnd;\n      element.addEventListener(\"pointerleave\", onPointerLeave, eventOptions);\n    };\n    element.addEventListener(\"pointerenter\", onPointerEnter, eventOptions);\n    element.addEventListener(\"pointerdown\", onPointerDown, eventOptions);\n  });\n  return cancel;\n}\n\n// ../../node_modules/motion-dom/dist/es/gestures/utils/is-node-or-child.mjs\nvar isNodeOrChild = (parent, child) => {\n  if (!child) {\n    return false;\n  } else if (parent === child) {\n    return true;\n  } else {\n    return isNodeOrChild(parent, child.parentElement);\n  }\n};\n\n// ../../node_modules/motion-dom/dist/es/gestures/utils/is-primary-pointer.mjs\nvar isPrimaryPointer = (event) => {\n  if (event.pointerType === \"mouse\") {\n    return typeof event.button !== \"number\" || event.button <= 0;\n  } else {\n    return event.isPrimary !== false;\n  }\n};\n\n// ../../node_modules/motion-dom/dist/es/gestures/press/utils/is-keyboard-accessible.mjs\nvar keyboardAccessibleElements = /* @__PURE__ */ new Set([\n  \"BUTTON\",\n  \"INPUT\",\n  \"SELECT\",\n  \"TEXTAREA\",\n  \"A\"\n]);\nfunction isElementKeyboardAccessible(element) {\n  return keyboardAccessibleElements.has(element.tagName) || element.isContentEditable === true;\n}\nvar textInputElements = /* @__PURE__ */ new Set([\"INPUT\", \"SELECT\", \"TEXTAREA\"]);\nfunction isElementTextInput(element) {\n  return textInputElements.has(element.tagName) || element.isContentEditable === true;\n}\n\n// ../../node_modules/motion-dom/dist/es/gestures/press/utils/state.mjs\nvar isPressing = /* @__PURE__ */ new WeakSet();\n\n// ../../node_modules/motion-dom/dist/es/gestures/press/utils/keyboard.mjs\nfunction filterEvents(callback) {\n  return (event) => {\n    if (event.key !== \"Enter\")\n      return;\n    callback(event);\n  };\n}\nfunction firePointerEvent(target, type) {\n  target.dispatchEvent(new PointerEvent(\"pointer\" + type, { isPrimary: true, bubbles: true }));\n}\nvar enableKeyboardPress = (focusEvent, eventOptions) => {\n  const element = focusEvent.currentTarget;\n  if (!element)\n    return;\n  const handleKeydown = filterEvents(() => {\n    if (isPressing.has(element))\n      return;\n    firePointerEvent(element, \"down\");\n    const handleKeyup = filterEvents(() => {\n      firePointerEvent(element, \"up\");\n    });\n    const handleBlur = () => firePointerEvent(element, \"cancel\");\n    element.addEventListener(\"keyup\", handleKeyup, eventOptions);\n    element.addEventListener(\"blur\", handleBlur, eventOptions);\n  });\n  element.addEventListener(\"keydown\", handleKeydown, eventOptions);\n  element.addEventListener(\"blur\", () => element.removeEventListener(\"keydown\", handleKeydown), eventOptions);\n};\n\n// ../../node_modules/motion-dom/dist/es/gestures/press/index.mjs\nfunction isValidPressEvent(event) {\n  return isPrimaryPointer(event) && !isDragActive();\n}\nvar claimedPointerDownEvents = /* @__PURE__ */ new WeakSet();\nfunction press(targetOrSelector, onPressStart, options = {}) {\n  const [targets, eventOptions, cancelEvents] = setupGesture(targetOrSelector, options);\n  const startPress = (startEvent) => {\n    const target = startEvent.currentTarget;\n    if (!isValidPressEvent(startEvent))\n      return;\n    if (claimedPointerDownEvents.has(startEvent))\n      return;\n    isPressing.add(target);\n    if (options.stopPropagation) {\n      claimedPointerDownEvents.add(startEvent);\n    }\n    const onPressEnd = onPressStart(target, startEvent);\n    const endEventOptions = { ...eventOptions, capture: true };\n    const onPointerEnd = (endEvent, success) => {\n      window.removeEventListener(\"pointerup\", onPointerUp, endEventOptions);\n      window.removeEventListener(\"pointercancel\", onPointerCancel, endEventOptions);\n      if (isPressing.has(target)) {\n        isPressing.delete(target);\n      }\n      if (!isValidPressEvent(endEvent)) {\n        return;\n      }\n      if (typeof onPressEnd === \"function\") {\n        onPressEnd(endEvent, { success });\n      }\n    };\n    const onPointerUp = (upEvent) => {\n      onPointerEnd(upEvent, target === window || target === document || options.useGlobalTarget || isNodeOrChild(target, upEvent.target));\n    };\n    const onPointerCancel = (cancelEvent) => {\n      onPointerEnd(cancelEvent, false);\n    };\n    window.addEventListener(\"pointerup\", onPointerUp, endEventOptions);\n    window.addEventListener(\"pointercancel\", onPointerCancel, endEventOptions);\n  };\n  targets.forEach((target) => {\n    const pointerDownTarget = options.useGlobalTarget ? window : target;\n    pointerDownTarget.addEventListener(\"pointerdown\", startPress, eventOptions);\n    if (isHTMLElement(target)) {\n      target.addEventListener(\"focus\", (event) => enableKeyboardPress(event, eventOptions));\n      if (!isElementKeyboardAccessible(target) && !target.hasAttribute(\"tabindex\")) {\n        target.tabIndex = 0;\n      }\n    }\n  });\n  return cancelEvents;\n}\n\n// ../../node_modules/motion-dom/dist/es/utils/is-svg-element.mjs\nfunction isSVGElement(element) {\n  return isObject(element) && \"ownerSVGElement\" in element;\n}\n\n// ../../node_modules/motion-dom/dist/es/resize/handle-element.mjs\nvar resizeHandlers = /* @__PURE__ */ new WeakMap();\nvar observer;\nvar getSize = (borderBoxAxis, svgAxis, htmlAxis) => (target, borderBoxSize) => {\n  if (borderBoxSize && borderBoxSize[0]) {\n    return borderBoxSize[0][borderBoxAxis + \"Size\"];\n  } else if (isSVGElement(target) && \"getBBox\" in target) {\n    return target.getBBox()[svgAxis];\n  } else {\n    return target[htmlAxis];\n  }\n};\nvar getWidth = /* @__PURE__ */ getSize(\"inline\", \"width\", \"offsetWidth\");\nvar getHeight = /* @__PURE__ */ getSize(\"block\", \"height\", \"offsetHeight\");\nfunction notifyTarget({ target, borderBoxSize }) {\n  resizeHandlers.get(target)?.forEach((handler) => {\n    handler(target, {\n      get width() {\n        return getWidth(target, borderBoxSize);\n      },\n      get height() {\n        return getHeight(target, borderBoxSize);\n      }\n    });\n  });\n}\nfunction notifyAll(entries) {\n  entries.forEach(notifyTarget);\n}\nfunction createResizeObserver() {\n  if (typeof ResizeObserver === \"undefined\")\n    return;\n  observer = new ResizeObserver(notifyAll);\n}\nfunction resizeElement(target, handler) {\n  if (!observer)\n    createResizeObserver();\n  const elements = resolveElements(target);\n  elements.forEach((element) => {\n    let elementHandlers = resizeHandlers.get(element);\n    if (!elementHandlers) {\n      elementHandlers = /* @__PURE__ */ new Set();\n      resizeHandlers.set(element, elementHandlers);\n    }\n    elementHandlers.add(handler);\n    observer?.observe(element);\n  });\n  return () => {\n    elements.forEach((element) => {\n      const elementHandlers = resizeHandlers.get(element);\n      elementHandlers?.delete(handler);\n      if (!elementHandlers?.size) {\n        observer?.unobserve(element);\n      }\n    });\n  };\n}\n\n// ../../node_modules/motion-dom/dist/es/resize/handle-window.mjs\nvar windowCallbacks = /* @__PURE__ */ new Set();\nvar windowResizeHandler;\nfunction createWindowResizeHandler() {\n  windowResizeHandler = () => {\n    const info2 = {\n      get width() {\n        return window.innerWidth;\n      },\n      get height() {\n        return window.innerHeight;\n      }\n    };\n    windowCallbacks.forEach((callback) => callback(info2));\n  };\n  window.addEventListener(\"resize\", windowResizeHandler);\n}\nfunction resizeWindow(callback) {\n  windowCallbacks.add(callback);\n  if (!windowResizeHandler)\n    createWindowResizeHandler();\n  return () => {\n    windowCallbacks.delete(callback);\n    if (!windowCallbacks.size && typeof windowResizeHandler === \"function\") {\n      window.removeEventListener(\"resize\", windowResizeHandler);\n      windowResizeHandler = void 0;\n    }\n  };\n}\n\n// ../../node_modules/motion-dom/dist/es/resize/index.mjs\nfunction resize(a, b) {\n  return typeof a === \"function\" ? resizeWindow(a) : resizeElement(a, b);\n}\n\n// ../../node_modules/motion-dom/dist/es/stats/buffer.mjs\nvar statsBuffer = {\n  value: null,\n  addProjectionMetrics: null\n};\n\n// ../../node_modules/motion-dom/dist/es/utils/is-svg-svg-element.mjs\nfunction isSVGSVGElement(element) {\n  return isSVGElement(element) && element.tagName === \"svg\";\n}\n\n// ../../node_modules/motion-dom/dist/es/utils/transform.mjs\nfunction transform(...args) {\n  const useImmediate = !Array.isArray(args[0]);\n  const argOffset = useImmediate ? 0 : -1;\n  const inputValue = args[0 + argOffset];\n  const inputRange = args[1 + argOffset];\n  const outputRange = args[2 + argOffset];\n  const options = args[3 + argOffset];\n  const interpolator = interpolate(inputRange, outputRange, options);\n  return useImmediate ? interpolator(inputValue) : interpolator;\n}\n\n// ../../node_modules/motion-dom/dist/es/value/types/utils/find.mjs\nvar valueTypes = [...dimensionValueTypes, color, complex];\nvar findValueType = (v) => valueTypes.find(testValueType(v));\n\n// ../../node_modules/motion-dom/dist/es/projection/geometry/models.mjs\nvar createAxisDelta = () => ({\n  translate: 0,\n  scale: 1,\n  origin: 0,\n  originPoint: 0\n});\nvar createDelta = () => ({\n  x: createAxisDelta(),\n  y: createAxisDelta()\n});\nvar createAxis = () => ({ min: 0, max: 0 });\nvar createBox = () => ({\n  x: createAxis(),\n  y: createAxis()\n});\n\n// ../../node_modules/motion-dom/dist/es/render/store.mjs\nvar visualElementStore = /* @__PURE__ */ new WeakMap();\n\n// ../../node_modules/motion-dom/dist/es/render/utils/is-animation-controls.mjs\nfunction isAnimationControls(v) {\n  return v !== null && typeof v === \"object\" && typeof v.start === \"function\";\n}\n\n// ../../node_modules/motion-dom/dist/es/render/utils/is-variant-label.mjs\nfunction isVariantLabel(v) {\n  return typeof v === \"string\" || Array.isArray(v);\n}\n\n// ../../node_modules/motion-dom/dist/es/render/utils/variant-props.mjs\nvar variantPriorityOrder = [\n  \"animate\",\n  \"whileInView\",\n  \"whileFocus\",\n  \"whileHover\",\n  \"whileTap\",\n  \"whileDrag\",\n  \"exit\"\n];\nvar variantProps = [\"initial\", ...variantPriorityOrder];\n\n// ../../node_modules/motion-dom/dist/es/render/utils/is-controlling-variants.mjs\nfunction isControllingVariants(props) {\n  return isAnimationControls(props.animate) || variantProps.some((name) => isVariantLabel(props[name]));\n}\nfunction isVariantNode(props) {\n  return Boolean(isControllingVariants(props) || props.variants);\n}\n\n// ../../node_modules/motion-dom/dist/es/render/utils/motion-values.mjs\nfunction updateMotionValuesFromProps(element, next, prev) {\n  for (const key in next) {\n    const nextValue = next[key];\n    const prevValue = prev[key];\n    if (isMotionValue(nextValue)) {\n      element.addValue(key, nextValue);\n    } else if (isMotionValue(prevValue)) {\n      element.addValue(key, motionValue(nextValue, { owner: element }));\n    } else if (prevValue !== nextValue) {\n      if (element.hasValue(key)) {\n        const existingValue = element.getValue(key);\n        if (existingValue.liveStyle === true) {\n          existingValue.jump(nextValue);\n        } else if (!existingValue.hasAnimated) {\n          existingValue.set(nextValue);\n        }\n      } else {\n        const latestValue = element.getStaticValue(key);\n        element.addValue(key, motionValue(latestValue !== void 0 ? latestValue : nextValue, { owner: element }));\n      }\n    }\n  }\n  for (const key in prev) {\n    if (next[key] === void 0)\n      element.removeValue(key);\n  }\n  return next;\n}\n\n// ../../node_modules/motion-dom/dist/es/render/utils/reduced-motion/state.mjs\nvar prefersReducedMotion = { current: null };\nvar hasReducedMotionListener = { current: false };\n\n// ../../node_modules/motion-dom/dist/es/render/utils/reduced-motion/index.mjs\nvar isBrowser2 = typeof window !== \"undefined\";\nfunction initPrefersReducedMotion() {\n  hasReducedMotionListener.current = true;\n  if (!isBrowser2)\n    return;\n  if (window.matchMedia) {\n    const motionMediaQuery = window.matchMedia(\"(prefers-reduced-motion)\");\n    const setReducedMotionPreferences = () => prefersReducedMotion.current = motionMediaQuery.matches;\n    motionMediaQuery.addEventListener(\"change\", setReducedMotionPreferences);\n    setReducedMotionPreferences();\n  } else {\n    prefersReducedMotion.current = false;\n  }\n}\n\n// ../../node_modules/motion-dom/dist/es/render/VisualElement.mjs\nvar propEventHandlers = [\n  \"AnimationStart\",\n  \"AnimationComplete\",\n  \"Update\",\n  \"BeforeLayoutMeasure\",\n  \"LayoutMeasure\",\n  \"LayoutAnimationStart\",\n  \"LayoutAnimationComplete\"\n];\nvar featureDefinitions = {};\nfunction setFeatureDefinitions(definitions) {\n  featureDefinitions = definitions;\n}\nfunction getFeatureDefinitions() {\n  return featureDefinitions;\n}\nvar VisualElement = class {\n  /**\n   * This method takes React props and returns found MotionValues. For example, HTML\n   * MotionValues will be found within the style prop, whereas for Three.js within attribute arrays.\n   *\n   * This isn't an abstract method as it needs calling in the constructor, but it is\n   * intended to be one.\n   */\n  scrapeMotionValuesFromProps(_props, _prevProps, _visualElement) {\n    return {};\n  }\n  constructor({ parent, props, presenceContext, reducedMotionConfig, skipAnimations, blockInitialAnimation, visualState }, options = {}) {\n    this.current = null;\n    this.children = /* @__PURE__ */ new Set();\n    this.isVariantNode = false;\n    this.isControllingVariants = false;\n    this.shouldReduceMotion = null;\n    this.shouldSkipAnimations = false;\n    this.values = /* @__PURE__ */ new Map();\n    this.KeyframeResolver = KeyframeResolver;\n    this.features = {};\n    this.valueSubscriptions = /* @__PURE__ */ new Map();\n    this.prevMotionValues = {};\n    this.hasBeenMounted = false;\n    this.events = {};\n    this.propEventSubscriptions = {};\n    this.notifyUpdate = () => this.notify(\"Update\", this.latestValues);\n    this.render = () => {\n      if (!this.current)\n        return;\n      this.triggerBuild();\n      this.renderInstance(this.current, this.renderState, this.props.style, this.projection);\n    };\n    this.renderScheduledAt = 0;\n    this.scheduleRender = () => {\n      const now2 = time.now();\n      if (this.renderScheduledAt < now2) {\n        this.renderScheduledAt = now2;\n        frame.render(this.render, false, true);\n      }\n    };\n    const { latestValues, renderState } = visualState;\n    this.latestValues = latestValues;\n    this.baseTarget = { ...latestValues };\n    this.initialValues = props.initial ? { ...latestValues } : {};\n    this.renderState = renderState;\n    this.parent = parent;\n    this.props = props;\n    this.presenceContext = presenceContext;\n    this.depth = parent ? parent.depth + 1 : 0;\n    this.reducedMotionConfig = reducedMotionConfig;\n    this.skipAnimationsConfig = skipAnimations;\n    this.options = options;\n    this.blockInitialAnimation = Boolean(blockInitialAnimation);\n    this.isControllingVariants = isControllingVariants(props);\n    this.isVariantNode = isVariantNode(props);\n    if (this.isVariantNode) {\n      this.variantChildren = /* @__PURE__ */ new Set();\n    }\n    this.manuallyAnimateOnMount = Boolean(parent && parent.current);\n    const { willChange, ...initialMotionValues } = this.scrapeMotionValuesFromProps(props, {}, this);\n    for (const key in initialMotionValues) {\n      const value = initialMotionValues[key];\n      if (latestValues[key] !== void 0 && isMotionValue(value)) {\n        value.set(latestValues[key]);\n      }\n    }\n  }\n  mount(instance) {\n    if (this.hasBeenMounted) {\n      for (const key in this.initialValues) {\n        this.values.get(key)?.jump(this.initialValues[key]);\n        this.latestValues[key] = this.initialValues[key];\n      }\n    }\n    this.current = instance;\n    visualElementStore.set(instance, this);\n    if (this.projection && !this.projection.instance) {\n      this.projection.mount(instance);\n    }\n    if (this.parent && this.isVariantNode && !this.isControllingVariants) {\n      this.removeFromVariantTree = this.parent.addVariantChild(this);\n    }\n    this.values.forEach((value, key) => this.bindToMotionValue(key, value));\n    if (this.reducedMotionConfig === \"never\") {\n      this.shouldReduceMotion = false;\n    } else if (this.reducedMotionConfig === \"always\") {\n      this.shouldReduceMotion = true;\n    } else {\n      if (!hasReducedMotionListener.current) {\n        initPrefersReducedMotion();\n      }\n      this.shouldReduceMotion = prefersReducedMotion.current;\n    }\n    if (false) {\n      warnOnce(this.shouldReduceMotion !== true, \"You have Reduced Motion enabled on your device. Animations may not appear as expected.\", \"reduced-motion-disabled\");\n    }\n    this.shouldSkipAnimations = this.skipAnimationsConfig ?? false;\n    this.parent?.addChild(this);\n    this.update(this.props, this.presenceContext);\n    this.hasBeenMounted = true;\n  }\n  unmount() {\n    this.projection && this.projection.unmount();\n    cancelFrame(this.notifyUpdate);\n    cancelFrame(this.render);\n    this.valueSubscriptions.forEach((remove) => remove());\n    this.valueSubscriptions.clear();\n    this.removeFromVariantTree && this.removeFromVariantTree();\n    this.parent?.removeChild(this);\n    for (const key in this.events) {\n      this.events[key].clear();\n    }\n    for (const key in this.features) {\n      const feature = this.features[key];\n      if (feature) {\n        feature.unmount();\n        feature.isMounted = false;\n      }\n    }\n    this.current = null;\n  }\n  addChild(child) {\n    this.children.add(child);\n    this.enteringChildren ?? (this.enteringChildren = /* @__PURE__ */ new Set());\n    this.enteringChildren.add(child);\n  }\n  removeChild(child) {\n    this.children.delete(child);\n    this.enteringChildren && this.enteringChildren.delete(child);\n  }\n  bindToMotionValue(key, value) {\n    if (this.valueSubscriptions.has(key)) {\n      this.valueSubscriptions.get(key)();\n    }\n    if (value.accelerate && acceleratedValues.has(key) && this.current instanceof HTMLElement) {\n      const { factory, keyframes: keyframes2, times, ease: ease2, duration } = value.accelerate;\n      const animation = new NativeAnimation({\n        element: this.current,\n        name: key,\n        keyframes: keyframes2,\n        times,\n        ease: ease2,\n        duration: secondsToMilliseconds(duration)\n      });\n      const cleanup = factory(animation);\n      this.valueSubscriptions.set(key, () => {\n        cleanup();\n        animation.cancel();\n      });\n      return;\n    }\n    const valueIsTransform = transformProps.has(key);\n    if (valueIsTransform && this.onBindTransform) {\n      this.onBindTransform();\n    }\n    const removeOnChange = value.on(\"change\", (latestValue) => {\n      this.latestValues[key] = latestValue;\n      this.props.onUpdate && frame.preRender(this.notifyUpdate);\n      if (valueIsTransform && this.projection) {\n        this.projection.isTransformDirty = true;\n      }\n      this.scheduleRender();\n    });\n    let removeSyncCheck;\n    if (typeof window !== \"undefined\" && window.MotionCheckAppearSync) {\n      removeSyncCheck = window.MotionCheckAppearSync(this, key, value);\n    }\n    this.valueSubscriptions.set(key, () => {\n      removeOnChange();\n      if (removeSyncCheck)\n        removeSyncCheck();\n    });\n  }\n  sortNodePosition(other) {\n    if (!this.current || !this.sortInstanceNodePosition || this.type !== other.type) {\n      return 0;\n    }\n    return this.sortInstanceNodePosition(this.current, other.current);\n  }\n  updateFeatures() {\n    let key = \"animation\";\n    for (key in featureDefinitions) {\n      const featureDefinition = featureDefinitions[key];\n      if (!featureDefinition)\n        continue;\n      const { isEnabled: isEnabled2, Feature: FeatureConstructor } = featureDefinition;\n      if (!this.features[key] && FeatureConstructor && isEnabled2(this.props)) {\n        this.features[key] = new FeatureConstructor(this);\n      }\n      if (this.features[key]) {\n        const feature = this.features[key];\n        if (feature.isMounted) {\n          feature.update();\n        } else {\n          feature.mount();\n          feature.isMounted = true;\n        }\n      }\n    }\n  }\n  triggerBuild() {\n    this.build(this.renderState, this.latestValues, this.props);\n  }\n  /**\n   * Measure the current viewport box with or without transforms.\n   * Only measures axis-aligned boxes, rotate and skew must be manually\n   * removed with a re-render to work.\n   */\n  measureViewportBox() {\n    return this.current ? this.measureInstanceViewportBox(this.current, this.props) : createBox();\n  }\n  getStaticValue(key) {\n    return this.latestValues[key];\n  }\n  setStaticValue(key, value) {\n    this.latestValues[key] = value;\n  }\n  /**\n   * Update the provided props. Ensure any newly-added motion values are\n   * added to our map, old ones removed, and listeners updated.\n   */\n  update(props, presenceContext) {\n    if (props.transformTemplate || this.props.transformTemplate) {\n      this.scheduleRender();\n    }\n    this.prevProps = this.props;\n    this.props = props;\n    this.prevPresenceContext = this.presenceContext;\n    this.presenceContext = presenceContext;\n    for (let i = 0; i < propEventHandlers.length; i++) {\n      const key = propEventHandlers[i];\n      if (this.propEventSubscriptions[key]) {\n        this.propEventSubscriptions[key]();\n        delete this.propEventSubscriptions[key];\n      }\n      const listenerName = \"on\" + key;\n      const listener = props[listenerName];\n      if (listener) {\n        this.propEventSubscriptions[key] = this.on(key, listener);\n      }\n    }\n    this.prevMotionValues = updateMotionValuesFromProps(this, this.scrapeMotionValuesFromProps(props, this.prevProps || {}, this), this.prevMotionValues);\n    if (this.handleChildMotionValue) {\n      this.handleChildMotionValue();\n    }\n  }\n  getProps() {\n    return this.props;\n  }\n  /**\n   * Returns the variant definition with a given name.\n   */\n  getVariant(name) {\n    return this.props.variants ? this.props.variants[name] : void 0;\n  }\n  /**\n   * Returns the defined default transition on this component.\n   */\n  getDefaultTransition() {\n    return this.props.transition;\n  }\n  getTransformPagePoint() {\n    return this.props.transformPagePoint;\n  }\n  getClosestVariantNode() {\n    return this.isVariantNode ? this : this.parent ? this.parent.getClosestVariantNode() : void 0;\n  }\n  /**\n   * Add a child visual element to our set of children.\n   */\n  addVariantChild(child) {\n    const closestVariantNode = this.getClosestVariantNode();\n    if (closestVariantNode) {\n      closestVariantNode.variantChildren && closestVariantNode.variantChildren.add(child);\n      return () => closestVariantNode.variantChildren.delete(child);\n    }\n  }\n  /**\n   * Add a motion value and bind it to this visual element.\n   */\n  addValue(key, value) {\n    const existingValue = this.values.get(key);\n    if (value !== existingValue) {\n      if (existingValue)\n        this.removeValue(key);\n      this.bindToMotionValue(key, value);\n      this.values.set(key, value);\n      this.latestValues[key] = value.get();\n    }\n  }\n  /**\n   * Remove a motion value and unbind any active subscriptions.\n   */\n  removeValue(key) {\n    this.values.delete(key);\n    const unsubscribe = this.valueSubscriptions.get(key);\n    if (unsubscribe) {\n      unsubscribe();\n      this.valueSubscriptions.delete(key);\n    }\n    delete this.latestValues[key];\n    this.removeValueFromRenderState(key, this.renderState);\n  }\n  /**\n   * Check whether we have a motion value for this key\n   */\n  hasValue(key) {\n    return this.values.has(key);\n  }\n  getValue(key, defaultValue) {\n    if (this.props.values && this.props.values[key]) {\n      return this.props.values[key];\n    }\n    let value = this.values.get(key);\n    if (value === void 0 && defaultValue !== void 0) {\n      value = motionValue(defaultValue === null ? void 0 : defaultValue, { owner: this });\n      this.addValue(key, value);\n    }\n    return value;\n  }\n  /**\n   * If we're trying to animate to a previously unencountered value,\n   * we need to check for it in our state and as a last resort read it\n   * directly from the instance (which might have performance implications).\n   */\n  readValue(key, target) {\n    let value = this.latestValues[key] !== void 0 || !this.current ? this.latestValues[key] : this.getBaseTargetFromProps(this.props, key) ?? this.readValueFromInstance(this.current, key, this.options);\n    if (value !== void 0 && value !== null) {\n      if (typeof value === \"string\" && (isNumericalString(value) || isZeroValueString(value))) {\n        value = parseFloat(value);\n      } else if (!findValueType(value) && complex.test(target)) {\n        value = getAnimatableNone2(key, target);\n      }\n      this.setBaseTarget(key, isMotionValue(value) ? value.get() : value);\n    }\n    return isMotionValue(value) ? value.get() : value;\n  }\n  /**\n   * Set the base target to later animate back to. This is currently\n   * only hydrated on creation and when we first read a value.\n   */\n  setBaseTarget(key, value) {\n    this.baseTarget[key] = value;\n  }\n  /**\n   * Find the base target for a value thats been removed from all animation\n   * props.\n   */\n  getBaseTarget(key) {\n    const { initial } = this.props;\n    let valueFromInitial;\n    if (typeof initial === \"string\" || typeof initial === \"object\") {\n      const variant = resolveVariantFromProps(this.props, initial, this.presenceContext?.custom);\n      if (variant) {\n        valueFromInitial = variant[key];\n      }\n    }\n    if (initial && valueFromInitial !== void 0) {\n      return valueFromInitial;\n    }\n    const target = this.getBaseTargetFromProps(this.props, key);\n    if (target !== void 0 && !isMotionValue(target))\n      return target;\n    return this.initialValues[key] !== void 0 && valueFromInitial === void 0 ? void 0 : this.baseTarget[key];\n  }\n  on(eventName, callback) {\n    if (!this.events[eventName]) {\n      this.events[eventName] = new SubscriptionManager();\n    }\n    return this.events[eventName].add(callback);\n  }\n  notify(eventName, ...args) {\n    if (this.events[eventName]) {\n      this.events[eventName].notify(...args);\n    }\n  }\n  scheduleRenderMicrotask() {\n    microtask.render(this.render);\n  }\n};\n\n// ../../node_modules/motion-dom/dist/es/render/dom/DOMVisualElement.mjs\nvar DOMVisualElement = class extends VisualElement {\n  constructor() {\n    super(...arguments);\n    this.KeyframeResolver = DOMKeyframesResolver;\n  }\n  sortInstanceNodePosition(a, b) {\n    return a.compareDocumentPosition(b) & 2 ? 1 : -1;\n  }\n  getBaseTargetFromProps(props, key) {\n    const style = props.style;\n    return style ? style[key] : void 0;\n  }\n  removeValueFromRenderState(key, { vars, style }) {\n    delete vars[key];\n    delete style[key];\n  }\n  handleChildMotionValue() {\n    if (this.childSubscription) {\n      this.childSubscription();\n      delete this.childSubscription;\n    }\n    const { children } = this.props;\n    if (isMotionValue(children)) {\n      this.childSubscription = children.on(\"change\", (latest) => {\n        if (this.current) {\n          this.current.textContent = `${latest}`;\n        }\n      });\n    }\n  }\n};\n\n// ../../node_modules/motion-dom/dist/es/render/Feature.mjs\nvar Feature = class {\n  constructor(node) {\n    this.isMounted = false;\n    this.node = node;\n  }\n  update() {\n  }\n};\n\n// ../../node_modules/motion-dom/dist/es/projection/geometry/conversion.mjs\nfunction convertBoundingBoxToBox({ top, left, right, bottom }) {\n  return {\n    x: { min: left, max: right },\n    y: { min: top, max: bottom }\n  };\n}\nfunction convertBoxToBoundingBox({ x, y }) {\n  return { top: y.min, right: x.max, bottom: y.max, left: x.min };\n}\nfunction transformBoxPoints(point, transformPoint2) {\n  if (!transformPoint2)\n    return point;\n  const topLeft = transformPoint2({ x: point.left, y: point.top });\n  const bottomRight = transformPoint2({ x: point.right, y: point.bottom });\n  return {\n    top: topLeft.y,\n    left: topLeft.x,\n    bottom: bottomRight.y,\n    right: bottomRight.x\n  };\n}\n\n// ../../node_modules/motion-dom/dist/es/projection/utils/has-transform.mjs\nfunction isIdentityScale(scale2) {\n  return scale2 === void 0 || scale2 === 1;\n}\nfunction hasScale({ scale: scale2, scaleX: scaleX2, scaleY: scaleY2 }) {\n  return !isIdentityScale(scale2) || !isIdentityScale(scaleX2) || !isIdentityScale(scaleY2);\n}\nfunction hasTransform(values) {\n  return hasScale(values) || has2DTranslate(values) || values.z || values.rotate || values.rotateX || values.rotateY || values.skewX || values.skewY;\n}\nfunction has2DTranslate(values) {\n  return is2DTranslate(values.x) || is2DTranslate(values.y);\n}\nfunction is2DTranslate(value) {\n  return value && value !== \"0%\";\n}\n\n// ../../node_modules/motion-dom/dist/es/projection/geometry/delta-apply.mjs\nfunction scalePoint(point, scale2, originPoint) {\n  const distanceFromOrigin = point - originPoint;\n  const scaled = scale2 * distanceFromOrigin;\n  return originPoint + scaled;\n}\nfunction applyPointDelta(point, translate, scale2, originPoint, boxScale) {\n  if (boxScale !== void 0) {\n    point = scalePoint(point, boxScale, originPoint);\n  }\n  return scalePoint(point, scale2, originPoint) + translate;\n}\nfunction applyAxisDelta(axis, translate = 0, scale2 = 1, originPoint, boxScale) {\n  axis.min = applyPointDelta(axis.min, translate, scale2, originPoint, boxScale);\n  axis.max = applyPointDelta(axis.max, translate, scale2, originPoint, boxScale);\n}\nfunction applyBoxDelta(box, { x, y }) {\n  applyAxisDelta(box.x, x.translate, x.scale, x.originPoint);\n  applyAxisDelta(box.y, y.translate, y.scale, y.originPoint);\n}\nvar TREE_SCALE_SNAP_MIN = 0.999999999999;\nvar TREE_SCALE_SNAP_MAX = 1.0000000000001;\nfunction applyTreeDeltas(box, treeScale, treePath, isSharedTransition = false) {\n  const treeLength = treePath.length;\n  if (!treeLength)\n    return;\n  treeScale.x = treeScale.y = 1;\n  let node;\n  let delta;\n  for (let i = 0; i < treeLength; i++) {\n    node = treePath[i];\n    delta = node.projectionDelta;\n    const { visualElement } = node.options;\n    if (visualElement && visualElement.props.style && visualElement.props.style.display === \"contents\") {\n      continue;\n    }\n    if (isSharedTransition && node.options.layoutScroll && node.scroll && node !== node.root) {\n      translateAxis(box.x, -node.scroll.offset.x);\n      translateAxis(box.y, -node.scroll.offset.y);\n    }\n    if (delta) {\n      treeScale.x *= delta.x.scale;\n      treeScale.y *= delta.y.scale;\n      applyBoxDelta(box, delta);\n    }\n    if (isSharedTransition && hasTransform(node.latestValues)) {\n      transformBox(box, node.latestValues, node.layout?.layoutBox);\n    }\n  }\n  if (treeScale.x < TREE_SCALE_SNAP_MAX && treeScale.x > TREE_SCALE_SNAP_MIN) {\n    treeScale.x = 1;\n  }\n  if (treeScale.y < TREE_SCALE_SNAP_MAX && treeScale.y > TREE_SCALE_SNAP_MIN) {\n    treeScale.y = 1;\n  }\n}\nfunction translateAxis(axis, distance2) {\n  axis.min += distance2;\n  axis.max += distance2;\n}\nfunction transformAxis(axis, axisTranslate, axisScale, boxScale, axisOrigin = 0.5) {\n  const originPoint = mixNumber(axis.min, axis.max, axisOrigin);\n  applyAxisDelta(axis, axisTranslate, axisScale, originPoint, boxScale);\n}\nfunction resolveAxisTranslate(value, axis) {\n  if (typeof value === \"string\") {\n    return parseFloat(value) / 100 * (axis.max - axis.min);\n  }\n  return value;\n}\nfunction transformBox(box, transform2, sourceBox) {\n  const resolveBox = sourceBox ?? box;\n  transformAxis(box.x, resolveAxisTranslate(transform2.x, resolveBox.x), transform2.scaleX, transform2.scale, transform2.originX);\n  transformAxis(box.y, resolveAxisTranslate(transform2.y, resolveBox.y), transform2.scaleY, transform2.scale, transform2.originY);\n}\n\n// ../../node_modules/motion-dom/dist/es/projection/utils/measure.mjs\nfunction measureViewportBox(instance, transformPoint2) {\n  return convertBoundingBoxToBox(transformBoxPoints(instance.getBoundingClientRect(), transformPoint2));\n}\nfunction measurePageBox(element, rootProjectionNode2, transformPagePoint) {\n  const viewportBox = measureViewportBox(element, transformPagePoint);\n  const { scroll } = rootProjectionNode2;\n  if (scroll) {\n    translateAxis(viewportBox.x, scroll.offset.x);\n    translateAxis(viewportBox.y, scroll.offset.y);\n  }\n  return viewportBox;\n}\n\n// ../../node_modules/motion-dom/dist/es/render/html/utils/build-transform.mjs\nvar translateAlias = {\n  x: \"translateX\",\n  y: \"translateY\",\n  z: \"translateZ\",\n  transformPerspective: \"perspective\"\n};\nvar numTransforms = transformPropOrder.length;\nfunction buildTransform(latestValues, transform2, transformTemplate) {\n  let transformString = \"\";\n  let transformIsDefault = true;\n  for (let i = 0; i < numTransforms; i++) {\n    const key = transformPropOrder[i];\n    const value = latestValues[key];\n    if (value === void 0)\n      continue;\n    let valueIsDefault = true;\n    if (typeof value === \"number\") {\n      valueIsDefault = value === (key.startsWith(\"scale\") ? 1 : 0);\n    } else {\n      const parsed = parseFloat(value);\n      valueIsDefault = key.startsWith(\"scale\") ? parsed === 1 : parsed === 0;\n    }\n    if (!valueIsDefault || transformTemplate) {\n      const valueAsType = getValueAsType(value, numberValueTypes[key]);\n      if (!valueIsDefault) {\n        transformIsDefault = false;\n        const transformName = translateAlias[key] || key;\n        transformString += `${transformName}(${valueAsType}) `;\n      }\n      if (transformTemplate) {\n        transform2[key] = valueAsType;\n      }\n    }\n  }\n  const pathRotation = latestValues.pathRotation;\n  if (pathRotation) {\n    transformIsDefault = false;\n    transformString += `rotate(${getValueAsType(pathRotation, numberValueTypes.pathRotation)}) `;\n  }\n  transformString = transformString.trim();\n  if (transformTemplate) {\n    transformString = transformTemplate(transform2, transformIsDefault ? \"\" : transformString);\n  } else if (transformIsDefault) {\n    transformString = \"none\";\n  }\n  return transformString;\n}\n\n// ../../node_modules/motion-dom/dist/es/render/html/utils/build-styles.mjs\nfunction buildHTMLStyles(state, latestValues, transformTemplate) {\n  const { style, vars, transformOrigin } = state;\n  let hasTransform2 = false;\n  let hasTransformOrigin = false;\n  for (const key in latestValues) {\n    const value = latestValues[key];\n    if (transformProps.has(key)) {\n      hasTransform2 = true;\n      continue;\n    } else if (isCSSVariableName(key)) {\n      vars[key] = value;\n      continue;\n    } else {\n      const valueAsType = getValueAsType(value, numberValueTypes[key]);\n      if (key.startsWith(\"origin\")) {\n        hasTransformOrigin = true;\n        transformOrigin[key] = valueAsType;\n      } else {\n        style[key] = valueAsType;\n      }\n    }\n  }\n  if (!latestValues.transform) {\n    if (hasTransform2 || transformTemplate) {\n      style.transform = buildTransform(latestValues, state.transform, transformTemplate);\n    } else if (style.transform) {\n      style.transform = \"none\";\n    }\n  }\n  if (hasTransformOrigin) {\n    const { originX = \"50%\", originY = \"50%\", originZ = 0 } = transformOrigin;\n    style.transformOrigin = `${originX} ${originY} ${originZ}`;\n  }\n}\n\n// ../../node_modules/motion-dom/dist/es/render/html/utils/render.mjs\nfunction renderHTML(element, { style, vars }, styleProp, projection) {\n  const elementStyle = element.style;\n  let key;\n  for (key in style) {\n    elementStyle[key] = style[key];\n  }\n  projection?.applyProjectionStyles(elementStyle, styleProp);\n  for (key in vars) {\n    elementStyle.setProperty(key, vars[key]);\n  }\n}\n\n// ../../node_modules/motion-dom/dist/es/projection/styles/scale-border-radius.mjs\nfunction pixelsToPercent(pixels, axis) {\n  if (axis.max === axis.min)\n    return 0;\n  return pixels / (axis.max - axis.min) * 100;\n}\nvar correctBorderRadius = {\n  correct: (latest, node) => {\n    if (!node.target)\n      return latest;\n    if (typeof latest === \"string\") {\n      if (px.test(latest)) {\n        latest = parseFloat(latest);\n      } else {\n        return latest;\n      }\n    }\n    const x = pixelsToPercent(latest, node.target.x);\n    const y = pixelsToPercent(latest, node.target.y);\n    return `${x}% ${y}%`;\n  }\n};\n\n// ../../node_modules/motion-dom/dist/es/projection/styles/scale-box-shadow.mjs\nvar correctBoxShadow = {\n  correct: (latest, { treeScale, projectionDelta }) => {\n    const original = latest;\n    const shadow = complex.parse(latest);\n    if (shadow.length > 5)\n      return original;\n    const template = complex.createTransformer(latest);\n    const offset = typeof shadow[0] !== \"number\" ? 1 : 0;\n    const xScale = projectionDelta.x.scale * treeScale.x;\n    const yScale = projectionDelta.y.scale * treeScale.y;\n    shadow[0 + offset] /= xScale;\n    shadow[1 + offset] /= yScale;\n    const averageScale = mixNumber(xScale, yScale, 0.5);\n    if (typeof shadow[2 + offset] === \"number\")\n      shadow[2 + offset] /= averageScale;\n    if (typeof shadow[3 + offset] === \"number\")\n      shadow[3 + offset] /= averageScale;\n    return template(shadow);\n  }\n};\n\n// ../../node_modules/motion-dom/dist/es/projection/styles/scale-correction.mjs\nvar scaleCorrectors = {\n  borderRadius: {\n    ...correctBorderRadius,\n    applyTo: [...cornerRadiusProps]\n  },\n  borderTopLeftRadius: correctBorderRadius,\n  borderTopRightRadius: correctBorderRadius,\n  borderBottomLeftRadius: correctBorderRadius,\n  borderBottomRightRadius: correctBorderRadius,\n  boxShadow: correctBoxShadow\n};\n\n// ../../node_modules/motion-dom/dist/es/render/utils/is-forced-motion-value.mjs\nfunction isForcedMotionValue(key, { layout: layout2, layoutId }) {\n  return transformProps.has(key) || key.startsWith(\"origin\") || (layout2 || layoutId !== void 0) && (!!scaleCorrectors[key] || key === \"opacity\");\n}\n\n// ../../node_modules/motion-dom/dist/es/render/html/utils/scrape-motion-values.mjs\nfunction scrapeMotionValuesFromProps(props, prevProps, visualElement) {\n  const style = props.style;\n  const prevStyle = prevProps?.style;\n  const newValues = {};\n  if (!style)\n    return newValues;\n  for (const key in style) {\n    if (isMotionValue(style[key]) || prevStyle && isMotionValue(prevStyle[key]) || isForcedMotionValue(key, props) || visualElement?.getValue(key)?.liveStyle !== void 0) {\n      newValues[key] = style[key];\n    }\n  }\n  return newValues;\n}\n\n// ../../node_modules/motion-dom/dist/es/render/html/HTMLVisualElement.mjs\nfunction getComputedStyle2(element) {\n  return window.getComputedStyle(element);\n}\nvar HTMLVisualElement = class extends DOMVisualElement {\n  constructor() {\n    super(...arguments);\n    this.type = \"html\";\n    this.renderInstance = renderHTML;\n  }\n  mount(instance) {\n    invariant(Boolean(instance.style), \"motion.create() components must forward their ref to a HTML or SVG element\", \"custom-component-ref\");\n    super.mount(instance);\n  }\n  readValueFromInstance(instance, key) {\n    if (transformProps.has(key)) {\n      return this.projection?.isProjecting ? defaultTransformValue(key) : readTransformValue(instance, key);\n    } else {\n      const computedStyle = getComputedStyle2(instance);\n      const value = (isCSSVariableName(key) ? computedStyle.getPropertyValue(key) : computedStyle[key]) || 0;\n      return typeof value === \"string\" ? value.trim() : value;\n    }\n  }\n  measureInstanceViewportBox(instance, { transformPagePoint }) {\n    return measureViewportBox(instance, transformPagePoint);\n  }\n  build(renderState, latestValues, props) {\n    buildHTMLStyles(renderState, latestValues, props.transformTemplate);\n  }\n  scrapeMotionValuesFromProps(props, prevProps, visualElement) {\n    return scrapeMotionValuesFromProps(props, prevProps, visualElement);\n  }\n};\n\n// ../../node_modules/motion-dom/dist/es/render/object/ObjectVisualElement.mjs\nfunction isObjectKey(key, object) {\n  return key in object;\n}\nvar ObjectVisualElement = class extends VisualElement {\n  constructor() {\n    super(...arguments);\n    this.type = \"object\";\n  }\n  readValueFromInstance(instance, key) {\n    if (isObjectKey(key, instance)) {\n      const value = instance[key];\n      if (typeof value === \"string\" || typeof value === \"number\") {\n        return value;\n      }\n    }\n    return void 0;\n  }\n  getBaseTargetFromProps() {\n    return void 0;\n  }\n  removeValueFromRenderState(key, renderState) {\n    delete renderState.output[key];\n  }\n  measureInstanceViewportBox() {\n    return createBox();\n  }\n  build(renderState, latestValues) {\n    Object.assign(renderState.output, latestValues);\n  }\n  renderInstance(instance, { output }) {\n    Object.assign(instance, output);\n  }\n  sortInstanceNodePosition() {\n    return 0;\n  }\n};\n\n// ../../node_modules/motion-dom/dist/es/render/svg/utils/path.mjs\nvar dashKeys = {\n  offset: \"stroke-dashoffset\",\n  array: \"stroke-dasharray\"\n};\nvar camelKeys = {\n  offset: \"strokeDashoffset\",\n  array: \"strokeDasharray\"\n};\nfunction buildSVGPath(attrs, length, spacing = 1, offset = 0, useDashCase = true) {\n  attrs.pathLength = 1;\n  const keys = useDashCase ? dashKeys : camelKeys;\n  attrs[keys.offset] = `${-offset}`;\n  attrs[keys.array] = `${length} ${spacing}`;\n}\n\n// ../../node_modules/motion-dom/dist/es/render/svg/utils/build-attrs.mjs\nvar cssMotionPathProperties = [\n  \"offsetDistance\",\n  \"offsetPath\",\n  \"offsetRotate\",\n  \"offsetAnchor\"\n];\nfunction buildSVGAttrs(state, {\n  attrX,\n  attrY,\n  attrScale,\n  pathLength,\n  pathSpacing = 1,\n  pathOffset = 0,\n  // This is object creation, which we try to avoid per-frame.\n  ...latest\n}, isSVGTag2, transformTemplate, styleProp) {\n  buildHTMLStyles(state, latest, transformTemplate);\n  if (isSVGTag2) {\n    if (state.style.viewBox) {\n      state.attrs.viewBox = state.style.viewBox;\n    }\n    return;\n  }\n  state.attrs = state.style;\n  state.style = {};\n  const { attrs, style } = state;\n  if (attrs.transform) {\n    style.transform = attrs.transform;\n    delete attrs.transform;\n  }\n  if (style.transform || attrs.transformOrigin) {\n    style.transformOrigin = attrs.transformOrigin ?? \"50% 50%\";\n    delete attrs.transformOrigin;\n  }\n  if (style.transform) {\n    style.transformBox = styleProp?.transformBox ?? \"fill-box\";\n    delete attrs.transformBox;\n  }\n  for (const key of cssMotionPathProperties) {\n    if (attrs[key] !== void 0) {\n      style[key] = attrs[key];\n      delete attrs[key];\n    }\n  }\n  if (attrX !== void 0)\n    attrs.x = attrX;\n  if (attrY !== void 0)\n    attrs.y = attrY;\n  if (attrScale !== void 0)\n    attrs.scale = attrScale;\n  if (pathLength !== void 0) {\n    buildSVGPath(attrs, pathLength, pathSpacing, pathOffset, false);\n  }\n}\n\n// ../../node_modules/motion-dom/dist/es/render/svg/utils/camel-case-attrs.mjs\nvar camelCaseAttributes = /* @__PURE__ */ new Set([\n  \"baseFrequency\",\n  \"diffuseConstant\",\n  \"kernelMatrix\",\n  \"kernelUnitLength\",\n  \"keySplines\",\n  \"keyTimes\",\n  \"limitingConeAngle\",\n  \"markerHeight\",\n  \"markerWidth\",\n  \"numOctaves\",\n  \"targetX\",\n  \"targetY\",\n  \"surfaceScale\",\n  \"specularConstant\",\n  \"specularExponent\",\n  \"stdDeviation\",\n  \"tableValues\",\n  \"viewBox\",\n  \"gradientTransform\",\n  \"pathLength\",\n  \"startOffset\",\n  \"textLength\",\n  \"lengthAdjust\"\n]);\n\n// ../../node_modules/motion-dom/dist/es/render/svg/utils/is-svg-tag.mjs\nvar isSVGTag = (tag) => typeof tag === \"string\" && tag.toLowerCase() === \"svg\";\n\n// ../../node_modules/motion-dom/dist/es/render/svg/utils/render.mjs\nfunction renderSVG(element, renderState, _styleProp, projection) {\n  renderHTML(element, renderState, void 0, projection);\n  for (const key in renderState.attrs) {\n    element.setAttribute(!camelCaseAttributes.has(key) ? camelToDash(key) : key, renderState.attrs[key]);\n  }\n}\n\n// ../../node_modules/motion-dom/dist/es/render/svg/utils/scrape-motion-values.mjs\nfunction scrapeMotionValuesFromProps2(props, prevProps, visualElement) {\n  const newValues = scrapeMotionValuesFromProps(props, prevProps, visualElement);\n  for (const key in props) {\n    if (isMotionValue(props[key]) || isMotionValue(prevProps[key])) {\n      const targetKey = transformPropOrder.indexOf(key) !== -1 ? \"attr\" + key.charAt(0).toUpperCase() + key.substring(1) : key;\n      newValues[targetKey] = props[key];\n    }\n  }\n  return newValues;\n}\n\n// ../../node_modules/motion-dom/dist/es/render/svg/SVGVisualElement.mjs\nvar SVGVisualElement = class extends DOMVisualElement {\n  constructor() {\n    super(...arguments);\n    this.type = \"svg\";\n    this.isSVGTag = false;\n    this.measureInstanceViewportBox = createBox;\n  }\n  getBaseTargetFromProps(props, key) {\n    return props[key];\n  }\n  readValueFromInstance(instance, key) {\n    if (transformProps.has(key)) {\n      const defaultType = getDefaultValueType(key);\n      return defaultType ? defaultType.default || 0 : 0;\n    }\n    key = !camelCaseAttributes.has(key) ? camelToDash(key) : key;\n    return instance.getAttribute(key);\n  }\n  scrapeMotionValuesFromProps(props, prevProps, visualElement) {\n    return scrapeMotionValuesFromProps2(props, prevProps, visualElement);\n  }\n  build(renderState, latestValues, props) {\n    buildSVGAttrs(renderState, latestValues, this.isSVGTag, props.transformTemplate, props.style);\n  }\n  renderInstance(instance, renderState, styleProp, projection) {\n    renderSVG(instance, renderState, styleProp, projection);\n  }\n  mount(instance) {\n    this.isSVGTag = isSVGTag(instance.tagName);\n    super.mount(instance);\n  }\n};\n\n// ../../node_modules/motion-dom/dist/es/render/utils/get-variant-context.mjs\nvar numVariantProps = variantProps.length;\nfunction getVariantContext(visualElement) {\n  if (!visualElement)\n    return void 0;\n  if (!visualElement.isControllingVariants) {\n    const context2 = visualElement.parent ? getVariantContext(visualElement.parent) || {} : {};\n    if (visualElement.props.initial !== void 0) {\n      context2.initial = visualElement.props.initial;\n    }\n    return context2;\n  }\n  const context = {};\n  for (let i = 0; i < numVariantProps; i++) {\n    const name = variantProps[i];\n    const prop = visualElement.props[name];\n    if (isVariantLabel(prop) || prop === false) {\n      context[name] = prop;\n    }\n  }\n  return context;\n}\n\n// ../../node_modules/motion-dom/dist/es/render/utils/shallow-compare.mjs\nfunction shallowCompare(next, prev) {\n  if (!Array.isArray(prev))\n    return false;\n  const prevLength = prev.length;\n  if (prevLength !== next.length)\n    return false;\n  for (let i = 0; i < prevLength; i++) {\n    if (prev[i] !== next[i])\n      return false;\n  }\n  return true;\n}\n\n// ../../node_modules/motion-dom/dist/es/render/utils/animation-state.mjs\nvar reversePriorityOrder = [...variantPriorityOrder].reverse();\nvar numAnimationTypes = variantPriorityOrder.length;\nfunction createAnimateFunction(visualElement) {\n  return (animations2) => {\n    return Promise.all(animations2.map(({ animation, options }) => animateVisualElement(visualElement, animation, options)));\n  };\n}\nfunction createAnimationState(visualElement) {\n  let animate2 = createAnimateFunction(visualElement);\n  let state = createState();\n  let isInitialRender = true;\n  let wasReset = false;\n  const buildResolvedTypeValues = (type) => (acc, definition) => {\n    const resolved = resolveVariant(visualElement, definition, type === \"exit\" ? visualElement.presenceContext?.custom : void 0);\n    if (resolved) {\n      const { transition, transitionEnd, ...target } = resolved;\n      acc = { ...acc, ...target, ...transitionEnd };\n    }\n    return acc;\n  };\n  function setAnimateFunction(makeAnimator) {\n    animate2 = makeAnimator(visualElement);\n  }\n  function animateChanges(changedActiveType) {\n    const { props } = visualElement;\n    const context = getVariantContext(visualElement.parent) || {};\n    const animations2 = [];\n    const removedKeys = /* @__PURE__ */ new Set();\n    let encounteredKeys = {};\n    let removedVariantIndex = Infinity;\n    for (let i = 0; i < numAnimationTypes; i++) {\n      const type = reversePriorityOrder[i];\n      const typeState = state[type];\n      const prop = props[type] !== void 0 ? props[type] : context[type];\n      const propIsVariant = isVariantLabel(prop);\n      const activeDelta = type === changedActiveType ? typeState.isActive : null;\n      if (activeDelta === false)\n        removedVariantIndex = i;\n      let isInherited = prop === context[type] && prop !== props[type] && propIsVariant;\n      if (isInherited && (isInitialRender || wasReset) && visualElement.manuallyAnimateOnMount) {\n        isInherited = false;\n      }\n      typeState.protectedKeys = { ...encounteredKeys };\n      if (\n        // If it isn't active and hasn't *just* been set as inactive\n        !typeState.isActive && activeDelta === null || // If we didn't and don't have any defined prop for this animation type\n        !prop && !typeState.prevProp || // Or if the prop doesn't define an animation\n        isAnimationControls(prop) || typeof prop === \"boolean\"\n      ) {\n        continue;\n      }\n      if (type === \"exit\" && typeState.isActive && activeDelta !== true) {\n        if (typeState.prevResolvedValues) {\n          encounteredKeys = {\n            ...encounteredKeys,\n            ...typeState.prevResolvedValues\n          };\n        }\n        continue;\n      }\n      const variantDidChange = checkVariantsDidChange(typeState.prevProp, prop);\n      let shouldAnimateType = variantDidChange || // If we're making this variant active, we want to always make it active\n      type === changedActiveType && typeState.isActive && !isInherited && propIsVariant || // If we removed a higher-priority variant (i is in reverse order)\n      i > removedVariantIndex && propIsVariant;\n      let handledRemovedValues = false;\n      const definitionList = Array.isArray(prop) ? prop : [prop];\n      let resolvedValues = definitionList.reduce(buildResolvedTypeValues(type), {});\n      if (activeDelta === false)\n        resolvedValues = {};\n      const { prevResolvedValues = {} } = typeState;\n      const allKeys = {\n        ...prevResolvedValues,\n        ...resolvedValues\n      };\n      const markToAnimate = (key) => {\n        shouldAnimateType = true;\n        if (removedKeys.has(key)) {\n          handledRemovedValues = true;\n          removedKeys.delete(key);\n        }\n        typeState.needsAnimating[key] = true;\n        const motionValue2 = visualElement.getValue(key);\n        if (motionValue2)\n          motionValue2.liveStyle = false;\n      };\n      for (const key in allKeys) {\n        const next = resolvedValues[key];\n        const prev = prevResolvedValues[key];\n        if (encounteredKeys.hasOwnProperty(key))\n          continue;\n        let valueHasChanged = false;\n        if (isKeyframesTarget(next) && isKeyframesTarget(prev)) {\n          valueHasChanged = !shallowCompare(next, prev) || variantDidChange;\n        } else {\n          valueHasChanged = next !== prev;\n        }\n        if (valueHasChanged) {\n          if (next !== void 0 && next !== null) {\n            markToAnimate(key);\n          } else {\n            removedKeys.add(key);\n          }\n        } else if (next !== void 0 && removedKeys.has(key)) {\n          markToAnimate(key);\n        } else {\n          typeState.protectedKeys[key] = true;\n        }\n      }\n      typeState.prevProp = prop;\n      typeState.prevResolvedValues = resolvedValues;\n      if (typeState.isActive) {\n        encounteredKeys = { ...encounteredKeys, ...resolvedValues };\n      }\n      if ((isInitialRender || wasReset) && visualElement.blockInitialAnimation) {\n        shouldAnimateType = false;\n      }\n      const willAnimateViaParent = isInherited && variantDidChange;\n      const needsAnimating = !willAnimateViaParent || handledRemovedValues;\n      if (shouldAnimateType && needsAnimating) {\n        animations2.push(...definitionList.map((animation) => {\n          const options = { type };\n          if (typeof animation === \"string\" && (isInitialRender || wasReset) && !willAnimateViaParent && visualElement.manuallyAnimateOnMount && visualElement.parent) {\n            const { parent } = visualElement;\n            const parentVariant = resolveVariant(parent, animation);\n            if (parent.enteringChildren && parentVariant) {\n              const { delayChildren } = parentVariant.transition || {};\n              options.delay = calcChildStagger(parent.enteringChildren, visualElement, delayChildren);\n            }\n          }\n          return {\n            animation,\n            options\n          };\n        }));\n      }\n    }\n    if (removedKeys.size) {\n      const fallbackAnimation = {};\n      if (typeof props.initial !== \"boolean\") {\n        const initialTransition = resolveVariant(visualElement, Array.isArray(props.initial) ? props.initial[0] : props.initial);\n        if (initialTransition && initialTransition.transition) {\n          fallbackAnimation.transition = initialTransition.transition;\n        }\n      }\n      removedKeys.forEach((key) => {\n        const fallbackTarget = visualElement.getBaseTarget(key);\n        const motionValue2 = visualElement.getValue(key);\n        if (motionValue2)\n          motionValue2.liveStyle = true;\n        fallbackAnimation[key] = fallbackTarget ?? null;\n      });\n      animations2.push({ animation: fallbackAnimation });\n    }\n    let shouldAnimate = Boolean(animations2.length);\n    if (isInitialRender && (props.initial === false || props.initial === props.animate) && !visualElement.manuallyAnimateOnMount) {\n      shouldAnimate = false;\n    }\n    isInitialRender = false;\n    wasReset = false;\n    return shouldAnimate ? animate2(animations2) : Promise.resolve();\n  }\n  function setActive(type, isActive) {\n    if (state[type].isActive === isActive)\n      return Promise.resolve();\n    visualElement.variantChildren?.forEach((child) => child.animationState?.setActive(type, isActive));\n    state[type].isActive = isActive;\n    const animations2 = animateChanges(type);\n    for (const key in state) {\n      state[key].protectedKeys = {};\n    }\n    return animations2;\n  }\n  return {\n    animateChanges,\n    setActive,\n    setAnimateFunction,\n    getState: () => state,\n    reset: () => {\n      state = createState();\n      wasReset = true;\n    }\n  };\n}\nfunction checkVariantsDidChange(prev, next) {\n  if (typeof next === \"string\") {\n    return next !== prev;\n  } else if (Array.isArray(next)) {\n    return !shallowCompare(next, prev);\n  }\n  return false;\n}\nfunction createTypeState(isActive = false) {\n  return {\n    isActive,\n    protectedKeys: {},\n    needsAnimating: {},\n    prevResolvedValues: {}\n  };\n}\nfunction createState() {\n  return {\n    animate: createTypeState(true),\n    whileInView: createTypeState(),\n    whileHover: createTypeState(),\n    whileTap: createTypeState(),\n    whileDrag: createTypeState(),\n    whileFocus: createTypeState(),\n    exit: createTypeState()\n  };\n}\n\n// ../../node_modules/motion-dom/dist/es/projection/geometry/copy.mjs\nfunction copyAxisInto(axis, originAxis) {\n  axis.min = originAxis.min;\n  axis.max = originAxis.max;\n}\nfunction copyBoxInto(box, originBox) {\n  copyAxisInto(box.x, originBox.x);\n  copyAxisInto(box.y, originBox.y);\n}\nfunction copyAxisDeltaInto(delta, originDelta) {\n  delta.translate = originDelta.translate;\n  delta.scale = originDelta.scale;\n  delta.originPoint = originDelta.originPoint;\n  delta.origin = originDelta.origin;\n}\n\n// ../../node_modules/motion-dom/dist/es/projection/geometry/delta-calc.mjs\nvar SCALE_PRECISION = 1e-4;\nvar SCALE_MIN = 1 - SCALE_PRECISION;\nvar SCALE_MAX = 1 + SCALE_PRECISION;\nvar TRANSLATE_PRECISION = 0.01;\nvar TRANSLATE_MIN = 0 - TRANSLATE_PRECISION;\nvar TRANSLATE_MAX = 0 + TRANSLATE_PRECISION;\nfunction calcLength(axis) {\n  return axis.max - axis.min;\n}\nfunction isNear(value, target, maxDistance) {\n  return Math.abs(value - target) <= maxDistance;\n}\nfunction calcAxisDelta(delta, source, target, origin = 0.5) {\n  delta.origin = origin;\n  delta.originPoint = mixNumber(source.min, source.max, delta.origin);\n  delta.scale = calcLength(target) / calcLength(source);\n  delta.translate = mixNumber(target.min, target.max, delta.origin) - delta.originPoint;\n  if (delta.scale >= SCALE_MIN && delta.scale <= SCALE_MAX || isNaN(delta.scale)) {\n    delta.scale = 1;\n  }\n  if (delta.translate >= TRANSLATE_MIN && delta.translate <= TRANSLATE_MAX || isNaN(delta.translate)) {\n    delta.translate = 0;\n  }\n}\nfunction calcBoxDelta(delta, source, target, origin) {\n  calcAxisDelta(delta.x, source.x, target.x, origin ? origin.originX : void 0);\n  calcAxisDelta(delta.y, source.y, target.y, origin ? origin.originY : void 0);\n}\nfunction calcRelativeAxis(target, relative, parent, anchor = 0) {\n  const anchorPoint = anchor ? mixNumber(parent.min, parent.max, anchor) : parent.min;\n  target.min = anchorPoint + relative.min;\n  target.max = target.min + calcLength(relative);\n}\nfunction calcRelativeBox(target, relative, parent, anchor) {\n  calcRelativeAxis(target.x, relative.x, parent.x, anchor?.x);\n  calcRelativeAxis(target.y, relative.y, parent.y, anchor?.y);\n}\nfunction calcRelativeAxisPosition(target, layout2, parent, anchor = 0) {\n  const anchorPoint = anchor ? mixNumber(parent.min, parent.max, anchor) : parent.min;\n  target.min = layout2.min - anchorPoint;\n  target.max = target.min + calcLength(layout2);\n}\nfunction calcRelativePosition(target, layout2, parent, anchor) {\n  calcRelativeAxisPosition(target.x, layout2.x, parent.x, anchor?.x);\n  calcRelativeAxisPosition(target.y, layout2.y, parent.y, anchor?.y);\n}\n\n// ../../node_modules/motion-dom/dist/es/projection/geometry/delta-remove.mjs\nfunction removePointDelta(point, translate, scale2, originPoint, boxScale) {\n  point -= translate;\n  point = scalePoint(point, 1 / scale2, originPoint);\n  if (boxScale !== void 0) {\n    point = scalePoint(point, 1 / boxScale, originPoint);\n  }\n  return point;\n}\nfunction removeAxisDelta(axis, translate = 0, scale2 = 1, origin = 0.5, boxScale, originAxis = axis, sourceAxis = axis) {\n  if (percent.test(translate)) {\n    translate = parseFloat(translate);\n    const relativeProgress = mixNumber(sourceAxis.min, sourceAxis.max, translate / 100);\n    translate = relativeProgress - sourceAxis.min;\n  }\n  if (typeof translate !== \"number\")\n    return;\n  let originPoint = mixNumber(originAxis.min, originAxis.max, origin);\n  if (axis === originAxis)\n    originPoint -= translate;\n  axis.min = removePointDelta(axis.min, translate, scale2, originPoint, boxScale);\n  axis.max = removePointDelta(axis.max, translate, scale2, originPoint, boxScale);\n}\nfunction removeAxisTransforms(axis, transforms, [key, scaleKey, originKey], origin, sourceAxis) {\n  removeAxisDelta(axis, transforms[key], transforms[scaleKey], transforms[originKey], transforms.scale, origin, sourceAxis);\n}\nvar xKeys = [\"x\", \"scaleX\", \"originX\"];\nvar yKeys = [\"y\", \"scaleY\", \"originY\"];\nfunction removeBoxTransforms(box, transforms, originBox, sourceBox) {\n  removeAxisTransforms(box.x, transforms, xKeys, originBox ? originBox.x : void 0, sourceBox ? sourceBox.x : void 0);\n  removeAxisTransforms(box.y, transforms, yKeys, originBox ? originBox.y : void 0, sourceBox ? sourceBox.y : void 0);\n}\n\n// ../../node_modules/motion-dom/dist/es/projection/geometry/utils.mjs\nfunction isAxisDeltaZero(delta) {\n  return delta.translate === 0 && delta.scale === 1;\n}\nfunction isDeltaZero(delta) {\n  return isAxisDeltaZero(delta.x) && isAxisDeltaZero(delta.y);\n}\nfunction axisEquals(a, b) {\n  return a.min === b.min && a.max === b.max;\n}\nfunction boxEquals(a, b) {\n  return axisEquals(a.x, b.x) && axisEquals(a.y, b.y);\n}\nfunction axisEqualsRounded(a, b) {\n  return Math.round(a.min) === Math.round(b.min) && Math.round(a.max) === Math.round(b.max);\n}\nfunction boxEqualsRounded(a, b) {\n  return axisEqualsRounded(a.x, b.x) && axisEqualsRounded(a.y, b.y);\n}\nfunction aspectRatio(box) {\n  return calcLength(box.x) / calcLength(box.y);\n}\nfunction axisDeltaEquals(a, b) {\n  return a.translate === b.translate && a.scale === b.scale && a.originPoint === b.originPoint;\n}\n\n// ../../node_modules/motion-dom/dist/es/projection/utils/each-axis.mjs\nfunction eachAxis(callback) {\n  return [callback(\"x\"), callback(\"y\")];\n}\n\n// ../../node_modules/motion-dom/dist/es/projection/styles/transform.mjs\nfunction buildProjectionTransform(delta, treeScale, latestTransform) {\n  let transform2 = \"\";\n  const xTranslate = delta.x.translate / treeScale.x;\n  const yTranslate = delta.y.translate / treeScale.y;\n  const zTranslate = latestTransform?.z || 0;\n  if (xTranslate || yTranslate || zTranslate) {\n    transform2 = `translate3d(${xTranslate}px, ${yTranslate}px, ${zTranslate}px) `;\n  }\n  if (treeScale.x !== 1 || treeScale.y !== 1) {\n    transform2 += `scale(${1 / treeScale.x}, ${1 / treeScale.y}) `;\n  }\n  if (latestTransform) {\n    const { transformPerspective, rotate: rotate2, pathRotation, rotateX, rotateY, skewX, skewY } = latestTransform;\n    if (transformPerspective)\n      transform2 = `perspective(${transformPerspective}px) ${transform2}`;\n    if (rotate2)\n      transform2 += `rotate(${rotate2}deg) `;\n    if (pathRotation)\n      transform2 += `rotate(${pathRotation}deg) `;\n    if (rotateX)\n      transform2 += `rotateX(${rotateX}deg) `;\n    if (rotateY)\n      transform2 += `rotateY(${rotateY}deg) `;\n    if (skewX)\n      transform2 += `skewX(${skewX}deg) `;\n    if (skewY)\n      transform2 += `skewY(${skewY}deg) `;\n  }\n  const elementScaleX = delta.x.scale * treeScale.x;\n  const elementScaleY = delta.y.scale * treeScale.y;\n  if (elementScaleX !== 1 || elementScaleY !== 1) {\n    transform2 += `scale(${elementScaleX}, ${elementScaleY})`;\n  }\n  return transform2 || \"none\";\n}\n\n// ../../node_modules/motion-dom/dist/es/projection/animation/mix-values.mjs\nvar numBorders = cornerRadiusProps.length;\nvar asNumber = (value) => typeof value === \"string\" ? parseFloat(value) : value;\nvar isPx = (value) => typeof value === \"number\" || px.test(value);\nfunction mixValues(target, follow, lead, progress2, shouldCrossfadeOpacity, isOnlyMember) {\n  if (shouldCrossfadeOpacity) {\n    target.opacity = mixNumber(0, lead.opacity ?? 1, easeCrossfadeIn(progress2));\n    target.opacityExit = mixNumber(follow.opacity ?? 1, 0, easeCrossfadeOut(progress2));\n  } else if (isOnlyMember) {\n    target.opacity = mixNumber(follow.opacity ?? 1, lead.opacity ?? 1, progress2);\n  }\n  for (let i = 0; i < numBorders; i++) {\n    const borderLabel = cornerRadiusProps[i];\n    let followRadius = getRadius(follow, borderLabel);\n    let leadRadius = getRadius(lead, borderLabel);\n    if (followRadius === void 0 && leadRadius === void 0)\n      continue;\n    followRadius || (followRadius = 0);\n    leadRadius || (leadRadius = 0);\n    const canMix = followRadius === 0 || leadRadius === 0 || isPx(followRadius) === isPx(leadRadius);\n    if (canMix) {\n      target[borderLabel] = Math.max(mixNumber(asNumber(followRadius), asNumber(leadRadius), progress2), 0);\n      if (percent.test(leadRadius) || percent.test(followRadius)) {\n        target[borderLabel] += \"%\";\n      }\n    } else {\n      target[borderLabel] = leadRadius;\n    }\n  }\n  if (follow.rotate || lead.rotate) {\n    target.rotate = mixNumber(follow.rotate || 0, lead.rotate || 0, progress2);\n  }\n}\nfunction getRadius(values, radiusName) {\n  return values[radiusName] !== void 0 ? values[radiusName] : values.borderRadius;\n}\nvar easeCrossfadeIn = /* @__PURE__ */ compress(0, 0.5, circOut);\nvar easeCrossfadeOut = /* @__PURE__ */ compress(0.5, 0.95, noop);\nfunction compress(min, max, easing) {\n  return (p) => {\n    if (p < min)\n      return 0;\n    if (p > max)\n      return 1;\n    return easing(progress(min, max, p));\n  };\n}\n\n// ../../node_modules/motion-dom/dist/es/animation/animate/single-value.mjs\nfunction animateSingleValue(value, keyframes2, options) {\n  const motionValue$1 = isMotionValue(value) ? value : motionValue(value);\n  motionValue$1.start(animateMotionValue(\"\", motionValue$1, keyframes2, options));\n  return motionValue$1.animation;\n}\n\n// ../../node_modules/motion-dom/dist/es/events/add-dom-event.mjs\nfunction addDomEvent(target, eventName, handler, options = { passive: true }) {\n  target.addEventListener(eventName, handler, options);\n  return () => target.removeEventListener(eventName, handler, options);\n}\n\n// ../../node_modules/motion-dom/dist/es/projection/utils/compare-by-depth.mjs\nvar compareByDepth = (a, b) => a.depth - b.depth;\n\n// ../../node_modules/motion-dom/dist/es/projection/utils/flat-tree.mjs\nvar FlatTree = class {\n  constructor() {\n    this.children = [];\n    this.isDirty = false;\n  }\n  add(child) {\n    addUniqueItem(this.children, child);\n    this.isDirty = true;\n  }\n  remove(child) {\n    removeItem(this.children, child);\n    this.isDirty = true;\n  }\n  forEach(callback) {\n    this.isDirty && this.children.sort(compareByDepth);\n    this.isDirty = false;\n    this.children.forEach(callback);\n  }\n};\n\n// ../../node_modules/motion-dom/dist/es/utils/delay.mjs\nfunction delay(callback, timeout) {\n  const start = time.now();\n  const checkElapsed = ({ timestamp }) => {\n    const elapsed = timestamp - start;\n    if (elapsed >= timeout) {\n      cancelFrame(checkElapsed);\n      callback(elapsed - timeout);\n    }\n  };\n  frame.setup(checkElapsed, true);\n  return () => cancelFrame(checkElapsed);\n}\n\n// ../../node_modules/motion-dom/dist/es/value/utils/resolve-motion-value.mjs\nfunction resolveMotionValue(value) {\n  return isMotionValue(value) ? value.get() : value;\n}\n\n// ../../node_modules/motion-dom/dist/es/projection/shared/stack.mjs\nvar NodeStack = class {\n  constructor() {\n    this.members = [];\n  }\n  add(node) {\n    addUniqueItem(this.members, node);\n    for (let i = this.members.length - 1; i >= 0; i--) {\n      const member = this.members[i];\n      if (member === node || member === this.lead || member === this.prevLead)\n        continue;\n      const inst = member.instance;\n      if ((!inst || inst.isConnected === false) && !member.snapshot) {\n        removeItem(this.members, member);\n        member.unmount();\n      }\n    }\n    node.scheduleRender();\n  }\n  remove(node) {\n    removeItem(this.members, node);\n    if (node === this.prevLead)\n      this.prevLead = void 0;\n    if (node === this.lead) {\n      const prevLead = this.members[this.members.length - 1];\n      if (prevLead)\n        this.promote(prevLead);\n    }\n  }\n  relegate(node) {\n    for (let i = this.members.indexOf(node) - 1; i >= 0; i--) {\n      const member = this.members[i];\n      if (member.isPresent !== false && member.instance?.isConnected !== false) {\n        this.promote(member);\n        return true;\n      }\n    }\n    return false;\n  }\n  promote(node, preserveFollowOpacity) {\n    const prevLead = this.lead;\n    if (node === prevLead)\n      return;\n    this.prevLead = prevLead;\n    this.lead = node;\n    node.show();\n    if (prevLead) {\n      prevLead.updateSnapshot();\n      node.scheduleRender();\n      const { layoutDependency: prevDep } = prevLead.options;\n      const { layoutDependency: nextDep } = node.options;\n      if (prevDep === void 0 || prevDep !== nextDep) {\n        node.resumeFrom = prevLead;\n        if (preserveFollowOpacity)\n          prevLead.preserveOpacity = true;\n        if (prevLead.snapshot) {\n          node.snapshot = prevLead.snapshot;\n          node.snapshot.latestValues = prevLead.animationValues || prevLead.latestValues;\n        }\n        if (node.root?.isUpdating)\n          node.isLayoutDirty = true;\n      }\n      if (node.options.crossfade === false)\n        prevLead.hide();\n    }\n  }\n  exitAnimationComplete() {\n    this.members.forEach((member) => {\n      member.options.onExitComplete?.();\n      member.resumingFrom?.options.onExitComplete?.();\n    });\n  }\n  scheduleRender() {\n    this.members.forEach((member) => member.instance && member.scheduleRender(false));\n  }\n  removeLeadSnapshot() {\n    if (this.lead?.snapshot)\n      this.lead.snapshot = void 0;\n  }\n};\n\n// ../../node_modules/motion-dom/dist/es/projection/node/state.mjs\nvar globalProjectionState = {\n  /**\n   * Global flag as to whether the tree has animated since the last time\n   * we resized the window\n   */\n  hasAnimatedSinceResize: true,\n  /**\n   * We set this to true once, on the first update. Any nodes added to the tree beyond that\n   * update will be given a `data-projection-id` attribute.\n   */\n  hasEverUpdated: false\n};\n\n// ../../node_modules/motion-dom/dist/es/projection/node/create-projection-node.mjs\nvar metrics = {\n  nodes: 0,\n  calculatedTargetDeltas: 0,\n  calculatedProjections: 0\n};\nvar transformAxes = [\"\", \"X\", \"Y\", \"Z\"];\nvar animationTarget = 1e3;\nvar id = 0;\nfunction resetDistortingTransform(key, visualElement, values, sharedAnimationValues) {\n  const { latestValues } = visualElement;\n  if (latestValues[key]) {\n    values[key] = latestValues[key];\n    visualElement.setStaticValue(key, 0);\n    if (sharedAnimationValues) {\n      sharedAnimationValues[key] = 0;\n    }\n  }\n}\nfunction cancelTreeOptimisedTransformAnimations(projectionNode) {\n  projectionNode.hasCheckedOptimisedAppear = true;\n  if (projectionNode.root === projectionNode)\n    return;\n  const { visualElement } = projectionNode.options;\n  if (!visualElement)\n    return;\n  const appearId = getOptimisedAppearId(visualElement);\n  if (window.MotionHasOptimisedAnimation(appearId, \"transform\")) {\n    const { layout: layout2, layoutId } = projectionNode.options;\n    window.MotionCancelOptimisedAnimation(appearId, \"transform\", frame, !(layout2 || layoutId));\n  }\n  const { parent } = projectionNode;\n  if (parent && !parent.hasCheckedOptimisedAppear) {\n    cancelTreeOptimisedTransformAnimations(parent);\n  }\n}\nfunction createProjectionNode({ attachResizeListener, defaultParent, measureScroll, checkIsScrollRoot, resetTransform }) {\n  return class ProjectionNode {\n    constructor(latestValues = {}, parent = defaultParent?.()) {\n      this.id = id++;\n      this.animationId = 0;\n      this.animationCommitId = 0;\n      this.children = /* @__PURE__ */ new Set();\n      this.options = {};\n      this.isTreeAnimating = false;\n      this.isAnimationBlocked = false;\n      this.isLayoutDirty = false;\n      this.isProjectionDirty = false;\n      this.isSharedProjectionDirty = false;\n      this.isTransformDirty = false;\n      this.updateManuallyBlocked = false;\n      this.updateBlockedByResize = false;\n      this.isUpdating = false;\n      this.isSVG = false;\n      this.needsReset = false;\n      this.shouldResetTransform = false;\n      this.hasCheckedOptimisedAppear = false;\n      this.treeScale = { x: 1, y: 1 };\n      this.eventHandlers = /* @__PURE__ */ new Map();\n      this.hasTreeAnimated = false;\n      this.layoutVersion = 0;\n      this.updateScheduled = false;\n      this.scheduleUpdate = () => this.update();\n      this.projectionUpdateScheduled = false;\n      this.checkUpdateFailed = () => {\n        if (this.isUpdating) {\n          this.isUpdating = false;\n          this.clearAllSnapshots();\n        }\n      };\n      this.updateProjection = () => {\n        this.projectionUpdateScheduled = false;\n        if (statsBuffer.value) {\n          metrics.nodes = metrics.calculatedTargetDeltas = metrics.calculatedProjections = 0;\n        }\n        this.nodes.forEach(propagateDirtyNodes);\n        this.nodes.forEach(resolveTargetDelta);\n        this.nodes.forEach(calcProjection);\n        this.nodes.forEach(cleanDirtyNodes);\n        if (statsBuffer.addProjectionMetrics) {\n          statsBuffer.addProjectionMetrics(metrics);\n        }\n      };\n      this.resolvedRelativeTargetAt = 0;\n      this.linkedParentVersion = 0;\n      this.hasProjected = false;\n      this.isVisible = true;\n      this.animationProgress = 0;\n      this.sharedNodes = /* @__PURE__ */ new Map();\n      this.latestValues = latestValues;\n      this.root = parent ? parent.root || parent : this;\n      this.path = parent ? [...parent.path, parent] : [];\n      this.parent = parent;\n      this.depth = parent ? parent.depth + 1 : 0;\n      for (let i = 0; i < this.path.length; i++) {\n        this.path[i].shouldResetTransform = true;\n      }\n      if (this.root === this)\n        this.nodes = new FlatTree();\n    }\n    addEventListener(name, handler) {\n      if (!this.eventHandlers.has(name)) {\n        this.eventHandlers.set(name, new SubscriptionManager());\n      }\n      return this.eventHandlers.get(name).add(handler);\n    }\n    notifyListeners(name, ...args) {\n      const subscriptionManager = this.eventHandlers.get(name);\n      subscriptionManager && subscriptionManager.notify(...args);\n    }\n    hasListeners(name) {\n      return this.eventHandlers.has(name);\n    }\n    /**\n     * Lifecycles\n     */\n    mount(instance) {\n      if (this.instance)\n        return;\n      this.isSVG = isSVGElement(instance) && !isSVGSVGElement(instance);\n      this.instance = instance;\n      const { layoutId, layout: layout2, visualElement } = this.options;\n      if (visualElement && !visualElement.current) {\n        visualElement.mount(instance);\n      }\n      this.root.nodes.add(this);\n      this.parent && this.parent.children.add(this);\n      if (this.root.hasTreeAnimated && (layout2 || layoutId)) {\n        this.isLayoutDirty = true;\n      }\n      if (attachResizeListener) {\n        let cancelDelay;\n        let innerWidth = 0;\n        const resizeUnblockUpdate = () => this.root.updateBlockedByResize = false;\n        frame.read(() => {\n          innerWidth = window.innerWidth;\n        });\n        attachResizeListener(instance, () => {\n          const newInnerWidth = window.innerWidth;\n          if (newInnerWidth === innerWidth)\n            return;\n          innerWidth = newInnerWidth;\n          this.root.updateBlockedByResize = true;\n          cancelDelay && cancelDelay();\n          cancelDelay = delay(resizeUnblockUpdate, 250);\n          if (globalProjectionState.hasAnimatedSinceResize) {\n            globalProjectionState.hasAnimatedSinceResize = false;\n            this.nodes.forEach(finishAnimation);\n          }\n        });\n      }\n      if (layoutId) {\n        this.root.registerSharedNode(layoutId, this);\n      }\n      if (this.options.animate !== false && visualElement && (layoutId || layout2)) {\n        this.addEventListener(\"didUpdate\", ({ delta, hasLayoutChanged, hasRelativeLayoutChanged, layout: newLayout }) => {\n          if (this.isTreeAnimationBlocked()) {\n            this.target = void 0;\n            this.relativeTarget = void 0;\n            return;\n          }\n          const layoutTransition = this.options.transition || visualElement.getDefaultTransition() || defaultLayoutTransition;\n          const { onLayoutAnimationStart, onLayoutAnimationComplete } = visualElement.getProps();\n          const hasTargetChanged = !this.targetLayout || !boxEqualsRounded(this.targetLayout, newLayout);\n          const hasOnlyRelativeTargetChanged = !hasLayoutChanged && hasRelativeLayoutChanged;\n          if (this.options.layoutRoot || this.resumeFrom || hasOnlyRelativeTargetChanged || hasLayoutChanged && (hasTargetChanged || !this.currentAnimation)) {\n            if (this.resumeFrom) {\n              this.resumingFrom = this.resumeFrom;\n              this.resumingFrom.resumingFrom = void 0;\n            }\n            const animationOptions = {\n              ...getValueTransition(layoutTransition, \"layout\"),\n              onPlay: onLayoutAnimationStart,\n              onComplete: onLayoutAnimationComplete\n            };\n            if (visualElement.shouldReduceMotion || this.options.layoutRoot) {\n              animationOptions.delay = 0;\n              animationOptions.type = false;\n            }\n            this.startAnimation(animationOptions);\n            this.setAnimationOrigin(delta, hasOnlyRelativeTargetChanged, animationOptions.path);\n          } else {\n            if (!hasLayoutChanged) {\n              finishAnimation(this);\n            }\n            if (this.isLead() && this.options.onExitComplete) {\n              this.options.onExitComplete();\n            }\n          }\n          this.targetLayout = newLayout;\n        });\n      }\n    }\n    unmount() {\n      this.options.layoutId && this.willUpdate();\n      this.root.nodes.remove(this);\n      const stack = this.getStack();\n      stack && stack.remove(this);\n      this.parent && this.parent.children.delete(this);\n      this.instance = void 0;\n      this.eventHandlers.clear();\n      cancelFrame(this.updateProjection);\n    }\n    // only on the root\n    blockUpdate() {\n      this.updateManuallyBlocked = true;\n    }\n    unblockUpdate() {\n      this.updateManuallyBlocked = false;\n    }\n    isUpdateBlocked() {\n      return this.updateManuallyBlocked || this.updateBlockedByResize;\n    }\n    isTreeAnimationBlocked() {\n      return this.isAnimationBlocked || this.parent && this.parent.isTreeAnimationBlocked() || false;\n    }\n    // Note: currently only running on root node\n    startUpdate() {\n      if (this.isUpdateBlocked())\n        return;\n      this.isUpdating = true;\n      this.nodes && this.nodes.forEach(resetSkewAndRotation);\n      this.animationId++;\n    }\n    getTransformTemplate() {\n      const { visualElement } = this.options;\n      return visualElement && visualElement.getProps().transformTemplate;\n    }\n    willUpdate(shouldNotifyListeners = true) {\n      this.root.hasTreeAnimated = true;\n      if (this.root.isUpdateBlocked()) {\n        this.options.onExitComplete && this.options.onExitComplete();\n        return;\n      }\n      if (window.MotionCancelOptimisedAnimation && !this.hasCheckedOptimisedAppear) {\n        cancelTreeOptimisedTransformAnimations(this);\n      }\n      !this.root.isUpdating && this.root.startUpdate();\n      if (this.isLayoutDirty)\n        return;\n      this.isLayoutDirty = true;\n      for (let i = 0; i < this.path.length; i++) {\n        const node = this.path[i];\n        node.shouldResetTransform = true;\n        if (typeof node.latestValues.x === \"string\" || typeof node.latestValues.y === \"string\") {\n          node.isLayoutDirty = true;\n        }\n        node.updateScroll(\"snapshot\");\n        if (node.options.layoutRoot) {\n          node.willUpdate(false);\n        }\n      }\n      const { layoutId, layout: layout2 } = this.options;\n      if (layoutId === void 0 && !layout2)\n        return;\n      const transformTemplate = this.getTransformTemplate();\n      this.prevTransformTemplateValue = transformTemplate ? transformTemplate(this.latestValues, \"\") : void 0;\n      this.updateSnapshot();\n      shouldNotifyListeners && this.notifyListeners(\"willUpdate\");\n    }\n    update() {\n      this.updateScheduled = false;\n      const updateWasBlocked = this.isUpdateBlocked();\n      if (updateWasBlocked) {\n        const wasBlockedByResize = this.updateBlockedByResize;\n        this.unblockUpdate();\n        this.updateBlockedByResize = false;\n        this.clearAllSnapshots();\n        if (wasBlockedByResize) {\n          this.nodes.forEach(forceLayoutMeasure);\n        }\n        this.nodes.forEach(clearMeasurements);\n        return;\n      }\n      if (this.animationId <= this.animationCommitId) {\n        this.nodes.forEach(clearIsLayoutDirty);\n        return;\n      }\n      this.animationCommitId = this.animationId;\n      if (!this.isUpdating) {\n        this.nodes.forEach(clearIsLayoutDirty);\n      } else {\n        this.isUpdating = false;\n        this.nodes.forEach(ensureDraggedNodesSnapshotted);\n        this.nodes.forEach(resetTransformStyle);\n        this.nodes.forEach(updateLayout);\n        this.nodes.forEach(notifyLayoutUpdate);\n      }\n      this.clearAllSnapshots();\n      const now2 = time.now();\n      frameData.delta = clamp(0, 1e3 / 60, now2 - frameData.timestamp);\n      frameData.timestamp = now2;\n      frameData.isProcessing = true;\n      frameSteps.update.process(frameData);\n      frameSteps.preRender.process(frameData);\n      frameSteps.render.process(frameData);\n      frameData.isProcessing = false;\n    }\n    didUpdate() {\n      if (!this.updateScheduled) {\n        this.updateScheduled = true;\n        microtask.read(this.scheduleUpdate);\n      }\n    }\n    clearAllSnapshots() {\n      this.nodes.forEach(clearSnapshot);\n      this.sharedNodes.forEach(removeLeadSnapshots);\n    }\n    scheduleUpdateProjection() {\n      if (!this.projectionUpdateScheduled) {\n        this.projectionUpdateScheduled = true;\n        frame.preRender(this.updateProjection, false, true);\n      }\n    }\n    scheduleCheckAfterUnmount() {\n      frame.postRender(() => {\n        if (this.isLayoutDirty) {\n          this.root.didUpdate();\n        } else {\n          this.root.checkUpdateFailed();\n        }\n      });\n    }\n    /**\n     * Update measurements\n     */\n    updateSnapshot() {\n      if (this.snapshot || !this.instance)\n        return;\n      this.snapshot = this.measure();\n      if (this.snapshot && !calcLength(this.snapshot.measuredBox.x) && !calcLength(this.snapshot.measuredBox.y)) {\n        this.snapshot = void 0;\n      }\n    }\n    updateLayout() {\n      if (!this.instance)\n        return;\n      this.updateScroll();\n      if (!(this.options.alwaysMeasureLayout && this.isLead()) && !this.isLayoutDirty) {\n        return;\n      }\n      if (this.resumeFrom && !this.resumeFrom.instance) {\n        for (let i = 0; i < this.path.length; i++) {\n          const node = this.path[i];\n          node.updateScroll();\n        }\n      }\n      const prevLayout = this.layout;\n      this.layout = this.measure(false);\n      this.layoutVersion++;\n      if (!this.layoutCorrected)\n        this.layoutCorrected = createBox();\n      this.isLayoutDirty = false;\n      this.projectionDelta = void 0;\n      this.notifyListeners(\"measure\", this.layout.layoutBox);\n      const { visualElement } = this.options;\n      visualElement && visualElement.notify(\"LayoutMeasure\", this.layout.layoutBox, prevLayout ? prevLayout.layoutBox : void 0);\n    }\n    updateScroll(phase = \"measure\") {\n      let needsMeasurement = Boolean(this.options.layoutScroll && this.instance);\n      if (this.scroll && this.scroll.animationId === this.root.animationId && this.scroll.phase === phase) {\n        needsMeasurement = false;\n      }\n      if (needsMeasurement && this.instance) {\n        const isRoot = checkIsScrollRoot(this.instance);\n        this.scroll = {\n          animationId: this.root.animationId,\n          phase,\n          isRoot,\n          offset: measureScroll(this.instance),\n          wasRoot: this.scroll ? this.scroll.isRoot : isRoot\n        };\n      }\n    }\n    resetTransform() {\n      if (!resetTransform)\n        return;\n      const isResetRequested = this.isLayoutDirty || this.shouldResetTransform || this.options.alwaysMeasureLayout;\n      const hasProjection = this.projectionDelta && !isDeltaZero(this.projectionDelta);\n      const transformTemplate = this.getTransformTemplate();\n      const transformTemplateValue = transformTemplate ? transformTemplate(this.latestValues, \"\") : void 0;\n      const transformTemplateHasChanged = transformTemplateValue !== this.prevTransformTemplateValue;\n      if (isResetRequested && this.instance && (hasProjection || hasTransform(this.latestValues) || transformTemplateHasChanged)) {\n        resetTransform(this.instance, transformTemplateValue);\n        this.shouldResetTransform = false;\n        this.scheduleRender();\n      }\n    }\n    measure(removeTransform = true) {\n      const pageBox = this.measurePageBox();\n      let layoutBox = this.removeElementScroll(pageBox);\n      if (removeTransform) {\n        layoutBox = this.removeTransform(layoutBox);\n      }\n      roundBox(layoutBox);\n      return {\n        animationId: this.root.animationId,\n        measuredBox: pageBox,\n        layoutBox,\n        latestValues: {},\n        source: this.id\n      };\n    }\n    measurePageBox() {\n      const { visualElement } = this.options;\n      if (!visualElement)\n        return createBox();\n      const box = visualElement.measureViewportBox();\n      const wasInScrollRoot = this.scroll?.wasRoot || this.path.some(checkNodeWasScrollRoot);\n      if (!wasInScrollRoot) {\n        const { scroll } = this.root;\n        if (scroll) {\n          translateAxis(box.x, scroll.offset.x);\n          translateAxis(box.y, scroll.offset.y);\n        }\n      }\n      return box;\n    }\n    removeElementScroll(box) {\n      const boxWithoutScroll = createBox();\n      copyBoxInto(boxWithoutScroll, box);\n      if (this.scroll?.wasRoot) {\n        return boxWithoutScroll;\n      }\n      for (let i = 0; i < this.path.length; i++) {\n        const node = this.path[i];\n        const { scroll, options } = node;\n        if (node !== this.root && scroll && options.layoutScroll) {\n          if (scroll.wasRoot) {\n            copyBoxInto(boxWithoutScroll, box);\n          }\n          translateAxis(boxWithoutScroll.x, scroll.offset.x);\n          translateAxis(boxWithoutScroll.y, scroll.offset.y);\n        }\n      }\n      return boxWithoutScroll;\n    }\n    applyTransform(box, transformOnly = false, output) {\n      const withTransforms = output || createBox();\n      copyBoxInto(withTransforms, box);\n      for (let i = 0; i < this.path.length; i++) {\n        const node = this.path[i];\n        if (!transformOnly && node.options.layoutScroll && node.scroll && node !== node.root) {\n          translateAxis(withTransforms.x, -node.scroll.offset.x);\n          translateAxis(withTransforms.y, -node.scroll.offset.y);\n        }\n        if (!hasTransform(node.latestValues))\n          continue;\n        transformBox(withTransforms, node.latestValues, node.layout?.layoutBox);\n      }\n      if (hasTransform(this.latestValues)) {\n        transformBox(withTransforms, this.latestValues, this.layout?.layoutBox);\n      }\n      return withTransforms;\n    }\n    removeTransform(box) {\n      const boxWithoutTransform = createBox();\n      copyBoxInto(boxWithoutTransform, box);\n      for (let i = 0; i < this.path.length; i++) {\n        const node = this.path[i];\n        if (!hasTransform(node.latestValues))\n          continue;\n        let sourceBox;\n        if (node.instance) {\n          hasScale(node.latestValues) && node.updateSnapshot();\n          sourceBox = createBox();\n          copyBoxInto(sourceBox, node.measurePageBox());\n        }\n        removeBoxTransforms(boxWithoutTransform, node.latestValues, node.snapshot?.layoutBox, sourceBox);\n      }\n      if (hasTransform(this.latestValues)) {\n        removeBoxTransforms(boxWithoutTransform, this.latestValues);\n      }\n      return boxWithoutTransform;\n    }\n    setTargetDelta(delta) {\n      this.targetDelta = delta;\n      this.root.scheduleUpdateProjection();\n      this.isProjectionDirty = true;\n    }\n    setOptions(options) {\n      this.options = {\n        ...this.options,\n        ...options,\n        crossfade: options.crossfade !== void 0 ? options.crossfade : true\n      };\n    }\n    clearMeasurements() {\n      this.scroll = void 0;\n      this.layout = void 0;\n      this.snapshot = void 0;\n      this.prevTransformTemplateValue = void 0;\n      this.targetDelta = void 0;\n      this.target = void 0;\n      this.isLayoutDirty = false;\n    }\n    forceRelativeParentToResolveTarget() {\n      if (!this.relativeParent)\n        return;\n      if (this.relativeParent.resolvedRelativeTargetAt !== frameData.timestamp) {\n        this.relativeParent.resolveTargetDelta(true);\n      }\n    }\n    resolveTargetDelta(forceRecalculation = false) {\n      const lead = this.getLead();\n      this.isProjectionDirty || (this.isProjectionDirty = lead.isProjectionDirty);\n      this.isTransformDirty || (this.isTransformDirty = lead.isTransformDirty);\n      this.isSharedProjectionDirty || (this.isSharedProjectionDirty = lead.isSharedProjectionDirty);\n      const isShared = Boolean(this.resumingFrom) || this !== lead;\n      const canSkip = !(forceRecalculation || isShared && this.isSharedProjectionDirty || this.isProjectionDirty || this.parent?.isProjectionDirty || this.attemptToResolveRelativeTarget || this.root.updateBlockedByResize);\n      if (canSkip)\n        return;\n      const { layout: layout2, layoutId } = this.options;\n      if (!this.layout || !(layout2 || layoutId))\n        return;\n      this.resolvedRelativeTargetAt = frameData.timestamp;\n      const relativeParent = this.getClosestProjectingParent();\n      if (relativeParent && this.linkedParentVersion !== relativeParent.layoutVersion && !relativeParent.options.layoutRoot) {\n        this.removeRelativeTarget();\n      }\n      if (!this.targetDelta && !this.relativeTarget) {\n        if (this.options.layoutAnchor !== false && relativeParent && relativeParent.layout) {\n          this.createRelativeTarget(relativeParent, this.layout.layoutBox, relativeParent.layout.layoutBox);\n        } else {\n          this.removeRelativeTarget();\n        }\n      }\n      if (!this.relativeTarget && !this.targetDelta)\n        return;\n      if (!this.target) {\n        this.target = createBox();\n        this.targetWithTransforms = createBox();\n      }\n      if (this.relativeTarget && this.relativeTargetOrigin && this.relativeParent && this.relativeParent.target) {\n        this.forceRelativeParentToResolveTarget();\n        calcRelativeBox(this.target, this.relativeTarget, this.relativeParent.target, this.options.layoutAnchor || void 0);\n      } else if (this.targetDelta) {\n        if (Boolean(this.resumingFrom)) {\n          this.applyTransform(this.layout.layoutBox, false, this.target);\n        } else {\n          copyBoxInto(this.target, this.layout.layoutBox);\n        }\n        applyBoxDelta(this.target, this.targetDelta);\n      } else {\n        copyBoxInto(this.target, this.layout.layoutBox);\n      }\n      if (this.attemptToResolveRelativeTarget) {\n        this.attemptToResolveRelativeTarget = false;\n        if (this.options.layoutAnchor !== false && relativeParent && Boolean(relativeParent.resumingFrom) === Boolean(this.resumingFrom) && !relativeParent.options.layoutScroll && relativeParent.target && this.animationProgress !== 1) {\n          this.createRelativeTarget(relativeParent, this.target, relativeParent.target);\n        } else {\n          this.relativeParent = this.relativeTarget = void 0;\n        }\n      }\n      if (statsBuffer.value) {\n        metrics.calculatedTargetDeltas++;\n      }\n    }\n    getClosestProjectingParent() {\n      if (!this.parent || hasScale(this.parent.latestValues) || has2DTranslate(this.parent.latestValues)) {\n        return void 0;\n      }\n      if (this.parent.isProjecting()) {\n        return this.parent;\n      } else {\n        return this.parent.getClosestProjectingParent();\n      }\n    }\n    isProjecting() {\n      return Boolean((this.relativeTarget || this.targetDelta || this.options.layoutRoot) && this.layout);\n    }\n    createRelativeTarget(relativeParent, layout2, parentLayout) {\n      this.relativeParent = relativeParent;\n      this.linkedParentVersion = relativeParent.layoutVersion;\n      this.forceRelativeParentToResolveTarget();\n      this.relativeTarget = createBox();\n      this.relativeTargetOrigin = createBox();\n      calcRelativePosition(this.relativeTargetOrigin, layout2, parentLayout, this.options.layoutAnchor || void 0);\n      copyBoxInto(this.relativeTarget, this.relativeTargetOrigin);\n    }\n    removeRelativeTarget() {\n      this.relativeParent = this.relativeTarget = void 0;\n    }\n    calcProjection() {\n      const lead = this.getLead();\n      const isShared = Boolean(this.resumingFrom) || this !== lead;\n      let canSkip = true;\n      if (this.isProjectionDirty || this.parent?.isProjectionDirty) {\n        canSkip = false;\n      }\n      if (isShared && (this.isSharedProjectionDirty || this.isTransformDirty)) {\n        canSkip = false;\n      }\n      if (this.resolvedRelativeTargetAt === frameData.timestamp) {\n        canSkip = false;\n      }\n      if (canSkip)\n        return;\n      const { layout: layout2, layoutId } = this.options;\n      this.isTreeAnimating = Boolean(this.parent && this.parent.isTreeAnimating || this.currentAnimation || this.pendingAnimation);\n      if (!this.isTreeAnimating) {\n        this.targetDelta = this.relativeTarget = void 0;\n      }\n      if (!this.layout || !(layout2 || layoutId))\n        return;\n      copyBoxInto(this.layoutCorrected, this.layout.layoutBox);\n      const prevTreeScaleX = this.treeScale.x;\n      const prevTreeScaleY = this.treeScale.y;\n      applyTreeDeltas(this.layoutCorrected, this.treeScale, this.path, isShared);\n      if (lead.layout && !lead.target && (this.treeScale.x !== 1 || this.treeScale.y !== 1)) {\n        lead.target = lead.layout.layoutBox;\n        lead.targetWithTransforms = createBox();\n      }\n      const { target } = lead;\n      if (!target) {\n        if (this.prevProjectionDelta) {\n          this.createProjectionDeltas();\n          this.scheduleRender();\n        }\n        return;\n      }\n      if (!this.projectionDelta || !this.prevProjectionDelta) {\n        this.createProjectionDeltas();\n      } else {\n        copyAxisDeltaInto(this.prevProjectionDelta.x, this.projectionDelta.x);\n        copyAxisDeltaInto(this.prevProjectionDelta.y, this.projectionDelta.y);\n      }\n      calcBoxDelta(this.projectionDelta, this.layoutCorrected, target, this.latestValues);\n      if (this.treeScale.x !== prevTreeScaleX || this.treeScale.y !== prevTreeScaleY || !axisDeltaEquals(this.projectionDelta.x, this.prevProjectionDelta.x) || !axisDeltaEquals(this.projectionDelta.y, this.prevProjectionDelta.y)) {\n        this.hasProjected = true;\n        this.scheduleRender();\n        this.notifyListeners(\"projectionUpdate\", target);\n      }\n      if (statsBuffer.value) {\n        metrics.calculatedProjections++;\n      }\n    }\n    hide() {\n      this.isVisible = false;\n    }\n    show() {\n      this.isVisible = true;\n    }\n    scheduleRender(notifyAll2 = true) {\n      this.options.visualElement?.scheduleRender();\n      if (notifyAll2) {\n        const stack = this.getStack();\n        stack && stack.scheduleRender();\n      }\n      if (this.resumingFrom && !this.resumingFrom.instance) {\n        this.resumingFrom = void 0;\n      }\n    }\n    createProjectionDeltas() {\n      this.prevProjectionDelta = createDelta();\n      this.projectionDelta = createDelta();\n      this.projectionDeltaWithTransform = createDelta();\n    }\n    setAnimationOrigin(delta, hasOnlyRelativeTargetChanged = false, pathFn) {\n      const snapshot = this.snapshot;\n      const snapshotLatestValues = snapshot ? snapshot.latestValues : {};\n      const mixedValues = { ...this.latestValues };\n      const targetDelta = createDelta();\n      if (!this.relativeParent || !this.relativeParent.options.layoutRoot) {\n        this.relativeTarget = this.relativeTargetOrigin = void 0;\n      }\n      this.attemptToResolveRelativeTarget = !hasOnlyRelativeTargetChanged;\n      const relativeLayout = createBox();\n      const snapshotSource = snapshot ? snapshot.source : void 0;\n      const layoutSource = this.layout ? this.layout.source : void 0;\n      const isSharedLayoutAnimation = snapshotSource !== layoutSource;\n      const stack = this.getStack();\n      const isOnlyMember = !stack || stack.members.length <= 1;\n      const shouldCrossfadeOpacity = Boolean(isSharedLayoutAnimation && !isOnlyMember && this.options.crossfade === true && !this.path.some(hasOpacityCrossfade));\n      this.animationProgress = 0;\n      let prevRelativeTarget;\n      const interpolate2 = pathFn?.interpolateProjection(delta);\n      this.mixTargetDelta = (latest) => {\n        const progress2 = latest / 1e3;\n        const point = interpolate2?.(progress2);\n        if (point) {\n          targetDelta.x.translate = point.x;\n          targetDelta.x.scale = mixNumber(delta.x.scale, 1, progress2);\n          targetDelta.x.origin = delta.x.origin;\n          targetDelta.x.originPoint = delta.x.originPoint;\n          targetDelta.y.translate = point.y;\n          targetDelta.y.scale = mixNumber(delta.y.scale, 1, progress2);\n          targetDelta.y.origin = delta.y.origin;\n          targetDelta.y.originPoint = delta.y.originPoint;\n        } else {\n          mixAxisDeltaLinear(targetDelta.x, delta.x, progress2);\n          mixAxisDeltaLinear(targetDelta.y, delta.y, progress2);\n        }\n        this.setTargetDelta(targetDelta);\n        if (this.relativeTarget && this.relativeTargetOrigin && this.layout && this.relativeParent && this.relativeParent.layout) {\n          calcRelativePosition(relativeLayout, this.layout.layoutBox, this.relativeParent.layout.layoutBox, this.options.layoutAnchor || void 0);\n          mixBox(this.relativeTarget, this.relativeTargetOrigin, relativeLayout, progress2);\n          if (prevRelativeTarget && boxEquals(this.relativeTarget, prevRelativeTarget)) {\n            this.isProjectionDirty = false;\n          }\n          if (!prevRelativeTarget)\n            prevRelativeTarget = createBox();\n          copyBoxInto(prevRelativeTarget, this.relativeTarget);\n        }\n        if (isSharedLayoutAnimation) {\n          this.animationValues = mixedValues;\n          mixValues(mixedValues, snapshotLatestValues, this.latestValues, progress2, shouldCrossfadeOpacity, isOnlyMember);\n        }\n        if (point && point.rotate !== void 0) {\n          if (!this.animationValues)\n            this.animationValues = mixedValues;\n          this.animationValues.pathRotation = point.rotate;\n        }\n        this.root.scheduleUpdateProjection();\n        this.scheduleRender();\n        this.animationProgress = progress2;\n      };\n      this.mixTargetDelta(this.options.layoutRoot ? 1e3 : 0);\n    }\n    startAnimation(options) {\n      this.notifyListeners(\"animationStart\");\n      this.currentAnimation?.stop();\n      this.resumingFrom?.currentAnimation?.stop();\n      if (this.pendingAnimation) {\n        cancelFrame(this.pendingAnimation);\n        this.pendingAnimation = void 0;\n      }\n      this.pendingAnimation = frame.update(() => {\n        globalProjectionState.hasAnimatedSinceResize = true;\n        this.motionValue || (this.motionValue = motionValue(0));\n        this.motionValue.jump(0, false);\n        this.currentAnimation = animateSingleValue(this.motionValue, [0, 1e3], {\n          ...options,\n          velocity: 0,\n          isSync: true,\n          onUpdate: (latest) => {\n            this.mixTargetDelta(latest);\n            options.onUpdate && options.onUpdate(latest);\n          },\n          onComplete: () => {\n            options.onComplete && options.onComplete();\n            this.completeAnimation();\n          }\n        });\n        if (this.resumingFrom) {\n          this.resumingFrom.currentAnimation = this.currentAnimation;\n        }\n        this.pendingAnimation = void 0;\n      });\n    }\n    completeAnimation() {\n      if (this.resumingFrom) {\n        this.resumingFrom.currentAnimation = void 0;\n        this.resumingFrom.preserveOpacity = void 0;\n      }\n      const stack = this.getStack();\n      stack && stack.exitAnimationComplete();\n      this.resumingFrom = this.currentAnimation = this.animationValues = void 0;\n      this.notifyListeners(\"animationComplete\");\n    }\n    finishAnimation() {\n      if (this.currentAnimation) {\n        this.mixTargetDelta && this.mixTargetDelta(animationTarget);\n        this.currentAnimation.stop();\n      }\n      this.completeAnimation();\n    }\n    applyTransformsToTarget() {\n      const lead = this.getLead();\n      let { targetWithTransforms, target, layout: layout2, latestValues } = lead;\n      if (!targetWithTransforms || !target || !layout2)\n        return;\n      if (this !== lead && this.layout && layout2 && shouldAnimatePositionOnly(this.options.animationType, this.layout.layoutBox, layout2.layoutBox)) {\n        target = this.target || createBox();\n        const xLength = calcLength(this.layout.layoutBox.x);\n        target.x.min = lead.target.x.min;\n        target.x.max = target.x.min + xLength;\n        const yLength = calcLength(this.layout.layoutBox.y);\n        target.y.min = lead.target.y.min;\n        target.y.max = target.y.min + yLength;\n      }\n      copyBoxInto(targetWithTransforms, target);\n      transformBox(targetWithTransforms, latestValues);\n      calcBoxDelta(this.projectionDeltaWithTransform, this.layoutCorrected, targetWithTransforms, latestValues);\n    }\n    registerSharedNode(layoutId, node) {\n      if (!this.sharedNodes.has(layoutId)) {\n        this.sharedNodes.set(layoutId, new NodeStack());\n      }\n      const stack = this.sharedNodes.get(layoutId);\n      stack.add(node);\n      const config = node.options.initialPromotionConfig;\n      node.promote({\n        transition: config ? config.transition : void 0,\n        preserveFollowOpacity: config && config.shouldPreserveFollowOpacity ? config.shouldPreserveFollowOpacity(node) : void 0\n      });\n    }\n    isLead() {\n      const stack = this.getStack();\n      return stack ? stack.lead === this : true;\n    }\n    getLead() {\n      const { layoutId } = this.options;\n      return layoutId ? this.getStack()?.lead || this : this;\n    }\n    getPrevLead() {\n      const { layoutId } = this.options;\n      return layoutId ? this.getStack()?.prevLead : void 0;\n    }\n    getStack() {\n      const { layoutId } = this.options;\n      if (layoutId)\n        return this.root.sharedNodes.get(layoutId);\n    }\n    promote({ needsReset, transition, preserveFollowOpacity } = {}) {\n      const stack = this.getStack();\n      if (stack)\n        stack.promote(this, preserveFollowOpacity);\n      if (needsReset) {\n        this.projectionDelta = void 0;\n        this.needsReset = true;\n      }\n      if (transition)\n        this.setOptions({ transition });\n    }\n    relegate() {\n      const stack = this.getStack();\n      if (stack) {\n        return stack.relegate(this);\n      } else {\n        return false;\n      }\n    }\n    resetSkewAndRotation() {\n      const { visualElement } = this.options;\n      if (!visualElement)\n        return;\n      let hasDistortingTransform = false;\n      const { latestValues } = visualElement;\n      if (latestValues.z || latestValues.rotate || latestValues.rotateX || latestValues.rotateY || latestValues.rotateZ || latestValues.skewX || latestValues.skewY) {\n        hasDistortingTransform = true;\n      }\n      if (!hasDistortingTransform)\n        return;\n      const resetValues = {};\n      if (latestValues.z) {\n        resetDistortingTransform(\"z\", visualElement, resetValues, this.animationValues);\n      }\n      for (let i = 0; i < transformAxes.length; i++) {\n        resetDistortingTransform(`rotate${transformAxes[i]}`, visualElement, resetValues, this.animationValues);\n        resetDistortingTransform(`skew${transformAxes[i]}`, visualElement, resetValues, this.animationValues);\n      }\n      visualElement.render();\n      for (const key in resetValues) {\n        visualElement.setStaticValue(key, resetValues[key]);\n        if (this.animationValues) {\n          this.animationValues[key] = resetValues[key];\n        }\n      }\n      visualElement.scheduleRender();\n    }\n    applyProjectionStyles(targetStyle, styleProp) {\n      if (!this.instance || this.isSVG)\n        return;\n      if (!this.isVisible) {\n        targetStyle.visibility = \"hidden\";\n        return;\n      }\n      const transformTemplate = this.getTransformTemplate();\n      if (this.needsReset) {\n        this.needsReset = false;\n        targetStyle.visibility = \"\";\n        targetStyle.opacity = \"\";\n        targetStyle.pointerEvents = resolveMotionValue(styleProp?.pointerEvents) || \"\";\n        targetStyle.transform = transformTemplate ? transformTemplate(this.latestValues, \"\") : \"none\";\n        return;\n      }\n      const lead = this.getLead();\n      if (!this.projectionDelta || !this.layout || !lead.target) {\n        if (this.options.layoutId) {\n          targetStyle.opacity = this.latestValues.opacity !== void 0 ? this.latestValues.opacity : 1;\n          targetStyle.pointerEvents = resolveMotionValue(styleProp?.pointerEvents) || \"\";\n        }\n        if (this.hasProjected && !hasTransform(this.latestValues)) {\n          targetStyle.transform = transformTemplate ? transformTemplate({}, \"\") : \"none\";\n          this.hasProjected = false;\n        }\n        return;\n      }\n      targetStyle.visibility = \"\";\n      const valuesToRender = lead.animationValues || lead.latestValues;\n      this.applyTransformsToTarget();\n      let transform2 = buildProjectionTransform(this.projectionDeltaWithTransform, this.treeScale, valuesToRender);\n      if (transformTemplate) {\n        transform2 = transformTemplate(valuesToRender, transform2);\n      }\n      targetStyle.transform = transform2;\n      const { x, y } = this.projectionDelta;\n      targetStyle.transformOrigin = `${x.origin * 100}% ${y.origin * 100}% 0`;\n      if (lead.animationValues) {\n        targetStyle.opacity = lead === this ? valuesToRender.opacity ?? this.latestValues.opacity ?? 1 : this.preserveOpacity ? this.latestValues.opacity : valuesToRender.opacityExit;\n      } else {\n        targetStyle.opacity = lead === this ? valuesToRender.opacity !== void 0 ? valuesToRender.opacity : \"\" : valuesToRender.opacityExit !== void 0 ? valuesToRender.opacityExit : 0;\n      }\n      for (const key in scaleCorrectors) {\n        if (valuesToRender[key] === void 0)\n          continue;\n        const { correct, applyTo, isCSSVariable } = scaleCorrectors[key];\n        const corrected = transform2 === \"none\" ? valuesToRender[key] : correct(valuesToRender[key], lead);\n        if (applyTo) {\n          const num = applyTo.length;\n          for (let i = 0; i < num; i++) {\n            targetStyle[applyTo[i]] = corrected;\n          }\n        } else {\n          if (isCSSVariable) {\n            this.options.visualElement.renderState.vars[key] = corrected;\n          } else {\n            targetStyle[key] = corrected;\n          }\n        }\n      }\n      if (this.options.layoutId) {\n        targetStyle.pointerEvents = lead === this ? resolveMotionValue(styleProp?.pointerEvents) || \"\" : \"none\";\n      }\n    }\n    clearSnapshot() {\n      this.resumeFrom = this.snapshot = void 0;\n    }\n    // Only run on root\n    resetTree() {\n      this.root.nodes.forEach((node) => node.currentAnimation?.stop());\n      this.root.nodes.forEach(clearMeasurements);\n      this.root.sharedNodes.clear();\n    }\n  };\n}\nfunction updateLayout(node) {\n  node.updateLayout();\n}\nfunction notifyLayoutUpdate(node) {\n  const snapshot = node.resumeFrom?.snapshot || node.snapshot;\n  if (node.isLead() && node.layout && snapshot && node.hasListeners(\"didUpdate\")) {\n    const { layoutBox: layout2, measuredBox: measuredLayout } = node.layout;\n    const { animationType } = node.options;\n    const isShared = snapshot.source !== node.layout.source;\n    if (animationType === \"size\") {\n      eachAxis((axis) => {\n        const axisSnapshot = isShared ? snapshot.measuredBox[axis] : snapshot.layoutBox[axis];\n        const length = calcLength(axisSnapshot);\n        axisSnapshot.min = layout2[axis].min;\n        axisSnapshot.max = axisSnapshot.min + length;\n      });\n    } else if (animationType === \"x\" || animationType === \"y\") {\n      const snapAxis = animationType === \"x\" ? \"y\" : \"x\";\n      copyAxisInto(isShared ? snapshot.measuredBox[snapAxis] : snapshot.layoutBox[snapAxis], layout2[snapAxis]);\n    } else if (shouldAnimatePositionOnly(animationType, snapshot.layoutBox, layout2)) {\n      eachAxis((axis) => {\n        const axisSnapshot = isShared ? snapshot.measuredBox[axis] : snapshot.layoutBox[axis];\n        const length = calcLength(layout2[axis]);\n        axisSnapshot.max = axisSnapshot.min + length;\n        if (node.relativeTarget && !node.currentAnimation) {\n          node.isProjectionDirty = true;\n          node.relativeTarget[axis].max = node.relativeTarget[axis].min + length;\n        }\n      });\n    }\n    const layoutDelta = createDelta();\n    calcBoxDelta(layoutDelta, layout2, snapshot.layoutBox);\n    const visualDelta = createDelta();\n    if (isShared) {\n      calcBoxDelta(visualDelta, node.applyTransform(measuredLayout, true), snapshot.measuredBox);\n    } else {\n      calcBoxDelta(visualDelta, layout2, snapshot.layoutBox);\n    }\n    const hasLayoutChanged = !isDeltaZero(layoutDelta);\n    let hasRelativeLayoutChanged = false;\n    if (!node.resumeFrom) {\n      const relativeParent = node.getClosestProjectingParent();\n      if (relativeParent && !relativeParent.resumeFrom) {\n        const { snapshot: parentSnapshot, layout: parentLayout } = relativeParent;\n        if (parentSnapshot && parentLayout) {\n          const anchor = node.options.layoutAnchor || void 0;\n          const relativeSnapshot = createBox();\n          calcRelativePosition(relativeSnapshot, snapshot.layoutBox, parentSnapshot.layoutBox, anchor);\n          const relativeLayout = createBox();\n          calcRelativePosition(relativeLayout, layout2, parentLayout.layoutBox, anchor);\n          if (!boxEqualsRounded(relativeSnapshot, relativeLayout)) {\n            hasRelativeLayoutChanged = true;\n          }\n          if (relativeParent.options.layoutRoot) {\n            node.relativeTarget = relativeLayout;\n            node.relativeTargetOrigin = relativeSnapshot;\n            node.relativeParent = relativeParent;\n          }\n        }\n      }\n    }\n    node.notifyListeners(\"didUpdate\", {\n      layout: layout2,\n      snapshot,\n      delta: visualDelta,\n      layoutDelta,\n      hasLayoutChanged,\n      hasRelativeLayoutChanged\n    });\n  } else if (node.isLead()) {\n    const { onExitComplete } = node.options;\n    onExitComplete && onExitComplete();\n  }\n  node.options.transition = void 0;\n}\nfunction propagateDirtyNodes(node) {\n  if (statsBuffer.value) {\n    metrics.nodes++;\n  }\n  if (!node.parent)\n    return;\n  if (!node.isProjecting()) {\n    node.isProjectionDirty = node.parent.isProjectionDirty;\n  }\n  node.isSharedProjectionDirty || (node.isSharedProjectionDirty = Boolean(node.isProjectionDirty || node.parent.isProjectionDirty || node.parent.isSharedProjectionDirty));\n  node.isTransformDirty || (node.isTransformDirty = node.parent.isTransformDirty);\n}\nfunction cleanDirtyNodes(node) {\n  node.isProjectionDirty = node.isSharedProjectionDirty = node.isTransformDirty = false;\n}\nfunction clearSnapshot(node) {\n  node.clearSnapshot();\n}\nfunction clearMeasurements(node) {\n  node.clearMeasurements();\n}\nfunction forceLayoutMeasure(node) {\n  node.isLayoutDirty = true;\n  node.updateLayout();\n}\nfunction clearIsLayoutDirty(node) {\n  node.isLayoutDirty = false;\n}\nfunction ensureDraggedNodesSnapshotted(node) {\n  if (node.isAnimationBlocked && node.layout && !node.isLayoutDirty) {\n    node.snapshot = node.layout;\n    node.isLayoutDirty = true;\n  }\n}\nfunction resetTransformStyle(node) {\n  const { visualElement } = node.options;\n  if (visualElement && visualElement.getProps().onBeforeLayoutMeasure) {\n    visualElement.notify(\"BeforeLayoutMeasure\");\n  }\n  node.resetTransform();\n}\nfunction finishAnimation(node) {\n  node.finishAnimation();\n  node.targetDelta = node.relativeTarget = node.target = void 0;\n  node.isProjectionDirty = true;\n}\nfunction resolveTargetDelta(node) {\n  node.resolveTargetDelta();\n}\nfunction calcProjection(node) {\n  node.calcProjection();\n}\nfunction resetSkewAndRotation(node) {\n  node.resetSkewAndRotation();\n}\nfunction removeLeadSnapshots(stack) {\n  stack.removeLeadSnapshot();\n}\nfunction mixAxisDeltaLinear(output, delta, p) {\n  output.translate = mixNumber(delta.translate, 0, p);\n  output.scale = mixNumber(delta.scale, 1, p);\n  output.origin = delta.origin;\n  output.originPoint = delta.originPoint;\n}\nfunction mixAxis(output, from, to, p) {\n  output.min = mixNumber(from.min, to.min, p);\n  output.max = mixNumber(from.max, to.max, p);\n}\nfunction mixBox(output, from, to, p) {\n  mixAxis(output.x, from.x, to.x, p);\n  mixAxis(output.y, from.y, to.y, p);\n}\nfunction hasOpacityCrossfade(node) {\n  return node.animationValues && node.animationValues.opacityExit !== void 0;\n}\nvar defaultLayoutTransition = {\n  duration: 0.45,\n  ease: [0.4, 0, 0.1, 1]\n};\nvar userAgentContains = (string) => typeof navigator !== \"undefined\" && navigator.userAgent && navigator.userAgent.toLowerCase().includes(string);\nvar roundPoint = userAgentContains(\"applewebkit/\") && !userAgentContains(\"chrome/\") ? Math.round : noop;\nfunction roundAxis(axis) {\n  axis.min = roundPoint(axis.min);\n  axis.max = roundPoint(axis.max);\n}\nfunction roundBox(box) {\n  roundAxis(box.x);\n  roundAxis(box.y);\n}\nfunction shouldAnimatePositionOnly(animationType, snapshot, layout2) {\n  return animationType === \"position\" || animationType === \"preserve-aspect\" && !isNear(aspectRatio(snapshot), aspectRatio(layout2), 0.2);\n}\nfunction checkNodeWasScrollRoot(node) {\n  return node !== node.root && node.scroll?.wasRoot;\n}\n\n// ../../node_modules/motion-dom/dist/es/projection/node/DocumentProjectionNode.mjs\nvar DocumentProjectionNode = createProjectionNode({\n  attachResizeListener: (ref, notify) => addDomEvent(ref, \"resize\", notify),\n  measureScroll: () => ({\n    x: document.documentElement.scrollLeft || document.body?.scrollLeft || 0,\n    y: document.documentElement.scrollTop || document.body?.scrollTop || 0\n  }),\n  checkIsScrollRoot: () => true\n});\n\n// ../../node_modules/motion-dom/dist/es/projection/node/HTMLProjectionNode.mjs\nvar rootProjectionNode = {\n  current: void 0\n};\nvar HTMLProjectionNode = createProjectionNode({\n  measureScroll: (instance) => ({\n    x: instance.scrollLeft,\n    y: instance.scrollTop\n  }),\n  defaultParent: () => {\n    if (!rootProjectionNode.current) {\n      const documentNode = new DocumentProjectionNode({});\n      documentNode.mount(window);\n      documentNode.setOptions({ layoutScroll: true });\n      rootProjectionNode.current = documentNode;\n    }\n    return rootProjectionNode.current;\n  },\n  resetTransform: (instance, value) => {\n    instance.style.transform = value !== void 0 ? value : \"none\";\n  },\n  checkIsScrollRoot: (instance) => Boolean(window.getComputedStyle(instance).position === \"fixed\")\n});\n\n// ../../node_modules/framer-motion/dist/es/components/AnimatePresence/PopChild.mjs\nimport * as React2 from \"react\";\nimport { useId, useRef as useRef2, useContext, useInsertionEffect } from \"react\";\n\n// ../../node_modules/framer-motion/dist/es/context/MotionConfigContext.mjs\nimport { createContext as createContext3 } from \"react\";\nvar MotionConfigContext = createContext3({\n  transformPagePoint: (p) => p,\n  isStatic: false,\n  reducedMotion: \"never\"\n});\n\n// ../../node_modules/framer-motion/dist/es/utils/use-composed-ref.mjs\nimport * as React from \"react\";\nfunction setRef(ref, value) {\n  if (typeof ref === \"function\") {\n    return ref(value);\n  } else if (ref !== null && ref !== void 0) {\n    ref.current = value;\n  }\n}\nfunction composeRefs(...refs) {\n  return (node) => {\n    let hasCleanup = false;\n    const cleanups = refs.map((ref) => {\n      const cleanup = setRef(ref, node);\n      if (!hasCleanup && typeof cleanup === \"function\") {\n        hasCleanup = true;\n      }\n      return cleanup;\n    });\n    if (hasCleanup) {\n      return () => {\n        for (let i = 0; i < cleanups.length; i++) {\n          const cleanup = cleanups[i];\n          if (typeof cleanup === \"function\") {\n            cleanup();\n          } else {\n            setRef(refs[i], null);\n          }\n        }\n      };\n    }\n  };\n}\nfunction useComposedRefs(...refs) {\n  return React.useCallback(composeRefs(...refs), refs);\n}\n\n// ../../node_modules/framer-motion/dist/es/components/AnimatePresence/PopChild.mjs\nvar PopChildMeasure = class extends React2.Component {\n  getSnapshotBeforeUpdate(prevProps) {\n    const element = this.props.childRef.current;\n    if (isHTMLElement(element) && prevProps.isPresent && !this.props.isPresent && this.props.pop !== false) {\n      const parent = element.offsetParent;\n      const parentWidth = isHTMLElement(parent) ? parent.offsetWidth || 0 : 0;\n      const parentHeight = isHTMLElement(parent) ? parent.offsetHeight || 0 : 0;\n      const computedStyle = getComputedStyle(element);\n      const size = this.props.sizeRef.current;\n      size.height = parseFloat(computedStyle.height);\n      size.width = parseFloat(computedStyle.width);\n      size.top = element.offsetTop;\n      size.left = element.offsetLeft;\n      size.right = parentWidth - size.width - size.left;\n      size.bottom = parentHeight - size.height - size.top;\n      size.direction = computedStyle.direction;\n    }\n    return null;\n  }\n  /**\n   * Required with getSnapshotBeforeUpdate to stop React complaining.\n   */\n  componentDidUpdate() {\n  }\n  render() {\n    return this.props.children;\n  }\n};\nfunction PopChild({ children, isPresent, anchorX, anchorY, root, pop }) {\n  const id3 = useId();\n  const ref = useRef2(null);\n  const size = useRef2({\n    width: 0,\n    height: 0,\n    top: 0,\n    left: 0,\n    right: 0,\n    bottom: 0,\n    direction: \"ltr\"\n  });\n  const { nonce } = useContext(MotionConfigContext);\n  const childRef = pop !== false ? children.props?.ref ?? children?.ref : void 0;\n  const composedRef = useComposedRefs(ref, childRef);\n  useInsertionEffect(() => {\n    const { width, height, top, left, right, bottom, direction } = size.current;\n    if (isPresent || pop === false || !ref.current || !width || !height)\n      return;\n    const isRTL = direction === \"rtl\";\n    const x = anchorX === \"left\" ? isRTL ? `right: ${right}` : `left: ${left}` : isRTL ? `left: ${left}` : `right: ${right}`;\n    const y = anchorY === \"bottom\" ? `bottom: ${bottom}` : `top: ${top}`;\n    ref.current.dataset.motionPopId = id3;\n    const style = document.createElement(\"style\");\n    if (nonce)\n      style.nonce = nonce;\n    const parent = root ?? document.head;\n    parent.appendChild(style);\n    if (style.sheet) {\n      style.sheet.insertRule(`\n          [data-motion-pop-id=\"${id3}\"] {\n            position: absolute !important;\n            width: ${width}px !important;\n            height: ${height}px !important;\n            ${x}px !important;\n            ${y}px !important;\n          }\n        `);\n    }\n    return () => {\n      ref.current?.removeAttribute(\"data-motion-pop-id\");\n      if (parent.contains(style)) {\n        parent.removeChild(style);\n      }\n    };\n  }, [isPresent]);\n  return jsx(PopChildMeasure, { isPresent, childRef: ref, sizeRef: size, pop, children: pop === false ? children : React2.cloneElement(children, { ref: composedRef }) });\n}\n\n// ../../node_modules/framer-motion/dist/es/components/AnimatePresence/PresenceChild.mjs\nvar PresenceChild = ({ children, initial, isPresent, onExitComplete, custom, presenceAffectsLayout, mode, anchorX, anchorY, root }) => {\n  const presenceChildren = useConstant(newChildrenMap);\n  const id3 = useId2();\n  const isPresentRef = useRef3(isPresent);\n  const onExitCompleteRef = useRef3(onExitComplete);\n  useIsomorphicLayoutEffect(() => {\n    isPresentRef.current = isPresent;\n    onExitCompleteRef.current = onExitComplete;\n  });\n  let isReusedContext = true;\n  let context = useMemo(() => {\n    isReusedContext = false;\n    return {\n      id: id3,\n      initial,\n      isPresent,\n      custom,\n      onExitComplete: (childId) => {\n        presenceChildren.set(childId, true);\n        for (const isComplete of presenceChildren.values()) {\n          if (!isComplete)\n            return;\n        }\n        onExitComplete && onExitComplete();\n      },\n      register: (childId) => {\n        presenceChildren.set(childId, false);\n        return () => {\n          presenceChildren.delete(childId);\n          !isPresentRef.current && !presenceChildren.size && onExitCompleteRef.current?.();\n        };\n      }\n    };\n  }, [isPresent, presenceChildren, onExitComplete]);\n  if (presenceAffectsLayout && isReusedContext) {\n    context = { ...context };\n  }\n  useMemo(() => {\n    presenceChildren.forEach((_, key) => presenceChildren.set(key, false));\n  }, [isPresent]);\n  React3.useEffect(() => {\n    !isPresent && !presenceChildren.size && onExitComplete && onExitComplete();\n  }, [isPresent]);\n  children = jsx2(PopChild, { pop: mode === \"popLayout\", isPresent, anchorX, anchorY, root, children });\n  return jsx2(PresenceContext.Provider, { value: context, children });\n};\nfunction newChildrenMap() {\n  return /* @__PURE__ */ new Map();\n}\n\n// ../../node_modules/framer-motion/dist/es/components/AnimatePresence/use-presence.mjs\nimport { useContext as useContext2, useId as useId3, useEffect as useEffect3, useCallback as useCallback2 } from \"react\";\nfunction usePresence(subscribe = true) {\n  const context = useContext2(PresenceContext);\n  if (context === null)\n    return [true, null];\n  const { isPresent, onExitComplete, register } = context;\n  const id3 = useId3();\n  useEffect3(() => {\n    if (subscribe) {\n      return register(id3);\n    }\n  }, [subscribe]);\n  const safeToRemove = useCallback2(() => subscribe && onExitComplete && onExitComplete(id3), [id3, onExitComplete, subscribe]);\n  return !isPresent && onExitComplete ? [false, safeToRemove] : [true];\n}\n\n// ../../node_modules/framer-motion/dist/es/components/AnimatePresence/utils.mjs\nimport { Children, isValidElement } from \"react\";\nvar getChildKey = (child) => child.key || \"\";\nfunction onlyElements(children) {\n  const filtered = [];\n  Children.forEach(children, (child) => {\n    if (isValidElement(child))\n      filtered.push(child);\n  });\n  return filtered;\n}\n\n// ../../node_modules/framer-motion/dist/es/components/AnimatePresence/index.mjs\nvar AnimatePresence = ({ children, custom, initial = true, onExitComplete, presenceAffectsLayout = true, mode = \"sync\", propagate = false, anchorX = \"left\", anchorY = \"top\", root }) => {\n  const [isParentPresent, safeToRemove] = usePresence(propagate);\n  const presentChildren = useMemo2(() => onlyElements(children), [children]);\n  const presentKeys = propagate && !isParentPresent ? [] : presentChildren.map(getChildKey);\n  const isInitialRender = useRef4(true);\n  const pendingPresentChildren = useRef4(presentChildren);\n  const exitComplete = useConstant(() => /* @__PURE__ */ new Map());\n  const exitingComponents = useRef4(/* @__PURE__ */ new Set());\n  const [diffedChildren, setDiffedChildren] = useState(presentChildren);\n  const [renderedChildren, setRenderedChildren] = useState(presentChildren);\n  useIsomorphicLayoutEffect(() => {\n    isInitialRender.current = false;\n    pendingPresentChildren.current = presentChildren;\n    for (let i = 0; i < renderedChildren.length; i++) {\n      const key = getChildKey(renderedChildren[i]);\n      if (!presentKeys.includes(key)) {\n        if (exitComplete.get(key) !== true) {\n          exitComplete.set(key, false);\n        }\n      } else {\n        exitComplete.delete(key);\n        exitingComponents.current.delete(key);\n      }\n    }\n  }, [renderedChildren, presentKeys.length, presentKeys.join(\"-\")]);\n  const exitingChildren = [];\n  if (presentChildren !== diffedChildren) {\n    let nextChildren = [...presentChildren];\n    for (let i = 0; i < renderedChildren.length; i++) {\n      const child = renderedChildren[i];\n      const key = getChildKey(child);\n      if (!presentKeys.includes(key)) {\n        nextChildren.splice(i, 0, child);\n        exitingChildren.push(child);\n      }\n    }\n    if (mode === \"wait\" && exitingChildren.length) {\n      nextChildren = exitingChildren;\n    }\n    setRenderedChildren(onlyElements(nextChildren));\n    setDiffedChildren(presentChildren);\n    return null;\n  }\n  if (false) {\n    console.warn(`You're attempting to animate multiple children within AnimatePresence, but its mode is set to \"wait\". This will lead to odd visual behaviour.`);\n  }\n  const { forceRender } = useContext3(LayoutGroupContext);\n  return jsx3(Fragment, { children: renderedChildren.map((child) => {\n    const key = getChildKey(child);\n    const isPresent = propagate && !isParentPresent ? false : presentChildren === renderedChildren || presentKeys.includes(key);\n    const onExit = () => {\n      if (exitingComponents.current.has(key)) {\n        return;\n      }\n      if (exitComplete.has(key)) {\n        exitingComponents.current.add(key);\n        exitComplete.set(key, true);\n      } else {\n        return;\n      }\n      let isEveryExitComplete = true;\n      exitComplete.forEach((isExitComplete) => {\n        if (!isExitComplete)\n          isEveryExitComplete = false;\n      });\n      if (isEveryExitComplete) {\n        forceRender?.();\n        setRenderedChildren(pendingPresentChildren.current);\n        propagate && safeToRemove?.();\n        onExitComplete && onExitComplete();\n      }\n    };\n    return jsx3(PresenceChild, { isPresent, initial: !isInitialRender.current || initial ? void 0 : false, custom, presenceAffectsLayout, mode, root, onExitComplete: isPresent ? void 0 : onExit, anchorX, anchorY, children: child }, key);\n  }) });\n};\n\n// ../../node_modules/framer-motion/dist/es/context/LazyContext.mjs\nimport { createContext as createContext4 } from \"react\";\nvar LazyContext = createContext4({ strict: false });\n\n// ../../node_modules/framer-motion/dist/es/motion/features/definitions.mjs\nvar featureProps = {\n  animation: [\n    \"animate\",\n    \"variants\",\n    \"whileHover\",\n    \"whileTap\",\n    \"exit\",\n    \"whileInView\",\n    \"whileFocus\",\n    \"whileDrag\"\n  ],\n  exit: [\"exit\"],\n  drag: [\"drag\", \"dragControls\"],\n  focus: [\"whileFocus\"],\n  hover: [\"whileHover\", \"onHoverStart\", \"onHoverEnd\"],\n  tap: [\"whileTap\", \"onTap\", \"onTapStart\", \"onTapCancel\"],\n  pan: [\"onPan\", \"onPanStart\", \"onPanSessionStart\", \"onPanEnd\"],\n  inView: [\"whileInView\", \"onViewportEnter\", \"onViewportLeave\"],\n  layout: [\"layout\", \"layoutId\"]\n};\nvar isInitialized = false;\nfunction initFeatureDefinitions() {\n  if (isInitialized)\n    return;\n  const initialFeatureDefinitions = {};\n  for (const key in featureProps) {\n    initialFeatureDefinitions[key] = {\n      isEnabled: (props) => featureProps[key].some((name) => !!props[name])\n    };\n  }\n  setFeatureDefinitions(initialFeatureDefinitions);\n  isInitialized = true;\n}\nfunction getInitializedFeatureDefinitions() {\n  initFeatureDefinitions();\n  return getFeatureDefinitions();\n}\n\n// ../../node_modules/framer-motion/dist/es/motion/features/load-features.mjs\nfunction loadFeatures(features) {\n  const featureDefinitions2 = getInitializedFeatureDefinitions();\n  for (const key in features) {\n    featureDefinitions2[key] = {\n      ...featureDefinitions2[key],\n      ...features[key]\n    };\n  }\n  setFeatureDefinitions(featureDefinitions2);\n}\n\n// ../../node_modules/framer-motion/dist/es/motion/utils/valid-prop.mjs\nvar validMotionProps = /* @__PURE__ */ new Set([\n  \"animate\",\n  \"exit\",\n  \"variants\",\n  \"initial\",\n  \"style\",\n  \"values\",\n  \"variants\",\n  \"transition\",\n  \"transformTemplate\",\n  \"custom\",\n  \"inherit\",\n  \"onBeforeLayoutMeasure\",\n  \"onAnimationStart\",\n  \"onAnimationComplete\",\n  \"onUpdate\",\n  \"onDragStart\",\n  \"onDrag\",\n  \"onDragEnd\",\n  \"onMeasureDragConstraints\",\n  \"onDirectionLock\",\n  \"onDragTransitionEnd\",\n  \"_dragX\",\n  \"_dragY\",\n  \"onHoverStart\",\n  \"onHoverEnd\",\n  \"onViewportEnter\",\n  \"onViewportLeave\",\n  \"globalTapTarget\",\n  \"propagate\",\n  \"ignoreStrict\",\n  \"viewport\"\n]);\nfunction isValidMotionProp(key) {\n  return key.startsWith(\"while\") || key.startsWith(\"drag\") && key !== \"draggable\" || key.startsWith(\"layout\") || key.startsWith(\"onTap\") || key.startsWith(\"onPan\") || key.startsWith(\"onLayout\") || validMotionProps.has(key);\n}\n\n// ../../node_modules/framer-motion/dist/es/render/dom/utils/filter-props.mjs\nvar shouldForward = (key) => !isValidMotionProp(key);\nfunction loadExternalIsValidProp(isValidProp) {\n  if (typeof isValidProp !== \"function\")\n    return;\n  shouldForward = (key) => key.startsWith(\"on\") ? !isValidMotionProp(key) : isValidProp(key);\n}\ntry {\n  const emotionPkg = \"@emotion/is-prop-valid\";\n  loadExternalIsValidProp((void 0)(emotionPkg).default);\n} catch {\n}\nfunction filterProps(props, isDom, forwardMotionProps) {\n  const filteredProps = {};\n  for (const key in props) {\n    if (key === \"values\" && typeof props.values === \"object\")\n      continue;\n    if (isMotionValue(props[key]))\n      continue;\n    if (shouldForward(key) || forwardMotionProps === true && isValidMotionProp(key) || !isDom && !isValidMotionProp(key) || // If trying to use native HTML drag events, forward drag listeners\n    props[\"draggable\"] && key.startsWith(\"onDrag\")) {\n      filteredProps[key] = props[key];\n    }\n  }\n  return filteredProps;\n}\n\n// ../../node_modules/framer-motion/dist/es/motion/index.mjs\nimport { jsxs, jsx as jsx4 } from \"react/jsx-runtime\";\nimport { forwardRef, useContext as useContext7 } from \"react\";\n\n// ../../node_modules/framer-motion/dist/es/context/MotionContext/index.mjs\nimport { createContext as createContext5 } from \"react\";\nvar MotionContext = /* @__PURE__ */ createContext5({});\n\n// ../../node_modules/framer-motion/dist/es/context/MotionContext/create.mjs\nimport { useContext as useContext4, useMemo as useMemo3 } from \"react\";\n\n// ../../node_modules/framer-motion/dist/es/context/MotionContext/utils.mjs\nfunction getCurrentTreeVariants(props, context) {\n  if (isControllingVariants(props)) {\n    const { initial, animate: animate2 } = props;\n    return {\n      initial: initial === false || isVariantLabel(initial) ? initial : void 0,\n      animate: isVariantLabel(animate2) ? animate2 : void 0\n    };\n  }\n  return props.inherit !== false ? context : {};\n}\n\n// ../../node_modules/framer-motion/dist/es/context/MotionContext/create.mjs\nfunction useCreateMotionContext(props) {\n  const { initial, animate: animate2 } = getCurrentTreeVariants(props, useContext4(MotionContext));\n  return useMemo3(() => ({ initial, animate: animate2 }), [variantLabelsAsDependency(initial), variantLabelsAsDependency(animate2)]);\n}\nfunction variantLabelsAsDependency(prop) {\n  return Array.isArray(prop) ? prop.join(\" \") : prop;\n}\n\n// ../../node_modules/framer-motion/dist/es/render/dom/use-render.mjs\nimport { Fragment as Fragment2, useMemo as useMemo6, createElement } from \"react\";\n\n// ../../node_modules/framer-motion/dist/es/render/html/use-props.mjs\nimport { useMemo as useMemo4 } from \"react\";\n\n// ../../node_modules/framer-motion/dist/es/render/html/utils/create-render-state.mjs\nvar createHtmlRenderState = () => ({\n  style: {},\n  transform: {},\n  transformOrigin: {},\n  vars: {}\n});\n\n// ../../node_modules/framer-motion/dist/es/render/html/use-props.mjs\nfunction copyRawValuesOnly(target, source, props) {\n  for (const key in source) {\n    if (!isMotionValue(source[key]) && !isForcedMotionValue(key, props)) {\n      target[key] = source[key];\n    }\n  }\n}\nfunction useInitialMotionValues({ transformTemplate }, visualState) {\n  return useMemo4(() => {\n    const state = createHtmlRenderState();\n    buildHTMLStyles(state, visualState, transformTemplate);\n    return Object.assign({}, state.vars, state.style);\n  }, [visualState]);\n}\nfunction useStyle(props, visualState) {\n  const styleProp = props.style || {};\n  const style = {};\n  copyRawValuesOnly(style, styleProp, props);\n  Object.assign(style, useInitialMotionValues(props, visualState));\n  return style;\n}\nfunction useHTMLProps(props, visualState) {\n  const htmlProps = {};\n  const style = useStyle(props, visualState);\n  if (props.drag && props.dragListener !== false) {\n    htmlProps.draggable = false;\n    style.userSelect = style.WebkitUserSelect = style.WebkitTouchCallout = \"none\";\n    style.touchAction = props.drag === true ? \"none\" : `pan-${props.drag === \"x\" ? \"y\" : \"x\"}`;\n  }\n  if (props.tabIndex === void 0 && (props.onTap || props.onTapStart || props.whileTap)) {\n    htmlProps.tabIndex = 0;\n  }\n  htmlProps.style = style;\n  return htmlProps;\n}\n\n// ../../node_modules/framer-motion/dist/es/render/svg/use-props.mjs\nimport { useMemo as useMemo5 } from \"react\";\n\n// ../../node_modules/framer-motion/dist/es/render/svg/utils/create-render-state.mjs\nvar createSvgRenderState = () => ({\n  ...createHtmlRenderState(),\n  attrs: {}\n});\n\n// ../../node_modules/framer-motion/dist/es/render/svg/use-props.mjs\nfunction useSVGProps(props, visualState, _isStatic, Component3) {\n  const visualProps = useMemo5(() => {\n    const state = createSvgRenderState();\n    buildSVGAttrs(state, visualState, isSVGTag(Component3), props.transformTemplate, props.style);\n    return {\n      ...state.attrs,\n      style: { ...state.style }\n    };\n  }, [visualState]);\n  if (props.style) {\n    const rawStyles = {};\n    copyRawValuesOnly(rawStyles, props.style, props);\n    visualProps.style = { ...rawStyles, ...visualProps.style };\n  }\n  return visualProps;\n}\n\n// ../../node_modules/framer-motion/dist/es/render/svg/lowercase-elements.mjs\nvar lowercaseSVGElements = [\n  \"animate\",\n  \"circle\",\n  \"defs\",\n  \"desc\",\n  \"ellipse\",\n  \"g\",\n  \"image\",\n  \"line\",\n  \"filter\",\n  \"marker\",\n  \"mask\",\n  \"metadata\",\n  \"path\",\n  \"pattern\",\n  \"polygon\",\n  \"polyline\",\n  \"rect\",\n  \"stop\",\n  \"switch\",\n  \"symbol\",\n  \"svg\",\n  \"text\",\n  \"tspan\",\n  \"use\",\n  \"view\"\n];\n\n// ../../node_modules/framer-motion/dist/es/render/dom/utils/is-svg-component.mjs\nfunction isSVGComponent(Component3) {\n  if (\n    /**\n     * If it's not a string, it's a custom React component. Currently we only support\n     * HTML custom React components.\n     */\n    typeof Component3 !== \"string\" || /**\n     * If it contains a dash, the element is a custom HTML webcomponent.\n     */\n    Component3.includes(\"-\")\n  ) {\n    return false;\n  } else if (\n    /**\n     * If it's in our list of lowercase SVG tags, it's an SVG component\n     */\n    lowercaseSVGElements.indexOf(Component3) > -1 || /**\n     * If it contains a capital letter, it's an SVG component\n     */\n    /[A-Z]/u.test(Component3)\n  ) {\n    return true;\n  }\n  return false;\n}\n\n// ../../node_modules/framer-motion/dist/es/render/dom/use-render.mjs\nfunction useRender(Component3, props, ref, { latestValues }, isStatic, forwardMotionProps = false, isSVG) {\n  const useVisualProps = isSVG ?? isSVGComponent(Component3) ? useSVGProps : useHTMLProps;\n  const visualProps = useVisualProps(props, latestValues, isStatic, Component3);\n  const filteredProps = filterProps(props, typeof Component3 === \"string\", forwardMotionProps);\n  const elementProps = Component3 !== Fragment2 ? { ...filteredProps, ...visualProps, ref } : {};\n  const { children } = props;\n  const renderedChildren = useMemo6(() => isMotionValue(children) ? children.get() : children, [children]);\n  return createElement(Component3, {\n    ...elementProps,\n    children: renderedChildren\n  });\n}\n\n// ../../node_modules/framer-motion/dist/es/motion/utils/use-visual-state.mjs\nimport { useContext as useContext5 } from \"react\";\nfunction makeState({ scrapeMotionValuesFromProps: scrapeMotionValuesFromProps3, createRenderState }, props, context, presenceContext) {\n  const state = {\n    latestValues: makeLatestValues(props, context, presenceContext, scrapeMotionValuesFromProps3),\n    renderState: createRenderState()\n  };\n  return state;\n}\nfunction makeLatestValues(props, context, presenceContext, scrapeMotionValues) {\n  const values = {};\n  const motionValues = scrapeMotionValues(props, {});\n  for (const key in motionValues) {\n    values[key] = resolveMotionValue(motionValues[key]);\n  }\n  let { initial, animate: animate2 } = props;\n  const isControllingVariants$1 = isControllingVariants(props);\n  const isVariantNode$1 = isVariantNode(props);\n  if (context && isVariantNode$1 && !isControllingVariants$1 && props.inherit !== false) {\n    if (initial === void 0)\n      initial = context.initial;\n    if (animate2 === void 0)\n      animate2 = context.animate;\n  }\n  let isInitialAnimationBlocked = presenceContext ? presenceContext.initial === false : false;\n  isInitialAnimationBlocked = isInitialAnimationBlocked || initial === false;\n  const variantToSet = isInitialAnimationBlocked ? animate2 : initial;\n  if (variantToSet && typeof variantToSet !== \"boolean\" && !isAnimationControls(variantToSet)) {\n    const list = Array.isArray(variantToSet) ? variantToSet : [variantToSet];\n    for (let i = 0; i < list.length; i++) {\n      const resolved = resolveVariantFromProps(props, list[i]);\n      if (resolved) {\n        const { transitionEnd, transition, ...target } = resolved;\n        for (const key in target) {\n          let valueTarget = target[key];\n          if (Array.isArray(valueTarget)) {\n            const index = isInitialAnimationBlocked ? valueTarget.length - 1 : 0;\n            valueTarget = valueTarget[index];\n          }\n          if (valueTarget !== null) {\n            values[key] = valueTarget;\n          }\n        }\n        for (const key in transitionEnd) {\n          values[key] = transitionEnd[key];\n        }\n      }\n    }\n  }\n  return values;\n}\nvar makeUseVisualState = (config) => (props, isStatic) => {\n  const context = useContext5(MotionContext);\n  const presenceContext = useContext5(PresenceContext);\n  const make = () => makeState(config, props, context, presenceContext);\n  return isStatic ? make() : useConstant(make);\n};\n\n// ../../node_modules/framer-motion/dist/es/render/html/use-html-visual-state.mjs\nvar useHTMLVisualState = /* @__PURE__ */ makeUseVisualState({\n  scrapeMotionValuesFromProps,\n  createRenderState: createHtmlRenderState\n});\n\n// ../../node_modules/framer-motion/dist/es/render/svg/use-svg-visual-state.mjs\nvar useSVGVisualState = /* @__PURE__ */ makeUseVisualState({\n  scrapeMotionValuesFromProps: scrapeMotionValuesFromProps2,\n  createRenderState: createSvgRenderState\n});\n\n// ../../node_modules/framer-motion/dist/es/motion/utils/symbol.mjs\nvar motionComponentSymbol = /* @__PURE__ */ Symbol.for(\"motionComponentSymbol\");\n\n// ../../node_modules/framer-motion/dist/es/motion/utils/use-motion-ref.mjs\nimport { useRef as useRef5, useInsertionEffect as useInsertionEffect2, useCallback as useCallback3 } from \"react\";\nfunction useMotionRef(visualState, visualElement, externalRef) {\n  const externalRefContainer = useRef5(externalRef);\n  useInsertionEffect2(() => {\n    externalRefContainer.current = externalRef;\n  });\n  const refCleanup = useRef5(null);\n  return useCallback3((instance) => {\n    if (instance) {\n      visualState.onMount?.(instance);\n    }\n    if (visualElement) {\n      instance ? visualElement.mount(instance) : visualElement.unmount();\n    }\n    const ref = externalRefContainer.current;\n    if (typeof ref === \"function\") {\n      if (instance) {\n        const cleanup = ref(instance);\n        if (typeof cleanup === \"function\") {\n          refCleanup.current = cleanup;\n        }\n      } else if (refCleanup.current) {\n        refCleanup.current();\n        refCleanup.current = null;\n      } else {\n        ref(instance);\n      }\n    } else if (ref) {\n      ref.current = instance;\n    }\n  }, [visualElement]);\n}\n\n// ../../node_modules/framer-motion/dist/es/motion/utils/use-visual-element.mjs\nimport { useContext as useContext6, useRef as useRef6, useInsertionEffect as useInsertionEffect3, useEffect as useEffect4 } from \"react\";\n\n// ../../node_modules/framer-motion/dist/es/context/SwitchLayoutGroupContext.mjs\nimport { createContext as createContext6 } from \"react\";\nvar SwitchLayoutGroupContext = createContext6({});\n\n// ../../node_modules/framer-motion/dist/es/utils/is-ref-object.mjs\nfunction isRefObject(ref) {\n  return ref && typeof ref === \"object\" && Object.prototype.hasOwnProperty.call(ref, \"current\");\n}\n\n// ../../node_modules/framer-motion/dist/es/motion/utils/use-visual-element.mjs\nfunction useVisualElement(Component3, visualState, props, createVisualElement, ProjectionNodeConstructor, isSVG) {\n  const { visualElement: parent } = useContext6(MotionContext);\n  const lazyContext = useContext6(LazyContext);\n  const presenceContext = useContext6(PresenceContext);\n  const motionConfig = useContext6(MotionConfigContext);\n  const reducedMotionConfig = motionConfig.reducedMotion;\n  const skipAnimations = motionConfig.skipAnimations;\n  const visualElementRef = useRef6(null);\n  const hasMountedOnce = useRef6(false);\n  createVisualElement = createVisualElement || lazyContext.renderer;\n  if (!visualElementRef.current && createVisualElement) {\n    visualElementRef.current = createVisualElement(Component3, {\n      visualState,\n      parent,\n      props,\n      presenceContext,\n      blockInitialAnimation: presenceContext ? presenceContext.initial === false : false,\n      reducedMotionConfig,\n      skipAnimations,\n      isSVG\n    });\n    if (hasMountedOnce.current && visualElementRef.current) {\n      visualElementRef.current.manuallyAnimateOnMount = true;\n    }\n  }\n  const visualElement = visualElementRef.current;\n  const initialLayoutGroupConfig = useContext6(SwitchLayoutGroupContext);\n  if (visualElement && !visualElement.projection && ProjectionNodeConstructor && (visualElement.type === \"html\" || visualElement.type === \"svg\")) {\n    createProjectionNode2(visualElementRef.current, props, ProjectionNodeConstructor, initialLayoutGroupConfig);\n  }\n  const isMounted = useRef6(false);\n  useInsertionEffect3(() => {\n    if (visualElement && isMounted.current) {\n      visualElement.update(props, presenceContext);\n    }\n  });\n  const optimisedAppearId = props[optimizedAppearDataAttribute];\n  const wantsHandoff = useRef6(Boolean(optimisedAppearId) && typeof window !== \"undefined\" && !window.MotionHandoffIsComplete?.(optimisedAppearId) && window.MotionHasOptimisedAnimation?.(optimisedAppearId));\n  useIsomorphicLayoutEffect(() => {\n    hasMountedOnce.current = true;\n    if (!visualElement)\n      return;\n    isMounted.current = true;\n    window.MotionIsMounted = true;\n    visualElement.updateFeatures();\n    visualElement.scheduleRenderMicrotask();\n    if (wantsHandoff.current && visualElement.animationState) {\n      visualElement.animationState.animateChanges();\n    }\n  });\n  useEffect4(() => {\n    if (!visualElement)\n      return;\n    if (!wantsHandoff.current && visualElement.animationState) {\n      visualElement.animationState.animateChanges();\n    }\n    if (wantsHandoff.current) {\n      queueMicrotask(() => {\n        window.MotionHandoffMarkAsComplete?.(optimisedAppearId);\n      });\n      wantsHandoff.current = false;\n    }\n    visualElement.enteringChildren = void 0;\n  });\n  return visualElement;\n}\nfunction createProjectionNode2(visualElement, props, ProjectionNodeConstructor, initialPromotionConfig) {\n  const { layoutId, layout: layout2, drag: drag2, dragConstraints, layoutScroll, layoutRoot, layoutAnchor, layoutCrossfade } = props;\n  visualElement.projection = new ProjectionNodeConstructor(visualElement.latestValues, props[\"data-framer-portal-id\"] ? void 0 : getClosestProjectingNode(visualElement.parent));\n  visualElement.projection.setOptions({\n    layoutId,\n    layout: layout2,\n    alwaysMeasureLayout: Boolean(drag2) || dragConstraints && isRefObject(dragConstraints),\n    visualElement,\n    /**\n     * TODO: Update options in an effect. This could be tricky as it'll be too late\n     * to update by the time layout animations run.\n     * We also need to fix this safeToRemove by linking it up to the one returned by usePresence,\n     * ensuring it gets called if there's no potential layout animations.\n     *\n     */\n    animationType: typeof layout2 === \"string\" ? layout2 : \"both\",\n    initialPromotionConfig,\n    crossfade: layoutCrossfade,\n    layoutScroll,\n    layoutRoot,\n    layoutAnchor\n  });\n}\nfunction getClosestProjectingNode(visualElement) {\n  if (!visualElement)\n    return void 0;\n  return visualElement.options.allowProjection !== false ? visualElement.projection : getClosestProjectingNode(visualElement.parent);\n}\n\n// ../../node_modules/framer-motion/dist/es/motion/index.mjs\nfunction createMotionComponent(Component3, { forwardMotionProps = false, type } = {}, preloadedFeatures, createVisualElement) {\n  preloadedFeatures && loadFeatures(preloadedFeatures);\n  const isSVG = type ? type === \"svg\" : isSVGComponent(Component3);\n  const useVisualState = isSVG ? useSVGVisualState : useHTMLVisualState;\n  function MotionDOMComponent(props, externalRef) {\n    let MeasureLayout2;\n    const configAndProps = {\n      ...useContext7(MotionConfigContext),\n      ...props,\n      layoutId: useLayoutId(props)\n    };\n    const { isStatic } = configAndProps;\n    const context = useCreateMotionContext(props);\n    const visualState = useVisualState(props, isStatic);\n    if (!isStatic && typeof window !== \"undefined\") {\n      useStrictMode(configAndProps, preloadedFeatures);\n      const layoutProjection = getProjectionFunctionality(configAndProps);\n      MeasureLayout2 = layoutProjection.MeasureLayout;\n      context.visualElement = useVisualElement(Component3, visualState, configAndProps, createVisualElement, layoutProjection.ProjectionNode, isSVG);\n    }\n    return jsxs(MotionContext.Provider, { value: context, children: [MeasureLayout2 && context.visualElement ? jsx4(MeasureLayout2, { visualElement: context.visualElement, ...configAndProps }) : null, useRender(Component3, props, useMotionRef(visualState, context.visualElement, externalRef), visualState, isStatic, forwardMotionProps, isSVG)] });\n  }\n  MotionDOMComponent.displayName = `motion.${typeof Component3 === \"string\" ? Component3 : `create(${Component3.displayName ?? Component3.name ?? \"\"})`}`;\n  const ForwardRefMotionComponent = forwardRef(MotionDOMComponent);\n  ForwardRefMotionComponent[motionComponentSymbol] = Component3;\n  return ForwardRefMotionComponent;\n}\nfunction useLayoutId({ layoutId }) {\n  const layoutGroupId = useContext7(LayoutGroupContext).id;\n  return layoutGroupId && layoutId !== void 0 ? layoutGroupId + \"-\" + layoutId : layoutId;\n}\nfunction useStrictMode(configAndProps, preloadedFeatures) {\n  const isStrict = useContext7(LazyContext).strict;\n  if (false) {\n    const strictMessage = \"You have rendered a `motion` component within a `LazyMotion` component. This will break tree shaking. Import and render a `m` component instead.\";\n    configAndProps.ignoreStrict ? warning2(false, strictMessage, \"lazy-strict-mode\") : invariant(false, strictMessage, \"lazy-strict-mode\");\n  }\n}\nfunction getProjectionFunctionality(props) {\n  const featureDefinitions2 = getInitializedFeatureDefinitions();\n  const { drag: drag2, layout: layout2 } = featureDefinitions2;\n  if (!drag2 && !layout2)\n    return {};\n  const combined = { ...drag2, ...layout2 };\n  return {\n    MeasureLayout: drag2?.isEnabled(props) || layout2?.isEnabled(props) ? combined.MeasureLayout : void 0,\n    ProjectionNode: combined.ProjectionNode\n  };\n}\n\n// ../../node_modules/framer-motion/dist/es/render/components/create-proxy.mjs\nfunction createMotionProxy(preloadedFeatures, createVisualElement) {\n  if (typeof Proxy === \"undefined\") {\n    return createMotionComponent;\n  }\n  const componentCache = /* @__PURE__ */ new Map();\n  const factory = (Component3, options) => {\n    return createMotionComponent(Component3, options, preloadedFeatures, createVisualElement);\n  };\n  const deprecatedFactoryFunction = (Component3, options) => {\n    if (false) {\n      warnOnce(false, \"motion() is deprecated. Use motion.create() instead.\");\n    }\n    return factory(Component3, options);\n  };\n  return new Proxy(deprecatedFactoryFunction, {\n    /**\n     * Called when `motion` is referenced with a prop: `motion.div`, `motion.input` etc.\n     * The prop name is passed through as `key` and we can use that to generate a `motion`\n     * DOM component with that name.\n     */\n    get: (_target, key) => {\n      if (key === \"create\")\n        return factory;\n      if (!componentCache.has(key)) {\n        componentCache.set(key, createMotionComponent(key, void 0, preloadedFeatures, createVisualElement));\n      }\n      return componentCache.get(key);\n    }\n  });\n}\n\n// ../../node_modules/framer-motion/dist/es/render/dom/create-visual-element.mjs\nimport { Fragment as Fragment3 } from \"react\";\nvar createDomVisualElement = (Component3, options) => {\n  const isSVG = options.isSVG ?? isSVGComponent(Component3);\n  return isSVG ? new SVGVisualElement(options) : new HTMLVisualElement(options, {\n    allowProjection: Component3 !== Fragment3\n  });\n};\n\n// ../../node_modules/framer-motion/dist/es/motion/features/animation/index.mjs\nvar AnimationFeature = class extends Feature {\n  /**\n   * We dynamically generate the AnimationState manager as it contains a reference\n   * to the underlying animation library. We only want to load that if we load this,\n   * so people can optionally code split it out using the `m` component.\n   */\n  constructor(node) {\n    super(node);\n    node.animationState || (node.animationState = createAnimationState(node));\n  }\n  updateAnimationControlsSubscription() {\n    const { animate: animate2 } = this.node.getProps();\n    if (isAnimationControls(animate2)) {\n      this.unmountControls = animate2.subscribe(this.node);\n    }\n  }\n  /**\n   * Subscribe any provided AnimationControls to the component's VisualElement\n   */\n  mount() {\n    this.updateAnimationControlsSubscription();\n  }\n  update() {\n    const { animate: animate2 } = this.node.getProps();\n    const { animate: prevAnimate } = this.node.prevProps || {};\n    if (animate2 !== prevAnimate) {\n      this.updateAnimationControlsSubscription();\n    }\n  }\n  unmount() {\n    this.node.animationState.reset();\n    this.unmountControls?.();\n  }\n};\n\n// ../../node_modules/framer-motion/dist/es/motion/features/animation/exit.mjs\nvar id2 = 0;\nvar ExitAnimationFeature = class extends Feature {\n  constructor() {\n    super(...arguments);\n    this.id = id2++;\n    this.isExitComplete = false;\n  }\n  update() {\n    if (!this.node.presenceContext)\n      return;\n    const { isPresent, onExitComplete } = this.node.presenceContext;\n    const { isPresent: prevIsPresent } = this.node.prevPresenceContext || {};\n    if (!this.node.animationState || isPresent === prevIsPresent) {\n      return;\n    }\n    if (isPresent && prevIsPresent === false) {\n      if (this.isExitComplete) {\n        const { initial, custom } = this.node.getProps();\n        if (typeof initial === \"string\" || typeof initial === \"object\" && initial !== null && !Array.isArray(initial)) {\n          const resolved = resolveVariant(this.node, initial, custom);\n          if (resolved) {\n            const { transition, transitionEnd, ...target } = resolved;\n            for (const key in target) {\n              this.node.getValue(key)?.jump(target[key]);\n            }\n          }\n        }\n        this.node.animationState.reset();\n        this.node.animationState.animateChanges();\n      } else {\n        this.node.animationState.setActive(\"exit\", false);\n      }\n      this.isExitComplete = false;\n      return;\n    }\n    const exitAnimation = this.node.animationState.setActive(\"exit\", !isPresent);\n    if (onExitComplete && !isPresent) {\n      exitAnimation.then(() => {\n        this.isExitComplete = true;\n        onExitComplete(this.id);\n      });\n    }\n  }\n  mount() {\n    const { register, onExitComplete } = this.node.presenceContext || {};\n    if (onExitComplete) {\n      onExitComplete(this.id);\n    }\n    if (register) {\n      this.unmount = register(this.id);\n    }\n  }\n  unmount() {\n  }\n};\n\n// ../../node_modules/framer-motion/dist/es/motion/features/animations.mjs\nvar animations = {\n  animation: {\n    Feature: AnimationFeature\n  },\n  exit: {\n    Feature: ExitAnimationFeature\n  }\n};\n\n// ../../node_modules/framer-motion/dist/es/events/event-info.mjs\nfunction extractEventInfo(event) {\n  return {\n    point: {\n      x: event.pageX,\n      y: event.pageY\n    }\n  };\n}\nvar addPointerInfo = (handler) => (event) => isPrimaryPointer(event) && handler(event, extractEventInfo(event));\n\n// ../../node_modules/framer-motion/dist/es/events/add-pointer-event.mjs\nfunction addPointerEvent(target, eventName, handler, options) {\n  return addDomEvent(target, eventName, addPointerInfo(handler), options);\n}\n\n// ../../node_modules/framer-motion/dist/es/utils/get-context-window.mjs\nvar getContextWindow = ({ current }) => {\n  return current ? current.ownerDocument.defaultView : null;\n};\n\n// ../../node_modules/framer-motion/dist/es/utils/distance.mjs\nvar distance = (a, b) => Math.abs(a - b);\nfunction distance2D(a, b) {\n  const xDelta = distance(a.x, b.x);\n  const yDelta = distance(a.y, b.y);\n  return Math.sqrt(xDelta ** 2 + yDelta ** 2);\n}\n\n// ../../node_modules/framer-motion/dist/es/gestures/pan/PanSession.mjs\nvar overflowStyles = /* @__PURE__ */ new Set([\"auto\", \"scroll\"]);\nvar PanSession = class {\n  constructor(event, handlers, { transformPagePoint, contextWindow = window, dragSnapToOrigin = false, distanceThreshold = 3, element } = {}) {\n    this.startEvent = null;\n    this.lastMoveEvent = null;\n    this.lastMoveEventInfo = null;\n    this.lastRawMoveEventInfo = null;\n    this.handlers = {};\n    this.contextWindow = window;\n    this.scrollPositions = /* @__PURE__ */ new Map();\n    this.removeScrollListeners = null;\n    this.onElementScroll = (event2) => {\n      this.handleScroll(event2.target);\n    };\n    this.onWindowScroll = () => {\n      this.handleScroll(window);\n    };\n    this.updatePoint = () => {\n      if (!(this.lastMoveEvent && this.lastMoveEventInfo))\n        return;\n      if (this.lastRawMoveEventInfo) {\n        this.lastMoveEventInfo = transformPoint(this.lastRawMoveEventInfo, this.transformPagePoint);\n      }\n      const info3 = getPanInfo(this.lastMoveEventInfo, this.history);\n      const isPanStarted = this.startEvent !== null;\n      const isDistancePastThreshold = distance2D(info3.offset, { x: 0, y: 0 }) >= this.distanceThreshold;\n      if (!isPanStarted && !isDistancePastThreshold)\n        return;\n      const { point: point2 } = info3;\n      const { timestamp: timestamp2 } = frameData;\n      this.history.push({ ...point2, timestamp: timestamp2 });\n      const { onStart, onMove } = this.handlers;\n      if (!isPanStarted) {\n        onStart && onStart(this.lastMoveEvent, info3);\n        this.startEvent = this.lastMoveEvent;\n      }\n      onMove && onMove(this.lastMoveEvent, info3);\n    };\n    this.handlePointerMove = (event2, info3) => {\n      this.lastMoveEvent = event2;\n      this.lastRawMoveEventInfo = info3;\n      this.lastMoveEventInfo = transformPoint(info3, this.transformPagePoint);\n      frame.update(this.updatePoint, true);\n    };\n    this.handlePointerUp = (event2, info3) => {\n      this.end();\n      const { onEnd, onSessionEnd, resumeAnimation } = this.handlers;\n      if (this.dragSnapToOrigin || !this.startEvent) {\n        resumeAnimation && resumeAnimation();\n      }\n      if (!(this.lastMoveEvent && this.lastMoveEventInfo))\n        return;\n      const panInfo = getPanInfo(event2.type === \"pointercancel\" ? this.lastMoveEventInfo : transformPoint(info3, this.transformPagePoint), this.history);\n      if (this.startEvent && onEnd) {\n        onEnd(event2, panInfo);\n      }\n      onSessionEnd && onSessionEnd(event2, panInfo);\n    };\n    if (!isPrimaryPointer(event))\n      return;\n    this.dragSnapToOrigin = dragSnapToOrigin;\n    this.handlers = handlers;\n    this.transformPagePoint = transformPagePoint;\n    this.distanceThreshold = distanceThreshold;\n    this.contextWindow = contextWindow || window;\n    const info2 = extractEventInfo(event);\n    const initialInfo = transformPoint(info2, this.transformPagePoint);\n    const { point } = initialInfo;\n    const { timestamp } = frameData;\n    this.history = [{ ...point, timestamp }];\n    const { onSessionStart } = handlers;\n    onSessionStart && onSessionStart(event, getPanInfo(initialInfo, this.history));\n    const eventOptions = { passive: true, capture: true };\n    this.removeListeners = pipe(addPointerEvent(this.contextWindow, \"pointermove\", this.handlePointerMove, eventOptions), addPointerEvent(this.contextWindow, \"pointerup\", this.handlePointerUp, eventOptions), addPointerEvent(this.contextWindow, \"pointercancel\", this.handlePointerUp, eventOptions));\n    if (element) {\n      this.startScrollTracking(element);\n    }\n  }\n  /**\n   * Start tracking scroll on ancestors and window.\n   */\n  startScrollTracking(element) {\n    let current = element.parentElement;\n    while (current) {\n      const style = getComputedStyle(current);\n      if (overflowStyles.has(style.overflowX) || overflowStyles.has(style.overflowY)) {\n        this.scrollPositions.set(current, {\n          x: current.scrollLeft,\n          y: current.scrollTop\n        });\n      }\n      current = current.parentElement;\n    }\n    this.scrollPositions.set(window, {\n      x: window.scrollX,\n      y: window.scrollY\n    });\n    window.addEventListener(\"scroll\", this.onElementScroll, {\n      capture: true\n    });\n    window.addEventListener(\"scroll\", this.onWindowScroll);\n    this.removeScrollListeners = () => {\n      window.removeEventListener(\"scroll\", this.onElementScroll, {\n        capture: true\n      });\n      window.removeEventListener(\"scroll\", this.onWindowScroll);\n    };\n  }\n  /**\n   * Handle scroll compensation during drag.\n   *\n   * For element scroll: adjusts history origin since pageX/pageY doesn't change.\n   * For window scroll: adjusts lastMoveEventInfo since pageX/pageY would change.\n   */\n  handleScroll(target) {\n    const initial = this.scrollPositions.get(target);\n    if (!initial)\n      return;\n    const isWindow = target === window;\n    const current = isWindow ? { x: window.scrollX, y: window.scrollY } : {\n      x: target.scrollLeft,\n      y: target.scrollTop\n    };\n    const delta = { x: current.x - initial.x, y: current.y - initial.y };\n    if (delta.x === 0 && delta.y === 0)\n      return;\n    if (isWindow) {\n      if (this.lastMoveEventInfo) {\n        this.lastMoveEventInfo.point.x += delta.x;\n        this.lastMoveEventInfo.point.y += delta.y;\n      }\n    } else {\n      if (this.history.length > 0) {\n        this.history[0].x -= delta.x;\n        this.history[0].y -= delta.y;\n      }\n    }\n    this.scrollPositions.set(target, current);\n    frame.update(this.updatePoint, true);\n  }\n  updateHandlers(handlers) {\n    this.handlers = handlers;\n  }\n  end() {\n    this.removeListeners && this.removeListeners();\n    this.removeScrollListeners && this.removeScrollListeners();\n    this.scrollPositions.clear();\n    cancelFrame(this.updatePoint);\n  }\n};\nfunction transformPoint(info2, transformPagePoint) {\n  return transformPagePoint ? { point: transformPagePoint(info2.point) } : info2;\n}\nfunction subtractPoint(a, b) {\n  return { x: a.x - b.x, y: a.y - b.y };\n}\nfunction getPanInfo({ point }, history) {\n  return {\n    point,\n    delta: subtractPoint(point, lastDevicePoint(history)),\n    offset: subtractPoint(point, startDevicePoint(history)),\n    velocity: getVelocity(history, 0.1)\n  };\n}\nfunction startDevicePoint(history) {\n  return history[0];\n}\nfunction lastDevicePoint(history) {\n  return history[history.length - 1];\n}\nfunction getVelocity(history, timeDelta) {\n  if (history.length < 2) {\n    return { x: 0, y: 0 };\n  }\n  let i = history.length - 1;\n  let timestampedPoint = null;\n  const lastPoint = lastDevicePoint(history);\n  while (i >= 0) {\n    timestampedPoint = history[i];\n    if (lastPoint.timestamp - timestampedPoint.timestamp > secondsToMilliseconds(timeDelta)) {\n      break;\n    }\n    i--;\n  }\n  if (!timestampedPoint) {\n    return { x: 0, y: 0 };\n  }\n  if (timestampedPoint === history[0] && history.length > 2 && lastPoint.timestamp - timestampedPoint.timestamp > secondsToMilliseconds(timeDelta) * 2) {\n    timestampedPoint = history[1];\n  }\n  const time2 = millisecondsToSeconds(lastPoint.timestamp - timestampedPoint.timestamp);\n  if (time2 === 0) {\n    return { x: 0, y: 0 };\n  }\n  const currentVelocity = {\n    x: (lastPoint.x - timestampedPoint.x) / time2,\n    y: (lastPoint.y - timestampedPoint.y) / time2\n  };\n  if (currentVelocity.x === Infinity) {\n    currentVelocity.x = 0;\n  }\n  if (currentVelocity.y === Infinity) {\n    currentVelocity.y = 0;\n  }\n  return currentVelocity;\n}\n\n// ../../node_modules/framer-motion/dist/es/gestures/drag/utils/constraints.mjs\nfunction applyConstraints(point, { min, max }, elastic) {\n  if (min !== void 0 && point < min) {\n    point = elastic ? mixNumber(min, point, elastic.min) : Math.max(point, min);\n  } else if (max !== void 0 && point > max) {\n    point = elastic ? mixNumber(max, point, elastic.max) : Math.min(point, max);\n  }\n  return point;\n}\nfunction calcRelativeAxisConstraints(axis, min, max) {\n  return {\n    min: min !== void 0 ? axis.min + min : void 0,\n    max: max !== void 0 ? axis.max + max - (axis.max - axis.min) : void 0\n  };\n}\nfunction calcRelativeConstraints(layoutBox, { top, left, bottom, right }) {\n  return {\n    x: calcRelativeAxisConstraints(layoutBox.x, left, right),\n    y: calcRelativeAxisConstraints(layoutBox.y, top, bottom)\n  };\n}\nfunction calcViewportAxisConstraints(layoutAxis, constraintsAxis) {\n  let min = constraintsAxis.min - layoutAxis.min;\n  let max = constraintsAxis.max - layoutAxis.max;\n  if (constraintsAxis.max - constraintsAxis.min < layoutAxis.max - layoutAxis.min) {\n    [min, max] = [max, min];\n  }\n  return { min, max };\n}\nfunction calcViewportConstraints(layoutBox, constraintsBox) {\n  return {\n    x: calcViewportAxisConstraints(layoutBox.x, constraintsBox.x),\n    y: calcViewportAxisConstraints(layoutBox.y, constraintsBox.y)\n  };\n}\nfunction calcOrigin(source, target) {\n  let origin = 0.5;\n  const sourceLength = calcLength(source);\n  const targetLength = calcLength(target);\n  if (targetLength > sourceLength) {\n    origin = progress(target.min, target.max - sourceLength, source.min);\n  } else if (sourceLength > targetLength) {\n    origin = progress(source.min, source.max - targetLength, target.min);\n  }\n  return clamp(0, 1, origin);\n}\nfunction rebaseAxisConstraints(layout2, constraints) {\n  const relativeConstraints = {};\n  if (constraints.min !== void 0) {\n    relativeConstraints.min = constraints.min - layout2.min;\n  }\n  if (constraints.max !== void 0) {\n    relativeConstraints.max = constraints.max - layout2.min;\n  }\n  return relativeConstraints;\n}\nvar defaultElastic = 0.35;\nfunction resolveDragElastic(dragElastic = defaultElastic) {\n  if (dragElastic === false) {\n    dragElastic = 0;\n  } else if (dragElastic === true) {\n    dragElastic = defaultElastic;\n  }\n  return {\n    x: resolveAxisElastic(dragElastic, \"left\", \"right\"),\n    y: resolveAxisElastic(dragElastic, \"top\", \"bottom\")\n  };\n}\nfunction resolveAxisElastic(dragElastic, minLabel, maxLabel) {\n  return {\n    min: resolvePointElastic(dragElastic, minLabel),\n    max: resolvePointElastic(dragElastic, maxLabel)\n  };\n}\nfunction resolvePointElastic(dragElastic, label) {\n  return typeof dragElastic === \"number\" ? dragElastic : dragElastic[label] || 0;\n}\n\n// ../../node_modules/framer-motion/dist/es/gestures/drag/VisualElementDragControls.mjs\nvar elementDragControls = /* @__PURE__ */ new WeakMap();\nvar VisualElementDragControls = class {\n  constructor(visualElement) {\n    this.openDragLock = null;\n    this.isDragging = false;\n    this.currentDirection = null;\n    this.originPoint = { x: 0, y: 0 };\n    this.constraints = false;\n    this.hasMutatedConstraints = false;\n    this.elastic = createBox();\n    this.latestPointerEvent = null;\n    this.latestPanInfo = null;\n    this.visualElement = visualElement;\n  }\n  start(originEvent, { snapToCursor = false, distanceThreshold } = {}) {\n    const { presenceContext } = this.visualElement;\n    if (presenceContext && presenceContext.isPresent === false)\n      return;\n    const onSessionStart = (event) => {\n      if (snapToCursor) {\n        this.snapToCursor(extractEventInfo(event).point);\n      }\n      this.stopAnimation();\n    };\n    const onStart = (event, info2) => {\n      const { drag: drag2, dragPropagation, onDragStart } = this.getProps();\n      if (drag2 && !dragPropagation) {\n        if (this.openDragLock)\n          this.openDragLock();\n        this.openDragLock = setDragLock(drag2);\n        if (!this.openDragLock)\n          return;\n      }\n      this.latestPointerEvent = event;\n      this.latestPanInfo = info2;\n      this.isDragging = true;\n      this.currentDirection = null;\n      this.resolveConstraints();\n      if (this.visualElement.projection) {\n        this.visualElement.projection.isAnimationBlocked = true;\n        this.visualElement.projection.target = void 0;\n      }\n      eachAxis((axis) => {\n        let current = this.getAxisMotionValue(axis).get() || 0;\n        if (percent.test(current)) {\n          const { projection } = this.visualElement;\n          if (projection && projection.layout) {\n            const measuredAxis = projection.layout.layoutBox[axis];\n            if (measuredAxis) {\n              const length = calcLength(measuredAxis);\n              current = length * (parseFloat(current) / 100);\n            }\n          }\n        }\n        this.originPoint[axis] = current;\n      });\n      if (onDragStart) {\n        frame.update(() => onDragStart(event, info2), false, true);\n      }\n      addValueToWillChange(this.visualElement, \"transform\");\n      const { animationState } = this.visualElement;\n      animationState && animationState.setActive(\"whileDrag\", true);\n    };\n    const onMove = (event, info2) => {\n      this.latestPointerEvent = event;\n      this.latestPanInfo = info2;\n      const { dragPropagation, dragDirectionLock, onDirectionLock, onDrag } = this.getProps();\n      if (!dragPropagation && !this.openDragLock)\n        return;\n      const { offset } = info2;\n      if (dragDirectionLock && this.currentDirection === null) {\n        this.currentDirection = getCurrentDirection(offset);\n        if (this.currentDirection !== null) {\n          onDirectionLock && onDirectionLock(this.currentDirection);\n        }\n        return;\n      }\n      this.updateAxis(\"x\", info2.point, offset);\n      this.updateAxis(\"y\", info2.point, offset);\n      this.visualElement.render();\n      if (onDrag) {\n        frame.update(() => onDrag(event, info2), false, true);\n      }\n    };\n    const onSessionEnd = (event, info2) => {\n      this.latestPointerEvent = event;\n      this.latestPanInfo = info2;\n      this.stop(event, info2);\n      this.latestPointerEvent = null;\n      this.latestPanInfo = null;\n    };\n    const resumeAnimation = () => {\n      const { dragSnapToOrigin: snap } = this.getProps();\n      if (snap || this.constraints) {\n        this.startAnimation({ x: 0, y: 0 });\n      }\n    };\n    const { dragSnapToOrigin } = this.getProps();\n    this.panSession = new PanSession(originEvent, {\n      onSessionStart,\n      onStart,\n      onMove,\n      onSessionEnd,\n      resumeAnimation\n    }, {\n      transformPagePoint: this.visualElement.getTransformPagePoint(),\n      dragSnapToOrigin,\n      distanceThreshold,\n      contextWindow: getContextWindow(this.visualElement),\n      element: this.visualElement.current\n    });\n  }\n  /**\n   * @internal\n   */\n  stop(event, panInfo) {\n    const finalEvent = event || this.latestPointerEvent;\n    const finalPanInfo = panInfo || this.latestPanInfo;\n    const isDragging2 = this.isDragging;\n    this.cancel();\n    if (!isDragging2 || !finalPanInfo || !finalEvent)\n      return;\n    const { velocity } = finalPanInfo;\n    this.startAnimation(velocity);\n    const { onDragEnd } = this.getProps();\n    if (onDragEnd) {\n      frame.postRender(() => onDragEnd(finalEvent, finalPanInfo));\n    }\n  }\n  /**\n   * @internal\n   */\n  cancel() {\n    this.isDragging = false;\n    const { projection, animationState } = this.visualElement;\n    if (projection) {\n      projection.isAnimationBlocked = false;\n    }\n    this.endPanSession();\n    const { dragPropagation } = this.getProps();\n    if (!dragPropagation && this.openDragLock) {\n      this.openDragLock();\n      this.openDragLock = null;\n    }\n    animationState && animationState.setActive(\"whileDrag\", false);\n  }\n  /**\n   * Clean up the pan session without modifying other drag state.\n   * This is used during unmount to ensure event listeners are removed\n   * without affecting projection animations or drag locks.\n   * @internal\n   */\n  endPanSession() {\n    this.panSession && this.panSession.end();\n    this.panSession = void 0;\n  }\n  updateAxis(axis, _point, offset) {\n    const { drag: drag2 } = this.getProps();\n    if (!offset || !shouldDrag(axis, drag2, this.currentDirection))\n      return;\n    const axisValue = this.getAxisMotionValue(axis);\n    let next = this.originPoint[axis] + offset[axis];\n    if (this.constraints && this.constraints[axis]) {\n      next = applyConstraints(next, this.constraints[axis], this.elastic[axis]);\n    }\n    axisValue.set(next);\n  }\n  resolveConstraints() {\n    const { dragConstraints, dragElastic } = this.getProps();\n    const layout2 = this.visualElement.projection && !this.visualElement.projection.layout ? this.visualElement.projection.measure(false) : this.visualElement.projection?.layout;\n    const prevConstraints = this.constraints;\n    if (dragConstraints && isRefObject(dragConstraints)) {\n      if (!this.constraints) {\n        this.constraints = this.resolveRefConstraints();\n      }\n    } else {\n      if (dragConstraints && layout2) {\n        this.constraints = calcRelativeConstraints(layout2.layoutBox, dragConstraints);\n      } else {\n        this.constraints = false;\n      }\n    }\n    this.elastic = resolveDragElastic(dragElastic);\n    if (prevConstraints !== this.constraints && !isRefObject(dragConstraints) && layout2 && this.constraints && !this.hasMutatedConstraints) {\n      eachAxis((axis) => {\n        if (this.constraints !== false && this.getAxisMotionValue(axis)) {\n          this.constraints[axis] = rebaseAxisConstraints(layout2.layoutBox[axis], this.constraints[axis]);\n        }\n      });\n    }\n  }\n  resolveRefConstraints() {\n    const { dragConstraints: constraints, onMeasureDragConstraints } = this.getProps();\n    if (!constraints || !isRefObject(constraints))\n      return false;\n    const constraintsElement = constraints.current;\n    invariant(constraintsElement !== null, \"If `dragConstraints` is set as a React ref, that ref must be passed to another component's `ref` prop.\", \"drag-constraints-ref\");\n    const { projection } = this.visualElement;\n    if (!projection || !projection.layout)\n      return false;\n    if (projection.root) {\n      projection.root.scroll = void 0;\n      projection.root.updateScroll();\n    }\n    const constraintsBox = measurePageBox(constraintsElement, projection.root, this.visualElement.getTransformPagePoint());\n    let measuredConstraints = calcViewportConstraints(projection.layout.layoutBox, constraintsBox);\n    if (onMeasureDragConstraints) {\n      const userConstraints = onMeasureDragConstraints(convertBoxToBoundingBox(measuredConstraints));\n      this.hasMutatedConstraints = !!userConstraints;\n      if (userConstraints) {\n        measuredConstraints = convertBoundingBoxToBox(userConstraints);\n      }\n    }\n    return measuredConstraints;\n  }\n  startAnimation(velocity) {\n    const { drag: drag2, dragMomentum, dragElastic, dragTransition, dragSnapToOrigin, onDragTransitionEnd } = this.getProps();\n    const constraints = this.constraints || {};\n    const momentumAnimations = eachAxis((axis) => {\n      if (!shouldDrag(axis, drag2, this.currentDirection)) {\n        return;\n      }\n      let transition = constraints && constraints[axis] || {};\n      if (dragSnapToOrigin === true || dragSnapToOrigin === axis)\n        transition = { min: 0, max: 0 };\n      const bounceStiffness = dragElastic ? 200 : 1e6;\n      const bounceDamping = dragElastic ? 40 : 1e7;\n      const inertia2 = {\n        type: \"inertia\",\n        velocity: dragMomentum ? velocity[axis] : 0,\n        bounceStiffness,\n        bounceDamping,\n        timeConstant: 750,\n        restDelta: 1,\n        restSpeed: 10,\n        ...dragTransition,\n        ...transition\n      };\n      return this.startAxisValueAnimation(axis, inertia2);\n    });\n    return Promise.all(momentumAnimations).then(onDragTransitionEnd);\n  }\n  startAxisValueAnimation(axis, transition) {\n    const axisValue = this.getAxisMotionValue(axis);\n    addValueToWillChange(this.visualElement, axis);\n    return axisValue.start(animateMotionValue(axis, axisValue, 0, transition, this.visualElement, false));\n  }\n  stopAnimation() {\n    eachAxis((axis) => this.getAxisMotionValue(axis).stop());\n  }\n  /**\n   * Drag works differently depending on which props are provided.\n   *\n   * - If _dragX and _dragY are provided, we output the gesture delta directly to those motion values.\n   * - Otherwise, we apply the delta to the x/y motion values.\n   */\n  getAxisMotionValue(axis) {\n    const dragKey = `_drag${axis.toUpperCase()}`;\n    const props = this.visualElement.getProps();\n    const externalMotionValue = props[dragKey];\n    return externalMotionValue ? externalMotionValue : this.visualElement.getValue(axis, this.visualElement.latestValues[axis] ?? 0);\n  }\n  snapToCursor(point) {\n    eachAxis((axis) => {\n      const { drag: drag2 } = this.getProps();\n      if (!shouldDrag(axis, drag2, this.currentDirection))\n        return;\n      const { projection } = this.visualElement;\n      const axisValue = this.getAxisMotionValue(axis);\n      if (projection && projection.layout) {\n        const { min, max } = projection.layout.layoutBox[axis];\n        const current = axisValue.get() || 0;\n        axisValue.set(point[axis] - mixNumber(min, max, 0.5) + current);\n      }\n    });\n  }\n  /**\n   * When the viewport resizes we want to check if the measured constraints\n   * have changed and, if so, reposition the element within those new constraints\n   * relative to where it was before the resize.\n   */\n  scalePositionWithinConstraints() {\n    if (!this.visualElement.current)\n      return;\n    const { drag: drag2, dragConstraints } = this.getProps();\n    const { projection } = this.visualElement;\n    if (!isRefObject(dragConstraints) || !projection || !this.constraints)\n      return;\n    this.stopAnimation();\n    const boxProgress = { x: 0, y: 0 };\n    eachAxis((axis) => {\n      const axisValue = this.getAxisMotionValue(axis);\n      if (axisValue && this.constraints !== false) {\n        const latest = axisValue.get();\n        boxProgress[axis] = calcOrigin({ min: latest, max: latest }, this.constraints[axis]);\n      }\n    });\n    const { transformTemplate } = this.visualElement.getProps();\n    this.visualElement.current.style.transform = transformTemplate ? transformTemplate({}, \"\") : \"none\";\n    projection.root && projection.root.updateScroll();\n    projection.updateLayout();\n    this.constraints = false;\n    this.resolveConstraints();\n    eachAxis((axis) => {\n      if (!shouldDrag(axis, drag2, null))\n        return;\n      const axisValue = this.getAxisMotionValue(axis);\n      const { min, max } = this.constraints[axis];\n      axisValue.set(mixNumber(min, max, boxProgress[axis]));\n    });\n    this.visualElement.render();\n  }\n  addListeners() {\n    if (!this.visualElement.current)\n      return;\n    elementDragControls.set(this.visualElement, this);\n    const element = this.visualElement.current;\n    const stopPointerListener = addPointerEvent(element, \"pointerdown\", (event) => {\n      const { drag: drag2, dragListener = true } = this.getProps();\n      const target = event.target;\n      const isClickingTextInputChild = target !== element && isElementTextInput(target);\n      if (drag2 && dragListener && !isClickingTextInputChild) {\n        this.start(event);\n      }\n    });\n    let stopResizeObservers;\n    const measureDragConstraints = () => {\n      const { dragConstraints } = this.getProps();\n      if (isRefObject(dragConstraints) && dragConstraints.current) {\n        this.constraints = this.resolveRefConstraints();\n        if (!stopResizeObservers) {\n          stopResizeObservers = startResizeObservers(element, dragConstraints.current, () => this.scalePositionWithinConstraints());\n        }\n      }\n    };\n    const { projection } = this.visualElement;\n    const stopMeasureLayoutListener = projection.addEventListener(\"measure\", measureDragConstraints);\n    if (projection && !projection.layout) {\n      projection.root && projection.root.updateScroll();\n      projection.updateLayout();\n    }\n    frame.read(measureDragConstraints);\n    const stopResizeListener = addDomEvent(window, \"resize\", () => this.scalePositionWithinConstraints());\n    const stopLayoutUpdateListener = projection.addEventListener(\"didUpdate\", (({ delta, hasLayoutChanged }) => {\n      if (this.isDragging && hasLayoutChanged) {\n        eachAxis((axis) => {\n          const motionValue2 = this.getAxisMotionValue(axis);\n          if (!motionValue2)\n            return;\n          this.originPoint[axis] += delta[axis].translate;\n          motionValue2.set(motionValue2.get() + delta[axis].translate);\n        });\n        this.visualElement.render();\n      }\n    }));\n    return () => {\n      stopResizeListener();\n      stopPointerListener();\n      stopMeasureLayoutListener();\n      stopLayoutUpdateListener && stopLayoutUpdateListener();\n      stopResizeObservers && stopResizeObservers();\n    };\n  }\n  getProps() {\n    const props = this.visualElement.getProps();\n    const { drag: drag2 = false, dragDirectionLock = false, dragPropagation = false, dragConstraints = false, dragElastic = defaultElastic, dragMomentum = true } = props;\n    return {\n      ...props,\n      drag: drag2,\n      dragDirectionLock,\n      dragPropagation,\n      dragConstraints,\n      dragElastic,\n      dragMomentum\n    };\n  }\n};\nfunction skipFirstCall(callback) {\n  let isFirst = true;\n  return () => {\n    if (isFirst) {\n      isFirst = false;\n      return;\n    }\n    callback();\n  };\n}\nfunction startResizeObservers(element, constraintsElement, onResize) {\n  const stopElement = resize(element, skipFirstCall(onResize));\n  const stopContainer = resize(constraintsElement, skipFirstCall(onResize));\n  return () => {\n    stopElement();\n    stopContainer();\n  };\n}\nfunction shouldDrag(direction, drag2, currentDirection) {\n  return (drag2 === true || drag2 === direction) && (currentDirection === null || currentDirection === direction);\n}\nfunction getCurrentDirection(offset, lockThreshold = 10) {\n  let direction = null;\n  if (Math.abs(offset.y) > lockThreshold) {\n    direction = \"y\";\n  } else if (Math.abs(offset.x) > lockThreshold) {\n    direction = \"x\";\n  }\n  return direction;\n}\n\n// ../../node_modules/framer-motion/dist/es/gestures/drag/index.mjs\nvar DragGesture = class extends Feature {\n  constructor(node) {\n    super(node);\n    this.removeGroupControls = noop;\n    this.removeListeners = noop;\n    this.controls = new VisualElementDragControls(node);\n  }\n  mount() {\n    const { dragControls } = this.node.getProps();\n    if (dragControls) {\n      this.removeGroupControls = dragControls.subscribe(this.controls);\n    }\n    this.removeListeners = this.controls.addListeners() || noop;\n  }\n  update() {\n    const { dragControls } = this.node.getProps();\n    const { dragControls: prevDragControls } = this.node.prevProps || {};\n    if (dragControls !== prevDragControls) {\n      this.removeGroupControls();\n      if (dragControls) {\n        this.removeGroupControls = dragControls.subscribe(this.controls);\n      }\n    }\n  }\n  unmount() {\n    this.removeGroupControls();\n    this.removeListeners();\n    if (!this.controls.isDragging) {\n      this.controls.endPanSession();\n    }\n  }\n};\n\n// ../../node_modules/framer-motion/dist/es/gestures/pan/index.mjs\nvar asyncHandler = (handler) => (event, info2) => {\n  if (handler) {\n    frame.update(() => handler(event, info2), false, true);\n  }\n};\nvar PanGesture = class extends Feature {\n  constructor() {\n    super(...arguments);\n    this.removePointerDownListener = noop;\n  }\n  onPointerDown(pointerDownEvent) {\n    this.session = new PanSession(pointerDownEvent, this.createPanHandlers(), {\n      transformPagePoint: this.node.getTransformPagePoint(),\n      contextWindow: getContextWindow(this.node)\n    });\n  }\n  createPanHandlers() {\n    const { onPanSessionStart, onPanStart, onPan, onPanEnd } = this.node.getProps();\n    return {\n      onSessionStart: asyncHandler(onPanSessionStart),\n      onStart: asyncHandler(onPanStart),\n      onMove: asyncHandler(onPan),\n      onEnd: (event, info2) => {\n        delete this.session;\n        if (onPanEnd) {\n          frame.postRender(() => onPanEnd(event, info2));\n        }\n      }\n    };\n  }\n  mount() {\n    this.removePointerDownListener = addPointerEvent(this.node.current, \"pointerdown\", (event) => this.onPointerDown(event));\n  }\n  update() {\n    this.session && this.session.updateHandlers(this.createPanHandlers());\n  }\n  unmount() {\n    this.removePointerDownListener();\n    this.session && this.session.end();\n  }\n};\n\n// ../../node_modules/framer-motion/dist/es/motion/features/layout/MeasureLayout.mjs\nimport { jsx as jsx5 } from \"react/jsx-runtime\";\nimport { useContext as useContext8, Component as Component2 } from \"react\";\nvar hasTakenAnySnapshot = false;\nvar MeasureLayoutWithContext = class extends Component2 {\n  /**\n   * This only mounts projection nodes for components that\n   * need measuring, we might want to do it for all components\n   * in order to incorporate transforms\n   */\n  componentDidMount() {\n    const { visualElement, layoutGroup, switchLayoutGroup, layoutId } = this.props;\n    const { projection } = visualElement;\n    if (projection) {\n      if (layoutGroup.group)\n        layoutGroup.group.add(projection);\n      if (switchLayoutGroup && switchLayoutGroup.register && layoutId) {\n        switchLayoutGroup.register(projection);\n      }\n      if (hasTakenAnySnapshot) {\n        projection.root.didUpdate();\n      }\n      projection.addEventListener(\"animationComplete\", () => {\n        this.safeToRemove();\n      });\n      projection.setOptions({\n        ...projection.options,\n        layoutDependency: this.props.layoutDependency,\n        onExitComplete: () => this.safeToRemove()\n      });\n    }\n    globalProjectionState.hasEverUpdated = true;\n  }\n  getSnapshotBeforeUpdate(prevProps) {\n    const { layoutDependency, visualElement, drag: drag2, isPresent } = this.props;\n    const { projection } = visualElement;\n    if (!projection)\n      return null;\n    projection.isPresent = isPresent;\n    if (prevProps.layoutDependency !== layoutDependency) {\n      projection.setOptions({\n        ...projection.options,\n        layoutDependency\n      });\n    }\n    hasTakenAnySnapshot = true;\n    if (drag2 || prevProps.layoutDependency !== layoutDependency || layoutDependency === void 0 || prevProps.isPresent !== isPresent) {\n      projection.willUpdate();\n    } else {\n      this.safeToRemove();\n    }\n    if (prevProps.isPresent !== isPresent) {\n      if (isPresent) {\n        projection.promote();\n      } else if (!projection.relegate()) {\n        frame.postRender(() => {\n          const stack = projection.getStack();\n          if (!stack || !stack.members.length) {\n            this.safeToRemove();\n          }\n        });\n      }\n    }\n    return null;\n  }\n  componentDidUpdate() {\n    const { visualElement, layoutAnchor } = this.props;\n    const { projection } = visualElement;\n    if (projection) {\n      projection.options.layoutAnchor = layoutAnchor;\n      projection.root.didUpdate();\n      microtask.postRender(() => {\n        if (!projection.currentAnimation && projection.isLead()) {\n          this.safeToRemove();\n        }\n      });\n    }\n  }\n  componentWillUnmount() {\n    const { visualElement, layoutGroup, switchLayoutGroup: promoteContext } = this.props;\n    const { projection } = visualElement;\n    hasTakenAnySnapshot = true;\n    if (projection) {\n      projection.scheduleCheckAfterUnmount();\n      if (layoutGroup && layoutGroup.group)\n        layoutGroup.group.remove(projection);\n      if (promoteContext && promoteContext.deregister)\n        promoteContext.deregister(projection);\n    }\n  }\n  safeToRemove() {\n    const { safeToRemove } = this.props;\n    safeToRemove && safeToRemove();\n  }\n  render() {\n    return null;\n  }\n};\nfunction MeasureLayout(props) {\n  const [isPresent, safeToRemove] = usePresence();\n  const layoutGroup = useContext8(LayoutGroupContext);\n  return jsx5(MeasureLayoutWithContext, { ...props, layoutGroup, switchLayoutGroup: useContext8(SwitchLayoutGroupContext), isPresent, safeToRemove });\n}\n\n// ../../node_modules/framer-motion/dist/es/motion/features/drag.mjs\nvar drag = {\n  pan: {\n    Feature: PanGesture\n  },\n  drag: {\n    Feature: DragGesture,\n    ProjectionNode: HTMLProjectionNode,\n    MeasureLayout\n  }\n};\n\n// ../../node_modules/framer-motion/dist/es/gestures/hover.mjs\nfunction handleHoverEvent(node, event, lifecycle) {\n  const { props } = node;\n  if (node.animationState && props.whileHover) {\n    node.animationState.setActive(\"whileHover\", lifecycle === \"Start\");\n  }\n  const eventName = \"onHover\" + lifecycle;\n  const callback = props[eventName];\n  if (callback) {\n    frame.postRender(() => callback(event, extractEventInfo(event)));\n  }\n}\nvar HoverGesture = class extends Feature {\n  mount() {\n    const { current } = this.node;\n    if (!current)\n      return;\n    this.unmount = hover(current, (_element, startEvent) => {\n      handleHoverEvent(this.node, startEvent, \"Start\");\n      return (endEvent) => handleHoverEvent(this.node, endEvent, \"End\");\n    });\n  }\n  unmount() {\n  }\n};\n\n// ../../node_modules/framer-motion/dist/es/gestures/focus.mjs\nvar FocusGesture = class extends Feature {\n  constructor() {\n    super(...arguments);\n    this.isActive = false;\n  }\n  onFocus() {\n    let isFocusVisible = false;\n    try {\n      isFocusVisible = this.node.current.matches(\":focus-visible\");\n    } catch (e10) {\n      isFocusVisible = true;\n    }\n    if (!isFocusVisible || !this.node.animationState)\n      return;\n    this.node.animationState.setActive(\"whileFocus\", true);\n    this.isActive = true;\n  }\n  onBlur() {\n    if (!this.isActive || !this.node.animationState)\n      return;\n    this.node.animationState.setActive(\"whileFocus\", false);\n    this.isActive = false;\n  }\n  mount() {\n    this.unmount = pipe(addDomEvent(this.node.current, \"focus\", () => this.onFocus()), addDomEvent(this.node.current, \"blur\", () => this.onBlur()));\n  }\n  unmount() {\n  }\n};\n\n// ../../node_modules/framer-motion/dist/es/gestures/press.mjs\nfunction handlePressEvent(node, event, lifecycle) {\n  const { props } = node;\n  if (node.current instanceof HTMLButtonElement && node.current.disabled) {\n    return;\n  }\n  if (node.animationState && props.whileTap) {\n    node.animationState.setActive(\"whileTap\", lifecycle === \"Start\");\n  }\n  const eventName = \"onTap\" + (lifecycle === \"End\" ? \"\" : lifecycle);\n  const callback = props[eventName];\n  if (callback) {\n    frame.postRender(() => callback(event, extractEventInfo(event)));\n  }\n}\nvar PressGesture = class extends Feature {\n  mount() {\n    const { current } = this.node;\n    if (!current)\n      return;\n    const { globalTapTarget, propagate } = this.node.props;\n    this.unmount = press(current, (_element, startEvent) => {\n      handlePressEvent(this.node, startEvent, \"Start\");\n      return (endEvent, { success }) => handlePressEvent(this.node, endEvent, success ? \"End\" : \"Cancel\");\n    }, {\n      useGlobalTarget: globalTapTarget,\n      stopPropagation: propagate?.tap === false\n    });\n  }\n  unmount() {\n  }\n};\n\n// ../../node_modules/framer-motion/dist/es/motion/features/viewport/observers.mjs\nvar observerCallbacks = /* @__PURE__ */ new WeakMap();\nvar observers = /* @__PURE__ */ new WeakMap();\nvar fireObserverCallback = (entry) => {\n  const callback = observerCallbacks.get(entry.target);\n  callback && callback(entry);\n};\nvar fireAllObserverCallbacks = (entries) => {\n  entries.forEach(fireObserverCallback);\n};\nfunction initIntersectionObserver({ root, ...options }) {\n  const lookupRoot = root || document;\n  if (!observers.has(lookupRoot)) {\n    observers.set(lookupRoot, {});\n  }\n  const rootObservers = observers.get(lookupRoot);\n  const key = JSON.stringify(options);\n  if (!rootObservers[key]) {\n    rootObservers[key] = new IntersectionObserver(fireAllObserverCallbacks, { root, ...options });\n  }\n  return rootObservers[key];\n}\nfunction observeIntersection(element, options, callback) {\n  const rootInteresectionObserver = initIntersectionObserver(options);\n  observerCallbacks.set(element, callback);\n  rootInteresectionObserver.observe(element);\n  return () => {\n    observerCallbacks.delete(element);\n    rootInteresectionObserver.unobserve(element);\n  };\n}\n\n// ../../node_modules/framer-motion/dist/es/motion/features/viewport/index.mjs\nvar thresholdNames = {\n  some: 0,\n  all: 1\n};\nvar InViewFeature = class extends Feature {\n  constructor() {\n    super(...arguments);\n    this.hasEnteredView = false;\n    this.isInView = false;\n  }\n  startObserver() {\n    this.stopObserver?.();\n    const { viewport = {} } = this.node.getProps();\n    const { root, margin: rootMargin, amount = \"some\", once } = viewport;\n    const options = {\n      root: root ? root.current : void 0,\n      rootMargin,\n      threshold: typeof amount === \"number\" ? amount : thresholdNames[amount]\n    };\n    const onIntersectionUpdate = (entry) => {\n      const { isIntersecting } = entry;\n      if (this.isInView === isIntersecting)\n        return;\n      this.isInView = isIntersecting;\n      if (once && !isIntersecting && this.hasEnteredView) {\n        return;\n      } else if (isIntersecting) {\n        this.hasEnteredView = true;\n      }\n      if (this.node.animationState) {\n        this.node.animationState.setActive(\"whileInView\", isIntersecting);\n      }\n      const { onViewportEnter, onViewportLeave } = this.node.getProps();\n      const callback = isIntersecting ? onViewportEnter : onViewportLeave;\n      callback && callback(entry);\n    };\n    this.stopObserver = observeIntersection(this.node.current, options, onIntersectionUpdate);\n  }\n  mount() {\n    this.startObserver();\n  }\n  update() {\n    if (typeof IntersectionObserver === \"undefined\")\n      return;\n    const { props, prevProps } = this.node;\n    const hasOptionsChanged = [\"amount\", \"margin\", \"root\"].some(hasViewportOptionChanged(props, prevProps));\n    if (hasOptionsChanged) {\n      this.startObserver();\n    }\n  }\n  unmount() {\n    this.stopObserver?.();\n    this.hasEnteredView = false;\n    this.isInView = false;\n  }\n};\nfunction hasViewportOptionChanged({ viewport = {} }, { viewport: prevViewport = {} } = {}) {\n  return (name) => viewport[name] !== prevViewport[name];\n}\n\n// ../../node_modules/framer-motion/dist/es/motion/features/gestures.mjs\nvar gestureAnimations = {\n  inView: {\n    Feature: InViewFeature\n  },\n  tap: {\n    Feature: PressGesture\n  },\n  focus: {\n    Feature: FocusGesture\n  },\n  hover: {\n    Feature: HoverGesture\n  }\n};\n\n// ../../node_modules/framer-motion/dist/es/motion/features/layout.mjs\nvar layout = {\n  layout: {\n    ProjectionNode: HTMLProjectionNode,\n    MeasureLayout\n  }\n};\n\n// ../../node_modules/framer-motion/dist/es/render/components/motion/feature-bundle.mjs\nvar featureBundle = {\n  ...animations,\n  ...gestureAnimations,\n  ...drag,\n  ...layout\n};\n\n// ../../node_modules/framer-motion/dist/es/render/components/motion/proxy.mjs\nvar motion = /* @__PURE__ */ createMotionProxy(featureBundle, createDomVisualElement);\n\n// ../../node_modules/framer-motion/dist/es/utils/use-motion-value-event.mjs\nimport { useInsertionEffect as useInsertionEffect4 } from \"react\";\nfunction useMotionValueEvent(value, event, callback) {\n  useInsertionEffect4(() => value.on(event, callback), [value, event, callback]);\n}\n\n// ../../node_modules/framer-motion/dist/es/value/use-motion-value.mjs\nimport { useContext as useContext9, useState as useState2, useEffect as useEffect5 } from \"react\";\nfunction useMotionValue(initial) {\n  const value = useConstant(() => motionValue(initial));\n  const { isStatic } = useContext9(MotionConfigContext);\n  if (isStatic) {\n    const [, setLatest] = useState2(initial);\n    useEffect5(() => value.on(\"change\", setLatest), []);\n  }\n  return value;\n}\n\n// ../../node_modules/framer-motion/dist/es/value/use-combine-values.mjs\nfunction useCombineMotionValues(values, combineValues) {\n  const value = useMotionValue(combineValues());\n  const updateValue = () => value.set(combineValues());\n  updateValue();\n  useIsomorphicLayoutEffect(() => {\n    const scheduleUpdate = () => frame.preRender(updateValue, false, true);\n    const subscriptions = values.map((v) => v.on(\"change\", scheduleUpdate));\n    return () => {\n      subscriptions.forEach((unsubscribe) => unsubscribe());\n      cancelFrame(updateValue);\n    };\n  });\n  return value;\n}\n\n// ../../node_modules/framer-motion/dist/es/value/use-computed.mjs\nfunction useComputed(compute) {\n  collectMotionValues.current = [];\n  compute();\n  const value = useCombineMotionValues(collectMotionValues.current, compute);\n  collectMotionValues.current = void 0;\n  return value;\n}\n\n// ../../node_modules/framer-motion/dist/es/value/use-transform.mjs\nfunction useTransform(input, inputRangeOrTransformer, outputRangeOrMap, options) {\n  if (typeof input === \"function\") {\n    return useComputed(input);\n  }\n  const isOutputMap = outputRangeOrMap !== void 0 && !Array.isArray(outputRangeOrMap) && typeof inputRangeOrTransformer !== \"function\";\n  if (isOutputMap) {\n    return useMapTransform(input, inputRangeOrTransformer, outputRangeOrMap, options);\n  }\n  const outputRange = outputRangeOrMap;\n  const transformer = typeof inputRangeOrTransformer === \"function\" ? inputRangeOrTransformer : transform(inputRangeOrTransformer, outputRange, options);\n  const result = Array.isArray(input) ? useListTransform(input, transformer) : useListTransform([input], ([latest]) => transformer(latest));\n  const inputAccelerate = !Array.isArray(input) ? input.accelerate : void 0;\n  if (inputAccelerate && !inputAccelerate.isTransformed && typeof inputRangeOrTransformer !== \"function\" && Array.isArray(outputRangeOrMap) && options?.clamp !== false) {\n    result.accelerate = {\n      ...inputAccelerate,\n      times: inputRangeOrTransformer,\n      keyframes: outputRangeOrMap,\n      isTransformed: true,\n      ...options?.ease ? { ease: options.ease } : {}\n    };\n  }\n  return result;\n}\nfunction useListTransform(values, transformer) {\n  const latest = useConstant(() => []);\n  return useCombineMotionValues(values, () => {\n    latest.length = 0;\n    const numValues = values.length;\n    for (let i = 0; i < numValues; i++) {\n      latest[i] = values[i].get();\n    }\n    return transformer(latest);\n  });\n}\nfunction useMapTransform(inputValue, inputRange, outputMap, options) {\n  const keys = useConstant(() => Object.keys(outputMap));\n  const output = useConstant(() => ({}));\n  for (const key of keys) {\n    output[key] = useTransform(inputValue, inputRange, outputMap[key], options);\n  }\n  return output;\n}\n\n// ../../node_modules/framer-motion/dist/es/value/use-velocity.mjs\nfunction useVelocity(value) {\n  const velocity = useMotionValue(value.getVelocity());\n  const updateVelocity = () => {\n    const latest = value.getVelocity();\n    velocity.set(latest);\n    if (latest)\n      frame.update(updateVelocity);\n  };\n  useMotionValueEvent(value, \"change\", () => {\n    frame.update(updateVelocity, false, true);\n  });\n  return velocity;\n}\n\n// ../../node_modules/framer-motion/dist/es/utils/reduced-motion/use-reduced-motion.mjs\nimport { useState as useState3 } from \"react\";\nfunction useReducedMotion() {\n  !hasReducedMotionListener.current && initPrefersReducedMotion();\n  const [shouldReduceMotion] = useState3(prefersReducedMotion.current);\n  if (false) {\n    warnOnce(shouldReduceMotion !== true, \"You have Reduced Motion enabled on your device. Animations may not appear as expected.\", \"reduced-motion-disabled\");\n  }\n  return shouldReduceMotion;\n}\n\n// ../../node_modules/framer-motion/dist/es/animation/utils/is-dom-keyframes.mjs\nfunction isDOMKeyframes(keyframes2) {\n  return typeof keyframes2 === \"object\" && !Array.isArray(keyframes2);\n}\n\n// ../../node_modules/framer-motion/dist/es/animation/animate/resolve-subjects.mjs\nfunction resolveSubjects(subject, keyframes2, scope, selectorCache) {\n  if (subject == null) {\n    return [];\n  }\n  if (typeof subject === \"string\" && isDOMKeyframes(keyframes2)) {\n    return resolveElements(subject, scope, selectorCache);\n  } else if (subject instanceof NodeList) {\n    return Array.from(subject);\n  } else if (Array.isArray(subject)) {\n    return subject.filter((s) => s != null);\n  } else {\n    return [subject];\n  }\n}\n\n// ../../node_modules/framer-motion/dist/es/animation/sequence/utils/calc-repeat-duration.mjs\nfunction calculateRepeatDuration(duration, repeat, repeatDelay) {\n  return duration * (repeat + 1) + repeatDelay * repeat;\n}\n\n// ../../node_modules/framer-motion/dist/es/animation/sequence/utils/calc-time.mjs\nfunction calcNextTime(current, next, prev, labels) {\n  if (typeof next === \"number\") {\n    return next;\n  } else if (next.startsWith(\"-\") || next.startsWith(\"+\")) {\n    return Math.max(0, current + parseFloat(next));\n  } else if (next === \"<\") {\n    return prev;\n  } else if (next.startsWith(\"<\")) {\n    return Math.max(0, prev + parseFloat(next.slice(1)));\n  } else {\n    return labels.get(next) ?? current;\n  }\n}\n\n// ../../node_modules/framer-motion/dist/es/animation/sequence/utils/edit.mjs\nfunction eraseKeyframes(sequence, startTime, endTime) {\n  for (let i = 0; i < sequence.length; i++) {\n    const keyframe = sequence[i];\n    if (keyframe.at > startTime && keyframe.at < endTime) {\n      removeItem(sequence, keyframe);\n      i--;\n    }\n  }\n}\nfunction addKeyframes(sequence, keyframes2, easing, offset, startTime, endTime) {\n  eraseKeyframes(sequence, startTime, endTime);\n  for (let i = 0; i < keyframes2.length; i++) {\n    sequence.push({\n      value: keyframes2[i],\n      at: mixNumber(startTime, endTime, offset[i]),\n      easing: getEasingForSegment(easing, i)\n    });\n  }\n}\n\n// ../../node_modules/framer-motion/dist/es/animation/sequence/utils/normalize-times.mjs\nfunction normalizeTimes(times, repeat, repeatDelayUnits = 0) {\n  const totalUnits = repeat + 1 + repeat * repeatDelayUnits;\n  for (let i = 0; i < times.length; i++) {\n    times[i] = times[i] / totalUnits;\n  }\n}\n\n// ../../node_modules/framer-motion/dist/es/animation/sequence/utils/sort.mjs\nfunction compareByTime(a, b) {\n  if (a.at === b.at) {\n    if (a.value === null)\n      return 1;\n    if (b.value === null)\n      return -1;\n    return 0;\n  } else {\n    return a.at - b.at;\n  }\n}\n\n// ../../node_modules/framer-motion/dist/es/animation/sequence/create.mjs\nvar defaultSegmentEasing = \"easeInOut\";\nvar MAX_REPEAT = 20;\nfunction createAnimationsFromSequence(sequence, { defaultTransition = {}, ...sequenceTransition } = {}, scope, generators) {\n  const defaultDuration = defaultTransition.duration || 0.3;\n  const animationDefinitions = /* @__PURE__ */ new Map();\n  const sequences = /* @__PURE__ */ new Map();\n  const elementCache = {};\n  const timeLabels = /* @__PURE__ */ new Map();\n  let prevTime = 0;\n  let currentTime = 0;\n  let totalDuration = 0;\n  for (let i = 0; i < sequence.length; i++) {\n    const segment = sequence[i];\n    if (typeof segment === \"string\") {\n      timeLabels.set(segment, currentTime);\n      continue;\n    } else if (!Array.isArray(segment)) {\n      timeLabels.set(segment.name, calcNextTime(currentTime, segment.at, prevTime, timeLabels));\n      continue;\n    }\n    let [subject, keyframes2, transition = {}] = segment;\n    if (transition.at !== void 0) {\n      currentTime = calcNextTime(currentTime, transition.at, prevTime, timeLabels);\n    }\n    let maxDuration = 0;\n    const resolveValueSequence = (valueKeyframes, valueTransition, valueSequence, elementIndex = 0, numSubjects = 0) => {\n      const valueKeyframesAsList = keyframesAsList(valueKeyframes);\n      const { delay: delay2 = 0, times = defaultOffset(valueKeyframesAsList), type = defaultTransition.type || \"keyframes\", repeat, repeatType, repeatDelay = 0, ...remainingTransition } = valueTransition;\n      let { ease: ease2 = defaultTransition.ease || \"easeOut\", duration } = valueTransition;\n      const calculatedDelay = typeof delay2 === \"function\" ? delay2(elementIndex, numSubjects) : delay2;\n      const numKeyframes = valueKeyframesAsList.length;\n      const createGenerator = isGenerator(type) ? type : generators?.[type || \"keyframes\"];\n      if (numKeyframes <= 2 && createGenerator) {\n        let absoluteDelta = 100;\n        if (numKeyframes === 2 && isNumberKeyframesArray(valueKeyframesAsList)) {\n          const delta = valueKeyframesAsList[1] - valueKeyframesAsList[0];\n          absoluteDelta = Math.abs(delta);\n        }\n        const springTransition = {\n          ...defaultTransition,\n          ...remainingTransition\n        };\n        if (duration !== void 0) {\n          springTransition.duration = secondsToMilliseconds(duration);\n        }\n        const springEasing = createGeneratorEasing(springTransition, absoluteDelta, createGenerator);\n        ease2 = springEasing.ease;\n        duration = springEasing.duration;\n      }\n      duration ?? (duration = defaultDuration);\n      const startTime = currentTime + calculatedDelay;\n      if (times.length === 1 && times[0] === 0) {\n        times[1] = 1;\n      }\n      const remainder = times.length - valueKeyframesAsList.length;\n      remainder > 0 && fillOffset(times, remainder);\n      valueKeyframesAsList.length === 1 && valueKeyframesAsList.unshift(null);\n      if (repeat) {\n        warning2(repeat < MAX_REPEAT, `Sequence segments can't repeat ${repeat} times \\u2014 ignoring repeat option. Use a value below ${MAX_REPEAT} or apply repeat at the sequence level instead.`);\n      }\n      if (repeat && repeat < MAX_REPEAT) {\n        const repeatDelayUnits = duration > 0 ? repeatDelay / duration : 0;\n        duration = calculateRepeatDuration(duration, repeat, repeatDelay);\n        const originalKeyframes = [...valueKeyframesAsList];\n        const originalTimes = [...times];\n        ease2 = Array.isArray(ease2) ? [...ease2] : [ease2];\n        const originalEase = [...ease2];\n        const isFlipping = repeatType === \"reverse\" || repeatType === \"mirror\";\n        let flippedKeyframes = originalKeyframes;\n        let flippedEases = originalEase;\n        if (isFlipping) {\n          flippedKeyframes = [...originalKeyframes].reverse();\n          if (repeatType === \"reverse\") {\n            flippedEases = [...originalEase].reverse().map((e10) => typeof e10 === \"function\" ? reverseEasing(e10) : e10);\n          }\n        }\n        for (let repeatIndex = 0; repeatIndex < repeat; repeatIndex++) {\n          const isFlipped = isFlipping && repeatIndex % 2 === 0;\n          const iterKeyframes = isFlipped ? flippedKeyframes : originalKeyframes;\n          const iterEase = isFlipped ? flippedEases : originalEase;\n          const iterStartOffset = (repeatIndex + 1) * (1 + repeatDelayUnits);\n          if (repeatDelayUnits > 0) {\n            valueKeyframesAsList.push(valueKeyframesAsList[valueKeyframesAsList.length - 1]);\n            times.push(iterStartOffset);\n            ease2.push(\"linear\");\n          }\n          valueKeyframesAsList.push(...iterKeyframes);\n          for (let keyframeIndex = 0; keyframeIndex < iterKeyframes.length; keyframeIndex++) {\n            times.push(originalTimes[keyframeIndex] + iterStartOffset);\n            ease2.push(keyframeIndex === 0 ? \"linear\" : getEasingForSegment(iterEase, keyframeIndex - 1));\n          }\n        }\n        normalizeTimes(times, repeat, repeatDelayUnits);\n      }\n      const targetTime = startTime + duration;\n      addKeyframes(valueSequence, valueKeyframesAsList, ease2, times, startTime, targetTime);\n      maxDuration = Math.max(calculatedDelay + duration, maxDuration);\n      totalDuration = Math.max(targetTime, totalDuration);\n    };\n    if (isMotionValue(subject)) {\n      const subjectSequence = getSubjectSequence(subject, sequences);\n      resolveValueSequence(keyframes2, transition, getValueSequence(\"default\", subjectSequence));\n    } else {\n      const subjects = resolveSubjects(subject, keyframes2, scope, elementCache);\n      const numSubjects = subjects.length;\n      for (let subjectIndex = 0; subjectIndex < numSubjects; subjectIndex++) {\n        keyframes2 = keyframes2;\n        transition = transition;\n        const thisSubject = subjects[subjectIndex];\n        const subjectSequence = getSubjectSequence(thisSubject, sequences);\n        for (const key in keyframes2) {\n          resolveValueSequence(keyframes2[key], getValueTransition2(transition, key), getValueSequence(key, subjectSequence), subjectIndex, numSubjects);\n        }\n      }\n    }\n    prevTime = currentTime;\n    currentTime += maxDuration;\n  }\n  sequences.forEach((valueSequences, element) => {\n    for (const key in valueSequences) {\n      const valueSequence = valueSequences[key];\n      valueSequence.sort(compareByTime);\n      const keyframes2 = [];\n      const valueOffset = [];\n      const valueEasing = [];\n      for (let i = 0; i < valueSequence.length; i++) {\n        const { at, value, easing } = valueSequence[i];\n        keyframes2.push(value);\n        valueOffset.push(progress(0, totalDuration, at));\n        valueEasing.push(easing || \"easeOut\");\n      }\n      if (valueOffset[0] !== 0) {\n        valueOffset.unshift(0);\n        keyframes2.unshift(keyframes2[0]);\n        valueEasing.unshift(defaultSegmentEasing);\n      }\n      if (valueOffset[valueOffset.length - 1] !== 1) {\n        valueOffset.push(1);\n        keyframes2.push(null);\n      }\n      if (!animationDefinitions.has(element)) {\n        animationDefinitions.set(element, {\n          keyframes: {},\n          transition: {}\n        });\n      }\n      const definition = animationDefinitions.get(element);\n      definition.keyframes[key] = keyframes2;\n      const { type: _type, ...remainingDefaultTransition } = defaultTransition;\n      definition.transition[key] = {\n        ...remainingDefaultTransition,\n        duration: totalDuration,\n        ease: valueEasing,\n        times: valueOffset,\n        ...sequenceTransition\n      };\n    }\n  });\n  return animationDefinitions;\n}\nfunction getSubjectSequence(subject, sequences) {\n  !sequences.has(subject) && sequences.set(subject, {});\n  return sequences.get(subject);\n}\nfunction getValueSequence(name, sequences) {\n  if (!sequences[name])\n    sequences[name] = [];\n  return sequences[name];\n}\nfunction keyframesAsList(keyframes2) {\n  return Array.isArray(keyframes2) ? keyframes2 : [keyframes2];\n}\nfunction getValueTransition2(transition, key) {\n  return transition && transition[key] ? {\n    ...transition,\n    ...transition[key]\n  } : { ...transition };\n}\nvar isNumber = (keyframe) => typeof keyframe === \"number\";\nvar isNumberKeyframesArray = (keyframes2) => keyframes2.every(isNumber);\n\n// ../../node_modules/framer-motion/dist/es/animation/utils/create-visual-element.mjs\nfunction createDOMVisualElement(element) {\n  const options = {\n    presenceContext: null,\n    props: {},\n    visualState: {\n      renderState: {\n        transform: {},\n        transformOrigin: {},\n        style: {},\n        vars: {},\n        attrs: {}\n      },\n      latestValues: {}\n    }\n  };\n  const node = isSVGElement(element) && !isSVGSVGElement(element) ? new SVGVisualElement(options) : new HTMLVisualElement(options);\n  node.mount(element);\n  visualElementStore.set(element, node);\n}\nfunction createObjectVisualElement(subject) {\n  const options = {\n    presenceContext: null,\n    props: {},\n    visualState: {\n      renderState: {\n        output: {}\n      },\n      latestValues: {}\n    }\n  };\n  const node = new ObjectVisualElement(options);\n  node.mount(subject);\n  visualElementStore.set(subject, node);\n}\n\n// ../../node_modules/framer-motion/dist/es/animation/animate/subject.mjs\nfunction isSingleValue(subject, keyframes2) {\n  return isMotionValue(subject) || typeof subject === \"number\" || typeof subject === \"string\" && !isDOMKeyframes(keyframes2);\n}\nfunction animateSubject(subject, keyframes2, options, scope) {\n  const animations2 = [];\n  if (isSingleValue(subject, keyframes2)) {\n    animations2.push(animateSingleValue(subject, isDOMKeyframes(keyframes2) ? keyframes2.default || keyframes2 : keyframes2, options ? options.default || options : options));\n  } else {\n    if (subject == null) {\n      return animations2;\n    }\n    const subjects = resolveSubjects(subject, keyframes2, scope);\n    const numSubjects = subjects.length;\n    invariant(Boolean(numSubjects), \"No valid elements provided.\", \"no-valid-elements\");\n    for (let i = 0; i < numSubjects; i++) {\n      const thisSubject = subjects[i];\n      const createVisualElement = thisSubject instanceof Element ? createDOMVisualElement : createObjectVisualElement;\n      if (!visualElementStore.has(thisSubject)) {\n        createVisualElement(thisSubject);\n      }\n      const visualElement = visualElementStore.get(thisSubject);\n      const transition = { ...options };\n      if (\"delay\" in transition && typeof transition.delay === \"function\") {\n        transition.delay = transition.delay(i, numSubjects);\n      }\n      animations2.push(...animateTarget(visualElement, { ...keyframes2, transition }, {}));\n    }\n  }\n  return animations2;\n}\n\n// ../../node_modules/framer-motion/dist/es/animation/animate/sequence.mjs\nfunction animateSequence(sequence, options, scope) {\n  const animations2 = [];\n  const processedSequence = sequence.map((segment) => {\n    if (Array.isArray(segment) && typeof segment[0] === \"function\") {\n      const callback = segment[0];\n      const mv = motionValue(0);\n      mv.on(\"change\", callback);\n      if (segment.length === 1) {\n        return [mv, [0, 1]];\n      } else if (segment.length === 2) {\n        return [mv, [0, 1], segment[1]];\n      } else {\n        return [mv, segment[1], segment[2]];\n      }\n    }\n    return segment;\n  });\n  const animationDefinitions = createAnimationsFromSequence(processedSequence, options, scope, { spring });\n  animationDefinitions.forEach(({ keyframes: keyframes2, transition }, subject) => {\n    animations2.push(...animateSubject(subject, keyframes2, transition));\n  });\n  return animations2;\n}\n\n// ../../node_modules/framer-motion/dist/es/animation/animate/index.mjs\nfunction isSequence(value) {\n  return Array.isArray(value) && value.some(Array.isArray);\n}\nfunction createScopedAnimate(options = {}) {\n  const { scope, reduceMotion, skipAnimations } = options;\n  function scopedAnimate(subjectOrSequence, optionsOrKeyframes, options2) {\n    let animations2 = [];\n    let animationOnComplete;\n    const inherited = {};\n    if (reduceMotion !== void 0)\n      inherited.reduceMotion = reduceMotion;\n    if (skipAnimations !== void 0)\n      inherited.skipAnimations = skipAnimations;\n    if (isSequence(subjectOrSequence)) {\n      const { onComplete, ...sequenceOptions } = optionsOrKeyframes || {};\n      if (typeof onComplete === \"function\") {\n        animationOnComplete = onComplete;\n      }\n      animations2 = animateSequence(subjectOrSequence, { ...inherited, ...sequenceOptions }, scope);\n    } else {\n      const { onComplete, ...rest } = options2 || {};\n      if (typeof onComplete === \"function\") {\n        animationOnComplete = onComplete;\n      }\n      animations2 = animateSubject(subjectOrSequence, optionsOrKeyframes, { ...inherited, ...rest }, scope);\n    }\n    const animation = new GroupAnimationWithThen(animations2);\n    if (animationOnComplete) {\n      animation.finished.then(animationOnComplete);\n    }\n    if (scope) {\n      scope.animations.push(animation);\n      animation.finished.then(() => {\n        removeItem(scope.animations, animation);\n      });\n    }\n    return animation;\n  }\n  return scopedAnimate;\n}\nvar animate = createScopedAnimate();\n\n// ../../node_modules/motion/dist/es/react.mjs\nvar motion2 = motion;\n\n// src/web/media.ts\nimport React4 from \"react\";\nvar e = React4.createElement;\nfunction buildGalleryImageAttributes(item, plan, loadingOverride, fullSize = false) {\n  const original = item.accessState === \"locked\" ? \"\" : safeGalleryMediaSrc(item.imageUrl);\n  const thumbnail = safeGalleryMediaSrc(item.thumbnailUrl);\n  const src = fullSize ? original || thumbnail : thumbnail || original;\n  if (!src) return null;\n  const loading = loadingOverride ?? plan?.loading ?? \"lazy\";\n  const srcSet = item.accessState !== \"locked\" && plan?.srcset ? responsiveSrcSet(item) : \"\";\n  return {\n    alt: item.altText || item.title || \"\",\n    decoding: \"async\",\n    fetchPriority: loading === \"eager\" && (!plan || plan.fetchPriority === \"high\") ? \"high\" : void 0,\n    height: item.height || void 0,\n    loading,\n    sizes: srcSet ? plan?.sizes : void 0,\n    src,\n    srcSet: srcSet || void 0,\n    width: item.width || void 0\n  };\n}\nfunction MediaPreview(props) {\n  const attributes = buildGalleryImageAttributes(props.item, props.plan, props.loading, props.fullSize);\n  const fallback = props.item.accessState === \"locked\" ? \"\" : safeGalleryMediaSrc(props.fullSize ? props.item.thumbnailUrl : props.item.imageUrl);\n  return e(GalleryImage, { key: JSON.stringify([attributes?.src, attributes?.srcSet, fallback]), attributes, fallback, onUnavailable: props.onUnavailable, title: props.item.title });\n}\nfunction GalleryImage(props) {\n  const [failures, setFailures] = React4.useState(0);\n  const attributes = props.attributes;\n  const unavailable = !attributes || failures > 0 && (failures > 1 || !props.fallback || props.fallback === attributes.src);\n  React4.useEffect(() => {\n    if (unavailable) props.onUnavailable?.();\n  }, [unavailable, props.onUnavailable]);\n  if (!attributes) {\n    return e(\n      \"div\",\n      { className: \"cedros-gallery-image cedros-gallery-image--empty\" },\n      e(MissingMediaIcon),\n      e(\"span\", null, \"Preview unavailable\")\n    );\n  }\n  if (unavailable) {\n    return e(\n      \"div\",\n      { className: \"cedros-gallery-image cedros-gallery-image--empty\", role: \"status\" },\n      e(MissingMediaIcon),\n      e(\"span\", null, \"Image unavailable\"),\n      e(\"small\", null, \"Reload the page to try again.\")\n    );\n  }\n  return e(\"img\", {\n    ...attributes,\n    ...failures > 0 ? { src: props.fallback, srcSet: void 0, sizes: void 0 } : {},\n    className: \"cedros-gallery-image\",\n    onError: () => setFailures((count) => count + 1)\n  });\n}\nfunction MissingMediaIcon() {\n  return e(\n    \"svg\",\n    { \"aria-hidden\": true, className: \"cedros-gallery-missing-media-icon\", fill: \"none\", stroke: \"currentColor\", strokeWidth: 1.5, viewBox: \"0 0 24 24\" },\n    e(\"rect\", { x: 3, y: 3, width: 18, height: 18, rx: 2 }),\n    e(\"circle\", { cx: 8, cy: 8, r: 1.5 }),\n    e(\"path\", { d: \"M3 17l5-5 4 4 4-5 5 6\" })\n  );\n}\nfunction safePublicHref(input) {\n  const value = typeof input === \"string\" ? input.trim() : \"\";\n  if (!value || value.startsWith(\"//\") || /[\\u0000-\\u0020\\u007f\\\\]/.test(value)) return \"\";\n  if (value.startsWith(\"/\")) return value;\n  try {\n    const url = new URL(value);\n    return url.protocol === \"http:\" || url.protocol === \"https:\" ? value : \"\";\n  } catch {\n    return \"\";\n  }\n}\nfunction responsiveSrcSet(item) {\n  return item.responsiveSources.map((source) => {\n    const url = safeGalleryMediaSrc(source.url);\n    return url ? `${url} ${source.width}w` : \"\";\n  }).filter(Boolean).join(\", \");\n}\n\n// src/web/caption.ts\nimport React5 from \"react\";\nvar e2 = React5.createElement;\nfunction GalleryCardCaption({ text, label = \"caption\" }) {\n  const [expanded, setExpanded] = React5.useState(false);\n  const contentId = React5.useId();\n  const long = text.length > 180;\n  return e2(\n    \"div\",\n    { className: \"cedros-gallery-caption-region\" },\n    e2(\"p\", { className: `cedros-gallery-caption${long && !expanded ? \" cedros-gallery-caption--summary\" : \"\"}`, id: contentId }, text),\n    long && e2(\"button\", {\n      \"aria-controls\": contentId,\n      \"aria-expanded\": expanded,\n      className: \"cedros-gallery-button cedros-gallery-button--ghost cedros-gallery-caption-region__toggle\",\n      onClick: () => setExpanded((value) => !value),\n      type: \"button\"\n    }, expanded ? \"Show less\" : `Read ${label}`)\n  );\n}\n\n// src/web/markup.ts\nfunction contentHeadingTag(input) {\n  const level = typeof input === \"number\" && Number.isInteger(input) ? Math.max(2, Math.min(6, input)) : 2;\n  return `h${level}`;\n}\n\n// src/web/scroll-boundary.ts\nimport React6 from \"react\";\n\n// src/web/motion.ts\nvar galleryInteractionSpring = {\n  type: \"spring\",\n  stiffness: 520,\n  damping: 38,\n  mass: 0.8\n};\nvar galleryPanelSpring = {\n  type: \"spring\",\n  stiffness: 420,\n  damping: 36,\n  mass: 0.9\n};\nvar galleryLayoutSpring = {\n  type: \"spring\",\n  stiffness: 380,\n  damping: 34,\n  mass: 0.85\n};\nvar gallerySharedAxisOffset = 72;\nvar sharedAxisVariants = {\n  center: { opacity: 1, x: 0 },\n  enter: (direction) => ({ opacity: 0, x: direction * gallerySharedAxisOffset }),\n  exit: (direction) => ({ opacity: 0, x: -direction * gallerySharedAxisOffset })\n};\nvar fadeAxisVariants = {\n  center: { opacity: 1 },\n  enter: { opacity: 0 },\n  exit: { opacity: 0 }\n};\nfunction useGalleryReducedMotion() {\n  return Boolean(useReducedMotion());\n}\nfunction velocityBlurFilter(velocity, options = {}) {\n  const { ceiling = 1800, max = 2, threshold = 350 } = options;\n  const amount = effectAmount(velocity, ceiling, max, threshold);\n  return amount > 0.05 ? `blur(${amount.toFixed(2)}px)` : \"none\";\n}\nfunction velocityStretchScale(velocity, options = {}) {\n  const { ceiling = 1800, max = 0.025, threshold = 0 } = options;\n  return 1 + effectAmount(velocity, ceiling, max, threshold);\n}\nfunction horizontalLayout(layout2) {\n  return [\"justified\", \"filmstrip\", \"horizontal-scroll\", \"carousel\", \"slider\", \"fullscreen-slideshow\"].includes(layout2);\n}\nfunction supportsLayoutAnimation(layout2) {\n  return layout2 !== \"masonry\";\n}\nfunction effectAmount(velocity, ceiling, max, threshold) {\n  const span = Math.max(1, ceiling - threshold);\n  const scaled = (Math.abs(velocity) - threshold) / span * max;\n  return Math.min(max, Math.max(0, scaled));\n}\n\n// src/web/scroll-boundary.ts\nvar edgeResistanceRatio = 0.08;\nvar maxEdgePullPx = 48;\nvar edgeNudgePx = 18;\nvar releaseDelayMs = 90;\nfunction useEdgeResistance(input) {\n  const pull = useMotionValue(0);\n  const playbackRef = React6.useRef(null);\n  const releaseTimerRef = React6.useRef(0);\n  const reducedMotionRef = React6.useRef(input.reducedMotion);\n  reducedMotionRef.current = input.reducedMotion;\n  const stopPlayback = React6.useCallback(() => {\n    playbackRef.current?.stop();\n    playbackRef.current = null;\n  }, []);\n  const clearReleaseTimer = React6.useCallback(() => {\n    if (!releaseTimerRef.current) return;\n    globalThis.clearTimeout(releaseTimerRef.current);\n    releaseTimerRef.current = 0;\n  }, []);\n  const release = React6.useCallback(() => {\n    clearReleaseTimer();\n    stopPlayback();\n    if (reducedMotionRef.current || pull.get() === 0) {\n      pull.set(0);\n      return;\n    }\n    playbackRef.current = animate(pull, 0, galleryInteractionSpring);\n  }, [clearReleaseTimer, pull, stopPlayback]);\n  const scheduleRelease = React6.useCallback(() => {\n    clearReleaseTimer();\n    releaseTimerRef.current = globalThis.setTimeout(release, releaseDelayMs);\n  }, [clearReleaseTimer, release]);\n  const applyOverscroll = React6.useCallback((excessPx) => {\n    if (reducedMotionRef.current) return;\n    clearReleaseTimer();\n    stopPlayback();\n    pull.set(clampPull(excessPx * edgeResistanceRatio));\n  }, [clearReleaseTimer, pull, stopPlayback]);\n  const nudge = React6.useCallback((direction) => {\n    if (reducedMotionRef.current) return;\n    clearReleaseTimer();\n    stopPlayback();\n    playbackRef.current = animate(pull, [pull.get(), clampPull(direction * edgeNudgePx), 0], {\n      duration: 0.36,\n      ease: [0.16, 1, 0.3, 1],\n      times: [0, 0.3, 1]\n    });\n  }, [clearReleaseTimer, pull, stopPlayback]);\n  const resistWheel = React6.useCallback((event, axis = \"x\") => {\n    if (reducedMotionRef.current) return;\n    const element = event.currentTarget;\n    const delta = axis === \"x\" && Math.abs(event.deltaX) >= Math.abs(event.deltaY) ? event.deltaX : event.deltaY;\n    if (!delta) return;\n    const position = axis === \"x\" ? element.scrollLeft : element.scrollTop;\n    const extent = axis === \"x\" ? element.scrollWidth - element.clientWidth : element.scrollHeight - element.clientHeight;\n    if (extent <= 0) return;\n    const pastStart = delta < 0 && position <= 1;\n    const pastEnd = delta > 0 && position >= extent - 1;\n    if (!pastStart && !pastEnd) return;\n    clearReleaseTimer();\n    stopPlayback();\n    pull.set(clampPull(pull.get() - delta * edgeResistanceRatio));\n    scheduleRelease();\n  }, [clearReleaseTimer, pull, scheduleRelease, stopPlayback]);\n  React6.useEffect(() => {\n    if (!input.reducedMotion) return;\n    clearReleaseTimer();\n    stopPlayback();\n    pull.set(0);\n  }, [clearReleaseTimer, input.reducedMotion, pull, stopPlayback]);\n  React6.useEffect(() => () => {\n    clearReleaseTimer();\n    stopPlayback();\n  }, [clearReleaseTimer, stopPlayback]);\n  return React6.useMemo(\n    () => ({ applyOverscroll, nudge, pull, release, resistWheel }),\n    [applyOverscroll, nudge, pull, release, resistWheel]\n  );\n}\nfunction useScrollEdges(input) {\n  const axis = input.axis ?? \"x\";\n  const { ref } = input;\n  const [edges, setEdges] = React6.useState({ atEnd: input.initialAtEnd ?? false, atStart: true });\n  const sync = React6.useCallback(() => {\n    const element = ref.current;\n    if (!element) return;\n    const position = axis === \"x\" ? element.scrollLeft : element.scrollTop;\n    const extent = axis === \"x\" ? element.scrollWidth - element.clientWidth : element.scrollHeight - element.clientHeight;\n    const next = { atEnd: position >= extent - 1, atStart: position <= 1 };\n    setEdges((current) => current.atEnd === next.atEnd && current.atStart === next.atStart ? current : next);\n  }, [axis, ref]);\n  React6.useEffect(() => {\n    const element = ref.current;\n    if (!element) return;\n    const observer2 = typeof ResizeObserver === \"undefined\" ? null : new ResizeObserver(sync);\n    observer2?.observe(element);\n    sync();\n    return () => observer2?.disconnect();\n  }, [ref, sync]);\n  return React6.useMemo(\n    () => ({ atEnd: edges.atEnd, atStart: edges.atStart, sync }),\n    [edges.atEnd, edges.atStart, sync]\n  );\n}\nfunction scrollOverscroll(desired, extent) {\n  if (desired < 0) return -desired;\n  if (desired > extent) return -(desired - extent);\n  return 0;\n}\nfunction clampPull(value) {\n  return Math.min(maxEdgePullPx, Math.max(-maxEdgePullPx, value));\n}\n\n// src/web/album-block.ts\nvar e3 = React7.createElement;\nfunction AlbumBlockView(input) {\n  const view = buildAlbumView(input.props);\n  const heading = contentHeadingTag(view.headingLevel);\n  const reducedMotion = useGalleryReducedMotion();\n  const cards = [\n    ...view.childAlbums.map((album) => ({\n      id: album.id,\n      title: album.title || \"Untitled album\",\n      description: album.description,\n      href: album.href,\n      coverImageUrl: album.coverImageUrl,\n      coverAltText: album.coverAltText,\n      meta: `${formatAlbumCount(album.galleryCount)} galleries \\xB7 ${formatAlbumCount(album.imageCount)} images`,\n      exactMeta: `${exactAlbumCount(album.galleryCount)} galleries \\xB7 ${exactAlbumCount(album.imageCount)} images`,\n      type: \"Album\"\n    })),\n    ...view.galleries.map((gallery) => ({\n      id: gallery.id,\n      title: gallery.title || \"Untitled gallery\",\n      description: gallery.description,\n      href: gallery.href,\n      coverImageUrl: gallery.coverImageUrl,\n      coverAltText: gallery.coverAltText,\n      meta: `${formatAlbumCount(gallery.imageCount)} ${gallery.imageCount === 1 ? \"image\" : \"images\"}`,\n      exactMeta: `${exactAlbumCount(gallery.imageCount)} ${gallery.imageCount === 1 ? \"image\" : \"images\"}`,\n      type: \"Gallery\"\n    }))\n  ];\n  return e3(\n    \"section\",\n    { className: `cedros-gallery-album cedros-gallery-album--${view.layout}` },\n    e3(\n      \"header\",\n      { className: \"cedros-gallery-header\" },\n      e3(\n        \"div\",\n        null,\n        e3(heading, { className: \"cedros-gallery-heading\" }, view.title),\n        view.showDescription && view.description ? e3(\"p\", { className: \"cedros-gallery-description\" }, view.description) : null\n      )\n    ),\n    cards.length ? e3(\n      AlbumCollectionsViewport,\n      { carousel: view.layout === \"carousel\", reducedMotion, count: cards.length },\n      cards.map((card) => e3(AlbumCard, {\n        card,\n        key: `${card.type}:${card.id}`,\n        headingLevel: Math.min(6, view.headingLevel + 1),\n        reducedMotion,\n        showCounts: view.showCounts,\n        showDescription: view.showDescription\n      }))\n    ) : e3(\"p\", { className: \"cedros-gallery-empty\" }, \"No published galleries are available in this album.\")\n  );\n}\nfunction AlbumCollectionsViewport(props) {\n  const viewport = React7.useRef(null);\n  const edges = useScrollEdges({ ref: viewport, initialAtEnd: props.count <= 1 });\n  const viewportId = React7.useId();\n  React7.useEffect(() => edges.sync(), [props.carousel, props.count, edges.sync]);\n  function move(direction) {\n    const element = viewport.current;\n    if (!element) return;\n    const first = element.firstElementChild;\n    const step = first ? first.getBoundingClientRect().width + 16 : element.clientWidth;\n    element.scrollBy({ left: direction * step, behavior: props.reducedMotion ? \"instant\" : \"smooth\" });\n  }\n  const content = e3(\"div\", {\n    className: \"cedros-gallery-album__grid\",\n    id: viewportId,\n    onScroll: props.carousel ? edges.sync : void 0,\n    ref: viewport\n  }, props.children);\n  if (!props.carousel) return content;\n  return e3(\n    \"div\",\n    { className: \"cedros-gallery-album__carousel\" },\n    props.count > 1 && e3(\n      \"div\",\n      { className: \"cedros-gallery-album__navigation\", \"aria-label\": \"Collection navigation\", role: \"group\" },\n      e3(\"button\", {\n        \"aria-controls\": viewportId,\n        className: \"cedros-gallery-button cedros-gallery-button--ghost\",\n        disabled: edges.atStart,\n        onClick: () => move(-1),\n        type: \"button\"\n      }, \"Previous collections\"),\n      e3(\"button\", {\n        \"aria-controls\": viewportId,\n        className: \"cedros-gallery-button cedros-gallery-button--ghost\",\n        disabled: edges.atEnd,\n        onClick: () => move(1),\n        type: \"button\"\n      }, \"Next collections\")\n    ),\n    content\n  );\n}\nfunction AlbumCard(props) {\n  const href = safePublicHref(props.card.href);\n  const cover = safeGalleryMediaSrc(props.card.coverImageUrl);\n  const [failedCover, setFailedCover] = React7.useState(\"\");\n  const content = e3(\n    React7.Fragment,\n    null,\n    e3(\n      \"div\",\n      { className: \"cedros-gallery-album-card__cover\" },\n      cover && failedCover !== cover ? e3(\"img\", {\n        alt: props.card.coverAltText || props.card.title,\n        decoding: \"async\",\n        loading: \"lazy\",\n        src: cover,\n        onError: () => setFailedCover(cover)\n      }) : e3(React7.Fragment, null, e3(MissingMediaIcon), e3(\"span\", { className: \"cedros-gallery-album-card__missing\" }, \"Cover unavailable\"))\n    ),\n    e3(\n      \"div\",\n      { className: \"cedros-gallery-album-card__body\" },\n      props.card.type === \"Album\" && e3(\"p\", { className: \"cedros-gallery-kicker\" }, \"Album\"),\n      e3(contentHeadingTag(props.headingLevel), { className: `cedros-gallery-album-card__title${href ? \" cedros-gallery-album-card__title--preview\" : \"\"}`, title: href ? props.card.title : void 0 }, props.card.title),\n      props.showCounts && e3(\n        \"p\",\n        { className: \"cedros-gallery-album-card__count\", title: props.card.exactMeta },\n        props.card.meta === props.card.exactMeta ? props.card.meta : e3(\n          React7.Fragment,\n          null,\n          e3(\"span\", { \"aria-hidden\": true }, props.card.meta),\n          e3(\"span\", { className: \"cedros-gallery-visually-hidden\" }, props.card.exactMeta)\n        )\n      )\n    )\n  );\n  return e3(\n    motion2.article,\n    {\n      className: \"cedros-gallery-album-card\",\n      initial: false,\n      layout: !props.reducedMotion,\n      transition: { layout: galleryLayoutSpring }\n    },\n    href ? e3(\"a\", { className: \"cedros-gallery-album-card__main\", href }, content) : e3(\"div\", { className: \"cedros-gallery-album-card__main\" }, content),\n    props.showDescription && props.card.description ? e3(\n      \"div\",\n      { className: \"cedros-gallery-album-card__description\" },\n      e3(GalleryCardCaption, { key: props.card.description, label: \"description\", text: props.card.description })\n    ) : null\n  );\n}\nfunction formatAlbumCount(value) {\n  return new Intl.NumberFormat(void 0, value >= 1e4 ? { notation: \"compact\", maximumFractionDigits: 1 } : {}).format(value);\n}\nfunction exactAlbumCount(value) {\n  return new Intl.NumberFormat().format(value);\n}\n\n// src/web/before-after-block.ts\nimport React9 from \"react\";\n\n// src/web/visibility-clock.ts\nimport React8 from \"react\";\nfunction useVisibilityClock(boundaries, fixedNow = \"\") {\n  const [, refresh] = React8.useReducer((value) => value + 1, 0);\n  const signature = JSON.stringify(boundaries.filter(Number.isFinite).sort((a, b) => a - b));\n  React8.useEffect(() => {\n    if (fixedNow) return;\n    const times = JSON.parse(signature);\n    let timer;\n    const schedule = () => {\n      if (timer !== void 0) clearTimeout(timer);\n      const now2 = Date.now();\n      const next = times.find((time2) => time2 >= now2);\n      if (next !== void 0) timer = setTimeout(() => {\n        refresh();\n        schedule();\n      }, Math.min(6e4, next - now2 + 1));\n    };\n    const resume = () => {\n      refresh();\n      schedule();\n    };\n    schedule();\n    globalThis.addEventListener?.(\"focus\", resume);\n    globalThis.document?.addEventListener(\"visibilitychange\", resume);\n    return () => {\n      if (timer !== void 0) clearTimeout(timer);\n      globalThis.removeEventListener?.(\"focus\", resume);\n      globalThis.document?.removeEventListener(\"visibilitychange\", resume);\n    };\n  }, [fixedNow, signature]);\n  return fixedNow || (/* @__PURE__ */ new Date()).toISOString();\n}\n\n// src/web/before-after-block.ts\nvar e4 = React9.createElement;\nfunction BeforeAfterBlockView(input) {\n  const [position, setPosition] = React9.useState(50);\n  const [failedPair, setFailedPair] = React9.useState(\"\");\n  const stageRef = React9.useRef(null);\n  const draggingRef = React9.useRef(null);\n  const reducedMotion = useGalleryReducedMotion();\n  const edge = useEdgeResistance({ reducedMotion });\n  const props = input.props ?? {};\n  const view = buildBeforeAfterView(props);\n  const policy = record11(props.visibility);\n  const now2 = useVisibilityClock([\n    Date.parse(stringValue12(policy.publishAt ?? policy.scheduledAt)),\n    Date.parse(stringValue12(policy.expiresAt ?? policy.expirationDate))\n  ], stringValue12(record11(props.viewerContext).now));\n  const visibility = comparisonVisibility(props, now2);\n  const beforeUrl = visibility.visible ? safeGalleryMediaSrc(stringValue12(props.beforeImageUrl ?? props.beforeUrl)) : \"\";\n  const afterUrl = visibility.visible ? safeGalleryMediaSrc(stringValue12(props.afterImageUrl ?? props.afterUrl)) : \"\";\n  const beforeAlt = stringValue12(props.beforeAltText) || view.beforeLabel;\n  const afterAlt = stringValue12(props.afterAltText) || view.afterLabel;\n  const title = stringValue12(props.title) || `${view.beforeLabel} / ${view.afterLabel}`;\n  const description = stringValue12(props.description);\n  const heading = contentHeadingTag(props.headingLevel);\n  const pair = JSON.stringify([beforeUrl, afterUrl]);\n  const mediaFailed = failedPair === pair;\n  const mediaReady = Boolean(beforeUrl && afterUrl) && !mediaFailed;\n  React9.useEffect(() => setPosition(view.sliderPosition), [view.sliderPosition]);\n  return e4(\n    \"section\",\n    { className: `cedros-gallery-comparison cedros-gallery-comparison--${view.orientation}` },\n    e4(\n      \"header\",\n      { className: \"cedros-gallery-header\" },\n      e4(\n        \"div\",\n        null,\n        e4(heading, { className: \"cedros-gallery-heading\" }, title),\n        description && e4(\"p\", { className: \"cedros-gallery-description\" }, description)\n      )\n    ),\n    !visibility.visible && e4(\"p\", { className: \"cedros-gallery-empty\" }, \"This comparison is not publicly available.\"),\n    visibility.visible && !mediaReady && e4(\n      \"div\",\n      { className: \"cedros-gallery-empty\", role: \"status\" },\n      e4(\"p\", null, mediaFailed ? \"A comparison image could not be loaded.\" : \"Both comparison images must be available before you can compare them.\"),\n      mediaFailed && e4(\"button\", { className: \"cedros-gallery-button cedros-gallery-button--ghost\", type: \"button\", onClick: () => setFailedPair(\"\") }, \"Retry comparison\")\n    ),\n    visibility.visible && mediaReady && e4(\n      \"div\",\n      {\n        className: \"cedros-gallery-comparison__stage\",\n        key: pair,\n        onPointerCancel: (event) => releaseComparisonPointer(event, draggingRef, edge),\n        onPointerDown: (event) => {\n          draggingRef.current = event.pointerId;\n          event.currentTarget.setPointerCapture(event.pointerId);\n          updateComparisonPosition(event, stageRef.current, view.orientation, setPosition, edge);\n        },\n        onPointerMove: (event) => {\n          if (draggingRef.current === event.pointerId) updateComparisonPosition(event, stageRef.current, view.orientation, setPosition, edge);\n        },\n        onPointerUp: (event) => releaseComparisonPointer(event, draggingRef, edge),\n        ref: stageRef,\n        style: { \"--c1gb4l3-gallery-split\": `${position}%` }\n      },\n      e4(\"img\", { alt: beforeAlt, decoding: \"async\", loading: \"lazy\", src: beforeUrl, onError: () => setFailedPair(pair) }),\n      e4(\n        \"div\",\n        { className: \"cedros-gallery-comparison__after\" },\n        e4(\"img\", { alt: afterAlt, decoding: \"async\", loading: \"lazy\", src: afterUrl, onError: () => setFailedPair(pair) })\n      ),\n      e4(motion2.span, { \"aria-hidden\": true, className: \"cedros-gallery-comparison__divider\", style: view.orientation === \"vertical\" ? { y: edge.pull } : { x: edge.pull } })\n    ),\n    visibility.visible && mediaReady && view.showLabels && e4(\n      \"div\",\n      { className: \"cedros-gallery-comparison__labels\" },\n      e4(\"span\", null, view.beforeLabel),\n      e4(\"span\", null, view.afterLabel)\n    ),\n    visibility.visible && mediaReady && e4(\n      \"label\",\n      { className: \"cedros-gallery-field cedros-gallery-field--range\" },\n      e4(\"span\", null, \"Drag to compare, or use the arrow keys\"),\n      e4(\"input\", {\n        \"aria-label\": \"Comparison position\",\n        \"aria-valuetext\": `${Math.round(position)}% ${view.beforeLabel}, ${Math.round(100 - position)}% ${view.afterLabel}`,\n        max: 100,\n        min: 0,\n        onChange: (event) => setPosition(Number(event.currentTarget.value)),\n        type: \"range\",\n        value: position\n      })\n    )\n  );\n}\nfunction updateComparisonPosition(event, stage, orientation, setPosition, edge) {\n  if (!stage) return;\n  const bounds = stage.getBoundingClientRect();\n  const size = orientation === \"vertical\" ? bounds.height : bounds.width;\n  const offset = orientation === \"vertical\" ? event.clientY - bounds.top : event.clientX - bounds.left;\n  const raw = size > 0 ? offset / size * 100 : 50;\n  setPosition(Math.max(0, Math.min(100, raw)));\n  edge.applyOverscroll(comparisonOverscroll(raw, size));\n}\nfunction comparisonOverscroll(position, size) {\n  if (position < 0) return position / 100 * size;\n  if (position > 100) return (position - 100) / 100 * size;\n  return 0;\n}\nfunction releaseComparisonPointer(event, draggingRef, edge) {\n  if (draggingRef.current !== event.pointerId) return;\n  draggingRef.current = null;\n  if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);\n  edge.release();\n}\nfunction comparisonVisibility(props, now2) {\n  const config = record11(props.config);\n  const access = record11(config.access);\n  const policy = normalizeVisibilityPolicy({\n    mode: props.accessMode ?? access.mode,\n    requiredClaim: access.requiredClaim,\n    ...record11(props.visibility)\n  });\n  return decideGalleryVisibility(policy, normalizeVisibilityContext({ ...record11(props.viewerContext), now: now2 }));\n}\nfunction stringValue12(input) {\n  return typeof input === \"string\" ? input.trim() : \"\";\n}\nfunction record11(input) {\n  return typeof input === \"object\" && input !== null && !Array.isArray(input) ? input : {};\n}\n\n// src/web/gallery-block.ts\nimport React14 from \"react\";\n\n// src/modal-dialog.ts\nimport React10 from \"react\";\nfunction modalState(panel) {\n  const owner = panel.ownerDocument;\n  return owner.__cedrosGalleryModalState ??= { stack: [], unlockedOverflow: \"\", inertElements: /* @__PURE__ */ new Map() };\n}\nfunction syncModalBackground(state) {\n  for (const [element, wasInert] of state.inertElements) {\n    element.toggleAttribute(\"inert\", wasInert);\n  }\n  state.inertElements.clear();\n  const panel = state.stack.at(-1);\n  if (!panel) return;\n  for (let branch = panel; branch.parentElement; branch = branch.parentElement) {\n    for (const sibling of branch.parentElement.children) {\n      if (sibling === branch || !(sibling instanceof HTMLElement) || sibling.hasAttribute(\"data-c1gb4l3-gallery-modal-backdrop\")) continue;\n      state.inertElements.set(sibling, sibling.hasAttribute(\"inert\"));\n      sibling.setAttribute(\"inert\", \"\");\n    }\n    if (branch.parentElement === panel.ownerDocument.body) break;\n  }\n}\nfunction isTopModalDialog(panel) {\n  return panel !== null && modalState(panel).stack.at(-1) === panel;\n}\nvar focusableSelector = [\n  \"a[href]\",\n  \"button:not([disabled])\",\n  \"input:not([disabled])\",\n  \"select:not([disabled])\",\n  \"textarea:not([disabled])\",\n  \"[tabindex]:not([tabindex='-1'])\"\n].join(\",\");\nfunction dialogControls(panel) {\n  return [...panel.querySelectorAll(focusableSelector)].filter((element) => {\n    if (element.tabIndex < 0 || element.matches(\":disabled\")) return false;\n    for (let ancestor = element; ancestor; ancestor = ancestor.parentElement) {\n      if (ancestor.hidden || ancestor.hasAttribute(\"inert\") || ancestor.getAttribute(\"aria-hidden\") === \"true\") return false;\n      const style = getComputedStyle(ancestor);\n      if (style.display === \"none\" || style.visibility === \"hidden\" || style.visibility === \"collapse\") return false;\n    }\n    return true;\n  });\n}\nfunction useModalDialog(input) {\n  const onCloseRef = React10.useRef(input.onClose);\n  onCloseRef.current = input.onClose;\n  React10.useEffect(() => {\n    if (!input.open || typeof document === \"undefined\") return;\n    const panel = input.panelRef.current;\n    if (!panel) return;\n    const owner = panel.ownerDocument;\n    const state = modalState(panel);\n    const opener = owner.activeElement instanceof HTMLElement ? owner.activeElement : null;\n    if (state.stack.length === 0) state.unlockedOverflow = owner.body.style.overflow;\n    state.stack.push(panel);\n    owner.body.style.overflow = \"hidden\";\n    syncModalBackground(state);\n    const initialFocus = dialogControls(panel)[0];\n    (initialFocus ?? panel).focus();\n    const onFocusIn = (event) => {\n      if (!input.trapFocus || !isTopModalDialog(panel) || event.target instanceof Node && panel.contains(event.target)) return;\n      (dialogControls(panel)[0] ?? panel).focus();\n    };\n    const onKeyDown = (event) => {\n      if (!isTopModalDialog(panel)) return;\n      if (event.key === \"Escape\" && input.closeOnEscape) {\n        event.preventDefault();\n        onCloseRef.current();\n        return;\n      }\n      if (event.key !== \"Tab\" || !input.trapFocus) return;\n      const focusable = dialogControls(panel);\n      if (!focusable.length) {\n        event.preventDefault();\n        panel.focus();\n        return;\n      }\n      const first = focusable[0];\n      const last = focusable[focusable.length - 1];\n      if (!focusable.some((element) => element === owner.activeElement)) {\n        event.preventDefault();\n        (event.shiftKey ? last : first).focus();\n      } else if (event.shiftKey && owner.activeElement === first) {\n        event.preventDefault();\n        last.focus();\n      } else if (!event.shiftKey && owner.activeElement === last) {\n        event.preventDefault();\n        first.focus();\n      }\n    };\n    owner.addEventListener(\"keydown\", onKeyDown);\n    owner.addEventListener(\"focusin\", onFocusIn);\n    return () => {\n      owner.removeEventListener(\"keydown\", onKeyDown);\n      owner.removeEventListener(\"focusin\", onFocusIn);\n      const wasTop = isTopModalDialog(panel);\n      const index = state.stack.indexOf(panel);\n      if (index >= 0) state.stack.splice(index, 1);\n      syncModalBackground(state);\n      if (state.stack.length === 0) owner.body.style.overflow = state.unlockedOverflow;\n      if (wasTop && opener?.isConnected) opener.focus();\n    };\n  }, [input.closeOnEscape, input.open, input.panelRef, input.trapFocus]);\n}\n\n// src/analytics.ts\nvar proofingEvents = /* @__PURE__ */ new Set([\n  \"image-favorited\",\n  \"image-selected\",\n  \"proofing-submitted\"\n]);\nvar commerceEvents = /* @__PURE__ */ new Set([\"linked-product-clicked\"]);\nfunction buildGalleryAnalyticsPayload(input) {\n  const value = record12(input);\n  const event = normalizeEvent(value.event);\n  return {\n    extensionId: \"cedros-gallery\",\n    eventId: `cedros-gallery:${event}`,\n    galleryId: stringValue13(value.galleryId),\n    itemId: stringValue13(value.itemId),\n    category: eventCategory(event),\n    metadata: sanitizeMetadata(record12(value.metadata))\n  };\n}\nfunction trackGalleryAnalyticsEvent(input, target = globalThis) {\n  const payload = buildGalleryAnalyticsPayload(input);\n  const track = target.cedrosAnalytics?.trackExtensionEvent;\n  if (typeof track !== \"function\") return { payload, reported: false, reason: \"unavailable\" };\n  try {\n    const result = track(extensionAnalyticsInput(payload));\n    if (isPromise(result)) {\n      void result.catch(() => logAnalyticsFailure(payload.eventId));\n      return { payload, reported: false, reason: \"pending\" };\n    }\n    return { payload, reported: result === true, reason: result === true ? \"sent\" : \"failed\" };\n  } catch {\n    logAnalyticsFailure(payload.eventId);\n    return { payload, reported: false, reason: \"failed\" };\n  }\n}\nfunction extensionAnalyticsInput(payload) {\n  return {\n    extensionId: payload.extensionId,\n    eventId: payload.eventId,\n    label: payload.itemId || payload.galleryId || void 0,\n    metadata: {\n      category: payload.category,\n      ...payload.galleryId ? { galleryId: payload.galleryId } : {},\n      ...payload.itemId ? { itemId: payload.itemId } : {},\n      ...payload.metadata\n    }\n  };\n}\nfunction normalizeEvent(input) {\n  if (typeof input !== \"string\") return \"gallery-viewed\";\n  return analyticsEvents.has(input) ? input : \"gallery-viewed\";\n}\nfunction eventCategory(event) {\n  if (commerceEvents.has(event)) return \"commerce-handoff\";\n  if (proofingEvents.has(event)) return \"proofing\";\n  return \"gallery\";\n}\nfunction sanitizeMetadata(input) {\n  const output = {};\n  for (const [key, value] of Object.entries(input)) {\n    if (isSensitiveKey(key)) continue;\n    if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n      output[key] = value;\n    }\n  }\n  return output;\n}\nfunction isSensitiveKey(key) {\n  const normalized = key.toLocaleLowerCase();\n  return normalized.includes(\"email\") || normalized.includes(\"token\") || normalized.includes(\"password\") || normalized.includes(\"secret\") || normalized.includes(\"credential\");\n}\nvar analyticsEvents = /* @__PURE__ */ new Set([\n  \"gallery-viewed\",\n  \"image-viewed\",\n  \"lightbox-opened\",\n  \"image-downloaded\",\n  \"gallery-shared\",\n  \"image-favorited\",\n  \"image-selected\",\n  \"proofing-submitted\",\n  \"gallery-filter-changed\",\n  \"gallery-search-performed\",\n  \"linked-product-clicked\"\n]);\nfunction stringValue13(input) {\n  return typeof input === \"string\" ? input.trim() : \"\";\n}\nfunction record12(input) {\n  return typeof input === \"object\" && input !== null && !Array.isArray(input) ? input : {};\n}\nfunction isPromise(input) {\n  return typeof input === \"object\" && input !== null && typeof input.catch === \"function\";\n}\nfunction logAnalyticsFailure(eventId) {\n  if (typeof console === \"undefined\" || typeof console.warn !== \"function\") return;\n  console.warn(\"Cedros Gallery analytics event failed.\", { eventId, reason: \"report_failed\" });\n}\n\n// src/web/access-gate.ts\nimport React11 from \"react\";\nvar e5 = React11.createElement;\nfunction initialGalleryAccessState() {\n  return { checking: false, credential: \"\", message: \"\", verified: false };\n}\nfunction credentialAccessMode(mode) {\n  return mode === \"password\" || mode === \"client-link\";\n}\nfunction gallerySignInHref() {\n  const location2 = globalThis.window?.location;\n  if (!location2 || !location2.pathname.startsWith(\"/\") || location2.pathname.startsWith(\"//\") || location2.pathname.includes(\"\\\\\")) return \"/login\";\n  return `/login?${new URLSearchParams({ returnTo: location2.pathname + location2.search + location2.hash })}`;\n}\nfunction GalleryAccessGate(props) {\n  if (props.visible) return null;\n  if (credentialAccessMode(props.mode) && props.state !== \"scheduled\" && props.state !== \"expired\") return e5(CredentialGate, props);\n  if (props.access.checking) return e5(\n    \"div\",\n    { className: \"cedros-gallery-access\", role: \"status\" },\n    e5(\"strong\", null, \"Checking access\\u2026\"),\n    e5(\"p\", null, \"Confirming this account with Cedros Login.\")\n  );\n  const canSignIn = (props.state === \"login-required\" || props.state === \"role-required\") && !props.access.message.startsWith(\"Role-based access is unavailable.\");\n  const retryable = props.access.message === \"Access check failed.\";\n  return e5(\n    \"div\",\n    { className: \"cedros-gallery-access\", role: \"status\" },\n    e5(\"strong\", null, retryable ? \"Access check unavailable\" : accessTitle(props.state)),\n    e5(\"p\", null, props.access.message || accessMessage(props.state)),\n    retryable ? e5(\"button\", {\n      className: \"cedros-gallery-button\",\n      onClick: props.onVerify,\n      type: \"button\"\n    }, \"Try again\") : null,\n    canSignIn && !retryable ? e5(\n      \"a\",\n      { className: \"cedros-gallery-button\", href: gallerySignInHref() },\n      props.state === \"role-required\" ? \"Sign in with another account\" : \"Sign in to view gallery\"\n    ) : null\n  );\n}\nfunction CredentialGate(props) {\n  const helpId = React11.useId();\n  return e5(\n    \"form\",\n    { className: \"cedros-gallery-access cedros-gallery-access--credential\", onSubmit: submit(props) },\n    e5(\n      \"p\",\n      { id: helpId, className: \"cedros-gallery-access__intro\" },\n      props.mode === \"client-link\" ? \"Enter the client code shared with you to view this private collection.\" : \"Enter the password shared with you to view this private collection.\"\n    ),\n    e5(\n      \"label\",\n      { className: \"cedros-gallery-field\" },\n      e5(\"span\", null, props.mode === \"client-link\" ? \"Client link code\" : \"Gallery password\"),\n      e5(\"input\", {\n        \"aria-describedby\": helpId,\n        autoComplete: props.mode === \"password\" ? \"current-password\" : \"one-time-code\",\n        onChange: (event) => props.onCredentialChange(event.currentTarget.value),\n        type: props.mode === \"password\" ? \"password\" : \"text\",\n        value: props.access.credential\n      })\n    ),\n    e5(\"button\", {\n      className: \"cedros-gallery-button\",\n      disabled: props.access.checking || !props.access.credential.trim(),\n      type: \"submit\"\n    }, props.access.checking ? \"Checking\\u2026\" : \"Unlock gallery\"),\n    props.access.message && e5(\"span\", { className: \"cedros-gallery-proofing__state\", role: \"status\" }, props.access.message)\n  );\n}\nfunction submit(props) {\n  return (event) => {\n    event.preventDefault();\n    props.onVerify();\n  };\n}\nfunction accessTitle(state) {\n  if (state === \"scheduled\") return \"Gallery opens soon\";\n  if (state === \"expired\") return \"Gallery has closed\";\n  if (state === \"login-required\") return \"Sign in required\";\n  if (state === \"role-required\") return \"A permitted account is required\";\n  return \"Gallery unavailable\";\n}\nfunction accessMessage(state) {\n  if (state === \"scheduled\") return \"This collection is not available yet. Return after its scheduled opening time.\";\n  if (state === \"expired\") return \"This collection is no longer available. Contact the site team if you need access.\";\n  if (state === \"login-required\") {\n    return \"Sign in with Cedros Login to view this gallery.\";\n  }\n  if (state === \"role-required\") {\n    return \"This gallery requires a role verified through Cedros Login.\";\n  }\n  return \"This gallery is not available for public viewing.\";\n}\n\n// src/web/gallery-actions.ts\nvar galleryBase = \"/extensions/cedros-gallery\";\nasync function submitProofing(props, selected, favorites, comments, setState, credential, idempotencyKey) {\n  const sessionId = props.proofing.sessionId || props.galleryId;\n  if (!sessionId) {\n    setState(\"Proofing session missing.\");\n    return { ok: false };\n  }\n  setState(\"Submitting\\u2026\");\n  try {\n    const response = await fetch(`${galleryBase}/v1/proofing/${encodeURIComponent(sessionId)}/submit`, {\n      body: JSON.stringify(proofingBody(props, selected, favorites, comments, credential, idempotencyKey)),\n      credentials: \"same-origin\",\n      headers: { \"content-type\": \"application/json\" },\n      method: \"POST\"\n    });\n    const body = await response.json().catch(() => ({}));\n    if (response.ok && body.ok === true && isRecord3(body.proofingState)) {\n      void trackGalleryAnalyticsEvent({\n        event: \"proofing-submitted\",\n        galleryId: props.galleryId,\n        metadata: { selectedCount: selected.size }\n      });\n      setState(\"Review submitted.\");\n      return { ok: true, proofingState: normalizeProofingRuntimeState(body.proofingState) };\n    }\n    setState(proofingErrorMessage(body.error));\n    return proofingFailure(response.status, props, credential, body.proofingState);\n  } catch {\n    setState(\"Submission could not reach the Gallery service.\");\n    return { ok: false };\n  }\n}\nasync function saveProofingDraft(props, selected, favorites, comments, credential, idempotencyKey) {\n  const sessionId = props.proofing.sessionId || props.galleryId;\n  if (!sessionId) return { ok: false };\n  try {\n    const response = await fetch(`${galleryBase}/v1/proofing/${encodeURIComponent(sessionId)}/feedback`, {\n      body: JSON.stringify(proofingBody(props, selected, favorites, comments, credential, idempotencyKey)),\n      credentials: \"same-origin\",\n      headers: { \"content-type\": \"application/json\" },\n      method: \"POST\"\n    });\n    const body = await response.json().catch(() => ({}));\n    if (response.ok && body.ok === true && isRecord3(body.proofingState)) {\n      return { ok: true, proofingState: normalizeProofingRuntimeState(body.proofingState) };\n    }\n    const failure = await proofingFailure(response.status, props, credential, body.proofingState);\n    if (response.status === 409) failure.message = proofingErrorMessage(body.error);\n    return failure;\n  } catch {\n    return { ok: false };\n  }\n}\nfunction proofingAccessDenied(status2) {\n  return status2 === 401 || status2 === 403 || status2 === 404;\n}\nasync function proofingFailure(status2, props, credential, state) {\n  const failure = {\n    ok: false,\n    accessDenied: proofingAccessDenied(status2),\n    proofingState: normalizeProofingRuntimeState(state)\n  };\n  if (status2 !== 409) return failure;\n  try {\n    const sessionId = props.proofing.sessionId || props.galleryId;\n    const response = await fetch(`${galleryBase}/v1/access/validate`, {\n      body: JSON.stringify(accessBody(props, credential, sessionId)),\n      credentials: \"same-origin\",\n      headers: { \"content-type\": \"application/json\" },\n      method: \"POST\"\n    });\n    const body = await response.json().catch(() => ({}));\n    if (proofingAccessDenied(response.status) || response.ok && body.allowed === false) {\n      return { ok: false, accessDenied: true };\n    }\n    if (response.ok && body.allowed === true) {\n      failure.proofingState = normalizeProofingRuntimeState(body.proofingState);\n      if (Array.isArray(body.reviewImages)) failure.reviewImages = body.reviewImages;\n    }\n  } catch {\n  }\n  return failure;\n}\nasync function reportDownload(view, item, decision2) {\n  try {\n    const response = await fetch(`${galleryBase}/v1/downloads/request`, {\n      body: JSON.stringify({\n        accessAllowed: item.accessState !== \"locked\",\n        galleryId: view.galleryId,\n        itemId: item.id,\n        kind: decision2.kind,\n        requireEntitlement: view.downloadPolicy.requireEntitlement || item.requiresPurchase,\n        requireLogin: view.downloadPolicy.requireLogin\n      }),\n      credentials: \"same-origin\",\n      headers: { \"content-type\": \"application/json\" },\n      method: \"POST\"\n    });\n    if (!response.ok) return;\n    const result = await response.json();\n    if (result.allowed !== true) return;\n    void trackGalleryAnalyticsEvent({ event: \"image-downloaded\", galleryId: view.galleryId, itemId: item.id });\n  } catch {\n    logDownloadPolicyFailure();\n  }\n}\nasync function validateGalleryAccess(props, credential, setAccess, setProofingState, setProofingDraft, isCurrent = () => true, setReviewImages) {\n  const sessionId = props.proofing.enabled ? props.proofing.sessionId || props.galleryId : \"\";\n  setAccess((current) => ({ ...current, checking: true, message: \"Checking\\u2026\" }));\n  try {\n    const response = await fetch(`${galleryBase}/v1/access/validate`, {\n      body: JSON.stringify(accessBody(props, credential, sessionId)),\n      credentials: \"same-origin\",\n      headers: { \"content-type\": \"application/json\" },\n      method: \"POST\"\n    });\n    const body = await response.json().catch(() => ({}));\n    if (!isCurrent()) return;\n    if (!response.ok) throw new Error(`access ${response.status}`);\n    const allowed = body.allowed === true;\n    const proofingState = normalizeProofingRuntimeState(body.proofingState);\n    if (proofingState && setProofingState) setProofingState(proofingState);\n    if (allowed && Array.isArray(body.reviewImages)) setReviewImages?.(body.reviewImages);\n    const proofingDraft = normalizeProofingDraft(body.proofingDraft);\n    if (allowed && setProofingDraft) setProofingDraft(proofingDraft);\n    setAccess((current) => accessResult(current, allowed, body.state, body.reason));\n  } catch {\n    if (!isCurrent()) return;\n    setAccess((current) => ({ ...current, checking: false, message: \"Access check failed.\", verified: false }));\n  }\n}\nfunction accessBody(props, credential, sessionId) {\n  return {\n    credential: credential.trim(),\n    galleryId: props.galleryId,\n    mode: props.visibilityPolicy.mode,\n    ...sessionId ? { sessionId } : {}\n  };\n}\nfunction reportFilterChange(galleryId, filter2, value, reset = false) {\n  void trackGalleryAnalyticsEvent({\n    event: \"gallery-filter-changed\",\n    galleryId,\n    metadata: { filter: filter2, hasValue: Boolean(value), reset }\n  });\n}\nfunction reportSearch(event, galleryId, query) {\n  event.preventDefault();\n  reportSearchValue(galleryId, query);\n}\nfunction reportSearchValue(galleryId, query) {\n  const trimmed = query.trim();\n  if (!trimmed) return;\n  void trackGalleryAnalyticsEvent({\n    event: \"gallery-search-performed\",\n    galleryId,\n    metadata: { queryLength: trimmed.length }\n  });\n}\nfunction proofingBody(props, selected, favorites, comments, credential, idempotencyKey) {\n  const itemLabels = proofingItemLabels(selected, favorites, comments, props.items);\n  const body = {\n    comments: Object.entries(comments).filter(([, comment]) => comment.trim()).map(([itemId, comment]) => ({ itemId, comment: comment.trim() })).sort((left, right) => left.itemId.localeCompare(right.itemId)),\n    favoriteItemIds: [...favorites].sort(),\n    idempotencyKey,\n    ...Object.keys(itemLabels).length ? { itemLabels } : {},\n    mode: props.visibilityPolicy.mode,\n    selectedItemIds: [...selected].sort()\n  };\n  if (credential.trim()) body.credential = credential.trim();\n  return body;\n}\nfunction proofingResponseFingerprint(selected, favorites, comments, items = []) {\n  return JSON.stringify({\n    comments: Object.entries(comments).filter(([, comment]) => comment.trim()).map(([itemId, comment]) => [itemId, comment.trim()]).sort(([left], [right]) => left.localeCompare(right)),\n    favorites: [...favorites].sort(),\n    itemLabels: proofingItemLabels(selected, favorites, comments, items),\n    selected: [...selected].sort()\n  });\n}\nfunction proofingItemLabels(selected, favorites, comments, items) {\n  const referencedItemIds = /* @__PURE__ */ new Set([\n    ...selected,\n    ...favorites,\n    ...Object.keys(comments).filter((itemId) => comments[itemId]?.trim())\n  ]);\n  return Object.fromEntries(items.flatMap((item) => {\n    const label = Array.from(item.title.trim()).slice(0, 160).join(\"\");\n    return referencedItemIds.has(item.id) && label ? [[item.id, label]] : [];\n  }));\n}\nfunction newProofingIdempotencyKey(sessionId) {\n  const random = typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\" ? crypto.randomUUID() : `${Date.now()}-${Math.random().toString(36).slice(2)}`;\n  return `${sessionId.slice(0, 32)}:${random}`.slice(0, 128);\n}\nfunction normalizeProofingRuntimeState(input) {\n  if (!isRecord3(input)) return void 0;\n  const state = {};\n  for (const key of [\"enabled\", \"expired\", \"locked\", \"lockAfterSubmit\", \"submitted\"]) {\n    if (typeof input[key] === \"boolean\") state[key] = input[key];\n  }\n  if (typeof input.deadline === \"string\") state.deadline = input.deadline;\n  for (const key of [\"requiredSelections\", \"selectionLimit\"]) {\n    if (typeof input[key] === \"number\" && Number.isInteger(input[key])) state[key] = input[key];\n  }\n  return state;\n}\nfunction normalizeProofingDraft(input) {\n  if (!isRecord3(input)) return void 0;\n  const selectedItemIds = stringList(input.selectedItemIds);\n  const favoriteItemIds = stringList(input.favoriteItemIds);\n  const comments = Array.isArray(input.comments) ? Object.fromEntries(input.comments.flatMap((value) => {\n    if (!isRecord3(value)) return [];\n    const itemId = stringValue14(value.itemId, 128);\n    const comment = stringValue14(value.comment, 1e3);\n    return itemId && comment ? [[itemId, comment]] : [];\n  })) : {};\n  return { comments, favoriteItemIds, selectedItemIds };\n}\nfunction proofingErrorMessage(error) {\n  if (typeof error !== \"string\") return \"Review could not be saved. Please try again.\";\n  if (error.includes(\"reload\")) return \"This review changed. Reload the page to restore the latest saved response before continuing.\";\n  if (error.includes(\"no eligible items\")) return \"This review is not ready yet. Ask the site team to finish connecting its images.\";\n  if (error.includes(\"selection limit\")) return \"Too many images are selected for this review.\";\n  if (error.includes(\"required selections\")) return \"Choose the required number of images before submitting.\";\n  if (error.includes(\"locked\")) return \"This review has already been finalized.\";\n  if (error.includes(\"expired\")) return \"This review has closed.\";\n  if (error.includes(\"does not belong\") || error.includes(\"unknown item\")) return \"One of the selected images is no longer in this review. Reload and try again.\";\n  return \"Review could not be saved. Please try again.\";\n}\nfunction accessResult(current, allowed, state, reason2) {\n  return {\n    ...current,\n    checking: false,\n    message: allowed ? \"Access verified.\" : accessFailureMessage(state, reason2),\n    verified: allowed\n  };\n}\nfunction accessFailureMessage(state, reason2) {\n  if (state === \"not-ready\" || reason2?.includes(\"no eligible items\")) {\n    return \"This review is not ready yet. Ask the site team to finish connecting its images.\";\n  }\n  if (state === \"unavailable\") return \"Role-based access is unavailable. Ask the site team to use a review password instead.\";\n  if (state === \"disabled\" || state === \"expired\" || reason2?.includes(\"expired\")) return \"This review has closed.\";\n  if (state === \"login\") return \"Sign in is required for this gallery.\";\n  if (state === \"role\") return \"Your account does not have access to this gallery.\";\n  return \"Access could not be verified.\";\n}\nfunction logDownloadPolicyFailure() {\n  if (typeof console === \"undefined\" || typeof console.warn !== \"function\") return;\n  console.warn(\"Cedros Gallery download policy request failed.\", { reason: \"request_failed\" });\n}\nfunction isRecord3(input) {\n  return typeof input === \"object\" && input !== null && !Array.isArray(input);\n}\nfunction stringList(input) {\n  if (!Array.isArray(input)) return [];\n  return [...new Set(input.map((value) => stringValue14(value, 128)).filter(Boolean))].slice(0, 1e4);\n}\nfunction stringValue14(input, maxLength) {\n  return typeof input === \"string\" ? Array.from(input.trim()).slice(0, maxLength).join(\"\") : \"\";\n}\n\n// src/web/gallery-controls.ts\nimport React12 from \"react\";\nvar e6 = React12.createElement;\nvar sortOptions = [\n  [\"manual\", \"Curated order\"],\n  [\"featured\", \"Featured\"],\n  [\"newest\", \"Newest\"],\n  [\"oldest\", \"Oldest\"],\n  [\"title-az\", \"Title A-Z\"],\n  [\"title-za\", \"Title Z-A\"],\n  [\"category\", \"Category\"],\n  [\"artist\", \"Artist\"],\n  [\"product-status\", \"Availability\"]\n];\nfunction GalleryControls(props) {\n  const disclosureId = React12.useId();\n  const [advancedOpen, setAdvancedOpen] = React12.useState(false);\n  const advancedDisabled = !advancedOpen;\n  const advancedKeys = [\n    ...props.config.tags ? [\"tag\"] : [],\n    \"artist\",\n    \"orientation\",\n    \"productStatus\"\n  ];\n  const usefulAdvancedKeys = advancedKeys.filter((key) => uniqueOptions(props.items, key).length > 1 || props.filters[key]);\n  const activeCount = activeGalleryFilterCount(props.filters);\n  const update = (key, value) => {\n    props.setFilters({ ...props.filters, [key]: value });\n    if (key !== \"query\") reportFilterChange(props.galleryId, key, value);\n  };\n  const clear = () => {\n    props.setFilters(clearGalleryFilters(props.filters));\n    reportFilterChange(props.galleryId, \"category\", \"\", true);\n  };\n  return e6(\n    \"form\",\n    {\n      className: `cedros-gallery-toolbar cedros-gallery-toolbar--${props.config.display}${advancedOpen ? \" is-expanded\" : \"\"}`,\n      onSubmit: (event) => reportSearch(event, props.galleryId, props.filters.query)\n    },\n    e6(\n      \"div\",\n      { className: \"cedros-gallery-toolbar__primary\" },\n      props.config.search && e6(\n        \"label\",\n        { className: \"cedros-gallery-field cedros-gallery-field--search\" },\n        e6(\"span\", null, \"Search images\"),\n        e6(\"input\", {\n          onBlur: () => reportSearchValue(props.galleryId, props.filters.query),\n          onChange: (event) => update(\"query\", event.currentTarget.value),\n          placeholder: \"Search images\\u2026\",\n          type: \"search\",\n          value: props.filters.query\n        })\n      ),\n      props.config.categories && filterSelect(\"Category\", \"category\", props, false),\n      e6(\"button\", {\n        \"aria-controls\": disclosureId,\n        \"aria-expanded\": advancedOpen,\n        className: \"cedros-gallery-button cedros-gallery-button--ghost cedros-gallery-toolbar__toggle\",\n        onClick: () => setAdvancedOpen((current) => !current),\n        type: \"button\"\n      }, advancedOpen ? \"Hide filters\" : props.sort === \"manual\" ? \"More filters\" : `More filters \\xB7 ${sortOptions.find(([value]) => value === props.sort)?.[1] ?? \"Custom order\"}`),\n      activeCount > 0 && e6(\"button\", {\n        className: \"cedros-gallery-button cedros-gallery-button--ghost\",\n        onClick: clear,\n        type: \"button\"\n      }, \"Clear filters\")\n    ),\n    e6(\"div\", {\n      \"aria-hidden\": advancedDisabled,\n      className: \"cedros-gallery-toolbar__disclosure\",\n      id: disclosureId,\n      inert: advancedDisabled\n    }, e6(\n      \"div\",\n      { className: \"cedros-gallery-toolbar__advanced\" },\n      e6(\n        \"label\",\n        { className: \"cedros-gallery-field\" },\n        e6(\"span\", null, \"Sort\"),\n        e6(\"select\", {\n          \"aria-label\": \"Sort\",\n          disabled: advancedDisabled,\n          value: props.sort,\n          onChange: (event) => props.setSort(event.currentTarget.value)\n        }, sortOptions.map(([value, label]) => e6(\"option\", { key: value, value }, label)))\n      ),\n      usefulAdvancedKeys.map((key) => e6(React12.Fragment, { key }, filterSelect(\n        { category: \"Category\", tag: \"Tag\", artist: \"Artist\", orientation: \"Orientation\", productStatus: \"Availability\", accessState: \"Access\" }[key],\n        key,\n        props,\n        advancedDisabled\n      )))\n    ))\n  );\n}\nfunction filterSelect(label, key, props, disabled2) {\n  const options = uniqueOptions(props.items, key);\n  if (options.length <= 1 && !props.filters[key]) return null;\n  const displayedOptions = props.filters[key] && !options.includes(props.filters[key]) ? [props.filters[key], ...options] : options;\n  return e6(\n    \"label\",\n    { className: \"cedros-gallery-field\" },\n    e6(\"span\", null, label),\n    e6(\n      \"select\",\n      {\n        \"aria-label\": label,\n        disabled: disabled2,\n        onChange: (event) => {\n          props.setFilters({ ...props.filters, [key]: event.currentTarget.value });\n          reportFilterChange(props.galleryId, key, event.currentTarget.value);\n        },\n        value: props.filters[key]\n      },\n      e6(\"option\", { value: \"\" }, `All ${label === \"Category\" ? \"categories\" : label.toLowerCase()}`),\n      displayedOptions.map((option) => e6(\n        \"option\",\n        { key: option, value: option },\n        key === \"orientation\" || key === \"productStatus\" ? option[0].toUpperCase() + option.slice(1) : option\n      ))\n    )\n  );\n}\nfunction uniqueOptions(items, key) {\n  const values = key === \"tag\" ? items.flatMap((item) => item.tags) : items.map((item) => String(item[key]));\n  return [...new Set(values.filter((value) => value && !(key === \"orientation\" && value === \"unknown\") && !(key === \"productStatus\" && value === \"none\")))].sort((a, b) => a.localeCompare(b));\n}\nfunction clearGalleryFilters(current) {\n  return {\n    ...current,\n    category: \"\",\n    tag: \"\",\n    artist: \"\",\n    orientation: \"\",\n    productStatus: \"\",\n    accessState: \"\",\n    query: \"\",\n    selectedOnly: false,\n    featuredOnly: false\n  };\n}\nfunction activeGalleryFilterCount(filters) {\n  return Object.values(filters).filter((value) => value === true || typeof value === \"string\" && value.length > 0).length;\n}\n\n// src/web/gallery-viewport.ts\nimport React13 from \"react\";\nvar e7 = React13.createElement;\nfunction GalleryItemsViewport(props) {\n  if (!horizontalLayout(props.layout)) {\n    return e7(\"div\", { className: `cedros-gallery-items cedros-gallery-items--${safeClass(props.layout)}` }, props.children);\n  }\n  return e7(HorizontalGalleryViewport, props);\n}\nfunction HorizontalGalleryViewport(props) {\n  const viewportRef = React13.useRef(null);\n  const dragRef = React13.useRef(null);\n  const scrollPosition = useMotionValue(0);\n  const edge = useEdgeResistance({ reducedMotion: props.reducedMotion });\n  const [activeIndex, setActiveIndex] = React13.useState(0);\n  const edges = useScrollEdges({ initialAtEnd: props.children.length <= 1, ref: viewportRef });\n  const [hovered, setHovered] = React13.useState(false);\n  const [focused, setFocused] = React13.useState(false);\n  const [dragging, setDragging] = React13.useState(false);\n  const [pageHidden, setPageHidden] = React13.useState(false);\n  const [userPaused, setUserPaused] = React13.useState(false);\n  const paused = props.carousel.pauseOnHover && hovered || props.carousel.pauseOnInteraction && focused || dragging || pageHidden || userPaused;\n  const syncScrollState = React13.useCallback(() => {\n    const viewport = viewportRef.current;\n    if (!viewport) return;\n    const items = [...viewport.querySelectorAll(\".cedros-gallery-item\")];\n    const reference = viewport.scrollLeft + (props.carousel.centerMode ? viewport.clientWidth / 2 : 0);\n    const next = items.reduce((closest, item, index) => {\n      const point = item.offsetLeft + (props.carousel.centerMode ? item.offsetWidth / 2 : 0);\n      const closestItem = items[closest];\n      const closestPoint = closestItem ? closestItem.offsetLeft + (props.carousel.centerMode ? closestItem.offsetWidth / 2 : 0) : Number.POSITIVE_INFINITY;\n      return Math.abs(point - reference) < Math.abs(closestPoint - reference) ? index : closest;\n    }, 0);\n    setActiveIndex(Math.max(0, Math.min(props.children.length - 1, next)));\n    edges.sync();\n    if (Math.abs(scrollPosition.get() - viewport.scrollLeft) > 0.5) scrollPosition.set(viewport.scrollLeft);\n  }, [edges.sync, props.carousel.centerMode, props.children.length, scrollPosition]);\n  React13.useEffect(() => {\n    const viewport = viewportRef.current;\n    if (!viewport) return;\n    const unsubscribe = scrollPosition.on(\"change\", (value) => {\n      if (Math.abs(viewport.scrollLeft - value) > 0.5) viewport.scrollLeft = value;\n    });\n    const observer2 = typeof ResizeObserver === \"undefined\" ? null : new ResizeObserver(syncScrollState);\n    observer2?.observe(viewport);\n    syncScrollState();\n    return () => {\n      observer2?.disconnect();\n      unsubscribe();\n    };\n  }, [scrollPosition, syncScrollState]);\n  const scrollToIndex = React13.useCallback((index, intent = \"user\") => {\n    const viewport = viewportRef.current;\n    if (!viewport || !props.children.length) return;\n    const lastIndex = props.children.length - 1;\n    if (!props.carousel.infiniteLoop && (index < 0 || index > lastIndex)) {\n      if (intent === \"user\") edge.nudge(index < 0 ? 1 : -1);\n      return;\n    }\n    const normalized = props.carousel.infiniteLoop ? (index + props.children.length) % props.children.length : Math.max(0, Math.min(lastIndex, index));\n    const target = viewport.querySelector(`.cedros-gallery-carousel-index-${normalized}`);\n    const max = Math.max(0, viewport.scrollWidth - viewport.clientWidth);\n    const desired = target ? target.offsetLeft - (props.carousel.centerMode ? (viewport.clientWidth - target.offsetWidth) / 2 : 0) : max * (normalized / Math.max(1, props.children.length - 1));\n    const next = Math.max(0, Math.min(max, desired));\n    if (props.reducedMotion) {\n      scrollPosition.set(next);\n    } else {\n      animate(scrollPosition, next, galleryInteractionSpring);\n    }\n    setActiveIndex(normalized);\n  }, [edge.nudge, props.carousel.centerMode, props.carousel.infiniteLoop, props.children.length, props.reducedMotion, scrollPosition]);\n  React13.useEffect(() => {\n    if (!props.carousel.autoplay || props.reducedMotion || paused || props.children.length <= 1) return;\n    const interval = window.setInterval(() => scrollToIndex(activeIndex + 1, \"auto\"), props.carousel.autoplaySpeedMs);\n    return () => window.clearInterval(interval);\n  }, [activeIndex, paused, props.carousel.autoplay, props.carousel.autoplaySpeedMs, props.children.length, props.reducedMotion, scrollToIndex]);\n  React13.useEffect(() => {\n    if (typeof document === \"undefined\") return;\n    const update = () => setPageHidden(document.visibilityState === \"hidden\");\n    update();\n    document.addEventListener(\"visibilitychange\", update);\n    return () => document.removeEventListener(\"visibilitychange\", update);\n  }, []);\n  const onPointerDown = (event) => {\n    if (event.button !== 0 || interactiveTarget(event.target)) return;\n    const viewport = viewportRef.current;\n    if (!viewport) return;\n    dragRef.current = { pointerId: event.pointerId, startScroll: viewport.scrollLeft, startX: event.clientX };\n    viewport.setPointerCapture(event.pointerId);\n    setDragging(true);\n  };\n  const onPointerMove = (event) => {\n    const drag2 = dragRef.current;\n    const viewport = viewportRef.current;\n    if (!drag2 || !viewport || drag2.pointerId !== event.pointerId) return;\n    const delta = event.clientX - drag2.startX;\n    const desired = drag2.startScroll - delta;\n    const max = Math.max(0, viewport.scrollWidth - viewport.clientWidth);\n    viewport.scrollLeft = Math.max(0, Math.min(max, desired));\n    edge.applyOverscroll(scrollOverscroll(desired, max));\n  };\n  const releasePointer = (event) => {\n    const viewport = viewportRef.current;\n    if (dragRef.current?.pointerId !== event.pointerId) return;\n    dragRef.current = null;\n    if (viewport?.hasPointerCapture(event.pointerId)) viewport.releasePointerCapture(event.pointerId);\n    edge.release();\n    setDragging(false);\n    syncScrollState();\n  };\n  const children = props.children.map((child, index) => React13.cloneElement(\n    child,\n    { carouselActive: index === activeIndex, carouselIndex: index }\n  ));\n  const showNavigation = props.carousel.dots || props.carousel.thumbnailNav;\n  return e7(\n    \"div\",\n    {\n      className: `cedros-gallery-carousel cedros-gallery-carousel--${safeClass(props.carousel.transition)}${props.carousel.centerMode ? \" cedros-gallery-carousel--center\" : \"\"}`,\n      onBlur: (event) => {\n        if (!event.currentTarget.contains(event.relatedTarget)) setFocused(false);\n      },\n      onFocus: () => setFocused(true),\n      onMouseEnter: () => setHovered(true),\n      onMouseLeave: () => setHovered(false),\n      style: {\n        \"--c1gb4l3-gallery-carousel-duration\": `${props.carousel.transitionSpeedMs}ms`,\n        \"--c1gb4l3-gallery-slides-desktop\": String(props.carousel.responsiveSlidesPerView.desktop),\n        \"--c1gb4l3-gallery-slides-mobile\": String(props.carousel.responsiveSlidesPerView.mobile),\n        \"--c1gb4l3-gallery-slides-tablet\": String(props.carousel.responsiveSlidesPerView.tablet)\n      }\n    },\n    e7(\"div\", {\n      \"aria-label\": \"Gallery carousel\",\n      className: `cedros-gallery-carousel__viewport${edges.atStart ? \" is-at-start\" : \"\"}${edges.atEnd ? \" is-at-end\" : \"\"}`,\n      onKeyDown: (event) => {\n        if (event.defaultPrevented || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey || event.target instanceof Element && event.target.closest(\"input, select, textarea, [contenteditable]:not([contenteditable='false'])\")) return;\n        if (event.key === \"ArrowLeft\") {\n          event.preventDefault();\n          scrollToIndex(activeIndex - 1);\n        }\n        if (event.key === \"ArrowRight\") {\n          event.preventDefault();\n          scrollToIndex(activeIndex + 1);\n        }\n      },\n      onPointerCancel: releasePointer,\n      onLostPointerCapture: releasePointer,\n      onPointerDown,\n      onPointerMove,\n      onPointerUp: releasePointer,\n      onScroll: syncScrollState,\n      onWheel: (event) => edge.resistWheel(event, \"x\"),\n      ref: viewportRef,\n      role: \"region\",\n      tabIndex: 0\n    }, e7(motion2.div, {\n      className: `cedros-gallery-items cedros-gallery-items--${safeClass(props.layout)}`,\n      style: { x: edge.pull }\n    }, children)),\n    (props.carousel.arrows || props.carousel.autoplay && props.pauseAutoplay) && e7(\n      \"div\",\n      { className: \"cedros-gallery-carousel__arrows\" },\n      props.carousel.autoplay && props.pauseAutoplay && e7(\"button\", {\n        \"aria-pressed\": userPaused,\n        className: \"cedros-gallery-button cedros-gallery-button--ghost\",\n        onClick: () => setUserPaused((current) => !current),\n        type: \"button\"\n      }, userPaused ? \"Play slideshow\" : \"Pause slideshow\"),\n      props.carousel.arrows && e7(\"button\", { \"aria-label\": \"Previous images\", className: \"cedros-gallery-icon-button\", disabled: edges.atStart && !props.carousel.infiniteLoop, onClick: () => scrollToIndex(activeIndex - 1), type: \"button\" }, \"\\u2190\"),\n      props.carousel.arrows && e7(\"button\", { \"aria-label\": \"Next images\", className: \"cedros-gallery-icon-button\", disabled: edges.atEnd && !props.carousel.infiniteLoop, onClick: () => scrollToIndex(activeIndex + 1), type: \"button\" }, \"\\u2192\")\n    ),\n    showNavigation && e7(\n      \"div\",\n      { \"aria-label\": \"Choose image\", className: `cedros-gallery-carousel__nav${props.carousel.thumbnailNav ? \" cedros-gallery-carousel__nav--thumbnails\" : \"\"}`, role: \"group\" },\n      props.navItems.map((item, index) => e7(\"button\", {\n        \"aria-label\": `Show ${item.label}`,\n        \"aria-pressed\": index === activeIndex,\n        className: \"cedros-gallery-carousel__dot\",\n        key: item.id,\n        onClick: () => scrollToIndex(index),\n        type: \"button\"\n      }, props.carousel.thumbnailNav ? String(index + 1) : e7(\"span\", { \"aria-hidden\": true })))\n    )\n  );\n}\nfunction interactiveTarget(target) {\n  return target instanceof Element && Boolean(target.closest(\"a, button, input, select, textarea, label\"));\n}\nfunction safeClass(value) {\n  return value.replace(/[^a-z0-9-]/gi, \"-\");\n}\n\n// src/web/gallery-block.ts\nvar e8 = React14.createElement;\nfunction GalleryBlockView({ props }) {\n  const candidate = React14.useMemo(() => normalizeGalleryBlockProps(props), [props]);\n  const signature = JSON.stringify(candidate);\n  const configuration = React14.useRef({ signature, value: candidate });\n  if (configuration.current.signature !== signature) {\n    configuration.current = { signature, value: candidate };\n  }\n  const normalized = configuration.current.value;\n  const [filters, setFilters] = React14.useState(normalized.filters);\n  const [sort, setSort] = React14.useState(normalized.sort);\n  const [activeId, setActiveId] = React14.useState(null);\n  const [navigationDirection, setNavigationDirection] = React14.useState(0);\n  const [selected, setSelected] = React14.useState(() => idSet(normalized.items, \"selected\"));\n  const [favorites, setFavorites] = React14.useState(() => idSet(normalized.items, \"favorite\"));\n  const [comments, setComments] = React14.useState({});\n  const [submitState, setSubmitState] = React14.useState(\"\");\n  const [confirmingSubmit, setConfirmingSubmit] = React14.useState(false);\n  const [draftStatus, setDraftStatus] = React14.useState(\"\");\n  const [accessRecord, setAccessRecord] = React14.useState(() => ({ owner: normalized, value: initialGalleryAccessState() }));\n  const access = accessRecord.owner === normalized ? accessRecord.value : initialGalleryAccessState();\n  const setAccess = (next) => {\n    setAccessRecord((current) => ({\n      owner: normalized,\n      value: typeof next === \"function\" ? next(current.owner === normalized ? current.value : initialGalleryAccessState()) : next\n    }));\n  };\n  const [serverImages, setServerImages] = React14.useState(null);\n  const accessImagesRef = React14.useRef(null);\n  const [serverProofing, setServerProofing] = React14.useState(null);\n  const [visibleCount, setVisibleCount] = React14.useState(normalized.performance.pageSize);\n  const [page, setPage] = React14.useState(1);\n  const [pageDirection, setPageDirection] = React14.useState(0);\n  const proofingAttemptRef = React14.useRef({ fingerprint: \"\", key: \"\" });\n  const draftAttemptRef = React14.useRef({ fingerprint: \"\", key: \"\" });\n  const lastSavedDraftRef = React14.useRef(\"\");\n  const draftSavingRef = React14.useRef(false);\n  const draftUncertainRef = React14.useRef(false);\n  const [savingDraft, setSavingDraft] = React14.useState(false);\n  const submitBusyRef = React14.useRef(false);\n  const proofingEpochRef = React14.useRef(0);\n  const accessEpochRef = React14.useRef(0);\n  const draftPendingRef = React14.useRef(false);\n  const draftSnapshotRef = React14.useRef(null);\n  const reducedMotion = useGalleryReducedMotion();\n  const deadline = serverProofing?.deadline || normalized.proofing.deadline;\n  const now2 = useVisibilityClock([\n    Date.parse(normalized.visibilityPolicy.publishAt),\n    Date.parse(normalized.visibilityPolicy.expiresAt),\n    Date.parse(/^\\d{4}-\\d{2}-\\d{2}$/.test(deadline) ? `${deadline}T23:59:59.999Z` : deadline)\n  ], normalized.visibilityContext.now);\n  React14.useEffect(() => {\n    setFilters(normalized.filters);\n    setSort(normalized.sort);\n    setSelected(idSet(normalized.items, \"selected\"));\n    setFavorites(idSet(normalized.items, \"favorite\"));\n    setComments({});\n    setSubmitState(\"\");\n    setConfirmingSubmit(false);\n    setDraftStatus(\"\");\n    setAccess(initialGalleryAccessState());\n    setServerProofing(null);\n    setServerImages(null);\n    accessImagesRef.current = null;\n    proofingAttemptRef.current = { fingerprint: \"\", key: \"\" };\n    draftAttemptRef.current = { fingerprint: \"\", key: \"\" };\n    lastSavedDraftRef.current = \"\";\n    draftUncertainRef.current = false;\n    draftPendingRef.current = false;\n    submitBusyRef.current = false;\n    proofingEpochRef.current += 1;\n    accessEpochRef.current += 1;\n    setVisibleCount(normalized.performance.pageSize);\n    setPage(1);\n    setPageDirection(0);\n  }, [normalized]);\n  React14.useEffect(() => {\n    setVisibleCount(normalized.performance.pageSize);\n    setPage(1);\n    setPageDirection(0);\n  }, [filters, normalized.performance.pageSize, sort]);\n  React14.useEffect(() => {\n    const automaticAccessCheck = normalized.proofing.enabled || normalized.visibilityPolicy.mode === \"logged-in\" || normalized.visibilityPolicy.mode === \"role\";\n    if (!automaticAccessCheck || credentialAccessMode(normalized.visibilityPolicy.mode)) return;\n    verifyAccess(\"\");\n    return () => {\n      accessEpochRef.current += 1;\n    };\n  }, [normalized]);\n  const viewerContext = React14.useMemo(() => {\n    const mode = normalized.visibilityPolicy.mode;\n    const accountAccessVerified = access.verified && (mode === \"logged-in\" || mode === \"role\");\n    const roles = mode === \"role\" && access.verified && normalized.visibilityPolicy.requiredRole ? [.../* @__PURE__ */ new Set([...normalized.visibilityContext.roles, normalized.visibilityPolicy.requiredRole])] : normalized.visibilityContext.roles;\n    return {\n      ...normalized.visibilityContext,\n      now: now2,\n      authenticated: normalized.visibilityContext.authenticated || accountAccessVerified,\n      credentialVerified: normalized.visibilityContext.credentialVerified || access.verified,\n      roles\n    };\n  }, [access.verified, normalized.visibilityContext, normalized.visibilityPolicy.mode, normalized.visibilityPolicy.requiredRole, now2]);\n  const runtimeProps = React14.useMemo(() => ({\n    ...props ?? {},\n    filters,\n    items: (accessRecord.owner === normalized && access.verified && serverImages !== null ? serverImages : normalized.items).map((item) => normalized.proofing.enabled ? { ...item, selected: selected.has(item.id), favorite: favorites.has(item.id) } : item),\n    ...accessRecord.owner === normalized && serverProofing ? { proofingSession: { ...recordValue(props?.proofingSession), ...serverProofing } } : {},\n    sort,\n    viewerContext\n  }), [accessRecord.owner, access.verified, normalized, filters, props, serverImages, serverProofing, sort, viewerContext, selected, favorites]);\n  const effective = React14.useMemo(() => normalizeGalleryBlockProps(runtimeProps), [runtimeProps]);\n  const view = React14.useMemo(\n    () => buildGalleryView(runtimeProps),\n    [runtimeProps]\n  );\n  const activeIndex = view.items.findIndex((item) => item.id === activeId);\n  const activeItem = activeIndex >= 0 ? view.items[activeIndex] : null;\n  React14.useEffect(() => {\n    if (!view.visibilitySummary.visible) setActiveId(null);\n  }, [view.visibilitySummary.visible]);\n  const handoffs = React14.useMemo(() => handoffsByItem(view), [view]);\n  const loadingPlans = React14.useMemo(() => loadingPlansByItem(view), [view]);\n  const renderedItems = visibleItemsForPage(view, normalized, visibleCount, page);\n  const virtualized = normalized.performance.virtualization;\n  const animateLayout = !reducedMotion && !virtualized && supportsLayoutAnimation(view.layout);\n  const eligibleItemIds = React14.useMemo(() => new Set(effective.items.map((item) => item.id)), [effective.items]);\n  const responseSelected = React14.useMemo(() => intersectSet(selected, eligibleItemIds), [eligibleItemIds, selected]);\n  const responseFavorites = React14.useMemo(() => intersectSet(favorites, eligibleItemIds), [eligibleItemIds, favorites]);\n  const responseComments = React14.useMemo(() => Object.fromEntries(\n    Object.entries(comments).filter(([itemId]) => eligibleItemIds.has(itemId))\n  ), [comments, eligibleItemIds]);\n  const draftFingerprint = React14.useMemo(() => proofingResponseFingerprint(\n    responseSelected,\n    responseFavorites,\n    responseComments,\n    effective.items\n  ), [effective.items, responseComments, responseFavorites, responseSelected]);\n  draftSnapshotRef.current = {\n    accessReady: access.verified,\n    comments: responseComments,\n    credential: credentialAccessMode(effective.visibilityPolicy.mode) ? access.credential : \"\",\n    favorites: responseFavorites,\n    fingerprint: draftFingerprint,\n    props: effective,\n    selected: responseSelected\n  };\n  React14.useEffect(() => {\n    if (!effective.proofing.enabled || !access.verified || effective.proofing.locked || effective.proofing.expired) return;\n    if (draftFingerprint === lastSavedDraftRef.current && !draftUncertainRef.current) {\n      setDraftStatus((current) => current === \"Changes not saved yet.\" ? \"Progress saved.\" : current);\n      return;\n    }\n    setDraftStatus(\"Changes not saved yet.\");\n    const timer = globalThis.setTimeout(() => void persistLatestDraft(), 900);\n    return () => globalThis.clearTimeout(timer);\n  }, [access.verified, draftFingerprint, effective.proofing.enabled, effective.proofing.expired, effective.proofing.locked]);\n  React14.useEffect(() => {\n    const warnOnExit = (event) => {\n      const snapshot = draftSnapshotRef.current;\n      if (!snapshot?.accessReady || !snapshot.props.proofing.enabled || snapshot.props.proofing.locked || snapshot.props.proofing.expired || snapshot.fingerprint === lastSavedDraftRef.current && !draftSavingRef.current && !draftUncertainRef.current) return;\n      event.preventDefault();\n      event.returnValue = \"\";\n    };\n    globalThis.addEventListener?.(\"beforeunload\", warnOnExit);\n    return () => globalThis.removeEventListener?.(\"beforeunload\", warnOnExit);\n  }, []);\n  const style = {\n    \"--c1gb4l3-gallery-card-padding\": `${normalized.presentation.card.padding || 14}px`,\n    \"--c1gb4l3-gallery-columns\": String(Math.max(1, normalized.columns)),\n    \"--c1gb4l3-gallery-gap\": `${normalized.gap}px`,\n    \"--c1gb4l3-gallery-hover-duration\": `${normalized.presentation.card.transitionMs}ms`,\n    \"--c1gb4l3-gallery-min-column\": `${normalized.presentation.grid.minColumnWidth}px`,\n    \"--c1gb4l3-gallery-mosaic-span\": String(Math.min(2, Math.max(1, normalized.columns))),\n    \"--c1gb4l3-gallery-radius-card\": `${normalized.presentation.card.radius}px`\n  };\n  React14.useEffect(() => {\n    if (!view.galleryId) return;\n    void trackGalleryAnalyticsEvent({\n      event: \"gallery-viewed\",\n      galleryId: view.galleryId,\n      metadata: { itemCount: view.itemCount, layout: view.layout }\n    });\n  }, [view.galleryId]);\n  const openItem = (item) => {\n    if (!view.controls.lightbox) return;\n    setNavigationDirection(0);\n    setActiveId(item.id);\n    void trackGalleryAnalyticsEvent({ event: \"lightbox-opened\", galleryId: view.galleryId, itemId: item.id });\n    void trackGalleryAnalyticsEvent({ event: \"image-viewed\", galleryId: view.galleryId, itemId: item.id });\n  };\n  const navigateLightbox = (offset) => {\n    setNavigationDirection(offset);\n    setActiveId(adjacentId(view.items, activeIndex, offset));\n  };\n  const chooseLightboxItem = (index) => {\n    const next = view.items[index];\n    if (!next) return;\n    setNavigationDirection(index === activeIndex ? 0 : index > activeIndex ? 1 : -1);\n    setActiveId(next.id);\n  };\n  const toggleSelected = (item) => {\n    if (!access.verified || submitBusyRef.current || effective.proofing.locked || effective.proofing.expired) return;\n    if (!selected.has(item.id) && effective.proofing.selectionLimit > 0 && responseSelected.size >= effective.proofing.selectionLimit) {\n      setSubmitState(`You can select up to ${effective.proofing.selectionLimit} ${effective.proofing.selectionLimit === 1 ? \"image\" : \"images\"}. Deselect one first.`);\n      return;\n    }\n    setConfirmingSubmit(false);\n    setSubmitState(\"\");\n    setSelected((current) => toggleSet(current, item.id));\n    void trackGalleryAnalyticsEvent({ event: \"image-selected\", galleryId: view.galleryId, itemId: item.id });\n  };\n  const toggleFavorite = (item) => {\n    if (!access.verified || submitBusyRef.current || effective.proofing.locked || effective.proofing.expired) return;\n    setConfirmingSubmit(false);\n    setSubmitState(\"\");\n    setFavorites((current) => toggleSet(current, item.id));\n    void trackGalleryAnalyticsEvent({ event: \"image-favorited\", galleryId: view.galleryId, itemId: item.id });\n  };\n  function verifyAccess(credential = access.credential) {\n    const epoch = ++accessEpochRef.current;\n    proofingEpochRef.current += 1;\n    submitBusyRef.current = false;\n    setSubmitState(\"\");\n    setConfirmingSubmit(false);\n    setAccess((current) => ({ ...current, verified: false }));\n    accessImagesRef.current = null;\n    setServerImages(null);\n    void validateGalleryAccess(\n      normalized,\n      credential,\n      setAccess,\n      setServerProofing,\n      restoreProofingDraft,\n      () => epoch === accessEpochRef.current,\n      (images) => {\n        const items = normalizeGalleryItems(images);\n        accessImagesRef.current = items;\n        setServerImages(items);\n      }\n    );\n  }\n  function revokeReviewAccess() {\n    accessEpochRef.current += 1;\n    proofingEpochRef.current += 1;\n    submitBusyRef.current = false;\n    draftPendingRef.current = false;\n    accessImagesRef.current = null;\n    setServerImages(null);\n    setServerProofing(null);\n    setActiveId(null);\n    setConfirmingSubmit(false);\n    setSubmitState(\"\");\n    setDraftStatus(\"\");\n    setAccess((current) => ({\n      ...current,\n      checking: false,\n      verified: false,\n      message: \"Review access has changed. Check access again or contact the site team.\"\n    }));\n  }\n  const submitReview = async () => {\n    if (!access.verified || submitBusyRef.current || draftSavingRef.current || effective.proofing.locked || effective.proofing.expired) return;\n    submitBusyRef.current = true;\n    const fingerprint = proofingResponseFingerprint(\n      responseSelected,\n      responseFavorites,\n      responseComments,\n      effective.items\n    );\n    if (proofingAttemptRef.current.fingerprint !== fingerprint) {\n      proofingAttemptRef.current = {\n        fingerprint,\n        key: newProofingIdempotencyKey(effective.proofing.sessionId || effective.galleryId)\n      };\n    }\n    const epoch = ++proofingEpochRef.current;\n    const result = await submitProofing(\n      effective,\n      responseSelected,\n      responseFavorites,\n      responseComments,\n      (message) => {\n        if (epoch === proofingEpochRef.current) setSubmitState(message);\n      },\n      credentialAccessMode(effective.visibilityPolicy.mode) ? access.credential : \"\",\n      proofingAttemptRef.current.key\n    );\n    if (epoch !== proofingEpochRef.current) return;\n    submitBusyRef.current = false;\n    if (result.accessDenied) {\n      revokeReviewAccess();\n      return;\n    }\n    if (result.reviewImages) setServerImages(normalizeGalleryItems(result.reviewImages));\n    if (result.ok) {\n      draftUncertainRef.current = false;\n      lastSavedDraftRef.current = draftFingerprint;\n      setDraftStatus(\"\");\n      setConfirmingSubmit(false);\n    }\n    if (result.proofingState) setServerProofing(result.proofingState);\n  };\n  const updateComment = (itemId, comment) => {\n    if (!access.verified || submitBusyRef.current || effective.proofing.locked || effective.proofing.expired) return;\n    setConfirmingSubmit(false);\n    setSubmitState(\"\");\n    setComments((current) => ({ ...current, [itemId]: Array.from(comment).slice(0, 1e3).join(\"\") }));\n  };\n  function restoreProofingDraft(draft) {\n    draftUncertainRef.current = false;\n    const images = accessImagesRef.current ?? normalized.items;\n    const allowed = new Set(images.map((item) => item.id));\n    const nextSelected = new Set((draft?.selectedItemIds ?? []).filter((itemId) => allowed.has(itemId)));\n    const nextFavorites = new Set((draft?.favoriteItemIds ?? []).filter((itemId) => allowed.has(itemId)));\n    const nextComments = Object.fromEntries(\n      Object.entries(draft?.comments ?? {}).filter(([itemId]) => allowed.has(itemId))\n    );\n    setSelected(nextSelected);\n    setFavorites(nextFavorites);\n    setComments(nextComments);\n    lastSavedDraftRef.current = proofingResponseFingerprint(\n      nextSelected,\n      nextFavorites,\n      nextComments,\n      images\n    );\n    setDraftStatus(draft ? \"Saved progress restored.\" : \"\");\n  }\n  async function persistLatestDraft() {\n    if (submitBusyRef.current) return;\n    if (draftSavingRef.current) {\n      draftPendingRef.current = true;\n      return;\n    }\n    draftSavingRef.current = true;\n    setSavingDraft(true);\n    do {\n      draftPendingRef.current = false;\n      const epoch = proofingEpochRef.current;\n      const snapshot = draftSnapshotRef.current;\n      if (snapshot?.props.proofing.locked || snapshot?.props.proofing.expired || snapshot?.props.proofing.enabled === false) break;\n      if (!snapshot?.accessReady) break;\n      if (!snapshot || snapshot.fingerprint === lastSavedDraftRef.current && !draftUncertainRef.current) break;\n      if (draftAttemptRef.current.fingerprint !== snapshot.fingerprint) {\n        draftAttemptRef.current = {\n          fingerprint: snapshot.fingerprint,\n          key: newProofingIdempotencyKey(snapshot.props.proofing.sessionId || snapshot.props.galleryId)\n        };\n      }\n      setDraftStatus(\"Saving progress\\u2026\");\n      const result = await saveProofingDraft(\n        snapshot.props,\n        snapshot.selected,\n        snapshot.favorites,\n        snapshot.comments,\n        snapshot.credential,\n        draftAttemptRef.current.key\n      );\n      if (epoch !== proofingEpochRef.current) continue;\n      if (result.accessDenied) {\n        revokeReviewAccess();\n        break;\n      }\n      if (result.reviewImages) setServerImages(normalizeGalleryItems(result.reviewImages));\n      if (result.proofingState) setServerProofing(result.proofingState);\n      if (!result.ok) {\n        draftUncertainRef.current = true;\n        setDraftStatus(result.message || \"Progress isn't saved. Retry when the connection is available.\");\n        break;\n      }\n      draftUncertainRef.current = false;\n      lastSavedDraftRef.current = snapshot.fingerprint;\n      setDraftStatus(\"Progress saved.\");\n    } while (draftPendingRef.current || draftSnapshotRef.current?.fingerprint !== lastSavedDraftRef.current);\n    draftSavingRef.current = false;\n    setSavingDraft(false);\n  }\n  const proofingDisabled = !access.verified || effective.proofing.locked || effective.proofing.expired || submitState === \"Submitting\\u2026\";\n  const lightbox = activeItem && e8(GalleryLightbox, {\n    comments,\n    direction: navigationDirection,\n    favorite: favorites.has(activeItem.id),\n    focusTrap: effective.config.accessibility.focusTrap,\n    galleryId: view.galleryId,\n    handoff: handoffs.get(activeItem.id),\n    item: activeItem,\n    items: view.items,\n    keyboard: effective.config.viewer.keyboard && effective.presentation.viewer.keyboard,\n    key: \"gallery-lightbox\",\n    onClose: () => setActiveId(null),\n    onComment: (comment) => updateComment(activeItem.id, comment),\n    onFavorite: () => toggleFavorite(activeItem),\n    onNext: () => navigateLightbox(1),\n    onPrevious: () => navigateLightbox(-1),\n    onSelectItem: chooseLightboxItem,\n    onSelect: () => toggleSelected(activeItem),\n    proofing: {\n      comments: effective.config.proofing.comments,\n      disabled: proofingDisabled,\n      enabled: effective.proofing.enabled,\n      favorites: effective.config.proofing.favorites,\n      selections: effective.config.proofing.selections\n    },\n    reducedMotion,\n    selected: selected.has(activeItem.id),\n    swipe: effective.config.viewer.swipe && effective.presentation.viewer.swipe,\n    viewer: {\n      ...effective.presentation.viewer,\n      metadata: effective.config.viewer.metadataPanel || effective.presentation.viewer.metadata,\n      share: effective.config.viewer.share || effective.presentation.viewer.share,\n      thumbnailStrip: effective.config.viewer.thumbnails && effective.presentation.viewer.thumbnailStrip,\n      zoom: effective.config.viewer.zoom && effective.presentation.viewer.zoom\n    },\n    view\n  });\n  const itemsViewport = view.items.length ? e8(GalleryItemsViewport, {\n    carousel: normalized.presentation.carousel,\n    children: renderedItems.map((item) => e8(GalleryItemCard, {\n      animateLayout,\n      card: normalized.presentation.card,\n      headingLevel: Math.min(6, view.headingLevel + 1),\n      comment: responseComments[item.id] ?? \"\",\n      comments: effective.proofing.enabled && effective.config.proofing.comments,\n      onComment: (comment) => updateComment(item.id, comment),\n      favorite: favorites.has(item.id),\n      favorites: effective.proofing.enabled && effective.config.proofing.favorites,\n      galleryId: view.galleryId,\n      handoff: handoffs.get(item.id),\n      item,\n      key: item.id,\n      lightbox: view.controls.lightbox,\n      loadingPlan: loadingPlans.get(item.id),\n      onFavorite: () => toggleFavorite(item),\n      onOpen: () => openItem(item),\n      onSelect: () => toggleSelected(item),\n      proofingDisabled,\n      reducedMotion,\n      selected: selected.has(item.id),\n      selections: effective.proofing.enabled && effective.config.proofing.selections,\n      showCaptions: view.controls.captions,\n      sharedArtist: sharedGalleryArtist(view.items)\n    })),\n    layout: view.layout,\n    navItems: renderedItems.map((item) => ({ id: item.id, label: item.title || \"Untitled image\" })),\n    pauseAutoplay: normalized.config.accessibility.pauseAutoplay,\n    reducedMotion\n  }) : e8(\n    \"div\",\n    { className: \"cedros-gallery-empty\", role: \"status\" },\n    e8(\"strong\", null, activeGalleryFilterCount(filters) ? \"No matching images\" : effective.proofing.enabled ? \"Your review images aren't ready yet\" : \"No images to show yet\"),\n    e8(\"p\", null, activeGalleryFilterCount(filters) ? \"Try a different search or clear your filters to see the collection.\" : effective.proofing.enabled ? \"Your images will appear here when the review is ready. Contact the team that shared this link if you expected to see them.\" : \"Published images will appear here when this collection is ready.\"),\n    activeGalleryFilterCount(filters) ? e8(\"button\", { className: \"cedros-gallery-button cedros-gallery-button--ghost\", type: \"button\", onClick: () => setFilters(clearGalleryFilters(filters)) }, \"Clear filters\") : null\n  );\n  const pagedItems = normalized.performance.pagination === \"paged\" && !reducedMotion ? e8(\n    \"div\",\n    { className: \"cedros-gallery-pages\" },\n    e8(\n      AnimatePresence,\n      { custom: pageDirection, initial: false, mode: \"sync\" },\n      e8(motion2.div, {\n        animate: \"center\",\n        className: \"cedros-gallery-pages__page\",\n        custom: pageDirection,\n        exit: \"exit\",\n        initial: \"enter\",\n        key: `gallery-page-${page}`,\n        transition: galleryPanelSpring,\n        variants: pageDirection === 0 ? fadeAxisVariants : sharedAxisVariants\n      }, itemsViewport)\n    )\n  ) : itemsViewport;\n  const className = `cedros-gallery-block${effective.proofing.enabled ? \" cedros-gallery-block--proofing\" : \"\"} cedros-gallery-block--${layoutClass(view.layout)}${virtualized ? \" cedros-gallery-block--virtualized\" : \"\"}`;\n  return e8(\n    \"section\",\n    { className, style, \"data-gallery-id\": view.galleryId || void 0 },\n    e8(GalleryHeader, { view, title: props?.title, description: props?.description }),\n    e8(GalleryAccessGate, {\n      access,\n      mode: normalized.visibilityPolicy.mode,\n      onCredentialChange: (credential) => {\n        accessEpochRef.current += 1;\n        proofingEpochRef.current += 1;\n        submitBusyRef.current = false;\n        setSubmitState(\"\");\n        setConfirmingSubmit(false);\n        setAccess({ checking: false, credential, message: \"\", verified: false });\n      },\n      onVerify: () => verifyAccess(),\n      state: view.visibilitySummary.state,\n      visible: view.visibilitySummary.visible\n    }),\n    view.visibilitySummary.visible && effective.proofing.enabled && !access.verified && e8(\n      \"div\",\n      { className: \"cedros-gallery-access\", role: \"status\" },\n      e8(\"p\", null, access.checking ? \"Checking review access\\u2026\" : access.message || \"Review access has not been verified.\"),\n      e8(\"button\", { className: \"cedros-gallery-button\", type: \"button\", disabled: access.checking, onClick: () => verifyAccess() }, \"Retry review access\")\n    ),\n    view.visibilitySummary.visible && (effective.items.length > 0 || effective.proofing.submitted) && e8(GalleryStatusBar, {\n      accessReady: view.visibilitySummary.visible && access.verified,\n      comments: responseComments,\n      confirmingSubmit,\n      favorites: responseFavorites,\n      draftStatus,\n      normalized: effective,\n      onCancelSubmit: () => setConfirmingSubmit(false),\n      onRetryDraft: persistLatestDraft,\n      onSubmit: () => effective.proofing.lockAfterSubmit ? setConfirmingSubmit(true) : void submitReview(),\n      onSubmitConfirmed: () => void submitReview(),\n      selected: responseSelected,\n      selectedOnly: filters.selectedOnly,\n      onToggleSelected: () => {\n        setFilters((current) => ({ ...current, selectedOnly: !current.selectedOnly }));\n      },\n      savingDraft,\n      submitState\n    }),\n    view.visibilitySummary.visible && view.controls.filters && (view.items.length > 1 || activeGalleryFilterCount(filters) > 0) && e8(GalleryControls, { config: normalized.config.filters, filters, galleryId: view.galleryId, items: filterVisibleGalleryItems(effective.items, viewerContext), setFilters, setSort, sort }),\n    view.visibilitySummary.visible ? pagedItems : null,\n    view.visibilitySummary.visible && e8(GalleryPagination, {\n      mode: normalized.performance.pagination,\n      onMore: () => setVisibleCount((count) => count + normalized.performance.pageSize),\n      onNext: () => {\n        setPageDirection(1);\n        setPage((current) => current + 1);\n      },\n      onPrevious: () => {\n        setPageDirection(-1);\n        setPage((current) => Math.max(1, current - 1));\n      },\n      page,\n      pageSize: normalized.performance.pageSize,\n      renderedCount: renderedItems.length,\n      totalCount: view.items.length\n    }),\n    view.visibilitySummary.visible && (reducedMotion ? lightbox : e8(AnimatePresence, null, lightbox))\n  );\n}\nfunction GalleryHeader({ view, title, description }) {\n  const heading = contentHeadingTag(view.headingLevel);\n  const headingText = typeof title === \"string\" && title.trim() ? title.trim() : view.seoSummary.title || \"Gallery\";\n  const descriptionText = typeof description === \"string\" ? description.trim() : view.seoSummary.description;\n  const artist = view.controls.captions ? sharedGalleryArtist(view.items) : \"\";\n  return e8(\n    \"header\",\n    { className: \"cedros-gallery-header\" },\n    e8(\n      \"div\",\n      null,\n      e8(heading, { className: \"cedros-gallery-heading\" }, headingText),\n      descriptionText && e8(\"p\", { className: \"cedros-gallery-description\" }, descriptionText),\n      view.visibilitySummary.visible && artist && !descriptionText.includes(artist) ? e8(\"p\", { className: \"cedros-gallery-collection-context\" }, artist) : null\n    )\n  );\n}\nfunction GalleryStatusBar(props) {\n  const plan = props.normalized.proofing;\n  const features = props.normalized.config.proofing;\n  const overLimit = plan.selectionLimit > 0 && props.selected.size > plan.selectionLimit;\n  const ready = props.accessReady && !plan.locked && !plan.expired && !overLimit && props.selected.size >= plan.requiredSelections;\n  const hasResponseControls = features.selections || features.favorites || features.comments;\n  const commentCount = Object.values(props.comments).filter((comment) => comment.trim()).length;\n  const submitting = props.submitState === \"Submitting\\u2026\";\n  const statusRef = React14.useRef(null);\n  const confirmationRef = React14.useRef(null);\n  const submitRef = React14.useRef(null);\n  const wasConfirming = React14.useRef(false);\n  const wasClosed = React14.useRef(plan.locked || plan.expired);\n  React14.useEffect(() => {\n    if (props.confirmingSubmit) {\n      confirmationRef.current?.scrollIntoView?.({ block: \"start\" });\n      confirmationRef.current?.focus({ preventScroll: true });\n    } else if (wasConfirming.current && !plan.locked && !plan.expired) {\n      submitRef.current?.focus({ preventScroll: true });\n    }\n    wasConfirming.current = props.confirmingSubmit;\n  }, [props.confirmingSubmit, plan.locked, plan.expired]);\n  React14.useEffect(() => {\n    const closed = plan.locked || plan.expired;\n    if (closed && !wasClosed.current) {\n      statusRef.current?.scrollIntoView?.({ block: \"start\" });\n      statusRef.current?.focus({ preventScroll: true });\n    }\n    wasClosed.current = closed;\n  }, [plan.locked, plan.expired]);\n  if (!plan.enabled) return null;\n  return e8(\n    \"div\",\n    { className: `cedros-gallery-proofing${props.confirmingSubmit || plan.locked || plan.expired ? \" cedros-gallery-proofing--static\" : \"\"}`, \"aria-live\": \"polite\", ref: statusRef, tabIndex: -1 },\n    e8(\n      \"div\",\n      { className: \"cedros-gallery-proofing__summary\" },\n      features.selections && e8(\"strong\", null, proofingSelectionGuidance(plan.requiredSelections, props.selected.size)),\n      e8(\n        \"span\",\n        null,\n        plan.deadline ? `Due ${formatProofingDeadline(plan.deadline)}` : \"\",\n        features.selections && plan.selectionLimit > 0 ? `${plan.deadline ? \" \\xB7 \" : \"\"}Up to ${plan.selectionLimit} selections` : \"\",\n        features.favorites && props.favorites.size > 0 ? `${plan.deadline || features.selections && plan.selectionLimit > 0 ? \" \\xB7 \" : \"\"}${formatImageCount(props.favorites.size)} ${props.favorites.size === 1 ? \"favorite\" : \"favorites\"}` : \"\",\n        props.draftStatus && !plan.locked ? `${plan.deadline || features.selections && plan.selectionLimit > 0 || features.favorites && props.favorites.size > 0 ? \" \\xB7 \" : \"\"}${props.draftStatus}` : \"\"\n      ),\n      hasResponseControls && features.selections && props.accessReady && !plan.locked && !plan.expired && props.selected.size < plan.requiredSelections ? e8(\n        \"span\",\n        { className: \"cedros-gallery-proofing__state\" },\n        `Choose ${formatImageCount(plan.requiredSelections - props.selected.size)} more ${plan.requiredSelections - props.selected.size === 1 ? \"image\" : \"images\"} to continue.`\n      ) : null\n    ),\n    features.selections && props.accessReady && (props.selected.size > 0 || props.selectedOnly) && e8(\"button\", {\n      \"aria-pressed\": props.selectedOnly,\n      className: activeButton(props.selectedOnly),\n      onClick: props.onToggleSelected,\n      type: \"button\"\n    }, props.selectedOnly ? \"Show all images\" : `Show selected (${formatImageCount(props.selected.size)})`),\n    (plan.expired || plan.locked) && e8(\n      \"span\",\n      { className: \"cedros-gallery-proofing__state\" },\n      plan.submitted ? \"Review submitted. Your final response is saved and ready for the site team.\" : \"This review has closed.\"\n    ),\n    plan.submitted && !plan.locked && e8(\"span\", { className: \"cedros-gallery-proofing__state\" }, \"Latest review submitted. You can update it below.\"),\n    props.draftStatus.startsWith(\"Progress isn't saved\") && !plan.locked && e8(\"button\", {\n      className: \"cedros-gallery-button cedros-gallery-button--ghost\",\n      onClick: props.onRetryDraft,\n      type: \"button\"\n    }, \"Retry save\"),\n    hasResponseControls && !plan.locked && !plan.expired && !props.confirmingSubmit && e8(\"button\", {\n      className: \"cedros-gallery-button\",\n      disabled: !ready || submitting || props.savingDraft,\n      onClick: props.onSubmit,\n      ref: submitRef,\n      type: \"button\"\n    }, submitting ? \"Submitting\\u2026\" : plan.submitted ? plan.lockAfterSubmit ? \"Review and resubmit\" : \"Submit updated review\" : plan.lockAfterSubmit ? \"Review and submit\" : \"Submit review\"),\n    props.confirmingSubmit && ready && e8(\n      \"div\",\n      { \"aria-label\": \"Confirm final review\", className: \"cedros-gallery-proofing__confirm\", ref: confirmationRef, role: \"group\", tabIndex: -1 },\n      e8(\"strong\", null, \"Submit this as the final review?\"),\n      e8(\n        \"span\",\n        null,\n        `${props.selected.size} selected \\xB7 ${props.favorites.size} ${props.favorites.size === 1 ? \"favorite\" : \"favorites\"} \\xB7 ${commentCount} ${commentCount === 1 ? \"comment\" : \"comments\"}`\n      ),\n      props.selected.size > 0 && e8(\n        \"ul\",\n        { className: \"cedros-gallery-proofing__selected\", \"aria-label\": \"Images in your final selection\" },\n        props.normalized.items.filter((item) => props.selected.has(item.id)).map((item) => e8(\n          \"li\",\n          { key: item.id },\n          e8(MediaPreview, { item, loading: \"eager\" }),\n          e8(\"span\", null, item.title || \"Untitled image\")\n        ))\n      ),\n      e8(\n        \"span\",\n        { className: \"cedros-gallery-proofing__state\" },\n        \"You won't be able to change it unless the site team reopens the review.\"\n      ),\n      e8(\n        \"div\",\n        { className: \"cedros-gallery-proofing__confirm-actions\" },\n        e8(\"button\", {\n          className: \"cedros-gallery-button cedros-gallery-button--ghost\",\n          disabled: submitting,\n          onClick: props.onCancelSubmit,\n          type: \"button\"\n        }, \"Keep editing\"),\n        e8(\"button\", {\n          className: \"cedros-gallery-button\",\n          disabled: submitting || props.savingDraft,\n          onClick: props.onSubmitConfirmed,\n          type: \"button\"\n        }, submitting ? \"Submitting\\u2026\" : \"Submit final review\")\n      )\n    ),\n    props.submitState && !plan.locked && e8(\"span\", { className: \"cedros-gallery-proofing__state\" }, props.submitState)\n  );\n}\nfunction proofingSelectionGuidance(requiredSelections, selectedCount) {\n  return requiredSelections > 0 ? `${selectedCount} of ${requiredSelections} required ${requiredSelections === 1 ? \"selection\" : \"selections\"}` : `${selectedCount} selected`;\n}\nfunction formatProofingDeadline(input) {\n  const dateOnly = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(input);\n  const value = dateOnly ? new Date(Number(dateOnly[1]), Number(dateOnly[2]) - 1, Number(dateOnly[3])) : new Date(input);\n  if (!Number.isFinite(value.getTime())) return input;\n  return new Intl.DateTimeFormat(void 0, { dateStyle: \"medium\" }).format(value);\n}\nfunction GalleryItemCard(props) {\n  const commentId = React14.useId();\n  const commentRef = React14.useRef(null);\n  const [commentOpen, setCommentOpen] = React14.useState(false);\n  React14.useEffect(() => {\n    if (commentOpen) commentRef.current?.focus();\n  }, [commentOpen]);\n  const mediaKey = JSON.stringify([props.item.imageUrl, props.item.thumbnailUrl, props.item.accessState]);\n  const [unavailableMedia, setUnavailableMedia] = React14.useState(\"\");\n  const onUnavailable = React14.useCallback(() => setUnavailableMedia(mediaKey), [mediaKey]);\n  const previewMissing = !buildGalleryImageAttributes(props.item, props.loadingPlan);\n  const mediaLabel = `${props.item.title || \"Untitled image\"}${previewMissing ? \" \\u2014 Preview unavailable\" : unavailableMedia === mediaKey ? \" \\u2014 Image unavailable. Reload the page to try again.\" : \"\"}`;\n  const media = e8(MediaPreview, { item: props.item, onUnavailable, plan: props.loadingPlan });\n  const detailHref = safePublicHref(props.item.detailUrl);\n  return e8(\n    motion2.article,\n    {\n      className: `cedros-gallery-item cedros-gallery-item--border-${props.card.border} cedros-gallery-item--shadow-${props.card.shadow} cedros-gallery-item--hover-${layoutClass(props.card.hoverEffect)}${props.selected || props.favorite ? \" has-active-proofing\" : \"\"}${props.carouselIndex === void 0 ? \"\" : ` cedros-gallery-carousel-index-${props.carouselIndex}`}${props.carouselActive === void 0 ? \"\" : props.carouselActive ? \" is-carousel-active\" : \" is-carousel-inactive\"}`,\n      initial: false,\n      layout: props.animateLayout,\n      transition: { ...galleryInteractionSpring, layout: galleryLayoutSpring },\n      whileHover: props.reducedMotion ? void 0 : hoverTarget(props.card.hoverEffect)\n    },\n    props.lightbox ? e8(\"button\", { \"aria-label\": mediaLabel, className: \"cedros-gallery-media-button\", onClick: props.onOpen, type: \"button\" }, media) : e8(\"div\", { className: \"cedros-gallery-media-button\" }, media),\n    e8(\n      \"div\",\n      { className: \"cedros-gallery-item__body\" },\n      e8(\n        \"div\",\n        { className: \"cedros-gallery-item__title-row\" },\n        e8(\n          contentHeadingTag(props.headingLevel),\n          {\n            className: `cedros-gallery-item__title${detailHref || props.lightbox ? \" cedros-gallery-item__title--preview\" : \"\"}`,\n            title: detailHref || props.lightbox ? props.item.title || \"Untitled image\" : void 0\n          },\n          detailHref ? e8(\"a\", { href: detailHref }, props.item.title || \"Untitled image\") : props.lightbox ? e8(\"button\", {\n            className: \"cedros-gallery-title-button\",\n            onClick: props.onOpen,\n            type: \"button\"\n          }, props.item.title || \"Untitled image\") : props.item.title || \"Untitled image\"\n        ),\n        e8(BadgeList, { item: props.item })\n      ),\n      (props.selections || props.favorites || props.comments || props.handoff?.cta.visible) && e8(\n        \"div\",\n        { className: \"cedros-gallery-item__actions\" },\n        props.selections && e8(\"button\", { \"aria-pressed\": props.selected, className: activeButton(props.selected), disabled: props.proofingDisabled, onClick: props.onSelect, type: \"button\" }, props.selected ? \"Selected\" : \"Select\"),\n        props.favorites && e8(\"button\", { \"aria-pressed\": props.favorite, className: `${activeButton(props.favorite)} cedros-gallery-button--quiet`, disabled: props.proofingDisabled, onClick: props.onFavorite, type: \"button\" }, props.favorite ? \"Favorited\" : \"Favorite\"),\n        props.comments && (!props.proofingDisabled || props.comment) && e8(\"button\", {\n          \"aria-controls\": commentId,\n          \"aria-expanded\": commentOpen,\n          className: \"cedros-gallery-button cedros-gallery-button--quiet\",\n          onClick: () => setCommentOpen((open) => !open),\n          type: \"button\"\n        }, commentOpen ? \"Hide comment\" : props.comment ? props.proofingDisabled ? \"View comment\" : \"Edit comment\" : \"Add comment\"),\n        e8(CommerceLink, { galleryId: props.galleryId, handoff: props.handoff, item: props.item })\n      ),\n      props.comments && e8(\n        \"div\",\n        { hidden: !commentOpen, id: commentId },\n        e8(\n          \"label\",\n          { className: \"cedros-gallery-field cedros-gallery-field--comment\" },\n          e8(\"span\", null, \"Comment\"),\n          e8(\"textarea\", {\n            \"aria-label\": `Comment on ${props.item.title || \"Untitled image\"}`,\n            maxLength: 2e3,\n            onChange: (event) => props.onComment(event.currentTarget.value),\n            readOnly: props.proofingDisabled,\n            ref: commentRef,\n            rows: 3,\n            value: props.comment\n          })\n        )\n      ),\n      props.showCaptions && cardCaptionText(props.item, props.sharedArtist) && e8(GalleryCardCaption, { key: props.item.id, text: cardCaptionText(props.item, props.sharedArtist) })\n    )\n  );\n}\nfunction formatImageCount(value) {\n  return new Intl.NumberFormat().format(value);\n}\nfunction GalleryLightbox(props) {\n  const panelRef = React14.useRef(null);\n  const thumbnailsRef = React14.useRef(null);\n  const thumbnailEdge = useEdgeResistance({ reducedMotion: props.reducedMotion });\n  const thumbnailEdges = useScrollEdges({ ref: thumbnailsRef });\n  const [zoomed, setZoomed] = React14.useState(false);\n  const mediaKey = JSON.stringify([props.item.id, props.item.imageUrl, props.item.thumbnailUrl, props.item.accessState]);\n  const [mediaState, setMediaState] = React14.useState({ key: mediaKey, unavailable: false });\n  const mediaUnavailable = mediaState.key === mediaKey && mediaState.unavailable;\n  const onMediaUnavailable = React14.useCallback(() => {\n    setMediaState((current) => current.key === mediaKey ? { key: mediaKey, unavailable: true } : current);\n  }, [mediaKey]);\n  const [shareStatus, setShareStatus] = React14.useState(\"\");\n  const activeIndex = props.items.findIndex((item) => item.id === props.item.id);\n  React14.useEffect(() => {\n    setZoomed(false);\n    setMediaState({ key: mediaKey, unavailable: false });\n  }, [mediaKey]);\n  React14.useEffect(() => setShareStatus(\"\"), [props.item.id]);\n  useModalDialog({\n    closeOnEscape: props.viewer.closeOnEscape,\n    onClose: props.onClose,\n    open: true,\n    panelRef,\n    trapFocus: props.focusTrap\n  });\n  React14.useEffect(() => {\n    if (!props.keyboard) return;\n    const onKeyDown = (event) => {\n      if (!isTopModalDialog(panelRef.current) || event.defaultPrevented || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) return;\n      if (event.target instanceof Element && event.target.closest(\"input, select, textarea, [contenteditable]:not([contenteditable='false'])\")) return;\n      if (event.key === \"ArrowRight\") {\n        event.preventDefault();\n        props.onNext();\n      }\n      if (event.key === \"ArrowLeft\") {\n        event.preventDefault();\n        props.onPrevious();\n      }\n    };\n    document.addEventListener(\"keydown\", onKeyDown);\n    return () => document.removeEventListener(\"keydown\", onKeyDown);\n  }, [props.keyboard, props.onNext, props.onPrevious]);\n  const enter = props.reducedMotion ? { opacity: 0 } : { opacity: 0, scale: 0.97, y: 16 };\n  return e8(\n    motion2.div,\n    { animate: { opacity: 1 }, className: \"cedros-gallery-lightbox\", exit: { opacity: 0 }, initial: { opacity: 0 } },\n    e8(\"div\", { className: \"cedros-gallery-lightbox__backdrop\", onClick: props.viewer.closeOnBackdrop ? props.onClose : void 0, \"aria-hidden\": true, \"data-c1gb4l3-gallery-modal-backdrop\": true }),\n    e8(\n      motion2.div,\n      { animate: { opacity: 1, scale: 1, y: 0 }, className: `cedros-gallery-lightbox__panel cedros-gallery-lightbox__panel--${layoutClass(props.viewer.mode)}${props.viewer.fullscreen ? \" is-fullscreen\" : \"\"}`, exit: enter, initial: enter, ref: panelRef, role: \"dialog\", \"aria-modal\": \"true\", \"aria-label\": props.item.title || \"Gallery image\", tabIndex: -1, transition: props.reducedMotion ? { duration: 0.12 } : galleryPanelSpring },\n      e8(\n        \"button\",\n        { className: \"cedros-gallery-icon-button cedros-gallery-lightbox__close\", onClick: props.onClose, type: \"button\", \"aria-label\": \"Close\", title: \"Close viewer\" },\n        e8(\n          \"svg\",\n          { \"aria-hidden\": true, fill: \"none\", height: 16, stroke: \"currentColor\", strokeLinecap: \"round\", strokeLinejoin: \"round\", strokeWidth: 2, viewBox: \"0 0 24 24\", width: 16 },\n          e8(\"path\", { d: \"M18 6 6 18\" }),\n          e8(\"path\", { d: \"m6 6 12 12\" })\n        )\n      ),\n      e8(GalleryLightboxMedia, {\n        direction: props.direction,\n        item: props.item,\n        onNext: props.onNext,\n        onUnavailable: onMediaUnavailable,\n        pan: props.viewer.pan,\n        onPrevious: props.onPrevious,\n        reducedMotion: props.reducedMotion,\n        swipe: props.swipe,\n        zoomed: zoomed && !mediaUnavailable\n      }),\n      e8(\n        \"aside\",\n        { className: \"cedros-gallery-lightbox__details\" },\n        e8(\"h2\", { className: \"cedros-gallery-lightbox__identity\" }, props.item.title || \"Untitled image\"),\n        e8(\n          \"div\",\n          { className: \"cedros-gallery-lightbox__toolbar\" },\n          props.viewer.counter && e8(\"p\", { className: \"cedros-gallery-lightbox__counter\" }, `${activeIndex + 1} / ${props.items.length}`),\n          e8(\n            \"div\",\n            { className: \"cedros-gallery-lightbox__nav\" },\n            e8(\"button\", { className: \"cedros-gallery-button cedros-gallery-button--ghost\", disabled: props.items.length <= 1, onClick: props.onPrevious, type: \"button\" }, \"Previous\"),\n            e8(\"button\", { className: \"cedros-gallery-button cedros-gallery-button--ghost\", disabled: props.items.length <= 1, onClick: props.onNext, type: \"button\" }, \"Next\")\n          )\n        ),\n        props.viewer.caption && captionText(props.item) && e8(GalleryCardCaption, { key: props.item.id, text: captionText(props.item) }),\n        e8(BadgeList, { item: props.item }),\n        props.proofing.enabled && (props.proofing.selections || props.proofing.favorites) && e8(\n          \"div\",\n          { className: \"cedros-gallery-lightbox__nav\" },\n          props.proofing.selections && e8(\"button\", { \"aria-pressed\": props.selected, className: activeButton(props.selected), disabled: props.proofing.disabled, onClick: props.onSelect, type: \"button\" }, props.selected ? \"Selected\" : \"Select\"),\n          props.proofing.favorites && e8(\"button\", { \"aria-pressed\": props.favorite, className: `${activeButton(props.favorite)} cedros-gallery-button--quiet`, disabled: props.proofing.disabled, onClick: props.onFavorite, type: \"button\" }, props.favorite ? \"Favorited\" : \"Favorite\")\n        ),\n        props.proofing.enabled && props.proofing.comments && e8(\n          \"label\",\n          { className: \"cedros-gallery-field cedros-gallery-field--comment\" },\n          e8(\"span\", null, \"Comment\"),\n          e8(\"textarea\", { disabled: props.proofing.disabled, maxLength: 2e3, value: props.comments[props.item.id] ?? \"\", onChange: (event) => props.onComment(event.currentTarget.value), rows: 4 })\n        ),\n        (props.viewer.productCta || props.handoff?.cta.visible) && e8(CommerceLink, { galleryId: props.galleryId, handoff: props.handoff, item: props.item }),\n        e8(\n          \"div\",\n          { className: \"cedros-gallery-lightbox__nav cedros-gallery-lightbox__utilities\" },\n          downloadLink(props.item, props.view),\n          props.viewer.zoom && !mediaUnavailable && buildGalleryImageAttributes(props.item, void 0, \"eager\", true) && e8(\"button\", { \"aria-pressed\": zoomed, className: \"cedros-gallery-button cedros-gallery-button--ghost\", onClick: () => setZoomed((current) => !current), type: \"button\" }, zoomed ? \"Reset zoom\" : \"Zoom\"),\n          props.viewer.share && e8(\"button\", {\n            className: \"cedros-gallery-button cedros-gallery-button--ghost\",\n            onClick: () => void shareGalleryItem(props.galleryId, props.item).then((result) => setShareStatus(result)),\n            type: \"button\"\n          }, \"Share\")\n        ),\n        shareStatus && e8(\"p\", { role: \"status\" }, shareStatus),\n        props.viewer.metadata && e8(GalleryMetadata, { item: props.item })\n      ),\n      props.viewer.thumbnailStrip && e8(\"div\", {\n        className: `cedros-gallery-lightbox__thumbnails${thumbnailEdges.atStart ? \" is-at-start\" : \"\"}${thumbnailEdges.atEnd ? \" is-at-end\" : \"\"}`,\n        onScroll: thumbnailEdges.sync,\n        onWheel: (event) => thumbnailEdge.resistWheel(event, \"x\"),\n        ref: thumbnailsRef\n      }, e8(\n        motion2.div,\n        {\n          \"aria-label\": \"Gallery thumbnails\",\n          className: \"cedros-gallery-lightbox__thumbnail-track\",\n          role: \"list\",\n          style: { x: thumbnailEdge.pull }\n        },\n        props.items.map((item, index) => e8(\"div\", { key: item.id, role: \"listitem\" }, e8(\"button\", {\n          \"aria-current\": index === activeIndex ? \"true\" : void 0,\n          \"aria-label\": `Show ${item.title || \"Untitled image\"}`,\n          className: \"cedros-gallery-lightbox__thumbnail\",\n          onClick: () => props.onSelectItem(index),\n          type: \"button\"\n        }, e8(MediaPreview, { item }))))\n      ))\n    )\n  );\n}\nfunction GalleryLightboxMedia(props) {\n  const dragX = useMotionValue(0);\n  const velocity = useVelocity(dragX);\n  const stretch = useTransform(velocity, (value) => velocityStretchScale(value));\n  const blur = useTransform(velocity, (value) => velocityBlurFilter(value));\n  const axisVariants = props.reducedMotion || props.direction === 0 ? fadeAxisVariants : sharedAxisVariants;\n  return e8(\n    \"div\",\n    { className: \"cedros-gallery-lightbox__media\" },\n    e8(\n      AnimatePresence,\n      { custom: props.direction, initial: false, mode: \"sync\" },\n      e8(motion2.div, {\n        animate: \"center\",\n        className: \"cedros-gallery-lightbox__media-step\",\n        custom: props.direction,\n        exit: \"exit\",\n        initial: \"enter\",\n        key: props.item.id,\n        transition: props.reducedMotion ? { duration: 0.1 } : galleryInteractionSpring,\n        variants: axisVariants\n      }, e8(motion2.div, {\n        animate: { scale: props.zoomed ? 1.8 : 1 },\n        className: props.zoomed ? \"is-zoomed\" : void 0,\n        drag: props.zoomed && props.pan ? true : props.swipe && !props.reducedMotion ? \"x\" : false,\n        dragConstraints: props.zoomed ? { bottom: 180, left: -240, right: 240, top: -180 } : { left: 0, right: 0 },\n        dragElastic: props.zoomed ? 0.05 : 0.08,\n        dragMomentum: false,\n        onDragEnd: (_event, info2) => {\n          if (props.zoomed) return;\n          if (info2.offset.x < -56 || info2.velocity.x < -600) props.onNext();\n          if (info2.offset.x > 56 || info2.velocity.x > 600) props.onPrevious();\n        },\n        style: props.reducedMotion ? void 0 : { filter: blur, scaleX: stretch, x: dragX },\n        transition: galleryInteractionSpring\n      }, e8(MediaPreview, { item: props.item, loading: \"eager\", fullSize: true, onUnavailable: props.onUnavailable })))\n    )\n  );\n}\nfunction GalleryMetadata({ item }) {\n  const entries = [\n    [\"Artist\", item.artist],\n    [\"Category\", item.category],\n    [\"Credit\", item.credit],\n    [\"Orientation\", item.orientation === \"unknown\" ? \"\" : item.orientation[0].toUpperCase() + item.orientation.slice(1)]\n  ].filter((entry) => Boolean(entry[1]));\n  if (!entries.length) return null;\n  return e8(\n    \"details\",\n    { className: \"cedros-gallery-lightbox__more\" },\n    e8(\"summary\", null, \"Image details\"),\n    e8(\"dl\", { className: \"cedros-gallery-lightbox__metadata\" }, entries.map(\n      ([label, value]) => e8(\"div\", { key: label }, e8(\"dt\", null, label), e8(\"dd\", null, value))\n    ))\n  );\n}\nasync function shareGalleryItem(galleryId, item) {\n  const url = safePublicHref(item.detailUrl) || (typeof location === \"undefined\" ? \"\" : location.href);\n  const data = { title: item.title || \"Untitled image\", url };\n  try {\n    if (typeof navigator !== \"undefined\" && navigator.share) {\n      await navigator.share(data);\n      void trackGalleryAnalyticsEvent({ event: \"gallery-shared\", galleryId, itemId: item.id });\n      return \"Shared.\";\n    } else if (url && typeof navigator !== \"undefined\" && navigator.clipboard?.writeText) {\n      await navigator.clipboard.writeText(url);\n      void trackGalleryAnalyticsEvent({ event: \"gallery-shared\", galleryId, itemId: item.id });\n      return \"Link copied.\";\n    } else {\n      return \"Sharing is unavailable. Copy the page URL from your browser.\";\n    }\n  } catch {\n    return \"Sharing did not complete. Try copying the page URL from your browser.\";\n  }\n}\nfunction CommerceLink({ galleryId, handoff, item }) {\n  if (!handoff?.cta.visible) return null;\n  const href = safeHref(handoff.cta.url);\n  if (!handoff.cta.enabled || !href) {\n    return e8(\"span\", { className: \"cedros-gallery-commerce cedros-gallery-commerce--disabled\" }, handoff.cta.label);\n  }\n  return e8(\"a\", {\n    className: \"cedros-gallery-commerce\",\n    href,\n    onClick: () => void trackGalleryAnalyticsEvent({\n      event: \"linked-product-clicked\",\n      galleryId,\n      itemId: item.id,\n      metadata: { action: handoff.cta.action, source: handoff.source }\n    }),\n    rel: externalRel(href),\n    target: externalTarget(href)\n  }, handoff.cta.label || item.priceLabel || \"View\");\n}\nfunction BadgeList({ item }) {\n  const badges = [\n    item.featured && \"Featured\",\n    item.accessState === \"locked\" && \"Locked\",\n    item.productStatus !== \"none\" && (item.availabilityLabel || { available: \"Available\", sold: \"Sold\", unavailable: \"Unavailable\" }[item.productStatus]),\n    item.priceLabel\n  ].filter(Boolean);\n  if (!badges.length) return null;\n  return e8(\"div\", { className: \"cedros-gallery-badges\" }, badges.map((badge) => e8(\"span\", { key: String(badge) }, badge)));\n}\nfunction downloadLink(item, view) {\n  const decision2 = buildGalleryDownloadDecision(item, view.downloadPolicy, {\n    authenticated: view.visibilityContext.authenticated\n  });\n  if (!decision2.visible) return null;\n  if (!decision2.enabled) {\n    return e8(\"span\", {\n      className: \"cedros-gallery-button cedros-gallery-button--ghost\",\n      \"aria-disabled\": true,\n      title: decision2.reason\n    }, decision2.label);\n  }\n  return e8(\"a\", {\n    className: \"cedros-gallery-button cedros-gallery-button--ghost\",\n    download: true,\n    href: decision2.href,\n    onClick: () => void reportDownload(view, item, decision2)\n  }, decision2.label);\n}\nfunction handoffsByItem(view) {\n  return new Map(view.commerceHandoffs.map((handoff) => [handoff.itemId, handoff]));\n}\nfunction loadingPlansByItem(view) {\n  return new Map(view.imageLoading.map((plan) => [plan.itemId, plan]));\n}\nfunction visibleItemsForPage(view, props, visibleCount, page) {\n  if (props.performance.pagination === \"none\") return view.items;\n  if (props.performance.pagination === \"paged\") {\n    const start = (page - 1) * props.performance.pageSize;\n    return view.items.slice(start, start + props.performance.pageSize);\n  }\n  return view.items.slice(0, visibleCount);\n}\nfunction GalleryPagination(props) {\n  if (props.mode === \"none\" || props.totalCount <= props.pageSize) return null;\n  const pageCount = Math.ceil(props.totalCount / props.pageSize);\n  if (props.mode === \"paged\") return e8(\n    \"nav\",\n    {\n      \"aria-label\": \"Gallery pagination\",\n      className: \"cedros-gallery-pagination\"\n    },\n    e8(\"button\", { className: \"cedros-gallery-button cedros-gallery-button--ghost\", disabled: props.page <= 1, onClick: props.onPrevious, type: \"button\" }, \"Previous\"),\n    e8(\"p\", null, `Page ${props.page} of ${pageCount}.`),\n    e8(\"button\", { className: \"cedros-gallery-button cedros-gallery-button--ghost\", disabled: props.page >= pageCount, onClick: props.onNext, type: \"button\" }, \"Next\")\n  );\n  if (props.renderedCount >= props.totalCount) return null;\n  return e8(\n    \"nav\",\n    { \"aria-label\": \"Gallery pagination\", className: \"cedros-gallery-pagination\" },\n    e8(\"p\", null, `Showing ${props.renderedCount} of ${props.totalCount} images.`),\n    e8(\"button\", { className: \"cedros-gallery-button\", onClick: props.onMore, type: \"button\" }, \"Load more\")\n  );\n}\nfunction idSet(items, key) {\n  return new Set(items.filter((item) => item[key]).map((item) => item.id));\n}\nfunction intersectSet(values, allowed) {\n  return new Set([...values].filter((value) => allowed.has(value)));\n}\nfunction toggleSet(values, id3) {\n  const next = new Set(values);\n  next.has(id3) ? next.delete(id3) : next.add(id3);\n  return next;\n}\nfunction adjacentId(items, index, offset) {\n  if (!items.length) return null;\n  return items[(index + offset + items.length) % items.length]?.id ?? null;\n}\nfunction captionText(item) {\n  return item.caption || item.description || item.artist || item.credit;\n}\nfunction sharedGalleryArtist(items) {\n  const artist = items[0]?.artist ?? \"\";\n  return artist && items.every((item) => item.artist === artist) ? artist : \"\";\n}\nfunction cardCaptionText(item, sharedArtist) {\n  return item.caption || item.description || (item.artist !== sharedArtist ? item.artist : \"\") || item.credit;\n}\nfunction activeButton(active) {\n  return `cedros-gallery-button ${active ? \"cedros-gallery-button--active\" : \"cedros-gallery-button--ghost\"}`;\n}\nfunction layoutClass(layout2) {\n  return layout2.replace(/[^a-z0-9-]/gi, \"-\");\n}\nfunction hoverTarget(effect) {\n  if (effect === \"lift\") return { y: -5 };\n  if (effect === \"zoom\") return { scale: 1.015 };\n  if (effect === \"tilt\") return { rotate: -0.75, scale: 1.01 };\n  return void 0;\n}\nfunction safeHref(input) {\n  if (!input) return \"\";\n  if (input.startsWith(\"/\") || input.startsWith(\"#\")) return input;\n  try {\n    const url = new URL(input);\n    return url.protocol === \"http:\" || url.protocol === \"https:\" || url.protocol === \"mailto:\" ? input : \"\";\n  } catch {\n    return \"\";\n  }\n}\nfunction externalTarget(href) {\n  return href.startsWith(\"http\") ? \"_blank\" : void 0;\n}\nfunction externalRel(href) {\n  return href.startsWith(\"http\") ? \"noreferrer\" : void 0;\n}\nfunction recordValue(input) {\n  return typeof input === \"object\" && input !== null && !Array.isArray(input) ? input : {};\n}\n\n// src/web/submission-form.ts\nimport React16 from \"react\";\n\n// src/labeled-field.ts\nimport React15 from \"react\";\nfunction LabeledField(props) {\n  const generatedId = React15.useId();\n  const id3 = props.control.props.id || generatedId;\n  const labelId = `${id3}-label`;\n  const helpId = `${id3}-help`;\n  const description = [props.control.props[\"aria-describedby\"], props.help ? helpId : \"\"].filter(Boolean).join(\" \");\n  return React15.createElement(\n    \"label\",\n    { className: props.className, htmlFor: id3 },\n    React15.createElement(\"span\", { className: props.labelClassName, id: labelId }, props.label),\n    React15.cloneElement(props.control, {\n      id: id3,\n      \"aria-labelledby\": props.control.props[\"aria-labelledby\"] || labelId,\n      \"aria-describedby\": description || void 0\n    }),\n    props.help ? React15.createElement(\"span\", { className: props.helpClassName, id: helpId }, props.help) : null\n  );\n}\n\n// src/web/submission-form.ts\nvar e9 = React16.createElement;\nvar acceptedTypes = /* @__PURE__ */ new Set([\"image/jpeg\", \"image/png\", \"image/webp\", \"image/gif\"]);\nvar maxSubmissionBytes = 1e6;\nfunction submissionImageError(file) {\n  if (!acceptedTypes.has(file.type)) return \"Use a JPEG, PNG, WebP, or GIF image.\";\n  if (file.size === 0) return \"The selected image is empty.\";\n  if (file.size > maxSubmissionBytes) return \"Images must be 1 MB or smaller.\";\n  return \"\";\n}\nfunction SubmissionFormBlockView({ props = {} }) {\n  return e9(SubmissionForm, { key: stringValue15(props.galleryId), props });\n}\nfunction SubmissionForm({ props = {} }) {\n  const formId = React16.useId();\n  const title = stringValue15(props.title) || \"Submit your image\";\n  const description = stringValue15(props.description) || \"Upload one image for private review. A Cedros account is required.\";\n  const galleryId = stringValue15(props.galleryId);\n  const [state, setState] = React16.useState({ kind: \"idle\", message: \"\" });\n  const [statusState, setStatusState] = React16.useState({\n    kind: \"loading\",\n    message: \"Checking your sign-in\\u2026\",\n    entries: []\n  });\n  const [nextOffset, setNextOffset] = React16.useState(null);\n  const [loadingMore, setLoadingMore] = React16.useState(false);\n  const [titleValue, setTitleValue] = React16.useState(\"\");\n  const [titleEdited, setTitleEdited] = React16.useState(false);\n  const [selectedImage, setSelectedImage] = React16.useState(null);\n  const [previewUrl, setPreviewUrl] = React16.useState(\"\");\n  const [previewFailed, setPreviewFailed] = React16.useState(false);\n  const [showNewSubmission, setShowNewSubmission] = React16.useState(true);\n  const initialHistoryLoaded = React16.useRef(false);\n  const focusNewSubmission = React16.useRef(false);\n  const fileRef = React16.useRef(null);\n  const formRef = React16.useRef(null);\n  const idempotencyRef = React16.useRef({ fingerprint: \"\", key: \"\" });\n  const statusRequestRef = React16.useRef(0);\n  const submittingRef = React16.useRef(false);\n  React16.useEffect(() => {\n    setPreviewFailed(false);\n    const urls = globalThis.window?.URL;\n    if (!selectedImage || typeof urls?.createObjectURL !== \"function\") {\n      setPreviewUrl(\"\");\n      return;\n    }\n    const url = urls.createObjectURL(selectedImage);\n    setPreviewUrl(url);\n    return () => urls.revokeObjectURL(url);\n  }, [selectedImage]);\n  React16.useEffect(() => {\n    if (statusState.kind !== \"ready\" || initialHistoryLoaded.current) return;\n    initialHistoryLoaded.current = true;\n    setShowNewSubmission(statusState.entries.length === 0);\n  }, [statusState.kind, statusState.entries.length]);\n  React16.useEffect(() => {\n    if (!showNewSubmission || statusState.kind !== \"ready\" || !focusNewSubmission.current) return;\n    focusNewSubmission.current = false;\n    formRef.current?.scrollIntoView?.({ block: \"start\" });\n    fileRef.current?.focus();\n  }, [showNewSubmission, statusState.kind]);\n  React16.useEffect(() => {\n    void loadStatuses();\n    const reloadOnFocus = () => void loadStatuses(true);\n    globalThis.addEventListener?.(\"focus\", reloadOnFocus);\n    return () => globalThis.removeEventListener?.(\"focus\", reloadOnFocus);\n  }, []);\n  React16.useEffect(() => {\n    if (statusState.kind !== \"ready\" || !statusState.entries.some((entry) => entry.status === \"pending\")) return;\n    const timer = globalThis.setInterval(() => {\n      if (globalThis.document?.visibilityState === \"hidden\") return;\n      void loadStatuses(true);\n    }, 6e4);\n    return () => globalThis.clearInterval(timer);\n  }, [statusState.kind, statusState.entries]);\n  const submissionDisabled = state.kind === \"submitting\" || statusState.kind !== \"ready\";\n  async function loadStatuses(background = false, offset = 0) {\n    const requestId = ++statusRequestRef.current;\n    setLoadingMore(offset > 0);\n    if (!background && !offset) {\n      setNextOffset(null);\n      setStatusState((current) => ({ ...current, kind: \"loading\", message: \"Checking your submissions\\u2026\" }));\n    }\n    try {\n      const response = await fetch(`/extensions/cedros-gallery/v1/submissions/mine${offset ? `?offset=${offset}` : \"\"}`, {\n        credentials: \"same-origin\",\n        method: \"GET\"\n      });\n      if (requestId !== statusRequestRef.current) return;\n      if (response.status === 401) {\n        setNextOffset(null);\n        return setStatusState({ kind: \"auth\", message: \"Sign in to check your submissions.\", entries: [] });\n      }\n      if (response.status === 403) {\n        setNextOffset(null);\n        return setStatusState({ kind: \"denied\", message: \"This account cannot access image submissions. Contact the site team or refresh after access is restored.\", entries: [] });\n      }\n      const payload = await response.json().catch(() => ({}));\n      if (requestId !== statusRequestRef.current) return;\n      if (!response.ok || !isRecord4(payload) || payload.ok !== true || !Array.isArray(payload.entries)) {\n        return setStatusState((current) => (background || offset > 0) && current.kind === \"ready\" ? { ...current, message: \"Status could not be refreshed. Use Refresh status to try again.\" } : { kind: \"error\", message: \"Your submission status could not be loaded. Please try again.\", entries: [] });\n      }\n      const page = isRecord4(payload.page) ? payload.page : {};\n      if (page.hasMore === true && (!Number.isSafeInteger(page.nextOffset) || Number(page.nextOffset) <= offset)) {\n        throw new Error(\"Invalid history pagination\");\n      }\n      setNextOffset(page.hasMore === true ? Number(page.nextOffset) : null);\n      const incoming = normalizeOwnedSubmissions(payload);\n      setStatusState((current) => ({ kind: \"ready\", message: \"\", entries: offset ? [...new Map([...current.entries, ...incoming].map((entry) => [entry.id, entry])).values()] : incoming }));\n    } catch {\n      if (requestId !== statusRequestRef.current) return;\n      setStatusState((current) => (background || offset > 0) && current.kind === \"ready\" ? { ...current, message: \"Status could not be refreshed. Use Refresh status to try again.\" } : { kind: \"error\", message: \"The Gallery service could not be reached. Please retry.\", entries: [] });\n    } finally {\n      if (requestId === statusRequestRef.current) setLoadingMore(false);\n    }\n  }\n  async function submit2(event) {\n    event.preventDefault();\n    if (submittingRef.current || submissionDisabled || !showNewSubmission) return;\n    const form = event.currentTarget;\n    const fields = new FormData(form);\n    const file = fileRef.current?.files?.[0];\n    if (!file) return setState({ kind: \"error\", message: \"Choose an image to submit.\" });\n    const imageError = submissionImageError(file);\n    if (imageError) return setState({ kind: \"error\", message: imageError });\n    const titleValue2 = stringValue15(fields.get(\"title\"));\n    const altText = stringValue15(fields.get(\"altText\"));\n    if (!titleValue2 || !altText) {\n      return setState({ kind: \"error\", message: \"Title and alt text are required.\" });\n    }\n    const caption = stringValue15(fields.get(\"caption\"));\n    const generation = Object.fromEntries(\n      [\"prompt\", \"provider\", \"model\", \"negativePrompt\", \"seed\", \"promptVersion\"].map((key) => [key, stringValue15(fields.get(`generation.${key}`))]).filter(([, value]) => value)\n    );\n    const hasGeneration = Object.keys(generation).length > 0;\n    if (hasGeneration && (!generation.prompt || !generation.provider || !generation.model)) {\n      return setState({ kind: \"error\", message: \"For an AI-generated image, include the prompt, provider, and model.\" });\n    }\n    const fingerprint = JSON.stringify([\n      file.name,\n      file.size,\n      file.lastModified,\n      file.type,\n      titleValue2,\n      altText,\n      caption,\n      galleryId,\n      generation\n    ]);\n    if (idempotencyRef.current.fingerprint !== fingerprint) {\n      idempotencyRef.current = { fingerprint, key: newIdempotencyKey() };\n    }\n    submittingRef.current = true;\n    setState({ kind: \"submitting\", message: \"Uploading your image\\u2026\" });\n    try {\n      const response = await fetch(\"/extensions/cedros-gallery/v1/submissions\", {\n        body: JSON.stringify({\n          idempotencyKey: idempotencyRef.current.key,\n          title: titleValue2,\n          altText,\n          caption,\n          fileName: file.name,\n          contentType: file.type,\n          contentBase64: await fileBase64(file),\n          ...hasGeneration ? { generation } : {},\n          ...galleryId ? { galleryId } : {}\n        }),\n        credentials: \"same-origin\",\n        headers: { \"content-type\": \"application/json\" },\n        method: \"POST\"\n      });\n      const payload = await response.json().catch(() => ({}));\n      if (response.status === 401) {\n        statusRequestRef.current += 1;\n        setLoadingMore(false);\n        setNextOffset(null);\n        setStatusState({ kind: \"auth\", message: \"Sign in to submit and check your submissions.\", entries: [] });\n        return setState({ kind: \"auth\", message: \"Sign in to submit an image.\" });\n      }\n      if (response.status === 403) {\n        statusRequestRef.current += 1;\n        setLoadingMore(false);\n        setNextOffset(null);\n        setStatusState({ kind: \"denied\", message: \"This account cannot access image submissions. Contact the site team or refresh after access is restored.\", entries: [] });\n        return setState({ kind: \"error\", message: \"This account cannot submit images here. Your image and details have been kept.\" });\n      }\n      if (!response.ok || payload.ok !== true || !stringValue15(payload.submission?.id)) {\n        return setState({\n          kind: \"error\",\n          message: payload.error || \"Your image could not be submitted. Please try again.\"\n        });\n      }\n      form.reset();\n      setTitleValue(\"\");\n      setTitleEdited(false);\n      setSelectedImage(null);\n      setShowNewSubmission(false);\n      idempotencyRef.current = { fingerprint: \"\", key: \"\" };\n      setState({\n        kind: \"success\",\n        message: payload.submission?.id ? `Submitted for review. Track the decision in Your submissions. Reference: ${payload.submission.id}` : \"Submitted for review. Track the decision in Your submissions.\"\n      });\n      void loadStatuses();\n    } catch {\n      setState({ kind: \"error\", message: \"The Gallery service could not be reached. Please retry.\" });\n    } finally {\n      submittingRef.current = false;\n    }\n  }\n  return e9(\n    \"section\",\n    {\n      className: `cedros-gallery-block cedros-gallery-submission${statusState.entries.length > 0 ? \" cedros-gallery-submission--returning\" : \"\"}`,\n      \"data-extension-id\": \"cedros-gallery\"\n    },\n    e9(\n      \"header\",\n      { className: \"cedros-gallery-header\" },\n      e9(\n        \"div\",\n        null,\n        e9(\"h2\", { className: \"cedros-gallery-heading\" }, title),\n        e9(\"p\", { className: \"cedros-gallery-description\" }, description)\n      ),\n      statusState.kind === \"ready\" && (statusState.entries.length > 0 || !showNewSubmission) && e9(\"button\", {\n        className: `cedros-gallery-button${showNewSubmission ? \" cedros-gallery-button--ghost\" : \"\"}`,\n        disabled: state.kind === \"submitting\",\n        onClick: () => {\n          focusNewSubmission.current = !showNewSubmission;\n          setShowNewSubmission((open) => !open);\n        },\n        type: \"button\",\n        \"aria-expanded\": showNewSubmission,\n        \"aria-controls\": formId\n      }, showNewSubmission ? \"Back to submissions\" : selectedImage ? \"Continue submission\" : \"New submission\")\n    ),\n    state.kind === \"success\" && e9(\"p\", {\n      className: \"cedros-gallery-submission__status cedros-gallery-submission__status--success\",\n      role: \"status\"\n    }, state.message),\n    statusState.kind !== \"ready\" && e9(\n      \"div\",\n      { className: \"cedros-gallery-submission__access\", role: statusState.kind === \"denied\" || statusState.kind === \"error\" ? \"alert\" : \"status\" },\n      e9(\"strong\", null, statusState.kind === \"auth\" ? \"Sign in to submit an image\" : statusState.kind === \"denied\" ? \"Image submissions are unavailable for this account\" : statusState.kind === \"error\" ? \"Submission access could not be checked\" : \"Checking submission access\\u2026\"),\n      e9(\"p\", null, statusState.message),\n      statusState.kind === \"auth\" ? e9(\"a\", { className: \"cedros-gallery-button\", href: gallerySignInHref() }, \"Sign in to submit\") : null,\n      statusState.kind === \"denied\" || statusState.kind === \"error\" ? e9(\"button\", { className: \"cedros-gallery-button cedros-gallery-button--ghost\", type: \"button\", onClick: () => void loadStatuses() }, \"Check access again\") : null\n    ),\n    statusState.kind === \"ready\" && statusState.entries.length > 0 && !showNewSubmission && e9(SubmissionStatusPanel, { onLoad: () => void loadStatuses(), state: statusState }),\n    e9(\n      \"form\",\n      {\n        \"aria-busy\": state.kind === \"submitting\",\n        className: \"cedros-gallery-submission__form\",\n        hidden: statusState.kind !== \"ready\" || !showNewSubmission,\n        id: formId,\n        onSubmit: submit2,\n        ref: formRef\n      },\n      e9(\n        \"fieldset\",\n        { disabled: submissionDisabled || !showNewSubmission },\n        field(\"Image\", e9(\"input\", {\n          accept: \"image/jpeg,image/png,image/webp,image/gif\",\n          name: \"image\",\n          onChange: (event) => {\n            const file = event.currentTarget.files?.[0];\n            const message = file ? submissionImageError(file) : \"\";\n            setSelectedImage(file && !message ? file : null);\n            setState({ kind: message ? \"error\" : \"idle\", message });\n            if (file && (!titleEdited || !titleValue.trim())) {\n              setTitleValue(titleFromFileName(file.name));\n              setTitleEdited(false);\n            }\n          },\n          ref: fileRef,\n          required: true,\n          type: \"file\"\n        }), \"JPEG, PNG, WebP, or GIF. Maximum 1 MB.\", \"cedros-gallery-field--upload\"),\n        selectedImage && e9(\n          \"figure\",\n          { className: \"cedros-gallery-submission__image-preview\" },\n          previewUrl && !previewFailed ? e9(\"img\", {\n            alt: \"Selected image preview\",\n            onError: () => setPreviewFailed(true),\n            src: previewUrl\n          }) : e9(\"p\", null, previewFailed ? \"This image could not be previewed. Check the file before submitting.\" : \"Your image is selected.\"),\n          e9(\n            \"figcaption\",\n            null,\n            selectedImage.name,\n            \" \\xB7 \",\n            new Intl.NumberFormat(void 0, { style: \"unit\", unit: selectedImage.size < 1e3 ? \"byte\" : \"kilobyte\", maximumFractionDigits: 1 }).format(selectedImage.size < 1e3 ? selectedImage.size : selectedImage.size / 1e3)\n          )\n        ),\n        field(\"Title\", e9(\"input\", {\n          maxLength: 160,\n          name: \"title\",\n          onChange: (event) => {\n            setTitleValue(event.currentTarget.value);\n            setTitleEdited(true);\n          },\n          type: \"text\",\n          required: true,\n          value: titleValue\n        }), \"Filled from the filename. Edit it if a clearer title will help the review team.\"),\n        field(\n          \"Alt text\",\n          e9(\"textarea\", { maxLength: 500, name: \"altText\", required: true, rows: 3 }),\n          \"Describe the image for people who cannot see it.\"\n        ),\n        e9(\n          \"details\",\n          { className: \"cedros-gallery-submission__caption\" },\n          e9(\"summary\", null, \"Add a caption (optional)\"),\n          field(\"Caption (optional)\", e9(\"textarea\", { maxLength: 2e3, name: \"caption\", rows: 4 }))\n        ),\n        e9(\n          \"details\",\n          { className: \"cedros-gallery-submission__caption\" },\n          e9(\"summary\", null, \"AI generation details (optional)\"),\n          e9(\"p\", null, \"Include these details for generated images. They stay with the private submission for review; do not include secrets or personal information.\"),\n          field(\"Generation prompt\", e9(\"textarea\", { maxLength: 12e3, name: \"generation.prompt\", rows: 6 })),\n          field(\"Generation provider\", e9(\"input\", { maxLength: 80, name: \"generation.provider\", type: \"text\" })),\n          field(\"Generation model\", e9(\"input\", { maxLength: 160, name: \"generation.model\", type: \"text\" })),\n          field(\"Negative prompt (optional)\", e9(\"textarea\", { maxLength: 4e3, name: \"generation.negativePrompt\", rows: 3 })),\n          field(\"Seed (optional)\", e9(\"input\", { maxLength: 160, name: \"generation.seed\", type: \"text\" })),\n          field(\"Prompt version (optional)\", e9(\"input\", { maxLength: 80, name: \"generation.promptVersion\", type: \"text\" }))\n        ),\n        e9(\n          \"div\",\n          { className: \"cedros-gallery-submission__actions\" },\n          e9(\"button\", {\n            className: \"cedros-gallery-button\",\n            disabled: submissionDisabled || !selectedImage,\n            type: \"submit\"\n          }, state.kind === \"submitting\" ? \"Submitting\\u2026\" : statusState.kind === \"loading\" ? \"Checking sign-in\\u2026\" : \"Submit for review\"),\n          statusState.kind === \"ready\" && statusState.entries.length === 0 && e9(\"button\", {\n            className: \"cedros-gallery-button cedros-gallery-button--quiet\",\n            disabled: state.kind === \"submitting\",\n            onClick: () => void loadStatuses(),\n            type: \"button\"\n          }, \"Check access\")\n        )\n      ),\n      state.message && state.kind !== \"success\" ? e9(\"p\", {\n        className: `cedros-gallery-submission__status cedros-gallery-submission__status--${state.kind}`,\n        role: state.kind === \"error\" || state.kind === \"auth\" ? \"alert\" : \"status\"\n      }, state.message) : null\n    ),\n    statusState.kind === \"ready\" && statusState.entries.length > 0 && showNewSubmission && e9(SubmissionStatusPanel, { onLoad: () => void loadStatuses(), state: statusState }),\n    nextOffset !== null && e9(\"button\", {\n      type: \"button\",\n      className: \"cedros-gallery-button\",\n      disabled: loadingMore || statusState.kind === \"loading\",\n      onClick: () => {\n        if (!loadingMore) void loadStatuses(false, nextOffset);\n      }\n    }, loadingMore ? \"Loading submissions\\u2026\" : \"Load more submissions\")\n  );\n}\nfunction SubmissionStatusPanel(props) {\n  const headingId = React16.useId();\n  return e9(\n    \"section\",\n    { className: \"cedros-gallery-submission__history\", \"aria-labelledby\": headingId },\n    e9(\n      \"div\",\n      { className: \"cedros-gallery-submission__history-heading\" },\n      e9(\n        \"div\",\n        null,\n        e9(\"h3\", { id: headingId }, \"Your submissions\"),\n        e9(\"p\", null, \"Decisions and notes from the review team.\")\n      ),\n      e9(\"button\", {\n        className: \"cedros-gallery-button cedros-gallery-button--ghost\",\n        disabled: props.state.kind === \"loading\",\n        onClick: props.onLoad,\n        type: \"button\"\n      }, props.state.kind === \"loading\" ? \"Checking\\u2026\" : props.state.kind === \"ready\" ? \"Refresh status\" : \"Check status\")\n    ),\n    props.state.message ? e9(\"p\", {\n      className: `cedros-gallery-submission__status cedros-gallery-submission__status--${props.state.kind}`,\n      role: props.state.kind === \"error\" || props.state.kind === \"auth\" || props.state.kind === \"denied\" ? \"alert\" : \"status\"\n    }, props.state.message) : null,\n    props.state.kind === \"ready\" && props.state.entries.length === 0 ? e9(\"p\", { className: \"cedros-gallery-empty\" }, \"No submissions were found for this account.\") : null,\n    props.state.entries.length ? e9(\n      \"ul\",\n      { className: \"cedros-gallery-submission__history-list\" },\n      props.state.entries.map((entry) => {\n        const timeline = submissionTimeline(entry);\n        return e9(\n          \"li\",\n          {\n            className: \"cedros-gallery-submission__history-item\",\n            key: entry.id\n          },\n          e9(\n            \"div\",\n            null,\n            e9(\"strong\", null, entry.title),\n            timeline ? e9(\"span\", null, timeline) : null\n          ),\n          e9(\"span\", {\n            className: `cedros-gallery-submission__decision cedros-gallery-submission__decision--${entry.status}`\n          }, submissionStatusLabel(entry.status)),\n          entry.reviewNote ? e9(\"p\", null, entry.reviewNote) : null,\n          e9(\n            \"details\",\n            { className: \"cedros-gallery-submission__reference\" },\n            e9(\"summary\", null, \"Submission reference\"),\n            e9(\"code\", null, entry.id)\n          )\n        );\n      })\n    ) : null\n  );\n}\nfunction normalizeOwnedSubmissions(input) {\n  if (!isRecord4(input) || !Array.isArray(input.entries)) return [];\n  return input.entries.flatMap((entry) => {\n    if (!isRecord4(entry)) return [];\n    const id3 = stringValue15(entry.id);\n    const title = stringValue15(entry.title);\n    const status2 = submissionStatus(entry.status);\n    if (!id3 || !title || !status2) return [];\n    return [{\n      id: id3,\n      title,\n      status: status2,\n      createdAt: stringValue15(entry.createdAt),\n      updatedAt: stringValue15(entry.updatedAt),\n      reviewNote: stringValue15(entry.reviewNote)\n    }];\n  });\n}\nfunction submissionStatus(value) {\n  return value === \"pending\" || value === \"approved\" || value === \"rejected\" ? value : null;\n}\nfunction submissionStatusLabel(status2) {\n  if (status2 === \"approved\") return \"Approved for consideration\";\n  if (status2 === \"rejected\") return \"Not accepted\";\n  return \"Awaiting review\";\n}\nfunction submissionTimeline(entry) {\n  const submitted = formatSubmissionTimestamp(entry.createdAt);\n  const updated = entry.updatedAt && entry.updatedAt !== entry.createdAt ? formatSubmissionTimestamp(entry.updatedAt) : \"\";\n  if (entry.status === \"pending\") return submitted ? `Submitted ${submitted}` : \"\";\n  if (submitted && updated) return `Submitted ${submitted} \\xB7 Decision updated ${updated}`;\n  if (updated) return `Decision updated ${updated}`;\n  return submitted ? `Submitted ${submitted}` : \"\";\n}\nfunction formatSubmissionTimestamp(value) {\n  const timestamp = Date.parse(value);\n  if (!Number.isFinite(timestamp)) return \"\";\n  return new Intl.DateTimeFormat(void 0, {\n    dateStyle: \"medium\",\n    timeStyle: \"short\"\n  }).format(new Date(timestamp));\n}\nfunction validateSubmissionFormProps(input) {\n  const value = isRecord4(input) ? input : {};\n  const errors = [];\n  if (value.galleryId !== void 0 && typeof value.galleryId !== \"string\") {\n    errors.push(\"galleryId must be a string\");\n  } else if (typeof value.galleryId === \"string\" && value.galleryId.trim().length > 128) {\n    errors.push(\"galleryId must be 128 characters or fewer\");\n  }\n  return { valid: errors.length === 0, errors };\n}\nfunction titleFromFileName(fileName) {\n  const withoutPath = fileName.split(/[\\\\/]/).pop() ?? \"\";\n  const withoutExtension = withoutPath.replace(/\\.[^.]+$/, \"\");\n  return withoutExtension.replace(/[_-]+/g, \" \").replace(/\\s+/g, \" \").trim().slice(0, 160) || \"Untitled image\";\n}\nfunction field(label, control, help = \"\", className = \"\") {\n  return e9(LabeledField, {\n    label,\n    control,\n    help,\n    className: `cedros-gallery-field cedros-gallery-submission__field${className ? ` ${className}` : \"\"}`,\n    helpClassName: \"cedros-gallery-submission__help\"\n  });\n}\nasync function fileBase64(file) {\n  const bytes = new Uint8Array(await file.arrayBuffer());\n  let binary = \"\";\n  const chunkSize = 32768;\n  for (let offset = 0; offset < bytes.length; offset += chunkSize) {\n    binary += String.fromCharCode(...bytes.subarray(offset, offset + chunkSize));\n  }\n  return btoa(binary);\n}\nfunction newIdempotencyKey() {\n  if (typeof globalThis.crypto?.randomUUID === \"function\") {\n    return globalThis.crypto.randomUUID();\n  }\n  if (typeof globalThis.crypto?.getRandomValues === \"function\") {\n    const bytes = globalThis.crypto.getRandomValues(new Uint8Array(16));\n    return `submission-${Array.from(bytes, (byte) => byte.toString(16).padStart(2, \"0\")).join(\"\")}`;\n  }\n  return `submission-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n}\nfunction stringValue15(value) {\n  return typeof value === \"string\" ? value.trim() : \"\";\n}\nfunction isRecord4(value) {\n  return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n// src/web/register.ts\ninstallGalleryStyles();\nvar galleryDefaults = {\n  galleryId: \"\",\n  layout: \"grid\",\n  columns: 3,\n  gap: 16,\n  headingLevel: 2,\n  lightbox: true,\n  showFilters: false,\n  showCaptions: true,\n  commerceMode: \"none\",\n  sort: \"manual\",\n  filters: {\n    category: \"\",\n    tag: \"\",\n    artist: \"\",\n    orientation: \"\",\n    productStatus: \"\",\n    accessState: \"\",\n    query: \"\",\n    selectedOnly: false,\n    featuredOnly: false\n  },\n  items: [],\n  config: buildPresetGalleryConfig(\"portfolio\"),\n  presentation: normalizeGalleryPresentation({ layout: \"grid\" })\n};\nvar contentBlocks = [\n  {\n    type: \"cedros-gallery:gallery\",\n    displayName: \"Gallery\",\n    category: \"media\",\n    defaultProps: galleryDefaults,\n    Component: GalleryBlockView,\n    validateProps: validateGalleryBlockProps,\n    preview: { layout: \"grid\", items: 6 }\n  },\n  {\n    type: \"cedros-gallery:album\",\n    displayName: \"Gallery Album\",\n    category: \"media\",\n    defaultProps: {\n      albumId: \"\",\n      title: \"\",\n      description: \"\",\n      headingLevel: 2,\n      layout: \"grid\",\n      showCounts: true,\n      showDescription: false,\n      galleries: [],\n      childAlbums: []\n    },\n    Component: AlbumBlockView,\n    validateProps: validateAlbumBlockProps,\n    preview: { layout: \"album-grid\", items: 4 }\n  },\n  {\n    type: \"cedros-gallery:before-after\",\n    displayName: \"Before / After\",\n    category: \"media\",\n    defaultProps: {\n      beforeMediaId: \"\",\n      afterMediaId: \"\",\n      beforeLabel: \"Before\",\n      afterLabel: \"After\",\n      orientation: \"horizontal\",\n      sliderPosition: 50,\n      showLabels: true,\n      beforeImageUrl: \"\",\n      afterImageUrl: \"\",\n      title: \"\",\n      description: \"\",\n      headingLevel: 2,\n      visibility: { mode: \"public\" }\n    },\n    Component: BeforeAfterBlockView,\n    validateProps: validateBeforeAfterProps,\n    preview: { layout: \"comparison\" }\n  },\n  {\n    type: \"cedros-gallery:submission-form\",\n    displayName: \"Image Submission Form\",\n    category: \"forms\",\n    defaultProps: {\n      title: \"Submit your image\",\n      description: \"Upload one image for private review. A Cedros account is required.\",\n      galleryId: \"\"\n    },\n    Component: SubmissionFormBlockView,\n    validateProps: validateSubmissionFormProps,\n    preview: { layout: \"form\", items: 1 }\n  }\n];\nvar contentBlockRenderers = contentBlocks.map((block) => {\n  const Component3 = block.Component;\n  return {\n    type: block.type,\n    render: (input) => React17.createElement(Component3, { props: input.block?.props ?? input.props })\n  };\n});\nfunction registerCedrosWebSurface() {\n  installGalleryStyles();\n  return {\n    ...extensionBootstrap,\n    contentBlocks,\n    contentBlockRenderers,\n    contentTemplates: generatedContentTemplates\n  };\n}\nvar register_default = registerCedrosWebSurface;\nexport {\n  register_default as default,\n  registerCedrosWebSurface\n};\n","imports":[{"dynamic":false,"end":49,"specifier":"react","start":44},{"dynamic":false,"end":163695,"specifier":"react","start":163690},{"dynamic":false,"end":163836,"specifier":"react/jsx-runtime","start":163819},{"dynamic":false,"end":163937,"specifier":"react","start":163932},{"dynamic":false,"end":164052,"specifier":"react","start":164047},{"dynamic":false,"end":164196,"specifier":"react","start":164191},{"dynamic":false,"end":164466,"specifier":"react","start":164461},{"dynamic":false,"end":164868,"specifier":"react/jsx-runtime","start":164851},{"dynamic":false,"end":164901,"specifier":"react","start":164896},{"dynamic":false,"end":164970,"specifier":"react","start":164965},{"dynamic":false,"end":165100,"specifier":"react","start":165095},{"dynamic":false,"end":165286,"specifier":"react/jsx-runtime","start":165269},{"dynamic":false,"end":397158,"specifier":"react","start":397153},{"dynamic":false,"end":397240,"specifier":"react","start":397235},{"dynamic":false,"end":397374,"specifier":"react","start":397369},{"dynamic":false,"end":397601,"specifier":"react","start":397596},{"dynamic":false,"end":403437,"specifier":"react","start":403432},{"dynamic":false,"end":404088,"specifier":"react","start":404083},{"dynamic":false,"end":407844,"specifier":"react","start":407839},{"dynamic":false,"end":411394,"specifier":"react/jsx-runtime","start":411377},{"dynamic":false,"end":411457,"specifier":"react","start":411452},{"dynamic":false,"end":411591,"specifier":"react","start":411586},{"dynamic":false,"end":411797,"specifier":"react","start":411792},{"dynamic":false,"end":412835,"specifier":"react","start":412830},{"dynamic":false,"end":412951,"specifier":"react","start":412946},{"dynamic":false,"end":414592,"specifier":"react","start":414587},{"dynamic":false,"end":417408,"specifier":"react","start":417403},{"dynamic":false,"end":420561,"specifier":"react","start":420556},{"dynamic":false,"end":421698,"specifier":"react","start":421693},{"dynamic":false,"end":421837,"specifier":"react","start":421832},{"dynamic":false,"end":430477,"specifier":"react","start":430472},{"dynamic":false,"end":463138,"specifier":"react/jsx-runtime","start":463121},{"dynamic":false,"end":463214,"specifier":"react","start":463209},{"dynamic":false,"end":473599,"specifier":"react","start":473594},{"dynamic":false,"end":473909,"specifier":"react","start":473904},{"dynamic":false,"end":477551,"specifier":"react","start":477546},{"dynamic":false,"end":493913,"specifier":"react","start":493908},{"dynamic":false,"end":497330,"specifier":"react","start":497325},{"dynamic":false,"end":498343,"specifier":"react","start":498338},{"dynamic":false,"end":510832,"specifier":"react","start":510827},{"dynamic":false,"end":510892,"specifier":"react","start":510887},{"dynamic":false,"end":518485,"specifier":"react","start":518480},{"dynamic":false,"end":518538,"specifier":"react","start":518533},{"dynamic":false,"end":526386,"specifier":"react","start":526381},{"dynamic":false,"end":542799,"specifier":"react","start":542794},{"dynamic":false,"end":548333,"specifier":"react","start":548328},{"dynamic":false,"end":614333,"specifier":"react","start":614328},{"dynamic":false,"end":614387,"specifier":"react","start":614382}],"hasUnsupportedDynamicImports":false},{"path":"workspace/react/dist/web/styles.css","kind":"style","text":".cedros-gallery-block {\n\n      --c1gb4l3-gallery-stage: #0a0a0a;\n      --c1gb4l3-gallery-radius-control: 6px;\n      --c1gb4l3-gallery-radius-card: 8px;\n      --c1gb4l3-gallery-radius-panel: 12px;\n      box-sizing: border-box;\n      color: var(--c1gb4l3-runtime-text, inherit);\n      display: grid;\n      gap: 24px;\n      max-width: 100%;\n      min-width: 0;\n      container-type: inline-size;\n      overflow-wrap: anywhere;\n    }\n    .cedros-gallery-block [hidden],\n    .cedros-gallery-album [hidden] { display: none; }\n    .cedros-gallery-block *,\n    .cedros-gallery-album *,\n    .cedros-gallery-comparison * {\n      box-sizing: border-box;\n      min-width: 0;\n    }\n    .cedros-gallery-header {\n      align-items: end;\n      display: flex;\n      gap: 16px;\n      justify-content: space-between;\n    }\n    .cedros-gallery-collection-context {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      font-size: .875rem;\n      margin: 8px 0 0;\n    }\n    .cedros-gallery-title-button {\n      background: transparent;\n      border: 0;\n      color: inherit;\n      cursor: pointer;\n      font: inherit;\n      padding: 0;\n      text-align: start;\n    }\n    .cedros-gallery-title-button:hover { text-decoration: underline; text-underline-offset: .2em; }\n    .cedros-gallery-submission__image-preview {\n      background: var(--c1gb4l3-runtime-bg, transparent);\n      border: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      border-radius: var(--c1gb4l3-gallery-radius-card, 8px);\n      margin: 0;\n      overflow: hidden;\n    }\n    .cedros-gallery-submission__image-preview img {\n      display: block;\n      height: min(36vh, 280px);\n      object-fit: contain;\n      width: 100%;\n    }\n    .cedros-gallery-submission__image-preview figcaption,\n    .cedros-gallery-submission__image-preview > p {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      font-size: .8125rem;\n      margin: 0;\n      overflow-wrap: anywhere;\n      padding: 12px;\n    }\n    .cedros-gallery-submission__caption summary {\n      cursor: pointer;\n      min-height: 44px;\n      padding-block: 12px;\n    }\n    .cedros-gallery-submission__caption summary:focus-visible {\n      outline: 2px solid var(--c1gb4l3-runtime-accent, currentColor);\n      outline-offset: 4px;\n    }\n    .cedros-gallery-submission--returning > .cedros-gallery-submission__history {\n      border-top: 0;\n      margin-top: 0;\n      padding-top: 0;\n    }\n    .cedros-gallery-submission > .cedros-gallery-header > .cedros-gallery-button {\n      align-self: flex-start;\n      flex-shrink: 0;\n    }\n    .cedros-gallery-submission > .cedros-gallery-header {\n      align-items: flex-start;\n      flex-direction: row;\n      flex-wrap: wrap;\n    }\n    .cedros-gallery-submission > .cedros-gallery-header > div { flex: 1 1 320px; }\n    .cedros-gallery-field--upload input[type=\"file\"] {\n      background: var(--c1gb4l3-runtime-panel, transparent);\n      padding: 12px;\n    }\n    .cedros-gallery-field--upload input::file-selector-button {\n      background: var(--c1gb4l3-runtime-bg, #fff);\n      border: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      border-radius: var(--c1gb4l3-gallery-radius-control, 6px);\n      color: var(--c1gb4l3-runtime-text, #111);\n      cursor: pointer;\n      font: inherit;\n      margin-inline-end: 12px;\n      min-height: 44px;\n      padding: 8px 12px;\n    }\n    .cedros-gallery-field--upload input::file-selector-button:hover { background: var(--c1gb4l3-runtime-accent-soft, transparent); }\n    .cedros-gallery-title-button:focus-visible {\n      outline: 2px solid var(--c1gb4l3-runtime-accent, currentColor);\n      outline-offset: 4px;\n      border-radius: var(--c1gb4l3-gallery-radius-control, 6px);\n    }\n    .cedros-gallery-block--proofing > .cedros-gallery-proofing {\n      position: sticky;\n      top: 12px;\n      z-index: 2;\n    }\n    .cedros-gallery-block--proofing > .cedros-gallery-proofing--static { position: static; }\n    .cedros-gallery-proofing,\n    .cedros-gallery-proofing__confirm { scroll-margin-block-start: 16px; }\n    @media (max-height: 480px) {\n      .cedros-gallery-block--proofing > .cedros-gallery-proofing { position: static; }\n    }\n    .cedros-gallery-heading {\n      font: inherit;\n      font-size: 1.5rem;\n      font-weight: 700;\n      line-height: 1.25;\n      margin: 0;\n    }\n    .cedros-gallery-kicker {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      font-size: .8125rem;\n      font-weight: 600;\n      letter-spacing: 0;\n      margin: 0 0 8px;\n      text-transform: none;\n    }\n    .cedros-gallery-description {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      margin: 8px 0 0;\n      max-width: 70ch;\n    }\n    .cedros-gallery-stats {\n      display: flex;\n      flex-wrap: wrap;\n      gap: 12px;\n      justify-content: flex-end;\n      margin: 0;\n    }\n    .cedros-gallery-stats div,\n    .cedros-gallery-access,\n    .cedros-gallery-proofing,\n    .cedros-gallery-toolbar {\n      border: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      background: var(--c1gb4l3-runtime-panel, transparent);\n      border-radius: var(--c1gb4l3-gallery-radius-control, 6px);\n    }\n    .cedros-gallery-stats div {\n      min-width: 88px;\n      padding: 8px 12px;\n    }\n    .cedros-gallery-stats dt {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      font-size: .75rem;\n      margin: 0;\n    }\n    .cedros-gallery-stats dd {\n      font-weight: 700;\n      margin: 4px 0 0;\n    }\n    .cedros-gallery-toolbar {\n      border: 0;\n      background: transparent;\n      display: grid;\n      gap: 0;\n      padding: 0;\n    }\n    .cedros-gallery-toolbar__primary,\n    .cedros-gallery-toolbar__advanced {\n      align-items: end;\n      display: flex;\n      flex-wrap: wrap;\n      gap: 12px;\n    }\n    .cedros-gallery-toolbar__primary > .cedros-gallery-field {\n      flex: 0 1 180px;\n    }\n    .cedros-gallery-toolbar__primary > .cedros-gallery-field--search {\n      flex: 1 1 240px;\n    }\n    .cedros-gallery-toolbar__disclosure {\n      display: grid;\n      grid-template-rows: 0fr;\n      transition: grid-template-rows var(--motion-duration-standard, 220ms) var(--motion-ease-standard, cubic-bezier(0.16, 1, 0.3, 1));\n    }\n    .cedros-gallery-toolbar.is-expanded .cedros-gallery-toolbar__disclosure {\n      grid-template-rows: 1fr;\n    }\n    .cedros-gallery-toolbar__advanced {\n      min-height: 0;\n      overflow: hidden;\n    }\n    .cedros-gallery-toolbar.is-expanded .cedros-gallery-toolbar__advanced {\n      padding-top: 12px;\n    }\n    .cedros-gallery-toolbar .cedros-gallery-toolbar__toggle {\n      display: inline-flex;\n    }\n    .cedros-gallery-field {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      display: grid;\n      font-size: .875rem;\n      gap: 8px;\n    }\n    .cedros-gallery-field input,\n    .cedros-gallery-field select,\n    .cedros-gallery-field textarea {\n      background: var(--c1gb4l3-runtime-bg, #fff);\n      border: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      border-radius: var(--c1gb4l3-gallery-radius-control, 6px);\n      color: var(--c1gb4l3-runtime-text, #111);\n      font: inherit;\n      margin: 0;\n      min-height: 44px;\n      padding: 8px 12px;\n      width: 100%;\n    }\n    .cedros-gallery-field--comment textarea {\n      min-height: 92px;\n      resize: vertical;\n    }\n    .cedros-gallery-submission {\n      margin-inline: auto;\n      max-width: 720px;\n      width: 100%;\n    }\n    .cedros-gallery-submission__access {\n      background: var(--c1gb4l3-runtime-panel, transparent);\n      border: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      border-radius: var(--c1gb4l3-gallery-radius-control, 6px);\n      display: grid;\n      gap: 12px;\n      padding: 24px;\n    }\n    .cedros-gallery-submission__access p { margin: 0; }\n    .cedros-gallery-submission__access .cedros-gallery-button { justify-self: start; }\n    .cedros-gallery-visually-hidden {\n      clip-path: inset(50%);\n      height: 1px;\n      overflow: hidden;\n      position: absolute;\n      white-space: nowrap;\n      width: 1px;\n    }\n    .cedros-gallery-submission__form {\n      background: var(--c1gb4l3-runtime-panel, transparent);\n      border: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      border-radius: var(--c1gb4l3-gallery-radius-panel, 12px);\n      display: grid;\n      gap: 16px;\n      padding: clamp(16px, 4vw, 24px);\n    }\n    .cedros-gallery-submission__form[hidden] { display: none; }\n    .cedros-gallery-submission__form fieldset {\n      border: 0;\n      display: grid;\n      gap: 16px;\n      margin: 0;\n      min-width: 0;\n      padding: 0;\n    }\n    .cedros-gallery-submission__form fieldset:disabled {\n      opacity: .72;\n    }\n    .cedros-gallery-submission__help,\n    .cedros-gallery-submission__status {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n    }\n    .cedros-gallery-submission__field input[type=\"file\"] {\n      max-width: 100%;\n      padding-block: 7px;\n    }\n    .cedros-gallery-submission__field input[type=\"file\"]::file-selector-button {\n      background: var(--c1gb4l3-runtime-panel, transparent);\n      border: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      border-radius: var(--c1gb4l3-gallery-radius-control, 6px);\n      color: var(--c1gb4l3-runtime-text, inherit);\n      cursor: pointer;\n      font: inherit;\n      font-weight: 600;\n      margin-inline-end: 12px;\n      padding: 8px 12px;\n    }\n    .cedros-gallery-submission__actions {\n      display: flex;\n      flex-wrap: wrap;\n      gap: 12px;\n    }\n    .cedros-gallery-submission__status {\n      margin: 0;\n    }\n    .cedros-gallery-submission__status--error,\n    .cedros-gallery-submission__status--auth {\n      color: var(--c1gb4l3-runtime-error, #b42318);\n    }\n    .cedros-gallery-submission__status--success {\n      color: var(--c1gb4l3-runtime-text, inherit);\n    }\n    .cedros-gallery-submission__history {\n      border-top: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      display: grid;\n      gap: 16px;\n      margin-top: 24px;\n      padding-top: 24px;\n    }\n    .cedros-gallery-submission__history-heading {\n      align-items: start;\n      display: flex;\n      gap: 16px;\n      justify-content: space-between;\n    }\n    .cedros-gallery-submission__history-heading .cedros-gallery-button { flex: none; }\n    .cedros-gallery-submission__history-heading > div { max-width: 44ch; }\n    @container (max-width: 480px) {\n      .cedros-gallery-submission__history-heading { align-items: flex-start; flex-direction: column; }\n    }\n    @media (max-width: 480px) {\n      .cedros-gallery-submission__history-heading { align-items: flex-start; flex-direction: column; }\n    }\n    .cedros-gallery-submission__history-heading h3,\n    .cedros-gallery-submission__history-heading p {\n      margin: 0;\n    }\n    .cedros-gallery-submission__history-heading p,\n    .cedros-gallery-submission__history-item > div > span {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n    }\n    .cedros-gallery-submission__history-list {\n      display: grid;\n      gap: 0;\n      list-style: none;\n      margin: 0;\n      padding: 0;\n    }\n    .cedros-gallery-submission__history-item {\n      align-items: start;\n      border-bottom: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      display: grid;\n      gap: 8px 16px;\n      grid-template-columns: minmax(0, 1fr) auto;\n      padding: 16px 0;\n    }\n    .cedros-gallery-submission__history-item:last-child { border-bottom: 0; }\n    .cedros-gallery-submission__history-item > div > span { font-size: .8125rem; }\n    .cedros-gallery-submission__history-item > div {\n      display: grid;\n      gap: 4px;\n      overflow-wrap: anywhere;\n    }\n    .cedros-gallery-submission__history-item > p {\n      grid-column: 1 / -1;\n      margin: 0;\n    }\n    .cedros-gallery-submission__reference {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      font-size: .8125rem;\n      grid-column: 1 / -1;\n    }\n    .cedros-gallery-submission__reference summary { cursor: pointer; padding-block: 8px; }\n    .cedros-gallery-submission__reference code { display: block; overflow-wrap: anywhere; padding-block: 8px; }\n    .cedros-gallery-submission__reference summary:focus-visible {\n      outline: 2px solid var(--c1gb4l3-runtime-accent, currentColor);\n      outline-offset: 3px;\n    }\n    .cedros-gallery-submission__decision {\n      justify-self: start;\n      border: 1px solid currentColor;\n      border-radius: 999px;\n      font-size: .75rem;\n      font-weight: 700;\n      padding: 4px 8px;\n    }\n    .cedros-gallery-submission__decision--approved {\n      color: var(--c1gb4l3-runtime-text, inherit);\n    }\n    .cedros-gallery-submission__decision--rejected {\n      color: var(--c1gb4l3-runtime-error, #b42318);\n    }\n    .cedros-gallery-submission__decision--pending {\n      background: color-mix(in srgb, var(--c1gb4l3-runtime-warning, #9a6700) 12%, var(--c1gb4l3-runtime-panel, #fff));\n      border-color: var(--c1gb4l3-runtime-warning, #9a6700);\n      color: var(--c1gb4l3-runtime-text, inherit);\n    }\n    .cedros-gallery-proofing {\n      align-items: center;\n      display: flex;\n      flex-wrap: wrap;\n      gap: 12px;\n      padding: 16px;\n    }\n    .cedros-gallery-proofing__summary {\n      display: grid;\n      flex: 1 1 240px;\n      gap: 4px;\n    }\n    .cedros-gallery-proofing__summary > span {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      font-size: .8125rem;\n    }\n    .cedros-gallery-proofing__state {\n      flex: 1 1 100%;\n    }\n    .cedros-gallery-proofing__summary + .cedros-gallery-proofing__state {\n      flex: 1 1 240px;\n    }\n    .cedros-gallery-access {\n      align-items: end;\n      display: grid;\n      gap: 12px;\n      grid-template-columns: minmax(180px, 1fr) auto;\n      padding: 12px;\n    }\n    .cedros-gallery-access--credential {\n      max-width: min(100%, 36rem);\n    }\n    .cedros-gallery-access__intro {\n      grid-column: 1 / -1;\n    }\n    .cedros-gallery-access p {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      margin: 0;\n    }\n    .cedros-gallery-proofing__state {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n    }\n    .cedros-gallery-proofing__confirm {\n      align-items: flex-start;\n      background: var(--c1gb4l3-runtime-panel, transparent);\n      border: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      border-radius: var(--c1gb4l3-gallery-radius-control, 6px);\n      display: grid;\n      flex: 1 1 100%;\n      gap: 8px;\n      padding: 12px;\n    }\n    .cedros-gallery-proofing__selected {\n      display: grid;\n      gap: 8px 16px;\n      grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));\n      list-style: none;\n      margin: 0;\n      max-height: 280px;\n      overflow-y: auto;\n      padding: 0;\n    }\n    .cedros-gallery-proofing__selected li {\n      align-items: center;\n      display: grid;\n      gap: 12px;\n      grid-template-columns: 64px minmax(0, 1fr);\n    }\n    .cedros-gallery-proofing__selected .cedros-gallery-image {\n      aspect-ratio: 1;\n      height: 64px;\n      min-height: 0;\n      padding: 0;\n    }\n    .cedros-gallery-proofing__selected .cedros-gallery-image--empty {\n      font-size: .625rem;\n      line-height: 1.2;\n    }\n    .cedros-gallery-proofing__selected .cedros-gallery-image--empty small { display: none; }\n    .cedros-gallery-proofing__confirm-actions {\n      display: flex;\n      flex-wrap: wrap;\n      gap: 8px;\n    }\n    .cedros-gallery-button,\n    .cedros-gallery-commerce {\n      align-items: center;\n      background: var(--c1gb4l3-runtime-action-bg, #111);\n      border: 1px solid var(--c1gb4l3-runtime-action-bg, #111);\n      border-radius: var(--c1gb4l3-gallery-radius-control, 6px);\n      color: var(--c1gb4l3-runtime-action-fg, #fff);\n      cursor: pointer;\n      display: inline-flex;\n      font: inherit;\n      font-size: .875rem;\n      font-weight: 600;\n      justify-content: center;\n      min-height: 44px;\n      padding: 8px 12px;\n      text-decoration: none;\n      transition: background-color var(--motion-duration-fast, 160ms) var(--motion-ease-standard, cubic-bezier(0.16, 1, 0.3, 1)),\n        border-color var(--motion-duration-fast, 160ms) var(--motion-ease-standard, cubic-bezier(0.16, 1, 0.3, 1)),\n        color var(--motion-duration-fast, 160ms) var(--motion-ease-standard, cubic-bezier(0.16, 1, 0.3, 1));\n    }\n    .cedros-gallery-button:not(:disabled):hover,\n    .cedros-gallery-commerce:not(.cedros-gallery-commerce--disabled):hover {\n      background: color-mix(in srgb, var(--c1gb4l3-runtime-action-bg, #111) 88%, var(--c1gb4l3-runtime-action-fg, #fff));\n    }\n    .cedros-gallery-button:not(:disabled):active,\n    .cedros-gallery-commerce:not(.cedros-gallery-commerce--disabled):active,\n    .cedros-gallery-icon-button:not(:disabled):active {\n      transform: scale(.98);\n    }\n    .cedros-gallery-field :disabled { cursor: not-allowed; opacity: .55; }\n    .cedros-gallery-button--ghost:not(:disabled):hover,\n    .cedros-gallery-icon-button:not(:disabled):hover {\n      background: var(--c1gb4l3-runtime-accent-soft, rgba(127,127,127,.12));\n    }\n    .cedros-gallery-icon-button:disabled,\n    .cedros-gallery-button:disabled,\n    .cedros-gallery-commerce--disabled {\n      cursor: not-allowed;\n      opacity: .55;\n    }\n    .cedros-gallery-button--ghost {\n      background: transparent;\n      border-color: var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      color: var(--c1gb4l3-runtime-text, inherit);\n    }\n    .cedros-gallery-button--active,\n    .cedros-gallery-button--active:not(:disabled):hover {\n      background: var(--c1gb4l3-runtime-accent-soft, rgba(127,127,127,.18));\n      border-color: var(--c1gb4l3-runtime-accent, currentColor);\n      color: var(--c1gb4l3-runtime-text, inherit);\n    }\n    .cedros-gallery-field input:focus-visible,\n    .cedros-gallery-field select:focus-visible,\n    .cedros-gallery-field textarea:focus-visible,\n    .cedros-gallery-album-card > a:focus-visible,\n    .cedros-gallery-button:focus-visible,\n    .cedros-gallery-commerce:focus-visible,\n    .cedros-gallery-icon-button:focus-visible,\n    .cedros-gallery-media-button:focus-visible,\n    .cedros-gallery-carousel__dot:focus-visible,\n    .cedros-gallery-lightbox__thumbnail:focus-visible,\n    .cedros-gallery-lightbox__panel:focus-visible,\n    .cedros-gallery-proofing__confirm:focus-visible {\n      outline: 2px solid var(--c1gb4l3-runtime-accent, currentColor);\n      outline-offset: 3px;\n    }\n    .cedros-gallery-button.cedros-gallery-button--quiet {\n      background: transparent;\n      border-color: transparent;\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n    }\n    .cedros-gallery-button--quiet:not(:disabled):hover,\n    .cedros-gallery-button--quiet:not(:disabled)[aria-pressed=\"true\"] {\n      background: var(--c1gb4l3-runtime-accent-soft, transparent);\n      color: var(--c1gb4l3-runtime-text, inherit);\n    }\n    .cedros-gallery-media-button:focus-visible,\n    .cedros-gallery-album-card > a:focus-visible,\n    .cedros-gallery-lightbox__thumbnail:focus-visible {\n      outline-offset: -3px;\n    }\n    .cedros-gallery-lightbox__thumbnails:has(:focus-visible) { mask-image: none; }\n    .cedros-gallery-pages {\n      display: grid;\n    }\n    .cedros-gallery-pages__page {\n      grid-area: 1 / 1;\n      min-width: 0;\n    }\n    .cedros-gallery-items {\n      display: grid;\n      gap: var(--c1gb4l3-gallery-gap, 16px);\n    }\n    .cedros-gallery-block--virtualized .cedros-gallery-items:not(.cedros-gallery-items--masonry) > .cedros-gallery-item {\n      contain-intrinsic-size: auto var(--c1gb4l3-gallery-intrinsic-height, 320px);\n      content-visibility: auto;\n    }\n    .cedros-gallery-items--grid,\n    .cedros-gallery-items--mosaic,\n    .cedros-gallery-items--featured-thumbnails,\n    .cedros-gallery-items--product,\n    .cedros-gallery-items--album-cover-grid {\n      grid-template-columns: repeat(var(--c1gb4l3-gallery-columns, 3), minmax(0, 1fr));\n    }\n    .cedros-gallery-items--mosaic > .cedros-gallery-item:first-child {\n      display: flex;\n      flex-direction: column;\n      grid-column: span var(--c1gb4l3-gallery-mosaic-span, 2);\n      grid-row: span 2;\n    }\n    .cedros-gallery-items--mosaic > .cedros-gallery-item:first-child > .cedros-gallery-media-button {\n      aspect-ratio: auto;\n      flex: 1;\n      min-height: 240px;\n    }\n    .cedros-gallery-items--masonry {\n      column-count: var(--c1gb4l3-gallery-columns, 3);\n      column-gap: var(--c1gb4l3-gallery-gap, 16px);\n      display: block;\n    }\n    .cedros-gallery-items--masonry .cedros-gallery-item {\n      break-inside: avoid;\n      margin: 0 0 var(--c1gb4l3-gallery-gap, 16px);\n    }\n    .cedros-gallery-items--masonry:has(> .cedros-gallery-item:only-child) {\n      column-count: 1;\n      max-width: min(100%, 640px);\n    }\n    .cedros-gallery-items--grid:has(> .cedros-gallery-item:only-child),\n    .cedros-gallery-items--product:has(> .cedros-gallery-item:only-child),\n    .cedros-gallery-items--album-cover-grid:has(> .cedros-gallery-item:only-child) {\n      grid-template-columns: minmax(0, 1fr);\n      max-width: min(100%, 640px);\n    }\n    .cedros-gallery-carousel {\n      --c1gb4l3-gallery-slides-current: var(--c1gb4l3-gallery-slides-desktop, 1);\n      container-type: inline-size;\n      display: grid;\n      gap: 12px;\n      min-width: 0;\n      position: relative;\n    }\n    .cedros-gallery-carousel__viewport {\n      min-width: 0;\n      overflow-x: auto;\n      overscroll-behavior-inline: contain;\n      scrollbar-width: thin;\n      scroll-snap-type: x mandatory;\n    }\n    .cedros-gallery-carousel::before,\n    .cedros-gallery-carousel::after {\n      content: \"\";\n      inset: 0 auto 64px;\n      opacity: 0;\n      pointer-events: none;\n      position: absolute;\n      transition: opacity var(--motion-duration-fast, 160ms) var(--motion-ease-standard, cubic-bezier(0.16, 1, 0.3, 1));\n      width: 36px;\n      z-index: 2;\n    }\n    .cedros-gallery-carousel::before {\n      background: linear-gradient(90deg, var(--c1gb4l3-runtime-bg, #fff), transparent);\n      left: 0;\n    }\n    .cedros-gallery-carousel::after {\n      background: linear-gradient(270deg, var(--c1gb4l3-runtime-bg, #fff), transparent);\n      right: 0;\n    }\n    .cedros-gallery-carousel:has(.cedros-gallery-carousel__viewport:not(.is-at-start))::before,\n    .cedros-gallery-carousel:has(.cedros-gallery-carousel__viewport:not(.is-at-end))::after {\n      opacity: 1;\n    }\n    .cedros-gallery-carousel__viewport:focus-visible {\n      border-radius: var(--c1gb4l3-gallery-radius-control, 6px);\n      outline: 2px solid var(--c1gb4l3-runtime-accent, currentColor);\n      outline-offset: 3px;\n    }\n    .cedros-gallery-items--justified,\n    .cedros-gallery-items--filmstrip,\n    .cedros-gallery-items--horizontal-scroll,\n    .cedros-gallery-items--carousel,\n    .cedros-gallery-items--fullscreen-slideshow,\n    .cedros-gallery-items--slider {\n      display: flex;\n      padding-bottom: 8px;\n      width: max-content;\n    }\n    .cedros-gallery-items--justified .cedros-gallery-item,\n    .cedros-gallery-items--filmstrip .cedros-gallery-item,\n    .cedros-gallery-items--horizontal-scroll .cedros-gallery-item,\n    .cedros-gallery-items--carousel .cedros-gallery-item,\n    .cedros-gallery-items--fullscreen-slideshow .cedros-gallery-item,\n    .cedros-gallery-items--slider .cedros-gallery-item {\n      flex: 0 0 min(82cqw, calc((100cqw - (var(--c1gb4l3-gallery-gap, 16px) * (var(--c1gb4l3-gallery-slides-current) - 1))) / var(--c1gb4l3-gallery-slides-current)));\n      scroll-snap-align: start;\n      scroll-snap-stop: always;\n      transition: opacity var(--c1gb4l3-gallery-carousel-duration, 350ms) var(--motion-ease-standard, cubic-bezier(0.16, 1, 0.3, 1)),\n        filter var(--c1gb4l3-gallery-carousel-duration, 350ms) var(--motion-ease-standard, cubic-bezier(0.16, 1, 0.3, 1)),\n        transform var(--c1gb4l3-gallery-carousel-duration, 350ms) var(--motion-ease-standard, cubic-bezier(0.16, 1, 0.3, 1));\n    }\n    .cedros-gallery-items--fullscreen-slideshow .cedros-gallery-item {\n      flex-basis: 100cqw;\n    }\n    .cedros-gallery-items--fullscreen-slideshow .cedros-gallery-media-button {\n      aspect-ratio: auto;\n      height: clamp(240px, 60svh, 720px);\n    }\n    @container (max-width: 760px) {\n      .cedros-gallery-items--fullscreen-slideshow .cedros-gallery-media-button { height: clamp(240px, 35svh, 400px); }\n    }\n    @media (max-width: 760px) {\n      .cedros-gallery-items--fullscreen-slideshow .cedros-gallery-media-button { height: clamp(240px, 35svh, 400px); }\n    }\n    .cedros-gallery-carousel--center .cedros-gallery-carousel__viewport {\n      scroll-padding-inline: max(0px, calc((100% - min(82vw, 360px)) / 2));\n    }\n    .cedros-gallery-carousel--fade .cedros-gallery-item.is-carousel-inactive {\n      opacity: .55;\n    }\n    .cedros-gallery-carousel--zoom .cedros-gallery-item.is-carousel-inactive {\n      opacity: .72;\n      transform: scale(.96);\n    }\n    .cedros-gallery-carousel--coverflow .cedros-gallery-item.is-carousel-inactive {\n      filter: saturate(.78);\n      opacity: .68;\n      transform: perspective(900px) rotateY(-4deg) scale(.94);\n    }\n    .cedros-gallery-carousel__arrows {\n      display: flex;\n      gap: 8px;\n      justify-content: flex-end;\n    }\n    .cedros-gallery-carousel__nav {\n      display: flex;\n      flex-wrap: wrap;\n      gap: 8px;\n      justify-content: center;\n    }\n    .cedros-gallery-carousel__dot {\n      background: transparent;\n      border: 0;\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      cursor: pointer;\n      display: grid;\n      height: 44px;\n      padding: 0;\n      place-items: center;\n      width: 44px;\n    }\n    .cedros-gallery-carousel__dot::before {\n      background: currentColor;\n      border-radius: 999px;\n      content: \"\";\n      height: 8px;\n      width: 8px;\n    }\n    .cedros-gallery-carousel__dot[aria-pressed=\"true\"] {\n      color: var(--c1gb4l3-runtime-text, inherit);\n    }\n    .cedros-gallery-carousel__dot[aria-pressed=\"true\"]::before {\n      transform: scale(1.25);\n    }\n    .cedros-gallery-carousel__nav--thumbnails .cedros-gallery-carousel__dot {\n      align-items: center;\n      display: inline-flex;\n      font-size: .75rem;\n      height: 44px;\n      justify-content: center;\n      width: 44px;\n    }\n    .cedros-gallery-carousel__nav--thumbnails .cedros-gallery-carousel__dot::before {\n      display: none;\n    }\n    .cedros-gallery-items--vertical-stack,\n    .cedros-gallery-items--story {\n      grid-template-columns: 1fr;\n    }\n    .cedros-gallery-items--story {\n      margin-inline: auto;\n      max-width: 48rem;\n      width: 100%;\n    }\n    .cedros-gallery-items--featured-thumbnails > .cedros-gallery-item:first-child {\n      grid-column: 1 / -1;\n    }\n    .cedros-gallery-items--featured-thumbnails > .cedros-gallery-item:first-child > .cedros-gallery-media-button {\n      aspect-ratio: auto;\n      height: clamp(240px, 45svh, 560px);\n    }\n    .cedros-gallery-items--before-after {\n      grid-template-columns: repeat(2, minmax(0, 1fr));\n    }\n    .cedros-gallery-item,\n    .cedros-gallery-album-card {\n      background: var(--c1gb4l3-runtime-panel, transparent);\n      border: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      border-radius: var(--c1gb4l3-gallery-radius-card, 8px);\n      overflow: hidden;\n      transform-origin: center bottom;\n    }\n    .cedros-gallery-item--border-none {\n      border-color: transparent;\n    }\n    .cedros-gallery-item--border-hairline {\n      border-color: color-mix(in srgb, var(--c1gb4l3-runtime-border, currentColor) 58%, transparent);\n    }\n    .cedros-gallery-item--border-solid {\n      border-color: var(--c1gb4l3-runtime-border, rgba(127,127,127,.4));\n    }\n    .cedros-gallery-item--shadow-subtle {\n      box-shadow: 0 8px 24px color-mix(in srgb, var(--c1gb4l3-runtime-text, #111) 8%, transparent);\n    }\n    .cedros-gallery-item--shadow-raised {\n      box-shadow: 0 18px 44px color-mix(in srgb, var(--c1gb4l3-runtime-text, #111) 14%, transparent);\n    }\n    .cedros-gallery-media-button {\n      aspect-ratio: 4 / 3;\n      background: var(--c1gb4l3-runtime-accent-soft, rgba(127,127,127,.12));\n      border: 0;\n      color: inherit;\n      cursor: zoom-in;\n      display: block;\n      font: inherit;\n      padding: 0;\n      position: relative;\n      width: 100%;\n    }\n    .cedros-gallery-image {\n      display: block;\n      height: 100%;\n      object-fit: cover;\n      transition: filter var(--c1gb4l3-gallery-hover-duration, 180ms) var(--motion-ease-standard, cubic-bezier(0.16, 1, 0.3, 1)),\n        transform var(--c1gb4l3-gallery-hover-duration, 180ms) var(--motion-ease-standard, cubic-bezier(0.16, 1, 0.3, 1));\n      width: 100%;\n    }\n    .cedros-gallery-image--empty,\n    .cedros-gallery-comparison__empty,\n    .cedros-gallery-album-card__cover {\n      align-items: center;\n      background: var(--c1gb4l3-runtime-panel, #fff);\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      display: flex;\n      flex-direction: column;\n      gap: 8px;\n      justify-content: center;\n      min-height: 180px;\n      padding: 16px;\n      text-align: center;\n    }\n    .cedros-gallery-missing-media-icon {\n      flex: none;\n      height: 28px;\n      opacity: .6;\n      width: 28px;\n    }\n    .cedros-gallery-proofing__selected .cedros-gallery-missing-media-icon { display: none; }\n    .cedros-gallery-item__body,\n    .cedros-gallery-album-card__body {\n      display: grid;\n      gap: 12px;\n      padding: var(--c1gb4l3-gallery-card-padding, 14px);\n    }\n    .cedros-gallery-item__body,\n    .cedros-gallery-item__title,\n    .cedros-gallery-caption,\n    .cedros-gallery-badges {\n      transition: opacity var(--c1gb4l3-gallery-hover-duration, 180ms) var(--motion-ease-standard, cubic-bezier(0.16, 1, 0.3, 1)),\n        transform var(--c1gb4l3-gallery-hover-duration, 180ms) var(--motion-ease-standard, cubic-bezier(0.16, 1, 0.3, 1));\n    }\n    .cedros-gallery-item__title-row {\n      align-items: stretch;\n      display: flex;\n      flex-direction: column;\n      gap: 8px;\n    }\n    .cedros-gallery-item__title,\n    .cedros-gallery-album-card__title {\n      font: inherit;\n      font-size: 1rem;\n      font-weight: 600;\n      line-height: 1.2;\n      margin: 0;\n    }\n    .cedros-gallery-item__title--preview > a,\n    .cedros-gallery-item__title--preview > button,\n    .cedros-gallery-album-card__title--preview {\n      display: -webkit-box;\n      -webkit-box-orient: vertical;\n      -webkit-line-clamp: 3;\n      overflow: hidden;\n    }\n    .cedros-gallery-item__title a {\n      color: inherit;\n    }\n    .cedros-gallery-caption,\n    .cedros-gallery-album-card p {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      margin: 0;\n    }\n    .cedros-gallery-empty {\n      align-items: start;\n      border-block: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      display: grid;\n      gap: 8px;\n      margin: 0;\n      padding: 32px 0;\n    }\n    .cedros-gallery-empty strong {\n      color: var(--c1gb4l3-runtime-text, inherit);\n    }\n    .cedros-gallery-empty p { margin: 0; }\n    .cedros-gallery-empty .cedros-gallery-button { justify-self: start; }\n    .cedros-gallery-pagination {\n      align-items: center;\n      display: flex;\n      gap: 12px;\n      justify-content: center;\n      flex-wrap: wrap;\n    }\n    .cedros-gallery-pagination p {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      margin: 0;\n    }\n    .cedros-gallery-badges,\n    .cedros-gallery-item__actions,\n    .cedros-gallery-lightbox__nav {\n      display: flex;\n      flex-wrap: wrap;\n      gap: 8px;\n    }\n    .cedros-gallery-item__actions {\n      transition: opacity var(--c1gb4l3-gallery-hover-duration, 180ms) var(--motion-ease-standard, cubic-bezier(0.16, 1, 0.3, 1)),\n        transform var(--c1gb4l3-gallery-hover-duration, 180ms) var(--motion-ease-standard, cubic-bezier(0.16, 1, 0.3, 1));\n    }\n    @media (hover: hover) and (pointer: fine) {\n      .cedros-gallery-item--hover-slide-caption:not(:hover):not(:focus-within) .cedros-gallery-item__body {\n        transform: translateY(5px);\n      }\n      .cedros-gallery-item--hover-reveal-title:not(:hover):not(:focus-within) .cedros-gallery-item__title,\n      .cedros-gallery-item--hover-reveal-metadata:not(:hover):not(:focus-within) .cedros-gallery-caption,\n      .cedros-gallery-item--hover-reveal-metadata:not(:hover):not(:focus-within) .cedros-gallery-badges {\n        opacity: .45;\n        transform: translateY(3px);\n      }\n    }\n    .cedros-gallery-item--hover-grayscale-to-color:not(:hover):not(:focus-within) .cedros-gallery-image {\n      filter: grayscale(1);\n    }\n    .cedros-gallery-item--hover-color-to-grayscale:hover .cedros-gallery-image,\n    .cedros-gallery-item--hover-color-to-grayscale:focus-within .cedros-gallery-image {\n      filter: grayscale(1);\n    }\n    .cedros-gallery-item--hover-blur:hover .cedros-gallery-image,\n    .cedros-gallery-item--hover-blur:focus-within .cedros-gallery-image {\n      filter: blur(1.5px);\n      transform: scale(1.015);\n    }\n    .cedros-gallery-item--hover-fade-overlay:hover .cedros-gallery-image,\n    .cedros-gallery-item--hover-fade-overlay:focus-within .cedros-gallery-image {\n      filter: brightness(.82);\n    }\n    .cedros-gallery-item__title-row > .cedros-gallery-badges {\n      flex: 0 0 auto;\n      justify-content: flex-start;\n      max-width: 100%;\n    }\n    .cedros-gallery-badges span {\n      background: var(--c1gb4l3-runtime-accent-soft, rgba(127,127,127,.12));\n      border-radius: 999px;\n      font-variant-numeric: tabular-nums;\n      max-width: 100%;\n      overflow-wrap: anywhere;\n      white-space: normal;\n      color: var(--c1gb4l3-runtime-text, inherit);\n      font-size: .75rem;\n      padding: 4px 8px;\n    }\n    .cedros-gallery-lightbox {\n      inset: 0;\n      position: fixed;\n      z-index: var(--z-modal, 1000);\n    }\n    .cedros-gallery-lightbox__backdrop {\n      background: rgba(0,0,0,.72);\n      border: 0;\n      inset: 0;\n      position: absolute;\n      width: 100%;\n    }\n    .cedros-gallery-lightbox__panel {\n      background: var(--c1gb4l3-runtime-panel, #fff);\n      border: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      border-radius: var(--c1gb4l3-gallery-radius-panel, 12px);\n      color: var(--c1gb4l3-runtime-text, #111);\n      display: grid;\n      grid-template-columns: minmax(0, 1fr) minmax(280px, 360px);\n      grid-template-rows: minmax(0, 1fr) auto;\n      inset: 24px;\n      overflow: hidden;\n      position: absolute;\n    }\n    .cedros-gallery-lightbox__panel.is-fullscreen {\n      border-radius: 0;\n      inset: 0;\n    }\n    .cedros-gallery-lightbox__media {\n      background: var(--c1gb4l3-gallery-stage, #0a0a0a);\n      min-height: 320px;\n      overflow: hidden;\n      position: relative;\n    }\n    .cedros-gallery-lightbox__media .cedros-gallery-image--empty {\n      background: var(--c1gb4l3-runtime-panel, #fff);\n      color: var(--c1gb4l3-runtime-muted, #525252);\n    }\n    .cedros-gallery-lightbox__media-step {\n      height: 100%;\n      inset: 0;\n      position: absolute;\n      width: 100%;\n    }\n    .cedros-gallery-lightbox__media-step > div {\n      height: 100%;\n      width: 100%;\n    }\n    .cedros-gallery-lightbox__media-step .is-zoomed {\n      cursor: grab;\n      touch-action: none;\n    }\n    .cedros-gallery-lightbox__media-step .is-zoomed:active {\n      cursor: grabbing;\n    }\n    .cedros-gallery-lightbox__media .cedros-gallery-image {\n      object-fit: contain;\n    }\n    .cedros-gallery-lightbox__details {\n      align-content: start;\n      display: grid;\n      gap: 16px;\n      overflow: auto;\n      overflow-wrap: anywhere;\n      padding: 16px;\n    }\n    .cedros-gallery-icon-button.cedros-gallery-lightbox__close {\n      background: var(--c1gb4l3-runtime-panel, #fff);\n      position: absolute;\n      right: 12px;\n      top: 12px;\n      z-index: 3;\n    }\n    .cedros-gallery-lightbox__toolbar {\n      align-items: center;\n      display: flex;\n      flex-wrap: wrap;\n      gap: 8px 12px;\n      padding-right: 48px;\n    }\n    .cedros-gallery-caption-region { display: grid; gap: 8px; }\n    .cedros-gallery-caption--summary {\n      display: -webkit-box;\n      -webkit-box-orient: vertical;\n      -webkit-line-clamp: 3;\n      overflow: hidden;\n    }\n    .cedros-gallery-caption-region__toggle { justify-self: start; }\n    .cedros-gallery-album-card__count { font-size: .8125rem; font-variant-numeric: tabular-nums; }\n    .cedros-gallery-lightbox__details p { margin: 0; }\n    .cedros-gallery-lightbox__details h2 {\n      font: inherit;\n      font-size: 1.25rem;\n      font-weight: 700;\n      margin: 0;\n    }\n    .cedros-gallery-lightbox__identity { padding-inline-end: 48px; }\n    .cedros-gallery-lightbox__utilities { border-top: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28)); padding-top: 12px; }\n    .cedros-gallery-lightbox__utilities:empty { display: none; }\n    .cedros-gallery-lightbox__more summary {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      cursor: pointer;\n      min-height: 44px;\n      padding-block: 12px;\n    }\n    .cedros-gallery-lightbox__more summary:focus-visible {\n      outline: 2px solid var(--c1gb4l3-runtime-accent, currentColor);\n      outline-offset: 3px;\n    }\n    .cedros-gallery-lightbox__counter {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      font-size: .8125rem;\n      margin: 0;\n    }\n    .cedros-gallery-lightbox__metadata {\n      display: grid;\n      gap: 8px;\n      margin: 0;\n    }\n    .cedros-gallery-lightbox__metadata div {\n      display: flex;\n      gap: 12px;\n      justify-content: space-between;\n    }\n    .cedros-gallery-lightbox__metadata dt {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n    }\n    .cedros-gallery-lightbox__metadata dd {\n      margin: 0;\n      text-align: right;\n    }\n    .cedros-gallery-lightbox__thumbnails {\n      grid-column: 1 / -1;\n      mask-image: linear-gradient(\n        90deg,\n        transparent 0,\n        #000 var(--c1gb4l3-gallery-thumbnail-fade-start, 32px),\n        #000 calc(100% - var(--c1gb4l3-gallery-thumbnail-fade-end, 32px)),\n        transparent 100%\n      );\n      overflow-x: auto;\n      overscroll-behavior-inline: contain;\n      padding: 8px;\n      scroll-snap-type: x mandatory;\n    }\n    .cedros-gallery-lightbox__thumbnails.is-at-start {\n      --c1gb4l3-gallery-thumbnail-fade-start: 0px;\n    }\n    .cedros-gallery-lightbox__thumbnails.is-at-end {\n      --c1gb4l3-gallery-thumbnail-fade-end: 0px;\n    }\n    .cedros-gallery-lightbox__thumbnail-track {\n      display: flex;\n      gap: 8px;\n      width: max-content;\n    }\n    .cedros-gallery-lightbox__thumbnail {\n      background: var(--c1gb4l3-gallery-stage, #0a0a0a);\n      border: 2px solid transparent;\n      border-radius: var(--c1gb4l3-gallery-radius-control, 6px);\n      height: 54px;\n      overflow: hidden;\n      padding: 0;\n      scroll-snap-align: center;\n      width: 72px;\n    }\n    .cedros-gallery-lightbox__thumbnail[aria-current=\"true\"] {\n      border-color: var(--c1gb4l3-runtime-accent, currentColor);\n    }\n    .cedros-gallery-lightbox__thumbnail .cedros-gallery-image {\n      object-fit: cover;\n    }\n    .cedros-gallery-icon-button {\n      align-items: center;\n      display: inline-flex;\n      justify-content: center;\n      font: inherit;\n      background: transparent;\n      border: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      border-radius: var(--c1gb4l3-gallery-radius-control, 6px);\n      color: inherit;\n      justify-self: end;\n      cursor: pointer;\n      min-height: 44px;\n      min-width: 44px;\n    }\n    .cedros-gallery-album {\n      --c1gb4l3-gallery-card-padding: 16px;\n\n      --c1gb4l3-gallery-stage: #0a0a0a;\n      --c1gb4l3-gallery-radius-control: 6px;\n      --c1gb4l3-gallery-radius-card: 8px;\n      --c1gb4l3-gallery-radius-panel: 12px;\n      box-sizing: border-box;\n      color: var(--c1gb4l3-runtime-text, inherit);\n      display: grid;\n      gap: 24px;\n      max-width: 100%;\n      min-width: 0;\n      container-type: inline-size;\n      overflow-wrap: anywhere;\n    }\n    .cedros-gallery-album__grid {\n      display: grid;\n      gap: 16px;\n      grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));\n    }\n    .cedros-gallery-album__grid:has(> .cedros-gallery-album-card:only-child) {\n      grid-template-columns: minmax(0, 1fr);\n      max-width: min(100%, 640px);\n    }\n    .cedros-gallery-album--masonry .cedros-gallery-album__grid {\n      columns: 300px;\n      display: block;\n    }\n    .cedros-gallery-album--masonry .cedros-gallery-album-card {\n      break-inside: avoid;\n      margin-bottom: 16px;\n    }\n    .cedros-gallery-album--featured .cedros-gallery-album-card:first-child { grid-column: 1 / -1; }\n    .cedros-gallery-album--featured .cedros-gallery-album-card:first-child .cedros-gallery-album-card__cover {\n      aspect-ratio: auto;\n      height: clamp(240px, 40svh, 480px);\n    }\n    .cedros-gallery-album--list .cedros-gallery-album__grid {\n      grid-template-columns: minmax(0, 1fr);\n      max-width: 100%;\n    }\n    .cedros-gallery-album--list .cedros-gallery-album-card { min-height: 9rem; position: relative; }\n    .cedros-gallery-album--list .cedros-gallery-album-card__main { padding-inline-start: 12rem; }\n    .cedros-gallery-album--list .cedros-gallery-album-card__cover {\n      aspect-ratio: auto;\n      bottom: 0;\n      height: 100%;\n      inset-inline-start: 0;\n      position: absolute;\n      top: 0;\n      width: 12rem;\n    }\n    .cedros-gallery-album--list .cedros-gallery-album-card__description {\n      padding-inline-start: calc(12rem + var(--c1gb4l3-gallery-card-padding, 16px));\n    }\n    .cedros-gallery-album__carousel { display: grid; gap: 12px; min-width: 0; }\n    .cedros-gallery-album--carousel .cedros-gallery-album__grid {\n      align-items: start;\n      display: grid;\n      grid-auto-columns: min(85%, 400px);\n      grid-auto-flow: column;\n      grid-template-columns: none;\n      max-width: 100%;\n      overflow-x: auto;\n      overscroll-behavior-inline: contain;\n      padding-bottom: 8px;\n      scroll-snap-type: x mandatory;\n    }\n    .cedros-gallery-album--carousel .cedros-gallery-album-card { scroll-snap-align: start; }\n    .cedros-gallery-album__navigation { display: flex; flex-wrap: wrap; gap: 8px; justify-content: flex-end; }\n    @container (max-width: 32rem) {\n      .cedros-gallery-album--list .cedros-gallery-album-card__main { padding-inline-start: 0; }\n      .cedros-gallery-album--list .cedros-gallery-album-card__cover { aspect-ratio: 4 / 3; height: auto; position: static; width: auto; }\n      .cedros-gallery-album--list .cedros-gallery-album-card__description { padding-inline-start: var(--c1gb4l3-gallery-card-padding, 16px); }\n    }\n    .cedros-gallery-album-card__main {\n      color: inherit;\n      display: block;\n      text-decoration: none;\n    }\n    .cedros-gallery-album-card__description {\n      padding: 0 var(--c1gb4l3-gallery-card-padding, 16px) var(--c1gb4l3-gallery-card-padding, 16px);\n    }\n    .cedros-gallery-album-card__cover {\n      aspect-ratio: 4 / 3;\n      min-height: 0;\n      padding: 0;\n      overflow: hidden;\n    }\n    .cedros-gallery-album-card__cover img {\n      display: block;\n      height: 100%;\n      object-fit: cover;\n      width: 100%;\n    }\n    .cedros-gallery-comparison {\n\n      --c1gb4l3-gallery-stage: #0a0a0a;\n      --c1gb4l3-gallery-radius-control: 6px;\n      --c1gb4l3-gallery-radius-card: 8px;\n      --c1gb4l3-gallery-radius-panel: 12px;\n      box-sizing: border-box;\n      color: var(--c1gb4l3-runtime-text, inherit);\n      display: grid;\n      gap: 16px;\n      max-width: 100%;\n      min-width: 0;\n      container-type: inline-size;\n      overflow-wrap: anywhere;\n    }\n    .cedros-gallery-comparison__stage {\n      aspect-ratio: 16 / 9;\n      background: var(--c1gb4l3-runtime-accent-soft, rgba(127,127,127,.12));\n      border: 1px solid var(--c1gb4l3-runtime-border, rgba(127,127,127,.28));\n      border-radius: var(--c1gb4l3-gallery-radius-card, 8px);\n      cursor: ew-resize;\n      overflow: hidden;\n      position: relative;\n      touch-action: none;\n    }\n    .cedros-gallery-comparison__stage img {\n      display: block;\n      height: 100%;\n      object-fit: cover;\n      width: 100%;\n    }\n    .cedros-gallery-comparison__after {\n      clip-path: inset(0 0 0 var(--c1gb4l3-gallery-split, 50%));\n      inset: 0;\n      position: absolute;\n    }\n    .cedros-gallery-comparison--vertical .cedros-gallery-comparison__stage {\n      cursor: ns-resize;\n    }\n    .cedros-gallery-comparison--vertical .cedros-gallery-comparison__after {\n      clip-path: inset(var(--c1gb4l3-gallery-split, 50%) 0 0 0);\n    }\n    .cedros-gallery-comparison__divider {\n      background: var(--c1gb4l3-runtime-panel, #fff);\n      box-shadow: 0 0 0 1px color-mix(in srgb, var(--c1gb4l3-runtime-text, #111) 16%, transparent);\n      bottom: 0;\n      left: var(--c1gb4l3-gallery-split, 50%);\n      pointer-events: none;\n      position: absolute;\n      top: 0;\n      width: 2px;\n      z-index: 2;\n    }\n    .cedros-gallery-comparison__divider::after {\n      background: var(--c1gb4l3-runtime-action-bg, #111);\n      border: 1px solid var(--c1gb4l3-runtime-action-fg, #fff);\n      border-radius: 999px;\n      content: \"↔\";\n      color: var(--c1gb4l3-runtime-action-fg, #fff);\n      display: grid;\n      font-size: 12px;\n      height: 32px;\n      left: 50%;\n      place-items: center;\n      position: absolute;\n      top: 50%;\n      transform: translate(-50%, -50%);\n      width: 32px;\n    }\n    .cedros-gallery-comparison--vertical .cedros-gallery-comparison__divider {\n      bottom: auto;\n      height: 2px;\n      left: 0;\n      right: 0;\n      top: var(--c1gb4l3-gallery-split, 50%);\n      width: auto;\n    }\n    .cedros-gallery-comparison--vertical .cedros-gallery-comparison__divider::after {\n      content: \"↕\";\n      left: 50%;\n      top: 50%;\n    }\n    .cedros-gallery-comparison__labels {\n      color: var(--c1gb4l3-runtime-muted, currentColor);\n      display: grid;\n      font-size: .875em;\n      gap: 16px;\n      grid-template-columns: repeat(2, minmax(0, 1fr));\n    }\n    .cedros-gallery-comparison__labels span {\n      overflow-wrap: anywhere;\n    }\n    .cedros-gallery-comparison__labels span:last-child {\n      text-align: right;\n    }\n    .cedros-gallery-field--range input {\n      accent-color: var(--c1gb4l3-runtime-accent, currentColor);\n      padding-left: 0;\n      padding-right: 0;\n    }\n    @media (max-width: 760px) {\n      .cedros-gallery-block,\n      .cedros-gallery-album,\n      .cedros-gallery-comparison {\n        width: 100%;\n      }\n      .cedros-gallery-button,\n      .cedros-gallery-commerce,\n      .cedros-gallery-icon-button {\n        min-height: 44px;\n      }\n      .cedros-gallery-carousel {\n        --c1gb4l3-gallery-slides-current: var(--c1gb4l3-gallery-slides-mobile, 1);\n      }\n      .cedros-gallery-header,\n      .cedros-gallery-item__title-row {\n        align-items: stretch;\n        flex-direction: column;\n      }\n      .cedros-gallery-item__title-row > .cedros-gallery-badges {\n        justify-content: flex-start;\n        max-width: none;\n      }\n      .cedros-gallery-submission__history-item {\n        grid-template-columns: 1fr;\n      }\n      .cedros-gallery-submission__history-item > p {\n        grid-column: auto;\n      }\n      .cedros-gallery-stats {\n        justify-content: flex-start;\n      }\n      .cedros-gallery-access {\n        align-items: stretch;\n        grid-template-columns: 1fr;\n      }\n      .cedros-gallery-toolbar__primary {\n        display: grid;\n        grid-template-columns: repeat(2, minmax(0, 1fr));\n      }\n      .cedros-gallery-field--search {\n        grid-column: 1 / -1;\n      }\n      .cedros-gallery-toolbar .cedros-gallery-toolbar__toggle {\n        display: inline-flex;\n      }\n      .cedros-gallery-toolbar__disclosure {\n        grid-template-rows: 0fr;\n      }\n      .cedros-gallery-toolbar.is-expanded .cedros-gallery-toolbar__disclosure {\n        grid-template-rows: 1fr;\n      }\n      .cedros-gallery-toolbar__advanced {\n        grid-template-columns: 1fr;\n      }\n      .cedros-gallery-items--before-after,\n      .cedros-gallery-items--grid,\n      .cedros-gallery-items--mosaic,\n      .cedros-gallery-items--featured-thumbnails,\n      .cedros-gallery-items--product,\n      .cedros-gallery-items--album-cover-grid {\n        grid-template-columns: 1fr;\n      }\n      .cedros-gallery-items--masonry {\n        column-count: 1;\n      }\n      .cedros-gallery-items--mosaic > .cedros-gallery-item:first-child {\n        grid-column: auto;\n        grid-row: auto;\n      }\n      .cedros-gallery-items--mosaic > .cedros-gallery-item:first-child > .cedros-gallery-media-button {\n        aspect-ratio: 4 / 3;\n        min-height: 0;\n      }\n      .cedros-gallery-lightbox__panel {\n        grid-template-columns: 1fr;\n        grid-template-rows: minmax(0, 45dvh) minmax(0, 1fr) auto;\n        inset: 8px;\n      }\n      .cedros-gallery-lightbox__panel.is-fullscreen {\n        inset: 0;\n      }\n      .cedros-gallery-lightbox__media {\n        min-height: 0;\n      }\n      .cedros-gallery-lightbox__details {\n        padding: 12px;\n      }\n      .cedros-gallery-lightbox__toolbar { padding-right: 0; }\n      .cedros-gallery-lightbox__metadata div {\n        flex-wrap: wrap;\n      }\n      .cedros-gallery-lightbox__thumbnails {\n        max-width: 100%;\n      }\n    }\n    @media (max-width: 380px) {\n      .cedros-gallery-submission__actions > *,\n      .cedros-gallery-proofing__confirm-actions > * {\n        width: 100%;\n      }\n    }\n    @media (min-width: 761px) and (max-width: 1024px) {\n      .cedros-gallery-carousel {\n        --c1gb4l3-gallery-slides-current: var(--c1gb4l3-gallery-slides-tablet, 2);\n      }\n    }\n    @container (max-width: 760px) {\n      .cedros-gallery-block,\n      .cedros-gallery-album,\n      .cedros-gallery-comparison {\n        width: 100%;\n      }\n      .cedros-gallery-button,\n      .cedros-gallery-commerce,\n      .cedros-gallery-icon-button {\n        min-height: 44px;\n      }\n      .cedros-gallery-carousel {\n        --c1gb4l3-gallery-slides-current: var(--c1gb4l3-gallery-slides-mobile, 1);\n      }\n      .cedros-gallery-header,\n      .cedros-gallery-item__title-row {\n        align-items: stretch;\n        flex-direction: column;\n      }\n      .cedros-gallery-item__title-row > .cedros-gallery-badges {\n        justify-content: flex-start;\n        max-width: none;\n      }\n      .cedros-gallery-submission__history-item {\n        grid-template-columns: 1fr;\n      }\n      .cedros-gallery-submission__history-item > p {\n        grid-column: auto;\n      }\n      .cedros-gallery-stats {\n        justify-content: flex-start;\n      }\n      .cedros-gallery-access {\n        align-items: stretch;\n        grid-template-columns: 1fr;\n      }\n      .cedros-gallery-toolbar__primary {\n        display: grid;\n        grid-template-columns: repeat(2, minmax(0, 1fr));\n      }\n      .cedros-gallery-field--search {\n        grid-column: 1 / -1;\n      }\n      .cedros-gallery-toolbar .cedros-gallery-toolbar__toggle {\n        display: inline-flex;\n      }\n      .cedros-gallery-toolbar__disclosure {\n        grid-template-rows: 0fr;\n      }\n      .cedros-gallery-toolbar.is-expanded .cedros-gallery-toolbar__disclosure {\n        grid-template-rows: 1fr;\n      }\n      .cedros-gallery-toolbar__advanced {\n        grid-template-columns: 1fr;\n      }\n      .cedros-gallery-items--before-after,\n      .cedros-gallery-items--grid,\n      .cedros-gallery-items--mosaic,\n      .cedros-gallery-items--featured-thumbnails,\n      .cedros-gallery-items--product,\n      .cedros-gallery-items--album-cover-grid {\n        grid-template-columns: 1fr;\n      }\n      .cedros-gallery-items--masonry {\n        column-count: 1;\n      }\n      .cedros-gallery-items--mosaic > .cedros-gallery-item:first-child {\n        grid-column: auto;\n        grid-row: auto;\n      }\n      .cedros-gallery-items--mosaic > .cedros-gallery-item:first-child > .cedros-gallery-media-button {\n        aspect-ratio: 4 / 3;\n        min-height: 0;\n      }\n    }\n    @container (max-width: 380px) {\n      .cedros-gallery-submission__actions > *,\n      .cedros-gallery-proofing__confirm-actions > * {\n        width: 100%;\n      }\n    }\n    @container (min-width: 761px) and (max-width: 1024px) {\n      .cedros-gallery-carousel {\n        --c1gb4l3-gallery-slides-current: var(--c1gb4l3-gallery-slides-tablet, 2);\n      }\n    }\n    @media (prefers-reduced-motion: reduce) {\n      .cedros-gallery-block,\n      .cedros-gallery-block *,\n      .cedros-gallery-block *::before,\n      .cedros-gallery-block *::after,\n      .cedros-gallery-album,\n      .cedros-gallery-album *,\n      .cedros-gallery-album *::before,\n      .cedros-gallery-album *::after,\n      .cedros-gallery-comparison,\n      .cedros-gallery-comparison *,\n      .cedros-gallery-comparison *::before,\n      .cedros-gallery-comparison *::after {\n        animation-delay: 0ms !important;\n        animation-duration: .01ms !important;\n        animation-iteration-count: 1 !important;\n        scroll-behavior: auto !important;\n        transition-delay: 0ms !important;\n        transition-duration: .01ms !important;\n      }\n    }\n"}]}