{
  "id": "editorial-parallax-showcase",
  "kind": "element",
  "title": "Editorial parallax showcase",
  "summary": "An editorial page section with a serif italic intro and four glass cards, a tilted capsule photo and two drawn accents that drift past at different speeds as you scroll.",
  "url": "https://enrichr.dev/elements/editorial-parallax-showcase.html",
  "section": "page",
  "techniques": [
    "parallax",
    "scroll-driven",
    "reveal"
  ],
  "stack": [
    "Vanilla JS",
    "CSS",
    "SVG"
  ],
  "frameworks": [
    "React",
    "Next.js",
    "Vanilla"
  ],
  "mood": [
    "editorial",
    "calm"
  ],
  "intents": [
    "editorial parallax section",
    "overlapping cards parallax scroll",
    "serif headline landing section",
    "capsule photo with floating cards",
    "scroll speed layers page section"
  ],
  "status": "tested",
  "params": [
    {
      "key": "depth",
      "label": "Parallax depth (px at speed 1)",
      "type": "range",
      "min": 0,
      "max": 2400,
      "step": 50,
      "value": 1200
    },
    {
      "key": "photo",
      "label": "Capsule photo",
      "type": "select",
      "options": [
        [
          "corgi-1",
          "Corgi puppy on orange"
        ],
        [
          "corgi-2",
          "Corgi in a flower field"
        ],
        [
          "corgi-3",
          "Corgi on a rock"
        ],
        [
          "corgi-4",
          "Two dogs on a dirt road"
        ],
        [
          "corgi-5",
          "Corgi lying on white"
        ],
        [
          "corgi-6",
          "Corgi standing on white"
        ]
      ],
      "value": "corgi-2"
    },
    {
      "key": "eyebrow",
      "label": "Eyebrow",
      "type": "text",
      "value": "How we build"
    },
    {
      "key": "lede",
      "label": "Intro headline",
      "type": "text",
      "value": "Build pages that move with calm, deliberate care."
    },
    {
      "key": "heading",
      "label": "Section heading",
      "type": "text",
      "value": "Clear, Calm, Considered"
    },
    {
      "key": "word",
      "label": "Underlined serif word",
      "type": "text",
      "value": "motion."
    },
    {
      "key": "background",
      "label": "Background",
      "type": "color",
      "value": "#fbf8f1"
    },
    {
      "key": "ink",
      "label": "Ink",
      "type": "color",
      "value": "#0c1e18"
    },
    {
      "key": "accent",
      "label": "Accent (eyebrow, curve, card hover)",
      "type": "color",
      "value": "#1a7a4c"
    },
    {
      "key": "card",
      "label": "Card",
      "type": "color",
      "value": "#ffffff"
    },
    {
      "key": "highlight",
      "label": "Icon on hover",
      "type": "color",
      "value": "#e6ff55"
    },
    {
      "key": "warm",
      "label": "Spiral",
      "type": "color",
      "value": "#e54c1e"
    },
    {
      "key": "leaf",
      "label": "Leaf",
      "type": "color",
      "value": "#005236"
    }
  ],
  "license": "Free to use in personal and client projects during the preview. Final licence terms will be published here before any paid tier starts; ask before reselling the code as a collection.",
  "contract": "function mount(root, opts) -> { update(partialOpts), destroy() }; root must contain the element markup",
  "exports": {
    "claude": "Add the \"Editorial parallax showcase\" element to this project.\n\nThis is the \"Editorial parallax showcase\" element from the Enrichr Library: An editorial page section with a serif italic intro and four glass cards, a tilted capsule photo and two drawn accents that drift past at different speeds as you scroll.\nPage: https://enrichr.dev/elements/editorial-parallax-showcase.html\nMachine-readable spec: https://enrichr.dev/elements/editorial-parallax-showcase.json\n\nElement contract (vanilla JavaScript, no dependencies):\n- The JavaScript defines a function mount(root, opts).\n- root is an empty container element. Set root.innerHTML to the markup first, then call mount(root, opts).\n- It returns an object with update(partialOpts) and destroy(). Call destroy() when the element is removed. Some elements also return replay().\n- The CSS classes all start with \"ef-\" so they will not collide with your styles.\n\nSteps:\n1. Look at the project first to see its framework and where components, styles and static files live. Follow its conventions.\n2. Fetch https://enrichr.dev/elements/editorial-parallax-showcase.json if you can read URLs (fields: source.markup, source.css, source.js, params); otherwise use the source at the end of this message.\n3. Add the files, mount it where I tell you (default: the top of the home page), and pass the settings below as the opts.\n4. Keep the behaviour of the source unchanged. Do not add dependencies. Respect prefers-reduced-motion. Keep text as real HTML.\n5. Run the dev server and check it. with reduced motion on, nothing moves; it works at 375px wide and with touch only; there are no console errors; scrolling stays smooth; destroy() is called when it unmounts.\n\nSettings:\n{{SETTINGS}}\n\nSource:\n{{CODE}}",
    "chatgpt": "I want the \"Editorial parallax showcase\" element on my website. Below is its complete source. Please:\n1. Build one self-contained index.html that I can open locally to see it working (put the CSS in a <style> tag and the JavaScript in a <script> tag, with the markup in the body).\n2. Then explain, step by step, which parts go where in my own site, and how to mount it. My stack is: [tell me yours, or say \"plain HTML\"].\n3. Keep the behaviour of the source unchanged. Do not add dependencies. Respect prefers-reduced-motion. Keep text as real HTML.\n\nThis is the \"Editorial parallax showcase\" element from the Enrichr Library: An editorial page section with a serif italic intro and four glass cards, a tilted capsule photo and two drawn accents that drift past at different speeds as you scroll.\nPage: https://enrichr.dev/elements/editorial-parallax-showcase.html\nMachine-readable spec: https://enrichr.dev/elements/editorial-parallax-showcase.json\n\nElement contract (vanilla JavaScript, no dependencies):\n- The JavaScript defines a function mount(root, opts).\n- root is an empty container element. Set root.innerHTML to the markup first, then call mount(root, opts).\n- It returns an object with update(partialOpts) and destroy(). Call destroy() when the element is removed. Some elements also return replay().\n- The CSS classes all start with \"ef-\" so they will not collide with your styles.\n\nSettings:\n{{SETTINGS}}\n\nSource:\n{{CODE}}\n\nVerify: with reduced motion on, nothing moves; it works at 375px wide and with touch only; there are no console errors; scrolling stays smooth; destroy() is called when it unmounts.",
    "cursor": "Add the \"Editorial parallax showcase\" element to this codebase.\n\nThis is the \"Editorial parallax showcase\" element from the Enrichr Library: An editorial page section with a serif italic intro and four glass cards, a tilted capsule photo and two drawn accents that drift past at different speeds as you scroll.\nPage: https://enrichr.dev/elements/editorial-parallax-showcase.html\nMachine-readable spec: https://enrichr.dev/elements/editorial-parallax-showcase.json\n\nElement contract (vanilla JavaScript, no dependencies):\n- The JavaScript defines a function mount(root, opts).\n- root is an empty container element. Set root.innerHTML to the markup first, then call mount(root, opts).\n- It returns an object with update(partialOpts) and destroy(). Call destroy() when the element is removed. Some elements also return replay().\n- The CSS classes all start with \"ef-\" so they will not collide with your styles.\n\nUse Composer / agent mode. First search the repo for how components, styles and scripts are organised, then add the files in the matching places, mount it on the page I name, and run the app to confirm it works. Keep the behaviour of the source unchanged. Do not add dependencies. Respect prefers-reduced-motion. Keep text as real HTML.\n\nSettings:\n{{SETTINGS}}\n\nSource:\n{{CODE}}\n\nVerify: with reduced motion on, nothing moves; it works at 375px wide and with touch only; there are no console errors; scrolling stays smooth; destroy() is called when it unmounts.\n\nOptional: save this as .cursor/rules/enrichr-editorial-parallax-showcase.mdc so the rule stays with the project:\n---\ndescription: How to use the Enrichr Editorial parallax showcase element\nalwaysApply: false\n---\nmount(root, opts) expects the element markup inside root and returns { update, destroy }. Always call destroy() on unmount and never edit the ef- class names.",
    "v0": "Create a Next.js (App Router) client component for the \"Editorial parallax showcase\" element. Tailwind is available but this component needs no utility classes.\n\nThis is the \"Editorial parallax showcase\" element from the Enrichr Library: An editorial page section with a serif italic intro and four glass cards, a tilted capsule photo and two drawn accents that drift past at different speeds as you scroll.\nPage: https://enrichr.dev/elements/editorial-parallax-showcase.html\nMachine-readable spec: https://enrichr.dev/elements/editorial-parallax-showcase.json\n\nElement contract (vanilla JavaScript, no dependencies):\n- The JavaScript defines a function mount(root, opts).\n- root is an empty container element. Set root.innerHTML to the markup first, then call mount(root, opts).\n- It returns an object with update(partialOpts) and destroy(). Call destroy() when the element is removed. Some elements also return replay().\n- The CSS classes all start with \"ef-\" so they will not collide with your styles.\n\nFiles to create:\n- editorial-parallax-showcase.js : the JavaScript below, with one line appended at the end: export { mount };  (and the markup exported as: export const markup = \"<the markup string>\";). If the project uses TypeScript and does not allow JS imports, put // @ts-nocheck on the first line.\n- the CSS below goes in your global stylesheet (or a plain .css file imported once at the app root). The class names are global and start with ef-.\n\nUse this component as the wrapper (adjust the import paths):\n```tsx\n\"use client\";\nimport { useEffect, useRef } from \"react\";\nimport { markup, mount } from \"./editorial-parallax-showcase\"; // markup is the HTML string; mount is the JavaScript's mount function\n\nexport default function EditorialParallaxShowcase(props: Record<string, unknown>) {\n  const ref = useRef<HTMLDivElement>(null);\n  const fx = useRef<{ update: (o: object) => void; destroy: () => void } | null>(null);\n  useEffect(() => {\n    const root = ref.current;\n    if (!root) return;\n    root.innerHTML = markup;\n    fx.current = mount(root, props);\n    return () => { fx.current?.destroy(); fx.current = null; root.innerHTML = \"\"; };\n  }, []);\n  useEffect(() => { fx.current?.update(props); }, [JSON.stringify(props)]);\n  return <div ref={ref} />;\n}\n```\n\nRender it on the home page so I can see it. Keep the behaviour of the source unchanged. Do not add dependencies. Respect prefers-reduced-motion. Keep text as real HTML.\n\nSettings:\n{{SETTINGS}}\n\nSource:\n{{CODE}}",
    "lovable": "Add the \"Editorial parallax showcase\" element to this React + Vite + TypeScript + Tailwind project. Do not install any packages.\n\nThis is the \"Editorial parallax showcase\" element from the Enrichr Library: An editorial page section with a serif italic intro and four glass cards, a tilted capsule photo and two drawn accents that drift past at different speeds as you scroll.\nPage: https://enrichr.dev/elements/editorial-parallax-showcase.html\nMachine-readable spec: https://enrichr.dev/elements/editorial-parallax-showcase.json\n\nElement contract (vanilla JavaScript, no dependencies):\n- The JavaScript defines a function mount(root, opts).\n- root is an empty container element. Set root.innerHTML to the markup first, then call mount(root, opts).\n- It returns an object with update(partialOpts) and destroy(). Call destroy() when the element is removed. Some elements also return replay().\n- The CSS classes all start with \"ef-\" so they will not collide with your styles.\n\nFiles to create:\n- editorial-parallax-showcase.js : the JavaScript below, with one line appended at the end: export { mount };  (and the markup exported as: export const markup = \"<the markup string>\";). If the project uses TypeScript and does not allow JS imports, put // @ts-nocheck on the first line.\n- the CSS below goes in your global stylesheet (or a plain .css file imported once at the app root). The class names are global and start with ef-.\n\nWrapper component (src/components/EditorialParallaxShowcase.tsx):\n```tsx\n\"use client\";\nimport { useEffect, useRef } from \"react\";\nimport { markup, mount } from \"./editorial-parallax-showcase\"; // markup is the HTML string; mount is the JavaScript's mount function\n\nexport default function EditorialParallaxShowcase(props: Record<string, unknown>) {\n  const ref = useRef<HTMLDivElement>(null);\n  const fx = useRef<{ update: (o: object) => void; destroy: () => void } | null>(null);\n  useEffect(() => {\n    const root = ref.current;\n    if (!root) return;\n    root.innerHTML = markup;\n    fx.current = mount(root, props);\n    return () => { fx.current?.destroy(); fx.current = null; root.innerHTML = \"\"; };\n  }, []);\n  useEffect(() => { fx.current?.update(props); }, [JSON.stringify(props)]);\n  return <div ref={ref} />;\n}\n```\n\nRemove the \"use client\" line if it is not needed. Show it on the home page. Keep the behaviour of the source unchanged. Do not add dependencies. Respect prefers-reduced-motion. Keep text as real HTML.\n\nSettings:\n{{SETTINGS}}\n\nSource:\n{{CODE}}",
    "bolt": "Create a small Vite project (vanilla JavaScript, no framework unless I already have one) that shows the \"Editorial parallax showcase\" element.\n\nThis is the \"Editorial parallax showcase\" element from the Enrichr Library: An editorial page section with a serif italic intro and four glass cards, a tilted capsule photo and two drawn accents that drift past at different speeds as you scroll.\nPage: https://enrichr.dev/elements/editorial-parallax-showcase.html\nMachine-readable spec: https://enrichr.dev/elements/editorial-parallax-showcase.json\n\nElement contract (vanilla JavaScript, no dependencies):\n- The JavaScript defines a function mount(root, opts).\n- root is an empty container element. Set root.innerHTML to the markup first, then call mount(root, opts).\n- It returns an object with update(partialOpts) and destroy(). Call destroy() when the element is removed. Some elements also return replay().\n- The CSS classes all start with \"ef-\" so they will not collide with your styles.\n\nFiles: index.html (a container element, then a script tag), style.css (the CSS below), editorial-parallax-showcase.js (the JavaScript below) and main.js that sets the container's innerHTML to the markup and calls mount(container, opts) with the settings below. Keep the behaviour of the source unchanged. Do not add dependencies. Respect prefers-reduced-motion. Keep text as real HTML.\n\nSettings:\n{{SETTINGS}}\n\nSource:\n{{CODE}}\n\nVerify: with reduced motion on, nothing moves; it works at 375px wide and with touch only; there are no console errors; scrolling stays smooth; destroy() is called when it unmounts.",
    "replit": "Create a new HTML, CSS and JavaScript Repl that shows the \"Editorial parallax showcase\" element. No packages, no server code.\n\nThis is the \"Editorial parallax showcase\" element from the Enrichr Library: An editorial page section with a serif italic intro and four glass cards, a tilted capsule photo and two drawn accents that drift past at different speeds as you scroll.\nPage: https://enrichr.dev/elements/editorial-parallax-showcase.html\nMachine-readable spec: https://enrichr.dev/elements/editorial-parallax-showcase.json\n\nElement contract (vanilla JavaScript, no dependencies):\n- The JavaScript defines a function mount(root, opts).\n- root is an empty container element. Set root.innerHTML to the markup first, then call mount(root, opts).\n- It returns an object with update(partialOpts) and destroy(). Call destroy() when the element is removed. Some elements also return replay().\n- The CSS classes all start with \"ef-\" so they will not collide with your styles.\n\nFiles: index.html (a container element, link style.css, load editorial-parallax-showcase.js and then main.js), style.css (the CSS below), editorial-parallax-showcase.js (the JavaScript below), main.js (sets the container's innerHTML to the markup, then calls mount(container, opts) with the settings below). Press Run to preview. Keep the behaviour of the source unchanged. Do not add dependencies. Respect prefers-reduced-motion. Keep text as real HTML.\n\nSettings:\n{{SETTINGS}}\n\nSource:\n{{CODE}}",
    "figma": "Designer handoff notes for the \"Editorial parallax showcase\" element (Enrichr Library). Figma cannot run this JavaScript inside a design file, so use it as a motion reference and hand the code to a developer.\n\nThis is the \"Editorial parallax showcase\" element from the Enrichr Library: An editorial page section with a serif italic intro and four glass cards, a tilted capsule photo and two drawn accents that drift past at different speeds as you scroll.\nPage: https://enrichr.dev/elements/editorial-parallax-showcase.html\nMachine-readable spec: https://enrichr.dev/elements/editorial-parallax-showcase.json\n\nWhat it does: The section's scroll progress runs from 0, when its top reaches the bottom of the screen, to 1, when its bottom passes the top: (screen height minus its top) divided by (screen height plus its height). Every floating piece has its own speed, from -0.15 for the spiral to 0.35 for the far left card, and moves down by (progress minus 0.5) times its speed times 1200 px, so all of them line up at the midpoint and spread apart before and after it. A short CSS transition on transform (0.4 seconds for the cards, 0.15 seconds for the photo and accents, on a soft ease-out curve) smooths the steps between scroll events. Scroll events from the page or any scrolling parent schedule one frame. The capsule is an ellipse with a taller bottom, turned -12 degrees, and the photo inside is turned back and enlarged so the dog stays upright. The serif word's underline draws from left to right over 0.8 seconds once the section is 15% on screen. Below 900 px wide the cards and photo stack and the parallax is off.\nAccessibility: Headings, card titles and text are real text in reading order, and the photo has alt text; the curve, spiral and leaf are hidden from screen readers. With prefers-reduced-motion nothing moves with the scroll, the underline is shown at once and the scroll prompt stops pulsing. Nothing needs a pointer; card hover is a visual extra.\n\nTunable settings:\n- Parallax depth (px at speed 1): range 0 to 2400, step 50, default 1200\n- Capsule photo: select (Corgi puppy on orange / Corgi in a flower field / Corgi on a rock / Two dogs on a dirt road / Corgi lying on white / Corgi standing on white), default corgi-2\n- Eyebrow: text, default How we build\n- Intro headline: text, default Build pages that move with calm, deliberate care.\n- Section heading: text, default Clear, Calm, Considered\n- Underlined serif word: text, default motion.\n- Background: color, default #fbf8f1\n- Ink: color, default #0c1e18\n- Accent (eyebrow, curve, card hover): color, default #1a7a4c\n- Card: color, default #ffffff\n- Icon on hover: color, default #e6ff55\n- Spiral: color, default #e54c1e\n- Leaf: color, default #005236\n\nCurrent settings:\n{{SETTINGS}}\n\nFor the developer: Element contract (vanilla JavaScript, no dependencies):\n- The JavaScript defines a function mount(root, opts).\n- root is an empty container element. Set root.innerHTML to the markup first, then call mount(root, opts).\n- It returns an object with update(partialOpts) and destroy(). Call destroy() when the element is removed. Some elements also return replay().\n- The CSS classes all start with \"ef-\" so they will not collide with your styles.\n\nIn Figma:\n- Draw the resting state as a frame and the end state as a second frame; link them with Smart Animate to show the motion in a prototype.\n- Put the settings above in the frame's notes or Dev Mode annotations so the developer matches them.\n- Link https://enrichr.dev/elements/editorial-parallax-showcase.html in the handoff: the live demo and the copy-ready code are there. Developers can paste the prompts for Claude, Cursor or v0 from the Export menu.\nNothing is copied from another designer's file; this is original code from Enrichr.",
    "framer": "Add the \"Editorial parallax showcase\" element to Framer as a code component. Framer code components are React, so wrap the vanilla code like this. Check it in the Framer editor, as Framer's component API can change.\n\nThis is the \"Editorial parallax showcase\" element from the Enrichr Library: An editorial page section with a serif italic intro and four glass cards, a tilted capsule photo and two drawn accents that drift past at different speeds as you scroll.\nPage: https://enrichr.dev/elements/editorial-parallax-showcase.html\nMachine-readable spec: https://enrichr.dev/elements/editorial-parallax-showcase.json\n\nElement contract (vanilla JavaScript, no dependencies):\n- The JavaScript defines a function mount(root, opts).\n- root is an empty container element. Set root.innerHTML to the markup first, then call mount(root, opts).\n- It returns an object with update(partialOpts) and destroy(). Call destroy() when the element is removed. Some elements also return replay().\n- The CSS classes all start with \"ef-\" so they will not collide with your styles.\n\n1. In Framer: Assets > Code > New component. Name it EditorialParallaxShowcase.\n2. Paste the JavaScript below into a separate code file named editorial-parallax-showcase.js in the same project, with  export { mount };  and  export const markup = \"<the markup string>\";  added. Put the CSS into the component as a <style> tag.\n3. Component:\n```tsx\nimport { addPropertyControls, ControlType } from \"framer\"\nimport { useEffect, useRef } from \"react\";\nimport { markup, mount } from \"./editorial-parallax-showcase\"; // markup is the HTML string; mount is the JavaScript's mount function\n\nexport default function EditorialParallaxShowcase(props: any) {\n  const ref = useRef<HTMLDivElement>(null);\n  const fx = useRef<{ update: (o: object) => void; destroy: () => void } | null>(null);\n  useEffect(() => {\n    const root = ref.current;\n    if (!root) return;\n    root.innerHTML = markup;\n    fx.current = mount(root, props);\n    return () => { fx.current?.destroy(); fx.current = null; root.innerHTML = \"\"; };\n  }, []);\n  useEffect(() => { fx.current?.update(props); }, [JSON.stringify(props)]);\n  return <div ref={ref} />;\n}\n\naddPropertyControls(EditorialParallaxShowcase, {\n  depth: { type: ControlType.Number, title: \"Parallax depth\", min: 0, max: 2400, step: 50, defaultValue: 1200 },\n  photo: { type: ControlType.Enum, title: \"Capsule photo\", options: [\"corgi-1\",\"corgi-2\",\"corgi-3\",\"corgi-4\",\"corgi-5\",\"corgi-6\"], optionTitles: [\"Corgi puppy on orange\",\"Corgi in a flower field\",\"Corgi on a rock\",\"Two dogs on a dirt road\",\"Corgi lying on white\",\"Corgi standing on white\"], defaultValue: \"corgi-2\" },\n  eyebrow: { type: ControlType.String, title: \"Eyebrow\", defaultValue: \"How we build\" },\n  lede: { type: ControlType.String, title: \"Intro headline\", defaultValue: \"Build pages that move with calm, deliberate care.\" },\n  heading: { type: ControlType.String, title: \"Section heading\", defaultValue: \"Clear, Calm, Considered\" },\n  word: { type: ControlType.String, title: \"Underlined serif word\", defaultValue: \"motion.\" },\n  background: { type: ControlType.Color, title: \"Background\", defaultValue: \"#fbf8f1\" },\n  ink: { type: ControlType.Color, title: \"Ink\", defaultValue: \"#0c1e18\" },\n  accent: { type: ControlType.Color, title: \"Accent (eyebrow, curve, card hover)\", defaultValue: \"#1a7a4c\" },\n  card: { type: ControlType.Color, title: \"Card\", defaultValue: \"#ffffff\" },\n  highlight: { type: ControlType.Color, title: \"Icon on hover\", defaultValue: \"#e6ff55\" },\n  warm: { type: ControlType.Color, title: \"Spiral\", defaultValue: \"#e54c1e\" },\n  leaf: { type: ControlType.Color, title: \"Leaf\", defaultValue: \"#005236\" },\n})\n```\n4. Keep the behaviour of the source unchanged. Do not add dependencies. Respect prefers-reduced-motion. Keep text as real HTML.\n\nSettings:\n{{SETTINGS}}\n\nSource:\n{{CODE}}",
    "webflow": "Add the \"Editorial parallax showcase\" element to a Webflow site with an Embed element. Test it on the published or preview site: scripts in embeds may not run inside the Designer canvas.\n\nThis is the \"Editorial parallax showcase\" element from the Enrichr Library: An editorial page section with a serif italic intro and four glass cards, a tilted capsule photo and two drawn accents that drift past at different speeds as you scroll.\nPage: https://enrichr.dev/elements/editorial-parallax-showcase.html\nMachine-readable spec: https://enrichr.dev/elements/editorial-parallax-showcase.json\n\nElement contract (vanilla JavaScript, no dependencies):\n- The JavaScript defines a function mount(root, opts).\n- root is an empty container element. Set root.innerHTML to the markup first, then call mount(root, opts).\n- It returns an object with update(partialOpts) and destroy(). Call destroy() when the element is removed. Some elements also return replay().\n- The CSS classes all start with \"ef-\" so they will not collide with your styles.\n\n1. Add an Embed element where it should appear. Paste a <style> block with the CSS, one container <div id=\"enrichr-editorial-parallax-showcase\"></div>, and a <script> block with the JavaScript followed by:\n   mount(document.getElementById(\"enrichr-editorial-parallax-showcase\"), { ...your settings... });\n   (set the container's innerHTML to the markup first, as in the contract).\n2. Embed elements have a size limit (check Webflow's current number). If the code is longer, host the JS and CSS as files and link them from Custom code in the page settings, then keep only the container and the mount call in the Embed.\n3. Keep the behaviour of the source unchanged. Do not add dependencies. Respect prefers-reduced-motion. Keep text as real HTML.\n\nSettings:\n{{SETTINGS}}\n\nSource:\n{{CODE}}"
  },
  "exportTools": [
    "claude",
    "chatgpt",
    "cursor",
    "v0",
    "lovable",
    "bolt",
    "replit",
    "figma",
    "framer",
    "webflow"
  ],
  "accessibility": "Headings, card titles and text are real text in reading order, and the photo has alt text; the curve, spiral and leaf are hidden from screen readers. With prefers-reduced-motion nothing moves with the scroll, the underline is shown at once and the scroll prompt stops pulsing. Nothing needs a pointer; card hover is a visual extra.",
  "performance": "Only transform changes on scroll, one translate per piece, with one getBoundingClientRect read per frame. Work happens only when the page scrolls and the section is near the screen. The cards' backdrop blur is the heaviest part; drop it if you target very old phones.",
  "dependencies": [],
  "codepen": "https://codepen.io/Enrichr-Dev/pen/OPprwBr",
  "source": {
    "markup": "<div class=\"ef-eps\">\n  <div class=\"ef-eps__intro\">\n    <span class=\"ef-eps__eyebrow\">How we build</span>\n    <h2 class=\"ef-eps__lede\">Build pages that move with calm, deliberate care.</h2>\n    <p class=\"ef-eps__intro-text\">We pair careful layout with motion that earns its place. Real text, light code, and nothing that gets in the reader's way, from the first line to the last.</p>\n    <div class=\"ef-eps__prompt\">\n      <span class=\"ef-eps__prompt-text\">Scroll to explore the parts</span>\n      <svg class=\"ef-eps__down\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\" aria-hidden=\"true\" focusable=\"false\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M19 14l-7 7m0 0l-7-7m7 7V3\"/></svg>\n    </div>\n  </div>\n  <div class=\"ef-eps__main\">\n    <div class=\"ef-eps__head\">\n      <div class=\"ef-eps__head-l\">\n        <h2 class=\"ef-eps__heading\">Clear, Calm, Considered<br><span class=\"ef-eps__serif\">motion.</span></h2>\n        <p class=\"ef-eps__sub\">Plain code that does what it says, kind to readers and to their batteries, with no exceptions.</p>\n      </div>\n      <div class=\"ef-eps__head-r\" aria-hidden=\"true\">\n        <svg class=\"ef-eps__curve\" viewBox=\"0 0 443 454\" fill=\"none\" focusable=\"false\"><path fill=\"currentColor\" d=\"M359.477 453.019C359.488 453.324 359.743 453.562 360.048 453.551L365.011 453.376C365.315 453.365 365.554 453.11 365.543 452.805C365.532 452.501 365.277 452.262 364.972 452.273L360.56 452.429L360.405 448.017C360.394 447.712 360.138 447.474 359.834 447.485C359.529 447.496 359.291 447.751 359.302 448.056L359.477 453.019ZM1.13069 19.0358C201.979 -29.9272 338.641 28.0524 401.572 123.362C464.513 218.687 453.828 351.533 359.625 452.623L360.432 453.376C454.944 351.955 465.745 218.551 402.493 122.754C339.23 26.9416 202.021 -31.0734 0.869309 17.9636L1.13069 19.0358Z\"/></svg>\n      </div>\n    </div>\n    <div class=\"ef-eps__layout\">\n      <div class=\"ef-eps__pair\">\n        <div class=\"ef-eps__card ef-eps__float ef-eps__c1\" data-speed=\"0.35\">\n          <div class=\"ef-eps__icon\"><svg fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\" aria-hidden=\"true\" focusable=\"false\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M12 3v1m0 16v1m9-9h-1M4 12H3m15.364-6.364l-.707.707M6.343 17.657l-.707.707m0-12.728l.707.707m12.728 12.728l.707-.707M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"/></svg></div>\n          <h3 class=\"ef-eps__card-title\">Real Text, Always</h3>\n          <p class=\"ef-eps__card-text\">Headings stay headings and links stay links, so screen readers and search engines read the page as it was written.</p>\n        </div>\n        <div class=\"ef-eps__card ef-eps__float ef-eps__c2\" data-speed=\"0.12\">\n          <div class=\"ef-eps__icon\"><svg fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\" aria-hidden=\"true\" focusable=\"false\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\"/></svg></div>\n          <h3 class=\"ef-eps__card-title\">Open Code</h3>\n          <p class=\"ef-eps__card-text\">No black boxes. Every part ships as plain HTML, CSS and JavaScript you can read, copy and change.</p>\n        </div>\n      </div>\n      <div class=\"ef-eps__center\">\n        <div class=\"ef-eps__frame\">\n          <div class=\"ef-eps__float ef-eps__shape\" data-speed=\"0.04\">\n            <div class=\"ef-eps__oblong\"><img class=\"ef-eps__img\" src=\"/img/library/corgi-2.jpg\" alt=\"A corgi smiling in a field of flowers\" decoding=\"async\"></div>\n          </div>\n          <div class=\"ef-eps__float ef-eps__spiral\" data-speed=\"-0.15\" aria-hidden=\"true\">\n            <svg viewBox=\"0 0 100 100\" fill=\"none\" focusable=\"false\"><path d=\"M20,50 C20,30 40,15 60,20 C75,25 85,45 80,65 C75,80 50,90 35,80 C25,72 30,55 45,50 C55,45 65,55 60,65 C55,72 45,70 42,62\" stroke=\"currentColor\" stroke-width=\"4\" stroke-linecap=\"round\" fill=\"none\"/></svg>\n          </div>\n          <div class=\"ef-eps__float ef-eps__leaf\" data-speed=\"0.25\" aria-hidden=\"true\">\n            <svg viewBox=\"0 0 100 100\" fill=\"none\" focusable=\"false\"><path d=\"M10,80 Q35,85 55,65 Q85,35 90,10 Q65,15 35,45 Q15,65 10,80 Z\" fill=\"currentColor\" fill-opacity=\"0.15\" stroke=\"currentColor\" stroke-width=\"2\"/><path d=\"M10,80 Q50,55 90,10\" stroke=\"currentColor\" stroke-width=\"2\"/></svg>\n          </div>\n        </div>\n      </div>\n      <div class=\"ef-eps__pair\">\n        <div class=\"ef-eps__card ef-eps__float ef-eps__c3\" data-speed=\"0.18\">\n          <div class=\"ef-eps__icon\"><svg fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\" aria-hidden=\"true\" focusable=\"false\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M13 10V3L4 14h7v7l9-11h-7z\"/></svg></div>\n          <h3 class=\"ef-eps__card-title\">Light on Its Feet</h3>\n          <p class=\"ef-eps__card-text\">Motion runs on the compositor, pauses off screen and respects reduced motion, so pages stay quick on any phone.</p>\n        </div>\n        <div class=\"ef-eps__card ef-eps__float ef-eps__c4\" data-speed=\"0.08\">\n          <div class=\"ef-eps__icon\"><svg fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\" aria-hidden=\"true\" focusable=\"false\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z\"/></svg></div>\n          <h3 class=\"ef-eps__card-title\">Built to Last</h3>\n          <p class=\"ef-eps__card-text\">No frameworks to update and no libraries to load. What you paste today still works next year.</p>\n        </div>\n      </div>\n    </div>\n  </div>\n</div>",
    "css": "/* Enrichr Library · https://enrichr.dev */\n.ef-eps { --ef-eps-bg: #fbf8f1; --ef-eps-ink: #0c1e18; --ef-eps-acc: #1a7a4c; --ef-eps-card: #ffffff; --ef-eps-hi: #e6ff55; --ef-eps-warm: #e54c1e; --ef-eps-leaf: #005236;\n  --ef-eps-line: color-mix(in srgb, var(--ef-eps-ink) 10%, var(--ef-eps-bg)); --ef-eps-muted: color-mix(in srgb, var(--ef-eps-ink) 62%, var(--ef-eps-bg));\n  --ef-eps-serif: \"Instrument Serif\", \"Playfair Display\", Georgia, \"Times New Roman\", serif;\n  position: relative; width: 100%; box-sizing: border-box; overflow: hidden; border-radius: 1rem; background: var(--ef-eps-bg); color: var(--ef-eps-ink); font-family: \"Instrument Sans\", system-ui, sans-serif; -webkit-font-smoothing: antialiased; container-type: inline-size; }\n.ef-eps *, .ef-eps *::before, .ef-eps *::after { box-sizing: border-box; }\n.ef-eps svg { display: block; }\n\n/* intro */\n.ef-eps__intro { max-width: 80rem; margin: 0 auto; padding: 96px 24px 32px; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; }\n.ef-eps__eyebrow { display: block; margin-bottom: 16px; font-size: 12px; font-weight: 700; letter-spacing: 0.3em; text-transform: uppercase; color: var(--ef-eps-acc); }\n.ef-eps .ef-eps__lede { max-width: 56rem; margin: 0 0 24px; font-family: var(--ef-eps-serif); font-style: italic; font-weight: 400; font-size: 36px; line-height: 1.15; letter-spacing: normal; text-transform: none; color: var(--ef-eps-ink); opacity: 1; }\n.ef-eps .ef-eps__intro-text { max-width: 36rem; margin: 0 0 32px; font-size: 14px; line-height: 1.625; color: var(--ef-eps-muted); opacity: 1; }\n.ef-eps__prompt { display: flex; flex-direction: column; align-items: center; gap: 12px; }\n.ef-eps__prompt-text { font-size: 12px; font-weight: 700; letter-spacing: 0.25em; text-transform: uppercase; color: color-mix(in srgb, var(--ef-eps-ink) 40%, transparent); animation: ef-eps-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; }\n.ef-eps__down { width: 20px; height: 20px; color: var(--ef-eps-acc); animation: ef-eps-bounce 1s infinite; }\n@keyframes ef-eps-pulse { 50% { opacity: 0.5; } }\n@keyframes ef-eps-bounce { 0%, 100% { transform: translateY(-25%); animation-timing-function: cubic-bezier(0.8, 0, 1, 1); } 50% { transform: none; animation-timing-function: cubic-bezier(0, 0, 0.2, 1); } }\n.ef-eps.is-off .ef-eps__prompt-text, .ef-eps.is-off .ef-eps__down { animation-play-state: paused; }\n\n/* main section */\n.ef-eps__main { position: relative; max-width: 1440px; margin: 0 auto; padding: 96px 24px 8rem; user-select: none; }\n.ef-eps__head { position: relative; z-index: 10; display: grid; grid-template-columns: 1fr; gap: 32px; margin-bottom: 64px; }\n.ef-eps__head-l { display: flex; flex-direction: column; justify-content: center; }\n.ef-eps__head-r { display: none; }\n.ef-eps .ef-eps__heading { margin: 0; font-family: \"Instrument Sans\", system-ui, sans-serif; font-size: 30px; font-weight: 400; line-height: 1.25; letter-spacing: -0.025em; text-transform: none; color: var(--ef-eps-ink); opacity: 1; }\n.ef-eps__serif { position: relative; display: inline-block; margin-top: 8px; font-family: var(--ef-eps-serif); font-style: italic; }\n.ef-eps__serif::after { content: \"\"; position: absolute; bottom: 4px; left: 0; width: 100%; height: 1px; background: var(--ef-eps-ink); transform: scaleX(0); transform-origin: right; transition: transform 0.8s cubic-bezier(0.77, 0, 0.175, 1); }\n.ef-eps__serif.is-active::after { transform: scaleX(1); transform-origin: left; }\n.ef-eps .ef-eps__sub { max-width: 28rem; margin: 16px 0 0; font-size: 14px; line-height: 1.5; color: var(--ef-eps-muted); opacity: 1; }\n.ef-eps__curve { width: 280px; height: 280px; transform: rotate(15deg); color: color-mix(in srgb, var(--ef-eps-acc) 60%, transparent); }\n\n.ef-eps__layout { position: relative; width: 100%; min-height: 1000px; display: flex; flex-direction: column; }\n.ef-eps__pair { display: flex; flex-direction: column; gap: 32px; justify-content: space-between; padding: 0 8px; }\n.ef-eps__float { will-change: transform; transition: transform 0.15s cubic-bezier(0.25, 1, 0.5, 1); }\n.ef-eps__card { width: 100%; max-width: 320px; padding: 2.5rem 2rem; border-radius: 1.5rem; background: color-mix(in srgb, var(--ef-eps-card) 94%, transparent); -webkit-backdrop-filter: blur(20px); backdrop-filter: blur(20px); border: 1px solid color-mix(in srgb, var(--ef-eps-line) 40%, transparent); box-shadow: 0 20px 50px rgba(0, 0, 0, 0.02), inset 0 0 0 1px color-mix(in srgb, var(--ef-eps-card) 90%, transparent); transition: all 0.4s cubic-bezier(0.25, 1, 0.5, 1); }\n.ef-eps__card:hover { transform: translateY(-5px); box-shadow: 0 30px 60px color-mix(in srgb, var(--ef-eps-acc) 12%, transparent), inset 0 0 0 1px var(--ef-eps-card); border-color: var(--ef-eps-acc); }\n.ef-eps__icon { display: flex; align-items: center; justify-content: center; width: 52px; height: 52px; margin-bottom: 1.5rem; border-radius: 50%; background: var(--ef-eps-bg); border: 1px solid color-mix(in srgb, var(--ef-eps-line) 60%, transparent); box-shadow: 0 6px 15px rgba(0, 0, 0, 0.02); color: var(--ef-eps-ink); transition: all 0.3s ease; }\n.ef-eps__icon svg { width: 20px; height: 20px; }\n.ef-eps__c1 .ef-eps__icon svg { width: 24px; height: 24px; }\n.ef-eps__card:hover .ef-eps__icon { background: var(--ef-eps-ink); color: var(--ef-eps-hi); border-color: var(--ef-eps-ink); }\n.ef-eps .ef-eps__card-title { margin: 0 0 8px; font-family: \"Instrument Sans\", system-ui, sans-serif; font-size: 18px; font-weight: 600; line-height: 1.55; letter-spacing: -0.025em; text-transform: none; color: var(--ef-eps-ink); opacity: 1; }\n.ef-eps .ef-eps__card-text { margin: 0; font-size: 12px; line-height: 1.625; color: var(--ef-eps-muted); opacity: 1; }\n\n.ef-eps__center { position: relative; z-index: 10; display: flex; justify-content: center; align-items: center; width: 290px; height: 390px; margin: 48px auto; }\n.ef-eps__frame { position: relative; width: 100%; height: 100%; }\n.ef-eps__shape { width: 100%; height: 100%; }\n.ef-eps__oblong { position: relative; width: 100%; height: 100%; overflow: hidden; border-radius: 50% 50% 50% 50% / 45% 45% 55% 55%; transform: rotate(-12deg); box-shadow: 0 35px 80px color-mix(in srgb, var(--ef-eps-ink) 8%, transparent); border: 1px solid color-mix(in srgb, var(--ef-eps-line) 50%, transparent); background: var(--ef-eps-line); transition: transform 0.5s cubic-bezier(0.25, 1, 0.5, 1); }\n.ef-eps__img { display: block; width: 100%; height: 115%; object-fit: cover; transform: rotate(12deg) scale(1.15) translateY(-5%); transition: transform 0.3s ease-out; }\n.ef-eps__spiral { position: absolute; left: -48px; bottom: -32px; z-index: 30; width: 96px; height: 96px; color: color-mix(in srgb, var(--ef-eps-warm) 80%, transparent); filter: drop-shadow(0 10px 8px rgba(0, 0, 0, 0.04)) drop-shadow(0 4px 3px rgba(0, 0, 0, 0.1)); }\n.ef-eps__leaf { position: absolute; right: -32px; top: -48px; z-index: 30; width: 80px; height: 80px; color: color-mix(in srgb, var(--ef-eps-leaf) 80%, transparent); filter: drop-shadow(0 4px 3px rgba(0, 0, 0, 0.07)) drop-shadow(0 2px 2px rgba(0, 0, 0, 0.06)); }\n.ef-eps__spiral svg, .ef-eps__leaf svg { width: 100%; height: 100%; }\n\n@container (min-width: 640px) {\n  .ef-eps__pair { flex-direction: row; padding: 0; }\n}\n@container (min-width: 768px) {\n  .ef-eps .ef-eps__lede { font-size: 60px; }\n  .ef-eps .ef-eps__intro-text { font-size: 16px; }\n  .ef-eps__main { padding-left: 48px; padding-right: 48px; }\n  .ef-eps .ef-eps__heading { font-size: 48px; }\n  .ef-eps .ef-eps__sub { font-size: 16px; }\n  .ef-eps__center { width: 350px; height: 480px; }\n  .ef-eps__spiral { width: 128px; height: 128px; }\n  .ef-eps__leaf { width: 112px; height: 112px; }\n}\n@container (min-width: 900px) {\n  .ef-eps__head { grid-template-columns: repeat(12, minmax(0, 1fr)); margin-bottom: 96px; }\n  .ef-eps__head-l { grid-column: span 8 / span 8; }\n  .ef-eps__head-r { grid-column: span 4 / span 4; display: flex; align-items: center; justify-content: flex-end; position: relative; }\n  .ef-eps .ef-eps__heading { font-size: 60px; }\n  .ef-eps__layout { display: block; }\n  .ef-eps__pair { display: contents; }\n  .ef-eps__card { position: absolute; width: 23%; max-width: 300px; }\n  .ef-eps__c1 { left: 2%; top: 12%; }\n  .ef-eps__c2 { left: 27%; top: 2%; z-index: 20; }\n  .ef-eps__c3 { right: 27%; bottom: 2%; z-index: 20; }\n  .ef-eps__c4 { right: 2%; bottom: 12%; }\n  .ef-eps__center { position: absolute; left: 50%; top: 8%; width: 40%; max-width: 480px; height: 480px; margin: 0; transform: translateX(-50%); }\n}\n@media (prefers-reduced-motion: reduce) {\n  .ef-eps__prompt-text, .ef-eps__down { animation: none; }\n  .ef-eps__float { transform: none !important; transition: none; }\n  .ef-eps__serif::after { transition: none; }\n}",
    "js": "// Enrichr Library · https://enrichr.dev\n// Editorial parallax showcase: an editorial intro with a serif italic headline, then a section where four glass cards, a\n// tilted capsule photo and two drawn accents overlap. As the section passes through the viewport each piece moves at its\n// own speed: progress runs from 0 (section top at the bottom of the screen) to 1 (section bottom past the top), and each\n// piece shifts by (progress - 0.5) x its speed x 1200 px, smoothed by a short CSS transition. The serif word gets an\n// underline that draws in once the section is on screen. Below 900 px wide the layout stacks and the parallax switches off.\n// Scroll work is one requestAnimationFrame per scroll event while the section is near the viewport. Reduced motion keeps\n// everything in place, shows the underline at once and stops the scroll prompt from pulsing.\n// mount(root, { depth (px of travel at speed 1), photo (corgi-1 to corgi-6), eyebrow, lede, heading, word,\n//               background, ink, accent, card, highlight, warm (spiral), leaf })\nfunction mount(root, o) {\n  var reduce = window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n  var box = root.querySelector(\".ef-eps\");\n  var main = root.querySelector(\".ef-eps__main\");\n  var serif = root.querySelector(\".ef-eps__serif\");\n  var img = root.querySelector(\".ef-eps__img\");\n  var floats = [].slice.call(root.querySelectorAll(\".ef-eps__float\")).map(function (el) { return { el: el, speed: parseFloat(el.getAttribute(\"data-speed\")) || 0 }; });\n  var heading = root.querySelector(\".ef-eps__heading\");\n  var opts = {}, raf = 0, near = true, io = null, io2 = null, ro = null, destroyed = false, wide = true;\n  var ALT = { \"corgi-1\": \"A corgi puppy against an orange wall\", \"corgi-2\": \"A corgi smiling in a field of flowers\", \"corgi-3\": \"A corgi standing on a rock outdoors\", \"corgi-4\": \"Two dogs running down a dirt road\", \"corgi-5\": \"A corgi lying on a white background\", \"corgi-6\": \"A corgi standing on a white background\" };\n\n  function num(v, d) { v = Number(v); return isFinite(v) ? v : d; }\n  function draw() {\n    raf = 0;\n    if (destroyed) return;\n    wide = box.clientWidth >= 900;\n    if (reduce || !wide) { floats.forEach(function (f) { f.el.style.transform = \"\"; }); return; }\n    if (!near) return;\n    var vh = window.innerHeight || document.documentElement.clientHeight || 800;\n    var r = main.getBoundingClientRect();\n    var p = Math.max(0, Math.min(1, (vh - r.top) / (vh + r.height)));\n    var c = p - 0.5;\n    floats.forEach(function (f) { f.el.style.transform = \"translate3d(0,\" + (c * f.speed * opts.depth).toFixed(2) + \"px,0)\"; });\n  }\n  function kick() { if (!raf && !destroyed) raf = requestAnimationFrame(draw); }\n  function update(next) {\n    opts = Object.assign({\n      depth: 1200, photo: \"corgi-2\", eyebrow: \"How we build\", lede: \"Build pages that move with calm, deliberate care.\",\n      heading: \"Clear, Calm, Considered\", word: \"motion.\",\n      background: \"#fbf8f1\", ink: \"#0c1e18\", accent: \"#1a7a4c\", card: \"#ffffff\", highlight: \"#e6ff55\", warm: \"#e54c1e\", leaf: \"#005236\"\n    }, opts, next || {});\n    opts.depth = Math.max(0, num(opts.depth, 1200));\n    var photo = /^corgi-[1-6]$/.test(opts.photo) ? opts.photo : \"corgi-2\";\n    var src = \"/img/library/\" + photo + \".jpg\";\n    if (img.getAttribute(\"src\") !== src) { img.setAttribute(\"src\", src); img.alt = ALT[photo]; }\n    root.querySelector(\".ef-eps__eyebrow\").textContent = opts.eyebrow;\n    root.querySelector(\".ef-eps__lede\").textContent = opts.lede;\n    heading.firstChild.nodeValue = opts.heading;\n    serif.textContent = opts.word;\n    var map = { background: \"bg\", ink: \"ink\", accent: \"acc\", card: \"card\", highlight: \"hi\", warm: \"warm\", leaf: \"leaf\" };\n    Object.keys(map).forEach(function (k) { box.style.setProperty(\"--ef-eps-\" + map[k], opts[k]); });\n    kick();\n  }\n\n  update(o);\n  if (reduce) serif.classList.add(\"is-active\");\n  window.addEventListener(\"scroll\", kick, { passive: true, capture: true });\n  window.addEventListener(\"resize\", kick, { passive: true });\n  if (\"IntersectionObserver\" in window) {\n    io = new IntersectionObserver(function (e) { near = e[0].isIntersecting; if (near) kick(); }, { rootMargin: \"200px 0px\" });\n    io.observe(main);\n    io2 = new IntersectionObserver(function (e) {\n      e.forEach(function (x) { if (x.isIntersecting) serif.classList.add(\"is-active\"); });\n    }, { threshold: 0.15 });\n    io2.observe(main);\n  } else serif.classList.add(\"is-active\");\n  var introIo = null;\n  if (\"IntersectionObserver\" in window) { introIo = new IntersectionObserver(function (e) { box.classList.toggle(\"is-off\", !e[0].isIntersecting); }); introIo.observe(root.querySelector(\".ef-eps__intro\")); }\n  if (\"ResizeObserver\" in window) { ro = new ResizeObserver(kick); ro.observe(box); }\n  return {\n    update: update,\n    destroy: function () {\n      destroyed = true; cancelAnimationFrame(raf);\n      window.removeEventListener(\"scroll\", kick, { passive: true, capture: true });\n      window.removeEventListener(\"resize\", kick, { passive: true });\n      if (io) io.disconnect(); if (io2) io2.disconnect(); if (introIo) introIo.disconnect(); if (ro) ro.disconnect();\n    }\n  };\n}"
  }
}