{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "gold-leaf",
  "title": "Gold Leaf",
  "description": "Gilds text with real-looking gold leaf: square leaves with visible seams, slight tone differences, fine cracks and missed flecks, and burnished metal with a highlight that follows the pointer. A slow pass of light runs on touch screens, and an optional lay animation settles the leaves on in a staggered sweep. The text stays real, selectable text.",
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/new-york/blocks/gold-leaf/gold-leaf.tsx",
      "content": "\"use client\"\r\n\r\nimport * as React from \"react\"\r\n\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nexport type GoldLeafTone = \"yellow\" | \"rose\" | \"white\" | \"copper\"\r\n\r\ntype Metal = { dark: string; mid: string; light: string; bright: string }\r\n\r\n/** Metal ramps, shadow to burnished highlight. \"white\" is palladium, which stays bright without tarnishing. */\r\nexport const goldLeafTones: Record<GoldLeafTone, Metal> = {\r\n  yellow: { dark: \"#5f3d0b\", mid: \"#b8893a\", light: \"#e9c873\", bright: \"#fff5d2\" },\r\n  rose: { dark: \"#62301f\", mid: \"#b6735a\", light: \"#e8b296\", bright: \"#ffe8da\" },\r\n  white: { dark: \"#4d4a44\", mid: \"#9d998f\", light: \"#d9d5ca\", bright: \"#ffffff\" },\r\n  copper: { dark: \"#4a1c0b\", mid: \"#a4522b\", light: \"#df9165\", bright: \"#ffdcc4\" },\r\n}\r\n\r\n/** Oil size, the tacky amber mordant the leaf is laid onto. Shows under the leaves while they settle. */\r\nconst SIZE = \"#a87b2e\"\r\n\r\n/** Leaves per tile. Rows are offset at random, so the repeat is hard to spot. */\r\nconst COLS = 6\r\nconst ROWS = 5\r\n\r\n/** Per-leaf ramp steepness for the lay. Higher is a crisper hand-off from size to leaf. */\r\nconst RAMP = 5\r\n/** Pushes an unloaded delay map to \"not laid yet\" instead of \"laid\", so nothing flashes in early. */\r\nconst GUARD = 60\r\n\r\n/** Where the light rests when nothing is moving it, as a fraction of the box, and how strong. */\r\nconst REST = { x: 0.24, y: 0.16, e: 0.42 }\r\n\r\nfunction prng(seed: number) {\r\n  let a = seed >>> 0 || 1\r\n  return () => {\r\n    a = (a + 0x6d2b79f5) | 0\r\n    let t = Math.imul(a ^ (a >>> 15), 1 | a)\r\n    t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t\r\n    return ((t ^ (t >>> 14)) >>> 0) / 4294967296\r\n  }\r\n}\r\n\r\nconst f = (n: number) => Math.round(n * 10) / 10\r\nconst clamp01 = (n: number) => Math.min(1, Math.max(0, n))\r\nconst svgUrl = (svg: string) => `url(\"data:image/svg+xml,${encodeURIComponent(svg)}\")`\r\n\r\ntype Leaf = {\r\n  x: number\r\n  y: number\r\n  w: number\r\n  h: number\r\n  /** -1 to 1. Leaves from one book differ slightly in thickness and tone. */\r\n  tone: number\r\n  /** 0 to 1. How squarely the leaf faces the light, so each one catches the glint differently. */\r\n  facet: number\r\n  /** 0 to 1. Random part of the lay order. */\r\n  order: number\r\n  /** Leaf-local SVG for the face texture and for the missing flecks. */\r\n  face: string\r\n  holes: string\r\n}\r\n\r\n/**\r\n * Lays one tile of leaves, row by row, each overlapping the last by a few percent the way a gilder\r\n * works along a line. Seeded, so the server and client draw the same sheet.\r\n */\r\nfunction layLeaves(size: number, cracks: number, seed: number, metal: Metal): Leaf[] {\r\n  const rand = prng(seed)\r\n  const crackRand = prng(seed + 101)\r\n  const fleckRand = prng(seed + 202)\r\n  const leaves: Leaf[] = []\r\n  const c = clamp01(cracks)\r\n\r\n  for (let r = 0; r < ROWS; r++) {\r\n    const offset = rand() * size\r\n    for (let col = 0; col < COLS; col++) {\r\n      const j = () => (rand() - 0.5) * size * 0.08\r\n      const w = size * (1.04 + rand() * 0.05)\r\n      const h = size * (1.04 + rand() * 0.05)\r\n      const tone = rand() * 2 - 1\r\n      const wave1 = j() * 0.25\r\n      const wave2 = j() * 0.25\r\n\r\n      // Only the top and left edges show: the next leaf covers this one's right and bottom.\r\n      const seam = `M0 ${f(h)}L${f(wave1)} ${f(h / 2)}L0 0L${f(w / 2)} ${f(wave2)}L${f(w)} 0`\r\n      const lip = `M0.9 ${f(h)}L${f(wave1 + 0.9)} ${f(h / 2)}L0.9 0.9L${f(w / 2)} ${f(wave2 + 0.9)}L${f(w)} 0.9`\r\n      let face =\r\n        `<rect width=\"${f(w)}\" height=\"${f(h)}\" fill=\"${tone > 0 ? metal.bright : metal.dark}\" fill-opacity=\"${(Math.abs(tone) * 0.24).toFixed(3)}\"/>` +\r\n        `<path d=\"${seam}\" fill=\"none\" stroke=\"#24160a\" stroke-opacity=\"0.5\" stroke-width=\"0.9\"/>` +\r\n        `<path d=\"${lip}\" fill=\"none\" stroke=\"${metal.bright}\" stroke-opacity=\"0.55\" stroke-width=\"0.6\"/>`\r\n\r\n      // Skewings: faint creases where the leaf folded on the cushion.\r\n      const creases = Math.floor(crackRand() * 2.2)\r\n      for (let k = 0; k < creases; k++) {\r\n        const x = crackRand() * w\r\n        const y = crackRand() * h\r\n        const a = crackRand() * Math.PI\r\n        const len = size * (0.2 + crackRand() * 0.3)\r\n        face += `<path d=\"M${f(x)} ${f(y)}l${f(Math.cos(a) * len)} ${f(Math.sin(a) * len)}\" stroke=\"${metal.bright}\" stroke-opacity=\"0.16\" stroke-width=\"0.7\"/>`\r\n      }\r\n\r\n      // Cracks: jagged hairlines that wander across the leaf.\r\n      const count = Math.floor(c * 2.6 + crackRand() * c * 1.4)\r\n      for (let k = 0; k < count; k++) {\r\n        let x = crackRand() * w\r\n        let y = crackRand() * h\r\n        let a = crackRand() * Math.PI * 2\r\n        let d = `M${f(x)} ${f(y)}`\r\n        const steps = 4 + Math.floor(crackRand() * 4)\r\n        for (let s = 0; s < steps; s++) {\r\n          a += (crackRand() - 0.5) * 1.3\r\n          const len = size * (0.05 + crackRand() * 0.08)\r\n          x += Math.cos(a) * len\r\n          y += Math.sin(a) * len\r\n          d += `L${f(x)} ${f(y)}`\r\n        }\r\n        face +=\r\n          `<path d=\"${d}\" fill=\"none\" stroke=\"#2b1405\" stroke-opacity=\"0.6\" stroke-width=\"0.75\" stroke-linejoin=\"round\"/>` +\r\n          `<path d=\"${d}\" transform=\"translate(0.7 0.7)\" fill=\"none\" stroke=\"${metal.bright}\" stroke-opacity=\"0.3\" stroke-width=\"0.5\"/>`\r\n      }\r\n\r\n      // Flecks the leaf missed, mostly along the seams where it tore.\r\n      let holes = \"\"\r\n      const flecks = Math.floor(c * 2.4 + fleckRand() * c * 2)\r\n      for (let k = 0; k < flecks; k++) {\r\n        const edge = fleckRand() < 0.7\r\n        const cx = edge && fleckRand() < 0.5 ? fleckRand() * size * 0.12 : fleckRand() * w\r\n        const cy = edge && cx > size * 0.12 ? fleckRand() * size * 0.12 : fleckRand() * h\r\n        const radius = size * (0.012 + fleckRand() * 0.035)\r\n        let p = \"\"\r\n        for (let v = 0; v < 6; v++) {\r\n          const ang = (v / 6) * Math.PI * 2\r\n          const rr = radius * (0.5 + fleckRand() * 0.8)\r\n          p += `${v ? \"L\" : \"M\"}${f(cx + Math.cos(ang) * rr)} ${f(cy + Math.sin(ang) * rr)}`\r\n        }\r\n        holes += `<path d=\"${p}Z\"/>`\r\n      }\r\n\r\n      leaves.push({\r\n        x: offset + col * size + j(),\r\n        y: r * size + j(),\r\n        w,\r\n        h,\r\n        tone,\r\n        facet: rand(),\r\n        order: rand(),\r\n        face,\r\n        holes,\r\n      })\r\n    }\r\n  }\r\n  return leaves\r\n}\r\n\r\n/** Places each leaf in the tile, plus the copies that wrap round the edges so the tile repeats seamlessly. */\r\nfunction placements(leaves: Leaf[], tw: number, th: number, draw: (leaf: Leaf, x: number, y: number) => string) {\r\n  let out = \"\"\r\n  for (const leaf of leaves) {\r\n    for (const dy of [-th, 0, th]) {\r\n      for (const dx of [-tw, 0, tw]) {\r\n        const x = leaf.x + dx\r\n        const y = leaf.y + dy\r\n        if (x > tw || y > th || x + leaf.w < 0 || y + leaf.h < 0) continue\r\n        out += draw(leaf, x, y)\r\n      }\r\n    }\r\n  }\r\n  return out\r\n}\r\n\r\nfunction sheet(size: number, cracks: number, seed: number, metal: Metal) {\r\n  const leaves = layLeaves(size, cracks, seed, metal)\r\n  const tw = COLS * size\r\n  const th = ROWS * size\r\n  const open = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${tw}\" height=\"${th}\" viewBox=\"0 0 ${tw} ${th}\">`\r\n  const at = (x: number, y: number) => `transform=\"translate(${f(x)} ${f(y)})\"`\r\n\r\n  const face = placements(leaves, tw, th, (l, x, y) => `<g ${at(x, y)}>${l.face}</g>`)\r\n  // Masks are luminance inside the SVG so a later leaf can replace an earlier one, then become alpha outside.\r\n  const holes = placements(leaves, tw, th, (l, x, y) => (l.holes ? `<g ${at(x, y)} fill=\"#000\">${l.holes}</g>` : \"\"))\r\n  const facets = placements(leaves, tw, th, (l, x, y) => {\r\n    const g = Math.round((0.3 + l.facet * 0.7) * 255)\r\n    return `<g ${at(x, y)}><rect width=\"${f(l.w)}\" height=\"${f(l.h)}\" fill=\"rgb(${g},${g},${g})\"/><g fill=\"#000\">${l.holes}</g></g>`\r\n  })\r\n  const mask = (body: string, base: string) =>\r\n    `${open}<defs><mask id=\"m\" maskUnits=\"userSpaceOnUse\" x=\"0\" y=\"0\" width=\"${tw}\" height=\"${th}\">${base}${body}</mask></defs>` +\r\n    `<rect width=\"${tw}\" height=\"${th}\" fill=\"#fff\" mask=\"url(#m)\"/></svg>`\r\n\r\n  return {\r\n    leaves,\r\n    tw,\r\n    th,\r\n    face: svgUrl(`${open}${face}</svg>`),\r\n    holes: svgUrl(mask(holes, `<rect width=\"${tw}\" height=\"${th}\" fill=\"#fff\"/>`)),\r\n    facets: svgUrl(mask(facets, \"\")),\r\n  }\r\n}\r\n\r\n/** Filter region for the lay, as a fraction of the box. Generous, so serif overhangs are not clipped. */\r\nconst REGION = { x: -0.1, y: -0.2, w: 1.2, h: 1.4 }\r\n\r\n/**\r\n * A grey map the size of the element: each leaf's grey is when it lands. Mostly a left-to-right sweep,\r\n * with some randomness so it reads as a hand laying leaves, not a wipe.\r\n */\r\nfunction delayMap(leaves: Leaf[], tw: number, th: number, width: number, height: number, seed: number) {\r\n  const x0 = REGION.x * width\r\n  const y0 = REGION.y * height\r\n  const mw = REGION.w * width\r\n  const mh = REGION.h * height\r\n  let rects = \"\"\r\n  for (let ty = Math.floor(y0 / th) - 1; ty <= Math.ceil((y0 + mh) / th); ty++) {\r\n    for (let r = 0; r < ROWS; r++) {\r\n      for (let tx = Math.floor(x0 / tw) - 1; tx <= Math.ceil((x0 + mw) / tw); tx++) {\r\n        for (let c = 0; c < COLS; c++) {\r\n          const leaf = leaves[r * COLS + c]\r\n          const x = leaf.x + tx * tw\r\n          const y = leaf.y + ty * th\r\n          if (x > x0 + mw || y > y0 + mh || x + leaf.w < x0 || y + leaf.h < y0) continue\r\n          const sweep = clamp01(((x + leaf.w / 2) / width) * 0.82 + ((y + leaf.h / 2) / height) * 0.18)\r\n          const jitter = prng(seed * 7919 + (tx + 64) * 131 + (ty + 64) * 9173 + r * COLS + c)()\r\n          const g = Math.round(clamp01(sweep * 0.7 + (leaf.order * 0.5 + jitter * 0.5) * 0.3) * 255)\r\n          rects += `<rect x=\"${f(x)}\" y=\"${f(y)}\" width=\"${f(leaf.w)}\" height=\"${f(leaf.h)}\" fill=\"rgb(${g},${g},${g})\"/>`\r\n        }\r\n      }\r\n    }\r\n  }\r\n  const svg =\r\n    `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${f(mw)}\" height=\"${f(mh)}\" viewBox=\"${f(x0)} ${f(y0)} ${f(mw)} ${f(mh)}\" preserveAspectRatio=\"none\">` +\r\n    `<rect x=\"${f(x0)}\" y=\"${f(y0)}\" width=\"${f(mw)}\" height=\"${f(mh)}\" fill=\"#fff\"/>${rects}</svg>`\r\n  return `data:image/svg+xml,${encodeURIComponent(svg)}`\r\n}\r\n\r\n/** Leaf cover at lay time `t`: alpha ramps from 0 to 1 as `t` passes each leaf's grey. */\r\nconst coverMatrix = (t: number) => `0 0 0 0 1  0 0 0 0 1  0 0 0 0 1  ${-RAMP} 0 0 ${GUARD} ${f(RAMP * t - GUARD)}`\r\n\r\nconst reducedQuery = \"(prefers-reduced-motion: reduce)\"\r\nfunction subscribeReduced(onChange: () => void) {\r\n  const mq = window.matchMedia(reducedQuery)\r\n  mq.addEventListener(\"change\", onChange)\r\n  return () => mq.removeEventListener(\"change\", onChange)\r\n}\r\nfunction useReducedMotion() {\r\n  return React.useSyncExternalStore(\r\n    subscribeReduced,\r\n    () => window.matchMedia(reducedQuery).matches,\r\n    () => false\r\n  )\r\n}\r\n\r\nexport interface GoldLeafProps extends React.HTMLAttributes<HTMLElement> {\r\n  /** Element to render. Default \"span\". */\r\n  as?: React.ElementType\r\n  /** Metal. \"yellow\" is 23k gold, \"white\" is palladium. Default \"yellow\". */\r\n  tone?: GoldLeafTone\r\n  /** Edge of one leaf in px. Real leaf is about 80mm; on a title, 24 to 48 reads well. Default 32. */\r\n  leafSize?: number\r\n  /** Cracks and missing flecks, 0 to 1. 0 is a fresh, perfect lay. Default 0.3. */\r\n  cracks?: number\r\n  /** Strength of the moving highlight, 0 to 1. Default 0.85. */\r\n  sheen?: number\r\n  /** Light follows the pointer, or sweeps slowly on touch screens. Off leaves a still highlight. Default true. */\r\n  interactive?: boolean\r\n  /** Lay the leaves on in a staggered sweep the first time it scrolls into view. Default false. */\r\n  lay?: boolean\r\n  /** Length of the lay in ms. Default 1800. */\r\n  layDuration?: number\r\n  /** Seed for the leaf layout, cracks and flecks. Default 7. */\r\n  seed?: number\r\n  ref?: React.Ref<HTMLElement>\r\n}\r\n\r\n/**\r\n * Text gilded with gold leaf: square leaves with visible seams, cracks and missed flecks, burnished\r\n * metal and a highlight that follows the pointer. The text stays real, selectable text.\r\n */\r\nexport function GoldLeaf({\r\n  as: Comp = \"span\",\r\n  tone = \"yellow\",\r\n  leafSize = 32,\r\n  cracks = 0.3,\r\n  sheen = 0.85,\r\n  interactive = true,\r\n  lay = false,\r\n  layDuration = 1800,\r\n  seed = 7,\r\n  className,\r\n  children,\r\n  ...props\r\n}: GoldLeafProps) {\r\n  const id = React.useId().replace(/[^\\w-]/g, \"\")\r\n  const reliefId = `gl-relief-${id}`\r\n  const layFaceId = `gl-lay-${id}`\r\n  const layMaskId = `gl-mask-${id}`\r\n\r\n  const boxRef = React.useRef<HTMLSpanElement>(null)\r\n  const faceRef = React.useRef<HTMLSpanElement>(null)\r\n  const glintRef = React.useRef<HTMLSpanElement>(null)\r\n  const faceMatrixRef = React.useRef<SVGFEColorMatrixElement>(null)\r\n  const maskMatrixRef = React.useRef<SVGFEColorMatrixElement>(null)\r\n\r\n  const reduced = useReducedMotion()\r\n  const [phase, setPhase] = React.useState<\"unlaid\" | \"laying\" | \"laid\">(lay ? \"unlaid\" : \"laid\")\r\n  const [map, setMap] = React.useState<string | undefined>(undefined)\r\n  const state = reduced ? \"laid\" : phase\r\n\r\n  const metal = goldLeafTones[tone] ?? goldLeafTones.yellow\r\n  const size = Math.max(8, leafSize)\r\n  const leaf = React.useMemo(() => sheet(size, cracks, seed, metal), [size, cracks, seed, metal])\r\n\r\n  // Wait for the element to be seen (in a visible tab), then build its delay map and start laying.\r\n  React.useEffect(() => {\r\n    const face = faceRef.current\r\n    if (state !== \"unlaid\" || !face) return\r\n    let observer: IntersectionObserver | undefined\r\n    const start = () => {\r\n      if (document.visibilityState !== \"visible\") return\r\n      document.removeEventListener(\"visibilitychange\", start)\r\n      observer = new IntersectionObserver(\r\n        ([entry]) => {\r\n          if (!entry.isIntersecting) return\r\n          observer?.disconnect()\r\n          const { width, height } = face.getBoundingClientRect()\r\n          setMap(delayMap(leaf.leaves, leaf.tw, leaf.th, width, height, seed))\r\n          setPhase(\"laying\")\r\n        },\r\n        { threshold: 0.35 }\r\n      )\r\n      observer.observe(face)\r\n    }\r\n    document.addEventListener(\"visibilitychange\", start)\r\n    start()\r\n    return () => {\r\n      document.removeEventListener(\"visibilitychange\", start)\r\n      observer?.disconnect()\r\n    }\r\n  }, [state, leaf, seed])\r\n\r\n  // The lay itself: one filter attribute per frame, with the glint riding the leading edge.\r\n  React.useEffect(() => {\r\n    if (state !== \"laying\" || !map) return\r\n    const glint = glintRef.current\r\n    const mats = [faceMatrixRef.current, maskMatrixRef.current]\r\n    let raf = 0\r\n    let t0 = 0\r\n    let cancelled = false\r\n\r\n    const tick = (now: number) => {\r\n      if (!t0) t0 = now\r\n      const p = Math.min(1, (now - t0) / layDuration)\r\n      // A gentle ease-out, so the first leaves go down briskly and the last few settle.\r\n      const t = (1 - (1 - p) ** 1.5) * (1 + 1 / RAMP)\r\n      for (const m of mats) m?.setAttribute(\"values\", coverMatrix(t))\r\n      if (glint) {\r\n        glint.style.setProperty(\"--gl-x\", `${((t * 0.95 - 0.08) * 100).toFixed(2)}%`)\r\n        glint.style.setProperty(\"--gl-y\", `${(40 + p * 20).toFixed(2)}%`)\r\n        glint.style.setProperty(\"--gl-e\", (Math.sin(Math.PI * p) * 0.75 + REST.e * p).toFixed(3))\r\n      }\r\n      if (p < 1) raf = requestAnimationFrame(tick)\r\n      else setPhase(\"laid\")\r\n    }\r\n    // Let the map decode first; feImage would otherwise show nothing for a frame or two.\r\n    const img = new Image()\r\n    img.src = map\r\n    img\r\n      .decode()\r\n      .catch(() => undefined)\r\n      .then(() => {\r\n        if (!cancelled) raf = requestAnimationFrame(tick)\r\n      })\r\n    return () => {\r\n      cancelled = true\r\n      cancelAnimationFrame(raf)\r\n    }\r\n  }, [state, map, layDuration])\r\n\r\n  // The light. A spring towards the pointer on mouse and pen, a slow sweep on touch, still otherwise.\r\n  React.useEffect(() => {\r\n    const box = boxRef.current\r\n    const glint = glintRef.current\r\n    if (state !== \"laid\" || !box || !glint) return\r\n\r\n    let rect = box.getBoundingClientRect()\r\n    const write = (x: number, y: number, e: number) => {\r\n      const r = Math.max(48, Math.min(rect.width * 0.45, rect.height * 1.1))\r\n      glint.style.setProperty(\"--gl-x\", `${(x * 100).toFixed(2)}%`)\r\n      glint.style.setProperty(\"--gl-y\", `${(y * 100).toFixed(2)}%`)\r\n      glint.style.setProperty(\"--gl-r\", `${r.toFixed(1)}px`)\r\n      glint.style.setProperty(\"--gl-e\", e.toFixed(3))\r\n    }\r\n\r\n    if (reduced || !interactive) {\r\n      write(REST.x, REST.y, REST.e)\r\n      const ro = new ResizeObserver(() => {\r\n        rect = box.getBoundingClientRect()\r\n        write(REST.x, REST.y, REST.e)\r\n      })\r\n      ro.observe(box)\r\n      return () => ro.disconnect()\r\n    }\r\n\r\n    const follow = window.matchMedia(\"(any-pointer: fine)\").matches\r\n    let x = REST.x\r\n    let y = REST.y\r\n    let e = REST.e\r\n    let vx = 0\r\n    let vy = 0\r\n    let px: number | null = null\r\n    let py = 0\r\n    let raf = 0\r\n    let timer = 0\r\n    let last = 0\r\n    let visible = false\r\n    let t0 = 0\r\n    write(x, y, e)\r\n\r\n    // Pointer to light: under the pointer while it is over the text, then easing out past the edges.\r\n    // Far away the highlight dims but never goes dark, so the metal still reads as metal.\r\n    const aim = () => {\r\n      if (px === null) return [REST.x, REST.y, REST.e] as const\r\n      const hw = rect.width / 2\r\n      const hh = rect.height / 2\r\n      const dx = (px - (rect.left + hw)) / hw\r\n      const dy = (py - (rect.top + hh)) / hh\r\n      const soft = (d: number) => d / (1 + 0.25 * Math.abs(d))\r\n      const ox = Math.max(0, Math.abs(px - rect.left - hw) - hw)\r\n      const oy = Math.max(0, Math.abs(py - rect.top - hh) - hh)\r\n      const reach = Math.max(rect.height * 2, 180)\r\n      const near = 1 / (1 + (Math.hypot(ox, oy) / reach) ** 2)\r\n      return [0.5 + soft(dx) * 0.5, 0.5 + soft(dy) * 0.5, 0.3 + 0.7 * near] as const\r\n    }\r\n\r\n    const followTick = (now: number) => {\r\n      const dt = Math.min(0.05, (now - last) / 1000)\r\n      last = now\r\n      rect = box.getBoundingClientRect()\r\n      const [tx, ty, te] = aim()\r\n      // Slightly under-damped spring: it glides after the pointer and settles without a wobble.\r\n      const k = 140\r\n      const c = 22\r\n      vx += ((tx - x) * k - vx * c) * dt\r\n      vy += ((ty - y) * k - vy * c) * dt\r\n      x += vx * dt\r\n      y += vy * dt\r\n      e += (te - e) * (1 - Math.exp(-dt * 6))\r\n      write(x, y, e)\r\n      const settled =\r\n        Math.abs(tx - x) < 5e-4 && Math.abs(ty - y) < 5e-4 && Math.abs(vx) + Math.abs(vy) < 1e-3 && Math.abs(te - e) < 2e-3\r\n      raf = settled ? 0 : requestAnimationFrame(followTick)\r\n    }\r\n\r\n    // Touch: a pass of light every few seconds, from the resting spot off the far corner, then back.\r\n    const PERIOD = 7000\r\n    const PASS = 2400\r\n    const RETURN = 700\r\n    const sweepTick = (now: number) => {\r\n      const t = (now - t0) % PERIOD\r\n      if (t < PASS) {\r\n        const p = t / PASS\r\n        const s = p < 0.5 ? 4 * p * p * p : 1 - (-2 * p + 2) ** 3 / 2\r\n        const fade = 1 - clamp01((p - 0.7) / 0.3)\r\n        write(REST.x + (1.35 - REST.x) * s, REST.y + (0.85 - REST.y) * s, REST.e * fade + 0.55 * Math.sin(Math.PI * p))\r\n      } else if (t < PASS + RETURN) {\r\n        const q = (t - PASS) / RETURN\r\n        write(REST.x, REST.y, REST.e * (1 - (1 - q) ** 3))\r\n      } else {\r\n        write(REST.x, REST.y, REST.e)\r\n        raf = 0\r\n        timer = window.setTimeout(() => {\r\n          raf = requestAnimationFrame(sweepTick)\r\n        }, PERIOD - t)\r\n        return\r\n      }\r\n      raf = requestAnimationFrame(sweepTick)\r\n    }\r\n\r\n    const stop = () => {\r\n      cancelAnimationFrame(raf)\r\n      clearTimeout(timer)\r\n      raf = 0\r\n    }\r\n    const kick = () => {\r\n      if (raf || !visible || document.hidden) return\r\n      if (follow) {\r\n        last = performance.now()\r\n        raf = requestAnimationFrame(followTick)\r\n      } else {\r\n        clearTimeout(timer)\r\n        // First pass a beat after it comes into view.\r\n        t0 = performance.now() - PERIOD + 1200\r\n        raf = requestAnimationFrame(sweepTick)\r\n      }\r\n    }\r\n\r\n    const onMove = (event: PointerEvent) => {\r\n      if (event.pointerType === \"touch\") return\r\n      px = event.clientX\r\n      py = event.clientY\r\n      kick()\r\n    }\r\n    const onOut = (event: PointerEvent) => {\r\n      if (event.relatedTarget) return\r\n      px = null\r\n      kick()\r\n    }\r\n    const onVisibility = () => (document.hidden ? stop() : kick())\r\n    const io = new IntersectionObserver(\r\n      ([entry]) => {\r\n        visible = entry.isIntersecting\r\n        if (visible) kick()\r\n        else stop()\r\n      },\r\n      { rootMargin: \"20% 0px\" }\r\n    )\r\n    io.observe(box)\r\n    document.addEventListener(\"visibilitychange\", onVisibility)\r\n    if (follow) {\r\n      window.addEventListener(\"pointermove\", onMove, { passive: true })\r\n      window.addEventListener(\"pointerout\", onOut, { passive: true })\r\n      window.addEventListener(\"scroll\", kick, { passive: true, capture: true })\r\n    }\r\n\r\n    return () => {\r\n      stop()\r\n      io.disconnect()\r\n      document.removeEventListener(\"visibilitychange\", onVisibility)\r\n      window.removeEventListener(\"pointermove\", onMove)\r\n      window.removeEventListener(\"pointerout\", onOut)\r\n      window.removeEventListener(\"scroll\", kick, { capture: true })\r\n    }\r\n  }, [state, reduced, interactive])\r\n\r\n  // Burnished metal, one reflection per line of text: bright sky above, dark horizon below the middle.\r\n  const env = `linear-gradient(180deg, ${metal.mid} 0%, ${metal.light} 16%, ${metal.bright} 30%, ${metal.light} 42%, ${metal.dark} 60%, ${metal.mid} 74%, ${metal.light} 88%, ${metal.mid} 100%)`\r\n  const tile = `${leaf.tw}px ${leaf.th}px`\r\n  const glint =\r\n    `radial-gradient(circle var(--gl-r, 120px) at var(--gl-x, 24%) var(--gl-y, 16%), ${metal.bright} 0%, ${metal.bright}e6 10%, ${metal.light}80 34%, ${metal.light}00 100%),` +\r\n    `linear-gradient(104deg, transparent calc(var(--gl-x, 24%) - 24%), ${metal.bright}66 var(--gl-x, 24%), transparent calc(var(--gl-x, 24%) + 24%))`\r\n\r\n  // Room around the glyphs so serif overhangs sit inside the box, and so inside the masks and filters.\r\n  const pad = \"0.15em 0.1em\"\r\n  const textClip: React.CSSProperties = { WebkitBackgroundClip: \"text\", backgroundClip: \"text\" }\r\n\r\n  return (\r\n    <Comp\r\n      data-slot=\"gold-leaf\"\r\n      data-state={state}\r\n      className={cn(\"group/gold-leaf inline-block\", className)}\r\n      {...props}\r\n    >\r\n      <span\r\n        ref={boxRef}\r\n        // flow-root stops the face's negative margin collapsing through, which would offset the glint copy.\r\n        className=\"relative isolate flow-root\"\r\n        style={\r\n          {\r\n            \"--gl-relief\": `url(#${reliefId})`,\r\n            \"--gl-lay\": `url(#${reliefId}) url(#${layFaceId})`,\r\n            \"--gl-mask\": `url(#${layMaskId})`,\r\n          } as React.CSSProperties\r\n        }\r\n      >\r\n        <svg aria-hidden className=\"pointer-events-none absolute size-0 overflow-hidden\" focusable=\"false\">\r\n          <defs>\r\n            {/* Leaf relief: bevelled glyph edges plus a fine crinkle, lit from the upper left. */}\r\n            <filter id={reliefId} x=\"-10%\" y=\"-20%\" width=\"120%\" height=\"140%\" colorInterpolationFilters=\"sRGB\">\r\n              <feGaussianBlur in=\"SourceAlpha\" stdDeviation={1.1} result=\"bevel\" />\r\n              <feTurbulence type=\"fractalNoise\" baseFrequency=\"0.7\" numOctaves={2} seed={seed} result=\"crinkle\" />\r\n              <feComposite in=\"bevel\" in2=\"crinkle\" operator=\"arithmetic\" k2={1} k3={0.07} result=\"height\" />\r\n              <feDiffuseLighting in=\"height\" surfaceScale={2.5} diffuseConstant={1.08} lightingColor=\"#fff\" result=\"diffuse\">\r\n                <feDistantLight azimuth={225} elevation={58} />\r\n              </feDiffuseLighting>\r\n              <feSpecularLighting\r\n                in=\"height\"\r\n                surfaceScale={2.5}\r\n                specularConstant={0.85}\r\n                specularExponent={22}\r\n                lightingColor={metal.bright}\r\n                result=\"spec\"\r\n              >\r\n                <feDistantLight azimuth={225} elevation={58} />\r\n              </feSpecularLighting>\r\n              <feComposite in=\"SourceGraphic\" in2=\"diffuse\" operator=\"arithmetic\" k1={1} result=\"shaded\" />\r\n              <feComposite in=\"spec\" in2=\"SourceAlpha\" operator=\"in\" result=\"spec\" />\r\n              <feComposite in=\"shaded\" in2=\"spec\" operator=\"arithmetic\" k2={1} k3={0.5} result=\"lit\" />\r\n              <feComposite in=\"lit\" in2=\"SourceAlpha\" operator=\"in\" />\r\n            </filter>\r\n            {lay && (\r\n              <>\r\n                <filter\r\n                  id={layFaceId}\r\n                  x={REGION.x}\r\n                  y={REGION.y}\r\n                  width={REGION.w}\r\n                  height={REGION.h}\r\n                  primitiveUnits=\"objectBoundingBox\"\r\n                  colorInterpolationFilters=\"sRGB\"\r\n                >\r\n                  <feImage href={map} x={REGION.x} y={REGION.y} width={REGION.w} height={REGION.h} preserveAspectRatio=\"none\" result=\"map\" />\r\n                  <feColorMatrix ref={faceMatrixRef} in=\"map\" type=\"matrix\" values={coverMatrix(0)} result=\"cover\" />\r\n                  {/* A leaf brightens as it lands: 4a(1 - a) peaks halfway through its ramp. */}\r\n                  <feComposite in=\"cover\" in2=\"cover\" operator=\"arithmetic\" k1={-4} k2={4} result=\"flash\" />\r\n                  <feComposite in=\"SourceGraphic\" in2=\"cover\" operator=\"in\" result=\"leaf\" />\r\n                  <feFlood floodColor={SIZE} floodOpacity={0.55} />\r\n                  <feComposite in2=\"SourceAlpha\" operator=\"in\" result=\"size\" />\r\n                  <feComposite in=\"leaf\" in2=\"size\" operator=\"over\" result=\"laid\" />\r\n                  <feFlood floodColor={metal.bright} />\r\n                  <feComposite in2=\"flash\" operator=\"in\" />\r\n                  <feComposite in2=\"SourceAlpha\" operator=\"in\" result=\"glow\" />\r\n                  <feComposite in=\"laid\" in2=\"glow\" operator=\"arithmetic\" k2={1} k3={0.35} />\r\n                </filter>\r\n                <filter\r\n                  id={layMaskId}\r\n                  x={REGION.x}\r\n                  y={REGION.y}\r\n                  width={REGION.w}\r\n                  height={REGION.h}\r\n                  primitiveUnits=\"objectBoundingBox\"\r\n                  colorInterpolationFilters=\"sRGB\"\r\n                >\r\n                  <feImage href={map} x={REGION.x} y={REGION.y} width={REGION.w} height={REGION.h} preserveAspectRatio=\"none\" result=\"map\" />\r\n                  <feColorMatrix ref={maskMatrixRef} in=\"map\" type=\"matrix\" values={coverMatrix(0)} result=\"cover\" />\r\n                  <feComposite in=\"SourceGraphic\" in2=\"cover\" operator=\"in\" />\r\n                </filter>\r\n              </>\r\n            )}\r\n          </defs>\r\n        </svg>\r\n\r\n        <span\r\n          ref={faceRef}\r\n          data-slot=\"gold-leaf-face\"\r\n          className={cn(\r\n            \"block text-transparent [filter:var(--gl-relief)]\",\r\n            \"motion-safe:group-data-[state=unlaid]/gold-leaf:[filter:var(--gl-lay)] motion-safe:group-data-[state=laying]/gold-leaf:[filter:var(--gl-lay)]\"\r\n          )}\r\n          style={{\r\n            ...textClip,\r\n            padding: pad,\r\n            margin: \"-0.15em -0.1em\",\r\n            backgroundImage: `${leaf.face}, ${env}`,\r\n            backgroundSize: `${tile}, 100% 1lh`,\r\n            backgroundPosition: \"0 0, 0 0.15em\",\r\n            backgroundOrigin: \"border-box\",\r\n            maskImage: leaf.holes,\r\n            WebkitMaskImage: leaf.holes,\r\n            maskSize: tile,\r\n            WebkitMaskSize: tile,\r\n          }}\r\n        >\r\n          {children}\r\n        </span>\r\n\r\n        {/* The highlight: a copy of the text on its own layer, so moving it never re-runs the relief filter. */}\r\n        <span\r\n          ref={glintRef}\r\n          aria-hidden\r\n          inert\r\n          data-slot=\"gold-leaf-glint\"\r\n          className={cn(\r\n            \"pointer-events-none absolute text-transparent select-none\",\r\n            \"motion-safe:group-data-[state=unlaid]/gold-leaf:[filter:var(--gl-mask)] motion-safe:group-data-[state=laying]/gold-leaf:[filter:var(--gl-mask)]\"\r\n          )}\r\n          style={{\r\n            ...textClip,\r\n            inset: \"-0.15em -0.1em\",\r\n            padding: pad,\r\n            backgroundImage: glint,\r\n            backgroundOrigin: \"border-box\",\r\n            maskImage: leaf.facets,\r\n            WebkitMaskImage: leaf.facets,\r\n            maskSize: tile,\r\n            WebkitMaskSize: tile,\r\n            mixBlendMode: \"screen\",\r\n            opacity: `calc(var(--gl-e, ${REST.e}) * ${clamp01(sheen)})`,\r\n            willChange: \"opacity\",\r\n          }}\r\n        >\r\n          {children}\r\n        </span>\r\n      </span>\r\n    </Comp>\r\n  )\r\n}\r\n",
      "type": "registry:component"
    }
  ],
  "meta": {
    "addedAt": "2026-10-27"
  },
  "type": "registry:component"
}