@roxyapi/ui 0.3.1 → 0.4.0

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.
Files changed (165) hide show
  1. package/AGENTS.md +27 -1
  2. package/README.md +115 -14
  3. package/dist/cdn/components/ashtakavarga-grid.js +74 -19
  4. package/dist/cdn/components/ashtakavarga-grid.js.map +2 -2
  5. package/dist/cdn/components/biorhythm-chart.js +18 -4
  6. package/dist/cdn/components/biorhythm-chart.js.map +2 -2
  7. package/dist/cdn/components/choghadiya-grid.js +47 -12
  8. package/dist/cdn/components/choghadiya-grid.js.map +3 -3
  9. package/dist/cdn/components/compatibility-card.js +21 -7
  10. package/dist/cdn/components/compatibility-card.js.map +2 -2
  11. package/dist/cdn/components/dasha-timeline.js +113 -28
  12. package/dist/cdn/components/dasha-timeline.js.map +3 -3
  13. package/dist/cdn/components/data.js +27 -13
  14. package/dist/cdn/components/data.js.map +2 -2
  15. package/dist/cdn/components/divisional-chart.js +225 -118
  16. package/dist/cdn/components/divisional-chart.js.map +4 -4
  17. package/dist/cdn/components/dosha-card.js +18 -4
  18. package/dist/cdn/components/dosha-card.js.map +2 -2
  19. package/dist/cdn/components/endpoint-form.js +25 -11
  20. package/dist/cdn/components/endpoint-form.js.map +2 -2
  21. package/dist/cdn/components/guna-milan.js +20 -6
  22. package/dist/cdn/components/guna-milan.js.map +2 -2
  23. package/dist/cdn/components/hexagram.js +22 -8
  24. package/dist/cdn/components/hexagram.js.map +2 -2
  25. package/dist/cdn/components/horoscope-card.js +20 -6
  26. package/dist/cdn/components/horoscope-card.js.map +2 -2
  27. package/dist/cdn/components/kp-chart.js +19 -5
  28. package/dist/cdn/components/kp-chart.js.map +2 -2
  29. package/dist/cdn/components/kp-planets-table.js +17 -3
  30. package/dist/cdn/components/kp-planets-table.js.map +2 -2
  31. package/dist/cdn/components/kp-ruling-planets.js +17 -3
  32. package/dist/cdn/components/kp-ruling-planets.js.map +2 -2
  33. package/dist/cdn/components/location-search.js +18 -4
  34. package/dist/cdn/components/location-search.js.map +2 -2
  35. package/dist/cdn/components/moon-phase.js +27 -13
  36. package/dist/cdn/components/moon-phase.js.map +2 -2
  37. package/dist/cdn/components/nakshatra-card.js +16 -2
  38. package/dist/cdn/components/nakshatra-card.js.map +2 -2
  39. package/dist/cdn/components/natal-chart.js +79 -40
  40. package/dist/cdn/components/natal-chart.js.map +3 -3
  41. package/dist/cdn/components/numerology-card.js +18 -4
  42. package/dist/cdn/components/numerology-card.js.map +2 -2
  43. package/dist/cdn/components/panchang-table.js +53 -25
  44. package/dist/cdn/components/panchang-table.js.map +3 -3
  45. package/dist/cdn/components/shadbala-table.js +24 -10
  46. package/dist/cdn/components/shadbala-table.js.map +2 -2
  47. package/dist/cdn/components/synastry-chart.js +96 -48
  48. package/dist/cdn/components/synastry-chart.js.map +3 -3
  49. package/dist/cdn/components/tarot-card.js +17 -3
  50. package/dist/cdn/components/tarot-card.js.map +2 -2
  51. package/dist/cdn/components/tarot-spread.js +39 -25
  52. package/dist/cdn/components/tarot-spread.js.map +2 -2
  53. package/dist/cdn/components/transits-table.js +18 -4
  54. package/dist/cdn/components/transits-table.js.map +2 -2
  55. package/dist/cdn/components/vedic-kundli.js +215 -105
  56. package/dist/cdn/components/vedic-kundli.js.map +4 -4
  57. package/dist/cdn/components/vedic-planets-table.js +22 -8
  58. package/dist/cdn/components/vedic-planets-table.js.map +2 -2
  59. package/dist/cdn/components/western-planets-table.js +18 -4
  60. package/dist/cdn/components/western-planets-table.js.map +2 -2
  61. package/dist/cdn/components/yoga-list.js +17 -3
  62. package/dist/cdn/components/yoga-list.js.map +2 -2
  63. package/dist/cdn/roxy-ui.js +1082 -816
  64. package/dist/cdn/roxy-ui.js.map +4 -4
  65. package/dist/components/ashtakavarga-grid.d.ts +13 -1
  66. package/dist/components/ashtakavarga-grid.d.ts.map +1 -1
  67. package/dist/components/ashtakavarga-grid.js +86 -11
  68. package/dist/components/ashtakavarga-grid.js.map +2 -2
  69. package/dist/components/biorhythm-chart.js +14 -0
  70. package/dist/components/biorhythm-chart.js.map +2 -2
  71. package/dist/components/choghadiya-grid.d.ts +6 -0
  72. package/dist/components/choghadiya-grid.d.ts.map +1 -1
  73. package/dist/components/choghadiya-grid.js +50 -2
  74. package/dist/components/choghadiya-grid.js.map +2 -2
  75. package/dist/components/compatibility-card.js +14 -0
  76. package/dist/components/compatibility-card.js.map +2 -2
  77. package/dist/components/dasha-timeline.d.ts +10 -0
  78. package/dist/components/dasha-timeline.d.ts.map +1 -1
  79. package/dist/components/dasha-timeline.js +135 -4
  80. package/dist/components/dasha-timeline.js.map +2 -2
  81. package/dist/components/data.js +14 -0
  82. package/dist/components/data.js.map +2 -2
  83. package/dist/components/divisional-chart.d.ts +9 -6
  84. package/dist/components/divisional-chart.d.ts.map +1 -1
  85. package/dist/components/divisional-chart.js +546 -251
  86. package/dist/components/divisional-chart.js.map +4 -4
  87. package/dist/components/dosha-card.js +14 -0
  88. package/dist/components/dosha-card.js.map +2 -2
  89. package/dist/components/endpoint-form.js +14 -0
  90. package/dist/components/endpoint-form.js.map +2 -2
  91. package/dist/components/guna-milan.js +14 -0
  92. package/dist/components/guna-milan.js.map +2 -2
  93. package/dist/components/hexagram.js +14 -0
  94. package/dist/components/hexagram.js.map +2 -2
  95. package/dist/components/horoscope-card.js +14 -0
  96. package/dist/components/horoscope-card.js.map +2 -2
  97. package/dist/components/kp-chart.js +14 -0
  98. package/dist/components/kp-chart.js.map +2 -2
  99. package/dist/components/kp-planets-table.js +14 -0
  100. package/dist/components/kp-planets-table.js.map +2 -2
  101. package/dist/components/kp-ruling-planets.js +14 -0
  102. package/dist/components/kp-ruling-planets.js.map +2 -2
  103. package/dist/components/location-search.js +14 -0
  104. package/dist/components/location-search.js.map +2 -2
  105. package/dist/components/moon-phase.js +14 -0
  106. package/dist/components/moon-phase.js.map +2 -2
  107. package/dist/components/nakshatra-card.js +14 -0
  108. package/dist/components/nakshatra-card.js.map +2 -2
  109. package/dist/components/natal-chart.d.ts.map +1 -1
  110. package/dist/components/natal-chart.js +76 -6
  111. package/dist/components/natal-chart.js.map +2 -2
  112. package/dist/components/numerology-card.js +14 -0
  113. package/dist/components/numerology-card.js.map +2 -2
  114. package/dist/components/panchang-table.d.ts +1 -0
  115. package/dist/components/panchang-table.d.ts.map +1 -1
  116. package/dist/components/panchang-table.js +37 -1
  117. package/dist/components/panchang-table.js.map +2 -2
  118. package/dist/components/shadbala-table.js +14 -0
  119. package/dist/components/shadbala-table.js.map +2 -2
  120. package/dist/components/synastry-chart.d.ts +6 -0
  121. package/dist/components/synastry-chart.d.ts.map +1 -1
  122. package/dist/components/synastry-chart.js +106 -7
  123. package/dist/components/synastry-chart.js.map +2 -2
  124. package/dist/components/tarot-card.js +14 -0
  125. package/dist/components/tarot-card.js.map +2 -2
  126. package/dist/components/tarot-spread.js +14 -0
  127. package/dist/components/tarot-spread.js.map +2 -2
  128. package/dist/components/transits-table.js +14 -0
  129. package/dist/components/transits-table.js.map +2 -2
  130. package/dist/components/vedic-kundli.d.ts +14 -9
  131. package/dist/components/vedic-kundli.d.ts.map +1 -1
  132. package/dist/components/vedic-kundli.js +537 -245
  133. package/dist/components/vedic-kundli.js.map +4 -4
  134. package/dist/components/vedic-planets-table.js +14 -0
  135. package/dist/components/vedic-planets-table.js.map +2 -2
  136. package/dist/components/western-planets-table.js +14 -0
  137. package/dist/components/western-planets-table.js.map +2 -2
  138. package/dist/components/yoga-list.js +14 -0
  139. package/dist/components/yoga-list.js.map +2 -2
  140. package/dist/index.cjs +1397 -797
  141. package/dist/index.cjs.map +4 -4
  142. package/dist/index.js +1278 -678
  143. package/dist/index.js.map +4 -4
  144. package/dist/manifest.json +23 -23
  145. package/dist/styles/tokens.css +8 -23
  146. package/dist/utils/base-styles.d.ts.map +1 -1
  147. package/dist/utils/kundli-render.d.ts +43 -104
  148. package/dist/utils/kundli-render.d.ts.map +1 -1
  149. package/dist/utils/kundli-styles.d.ts +13 -0
  150. package/dist/utils/kundli-styles.d.ts.map +1 -0
  151. package/dist/version.d.ts +1 -1
  152. package/package.json +1 -1
  153. package/src/components/ashtakavarga-grid.ts +73 -11
  154. package/src/components/choghadiya-grid.ts +37 -2
  155. package/src/components/dasha-timeline.ts +135 -4
  156. package/src/components/divisional-chart.ts +40 -97
  157. package/src/components/natal-chart.ts +89 -6
  158. package/src/components/panchang-table.ts +34 -1
  159. package/src/components/synastry-chart.ts +84 -8
  160. package/src/components/vedic-kundli.ts +35 -95
  161. package/src/styles/tokens.css +8 -23
  162. package/src/utils/base-styles.ts +14 -0
  163. package/src/utils/kundli-render.ts +609 -270
  164. package/src/utils/kundli-styles.ts +124 -0
  165. package/src/version.ts +1 -1
@@ -10,7 +10,7 @@ var __decorateClass = (decorators, target, key, kind) => {
10
10
  };
11
11
 
12
12
  // packages/ui/src/components/divisional-chart.ts
13
- import { css as css2, html, LitElement, nothing as nothing2 } from "lit";
13
+ import { css as css3, html as html2, LitElement, nothing as nothing2 } from "lit";
14
14
  import { customElement, property } from "lit/decorators.js";
15
15
 
16
16
  // packages/ui/src/tokens/index.ts
@@ -170,10 +170,24 @@ var baseStyles = css`
170
170
  outline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));
171
171
  outline-offset: 2px;
172
172
  }
173
+
174
+ /* Force the text-style variant on every Unicode glyph in the component.
175
+ * macOS and iOS substitute coloured emoji glyphs for the planetary and
176
+ * gender Unicode code points (Mars, Venus, Mercury, etc.) when the
177
+ * system colour-emoji font wins font selection. The text-style variant
178
+ * keeps glyphs monochrome so they inherit the surrounding fill colour
179
+ * and match the brand palette consistently across platforms.
180
+ *
181
+ * font-variant-emoji is part of CSS Fonts 4 (Safari 17+, Chrome 134+,
182
+ * Firefox 139+). On older browsers the rule is silently ignored.
183
+ */
184
+ :host {
185
+ font-variant-emoji: text;
186
+ }
173
187
  `;
174
188
 
175
189
  // packages/ui/src/utils/kundli-render.ts
176
- import { nothing, svg } from "lit";
190
+ import { html, nothing, svg } from "lit";
177
191
 
178
192
  // packages/ui/src/utils/degree.ts
179
193
  function normalizeLongitude(lon) {
@@ -204,25 +218,45 @@ function capitalize(s) {
204
218
  }
205
219
 
206
220
  // packages/ui/src/utils/kundli-render.ts
221
+ var VIEW_BOX = 400;
222
+ var MARGIN = 20;
223
+ var INNER = VIEW_BOX - 2 * MARGIN;
224
+ var CENTRE = VIEW_BOX / 2;
207
225
  var RASHI_TO_SIGN = Object.fromEntries(
208
226
  SIGNS_ORDER.map((s) => [s.toLowerCase(), s])
209
227
  );
228
+ var CHART_STYLES = [
229
+ { id: "north", label: "North" },
230
+ { id: "south", label: "South" },
231
+ { id: "east", label: "East" }
232
+ ];
210
233
  var RETRO_MARK = "\u02B3";
211
- function grahaLabel(p) {
234
+ function isDivisionalPlacement(p, cellSign) {
235
+ if (typeof p.longitude !== "number" || !Number.isFinite(p.longitude)) {
236
+ return false;
237
+ }
238
+ return longitudeToSignPosition(p.longitude).sign.toLowerCase() !== cellSign.toLowerCase();
239
+ }
240
+ function grahaLabel(p, cellSign) {
212
241
  const abbr = PLANET_ABBR[capitalize(p.graha)] ?? p.graha.slice(0, 2);
213
242
  const retro = p.isRetrograde ? RETRO_MARK : "";
214
- if (typeof p.longitude !== "number" || !Number.isFinite(p.longitude)) {
243
+ if (typeof p.longitude !== "number" || !Number.isFinite(p.longitude) || isDivisionalPlacement(p, cellSign)) {
215
244
  return `${abbr}${retro}`;
216
245
  }
217
246
  const { degree } = longitudeToSignPosition(p.longitude);
218
247
  return `${abbr} ${degree}\xB0${retro}`;
219
248
  }
220
- function grahaTitle(p) {
249
+ function grahaTitle(p, cellSign) {
221
250
  const parts = [capitalize(p.graha)];
251
+ const divisional = isDivisionalPlacement(p, cellSign);
252
+ if (divisional) {
253
+ parts.push(`in ${cellSign}`);
254
+ }
222
255
  if (typeof p.longitude === "number" && Number.isFinite(p.longitude)) {
223
256
  const sp = longitudeToSignPosition(p.longitude);
257
+ const minute = String(sp.minute).padStart(2, "0");
224
258
  parts.push(
225
- `${sp.degree}\xB0${String(sp.minute).padStart(2, "0")}' ${sp.sign}`
259
+ divisional ? `D1: ${sp.degree}\xB0${minute}' ${sp.sign}` : `${sp.degree}\xB0${minute}' ${sp.sign}`
226
260
  );
227
261
  }
228
262
  if (p.nakshatra?.name) {
@@ -233,249 +267,562 @@ function grahaTitle(p) {
233
267
  if (p.isRetrograde) parts.push("retrograde");
234
268
  return parts.join(" \xB7 ");
235
269
  }
236
- function renderPlanetStack(planets, cx, baseY, lineHeight) {
270
+ function renderPlanetStack(planets, cellSign, cx, baseY, lineHeight) {
237
271
  const startY = baseY - (planets.length - 1) * lineHeight / 2;
238
272
  return planets.map((p, j) => {
239
273
  const yPos = startY + j * lineHeight;
240
274
  return svg`<text class="planet-text" x=${cx} y=${yPos} text-anchor="middle" dominant-baseline="central">${grahaLabel(
241
- p
242
- )}<title>${grahaTitle(p)}</title></text>`;
275
+ p,
276
+ cellSign
277
+ )}<title>${grahaTitle(p, cellSign)}</title></text>`;
243
278
  });
244
279
  }
245
- var SOUTH_HOUSE_CENTERS = {
246
- 1: { x: 150, y: 58 },
247
- 2: { x: 205, y: 52 },
248
- 3: { x: 253, y: 112 },
249
- 4: { x: 243, y: 150 },
250
- 5: { x: 253, y: 188 },
251
- 6: { x: 205, y: 248 },
252
- 7: { x: 150, y: 242 },
253
- 8: { x: 95, y: 248 },
254
- 9: { x: 47, y: 188 },
255
- 10: { x: 57, y: 150 },
256
- 11: { x: 47, y: 112 },
257
- 12: { x: 95, y: 52 }
258
- };
259
- var SOUTH_SIGN_POSITIONS = {
260
- 1: { x: 150, y: 35 },
261
- 2: { x: 222, y: 40 },
262
- 3: { x: 265, y: 100 },
263
- 4: { x: 265, y: 150 },
264
- 5: { x: 265, y: 200 },
265
- 6: { x: 222, y: 260 },
266
- 7: { x: 150, y: 265 },
267
- 8: { x: 78, y: 260 },
268
- 9: { x: 35, y: 200 },
269
- 10: { x: 35, y: 150 },
270
- 11: { x: 35, y: 100 },
271
- 12: { x: 78, y: 40 }
272
- };
273
- var NORTH_HOUSE_CENTERS = {
274
- 1: { x: 150, y: 60 },
275
- 2: { x: 225, y: 100 },
276
- 3: { x: 255, y: 150 },
277
- 4: { x: 225, y: 200 },
278
- 5: { x: 150, y: 240 },
279
- 6: { x: 75, y: 200 },
280
- 7: { x: 45, y: 150 },
281
- 8: { x: 75, y: 100 },
282
- 9: { x: 100, y: 80 },
283
- 10: { x: 150, y: 108 },
284
- 11: { x: 200, y: 80 },
285
- 12: { x: 200, y: 220 }
286
- };
287
- var EAST_HOUSE_CENTERS = {
288
- 1: { x: 150, y: 80 },
289
- // inner diamond, top
290
- 2: { x: 220, y: 33 },
291
- // top-right corner, upper triangle
292
- 3: { x: 267, y: 80 },
293
- // top-right corner, right triangle
294
- 4: { x: 220, y: 150 },
295
- // inner diamond, right
296
- 5: { x: 267, y: 220 },
297
- // bottom-right corner, right triangle
298
- 6: { x: 220, y: 267 },
299
- // bottom-right corner, lower triangle
300
- 7: { x: 150, y: 220 },
301
- // inner diamond, bottom
302
- 8: { x: 80, y: 267 },
303
- // bottom-left corner, lower triangle
304
- 9: { x: 33, y: 220 },
305
- // bottom-left corner, left triangle
306
- 10: { x: 80, y: 150 },
307
- // inner diamond, left
308
- 11: { x: 33, y: 80 },
309
- // top-left corner, left triangle
310
- 12: { x: 80, y: 33 }
311
- // top-left corner, upper triangle
312
- };
313
- var EAST_SIGN_POSITIONS = {
314
- 1: { x: 150, y: 55 },
315
- 2: { x: 235, y: 24 },
316
- 3: { x: 276, y: 62 },
317
- 4: { x: 242, y: 150 },
318
- 5: { x: 276, y: 238 },
319
- 6: { x: 235, y: 276 },
320
- 7: { x: 150, y: 245 },
321
- 8: { x: 65, y: 276 },
322
- 9: { x: 24, y: 238 },
323
- 10: { x: 58, y: 150 },
324
- 11: { x: 24, y: 62 },
325
- 12: { x: 65, y: 24 }
280
+ function toKundliViewModel(meta, divisionLabel) {
281
+ const placements = {};
282
+ for (const sign of SIGNS_ORDER) placements[sign.toLowerCase()] = [];
283
+ let lagnaSign = "";
284
+ for (const [name, pos] of Object.entries(meta ?? {})) {
285
+ const rashiKey = (pos?.rashi ?? "").toLowerCase();
286
+ if (name === "Lagna" || pos?.graha === "Lagna") {
287
+ lagnaSign = RASHI_TO_SIGN[rashiKey] ?? "";
288
+ continue;
289
+ }
290
+ if (!rashiKey || !(rashiKey in placements)) continue;
291
+ placements[rashiKey]?.push({
292
+ graha: pos.graha ?? name,
293
+ longitude: pos.longitude,
294
+ nakshatra: pos.nakshatra,
295
+ isRetrograde: pos.isRetrograde,
296
+ awastha: pos.awastha
297
+ });
298
+ }
299
+ return { lagnaSign, placements, divisionLabel };
300
+ }
301
+ var SOUTH_CELL = INNER / 4;
302
+ var SOUTH_CELL_GRID = {
303
+ Pisces: { col: 0, row: 0 },
304
+ Aries: { col: 1, row: 0 },
305
+ Taurus: { col: 2, row: 0 },
306
+ Gemini: { col: 3, row: 0 },
307
+ Cancer: { col: 3, row: 1 },
308
+ Leo: { col: 3, row: 2 },
309
+ Virgo: { col: 3, row: 3 },
310
+ Libra: { col: 2, row: 3 },
311
+ Scorpio: { col: 1, row: 3 },
312
+ Sagittarius: { col: 0, row: 3 },
313
+ Capricorn: { col: 0, row: 2 },
314
+ Aquarius: { col: 0, row: 1 }
326
315
  };
327
- function renderSouthHouseGroup(h) {
328
- const center = SOUTH_HOUSE_CENTERS[h.number];
329
- const signPos = SOUTH_SIGN_POSITIONS[h.number];
330
- if (!center || !signPos) return nothing;
331
- const signAbbr = SIGN_ABBR[h.sign] ?? "";
332
- const baseY = h.isLagna ? center.y + 8 : center.y;
316
+ function southCellRect(sign) {
317
+ const g = SOUTH_CELL_GRID[sign] ?? { col: 0, row: 0 };
318
+ return {
319
+ x: MARGIN + g.col * SOUTH_CELL,
320
+ y: MARGIN + g.row * SOUTH_CELL,
321
+ w: SOUTH_CELL,
322
+ h: SOUTH_CELL
323
+ };
324
+ }
325
+ function renderSouthFrame(divisionLabel) {
326
+ const a = MARGIN;
327
+ const b = MARGIN + SOUTH_CELL;
328
+ const c = MARGIN + 2 * SOUTH_CELL;
329
+ const d = MARGIN + 3 * SOUTH_CELL;
330
+ const e = VIEW_BOX - MARGIN;
333
331
  return svg`
334
- <g>
335
- ${h.isLagna ? svg`<rect
336
- class="lagna-bg"
337
- x=${center.x - 30} y=${center.y - 28}
338
- width="60" height="56" rx="6"
339
- />` : nothing}
340
- ${signAbbr ? svg`<text class="sign-text" x=${signPos.x} y=${signPos.y} text-anchor="middle" dominant-baseline="central">${signAbbr}</text>` : nothing}
341
- ${h.isLagna ? svg`<text class="lagna-marker" x=${center.x} y=${center.y - 18} text-anchor="middle" dominant-baseline="central">LAGNA</text>` : nothing}
342
- ${renderPlanetStack(h.planets, center.x, baseY, 13)}
332
+ <rect class="line" x=${a} y=${a} width=${INNER} height=${INNER} stroke-width="1.5" fill="none" />
333
+ <line class="line" x1=${a} y1=${b} x2=${e} y2=${b} stroke-width="1" />
334
+ <line class="line" x1=${a} y1=${d} x2=${e} y2=${d} stroke-width="1" />
335
+ <line class="line" x1=${b} y1=${a} x2=${b} y2=${e} stroke-width="1" />
336
+ <line class="line" x1=${d} y1=${a} x2=${d} y2=${e} stroke-width="1" />
337
+ <line class="line" x1=${a} y1=${c} x2=${b} y2=${c} stroke-width="1" />
338
+ <line class="line" x1=${d} y1=${c} x2=${e} y2=${c} stroke-width="1" />
339
+ <line class="line" x1=${c} y1=${a} x2=${c} y2=${b} stroke-width="1" />
340
+ <line class="line" x1=${c} y1=${d} x2=${c} y2=${e} stroke-width="1" />
341
+ ${divisionLabel ? svg`<text class="centre-label" x=${CENTRE} y=${CENTRE} text-anchor="middle" dominant-baseline="central">${divisionLabel}</text>` : nothing}
342
+ `;
343
+ }
344
+ function houseNumberInSign(sign, lagnaSign) {
345
+ const lagnaIdx = SIGNS_ORDER.findIndex((s) => s === lagnaSign);
346
+ const signIdx = SIGNS_ORDER.findIndex((s) => s === sign);
347
+ if (lagnaIdx === -1 || signIdx === -1) return 0;
348
+ return (signIdx - lagnaIdx + 12) % 12 + 1;
349
+ }
350
+ function renderSouthCell(sign, planets, isLagna, houseNum) {
351
+ const r = southCellRect(sign);
352
+ const cx = r.x + r.w / 2;
353
+ const cy = r.y + r.h / 2;
354
+ const signAbbr = SIGN_ABBR[sign] ?? sign.slice(0, 2);
355
+ const slashInset = 14;
356
+ return svg`
357
+ <g class=${isLagna ? "cell lagna" : "cell"}>
358
+ ${isLagna ? svg`
359
+ <rect class="lagna-bg" x=${r.x} y=${r.y} width=${r.w} height=${r.h} />
360
+ <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" />
361
+ ` : nothing}
362
+ <text class="sign-text" x=${r.x + 6} y=${r.y + 12} text-anchor="start" dominant-baseline="central">${signAbbr}</text>
363
+ ${houseNum > 0 ? svg`<text class="house-num" x=${r.x + r.w - 6} y=${r.y + 12} text-anchor="end" dominant-baseline="central">${houseNum}</text>` : nothing}
364
+ ${planets.length ? renderPlanetStack(planets, sign, cx, cy + 4, 14) : nothing}
343
365
  </g>
344
366
  `;
345
367
  }
346
- function renderNorthFrame() {
368
+ function renderSouthSvg(vm) {
369
+ const lagnaKey = vm.lagnaSign.toLowerCase();
370
+ return svg`
371
+ ${renderSouthFrame(vm.divisionLabel)}
372
+ ${SIGNS_ORDER.map(
373
+ (sign) => renderSouthCell(
374
+ sign,
375
+ vm.placements[sign.toLowerCase()] ?? [],
376
+ sign.toLowerCase() === lagnaKey,
377
+ houseNumberInSign(sign, vm.lagnaSign)
378
+ )
379
+ )}
380
+ `;
381
+ }
382
+ var NORTH_VERTICES = {
383
+ tl: { x: MARGIN, y: MARGIN },
384
+ tr: { x: VIEW_BOX - MARGIN, y: MARGIN },
385
+ br: { x: VIEW_BOX - MARGIN, y: VIEW_BOX - MARGIN },
386
+ bl: { x: MARGIN, y: VIEW_BOX - MARGIN },
387
+ top: { x: CENTRE, y: MARGIN },
388
+ right: { x: VIEW_BOX - MARGIN, y: CENTRE },
389
+ bottom: { x: CENTRE, y: VIEW_BOX - MARGIN },
390
+ left: { x: MARGIN, y: CENTRE },
391
+ tlMid: { x: CENTRE - INNER / 4, y: CENTRE - INNER / 4 },
392
+ trMid: { x: CENTRE + INNER / 4, y: CENTRE - INNER / 4 },
393
+ brMid: { x: CENTRE + INNER / 4, y: CENTRE + INNER / 4 },
394
+ blMid: { x: CENTRE - INNER / 4, y: CENTRE + INNER / 4 }
395
+ };
396
+ function centroidOf(pts) {
397
+ const x = pts.reduce((s, p) => s + p.x, 0) / pts.length;
398
+ const y = pts.reduce((s, p) => s + p.y, 0) / pts.length;
399
+ return { x, y };
400
+ }
401
+ var NORTH_HOUSE_CENTERS = {
402
+ 1: { x: CENTRE, y: NORTH_VERTICES.tlMid.y },
403
+ 2: centroidOf([NORTH_VERTICES.tl, NORTH_VERTICES.top, NORTH_VERTICES.tlMid]),
404
+ 3: centroidOf([NORTH_VERTICES.tl, NORTH_VERTICES.left, NORTH_VERTICES.tlMid]),
405
+ 4: { x: NORTH_VERTICES.tlMid.x, y: CENTRE },
406
+ 5: centroidOf([NORTH_VERTICES.bl, NORTH_VERTICES.left, NORTH_VERTICES.blMid]),
407
+ 6: centroidOf([
408
+ NORTH_VERTICES.bl,
409
+ NORTH_VERTICES.bottom,
410
+ NORTH_VERTICES.blMid
411
+ ]),
412
+ 7: { x: CENTRE, y: NORTH_VERTICES.blMid.y },
413
+ 8: centroidOf([
414
+ NORTH_VERTICES.br,
415
+ NORTH_VERTICES.bottom,
416
+ NORTH_VERTICES.brMid
417
+ ]),
418
+ 9: centroidOf([
419
+ NORTH_VERTICES.br,
420
+ NORTH_VERTICES.right,
421
+ NORTH_VERTICES.brMid
422
+ ]),
423
+ 10: { x: NORTH_VERTICES.brMid.x, y: CENTRE },
424
+ 11: centroidOf([
425
+ NORTH_VERTICES.tr,
426
+ NORTH_VERTICES.right,
427
+ NORTH_VERTICES.trMid
428
+ ]),
429
+ 12: centroidOf([NORTH_VERTICES.tr, NORTH_VERTICES.top, NORTH_VERTICES.trMid])
430
+ };
431
+ function rashiInHouse(houseNum, lagnaSign) {
432
+ const lagnaIdx = SIGNS_ORDER.findIndex((s) => s === lagnaSign);
433
+ if (lagnaIdx === -1) return houseNum;
434
+ return (lagnaIdx + houseNum - 1) % 12 + 1;
435
+ }
436
+ function renderNorthFrame(divisionLabel) {
437
+ const { tl, tr, br, bl, top, right, bottom, left } = NORTH_VERTICES;
347
438
  return svg`
348
- <polygon class="line" points="150,10 290,150 150,290 10,150" stroke-width="1.5" />
349
- <line class="line" x1="150" y1="10" x2="150" y2="290" stroke-width="1" />
350
- <line class="line" x1="10" y1="150" x2="290" y2="150" stroke-width="1" />
351
- <line class="line" x1="150" y1="10" x2="10" y2="150" stroke-width="0.6" stroke-dasharray="3,3" />
352
- <line class="line" x1="150" y1="10" x2="290" y2="150" stroke-width="0.6" stroke-dasharray="3,3" />
353
- <line class="line" x1="150" y1="290" x2="10" y2="150" stroke-width="0.6" stroke-dasharray="3,3" />
354
- <line class="line" x1="150" y1="290" x2="290" y2="150" stroke-width="0.6" stroke-dasharray="3,3" />
439
+ <rect class="line" x=${tl.x} y=${tl.y} width=${INNER} height=${INNER} stroke-width="1.5" fill="none" />
440
+ <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" />
441
+ <line class="line" x1=${tl.x} y1=${tl.y} x2=${br.x} y2=${br.y} stroke-width="1" />
442
+ <line class="line" x1=${tr.x} y1=${tr.y} x2=${bl.x} y2=${bl.y} stroke-width="1" />
443
+ ${divisionLabel ? svg`<text class="centre-label" x=${CENTRE} y=${CENTRE} text-anchor="middle" dominant-baseline="central">${divisionLabel}</text>` : nothing}
355
444
  `;
356
445
  }
357
- function renderNorthHouseGroup(h) {
358
- const center = NORTH_HOUSE_CENTERS[h.number];
359
- if (!center) return nothing;
360
- const signAbbr = SIGN_ABBR[h.sign] ?? "";
446
+ function renderNorthCell(houseNum, rashiNum, sign, planets, isLagna) {
447
+ const c = NORTH_HOUSE_CENTERS[houseNum];
448
+ if (!c) return svg``;
449
+ const rashiOffsetY = Math.min(14, Math.abs(c.y - CENTRE) * 0.45 + 6);
450
+ const ascOffsetY = rashiOffsetY + 12;
361
451
  return svg`
362
- <g>
363
- ${h.isLagna ? svg`<circle class="lagna-bg" cx=${center.x} cy=${center.y} r="22" />` : nothing}
364
- ${signAbbr ? svg`<text class="sign-text" x=${center.x} y=${center.y - 10} text-anchor="middle" dominant-baseline="central">${signAbbr}</text>` : nothing}
365
- <text class="house-num" x=${center.x} y=${center.y + 2} text-anchor="middle" dominant-baseline="central">${h.number}</text>
366
- ${renderPlanetStack(h.planets, center.x, center.y + 14, 11)}
452
+ <g class=${isLagna ? "cell lagna" : "cell"}>
453
+ <text class="rashi-num" x=${c.x} y=${c.y - rashiOffsetY} text-anchor="middle" dominant-baseline="central">${rashiNum}</text>
454
+ ${isLagna ? svg`<text class="lagna-marker" x=${c.x} y=${c.y - ascOffsetY} text-anchor="middle" dominant-baseline="central">Asc</text>` : nothing}
455
+ ${planets.length ? renderPlanetStack(planets, sign, c.x, c.y + 8, 12) : nothing}
367
456
  </g>
368
457
  `;
369
458
  }
370
- function renderSouthFrame() {
459
+ function renderNorthSvg(vm) {
460
+ const lagnaSign = vm.lagnaSign || "Aries";
371
461
  return svg`
372
- <polygon class="line" points="150,10 290,150 150,290 10,150" stroke-width="1.5" />
373
- <polygon class="line" points="220,80 220,220 80,220 80,80" stroke-width="1" fill="none" />
374
- <line class="line" x1="150" y1="10" x2="80" y2="80" stroke-width="1" />
375
- <line class="line" x1="150" y1="10" x2="220" y2="80" stroke-width="1" />
376
- <line class="line" x1="290" y1="150" x2="220" y2="80" stroke-width="1" />
377
- <line class="line" x1="290" y1="150" x2="220" y2="220" stroke-width="1" />
378
- <line class="line" x1="150" y1="290" x2="220" y2="220" stroke-width="1" />
379
- <line class="line" x1="150" y1="290" x2="80" y2="220" stroke-width="1" />
380
- <line class="line" x1="10" y1="150" x2="80" y2="220" stroke-width="1" />
381
- <line class="line" x1="10" y1="150" x2="80" y2="80" stroke-width="1" />
462
+ ${renderNorthFrame(vm.divisionLabel)}
463
+ ${Array.from({ length: 12 }, (_, i) => {
464
+ const houseNum = i + 1;
465
+ const rashiNum = rashiInHouse(houseNum, lagnaSign);
466
+ const sign = SIGNS_ORDER[rashiNum - 1] ?? "Aries";
467
+ return renderNorthCell(
468
+ houseNum,
469
+ rashiNum,
470
+ sign,
471
+ vm.placements[sign.toLowerCase()] ?? [],
472
+ houseNum === 1
473
+ );
474
+ })}
382
475
  `;
383
476
  }
384
- function renderEastFrame() {
477
+ var EAST_CELL = INNER / 3;
478
+ function eastCells() {
479
+ const a = MARGIN;
480
+ const b = MARGIN + EAST_CELL;
481
+ const c = MARGIN + 2 * EAST_CELL;
482
+ const d = VIEW_BOX - MARGIN;
483
+ const aries = [
484
+ { x: b, y: a },
485
+ { x: c, y: a },
486
+ { x: c, y: b },
487
+ { x: b, y: b }
488
+ ];
489
+ const cancer = [
490
+ { x: a, y: b },
491
+ { x: b, y: b },
492
+ { x: b, y: c },
493
+ { x: a, y: c }
494
+ ];
495
+ const libra = [
496
+ { x: b, y: c },
497
+ { x: c, y: c },
498
+ { x: c, y: d },
499
+ { x: b, y: d }
500
+ ];
501
+ const capricorn = [
502
+ { x: c, y: b },
503
+ { x: d, y: b },
504
+ { x: d, y: c },
505
+ { x: c, y: c }
506
+ ];
507
+ const taurus = [
508
+ { x: a, y: a },
509
+ { x: b, y: a },
510
+ { x: b, y: b }
511
+ ];
512
+ const gemini = [
513
+ { x: a, y: a },
514
+ { x: b, y: b },
515
+ { x: a, y: b }
516
+ ];
517
+ const leo = [
518
+ { x: a, y: c },
519
+ { x: b, y: c },
520
+ { x: a, y: d }
521
+ ];
522
+ const virgo = [
523
+ { x: b, y: c },
524
+ { x: b, y: d },
525
+ { x: a, y: d }
526
+ ];
527
+ const scorpio = [
528
+ { x: c, y: c },
529
+ { x: c, y: d },
530
+ { x: d, y: d }
531
+ ];
532
+ const sagittarius = [
533
+ { x: c, y: c },
534
+ { x: d, y: d },
535
+ { x: d, y: c }
536
+ ];
537
+ const aquarius = [
538
+ { x: d, y: a },
539
+ { x: d, y: b },
540
+ { x: c, y: b }
541
+ ];
542
+ const pisces = [
543
+ { x: c, y: a },
544
+ { x: d, y: a },
545
+ { x: c, y: b }
546
+ ];
547
+ const polys = {
548
+ Aries: aries,
549
+ Taurus: taurus,
550
+ Gemini: gemini,
551
+ Cancer: cancer,
552
+ Leo: leo,
553
+ Virgo: virgo,
554
+ Libra: libra,
555
+ Scorpio: scorpio,
556
+ Sagittarius: sagittarius,
557
+ Capricorn: capricorn,
558
+ Aquarius: aquarius,
559
+ Pisces: pisces
560
+ };
561
+ const out = {};
562
+ for (const [sign, points] of Object.entries(polys)) {
563
+ out[sign] = { points: [...points], centroid: centroidOf(points) };
564
+ }
565
+ return out;
566
+ }
567
+ var EAST_CELLS = eastCells();
568
+ function renderEastFrame(divisionLabel) {
569
+ const a = MARGIN;
570
+ const b = MARGIN + EAST_CELL;
571
+ const c = MARGIN + 2 * EAST_CELL;
572
+ const d = VIEW_BOX - MARGIN;
385
573
  return svg`
386
- <rect class="line" x="10" y="10" width="280" height="280" stroke-width="1.5" fill="none" />
387
- <line class="line" x1="10" y1="10" x2="290" y2="290" stroke-width="1" />
388
- <line class="line" x1="290" y1="10" x2="10" y2="290" stroke-width="1" />
389
- <polygon class="line" points="150,10 290,150 150,290 10,150" stroke-width="1" fill="none" />
574
+ <rect class="line" x=${a} y=${a} width=${INNER} height=${INNER} stroke-width="1.5" fill="none" />
575
+ <line class="line" x1=${a} y1=${b} x2=${b} y2=${b} stroke-width="1" />
576
+ <line class="line" x1=${c} y1=${b} x2=${d} y2=${b} stroke-width="1" />
577
+ <line class="line" x1=${a} y1=${c} x2=${b} y2=${c} stroke-width="1" />
578
+ <line class="line" x1=${c} y1=${c} x2=${d} y2=${c} stroke-width="1" />
579
+ <line class="line" x1=${b} y1=${a} x2=${b} y2=${b} stroke-width="1" />
580
+ <line class="line" x1=${b} y1=${c} x2=${b} y2=${d} stroke-width="1" />
581
+ <line class="line" x1=${c} y1=${a} x2=${c} y2=${b} stroke-width="1" />
582
+ <line class="line" x1=${c} y1=${c} x2=${c} y2=${d} stroke-width="1" />
583
+ <line class="line" x1=${a} y1=${a} x2=${b} y2=${b} stroke-width="1" />
584
+ <line class="line" x1=${d} y1=${a} x2=${c} y2=${b} stroke-width="1" />
585
+ <line class="line" x1=${d} y1=${d} x2=${c} y2=${c} stroke-width="1" />
586
+ <line class="line" x1=${a} y1=${d} x2=${b} y2=${c} stroke-width="1" />
587
+ ${divisionLabel ? svg`<text class="centre-label" x=${CENTRE} y=${CENTRE} text-anchor="middle" dominant-baseline="central">${divisionLabel}</text>` : nothing}
390
588
  `;
391
589
  }
392
- function renderEastHouseGroup(h) {
393
- const center = EAST_HOUSE_CENTERS[h.number];
394
- const signPos = EAST_SIGN_POSITIONS[h.number];
395
- if (!center || !signPos) return nothing;
396
- const signAbbr = SIGN_ABBR[h.sign] ?? "";
590
+ function renderEastCell(sign, planets, isLagna, houseNum) {
591
+ const cell = EAST_CELLS[sign];
592
+ if (!cell) return svg``;
593
+ const { centroid: cen, points } = cell;
594
+ const signAbbr = SIGN_ABBR[sign] ?? sign.slice(0, 2);
595
+ const polyPoints = points.map((p) => `${p.x},${p.y}`).join(" ");
397
596
  return svg`
398
- <g>
399
- ${h.isLagna ? svg`<circle class="lagna-bg" cx=${center.x} cy=${center.y} r="20" />` : nothing}
400
- ${signAbbr ? svg`<text class="sign-text" x=${signPos.x} y=${signPos.y} text-anchor="middle" dominant-baseline="central">${signAbbr}</text>` : nothing}
401
- ${h.isLagna ? svg`<text class="lagna-marker" x=${center.x} y=${center.y - 14} text-anchor="middle" dominant-baseline="central">LAGNA</text>` : nothing}
402
- ${renderPlanetStack(h.planets, center.x, center.y + 2, 11)}
597
+ <g class=${isLagna ? "cell lagna" : "cell"}>
598
+ ${isLagna ? svg`<polygon class="lagna-bg" points=${polyPoints} />` : nothing}
599
+ <text class="sign-text" x=${cen.x} y=${cen.y - 16} text-anchor="middle" dominant-baseline="central">${signAbbr}</text>
600
+ ${houseNum > 0 ? svg`<text class="house-num" x=${cen.x + 18} y=${cen.y - 16} text-anchor="start" dominant-baseline="central">${houseNum}</text>` : nothing}
601
+ ${isLagna ? svg`<text class="lagna-marker" x=${cen.x} y=${cen.y - 30} text-anchor="middle" dominant-baseline="central">Asc</text>` : nothing}
602
+ ${planets.length ? renderPlanetStack(planets, sign, cen.x, cen.y + 4, 12) : nothing}
403
603
  </g>
404
604
  `;
405
605
  }
406
- function buildHousesFromMeta(meta) {
407
- const byRashi = /* @__PURE__ */ new Map();
408
- let lagnaKey = "";
409
- for (const [name, pos] of Object.entries(meta)) {
410
- const rashiKey = (pos?.rashi ?? "").toLowerCase();
411
- if (name === "Lagna" || pos?.graha === "Lagna") {
412
- lagnaKey = rashiKey;
413
- continue;
414
- }
415
- if (!rashiKey) continue;
416
- const list = byRashi.get(rashiKey) ?? [];
417
- list.push({
418
- graha: pos.graha ?? name,
419
- longitude: pos.longitude,
420
- nakshatra: pos.nakshatra,
421
- isRetrograde: pos.isRetrograde,
422
- awastha: pos.awastha
423
- });
424
- byRashi.set(rashiKey, list);
425
- }
426
- return SIGNS_ORDER.map((sign, i) => {
427
- const key = sign.toLowerCase();
428
- return {
429
- number: i + 1,
606
+ function renderEastSvg(vm) {
607
+ const lagnaKey = vm.lagnaSign.toLowerCase();
608
+ return svg`
609
+ ${renderEastFrame(vm.divisionLabel)}
610
+ ${SIGNS_ORDER.map(
611
+ (sign) => renderEastCell(
430
612
  sign,
431
- planets: byRashi.get(key) ?? [],
432
- isLagna: lagnaKey === key
433
- };
434
- });
613
+ vm.placements[sign.toLowerCase()] ?? [],
614
+ sign.toLowerCase() === lagnaKey,
615
+ houseNumberInSign(sign, vm.lagnaSign)
616
+ )
617
+ )}
618
+ `;
435
619
  }
620
+ function renderKundliSvg(vm, style) {
621
+ switch (style) {
622
+ case "north":
623
+ return renderNorthSvg(vm);
624
+ case "east":
625
+ return renderEastSvg(vm);
626
+ default:
627
+ return renderSouthSvg(vm);
628
+ }
629
+ }
630
+ function renderKundliStyleTablist(active, setStyle) {
631
+ const onKeyDown = (e) => {
632
+ const idx = CHART_STYLES.findIndex((s) => s.id === active);
633
+ if (e.key === "ArrowRight") {
634
+ e.preventDefault();
635
+ const next = CHART_STYLES[(idx + 1) % CHART_STYLES.length];
636
+ if (next) setStyle(next.id);
637
+ } else if (e.key === "ArrowLeft") {
638
+ e.preventDefault();
639
+ const next = CHART_STYLES[(idx - 1 + CHART_STYLES.length) % CHART_STYLES.length];
640
+ if (next) setStyle(next.id);
641
+ }
642
+ };
643
+ return html`<div
644
+ class="kundli-tablist"
645
+ role="tablist"
646
+ aria-label="Kundli style"
647
+ @keydown=${onKeyDown}
648
+ >
649
+ ${CHART_STYLES.map(
650
+ (s) => html`<button
651
+ type="button"
652
+ class="kundli-tab"
653
+ role="tab"
654
+ id="kundli-tab-${s.id}"
655
+ aria-selected=${active === s.id ? "true" : "false"}
656
+ tabindex=${active === s.id ? "0" : "-1"}
657
+ @click=${() => setStyle(s.id)}
658
+ >
659
+ ${s.label}
660
+ </button>`
661
+ )}
662
+ </div>`;
663
+ }
664
+
665
+ // packages/ui/src/utils/kundli-styles.ts
666
+ import { css as css2 } from "lit";
667
+ var kundliStyles = css2`
668
+ .wrap {
669
+ display: grid;
670
+ gap: var(--roxy-space-md, 1rem);
671
+ }
672
+ .header {
673
+ display: flex;
674
+ flex-wrap: wrap;
675
+ align-items: center;
676
+ justify-content: space-between;
677
+ gap: var(--roxy-space-sm, 0.5rem);
678
+ }
679
+ .title {
680
+ font-size: var(--roxy-text-lg, 1.125rem);
681
+ font-weight: var(--roxy-weight-bold, 600);
682
+ margin: 0;
683
+ }
684
+ .kundli-tablist {
685
+ display: inline-flex;
686
+ gap: 2px;
687
+ border-bottom: 2px solid var(--roxy-border, #e4e4e7);
688
+ }
689
+ .kundli-tab {
690
+ padding: var(--roxy-space-xs, 0.25rem) var(--roxy-space-md, 1rem);
691
+ font-size: var(--roxy-text-sm, 0.875rem);
692
+ background: none;
693
+ border: none;
694
+ border-bottom: 2px solid transparent;
695
+ margin-bottom: -2px;
696
+ cursor: pointer;
697
+ color: var(--roxy-muted, #71717a);
698
+ font-family: inherit;
699
+ transition: color var(--roxy-motion-duration, 200ms)
700
+ var(--roxy-motion-easing, ease);
701
+ }
702
+ .kundli-tab[aria-selected='true'] {
703
+ color: var(--roxy-accent-fg, #b45309);
704
+ border-bottom-color: var(--roxy-accent, #f59e0b);
705
+ font-weight: var(--roxy-weight-bold, 600);
706
+ }
707
+ .kundli-tab:hover:not([aria-selected='true']) {
708
+ color: var(--roxy-fg, #0a0a0a);
709
+ }
710
+ .kundli-tab:focus-visible {
711
+ outline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));
712
+ outline-offset: 2px;
713
+ border-radius: 4px;
714
+ }
715
+ svg {
716
+ display: block;
717
+ width: 100%;
718
+ max-width: 560px;
719
+ aspect-ratio: 1 / 1;
720
+ height: auto;
721
+ margin: 0 auto;
722
+ }
723
+ .line {
724
+ fill: transparent;
725
+ stroke: var(--roxy-border, #d4d4d8);
726
+ }
727
+ .sign-text {
728
+ fill: var(--roxy-muted, #71717a);
729
+ font-size: 11px;
730
+ font-weight: 500;
731
+ font-family: var(--roxy-font-sans);
732
+ text-transform: uppercase;
733
+ letter-spacing: 0.04em;
734
+ }
735
+ .rashi-num {
736
+ fill: var(--roxy-muted, #71717a);
737
+ font-size: 12px;
738
+ font-weight: 500;
739
+ font-family: var(--roxy-font-sans);
740
+ }
741
+ .house-num {
742
+ fill: var(--roxy-accent-fg, #b45309);
743
+ font-size: 11px;
744
+ font-weight: 600;
745
+ font-family: var(--roxy-font-sans);
746
+ opacity: 0.85;
747
+ }
748
+ .planet-text {
749
+ fill: var(--roxy-fg, #0a0a0a);
750
+ font-size: 13px;
751
+ font-weight: 600;
752
+ font-family: var(--roxy-font-sans);
753
+ }
754
+ .centre-label {
755
+ fill: var(--roxy-muted, #71717a);
756
+ font-size: 14px;
757
+ font-weight: 600;
758
+ font-family: var(--roxy-font-sans);
759
+ letter-spacing: 0.02em;
760
+ }
761
+ .lagna-marker {
762
+ fill: var(--roxy-accent-fg, #b45309);
763
+ font-size: 10px;
764
+ font-weight: 700;
765
+ font-family: var(--roxy-font-sans);
766
+ letter-spacing: 0.08em;
767
+ text-transform: uppercase;
768
+ }
769
+ .lagna-bg {
770
+ fill: color-mix(in srgb, var(--roxy-accent, #f59e0b) 14%, transparent);
771
+ }
772
+ .lagna-slash {
773
+ stroke: var(--roxy-accent, #f59e0b);
774
+ stroke-linecap: round;
775
+ opacity: 0.7;
776
+ }
777
+ `;
436
778
 
437
779
  // packages/ui/src/components/divisional-chart.ts
438
780
  var RoxyDivisionalChart = class extends LitElement {
439
781
  constructor() {
440
782
  super(...arguments);
441
783
  this.data = null;
442
- this.chartStyle = "south";
784
+ this.chartStyle = "north";
785
+ this.setStyle = (next) => {
786
+ this.chartStyle = next;
787
+ };
443
788
  }
444
- buildHouses() {
445
- if (!this.data?.chart?.meta) return [];
446
- return buildHousesFromMeta(this.data.chart.meta);
789
+ viewModel() {
790
+ if (!this.data?.chart?.meta) return null;
791
+ const { division } = this.data;
792
+ const label = `D${division.number} ${division.name}`;
793
+ return toKundliViewModel(this.data.chart.meta, label);
447
794
  }
448
795
  render() {
449
- if (!this.data)
450
- return html`<div class="roxy-empty" role="status">No divisional chart data</div>`;
796
+ const vm = this.viewModel();
797
+ if (!this.data || !vm)
798
+ return html2`<div class="roxy-empty" role="status">No divisional chart data</div>`;
451
799
  const { division, vargottama } = this.data;
452
- const houses = this.buildHouses();
453
- const style = this.chartStyle;
454
- const frame = style === "north" ? renderNorthFrame() : style === "east" ? renderEastFrame() : renderSouthFrame();
455
- const houseGroup = style === "north" ? renderNorthHouseGroup : style === "east" ? renderEastHouseGroup : renderSouthHouseGroup;
456
- return html`<div class="wrap">
800
+ return html2`<div class="wrap">
457
801
  <div class="header">
458
- <h2 class="title">
459
- D${division.number} ${division.name}
460
- ${division.sanskritName && division.sanskritName !== division.name ? html`<span class="division-meta"> · ${division.sanskritName}</span>` : nothing2}
461
- </h2>
462
- ${division.significance ? html`<p class="significance">${division.significance}</p>` : nothing2}
802
+ <div>
803
+ <h2 class="title">
804
+ D${division.number} ${division.name}
805
+ ${division.sanskritName && division.sanskritName !== division.name ? html2`<span class="division-meta"> · ${division.sanskritName}</span>` : nothing2}
806
+ </h2>
807
+ ${division.significance ? html2`<p class="significance">${division.significance}</p>` : nothing2}
808
+ </div>
809
+ ${renderKundliStyleTablist(this.chartStyle, this.setStyle)}
463
810
  </div>
464
811
 
465
812
  <svg
466
- viewBox="0 0 300 300"
813
+ viewBox="0 0 400 400"
814
+ preserveAspectRatio="xMidYMid meet"
467
815
  role="img"
468
816
  aria-label="D${division.number} ${division.name} divisional chart with twelve sign houses"
469
817
  >
470
818
  <title>D${division.number} ${division.name}</title>
471
- ${frame}
472
- ${houses.map((h) => houseGroup(h))}
819
+ ${renderKundliSvg(vm, this.chartStyle)}
473
820
  </svg>
474
821
 
475
- ${vargottama && vargottama.length > 0 ? html`<div class="vargottama-row" role="list" aria-label="Vargottama planets">
822
+ ${vargottama && vargottama.length > 0 ? html2`<div class="vargottama-row" role="list" aria-label="Vargottama planets">
476
823
  <span class="vargottama-label">Vargottama:</span>
477
824
  ${vargottama.map(
478
- (planet) => html`<span class="vargottama-pill" role="listitem">
825
+ (planet) => html2`<span class="vargottama-pill" role="listitem">
479
826
  ${PLANET_GLYPH[planet] ?? ""} ${planet}
480
827
  </span>`
481
828
  )}
@@ -485,20 +832,8 @@ var RoxyDivisionalChart = class extends LitElement {
485
832
  };
486
833
  RoxyDivisionalChart.styles = [
487
834
  baseStyles,
488
- css2`
489
- .wrap {
490
- display: grid;
491
- gap: var(--roxy-space-md, 1rem);
492
- }
493
- .header {
494
- display: grid;
495
- gap: var(--roxy-space-xs, 0.25rem);
496
- }
497
- .title {
498
- font-size: var(--roxy-text-lg, 1.125rem);
499
- font-weight: var(--roxy-weight-bold, 600);
500
- margin: 0;
501
- }
835
+ kundliStyles,
836
+ css3`
502
837
  .division-meta {
503
838
  font-size: var(--roxy-text-sm, 0.875rem);
504
839
  color: var(--roxy-muted, #71717a);
@@ -511,46 +846,6 @@ RoxyDivisionalChart.styles = [
511
846
  padding-left: var(--roxy-space-sm, 0.5rem);
512
847
  margin: 0;
513
848
  }
514
- svg {
515
- display: block;
516
- width: 100%;
517
- max-width: 360px;
518
- margin: 0 auto;
519
- }
520
- .line {
521
- fill: transparent;
522
- stroke: var(--roxy-border, #e4e4e7);
523
- }
524
- .sign-text {
525
- fill: var(--roxy-muted, #71717a);
526
- font-size: 9px;
527
- font-weight: 500;
528
- font-family: var(--roxy-font-sans);
529
- }
530
- .planet-text {
531
- fill: var(--roxy-fg, #0a0a0a);
532
- font-size: 11px;
533
- font-weight: 600;
534
- font-family: var(--roxy-font-sans);
535
- }
536
- .house-num {
537
- fill: var(--roxy-muted, #71717a);
538
- font-size: 9px;
539
- font-weight: 400;
540
- font-family: var(--roxy-font-sans);
541
- }
542
- .lagna-marker {
543
- fill: var(--roxy-accent-fg, #b45309);
544
- font-size: 8px;
545
- font-weight: 700;
546
- font-family: var(--roxy-font-sans);
547
- letter-spacing: 0.05em;
548
- }
549
- .lagna-bg {
550
- fill: color-mix(in srgb, var(--roxy-accent, #f59e0b) 12%, transparent);
551
- stroke: color-mix(in srgb, var(--roxy-accent, #f59e0b) 45%, transparent);
552
- stroke-width: 0.8;
553
- }
554
849
  .vargottama-row {
555
850
  display: flex;
556
851
  flex-wrap: wrap;