diff --git a/src/apps/gameboard/static/apps/gameboard/natus-wheel.js b/src/apps/gameboard/static/apps/gameboard/natus-wheel.js index 384d33d..1cea60d 100644 --- a/src/apps/gameboard/static/apps/gameboard/natus-wheel.js +++ b/src/apps/gameboard/static/apps/gameboard/natus-wheel.js @@ -103,6 +103,12 @@ const NatusWheel = (() => { 'Cooperation', 'Regeneration', 'Enterprise', 'Career', 'Reward', 'Reprisal', ]; + // Cardinal / Fixed / Mutable — parallel index to SIGNS + const SIGN_MODALITIES = [ + 'Cardinal', 'Fixed', 'Mutable', 'Cardinal', 'Fixed', 'Mutable', + 'Cardinal', 'Fixed', 'Mutable', 'Cardinal', 'Fixed', 'Mutable', + ]; + // ── State ───────────────────────────────────────────────────────────────── let _svg = null; @@ -186,6 +192,21 @@ const NatusWheel = (() => { return ((ecliptic % 360) + 360) % 360 % 30; } + /** Return 1-based house number for an ecliptic degree given 12 cusps. */ + function _planetHouse(degree, cusps) { + degree = ((degree % 360) + 360) % 360; + for (let i = 0; i < 12; i++) { + const start = ((cusps[i] % 360) + 360) % 360; + const end = ((cusps[(i + 1) % 12] % 360) + 360) % 360; + if (start < end) { + if (start <= degree && degree < end) return i + 1; + } else { + if (degree >= start || degree < end) return i + 1; + } + } + return 1; + } + /** Inline SVG for a zodiac sign icon (preloaded path). */ function _signIconSvg(signName) { const d = _signPaths[signName]; @@ -400,8 +421,14 @@ const NatusWheel = (() => { if (_ttBody) { _ttBody.innerHTML = - `
${item.name} (${sym})
` + - `
@${inDeg}° ${pdata.sign} (${icon})${rx}
` + + `
` + + `${item.name}` + + `${sym}` + + `
` + + `
` + + `@${inDeg}° ${pdata.sign}${rx}` + + `${icon}` + + `
` + aspectHtml; } @@ -524,14 +551,41 @@ const NatusWheel = (() => { function _activateSign(idx) { _activeRing = 'signs'; _activeIdx = idx; - const sign = _signItems[idx]; + const sign = _signItems[idx]; + const elKey = sign.element.toLowerCase(); + const modality = SIGN_MODALITIES[idx]; + const vecImg = _elementVectorImg(sign.element); + const iconSvg = _signIconSvg(sign.name) || + `${sign.symbol}`; + + let planetsHtml = ''; + if (_currentData) { + const cusps = (_currentData.houses || {}).cusps || []; + const inSign = Object.entries(_currentData.planets || {}) + .filter(([, p]) => p.sign === sign.name) + .sort((a, b) => a[1].degree - b[1].degree); + inSign.forEach(([pname, pdata]) => { + const psym = PLANET_SYMBOLS[pname] || pname[0]; + const inDeg = _inSignDeg(pdata.degree).toFixed(1); + const house = cusps.length ? _planetHouse(pdata.degree, cusps) : null; + const domain = house ? HOUSE_LABELS[house] : ''; + planetsHtml += + `
${psym} @${inDeg}°` + + (domain ? `, House of ${domain}` : '') + `
`; + }); + } + if (_ttBody) { _ttBody.innerHTML = `
` + - `${sign.symbol}` + - `${sign.name}` + - ` · ${sign.element}` + - `
`; + `${sign.name}` + + `${iconSvg}` + + `` + + `
` + + `${modality} ${sign.element}` + + vecImg + + `
` + + (planetsHtml ? `
${planetsHtml}
` : ''); } _positionTooltipAtItem('signs', idx); if (_tooltipEl) { @@ -544,12 +598,28 @@ const NatusWheel = (() => { _activeRing = 'houses'; _activeIdx = idx; const house = _houseItems[idx]; + const cusps = (_currentData && (_currentData.houses || {}).cusps) || []; + + let planetsHtml = ''; + if (cusps.length && _currentData) { + const inHouse = Object.entries(_currentData.planets || {}) + .filter(([, p]) => _planetHouse(p.degree, cusps) === house.num) + .sort((a, b) => a[1].degree - b[1].degree); + inHouse.forEach(([pname, pdata]) => { + const psym = PLANET_SYMBOLS[pname] || pname[0]; + const inDeg = _inSignDeg(pdata.degree).toFixed(1); + const sicon = _signIconSvg(pdata.sign) || (SIGNS.find(s => s.name === pdata.sign) || {}).symbol || ''; + planetsHtml += `
${psym} @${inDeg}° ${sicon}
`; + }); + } + if (_ttBody) { _ttBody.innerHTML = `
` + - `${house.num}` + - ` · ${house.label}` + - `
`; + `House of ${house.label}` + + `${house.num}` + + `` + + (planetsHtml ? `
${planetsHtml}
` : ''); } _positionTooltipAtItem('houses', idx); if (_tooltipEl) { diff --git a/src/static_src/scss/_natus.scss b/src/static_src/scss/_natus.scss index 9ae330d..dd0e8bd 100644 --- a/src/static_src/scss/_natus.scss +++ b/src/static_src/scss/_natus.scss @@ -505,10 +505,83 @@ body[class*="-light"] { padding: 0.75rem 0.75rem 0.75rem 1.5rem; min-width: 14rem; - .tt-title { font-size: 1.25rem; font-weight: 700; margin-bottom: 0.3rem; } + .tt-title { font-size: 1.25rem; font-weight: 700; margin-bottom: 0; } .tt-description { font-size: 0.75rem; } .tt-sign-icon { fill: currentColor; vertical-align: middle; margin-bottom: 0.1em; } + // Planet tooltip — flex row: name | symbol; location row: @deg° Sign | sign icon + .tt-planet-header { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 0.5rem; + margin-bottom: 0.2rem; + } + .tt-planet-sym { + font-size: 1.2rem; + opacity: 0.85; + } + .tt-planet-loc { + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.5rem; + font-size: 0.8rem; + margin-bottom: 0.3rem; + } + .tt-planet-sign-icon { font-size: 1.2rem; line-height: 1; } + + // Sign tooltip — name in element color | SVG icon; modality | vector; planets + .tt-sign-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.5rem; + margin-bottom: 0.2rem; + } + .tt-sign-icon-wrap { + font-size: 1.5rem; + line-height: 1; + flex-shrink: 0; + .tt-sign-icon { fill: currentColor; } + } + .tt-sign-meta { + display: flex; + align-items: center; + justify-content: space-between; + font-size: 0.75rem; + opacity: 0.85; + margin-bottom: 0.3rem; + } + .tt-sign-planets { + display: flex; + flex-direction: column; + gap: 0.15rem; + margin-top: 0.1rem; + font-size: 0.85rem; + } + + // House tooltip — "House of X" | number; planets in house + .tt-house-header { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 0.5rem; + margin-bottom: 0.3rem; + } + .tt-house-num { + font-size: 1.4rem; + font-weight: 700; + opacity: 0.55; + flex-shrink: 0; + } + .tt-house-planets { + display: flex; + flex-direction: column; + gap: 0.15rem; + font-size: 0.85rem; + } + // DON|DOFF aspect line toggle — stacked at top-left outside the tooltip box, // matching the PRV/NXT pattern at the bottom corners. .nw-asp-don,