ZIP/WAREHOUSE/today_Tarot.php
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>신비한 타로 - 78장 풀 덱 에디션</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
    <style>
        @import url('https://fonts.googleapis.com/css2?family=Noto+Serif+KR:wght@400;700&family=Noto+Sans+KR:wght@300;400;700&display=swap');
        
        body { font-family: 'Noto Sans KR', sans-serif; background-color: #020617; }
        .font-serif-kr { font-family: 'Noto Serif KR', serif; }
        
        .perspective-1000 { perspective: 1000px; }
        .transform-style-3d { transform-style: preserve-3d; }
        .backface-hidden { backface-visibility: hidden; -webkit-backface-visibility: hidden; }
        .rotate-y-180 { transform: rotateY(180deg); }
        
        .card-bg-pattern {
            background-color: #1e1b4b;
            background-image: radial-gradient(#4338ca 1px, transparent 1px);
            background-size: 15px 15px;
        }

        @keyframes shuffle {
            0% { transform: translate(0, 0) rotate(0deg); }
            25% { transform: translate(30px, -10px) rotate(5deg); }
            50% { transform: translate(-30px, 10px) rotate(-5deg); }
            75% { transform: translate(20px, 5px) rotate(3deg); }
            100% { transform: translate(0, 0) rotate(0deg); }
        }
        .animate-shuffle { animation: shuffle 0.6s ease-in-out infinite; }
        
        .no-scrollbar::-webkit-scrollbar { display: none; }
        .no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }

        .fade-in { animation: fadeIn 0.8s ease-out forwards; }
        @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
    </style>
</head>
<body class="text-slate-200">
    <div id="root"></div>

    <script type="text/babel">
        const { useState, useEffect, useMemo } = React;

        // --- 아이콘 컴포넌트 ---
        const Icon = ({ type, size = 24, className = "" }) => {
            const icons = {
                sparkle: <path d="m12 3-1.912 5.813a2 2 0 0 1-1.275 1.275L3 12l5.813 1.912a2 2 0 0 1 1.275 1.275L12 21l1.912-5.813a2 2 0 0 1 1.275-1.275L21 12l-5.813-1.912a2 2 0 0 1-1.275-1.275Z"/>,
                moon: <path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"/>,
                star: <polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/>,
                refresh: (
                    <React.Fragment>
                        <path d="M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/>
                        <path d="M3 3v5h5"/>
                        <path d="M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16"/>
                        <path d="M16 16h5v5"/>
                    </React.Fragment>
                ),
                wand: (
                    <React.Fragment>
                        <path d="M18 2l4 4"/>
                        <path d="m17 7 3-3"/>
                        <path d="M2 22l15-15"/>
                        <path d="M11 15.5l1.5 1.5"/>
                        <path d="M15 11.5l1.5 1.5"/>
                        <path d="M19 7.5l1.5 1.5"/>
                        <path d="m4.5 20.5 1 1"/>
                    </React.Fragment>
                ),
                cup: (
                    <React.Fragment>
                        <path d="M6 3h12a2 2 0 0 1 2 2v2a8 8 0 0 1-16 0V5a2 2 0 0 1 2-2Z"/>
                        <path d="M12 15v6"/>
                        <path d="M8 21h8"/>
                    </React.Fragment>
                ),
                sword: (
                    <React.Fragment>
                        <path d="m14.5 2.5-8 8"/>
                        <path d="m21.5 9.5-8 8"/>
                        <path d="m5.9 10.1-4.4 4.4a2 2 0 0 0 0 2.8l1 1a2 2 0 0 0 2.8 0l4.4-4.4"/>
                        <path d="m18.1 13.9 4.4-4.4a2 2 0 0 0 0-2.8l-1-1a2 2 0 0 0-2.8 0l-4.4 4.4"/>
                        <path d="m3.5 20.5 3-3"/>
                    </React.Fragment>
                ),
                coin: (
                    <React.Fragment>
                        <circle cx="12" cy="12" r="8"/>
                        <path d="M12 8v8"/>
                        <path d="M8 12h8"/>
                    </React.Fragment>
                )
            };
            return (
                <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
                    {icons[type]}
                </svg>
            );
        };

        // --- 78장 타로 데이터 생성기 ---
        const generateFullDeck = () => {
            const major = [
                "광대", "마법사", "여사제", "여황제", "황제", "교황", "연인", "전차", "힘", "은둔자", 
                "운명의 수레바퀴", "정의", "매달린 사람", "죽음", "절제", "악마", "탑", "별", "달", "태양", "심판", "세계"
            ].map((name, i) => ({ id: `M${i}`, suit: "Major", name, num: i, desc: `인생의 중요한 전환점과 영적인 교훈을 상징하는 ${name} 카드입니다.` }));

            const suits = [
                { id: "W", name: "지팡이 (Wands)", icon: "wand", theme: "행동, 에너지, 열정" },
                { id: "C", name: "컵 (Cups)", icon: "cup", theme: "감정, 관계, 직관" },
                { id: "S", name: "검 (Swords)", icon: "sword", theme: "생각, 결단, 갈등" },
                { id: "P", name: "펜타클 (Pentacles)", icon: "coin", theme: "물질, 돈, 안정" }
            ];

            const minor = [];
            suits.forEach(suit => {
                for(let i=1; i<=14; i++) {
                    let cardName = "";
                    if (i === 1) cardName = `에이스 오브 ${suit.name.split(' ')[0]}`;
                    else if (i <= 10) cardName = `${i} 오브 ${suit.name.split(' ')[0]}`;
                    else if (i === 11) cardName = `페이지 오브 ${suit.name.split(' ')[0]}`;
                    else if (i === 12) cardName = `나이트 오브 ${suit.name.split(' ')[0]}`;
                    else if (i === 13) cardName = `퀸 오브 ${suit.name.split(' ')[0]}`;
                    else cardName = `킹 오브 ${suit.name.split(' ')[0]}`;

                    minor.push({
                        id: `${suit.id}${i}`,
                        suit: suit.id,
                        suitName: suit.name,
                        icon: suit.icon,
                        name: cardName,
                        desc: `${suit.theme}과 관련된 구체적인 상황을 나타내는 ${cardName} 카드입니다.`
                    });
                }
            });

            return [...major, ...minor];
        };

        const FULL_DECK = generateFullDeck();

        // --- 카드 컴포넌트 ---
        const TarotCard = ({ data, isFlipped, onClick, index }) => {
            return (
                <div 
                    className={`relative w-28 h-44 md:w-36 md:h-56 perspective-1000 transform-style-3d cursor-pointer transition-all duration-700 ${isFlipped ? 'rotate-y-180' : 'hover:-translate-y-4'}`}
                    onClick={onClick}
                    style={{ transitionDelay: `${index * 100}ms` }}
                >
                    {/* 뒷면 */}
                    <div className="absolute inset-0 w-full h-full card-bg-pattern rounded-xl border-2 border-indigo-500/50 flex flex-col items-center justify-center backface-hidden shadow-2xl">
                        <div className="w-[90%] h-[95%] border border-indigo-400/30 rounded-lg flex flex-col items-center justify-center relative overflow-hidden">
                            <Icon type="moon" size={40} className="text-indigo-400/40 mb-2" />
                            <Icon type="star" size={20} className="text-yellow-400/20 animate-pulse" />
                            <div className="absolute top-2 left-2"><Icon type="sparkle" size={12} className="text-white/10" /></div>
                            <div className="absolute bottom-2 right-2"><Icon type="sparkle" size={12} className="text-white/10" /></div>
                        </div>
                    </div>
                    
                    {/* 앞면 */}
                    <div className="absolute inset-0 w-full h-full bg-slate-900 rounded-xl border-2 border-yellow-600/70 flex flex-col items-center justify-between p-3 backface-hidden rotate-y-180 shadow-2xl overflow-hidden">
                        <div className="text-[10px] text-yellow-600/50 font-bold uppercase tracking-widest text-center w-full">
                            {data.suit === 'Major' ? `Major Arcana` : `Minor Arcana`}
                        </div>
                        
                        <div className="flex-1 flex flex-col items-center justify-center gap-4">
                            <div className={`p-4 rounded-full bg-slate-800 border ${data.suit === 'Major' ? 'border-purple-500/30 text-purple-400' : 'border-blue-500/30 text-blue-400'}`}>
                                <Icon type={data.suit === 'Major' ? 'star' : data.icon} size={32} />
                            </div>
                            <div className="text-center px-1">
                                <h3 className="text-[13px] md:text-sm font-bold text-slate-100 leading-tight font-serif-kr">{data.name}</h3>
                            </div>
                        </div>

                        <div className="w-full h-1 bg-gradient-to-r from-transparent via-yellow-600/20 to-transparent"></div>
                    </div>
                </div>
            );
        };

        const App = () => {
            const [step, setStep] = useState('intro'); // intro, shuffle, select, result
            const [deck, setDeck] = useState([]);
            const [selected, setSelected] = useState([]);

            const initGame = () => {
                setStep('shuffle');
                setTimeout(() => {
                    const shuffled = [...FULL_DECK].sort(() => Math.random() - 0.5);
                    setDeck(shuffled);
                    setStep('select');
                    setSelected([]);
                }, 2000);
            };

            const selectCard = (card) => {
                if (selected.length >= 3) return;
                const newSelected = [...selected, { ...card, flipped: false }];
                setSelected(newSelected);
                
                if (newSelected.length === 3) {
                    setTimeout(() => setStep('result'), 600);
                }
            };

            const flipCard = (index) => {
                const newSelected = [...selected];
                newSelected[index].flipped = true;
                setSelected(newSelected);
            };

            return (
                <div className="min-h-screen flex flex-col items-center relative overflow-hidden px-4">
                    {/* Background Decors */}
                    <div className="absolute top-0 left-0 w-full h-full pointer-events-none opacity-20">
                        <div className="absolute top-[-10%] left-[-10%] w-[40%] h-[40%] bg-purple-900 rounded-full blur-[120px]"></div>
                        <div className="absolute bottom-[-10%] right-[-10%] w-[40%] h-[40%] bg-blue-900 rounded-full blur-[120px]"></div>
                    </div>

                    <header className="w-full max-w-4xl py-10 flex flex-col items-center z-10">
                        <div className="flex items-center gap-3 mb-2 text-center">
                            <Icon type="sparkle" className="text-yellow-500" />
                            <h1 className="text-2xl md:text-3xl font-extrabold tracking-tighter text-white font-serif-kr">신비한 타로 운세</h1>
                            <Icon type="sparkle" className="text-yellow-500" />
                        </div>
                        <p className="text-slate-400 text-sm text-center">78장의 모든 운명이 당신의 선택을 기다립니다.</p>
                    </header>

                    <main className="flex-1 w-full max-w-6xl flex flex-col items-center justify-center z-10 py-4 md:py-10">
                        
                        {step === 'intro' && (
                            <div className="text-center fade-in">
                                <div className="mb-10 animate-bounce">
                                    <Icon type="moon" size={80} className="text-indigo-400 mx-auto" />
                                </div>
                                <button 
                                    onClick={initGame}
                                    className="px-10 py-4 bg-indigo-600 hover:bg-indigo-500 text-white rounded-full font-bold text-lg shadow-xl shadow-indigo-900/40 transition-all active:scale-95"
                                >
                                    운명의 카드 섞기
                                </button>
                            </div>
                        )}

                        {step === 'shuffle' && (
                            <div className="flex flex-col items-center gap-10">
                                <div className="relative w-32 h-48">
                                    {[1, 2, 3, 4, 5].map(i => (
                                        <div 
                                            key={i} 
                                            className="absolute inset-0 card-bg-pattern border-2 border-indigo-500/30 rounded-xl shadow-xl animate-shuffle"
                                            style={{ animationDelay: `${i * 0.1}s` }}
                                        ></div>
                                    ))}
                                </div>
                                <p className="text-xl font-bold text-indigo-300 animate-pulse">우주의 기운을 모으는 중...</p>
                            </div>
                        )}

                        {step === 'select' && (
                            <div className="w-full fade-in">
                                <h2 className="text-xl md:text-2xl font-bold text-center mb-10 text-white px-2">마음을 비우고 3장의 카드를 선택하세요 ({selected.length}/3)</h2>
                                <div className="flex overflow-x-auto gap-2 pb-10 no-scrollbar px-10">
                                    {deck.slice(0, 40).map((card, i) => {
                                        const isAlreadySelected = selected.some(s => s.id === card.id);
                                        return (
                                            <div 
                                                key={card.id}
                                                onClick={() => !isAlreadySelected && selectCard(card)}
                                                className={`min-w-[80px] h-32 md:min-w-[120px] md:h-48 card-bg-pattern rounded-lg border border-indigo-500/30 cursor-pointer transition-all hover:-translate-y-6 shadow-lg ${isAlreadySelected ? 'opacity-20 scale-90' : 'hover:border-yellow-500'}`}
                                            ></div>
                                        );
                                    })}
                                </div>
                                <div className="flex justify-center gap-4 md:gap-6 mt-10">
                                    {[0, 1, 2].map(i => (
                                        <div key={i} className="w-20 h-32 md:w-28 md:h-44 border-2 border-dashed border-slate-700 rounded-xl flex items-center justify-center">
                                            {selected[i] ? <Icon type="sparkle" className="text-yellow-500 animate-spin" /> : <span className="text-slate-700 font-bold">{i+1}</span>}
                                        </div>
                                    ))}
                                </div>
                            </div>
                        )}

                        {step === 'result' && (
                            <div className="w-full flex flex-col items-center fade-in pb-20">
                                <div className="grid grid-cols-1 md:grid-cols-3 gap-8 md:gap-10 mb-16 px-2">
                                    {selected.map((card, i) => (
                                        <div key={i} className="flex flex-col items-center gap-6">
                                            <div className="text-indigo-400 font-bold tracking-widest uppercase text-xs bg-slate-800 px-4 py-1 rounded-full border border-slate-700">
                                                {i === 0 ? '과거' : i === 1 ? '현재' : '미래'}
                                            </div>
                                            <TarotCard 
                                                data={card} 
                                                isFlipped={card.flipped} 
                                                onClick={() => flipCard(i)} 
                                                index={i}
                                            />
                                            <div className={`text-center max-w-[200px] transition-all duration-1000 ${card.flipped ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-4'}`}>
                                                <p className="text-yellow-500 font-bold mb-2 font-serif-kr text-lg">{card.name}</p>
                                                <p className="text-[13px] text-slate-400 leading-relaxed font-light">{card.desc}</p>
                                            </div>
                                        </div>
                                    ))}
                                </div>
                                
                                {selected.every(c => c.flipped) && (
                                    <button 
                                        onClick={initGame}
                                        className="flex items-center gap-2 px-8 py-3 bg-slate-800 hover:bg-slate-700 text-white rounded-full font-bold transition-all border border-slate-600 shadow-lg"
                                    >
                                        <Icon type="refresh" size={16} />
                                        다시 점치기
                                    </button>
                                )}
                            </div>
                        )}
                    </main>

                    <footer className="w-full py-8 text-center text-slate-600 text-[10px] md:text-xs z-10 border-t border-white/5 mt-auto">
                        <p>※ 이 타로는 78장의 풀 덱 데이터(Major 22 + Minor 56)를 기반으로 작동합니다.</p>
                        <p className="mt-1">© 2026 Mystic Tarot Engine v1.0</p>
                    </footer>
                </div>
            );
        };

        const root = ReactDOM.createRoot(document.getElementById('root'));
        root.render(<App />);
    </script>
</body>
</html>