# Bento Grid 2

> Solace UI bento grid block variation 2.

A shadcn/ui block from the [@solaceui](https://www.solaceui.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/solaceui/bento-grid-2).

- Page, with a live preview: https://shadcn.exchange/r/solaceui/bento-grid-2
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/solaceui/bento-grid-2-light-466d24c6f78a852b.png
- Registry item: https://www.solaceui.com/r/bento-grid-2.json
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://www.solaceui.com/r/bento-grid-2.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `lucide-react`, `motion`

## Files

### `src/registry/blocks/bento-grid/two/index.tsx`

```tsx
"use client";

import { useState } from "react";
import {
    BentoGridTemplateTwo,
    BentoItem,
} from "@/registry/blocks/bento-grid/two/bento-grid-template-two";

const sampleBentoData: BentoItem[] = [
    {
        id: "design-system",
        title: "Visual Design System",
        description: "A comprehensive blueprint system built for layout structure.",
        size: "large",
        tag: "Blueprint",
        link: "#design",
    },
    {
        id: "ai-studio",
        title: "AI Studio",
        description: "Train and run agent prompting nodes with simple inputs.",
        size: "small",
        tag: "Active",
        link: "#ai",
    },
    {
        id: "analytics",
        title: "Analytics Engine",
        description: "Real-time metric telemetry and sparkline graphing.",
        size: "small",
        tag: "Live",
        link: "#analytics",
    },
    {
        id: "cloud-platform",
        title: "Cloud Delivery Edge",
        description: "Globally distributed regional edge nodes with real-time status reporting.",
        size: "wide",
        tag: "Edge",
        link: "#cloud",
    },
    {
        id: "security",
        title: "Security Suite",
        description: "Enterprise access control with JWT signature validation.",
        size: "small",
        tag: "Secure",
        link: "#security",
    },
    {
        id: "dev-hub",
        title: "Developer Hub",
        description: "CLI components and automated workspace setups.",
        size: "small",
        tag: "CLI Tool",
        link: "#docs",
    },
    {
        id: "collaboration",
        title: "Realtime Collaboration",
        description: "Multiplayer live presence cursors and shared scaling viewports.",
        size: "small",
        tag: "Multiplayer",
        link: "#collaboration",
    },
    {
        id: "community",
        title: "Community & Integrations",
        description: "Sync schemas across third-party operations pipelines.",
        size: "small",
        tag: "Sync Ready",
        link: "#community",
    },
];

export default function BentoGridTwo() {
    const [items] = useState<BentoItem[]>(sampleBentoData);

    return (
        <div className="container mx-auto px-4 py-16 md:py-24">
            <BentoGridTemplateTwo items={items} gap={6} animate={true} />
        </div>
    );
}
```

### `src/registry/blocks/bento-grid/two/bento-grid-template-two.tsx`

```tsx
"use client";

import React, { useState, useEffect } from "react";
import { motion } from "motion/react";
import { cn } from "@/lib/utils";
import Link from "next/link";
import { ArrowUpRight, Lock, CheckCircle2, RefreshCw } from "lucide-react";

export type BentoItem = {
    id: string;
    title: string;
    description?: string;
    size?: "small" | "medium" | "large" | "wide" | "tall";
    tag?: string;
    link?: string;
};

export type BentoGridProps = {
    items: BentoItem[];
    className?: string;
    animate?: boolean;
    gap?: number;
};

export function BentoGridTemplateTwo({
    items,
    className,
    animate = true,
    gap = 6,
}: BentoGridProps) {
    return (
        <div
            className={cn(
                "grid grid-cols-1 md:grid-cols-4 auto-rows-[minmax(270px,auto)] w-full max-w-7xl mx-auto",
                className
            )}
            style={{ gap: `${gap * 0.25}rem` }}
        >
            {items.map((item, i) => {
                return (
                    <motion.div
                        key={item.id}
                        initial={animate ? { opacity: 0, y: 15 } : undefined}
                        animate={animate ? { opacity: 1, y: 0 } : undefined}
                        transition={{
                            duration: 0.4,
                            delay: animate ? i * 0.04 : 0,
                            ease: [0.25, 1, 0.5, 1],
                        }}
                        className={cn(
                            "col-span-1 h-full",
                            item.size === "large" && "md:col-span-2 md:row-span-2",
                            item.size === "wide" && "md:col-span-2 md:row-span-1"
                        )}
                    >
                        <BentoGridItem item={item} />
                    </motion.div>
                );
            })}
        </div>
    );
}

// Card 1: Visual Design System Morphing Mockup
function DesignSystemMockup() {
    const [isMobile, setIsMobile] = useState(false);

    useEffect(() => {
        const interval = setInterval(() => {
            setIsMobile((prev) => !prev);
        }, 3000);
        return () => clearInterval(interval);
    }, []);

    return (
        <div className="w-full h-full flex flex-col justify-between border border-zinc-200 bg-zinc-50/50 dark:border-zinc-900 dark:bg-[#050507] p-5 relative overflow-hidden select-none min-h-[220px]">
            {/* Blueprint Grid Lines */}
            <div className="absolute inset-0 opacity-10 pointer-events-none">
                <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" className="text-zinc-900 dark:text-white">
                    <defs>
                        <pattern id="design-grid" width="12" height="12" patternUnits="userSpaceOnUse">
                            <path d="M 12 0 L 0 0 0 12" fill="none" stroke="currentColor" strokeWidth="0.5" />
                        </pattern>
                      </defs>
                      <rect width="100%" height="100%" fill="url(#design-grid)" />
                </svg>
            </div>

            {/* Header details */}
            <div className="relative z-10 flex justify-between items-center font-mono text-[9px] text-zinc-400 dark:text-zinc-500 border-b border-zinc-200 dark:border-zinc-900 pb-2 mb-2">
                <span className="text-zinc-700 dark:text-zinc-300 font-semibold tracking-wider">RESPONSIVE CANVAS</span>
                <span>{isMobile ? "VIEWPORT: MOBILE" : "VIEWPORT: DESKTOP"}</span>
            </div>

            {/* Morphing layout boxes */}
            <div className="relative z-10 flex-grow flex flex-col justify-center gap-4 py-2">
                <motion.div 
                    layout
                    transition={{ duration: 0.6, ease: [0.25, 1, 0.5, 1] }}
                    className={cn(
                        "w-full flex gap-3",
                        isMobile ? "flex-col items-stretch" : "flex-row items-center"
                    )}
                >
                    {/* Box 1: Core Hero block */}
                    <motion.div 
                        layout
                        className="flex-grow p-3 border border-zinc-200 bg-white/80 dark:border-zinc-800 dark:bg-zinc-950/60 min-h-[50px] flex flex-col justify-between rounded-none"
                    >
                        <div className="h-1.5 w-1/3 bg-zinc-300 dark:bg-zinc-850" />
                        <div className="h-1 w-full bg-zinc-200 dark:bg-zinc-900/60 mt-2" />
                    </motion.div>

                    {/* Box 2: Secondary card */}
                    <motion.div 
                        layout
                        className={cn(
                            "p-3 border border-zinc-200 bg-white/80 dark:border-zinc-800 dark:bg-zinc-950/60 min-h-[50px] flex flex-col justify-between rounded-none",
                            isMobile ? "w-full" : "w-[30%]"
                        )}
                    >
                        <div className="h-1.5 w-1/2 bg-zinc-300 dark:bg-zinc-850" />
                        <div className="h-1 w-full bg-zinc-200 dark:bg-zinc-900/60 mt-2" />
                    </motion.div>

                    {/* Box 3: Tertiary card */}
                    <motion.div 
                        layout
                        className={cn(
                            "p-3 border border-zinc-200 bg-white/80 dark:border-zinc-800 dark:bg-zinc-950/60 min-h-[50px] flex flex-col justify-between rounded-none",
                            isMobile ? "w-full" : "w-[25%]"
                        )}
                    >
                        <div className="h-1.5 w-2/3 bg-indigo-500/20 dark:bg-indigo-500/15" />
                        <div className="h-1 w-full bg-zinc-200 dark:bg-zinc-900/60 mt-2" />
                    </motion.div>
                </motion.div>

                {/* Canvas alignment indicators */}
                <div className="flex justify-between items-center font-mono text-[8px] text-zinc-400 dark:text-zinc-650 mt-1">
                    <div className="flex items-center gap-1.5">
                        <span className="h-1 w-1 bg-indigo-500 rounded-full" />
                        <span>Auto-Layout: Flex</span>
                    </div>
                    <span>Gap: 12px</span>
                </div>
            </div>

            {/* Footer details */}
            <div className="relative z-10 text-[9px] font-mono text-zinc-400 dark:text-zinc-650 flex justify-between items-center pt-3 border-t border-zinc-200 dark:border-zinc-900">
                <span>COORDINATE MAPPING ENGINE</span>
                <span className="h-1.5 w-1.5 bg-indigo-500 animate-ping rounded-none" />
            </div>
        </div>
    );
}

// Card 2: AI Studio typewriting effect
function AIStudioMockup() {
    const text = "Design modular navigation bar with responsive layout";
    const [displayText, setDisplayText] = useState("");

    useEffect(() => {
        let i = 0;
        let isDeleting = false;
        let timer: NodeJS.Timeout;

        const type = () => {
            if (!isDeleting) {
                setDisplayText(text.slice(0, i));
                i++;
                if (i > text.length) {
                    isDeleting = true;
                    timer = setTimeout(type, 1500); // pause at the end
                    return;
                }
                timer = setTimeout(type, 70);
            } else {
                setDisplayText(text.slice(0, i));
                i--;
                if (i < 0) {
                    isDeleting = false;
                    i = 0;
                    timer = setTimeout(type, 500); // pause before starting over
                    return;
                }
                timer = setTimeout(type, 30);
            }
        };

        type();
        return () => clearTimeout(timer);
    }, []);

    return (
        <div className="w-full h-[120px] flex flex-col justify-between border border-zinc-200 bg-zinc-50/50 dark:border-zinc-900 dark:bg-[#040405] p-3 font-mono text-[10px] text-zinc-500 relative overflow-hidden select-none">
            <div className="space-y-1">
                <div className="flex items-center justify-between text-zinc-650 dark:text-zinc-400 pb-1.5 border-b border-zinc-200 dark:border-zinc-900/60">
                    <span>Agent Prompt</span>
                    <span className="text-[9px] text-zinc-400 dark:text-zinc-600">Model: sol-v4</span>
                </div>
                <div className="pt-2 text-[10px] leading-relaxed text-zinc-750 dark:text-zinc-400 min-h-[40px]">
                    <span className="text-zinc-400 dark:text-zinc-600">&gt; </span>
                    <span>{displayText}</span>
                    <span className="animate-pulse text-indigo-500 dark:text-indigo-400 font-bold ml-0.5">|</span>
                </div>
            </div>
            <div className="flex justify-between items-center pt-2 border-t border-zinc-200 dark:border-zinc-900/60">
                <span className="text-[9px] text-zinc-400 dark:text-zinc-600">Tokens: {displayText.length * 3} / 8k</span>
                <button className="px-2.5 py-0.5 bg-white border border-zinc-200 hover:bg-zinc-50 text-zinc-800 dark:bg-zinc-900 dark:border-zinc-800 dark:text-white dark:hover:bg-zinc-800 transition-colors cursor-pointer text-[9px] rounded-none">
                    EXECUTE
                </button>
            </div>
        </div>
    );
}

// Card 3: Analytics build of curve animation
function AnalyticsMockup() {
    return (
        <div className="w-full h-[120px] flex flex-col justify-between border border-zinc-200 bg-zinc-50/50 dark:border-zinc-900 dark:bg-[#040405] p-3 font-mono text-[10px] text-zinc-500 relative overflow-hidden select-none">
            <div className="flex items-center justify-between text-zinc-650 dark:text-zinc-400 pb-1.5 border-b border-zinc-200 dark:border-zinc-900/60">
                <span>Telemetry Rate</span>
                <span className="text-[9px] text-emerald-500 dark:text-emerald-400 flex items-center gap-1">
                    <span className="h-1.5 w-1.5 rounded-full bg-emerald-500 dark:bg-emerald-400 animate-pulse" />
                    ONLINE
                </span>
            </div>
            <div className="py-2.5 flex items-center justify-center">
                <svg className="w-full h-10" viewBox="0 0 100 30" fill="none" xmlns="http://www.w3.org/2000/svg">
                    {/* Background grid lines */}
                    <line x1="0" y1="10" x2="100" y2="10" stroke="currentColor" className="text-zinc-200/50 dark:text-zinc-900/50" strokeWidth="0.5" />
                    <line x1="0" y1="20" x2="100" y2="20" stroke="currentColor" className="text-zinc-200/50 dark:text-zinc-900/50" strokeWidth="0.5" />
                    
                    <motion.path
                        d="M0 25 L15 20 L30 22 L45 8 L60 18 L75 10 L90 5 L100 8"
                        stroke="#6366f1"
                        strokeWidth="1.5"
                        fill="none"
                        animate={{ pathLength: [0, 1, 1, 0] }}
                        transition={{
                            duration: 5,
                            repeat: Infinity,
                            ease: "easeInOut",
                            times: [0, 0.7, 0.9, 1]
                        }}
                    />
                    <motion.circle
                        cx="100"
                        cy="8"
                        r="2"
                        fill="#818cf8"
                        animate={{
                            opacity: [0, 0, 1, 0],
                            scale: [0.5, 1, 1.4, 0.5]
                        }}
                        transition={{
                            duration: 5,
                            repeat: Infinity,
                            ease: "easeInOut",
                            times: [0, 0.65, 0.7, 1]
                        }}
                    />
                </svg>
            </div>
            <div className="flex justify-between items-center text-[9px] text-zinc-400 dark:text-zinc-600">
                <span>AVG LATENCY: 14ms</span>
                <span>SYNC RATE: 99.98%</span>
            </div>
        </div>
    );
}

// Card 4: Cloud Latency Monitor Mockup
function CloudMockup() {
    const [latency1, setLatency1] = useState(11);
    const [latency2, setLatency2] = useState(24);
    const [latency3, setLatency3] = useState(38);

    useEffect(() => {
        const interval = setInterval(() => {
            setLatency1(Math.floor(9 + Math.random() * 5));
            setLatency2(Math.floor(21 + Math.random() * 6));
            setLatency3(Math.floor(35 + Math.random() * 7));
        }, 2000);
        return () => clearInterval(interval);
    }, []);

    return (
        <div className="w-full h-[100px] flex flex-col justify-between border border-zinc-200 bg-zinc-50/50 dark:border-zinc-900 dark:bg-[#040405] p-3 font-mono text-[10px] text-zinc-500 relative overflow-hidden select-none">
            <div className="flex items-center justify-between text-zinc-600 dark:text-zinc-400 pb-1.5 border-b border-zinc-200 dark:border-zinc-900/60">
                <span>Regional Edge Nodes</span>
                <span>Active Distribution</span>
            </div>
            <div className="grid grid-cols-3 gap-2.5 py-1">
                <div className="p-2 border border-zinc-205 bg-white dark:border-zinc-900 dark:bg-zinc-950/40 flex items-center justify-between">
                    <span>US-EAST</span>
                    <span className="text-emerald-500 dark:text-emerald-400 flex items-center gap-1 font-semibold">
                        <span className="size-1 rounded-full bg-emerald-500 dark:bg-emerald-400 animate-ping" />
                        {latency1}ms
                    </span>
                </div>
                <div className="p-2 border border-zinc-205 bg-white dark:border-zinc-900 dark:bg-zinc-950/40 flex items-center justify-between">
                    <span>EU-WEST</span>
                    <span className="text-emerald-500 dark:text-emerald-400 flex items-center gap-1 font-semibold">
                        <span className="size-1 rounded-full bg-emerald-500 dark:bg-emerald-400" />
                        {latency2}ms
                    </span>
                </div>
                <div className="p-2 border border-zinc-205 bg-white dark:border-zinc-900 dark:bg-zinc-950/40 flex items-center justify-between">
                    <span>AP-SOUTH</span>
                    <span className="text-emerald-500 dark:text-emerald-400 flex items-center gap-1 font-semibold">
                        <span className="size-1 rounded-full bg-emerald-500 dark:bg-emerald-400" />
                        {latency3}ms
                    </span>
                </div>
            </div>
        </div>
    );
}

// Card 5: Security Lock Mockup
function SecurityMockup() {
    const [isValidating, setIsValidating] = useState(false);

    useEffect(() => {
        const interval = setInterval(() => {
            setIsValidating(true);
            setTimeout(() => setIsValidating(false), 900);
        }, 4000);
        return () => clearInterval(interval);
    }, []);

    return (
        <div className="w-full h-[120px] flex flex-col justify-between border border-zinc-200 bg-zinc-50/50 dark:border-zinc-900 dark:bg-[#040405] p-3 font-mono text-[9px] text-zinc-500 relative overflow-hidden select-none">
            <div className="flex items-center justify-between text-zinc-650 dark:text-zinc-400 pb-1.5 border-b border-zinc-200 dark:border-zinc-900/60">
                <span>Access Control</span>
                <Lock className={cn("h-3 w-3 transition-colors duration-300", isValidating ? "text-emerald-500" : "text-indigo-500 dark:text-indigo-400")} />
            </div>
            <div className="py-2.5 break-all leading-normal opacity-85">
                <span className="text-indigo-550 dark:text-indigo-400 font-medium">eyJhbGciOiJIUzI1NiJ9.</span>
                <span className="text-zinc-600 dark:text-zinc-500">eyJuYW1lIjoiU2FyYWgifQ.</span>
                <span className="text-zinc-700 dark:text-zinc-700">signature-verification-key</span>
            </div>
            <div className="flex justify-between items-center text-[8px] font-semibold">
                <span>ALGORITHM: HS256</span>
                <span className={cn("transition-colors duration-300", isValidating ? "text-emerald-500" : "text-zinc-400 dark:text-zinc-600")}>
                    {isValidating ? "VERIFYING..." : "SIGNATURE VALIDATED"}
                </span>
            </div>
        </div>
    );
}

// Card 6: Developer CLI mockup
function DeveloperHubMockup() {
    const [step, setStep] = useState(0);

    useEffect(() => {
        const interval = setInterval(() => {
            setStep((prev) => (prev + 1) % 3);
        }, 3000);
        return () => clearInterval(interval);
    }, []);

    return (
        <div className="w-full h-[120px] flex flex-col justify-between border border-zinc-200 bg-zinc-50/50 dark:border-zinc-900 dark:bg-[#040405] p-3 font-mono text-[10px] text-zinc-500 relative overflow-hidden select-none">
            <div className="flex items-center gap-1 text-zinc-400 dark:text-zinc-750 pb-1.5 border-b border-zinc-200 dark:border-zinc-900/60">
                <div className="size-1.5 bg-zinc-300 dark:bg-zinc-800" />
                <div className="size-1.5 bg-zinc-300 dark:bg-zinc-800" />
                <div className="size-1.5 bg-zinc-300 dark:bg-zinc-800" />
                <span className="ml-auto text-[8px] text-zinc-400 dark:text-zinc-600">terminal</span>
            </div>
            <div className="py-2 space-y-1.5 min-h-[50px] flex flex-col justify-center">
                {step >= 0 && (
                    <div>
                        <span className="text-zinc-400 dark:text-zinc-600">$ </span>
                        <span className="text-zinc-900 dark:text-white">npx solaceui add bento-grid</span>
                    </div>
                )}
                {step === 1 && (
                    <div className="text-zinc-400 flex items-center gap-1.5 text-[9px]">
                        <RefreshCw className="h-2.5 w-2.5 animate-spin" />
                        <span>installing components...</span>
                    </div>
                )}
                {step === 2 && (
                    <div className="text-emerald-600 dark:text-emerald-500 opacity-90 text-[9px] flex items-center gap-1">
                        <CheckCircle2 className="h-3 w-3" />
                        <span>Component successfully added</span>
                    </div>
                )}
            </div>
            <div className="text-[8px] text-zinc-405 dark:text-zinc-700 border-t border-zinc-200 dark:border-zinc-900/40 pt-1.5">
                solaceui-cli@1.0.8
            </div>
        </div>
    );
}

// Card 8: Community Integrations Sync Grid Mockup
function CommunityMockup() {
    const [activeNode, setActiveNode] = useState(0);

    useEffect(() => {
        const interval = setInterval(() => {
            setActiveNode((prev) => (prev + 1) % 4);
        }, 1500);
        return () => clearInterval(interval);
    }, []);

    const nodes = ["GitHub", "Figma", "Slack", "Linear"];

    return (
        <div className="w-full h-[120px] flex flex-col justify-between border border-zinc-200 bg-zinc-50/50 dark:border-zinc-900 dark:bg-[#040405] p-3 font-mono text-[9px] text-zinc-500 relative overflow-hidden select-none">
            <div className="flex items-center justify-between text-zinc-600 dark:text-zinc-400 pb-1.5 border-b border-zinc-200 dark:border-zinc-900/60">
                <span>Schema Sync</span>
                <span className="text-[8px] text-indigo-400 animate-pulse">SYNCING</span>
            </div>
            <div className="grid grid-cols-2 gap-1.5 py-2">
                {nodes.map((node, index) => {
                    const isActive = activeNode === index;
                    return (
                        <div
                            key={node}
                            className={cn(
                                "p-1 border text-center transition-all duration-300 rounded-none cursor-pointer",
                                isActive 
                                    ? "border-indigo-500 bg-indigo-500/5 text-indigo-600 dark:border-indigo-400 dark:bg-indigo-400/5 dark:text-indigo-400 font-semibold"
                                    : "border-zinc-200 bg-white hover:text-black dark:border-zinc-900 dark:bg-zinc-950/40 dark:hover:text-white"
                            )}
                        >
                            {node}
                        </div>
                    );
                })}
            </div>
        </div>
    );
}

function BentoGridItem({ item }: { item: BentoItem }) {
    const { id, title, description, link, tag } = item;

    // Helper to render card visual mockup components
    const renderVisualMockup = () => {
        switch (id) {
            case "design-system":
                return <DesignSystemMockup />;

            case "ai-studio":
                return <AIStudioMockup />;

            case "analytics":
                return <AnalyticsMockup />;

            case "cloud-platform":
                return <CloudMockup />;

            case "security":
                return <SecurityMockup />;

            case "dev-hub":
                return <DeveloperHubMockup />;

            case "collaboration":
                return (
                    <div className="w-full h-[120px] border border-zinc-200 bg-zinc-50/50 dark:border-zinc-900 dark:bg-[#040405] relative overflow-hidden select-none">
                        <div className="absolute inset-0 opacity-[0.03] pointer-events-none">
                            <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" className="text-zinc-900 dark:text-white">
                                <defs>
                                    <pattern id="collab-grid" width="10" height="10" patternUnits="userSpaceOnUse">
                                        <circle cx="5" cy="5" r="0.5" fill="currentColor" />
                                    </pattern>
                                </defs>
                                <rect width="100%" height="100%" fill="url(#collab-grid)" />
                            </svg>
                        </div>
                        {/* Cursor 1 */}
                        <motion.div
                            className="absolute left-[15%] top-[35%] flex items-center gap-1 pointer-events-none z-10"
                            animate={{ x: [0, 20, -5, 0], y: [0, -10, 15, 0] }}
                            transition={{ duration: 7, repeat: Infinity, ease: "easeInOut" }}
                        >
                            <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
                                <path d="M0 0 L8 3 L5 5 L3 8 Z" fill="#6366f1" />
                            </svg>
                            <span className="px-1 py-0.2 bg-[#6366f1] text-white text-[7px] font-semibold uppercase tracking-wider rounded-none">SARAH</span>
                        </motion.div>
                        {/* Cursor 2 */}
                        <motion.div
                            className="absolute left-[55%] top-[20%] flex items-center gap-1 pointer-events-none z-10"
                            animate={{ x: [0, -25, 10, 0], y: [0, 20, -5, 0] }}
                            transition={{ duration: 9, repeat: Infinity, ease: "easeInOut", delay: 0.5 }}
                        >
                            <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
                                <path d="M0 0 L8 3 L5 5 L3 8 Z" fill="#ec4899" />
                            </svg>
                            <span className="px-1 py-0.2 bg-[#ec4899] text-white text-[7px] font-semibold uppercase tracking-wider rounded-none">MARCUS</span>
                        </motion.div>
                    </div>
                );

            case "community":
                return <CommunityMockup />;

            default:
                return null;
        }
    };

    const ContentWrapper = (
        <div className="group/item relative flex flex-col justify-between h-full bg-white border border-zinc-200 text-zinc-700 dark:bg-[#060608] dark:border-zinc-900 dark:text-zinc-300 p-6 relative overflow-hidden transition-all duration-300 hover:border-zinc-300 dark:hover:border-zinc-800 hover:scale-[1.01] hover:-translate-y-0.5 hover:shadow-[0_12px_25px_rgba(0,0,0,0.04)] dark:hover:shadow-[0_12px_25px_rgba(0,0,0,0.6)] select-none rounded-none">
            {/* Visual Header containing Tag and Arrow */}
            <div className="flex justify-between items-center mb-4 z-10">
                {tag && (
                    <span className="text-[9px] font-bold tracking-widest text-zinc-500 border border-zinc-250 bg-zinc-50 dark:border-zinc-900 dark:bg-zinc-950/50 px-2 py-0.5 rounded-none uppercase">
                        {tag}
                    </span>
                )}
                {link && (
                    <ArrowUpRight className="h-4 w-4 text-zinc-400 group-hover/item:text-zinc-900 dark:text-zinc-600 dark:group-hover/item:text-white group-hover/item:translate-x-0.5 group-hover/item:-translate-y-0.5 transition-all duration-300" />
                )}
            </div>

            {/* Custom Visual Graphic Content */}
            <div className="my-2 flex-grow flex items-center justify-center z-10">
                {renderVisualMockup()}
            </div>

            {/* Title & Description at the bottom */}
            <div className="mt-4 space-y-1.5 z-10">
                <h3 className="text-sm font-semibold tracking-tight text-zinc-900 dark:text-white group-hover/item:text-zinc-950 dark:group-hover/item:text-zinc-100 transition-colors">
                    {title}
                </h3>
                {description && (
                    <p className="text-xs text-zinc-500 dark:text-zinc-500 leading-relaxed max-w-sm">
                        {description}
                    </p>
                )}
            </div>
        </div>
    );

    if (link) {
        return (
            <Link href={link} className="block h-full w-full outline-none focus:outline-none rounded-none">
                {ContentWrapper}
            </Link>
        );
    }

    return ContentWrapper;
}
```
