콘텐츠로 건너뛰기

재회 가능 여부 타로카드로 알아보기

다시 만나고 싶은 그 사람을 떠올리며, 진지한 마음으로 카드를 선택해 주세요.

선택: 0/1
카드를 클릭해 선택/해제하세요.
`; const spreadSel = root.querySelector("#spread"); const revChk = root.querySelector("#rev"); const deckEl = root.querySelector("#deck"); const selCntEl = root.querySelector("#selCnt"); const needEl = root.querySelector("#need"); const revealBtn = root.querySelector("#reveal"); const intentionEl = root.querySelector(".intention"); const summaryEl = root.querySelector("#summary"); const storyEl = root.querySelector("#story"); const resultsEl = root.querySelector("#results"); const tiles = [...root.querySelectorAll(".tile")]; let order = [...Array(78).keys()]; let selected = []; let isRevealing = false; const shuffle = (a) => { for(let i=a.length-1;i>0;i--){const j=Math.floor(Math.random()*(i+1)); [a[i],a[j]]=[a[j],a[i]];} return a; }; function updateUIState() { const spreadKey = spreadSel.value; const need = SPREADS[spreadKey].size; needEl.textContent = need; selCntEl.textContent = selected.length; revealBtn.disabled = (selected.length !== need); tiles.forEach(t => { const on = (t.dataset.spread === spreadKey); t.classList.toggle("active", on); t.setAttribute("aria-selected", String(on)); }); const prompts = { one: "핵심 조언이 필요하신가요? 가장 마음이 끌리는 카드 1장을 골라주세요.", three: "과거-현재-미래의 흐름이 궁금하신가요? 순서대로 3장의 카드를 골라주세요.", reunion5: "재회에 대해 심층적으로 분석하고 싶다면, 신중하게 5장의 카드를 골라주세요.", cross6: "두 사람의 관계를 다각도에서 보고 싶다면, 6장의 카드를 골라주세요." }; intentionEl.innerHTML = `조용히 심호흡하고, 그 사람을 떠올리며... ${prompts[spreadKey]}`; } function resetSelection() { selected = []; summaryEl.hidden = true; storyEl.hidden = true; resultsEl.innerHTML = ""; root.querySelectorAll('.back.selected').forEach(b => b.classList.remove('selected')); updateUIState(); } function refreshDeck() { deckEl.innerHTML = ""; order.forEach(i => { const b = document.createElement("button"); b.type="button"; b.className="back"; b.dataset.idx=String(i); b.innerHTML = `카드 뒷면`; b.addEventListener("click", () => { if (isRevealing) return; const idx = Number(b.dataset.idx), need = SPREADS[spreadSel.value].size, pos = selected.indexOf(idx); if (pos >= 0) { selected.splice(pos, 1); b.classList.remove("selected"); } else { if (selected.length >= need) return; selected.push(idx); b.classList.add("selected"); } updateUIState(); }); deckEl.appendChild(b); }); resetSelection(); } function playConfetti() { const confettiContainer = root.querySelector('.confetti'); if(!confettiContainer) return; for (let i = 0; i < 50; i++) { const piece = document.createElement('div'); piece.className = 'confetti-piece'; piece.style.left = `${Math.random() * 100}%`; piece.style.animation = `fall ${2 + Math.random() * 3}s ${Math.random() * 2}s linear forwards`; piece.style.transform = `rotate(${Math.random() * 360}deg)`; confettiContainer.appendChild(piece); } setTimeout(() => confettiContainer.innerHTML = '', 5000); } if (!document.querySelector('#confetti-keyframes')) { const style = document.createElement('style'); style.id = 'confetti-keyframes'; style.innerHTML = `@keyframes fall { to { transform: translateY(100vh) rotate(720deg); opacity: 1; } }`; document.head.appendChild(style); } function compute() { if (isRevealing) return; isRevealing = true; root.querySelector('.loading-overlay').classList.add('active'); setTimeout(() => { const key = spreadSel.value; const positions = SPREADS[key].positions; const picks = selected.map(idx => { const card = DECK[idx]; const reversed = revChk.checked ? Math.random() < 0.5 : false; const face = reversed ? card.meaning.rev : card.meaning.up; return { ...face, title:card.title, image:card.image, reversed }; }); const tot = totalScore(picks, key); summaryEl.hidden = false; root.querySelector("#score").textContent = tot; const tag = scoreTag(tot); const tagEl = root.querySelector("#tag"); tagEl.textContent = tag.t; tagEl.className = "tag " + tag.c; root.querySelector("#advc").textContent = friendlyIntro(tot); const barFill = root.querySelector("#barfill"); barFill.style.width = tot + "%"; barFill.style.background = tot>=85 ? "var(--good)" : tot>=65 ? "var(--good)" : tot>=45 ? "var(--warn)" : "var(--bad)"; resultsEl.innerHTML = ""; picks.forEach((c,i) => { const wrap = document.createElement("div"); wrap.className = `card-wrapper ${key === 'one' ? 'is-single' : ''}`; wrap.innerHTML = `
${positions[i]}
${c.title} 이미지
${c.title} ${c.reversed?'':''}
${c.kw ? `
🗝️ 키워드: ${c.kw}
` : ''}

${c.text || c.story}

`; resultsEl.appendChild(wrap); }); const tips = advicePack(tot); storyEl.hidden = false; storyEl.innerHTML = `

총운 및 조언 📝

${friendlyIntro(tot)}

지금 시도해볼 만한 Action Plan

첫 메시지: ${tips.first}
타이밍: ${tips.timing}
주의할 점: ${tips.caution}

AI 타로로 오늘의 운세 확인하기
  • 연애·금전·직장·학업 한 번에
  • 설치 없이 즉시 결과
🔮 무료로 카드 뽑기
AI 타로로 오늘의 운세 확인하기
  • 연애·금전·직장·학업 한 번에
  • 설치 없이 즉시 결과
🔮 무료로 카드 뽑기

※ 본 타로는 즐거움을 위한 콘텐츠이며, 중요한 결정은 자신의 판단과 전문가의 조언을 참고하세요.

`; root.querySelector('.loading-overlay').classList.remove('active'); isRevealing = false; root.querySelector('#result-anchor').scrollIntoView({ behavior: 'smooth', block: 'start' }); if (tot >= 90) playConfetti(); root.querySelectorAll('.rcard').forEach((rc, i) => { setTimeout(() => rc.classList.add('is-flipped'), 200 * (i + 1)); }); }, 1500); } tiles.forEach(t => t.addEventListener("click", () => { spreadSel.value = t.dataset.spread; resetSelection(); })); root.querySelector("#shuffle").addEventListener("click", () => { order=shuffle(order); refreshDeck(); }); root.querySelector("#clear").addEventListener("click", resetSelection); revealBtn.addEventListener("click", compute); order = shuffle(order); refreshDeck(); } render(); })();