{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "sightline",
  "type": "registry:ui",
  "title": "Sightline",
  "description": "A pinned scroll section where an inline media card grows to full-bleed through a shaped SVG aperture (rounded, circle, pill or any custom path) — corners relax to square, a scrim rises, and the caption rides the aperture's edge before settling as an overlay. Reduced motion skips the pin for a static crossfade.",
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [
    "https://crucibleui.com/r/use-reduced-motion.json"
  ],
  "files": [
    {
      "path": "registry/default/scroll/sightline/sightline.tsx",
      "type": "registry:ui",
      "target": "components/crucible/sightline.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { useInView, useMotionValueEvent, useScroll, useSpring } from \"motion/react\";\n\nimport { cn } from \"@/lib/utils\";\nimport { useReducedMotion } from \"@/hooks/use-reduced-motion\";\n\nexport type SightlineShape = \"rounded\" | \"circle\" | \"pill\" | \"path\";\n\nexport interface SightlineProps\n  extends Omit<React.ComponentPropsWithoutRef<\"section\">, \"children\"> {\n  /**\n   * Media shown through the aperture. Any node works (an `<img>`, `<video>`,\n   * a gradient, a UI mock); it is stretched to fill the full-bleed frame.\n   * Takes precedence over `src`. When neither is given a seeded procedural\n   * plate (layered dusk ridgelines) renders.\n   */\n  children?: React.ReactNode;\n  /** Image or video URL (videos are detected by extension and play muted + looped). */\n  src?: string;\n  /** Alt text for `src` images. Leave empty for decorative media. @default \"\" */\n  alt?: string;\n  /** Aperture outline the media grows through. @default \"rounded\" */\n  shape?: SightlineShape;\n  /**\n   * Custom aperture outline for `shape=\"path\"`: an SVG path `d` string drawn in\n   * a 0–1 unit box (e.g. `\"M0.5 0 L1 1 L0 1 Z\"`). It scales from the center,\n   * keeping its aspect. @default an arched window\n   */\n  path?: string;\n  /** Section height as a percentage of the viewport (or the `scroller`'s height); the extra length is the pinned scroll distance. @default 220 */\n  pinLength?: number;\n  /** Caption that rides the aperture's bottom edge, then settles as an overlay once full-bleed. */\n  caption?: React.ReactNode;\n  /** Maximum scrim darkness laid over the media as it reaches full-bleed (0–1). @default 0.6 */\n  dim?: number;\n  /** Corner radius of the starting card in px (`rounded` shape). @default 28 */\n  radius?: number;\n  /**\n   * Scroll container to track instead of the window. Pass a ref to an\n   * `overflow-y-auto` ancestor; the pin then sizes itself to THAT box.\n   * @default the viewport\n   */\n  scroller?: React.RefObject<HTMLElement | null>;\n  /**\n   * Surface color around the card. Only painted in the reduced-motion\n   * crossfade (the card's surround fades out to reveal the full-bleed media).\n   * @default \"#0a0a0a\"\n   */\n  surface?: string;\n}\n\n/* ------------------------------------------------------------------------ */\n/* Geometry                                                                  */\n/* ------------------------------------------------------------------------ */\n\nconst DEFAULT_PATH =\n  \"M0 1 L0 0.5 C0 0.2239 0.2239 0 0.5 0 C0.7761 0 1 0.2239 1 0.5 L1 1 Z\";\n\nconst clamp01 = (v: number) => (v < 0 ? 0 : v > 1 ? 1 : v);\nconst lerp = (a: number, b: number, t: number) => a + (b - a) * t;\nconst easeInOut = (t: number) =>\n  t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;\nconst smooth = (a: number, b: number, v: number) => {\n  const t = clamp01((v - a) / (b - a));\n  return t * t * (3 - 2 * t);\n};\n\n/** Aperture reaches full-bleed at this progress; the remainder is the overlay hold. */\nconst GROW_START = 0.06;\nconst GROW_END = 0.8;\n\ninterface Frame {\n  /** Aperture box in px, centered in the stage. */\n  w: number;\n  h: number;\n  r: number;\n  /** Media parallax scale. */\n  zoom: number;\n  /** 0→1 growth (eased). */\n  e: number;\n}\n\nfunction cardSize(W: number, H: number, shape: SightlineShape) {\n  const w = Math.min(W * 0.62, 520);\n  const h = Math.min(H * 0.52, w * 0.68);\n  if (shape === \"circle\") {\n    const d = Math.min(W * 0.5, H * 0.52, 340);\n    return { w: d, h: d };\n  }\n  if (shape === \"pill\") return { w: Math.min(W * 0.66, 540), h: Math.min(H * 0.3, 150) };\n  if (shape === \"path\") {\n    const s = Math.min(W * 0.46, H * 0.56, 320);\n    return { w: s, h: s };\n  }\n  return { w, h };\n}\n\nfunction frameAt(p: number, W: number, H: number, shape: SightlineShape, radius: number): Frame {\n  const e = easeInOut(clamp01((p - GROW_START) / (GROW_END - GROW_START)));\n  const c = cardSize(W, H, shape);\n  const zoom = lerp(1.16, 1, e);\n  if (shape === \"circle\") {\n    const d = lerp(c.w, Math.hypot(W, H) + 2, e);\n    return { w: d, h: d, r: d / 2, zoom, e };\n  }\n  if (shape === \"path\") {\n    // A free-form outline never tiles the frame by itself — overshoot so\n    // its interior swallows the stage, and a union rect closes the corners.\n    const s = lerp(c.w, Math.max(W, H) * 2.6, e);\n    return { w: s, h: s, r: 0, zoom, e };\n  }\n  const w = lerp(c.w, W + 2, e);\n  const h = lerp(c.h, H + 2, e);\n  const r0 = shape === \"pill\" ? c.h / 2 : radius;\n  return { w, h, r: r0 * Math.pow(1 - e, 1.4), zoom, e };\n}\n\n/* ------------------------------------------------------------------------ */\n/* Procedural plate — seeded dusk ridgelines (pure math, SSR-identical)      */\n/* ------------------------------------------------------------------------ */\n\nfunction ridge(seed: number, base: number, amp: number): string {\n  const pts: string[] = [];\n  const n = 48;\n  for (let i = 0; i <= n; i++) {\n    const x = (i / n) * 1600;\n    const t = i / n;\n    const y =\n      base +\n      Math.sin(t * 6.1 + seed * 1.7) * amp * 0.55 +\n      Math.sin(t * 13.3 + seed * 3.1) * amp * 0.28 +\n      Math.sin(t * 29.7 + seed * 5.3) * amp * 0.12;\n    pts.push(`${x.toFixed(1)} ${y.toFixed(1)}`);\n  }\n  return `M0 1000 L${pts.join(\" L\")} L1600 1000 Z`;\n}\n\nconst RIDGES = [\n  { d: ridge(1, 560, 70), fill: \"#3b4a63\", opacity: 0.55 },\n  { d: ridge(2, 640, 85), fill: \"#26324a\", opacity: 0.8 },\n  { d: ridge(3, 730, 95), fill: \"#18202f\", opacity: 0.95 },\n  { d: ridge(4, 840, 80), fill: \"#0d121c\", opacity: 1 },\n];\n\nfunction SightlinePlate() {\n  const id = React.useId().replace(/:/g, \"\");\n  return (\n    <svg\n      aria-hidden\n      focusable=\"false\"\n      className=\"absolute inset-0 h-full w-full\"\n      viewBox=\"0 0 1600 1000\"\n      preserveAspectRatio=\"xMidYMid slice\"\n    >\n      <defs>\n        <linearGradient id={`${id}-sky`} x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n          <stop offset=\"0\" stopColor=\"#0a101c\" />\n          <stop offset=\"0.3\" stopColor=\"#1e2b44\" />\n          <stop offset=\"0.5\" stopColor=\"#5d7393\" />\n          <stop offset=\"0.6\" stopColor=\"#c3cfdd\" />\n        </linearGradient>\n        <radialGradient id={`${id}-sun`} cx=\"0.5\" cy=\"0.5\" r=\"0.5\">\n          <stop offset=\"0\" stopColor=\"#f8fafc\" stopOpacity=\"0.95\" />\n          <stop offset=\"0.25\" stopColor=\"#e2e8f0\" stopOpacity=\"0.5\" />\n          <stop offset=\"1\" stopColor=\"#e2e8f0\" stopOpacity=\"0\" />\n        </radialGradient>\n        <linearGradient id={`${id}-haze`} x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n          <stop offset=\"0\" stopColor=\"#c7d2e0\" stopOpacity=\"0\" />\n          <stop offset=\"1\" stopColor=\"#c7d2e0\" stopOpacity=\"0.18\" />\n        </linearGradient>\n      </defs>\n      <rect width=\"1600\" height=\"1000\" fill={`url(#${id}-sky)`} />\n      <circle cx=\"1010\" cy=\"470\" r=\"320\" fill={`url(#${id}-sun)`} />\n      <circle cx=\"1010\" cy=\"470\" r=\"30\" fill=\"#f8fafc\" />\n      {RIDGES.map((r, i) => (\n        <g key={i}>\n          <path d={r.d} fill={r.fill} opacity={r.opacity} />\n          {i < RIDGES.length - 1 && <path d={r.d} fill={`url(#${id}-haze)`} />}\n        </g>\n      ))}\n    </svg>\n  );\n}\n\n/* ------------------------------------------------------------------------ */\n/* Media                                                                     */\n/* ------------------------------------------------------------------------ */\n\nconst VIDEO_RE = /\\.(mp4|webm|mov|m4v|ogv)(\\?|#|$)/i;\n\nfunction SightlineMedia({ children, src, alt }: Pick<SightlineProps, \"children\" | \"src\" | \"alt\">) {\n  if (children) {\n    return <div className=\"absolute inset-0 [&>*]:h-full [&>*]:w-full\">{children}</div>;\n  }\n  if (src && VIDEO_RE.test(src)) {\n    return (\n      <video\n        className=\"absolute inset-0 h-full w-full object-cover\"\n        src={src}\n        autoPlay\n        muted\n        loop\n        playsInline\n        aria-label={alt || undefined}\n      />\n    );\n  }\n  if (src) {\n    // eslint-disable-next-line @next/next/no-img-element\n    return <img className=\"absolute inset-0 h-full w-full object-cover\" src={src} alt={alt ?? \"\"} draggable={false} />;\n  }\n  return <SightlinePlate />;\n}\n\n/* ------------------------------------------------------------------------ */\n/* Sightline                                                                 */\n/* ------------------------------------------------------------------------ */\n\n/**\n * Sightline — a pinned scroll section in which an inline media card grows to\n * full-bleed through a shaped aperture (rounded card, circle, pill or any\n * custom path), its corners relaxing to square while a scrim rises and the\n * caption rides the aperture's lower edge before settling as an overlay.\n */\nexport function Sightline({\n  children,\n  src,\n  alt = \"\",\n  shape = \"rounded\",\n  path = DEFAULT_PATH,\n  pinLength = 220,\n  caption,\n  dim = 0.6,\n  radius = 28,\n  scroller,\n  surface = \"#0a0a0a\",\n  className,\n  style,\n  ...props\n}: SightlineProps) {\n  const reduced = useReducedMotion();\n  const uid = React.useId().replace(/:/g, \"\");\n  const clipId = `sightline-${uid}-clip`;\n\n  const sectionRef = React.useRef<HTMLElement>(null);\n  const stageRef = React.useRef<HTMLDivElement>(null);\n  const mediaRef = React.useRef<HTMLDivElement>(null);\n  const scrimRef = React.useRef<HTMLDivElement>(null);\n  const captionRef = React.useRef<HTMLElement>(null);\n  const captionInnerRef = React.useRef<HTMLDivElement>(null);\n  const ruleRef = React.useRef<HTMLSpanElement>(null);\n  const shapeElRef = React.useRef<SVGRectElement & SVGPathElement>(null);\n  const unionRef = React.useRef<SVGRectElement>(null);\n  const rimRef = React.useRef<SVGRectElement & SVGPathElement>(null);\n  const rimSvgRef = React.useRef<SVGSVGElement>(null);\n\n  // Stage size (px) — clip fractions + caption placement derive from it.\n  const size = React.useRef({ W: 960, H: 540 });\n  // Scroller viewport height when pinned inside a container (null = window → vh units).\n  const [boxH, setBoxH] = React.useState<number | null>(null);\n\n  React.useEffect(() => {\n    const el = scroller?.current;\n    if (!el) return;\n    // ResizeObserver fires once on observe, so this also seeds the height.\n    const ro = new ResizeObserver(() => setBoxH(el.clientHeight));\n    ro.observe(el);\n    return () => ro.disconnect();\n  }, [scroller]);\n\n  const { scrollYProgress } = useScroll({\n    target: sectionRef,\n    container: scroller,\n    offset: [\"start start\", \"end end\"],\n  });\n  const progress = useSpring(scrollYProgress, { stiffness: 260, damping: 42, restDelta: 0.0004 });\n\n  const paint = React.useCallback(\n    (p: number) => {\n      const { W, H } = size.current;\n      if (W <= 0 || H <= 0) return;\n      const f = frameAt(p, W, H, shape, radius);\n      const x = (W - f.w) / 2;\n      const y = (H - f.h) / 2;\n\n      const el = shapeElRef.current;\n      const rim = rimRef.current;\n      if (shape === \"path\") {\n        const sx = f.w / W;\n        const sy = f.h / H;\n        el?.setAttribute(\n          \"transform\",\n          `translate(${(x / W).toFixed(5)} ${(y / H).toFixed(5)}) scale(${sx.toFixed(5)} ${sy.toFixed(5)})`\n        );\n        rim?.setAttribute(\"transform\", `translate(${x.toFixed(2)} ${y.toFixed(2)}) scale(${f.w.toFixed(3)})`);\n        // Union rect closes the frame once the outline has swallowed most of it.\n        const u = smooth(0.55, 1, f.e);\n        const uw = u * (W + 2);\n        const uh = u * (H + 2);\n        const ur = unionRef.current;\n        if (ur) {\n          ur.setAttribute(\"x\", String((W - uw) / 2 / W));\n          ur.setAttribute(\"y\", String((H - uh) / 2 / H));\n          ur.setAttribute(\"width\", String(uw / W));\n          ur.setAttribute(\"height\", String(uh / H));\n        }\n      } else if (el) {\n        el.setAttribute(\"x\", String(x / W));\n        el.setAttribute(\"y\", String(y / H));\n        el.setAttribute(\"width\", String(f.w / W));\n        el.setAttribute(\"height\", String(f.h / H));\n        el.setAttribute(\"rx\", String(f.r / W));\n        el.setAttribute(\"ry\", String(f.r / H));\n        if (rim) {\n          rim.setAttribute(\"x\", x.toFixed(2));\n          rim.setAttribute(\"y\", y.toFixed(2));\n          rim.setAttribute(\"width\", f.w.toFixed(2));\n          rim.setAttribute(\"height\", f.h.toFixed(2));\n          rim.setAttribute(\"rx\", f.r.toFixed(2));\n        }\n      }\n      if (rimSvgRef.current) rimSvgRef.current.style.opacity = String(1 - smooth(0.45, 0.95, f.e));\n\n      if (mediaRef.current) mediaRef.current.style.transform = `scale(${f.zoom.toFixed(4)})`;\n      if (scrimRef.current) scrimRef.current.style.opacity = String(dim * smooth(0.3, 1, p));\n\n      // Caption: ride just below the aperture edge, clamp inside the frame,\n      // then settle as an overlay past 0.85.\n      const cap = captionRef.current;\n      if (cap) {\n        const capH = cap.offsetHeight;\n        const edge = shape === \"path\" ? y + f.h : y + f.h;\n        const riding = edge + 18;\n        const settledY = H - capH - Math.max(28, H * 0.08);\n        const top = Math.min(riding, settledY);\n        cap.style.transform = `translate3d(0, ${top.toFixed(2)}px, 0)`;\n        const s = smooth(0.82, 0.97, p);\n        if (captionInnerRef.current) {\n          captionInnerRef.current.style.transform = `scale(${(1 + s * 0.28).toFixed(4)})`;\n          captionInnerRef.current.style.color = `rgb(255 255 255 / ${(0.62 + s * 0.38).toFixed(3)})`;\n        }\n        if (ruleRef.current) {\n          ruleRef.current.style.opacity = String(s);\n          ruleRef.current.style.transform = `scaleX(${s.toFixed(4)})`;\n        }\n      }\n    },\n    [shape, radius, dim]\n  );\n\n  useMotionValueEvent(progress, \"change\", paint);\n\n  // Measure the sticky stage and repaint on any size change.\n  React.useLayoutEffect(() => {\n    if (reduced) return;\n    const stage = stageRef.current;\n    if (!stage) return;\n    const measure = () => {\n      size.current = { W: stage.clientWidth, H: stage.clientHeight };\n      if (rimSvgRef.current) {\n        rimSvgRef.current.setAttribute(\"viewBox\", `0 0 ${size.current.W} ${size.current.H}`);\n      }\n      paint(progress.get());\n    };\n    measure();\n    const ro = new ResizeObserver(measure);\n    ro.observe(stage);\n    if (captionRef.current) ro.observe(captionRef.current);\n    return () => ro.disconnect();\n  }, [reduced, paint, progress, boxH]);\n\n  if (reduced) {\n    return (\n      <SightlineStatic\n        className={className}\n        style={style}\n        caption={caption}\n        shape={shape}\n        path={path}\n        radius={radius}\n        dim={dim}\n        surface={surface}\n        scroller={scroller}\n        boxH={boxH}\n        {...props}\n      >\n        <SightlineMedia src={src} alt={alt}>\n          {children}\n        </SightlineMedia>\n      </SightlineStatic>\n    );\n  }\n\n  const sectionHeight = boxH != null ? (boxH * pinLength) / 100 : `${pinLength}vh`;\n  const stageHeight = boxH != null ? boxH : \"100vh\";\n\n  return (\n    <section\n      ref={sectionRef}\n      data-crucible=\"sightline\"\n      className={cn(\"relative w-full\", className)}\n      style={{ height: sectionHeight, ...style }}\n      {...props}\n    >\n      <div\n        ref={stageRef}\n        className=\"sticky top-0 isolate w-full overflow-hidden\"\n        style={{ height: stageHeight }}\n      >\n        <svg aria-hidden focusable=\"false\" width=\"0\" height=\"0\" className=\"absolute\">\n          <defs>\n            <clipPath id={clipId} clipPathUnits=\"objectBoundingBox\">\n              {shape === \"path\" ? (\n                <>\n                  <path ref={shapeElRef} d={path} />\n                  <rect ref={unionRef} x=\"0.5\" y=\"0.5\" width=\"0\" height=\"0\" />\n                </>\n              ) : (\n                <rect ref={shapeElRef} x=\"0.2\" y=\"0.25\" width=\"0.6\" height=\"0.5\" />\n              )}\n            </clipPath>\n          </defs>\n        </svg>\n\n        <figure className=\"absolute inset-0 m-0\">\n          <div\n            className=\"absolute inset-0 overflow-hidden\"\n            style={{ clipPath: `url(#${clipId})`, WebkitClipPath: `url(#${clipId})` }}\n          >\n            <div ref={mediaRef} className=\"absolute inset-0 will-change-transform\">\n              <SightlineMedia src={src} alt={alt}>\n                {children}\n              </SightlineMedia>\n            </div>\n            <div\n              ref={scrimRef}\n              aria-hidden\n              className=\"pointer-events-none absolute inset-0 opacity-0\"\n              style={{\n                background:\n                  \"linear-gradient(to top, rgb(0 0 0 / 0.95) 0%, rgb(0 0 0 / 0.55) 45%, rgb(0 0 0 / 0.35) 100%)\",\n              }}\n            />\n          </div>\n\n          {/* Hairline rim tracing the aperture — fades as it reaches full-bleed. */}\n          <svg\n            ref={rimSvgRef}\n            aria-hidden\n            focusable=\"false\"\n            className=\"pointer-events-none absolute inset-0 h-full w-full overflow-visible\"\n          >\n            {shape === \"path\" ? (\n              <path\n                ref={rimRef}\n                d={path}\n                fill=\"none\"\n                stroke=\"rgb(255 255 255 / 0.22)\"\n                strokeWidth={1}\n                vectorEffect=\"non-scaling-stroke\"\n              />\n            ) : (\n              <rect ref={rimRef} fill=\"none\" stroke=\"rgb(255 255 255 / 0.2)\" strokeWidth={1} />\n            )}\n          </svg>\n\n          {caption != null && (\n            <figcaption\n              ref={captionRef}\n              className=\"pointer-events-none absolute inset-x-0 top-0 flex justify-center px-6 will-change-transform\"\n            >\n              <div\n                ref={captionInnerRef}\n                className=\"flex origin-top flex-col items-center gap-2 text-center text-sm font-medium tracking-tight text-white/60 [text-shadow:0_1px_12px_rgb(0_0_0/0.5)]\"\n              >\n                {caption}\n                <span ref={ruleRef} aria-hidden className=\"block h-px w-10 origin-center bg-white/60 opacity-0\" />\n              </div>\n            </figcaption>\n          )}\n        </figure>\n      </div>\n    </section>\n  );\n}\n\n/* ------------------------------------------------------------------------ */\n/* Reduced motion — no pin; the card's surround crossfades away on enter     */\n/* ------------------------------------------------------------------------ */\n\ninterface SightlineStaticProps\n  extends Omit<React.ComponentPropsWithoutRef<\"section\">, \"children\"> {\n  children: React.ReactNode;\n  caption?: React.ReactNode;\n  shape: SightlineShape;\n  path: string;\n  radius: number;\n  dim: number;\n  surface: string;\n  scroller?: React.RefObject<HTMLElement | null>;\n  boxH: number | null;\n}\n\nfunction SightlineStatic({\n  children,\n  caption,\n  shape,\n  path,\n  radius,\n  dim,\n  surface,\n  scroller,\n  boxH,\n  className,\n  style,\n  ...props\n}: SightlineStaticProps) {\n  const ref = React.useRef<HTMLElement>(null);\n  const maskId = `sightline-${React.useId().replace(/:/g, \"\")}-mask`;\n  const inView = useInView(ref, { root: scroller, amount: 0.8, once: true });\n  const [dims, setDims] = React.useState({ W: 960, H: 540 });\n\n  React.useLayoutEffect(() => {\n    const el = ref.current;\n    if (!el) return;\n    const measure = () => setDims({ W: el.clientWidth, H: el.clientHeight });\n    measure();\n    const ro = new ResizeObserver(measure);\n    ro.observe(el);\n    return () => ro.disconnect();\n  }, []);\n\n  const { W, H } = dims;\n  const f = frameAt(0, W, H, shape, radius);\n  const x = (W - f.w) / 2;\n  const y = (H - f.h) / 2;\n  const fade = \"opacity 900ms cubic-bezier(0.22, 1, 0.36, 1)\";\n\n  return (\n    <section\n      ref={ref}\n      data-crucible=\"sightline\"\n      className={cn(\"relative isolate w-full overflow-hidden\", className)}\n      style={{ height: boxH ?? \"100vh\", ...style }}\n      {...props}\n    >\n      <figure className=\"absolute inset-0 m-0\">\n        {children}\n        <div\n          aria-hidden\n          className=\"pointer-events-none absolute inset-0\"\n          style={{\n            opacity: inView ? dim : 0,\n            transition: fade,\n            background: \"linear-gradient(to top, rgb(0 0 0 / 0.95) 0%, rgb(0 0 0 / 0.55) 45%, rgb(0 0 0 / 0.35) 100%)\",\n          }}\n        />\n        {/* Surround painted in the surface color with a card-shaped hole. */}\n        <svg\n          aria-hidden\n          focusable=\"false\"\n          className=\"pointer-events-none absolute inset-0 h-full w-full\"\n          viewBox={`0 0 ${W} ${H}`}\n          style={{ opacity: inView ? 0 : 1, transition: fade }}\n        >\n          <defs>\n            <mask id={maskId}>\n              <rect width={W} height={H} fill=\"#fff\" />\n              {shape === \"path\" ? (\n                <path d={path} fill=\"#000\" transform={`translate(${x} ${y}) scale(${f.w})`} />\n              ) : (\n                <rect x={x} y={y} width={f.w} height={f.h} rx={f.r} fill=\"#000\" />\n              )}\n            </mask>\n          </defs>\n          <rect width={W} height={H} fill={surface} mask={`url(#${maskId})`} />\n        </svg>\n        {caption != null && (\n          <figcaption className=\"pointer-events-none absolute inset-x-0 bottom-[8%] flex justify-center px-6\">\n            <div className=\"text-center text-base font-medium tracking-tight text-white [text-shadow:0_1px_12px_rgb(0_0_0/0.5)]\">\n              {caption}\n            </div>\n          </figcaption>\n        )}\n      </figure>\n    </section>\n  );\n}\n\n"
    }
  ]
}