@roxyapi/ui 0.3.1 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +34 -7
- package/README.md +145 -26
- package/dist/cdn/components/ashtakavarga-grid.js +74 -19
- package/dist/cdn/components/ashtakavarga-grid.js.map +2 -2
- package/dist/cdn/components/biorhythm-chart.js +18 -4
- package/dist/cdn/components/biorhythm-chart.js.map +2 -2
- package/dist/cdn/components/choghadiya-grid.js +47 -12
- package/dist/cdn/components/choghadiya-grid.js.map +3 -3
- package/dist/cdn/components/compatibility-card.js +21 -7
- package/dist/cdn/components/compatibility-card.js.map +2 -2
- package/dist/cdn/components/dasha-timeline.js +113 -28
- package/dist/cdn/components/dasha-timeline.js.map +3 -3
- package/dist/cdn/components/data.js +27 -13
- package/dist/cdn/components/data.js.map +2 -2
- package/dist/cdn/components/divisional-chart.js +225 -118
- package/dist/cdn/components/divisional-chart.js.map +4 -4
- package/dist/cdn/components/dosha-card.js +18 -4
- package/dist/cdn/components/dosha-card.js.map +2 -2
- package/dist/cdn/components/endpoint-form.js +25 -11
- package/dist/cdn/components/endpoint-form.js.map +2 -2
- package/dist/cdn/components/guna-milan.js +20 -6
- package/dist/cdn/components/guna-milan.js.map +2 -2
- package/dist/cdn/components/hexagram.js +22 -8
- package/dist/cdn/components/hexagram.js.map +2 -2
- package/dist/cdn/components/horoscope-card.js +20 -6
- package/dist/cdn/components/horoscope-card.js.map +2 -2
- package/dist/cdn/components/kp-chart.js +19 -5
- package/dist/cdn/components/kp-chart.js.map +2 -2
- package/dist/cdn/components/kp-planets-table.js +17 -3
- package/dist/cdn/components/kp-planets-table.js.map +2 -2
- package/dist/cdn/components/kp-ruling-planets.js +17 -3
- package/dist/cdn/components/kp-ruling-planets.js.map +2 -2
- package/dist/cdn/components/location-search.js +18 -4
- package/dist/cdn/components/location-search.js.map +2 -2
- package/dist/cdn/components/moon-phase.js +27 -13
- package/dist/cdn/components/moon-phase.js.map +2 -2
- package/dist/cdn/components/nakshatra-card.js +16 -2
- package/dist/cdn/components/nakshatra-card.js.map +2 -2
- package/dist/cdn/components/natal-chart.js +79 -40
- package/dist/cdn/components/natal-chart.js.map +3 -3
- package/dist/cdn/components/numerology-card.js +18 -4
- package/dist/cdn/components/numerology-card.js.map +2 -2
- package/dist/cdn/components/panchang-table.js +53 -25
- package/dist/cdn/components/panchang-table.js.map +3 -3
- package/dist/cdn/components/shadbala-table.js +24 -10
- package/dist/cdn/components/shadbala-table.js.map +2 -2
- package/dist/cdn/components/synastry-chart.js +96 -48
- package/dist/cdn/components/synastry-chart.js.map +3 -3
- package/dist/cdn/components/tarot-card.js +17 -3
- package/dist/cdn/components/tarot-card.js.map +2 -2
- package/dist/cdn/components/tarot-spread.js +39 -25
- package/dist/cdn/components/tarot-spread.js.map +2 -2
- package/dist/cdn/components/transits-table.js +18 -4
- package/dist/cdn/components/transits-table.js.map +2 -2
- package/dist/cdn/components/vedic-kundli.js +215 -105
- package/dist/cdn/components/vedic-kundli.js.map +4 -4
- package/dist/cdn/components/vedic-planets-table.js +22 -8
- package/dist/cdn/components/vedic-planets-table.js.map +2 -2
- package/dist/cdn/components/western-planets-table.js +18 -4
- package/dist/cdn/components/western-planets-table.js.map +2 -2
- package/dist/cdn/components/yoga-list.js +17 -3
- package/dist/cdn/components/yoga-list.js.map +2 -2
- package/dist/cdn/roxy-ui.js +1082 -816
- package/dist/cdn/roxy-ui.js.map +4 -4
- package/dist/components/ashtakavarga-grid.d.ts +13 -1
- package/dist/components/ashtakavarga-grid.d.ts.map +1 -1
- package/dist/components/ashtakavarga-grid.js +86 -11
- package/dist/components/ashtakavarga-grid.js.map +2 -2
- package/dist/components/biorhythm-chart.js +14 -0
- package/dist/components/biorhythm-chart.js.map +2 -2
- package/dist/components/choghadiya-grid.d.ts +6 -0
- package/dist/components/choghadiya-grid.d.ts.map +1 -1
- package/dist/components/choghadiya-grid.js +50 -2
- package/dist/components/choghadiya-grid.js.map +2 -2
- package/dist/components/compatibility-card.js +14 -0
- package/dist/components/compatibility-card.js.map +2 -2
- package/dist/components/dasha-timeline.d.ts +10 -0
- package/dist/components/dasha-timeline.d.ts.map +1 -1
- package/dist/components/dasha-timeline.js +135 -4
- package/dist/components/dasha-timeline.js.map +2 -2
- package/dist/components/data.js +14 -0
- package/dist/components/data.js.map +2 -2
- package/dist/components/divisional-chart.d.ts +9 -6
- package/dist/components/divisional-chart.d.ts.map +1 -1
- package/dist/components/divisional-chart.js +546 -251
- package/dist/components/divisional-chart.js.map +4 -4
- package/dist/components/dosha-card.js +14 -0
- package/dist/components/dosha-card.js.map +2 -2
- package/dist/components/endpoint-form.js +14 -0
- package/dist/components/endpoint-form.js.map +2 -2
- package/dist/components/guna-milan.js +14 -0
- package/dist/components/guna-milan.js.map +2 -2
- package/dist/components/hexagram.js +14 -0
- package/dist/components/hexagram.js.map +2 -2
- package/dist/components/horoscope-card.js +14 -0
- package/dist/components/horoscope-card.js.map +2 -2
- package/dist/components/kp-chart.js +14 -0
- package/dist/components/kp-chart.js.map +2 -2
- package/dist/components/kp-planets-table.js +14 -0
- package/dist/components/kp-planets-table.js.map +2 -2
- package/dist/components/kp-ruling-planets.js +14 -0
- package/dist/components/kp-ruling-planets.js.map +2 -2
- package/dist/components/location-search.js +14 -0
- package/dist/components/location-search.js.map +2 -2
- package/dist/components/moon-phase.js +14 -0
- package/dist/components/moon-phase.js.map +2 -2
- package/dist/components/nakshatra-card.js +14 -0
- package/dist/components/nakshatra-card.js.map +2 -2
- package/dist/components/natal-chart.d.ts.map +1 -1
- package/dist/components/natal-chart.js +76 -6
- package/dist/components/natal-chart.js.map +2 -2
- package/dist/components/numerology-card.js +14 -0
- package/dist/components/numerology-card.js.map +2 -2
- package/dist/components/panchang-table.d.ts +1 -0
- package/dist/components/panchang-table.d.ts.map +1 -1
- package/dist/components/panchang-table.js +37 -1
- package/dist/components/panchang-table.js.map +2 -2
- package/dist/components/shadbala-table.js +14 -0
- package/dist/components/shadbala-table.js.map +2 -2
- package/dist/components/synastry-chart.d.ts +6 -0
- package/dist/components/synastry-chart.d.ts.map +1 -1
- package/dist/components/synastry-chart.js +106 -7
- package/dist/components/synastry-chart.js.map +2 -2
- package/dist/components/tarot-card.js +14 -0
- package/dist/components/tarot-card.js.map +2 -2
- package/dist/components/tarot-spread.js +14 -0
- package/dist/components/tarot-spread.js.map +2 -2
- package/dist/components/transits-table.js +14 -0
- package/dist/components/transits-table.js.map +2 -2
- package/dist/components/vedic-kundli.d.ts +14 -9
- package/dist/components/vedic-kundli.d.ts.map +1 -1
- package/dist/components/vedic-kundli.js +537 -245
- package/dist/components/vedic-kundli.js.map +4 -4
- package/dist/components/vedic-planets-table.js +14 -0
- package/dist/components/vedic-planets-table.js.map +2 -2
- package/dist/components/western-planets-table.js +14 -0
- package/dist/components/western-planets-table.js.map +2 -2
- package/dist/components/yoga-list.js +14 -0
- package/dist/components/yoga-list.js.map +2 -2
- package/dist/index.cjs +1397 -797
- package/dist/index.cjs.map +4 -4
- package/dist/index.js +1278 -678
- package/dist/index.js.map +4 -4
- package/dist/manifest.json +23 -23
- package/dist/styles/tokens.css +8 -23
- package/dist/utils/base-styles.d.ts.map +1 -1
- package/dist/utils/kundli-render.d.ts +43 -104
- package/dist/utils/kundli-render.d.ts.map +1 -1
- package/dist/utils/kundli-styles.d.ts +13 -0
- package/dist/utils/kundli-styles.d.ts.map +1 -0
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/components/ashtakavarga-grid.ts +73 -11
- package/src/components/choghadiya-grid.ts +37 -2
- package/src/components/dasha-timeline.ts +135 -4
- package/src/components/divisional-chart.ts +40 -97
- package/src/components/natal-chart.ts +89 -6
- package/src/components/panchang-table.ts +34 -1
- package/src/components/synastry-chart.ts +84 -8
- package/src/components/vedic-kundli.ts +35 -95
- package/src/styles/tokens.css +8 -23
- package/src/utils/base-styles.ts +14 -0
- package/src/utils/kundli-render.ts +609 -270
- package/src/utils/kundli-styles.ts +124 -0
- package/src/version.ts +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../src/components/vedic-kundli.ts", "../../src/utils/base-styles.ts", "../../src/utils/kundli-render.ts", "../../src/tokens/index.ts", "../../src/utils/degree.ts", "../../src/utils/string.ts"],
|
|
4
|
-
"sourcesContent": ["import { css, html, LitElement } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type { BirthChartResponse } from '../types/index.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport {\n\tbuildHousesFromMeta,\n\ttype HouseDef,\n\trenderEastFrame,\n\trenderEastHouseGroup,\n\trenderNorthFrame,\n\trenderNorthHouseGroup,\n\trenderSouthFrame,\n\trenderSouthHouseGroup,\n} from '../utils/kundli-render.js';\n\n/**\n * Vedic kundli (D1 Rashi chart). Pass `data` from /vedic-astrology/birth-chart.\n * Three render styles via the `chart-style` attribute: south (default),\n * north, and east. All three draw the identical planet-in-sign data, so the\n * style is purely a layout choice. Each planet shows its abbreviation and\n * whole-degree, with an SVG tooltip carrying exact position, nakshatra, pada,\n * and avastha.\n *\n * Theming flows through CSS custom properties on :host, so the chart adopts\n * the host page palette without runtime color probing.\n */\n@customElement('roxy-vedic-kundli')\nexport class RoxyVedicKundli extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`\n\t\t\t.wrap {\n\t\t\t\tdisplay: grid;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t}\n\t\t\t.title {\n\t\t\t\tfont-size: var(--roxy-text-lg, 1.125rem);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tmargin: 0;\n\t\t\t}\n\t\t\tsvg {\n\t\t\t\tdisplay: block;\n\t\t\t\twidth: 100%;\n\t\t\t\tmax-width: 360px;\n\t\t\t\tmargin: 0 auto;\n\t\t\t}\n\t\t\t.line {\n\t\t\t\tfill: transparent;\n\t\t\t\tstroke: var(--roxy-border, #e4e4e7);\n\t\t\t}\n\t\t\t.sign-text {\n\t\t\t\tfill: var(--roxy-muted, #71717a);\n\t\t\t\tfont-size: 9px;\n\t\t\t\tfont-weight: 500;\n\t\t\t\tfont-family: var(--roxy-font-sans);\n\t\t\t}\n\t\t\t.planet-text {\n\t\t\t\tfill: var(--roxy-fg, #0a0a0a);\n\t\t\t\tfont-size: 10px;\n\t\t\t\tfont-weight: 600;\n\t\t\t\tfont-family: var(--roxy-font-sans);\n\t\t\t}\n\t\t\t.house-num {\n\t\t\t\tfill: var(--roxy-muted, #71717a);\n\t\t\t\tfont-size: 9px;\n\t\t\t\tfont-weight: 400;\n\t\t\t\tfont-family: var(--roxy-font-sans);\n\t\t\t}\n\t\t\t.lagna-marker {\n\t\t\t\tfill: var(--roxy-accent-fg, #b45309);\n\t\t\t\tfont-size: 8px;\n\t\t\t\tfont-weight: 700;\n\t\t\t\tfont-family: var(--roxy-font-sans);\n\t\t\t\tletter-spacing: 0.05em;\n\t\t\t}\n\t\t\t.lagna-bg {\n\t\t\t\tfill: color-mix(in srgb, var(--roxy-accent, #f59e0b) 12%, transparent);\n\t\t\t\tstroke: color-mix(in srgb, var(--roxy-accent, #f59e0b) 45%, transparent);\n\t\t\t\tstroke-width: 0.8;\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ attribute: false })\n\tdata: BirthChartResponse | null = null;\n\n\t@property({ type: String, reflect: true, attribute: 'chart-style' })\n\tchartStyle: 'south' | 'north' | 'east' = 'south';\n\n\tprivate buildHouses(): HouseDef[] {\n\t\tif (!this.data?.meta) return [];\n\t\treturn buildHousesFromMeta(this.data.meta);\n\t}\n\n\trender() {\n\t\tif (!this.data)\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No kundli data</div>`;\n\t\tconst houses = this.buildHouses();\n\t\tconst style = this.chartStyle;\n\n\t\tconst frame =\n\t\t\tstyle === 'north'\n\t\t\t\t? renderNorthFrame()\n\t\t\t\t: style === 'east'\n\t\t\t\t\t? renderEastFrame()\n\t\t\t\t\t: renderSouthFrame();\n\t\tconst houseGroup =\n\t\t\tstyle === 'north'\n\t\t\t\t? renderNorthHouseGroup\n\t\t\t\t: style === 'east'\n\t\t\t\t\t? renderEastHouseGroup\n\t\t\t\t\t: renderSouthHouseGroup;\n\n\t\treturn html`<div class=\"wrap\">\n\t\t\t<h2 class=\"title\">Vedic kundli</h2>\n\t\t\t<svg\n\t\t\t\tviewBox=\"0 0 300 300\"\n\t\t\t\trole=\"img\"\n\t\t\t\taria-label=\"Vedic birth chart with twelve sign houses\"\n\t\t\t>\n\t\t\t\t<title>Vedic kundli</title>\n\t\t\t\t${frame}\n\t\t\t\t${houses.map((h) => houseGroup(h))}\n\t\t\t</svg>\n\t\t</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-vedic-kundli': RoxyVedicKundli;\n\t}\n}\n", "import { css } from 'lit';\n\n/**\n * Shared host styles every component pulls in. Sets default font, color,\n * container query support, and the entry fade-in.\n */\nexport const baseStyles = css`\n\t:host {\n\t\tdisplay: block;\n\t\tcontainer-type: inline-size;\n\t\tfont-family: var(\n\t\t\t--roxy-font-sans,\n\t\t\tsystem-ui,\n\t\t\t-apple-system,\n\t\t\tBlinkMacSystemFont,\n\t\t\t'Segoe UI',\n\t\t\tRoboto,\n\t\t\tsans-serif\n\t\t);\n\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\tbackground: transparent;\n\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\tline-height: var(--roxy-leading-normal, 1.5);\n\t\tanimation: roxy-fade-in var(--roxy-motion-duration, 200ms)\n\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1)) both;\n\t}\n\n\t*,\n\t*::before,\n\t*::after {\n\t\tbox-sizing: border-box;\n\t}\n\n\t@keyframes roxy-fade-in {\n\t\tfrom {\n\t\t\topacity: 0;\n\t\t\ttransform: translateY(2px);\n\t\t}\n\t\tto {\n\t\t\topacity: 1;\n\t\t\ttransform: translateY(0);\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t:host {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-skeleton {\n\t\tbackground: linear-gradient(\n\t\t\t90deg,\n\t\t\tvar(--roxy-border, #e4e4e7) 0%,\n\t\t\tcolor-mix(in srgb, var(--roxy-border, #e4e4e7) 60%, transparent) 50%,\n\t\t\tvar(--roxy-border, #e4e4e7) 100%\n\t\t);\n\t\tbackground-size: 200% 100%;\n\t\tanimation: roxy-shimmer 1.4s ease-in-out infinite;\n\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t}\n\n\t@keyframes roxy-shimmer {\n\t\t0% {\n\t\t\tbackground-position: 200% 0;\n\t\t}\n\t\t100% {\n\t\t\tbackground-position: -200% 0;\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t.roxy-skeleton {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-empty {\n\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\tcolor: var(--roxy-muted, #71717a);\n\t\ttext-align: center;\n\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t}\n\n\t:host(:focus-within) .roxy-card {\n\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\toutline-offset: 2px;\n\t}\n`;\n", "import type { TemplateResult } from 'lit';\nimport { nothing, svg } from 'lit';\nimport { PLANET_ABBR, SIGN_ABBR, SIGNS_ORDER } from '../tokens/index.js';\nimport { longitudeToSignPosition } from './degree.js';\nimport { capitalize } from './string.js';\n\nexport const KUNDLI_SIZE = 300;\nexport const KUNDLI_CENTER = 150;\n\n/**\n * Maps a lowercase rashi key (e.g. \"aries\") back to its canonical sign name\n * (e.g. \"Aries\"). Used by every kundli consumer to bridge spec lowercase\n * rashi keys to the title-cased SIGNS_ORDER tokens.\n */\nexport const RASHI_TO_SIGN: Record<string, string> = Object.fromEntries(\n\tSIGNS_ORDER.map((s) => [s.toLowerCase(), s] as const),\n);\n\n/**\n * A planet placed in a kundli house. This is a render-only view model, not an\n * API type: it carries just enough per-graha detail to draw a compact label\n * (abbreviation plus degree-within-sign plus retrograde mark) and a rich SVG\n * `<title>` tooltip (full position, nakshatra, pada, avastha). Both the D1\n * birth chart and the Dx divisional charts feed it from their `meta` map.\n */\nexport interface PlacedGraha {\n\tgraha: string;\n\tlongitude?: number;\n\tnakshatra?: { name?: string; pada?: number; lord?: string };\n\tisRetrograde?: boolean;\n\tawastha?: string;\n}\n\nexport interface HouseDef {\n\t/** 1-based cell number. For the sign-fixed styles (south, east) this is the rashi index, Aries = 1. */\n\tnumber: number;\n\t/** Sign name (TitleCase, e.g. \"Aries\"). */\n\tsign: string;\n\t/** Planets occupying this house, with full detail for label + tooltip. */\n\tplanets: PlacedGraha[];\n\t/** Whether this house is the ascendant (Lagna). */\n\tisLagna: boolean;\n}\n\n/** Superscript \"r\" used as a compact retrograde marker on planet labels. */\nconst RETRO_MARK = '\u02B3';\n\n/**\n * Compact in-cell label for a placed graha: abbreviation, whole-degree within\n * the sign, and a retrograde mark. Degree is omitted when longitude is absent.\n */\nfunction grahaLabel(p: PlacedGraha): string {\n\tconst abbr = PLANET_ABBR[capitalize(p.graha)] ?? p.graha.slice(0, 2);\n\tconst retro = p.isRetrograde ? RETRO_MARK : '';\n\tif (typeof p.longitude !== 'number' || !Number.isFinite(p.longitude)) {\n\t\treturn `${abbr}${retro}`;\n\t}\n\tconst { degree } = longitudeToSignPosition(p.longitude);\n\treturn `${abbr} ${degree}\u00B0${retro}`;\n}\n\n/**\n * Full-detail tooltip text for a placed graha: name, exact degree and minute,\n * nakshatra and pada, avastha, retrograde. Surfaced via an SVG `<title>` so the\n * chart cell itself stays compact.\n */\nfunction grahaTitle(p: PlacedGraha): string {\n\tconst parts: string[] = [capitalize(p.graha)];\n\tif (typeof p.longitude === 'number' && Number.isFinite(p.longitude)) {\n\t\tconst sp = longitudeToSignPosition(p.longitude);\n\t\tparts.push(\n\t\t\t`${sp.degree}\u00B0${String(sp.minute).padStart(2, '0')}' ${sp.sign}`,\n\t\t);\n\t}\n\tif (p.nakshatra?.name) {\n\t\tconst pada = p.nakshatra.pada ? ` pada ${p.nakshatra.pada}` : '';\n\t\tparts.push(`${p.nakshatra.name}${pada}`);\n\t}\n\tif (p.awastha) parts.push(p.awastha);\n\tif (p.isRetrograde) parts.push('retrograde');\n\treturn parts.join(' \u00B7 ');\n}\n\n/**\n * Render the stack of planet labels for one house cell. Shared by all three\n * styles: vertically centers the stack on `baseY`, one line per planet, each\n * with a `<title>` tooltip carrying the full detail.\n */\nfunction renderPlanetStack(\n\tplanets: PlacedGraha[],\n\tcx: number,\n\tbaseY: number,\n\tlineHeight: number,\n): (TemplateResult | typeof nothing)[] {\n\tconst startY = baseY - ((planets.length - 1) * lineHeight) / 2;\n\treturn planets.map((p, j) => {\n\t\tconst yPos = startY + j * lineHeight;\n\t\treturn svg`<text class=\"planet-text\" x=${cx} y=${yPos} text-anchor=\"middle\" dominant-baseline=\"central\">${grahaLabel(\n\t\t\tp,\n\t\t)}<title>${grahaTitle(p)}</title></text>`;\n\t});\n}\n\n/**\n * South Indian fixed-house square grid: house centers for planet text labels.\n * House 1 is fixed top-center; positions are in the 300x300 viewBox.\n */\nexport const SOUTH_HOUSE_CENTERS: Record<number, { x: number; y: number }> = {\n\t1: { x: 150, y: 58 },\n\t2: { x: 205, y: 52 },\n\t3: { x: 253, y: 112 },\n\t4: { x: 243, y: 150 },\n\t5: { x: 253, y: 188 },\n\t6: { x: 205, y: 248 },\n\t7: { x: 150, y: 242 },\n\t8: { x: 95, y: 248 },\n\t9: { x: 47, y: 188 },\n\t10: { x: 57, y: 150 },\n\t11: { x: 47, y: 112 },\n\t12: { x: 95, y: 52 },\n};\n\n/**\n * South Indian sign abbreviation positions (slightly outward from center).\n */\nexport const SOUTH_SIGN_POSITIONS: Record<number, { x: number; y: number }> = {\n\t1: { x: 150, y: 35 },\n\t2: { x: 222, y: 40 },\n\t3: { x: 265, y: 100 },\n\t4: { x: 265, y: 150 },\n\t5: { x: 265, y: 200 },\n\t6: { x: 222, y: 260 },\n\t7: { x: 150, y: 265 },\n\t8: { x: 78, y: 260 },\n\t9: { x: 35, y: 200 },\n\t10: { x: 35, y: 150 },\n\t11: { x: 35, y: 100 },\n\t12: { x: 78, y: 40 },\n};\n\n/**\n * North Indian style: 12 triangular house positions.\n * Lagna (house 1) is the top diamond, numbered clockwise.\n * Centers represent the visual midpoint of each triangular cell.\n */\nexport const NORTH_HOUSE_CENTERS: Record<number, { x: number; y: number }> = {\n\t1: { x: 150, y: 60 },\n\t2: { x: 225, y: 100 },\n\t3: { x: 255, y: 150 },\n\t4: { x: 225, y: 200 },\n\t5: { x: 150, y: 240 },\n\t6: { x: 75, y: 200 },\n\t7: { x: 45, y: 150 },\n\t8: { x: 75, y: 100 },\n\t9: { x: 100, y: 80 },\n\t10: { x: 150, y: 108 },\n\t11: { x: 200, y: 80 },\n\t12: { x: 200, y: 220 },\n};\n\n/**\n * East Indian style: a fixed-sign square (like South Indian) cut by both\n * diagonals and an inner diamond joining the side midpoints, giving 12 cells.\n * The four inner-diamond quadrilaterals hold the cardinal-position signs\n * (cell 1, 4, 7, 10) and the eight corner half-triangles fill between them,\n * laid out clockwise from the top so cell `n` holds the n-th rashi (Aries = 1).\n * Centers are the visual midpoints of those cells in the 300x300 viewBox,\n * derived from the frame geometry (square 10..290, diagonals, side-midpoint\n * diamond).\n *\n * @remarks The cell geometry is exact; the rashi-to-cell order follows the\n * common clockwise-from-top convention and is slated for a regional\n * reference-image confirmation pass (see docs/todo.md \"East Indian polish\").\n */\nexport const EAST_HOUSE_CENTERS: Record<number, { x: number; y: number }> = {\n\t1: { x: 150, y: 80 }, // inner diamond, top\n\t2: { x: 220, y: 33 }, // top-right corner, upper triangle\n\t3: { x: 267, y: 80 }, // top-right corner, right triangle\n\t4: { x: 220, y: 150 }, // inner diamond, right\n\t5: { x: 267, y: 220 }, // bottom-right corner, right triangle\n\t6: { x: 220, y: 267 }, // bottom-right corner, lower triangle\n\t7: { x: 150, y: 220 }, // inner diamond, bottom\n\t8: { x: 80, y: 267 }, // bottom-left corner, lower triangle\n\t9: { x: 33, y: 220 }, // bottom-left corner, left triangle\n\t10: { x: 80, y: 150 }, // inner diamond, left\n\t11: { x: 33, y: 80 }, // top-left corner, left triangle\n\t12: { x: 80, y: 33 }, // top-left corner, upper triangle\n};\n\n/**\n * East Indian sign abbreviation positions, nudged toward the outer edge of\n * every cell so the abbreviation and the planet stack do not collide.\n */\nexport const EAST_SIGN_POSITIONS: Record<number, { x: number; y: number }> = {\n\t1: { x: 150, y: 55 },\n\t2: { x: 235, y: 24 },\n\t3: { x: 276, y: 62 },\n\t4: { x: 242, y: 150 },\n\t5: { x: 276, y: 238 },\n\t6: { x: 235, y: 276 },\n\t7: { x: 150, y: 245 },\n\t8: { x: 65, y: 276 },\n\t9: { x: 24, y: 238 },\n\t10: { x: 58, y: 150 },\n\t11: { x: 24, y: 62 },\n\t12: { x: 65, y: 24 },\n};\n\n/**\n * Render a single south-Indian house group: lagna highlight, sign\n * abbreviation, planet labels with degree and tooltip.\n */\nexport function renderSouthHouseGroup(\n\th: HouseDef,\n): TemplateResult | typeof nothing {\n\tconst center = SOUTH_HOUSE_CENTERS[h.number];\n\tconst signPos = SOUTH_SIGN_POSITIONS[h.number];\n\tif (!center || !signPos) return nothing;\n\tconst signAbbr = SIGN_ABBR[h.sign] ?? '';\n\tconst baseY = h.isLagna ? center.y + 8 : center.y;\n\treturn svg`\n\t\t<g>\n\t\t\t${\n\t\t\t\th.isLagna\n\t\t\t\t\t? svg`<rect\n\t\t\t\t\t\t\tclass=\"lagna-bg\"\n\t\t\t\t\t\t\tx=${center.x - 30} y=${center.y - 28}\n\t\t\t\t\t\t\twidth=\"60\" height=\"56\" rx=\"6\"\n\t\t\t\t\t\t/>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t${\n\t\t\t\tsignAbbr\n\t\t\t\t\t? svg`<text class=\"sign-text\" x=${signPos.x} y=${signPos.y} text-anchor=\"middle\" dominant-baseline=\"central\">${signAbbr}</text>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t${\n\t\t\t\th.isLagna\n\t\t\t\t\t? svg`<text class=\"lagna-marker\" x=${center.x} y=${center.y - 18} text-anchor=\"middle\" dominant-baseline=\"central\">LAGNA</text>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t${renderPlanetStack(h.planets, center.x, baseY, 13)}\n\t\t</g>\n\t`;\n}\n\n/**\n * Render a north-Indian-style kundli wheel frame (grid lines only).\n * Returns the SVG structural lines; call `renderNorthHouseGroup` for content.\n */\nexport function renderNorthFrame(): TemplateResult {\n\treturn svg`\n\t\t<polygon class=\"line\" points=\"150,10 290,150 150,290 10,150\" stroke-width=\"1.5\" />\n\t\t<line class=\"line\" x1=\"150\" y1=\"10\" x2=\"150\" y2=\"290\" stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=\"10\" y1=\"150\" x2=\"290\" y2=\"150\" stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=\"150\" y1=\"10\" x2=\"10\" y2=\"150\" stroke-width=\"0.6\" stroke-dasharray=\"3,3\" />\n\t\t<line class=\"line\" x1=\"150\" y1=\"10\" x2=\"290\" y2=\"150\" stroke-width=\"0.6\" stroke-dasharray=\"3,3\" />\n\t\t<line class=\"line\" x1=\"150\" y1=\"290\" x2=\"10\" y2=\"150\" stroke-width=\"0.6\" stroke-dasharray=\"3,3\" />\n\t\t<line class=\"line\" x1=\"150\" y1=\"290\" x2=\"290\" y2=\"150\" stroke-width=\"0.6\" stroke-dasharray=\"3,3\" />\n\t`;\n}\n\n/**\n * Render a north-Indian house group (sign abbr + house number + planets).\n */\nexport function renderNorthHouseGroup(\n\th: HouseDef,\n): TemplateResult | typeof nothing {\n\tconst center = NORTH_HOUSE_CENTERS[h.number];\n\tif (!center) return nothing;\n\tconst signAbbr = SIGN_ABBR[h.sign] ?? '';\n\treturn svg`\n\t\t<g>\n\t\t\t${\n\t\t\t\th.isLagna\n\t\t\t\t\t? svg`<circle class=\"lagna-bg\" cx=${center.x} cy=${center.y} r=\"22\" />`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t${\n\t\t\t\tsignAbbr\n\t\t\t\t\t? svg`<text class=\"sign-text\" x=${center.x} y=${center.y - 10} text-anchor=\"middle\" dominant-baseline=\"central\">${signAbbr}</text>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t<text class=\"house-num\" x=${center.x} y=${center.y + 2} text-anchor=\"middle\" dominant-baseline=\"central\">${h.number}</text>\n\t\t\t${renderPlanetStack(h.planets, center.x, center.y + 14, 11)}\n\t\t</g>\n\t`;\n}\n\n/**\n * Render the south-Indian square frame (border diamond + inner square + radial lines).\n */\nexport function renderSouthFrame(): TemplateResult {\n\treturn svg`\n\t\t<polygon class=\"line\" points=\"150,10 290,150 150,290 10,150\" stroke-width=\"1.5\" />\n\t\t<polygon class=\"line\" points=\"220,80 220,220 80,220 80,80\" stroke-width=\"1\" fill=\"none\" />\n\t\t<line class=\"line\" x1=\"150\" y1=\"10\" x2=\"80\" y2=\"80\" stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=\"150\" y1=\"10\" x2=\"220\" y2=\"80\" stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=\"290\" y1=\"150\" x2=\"220\" y2=\"80\" stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=\"290\" y1=\"150\" x2=\"220\" y2=\"220\" stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=\"150\" y1=\"290\" x2=\"220\" y2=\"220\" stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=\"150\" y1=\"290\" x2=\"80\" y2=\"220\" stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=\"10\" y1=\"150\" x2=\"80\" y2=\"220\" stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=\"10\" y1=\"150\" x2=\"80\" y2=\"80\" stroke-width=\"1\" />\n\t`;\n}\n\n/**\n * Render the east-Indian square frame: outer square, both diagonals, and the\n * inner diamond joining the four side midpoints. Twelve triangular cells.\n */\nexport function renderEastFrame(): TemplateResult {\n\treturn svg`\n\t\t<rect class=\"line\" x=\"10\" y=\"10\" width=\"280\" height=\"280\" stroke-width=\"1.5\" fill=\"none\" />\n\t\t<line class=\"line\" x1=\"10\" y1=\"10\" x2=\"290\" y2=\"290\" stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=\"290\" y1=\"10\" x2=\"10\" y2=\"290\" stroke-width=\"1\" />\n\t\t<polygon class=\"line\" points=\"150,10 290,150 150,290 10,150\" stroke-width=\"1\" fill=\"none\" />\n\t`;\n}\n\n/**\n * Render an east-Indian house group. East Indian charts are sign-fixed like\n * the south style, so this mirrors `renderSouthHouseGroup` with the east cell\n * centers and a smaller line height to fit the triangular cells.\n */\nexport function renderEastHouseGroup(\n\th: HouseDef,\n): TemplateResult | typeof nothing {\n\tconst center = EAST_HOUSE_CENTERS[h.number];\n\tconst signPos = EAST_SIGN_POSITIONS[h.number];\n\tif (!center || !signPos) return nothing;\n\tconst signAbbr = SIGN_ABBR[h.sign] ?? '';\n\treturn svg`\n\t\t<g>\n\t\t\t${\n\t\t\t\th.isLagna\n\t\t\t\t\t? svg`<circle class=\"lagna-bg\" cx=${center.x} cy=${center.y} r=\"20\" />`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t${\n\t\t\t\tsignAbbr\n\t\t\t\t\t? svg`<text class=\"sign-text\" x=${signPos.x} y=${signPos.y} text-anchor=\"middle\" dominant-baseline=\"central\">${signAbbr}</text>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t${\n\t\t\t\th.isLagna\n\t\t\t\t\t? svg`<text class=\"lagna-marker\" x=${center.x} y=${center.y - 14} text-anchor=\"middle\" dominant-baseline=\"central\">LAGNA</text>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t${renderPlanetStack(h.planets, center.x, center.y + 2, 11)}\n\t\t</g>\n\t`;\n}\n\n/**\n * Bucket a graha-keyed `meta` map (from a D1 or Dx chart response) into the 12\n * sign-indexed houses. Shared by the kundli and divisional chart components so\n * both render the same rich per-graha detail. The Lagna entry is consumed only\n * to flag the ascendant cell, not rendered as a planet.\n */\nexport function buildHousesFromMeta(\n\tmeta: Record<\n\t\tstring,\n\t\t{\n\t\t\tgraha?: string;\n\t\t\trashi?: string;\n\t\t\tlongitude?: number;\n\t\t\tnakshatra?: { name?: string; pada?: number; lord?: string };\n\t\t\tisRetrograde?: boolean;\n\t\t\tawastha?: string;\n\t\t}\n\t>,\n): HouseDef[] {\n\tconst byRashi = new Map<string, PlacedGraha[]>();\n\tlet lagnaKey = '';\n\tfor (const [name, pos] of Object.entries(meta)) {\n\t\tconst rashiKey = (pos?.rashi ?? '').toLowerCase();\n\t\tif (name === 'Lagna' || pos?.graha === 'Lagna') {\n\t\t\tlagnaKey = rashiKey;\n\t\t\tcontinue;\n\t\t}\n\t\tif (!rashiKey) continue;\n\t\tconst list = byRashi.get(rashiKey) ?? [];\n\t\tlist.push({\n\t\t\tgraha: pos.graha ?? name,\n\t\t\tlongitude: pos.longitude,\n\t\t\tnakshatra: pos.nakshatra,\n\t\t\tisRetrograde: pos.isRetrograde,\n\t\t\tawastha: pos.awastha,\n\t\t});\n\t\tbyRashi.set(rashiKey, list);\n\t}\n\treturn SIGNS_ORDER.map((sign, i) => {\n\t\tconst key = sign.toLowerCase();\n\t\treturn {\n\t\t\tnumber: i + 1,\n\t\t\tsign,\n\t\t\tplanets: byRashi.get(key) ?? [],\n\t\t\tisLagna: lagnaKey === key,\n\t\t};\n\t});\n}\n", "/**\n * Symbol constants used across components. Single source of truth so chart\n * wheels, card headers, hexagram displays, and panchang tables stay visually\n * consistent.\n */\n\nexport const PLANET_GLYPH: Record<string, string> = {\n\tSun: '\u2609',\n\tMoon: '\u263D',\n\tMercury: '\u263F',\n\tVenus: '\u2640',\n\tEarth: '\u2641',\n\tMars: '\u2642',\n\tJupiter: '\u2643',\n\tSaturn: '\u2644',\n\tUranus: '\u2645',\n\tNeptune: '\u2646',\n\tPluto: '\u2647',\n\tRahu: '\u260A',\n\tKetu: '\u260B',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n\tNorthNode: '\u260A',\n\tSouthNode: '\u260B',\n\t'North node': '\u260A',\n\t'South node': '\u260B',\n\tChiron: '\u26B7',\n\tLilith: '\u26B8',\n\t'Black moon lilith': '\u26B8',\n};\n\nexport const PLANET_ABBR: Record<string, string> = {\n\tSun: 'Su',\n\tMoon: 'Mo',\n\tMercury: 'Me',\n\tVenus: 'Ve',\n\tMars: 'Ma',\n\tJupiter: 'Ju',\n\tSaturn: 'Sa',\n\tUranus: 'Ur',\n\tNeptune: 'Ne',\n\tPluto: 'Pl',\n\tRahu: 'Ra',\n\tKetu: 'Ke',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n};\n\nexport const SIGN_GLYPH: Record<string, string> = {\n\tAries: '\u2648',\n\tTaurus: '\u2649',\n\tGemini: '\u264A',\n\tCancer: '\u264B',\n\tLeo: '\u264C',\n\tVirgo: '\u264D',\n\tLibra: '\u264E',\n\tScorpio: '\u264F',\n\tSagittarius: '\u2650',\n\tCapricorn: '\u2651',\n\tAquarius: '\u2652',\n\tPisces: '\u2653',\n};\n\nexport const SIGN_ABBR: Record<string, string> = {\n\tAries: 'Ar',\n\tTaurus: 'Ta',\n\tGemini: 'Ge',\n\tCancer: 'Cn',\n\tLeo: 'Le',\n\tVirgo: 'Vi',\n\tLibra: 'Li',\n\tScorpio: 'Sc',\n\tSagittarius: 'Sg',\n\tCapricorn: 'Cp',\n\tAquarius: 'Aq',\n\tPisces: 'Pi',\n};\n\nexport const SIGNS_ORDER = [\n\t'Aries',\n\t'Taurus',\n\t'Gemini',\n\t'Cancer',\n\t'Leo',\n\t'Virgo',\n\t'Libra',\n\t'Scorpio',\n\t'Sagittarius',\n\t'Capricorn',\n\t'Aquarius',\n\t'Pisces',\n] as const;\n\n/**\n * Lowercase rashi keys in canonical zodiac order. Derived from `SIGNS_ORDER`\n * so the two stay in lockstep. The /vedic-astrology/birth-chart response\n * carries planet buckets keyed by these names.\n */\nexport const RASHI_KEYS = SIGNS_ORDER.map((s) =>\n\ts.toLowerCase(),\n) as readonly Lowercase<(typeof SIGNS_ORDER)[number]>[];\n\n/** Aspect symbols. Used by synastry and natal chart aspect tables. */\nexport const ASPECT_SYMBOL: Record<string, string> = {\n\tconjunction: '\u260C',\n\topposition: '\u260D',\n\ttrine: '\u25B3',\n\tsquare: '\u25A1',\n\tsextile: '\u2731',\n\tquincunx: '\u22BB',\n\tsemisextile: '\u22BC',\n};\n\n/** Trigrams used by I Ching hexagrams. Eight trigrams compose 64 hexagrams. */\nexport const TRIGRAM_GLYPH: Record<string, string> = {\n\theaven: '\u2630',\n\tlake: '\u2631',\n\tfire: '\u2632',\n\tthunder: '\u2633',\n\twind: '\u2634',\n\twater: '\u2635',\n\tmountain: '\u2636',\n\tearth: '\u2637',\n\tHeaven: '\u2630',\n\tLake: '\u2631',\n\tFire: '\u2632',\n\tThunder: '\u2633',\n\tWind: '\u2634',\n\tWater: '\u2635',\n\tMountain: '\u2636',\n\tEarth: '\u2637',\n};\n\n/** Moon phase emoji set. Used by moon phase card. */\nexport const MOON_PHASE_EMOJI: Record<string, string> = {\n\t'new moon': '\uD83C\uDF11',\n\t'waxing crescent': '\uD83C\uDF12',\n\t'first quarter': '\uD83C\uDF13',\n\t'waxing gibbous': '\uD83C\uDF14',\n\t'full moon': '\uD83C\uDF15',\n\t'waning gibbous': '\uD83C\uDF16',\n\t'last quarter': '\uD83C\uDF17',\n\t'waning crescent': '\uD83C\uDF18',\n};\n", "/**\n * Math helpers for converting raw ecliptic longitude decimals into the\n * sign / degree / minute / second triplet used across chart components.\n */\n\nimport { SIGNS_ORDER } from '../tokens/index.js';\n\nexport interface SignPosition {\n\tsign: string;\n\tsignIndex: number;\n\tdegree: number;\n\tminute: number;\n\tsecond: number;\n}\n\n/**\n * Wrap longitude into [0, 360) so negative or out-of-range values still\n * resolve to a real sign. Robust to wonky upstream data.\n */\nexport function normalizeLongitude(lon: number): number {\n\tconst wrapped = lon % 360;\n\treturn wrapped < 0 ? wrapped + 360 : wrapped;\n}\n\n/**\n * Convert decimal ecliptic longitude (0-360) into sign/degree/minute/second.\n * Used by every chart wheel and aspect table.\n */\nexport function longitudeToSignPosition(longitude: number): SignPosition {\n\tconst lon = normalizeLongitude(longitude);\n\tconst signIndex = Math.floor(lon / 30) % 12;\n\tconst within = lon % 30;\n\tconst degree = Math.floor(within);\n\tconst minuteFloat = (within - degree) * 60;\n\tconst minute = Math.floor(minuteFloat);\n\tconst second = Math.round((minuteFloat - minute) * 60);\n\treturn {\n\t\tsign: SIGNS_ORDER[signIndex] ?? 'Aries',\n\t\tsignIndex,\n\t\tdegree,\n\t\tminute,\n\t\tsecond,\n\t};\n}\n\n/** Compact display string like \"12\u00B0 Leo 34'\". Used in chart labels. */\nexport function formatSignPosition(longitude: number): string {\n\tconst { sign, degree, minute } = longitudeToSignPosition(longitude);\n\treturn `${degree}\u00B0 ${sign} ${String(minute).padStart(2, '0')}'`;\n}\n\n/**\n * The point diametrically opposite a longitude (e.g. Descendant from\n * Ascendant, IC from MC). Exact derivation, always 180 degrees away.\n */\nexport function oppositePoint(longitude: number): number {\n\treturn normalizeLongitude(longitude + 180);\n}\n\n/**\n * Midpoint of the forward arc from `start` to `end` (both ecliptic\n * longitudes). Handles the 360/0 wrap, so a house spanning 350 to 20 degrees\n * yields a midpoint of 5, not 185. Used to place house numbers between two\n * cusps regardless of how unequal the house is.\n */\nexport function arcMidpoint(start: number, end: number): number {\n\tconst s = normalizeLongitude(start);\n\tlet span = normalizeLongitude(end) - s;\n\tif (span < 0) span += 360;\n\treturn normalizeLongitude(s + span / 2);\n}\n\n/** Polar to cartesian for SVG wheel positioning. Angle in degrees, 0 at 3 o'clock. */\nexport function polarToCartesian(\n\tcx: number,\n\tcy: number,\n\tradius: number,\n\tangleDeg: number,\n): { x: number; y: number } {\n\tconst angleRad = (angleDeg * Math.PI) / 180;\n\treturn {\n\t\tx: cx + radius * Math.cos(angleRad),\n\t\ty: cy + radius * Math.sin(angleRad),\n\t};\n}\n", "/**\n * Shared string helpers used across components. Single source of truth so the\n * same formatting rules apply to every key/label/title that surfaces in the\n * shadow tree.\n *\n * - `capitalize`: title-cases the first character, lowercases the rest. Used\n * when matching API-supplied planet/sign names against the glyph maps in\n * `tokens/index.ts`, which use canonical TitleCase keys.\n * - `humanize`: turns an API key (`birth_date`, `birthDate`, `mahadasha-end`)\n * into a label suitable for display (\"Birth date\", \"Mahadasha end\").\n */\n\nexport function capitalize(s: string): string {\n\tif (!s) return '';\n\treturn s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();\n}\n\nexport function humanize(s: string): string {\n\treturn s\n\t\t.replace(/[_-]+/g, ' ')\n\t\t.replace(/([a-z])([A-Z])/g, '$1 $2')\n\t\t.replace(/^\\w/, (c) => c.toUpperCase());\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["
|
|
3
|
+
"sources": ["../../src/components/vedic-kundli.ts", "../../src/utils/base-styles.ts", "../../src/utils/kundli-render.ts", "../../src/tokens/index.ts", "../../src/utils/degree.ts", "../../src/utils/string.ts", "../../src/utils/kundli-styles.ts"],
|
|
4
|
+
"sourcesContent": ["import { html, LitElement } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type { BirthChartResponse } from '../types/index.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport {\n\ttype ChartStyle,\n\ttype KundliViewModel,\n\trenderKundliStyleTablist,\n\trenderKundliSvg,\n\ttoKundliViewModel,\n} from '../utils/kundli-render.js';\nimport { kundliStyles } from '../utils/kundli-styles.js';\n\n/**\n * Vedic kundli (D1 Rashi chart). Pass `data` from /vedic-astrology/birth-chart.\n * Three regional render styles are available; the visible tablist lets the\n * end user switch between South / North / East at any time. The same planet-\n * in-sign data feeds every style, so the toggle is purely a layout choice.\n *\n * Each planet shows its abbreviation and whole-degree-within-sign, with an\n * SVG tooltip carrying exact position, nakshatra, pada, and avastha. The host\n * page sets the initial style via `chart-style` attribute; from there the\n * user takes over.\n *\n * Theming flows through CSS custom properties on `:host`, so the chart\n * adopts the host page palette without runtime color probing.\n */\n@customElement('roxy-vedic-kundli')\nexport class RoxyVedicKundli extends LitElement {\n\tstatic styles = [baseStyles, kundliStyles];\n\n\t@property({ attribute: false })\n\tdata: BirthChartResponse | null = null;\n\n\t@property({ type: String, reflect: true, attribute: 'chart-style' })\n\tchartStyle: ChartStyle = 'north';\n\n\tprivate viewModel(): KundliViewModel | null {\n\t\tif (!this.data?.meta) return null;\n\t\treturn toKundliViewModel(this.data.meta, 'D1 Rashi');\n\t}\n\n\tprivate setStyle = (next: ChartStyle) => {\n\t\tthis.chartStyle = next;\n\t};\n\n\trender() {\n\t\tconst vm = this.viewModel();\n\t\tif (!vm)\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No kundli data</div>`;\n\t\treturn html`<div class=\"wrap\">\n\t\t\t<div class=\"header\">\n\t\t\t\t<h2 class=\"title\">Vedic kundli</h2>\n\t\t\t\t${renderKundliStyleTablist(this.chartStyle, this.setStyle)}\n\t\t\t</div>\n\t\t\t<svg\n\t\t\t\tviewBox=\"0 0 400 400\"\n\t\t\t\tpreserveAspectRatio=\"xMidYMid meet\"\n\t\t\t\trole=\"img\"\n\t\t\t\taria-label=\"Vedic birth chart with twelve sign houses\"\n\t\t\t>\n\t\t\t\t<title>Vedic kundli</title>\n\t\t\t\t${renderKundliSvg(vm, this.chartStyle)}\n\t\t\t</svg>\n\t\t</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-vedic-kundli': RoxyVedicKundli;\n\t}\n}\n", "import { css } from 'lit';\n\n/**\n * Shared host styles every component pulls in. Sets default font, color,\n * container query support, and the entry fade-in.\n */\nexport const baseStyles = css`\n\t:host {\n\t\tdisplay: block;\n\t\tcontainer-type: inline-size;\n\t\tfont-family: var(\n\t\t\t--roxy-font-sans,\n\t\t\tsystem-ui,\n\t\t\t-apple-system,\n\t\t\tBlinkMacSystemFont,\n\t\t\t'Segoe UI',\n\t\t\tRoboto,\n\t\t\tsans-serif\n\t\t);\n\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\tbackground: transparent;\n\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\tline-height: var(--roxy-leading-normal, 1.5);\n\t\tanimation: roxy-fade-in var(--roxy-motion-duration, 200ms)\n\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1)) both;\n\t}\n\n\t*,\n\t*::before,\n\t*::after {\n\t\tbox-sizing: border-box;\n\t}\n\n\t@keyframes roxy-fade-in {\n\t\tfrom {\n\t\t\topacity: 0;\n\t\t\ttransform: translateY(2px);\n\t\t}\n\t\tto {\n\t\t\topacity: 1;\n\t\t\ttransform: translateY(0);\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t:host {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-skeleton {\n\t\tbackground: linear-gradient(\n\t\t\t90deg,\n\t\t\tvar(--roxy-border, #e4e4e7) 0%,\n\t\t\tcolor-mix(in srgb, var(--roxy-border, #e4e4e7) 60%, transparent) 50%,\n\t\t\tvar(--roxy-border, #e4e4e7) 100%\n\t\t);\n\t\tbackground-size: 200% 100%;\n\t\tanimation: roxy-shimmer 1.4s ease-in-out infinite;\n\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t}\n\n\t@keyframes roxy-shimmer {\n\t\t0% {\n\t\t\tbackground-position: 200% 0;\n\t\t}\n\t\t100% {\n\t\t\tbackground-position: -200% 0;\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t.roxy-skeleton {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-empty {\n\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\tcolor: var(--roxy-muted, #71717a);\n\t\ttext-align: center;\n\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t}\n\n\t:host(:focus-within) .roxy-card {\n\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\toutline-offset: 2px;\n\t}\n\n\t/* Force the text-style variant on every Unicode glyph in the component.\n\t * macOS and iOS substitute coloured emoji glyphs for the planetary and\n\t * gender Unicode code points (Mars, Venus, Mercury, etc.) when the\n\t * system colour-emoji font wins font selection. The text-style variant\n\t * keeps glyphs monochrome so they inherit the surrounding fill colour\n\t * and match the brand palette consistently across platforms.\n\t *\n\t * font-variant-emoji is part of CSS Fonts 4 (Safari 17+, Chrome 134+,\n\t * Firefox 139+). On older browsers the rule is silently ignored.\n\t */\n\t:host {\n\t\tfont-variant-emoji: text;\n\t}\n`;\n", "import type { TemplateResult } from 'lit';\nimport { html, nothing, svg } from 'lit';\nimport { PLANET_ABBR, SIGN_ABBR, SIGNS_ORDER } from '../tokens/index.js';\nimport { longitudeToSignPosition } from './degree.js';\nimport { capitalize } from './string.js';\n\n/**\n * Canonical viewBox geometry for every kundli style. The chart is drawn into a\n * 360-unit square centred in a 400-unit viewBox, leaving a 20-unit gutter for\n * outer labels. All coordinates below are derived from these constants; change\n * them and every cell relocates correctly.\n *\n * @remarks SVG is vector-only and scales without raster loss, so the chart\n * remains crisp from a phone screen to a wall projector. Hosts size the chart\n * by setting `width` on the surrounding container; the SVG keeps a 1:1 aspect\n * ratio via the viewBox.\n */\nconst VIEW_BOX = 400;\nconst MARGIN = 20;\nconst INNER = VIEW_BOX - 2 * MARGIN; // 360\nconst CENTRE = VIEW_BOX / 2; // 200\n\n/**\n * Lowercase rashi key (`\"aries\"`) to canonical title-cased sign name (`\"Aries\"`).\n * Bridges API lowercase rashi strings to the SIGNS_ORDER tokens used everywhere\n * else in the render.\n */\nconst RASHI_TO_SIGN: Record<string, string> = Object.fromEntries(\n\tSIGNS_ORDER.map((s) => [s.toLowerCase(), s] as const),\n);\n\n/**\n * A graha placed inside a kundli cell. Render-only view model fed from a\n * `meta` map on the API response. Carries enough detail to draw a compact\n * in-cell label (abbreviation, whole degree, retrograde mark) and a rich SVG\n * `<title>` tooltip (exact position, nakshatra, pada, avastha).\n */\nexport interface PlacedGraha {\n\tgraha: string;\n\tlongitude?: number;\n\tnakshatra?: { name?: string; pada?: number; lord?: string };\n\tisRetrograde?: boolean;\n\tawastha?: string;\n}\n\n/**\n * Unified view model used by every kundli style. Caller passes a graha-keyed\n * `meta` map (from `/vedic-astrology/birth-chart`, `/divisional-chart`, or\n * `/navamsa`) through {@link toKundliViewModel} to produce this shape.\n *\n * `placements` is keyed by lowercase rashi name (`\"aries\"`, `\"taurus\"`, ...)\n * so the sign-fixed styles can index directly. The Lagna entry is not\n * counted as a planet; it only flags the ascendant cell.\n */\nexport interface KundliViewModel {\n\tlagnaSign: string;\n\tplacements: Record<string, PlacedGraha[]>;\n\tdivisionLabel?: string;\n}\n\n/**\n * Kundli regional styles. Sign-fixed (south, east) and house-fixed (north).\n * Exposed so consumers can type their own `chart-style` attribute reflection.\n */\nexport type ChartStyle = 'south' | 'north' | 'east';\n\nconst CHART_STYLES: ReadonlyArray<{ id: ChartStyle; label: string }> = [\n\t{ id: 'north', label: 'North' },\n\t{ id: 'south', label: 'South' },\n\t{ id: 'east', label: 'East' },\n];\n\nconst RETRO_MARK = '\u02B3';\n\n/**\n * True when the placed graha's longitude maps to a sign other than the cell\n * it occupies. The API preserves the D1 sidereal longitude on every chart, so\n * inside a D2..D60 cell that longitude refers to the D1 sign, not the cell's\n * divisional sign. In that case the degree-within-sign is not meaningful and\n * must be hidden from the in-cell label.\n */\nfunction isDivisionalPlacement(p: PlacedGraha, cellSign: string): boolean {\n\tif (typeof p.longitude !== 'number' || !Number.isFinite(p.longitude)) {\n\t\treturn false;\n\t}\n\treturn (\n\t\tlongitudeToSignPosition(p.longitude).sign.toLowerCase() !==\n\t\tcellSign.toLowerCase()\n\t);\n}\n\n/**\n * Compact in-cell graha label: abbreviation, optional whole-degree, retrograde\n * mark. The degree is shown only when the longitude actually maps to the cell\n * the graha is rendered in (the D1 case); divisional placements show the\n * abbreviation alone since the API longitude refers to D1, not the divisional\n * sign.\n */\nfunction grahaLabel(p: PlacedGraha, cellSign: string): string {\n\tconst abbr = PLANET_ABBR[capitalize(p.graha)] ?? p.graha.slice(0, 2);\n\tconst retro = p.isRetrograde ? RETRO_MARK : '';\n\tif (\n\t\ttypeof p.longitude !== 'number' ||\n\t\t!Number.isFinite(p.longitude) ||\n\t\tisDivisionalPlacement(p, cellSign)\n\t) {\n\t\treturn `${abbr}${retro}`;\n\t}\n\tconst { degree } = longitudeToSignPosition(p.longitude);\n\treturn `${abbr} ${degree}\u00B0${retro}`;\n}\n\n/**\n * Full-detail tooltip surfaced via the SVG `<title>` for each planet label.\n * Includes planet name, the divisional placement (when the longitude does not\n * match the cell, the cell's rashi is preferred), the exact D1 longitude as\n * the original reference, nakshatra and pada, avastha, and the retrograde\n * flag. Surfaces on hover or long-press without crowding the cell.\n */\nfunction grahaTitle(p: PlacedGraha, cellSign: string): string {\n\tconst parts: string[] = [capitalize(p.graha)];\n\tconst divisional = isDivisionalPlacement(p, cellSign);\n\tif (divisional) {\n\t\tparts.push(`in ${cellSign}`);\n\t}\n\tif (typeof p.longitude === 'number' && Number.isFinite(p.longitude)) {\n\t\tconst sp = longitudeToSignPosition(p.longitude);\n\t\tconst minute = String(sp.minute).padStart(2, '0');\n\t\tparts.push(\n\t\t\tdivisional\n\t\t\t\t? `D1: ${sp.degree}\u00B0${minute}' ${sp.sign}`\n\t\t\t\t: `${sp.degree}\u00B0${minute}' ${sp.sign}`,\n\t\t);\n\t}\n\tif (p.nakshatra?.name) {\n\t\tconst pada = p.nakshatra.pada ? ` pada ${p.nakshatra.pada}` : '';\n\t\tparts.push(`${p.nakshatra.name}${pada}`);\n\t}\n\tif (p.awastha) parts.push(p.awastha);\n\tif (p.isRetrograde) parts.push('retrograde');\n\treturn parts.join(' \u00B7 ');\n}\n\n/**\n * Render a vertically centred stack of planet labels at `(cx, baseY)`, one\n * line per planet, with an SVG `<title>` per line carrying the full tooltip.\n * The stack auto-centres on `baseY` regardless of count so a 1-planet cell\n * and a 5-planet cell both look intentional.\n */\nfunction renderPlanetStack(\n\tplanets: PlacedGraha[],\n\tcellSign: string,\n\tcx: number,\n\tbaseY: number,\n\tlineHeight: number,\n): TemplateResult[] {\n\tconst startY = baseY - ((planets.length - 1) * lineHeight) / 2;\n\treturn planets.map((p, j) => {\n\t\tconst yPos = startY + j * lineHeight;\n\t\treturn svg`<text class=\"planet-text\" x=${cx} y=${yPos} text-anchor=\"middle\" dominant-baseline=\"central\">${grahaLabel(\n\t\t\tp,\n\t\t\tcellSign,\n\t\t)}<title>${grahaTitle(p, cellSign)}</title></text>`;\n\t});\n}\n\n/**\n * Bucket a graha-keyed `meta` map (D1 birth chart or D2..D60 divisional\n * chart) into the unified {@link KundliViewModel} the renderer consumes. The\n * Lagna entry is recognised by `graha === 'Lagna'` (or key `\"Lagna\"`) and\n * sets `lagnaSign`; it is not bucketed as a placed planet.\n *\n * @param meta - Graha-keyed map; missing rashi entries are skipped.\n * @param divisionLabel - Optional title written inside the chart centre.\n */\nexport function toKundliViewModel(\n\tmeta: Record<\n\t\tstring,\n\t\t{\n\t\t\tgraha?: string;\n\t\t\trashi?: string;\n\t\t\tlongitude?: number;\n\t\t\tnakshatra?: { name?: string; pada?: number; lord?: string };\n\t\t\tisRetrograde?: boolean;\n\t\t\tawastha?: string;\n\t\t}\n\t>,\n\tdivisionLabel?: string,\n): KundliViewModel {\n\tconst placements: Record<string, PlacedGraha[]> = {};\n\tfor (const sign of SIGNS_ORDER) placements[sign.toLowerCase()] = [];\n\tlet lagnaSign = '';\n\tfor (const [name, pos] of Object.entries(meta ?? {})) {\n\t\tconst rashiKey = (pos?.rashi ?? '').toLowerCase();\n\t\tif (name === 'Lagna' || pos?.graha === 'Lagna') {\n\t\t\tlagnaSign = RASHI_TO_SIGN[rashiKey] ?? '';\n\t\t\tcontinue;\n\t\t}\n\t\tif (!rashiKey || !(rashiKey in placements)) continue;\n\t\tplacements[rashiKey]?.push({\n\t\t\tgraha: pos.graha ?? name,\n\t\t\tlongitude: pos.longitude,\n\t\t\tnakshatra: pos.nakshatra,\n\t\t\tisRetrograde: pos.isRetrograde,\n\t\t\tawastha: pos.awastha,\n\t\t});\n\t}\n\treturn { lagnaSign, placements, divisionLabel };\n}\n\n// ---------------------------------------------------------------------------\n// South Indian: 4x4 grid with central 2x2 hollow. Signs are FIXED to cells\n// (Pisces top-left corner, clockwise); houses rotate from the Lagna cell.\n// ---------------------------------------------------------------------------\n\nconst SOUTH_CELL = INNER / 4; // 90\n\n/**\n * Sign-to-cell column/row in the South Indian fixed-sign grid. Pisces sits in\n * the top-left corner and the remaining signs proceed clockwise around the\n * 12 perimeter cells. (col, row) origin is the chart top-left.\n */\nconst SOUTH_CELL_GRID: Record<string, { col: number; row: number }> = {\n\tPisces: { col: 0, row: 0 },\n\tAries: { col: 1, row: 0 },\n\tTaurus: { col: 2, row: 0 },\n\tGemini: { col: 3, row: 0 },\n\tCancer: { col: 3, row: 1 },\n\tLeo: { col: 3, row: 2 },\n\tVirgo: { col: 3, row: 3 },\n\tLibra: { col: 2, row: 3 },\n\tScorpio: { col: 1, row: 3 },\n\tSagittarius: { col: 0, row: 3 },\n\tCapricorn: { col: 0, row: 2 },\n\tAquarius: { col: 0, row: 1 },\n};\n\nfunction southCellRect(sign: string): {\n\tx: number;\n\ty: number;\n\tw: number;\n\th: number;\n} {\n\tconst g = SOUTH_CELL_GRID[sign] ?? { col: 0, row: 0 };\n\treturn {\n\t\tx: MARGIN + g.col * SOUTH_CELL,\n\t\ty: MARGIN + g.row * SOUTH_CELL,\n\t\tw: SOUTH_CELL,\n\t\th: SOUTH_CELL,\n\t};\n}\n\n/**\n * South Indian frame: outer square, the two full-span grid lines, and the\n * partial inner lines that bound the central 2x2 hollow on each edge.\n */\nfunction renderSouthFrame(divisionLabel?: string): TemplateResult {\n\tconst a = MARGIN;\n\tconst b = MARGIN + SOUTH_CELL; // 110\n\tconst c = MARGIN + 2 * SOUTH_CELL; // 200\n\tconst d = MARGIN + 3 * SOUTH_CELL; // 290\n\tconst e = VIEW_BOX - MARGIN; // 380\n\treturn svg`\n\t\t<rect class=\"line\" x=${a} y=${a} width=${INNER} height=${INNER} stroke-width=\"1.5\" fill=\"none\" />\n\t\t<line class=\"line\" x1=${a} y1=${b} x2=${e} y2=${b} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${a} y1=${d} x2=${e} y2=${d} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${b} y1=${a} x2=${b} y2=${e} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${d} y1=${a} x2=${d} y2=${e} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${a} y1=${c} x2=${b} y2=${c} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${d} y1=${c} x2=${e} y2=${c} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${c} y1=${a} x2=${c} y2=${b} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${c} y1=${d} x2=${c} y2=${e} stroke-width=\"1\" />\n\t\t${\n\t\t\tdivisionLabel\n\t\t\t\t? svg`<text class=\"centre-label\" x=${CENTRE} y=${CENTRE} text-anchor=\"middle\" dominant-baseline=\"central\">${divisionLabel}</text>`\n\t\t\t\t: nothing\n\t\t}\n\t`;\n}\n\n/**\n * House number for a given sign relative to a Lagna sign. House 1 is the\n * Lagna cell; subsequent houses follow the zodiac in order. Returns 0 when\n * the Lagna sign is unknown so the caller can skip rendering the badge.\n */\nfunction houseNumberInSign(sign: string, lagnaSign: string): number {\n\tconst lagnaIdx = SIGNS_ORDER.findIndex((s) => s === lagnaSign);\n\tconst signIdx = SIGNS_ORDER.findIndex((s) => s === sign);\n\tif (lagnaIdx === -1 || signIdx === -1) return 0;\n\treturn ((signIdx - lagnaIdx + 12) % 12) + 1;\n}\n\nfunction renderSouthCell(\n\tsign: string,\n\tplanets: PlacedGraha[],\n\tisLagna: boolean,\n\thouseNum: number,\n): TemplateResult {\n\tconst r = southCellRect(sign);\n\tconst cx = r.x + r.w / 2;\n\tconst cy = r.y + r.h / 2;\n\tconst signAbbr = SIGN_ABBR[sign] ?? sign.slice(0, 2);\n\t// Inset the Lagna diagonal so it does not collide with the chart frame on\n\t// corner cells (Pisces, Gemini, Virgo, Sagittarius) or with the sign label\n\t// in the top-left of every cell.\n\tconst slashInset = 14;\n\treturn svg`\n\t\t<g class=${isLagna ? 'cell lagna' : 'cell'}>\n\t\t\t${\n\t\t\t\tisLagna\n\t\t\t\t\t? svg`\n\t\t\t\t\t\t<rect class=\"lagna-bg\" x=${r.x} y=${r.y} width=${r.w} height=${r.h} />\n\t\t\t\t\t\t<line class=\"lagna-slash\" x1=${r.x + r.w - slashInset} y1=${r.y + slashInset} x2=${r.x + slashInset} y2=${r.y + r.h - slashInset} stroke-width=\"1.2\" />\n\t\t\t\t\t`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t<text class=\"sign-text\" x=${r.x + 6} y=${r.y + 12} text-anchor=\"start\" dominant-baseline=\"central\">${signAbbr}</text>\n\t\t\t${\n\t\t\t\thouseNum > 0\n\t\t\t\t\t? svg`<text class=\"house-num\" x=${r.x + r.w - 6} y=${r.y + 12} text-anchor=\"end\" dominant-baseline=\"central\">${houseNum}</text>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t${planets.length ? renderPlanetStack(planets, sign, cx, cy + 4, 14) : nothing}\n\t\t</g>\n\t`;\n}\n\nfunction renderSouthSvg(vm: KundliViewModel): TemplateResult {\n\tconst lagnaKey = vm.lagnaSign.toLowerCase();\n\treturn svg`\n\t\t${renderSouthFrame(vm.divisionLabel)}\n\t\t${SIGNS_ORDER.map((sign) =>\n\t\t\trenderSouthCell(\n\t\t\t\tsign,\n\t\t\t\tvm.placements[sign.toLowerCase()] ?? [],\n\t\t\t\tsign.toLowerCase() === lagnaKey,\n\t\t\t\thouseNumberInSign(sign, vm.lagnaSign),\n\t\t\t),\n\t\t)}\n\t`;\n}\n\n// ---------------------------------------------------------------------------\n// North Indian: outer square + inscribed midpoint diamond + both outer\n// diagonals. 12 cells: 4 cardinal diamonds + 8 corner triangles. Houses are\n// FIXED (H1 always top-centre); signs rotate from the Lagna sign.\n// ---------------------------------------------------------------------------\n\nconst NORTH_VERTICES = {\n\ttl: { x: MARGIN, y: MARGIN },\n\ttr: { x: VIEW_BOX - MARGIN, y: MARGIN },\n\tbr: { x: VIEW_BOX - MARGIN, y: VIEW_BOX - MARGIN },\n\tbl: { x: MARGIN, y: VIEW_BOX - MARGIN },\n\ttop: { x: CENTRE, y: MARGIN },\n\tright: { x: VIEW_BOX - MARGIN, y: CENTRE },\n\tbottom: { x: CENTRE, y: VIEW_BOX - MARGIN },\n\tleft: { x: MARGIN, y: CENTRE },\n\ttlMid: { x: CENTRE - INNER / 4, y: CENTRE - INNER / 4 },\n\ttrMid: { x: CENTRE + INNER / 4, y: CENTRE - INNER / 4 },\n\tbrMid: { x: CENTRE + INNER / 4, y: CENTRE + INNER / 4 },\n\tblMid: { x: CENTRE - INNER / 4, y: CENTRE + INNER / 4 },\n} as const;\n\n/**\n * Centroid (geometric mean) of an arbitrary set of polygon vertices. Used by\n * every cell that needs a label-anchor point; defining it once keeps the\n * North diamond and East triangle math identical.\n */\nfunction centroidOf(pts: Array<{ x: number; y: number }>): {\n\tx: number;\n\ty: number;\n} {\n\tconst x = pts.reduce((s, p) => s + p.x, 0) / pts.length;\n\tconst y = pts.reduce((s, p) => s + p.y, 0) / pts.length;\n\treturn { x, y };\n}\n\n/**\n * House centres for the North Indian diamond. Numbered 1..12 counter-clockwise\n * from the top diamond (H1 is always the ascendant cell). Centroids derived\n * from the canonical geometry above; do not edit by eye, recompute if you\n * change `VIEW_BOX` or `MARGIN`.\n */\nconst NORTH_HOUSE_CENTERS: Record<number, { x: number; y: number }> = {\n\t1: { x: CENTRE, y: NORTH_VERTICES.tlMid.y },\n\t2: centroidOf([NORTH_VERTICES.tl, NORTH_VERTICES.top, NORTH_VERTICES.tlMid]),\n\t3: centroidOf([NORTH_VERTICES.tl, NORTH_VERTICES.left, NORTH_VERTICES.tlMid]),\n\t4: { x: NORTH_VERTICES.tlMid.x, y: CENTRE },\n\t5: centroidOf([NORTH_VERTICES.bl, NORTH_VERTICES.left, NORTH_VERTICES.blMid]),\n\t6: centroidOf([\n\t\tNORTH_VERTICES.bl,\n\t\tNORTH_VERTICES.bottom,\n\t\tNORTH_VERTICES.blMid,\n\t]),\n\t7: { x: CENTRE, y: NORTH_VERTICES.blMid.y },\n\t8: centroidOf([\n\t\tNORTH_VERTICES.br,\n\t\tNORTH_VERTICES.bottom,\n\t\tNORTH_VERTICES.brMid,\n\t]),\n\t9: centroidOf([\n\t\tNORTH_VERTICES.br,\n\t\tNORTH_VERTICES.right,\n\t\tNORTH_VERTICES.brMid,\n\t]),\n\t10: { x: NORTH_VERTICES.brMid.x, y: CENTRE },\n\t11: centroidOf([\n\t\tNORTH_VERTICES.tr,\n\t\tNORTH_VERTICES.right,\n\t\tNORTH_VERTICES.trMid,\n\t]),\n\t12: centroidOf([NORTH_VERTICES.tr, NORTH_VERTICES.top, NORTH_VERTICES.trMid]),\n};\n\n/**\n * Rashi number (1..12, Aries=1) occupying the given house when the Lagna sits\n * in `lagnaSign`. House 1 is the Lagna sign; subsequent houses follow the\n * zodiac in order.\n */\nfunction rashiInHouse(houseNum: number, lagnaSign: string): number {\n\tconst lagnaIdx = SIGNS_ORDER.findIndex((s) => s === lagnaSign);\n\tif (lagnaIdx === -1) return houseNum;\n\treturn ((lagnaIdx + houseNum - 1) % 12) + 1;\n}\n\nfunction renderNorthFrame(divisionLabel?: string): TemplateResult {\n\tconst { tl, tr, br, bl, top, right, bottom, left } = NORTH_VERTICES;\n\treturn svg`\n\t\t<rect class=\"line\" x=${tl.x} y=${tl.y} width=${INNER} height=${INNER} stroke-width=\"1.5\" fill=\"none\" />\n\t\t<polygon class=\"line\" points=\"${top.x},${top.y} ${right.x},${right.y} ${bottom.x},${bottom.y} ${left.x},${left.y}\" stroke-width=\"1\" fill=\"none\" />\n\t\t<line class=\"line\" x1=${tl.x} y1=${tl.y} x2=${br.x} y2=${br.y} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${tr.x} y1=${tr.y} x2=${bl.x} y2=${bl.y} stroke-width=\"1\" />\n\t\t${\n\t\t\tdivisionLabel\n\t\t\t\t? svg`<text class=\"centre-label\" x=${CENTRE} y=${CENTRE} text-anchor=\"middle\" dominant-baseline=\"central\">${divisionLabel}</text>`\n\t\t\t\t: nothing\n\t\t}\n\t`;\n}\n\nfunction renderNorthCell(\n\thouseNum: number,\n\trashiNum: number,\n\tsign: string,\n\tplanets: PlacedGraha[],\n\tisLagna: boolean,\n): TemplateResult {\n\tconst c = NORTH_HOUSE_CENTERS[houseNum];\n\tif (!c) return svg``;\n\t// Tight cells (H2/3/5/6/8/9/11/12 corner triangles) clip the rasi number\n\t// when it sits too high above the centroid. Clamp the upward offset based\n\t// on the cell's distance from the chart vertical centre so the label\n\t// always stays comfortably inside its triangle or diamond.\n\tconst rashiOffsetY = Math.min(14, Math.abs(c.y - CENTRE) * 0.45 + 6);\n\tconst ascOffsetY = rashiOffsetY + 12;\n\treturn svg`\n\t\t<g class=${isLagna ? 'cell lagna' : 'cell'}>\n\t\t\t<text class=\"rashi-num\" x=${c.x} y=${c.y - rashiOffsetY} text-anchor=\"middle\" dominant-baseline=\"central\">${rashiNum}</text>\n\t\t\t${\n\t\t\t\tisLagna\n\t\t\t\t\t? svg`<text class=\"lagna-marker\" x=${c.x} y=${c.y - ascOffsetY} text-anchor=\"middle\" dominant-baseline=\"central\">Asc</text>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t${planets.length ? renderPlanetStack(planets, sign, c.x, c.y + 8, 12) : nothing}\n\t\t</g>\n\t`;\n}\n\nfunction renderNorthSvg(vm: KundliViewModel): TemplateResult {\n\tconst lagnaSign = vm.lagnaSign || 'Aries';\n\treturn svg`\n\t\t${renderNorthFrame(vm.divisionLabel)}\n\t\t${Array.from({ length: 12 }, (_, i) => {\n\t\t\tconst houseNum = i + 1;\n\t\t\tconst rashiNum = rashiInHouse(houseNum, lagnaSign);\n\t\t\tconst sign = SIGNS_ORDER[rashiNum - 1] ?? 'Aries';\n\t\t\treturn renderNorthCell(\n\t\t\t\thouseNum,\n\t\t\t\trashiNum,\n\t\t\t\tsign,\n\t\t\t\tvm.placements[sign.toLowerCase()] ?? [],\n\t\t\t\thouseNum === 1,\n\t\t\t);\n\t\t})}\n\t`;\n}\n\n// ---------------------------------------------------------------------------\n// East Indian (Bengali / Maithili): 3x3 underlying grid, 4 edge rectangles +\n// 4 corner cells each split by a diagonal from the outer chart corner to the\n// inner corner of the centre cell. Aries fixed top-centre; signs proceed\n// counter-clockwise. Houses rotate from the Lagna.\n// ---------------------------------------------------------------------------\n\nconst EAST_CELL = INNER / 3; // 120\n\ninterface EastCell {\n\t/** Vertices of the cell polygon, in viewBox units. */\n\tpoints: Array<{ x: number; y: number }>;\n\t/** Visual centroid for label placement. */\n\tcentroid: { x: number; y: number };\n}\n\nfunction eastCells(): Record<string, EastCell> {\n\tconst a = MARGIN; // 20\n\tconst b = MARGIN + EAST_CELL; // 140\n\tconst c = MARGIN + 2 * EAST_CELL; // 260\n\tconst d = VIEW_BOX - MARGIN; // 380\n\tconst aries = [\n\t\t{ x: b, y: a },\n\t\t{ x: c, y: a },\n\t\t{ x: c, y: b },\n\t\t{ x: b, y: b },\n\t];\n\tconst cancer = [\n\t\t{ x: a, y: b },\n\t\t{ x: b, y: b },\n\t\t{ x: b, y: c },\n\t\t{ x: a, y: c },\n\t];\n\tconst libra = [\n\t\t{ x: b, y: c },\n\t\t{ x: c, y: c },\n\t\t{ x: c, y: d },\n\t\t{ x: b, y: d },\n\t];\n\tconst capricorn = [\n\t\t{ x: c, y: b },\n\t\t{ x: d, y: b },\n\t\t{ x: d, y: c },\n\t\t{ x: c, y: c },\n\t];\n\tconst taurus = [\n\t\t{ x: a, y: a },\n\t\t{ x: b, y: a },\n\t\t{ x: b, y: b },\n\t];\n\tconst gemini = [\n\t\t{ x: a, y: a },\n\t\t{ x: b, y: b },\n\t\t{ x: a, y: b },\n\t];\n\tconst leo = [\n\t\t{ x: a, y: c },\n\t\t{ x: b, y: c },\n\t\t{ x: a, y: d },\n\t];\n\tconst virgo = [\n\t\t{ x: b, y: c },\n\t\t{ x: b, y: d },\n\t\t{ x: a, y: d },\n\t];\n\tconst scorpio = [\n\t\t{ x: c, y: c },\n\t\t{ x: c, y: d },\n\t\t{ x: d, y: d },\n\t];\n\tconst sagittarius = [\n\t\t{ x: c, y: c },\n\t\t{ x: d, y: d },\n\t\t{ x: d, y: c },\n\t];\n\tconst aquarius = [\n\t\t{ x: d, y: a },\n\t\t{ x: d, y: b },\n\t\t{ x: c, y: b },\n\t];\n\tconst pisces = [\n\t\t{ x: c, y: a },\n\t\t{ x: d, y: a },\n\t\t{ x: c, y: b },\n\t];\n\tconst polys = {\n\t\tAries: aries,\n\t\tTaurus: taurus,\n\t\tGemini: gemini,\n\t\tCancer: cancer,\n\t\tLeo: leo,\n\t\tVirgo: virgo,\n\t\tLibra: libra,\n\t\tScorpio: scorpio,\n\t\tSagittarius: sagittarius,\n\t\tCapricorn: capricorn,\n\t\tAquarius: aquarius,\n\t\tPisces: pisces,\n\t} as const;\n\tconst out: Record<string, EastCell> = {};\n\tfor (const [sign, points] of Object.entries(polys)) {\n\t\tout[sign] = { points: [...points], centroid: centroidOf(points) };\n\t}\n\treturn out;\n}\n\nconst EAST_CELLS = eastCells();\n\nfunction renderEastFrame(divisionLabel?: string): TemplateResult {\n\tconst a = MARGIN;\n\tconst b = MARGIN + EAST_CELL;\n\tconst c = MARGIN + 2 * EAST_CELL;\n\tconst d = VIEW_BOX - MARGIN;\n\treturn svg`\n\t\t<rect class=\"line\" x=${a} y=${a} width=${INNER} height=${INNER} stroke-width=\"1.5\" fill=\"none\" />\n\t\t<line class=\"line\" x1=${a} y1=${b} x2=${b} y2=${b} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${c} y1=${b} x2=${d} y2=${b} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${a} y1=${c} x2=${b} y2=${c} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${c} y1=${c} x2=${d} y2=${c} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${b} y1=${a} x2=${b} y2=${b} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${b} y1=${c} x2=${b} y2=${d} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${c} y1=${a} x2=${c} y2=${b} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${c} y1=${c} x2=${c} y2=${d} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${a} y1=${a} x2=${b} y2=${b} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${d} y1=${a} x2=${c} y2=${b} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${d} y1=${d} x2=${c} y2=${c} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${a} y1=${d} x2=${b} y2=${c} stroke-width=\"1\" />\n\t\t${\n\t\t\tdivisionLabel\n\t\t\t\t? svg`<text class=\"centre-label\" x=${CENTRE} y=${CENTRE} text-anchor=\"middle\" dominant-baseline=\"central\">${divisionLabel}</text>`\n\t\t\t\t: nothing\n\t\t}\n\t`;\n}\n\nfunction renderEastCell(\n\tsign: string,\n\tplanets: PlacedGraha[],\n\tisLagna: boolean,\n\thouseNum: number,\n): TemplateResult {\n\tconst cell = EAST_CELLS[sign];\n\tif (!cell) return svg``;\n\tconst { centroid: cen, points } = cell;\n\tconst signAbbr = SIGN_ABBR[sign] ?? sign.slice(0, 2);\n\tconst polyPoints = points.map((p) => `${p.x},${p.y}`).join(' ');\n\treturn svg`\n\t\t<g class=${isLagna ? 'cell lagna' : 'cell'}>\n\t\t\t${\n\t\t\t\tisLagna\n\t\t\t\t\t? svg`<polygon class=\"lagna-bg\" points=${polyPoints} />`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t<text class=\"sign-text\" x=${cen.x} y=${cen.y - 16} text-anchor=\"middle\" dominant-baseline=\"central\">${signAbbr}</text>\n\t\t\t${\n\t\t\t\thouseNum > 0\n\t\t\t\t\t? svg`<text class=\"house-num\" x=${cen.x + 18} y=${cen.y - 16} text-anchor=\"start\" dominant-baseline=\"central\">${houseNum}</text>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t${\n\t\t\t\tisLagna\n\t\t\t\t\t? svg`<text class=\"lagna-marker\" x=${cen.x} y=${cen.y - 30} text-anchor=\"middle\" dominant-baseline=\"central\">Asc</text>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t${planets.length ? renderPlanetStack(planets, sign, cen.x, cen.y + 4, 12) : nothing}\n\t\t</g>\n\t`;\n}\n\nfunction renderEastSvg(vm: KundliViewModel): TemplateResult {\n\tconst lagnaKey = vm.lagnaSign.toLowerCase();\n\treturn svg`\n\t\t${renderEastFrame(vm.divisionLabel)}\n\t\t${SIGNS_ORDER.map((sign) =>\n\t\t\trenderEastCell(\n\t\t\t\tsign,\n\t\t\t\tvm.placements[sign.toLowerCase()] ?? [],\n\t\t\t\tsign.toLowerCase() === lagnaKey,\n\t\t\t\thouseNumberInSign(sign, vm.lagnaSign),\n\t\t\t),\n\t\t)}\n\t`;\n}\n\n// ---------------------------------------------------------------------------\n// Public entry point\n// ---------------------------------------------------------------------------\n\n/**\n * Render the kundli body for the requested style. Returns the SVG inner\n * content; the caller wraps it in an `<svg>` element with the canonical\n * viewBox `0 0 400 400` and applies its own theming CSS.\n */\nexport function renderKundliSvg(\n\tvm: KundliViewModel,\n\tstyle: ChartStyle,\n): TemplateResult {\n\tswitch (style) {\n\t\tcase 'north':\n\t\t\treturn renderNorthSvg(vm);\n\t\tcase 'east':\n\t\t\treturn renderEastSvg(vm);\n\t\tdefault:\n\t\t\treturn renderSouthSvg(vm);\n\t}\n}\n\n/**\n * Render a WAI-ARIA-compliant tablist that lets the end user switch between\n * South / North / East kundli styles at runtime. The hosting component owns\n * the `chartStyle` state; this helper renders the buttons and wires the\n * arrow-key navigation plus click handler.\n *\n * @param active - The currently selected style.\n * @param setStyle - Callback the host component uses to update its state.\n */\nexport function renderKundliStyleTablist(\n\tactive: ChartStyle,\n\tsetStyle: (next: ChartStyle) => void,\n): TemplateResult {\n\tconst onKeyDown = (e: KeyboardEvent) => {\n\t\tconst idx = CHART_STYLES.findIndex((s) => s.id === active);\n\t\tif (e.key === 'ArrowRight') {\n\t\t\te.preventDefault();\n\t\t\tconst next = CHART_STYLES[(idx + 1) % CHART_STYLES.length];\n\t\t\tif (next) setStyle(next.id);\n\t\t} else if (e.key === 'ArrowLeft') {\n\t\t\te.preventDefault();\n\t\t\tconst next =\n\t\t\t\tCHART_STYLES[(idx - 1 + CHART_STYLES.length) % CHART_STYLES.length];\n\t\t\tif (next) setStyle(next.id);\n\t\t}\n\t};\n\treturn html`<div\n\t\tclass=\"kundli-tablist\"\n\t\trole=\"tablist\"\n\t\taria-label=\"Kundli style\"\n\t\t@keydown=${onKeyDown}\n\t>\n\t\t${CHART_STYLES.map(\n\t\t\t(s) => html`<button\n\t\t\t\ttype=\"button\"\n\t\t\t\tclass=\"kundli-tab\"\n\t\t\t\trole=\"tab\"\n\t\t\t\tid=\"kundli-tab-${s.id}\"\n\t\t\t\taria-selected=${active === s.id ? 'true' : 'false'}\n\t\t\t\ttabindex=${active === s.id ? '0' : '-1'}\n\t\t\t\t@click=${() => setStyle(s.id)}\n\t\t\t>\n\t\t\t\t${s.label}\n\t\t\t</button>`,\n\t\t)}\n\t</div>`;\n}\n", "/**\n * Symbol constants used across components. Single source of truth so chart\n * wheels, card headers, hexagram displays, and panchang tables stay visually\n * consistent.\n */\n\nexport const PLANET_GLYPH: Record<string, string> = {\n\tSun: '\u2609',\n\tMoon: '\u263D',\n\tMercury: '\u263F',\n\tVenus: '\u2640',\n\tEarth: '\u2641',\n\tMars: '\u2642',\n\tJupiter: '\u2643',\n\tSaturn: '\u2644',\n\tUranus: '\u2645',\n\tNeptune: '\u2646',\n\tPluto: '\u2647',\n\tRahu: '\u260A',\n\tKetu: '\u260B',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n\tNorthNode: '\u260A',\n\tSouthNode: '\u260B',\n\t'North node': '\u260A',\n\t'South node': '\u260B',\n\tChiron: '\u26B7',\n\tLilith: '\u26B8',\n\t'Black moon lilith': '\u26B8',\n};\n\nexport const PLANET_ABBR: Record<string, string> = {\n\tSun: 'Su',\n\tMoon: 'Mo',\n\tMercury: 'Me',\n\tVenus: 'Ve',\n\tMars: 'Ma',\n\tJupiter: 'Ju',\n\tSaturn: 'Sa',\n\tUranus: 'Ur',\n\tNeptune: 'Ne',\n\tPluto: 'Pl',\n\tRahu: 'Ra',\n\tKetu: 'Ke',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n};\n\nexport const SIGN_GLYPH: Record<string, string> = {\n\tAries: '\u2648',\n\tTaurus: '\u2649',\n\tGemini: '\u264A',\n\tCancer: '\u264B',\n\tLeo: '\u264C',\n\tVirgo: '\u264D',\n\tLibra: '\u264E',\n\tScorpio: '\u264F',\n\tSagittarius: '\u2650',\n\tCapricorn: '\u2651',\n\tAquarius: '\u2652',\n\tPisces: '\u2653',\n};\n\nexport const SIGN_ABBR: Record<string, string> = {\n\tAries: 'Ar',\n\tTaurus: 'Ta',\n\tGemini: 'Ge',\n\tCancer: 'Cn',\n\tLeo: 'Le',\n\tVirgo: 'Vi',\n\tLibra: 'Li',\n\tScorpio: 'Sc',\n\tSagittarius: 'Sg',\n\tCapricorn: 'Cp',\n\tAquarius: 'Aq',\n\tPisces: 'Pi',\n};\n\nexport const SIGNS_ORDER = [\n\t'Aries',\n\t'Taurus',\n\t'Gemini',\n\t'Cancer',\n\t'Leo',\n\t'Virgo',\n\t'Libra',\n\t'Scorpio',\n\t'Sagittarius',\n\t'Capricorn',\n\t'Aquarius',\n\t'Pisces',\n] as const;\n\n/**\n * Lowercase rashi keys in canonical zodiac order. Derived from `SIGNS_ORDER`\n * so the two stay in lockstep. The /vedic-astrology/birth-chart response\n * carries planet buckets keyed by these names.\n */\nexport const RASHI_KEYS = SIGNS_ORDER.map((s) =>\n\ts.toLowerCase(),\n) as readonly Lowercase<(typeof SIGNS_ORDER)[number]>[];\n\n/** Aspect symbols. Used by synastry and natal chart aspect tables. */\nexport const ASPECT_SYMBOL: Record<string, string> = {\n\tconjunction: '\u260C',\n\topposition: '\u260D',\n\ttrine: '\u25B3',\n\tsquare: '\u25A1',\n\tsextile: '\u2731',\n\tquincunx: '\u22BB',\n\tsemisextile: '\u22BC',\n};\n\n/** Trigrams used by I Ching hexagrams. Eight trigrams compose 64 hexagrams. */\nexport const TRIGRAM_GLYPH: Record<string, string> = {\n\theaven: '\u2630',\n\tlake: '\u2631',\n\tfire: '\u2632',\n\tthunder: '\u2633',\n\twind: '\u2634',\n\twater: '\u2635',\n\tmountain: '\u2636',\n\tearth: '\u2637',\n\tHeaven: '\u2630',\n\tLake: '\u2631',\n\tFire: '\u2632',\n\tThunder: '\u2633',\n\tWind: '\u2634',\n\tWater: '\u2635',\n\tMountain: '\u2636',\n\tEarth: '\u2637',\n};\n\n/** Moon phase emoji set. Used by moon phase card. */\nexport const MOON_PHASE_EMOJI: Record<string, string> = {\n\t'new moon': '\uD83C\uDF11',\n\t'waxing crescent': '\uD83C\uDF12',\n\t'first quarter': '\uD83C\uDF13',\n\t'waxing gibbous': '\uD83C\uDF14',\n\t'full moon': '\uD83C\uDF15',\n\t'waning gibbous': '\uD83C\uDF16',\n\t'last quarter': '\uD83C\uDF17',\n\t'waning crescent': '\uD83C\uDF18',\n};\n", "/**\n * Math helpers for converting raw ecliptic longitude decimals into the\n * sign / degree / minute / second triplet used across chart components.\n */\n\nimport { SIGNS_ORDER } from '../tokens/index.js';\n\nexport interface SignPosition {\n\tsign: string;\n\tsignIndex: number;\n\tdegree: number;\n\tminute: number;\n\tsecond: number;\n}\n\n/**\n * Wrap longitude into [0, 360) so negative or out-of-range values still\n * resolve to a real sign. Robust to wonky upstream data.\n */\nexport function normalizeLongitude(lon: number): number {\n\tconst wrapped = lon % 360;\n\treturn wrapped < 0 ? wrapped + 360 : wrapped;\n}\n\n/**\n * Convert decimal ecliptic longitude (0-360) into sign/degree/minute/second.\n * Used by every chart wheel and aspect table.\n */\nexport function longitudeToSignPosition(longitude: number): SignPosition {\n\tconst lon = normalizeLongitude(longitude);\n\tconst signIndex = Math.floor(lon / 30) % 12;\n\tconst within = lon % 30;\n\tconst degree = Math.floor(within);\n\tconst minuteFloat = (within - degree) * 60;\n\tconst minute = Math.floor(minuteFloat);\n\tconst second = Math.round((minuteFloat - minute) * 60);\n\treturn {\n\t\tsign: SIGNS_ORDER[signIndex] ?? 'Aries',\n\t\tsignIndex,\n\t\tdegree,\n\t\tminute,\n\t\tsecond,\n\t};\n}\n\n/** Compact display string like \"12\u00B0 Leo 34'\". Used in chart labels. */\nexport function formatSignPosition(longitude: number): string {\n\tconst { sign, degree, minute } = longitudeToSignPosition(longitude);\n\treturn `${degree}\u00B0 ${sign} ${String(minute).padStart(2, '0')}'`;\n}\n\n/**\n * The point diametrically opposite a longitude (e.g. Descendant from\n * Ascendant, IC from MC). Exact derivation, always 180 degrees away.\n */\nexport function oppositePoint(longitude: number): number {\n\treturn normalizeLongitude(longitude + 180);\n}\n\n/**\n * Midpoint of the forward arc from `start` to `end` (both ecliptic\n * longitudes). Handles the 360/0 wrap, so a house spanning 350 to 20 degrees\n * yields a midpoint of 5, not 185. Used to place house numbers between two\n * cusps regardless of how unequal the house is.\n */\nexport function arcMidpoint(start: number, end: number): number {\n\tconst s = normalizeLongitude(start);\n\tlet span = normalizeLongitude(end) - s;\n\tif (span < 0) span += 360;\n\treturn normalizeLongitude(s + span / 2);\n}\n\n/** Polar to cartesian for SVG wheel positioning. Angle in degrees, 0 at 3 o'clock. */\nexport function polarToCartesian(\n\tcx: number,\n\tcy: number,\n\tradius: number,\n\tangleDeg: number,\n): { x: number; y: number } {\n\tconst angleRad = (angleDeg * Math.PI) / 180;\n\treturn {\n\t\tx: cx + radius * Math.cos(angleRad),\n\t\ty: cy + radius * Math.sin(angleRad),\n\t};\n}\n", "/**\n * Shared string helpers used across components. Single source of truth so the\n * same formatting rules apply to every key/label/title that surfaces in the\n * shadow tree.\n *\n * - `capitalize`: title-cases the first character, lowercases the rest. Used\n * when matching API-supplied planet/sign names against the glyph maps in\n * `tokens/index.ts`, which use canonical TitleCase keys.\n * - `humanize`: turns an API key (`birth_date`, `birthDate`, `mahadasha-end`)\n * into a label suitable for display (\"Birth date\", \"Mahadasha end\").\n */\n\nexport function capitalize(s: string): string {\n\tif (!s) return '';\n\treturn s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();\n}\n\nexport function humanize(s: string): string {\n\treturn s\n\t\t.replace(/[_-]+/g, ' ')\n\t\t.replace(/([a-z])([A-Z])/g, '$1 $2')\n\t\t.replace(/^\\w/, (c) => c.toUpperCase());\n}\n", "import { css } from 'lit';\n\n/**\n * Shared CSS for every kundli renderer (`<roxy-vedic-kundli>`,\n * `<roxy-divisional-chart>`, and any future `<roxy-navamsa-chart>`). Centralises\n * the SVG layout (responsive viewBox + aspect ratio), the line/text classes,\n * and the Lagna highlight so the three components stay visually identical.\n *\n * @remarks Font sizes are written in viewBox user units (the chart is 400\u00D7400\n * inside a 1:1 aspect-ratio container), so they scale linearly from a 320px\n * phone surface to a wall projector without raster loss. The Lagna palette\n * tracks `--roxy-accent` so host themes flow through unchanged.\n */\nexport const kundliStyles = css`\n\t.wrap {\n\t\tdisplay: grid;\n\t\tgap: var(--roxy-space-md, 1rem);\n\t}\n\t.header {\n\t\tdisplay: flex;\n\t\tflex-wrap: wrap;\n\t\talign-items: center;\n\t\tjustify-content: space-between;\n\t\tgap: var(--roxy-space-sm, 0.5rem);\n\t}\n\t.title {\n\t\tfont-size: var(--roxy-text-lg, 1.125rem);\n\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\tmargin: 0;\n\t}\n\t.kundli-tablist {\n\t\tdisplay: inline-flex;\n\t\tgap: 2px;\n\t\tborder-bottom: 2px solid var(--roxy-border, #e4e4e7);\n\t}\n\t.kundli-tab {\n\t\tpadding: var(--roxy-space-xs, 0.25rem) var(--roxy-space-md, 1rem);\n\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\tbackground: none;\n\t\tborder: none;\n\t\tborder-bottom: 2px solid transparent;\n\t\tmargin-bottom: -2px;\n\t\tcursor: pointer;\n\t\tcolor: var(--roxy-muted, #71717a);\n\t\tfont-family: inherit;\n\t\ttransition: color var(--roxy-motion-duration, 200ms)\n\t\t\tvar(--roxy-motion-easing, ease);\n\t}\n\t.kundli-tab[aria-selected='true'] {\n\t\tcolor: var(--roxy-accent-fg, #b45309);\n\t\tborder-bottom-color: var(--roxy-accent, #f59e0b);\n\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t}\n\t.kundli-tab:hover:not([aria-selected='true']) {\n\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t}\n\t.kundli-tab:focus-visible {\n\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\toutline-offset: 2px;\n\t\tborder-radius: 4px;\n\t}\n\tsvg {\n\t\tdisplay: block;\n\t\twidth: 100%;\n\t\tmax-width: 560px;\n\t\taspect-ratio: 1 / 1;\n\t\theight: auto;\n\t\tmargin: 0 auto;\n\t}\n\t.line {\n\t\tfill: transparent;\n\t\tstroke: var(--roxy-border, #d4d4d8);\n\t}\n\t.sign-text {\n\t\tfill: var(--roxy-muted, #71717a);\n\t\tfont-size: 11px;\n\t\tfont-weight: 500;\n\t\tfont-family: var(--roxy-font-sans);\n\t\ttext-transform: uppercase;\n\t\tletter-spacing: 0.04em;\n\t}\n\t.rashi-num {\n\t\tfill: var(--roxy-muted, #71717a);\n\t\tfont-size: 12px;\n\t\tfont-weight: 500;\n\t\tfont-family: var(--roxy-font-sans);\n\t}\n\t.house-num {\n\t\tfill: var(--roxy-accent-fg, #b45309);\n\t\tfont-size: 11px;\n\t\tfont-weight: 600;\n\t\tfont-family: var(--roxy-font-sans);\n\t\topacity: 0.85;\n\t}\n\t.planet-text {\n\t\tfill: var(--roxy-fg, #0a0a0a);\n\t\tfont-size: 13px;\n\t\tfont-weight: 600;\n\t\tfont-family: var(--roxy-font-sans);\n\t}\n\t.centre-label {\n\t\tfill: var(--roxy-muted, #71717a);\n\t\tfont-size: 14px;\n\t\tfont-weight: 600;\n\t\tfont-family: var(--roxy-font-sans);\n\t\tletter-spacing: 0.02em;\n\t}\n\t.lagna-marker {\n\t\tfill: var(--roxy-accent-fg, #b45309);\n\t\tfont-size: 10px;\n\t\tfont-weight: 700;\n\t\tfont-family: var(--roxy-font-sans);\n\t\tletter-spacing: 0.08em;\n\t\ttext-transform: uppercase;\n\t}\n\t.lagna-bg {\n\t\tfill: color-mix(in srgb, var(--roxy-accent, #f59e0b) 14%, transparent);\n\t}\n\t.lagna-slash {\n\t\tstroke: var(--roxy-accent, #f59e0b);\n\t\tstroke-linecap: round;\n\t\topacity: 0.7;\n\t}\n`;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["html", "css", "html"]
|
|
7
7
|
}
|
|
@@ -154,6 +154,20 @@ var baseStyles = css`
|
|
|
154
154
|
outline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));
|
|
155
155
|
outline-offset: 2px;
|
|
156
156
|
}
|
|
157
|
+
|
|
158
|
+
/* Force the text-style variant on every Unicode glyph in the component.
|
|
159
|
+
* macOS and iOS substitute coloured emoji glyphs for the planetary and
|
|
160
|
+
* gender Unicode code points (Mars, Venus, Mercury, etc.) when the
|
|
161
|
+
* system colour-emoji font wins font selection. The text-style variant
|
|
162
|
+
* keeps glyphs monochrome so they inherit the surrounding fill colour
|
|
163
|
+
* and match the brand palette consistently across platforms.
|
|
164
|
+
*
|
|
165
|
+
* font-variant-emoji is part of CSS Fonts 4 (Safari 17+, Chrome 134+,
|
|
166
|
+
* Firefox 139+). On older browsers the rule is silently ignored.
|
|
167
|
+
*/
|
|
168
|
+
:host {
|
|
169
|
+
font-variant-emoji: text;
|
|
170
|
+
}
|
|
157
171
|
`;
|
|
158
172
|
|
|
159
173
|
// packages/ui/src/utils/degree.ts
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/components/vedic-planets-table.ts", "../../src/tokens/index.ts", "../../src/utils/base-styles.ts", "../../src/utils/degree.ts", "../../src/utils/string.ts"],
|
|
4
|
-
"sourcesContent": ["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { PLANET_GLYPH, SIGN_GLYPH } from '../tokens/index.js';\nimport type { BirthChartResponse } from '../types/index.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatSignPosition } from '../utils/degree.js';\nimport { capitalize } from '../utils/string.js';\n\n/**\n * Fixed display order: Lagna pinned first as the chart frame, then the nine\n * grahas in classical sequence. Any graha not in this list is appended.\n */\nconst GRAHA_ORDER = [\n\t'Lagna',\n\t'Sun',\n\t'Moon',\n\t'Mars',\n\t'Mercury',\n\t'Jupiter',\n\t'Venus',\n\t'Saturn',\n\t'Rahu',\n\t'Ketu',\n];\n\ntype MetaEntry = BirthChartResponse['meta'][string];\n\n/**\n * Vedic planetary positions table. Renders /vedic-astrology/birth-chart `meta`\n * as the full reference-grade positions grid a practitioner reads alongside\n * the kundli wheel: graha, rashi, exact degree, nakshatra and pada, nakshatra\n * lord, bhava (house), Baladi avastha, and retrograde.\n */\n@customElement('roxy-vedic-planets-table')\nexport class RoxyVedicPlanetsTable extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`\n\t\t\t.wrap {\n\t\t\t\tborder: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t\t\t\tbackground: var(--roxy-bg, #fff);\n\t\t\t\toverflow: auto;\n\t\t\t\tbox-shadow: var(--roxy-shadow-sm);\n\t\t\t}\n\t\t\t.head {\n\t\t\t\tpadding: var(--roxy-space-md, 1rem);\n\t\t\t\tborder-bottom: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t}\n\t\t\t.title {\n\t\t\t\tmargin: 0;\n\t\t\t\tfont-size: var(--roxy-text-lg, 1.125rem);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t}\n\t\t\ttable {\n\t\t\t\twidth: 100%;\n\t\t\t\tborder-collapse: collapse;\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tmin-width: 620px;\n\t\t\t}\n\t\t\tthead {\n\t\t\t\tbackground: color-mix(in srgb, var(--roxy-border, #e4e4e7) 20%, transparent);\n\t\t\t}\n\t\t\tth,\n\t\t\ttd {\n\t\t\t\tpadding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-md, 1rem);\n\t\t\t\ttext-align: left;\n\t\t\t\twhite-space: nowrap;\n\t\t\t}\n\t\t\tth {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\ttext-transform: uppercase;\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\tletter-spacing: 0.04em;\n\t\t\t}\n\t\t\ttbody tr {\n\t\t\t\tborder-top: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t}\n\t\t\ttbody tr.lagna {\n\t\t\t\tbackground: color-mix(in srgb, var(--roxy-accent, #f59e0b) 10%, transparent);\n\t\t\t}\n\t\t\ttd.graha {\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t}\n\t\t\t.glyph {\n\t\t\t\tmargin-right: 0.4em;\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t}\n\t\t\t/* On the tinted Lagna row the muted glyph drops below the WCAG AA\n\t\t\t contrast floor, so use the accent foreground there instead. */\n\t\t\ttbody tr.lagna .glyph {\n\t\t\t\tcolor: var(--roxy-accent-fg, #b45309);\n\t\t\t}\n\t\t\t.retro {\n\t\t\t\tcolor: var(--roxy-warning-fg, #9a3412);\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t}\n\t\t\t.num {\n\t\t\t\tfont-variant-numeric: tabular-nums;\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ attribute: false })\n\tdata: BirthChartResponse | null = null;\n\n\t/** Ordered [name, entry] pairs: GRAHA_ORDER first, then any extras. */\n\tprivate orderedRows(): Array<[string, MetaEntry]> {\n\t\tconst meta = this.data?.meta ?? {};\n\t\tconst seen = new Set<string>();\n\t\tconst rows: Array<[string, MetaEntry]> = [];\n\t\tfor (const name of GRAHA_ORDER) {\n\t\t\tconst entry = meta[name];\n\t\t\tif (entry) {\n\t\t\t\trows.push([name, entry]);\n\t\t\t\tseen.add(name);\n\t\t\t}\n\t\t}\n\t\tfor (const [name, entry] of Object.entries(meta)) {\n\t\t\tif (!seen.has(name)) rows.push([name, entry]);\n\t\t}\n\t\treturn rows;\n\t}\n\n\trender() {\n\t\tif (!this.data?.meta)\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No chart data</div>`;\n\t\tconst rows = this.orderedRows();\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Vedic planetary positions\" tabindex=\"0\">\n\t\t\t<header class=\"head\">\n\t\t\t\t<h2 class=\"title\">Planetary positions</h2>\n\t\t\t</header>\n\t\t\t<table role=\"table\">\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th scope=\"col\">Graha</th>\n\t\t\t\t\t\t<th scope=\"col\">Rashi</th>\n\t\t\t\t\t\t<th scope=\"col\">Degree</th>\n\t\t\t\t\t\t<th scope=\"col\">Nakshatra</th>\n\t\t\t\t\t\t<th scope=\"col\">Pada</th>\n\t\t\t\t\t\t<th scope=\"col\">Nak. lord</th>\n\t\t\t\t\t\t<th scope=\"col\">House</th>\n\t\t\t\t\t\t<th scope=\"col\">Avastha</th>\n\t\t\t\t\t\t<th scope=\"col\">Retro</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t${rows.map(([name, p]) => {\n\t\t\t\t\t\tconst isLagna = (p.graha ?? name) === 'Lagna';\n\t\t\t\t\t\tconst glyph = PLANET_GLYPH[capitalize(p.graha ?? name)] ?? '';\n\t\t\t\t\t\tconst signGlyph = SIGN_GLYPH[capitalize(p.rashi ?? '')] ?? '';\n\t\t\t\t\t\treturn html`<tr class=${isLagna ? 'lagna' : ''}>\n\t\t\t\t\t\t\t<td class=\"graha\">\n\t\t\t\t\t\t\t\t${glyph ? html`<span class=\"glyph\">${glyph}</span>` : nothing}${p.graha ?? name}\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t${signGlyph ? html`<span class=\"glyph\">${signGlyph}</span>` : nothing}${p.rashi ?? ''}\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td class=\"num\">\n\t\t\t\t\t\t\t\t${typeof p.longitude === 'number' ? formatSignPosition(p.longitude) : ''}\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td>${p.nakshatra?.name ?? ''}</td>\n\t\t\t\t\t\t\t<td class=\"num\">${p.nakshatra?.pada ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.nakshatra?.lord ?? ''}</td>\n\t\t\t\t\t\t\t<td class=\"num\">${typeof p.house === 'number' ? p.house : ''}</td>\n\t\t\t\t\t\t\t<td>${p.awastha ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.isRetrograde ? html`<span class=\"retro\">R</span>` : nothing}</td>\n\t\t\t\t\t\t</tr>`;\n\t\t\t\t\t})}\n\t\t\t\t</tbody>\n\t\t\t</table>\n\t\t</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-vedic-planets-table': RoxyVedicPlanetsTable;\n\t}\n}\n", "/**\n * Symbol constants used across components. Single source of truth so chart\n * wheels, card headers, hexagram displays, and panchang tables stay visually\n * consistent.\n */\n\nexport const PLANET_GLYPH: Record<string, string> = {\n\tSun: '\u2609',\n\tMoon: '\u263D',\n\tMercury: '\u263F',\n\tVenus: '\u2640',\n\tEarth: '\u2641',\n\tMars: '\u2642',\n\tJupiter: '\u2643',\n\tSaturn: '\u2644',\n\tUranus: '\u2645',\n\tNeptune: '\u2646',\n\tPluto: '\u2647',\n\tRahu: '\u260A',\n\tKetu: '\u260B',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n\tNorthNode: '\u260A',\n\tSouthNode: '\u260B',\n\t'North node': '\u260A',\n\t'South node': '\u260B',\n\tChiron: '\u26B7',\n\tLilith: '\u26B8',\n\t'Black moon lilith': '\u26B8',\n};\n\nexport const PLANET_ABBR: Record<string, string> = {\n\tSun: 'Su',\n\tMoon: 'Mo',\n\tMercury: 'Me',\n\tVenus: 'Ve',\n\tMars: 'Ma',\n\tJupiter: 'Ju',\n\tSaturn: 'Sa',\n\tUranus: 'Ur',\n\tNeptune: 'Ne',\n\tPluto: 'Pl',\n\tRahu: 'Ra',\n\tKetu: 'Ke',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n};\n\nexport const SIGN_GLYPH: Record<string, string> = {\n\tAries: '\u2648',\n\tTaurus: '\u2649',\n\tGemini: '\u264A',\n\tCancer: '\u264B',\n\tLeo: '\u264C',\n\tVirgo: '\u264D',\n\tLibra: '\u264E',\n\tScorpio: '\u264F',\n\tSagittarius: '\u2650',\n\tCapricorn: '\u2651',\n\tAquarius: '\u2652',\n\tPisces: '\u2653',\n};\n\nexport const SIGN_ABBR: Record<string, string> = {\n\tAries: 'Ar',\n\tTaurus: 'Ta',\n\tGemini: 'Ge',\n\tCancer: 'Cn',\n\tLeo: 'Le',\n\tVirgo: 'Vi',\n\tLibra: 'Li',\n\tScorpio: 'Sc',\n\tSagittarius: 'Sg',\n\tCapricorn: 'Cp',\n\tAquarius: 'Aq',\n\tPisces: 'Pi',\n};\n\nexport const SIGNS_ORDER = [\n\t'Aries',\n\t'Taurus',\n\t'Gemini',\n\t'Cancer',\n\t'Leo',\n\t'Virgo',\n\t'Libra',\n\t'Scorpio',\n\t'Sagittarius',\n\t'Capricorn',\n\t'Aquarius',\n\t'Pisces',\n] as const;\n\n/**\n * Lowercase rashi keys in canonical zodiac order. Derived from `SIGNS_ORDER`\n * so the two stay in lockstep. The /vedic-astrology/birth-chart response\n * carries planet buckets keyed by these names.\n */\nexport const RASHI_KEYS = SIGNS_ORDER.map((s) =>\n\ts.toLowerCase(),\n) as readonly Lowercase<(typeof SIGNS_ORDER)[number]>[];\n\n/** Aspect symbols. Used by synastry and natal chart aspect tables. */\nexport const ASPECT_SYMBOL: Record<string, string> = {\n\tconjunction: '\u260C',\n\topposition: '\u260D',\n\ttrine: '\u25B3',\n\tsquare: '\u25A1',\n\tsextile: '\u2731',\n\tquincunx: '\u22BB',\n\tsemisextile: '\u22BC',\n};\n\n/** Trigrams used by I Ching hexagrams. Eight trigrams compose 64 hexagrams. */\nexport const TRIGRAM_GLYPH: Record<string, string> = {\n\theaven: '\u2630',\n\tlake: '\u2631',\n\tfire: '\u2632',\n\tthunder: '\u2633',\n\twind: '\u2634',\n\twater: '\u2635',\n\tmountain: '\u2636',\n\tearth: '\u2637',\n\tHeaven: '\u2630',\n\tLake: '\u2631',\n\tFire: '\u2632',\n\tThunder: '\u2633',\n\tWind: '\u2634',\n\tWater: '\u2635',\n\tMountain: '\u2636',\n\tEarth: '\u2637',\n};\n\n/** Moon phase emoji set. Used by moon phase card. */\nexport const MOON_PHASE_EMOJI: Record<string, string> = {\n\t'new moon': '\uD83C\uDF11',\n\t'waxing crescent': '\uD83C\uDF12',\n\t'first quarter': '\uD83C\uDF13',\n\t'waxing gibbous': '\uD83C\uDF14',\n\t'full moon': '\uD83C\uDF15',\n\t'waning gibbous': '\uD83C\uDF16',\n\t'last quarter': '\uD83C\uDF17',\n\t'waning crescent': '\uD83C\uDF18',\n};\n", "import { css } from 'lit';\n\n/**\n * Shared host styles every component pulls in. Sets default font, color,\n * container query support, and the entry fade-in.\n */\nexport const baseStyles = css`\n\t:host {\n\t\tdisplay: block;\n\t\tcontainer-type: inline-size;\n\t\tfont-family: var(\n\t\t\t--roxy-font-sans,\n\t\t\tsystem-ui,\n\t\t\t-apple-system,\n\t\t\tBlinkMacSystemFont,\n\t\t\t'Segoe UI',\n\t\t\tRoboto,\n\t\t\tsans-serif\n\t\t);\n\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\tbackground: transparent;\n\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\tline-height: var(--roxy-leading-normal, 1.5);\n\t\tanimation: roxy-fade-in var(--roxy-motion-duration, 200ms)\n\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1)) both;\n\t}\n\n\t*,\n\t*::before,\n\t*::after {\n\t\tbox-sizing: border-box;\n\t}\n\n\t@keyframes roxy-fade-in {\n\t\tfrom {\n\t\t\topacity: 0;\n\t\t\ttransform: translateY(2px);\n\t\t}\n\t\tto {\n\t\t\topacity: 1;\n\t\t\ttransform: translateY(0);\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t:host {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-skeleton {\n\t\tbackground: linear-gradient(\n\t\t\t90deg,\n\t\t\tvar(--roxy-border, #e4e4e7) 0%,\n\t\t\tcolor-mix(in srgb, var(--roxy-border, #e4e4e7) 60%, transparent) 50%,\n\t\t\tvar(--roxy-border, #e4e4e7) 100%\n\t\t);\n\t\tbackground-size: 200% 100%;\n\t\tanimation: roxy-shimmer 1.4s ease-in-out infinite;\n\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t}\n\n\t@keyframes roxy-shimmer {\n\t\t0% {\n\t\t\tbackground-position: 200% 0;\n\t\t}\n\t\t100% {\n\t\t\tbackground-position: -200% 0;\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t.roxy-skeleton {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-empty {\n\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\tcolor: var(--roxy-muted, #71717a);\n\t\ttext-align: center;\n\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t}\n\n\t:host(:focus-within) .roxy-card {\n\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\toutline-offset: 2px;\n\t}\n`;\n", "/**\n * Math helpers for converting raw ecliptic longitude decimals into the\n * sign / degree / minute / second triplet used across chart components.\n */\n\nimport { SIGNS_ORDER } from '../tokens/index.js';\n\nexport interface SignPosition {\n\tsign: string;\n\tsignIndex: number;\n\tdegree: number;\n\tminute: number;\n\tsecond: number;\n}\n\n/**\n * Wrap longitude into [0, 360) so negative or out-of-range values still\n * resolve to a real sign. Robust to wonky upstream data.\n */\nexport function normalizeLongitude(lon: number): number {\n\tconst wrapped = lon % 360;\n\treturn wrapped < 0 ? wrapped + 360 : wrapped;\n}\n\n/**\n * Convert decimal ecliptic longitude (0-360) into sign/degree/minute/second.\n * Used by every chart wheel and aspect table.\n */\nexport function longitudeToSignPosition(longitude: number): SignPosition {\n\tconst lon = normalizeLongitude(longitude);\n\tconst signIndex = Math.floor(lon / 30) % 12;\n\tconst within = lon % 30;\n\tconst degree = Math.floor(within);\n\tconst minuteFloat = (within - degree) * 60;\n\tconst minute = Math.floor(minuteFloat);\n\tconst second = Math.round((minuteFloat - minute) * 60);\n\treturn {\n\t\tsign: SIGNS_ORDER[signIndex] ?? 'Aries',\n\t\tsignIndex,\n\t\tdegree,\n\t\tminute,\n\t\tsecond,\n\t};\n}\n\n/** Compact display string like \"12\u00B0 Leo 34'\". Used in chart labels. */\nexport function formatSignPosition(longitude: number): string {\n\tconst { sign, degree, minute } = longitudeToSignPosition(longitude);\n\treturn `${degree}\u00B0 ${sign} ${String(minute).padStart(2, '0')}'`;\n}\n\n/**\n * The point diametrically opposite a longitude (e.g. Descendant from\n * Ascendant, IC from MC). Exact derivation, always 180 degrees away.\n */\nexport function oppositePoint(longitude: number): number {\n\treturn normalizeLongitude(longitude + 180);\n}\n\n/**\n * Midpoint of the forward arc from `start` to `end` (both ecliptic\n * longitudes). Handles the 360/0 wrap, so a house spanning 350 to 20 degrees\n * yields a midpoint of 5, not 185. Used to place house numbers between two\n * cusps regardless of how unequal the house is.\n */\nexport function arcMidpoint(start: number, end: number): number {\n\tconst s = normalizeLongitude(start);\n\tlet span = normalizeLongitude(end) - s;\n\tif (span < 0) span += 360;\n\treturn normalizeLongitude(s + span / 2);\n}\n\n/** Polar to cartesian for SVG wheel positioning. Angle in degrees, 0 at 3 o'clock. */\nexport function polarToCartesian(\n\tcx: number,\n\tcy: number,\n\tradius: number,\n\tangleDeg: number,\n): { x: number; y: number } {\n\tconst angleRad = (angleDeg * Math.PI) / 180;\n\treturn {\n\t\tx: cx + radius * Math.cos(angleRad),\n\t\ty: cy + radius * Math.sin(angleRad),\n\t};\n}\n", "/**\n * Shared string helpers used across components. Single source of truth so the\n * same formatting rules apply to every key/label/title that surfaces in the\n * shadow tree.\n *\n * - `capitalize`: title-cases the first character, lowercases the rest. Used\n * when matching API-supplied planet/sign names against the glyph maps in\n * `tokens/index.ts`, which use canonical TitleCase keys.\n * - `humanize`: turns an API key (`birth_date`, `birthDate`, `mahadasha-end`)\n * into a label suitable for display (\"Birth date\", \"Mahadasha end\").\n */\n\nexport function capitalize(s: string): string {\n\tif (!s) return '';\n\treturn s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();\n}\n\nexport function humanize(s: string): string {\n\treturn s\n\t\t.replace(/[_-]+/g, ' ')\n\t\t.replace(/([a-z])([A-Z])/g, '$1 $2')\n\t\t.replace(/^\\w/, (c) => c.toUpperCase());\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { PLANET_GLYPH, SIGN_GLYPH } from '../tokens/index.js';\nimport type { BirthChartResponse } from '../types/index.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatSignPosition } from '../utils/degree.js';\nimport { capitalize } from '../utils/string.js';\n\n/**\n * Fixed display order: Lagna pinned first as the chart frame, then the nine\n * grahas in classical sequence. Any graha not in this list is appended.\n */\nconst GRAHA_ORDER = [\n\t'Lagna',\n\t'Sun',\n\t'Moon',\n\t'Mars',\n\t'Mercury',\n\t'Jupiter',\n\t'Venus',\n\t'Saturn',\n\t'Rahu',\n\t'Ketu',\n];\n\ntype MetaEntry = BirthChartResponse['meta'][string];\n\n/**\n * Vedic planetary positions table. Renders /vedic-astrology/birth-chart `meta`\n * as the full reference-grade positions grid a practitioner reads alongside\n * the kundli wheel: graha, rashi, exact degree, nakshatra and pada, nakshatra\n * lord, bhava (house), Baladi avastha, and retrograde.\n */\n@customElement('roxy-vedic-planets-table')\nexport class RoxyVedicPlanetsTable extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`\n\t\t\t.wrap {\n\t\t\t\tborder: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t\t\t\tbackground: var(--roxy-bg, #fff);\n\t\t\t\toverflow: auto;\n\t\t\t\tbox-shadow: var(--roxy-shadow-sm);\n\t\t\t}\n\t\t\t.head {\n\t\t\t\tpadding: var(--roxy-space-md, 1rem);\n\t\t\t\tborder-bottom: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t}\n\t\t\t.title {\n\t\t\t\tmargin: 0;\n\t\t\t\tfont-size: var(--roxy-text-lg, 1.125rem);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t}\n\t\t\ttable {\n\t\t\t\twidth: 100%;\n\t\t\t\tborder-collapse: collapse;\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tmin-width: 620px;\n\t\t\t}\n\t\t\tthead {\n\t\t\t\tbackground: color-mix(in srgb, var(--roxy-border, #e4e4e7) 20%, transparent);\n\t\t\t}\n\t\t\tth,\n\t\t\ttd {\n\t\t\t\tpadding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-md, 1rem);\n\t\t\t\ttext-align: left;\n\t\t\t\twhite-space: nowrap;\n\t\t\t}\n\t\t\tth {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\ttext-transform: uppercase;\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\tletter-spacing: 0.04em;\n\t\t\t}\n\t\t\ttbody tr {\n\t\t\t\tborder-top: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t}\n\t\t\ttbody tr.lagna {\n\t\t\t\tbackground: color-mix(in srgb, var(--roxy-accent, #f59e0b) 10%, transparent);\n\t\t\t}\n\t\t\ttd.graha {\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t}\n\t\t\t.glyph {\n\t\t\t\tmargin-right: 0.4em;\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t}\n\t\t\t/* On the tinted Lagna row the muted glyph drops below the WCAG AA\n\t\t\t contrast floor, so use the accent foreground there instead. */\n\t\t\ttbody tr.lagna .glyph {\n\t\t\t\tcolor: var(--roxy-accent-fg, #b45309);\n\t\t\t}\n\t\t\t.retro {\n\t\t\t\tcolor: var(--roxy-warning-fg, #9a3412);\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t}\n\t\t\t.num {\n\t\t\t\tfont-variant-numeric: tabular-nums;\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ attribute: false })\n\tdata: BirthChartResponse | null = null;\n\n\t/** Ordered [name, entry] pairs: GRAHA_ORDER first, then any extras. */\n\tprivate orderedRows(): Array<[string, MetaEntry]> {\n\t\tconst meta = this.data?.meta ?? {};\n\t\tconst seen = new Set<string>();\n\t\tconst rows: Array<[string, MetaEntry]> = [];\n\t\tfor (const name of GRAHA_ORDER) {\n\t\t\tconst entry = meta[name];\n\t\t\tif (entry) {\n\t\t\t\trows.push([name, entry]);\n\t\t\t\tseen.add(name);\n\t\t\t}\n\t\t}\n\t\tfor (const [name, entry] of Object.entries(meta)) {\n\t\t\tif (!seen.has(name)) rows.push([name, entry]);\n\t\t}\n\t\treturn rows;\n\t}\n\n\trender() {\n\t\tif (!this.data?.meta)\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No chart data</div>`;\n\t\tconst rows = this.orderedRows();\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Vedic planetary positions\" tabindex=\"0\">\n\t\t\t<header class=\"head\">\n\t\t\t\t<h2 class=\"title\">Planetary positions</h2>\n\t\t\t</header>\n\t\t\t<table role=\"table\">\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th scope=\"col\">Graha</th>\n\t\t\t\t\t\t<th scope=\"col\">Rashi</th>\n\t\t\t\t\t\t<th scope=\"col\">Degree</th>\n\t\t\t\t\t\t<th scope=\"col\">Nakshatra</th>\n\t\t\t\t\t\t<th scope=\"col\">Pada</th>\n\t\t\t\t\t\t<th scope=\"col\">Nak. lord</th>\n\t\t\t\t\t\t<th scope=\"col\">House</th>\n\t\t\t\t\t\t<th scope=\"col\">Avastha</th>\n\t\t\t\t\t\t<th scope=\"col\">Retro</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t${rows.map(([name, p]) => {\n\t\t\t\t\t\tconst isLagna = (p.graha ?? name) === 'Lagna';\n\t\t\t\t\t\tconst glyph = PLANET_GLYPH[capitalize(p.graha ?? name)] ?? '';\n\t\t\t\t\t\tconst signGlyph = SIGN_GLYPH[capitalize(p.rashi ?? '')] ?? '';\n\t\t\t\t\t\treturn html`<tr class=${isLagna ? 'lagna' : ''}>\n\t\t\t\t\t\t\t<td class=\"graha\">\n\t\t\t\t\t\t\t\t${glyph ? html`<span class=\"glyph\">${glyph}</span>` : nothing}${p.graha ?? name}\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t${signGlyph ? html`<span class=\"glyph\">${signGlyph}</span>` : nothing}${p.rashi ?? ''}\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td class=\"num\">\n\t\t\t\t\t\t\t\t${typeof p.longitude === 'number' ? formatSignPosition(p.longitude) : ''}\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td>${p.nakshatra?.name ?? ''}</td>\n\t\t\t\t\t\t\t<td class=\"num\">${p.nakshatra?.pada ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.nakshatra?.lord ?? ''}</td>\n\t\t\t\t\t\t\t<td class=\"num\">${typeof p.house === 'number' ? p.house : ''}</td>\n\t\t\t\t\t\t\t<td>${p.awastha ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.isRetrograde ? html`<span class=\"retro\">R</span>` : nothing}</td>\n\t\t\t\t\t\t</tr>`;\n\t\t\t\t\t})}\n\t\t\t\t</tbody>\n\t\t\t</table>\n\t\t</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-vedic-planets-table': RoxyVedicPlanetsTable;\n\t}\n}\n", "/**\n * Symbol constants used across components. Single source of truth so chart\n * wheels, card headers, hexagram displays, and panchang tables stay visually\n * consistent.\n */\n\nexport const PLANET_GLYPH: Record<string, string> = {\n\tSun: '\u2609',\n\tMoon: '\u263D',\n\tMercury: '\u263F',\n\tVenus: '\u2640',\n\tEarth: '\u2641',\n\tMars: '\u2642',\n\tJupiter: '\u2643',\n\tSaturn: '\u2644',\n\tUranus: '\u2645',\n\tNeptune: '\u2646',\n\tPluto: '\u2647',\n\tRahu: '\u260A',\n\tKetu: '\u260B',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n\tNorthNode: '\u260A',\n\tSouthNode: '\u260B',\n\t'North node': '\u260A',\n\t'South node': '\u260B',\n\tChiron: '\u26B7',\n\tLilith: '\u26B8',\n\t'Black moon lilith': '\u26B8',\n};\n\nexport const PLANET_ABBR: Record<string, string> = {\n\tSun: 'Su',\n\tMoon: 'Mo',\n\tMercury: 'Me',\n\tVenus: 'Ve',\n\tMars: 'Ma',\n\tJupiter: 'Ju',\n\tSaturn: 'Sa',\n\tUranus: 'Ur',\n\tNeptune: 'Ne',\n\tPluto: 'Pl',\n\tRahu: 'Ra',\n\tKetu: 'Ke',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n};\n\nexport const SIGN_GLYPH: Record<string, string> = {\n\tAries: '\u2648',\n\tTaurus: '\u2649',\n\tGemini: '\u264A',\n\tCancer: '\u264B',\n\tLeo: '\u264C',\n\tVirgo: '\u264D',\n\tLibra: '\u264E',\n\tScorpio: '\u264F',\n\tSagittarius: '\u2650',\n\tCapricorn: '\u2651',\n\tAquarius: '\u2652',\n\tPisces: '\u2653',\n};\n\nexport const SIGN_ABBR: Record<string, string> = {\n\tAries: 'Ar',\n\tTaurus: 'Ta',\n\tGemini: 'Ge',\n\tCancer: 'Cn',\n\tLeo: 'Le',\n\tVirgo: 'Vi',\n\tLibra: 'Li',\n\tScorpio: 'Sc',\n\tSagittarius: 'Sg',\n\tCapricorn: 'Cp',\n\tAquarius: 'Aq',\n\tPisces: 'Pi',\n};\n\nexport const SIGNS_ORDER = [\n\t'Aries',\n\t'Taurus',\n\t'Gemini',\n\t'Cancer',\n\t'Leo',\n\t'Virgo',\n\t'Libra',\n\t'Scorpio',\n\t'Sagittarius',\n\t'Capricorn',\n\t'Aquarius',\n\t'Pisces',\n] as const;\n\n/**\n * Lowercase rashi keys in canonical zodiac order. Derived from `SIGNS_ORDER`\n * so the two stay in lockstep. The /vedic-astrology/birth-chart response\n * carries planet buckets keyed by these names.\n */\nexport const RASHI_KEYS = SIGNS_ORDER.map((s) =>\n\ts.toLowerCase(),\n) as readonly Lowercase<(typeof SIGNS_ORDER)[number]>[];\n\n/** Aspect symbols. Used by synastry and natal chart aspect tables. */\nexport const ASPECT_SYMBOL: Record<string, string> = {\n\tconjunction: '\u260C',\n\topposition: '\u260D',\n\ttrine: '\u25B3',\n\tsquare: '\u25A1',\n\tsextile: '\u2731',\n\tquincunx: '\u22BB',\n\tsemisextile: '\u22BC',\n};\n\n/** Trigrams used by I Ching hexagrams. Eight trigrams compose 64 hexagrams. */\nexport const TRIGRAM_GLYPH: Record<string, string> = {\n\theaven: '\u2630',\n\tlake: '\u2631',\n\tfire: '\u2632',\n\tthunder: '\u2633',\n\twind: '\u2634',\n\twater: '\u2635',\n\tmountain: '\u2636',\n\tearth: '\u2637',\n\tHeaven: '\u2630',\n\tLake: '\u2631',\n\tFire: '\u2632',\n\tThunder: '\u2633',\n\tWind: '\u2634',\n\tWater: '\u2635',\n\tMountain: '\u2636',\n\tEarth: '\u2637',\n};\n\n/** Moon phase emoji set. Used by moon phase card. */\nexport const MOON_PHASE_EMOJI: Record<string, string> = {\n\t'new moon': '\uD83C\uDF11',\n\t'waxing crescent': '\uD83C\uDF12',\n\t'first quarter': '\uD83C\uDF13',\n\t'waxing gibbous': '\uD83C\uDF14',\n\t'full moon': '\uD83C\uDF15',\n\t'waning gibbous': '\uD83C\uDF16',\n\t'last quarter': '\uD83C\uDF17',\n\t'waning crescent': '\uD83C\uDF18',\n};\n", "import { css } from 'lit';\n\n/**\n * Shared host styles every component pulls in. Sets default font, color,\n * container query support, and the entry fade-in.\n */\nexport const baseStyles = css`\n\t:host {\n\t\tdisplay: block;\n\t\tcontainer-type: inline-size;\n\t\tfont-family: var(\n\t\t\t--roxy-font-sans,\n\t\t\tsystem-ui,\n\t\t\t-apple-system,\n\t\t\tBlinkMacSystemFont,\n\t\t\t'Segoe UI',\n\t\t\tRoboto,\n\t\t\tsans-serif\n\t\t);\n\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\tbackground: transparent;\n\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\tline-height: var(--roxy-leading-normal, 1.5);\n\t\tanimation: roxy-fade-in var(--roxy-motion-duration, 200ms)\n\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1)) both;\n\t}\n\n\t*,\n\t*::before,\n\t*::after {\n\t\tbox-sizing: border-box;\n\t}\n\n\t@keyframes roxy-fade-in {\n\t\tfrom {\n\t\t\topacity: 0;\n\t\t\ttransform: translateY(2px);\n\t\t}\n\t\tto {\n\t\t\topacity: 1;\n\t\t\ttransform: translateY(0);\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t:host {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-skeleton {\n\t\tbackground: linear-gradient(\n\t\t\t90deg,\n\t\t\tvar(--roxy-border, #e4e4e7) 0%,\n\t\t\tcolor-mix(in srgb, var(--roxy-border, #e4e4e7) 60%, transparent) 50%,\n\t\t\tvar(--roxy-border, #e4e4e7) 100%\n\t\t);\n\t\tbackground-size: 200% 100%;\n\t\tanimation: roxy-shimmer 1.4s ease-in-out infinite;\n\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t}\n\n\t@keyframes roxy-shimmer {\n\t\t0% {\n\t\t\tbackground-position: 200% 0;\n\t\t}\n\t\t100% {\n\t\t\tbackground-position: -200% 0;\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t.roxy-skeleton {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-empty {\n\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\tcolor: var(--roxy-muted, #71717a);\n\t\ttext-align: center;\n\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t}\n\n\t:host(:focus-within) .roxy-card {\n\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\toutline-offset: 2px;\n\t}\n\n\t/* Force the text-style variant on every Unicode glyph in the component.\n\t * macOS and iOS substitute coloured emoji glyphs for the planetary and\n\t * gender Unicode code points (Mars, Venus, Mercury, etc.) when the\n\t * system colour-emoji font wins font selection. The text-style variant\n\t * keeps glyphs monochrome so they inherit the surrounding fill colour\n\t * and match the brand palette consistently across platforms.\n\t *\n\t * font-variant-emoji is part of CSS Fonts 4 (Safari 17+, Chrome 134+,\n\t * Firefox 139+). On older browsers the rule is silently ignored.\n\t */\n\t:host {\n\t\tfont-variant-emoji: text;\n\t}\n`;\n", "/**\n * Math helpers for converting raw ecliptic longitude decimals into the\n * sign / degree / minute / second triplet used across chart components.\n */\n\nimport { SIGNS_ORDER } from '../tokens/index.js';\n\nexport interface SignPosition {\n\tsign: string;\n\tsignIndex: number;\n\tdegree: number;\n\tminute: number;\n\tsecond: number;\n}\n\n/**\n * Wrap longitude into [0, 360) so negative or out-of-range values still\n * resolve to a real sign. Robust to wonky upstream data.\n */\nexport function normalizeLongitude(lon: number): number {\n\tconst wrapped = lon % 360;\n\treturn wrapped < 0 ? wrapped + 360 : wrapped;\n}\n\n/**\n * Convert decimal ecliptic longitude (0-360) into sign/degree/minute/second.\n * Used by every chart wheel and aspect table.\n */\nexport function longitudeToSignPosition(longitude: number): SignPosition {\n\tconst lon = normalizeLongitude(longitude);\n\tconst signIndex = Math.floor(lon / 30) % 12;\n\tconst within = lon % 30;\n\tconst degree = Math.floor(within);\n\tconst minuteFloat = (within - degree) * 60;\n\tconst minute = Math.floor(minuteFloat);\n\tconst second = Math.round((minuteFloat - minute) * 60);\n\treturn {\n\t\tsign: SIGNS_ORDER[signIndex] ?? 'Aries',\n\t\tsignIndex,\n\t\tdegree,\n\t\tminute,\n\t\tsecond,\n\t};\n}\n\n/** Compact display string like \"12\u00B0 Leo 34'\". Used in chart labels. */\nexport function formatSignPosition(longitude: number): string {\n\tconst { sign, degree, minute } = longitudeToSignPosition(longitude);\n\treturn `${degree}\u00B0 ${sign} ${String(minute).padStart(2, '0')}'`;\n}\n\n/**\n * The point diametrically opposite a longitude (e.g. Descendant from\n * Ascendant, IC from MC). Exact derivation, always 180 degrees away.\n */\nexport function oppositePoint(longitude: number): number {\n\treturn normalizeLongitude(longitude + 180);\n}\n\n/**\n * Midpoint of the forward arc from `start` to `end` (both ecliptic\n * longitudes). Handles the 360/0 wrap, so a house spanning 350 to 20 degrees\n * yields a midpoint of 5, not 185. Used to place house numbers between two\n * cusps regardless of how unequal the house is.\n */\nexport function arcMidpoint(start: number, end: number): number {\n\tconst s = normalizeLongitude(start);\n\tlet span = normalizeLongitude(end) - s;\n\tif (span < 0) span += 360;\n\treturn normalizeLongitude(s + span / 2);\n}\n\n/** Polar to cartesian for SVG wheel positioning. Angle in degrees, 0 at 3 o'clock. */\nexport function polarToCartesian(\n\tcx: number,\n\tcy: number,\n\tradius: number,\n\tangleDeg: number,\n): { x: number; y: number } {\n\tconst angleRad = (angleDeg * Math.PI) / 180;\n\treturn {\n\t\tx: cx + radius * Math.cos(angleRad),\n\t\ty: cy + radius * Math.sin(angleRad),\n\t};\n}\n", "/**\n * Shared string helpers used across components. Single source of truth so the\n * same formatting rules apply to every key/label/title that surfaces in the\n * shadow tree.\n *\n * - `capitalize`: title-cases the first character, lowercases the rest. Used\n * when matching API-supplied planet/sign names against the glyph maps in\n * `tokens/index.ts`, which use canonical TitleCase keys.\n * - `humanize`: turns an API key (`birth_date`, `birthDate`, `mahadasha-end`)\n * into a label suitable for display (\"Birth date\", \"Mahadasha end\").\n */\n\nexport function capitalize(s: string): string {\n\tif (!s) return '';\n\treturn s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();\n}\n\nexport function humanize(s: string): string {\n\treturn s\n\t\t.replace(/[_-]+/g, ' ')\n\t\t.replace(/([a-z])([A-Z])/g, '$1 $2')\n\t\t.replace(/^\\w/, (c) => c.toUpperCase());\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["css", "css"]
|
|
7
7
|
}
|
|
@@ -154,6 +154,20 @@ var baseStyles = css`
|
|
|
154
154
|
outline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));
|
|
155
155
|
outline-offset: 2px;
|
|
156
156
|
}
|
|
157
|
+
|
|
158
|
+
/* Force the text-style variant on every Unicode glyph in the component.
|
|
159
|
+
* macOS and iOS substitute coloured emoji glyphs for the planetary and
|
|
160
|
+
* gender Unicode code points (Mars, Venus, Mercury, etc.) when the
|
|
161
|
+
* system colour-emoji font wins font selection. The text-style variant
|
|
162
|
+
* keeps glyphs monochrome so they inherit the surrounding fill colour
|
|
163
|
+
* and match the brand palette consistently across platforms.
|
|
164
|
+
*
|
|
165
|
+
* font-variant-emoji is part of CSS Fonts 4 (Safari 17+, Chrome 134+,
|
|
166
|
+
* Firefox 139+). On older browsers the rule is silently ignored.
|
|
167
|
+
*/
|
|
168
|
+
:host {
|
|
169
|
+
font-variant-emoji: text;
|
|
170
|
+
}
|
|
157
171
|
`;
|
|
158
172
|
|
|
159
173
|
// packages/ui/src/utils/degree.ts
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/components/western-planets-table.ts", "../../src/tokens/index.ts", "../../src/utils/base-styles.ts", "../../src/utils/degree.ts", "../../src/utils/format.ts", "../../src/utils/string.ts"],
|
|
4
|
-
"sourcesContent": ["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { PLANET_GLYPH, SIGN_GLYPH } from '../tokens/index.js';\nimport type { NatalChartResponse } from '../types/index.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatSignPosition } from '../utils/degree.js';\nimport { formatNumber } from '../utils/format.js';\nimport { capitalize } from '../utils/string.js';\n\n/** A body or point row, normalized so planets and the four angles share a table. */\ninterface BodyRow {\n\tname: string;\n\tsign?: string;\n\tlongitude?: number;\n\thouse?: number;\n\tspeed?: number;\n\tisRetrograde?: boolean;\n\t/** True for the chart angles (ASC, MC, Part of Fortune, Vertex). */\n\tisPoint?: boolean;\n}\n\n/**\n * Western planetary positions table. Renders a /astrology/natal-chart response\n * as the reference-grade positions grid astrologers read alongside the wheel:\n * every body with its sign, exact degree, house, and daily motion, followed by\n * the four chart points (Ascendant, Midheaven, Part of Fortune, Vertex).\n */\n@customElement('roxy-western-planets-table')\nexport class RoxyWesternPlanetsTable extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`\n\t\t\t.wrap {\n\t\t\t\tborder: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t\t\t\tbackground: var(--roxy-bg, #fff);\n\t\t\t\toverflow: auto;\n\t\t\t\tbox-shadow: var(--roxy-shadow-sm);\n\t\t\t}\n\t\t\t.head {\n\t\t\t\tpadding: var(--roxy-space-md, 1rem);\n\t\t\t\tborder-bottom: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t}\n\t\t\t.title {\n\t\t\t\tmargin: 0;\n\t\t\t\tfont-size: var(--roxy-text-lg, 1.125rem);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t}\n\t\t\ttable {\n\t\t\t\twidth: 100%;\n\t\t\t\tborder-collapse: collapse;\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tmin-width: 460px;\n\t\t\t}\n\t\t\tthead {\n\t\t\t\tbackground: color-mix(in srgb, var(--roxy-border, #e4e4e7) 20%, transparent);\n\t\t\t}\n\t\t\tth,\n\t\t\ttd {\n\t\t\t\tpadding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-md, 1rem);\n\t\t\t\ttext-align: left;\n\t\t\t\twhite-space: nowrap;\n\t\t\t}\n\t\t\tth {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\ttext-transform: uppercase;\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\tletter-spacing: 0.04em;\n\t\t\t}\n\t\t\ttbody tr {\n\t\t\t\tborder-top: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t}\n\t\t\ttbody tr.point {\n\t\t\t\tbackground: color-mix(in srgb, var(--roxy-accent, #f59e0b) 8%, transparent);\n\t\t\t}\n\t\t\ttd.body {\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t}\n\t\t\t.glyph {\n\t\t\t\tmargin-right: 0.4em;\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t}\n\t\t\t.retro {\n\t\t\t\tcolor: var(--roxy-danger, #dc2626);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t}\n\t\t\t.num {\n\t\t\t\tfont-variant-numeric: tabular-nums;\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ attribute: false })\n\tdata: NatalChartResponse | null = null;\n\n\t/** Build the ordered row list: the planets array, then the four chart points. */\n\tprivate rows(): BodyRow[] {\n\t\tconst d = this.data;\n\t\tif (!d) return [];\n\t\tconst rows: BodyRow[] = (d.planets ?? []).map((p) => ({\n\t\t\tname: p.name,\n\t\t\tsign: p.sign,\n\t\t\tlongitude: p.longitude,\n\t\t\thouse: p.house,\n\t\t\tspeed: p.speed,\n\t\t\tisRetrograde: p.isRetrograde,\n\t\t}));\n\t\tfor (const [name, point] of [\n\t\t\t['Ascendant', d.ascendant],\n\t\t\t['Midheaven', d.midheaven],\n\t\t\t['Part of Fortune', d.partOfFortune],\n\t\t\t['Vertex', d.vertex],\n\t\t] as const) {\n\t\t\tif (point) {\n\t\t\t\trows.push({\n\t\t\t\t\tname,\n\t\t\t\t\tsign: point.sign,\n\t\t\t\t\tlongitude: point.longitude,\n\t\t\t\t\tisPoint: true,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn rows;\n\t}\n\n\trender() {\n\t\tif (!this.data?.planets)\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No chart data</div>`;\n\t\tconst rows = this.rows();\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Western planetary positions\" tabindex=\"0\">\n\t\t\t<header class=\"head\">\n\t\t\t\t<h2 class=\"title\">Planetary positions</h2>\n\t\t\t</header>\n\t\t\t<table role=\"table\">\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th scope=\"col\">Body</th>\n\t\t\t\t\t\t<th scope=\"col\">Sign</th>\n\t\t\t\t\t\t<th scope=\"col\">Degree</th>\n\t\t\t\t\t\t<th scope=\"col\">House</th>\n\t\t\t\t\t\t<th scope=\"col\">Motion</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t${rows.map((r) => {\n\t\t\t\t\t\tconst glyph = PLANET_GLYPH[capitalize(r.name)] ?? '';\n\t\t\t\t\t\tconst signGlyph = SIGN_GLYPH[capitalize(r.sign ?? '')] ?? '';\n\t\t\t\t\t\tconst speed =\n\t\t\t\t\t\t\ttypeof r.speed === 'number' ? formatNumber(r.speed, 3) : '';\n\t\t\t\t\t\treturn html`<tr class=${r.isPoint ? 'point' : ''}>\n\t\t\t\t\t\t\t<td class=\"body\">\n\t\t\t\t\t\t\t\t${glyph ? html`<span class=\"glyph\">${glyph}</span>` : nothing}${r.name}\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t${signGlyph ? html`<span class=\"glyph\">${signGlyph}</span>` : nothing}${r.sign ?? ''}\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td class=\"num\">\n\t\t\t\t\t\t\t\t${typeof r.longitude === 'number' ? formatSignPosition(r.longitude) : ''}\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td class=\"num\">${typeof r.house === 'number' ? r.house : ''}</td>\n\t\t\t\t\t\t\t<td class=\"num\">\n\t\t\t\t\t\t\t\t${speed ? html`${speed}\u00B0/day` : nothing}\n\t\t\t\t\t\t\t\t${r.isRetrograde ? html`<span class=\"retro\"> \u211E</span>` : nothing}\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t</tr>`;\n\t\t\t\t\t})}\n\t\t\t\t</tbody>\n\t\t\t</table>\n\t\t</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-western-planets-table': RoxyWesternPlanetsTable;\n\t}\n}\n", "/**\n * Symbol constants used across components. Single source of truth so chart\n * wheels, card headers, hexagram displays, and panchang tables stay visually\n * consistent.\n */\n\nexport const PLANET_GLYPH: Record<string, string> = {\n\tSun: '\u2609',\n\tMoon: '\u263D',\n\tMercury: '\u263F',\n\tVenus: '\u2640',\n\tEarth: '\u2641',\n\tMars: '\u2642',\n\tJupiter: '\u2643',\n\tSaturn: '\u2644',\n\tUranus: '\u2645',\n\tNeptune: '\u2646',\n\tPluto: '\u2647',\n\tRahu: '\u260A',\n\tKetu: '\u260B',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n\tNorthNode: '\u260A',\n\tSouthNode: '\u260B',\n\t'North node': '\u260A',\n\t'South node': '\u260B',\n\tChiron: '\u26B7',\n\tLilith: '\u26B8',\n\t'Black moon lilith': '\u26B8',\n};\n\nexport const PLANET_ABBR: Record<string, string> = {\n\tSun: 'Su',\n\tMoon: 'Mo',\n\tMercury: 'Me',\n\tVenus: 'Ve',\n\tMars: 'Ma',\n\tJupiter: 'Ju',\n\tSaturn: 'Sa',\n\tUranus: 'Ur',\n\tNeptune: 'Ne',\n\tPluto: 'Pl',\n\tRahu: 'Ra',\n\tKetu: 'Ke',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n};\n\nexport const SIGN_GLYPH: Record<string, string> = {\n\tAries: '\u2648',\n\tTaurus: '\u2649',\n\tGemini: '\u264A',\n\tCancer: '\u264B',\n\tLeo: '\u264C',\n\tVirgo: '\u264D',\n\tLibra: '\u264E',\n\tScorpio: '\u264F',\n\tSagittarius: '\u2650',\n\tCapricorn: '\u2651',\n\tAquarius: '\u2652',\n\tPisces: '\u2653',\n};\n\nexport const SIGN_ABBR: Record<string, string> = {\n\tAries: 'Ar',\n\tTaurus: 'Ta',\n\tGemini: 'Ge',\n\tCancer: 'Cn',\n\tLeo: 'Le',\n\tVirgo: 'Vi',\n\tLibra: 'Li',\n\tScorpio: 'Sc',\n\tSagittarius: 'Sg',\n\tCapricorn: 'Cp',\n\tAquarius: 'Aq',\n\tPisces: 'Pi',\n};\n\nexport const SIGNS_ORDER = [\n\t'Aries',\n\t'Taurus',\n\t'Gemini',\n\t'Cancer',\n\t'Leo',\n\t'Virgo',\n\t'Libra',\n\t'Scorpio',\n\t'Sagittarius',\n\t'Capricorn',\n\t'Aquarius',\n\t'Pisces',\n] as const;\n\n/**\n * Lowercase rashi keys in canonical zodiac order. Derived from `SIGNS_ORDER`\n * so the two stay in lockstep. The /vedic-astrology/birth-chart response\n * carries planet buckets keyed by these names.\n */\nexport const RASHI_KEYS = SIGNS_ORDER.map((s) =>\n\ts.toLowerCase(),\n) as readonly Lowercase<(typeof SIGNS_ORDER)[number]>[];\n\n/** Aspect symbols. Used by synastry and natal chart aspect tables. */\nexport const ASPECT_SYMBOL: Record<string, string> = {\n\tconjunction: '\u260C',\n\topposition: '\u260D',\n\ttrine: '\u25B3',\n\tsquare: '\u25A1',\n\tsextile: '\u2731',\n\tquincunx: '\u22BB',\n\tsemisextile: '\u22BC',\n};\n\n/** Trigrams used by I Ching hexagrams. Eight trigrams compose 64 hexagrams. */\nexport const TRIGRAM_GLYPH: Record<string, string> = {\n\theaven: '\u2630',\n\tlake: '\u2631',\n\tfire: '\u2632',\n\tthunder: '\u2633',\n\twind: '\u2634',\n\twater: '\u2635',\n\tmountain: '\u2636',\n\tearth: '\u2637',\n\tHeaven: '\u2630',\n\tLake: '\u2631',\n\tFire: '\u2632',\n\tThunder: '\u2633',\n\tWind: '\u2634',\n\tWater: '\u2635',\n\tMountain: '\u2636',\n\tEarth: '\u2637',\n};\n\n/** Moon phase emoji set. Used by moon phase card. */\nexport const MOON_PHASE_EMOJI: Record<string, string> = {\n\t'new moon': '\uD83C\uDF11',\n\t'waxing crescent': '\uD83C\uDF12',\n\t'first quarter': '\uD83C\uDF13',\n\t'waxing gibbous': '\uD83C\uDF14',\n\t'full moon': '\uD83C\uDF15',\n\t'waning gibbous': '\uD83C\uDF16',\n\t'last quarter': '\uD83C\uDF17',\n\t'waning crescent': '\uD83C\uDF18',\n};\n", "import { css } from 'lit';\n\n/**\n * Shared host styles every component pulls in. Sets default font, color,\n * container query support, and the entry fade-in.\n */\nexport const baseStyles = css`\n\t:host {\n\t\tdisplay: block;\n\t\tcontainer-type: inline-size;\n\t\tfont-family: var(\n\t\t\t--roxy-font-sans,\n\t\t\tsystem-ui,\n\t\t\t-apple-system,\n\t\t\tBlinkMacSystemFont,\n\t\t\t'Segoe UI',\n\t\t\tRoboto,\n\t\t\tsans-serif\n\t\t);\n\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\tbackground: transparent;\n\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\tline-height: var(--roxy-leading-normal, 1.5);\n\t\tanimation: roxy-fade-in var(--roxy-motion-duration, 200ms)\n\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1)) both;\n\t}\n\n\t*,\n\t*::before,\n\t*::after {\n\t\tbox-sizing: border-box;\n\t}\n\n\t@keyframes roxy-fade-in {\n\t\tfrom {\n\t\t\topacity: 0;\n\t\t\ttransform: translateY(2px);\n\t\t}\n\t\tto {\n\t\t\topacity: 1;\n\t\t\ttransform: translateY(0);\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t:host {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-skeleton {\n\t\tbackground: linear-gradient(\n\t\t\t90deg,\n\t\t\tvar(--roxy-border, #e4e4e7) 0%,\n\t\t\tcolor-mix(in srgb, var(--roxy-border, #e4e4e7) 60%, transparent) 50%,\n\t\t\tvar(--roxy-border, #e4e4e7) 100%\n\t\t);\n\t\tbackground-size: 200% 100%;\n\t\tanimation: roxy-shimmer 1.4s ease-in-out infinite;\n\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t}\n\n\t@keyframes roxy-shimmer {\n\t\t0% {\n\t\t\tbackground-position: 200% 0;\n\t\t}\n\t\t100% {\n\t\t\tbackground-position: -200% 0;\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t.roxy-skeleton {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-empty {\n\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\tcolor: var(--roxy-muted, #71717a);\n\t\ttext-align: center;\n\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t}\n\n\t:host(:focus-within) .roxy-card {\n\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\toutline-offset: 2px;\n\t}\n`;\n", "/**\n * Math helpers for converting raw ecliptic longitude decimals into the\n * sign / degree / minute / second triplet used across chart components.\n */\n\nimport { SIGNS_ORDER } from '../tokens/index.js';\n\nexport interface SignPosition {\n\tsign: string;\n\tsignIndex: number;\n\tdegree: number;\n\tminute: number;\n\tsecond: number;\n}\n\n/**\n * Wrap longitude into [0, 360) so negative or out-of-range values still\n * resolve to a real sign. Robust to wonky upstream data.\n */\nexport function normalizeLongitude(lon: number): number {\n\tconst wrapped = lon % 360;\n\treturn wrapped < 0 ? wrapped + 360 : wrapped;\n}\n\n/**\n * Convert decimal ecliptic longitude (0-360) into sign/degree/minute/second.\n * Used by every chart wheel and aspect table.\n */\nexport function longitudeToSignPosition(longitude: number): SignPosition {\n\tconst lon = normalizeLongitude(longitude);\n\tconst signIndex = Math.floor(lon / 30) % 12;\n\tconst within = lon % 30;\n\tconst degree = Math.floor(within);\n\tconst minuteFloat = (within - degree) * 60;\n\tconst minute = Math.floor(minuteFloat);\n\tconst second = Math.round((minuteFloat - minute) * 60);\n\treturn {\n\t\tsign: SIGNS_ORDER[signIndex] ?? 'Aries',\n\t\tsignIndex,\n\t\tdegree,\n\t\tminute,\n\t\tsecond,\n\t};\n}\n\n/** Compact display string like \"12\u00B0 Leo 34'\". Used in chart labels. */\nexport function formatSignPosition(longitude: number): string {\n\tconst { sign, degree, minute } = longitudeToSignPosition(longitude);\n\treturn `${degree}\u00B0 ${sign} ${String(minute).padStart(2, '0')}'`;\n}\n\n/**\n * The point diametrically opposite a longitude (e.g. Descendant from\n * Ascendant, IC from MC). Exact derivation, always 180 degrees away.\n */\nexport function oppositePoint(longitude: number): number {\n\treturn normalizeLongitude(longitude + 180);\n}\n\n/**\n * Midpoint of the forward arc from `start` to `end` (both ecliptic\n * longitudes). Handles the 360/0 wrap, so a house spanning 350 to 20 degrees\n * yields a midpoint of 5, not 185. Used to place house numbers between two\n * cusps regardless of how unequal the house is.\n */\nexport function arcMidpoint(start: number, end: number): number {\n\tconst s = normalizeLongitude(start);\n\tlet span = normalizeLongitude(end) - s;\n\tif (span < 0) span += 360;\n\treturn normalizeLongitude(s + span / 2);\n}\n\n/** Polar to cartesian for SVG wheel positioning. Angle in degrees, 0 at 3 o'clock. */\nexport function polarToCartesian(\n\tcx: number,\n\tcy: number,\n\tradius: number,\n\tangleDeg: number,\n): { x: number; y: number } {\n\tconst angleRad = (angleDeg * Math.PI) / 180;\n\treturn {\n\t\tx: cx + radius * Math.cos(angleRad),\n\t\ty: cy + radius * Math.sin(angleRad),\n\t};\n}\n", "/**\n * Display formatters for ISO timestamps and floats coming back from the API.\n * Every helper returns \"\" for nullish or unparseable input so it falls out of\n * template literals cleanly.\n */\n\nexport function formatTime(input: unknown): string {\n\tif (typeof input !== 'string' || input.length === 0) return '';\n\tif (/^\\d{4}-\\d{2}-\\d{2}$/.test(input)) return '';\n\tconst bareTime = /^\\d{2}:\\d{2}(:\\d{2})?$/.test(input);\n\tconst iso = bareTime ? `1970-01-01T${input}` : input;\n\tconst d = new Date(iso);\n\tif (Number.isNaN(d.getTime())) return input;\n\treturn d.toLocaleTimeString(undefined, {\n\t\thour: 'numeric',\n\t\tminute: '2-digit',\n\t\thour12: true,\n\t});\n}\n\nexport function formatDate(input: unknown): string {\n\tif (typeof input !== 'string' || input.length === 0) return '';\n\tconst d = new Date(\n\t\t/^\\d{4}-\\d{2}-\\d{2}$/.test(input) ? `${input}T00:00:00` : input,\n\t);\n\tif (Number.isNaN(d.getTime())) return input;\n\treturn d.toLocaleDateString(undefined, {\n\t\tmonth: 'short',\n\t\tday: 'numeric',\n\t\tyear: 'numeric',\n\t});\n}\n\nexport function formatTimeRange(\n\tt: { start?: string; end?: string } | undefined,\n): string {\n\tif (!t) return '';\n\tconst start = formatTime(t.start);\n\tconst end = formatTime(t.end);\n\tif (start && end) return `${start} - ${end}`;\n\treturn start || end || '';\n}\n\nexport function formatNumber(value: unknown, dp = 1): string {\n\tif (typeof value !== 'number' || !Number.isFinite(value)) return '';\n\treturn value.toFixed(dp).replace(/\\.?0+$/, '');\n}\n\nexport function formatPercent(value: unknown, dp = 1): string {\n\tconst n = formatNumber(value, dp);\n\treturn n ? `${n}%` : '';\n}\n\n/**\n * CSS class name per aspect type. Used by natal and synastry chart aspect\n * lines so the same color encoding (harmonious vs challenging) applies in\n * both wheels. Keys are lowercase canonical names, values are CSS class\n * suffixes the chart components define in their `:host` styles.\n */\nexport const ASPECT_CLASS: Record<string, string> = {\n\tconjunction: 'aspect-conjunction',\n\tsextile: 'aspect-sextile',\n\tsquare: 'aspect-square',\n\ttrine: 'aspect-trine',\n\topposition: 'aspect-opposition',\n};\n\n/**\n * Normalize the `type` field on an aspect entry to a lowercase, hyphen-separated\n * canonical name (`SEMI_SEXTILE` \u2192 `semi-sextile`). Accepts any aspect-shaped\n * object so both natal and synastry inter-aspect entries can share this.\n */\nexport function normalizeAspect(a: { type?: string }): string {\n\treturn (a.type ?? '').toLowerCase().replace(/_/g, '-');\n}\n", "/**\n * Shared string helpers used across components. Single source of truth so the\n * same formatting rules apply to every key/label/title that surfaces in the\n * shadow tree.\n *\n * - `capitalize`: title-cases the first character, lowercases the rest. Used\n * when matching API-supplied planet/sign names against the glyph maps in\n * `tokens/index.ts`, which use canonical TitleCase keys.\n * - `humanize`: turns an API key (`birth_date`, `birthDate`, `mahadasha-end`)\n * into a label suitable for display (\"Birth date\", \"Mahadasha end\").\n */\n\nexport function capitalize(s: string): string {\n\tif (!s) return '';\n\treturn s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();\n}\n\nexport function humanize(s: string): string {\n\treturn s\n\t\t.replace(/[_-]+/g, ' ')\n\t\t.replace(/([a-z])([A-Z])/g, '$1 $2')\n\t\t.replace(/^\\w/, (c) => c.toUpperCase());\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { PLANET_GLYPH, SIGN_GLYPH } from '../tokens/index.js';\nimport type { NatalChartResponse } from '../types/index.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatSignPosition } from '../utils/degree.js';\nimport { formatNumber } from '../utils/format.js';\nimport { capitalize } from '../utils/string.js';\n\n/** A body or point row, normalized so planets and the four angles share a table. */\ninterface BodyRow {\n\tname: string;\n\tsign?: string;\n\tlongitude?: number;\n\thouse?: number;\n\tspeed?: number;\n\tisRetrograde?: boolean;\n\t/** True for the chart angles (ASC, MC, Part of Fortune, Vertex). */\n\tisPoint?: boolean;\n}\n\n/**\n * Western planetary positions table. Renders a /astrology/natal-chart response\n * as the reference-grade positions grid astrologers read alongside the wheel:\n * every body with its sign, exact degree, house, and daily motion, followed by\n * the four chart points (Ascendant, Midheaven, Part of Fortune, Vertex).\n */\n@customElement('roxy-western-planets-table')\nexport class RoxyWesternPlanetsTable extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`\n\t\t\t.wrap {\n\t\t\t\tborder: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t\t\t\tbackground: var(--roxy-bg, #fff);\n\t\t\t\toverflow: auto;\n\t\t\t\tbox-shadow: var(--roxy-shadow-sm);\n\t\t\t}\n\t\t\t.head {\n\t\t\t\tpadding: var(--roxy-space-md, 1rem);\n\t\t\t\tborder-bottom: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t}\n\t\t\t.title {\n\t\t\t\tmargin: 0;\n\t\t\t\tfont-size: var(--roxy-text-lg, 1.125rem);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t}\n\t\t\ttable {\n\t\t\t\twidth: 100%;\n\t\t\t\tborder-collapse: collapse;\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tmin-width: 460px;\n\t\t\t}\n\t\t\tthead {\n\t\t\t\tbackground: color-mix(in srgb, var(--roxy-border, #e4e4e7) 20%, transparent);\n\t\t\t}\n\t\t\tth,\n\t\t\ttd {\n\t\t\t\tpadding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-md, 1rem);\n\t\t\t\ttext-align: left;\n\t\t\t\twhite-space: nowrap;\n\t\t\t}\n\t\t\tth {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\ttext-transform: uppercase;\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\tletter-spacing: 0.04em;\n\t\t\t}\n\t\t\ttbody tr {\n\t\t\t\tborder-top: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t}\n\t\t\ttbody tr.point {\n\t\t\t\tbackground: color-mix(in srgb, var(--roxy-accent, #f59e0b) 8%, transparent);\n\t\t\t}\n\t\t\ttd.body {\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t}\n\t\t\t.glyph {\n\t\t\t\tmargin-right: 0.4em;\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t}\n\t\t\t.retro {\n\t\t\t\tcolor: var(--roxy-danger, #dc2626);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t}\n\t\t\t.num {\n\t\t\t\tfont-variant-numeric: tabular-nums;\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ attribute: false })\n\tdata: NatalChartResponse | null = null;\n\n\t/** Build the ordered row list: the planets array, then the four chart points. */\n\tprivate rows(): BodyRow[] {\n\t\tconst d = this.data;\n\t\tif (!d) return [];\n\t\tconst rows: BodyRow[] = (d.planets ?? []).map((p) => ({\n\t\t\tname: p.name,\n\t\t\tsign: p.sign,\n\t\t\tlongitude: p.longitude,\n\t\t\thouse: p.house,\n\t\t\tspeed: p.speed,\n\t\t\tisRetrograde: p.isRetrograde,\n\t\t}));\n\t\tfor (const [name, point] of [\n\t\t\t['Ascendant', d.ascendant],\n\t\t\t['Midheaven', d.midheaven],\n\t\t\t['Part of Fortune', d.partOfFortune],\n\t\t\t['Vertex', d.vertex],\n\t\t] as const) {\n\t\t\tif (point) {\n\t\t\t\trows.push({\n\t\t\t\t\tname,\n\t\t\t\t\tsign: point.sign,\n\t\t\t\t\tlongitude: point.longitude,\n\t\t\t\t\tisPoint: true,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn rows;\n\t}\n\n\trender() {\n\t\tif (!this.data?.planets)\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No chart data</div>`;\n\t\tconst rows = this.rows();\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Western planetary positions\" tabindex=\"0\">\n\t\t\t<header class=\"head\">\n\t\t\t\t<h2 class=\"title\">Planetary positions</h2>\n\t\t\t</header>\n\t\t\t<table role=\"table\">\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th scope=\"col\">Body</th>\n\t\t\t\t\t\t<th scope=\"col\">Sign</th>\n\t\t\t\t\t\t<th scope=\"col\">Degree</th>\n\t\t\t\t\t\t<th scope=\"col\">House</th>\n\t\t\t\t\t\t<th scope=\"col\">Motion</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t${rows.map((r) => {\n\t\t\t\t\t\tconst glyph = PLANET_GLYPH[capitalize(r.name)] ?? '';\n\t\t\t\t\t\tconst signGlyph = SIGN_GLYPH[capitalize(r.sign ?? '')] ?? '';\n\t\t\t\t\t\tconst speed =\n\t\t\t\t\t\t\ttypeof r.speed === 'number' ? formatNumber(r.speed, 3) : '';\n\t\t\t\t\t\treturn html`<tr class=${r.isPoint ? 'point' : ''}>\n\t\t\t\t\t\t\t<td class=\"body\">\n\t\t\t\t\t\t\t\t${glyph ? html`<span class=\"glyph\">${glyph}</span>` : nothing}${r.name}\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t${signGlyph ? html`<span class=\"glyph\">${signGlyph}</span>` : nothing}${r.sign ?? ''}\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td class=\"num\">\n\t\t\t\t\t\t\t\t${typeof r.longitude === 'number' ? formatSignPosition(r.longitude) : ''}\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td class=\"num\">${typeof r.house === 'number' ? r.house : ''}</td>\n\t\t\t\t\t\t\t<td class=\"num\">\n\t\t\t\t\t\t\t\t${speed ? html`${speed}\u00B0/day` : nothing}\n\t\t\t\t\t\t\t\t${r.isRetrograde ? html`<span class=\"retro\"> \u211E</span>` : nothing}\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t</tr>`;\n\t\t\t\t\t})}\n\t\t\t\t</tbody>\n\t\t\t</table>\n\t\t</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-western-planets-table': RoxyWesternPlanetsTable;\n\t}\n}\n", "/**\n * Symbol constants used across components. Single source of truth so chart\n * wheels, card headers, hexagram displays, and panchang tables stay visually\n * consistent.\n */\n\nexport const PLANET_GLYPH: Record<string, string> = {\n\tSun: '\u2609',\n\tMoon: '\u263D',\n\tMercury: '\u263F',\n\tVenus: '\u2640',\n\tEarth: '\u2641',\n\tMars: '\u2642',\n\tJupiter: '\u2643',\n\tSaturn: '\u2644',\n\tUranus: '\u2645',\n\tNeptune: '\u2646',\n\tPluto: '\u2647',\n\tRahu: '\u260A',\n\tKetu: '\u260B',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n\tNorthNode: '\u260A',\n\tSouthNode: '\u260B',\n\t'North node': '\u260A',\n\t'South node': '\u260B',\n\tChiron: '\u26B7',\n\tLilith: '\u26B8',\n\t'Black moon lilith': '\u26B8',\n};\n\nexport const PLANET_ABBR: Record<string, string> = {\n\tSun: 'Su',\n\tMoon: 'Mo',\n\tMercury: 'Me',\n\tVenus: 'Ve',\n\tMars: 'Ma',\n\tJupiter: 'Ju',\n\tSaturn: 'Sa',\n\tUranus: 'Ur',\n\tNeptune: 'Ne',\n\tPluto: 'Pl',\n\tRahu: 'Ra',\n\tKetu: 'Ke',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n};\n\nexport const SIGN_GLYPH: Record<string, string> = {\n\tAries: '\u2648',\n\tTaurus: '\u2649',\n\tGemini: '\u264A',\n\tCancer: '\u264B',\n\tLeo: '\u264C',\n\tVirgo: '\u264D',\n\tLibra: '\u264E',\n\tScorpio: '\u264F',\n\tSagittarius: '\u2650',\n\tCapricorn: '\u2651',\n\tAquarius: '\u2652',\n\tPisces: '\u2653',\n};\n\nexport const SIGN_ABBR: Record<string, string> = {\n\tAries: 'Ar',\n\tTaurus: 'Ta',\n\tGemini: 'Ge',\n\tCancer: 'Cn',\n\tLeo: 'Le',\n\tVirgo: 'Vi',\n\tLibra: 'Li',\n\tScorpio: 'Sc',\n\tSagittarius: 'Sg',\n\tCapricorn: 'Cp',\n\tAquarius: 'Aq',\n\tPisces: 'Pi',\n};\n\nexport const SIGNS_ORDER = [\n\t'Aries',\n\t'Taurus',\n\t'Gemini',\n\t'Cancer',\n\t'Leo',\n\t'Virgo',\n\t'Libra',\n\t'Scorpio',\n\t'Sagittarius',\n\t'Capricorn',\n\t'Aquarius',\n\t'Pisces',\n] as const;\n\n/**\n * Lowercase rashi keys in canonical zodiac order. Derived from `SIGNS_ORDER`\n * so the two stay in lockstep. The /vedic-astrology/birth-chart response\n * carries planet buckets keyed by these names.\n */\nexport const RASHI_KEYS = SIGNS_ORDER.map((s) =>\n\ts.toLowerCase(),\n) as readonly Lowercase<(typeof SIGNS_ORDER)[number]>[];\n\n/** Aspect symbols. Used by synastry and natal chart aspect tables. */\nexport const ASPECT_SYMBOL: Record<string, string> = {\n\tconjunction: '\u260C',\n\topposition: '\u260D',\n\ttrine: '\u25B3',\n\tsquare: '\u25A1',\n\tsextile: '\u2731',\n\tquincunx: '\u22BB',\n\tsemisextile: '\u22BC',\n};\n\n/** Trigrams used by I Ching hexagrams. Eight trigrams compose 64 hexagrams. */\nexport const TRIGRAM_GLYPH: Record<string, string> = {\n\theaven: '\u2630',\n\tlake: '\u2631',\n\tfire: '\u2632',\n\tthunder: '\u2633',\n\twind: '\u2634',\n\twater: '\u2635',\n\tmountain: '\u2636',\n\tearth: '\u2637',\n\tHeaven: '\u2630',\n\tLake: '\u2631',\n\tFire: '\u2632',\n\tThunder: '\u2633',\n\tWind: '\u2634',\n\tWater: '\u2635',\n\tMountain: '\u2636',\n\tEarth: '\u2637',\n};\n\n/** Moon phase emoji set. Used by moon phase card. */\nexport const MOON_PHASE_EMOJI: Record<string, string> = {\n\t'new moon': '\uD83C\uDF11',\n\t'waxing crescent': '\uD83C\uDF12',\n\t'first quarter': '\uD83C\uDF13',\n\t'waxing gibbous': '\uD83C\uDF14',\n\t'full moon': '\uD83C\uDF15',\n\t'waning gibbous': '\uD83C\uDF16',\n\t'last quarter': '\uD83C\uDF17',\n\t'waning crescent': '\uD83C\uDF18',\n};\n", "import { css } from 'lit';\n\n/**\n * Shared host styles every component pulls in. Sets default font, color,\n * container query support, and the entry fade-in.\n */\nexport const baseStyles = css`\n\t:host {\n\t\tdisplay: block;\n\t\tcontainer-type: inline-size;\n\t\tfont-family: var(\n\t\t\t--roxy-font-sans,\n\t\t\tsystem-ui,\n\t\t\t-apple-system,\n\t\t\tBlinkMacSystemFont,\n\t\t\t'Segoe UI',\n\t\t\tRoboto,\n\t\t\tsans-serif\n\t\t);\n\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\tbackground: transparent;\n\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\tline-height: var(--roxy-leading-normal, 1.5);\n\t\tanimation: roxy-fade-in var(--roxy-motion-duration, 200ms)\n\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1)) both;\n\t}\n\n\t*,\n\t*::before,\n\t*::after {\n\t\tbox-sizing: border-box;\n\t}\n\n\t@keyframes roxy-fade-in {\n\t\tfrom {\n\t\t\topacity: 0;\n\t\t\ttransform: translateY(2px);\n\t\t}\n\t\tto {\n\t\t\topacity: 1;\n\t\t\ttransform: translateY(0);\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t:host {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-skeleton {\n\t\tbackground: linear-gradient(\n\t\t\t90deg,\n\t\t\tvar(--roxy-border, #e4e4e7) 0%,\n\t\t\tcolor-mix(in srgb, var(--roxy-border, #e4e4e7) 60%, transparent) 50%,\n\t\t\tvar(--roxy-border, #e4e4e7) 100%\n\t\t);\n\t\tbackground-size: 200% 100%;\n\t\tanimation: roxy-shimmer 1.4s ease-in-out infinite;\n\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t}\n\n\t@keyframes roxy-shimmer {\n\t\t0% {\n\t\t\tbackground-position: 200% 0;\n\t\t}\n\t\t100% {\n\t\t\tbackground-position: -200% 0;\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t.roxy-skeleton {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-empty {\n\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\tcolor: var(--roxy-muted, #71717a);\n\t\ttext-align: center;\n\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t}\n\n\t:host(:focus-within) .roxy-card {\n\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\toutline-offset: 2px;\n\t}\n\n\t/* Force the text-style variant on every Unicode glyph in the component.\n\t * macOS and iOS substitute coloured emoji glyphs for the planetary and\n\t * gender Unicode code points (Mars, Venus, Mercury, etc.) when the\n\t * system colour-emoji font wins font selection. The text-style variant\n\t * keeps glyphs monochrome so they inherit the surrounding fill colour\n\t * and match the brand palette consistently across platforms.\n\t *\n\t * font-variant-emoji is part of CSS Fonts 4 (Safari 17+, Chrome 134+,\n\t * Firefox 139+). On older browsers the rule is silently ignored.\n\t */\n\t:host {\n\t\tfont-variant-emoji: text;\n\t}\n`;\n", "/**\n * Math helpers for converting raw ecliptic longitude decimals into the\n * sign / degree / minute / second triplet used across chart components.\n */\n\nimport { SIGNS_ORDER } from '../tokens/index.js';\n\nexport interface SignPosition {\n\tsign: string;\n\tsignIndex: number;\n\tdegree: number;\n\tminute: number;\n\tsecond: number;\n}\n\n/**\n * Wrap longitude into [0, 360) so negative or out-of-range values still\n * resolve to a real sign. Robust to wonky upstream data.\n */\nexport function normalizeLongitude(lon: number): number {\n\tconst wrapped = lon % 360;\n\treturn wrapped < 0 ? wrapped + 360 : wrapped;\n}\n\n/**\n * Convert decimal ecliptic longitude (0-360) into sign/degree/minute/second.\n * Used by every chart wheel and aspect table.\n */\nexport function longitudeToSignPosition(longitude: number): SignPosition {\n\tconst lon = normalizeLongitude(longitude);\n\tconst signIndex = Math.floor(lon / 30) % 12;\n\tconst within = lon % 30;\n\tconst degree = Math.floor(within);\n\tconst minuteFloat = (within - degree) * 60;\n\tconst minute = Math.floor(minuteFloat);\n\tconst second = Math.round((minuteFloat - minute) * 60);\n\treturn {\n\t\tsign: SIGNS_ORDER[signIndex] ?? 'Aries',\n\t\tsignIndex,\n\t\tdegree,\n\t\tminute,\n\t\tsecond,\n\t};\n}\n\n/** Compact display string like \"12\u00B0 Leo 34'\". Used in chart labels. */\nexport function formatSignPosition(longitude: number): string {\n\tconst { sign, degree, minute } = longitudeToSignPosition(longitude);\n\treturn `${degree}\u00B0 ${sign} ${String(minute).padStart(2, '0')}'`;\n}\n\n/**\n * The point diametrically opposite a longitude (e.g. Descendant from\n * Ascendant, IC from MC). Exact derivation, always 180 degrees away.\n */\nexport function oppositePoint(longitude: number): number {\n\treturn normalizeLongitude(longitude + 180);\n}\n\n/**\n * Midpoint of the forward arc from `start` to `end` (both ecliptic\n * longitudes). Handles the 360/0 wrap, so a house spanning 350 to 20 degrees\n * yields a midpoint of 5, not 185. Used to place house numbers between two\n * cusps regardless of how unequal the house is.\n */\nexport function arcMidpoint(start: number, end: number): number {\n\tconst s = normalizeLongitude(start);\n\tlet span = normalizeLongitude(end) - s;\n\tif (span < 0) span += 360;\n\treturn normalizeLongitude(s + span / 2);\n}\n\n/** Polar to cartesian for SVG wheel positioning. Angle in degrees, 0 at 3 o'clock. */\nexport function polarToCartesian(\n\tcx: number,\n\tcy: number,\n\tradius: number,\n\tangleDeg: number,\n): { x: number; y: number } {\n\tconst angleRad = (angleDeg * Math.PI) / 180;\n\treturn {\n\t\tx: cx + radius * Math.cos(angleRad),\n\t\ty: cy + radius * Math.sin(angleRad),\n\t};\n}\n", "/**\n * Display formatters for ISO timestamps and floats coming back from the API.\n * Every helper returns \"\" for nullish or unparseable input so it falls out of\n * template literals cleanly.\n */\n\nexport function formatTime(input: unknown): string {\n\tif (typeof input !== 'string' || input.length === 0) return '';\n\tif (/^\\d{4}-\\d{2}-\\d{2}$/.test(input)) return '';\n\tconst bareTime = /^\\d{2}:\\d{2}(:\\d{2})?$/.test(input);\n\tconst iso = bareTime ? `1970-01-01T${input}` : input;\n\tconst d = new Date(iso);\n\tif (Number.isNaN(d.getTime())) return input;\n\treturn d.toLocaleTimeString(undefined, {\n\t\thour: 'numeric',\n\t\tminute: '2-digit',\n\t\thour12: true,\n\t});\n}\n\nexport function formatDate(input: unknown): string {\n\tif (typeof input !== 'string' || input.length === 0) return '';\n\tconst d = new Date(\n\t\t/^\\d{4}-\\d{2}-\\d{2}$/.test(input) ? `${input}T00:00:00` : input,\n\t);\n\tif (Number.isNaN(d.getTime())) return input;\n\treturn d.toLocaleDateString(undefined, {\n\t\tmonth: 'short',\n\t\tday: 'numeric',\n\t\tyear: 'numeric',\n\t});\n}\n\nexport function formatTimeRange(\n\tt: { start?: string; end?: string } | undefined,\n): string {\n\tif (!t) return '';\n\tconst start = formatTime(t.start);\n\tconst end = formatTime(t.end);\n\tif (start && end) return `${start} - ${end}`;\n\treturn start || end || '';\n}\n\nexport function formatNumber(value: unknown, dp = 1): string {\n\tif (typeof value !== 'number' || !Number.isFinite(value)) return '';\n\treturn value.toFixed(dp).replace(/\\.?0+$/, '');\n}\n\nexport function formatPercent(value: unknown, dp = 1): string {\n\tconst n = formatNumber(value, dp);\n\treturn n ? `${n}%` : '';\n}\n\n/**\n * CSS class name per aspect type. Used by natal and synastry chart aspect\n * lines so the same color encoding (harmonious vs challenging) applies in\n * both wheels. Keys are lowercase canonical names, values are CSS class\n * suffixes the chart components define in their `:host` styles.\n */\nexport const ASPECT_CLASS: Record<string, string> = {\n\tconjunction: 'aspect-conjunction',\n\tsextile: 'aspect-sextile',\n\tsquare: 'aspect-square',\n\ttrine: 'aspect-trine',\n\topposition: 'aspect-opposition',\n};\n\n/**\n * Normalize the `type` field on an aspect entry to a lowercase, hyphen-separated\n * canonical name (`SEMI_SEXTILE` \u2192 `semi-sextile`). Accepts any aspect-shaped\n * object so both natal and synastry inter-aspect entries can share this.\n */\nexport function normalizeAspect(a: { type?: string }): string {\n\treturn (a.type ?? '').toLowerCase().replace(/_/g, '-');\n}\n", "/**\n * Shared string helpers used across components. Single source of truth so the\n * same formatting rules apply to every key/label/title that surfaces in the\n * shadow tree.\n *\n * - `capitalize`: title-cases the first character, lowercases the rest. Used\n * when matching API-supplied planet/sign names against the glyph maps in\n * `tokens/index.ts`, which use canonical TitleCase keys.\n * - `humanize`: turns an API key (`birth_date`, `birthDate`, `mahadasha-end`)\n * into a label suitable for display (\"Birth date\", \"Mahadasha end\").\n */\n\nexport function capitalize(s: string): string {\n\tif (!s) return '';\n\treturn s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();\n}\n\nexport function humanize(s: string): string {\n\treturn s\n\t\t.replace(/[_-]+/g, ' ')\n\t\t.replace(/([a-z])([A-Z])/g, '$1 $2')\n\t\t.replace(/^\\w/, (c) => c.toUpperCase());\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["css", "css"]
|
|
7
7
|
}
|
|
@@ -97,6 +97,20 @@ var baseStyles = css`
|
|
|
97
97
|
outline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));
|
|
98
98
|
outline-offset: 2px;
|
|
99
99
|
}
|
|
100
|
+
|
|
101
|
+
/* Force the text-style variant on every Unicode glyph in the component.
|
|
102
|
+
* macOS and iOS substitute coloured emoji glyphs for the planetary and
|
|
103
|
+
* gender Unicode code points (Mars, Venus, Mercury, etc.) when the
|
|
104
|
+
* system colour-emoji font wins font selection. The text-style variant
|
|
105
|
+
* keeps glyphs monochrome so they inherit the surrounding fill colour
|
|
106
|
+
* and match the brand palette consistently across platforms.
|
|
107
|
+
*
|
|
108
|
+
* font-variant-emoji is part of CSS Fonts 4 (Safari 17+, Chrome 134+,
|
|
109
|
+
* Firefox 139+). On older browsers the rule is silently ignored.
|
|
110
|
+
*/
|
|
111
|
+
:host {
|
|
112
|
+
font-variant-emoji: text;
|
|
113
|
+
}
|
|
100
114
|
`;
|
|
101
115
|
|
|
102
116
|
// packages/ui/src/components/yoga-list.ts
|