{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"card-stack-scroll","type":"registry:block","title":"card stack scroll","description":"\"sections stack via 228\" — panels pile up and settle as you scroll; the one beneath dims and recedes. The Apple keynote scroll.","author":"Motion Menu","categories":["role-content","signature","scroll"],"dependencies":[],"registryDependencies":[],"meta":{"number":"228","slug":"card-stack-scroll","framework":"react","docs":"https://motion-menu-two.vercel.app/p/card-stack-scroll.md"},"files":[{"path":"motion-menu/card-stack-scroll.html","type":"registry:file","target":"motion-menu/card-stack-scroll.html","content":"<article class=\"card\">\n        <header><span class=\"num\">228</span><h3>Card stack scroll</h3><div class=\"tags\"><i>scroll</i></div><a class=\"format-action\" data-format-link data-pattern-slug=\"card-stack-scroll\" href=\"/r/card-stack-scroll.json?framework=react\" title=\"Open the React registry output\">React ↗</a></header>\n        <div class=\"demo\">\n          <div class=\"stx-outer\" id=\"stx-outer\" data-lenis-prevent>\n            <div class=\"stx-track\">\n              <div class=\"stx-stick\">\n                <div class=\"stx-card\" style=\"background:linear-gradient(135deg,#b7ff2e,#5fd97a);\">01 · DESIGN</div>\n                <div class=\"stx-card\" style=\"background:linear-gradient(135deg,#7fd8ff,#5a8cff);\">02 · PROCURE</div>\n                <div class=\"stx-card\" style=\"background:linear-gradient(135deg,#ffb46b,#ff7e5f);\">03 · INSTALL</div>\n                <div class=\"stx-card\" style=\"background:linear-gradient(135deg,#d9a8ff,#9a6bff);\">04 · REFURBISH</div>\n              </div>\n            </div>\n          </div>\n          <p class=\"demo-hint\">scroll in here — each chapter climbs onto the last</p>\n        </div>\n        <p class=\"order\">Say: <b>\"sections stack via 228\"</b> — panels pile up and settle as you scroll; the one beneath dims and recedes. The Apple keynote scroll.</p>\n      </article>"},{"path":"motion-menu/card-stack-scroll.css","type":"registry:file","target":"motion-menu/card-stack-scroll.css","content":".card {\n    border: 1px solid var(--line); border-radius: 14px; background: var(--card);\n    overflow: hidden; display: flex; flex-direction: column;\n  }\n\n.card > header { display: flex; align-items: baseline; gap: .8rem; padding: 1.1rem 1.2rem .9rem; border-bottom: 1px solid var(--line); }\n\n.card .num { font-family: var(--mono); color: var(--acc); font-size: 1.05rem; }\n\n.card h3 { font-size: 1.02rem; font-weight: 600; letter-spacing: -0.01em; flex: 1; }\n\n.tags { display: flex; gap: .35rem; }\n\n.tags i {\n    font: 400 .62rem/1 var(--mono); font-style: normal; color: var(--dim);\n    border: 1px solid var(--line); border-radius: 99px; padding: .28em .6em; white-space: nowrap;\n  }\n\n.demo {\n    min-height: 250px; position: relative; display: flex; align-items: center; justify-content: center;\n    background: var(--bg2); overflow: hidden; flex: 1;\n  }\n\n.order { padding: .85rem 1.2rem; font-family: var(--mono); font-size: .72rem; color: var(--dim); border-top: 1px solid var(--line); }\n\n.order b { color: var(--txt); font-weight: 500; }\n\n.demo .btn.corner { position: absolute; top: 12px; right: 12px; padding: .55em 1em; font-size: .68rem; z-index: 5; }\n\n.demo-hint { position: absolute; bottom: 10px; left: 0; right: 0; text-align: center; font: 400 .65rem var(--mono); color: var(--dim); pointer-events: none; z-index: 4; }\n\n.ai-card .num { color: var(--acc2) !important; }\n\n.demo:has(.hascheck input:checked) .hasbtn { border-color: var(--acc); color: var(--acc); pointer-events: auto; opacity: 1; }\n\n/* ---------- next wave vol. 3 · 228–239 ---------- */\n  /* 228 card stack */\n  .stx-outer { width: 100%; height: 280px; overflow-y: auto; border-radius: 12px; background: #08080d; }\n\n.stx-track { height: 980px; }\n\n.stx-stick { position: sticky; top: 0; height: 280px; overflow: hidden; display: grid; place-items: center; }\n\n.stx-card { position: absolute; width: 74%; height: 62%; border-radius: 14px; display: grid; place-items: center; font: 600 .85rem var(--mono); letter-spacing: .08em; color: #0b0b10; box-shadow: 0 18px 40px rgba(0,0,0,.45); will-change: transform, filter; }"},{"path":"components/motion-menu/card-stack-scroll.tsx","type":"registry:component","content":"// @ts-nocheck — generated wrapper; inlined pattern JS is imperative DOM code, not authored TS.\n\"use client\";\n// card stack scroll — Motion Menu\nimport { useEffect, useRef } from \"react\";\n\nconst MARKUP = \"<article class=\\\"card\\\">\\n        <header><span class=\\\"num\\\">228</span><h3>Card stack scroll</h3><div class=\\\"tags\\\"><i>scroll</i></div><a class=\\\"format-action\\\" data-format-link data-pattern-slug=\\\"card-stack-scroll\\\" href=\\\"/r/card-stack-scroll.json?framework=react\\\" title=\\\"Open the React registry output\\\">React \\u2197</a></header>\\n        <div class=\\\"demo\\\">\\n          <div class=\\\"stx-outer\\\" id=\\\"stx-outer\\\" data-lenis-prevent>\\n            <div class=\\\"stx-track\\\">\\n              <div class=\\\"stx-stick\\\">\\n                <div class=\\\"stx-card\\\" style=\\\"background:linear-gradient(135deg,#b7ff2e,#5fd97a);\\\">01 \\u00b7 DESIGN</div>\\n                <div class=\\\"stx-card\\\" style=\\\"background:linear-gradient(135deg,#7fd8ff,#5a8cff);\\\">02 \\u00b7 PROCURE</div>\\n                <div class=\\\"stx-card\\\" style=\\\"background:linear-gradient(135deg,#ffb46b,#ff7e5f);\\\">03 \\u00b7 INSTALL</div>\\n                <div class=\\\"stx-card\\\" style=\\\"background:linear-gradient(135deg,#d9a8ff,#9a6bff);\\\">04 \\u00b7 REFURBISH</div>\\n              </div>\\n            </div>\\n          </div>\\n          <p class=\\\"demo-hint\\\">scroll in here \\u2014 each chapter climbs onto the last</p>\\n        </div>\\n        <p class=\\\"order\\\">Say: <b>\\\"sections stack via 228\\\"</b> \\u2014 panels pile up and settle as you scroll; the one beneath dims and recedes. The Apple keynote scroll.</p>\\n      </article>\";\n\nexport function CardStackScroll() {\n  const hostRef = useRef<HTMLDivElement>(null);\n\n  useEffect(() => {\n    const host = hostRef.current;\n    if (!host) return;\n    const $ = (s: string) => host.querySelector(s) as HTMLElement | null;\n    let disposed = false;\n    const cleanup: Array<() => void> = [];\n\n    (async () => {\n      if (disposed) return;\n      try {\n        /* ---- 228 · card stack scroll ---- */\n        {\n          const outer = document.getElementById('stx-outer');\n          const cards = [...outer.querySelectorAll('.stx-card')];\n          const N = cards.length;\n          const clamp01 = (x) => Math.max(0, Math.min(1, x));\n          const easeOut = (x) => 1 - Math.pow(1 - x, 3);\n          const layout = () => {\n            const max = outer.scrollHeight - outer.clientHeight;\n            const prog = max ? outer.scrollTop / max : 0;\n            cards.forEach((c, i) => {\n              const enter = i === 0 ? 1 : clamp01(prog * (N - 1) - (i - 1));\n              const cover = i === N - 1 ? 0 : clamp01(prog * (N - 1) - i);\n              c.style.transform = `translateY(${(1 - easeOut(enter)) * 115}%) scale(${1 - cover * 0.07})`;\n              c.style.filter = `brightness(${1 - cover * 0.45})`;\n            });\n          };\n          outer.addEventListener('scroll', layout, { passive: true });\n          layout();\n        }\n      } catch (err: any) {\n        console.warn(\"[motion-menu] card-stack-scroll failed to start:\", err);\n      }\n    })();\n\n    return () => {\n      disposed = true;\n      cleanup.forEach((fn) => { try { fn(); } catch (_) {} });\n    };\n  }, []);\n\n  return <div ref={hostRef} dangerouslySetInnerHTML={{ __html: MARKUP }} />;\n}\n\nexport default CardStackScroll;\n"}]}