{
  "id": "gradient-hands-hero",
  "kind": "element",
  "title": "Gradient hands hero",
  "summary": "A loud diagonal gradient hero with a huge three-line headline, a wobbling badge and two illustrated hands that sway, lean toward the pointer and sink away as you scroll past.",
  "url": "https://enrichr.dev/elements/gradient-hands-hero.html",
  "section": "hero",
  "techniques": [
    "pointer-interaction",
    "scroll-driven"
  ],
  "stack": [
    "Vanilla JS",
    "SVG"
  ],
  "frameworks": [
    "React",
    "Next.js",
    "Vanilla"
  ],
  "mood": [
    "playful",
    "energetic"
  ],
  "intents": [
    "playful gradient hero section",
    "illustrated hands hero animation",
    "big bold headline hero with badge",
    "hero that reacts to the mouse",
    "fun landing page hero with scroll exit"
  ],
  "status": "tested",
  "params": [
    {
      "key": "headline",
      "label": "Headline (lines separated by |)",
      "type": "text",
      "value": "Pages|that wave|back"
    },
    {
      "key": "badge",
      "label": "Badge text (lines separated by |)",
      "type": "text",
      "value": "Now in|the Library|+"
    },
    {
      "key": "prompt",
      "label": "Scroll prompt",
      "type": "text",
      "value": "Scroll and see what it can do"
    },
    {
      "key": "from",
      "label": "Gradient start",
      "type": "color",
      "value": "#005236"
    },
    {
      "key": "to",
      "label": "Gradient end",
      "type": "color",
      "value": "#e6ff55"
    },
    {
      "key": "handLeft",
      "label": "Left hand",
      "type": "color",
      "value": "#0a6b46"
    },
    {
      "key": "handRight",
      "label": "Right hand",
      "type": "color",
      "value": "#005236"
    },
    {
      "key": "accent",
      "label": "Pills and arrow",
      "type": "color",
      "value": "#e6ff55"
    },
    {
      "key": "ink",
      "label": "Ink (type and outlines)",
      "type": "color",
      "value": "#0c1e18"
    },
    {
      "key": "paper",
      "label": "Badge and prompt",
      "type": "color",
      "value": "#fbf8f1"
    }
  ],
  "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 \"Gradient hands hero\" element to this project.\n\nThis is the \"Gradient hands hero\" element from the Enrichr Library: A loud diagonal gradient hero with a huge three-line headline, a wobbling badge and two illustrated hands that sway, lean toward the pointer and sink away as you scroll past.\nPage: https://enrichr.dev/elements/gradient-hands-hero.html\nMachine-readable spec: https://enrichr.dev/elements/gradient-hands-hero.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/gradient-hands-hero.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 \"Gradient hands hero\" 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 \"Gradient hands hero\" element from the Enrichr Library: A loud diagonal gradient hero with a huge three-line headline, a wobbling badge and two illustrated hands that sway, lean toward the pointer and sink away as you scroll past.\nPage: https://enrichr.dev/elements/gradient-hands-hero.html\nMachine-readable spec: https://enrichr.dev/elements/gradient-hands-hero.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 \"Gradient hands hero\" element to this codebase.\n\nThis is the \"Gradient hands hero\" element from the Enrichr Library: A loud diagonal gradient hero with a huge three-line headline, a wobbling badge and two illustrated hands that sway, lean toward the pointer and sink away as you scroll past.\nPage: https://enrichr.dev/elements/gradient-hands-hero.html\nMachine-readable spec: https://enrichr.dev/elements/gradient-hands-hero.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-gradient-hands-hero.mdc so the rule stays with the project:\n---\ndescription: How to use the Enrichr Gradient hands hero 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 \"Gradient hands hero\" element. Tailwind is available but this component needs no utility classes.\n\nThis is the \"Gradient hands hero\" element from the Enrichr Library: A loud diagonal gradient hero with a huge three-line headline, a wobbling badge and two illustrated hands that sway, lean toward the pointer and sink away as you scroll past.\nPage: https://enrichr.dev/elements/gradient-hands-hero.html\nMachine-readable spec: https://enrichr.dev/elements/gradient-hands-hero.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- gradient-hands-hero.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 \"./gradient-hands-hero\"; // markup is the HTML string; mount is the JavaScript's mount function\n\nexport default function GradientHandsHero(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 \"Gradient hands hero\" element to this React + Vite + TypeScript + Tailwind project. Do not install any packages.\n\nThis is the \"Gradient hands hero\" element from the Enrichr Library: A loud diagonal gradient hero with a huge three-line headline, a wobbling badge and two illustrated hands that sway, lean toward the pointer and sink away as you scroll past.\nPage: https://enrichr.dev/elements/gradient-hands-hero.html\nMachine-readable spec: https://enrichr.dev/elements/gradient-hands-hero.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- gradient-hands-hero.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/GradientHandsHero.tsx):\n```tsx\n\"use client\";\nimport { useEffect, useRef } from \"react\";\nimport { markup, mount } from \"./gradient-hands-hero\"; // markup is the HTML string; mount is the JavaScript's mount function\n\nexport default function GradientHandsHero(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 \"Gradient hands hero\" element.\n\nThis is the \"Gradient hands hero\" element from the Enrichr Library: A loud diagonal gradient hero with a huge three-line headline, a wobbling badge and two illustrated hands that sway, lean toward the pointer and sink away as you scroll past.\nPage: https://enrichr.dev/elements/gradient-hands-hero.html\nMachine-readable spec: https://enrichr.dev/elements/gradient-hands-hero.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), gradient-hands-hero.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 \"Gradient hands hero\" element. No packages, no server code.\n\nThis is the \"Gradient hands hero\" element from the Enrichr Library: A loud diagonal gradient hero with a huge three-line headline, a wobbling badge and two illustrated hands that sway, lean toward the pointer and sink away as you scroll past.\nPage: https://enrichr.dev/elements/gradient-hands-hero.html\nMachine-readable spec: https://enrichr.dev/elements/gradient-hands-hero.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 gradient-hands-hero.js and then main.js), style.css (the CSS below), gradient-hands-hero.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 \"Gradient hands hero\" 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 \"Gradient hands hero\" element from the Enrichr Library: A loud diagonal gradient hero with a huge three-line headline, a wobbling badge and two illustrated hands that sway, lean toward the pointer and sink away as you scroll past.\nPage: https://enrichr.dev/elements/gradient-hands-hero.html\nMachine-readable spec: https://enrichr.dev/elements/gradient-hands-hero.json\n\nWhat it does: The background is one 135 degree linear gradient with five stops mixed from the two gradient colours, so it stays loud and smooth for any pair. The hands are one SVG path each, filled with their own gradient and outlined in ink, pinned to the bottom corners with their pivot at the wrist. One requestAnimationFrame loop drives them: an idle clock adds 0.016 per frame at 60 fps, the left hand turns -8 degrees plus a sine wave of 3 degrees at 1.2 times the clock, the right hand 8 degrees plus a cosine wave at 1.1 times, and both add up to 5 degrees toward the side of the element the pointer is on. The distance the hero has scrolled above the top of the screen is eased 8.5% of the way per frame, like the smooth scroll of the original page; as it reaches 90% of the hero's height the hands sink by 60% of the height and the headline rises by 18% and fades out. The badge wobbles between 9 and 17 degrees over 5 seconds and the arrow in the scroll prompt bobs 4 px every 1.6 seconds, both in CSS. A white dot with a difference blend follows the pointer and swells to 52 px over the pills and the badge.\nAccessibility: The headline, badge, prompt and FAQ link are real text; the hands and the pointer dot are hidden from screen readers. With prefers-reduced-motion the hands rest at their tilt, the badge and arrow stop, and scrolling no longer moves anything. The FAQ link keeps a visible focus ring, and the system cursor comes back on touch screens.\n\nTunable settings:\n- Headline (lines separated by |): text, default Pages|that wave|back\n- Badge text (lines separated by |): text, default Now in|the Library|+\n- Scroll prompt: text, default Scroll and see what it can do\n- Gradient start: color, default #005236\n- Gradient end: color, default #e6ff55\n- Left hand: color, default #0a6b46\n- Right hand: color, default #005236\n- Pills and arrow: color, default #e6ff55\n- Ink (type and outlines): color, default #0c1e18\n- Badge and prompt: color, default #fbf8f1\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/gradient-hands-hero.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 \"Gradient hands hero\" 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 \"Gradient hands hero\" element from the Enrichr Library: A loud diagonal gradient hero with a huge three-line headline, a wobbling badge and two illustrated hands that sway, lean toward the pointer and sink away as you scroll past.\nPage: https://enrichr.dev/elements/gradient-hands-hero.html\nMachine-readable spec: https://enrichr.dev/elements/gradient-hands-hero.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 GradientHandsHero.\n2. Paste the JavaScript below into a separate code file named gradient-hands-hero.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 \"./gradient-hands-hero\"; // markup is the HTML string; mount is the JavaScript's mount function\n\nexport default function GradientHandsHero(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(GradientHandsHero, {\n  headline: { type: ControlType.String, title: \"Headline (lines separated by |)\", defaultValue: \"Pages|that wave|back\" },\n  badge: { type: ControlType.String, title: \"Badge text (lines separated by |)\", defaultValue: \"Now in|the Library|+\" },\n  prompt: { type: ControlType.String, title: \"Scroll prompt\", defaultValue: \"Scroll and see what it can do\" },\n  from: { type: ControlType.Color, title: \"Gradient start\", defaultValue: \"#005236\" },\n  to: { type: ControlType.Color, title: \"Gradient end\", defaultValue: \"#e6ff55\" },\n  handLeft: { type: ControlType.Color, title: \"Left hand\", defaultValue: \"#0a6b46\" },\n  handRight: { type: ControlType.Color, title: \"Right hand\", defaultValue: \"#005236\" },\n  accent: { type: ControlType.Color, title: \"Pills and arrow\", defaultValue: \"#e6ff55\" },\n  ink: { type: ControlType.Color, title: \"Ink (type and outlines)\", defaultValue: \"#0c1e18\" },\n  paper: { type: ControlType.Color, title: \"Badge and prompt\", defaultValue: \"#fbf8f1\" },\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 \"Gradient hands hero\" 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 \"Gradient hands hero\" element from the Enrichr Library: A loud diagonal gradient hero with a huge three-line headline, a wobbling badge and two illustrated hands that sway, lean toward the pointer and sink away as you scroll past.\nPage: https://enrichr.dev/elements/gradient-hands-hero.html\nMachine-readable spec: https://enrichr.dev/elements/gradient-hands-hero.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-gradient-hands-hero\"></div>, and a <script> block with the JavaScript followed by:\n   mount(document.getElementById(\"enrichr-gradient-hands-hero\"), { ...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": "The headline, badge, prompt and FAQ link are real text; the hands and the pointer dot are hidden from screen readers. With prefers-reduced-motion the hands rest at their tilt, the badge and arrow stop, and scrolling no longer moves anything. The FAQ link keeps a visible focus ring, and the system cursor comes back on touch screens.",
  "performance": "Each frame sets three transforms and one opacity; there is no layout work. The hands are SVG with a drop shadow, promoted to their own layers so the shadow is painted once. The loop pauses off screen and in hidden tabs, and the CSS wobble and bob pause off screen too.",
  "dependencies": [],
  "codepen": "https://codepen.io/Enrichr-Dev/pen/jEBXpQN",
  "source": {
    "markup": "<div class=\"ef-ghh\">\n  <div class=\"ef-ghh__logo\"><svg viewBox=\"0 0 50 50\" aria-hidden=\"true\" focusable=\"false\"><path fill=\"currentColor\" d=\"m34.213 25.361 c0 2.655 1.381 4.808 3.086 4.808 0.781 0 1.494 -0.452 2.038 -1.198 0.267 -0.366 0.688 -0.589 1.142 -0.589 h0.054 c0.774 0 1.401 0.627 1.401 1.401 v10.65 h-10.651 c-0.774 0 -1.401 0.627 -1.401 1.401 v0.054 c0 0.453 0.222 0.874 0.589 1.141 0.746 0.544 1.198 1.257 1.198 2.038 0 1.705 -2.152 3.086 -4.808 3.086 -2.655 0 -4.808 -1.381 -4.808 -3.086 0 -0.781 0.452 -1.494 1.198 -2.038 0.366 -0.267 0.589 -0.688 0.589 -1.142 v-0.054 c0 -0.774 -0.627 -1.401 -1.401 -1.401 h-10.65 v-10.651 c0 -0.774 -0.627 -1.401 -1.401 -1.401 h-0.054 c-0.453 0 -0.875 0.222 -1.142 0.589 -0.543 0.746 -1.257 1.198 -2.038 1.198 -1.705 0 -3.086 -2.152 -3.086 -4.808 0 -2.655 1.381 -4.808 3.086 -4.808 0.781 0 1.495 0.452 2.038 1.198 0.267 0.366 0.688 0.589 1.141 0.589 h0.054 c0.774 0 1.401 -0.627 1.401 -1.401 v-10.65 h10.65 c0.774 0 1.401 -0.627 1.401 -1.401 v-0.054 c0 -0.453 -0.222 -0.875 -0.589 -1.142 -0.746 -0.543 -1.198 -1.257 -1.198 -2.038 0 -1.705 2.152 -3.086 4.808 -3.086 2.655 0 4.808 1.381 4.808 3.086 0 0.781 -0.452 1.495 -1.198 2.038 -0.366 0.267 -0.589 0.688 -0.589 1.141 v0.054 c0 0.774 0.627 1.401 1.401 1.401 h10.65 v10.65 c0 0.774 -0.627 1.401 -1.401 1.401 h-0.053 c-0.453 0 -0.874 -0.222 -1.141 -0.589 -0.544 -0.746 -1.257 -1.198 -2.038 -1.198 -1.705 0 -3.086 2.152 -3.086 4.808 z\"/></svg><span class=\"ef-ghh__word\">Enrichr</span></div>\n  <div class=\"ef-ghh__badge ef-ghh__hot\"><span class=\"ef-ghh__badge-text\">Now in<br>the Library<br>+</span></div>\n  <div class=\"ef-ghh__hero\">\n    <h2 class=\"ef-ghh__title\"></h2>\n    <div class=\"ef-ghh__scroll ef-ghh__hot\">Scroll and see what it can do <i class=\"ef-ghh__bob\" aria-hidden=\"true\">&#8595;</i></div>\n    <svg class=\"ef-ghh__hand ef-ghh__hand--l\" viewBox=\"0 0 300 340\" aria-hidden=\"true\" focusable=\"false\">\n      <defs><linearGradient class=\"ef-ghh__gl\" x1=\"0\" y1=\"1\" x2=\"1\" y2=\"0\"><stop offset=\"0\" class=\"ef-ghh__gl0\"/><stop offset=\"1\" class=\"ef-ghh__gl1\"/></linearGradient></defs>\n      <g class=\"ef-ghh__hand-g\" stroke-width=\"5\" stroke-linejoin=\"round\" stroke-linecap=\"round\">\n        <path class=\"ef-ghh__palm\" d=\"M72 196 L228 196 C248 226 254 266 242 304 L230 342 L90 342 C82 304 68 256 72 196 Z\"/>\n        <path class=\"ef-ghh__palm\" d=\"M62 200 C53 172 50 148 54 130 C58 112 79 110 85 125 C91 146 95 172 100 202 Z\"/>\n        <path class=\"ef-ghh__palm\" d=\"M99 200 C91 156 87 114 93 88 C98 66 124 64 131 85 C139 113 139 154 142 200 Z\"/>\n        <path class=\"ef-ghh__palm\" d=\"M141 202 C135 146 135 94 141 70 C147 46 175 46 181 70 C187 94 185 146 186 202 Z\"/>\n        <path class=\"ef-ghh__palm\" d=\"M185 200 C185 156 187 112 195 90 C203 66 231 70 233 94 C235 124 231 162 227 204 Z\"/>\n        <path class=\"ef-ghh__palm\" d=\"M212 262 C236 244 262 214 274 182 C283 160 270 142 253 148 C238 154 230 178 217 202 Z\"/>\n        <g fill=\"none\" stroke=\"var(--ef-ghh-ink)\" stroke-opacity=\"0.32\" stroke-width=\"3\">\n          <path d=\"M64 168 Q74 172 86 166 M70 142 Q76 146 84 142\"/>\n          <path d=\"M97 150 Q112 156 130 148 M98 118 Q112 124 128 116 M103 92 Q112 96 124 92\"/>\n          <path d=\"M142 140 Q161 147 184 138 M142 108 Q161 115 183 106 M146 78 Q162 84 178 76\"/>\n          <path d=\"M187 150 Q208 156 228 148 M190 120 Q210 126 230 118\"/>\n          <path d=\"M102 244 Q150 268 214 236\"/>\n          <path d=\"M98 270 Q146 296 206 276\"/>\n          <path d=\"M214 214 Q196 256 206 306\"/>\n          <path d=\"M240 168 Q252 172 262 166\"/>\n        </g>\n        <g fill=\"var(--ef-ghh-paper)\" fill-opacity=\"0.42\" stroke=\"none\">\n          <path d=\"M60 126 Q69 114 80 124 Q70 130 60 126 Z\"/>\n          <path d=\"M100 84 Q112 70 124 84 Q112 90 100 84 Z\"/>\n          <path d=\"M148 66 Q161 50 175 66 Q161 74 148 66 Z\"/>\n          <path d=\"M197 88 Q210 72 224 88 Q210 96 197 88 Z\"/>\n          <path d=\"M258 152 Q267 146 270 160 Q262 164 258 152 Z\"/>\n        </g>\n        <g fill=\"var(--ef-ghh-paper)\" fill-opacity=\"0.16\" stroke=\"none\">\n          <path d=\"M76 204 L100 204 C98 250 104 300 100 340 L92 340 C84 300 72 252 76 204 Z\"/>\n          <path d=\"M146 80 C144 120 144 160 146 196 L154 196 C152 160 154 120 156 84 Z\"/>\n        </g>\n      </g>\n    </svg>\n    <svg class=\"ef-ghh__hand ef-ghh__hand--r\" viewBox=\"0 0 300 340\" aria-hidden=\"true\" focusable=\"false\">\n      <defs><linearGradient class=\"ef-ghh__gr\" x1=\"1\" y1=\"1\" x2=\"0\" y2=\"0\"><stop offset=\"0\" class=\"ef-ghh__gr0\"/><stop offset=\"1\" class=\"ef-ghh__gr1\"/></linearGradient></defs>\n      <g class=\"ef-ghh__hand-g\" stroke-width=\"5\" stroke-linejoin=\"round\" stroke-linecap=\"round\" transform=\"translate(300,0) scale(-1,1)\">\n        <path class=\"ef-ghh__palm\" d=\"M72 196 L228 196 C248 226 254 266 242 304 L230 342 L90 342 C82 304 68 256 72 196 Z\"/>\n        <path class=\"ef-ghh__palm\" d=\"M62 200 C53 172 50 148 54 130 C58 112 79 110 85 125 C91 146 95 172 100 202 Z\"/>\n        <path class=\"ef-ghh__palm\" d=\"M99 200 C91 156 87 114 93 88 C98 66 124 64 131 85 C139 113 139 154 142 200 Z\"/>\n        <path class=\"ef-ghh__palm\" d=\"M141 202 C135 146 135 94 141 70 C147 46 175 46 181 70 C187 94 185 146 186 202 Z\"/>\n        <path class=\"ef-ghh__palm\" d=\"M185 200 C185 156 187 112 195 90 C203 66 231 70 233 94 C235 124 231 162 227 204 Z\"/>\n        <path class=\"ef-ghh__palm\" d=\"M212 262 C236 244 262 214 274 182 C283 160 270 142 253 148 C238 154 230 178 217 202 Z\"/>\n        <g fill=\"none\" stroke=\"var(--ef-ghh-ink)\" stroke-opacity=\"0.32\" stroke-width=\"3\">\n          <path d=\"M64 168 Q74 172 86 166 M70 142 Q76 146 84 142\"/>\n          <path d=\"M97 150 Q112 156 130 148 M98 118 Q112 124 128 116 M103 92 Q112 96 124 92\"/>\n          <path d=\"M142 140 Q161 147 184 138 M142 108 Q161 115 183 106 M146 78 Q162 84 178 76\"/>\n          <path d=\"M187 150 Q208 156 228 148 M190 120 Q210 126 230 118\"/>\n          <path d=\"M102 244 Q150 268 214 236\"/>\n          <path d=\"M98 270 Q146 296 206 276\"/>\n          <path d=\"M214 214 Q196 256 206 306\"/>\n          <path d=\"M240 168 Q252 172 262 166\"/>\n        </g>\n        <g fill=\"var(--ef-ghh-paper)\" fill-opacity=\"0.42\" stroke=\"none\">\n          <path d=\"M60 126 Q69 114 80 124 Q70 130 60 126 Z\"/>\n          <path d=\"M100 84 Q112 70 124 84 Q112 90 100 84 Z\"/>\n          <path d=\"M148 66 Q161 50 175 66 Q161 74 148 66 Z\"/>\n          <path d=\"M197 88 Q210 72 224 88 Q210 96 197 88 Z\"/>\n          <path d=\"M258 152 Q267 146 270 160 Q262 164 258 152 Z\"/>\n        </g>\n        <g fill=\"var(--ef-ghh-paper)\" fill-opacity=\"0.16\" stroke=\"none\">\n          <path d=\"M76 204 L100 204 C98 250 104 300 100 340 L92 340 C84 300 72 252 76 204 Z\"/>\n          <path d=\"M146 80 C144 120 144 160 146 196 L154 196 C152 160 154 120 156 84 Z\"/>\n        </g>\n      </g>\n    </svg>\n  </div>\n  <a class=\"ef-ghh__faq ef-ghh__hot\" href=\"#\">FAQ <b aria-hidden=\"true\">&#8593;</b></a>\n  <div class=\"ef-ghh__cursor\" aria-hidden=\"true\"></div>\n</div>",
    "css": "/* Enrichr Library · https://enrichr.dev */\n.ef-ghh { --ef-ghh-a: #005236; --ef-ghh-b: #e6ff55; --ef-ghh-ink: #0c1e18; --ef-ghh-acc: #e6ff55; --ef-ghh-paper: #fbf8f1;\n  position: relative; flex: 1 0 auto; width: 100%; height: 100%; min-height: 36rem; box-sizing: border-box; overflow: hidden; border-radius: 1rem; isolation: isolate;\n  background: linear-gradient(135deg, var(--ef-ghh-a) 0%, color-mix(in srgb, var(--ef-ghh-a) 72%, var(--ef-ghh-b)) 26%, color-mix(in srgb, var(--ef-ghh-a) 46%, var(--ef-ghh-b)) 52%, color-mix(in srgb, var(--ef-ghh-a) 18%, var(--ef-ghh-b)) 78%, var(--ef-ghh-b) 100%);\n  color: var(--ef-ghh-ink); font-family: \"Parkinsans\", \"Space Grotesk\", sans-serif; container-type: inline-size; touch-action: pan-y; }\n.ef-ghh *, .ef-ghh *::before, .ef-ghh *::after { box-sizing: border-box; }\n@media (pointer: fine) { .ef-ghh, .ef-ghh a { cursor: none; } }\n\n.ef-ghh__logo { position: absolute; top: 26px; left: 50%; z-index: 8; transform: translateX(-50%); display: flex; align-items: center; gap: 8px; padding: 8px 18px 8px 14px; border: 2px solid var(--ef-ghh-ink); border-radius: 999px; background: var(--ef-ghh-acc); box-shadow: 0 3px 0 var(--ef-ghh-ink); font-weight: 700; font-size: 17px; line-height: 1; white-space: nowrap; }\n.ef-ghh__logo svg { width: 22px; height: 22px; display: block; }\n.ef-ghh__word { letter-spacing: 0.01em; }\n\n.ef-ghh__badge { position: absolute; top: 34px; right: 4cqi; z-index: 8; width: 96px; height: 96px; border-radius: 50%; display: flex; align-items: center; justify-content: center; text-align: center; background: var(--ef-ghh-paper); border: 2px solid var(--ef-ghh-ink); font-weight: 800; font-size: 13px; line-height: 1.15; text-transform: uppercase; transform: rotate(12deg); animation: ef-ghh-wob 5s ease-in-out infinite; }\n.ef-ghh__badge-text { display: block; }\n@keyframes ef-ghh-wob { 0%, 100% { transform: rotate(9deg); } 50% { transform: rotate(17deg) scale(1.04); } }\n\n.ef-ghh__hero { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 5.5rem 6cqi; }\n.ef-ghh .ef-ghh__title { position: relative; z-index: 5; margin: 0; max-width: none; font-family: \"Parkinsans\", \"Space Grotesk\", sans-serif; font-size: clamp(3.6rem, 11.5cqi, 11.25rem); font-weight: 800; letter-spacing: 0.005em; line-height: 0.96; text-align: center; text-transform: uppercase; color: var(--ef-ghh-ink); opacity: 1; will-change: transform, opacity; }\n.ef-ghh__scroll { position: relative; z-index: 6; margin-top: 2.2rem; display: inline-flex; align-items: center; gap: 12px; padding: 15px 30px; border: 2px solid var(--ef-ghh-ink); border-radius: 999px; background: var(--ef-ghh-paper); box-shadow: 0 4px 0 rgba(0, 0, 0, 0.85); font-family: \"Instrument Sans\", system-ui, sans-serif; font-size: 15px; font-weight: 600; line-height: 1.2; }\n.ef-ghh__bob { width: 26px; height: 26px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; background: var(--ef-ghh-acc); border: 2px solid var(--ef-ghh-ink); font-style: normal; animation: ef-ghh-bob 1.6s infinite; }\n@keyframes ef-ghh-bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(4px); } }\n\n.ef-ghh__hand { position: absolute; bottom: -6%; z-index: 2; width: clamp(260px, 34cqi, 520px); height: auto; overflow: visible; transform-origin: 50% 100%; will-change: transform; filter: drop-shadow(0 20px 40px rgba(0, 0, 0, 0.15)); }\n.ef-ghh__hand--l { left: -4cqi; transform: rotate(-8deg); }\n.ef-ghh__hand--r { right: -4cqi; transform: rotate(8deg); }\n.ef-ghh__hand-g { stroke: var(--ef-ghh-ink); }\n\n.ef-ghh__faq { position: absolute; left: 24px; bottom: 22px; z-index: 8; display: flex; align-items: center; gap: 8px; padding: 12px 20px; border: 2px solid var(--ef-ghh-ink); border-radius: 999px; background: var(--ef-ghh-acc); box-shadow: 0 4px 0 rgba(0, 0, 0, 0.85); color: var(--ef-ghh-ink); font-family: \"Instrument Sans\", system-ui, sans-serif; font-weight: 700; font-size: 14px; line-height: 1; text-decoration: none; }\n.ef-ghh__faq b { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; border: 2px solid var(--ef-ghh-ink); border-radius: 50%; font-size: 12px; }\n.ef-ghh__faq:focus-visible { outline: 3px solid var(--ef-ghh-ink); outline-offset: 3px; }\n\n.ef-ghh__cursor { position: absolute; left: 0; top: 0; z-index: 20; width: 18px; height: 18px; margin: -9px 0 0 -9px; border-radius: 50%; background: #fff; mix-blend-mode: difference; pointer-events: none; opacity: 0; transition: width 0.2s, height 0.2s, margin 0.2s, opacity 0.2s; }\n.ef-ghh__cursor.is-on { opacity: 1; }\n.ef-ghh__cursor.is-big { width: 52px; height: 52px; margin: -26px 0 0 -26px; }\n@media (pointer: coarse) { .ef-ghh__cursor { display: none; } }\n\n@container (max-width: 820px) {\n  .ef-ghh__badge { width: 76px; height: 76px; font-size: 11px; }\n}\n.ef-ghh.is-off .ef-ghh__badge, .ef-ghh.is-off .ef-ghh__bob { animation-play-state: paused; }\n@media (prefers-reduced-motion: reduce) {\n  .ef-ghh__badge, .ef-ghh__bob { animation: none; }\n  .ef-ghh__cursor { transition: none; }\n}",
    "js": "// Enrichr Library · https://enrichr.dev\n// Gradient hands hero: a loud diagonal gradient, a huge three-line headline, a wobbling round badge, a logo pill and a\n// scroll prompt with a bobbing arrow, framed by two drawn hands (palm, four fingers, thumb, knuckle creases, nails and palm lines) at the bottom corners. Each frame the hands sway\n// on their own slow sine and cosine waves (3 degrees, at 1.2 and 1.1 times an idle clock), lean up to 5 degrees toward\n// the side the pointer is on, and when the hero is scrolled past they sink by up to 60% of its height while the headline\n// lifts by 18% and fades. The scroll value is eased 8.5% of the way each frame, like the smooth scroll of the original.\n// A white dot with a difference blend follows the pointer and swells over the pills and the badge.\n// Reduced motion holds the hands at rest and stops the wobble, bob and scroll reactions. The loop pauses off screen and in\n// hidden tabs.\n// mount(root, { headline (lines separated by |), badge (lines separated by |), prompt, from (gradient start), to (gradient end),\n//               handLeft, handRight, accent (pills), ink, paper (badge and prompt) })\nfunction mount(root, o) {\n  var reduce = window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n  var box = root.querySelector(\".ef-ghh\");\n  var title = root.querySelector(\".ef-ghh__title\");\n  var badge = root.querySelector(\".ef-ghh__badge-text\");\n  var scrollBtn = root.querySelector(\".ef-ghh__scroll\");\n  var handL = root.querySelector(\".ef-ghh__hand--l\");\n  var handR = root.querySelector(\".ef-ghh__hand--r\");\n  var cursor = root.querySelector(\".ef-ghh__cursor\");\n  var uid = \"ef-ghh-\" + Math.random().toString(36).slice(2, 8);\n  var opts = {}, raf = 0, last = 0, idle = 0, cur = 0, visible = true, destroyed = false, io = null, ro = null, offs = [];\n  var W = 1, H = 1, mouse = { x: 0.5, y: 0.5 };\n\n  [[\"ef-ghh__gl\", handL], [\"ef-ghh__gr\", handR]].forEach(function (g, i) {\n    var lg = g[1].querySelector(\".\" + g[0]); lg.id = uid + \"-\" + i;\n    Array.prototype.forEach.call(g[1].querySelectorAll(\".ef-ghh__palm\"), function (p) { p.setAttribute(\"fill\", \"url(#\" + lg.id + \")\"); });\n  });\n  function hex(h, d) { var m = /^#?([0-9a-f]{6})$/i.exec(h || \"\"); var v = parseInt(m ? m[1] : d, 16); return [v >> 16, (v >> 8) & 255, v & 255]; }\n  function mix(a, b, t) { var x = hex(a, \"000000\"), y = hex(b, \"ffffff\"); return \"rgb(\" + x.map(function (v, i) { return Math.round(v + (y[i] - v) * t); }).join(\",\") + \")\"; }\n  function esc(s) { return String(s).replace(/[&<>\"]/g, function (c) { return { \"&\": \"&amp;\", \"<\": \"&lt;\", \">\": \"&gt;\", '\"': \"&quot;\" }[c]; }); }\n\n  function frame(dt) {\n    var r = box.getBoundingClientRect();\n    var target = Math.max(0, -r.top);\n    if (reduce) cur = 0;\n    else { cur += (target - cur) * (1 - Math.pow(1 - 0.085, dt * 60)); if (Math.abs(cur - target) < 0.05) cur = target; }\n    idle += reduce ? 0 : 0.016 * dt * 60;\n    var mR = reduce ? 0 : mouse.x - 0.5;\n    var gone = Math.min(cur / (H * 0.9), 1);\n    var sway = reduce ? 0 : 1;\n    handL.style.transform = \"translateY(\" + (gone * 0.6 * H).toFixed(1) + \"px) rotate(\" + (-8 + Math.sin(idle * 1.2) * 3 * sway + mR * 10).toFixed(3) + \"deg)\";\n    handR.style.transform = \"translateY(\" + (gone * 0.6 * H).toFixed(1) + \"px) rotate(\" + (8 + Math.cos(idle * 1.1) * 3 * sway + mR * 10).toFixed(3) + \"deg)\";\n    title.style.transform = gone ? \"translateY(\" + (-gone * 0.18 * H).toFixed(1) + \"px)\" : \"\";\n    title.style.opacity = (1 - gone).toFixed(3);\n  }\n  function loop(now) {\n    raf = requestAnimationFrame(loop);\n    var dt = Math.min(0.05, (now - last) / 1000 || 0); last = now;\n    if (!visible || document.hidden) return;\n    frame(dt);\n  }\n  function size() { W = Math.max(1, box.clientWidth); H = Math.max(1, box.clientHeight); if (reduce) frame(0); }\n\n  function on(t, type, f, opt) { t.addEventListener(type, f, opt); offs.push(function () { t.removeEventListener(type, f, opt); }); }\n  on(box, \"pointermove\", function (e) {\n    var r = box.getBoundingClientRect(), x = e.clientX - r.left, y = e.clientY - r.top;\n    mouse.x = x / Math.max(1, r.width); mouse.y = y / Math.max(1, r.height);\n    cursor.style.transform = \"translate(\" + x.toFixed(1) + \"px,\" + y.toFixed(1) + \"px)\";\n    if (e.pointerType === \"mouse\") cursor.classList.add(\"is-on\");\n  }, { passive: true });\n  on(box, \"pointerleave\", function () { cursor.classList.remove(\"is-on\", \"is-big\"); });\n  on(box, \"pointerover\", function (e) { if (e.target.closest && e.target.closest(\".ef-ghh__hot\")) cursor.classList.add(\"is-big\"); });\n  on(box, \"pointerout\", function (e) { var t = e.target.closest && e.target.closest(\".ef-ghh__hot\"); if (t && !(e.relatedTarget && t.contains(e.relatedTarget))) cursor.classList.remove(\"is-big\"); });\n\n  function update(next) {\n    opts = Object.assign({ headline: \"Pages|that wave|back\", badge: \"Now in|the Library|+\", prompt: \"Scroll and see what it can do\", from: \"#005236\", to: \"#e6ff55\", handLeft: \"#0a6b46\", handRight: \"#005236\", accent: \"#e6ff55\", ink: \"#0c1e18\", paper: \"#fbf8f1\" }, opts, next || {});\n    var lines = String(opts.headline).split(\"|\").map(function (s) { return s.trim(); }).filter(Boolean);\n    title.innerHTML = lines.map(esc).join(\"<br>\");\n    badge.innerHTML = String(opts.badge).split(\"|\").map(function (s) { return esc(s.trim()); }).join(\"<br>\");\n    scrollBtn.firstChild.nodeValue = opts.prompt + \" \";\n    box.style.setProperty(\"--ef-ghh-a\", opts.from); box.style.setProperty(\"--ef-ghh-b\", opts.to);\n    box.style.setProperty(\"--ef-ghh-acc\", opts.accent); box.style.setProperty(\"--ef-ghh-ink\", opts.ink); box.style.setProperty(\"--ef-ghh-paper\", opts.paper);\n    var sl = handL.querySelectorAll(\"stop\"), sr = handR.querySelectorAll(\"stop\");\n    sl[0].setAttribute(\"stop-color\", opts.handLeft); sl[1].setAttribute(\"stop-color\", mix(opts.handLeft, opts.paper, 0.42));\n    sr[0].setAttribute(\"stop-color\", opts.handRight); sr[1].setAttribute(\"stop-color\", mix(opts.handRight, opts.to, 0.45));\n    if (reduce) frame(0);\n  }\n\n  update(o);\n  size();\n  frame(0);\n  if (!reduce) {\n    if (\"IntersectionObserver\" in window) { io = new IntersectionObserver(function (e) { visible = e[0].isIntersecting; box.classList.toggle(\"is-off\", !visible); }); io.observe(box); }\n    last = performance.now(); raf = requestAnimationFrame(loop);\n  }\n  if (\"ResizeObserver\" in window) { ro = new ResizeObserver(function () { if (!destroyed) size(); }); ro.observe(box); }\n  return {\n    update: update,\n    destroy: function () {\n      destroyed = true; cancelAnimationFrame(raf);\n      offs.forEach(function (f) { f(); }); offs = [];\n      if (io) io.disconnect(); if (ro) ro.disconnect();\n    }\n  };\n}"
  }
}