{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "folder-peek",
  "type": "registry:component",
  "title": "Folder Peek",
  "description": "A cardboard folder that opens on hover and lets its documents peek out with a soft bounce.",
  "author": "Marcelo Treviño Velázquez <https://furin.dev>",
  "dependencies": [],
  "categories": [
    "Cards"
  ],
  "docs": "Installed in components/furin/folder-peek/. Docs, live controls and props table: https://furin.dev/components/folder-peek/",
  "files": [
    {
      "path": "registry/folder-peek/FolderPeek.tsx",
      "content": "\"use client\";\nimport { useState } from \"react\";\nimport type { CSSProperties } from \"react\";\nimport \"./FolderPeek.css\";\n\nexport interface FolderPeekProps {\n  /** Texto de la etiqueta de la carpeta. */\n  label?: string;\n  /** Segunda línea pequeña de la etiqueta. */\n  sublabel?: string;\n  /** Color del cartón de la carpeta. */\n  color?: string;\n  /** Color de acento de los documentos. */\n  accent?: string;\n  /** Cuántos documentos asoman (1 a 3). */\n  documents?: number;\n  /** Escala de toda la carpeta. */\n  scale?: number;\n  /** Si es true, la carpeta se queda abierta. */\n  open?: boolean;\n  /** Clase extra para el contenedor. */\n  className?: string;\n  /** Estilos extra para el contenedor. */\n  style?: CSSProperties;\n}\n\n// Anchos de las \"líneas de texto\" de cada documento (porcentajes fijos, nada al azar entre renders).\nconst LINES = [[92, 100, 84, 96, 60, 90, 72], [100, 88, 94, 70, 98, 56, 80], [86, 98, 90, 64, 100, 78, 92]];\n\n/** Carpeta de cartón que se abre al pasar el cursor y deja asomar sus documentos. */\nexport function FolderPeek({\n  label = \"Projects 2026\",\n  sublabel = \"Archive · 24 documents\",\n  color = \"#d6a96c\",\n  accent = \"#3b6bff\",\n  documents = 3,\n  scale = 1,\n  open,\n  className = \"\",\n  style,\n}: FolderPeekProps) {\n  const [hover, setHover] = useState(false);\n  const isOpen = open ?? hover;\n  const n = Math.max(1, Math.min(3, Math.round(documents)));\n  const vars = { \"--fp-color\": color, \"--fp-accent\": accent, \"--fp-scale\": scale } as CSSProperties;\n  return (\n    <div\n      className={`furin-folder ${isOpen ? \"is-open\" : \"\"} ${className}`}\n      style={{ ...vars, ...style }}\n      onPointerEnter={(e) => { if (e.pointerType === \"mouse\") setHover(true); }}\n      onPointerLeave={(e) => { if (e.pointerType === \"mouse\") setHover(false); }}\n      onPointerDown={(e) => { if (e.pointerType !== \"mouse\") setHover((h) => !h); }}\n      role=\"img\"\n      aria-label={`Folder ${label}`}\n    >\n      <div className=\"furin-folder__shadow\" aria-hidden />\n      <div className=\"furin-folder__stage\">\n        <div className=\"furin-folder__back\" />\n        {Array.from({ length: n }, (_, i) => (\n          <div key={i} className={`furin-folder__doc furin-folder__doc--${i}`}>\n            <div className=\"furin-folder__docbar\" />\n            {i === 1 ? (\n              <div className=\"furin-folder__chart\" aria-hidden>{[38, 62, 48, 84, 66, 92].map((h, k) => <i key={k} style={{ height: `${h}%` }} />)}</div>\n            ) : (\n              <div className=\"furin-folder__title\" />\n            )}\n            {LINES[i].map((w, k) => <div key={k} className=\"furin-folder__line\" style={{ width: `${w}%` }} />)}\n          </div>\n        ))}\n        <div className=\"furin-folder__front\">\n          <div className=\"furin-folder__label\">\n            <b>{label}</b>\n            <span>{sublabel}</span>\n          </div>\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default FolderPeek;\n",
      "type": "registry:component",
      "target": "components/furin/folder-peek/FolderPeek.tsx"
    },
    {
      "path": "registry/folder-peek/FolderPeek.css",
      "content": ".furin-folder {\n  --fp-color: #d6a96c; --fp-accent: #3b6bff; --fp-scale: 1;\n  --fp-fiber: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75 0.5' numOctaves='4' seed='5' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .3 0 0 0 0 .18 0 0 0 0 .06 0 0 0 .9 -.28'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23f)'/%3E%3C/svg%3E\");\n  --fp-grain: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .3 0 0 0 0 .22 0 0 0 0 .1 0 0 0 .5 0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E\");\n  position: relative;\n  width: 100%;\n  height: 100%;\n  min-height: 320px;\n  display: grid;\n  place-items: center;\n  padding-top: 44px;\n  cursor: pointer;\n  -webkit-tap-highlight-color: transparent;\n}\n.furin-folder__shadow {\n  position: absolute; left: 50%; top: calc(50% + 96px * var(--fp-scale)); width: calc(300px * var(--fp-scale)); height: calc(30px * var(--fp-scale));\n  transform: translateX(-50%); border-radius: 50%;\n  background: radial-gradient(closest-side, rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0));\n  filter: blur(6px); transition: transform 700ms cubic-bezier(0.2, 1.1, 0.3, 1), opacity 500ms;\n}\n.furin-folder.is-open .furin-folder__shadow { transform: translateX(-50%) scale(1.1, 1.25); opacity: 0.85; }\n.furin-folder__stage {\n  position: relative; width: 320px; height: 240px; perspective: 1100px; perspective-origin: 50% 30%;\n  transform: scale(var(--fp-scale)) translateY(10px); transform-origin: 50% 50%;\n}\n.furin-folder__stage > div { position: absolute; }\n\n.furin-folder__back {\n  inset: 0;\n  clip-path: path(\"M12 0H112Q124 0 130 10L138 22Q142 29 152 29H308Q320 29 320 41V228Q320 240 308 240H12Q0 240 0 228V12Q0 0 12 0Z\");\n  background:\n    var(--fp-fiber) 0 0 / 300px 300px,\n    linear-gradient(180deg, rgba(255, 255, 255, 0.14), rgba(0, 0, 0, 0.1) 100%),\n    color-mix(in srgb, var(--fp-color) 82%, #4a2e12);\n  background-blend-mode: multiply, normal, normal;\n  filter: drop-shadow(0 1px 0 rgba(255, 255, 255, 0.25));\n}\n/* Documentos: entre el respaldo y la tapa. */\n.furin-folder__doc {\n  left: 24px; width: 272px; height: 178px; top: 44px; border-radius: 4px; padding: 18px 20px; box-sizing: border-box;\n  background: var(--fp-grain), linear-gradient(170deg, #fefdfa, #f1eee6);\n  background-blend-mode: multiply, normal;\n  box-shadow: 0 -1px 0 rgba(255, 255, 255, 0.6), 0 6px 14px -4px rgba(40, 24, 8, 0.45), 0 1px 2px rgba(40, 24, 8, 0.35);\n  display: flex; flex-direction: column; gap: 9px; overflow: hidden;\n  transition: transform 800ms cubic-bezier(0.2, 1.25, 0.3, 1);\n}\n.furin-folder__doc--0 { top: 40px; left: 28px; transform: rotate(-1.2deg); }\n.furin-folder__doc--1 { top: 46px; left: 20px; width: 278px; transform: rotate(0.9deg); transition-delay: 40ms; }\n.furin-folder__doc--2 { top: 52px; left: 26px; transform: rotate(-0.4deg); transition-delay: 80ms; }\n.furin-folder.is-open .furin-folder__doc--0 { transform: translateY(-100px) rotate(-3.2deg); }\n.furin-folder.is-open .furin-folder__doc--1 { transform: translateY(-70px) translateX(10px) rotate(2.4deg); transition-delay: 30ms; }\n.furin-folder.is-open .furin-folder__doc--2 { transform: translateY(-40px) translateX(-4px) rotate(-1deg); transition-delay: 70ms; }\n.furin-folder__docbar { height: 8px; width: 42%; border-radius: 2px; background: var(--fp-accent); opacity: 0.9; flex: none; }\n.furin-folder__title { height: 16px; width: 74%; border-radius: 3px; background: #2c2a26; opacity: 0.85; flex: none; margin-bottom: 4px; }\n.furin-folder__line { height: 5px; border-radius: 3px; background: #cdc8bb; flex: none; }\n.furin-folder__chart { height: 46px; display: flex; align-items: flex-end; gap: 6px; flex: none; margin-bottom: 4px; }\n.furin-folder__chart i { flex: 1; border-radius: 2px 2px 0 0; background: color-mix(in srgb, var(--fp-accent) 40%, #e9e5da); }\n.furin-folder__chart i:nth-child(4) { background: var(--fp-accent); }\n\n/* Tapa delantera: bisagra abajo, se inclina hacia quien mira. */\n.furin-folder__front {\n  left: 0; right: 0; top: 62px; bottom: 0; border-radius: 3px 3px 12px 12px;\n  transform-origin: 50% 100%;\n  transform: rotateX(0deg);\n  transition: transform 800ms cubic-bezier(0.2, 1.2, 0.3, 1);\n  background:\n    var(--fp-fiber) 0 0 / 300px 300px,\n    linear-gradient(180deg, rgba(255, 255, 255, 0.22) 0%, rgba(255, 255, 255, 0) 24%, rgba(0, 0, 0, 0.08) 100%),\n    color-mix(in srgb, var(--fp-color) 100%, #fff 0%);\n  background-blend-mode: multiply, normal, normal;\n  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.55), inset 0 -1px 0 rgba(60, 36, 10, 0.3), 0 -6px 14px -6px rgba(40, 24, 8, 0.35);\n}\n.furin-folder.is-open .furin-folder__front { transform: rotateX(-34deg); }\n/* Doblez horizontal del cartón. */\n.furin-folder__front::before { content: \"\"; position: absolute; left: 0; right: 0; top: 18px; height: 1px; background: rgba(70, 42, 12, 0.28); box-shadow: 0 1px 0 rgba(255, 255, 255, 0.3); }\n.furin-folder__label {\n  position: absolute; left: 22px; bottom: 24px; padding: 11px 16px 11px; border-radius: 3px; display: grid; gap: 3px;\n  background: var(--fp-grain), linear-gradient(170deg, #fffefb, #efebe1); background-blend-mode: multiply, normal;\n  box-shadow: 0 2px 5px rgba(50, 30, 8, 0.4), inset 0 0 0 1px rgba(0, 0, 0, 0.05);\n  transform: rotate(-1.5deg);\n  font-family: Geist, system-ui, sans-serif; color: #26241f;\n}\n.furin-folder__label b { font-size: 15px; font-weight: 650; letter-spacing: -0.01em; }\n.furin-folder__label span { font: 500 9.5px/1.2 \"JetBrains Mono\", ui-monospace, monospace; letter-spacing: 0.1em; text-transform: uppercase; color: rgba(38, 36, 31, 0.6); }\n@media (prefers-reduced-motion: reduce) { .furin-folder__front, .furin-folder__doc, .furin-folder__shadow { transition: none; } }\n",
      "type": "registry:file",
      "target": "components/furin/folder-peek/FolderPeek.css"
    }
  ]
}
