diff --git a/app/tarot-database-builders.js b/app/tarot-database-builders.js
index 203434a..ebd698d 100644
--- a/app/tarot-database-builders.js
+++ b/app/tarot-database-builders.js
@@ -258,6 +258,16 @@
return sign?.name?.en || sign?.name || sign?.id || fallback || "Unknown";
}
+ function formatDegreeRangeLabel(startDegree, endDegree) {
+ const start = Number(startDegree);
+ const end = Number(endDegree);
+ if (!Number.isFinite(start) || !Number.isFinite(end)) {
+ return "";
+ }
+
+ return `${String(Math.trunc(start)).padStart(2, "0")}°–${String(Math.trunc(end)).padStart(2, "0")}°`;
+ }
+
function buildDecanMetadata(decan, sign) {
if (!decan || !sign) {
return null;
@@ -268,9 +278,9 @@
return null;
}
- const startDegree = (index - 1) * 10;
- const endDegree = startDegree + 10;
- const dateRange = buildDecanDateRange(sign, index, decan);
+ const startDegree = (index - 1) * 10;
+ const endDegree = startDegree + 9;
+ const dateRange = buildDecanDateRange(sign, index, decan);
return {
decan,
@@ -282,6 +292,7 @@
startDegree,
endDegree,
dateRange,
+ degreeRangeLabel: formatDegreeRangeLabel(startDegree, endDegree),
normalizedCardName: normalizeMinorTarotCardName(decan.tarotMinorArcana || "")
};
}
@@ -566,7 +577,7 @@
return;
}
- const { startDegree, endDegree, dateRange, signId: metaSignId, signName, signSymbol, index } = decanMeta;
+ const { startDegree, endDegree, dateRange, degreeRangeLabel, signId: metaSignId, signName, signSymbol, index } = decanMeta;
const ruler = planets[decan.rulerPlanetId] || null;
const cardKey = canonicalCardName(cardName);
@@ -591,7 +602,7 @@
createRelation(
"decan",
`${metaSignId}-${index}`,
- `Decan ${decan.index}: ${sign.symbol || ""} ${signName} (${startDegree}°–${endDegree}°)${dateRange ? ` · ${dateRange.label}` : ""}`.trim(),
+ `Decan ${decan.index}: ${sign.symbol || ""} ${signName} (${degreeRangeLabel || `${startDegree}°–${endDegree}°`})${dateRange ? ` · ${dateRange.label}` : ""}`.trim(),
{
signId: metaSignId,
signName,
@@ -599,6 +610,7 @@
index,
startDegree,
endDegree,
+ degreeRangeLabel: degreeRangeLabel || null,
dateStart: dateRange?.startToken || null,
dateEnd: dateRange?.endToken || null,
dateRange: dateRange?.label || null
diff --git a/app/ui-alphabet-detail.js b/app/ui-alphabet-detail.js
index 9e1a50e..960fdca 100644
--- a/app/ui-alphabet-detail.js
+++ b/app/ui-alphabet-detail.js
@@ -115,7 +115,7 @@
return context.card("Astrology", `
- Type
- Element
- - Element
- ${elemEmoji[id] || ""} ${context.cap(id)}
+ - Element
- ${elemEmoji[id] || ""} ${context.inlineNavBtn(context.cap(id), "nav:elements", { "element-id": id })}
`);
}
@@ -127,6 +127,32 @@
`);
}
+ function renderElementOrPlanetValue(value, context) {
+ const token = context.normalizeId(value);
+ if (!token) {
+ return "—";
+ }
+
+ if (context.PLANET_SYMBOLS[token]) {
+ return `${context.PLANET_SYMBOLS[token]} ${context.inlineNavBtn(context.cap(token), "nav:planet", { "planet-id": token })}`;
+ }
+
+ if (["air", "water", "fire", "earth"].includes(token)) {
+ return context.inlineNavBtn(context.cap(token), "nav:elements", { "element-id": token });
+ }
+
+ return value || "—";
+ }
+
+ function renderTarotValue(value, context) {
+ const label = String(value || "").trim();
+ if (!label) {
+ return "—";
+ }
+
+ return context.inlineNavBtn(label, "nav:tarot-trump", { "card-name": label });
+ }
+
function renderHebrewDualityCard(letter, context) {
const duality = context.HEBREW_DOUBLE_DUALITY[context.normalizeId(letter?.hebrewLetterId)];
if (!duality) {
@@ -553,8 +579,8 @@
Name${letter.title}
English Letters${englishRefs.join(" / ") || "—"}
Transliteration${letter.transliteration || "—"}
- Element / Planet${letter.elementOrPlanet || "—"}
- Tarot${letter.tarot || "—"}
+ Element / Planet${renderElementOrPlanetValue(letter.elementOrPlanet, context)}
+ Tarot${renderTarotValue(letter.tarot, context)}
Numerology${letter.numerology || "—"}
Glyph SourceAPI asset: img/enochian (sourced from dCode set)
Position#${letter.index} of 21
diff --git a/app/ui-calendar-data.js b/app/ui-calendar-data.js
index 5398f8f..071faf2 100644
--- a/app/ui-calendar-data.js
+++ b/app/ui-calendar-data.js
@@ -1,6 +1,15 @@
(function () {
"use strict";
+ function formatDegreeLabel(value) {
+ const numeric = Number(value);
+ if (!Number.isFinite(numeric)) {
+ return "--";
+ }
+
+ return String(Math.trunc(numeric)).padStart(2, "0");
+ }
+
function buildDecanWindow(context, sign, decanIndex) {
const { buildSignDateBounds, addDays, formatDateLabel } = context;
const bounds = buildSignDateBounds(sign);
@@ -78,7 +87,7 @@
seen.add(key);
const startDegree = (Number(decan.index) - 1) * 10;
- const endDegree = startDegree + 10;
+ const endDegree = startDegree + 9;
const signName = sign?.name?.en || sign?.name || signId;
rows.push({
@@ -89,6 +98,7 @@
decanIndex: Number(decan.index),
startDegree,
endDegree,
+ degreeRangeLabel: `${formatDegreeLabel(startDegree)}°–${formatDegreeLabel(endDegree)}°`,
startTime: window.start.getTime(),
endTime: window.end.getTime(),
startMonth: window.start.getMonth() + 1,
diff --git a/app/ui-calendar-detail-panels.js b/app/ui-calendar-detail-panels.js
index a436cd1..c4860e3 100644
--- a/app/ui-calendar-detail-panels.js
+++ b/app/ui-calendar-detail-panels.js
@@ -27,6 +27,26 @@
return ``;
}
+ function buildSignInlineButton(signId, signName, signSymbol) {
+ if (!signId) {
+ return `${signSymbol ? `${signSymbol} ` : ""}${signName || "--"}`.trim();
+ }
+
+ const label = `${signSymbol ? `${signSymbol} ` : ""}${signName || signId}`.trim();
+ return inlineNavButton(label, "zodiac", { "sign-id": signId });
+ }
+
+ function buildHebrewInlineButton(hebrewLetterId, label) {
+ if (!hebrewLetterId) {
+ return label || "--";
+ }
+
+ return inlineNavButton(label || hebrewLetterId, "alphabet", {
+ alphabet: "hebrew",
+ "hebrew-letter-id": hebrewLetterId
+ });
+ }
+
function buildMajorArcanaRowsForMonth(context) {
const { month, api, getState } = context;
const currentState = getState();
@@ -142,6 +162,8 @@
? `${row.hebrewLetterChar ? `${row.hebrewLetterChar} ` : ""}${row.hebrewLetterName || row.hebrewLetterId}`
: "--";
const displayCardName = api.getDisplayTarotName(row.cardName, row.trumpNumber);
+ const signLabel = buildSignInlineButton(row.signId, row.signName, row.signSymbol);
+ const hebrewLabel = buildHebrewInlineButton(row.hebrewLetterId, label);
return `
@@ -149,11 +171,12 @@
${displayCardName}${row.trumpNumber != null ? ` · Trump ${row.trumpNumber}` : ""}
${row.rangeLabel}
- ${row.signSymbol} ${row.signName} · Hebrew: ${label}
+ ${signLabel} · Hebrew: ${hebrewLabel}
Days ${inlineNavButton(row.rangeLabel, "calendar-day-range", { "range-start": row.dayStart, "range-end": row.dayEnd })}
· Tarot ${inlineNavButton(displayCardName, "tarot-card", { "card-name": row.cardName, "trump-number": row.trumpNumber ?? "" })}
- ${row.hebrewLetterId ? ` · Hebrew ${inlineNavButton(label, "alphabet", { alphabet: "hebrew", "hebrew-letter-id": row.hebrewLetterId })}` : ""}
+ ${row.hebrewLetterId ? ` · Hebrew ${hebrewLabel}` : ""}
+ ${row.signId ? ` · Zodiac ${signLabel}` : ""}
`;
@@ -202,13 +225,14 @@
const list = rows.map((row) => {
const displayCardName = api.getDisplayTarotName(row.cardName);
+ const signLabel = buildSignInlineButton(row.signId, row.signName, row.signSymbol);
return `
- ${row.signSymbol} ${row.signName} · Decan ${row.decanIndex}
- ${row.startDegree}°–${row.endDegree}° · ${row.dateRange}
+ ${signLabel} · Decan ${row.decanIndex}
+ ${row.degreeRangeLabel || `${row.startDegree}°–${row.endDegree}°`} · ${row.dateRange}
-
Tarot ${inlineNavButton(displayCardName, "tarot-card", { "card-name": row.cardName })}
+
Tarot ${inlineNavButton(displayCardName, "tarot-card", { "card-name": row.cardName })} · Zodiac ${signLabel}
`;
}).join("");
@@ -291,6 +315,10 @@
const { month, api, getState, buildAssociationButtons, renderHolidaysCard } = context;
const currentState = getState();
const gregorianStartDate = api.getGregorianReferenceDateForCalendarMonth(month);
+ const zodiacSignId = month?.associations?.zodiacSignId || findSignIdByAstrologyName(month?.zodiacSign, context);
+ const zodiacLabel = buildSignInlineButton(zodiacSignId, api.cap(month.zodiacSign) || "--", "");
+ const hebrewLetterId = month?.associations?.hebrewLetterId || String(month?.hebrewLetterId || "").trim();
+ const hebrewLabel = buildHebrewInlineButton(hebrewLetterId, month.hebrewLetter || "--");
const factsRows = [
["Hebrew Name", month.nativeName || "--"],
["Month Order", month.leapYearOnly ? `${month.order} (leap year only)` : String(month.order)],
@@ -298,10 +326,10 @@
["Month Start (Gregorian)", api.formatGregorianReferenceDate(gregorianStartDate)],
["Days", month.daysVariant ? `${month.days}–${month.daysVariant} (varies)` : String(month.days || "--")],
["Season", month.season || "--"],
- ["Zodiac Sign", api.cap(month.zodiacSign) || "--"],
+ ["Zodiac Sign", zodiacLabel],
["Tribe of Israel", month.tribe || "--"],
["Sense", month.sense || "--"],
- ["Hebrew Letter", month.hebrewLetter || "--"]
+ ["Hebrew Letter", hebrewLabel]
].map(([dt, dd]) => `${dt}${dd}`).join("");
const monthOrder = Number(month?.order);
diff --git a/app/ui-cube-detail.js b/app/ui-cube-detail.js
index 0d49039..27a7683 100644
--- a/app/ui-cube-detail.js
+++ b/app/ui-cube-detail.js
@@ -104,6 +104,71 @@
return list;
}
+ function createAstrologyValue(astrology, context) {
+ const type = toDisplayText(astrology?.type).toLowerCase();
+ const name = toDisplayText(astrology?.name);
+
+ if (!name) {
+ return "";
+ }
+
+ if (type === "planet") {
+ return createInlineEventLink(name, "nav:planet", {
+ planetId: context.normalizeId(name)
+ });
+ }
+
+ if (type === "zodiac") {
+ return createInlineEventLink(name, "nav:zodiac", {
+ signId: context.normalizeId(name)
+ });
+ }
+
+ return name;
+ }
+
+ function createElementValue(elementName, context) {
+ const label = toDisplayText(elementName);
+ const elementId = context.normalizeId(label);
+
+ if (!elementId) {
+ return label;
+ }
+
+ return createInlineEventLink(label, "nav:elements", { elementId });
+ }
+
+ function appendPathAssociationRows(rows, pathEntry, context) {
+ if (!Array.isArray(rows) || !pathEntry) {
+ return;
+ }
+
+ const astrologyValue = createAstrologyValue(pathEntry?.astrology, context);
+ if (astrologyValue) {
+ rows.push({ label: "Astrology", value: astrologyValue });
+ }
+
+ const tarotCard = toDisplayText(pathEntry?.tarot?.card);
+ const tarotTrumpNumber = context.toFiniteNumber(pathEntry?.tarot?.trumpNumber);
+ if (tarotCard || tarotTrumpNumber != null) {
+ rows.push({
+ label: "Tarot",
+ value: createInlineEventLink(tarotCard || `Trump ${tarotTrumpNumber}`, "nav:tarot-trump", {
+ cardName: tarotCard,
+ trumpNumber: tarotTrumpNumber
+ })
+ });
+ }
+
+ const pathNo = context.toFiniteNumber(pathEntry?.pathNumber);
+ if (pathNo != null) {
+ rows.push({
+ label: "Path",
+ value: createInlineEventLink(`Path ${pathNo}`, "nav:kabbalah-path", { pathNo })
+ });
+ }
+ }
+
function createNavButton(label, eventName, detail) {
const button = document.createElement("button");
button.type = "button";
@@ -155,7 +220,7 @@
})
: centerLetterText
},
- { label: "Element", value: center?.element }
+ { label: "Element", value: createElementValue(center?.element, context) || center?.element }
];
if (centerTarotCard || centerTrumpNo != null) {
@@ -225,9 +290,8 @@
const pathNo = toFiniteNumber(connectorPath?.pathNumber);
const tarotCard = toDisplayText(connectorPath?.tarot?.card);
const tarotTrumpNumber = toFiniteNumber(connectorPath?.tarot?.trumpNumber);
- const astrologyType = toDisplayText(connectorPath?.astrology?.type);
- const astrologyName = toDisplayText(connectorPath?.astrology?.name);
- const astrologySummary = [astrologyType, astrologyName].filter(Boolean).join(": ");
+ const astrologySummary = createAstrologyValue(connectorPath?.astrology, context)
+ || [toDisplayText(connectorPath?.astrology?.type), toDisplayText(connectorPath?.astrology?.name)].filter(Boolean).join(": ");
elements.detailNameEl.textContent = connector?.name || "Mother Connector";
elements.detailSubEl.textContent = ["Mother Letter", letterText].filter(Boolean).join(" · ") || "Mother Letter";
@@ -329,9 +393,8 @@
const edgeLetterId = getEdgeLetterId(selectedEdge);
const edgeLetter = getEdgeLetter(selectedEdge);
const edgePath = getEdgePathEntry(selectedEdge);
- const astrologyType = toDisplayText(edgePath?.astrology?.type);
- const astrologyName = toDisplayText(edgePath?.astrology?.name);
const astrologySymbol = getEdgeAstrologySymbol(selectedEdge);
+ const astrologyName = toDisplayText(edgePath?.astrology?.name);
const astrologyText = astrologySymbol && astrologyName
? `${astrologySymbol} ${astrologyName}`
: astrologySymbol || astrologyName;
@@ -361,12 +424,7 @@
},
{
label: "Astrology",
- value: astrologyType === "zodiac" && astrologyName
- ? createInlineValue([
- astrologySymbol ? `${astrologySymbol} ` : "",
- createInlineEventLink(astrologyName, "nav:zodiac", { signId: normalizeId(astrologyName) })
- ])
- : astrologyText
+ value: createAstrologyValue(edgePath?.astrology, context) || astrologyText
}
];
@@ -420,6 +478,7 @@
getWallEdgeDirections,
getWallFaceLetterId,
getWallFaceLetter,
+ getPathEntryByLetterId,
getHebrewLetterName,
getEdgeLetter,
localDirectionOrder,
@@ -458,6 +517,7 @@
bodyEl.innerHTML = "";
const wallAssociations = wall.associations || {};
+ const faceLetterPath = getPathEntryByLetterId(wallFaceLetterId);
const wallFaceLetterName = getHebrewLetterName(wallFaceLetterId) || toDisplayText(wallFaceLetterId);
const faceLetterLabel = [wallFaceLetter, wallFaceLetterName].filter(Boolean).join(" ");
const wallRows = [
@@ -478,7 +538,7 @@
})
: wallFaceLetterText
},
- { label: "Element", value: wall.element },
+ { label: "Element", value: createElementValue(wall.element, context) || wall.element },
{
label: "Planet",
value: wallAssociations.planetId
@@ -497,6 +557,22 @@
}
];
+ if (faceLetterPath) {
+ appendPathAssociationRows(wallRows, faceLetterPath, context);
+ } else {
+ const directTarotCard = toDisplayText(wallAssociations?.tarotCard || wall?.tarotCard);
+ const directTrumpNumber = toFiniteNumber(wallAssociations?.tarotTrumpNumber);
+ if (directTarotCard || directTrumpNumber != null) {
+ wallRows.push({
+ label: "Tarot",
+ value: createInlineEventLink(directTarotCard || `Trump ${directTrumpNumber}`, "nav:tarot-trump", {
+ cardName: directTarotCard,
+ trumpNumber: directTrumpNumber
+ })
+ });
+ }
+ }
+
bodyEl.appendChild(createMetaCard("Wall Details", createDetailList(wallRows)));
if (Array.isArray(wall.keywords) && wall.keywords.length) {
@@ -612,9 +688,8 @@
? [edgeLetter, edgeLetterName].filter(Boolean).join(" ")
: "";
const edgePath = getEdgePathEntry(edge);
- const astrologyType = toDisplayText(edgePath?.astrology?.type);
- const astrologyName = toDisplayText(edgePath?.astrology?.name);
const astrologySymbol = getEdgeAstrologySymbol(edge);
+ const astrologyName = toDisplayText(edgePath?.astrology?.name);
const astrologyText = astrologySymbol && astrologyName
? `${astrologySymbol} ${astrologyName}`
: astrologySymbol || astrologyName;
@@ -655,12 +730,7 @@
},
{
label: "Astrology",
- value: astrologyType === "zodiac" && astrologyName
- ? createInlineValue([
- astrologySymbol ? `${astrologySymbol} ` : "",
- createInlineEventLink(astrologyName, "nav:zodiac", { signId: normalizeId(astrologyName) })
- ])
- : astrologyText
+ value: createAstrologyValue(edgePath?.astrology, context) || astrologyText
}
];
diff --git a/app/ui-cube.js b/app/ui-cube.js
index eba2800..4d16f02 100644
--- a/app/ui-cube.js
+++ b/app/ui-cube.js
@@ -735,6 +735,15 @@
return state.kabbalahPathsByLetterId.get(hebrewLetterId) || null;
}
+ function getPathEntryByLetterId(letterId) {
+ const normalizedLetterId = normalizeLetterKey(letterId);
+ if (!normalizedLetterId) {
+ return null;
+ }
+
+ return state.kabbalahPathsByLetterId.get(normalizedLetterId) || null;
+ }
+
const cubeMathUi = cubeMathHelpers.createCubeMathHelpers({
state,
CUBE_VERTICES,
@@ -940,6 +949,7 @@
getWallEdgeDirections,
getConnectorById,
getConnectorPathEntry,
+ getPathEntryByLetterId,
getCubeCenterData,
getCenterLetterId,
getCenterLetterSymbol,
diff --git a/app/ui-elements.js b/app/ui-elements.js
index 7f52d72..5f377ff 100644
--- a/app/ui-elements.js
+++ b/app/ui-elements.js
@@ -90,6 +90,18 @@
.join(" ");
}
+ function resolveHebrewLetterId(letterName) {
+ const token = normalize(letterName).replace(/[^a-z]/g, "");
+ if (!token) {
+ return "";
+ }
+
+ if (token === "yod") return "yod";
+ if (token === "vav") return "vav";
+ if (token === "heh") return "he";
+ return token;
+ }
+
function appendInlineParts(target, parts) {
(Array.isArray(parts) ? parts : []).forEach((part) => {
if (part instanceof Node) {
@@ -171,6 +183,7 @@
const aceCardName = ACE_BY_ELEMENT_ID[id] || "";
const hebrewLetter = HEBREW_LETTER_CHAR_BY_ELEMENT_ID[id] || "";
const hebrewLetterName = HEBREW_LETTER_NAME_BY_ELEMENT_ID[id] || "";
+ const hebrewLetterId = resolveHebrewLetterId(hebrewLetterName);
const courtRank = COURT_RANK_BY_ELEMENT_ID[id] || "";
const courtCardNames = courtRank
? COURT_SUITS.map((suit) => `${courtRank} of ${suit}`)
@@ -187,6 +200,7 @@
aceCardName,
hebrewLetter,
hebrewLetterName,
+ hebrewLetterId,
courtRank,
courtCardNames,
smallCardGroups,
@@ -267,16 +281,48 @@
const detailsCard = document.createElement("div");
detailsCard.className = "planet-meta-card";
- detailsCard.innerHTML = `
- Element Details
-
- - Name
- ${entry.name}
- - Symbol
- ${entry.symbol || "--"}
- - Hebrew Letter
- ${entry.hebrewLetter || "--"}
- - Court Rank
- ${entry.courtRank || "--"}
- - ID
- ${entry.id}
-
- `;
+ const detailsTitle = document.createElement("strong");
+ detailsTitle.textContent = "Element Details";
+
+ const detailsList = document.createElement("dl");
+ detailsList.className = "alpha-dl";
+
+ function appendDetailRow(label, value) {
+ const term = document.createElement("dt");
+ term.textContent = label;
+
+ const detail = document.createElement("dd");
+ if (value instanceof Node) {
+ detail.appendChild(value);
+ } else {
+ detail.textContent = String(value || "--");
+ }
+
+ detailsList.append(term, detail);
+ }
+
+ appendDetailRow("Name", entry.name);
+ appendDetailRow("Symbol", entry.symbol || "--");
+
+ const hebrewLetterLabel = `${entry.hebrewLetter || ""} ${entry.hebrewLetterName || ""}`.trim() || "--";
+ appendDetailRow(
+ "Hebrew Letter",
+ entry.hebrewLetterId
+ ? createInlineButton(hebrewLetterLabel, () => {
+ document.dispatchEvent(new CustomEvent("nav:alphabet", {
+ detail: {
+ alphabet: "hebrew",
+ hebrewLetterId: entry.hebrewLetterId
+ }
+ }));
+ })
+ : hebrewLetterLabel
+ );
+
+ appendDetailRow("Court Rank", entry.courtRank || "--");
+ appendDetailRow("ID", entry.id);
+
+ detailsCard.append(detailsTitle, detailsList);
const tarotCard = document.createElement("div");
tarotCard.className = "planet-meta-card";
diff --git a/app/ui-holidays-render.js b/app/ui-holidays-render.js
index 086ffdd..b931e46 100644
--- a/app/ui-holidays-render.js
+++ b/app/ui-holidays-render.js
@@ -253,9 +253,9 @@
: (confidence === "exact" ? "exact" : "approximate");
const monthName = monthLabelForCalendar(holiday?.calendarId, holiday?.monthId);
const holidayDate = holiday?.dateText || holiday?.date || holiday?.dateRange || "--";
- const sourceMonthLink = holiday?.monthId
- ? `Source month ${buildInlineNavButton(`${calendarLabel(holiday?.calendarId)} ${monthName}`, "calendar-month", { "calendar-id": holiday.calendarId || "", "month-id": holiday.monthId })}
`
- : "";
+ const sourceMonthValue = holiday?.monthId
+ ? buildInlineNavButton(monthName, "calendar-month", { "calendar-id": holiday.calendarId || "", "month-id": holiday.monthId })
+ : monthName;
return `