(function () { function createTarotDetailRenderer(dependencies) { const { getMonthRefsByCardId, getMagickDataset, resolveTarotCardImage, getDisplayCardName, buildTypeLabel, clearChildren, normalizeRelationObject, buildElementRelationsForCard, buildTetragrammatonRelationsForCard, buildSmallCardRulershipRelation, buildSmallCardCourtLinkRelations, buildCubeRelationsForCard, parseMonthDayToken, createRelationListItem, findSephirahForMinorCard } = dependencies || {}; function renderStaticRelationGroup(targetEl, cardEl, relations) { clearChildren(targetEl); if (!targetEl || !cardEl) return; if (!relations.length) { cardEl.hidden = true; return; } cardEl.hidden = false; relations.forEach((relation) => { targetEl.appendChild(createRelationListItem(relation)); }); } function renderDetail(card, elements) { if (!card || !elements) { return; } const cardDisplayName = getDisplayCardName(card); const imageUrl = typeof resolveTarotCardImage === "function" ? resolveTarotCardImage(card.name) : null; if (elements.tarotDetailImageEl) { if (imageUrl) { elements.tarotDetailImageEl.src = imageUrl; elements.tarotDetailImageEl.alt = cardDisplayName || card.name; elements.tarotDetailImageEl.style.display = "block"; elements.tarotDetailImageEl.style.cursor = "zoom-in"; elements.tarotDetailImageEl.title = "Click to enlarge"; } else { elements.tarotDetailImageEl.removeAttribute("src"); elements.tarotDetailImageEl.alt = ""; elements.tarotDetailImageEl.style.display = "none"; elements.tarotDetailImageEl.style.cursor = "default"; elements.tarotDetailImageEl.removeAttribute("title"); } } if (elements.tarotDetailNameEl) { elements.tarotDetailNameEl.textContent = cardDisplayName || card.name; } if (elements.tarotDetailTypeEl) { elements.tarotDetailTypeEl.textContent = buildTypeLabel(card); } if (elements.tarotDetailSummaryEl) { elements.tarotDetailSummaryEl.textContent = card.summary || "--"; } if (elements.tarotDetailUprightEl) { elements.tarotDetailUprightEl.textContent = card.meanings?.upright || "--"; } if (elements.tarotDetailReversedEl) { elements.tarotDetailReversedEl.textContent = card.meanings?.reversed || "--"; } const meaningText = String(card.meaning || card.meanings?.upright || "").trim(); if (elements.tarotMetaMeaningCardEl && elements.tarotDetailMeaningEl) { if (meaningText) { elements.tarotMetaMeaningCardEl.hidden = false; elements.tarotDetailMeaningEl.textContent = meaningText; } else { elements.tarotMetaMeaningCardEl.hidden = true; elements.tarotDetailMeaningEl.textContent = "--"; } } clearChildren(elements.tarotDetailKeywordsEl); (card.keywords || []).forEach((keyword) => { const chip = document.createElement("span"); chip.className = "tarot-keyword-chip"; chip.textContent = keyword; elements.tarotDetailKeywordsEl?.appendChild(chip); }); const allRelations = (card.relations || []) .map((relation, index) => normalizeRelationObject(relation, index)) .filter(Boolean); const uniqueByKey = new Set(); const dedupedRelations = allRelations.filter((relation) => { const key = `${relation.type || "relation"}|${relation.id || ""}|${relation.label || ""}`; if (uniqueByKey.has(key)) return false; uniqueByKey.add(key); return true; }); const planetRelations = dedupedRelations.filter((relation) => relation.type === "planetCorrespondence" || relation.type === "decanRuler" || relation.type === "planet" ); const zodiacRelations = dedupedRelations.filter((relation) => relation.type === "zodiacCorrespondence" || relation.type === "zodiac" || relation.type === "decan" ); const courtDateRelations = dedupedRelations.filter((relation) => relation.type === "courtDateWindow"); const hebrewRelations = dedupedRelations.filter((relation) => relation.type === "hebrewLetter"); const baseElementRelations = dedupedRelations.filter((relation) => relation.type === "element"); const elementRelations = buildElementRelationsForCard(card, baseElementRelations); const tetragrammatonRelations = buildTetragrammatonRelationsForCard(card); const smallCardRulershipRelation = buildSmallCardRulershipRelation(card); const zodiacRelationsWithRulership = smallCardRulershipRelation ? [...zodiacRelations, smallCardRulershipRelation] : zodiacRelations; const smallCardCourtLinkRelations = buildSmallCardCourtLinkRelations(card, dedupedRelations); const mergedCourtDateRelations = [...courtDateRelations, ...smallCardCourtLinkRelations]; const cubeRelations = buildCubeRelationsForCard(card); const monthRelations = (getMonthRefsByCardId().get(card.id) || []).map((month, index) => { const dateRange = String(month?.dateRange || "").trim(); const context = String(month?.context || "").trim(); const labelBase = dateRange || month.name; const label = context ? `${labelBase} · ${context}` : labelBase; return { type: "calendarMonth", id: month.id, label, data: { monthId: month.id, name: month.name, monthOrder: Number.isFinite(Number(month.order)) ? Number(month.order) : null, dateRange: dateRange || null, dateStart: month.startToken || null, dateEnd: month.endToken || null, context: context || null, source: month.source || null }, __key: `calendarMonth|${month.id}|${month.uniqueKey || index}` }; }); const relationMonthRows = dedupedRelations .filter((relation) => relation.type === "calendarMonth") .map((relation) => { const dateRange = String(relation?.data?.dateRange || "").trim(); const baseName = relation?.data?.name || relation.label; const label = dateRange && baseName ? `${baseName} · ${dateRange}` : baseName; return { type: "calendarMonth", id: relation?.data?.monthId || relation.id, label, data: { monthId: relation?.data?.monthId || relation.id, name: relation?.data?.name || relation.label, monthOrder: Number.isFinite(Number(relation?.data?.monthOrder)) ? Number(relation.data.monthOrder) : null, dateRange: dateRange || null, dateStart: relation?.data?.dateStart || null, dateEnd: relation?.data?.dateEnd || null, context: relation?.data?.signName || null }, __key: relation.__key }; }) .filter((entry) => entry.data.monthId); const mergedMonthMap = new Map(); [...monthRelations, ...relationMonthRows].forEach((entry) => { const monthId = entry?.data?.monthId; if (!monthId) { return; } const key = [ monthId, String(entry?.data?.dateRange || "").trim().toLowerCase(), String(entry?.data?.context || "").trim().toLowerCase(), String(entry?.label || "").trim().toLowerCase() ].join("|"); if (!mergedMonthMap.has(key)) { mergedMonthMap.set(key, entry); } }); const mergedMonthRelations = [...mergedMonthMap.values()].sort((left, right) => { const orderLeft = Number.isFinite(Number(left?.data?.monthOrder)) ? Number(left.data.monthOrder) : 999; const orderRight = Number.isFinite(Number(right?.data?.monthOrder)) ? Number(right.data.monthOrder) : 999; if (orderLeft !== orderRight) { return orderLeft - orderRight; } const startLeft = parseMonthDayToken(left?.data?.dateStart); const startRight = parseMonthDayToken(right?.data?.dateStart); const dayLeft = startLeft ? startLeft.day : 999; const dayRight = startRight ? startRight.day : 999; if (dayLeft !== dayRight) { return dayLeft - dayRight; } return String(left.label || "").localeCompare(String(right.label || "")); }); renderStaticRelationGroup(elements.tarotDetailPlanetEl, elements.tarotMetaPlanetCardEl, planetRelations); renderStaticRelationGroup(elements.tarotDetailElementEl, elements.tarotMetaElementCardEl, elementRelations); renderStaticRelationGroup(elements.tarotDetailTetragrammatonEl, elements.tarotMetaTetragrammatonCardEl, tetragrammatonRelations); renderStaticRelationGroup(elements.tarotDetailZodiacEl, elements.tarotMetaZodiacCardEl, zodiacRelationsWithRulership); renderStaticRelationGroup(elements.tarotDetailCourtDateEl, elements.tarotMetaCourtDateCardEl, mergedCourtDateRelations); renderStaticRelationGroup(elements.tarotDetailHebrewEl, elements.tarotMetaHebrewCardEl, hebrewRelations); renderStaticRelationGroup(elements.tarotDetailCubeEl, elements.tarotMetaCubeCardEl, cubeRelations); renderStaticRelationGroup(elements.tarotDetailCalendarEl, elements.tarotMetaCalendarCardEl, mergedMonthRelations); const kabPathEl = elements.tarotKabPathEl; if (kabPathEl) { const kabTree = getMagickDataset()?.grouped?.kabbalah?.["kabbalah-tree"]; const kabPath = (card.arcana === "Major" && typeof card.number === "number" && kabTree) ? kabTree.paths.find((path) => path.tarot?.trumpNumber === card.number) : null; const kabSeph = !kabPath ? findSephirahForMinorCard(card, kabTree) : null; if (kabPath) { const letter = kabPath.hebrewLetter || {}; const fromName = kabTree.sephiroth.find((seph) => seph.number === kabPath.connects.from)?.name || kabPath.connects.from; const toName = kabTree.sephiroth.find((seph) => seph.number === kabPath.connects.to)?.name || kabPath.connects.to; const astro = kabPath.astrology ? `${kabPath.astrology.name} (${kabPath.astrology.type})` : ""; kabPathEl.innerHTML = ` Kabbalah Tree — Path ${kabPath.pathNumber}
${letter.char || ""} ${letter.transliteration || ""} — “${letter.meaning || ""}” · ${letter.letterType || ""} ${fromName} → ${toName}${astro ? " · " + astro : ""}
`; const btn = document.createElement("button"); btn.type = "button"; btn.className = "kab-tarot-link"; btn.textContent = `View Path ${kabPath.pathNumber} in Kabbalah Tree`; btn.addEventListener("click", () => { document.dispatchEvent(new CustomEvent("tarot:view-kab-path", { detail: { pathNumber: kabPath.pathNumber } })); }); kabPathEl.appendChild(btn); kabPathEl.hidden = false; } else if (kabSeph) { const hebrewName = kabSeph.nameHebrew ? ` (${kabSeph.nameHebrew})` : ""; const translation = kabSeph.translation ? ` — ${kabSeph.translation}` : ""; const planetInfo = kabSeph.planet || ""; const tarotInfo = kabSeph.tarot ? ` · ${kabSeph.tarot}` : ""; kabPathEl.innerHTML = ` Kabbalah Tree — Sephirah ${kabSeph.number}
${kabSeph.number} ${kabSeph.name || ""}${hebrewName}${translation} ${planetInfo}${tarotInfo}
`; const btn = document.createElement("button"); btn.type = "button"; btn.className = "kab-tarot-link"; btn.textContent = `View Sephirah ${kabSeph.number} in Kabbalah Tree`; btn.addEventListener("click", () => { document.dispatchEvent(new CustomEvent("tarot:view-kab-path", { detail: { pathNumber: kabSeph.number } })); }); kabPathEl.appendChild(btn); kabPathEl.hidden = false; } else { kabPathEl.hidden = true; kabPathEl.innerHTML = ""; } } } return { renderStaticRelationGroup, renderDetail }; } window.TarotDetailUi = { createTarotDetailRenderer }; })();