ZIP/WAREHOUSE/eight_trigrams.php
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>오늘의 주역 운세</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
    <script 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+Sans+KR:wght@300;400;500;700&display=swap');
        body { font-family: 'Noto Sans KR', sans-serif; transition: background-color 0.5s ease; }
        
        /* 페이지 로딩 및 전환 애니메이션 */
        .fade-in-up { animation: fadeInUp 0.8s ease-out forwards; }
        @keyframes fadeInUp {
            from { opacity: 0; transform: translateY(30px); }
            to { opacity: 1; transform: translateY(0); }
        }

        /* 주사위 흔들기 애니메이션 */
        .dice-shake { animation: shake 0.5s infinite; }
        @keyframes shake {
            0% { transform: rotate(0deg) scale(1); }
            25% { transform: rotate(10deg) scale(1.1); }
            50% { transform: rotate(0deg) scale(1); }
            75% { transform: rotate(-10deg) scale(1.1); }
            100% { transform: rotate(0deg) scale(1); }
        }

        /* 괘(爻) 드로잉 애니메이션 */
        .line-draw { animation: lineDraw 1s ease-out forwards; opacity: 0; }
        @keyframes lineDraw {
            from { opacity: 0; transform: scaleX(0); }
            to { opacity: 1; transform: scaleX(1); }
        }
    </style>
</head>
<body class="bg-[#FDFBF7] dark:bg-slate-950 transition-colors duration-500">
    <div id="root"></div>

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

        // --- 고해상도 아이콘 컴포넌트 ---
        const IconBook = () => <svg className="w-7 h-7 text-amber-500" fill="none" stroke="currentColor" strokeWidth="2" viewBox="0 0 24 24"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20" /><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z" /></svg>;
        const IconDice = ({ className }) => (
            <svg className={className || "w-12 h-12"} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                <rect x="3" y="3" width="18" height="18" rx="2" ry="2" />
                <circle cx="8.5" cy="8.5" r="1.5" fill="currentColor" />
                <circle cx="15.5" cy="8.5" r="1.5" fill="currentColor" />
                <circle cx="15.5" cy="15.5" r="1.5" fill="currentColor" />
                <circle cx="8.5" cy="15.5" r="1.5" fill="currentColor" />
                <circle cx="12" cy="12" r="1.5" fill="currentColor" />
            </svg>
        );
        const IconKeyboard = () => <svg className="w-8 h-8 text-slate-700 dark:text-slate-300" fill="none" stroke="currentColor" strokeWidth="2" viewBox="0 0 24 24"><rect width="20" height="16" x="2" y="4" rx="2" ry="2" /><path d="M6 8h.001M10 8h.001M14 8h.001M18 8h.001M6 12h.001M10 12h.001M14 12h.001M18 12h.001" /></svg>;
        const IconSparkles = () => <svg className="w-5 h-5 text-amber-400 mr-2" fill="none" stroke="currentColor" strokeWidth="2" viewBox="0 0 24 24"><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.275L12 3Z" /></svg>;
        const IconRefresh = () => <svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" strokeWidth="2" viewBox="0 0 24 24"><path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8M21 3v5h-5M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16M8 16H3v5" /></svg>;
        const IconMoon = () => <svg className="w-6 h-6 text-blue-400" fill="none" stroke="currentColor" strokeWidth="2" viewBox="0 0 24 24"><path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"/></svg>;
        const IconSun = () => <svg className="w-6 h-6 text-yellow-500" fill="none" stroke="currentColor" strokeWidth="2" viewBox="0 0 24 24"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41"/></svg>;
        const IconLightbulb = () => <svg className="w-5 h-5 text-yellow-500 mr-2" fill="none" stroke="currentColor" strokeWidth="2" viewBox="0 0 24 24"><path d="M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A5 5 0 0 0 8 8c0 1.3.5 2.6 1.5 3.5.8.8 1.3 1.5 1.5 2.5M9 18h6M10 22h4" /></svg>;

        const TRIGRAMS = {
            1: { name: '건(乾)', nature: '하늘', binary: [1, 1, 1] },
            2: { name: '태(兌)', nature: '연못', binary: [0, 1, 1] },
            3: { name: '이(離)', nature: '불', binary: [1, 0, 1] },
            4: { name: '진(震)', nature: '우레', binary: [0, 0, 1] },
            5: { name: '손(巽)', nature: '바람', binary: [1, 1, 0] },
            6: { name: '감(坎)', nature: '물', binary: [0, 1, 0] },
            7: { name: '간(艮)', nature: '산', binary: [1, 0, 0] },
            8: { name: '곤(坤)', nature: '땅', binary: [0, 0, 0] },
        };

        const getHexagramInterpretation = (upper, lower) => {
            const descriptions = {
                '1-1': { title: '중천건 (重天乾)', desc: '용이 하늘로 승천하는 형상입니다. 강한 운세와 리더십이 필요한 시기입니다.', luck: '매우 길함', tip: '자신감을 가지고 추진하되, 독단을 경계하고 주변의 조언을 경청하십시오.' },
                '8-8': { title: '중지곤 (重地坤)', desc: '모든 것을 포용하는 땅의 형상입니다. 나서기보다 포용하고 따르는 것이 이롭습니다.', luck: '길함 (안정)', tip: '순리에 맡기고 기다리는 미덕이 필요한 때입니다. 서두르면 일을 그르칩니다.' },
                '1-8': { title: '천지비 (天地否)', desc: '하늘과 땅이 막혀 소통이 안 되는 형상입니다. 답답할 수 있으나 내실을 다져야 합니다.', luck: '흉함 (주의)', tip: '억지로 풀려 하지 말고 잠시 멈추어 자신을 돌아보는 시간을 가지십시오.' },
                '8-1': { title: '지천태 (地天泰)', desc: '하늘과 땅이 교류하여 만물이 화합하는 형상입니다. 모든 일이 순조롭게 풀립니다.', luck: '매우 길함', tip: '좋은 시기일수록 겸손함을 유지하여 다가올 변화에 대비하십시오.' },
                '3-6': { title: '화수미제 (火수미제)', desc: '아직 일이 완성되지 않은 상태입니다. 끝까지 방심하지 말고 마무리에 집중하세요.', luck: '보통 (노력 필요)', tip: '마지막 한 걸음이 성패를 결정합니다. 신중하게 마무리를 지으십시오.' },
                '6-3': { title: '수화기제 (수화기제)', desc: '물과 불이 균형을 이루어 이미 완성된 상태입니다. 현상 유지에 힘써야 합니다.', luck: '길함', tip: '성공 뒤의 나태함을 경계하고 현재의 안정을 지키는 데 주력하십시오.' },
            };
            const key = `${upper}-${lower}`;
            if (descriptions[key]) return descriptions[key];
            const u = TRIGRAMS[upper] || TRIGRAMS[1];
            const l = TRIGRAMS[lower] || TRIGRAMS[1];
            return {
                title: `${u.nature}${l.nature}괘`,
                desc: `위에는 ${u.name}, 아래에는 ${l.name}이 위치했습니다. 변화의 흐름을 읽고 신중하게 행동하세요.`,
                luck: '보통',
                tip: '상황의 변화를 예의주시하며 유연하게 대처하는 것이 필요합니다.'
            };
        };

        function JuyeokFortune() {
            const [step, setStep] = useState('intro');
            const [loading, setLoading] = useState(false);
            const [darkMode, setDarkMode] = useState(false);
            const [num1, setNum1] = useState('');
            const [num2, setNum2] = useState('');
            const [num3, setNum3] = useState('');
            const [result, setResult] = useState(null);

            const userInfo = "음력 1972년 1월 17일 오전 5시생";

            // 다크모드 토글 및 시스템 설정 감지
            useEffect(() => {
                if (darkMode) document.documentElement.classList.add('dark');
                else document.documentElement.classList.remove('dark');
            }, [darkMode]);

            const reset = () => {
                setStep('intro');
                setNum1(''); setNum2(''); setNum3('');
                setResult(null); setLoading(false);
            };

            const calculateHexagram = (n1, n2, n3) => {
                const cleanN1 = Math.floor(Math.abs(Number(n1) || 0));
                const cleanN2 = Math.floor(Math.abs(Number(n2) || 0));
                const cleanN3 = Math.floor(Math.abs(Number(n3) || 0));
                return { upper: cleanN1 % 8 || 8, lower: cleanN2 % 8 || 8, change: cleanN3 % 6 || 6 };
            };

            const handleDiceRoll = () => {
                setLoading(true);
                setTimeout(() => {
                    const r1 = Math.floor(Math.random() * 64) + 1;
                    const r2 = Math.floor(Math.random() * 64) + 1;
                    const r3 = Math.floor(Math.random() * 6) + 1;
                    setResult(calculateHexagram(r1, r2, r3));
                    setLoading(false);
                    setStep('result');
                }, 2000);
            };

            const handleManualInput = () => {
                if (!num1 || !num2 || !num3) return;
                setLoading(true);
                setTimeout(() => {
                    setResult(calculateHexagram(num1, num2, num3));
                    setLoading(false);
                    setStep('result');
                }, 1000);
            };

            const HexagramVisual = ({ upper, lower, activeLine }) => {
                const renderTrigram = (trigramNum, isUpper) => {
                    const trigram = TRIGRAMS[trigramNum] || TRIGRAMS[1];
                    return trigram.binary.map((val, idx) => {
                        const lineNum = isUpper ? (6 - idx) : (3 - idx);
                        const isActive = lineNum === activeLine;
                        const delay = (6 - lineNum) * 0.1;
                        return (
                            <div key={`${isUpper ? 'u' : 'l'}-${idx}`} className="flex items-center justify-center my-1.5 relative h-8 w-48">
                                <div className={`w-full flex justify-between items-center line-draw ${isActive ? 'animate-pulse' : ''}`} style={{animationDelay: `${delay}s`}}>
                                    {val === 1 ? (
                                        <div className={`h-6 w-full rounded-sm ${isActive ? 'bg-red-600 shadow-[0_0_15px_rgba(220,38,38,0.8)]' : 'bg-slate-800 dark:bg-slate-400'}`}></div>
                                    ) : (
                                        <div className="w-full flex justify-between">
                                            <div className={`h-6 w-[46%] rounded-sm ${isActive ? 'bg-red-600 shadow-[0_0_15px_rgba(220,38,38,0.8)]' : 'bg-slate-800 dark:bg-slate-400'}`}></div>
                                            <div className={`h-6 w-[46%] rounded-sm ${isActive ? 'bg-red-600 shadow-[0_0_15px_rgba(220,38,38,0.8)]' : 'bg-slate-800 dark:bg-slate-400'}`}></div>
                                        </div>
                                    )}
                                </div>
                                {isActive && <span className="absolute -right-12 text-red-600 font-bold text-xs whitespace-nowrap">동효(動)</span>}
                            </div>
                        );
                    });
                };
                return (
                    <div className="flex flex-col items-center bg-slate-50 dark:bg-slate-900/50 p-6 rounded-2xl border-2 border-slate-200 dark:border-slate-800 shadow-inner">
                        <div className="mb-1">{renderTrigram(upper, true)}</div>
                        <div>{renderTrigram(lower, false)}</div>
                    </div>
                );
            };

            return (
                <div className="min-h-screen transition-colors duration-500">
                    <header className="bg-slate-900 text-amber-50 p-6 shadow-2xl text-center relative overflow-hidden">
                        <div className="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-red-600 via-amber-400 to-red-600"></div>
                        
                        {/* 다크모드 토글 버튼 */}
                        <button onClick={() => setDarkMode(!darkMode)} className="absolute right-4 top-6 p-2 rounded-full bg-slate-800 hover:bg-slate-700 transition-all active:scale-90 shadow-lg">
                            {darkMode ? <IconSun /> : <IconMoon />}
                        </button>

                        <h1 className="text-3xl font-bold mb-2 flex items-center justify-center gap-2 fade-in-up">
                            <IconBook /> 오늘의 주역(周易)
                        </h1>
                        <div className="text-sm text-slate-400 flex items-center justify-center gap-2 mt-2 opacity-80">
                            <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2M12 7a4 4 0 1 0 0-8 4 4 0 0 0 0 8z"/></svg>
                            <span>의뢰인: {userInfo}</span>
                        </div>
                    </header>

                    <main className="max-w-2xl mx-auto p-6">
                        {step === 'intro' && (
                            <div className="bg-white dark:bg-slate-900 rounded-3xl shadow-2xl p-10 text-center border border-stone-100 dark:border-slate-800 fade-in-up">
                                <div className="mb-6 inline-block p-4 bg-amber-50 dark:bg-amber-900/20 rounded-full">
                                    <IconSparkles />
                                </div>
                                <h2 className="text-2xl font-bold mb-4 dark:text-white">마음을 비우고 운세를 묻습니다</h2>
                                <p className="text-slate-500 dark:text-slate-400 mb-10 leading-relaxed">주역은 우연을 통해 필연을 읽어내는 학문입니다.<br/>고민을 생각한 뒤 아래 버튼을 눌러주세요.</p>
                                <button onClick={() => setStep('method')} className="w-full bg-slate-900 dark:bg-slate-100 dark:text-slate-900 hover:bg-slate-800 dark:hover:bg-white text-white font-bold py-5 px-6 rounded-2xl transition-all flex items-center justify-center shadow-xl active:scale-95">
                                    운세 확인하기
                                </button>
                            </div>
                        )}

                        {step === 'method' && (
                            <div className="bg-white dark:bg-slate-900 rounded-3xl shadow-2xl p-10 border border-stone-100 dark:border-slate-800 fade-in-up">
                                <h2 className="text-xl font-bold mb-8 text-center dark:text-white">점괘를 뽑을 방법을 선택하세요</h2>
                                <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
                                    <button onClick={() => setStep('dice')} className="flex flex-col items-center justify-center p-8 bg-stone-50 dark:bg-slate-800 hover:bg-red-50 dark:hover:bg-red-900/20 border-2 border-stone-200 dark:border-slate-700 rounded-2xl transition-all group active:scale-95">
                                        <IconDice className="w-14 h-14 text-slate-700 dark:text-slate-300 group-hover:text-red-500 transition-colors" />
                                        <span className="font-bold text-lg mt-4 dark:text-white">주사위 던지기</span>
                                    </button>
                                    <button onClick={() => setStep('input')} className="flex flex-col items-center justify-center p-8 bg-stone-50 dark:bg-slate-800 hover:bg-blue-50 dark:hover:bg-blue-900/20 border-2 border-stone-200 dark:border-slate-700 rounded-2xl transition-all group active:scale-95">
                                        <IconKeyboard />
                                        <span className="font-bold text-lg mt-4 dark:text-white">숫자 직접 입력</span>
                                    </button>
                                </div>
                                <button onClick={() => setStep('intro')} className="mt-8 text-sm text-slate-400 underline w-full text-center hover:text-slate-600">뒤로 가기</button>
                            </div>
                        )}

                        {loading && (
                            <div className="bg-white dark:bg-slate-900 rounded-3xl shadow-2xl p-16 text-center border dark:border-slate-800 fade-in-up">
                                <div className="animate-spin inline-block mb-6 dark:text-white"><IconRefresh /></div>
                                <p className="text-xl font-medium text-slate-600 dark:text-slate-400 italic">하늘의 뜻을 읽는 중...</p>
                            </div>
                        )}

                        {step === 'dice' && !loading && (
                            <div className="bg-white dark:bg-slate-900 rounded-3xl shadow-2xl p-12 text-center border dark:border-slate-800 fade-in-up">
                                <div className="mb-10 flex justify-center dice-shake">
                                    <IconDice className="w-24 h-24 text-amber-600 dark:text-amber-500 drop-shadow-xl" />
                                </div>
                                <h3 className="text-2xl font-bold mb-4 dark:text-white">주사위 점</h3>
                                <p className="mb-10 text-slate-500 dark:text-slate-400">버튼을 누르면 세 번의 주사위가 던져집니다.</p>
                                <button onClick={handleDiceRoll} className="bg-red-600 hover:bg-red-700 text-white font-bold py-5 px-16 rounded-2xl shadow-lg transition-all active:scale-95 hover:shadow-red-500/30">
                                    주사위 던지기
                                </button>
                                <button onClick={() => setStep('method')} className="block mt-10 text-slate-400 text-sm mx-auto hover:text-slate-600">이전으로</button>
                            </div>
                        )}

                        {step === 'input' && !loading && (
                            <div className="bg-white dark:bg-slate-900 rounded-3xl shadow-2xl p-10 border dark:border-slate-800 fade-in-up">
                                <h3 className="text-xl font-bold mb-8 text-center dark:text-white">숫자 3개를 입력하세요</h3>
                                <div className="space-y-6 max-w-xs mx-auto">
                                    <input type="number" value={num1} onChange={(e)=>setNum1(e.target.value)} placeholder="상괘 숫자" className="w-full p-4 border-2 dark:bg-slate-800 dark:border-slate-700 dark:text-white rounded-xl text-center outline-none focus:border-amber-500 transition-all text-xl font-bold" />
                                    <input type="number" value={num2} onChange={(e)=>setNum2(e.target.value)} placeholder="하괘 숫자" className="w-full p-4 border-2 dark:bg-slate-800 dark:border-slate-700 dark:text-white rounded-xl text-center outline-none focus:border-amber-500 transition-all text-xl font-bold" />
                                    <input type="number" value={num3} onChange={(e)=>setNum3(e.target.value)} placeholder="동효 숫자" className="w-full p-4 border-2 dark:bg-slate-800 dark:border-slate-700 dark:text-white rounded-xl text-center outline-none focus:border-amber-500 transition-all text-xl font-bold" />
                                    <button onClick={handleManualInput} className="w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-4 rounded-xl shadow-lg active:scale-95 transition-all">결과 보기</button>
                                </div>
                            </div>
                        )}

                        {step === 'result' && result && !loading && (
                            <div className="bg-white dark:bg-slate-900 rounded-[2.5rem] shadow-2xl overflow-hidden border border-stone-100 dark:border-slate-800 fade-in-up">
                                <div className="bg-slate-50 dark:bg-slate-800/50 p-8 border-b dark:border-slate-700 flex justify-between items-center">
                                    <h2 className="text-3xl font-bold dark:text-white flex items-center gap-3">
                                        <IconBook /> {getHexagramInterpretation(result.upper, result.lower).title}
                                    </h2>
                                    <span className="font-bold text-red-600 dark:text-red-400 bg-red-50 dark:bg-red-900/20 px-4 py-1 rounded-full text-sm">
                                        {getHexagramInterpretation(result.upper, result.lower).luck}
                                    </span>
                                </div>
                                <div className="p-10">
                                    <div className="flex flex-col md:flex-row gap-10 items-center justify-center mb-10">
                                        <HexagramVisual upper={result.upper} lower={result.lower} activeLine={result.change} />
                                        <div className="flex-1 space-y-4 dark:text-slate-300 w-full">
                                            <div className="p-6 bg-stone-50 dark:bg-slate-800/50 rounded-2xl border dark:border-slate-700">
                                                <p className="text-sm font-bold text-slate-400 mb-2">괘 구성</p>
                                                <p className="text-lg font-bold">상괘: {TRIGRAMS[result.upper].name} ({TRIGRAMS[result.upper].nature})</p>
                                                <p className="text-lg font-bold mt-2">하괘: {TRIGRAMS[result.lower].name} ({TRIGRAMS[result.lower].nature})</p>
                                                <div className="mt-4 pt-4 border-t dark:border-slate-700">
                                                    <p className="text-sm font-bold text-red-600 dark:text-red-400">동효: 제 {result.change}효 변동</p>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                    <div className="border-t dark:border-slate-700 pt-10 space-y-8">
                                        <div>
                                            <h4 className="font-bold text-slate-800 dark:text-slate-200 mb-3 text-xl">괘의 풀이</h4>
                                            <p className="text-slate-600 dark:text-slate-400 leading-relaxed text-lg">{getHexagramInterpretation(result.upper, result.lower).desc}</p>
                                        </div>
                                        <div className="bg-amber-50 dark:bg-amber-900/20 p-6 rounded-2xl border border-amber-100 dark:border-amber-900/30 shadow-sm">
                                            <h4 className="font-bold text-amber-800 dark:text-amber-400 flex items-center mb-3 text-lg"><IconLightbulb /> 상세 조언</h4>
                                            <p className="text-amber-900 dark:text-amber-200 leading-relaxed">{getHexagramInterpretation(result.upper, result.lower).tip}</p>
                                        </div>
                                        <button onClick={reset} className="mt-10 flex items-center justify-center w-full py-4 text-slate-400 dark:text-slate-500 hover:text-slate-800 dark:hover:text-white border-2 border-dashed border-slate-200 dark:border-slate-800 rounded-2xl transition-all">
                                            <IconRefresh /> 다시 점치기
                                        </button>
                                    </div>
                                </div>
                            </div>
                        )}
                    </main>
                </div>
            );
        }

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