{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "glass-ai-card",
  "type": "registry:ui",
  "title": "Glass AI Card",
  "description": "iOS 26 liquid-glass content card with animated skeleton lines and hue-rotating gradient AI action button.",
  "dependencies": [
    "motion"
  ],
  "files": [
    {
      "path": "registry/ruixenui/glass-ai-card.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { motion } from \"motion/react\";\n\n/* ── theme ────────────────────────────────────────────────── */\n\nconst CSS = `\n.gc{\n  --gc-glass:linear-gradient(135deg,rgba(255,255,255,.78),rgba(255,255,255,.62));\n  --gc-border:rgba(0,0,0,.06);\n  --gc-shadow:0 0 1px rgba(0,0,0,.04),0 2px 8px rgba(0,0,0,.04),0 12px 32px rgba(0,0,0,.06),inset 0 1px 0 rgba(255,255,255,.8);\n  --gc-bar:rgba(0,0,0,.06);\n  --gc-bar-shimmer:rgba(0,0,0,.1);\n  --gc-dim:rgba(0,0,0,.45);\n  --gc-mid:rgba(0,0,0,.65);\n  --gc-hi:rgba(0,0,0,.88);\n  --gc-btn-bg:rgba(255,255,255,.92);\n  --gc-btn-border:rgba(0,0,0,.06);\n  --gc-btn-shadow:0 1px 3px rgba(0,0,0,.06);\n  --gc-hover:rgba(0,0,0,.03);\n  --gc-grad-a:#f472b6;\n  --gc-grad-b:#a78bfa;\n}\n.dark .gc,[data-theme=\"dark\"] .gc{\n  --gc-glass:linear-gradient(135deg,rgba(255,255,255,.05),rgba(255,255,255,.02));\n  --gc-border:rgba(255,255,255,.07);\n  --gc-shadow:0 1px 3px rgba(0,0,0,.12),inset 0 1px 0 rgba(255,255,255,.04);\n  --gc-bar:rgba(255,255,255,.06);\n  --gc-bar-shimmer:rgba(255,255,255,.1);\n  --gc-dim:rgba(255,255,255,.35);\n  --gc-mid:rgba(255,255,255,.55);\n  --gc-hi:rgba(255,255,255,.88);\n  --gc-btn-bg:rgba(255,255,255,.06);\n  --gc-btn-border:rgba(255,255,255,.08);\n  --gc-btn-shadow:0 1px 3px rgba(0,0,0,.12);\n  --gc-hover:rgba(255,255,255,.04);\n  --gc-grad-a:#f9a8d4;\n  --gc-grad-b:#c4b5fd;\n}\n@keyframes gc-shimmer{\n  0%{background-position:-200% 0}\n  100%{background-position:200% 0}\n}\n@keyframes gc-hue{\n  0%{filter:hue-rotate(0deg)}\n  100%{filter:hue-rotate(360deg)}\n}\n`;\n\n/* ── sound ────────────────────────────────────────────────── */\n\nlet _a: AudioContext, _b: AudioBuffer;\nconst tick = () => {\n  if (typeof window === \"undefined\") return;\n  if (!_a) {\n    _a = new AudioContext();\n    _b = _a.createBuffer(1, (_a.sampleRate * 0.003) | 0, _a.sampleRate);\n    const d = _b.getChannelData(0);\n    for (let i = 0; i < d.length; i++)\n      d[i] = (Math.random() * 2 - 1) * (1 - i / d.length) ** 4;\n  }\n  const s = _a.createBufferSource();\n  s.buffer = _b;\n  const g = _a.createGain();\n  g.gain.value = 0.08;\n  s.connect(g).connect(_a.destination);\n  s.start();\n};\n\n/* ── skeleton lines layout ───────────────────────────────── */\n\nconst DEFAULT_LINES: number[][] = [[100], [40, 20, 40], [40, 20], [20, 80]];\n\n/* ── component ───────────────────────────────────────────── */\n\ninterface GlassAICardProps {\n  lines?: number[][];\n  actionLabel?: string;\n  onAction?: () => void;\n  sound?: boolean;\n  style?: React.CSSProperties;\n}\n\nexport default function GlassAICard({\n  lines = DEFAULT_LINES,\n  actionLabel = \"Generate\",\n  onAction,\n  sound = true,\n  style,\n}: GlassAICardProps) {\n  const [pressed, setPressed] = React.useState(false);\n\n  const handleClick = () => {\n    if (sound) tick();\n    setPressed(true);\n    onAction?.();\n    setTimeout(() => setPressed(false), 600);\n  };\n\n  return (\n    <>\n      <style dangerouslySetInnerHTML={{ __html: CSS }} />\n      <div\n        className=\"gc\"\n        style={{\n          position: \"relative\",\n          minWidth: 320,\n          maxWidth: 400,\n          padding: 24,\n          background: \"var(--gc-glass)\",\n          border: \"1px solid var(--gc-border)\",\n          borderRadius: 16,\n          boxShadow: \"var(--gc-shadow)\",\n          backdropFilter: \"blur(24px)\",\n          WebkitBackdropFilter: \"blur(24px)\",\n          ...style,\n        }}\n      >\n        {/* skeleton line groups */}\n        <div style={{ display: \"flex\", flexDirection: \"column\", gap: 16 }}>\n          {lines.map((group, gi) => (\n            <div\n              key={gi}\n              style={{ display: \"flex\", flexDirection: \"column\", gap: 8 }}\n            >\n              {group.length === 1 ? (\n                <div\n                  style={{\n                    height: 6,\n                    borderRadius: 999,\n                    background: `linear-gradient(90deg, var(--gc-bar) 40%, var(--gc-bar-shimmer) 50%, var(--gc-bar) 60%)`,\n                    backgroundSize: \"200% 100%\",\n                    animation: \"gc-shimmer 2.4s ease-in-out infinite\",\n                    animationDelay: `${gi * 0.3}s`,\n                    width: `${group[0]}%`,\n                  }}\n                />\n              ) : (\n                <div style={{ display: \"flex\", gap: 4, alignItems: \"center\" }}>\n                  {group.map((w, i) => (\n                    <div\n                      key={i}\n                      style={{\n                        height: 6,\n                        borderRadius: 999,\n                        flex: `0 0 ${w}%`,\n                        background: `linear-gradient(90deg, var(--gc-bar) 40%, var(--gc-bar-shimmer) 50%, var(--gc-bar) 60%)`,\n                        backgroundSize: \"200% 100%\",\n                        animation: \"gc-shimmer 2.4s ease-in-out infinite\",\n                        animationDelay: `${(gi * group.length + i) * 0.15}s`,\n                      }}\n                    />\n                  ))}\n                </div>\n              )}\n            </div>\n          ))}\n        </div>\n\n        {/* action button */}\n        <div style={{ marginTop: 24 }}>\n          <motion.button\n            onClick={handleClick}\n            whileTap={{ scale: 0.96 }}\n            animate={pressed ? { scale: [1, 1.04, 1] } : {}}\n            transition={{ type: \"spring\", stiffness: 500, damping: 30 }}\n            style={{\n              position: \"relative\",\n              display: \"inline-flex\",\n              alignItems: \"center\",\n              gap: 6,\n              height: 32,\n              padding: \"0 14px\",\n              border: \"none\",\n              borderRadius: 999,\n              background: \"transparent\",\n              cursor: \"pointer\",\n              fontSize: 13,\n              fontWeight: 500,\n              color: \"var(--gc-hi)\",\n              overflow: \"hidden\",\n            }}\n          >\n            {/* animated gradient border ring */}\n            <span\n              style={{\n                position: \"absolute\",\n                inset: 0,\n                borderRadius: 999,\n                padding: 1,\n                overflow: \"hidden\",\n              }}\n            >\n              <span\n                style={{\n                  position: \"absolute\",\n                  inset: 0,\n                  borderRadius: 999,\n                  background: `linear-gradient(135deg, var(--gc-grad-a), var(--gc-grad-b))`,\n                  opacity: 0.5,\n                  animation: \"gc-hue 4s linear infinite\",\n                }}\n              />\n              <span\n                style={{\n                  position: \"relative\",\n                  display: \"block\",\n                  width: \"100%\",\n                  height: \"100%\",\n                  borderRadius: 999,\n                  background: \"var(--gc-btn-bg)\",\n                }}\n              />\n            </span>\n\n            {/* sparkles icon */}\n            <span style={{ position: \"relative\", display: \"flex\" }}>\n              <svg\n                width={12}\n                height={12}\n                viewBox=\"0 0 24 24\"\n                fill=\"currentColor\"\n                stroke=\"currentColor\"\n                strokeWidth={2}\n                strokeLinecap=\"round\"\n                strokeLinejoin=\"round\"\n              >\n                <path\n                  d=\"M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z\"\n                  opacity={1}\n                />\n                <path d=\"M20 3v4\" opacity={0.5} />\n                <path d=\"M22 5h-4\" opacity={0.5} />\n                <path d=\"M4 17v2\" opacity={0.5} />\n                <path d=\"M5 18H3\" opacity={0.5} />\n              </svg>\n            </span>\n\n            {/* label */}\n            <span style={{ position: \"relative\" }}>{actionLabel}</span>\n          </motion.button>\n        </div>\n      </div>\n    </>\n  );\n}\n",
      "type": "registry:ui",
      "target": "components/ruixen/glass-ai-card.tsx"
    }
  ]
}