@roxyapi/ui 0.1.1 → 0.1.3

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 (169) hide show
  1. package/AGENTS.md +2 -2
  2. package/LICENSE +21 -0
  3. package/README.md +505 -0
  4. package/THEMING.md +24 -7
  5. package/dist/cdn/components/biorhythm-chart.js +15 -22
  6. package/dist/cdn/components/biorhythm-chart.js.map +3 -3
  7. package/dist/cdn/components/compatibility-card.js +36 -34
  8. package/dist/cdn/components/compatibility-card.js.map +4 -4
  9. package/dist/cdn/components/dasha-timeline.js +35 -39
  10. package/dist/cdn/components/dasha-timeline.js.map +4 -4
  11. package/dist/cdn/components/data.js +6 -6
  12. package/dist/cdn/components/data.js.map +3 -3
  13. package/dist/cdn/components/dosha-card.js +13 -13
  14. package/dist/cdn/components/dosha-card.js.map +2 -2
  15. package/dist/cdn/components/endpoint-form.js +47 -28
  16. package/dist/cdn/components/endpoint-form.js.map +3 -3
  17. package/dist/cdn/components/guna-milan.js +18 -18
  18. package/dist/cdn/components/guna-milan.js.map +4 -4
  19. package/dist/cdn/components/hexagram.js +26 -26
  20. package/dist/cdn/components/hexagram.js.map +3 -3
  21. package/dist/cdn/components/horoscope-card.js +38 -38
  22. package/dist/cdn/components/horoscope-card.js.map +3 -3
  23. package/dist/cdn/components/kp-planets-table.js +10 -10
  24. package/dist/cdn/components/kp-planets-table.js.map +4 -4
  25. package/dist/cdn/components/location-search.js +6 -6
  26. package/dist/cdn/components/location-search.js.map +3 -3
  27. package/dist/cdn/components/moon-phase.js +21 -21
  28. package/dist/cdn/components/moon-phase.js.map +4 -4
  29. package/dist/cdn/components/natal-chart.js +61 -19
  30. package/dist/cdn/components/natal-chart.js.map +4 -4
  31. package/dist/cdn/components/numerology-card.js +40 -31
  32. package/dist/cdn/components/numerology-card.js.map +3 -3
  33. package/dist/cdn/components/panchang-table.js +25 -25
  34. package/dist/cdn/components/panchang-table.js.map +4 -4
  35. package/dist/cdn/components/synastry-chart.js +129 -39
  36. package/dist/cdn/components/synastry-chart.js.map +4 -4
  37. package/dist/cdn/components/tarot-card.js +49 -20
  38. package/dist/cdn/components/tarot-card.js.map +3 -3
  39. package/dist/cdn/components/tarot-spread.js +43 -27
  40. package/dist/cdn/components/tarot-spread.js.map +3 -3
  41. package/dist/cdn/components/vedic-kundli.js +23 -9
  42. package/dist/cdn/components/vedic-kundli.js.map +3 -3
  43. package/dist/cdn/roxy-ui.js +560 -350
  44. package/dist/cdn/roxy-ui.js.map +4 -4
  45. package/dist/components/biorhythm-chart.d.ts +2 -46
  46. package/dist/components/biorhythm-chart.d.ts.map +1 -1
  47. package/dist/components/biorhythm-chart.js +24 -23
  48. package/dist/components/biorhythm-chart.js.map +2 -2
  49. package/dist/components/compatibility-card.d.ts +2 -27
  50. package/dist/components/compatibility-card.d.ts.map +1 -1
  51. package/dist/components/compatibility-card.js +50 -29
  52. package/dist/components/compatibility-card.js.map +3 -3
  53. package/dist/components/dasha-timeline.d.ts +2 -31
  54. package/dist/components/dasha-timeline.d.ts.map +1 -1
  55. package/dist/components/dasha-timeline.js +32 -30
  56. package/dist/components/dasha-timeline.js.map +3 -3
  57. package/dist/components/data.d.ts +6 -0
  58. package/dist/components/data.d.ts.map +1 -1
  59. package/dist/components/data.js +9 -1
  60. package/dist/components/data.js.map +2 -2
  61. package/dist/components/dosha-card.d.ts +2 -16
  62. package/dist/components/dosha-card.d.ts.map +1 -1
  63. package/dist/components/dosha-card.js +12 -13
  64. package/dist/components/dosha-card.js.map +2 -2
  65. package/dist/components/endpoint-form.d.ts +2 -0
  66. package/dist/components/endpoint-form.d.ts.map +1 -1
  67. package/dist/components/endpoint-form.js +66 -8
  68. package/dist/components/endpoint-form.js.map +2 -2
  69. package/dist/components/guna-milan.d.ts +2 -20
  70. package/dist/components/guna-milan.d.ts.map +1 -1
  71. package/dist/components/guna-milan.js +22 -12
  72. package/dist/components/guna-milan.js.map +3 -3
  73. package/dist/components/hexagram.d.ts +3 -27
  74. package/dist/components/hexagram.d.ts.map +1 -1
  75. package/dist/components/hexagram.js +31 -15
  76. package/dist/components/hexagram.js.map +2 -2
  77. package/dist/components/horoscope-card.d.ts +2 -20
  78. package/dist/components/horoscope-card.d.ts.map +1 -1
  79. package/dist/components/horoscope-card.js +24 -15
  80. package/dist/components/horoscope-card.js.map +2 -2
  81. package/dist/components/kp-planets-table.d.ts +2 -21
  82. package/dist/components/kp-planets-table.d.ts.map +1 -1
  83. package/dist/components/kp-planets-table.js +10 -4
  84. package/dist/components/kp-planets-table.js.map +3 -3
  85. package/dist/components/location-search.d.ts +3 -11
  86. package/dist/components/location-search.d.ts.map +1 -1
  87. package/dist/components/location-search.js +45 -5
  88. package/dist/components/location-search.js.map +2 -2
  89. package/dist/components/moon-phase.d.ts +4 -21
  90. package/dist/components/moon-phase.d.ts.map +1 -1
  91. package/dist/components/moon-phase.js +17 -4
  92. package/dist/components/moon-phase.js.map +3 -3
  93. package/dist/components/natal-chart.d.ts +7 -43
  94. package/dist/components/natal-chart.d.ts.map +1 -1
  95. package/dist/components/natal-chart.js +130 -70
  96. package/dist/components/natal-chart.js.map +3 -3
  97. package/dist/components/numerology-card.d.ts +5 -37
  98. package/dist/components/numerology-card.d.ts.map +1 -1
  99. package/dist/components/numerology-card.js +54 -28
  100. package/dist/components/numerology-card.js.map +2 -2
  101. package/dist/components/panchang-table.d.ts +3 -62
  102. package/dist/components/panchang-table.d.ts.map +1 -1
  103. package/dist/components/panchang-table.js +62 -32
  104. package/dist/components/panchang-table.js.map +3 -3
  105. package/dist/components/synastry-chart.d.ts +9 -28
  106. package/dist/components/synastry-chart.d.ts.map +1 -1
  107. package/dist/components/synastry-chart.js +178 -38
  108. package/dist/components/synastry-chart.js.map +3 -3
  109. package/dist/components/tarot-card.d.ts +5 -29
  110. package/dist/components/tarot-card.d.ts.map +1 -1
  111. package/dist/components/tarot-card.js +59 -20
  112. package/dist/components/tarot-card.js.map +2 -2
  113. package/dist/components/tarot-spread.d.ts +2 -24
  114. package/dist/components/tarot-spread.d.ts.map +1 -1
  115. package/dist/components/tarot-spread.js +39 -13
  116. package/dist/components/tarot-spread.js.map +2 -2
  117. package/dist/components/vedic-kundli.d.ts +3 -23
  118. package/dist/components/vedic-kundli.d.ts.map +1 -1
  119. package/dist/components/vedic-kundli.js +25 -13
  120. package/dist/components/vedic-kundli.js.map +2 -2
  121. package/dist/index.cjs +1149 -358
  122. package/dist/index.cjs.map +4 -4
  123. package/dist/index.d.ts +6 -4
  124. package/dist/index.d.ts.map +1 -1
  125. package/dist/index.js +1149 -358
  126. package/dist/index.js.map +4 -4
  127. package/dist/manifest.d.ts +49 -0
  128. package/dist/manifest.d.ts.map +1 -0
  129. package/dist/manifest.json +1 -1
  130. package/dist/styles/tokens.css +47 -1
  131. package/dist/tokens/index.d.ts.map +1 -1
  132. package/dist/types/index.d.ts +2 -0
  133. package/dist/types/index.d.ts.map +1 -0
  134. package/dist/types/types.gen.d.ts +27811 -0
  135. package/dist/types/types.gen.d.ts.map +1 -0
  136. package/dist/utils/debounce.d.ts +9 -1
  137. package/dist/utils/debounce.d.ts.map +1 -1
  138. package/dist/utils/format.d.ts +15 -0
  139. package/dist/utils/format.d.ts.map +1 -0
  140. package/dist/version.d.ts +2 -0
  141. package/dist/version.d.ts.map +1 -0
  142. package/package.json +9 -1
  143. package/src/components/biorhythm-chart.ts +39 -84
  144. package/src/components/compatibility-card.ts +85 -52
  145. package/src/components/dasha-timeline.ts +55 -73
  146. package/src/components/data.ts +20 -1
  147. package/src/components/dosha-card.ts +18 -31
  148. package/src/components/endpoint-form.ts +79 -11
  149. package/src/components/guna-milan.ts +16 -34
  150. package/src/components/hexagram.ts +53 -43
  151. package/src/components/horoscope-card.ts +51 -39
  152. package/src/components/kp-planets-table.ts +8 -27
  153. package/src/components/location-search.ts +45 -20
  154. package/src/components/moon-phase.ts +28 -25
  155. package/src/components/natal-chart.ts +129 -84
  156. package/src/components/numerology-card.ts +87 -79
  157. package/src/components/panchang-table.ts +40 -78
  158. package/src/components/synastry-chart.ts +220 -78
  159. package/src/components/tarot-card.ts +76 -62
  160. package/src/components/tarot-spread.ts +72 -45
  161. package/src/components/vedic-kundli.ts +42 -51
  162. package/src/index.ts +14 -24
  163. package/src/manifest.ts +366 -0
  164. package/src/styles/tokens.css +47 -1
  165. package/src/tokens/index.ts +5 -0
  166. package/src/types/types.gen.ts +1 -1
  167. package/src/utils/debounce.ts +23 -4
  168. package/src/utils/format.ts +57 -0
  169. package/src/version.ts +2 -0
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/components/hexagram.ts", "../../src/tokens/index.ts", "../../src/utils/base-styles.ts"],
4
- "sourcesContent": ["import { css, html, LitElement, nothing, svg } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { TRIGRAM_GLYPH } from '../tokens/index.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\ninterface HexagramData {\n\tnumber?: number;\n\tsymbol?: string;\n\tchinese?: string;\n\tenglish?: string;\n\tpinyin?: string;\n\tupperTrigram?: string;\n\tlowerTrigram?: string;\n\tjudgment?: string;\n\timage?: string;\n\tinterpretation?: {\n\t\tgeneral?: string;\n\t\tlove?: string;\n\t\tcareer?: string;\n\t\tdecision?: string;\n\t\tadvice?: string;\n\t};\n\tchangingLines?: number[];\n\tresultingHexagram?: HexagramData;\n\tdailyMessage?: string;\n\thexagram?: HexagramData;\n\tlines?: number[]; // 6, 7, 8, 9 cast values\n\tchangingLinePositions?: number[];\n\tseed?: string;\n\tdate?: string;\n}\n\n/**\n * I Ching hexagram card. Renders /iching/hexagrams/{number}, /iching/cast,\n * /iching/daily, /iching/daily/cast.\n */\n@customElement('roxy-hexagram')\nexport class RoxyHexagram extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`\n\t\t\t.card {\n\t\t\t\tbackground: var(--roxy-bg, #fff);\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\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\t\t\tbox-shadow: var(--roxy-shadow-sm);\n\t\t\t\tdisplay: grid;\n\t\t\t\tgrid-template-columns: 6rem 1fr;\n\t\t\t\tgap: var(--roxy-space-lg, 1.5rem);\n\t\t\t}\n\n\t\t\t@container (max-width: 480px) {\n\t\t\t\t.card {\n\t\t\t\t\tgrid-template-columns: 1fr;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t.glyphs {\n\t\t\t\tdisplay: grid;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t\tjustify-items: center;\n\t\t\t}\n\t\t\t.symbol {\n\t\t\t\tfont-size: 3rem;\n\t\t\t\tline-height: 1;\n\t\t\t\tcolor: var(--roxy-accent-fg, #b45309);\n\t\t\t}\n\t\t\t.lines {\n\t\t\t\tdisplay: grid;\n\t\t\t\tgap: 4px;\n\t\t\t\twidth: 4rem;\n\t\t\t}\n\t\t\t.line {\n\t\t\t\tdisplay: flex;\n\t\t\t\tgap: 4px;\n\t\t\t\tjustify-content: center;\n\t\t\t\talign-items: center;\n\t\t\t\theight: 8px;\n\t\t\t}\n\t\t\t.seg {\n\t\t\t\tdisplay: block;\n\t\t\t\theight: 6px;\n\t\t\t\tbackground: var(--roxy-fg, #0a0a0a);\n\t\t\t\tborder-radius: 1px;\n\t\t\t}\n\t\t\t.line.broken .seg {\n\t\t\t\twidth: 1.4rem;\n\t\t\t}\n\t\t\t.line.solid .seg {\n\t\t\t\twidth: 3rem;\n\t\t\t}\n\t\t\t.line.changing .seg {\n\t\t\t\tbackground: var(--roxy-accent, #f59e0b);\n\t\t\t}\n\n\t\t\t.title {\n\t\t\t\tmargin: 0;\n\t\t\t\tfont-size: var(--roxy-text-xl, 1.5rem);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tletter-spacing: var(--roxy-tracking-tight);\n\t\t\t}\n\t\t\t.subtitle {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tmargin: 0 0 var(--roxy-space-sm, 0.5rem);\n\t\t\t}\n\t\t\t.trigrams {\n\t\t\t\tdisplay: flex;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t\tmargin-bottom: var(--roxy-space-sm, 0.5rem);\n\t\t\t\tcolor: var(--roxy-secondary, #475569);\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\ttext-transform: uppercase;\n\t\t\t\tletter-spacing: 0.06em;\n\t\t\t}\n\t\t\t.tri-glyph {\n\t\t\t\tfont-size: var(--roxy-text-xl, 1.5rem);\n\t\t\t\tcolor: var(--roxy-accent-fg, #b45309);\n\t\t\t\tmargin-right: 4px;\n\t\t\t\tvertical-align: middle;\n\t\t\t}\n\t\t\t.judgment,\n\t\t\t.image,\n\t\t\t.message {\n\t\t\t\tmargin: 0 0 var(--roxy-space-sm, 0.5rem);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t}\n\t\t\t.judgment::before {\n\t\t\t\tcontent: 'Judgment. ';\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tcolor: var(--roxy-secondary, #475569);\n\t\t\t}\n\t\t\t.image::before {\n\t\t\t\tcontent: 'Image. ';\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tcolor: var(--roxy-secondary, #475569);\n\t\t\t}\n\n\t\t\t.changing {\n\t\t\t\tmargin-top: var(--roxy-space-md, 1rem);\n\t\t\t\tpadding-top: var(--roxy-space-md, 1rem);\n\t\t\t\tborder-top: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tcolor: var(--roxy-accent-fg, #b45309);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ attribute: false })\n\tdata: HexagramData | null = null;\n\n\t@property({ type: String, reflect: true })\n\tmode: 'lookup' | 'cast' | 'daily' = 'lookup';\n\n\tprivate getHexagram(): HexagramData | null {\n\t\tif (!this.data) return null;\n\t\tif ('hexagram' in this.data && this.data.hexagram) {\n\t\t\treturn {\n\t\t\t\t...this.data.hexagram,\n\t\t\t\tlines: this.data.lines,\n\t\t\t\tchangingLinePositions: this.data.changingLinePositions,\n\t\t\t};\n\t\t}\n\t\treturn this.data;\n\t}\n\n\trender() {\n\t\tconst h = this.getHexagram();\n\t\tif (!h)\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No hexagram data</div>`;\n\n\t\tconst lines = h.lines ?? this.derivedLines(h);\n\t\tconst changing = new Set(h.changingLinePositions ?? []);\n\n\t\treturn html`<article class=\"card\" aria-label=\"I Ching hexagram\">\n\t\t\t<div class=\"glyphs\">\n\t\t\t\t${h.symbol ? html`<div class=\"symbol\">${h.symbol}</div>` : nothing}\n\t\t\t\t<div class=\"lines\" aria-hidden=\"true\">\n\t\t\t\t\t${lines\n\t\t\t\t\t\t.slice()\n\t\t\t\t\t\t.reverse()\n\t\t\t\t\t\t.map((l, idx) => {\n\t\t\t\t\t\t\t// reverse so visual top is line 6\n\t\t\t\t\t\t\tconst realIdx = lines.length - 1 - idx + 1;\n\t\t\t\t\t\t\tconst isChanging = changing.has(realIdx);\n\t\t\t\t\t\t\tconst broken = l === 6 || l === 8;\n\t\t\t\t\t\t\tconst cls = `${broken ? 'broken' : 'solid'}${isChanging ? ' changing' : ''}`;\n\t\t\t\t\t\t\treturn html`<div class=\"line ${cls}\">\n\t\t\t\t\t\t\t\t${\n\t\t\t\t\t\t\t\t\tbroken\n\t\t\t\t\t\t\t\t\t\t? svg`<span class=\"seg\"></span><span class=\"seg\"></span>`\n\t\t\t\t\t\t\t\t\t\t: svg`<span class=\"seg\"></span>`\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t</div>`;\n\t\t\t\t\t\t})}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<h2 class=\"title\">\n\t\t\t\t\t${h.number ? html`${h.number}. ` : nothing}${h.english ?? h.chinese ?? 'Hexagram'}\n\t\t\t\t</h2>\n\t\t\t\t<p class=\"subtitle\">\n\t\t\t\t\t${h.chinese ? html`${h.chinese}` : nothing}\n\t\t\t\t\t${h.pinyin ? html` \u00B7 ${h.pinyin}` : nothing}\n\t\t\t\t</p>\n\t\t\t\t<div class=\"trigrams\">\n\t\t\t\t\t${\n\t\t\t\t\t\th.upperTrigram\n\t\t\t\t\t\t\t? html`<div>\n\t\t\t\t\t\t\t\tUpper\n\t\t\t\t\t\t\t\t<span class=\"tri-glyph\"\n\t\t\t\t\t\t\t\t\t>${TRIGRAM_GLYPH[h.upperTrigram] ?? ''}</span\n\t\t\t\t\t\t\t\t>${h.upperTrigram}\n\t\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}\n\t\t\t\t\t${\n\t\t\t\t\t\th.lowerTrigram\n\t\t\t\t\t\t\t? html`<div>\n\t\t\t\t\t\t\t\tLower\n\t\t\t\t\t\t\t\t<span class=\"tri-glyph\"\n\t\t\t\t\t\t\t\t\t>${TRIGRAM_GLYPH[h.lowerTrigram] ?? ''}</span\n\t\t\t\t\t\t\t\t>${h.lowerTrigram}\n\t\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}\n\t\t\t\t</div>\n\t\t\t\t${h.judgment ? html`<p class=\"judgment\">${h.judgment}</p>` : nothing}\n\t\t\t\t${h.image ? html`<p class=\"image\">${h.image}</p>` : nothing}\n\t\t\t\t${h.dailyMessage ? html`<p class=\"message\">${h.dailyMessage}</p>` : nothing}\n\t\t\t\t${\n\t\t\t\t\th.interpretation?.general\n\t\t\t\t\t\t? html`<p>${h.interpretation.general}</p>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\tchanging.size > 0\n\t\t\t\t\t\t? html`<div class=\"changing\">\n\t\t\t\t\t\t\tChanging lines: ${Array.from(changing)\n\t\t\t\t\t\t\t\t.sort((a, b) => a - b)\n\t\t\t\t\t\t\t\t.join(', ')}.\n\t\t\t\t\t\t\t${\n\t\t\t\t\t\t\t\th.resultingHexagram?.english\n\t\t\t\t\t\t\t\t\t? html` Becomes hexagram ${h.resultingHexagram.number}\n\t\t\t\t\t\t\t\t\t\t${h.resultingHexagram.english}.`\n\t\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t</div>\n\t\t</article>`;\n\t}\n\n\t/** When the API only ships symbol+number with no line array, render six solid yang. */\n\tprivate derivedLines(h: HexagramData): number[] {\n\t\tif (!h.symbol) return Array.from({ length: 6 }, () => 7);\n\t\t// Map each character of the unicode hexagram block (U+4DC0..) to broken/solid\n\t\tconst cp = h.symbol.codePointAt(0) ?? 0;\n\t\tif (cp >= 0x4dc0 && cp <= 0x4dff) {\n\t\t\tconst offset = cp - 0x4dc0;\n\t\t\tconst lines: number[] = [];\n\t\t\tfor (let i = 0; i < 6; i++) {\n\t\t\t\tconst broken = (offset >> i) & 1;\n\t\t\t\tlines.push(broken ? 8 : 7);\n\t\t\t}\n\t\t\treturn lines;\n\t\t}\n\t\treturn Array.from({ length: 6 }, () => 7);\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-hexagram': RoxyHexagram;\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};\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/** 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"],
5
- "mappings": ";;;;;;;;;;;;AAAA,SAAS,OAAAA,MAAK,MAAM,YAAY,SAAS,WAAW;AACpD,SAAS,eAAe,gBAAgB;;;ACmGjC,IAAM,gBAAwC;AAAA,EACpD,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,MAAM;AAAA,EACN,SAAS;AAAA,EACT,MAAM;AAAA,EACN,OAAO;AAAA,EACP,UAAU;AAAA,EACV,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,MAAM;AAAA,EACN,SAAS;AAAA,EACT,MAAM;AAAA,EACN,OAAO;AAAA,EACP,UAAU;AAAA,EACV,OAAO;AACR;;;ACrHA,SAAS,WAAW;AAMb,IAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AF+BnB,IAAM,eAAN,cAA2B,WAAW;AAAA,EAAtC;AAAA;AAkHN,gBAA4B;AAG5B,gBAAoC;AAAA;AAAA,EAE5B,cAAmC;AAC1C,QAAI,CAAC,KAAK,KAAM,QAAO;AACvB,QAAI,cAAc,KAAK,QAAQ,KAAK,KAAK,UAAU;AAClD,aAAO;AAAA,QACN,GAAG,KAAK,KAAK;AAAA,QACb,OAAO,KAAK,KAAK;AAAA,QACjB,uBAAuB,KAAK,KAAK;AAAA,MAClC;AAAA,IACD;AACA,WAAO,KAAK;AAAA,EACb;AAAA,EAEA,SAAS;AACR,UAAM,IAAI,KAAK,YAAY;AAC3B,QAAI,CAAC;AACJ,aAAO;AAER,UAAM,QAAQ,EAAE,SAAS,KAAK,aAAa,CAAC;AAC5C,UAAM,WAAW,IAAI,IAAI,EAAE,yBAAyB,CAAC,CAAC;AAEtD,WAAO;AAAA;AAAA,MAEH,EAAE,SAAS,2BAA2B,EAAE,MAAM,WAAW,OAAO;AAAA;AAAA,OAE/D,MACA,MAAM,EACN,QAAQ,EACR,IAAI,CAAC,GAAG,QAAQ;AAEhB,YAAM,UAAU,MAAM,SAAS,IAAI,MAAM;AACzC,YAAM,aAAa,SAAS,IAAI,OAAO;AACvC,YAAM,SAAS,MAAM,KAAK,MAAM;AAChC,YAAM,MAAM,GAAG,SAAS,WAAW,OAAO,GAAG,aAAa,cAAc,EAAE;AAC1E,aAAO,wBAAwB,GAAG;AAAA,UAEhC,SACG,0DACA,8BACJ;AAAA;AAAA,IAEF,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,OAKD,EAAE,SAAS,OAAO,EAAE,MAAM,OAAO,OAAO,GAAG,EAAE,WAAW,EAAE,WAAW,UAAU;AAAA;AAAA;AAAA,OAG/E,EAAE,UAAU,OAAO,EAAE,OAAO,KAAK,OAAO;AAAA,OACxC,EAAE,SAAS,UAAU,EAAE,MAAM,KAAK,OAAO;AAAA;AAAA;AAAA,OAI1C,EAAE,eACC;AAAA;AAAA;AAAA,YAGG,cAAc,EAAE,YAAY,KAAK,EAAE;AAAA,WACpC,EAAE,YAAY;AAAA,iBAEhB,OACJ;AAAA,OAEC,EAAE,eACC;AAAA;AAAA;AAAA,YAGG,cAAc,EAAE,YAAY,KAAK,EAAE;AAAA,WACpC,EAAE,YAAY;AAAA,iBAEhB,OACJ;AAAA;AAAA,MAEC,EAAE,WAAW,2BAA2B,EAAE,QAAQ,SAAS,OAAO;AAAA,MAClE,EAAE,QAAQ,wBAAwB,EAAE,KAAK,SAAS,OAAO;AAAA,MACzD,EAAE,eAAe,0BAA0B,EAAE,YAAY,SAAS,OAAO;AAAA,MAE1E,EAAE,gBAAgB,UACf,UAAU,EAAE,eAAe,OAAO,SAClC,OACJ;AAAA,MAEC,SAAS,OAAO,IACb;AAAA,yBACiB,MAAM,KAAK,QAAQ,EACnC,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC,EACpB,KAAK,IAAI,CAAC;AAAA,SAEX,EAAE,mBAAmB,UAClB,yBAAyB,EAAE,kBAAkB,MAAM;AAAA,YAClD,EAAE,kBAAkB,OAAO,MAC5B,OACJ;AAAA,gBAEC,OACJ;AAAA;AAAA;AAAA,EAGH;AAAA;AAAA,EAGQ,aAAa,GAA2B;AAC/C,QAAI,CAAC,EAAE,OAAQ,QAAO,MAAM,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC;AAEvD,UAAM,KAAK,EAAE,OAAO,YAAY,CAAC,KAAK;AACtC,QAAI,MAAM,SAAU,MAAM,OAAQ;AACjC,YAAM,SAAS,KAAK;AACpB,YAAM,QAAkB,CAAC;AACzB,eAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC3B,cAAM,SAAU,UAAU,IAAK;AAC/B,cAAM,KAAK,SAAS,IAAI,CAAC;AAAA,MAC1B;AACA,aAAO;AAAA,IACR;AACA,WAAO,MAAM,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC;AAAA,EACzC;AACD;AA3Oa,aACL,SAAS;AAAA,EACf;AAAA,EACAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4GD;AAGA;AAAA,EADC,SAAS,EAAE,WAAW,MAAM,CAAC;AAAA,GAjHlB,aAkHZ;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,QAAQ,SAAS,KAAK,CAAC;AAAA,GApH7B,aAqHZ;AArHY,eAAN;AAAA,EADN,cAAc,eAAe;AAAA,GACjB;",
4
+ "sourcesContent": ["import { css, html, LitElement, nothing, svg } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { TRIGRAM_GLYPH } from '../tokens/index.js';\nimport type {\n\tCastReadingResponse,\n\tGetDailyHexagramResponse,\n\tGetHexagramResponse,\n\tGetRandomHexagramResponse,\n\tHexagram,\n\tLookupHexagramResponse,\n} from '../types/index.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\ntype HexagramData =\n\t| GetHexagramResponse\n\t| GetRandomHexagramResponse\n\t| LookupHexagramResponse\n\t| GetDailyHexagramResponse\n\t| CastReadingResponse;\n\n/**\n * I Ching hexagram card. Renders /iching/hexagrams/{number}, /iching/cast,\n * /iching/daily, /iching/daily/cast.\n */\n@customElement('roxy-hexagram')\nexport class RoxyHexagram extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`\n\t\t\t.card {\n\t\t\t\tbackground: var(--roxy-bg, #fff);\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\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\t\t\tbox-shadow: var(--roxy-shadow-sm);\n\t\t\t\tdisplay: grid;\n\t\t\t\tgrid-template-columns: 6rem 1fr;\n\t\t\t\tgap: var(--roxy-space-lg, 1.5rem);\n\t\t\t}\n\n\t\t\t@container (max-width: 480px) {\n\t\t\t\t.card {\n\t\t\t\t\tgrid-template-columns: 1fr;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t.glyphs {\n\t\t\t\tdisplay: grid;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t\tjustify-items: center;\n\t\t\t}\n\t\t\t.symbol {\n\t\t\t\tfont-size: 3rem;\n\t\t\t\tline-height: 1;\n\t\t\t\tcolor: var(--roxy-accent-fg, #b45309);\n\t\t\t}\n\t\t\t.lines {\n\t\t\t\tdisplay: grid;\n\t\t\t\tgap: 4px;\n\t\t\t\twidth: 4rem;\n\t\t\t}\n\t\t\t.line {\n\t\t\t\tdisplay: flex;\n\t\t\t\tgap: 4px;\n\t\t\t\tjustify-content: center;\n\t\t\t\talign-items: center;\n\t\t\t\theight: 8px;\n\t\t\t}\n\t\t\t.seg {\n\t\t\t\tdisplay: block;\n\t\t\t\theight: 6px;\n\t\t\t\tbackground: var(--roxy-fg, #0a0a0a);\n\t\t\t\tborder-radius: 1px;\n\t\t\t}\n\t\t\t.line.broken .seg {\n\t\t\t\twidth: 1.4rem;\n\t\t\t}\n\t\t\t.line.solid .seg {\n\t\t\t\twidth: 3rem;\n\t\t\t}\n\t\t\t.line.changing .seg {\n\t\t\t\tbackground: var(--roxy-accent, #f59e0b);\n\t\t\t}\n\n\t\t\t.title {\n\t\t\t\tmargin: 0;\n\t\t\t\tfont-size: var(--roxy-text-xl, 1.5rem);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tletter-spacing: var(--roxy-tracking-tight);\n\t\t\t}\n\t\t\t.subtitle {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tmargin: 0 0 var(--roxy-space-sm, 0.5rem);\n\t\t\t}\n\t\t\t.trigrams {\n\t\t\t\tdisplay: flex;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t\tmargin-bottom: var(--roxy-space-sm, 0.5rem);\n\t\t\t\tcolor: var(--roxy-secondary, #475569);\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\ttext-transform: uppercase;\n\t\t\t\tletter-spacing: 0.06em;\n\t\t\t}\n\t\t\t.tri-glyph {\n\t\t\t\tfont-size: var(--roxy-text-xl, 1.5rem);\n\t\t\t\tcolor: var(--roxy-accent-fg, #b45309);\n\t\t\t\tmargin-right: 4px;\n\t\t\t\tvertical-align: middle;\n\t\t\t}\n\t\t\t.judgment,\n\t\t\t.image,\n\t\t\t.message {\n\t\t\t\tmargin: 0 0 var(--roxy-space-sm, 0.5rem);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t}\n\t\t\t.judgment::before {\n\t\t\t\tcontent: 'Judgment. ';\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tcolor: var(--roxy-secondary, #475569);\n\t\t\t}\n\t\t\t.image::before {\n\t\t\t\tcontent: 'Image. ';\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tcolor: var(--roxy-secondary, #475569);\n\t\t\t}\n\n\t\t\t.changing {\n\t\t\t\tmargin-top: var(--roxy-space-md, 1rem);\n\t\t\t\tpadding-top: var(--roxy-space-md, 1rem);\n\t\t\t\tborder-top: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tcolor: var(--roxy-accent-fg, #b45309);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ attribute: false })\n\tdata: HexagramData | null = null;\n\n\t@property({ type: String, reflect: true })\n\tmode: 'lookup' | 'cast' | 'daily' = 'lookup';\n\n\tprivate resolveHexagram(): {\n\t\thex: Hexagram;\n\t\tlines?: number[];\n\t\tchangingLinePositions?: number[];\n\t\tdailyMessage?: string;\n\t\tresultingHexagram?: Hexagram;\n\t} | null {\n\t\tconst d = this.data;\n\t\tif (!d) return null;\n\t\tif ('hexagram' in d && d.hexagram) {\n\t\t\tif ('lines' in d) {\n\t\t\t\tconst cast = d as CastReadingResponse;\n\t\t\t\treturn {\n\t\t\t\t\thex: cast.hexagram as Hexagram,\n\t\t\t\t\tlines: cast.lines,\n\t\t\t\t\tchangingLinePositions: cast.changingLinePositions,\n\t\t\t\t\tresultingHexagram: cast.resultingHexagram as Hexagram | undefined,\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst daily = d as GetDailyHexagramResponse;\n\t\t\treturn {\n\t\t\t\thex: daily.hexagram as Hexagram,\n\t\t\t\tdailyMessage: daily.dailyMessage,\n\t\t\t};\n\t\t}\n\t\treturn { hex: d as Hexagram };\n\t}\n\n\trender() {\n\t\tconst resolved = this.resolveHexagram();\n\t\tif (!resolved)\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No hexagram data</div>`;\n\n\t\tconst {\n\t\t\thex: h,\n\t\t\tlines: castLines,\n\t\t\tchangingLinePositions,\n\t\t\tdailyMessage,\n\t\t\tresultingHexagram,\n\t\t} = resolved;\n\t\tconst lines = castLines ?? this.derivedLines(h);\n\t\tconst changing = new Set(changingLinePositions ?? []);\n\n\t\treturn html`<article class=\"card\" aria-label=\"I Ching hexagram\">\n\t\t\t<div class=\"glyphs\">\n\t\t\t\t${h.symbol ? html`<div class=\"symbol\">${h.symbol}</div>` : nothing}\n\t\t\t\t<div class=\"lines\" aria-hidden=\"true\">\n\t\t\t\t\t${lines\n\t\t\t\t\t\t.slice()\n\t\t\t\t\t\t.reverse()\n\t\t\t\t\t\t.map((l, idx) => {\n\t\t\t\t\t\t\t// reverse so visual top is line 6\n\t\t\t\t\t\t\tconst realIdx = lines.length - 1 - idx + 1;\n\t\t\t\t\t\t\tconst isChanging = changing.has(realIdx);\n\t\t\t\t\t\t\tconst broken = l === 6 || l === 8;\n\t\t\t\t\t\t\tconst cls = `${broken ? 'broken' : 'solid'}${isChanging ? ' changing' : ''}`;\n\t\t\t\t\t\t\treturn html`<div class=\"line ${cls}\">\n\t\t\t\t\t\t\t\t${\n\t\t\t\t\t\t\t\t\tbroken\n\t\t\t\t\t\t\t\t\t\t? svg`<span class=\"seg\"></span><span class=\"seg\"></span>`\n\t\t\t\t\t\t\t\t\t\t: svg`<span class=\"seg\"></span>`\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t</div>`;\n\t\t\t\t\t\t})}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<h2 class=\"title\">\n\t\t\t\t\t${h.number ? html`${h.number}. ` : nothing}${h.english ?? h.chinese ?? 'Hexagram'}\n\t\t\t\t</h2>\n\t\t\t\t<p class=\"subtitle\">\n\t\t\t\t\t${h.chinese ? html`${h.chinese}` : nothing}\n\t\t\t\t\t${h.pinyin ? html` \u00B7 ${h.pinyin}` : nothing}\n\t\t\t\t</p>\n\t\t\t\t<div class=\"trigrams\">\n\t\t\t\t\t${\n\t\t\t\t\t\th.upperTrigram\n\t\t\t\t\t\t\t? html`<div>\n\t\t\t\t\t\t\t\tUpper\n\t\t\t\t\t\t\t\t<span class=\"tri-glyph\"\n\t\t\t\t\t\t\t\t\t>${TRIGRAM_GLYPH[h.upperTrigram] ?? ''}</span\n\t\t\t\t\t\t\t\t>${h.upperTrigram}\n\t\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}\n\t\t\t\t\t${\n\t\t\t\t\t\th.lowerTrigram\n\t\t\t\t\t\t\t? html`<div>\n\t\t\t\t\t\t\t\tLower\n\t\t\t\t\t\t\t\t<span class=\"tri-glyph\"\n\t\t\t\t\t\t\t\t\t>${TRIGRAM_GLYPH[h.lowerTrigram] ?? ''}</span\n\t\t\t\t\t\t\t\t>${h.lowerTrigram}\n\t\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}\n\t\t\t\t</div>\n\t\t\t\t${h.judgment ? html`<p class=\"judgment\">${h.judgment}</p>` : nothing}\n\t\t\t\t${h.image ? html`<p class=\"image\">${h.image}</p>` : nothing}\n\t\t\t\t${dailyMessage ? html`<p class=\"message\">${dailyMessage}</p>` : nothing}\n\t\t\t\t${\n\t\t\t\t\th.interpretation?.general\n\t\t\t\t\t\t? html`<p>${h.interpretation.general}</p>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\tchanging.size > 0\n\t\t\t\t\t\t? html`<div class=\"changing\">\n\t\t\t\t\t\t\tChanging lines: ${Array.from(changing)\n\t\t\t\t\t\t\t\t.sort((a, b) => a - b)\n\t\t\t\t\t\t\t\t.join(', ')}.\n\t\t\t\t\t\t\t${\n\t\t\t\t\t\t\t\tresultingHexagram?.english\n\t\t\t\t\t\t\t\t\t? html` Becomes hexagram ${resultingHexagram.number}\n\t\t\t\t\t\t\t\t\t\t${resultingHexagram.english}.`\n\t\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t</div>\n\t\t</article>`;\n\t}\n\n\t/** When the API only ships symbol+number with no line array, render six solid yang. */\n\tprivate derivedLines(h: Hexagram): number[] {\n\t\t// Map each character of the unicode hexagram block (U+4DC0..) to broken/solid\n\t\tconst cp = h.symbol.codePointAt(0) ?? 0;\n\t\tif (cp >= 0x4dc0 && cp <= 0x4dff) {\n\t\t\tconst offset = cp - 0x4dc0;\n\t\t\tconst lines: number[] = [];\n\t\t\tfor (let i = 0; i < 6; i++) {\n\t\t\t\tconst broken = (offset >> i) & 1;\n\t\t\t\tlines.push(broken ? 8 : 7);\n\t\t\t}\n\t\t\treturn lines;\n\t\t}\n\t\treturn Array.from({ length: 6 }, () => 7);\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-hexagram': RoxyHexagram;\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/** 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"],
5
+ "mappings": "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",
6
6
  "names": ["css", "css"]
7
7
  }
@@ -1,24 +1,6 @@
1
1
  import { LitElement } from 'lit';
2
- interface HoroscopeData {
3
- sign?: string;
4
- date?: string;
5
- overview?: string;
6
- love?: string;
7
- career?: string;
8
- health?: string;
9
- finance?: string;
10
- advice?: string;
11
- luckyNumber?: number | string;
12
- luckyColor?: string;
13
- compatibleSigns?: string[];
14
- moonSign?: string;
15
- moonPhase?: string;
16
- energyRating?: number;
17
- week?: string;
18
- month?: string;
19
- luckyDays?: string[];
20
- luckyNumbers?: number[];
21
- }
2
+ import type { GetDailyHoroscopeResponse, GetMonthlyHoroscopeResponse, GetWeeklyHoroscopeResponse } from '../types/index.js';
3
+ type HoroscopeData = GetDailyHoroscopeResponse | GetWeeklyHoroscopeResponse | GetMonthlyHoroscopeResponse;
22
4
  /**
23
5
  * Daily, weekly, or monthly horoscope card. Pass `data` from
24
6
  * /astrology/horoscope/{sign}/{daily|weekly|monthly}.
@@ -1 +1 @@
1
- {"version":3,"file":"horoscope-card.d.ts","sourceRoot":"","sources":["../../src/components/horoscope-card.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAW,MAAM,KAAK,CAAC;AAKrD,UAAU,aAAa;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;;GAGG;AACH,qBACa,iBAAkB,SAAQ,UAAU;IAChD,MAAM,CAAC,MAAM,4BAsHX;IAGF,IAAI,EAAE,aAAa,GAAG,IAAI,CAAQ;IAGlC,MAAM,EAAE,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAW;IAEjD,MAAM;CA0HN;AAMD,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,qBAAqB;QAC9B,qBAAqB,EAAE,iBAAiB,CAAC;KACzC;CACD"}
1
+ {"version":3,"file":"horoscope-card.d.ts","sourceRoot":"","sources":["../../src/components/horoscope-card.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAW,MAAM,KAAK,CAAC;AAGrD,OAAO,KAAK,EACX,yBAAyB,EACzB,2BAA2B,EAC3B,0BAA0B,EAC1B,MAAM,mBAAmB,CAAC;AAG3B,KAAK,aAAa,GACf,yBAAyB,GACzB,0BAA0B,GAC1B,2BAA2B,CAAC;AAE/B;;;GAGG;AACH,qBACa,iBAAkB,SAAQ,UAAU;IAChD,MAAM,CAAC,MAAM,4BAsHX;IAGF,IAAI,EAAE,aAAa,GAAG,IAAI,CAAQ;IAGlC,MAAM,EAAE,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAW;IAEjD,MAAM;CAiJN;AAMD,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,qBAAqB;QAC9B,qBAAqB,EAAE,iBAAiB,CAAC;KACzC;CACD"}
@@ -128,8 +128,8 @@ var RoxyHoroscopeCard = class extends LitElement {
128
128
  return html`<div class="roxy-empty" role="status">No horoscope data</div>`;
129
129
  const sign = d.sign ?? "";
130
130
  const glyph = sign ? SIGN_GLYPH[capitalize(sign)] ?? "" : "";
131
- const energy = typeof d.energyRating === "number" ? d.energyRating : null;
132
- const dateLabel = d.date ?? d.week ?? d.month ?? "";
131
+ const energy = "energyRating" in d && typeof d.energyRating === "number" ? d.energyRating : null;
132
+ const dateLabel = "date" in d && d.date || "week" in d && d.week || "month" in d && d.month || "";
133
133
  return html`<article
134
134
  class="card"
135
135
  aria-label=${`${this.period} horoscope for ${sign}`}
@@ -167,31 +167,40 @@ var RoxyHoroscopeCard = class extends LitElement {
167
167
  <h3>Finance</h3>
168
168
  <p>${d.finance}</p>
169
169
  </div>` : nothing}
170
- ${d.advice ? html`<div class="section">
170
+ ${"advice" in d && d.advice ? html`<div class="section">
171
171
  <h3>Advice</h3>
172
172
  <p>${d.advice}</p>
173
173
  </div>` : nothing}
174
174
  </div>
175
175
 
176
- ${d.luckyNumber || d.luckyColor || (d.compatibleSigns?.length ?? 0) > 0 ? html`<div class="lucky">
177
- ${d.luckyNumber !== void 0 ? html`<span>Lucky number <strong>${d.luckyNumber}</strong></span>` : nothing}
178
- ${d.luckyColor ? html`<span>Lucky color <strong>${d.luckyColor}</strong></span>` : nothing}
179
- ${d.luckyNumbers?.length ? html`<span
176
+ ${(() => {
177
+ const luckyNumber = "luckyNumber" in d && d.luckyNumber !== void 0 ? d.luckyNumber : void 0;
178
+ const luckyColor = "luckyColor" in d && d.luckyColor ? d.luckyColor : "";
179
+ const luckyNumbers = "luckyNumbers" in d && d.luckyNumbers ? d.luckyNumbers : [];
180
+ const luckyDays = "luckyDays" in d && d.luckyDays ? d.luckyDays : [];
181
+ const compatibleSigns = d.compatibleSigns ?? [];
182
+ if (luckyNumber === void 0 && !luckyColor && luckyNumbers.length === 0 && luckyDays.length === 0 && compatibleSigns.length === 0)
183
+ return nothing;
184
+ return html`<div class="lucky">
185
+ ${luckyNumber !== void 0 ? html`<span>Lucky number <strong>${luckyNumber}</strong></span>` : nothing}
186
+ ${luckyColor ? html`<span>Lucky color <strong>${luckyColor}</strong></span>` : nothing}
187
+ ${luckyNumbers.length ? html`<span
180
188
  >Lucky numbers
181
- <strong>${d.luckyNumbers.join(", ")}</strong></span
189
+ <strong>${luckyNumbers.join(", ")}</strong></span
182
190
  >` : nothing}
183
- ${d.luckyDays?.length ? html`<span
184
- >Lucky days <strong>${d.luckyDays.join(", ")}</strong></span
191
+ ${luckyDays.length ? html`<span
192
+ >Lucky days <strong>${luckyDays.join(", ")}</strong></span
185
193
  >` : nothing}
186
- ${d.compatibleSigns?.length ? html`<span class="compat-wrap">
194
+ ${compatibleSigns.length ? html`<span class="compat-wrap">
187
195
  Best with
188
196
  <span class="compat"
189
- >${d.compatibleSigns.map(
190
- (s) => html`<span>${s}</span>`
191
- )}</span
197
+ >${compatibleSigns.map(
198
+ (s) => html`<span>${s}</span>`
199
+ )}</span
192
200
  >
193
201
  </span>` : nothing}
194
- </div>` : nothing}
202
+ </div>`;
203
+ })()}
195
204
  </article>`;
196
205
  }
197
206
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/components/horoscope-card.ts", "../../src/tokens/index.ts", "../../src/utils/base-styles.ts"],
4
- "sourcesContent": ["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { SIGN_GLYPH } from '../tokens/index.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\ninterface HoroscopeData {\n\tsign?: string;\n\tdate?: string;\n\toverview?: string;\n\tlove?: string;\n\tcareer?: string;\n\thealth?: string;\n\tfinance?: string;\n\tadvice?: string;\n\tluckyNumber?: number | string;\n\tluckyColor?: string;\n\tcompatibleSigns?: string[];\n\tmoonSign?: string;\n\tmoonPhase?: string;\n\tenergyRating?: number;\n\tweek?: string;\n\tmonth?: string;\n\tluckyDays?: string[];\n\tluckyNumbers?: number[];\n}\n\n/**\n * Daily, weekly, or monthly horoscope card. Pass `data` from\n * /astrology/horoscope/{sign}/{daily|weekly|monthly}.\n */\n@customElement('roxy-horoscope-card')\nexport class RoxyHoroscopeCard extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`\n\t\t\t.card {\n\t\t\t\tbackground: var(--roxy-bg, #fff);\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\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\t\t\tbox-shadow: var(--roxy-shadow-sm);\n\t\t\t\tdisplay: grid;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t}\n\n\t\t\t.head {\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t}\n\n\t\t\t.glyph {\n\t\t\t\tfont-size: 2.25rem;\n\t\t\t\tcolor: var(--roxy-accent-fg, #b45309);\n\t\t\t\tline-height: 1;\n\t\t\t}\n\n\t\t\t.title {\n\t\t\t\tfont-size: var(--roxy-text-xl, 1.5rem);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tmargin: 0;\n\t\t\t\tletter-spacing: var(--roxy-tracking-tight);\n\t\t\t\ttext-transform: capitalize;\n\t\t\t}\n\n\t\t\t.date {\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t}\n\n\t\t\t.energy {\n\t\t\t\tmargin-left: auto;\n\t\t\t\tfont-variant-numeric: tabular-nums;\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-secondary, #475569);\n\t\t\t}\n\t\t\t.energy-bar {\n\t\t\t\tdisplay: inline-block;\n\t\t\t\twidth: 6rem;\n\t\t\t\theight: 6px;\n\t\t\t\tbackground: var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-full, 9999px);\n\t\t\t\toverflow: hidden;\n\t\t\t\tmargin-left: 6px;\n\t\t\t\tvertical-align: middle;\n\t\t\t}\n\t\t\t.energy-bar > span {\n\t\t\t\tdisplay: block;\n\t\t\t\theight: 100%;\n\t\t\t\tbackground: var(--roxy-accent, #f59e0b);\n\t\t\t\ttransition:\n\t\t\t\t\twidth var(--roxy-motion-duration, 200ms)\n\t\t\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1));\n\t\t\t}\n\n\t\t\t.overview {\n\t\t\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t\tmargin: 0;\n\t\t\t}\n\n\t\t\t.sections {\n\t\t\t\tdisplay: grid;\n\t\t\t\tgrid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t}\n\n\t\t\t.section h3 {\n\t\t\t\tmargin: 0 0 var(--roxy-space-xs, 0.25rem) 0;\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\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\tletter-spacing: 0.06em;\n\t\t\t}\n\t\t\t.section p {\n\t\t\t\tmargin: 0;\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t}\n\n\t\t\t.lucky {\n\t\t\t\tdisplay: flex;\n\t\t\t\tflex-wrap: wrap;\n\t\t\t\tgap: var(--roxy-space-sm, 0.5rem);\n\t\t\t\tborder-top: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tpadding-top: var(--roxy-space-md, 1rem);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-secondary, #475569);\n\t\t\t}\n\n\t\t\t.lucky strong {\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t}\n\n\t\t\t.compat {\n\t\t\t\tdisplay: flex;\n\t\t\t\tflex-wrap: wrap;\n\t\t\t\tgap: var(--roxy-space-xs, 0.25rem);\n\t\t\t}\n\t\t\t.compat span {\n\t\t\t\tbackground: color-mix(in srgb, var(--roxy-accent, #f59e0b) 16%, transparent);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t\tpadding: 2px 8px;\n\t\t\t\tborder-radius: var(--roxy-radius-full, 9999px);\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\ttext-transform: capitalize;\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ attribute: false })\n\tdata: HoroscopeData | null = null;\n\n\t@property({ type: String, reflect: true })\n\tperiod: 'daily' | 'weekly' | 'monthly' = 'daily';\n\n\trender() {\n\t\tconst d = this.data;\n\t\tif (!d)\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No horoscope data</div>`;\n\n\t\tconst sign = d.sign ?? '';\n\t\tconst glyph = sign ? (SIGN_GLYPH[capitalize(sign)] ?? '') : '';\n\t\tconst energy = typeof d.energyRating === 'number' ? d.energyRating : null;\n\t\tconst dateLabel = d.date ?? d.week ?? d.month ?? '';\n\n\t\treturn html`<article\n\t\t\tclass=\"card\"\n\t\t\taria-label=${`${this.period} horoscope for ${sign}`}\n\t\t>\n\t\t\t<header class=\"head\">\n\t\t\t\t<span class=\"glyph\" aria-hidden=\"true\">${glyph}</span>\n\t\t\t\t<div>\n\t\t\t\t\t<h2 class=\"title\">${sign} ${this.period}</h2>\n\t\t\t\t\t${dateLabel ? html`<div class=\"date\">${dateLabel}</div>` : nothing}\n\t\t\t\t</div>\n\t\t\t\t${\n\t\t\t\t\tenergy !== null\n\t\t\t\t\t\t? html`<span class=\"energy\" aria-label=${`Energy ${energy} of 10`}>\n\t\t\t\t\t\t\tEnergy ${energy}/10\n\t\t\t\t\t\t\t<span class=\"energy-bar\"\n\t\t\t\t\t\t\t\t><span style=\"width: ${(energy / 10) * 100}%\"></span\n\t\t\t\t\t\t\t></span>\n\t\t\t\t\t\t</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t</header>\n\n\t\t\t${d.overview ? html`<p class=\"overview\">${d.overview}</p>` : nothing}\n\n\t\t\t<div class=\"sections\">\n\t\t\t\t${\n\t\t\t\t\td.love\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Love</h3>\n\t\t\t\t\t\t\t<p>${d.love}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\td.career\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Career</h3>\n\t\t\t\t\t\t\t<p>${d.career}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\td.health\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Health</h3>\n\t\t\t\t\t\t\t<p>${d.health}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\td.finance\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Finance</h3>\n\t\t\t\t\t\t\t<p>${d.finance}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\td.advice\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Advice</h3>\n\t\t\t\t\t\t\t<p>${d.advice}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t</div>\n\n\t\t\t${\n\t\t\t\td.luckyNumber || d.luckyColor || (d.compatibleSigns?.length ?? 0) > 0\n\t\t\t\t\t? html`<div class=\"lucky\">\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\td.luckyNumber !== undefined\n\t\t\t\t\t\t\t\t? html`<span>Lucky number <strong>${d.luckyNumber}</strong></span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\td.luckyColor\n\t\t\t\t\t\t\t\t? html`<span>Lucky color <strong>${d.luckyColor}</strong></span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\td.luckyNumbers?.length\n\t\t\t\t\t\t\t\t? html`<span\n\t\t\t\t\t\t\t\t\t>Lucky numbers\n\t\t\t\t\t\t\t\t\t<strong>${d.luckyNumbers.join(', ')}</strong></span\n\t\t\t\t\t\t\t\t>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\td.luckyDays?.length\n\t\t\t\t\t\t\t\t? html`<span\n\t\t\t\t\t\t\t\t\t>Lucky days <strong>${d.luckyDays.join(', ')}</strong></span\n\t\t\t\t\t\t\t\t>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\td.compatibleSigns?.length\n\t\t\t\t\t\t\t\t? html`<span class=\"compat-wrap\">\n\t\t\t\t\t\t\t\t\tBest with\n\t\t\t\t\t\t\t\t\t<span class=\"compat\"\n\t\t\t\t\t\t\t\t\t\t>${d.compatibleSigns.map(\n\t\t\t\t\t\t\t\t\t\t\t(s) => html`<span>${s}</span>`,\n\t\t\t\t\t\t\t\t\t\t)}</span\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t</span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t</div>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t</article>`;\n\t}\n}\n\nfunction capitalize(s: string): string {\n\treturn s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-horoscope-card': RoxyHoroscopeCard;\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};\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/** 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"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { SIGN_GLYPH } from '../tokens/index.js';\nimport type {\n\tGetDailyHoroscopeResponse,\n\tGetMonthlyHoroscopeResponse,\n\tGetWeeklyHoroscopeResponse,\n} from '../types/index.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\ntype HoroscopeData =\n\t| GetDailyHoroscopeResponse\n\t| GetWeeklyHoroscopeResponse\n\t| GetMonthlyHoroscopeResponse;\n\n/**\n * Daily, weekly, or monthly horoscope card. Pass `data` from\n * /astrology/horoscope/{sign}/{daily|weekly|monthly}.\n */\n@customElement('roxy-horoscope-card')\nexport class RoxyHoroscopeCard extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`\n\t\t\t.card {\n\t\t\t\tbackground: var(--roxy-bg, #fff);\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\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\t\t\tbox-shadow: var(--roxy-shadow-sm);\n\t\t\t\tdisplay: grid;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t}\n\n\t\t\t.head {\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t}\n\n\t\t\t.glyph {\n\t\t\t\tfont-size: 2.25rem;\n\t\t\t\tcolor: var(--roxy-accent-fg, #b45309);\n\t\t\t\tline-height: 1;\n\t\t\t}\n\n\t\t\t.title {\n\t\t\t\tfont-size: var(--roxy-text-xl, 1.5rem);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tmargin: 0;\n\t\t\t\tletter-spacing: var(--roxy-tracking-tight);\n\t\t\t\ttext-transform: capitalize;\n\t\t\t}\n\n\t\t\t.date {\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t}\n\n\t\t\t.energy {\n\t\t\t\tmargin-left: auto;\n\t\t\t\tfont-variant-numeric: tabular-nums;\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-secondary, #475569);\n\t\t\t}\n\t\t\t.energy-bar {\n\t\t\t\tdisplay: inline-block;\n\t\t\t\twidth: 6rem;\n\t\t\t\theight: 6px;\n\t\t\t\tbackground: var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-full, 9999px);\n\t\t\t\toverflow: hidden;\n\t\t\t\tmargin-left: 6px;\n\t\t\t\tvertical-align: middle;\n\t\t\t}\n\t\t\t.energy-bar > span {\n\t\t\t\tdisplay: block;\n\t\t\t\theight: 100%;\n\t\t\t\tbackground: var(--roxy-accent, #f59e0b);\n\t\t\t\ttransition:\n\t\t\t\t\twidth var(--roxy-motion-duration, 200ms)\n\t\t\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1));\n\t\t\t}\n\n\t\t\t.overview {\n\t\t\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t\tmargin: 0;\n\t\t\t}\n\n\t\t\t.sections {\n\t\t\t\tdisplay: grid;\n\t\t\t\tgrid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t}\n\n\t\t\t.section h3 {\n\t\t\t\tmargin: 0 0 var(--roxy-space-xs, 0.25rem) 0;\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\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\tletter-spacing: 0.06em;\n\t\t\t}\n\t\t\t.section p {\n\t\t\t\tmargin: 0;\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t}\n\n\t\t\t.lucky {\n\t\t\t\tdisplay: flex;\n\t\t\t\tflex-wrap: wrap;\n\t\t\t\tgap: var(--roxy-space-sm, 0.5rem);\n\t\t\t\tborder-top: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tpadding-top: var(--roxy-space-md, 1rem);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-secondary, #475569);\n\t\t\t}\n\n\t\t\t.lucky strong {\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t}\n\n\t\t\t.compat {\n\t\t\t\tdisplay: flex;\n\t\t\t\tflex-wrap: wrap;\n\t\t\t\tgap: var(--roxy-space-xs, 0.25rem);\n\t\t\t}\n\t\t\t.compat span {\n\t\t\t\tbackground: color-mix(in srgb, var(--roxy-accent, #f59e0b) 16%, transparent);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t\tpadding: 2px 8px;\n\t\t\t\tborder-radius: var(--roxy-radius-full, 9999px);\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\ttext-transform: capitalize;\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ attribute: false })\n\tdata: HoroscopeData | null = null;\n\n\t@property({ type: String, reflect: true })\n\tperiod: 'daily' | 'weekly' | 'monthly' = 'daily';\n\n\trender() {\n\t\tconst d = this.data;\n\t\tif (!d)\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No horoscope data</div>`;\n\n\t\tconst sign = d.sign ?? '';\n\t\tconst glyph = sign ? (SIGN_GLYPH[capitalize(sign)] ?? '') : '';\n\t\tconst energy =\n\t\t\t'energyRating' in d && typeof d.energyRating === 'number'\n\t\t\t\t? d.energyRating\n\t\t\t\t: null;\n\t\tconst dateLabel =\n\t\t\t('date' in d && d.date) ||\n\t\t\t('week' in d && d.week) ||\n\t\t\t('month' in d && d.month) ||\n\t\t\t'';\n\n\t\treturn html`<article\n\t\t\tclass=\"card\"\n\t\t\taria-label=${`${this.period} horoscope for ${sign}`}\n\t\t>\n\t\t\t<header class=\"head\">\n\t\t\t\t<span class=\"glyph\" aria-hidden=\"true\">${glyph}</span>\n\t\t\t\t<div>\n\t\t\t\t\t<h2 class=\"title\">${sign} ${this.period}</h2>\n\t\t\t\t\t${dateLabel ? html`<div class=\"date\">${dateLabel}</div>` : nothing}\n\t\t\t\t</div>\n\t\t\t\t${\n\t\t\t\t\tenergy !== null\n\t\t\t\t\t\t? html`<span class=\"energy\" aria-label=${`Energy ${energy} of 10`}>\n\t\t\t\t\t\t\tEnergy ${energy}/10\n\t\t\t\t\t\t\t<span class=\"energy-bar\"\n\t\t\t\t\t\t\t\t><span style=\"width: ${(energy / 10) * 100}%\"></span\n\t\t\t\t\t\t\t></span>\n\t\t\t\t\t\t</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t</header>\n\n\t\t\t${d.overview ? html`<p class=\"overview\">${d.overview}</p>` : nothing}\n\n\t\t\t<div class=\"sections\">\n\t\t\t\t${\n\t\t\t\t\td.love\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Love</h3>\n\t\t\t\t\t\t\t<p>${d.love}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\td.career\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Career</h3>\n\t\t\t\t\t\t\t<p>${d.career}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\td.health\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Health</h3>\n\t\t\t\t\t\t\t<p>${d.health}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\td.finance\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Finance</h3>\n\t\t\t\t\t\t\t<p>${d.finance}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\t'advice' in d && d.advice\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Advice</h3>\n\t\t\t\t\t\t\t<p>${d.advice}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t</div>\n\n\t\t\t${(() => {\n\t\t\t\tconst luckyNumber =\n\t\t\t\t\t'luckyNumber' in d && d.luckyNumber !== undefined\n\t\t\t\t\t\t? d.luckyNumber\n\t\t\t\t\t\t: undefined;\n\t\t\t\tconst luckyColor =\n\t\t\t\t\t'luckyColor' in d && d.luckyColor ? d.luckyColor : '';\n\t\t\t\tconst luckyNumbers =\n\t\t\t\t\t'luckyNumbers' in d && d.luckyNumbers ? d.luckyNumbers : [];\n\t\t\t\tconst luckyDays = 'luckyDays' in d && d.luckyDays ? d.luckyDays : [];\n\t\t\t\tconst compatibleSigns = d.compatibleSigns ?? [];\n\t\t\t\tif (\n\t\t\t\t\tluckyNumber === undefined &&\n\t\t\t\t\t!luckyColor &&\n\t\t\t\t\tluckyNumbers.length === 0 &&\n\t\t\t\t\tluckyDays.length === 0 &&\n\t\t\t\t\tcompatibleSigns.length === 0\n\t\t\t\t)\n\t\t\t\t\treturn nothing;\n\t\t\t\treturn html`<div class=\"lucky\">\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\tluckyNumber !== undefined\n\t\t\t\t\t\t\t\t? html`<span>Lucky number <strong>${luckyNumber}</strong></span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\tluckyColor\n\t\t\t\t\t\t\t\t? html`<span>Lucky color <strong>${luckyColor}</strong></span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\tluckyNumbers.length\n\t\t\t\t\t\t\t\t? html`<span\n\t\t\t\t\t\t\t\t\t>Lucky numbers\n\t\t\t\t\t\t\t\t\t<strong>${luckyNumbers.join(', ')}</strong></span\n\t\t\t\t\t\t\t\t>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\tluckyDays.length\n\t\t\t\t\t\t\t\t? html`<span\n\t\t\t\t\t\t\t\t\t>Lucky days <strong>${luckyDays.join(', ')}</strong></span\n\t\t\t\t\t\t\t\t>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\tcompatibleSigns.length\n\t\t\t\t\t\t\t\t? html`<span class=\"compat-wrap\">\n\t\t\t\t\t\t\t\t\tBest with\n\t\t\t\t\t\t\t\t\t<span class=\"compat\"\n\t\t\t\t\t\t\t\t\t\t>${compatibleSigns.map(\n\t\t\t\t\t\t\t\t\t\t\t(s) => html`<span>${s}</span>`,\n\t\t\t\t\t\t\t\t\t\t)}</span\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t</span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t</div>`;\n\t\t\t})()}\n\t\t</article>`;\n\t}\n}\n\nfunction capitalize(s: string): string {\n\treturn s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-horoscope-card': RoxyHoroscopeCard;\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/** 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"],
5
+ "mappings": "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",
6
6
  "names": ["css", "css"]
7
7
  }
@@ -1,30 +1,12 @@
1
1
  import { LitElement } from 'lit';
2
- interface KpPlanet {
3
- planet?: string;
4
- name?: string;
5
- sign?: string;
6
- signLord?: string;
7
- nakshatra?: string;
8
- nakshatraLord?: string;
9
- pada?: number;
10
- starLord?: string;
11
- subLord?: string;
12
- subSubLord?: string;
13
- kpNumber?: number;
14
- retrograde?: boolean;
15
- longitude?: number;
16
- }
17
- interface KpData {
18
- ayanamsa?: number | string;
19
- planets?: KpPlanet[];
20
- }
2
+ import type { KpPlanetsResponse } from '../types/index.js';
21
3
  /**
22
4
  * KP planets table with sub-lord and sub-sub-lord columns. Renders
23
5
  * /vedic-astrology/kp/planets.
24
6
  */
25
7
  export declare class RoxyKpPlanetsTable extends LitElement {
26
8
  static styles: import("lit").CSSResult[];
27
- data: KpData | null;
9
+ data: KpPlanetsResponse | null;
28
10
  render(): import("lit").TemplateResult<1>;
29
11
  }
30
12
  declare global {
@@ -32,5 +14,4 @@ declare global {
32
14
  'roxy-kp-planets-table': RoxyKpPlanetsTable;
33
15
  }
34
16
  }
35
- export {};
36
17
  //# sourceMappingURL=kp-planets-table.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"kp-planets-table.d.ts","sourceRoot":"","sources":["../../src/components/kp-planets-table.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAW,MAAM,KAAK,CAAC;AAIrD,UAAU,QAAQ;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,MAAM;IACf,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,OAAO,CAAC,EAAE,QAAQ,EAAE,CAAC;CACrB;AAED;;;GAGG;AACH,qBACa,kBAAmB,SAAQ,UAAU;IACjD,MAAM,CAAC,MAAM,4BA8DX;IAGF,IAAI,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE3B,MAAM;CAmDN;AAED,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,qBAAqB;QAC9B,uBAAuB,EAAE,kBAAkB,CAAC;KAC5C;CACD"}
1
+ {"version":3,"file":"kp-planets-table.d.ts","sourceRoot":"","sources":["../../src/components/kp-planets-table.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAW,MAAM,KAAK,CAAC;AAErD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAI3D;;;GAGG;AACH,qBACa,kBAAmB,SAAQ,UAAU;IACjD,MAAM,CAAC,MAAM,4BA8DX;IAGF,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAAQ;IAEtC,MAAM;CAmDN;AAED,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,qBAAqB;QAC9B,uBAAuB,EAAE,kBAAkB,CAAC;KAC5C;CACD"}
@@ -99,6 +99,12 @@ var baseStyles = css`
99
99
  }
100
100
  `;
101
101
 
102
+ // packages/ui/src/utils/format.ts
103
+ function formatNumber(value, dp = 1) {
104
+ if (typeof value !== "number" || !Number.isFinite(value)) return "";
105
+ return value.toFixed(dp).replace(/\.?0+$/, "");
106
+ }
107
+
102
108
  // packages/ui/src/components/kp-planets-table.ts
103
109
  var RoxyKpPlanetsTable = class extends LitElement {
104
110
  constructor() {
@@ -116,7 +122,7 @@ var RoxyKpPlanetsTable = class extends LitElement {
116
122
  >
117
123
  <header class="head">
118
124
  <h2 class="title">KP planets</h2>
119
- ${this.data.ayanamsa ? html`<span class="ayanamsa">Ayanamsa: ${this.data.ayanamsa}</span>` : nothing}
125
+ ${typeof this.data.ayanamsa === "number" ? html`<span class="ayanamsa">Ayanamsa: ${formatNumber(this.data.ayanamsa, 2)}°</span>` : nothing}
120
126
  </header>
121
127
  <table role="table">
122
128
  <thead>
@@ -135,13 +141,13 @@ var RoxyKpPlanetsTable = class extends LitElement {
135
141
  ${planets.map(
136
142
  (p) => html`<tr>
137
143
  <td class="planet">
138
- ${p.planet ?? p.name ?? ""}
144
+ ${p.planet}
139
145
  ${p.retrograde ? html`<span class="retro">R</span>` : nothing}
140
146
  </td>
141
147
  <td>${p.sign ?? ""}</td>
142
148
  <td>${p.signLord ?? ""}</td>
143
149
  <td>${p.nakshatra ?? ""}</td>
144
- <td>${p.starLord ?? p.nakshatraLord ?? ""}</td>
150
+ <td>${p.nakshatraLord ?? ""}</td>
145
151
  <td>${p.subLord ?? ""}</td>
146
152
  <td>${p.subSubLord ?? ""}</td>
147
153
  <td>${p.kpNumber ?? ""}</td>
@@ -209,7 +215,7 @@ RoxyKpPlanetsTable.styles = [
209
215
  color: var(--roxy-fg, #0a0a0a);
210
216
  }
211
217
  .retro {
212
- color: var(--roxy-warning, #ea580c);
218
+ color: var(--roxy-warning-fg, #9a3412);
213
219
  font-size: var(--roxy-text-xs, 0.75rem);
214
220
  margin-left: 4px;
215
221
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../../src/components/kp-planets-table.ts", "../../src/utils/base-styles.ts"],
4
- "sourcesContent": ["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\ninterface KpPlanet {\n\tplanet?: string;\n\tname?: string;\n\tsign?: string;\n\tsignLord?: string;\n\tnakshatra?: string;\n\tnakshatraLord?: string;\n\tpada?: number;\n\tstarLord?: string;\n\tsubLord?: string;\n\tsubSubLord?: string;\n\tkpNumber?: number;\n\tretrograde?: boolean;\n\tlongitude?: number;\n}\n\ninterface KpData {\n\tayanamsa?: number | string;\n\tplanets?: KpPlanet[];\n}\n\n/**\n * KP planets table with sub-lord and sub-sub-lord columns. Renders\n * /vedic-astrology/kp/planets.\n */\n@customElement('roxy-kp-planets-table')\nexport class RoxyKpPlanetsTable 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\tdisplay: flex;\n\t\t\t\tjustify-content: space-between;\n\t\t\t\tflex-wrap: wrap;\n\t\t\t\tgap: var(--roxy-space-sm, 0.5rem);\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\t.ayanamsa {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\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: 560px;\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\ttd.planet {\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.retro {\n\t\t\t\tcolor: var(--roxy-warning, #ea580c);\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\tmargin-left: 4px;\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ attribute: false })\n\tdata: KpData | null = null;\n\n\trender() {\n\t\tif (!this.data)\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No KP data</div>`;\n\t\tconst planets = this.data.planets ?? [];\n\n\t\treturn html`<div\n\t\t\tclass=\"wrap\"\n\t\t\taria-label=\"KP planets table\"\n\t\t\ttabindex=\"0\"\n\t\t>\n\t\t\t<header class=\"head\">\n\t\t\t\t<h2 class=\"title\">KP planets</h2>\n\t\t\t\t${\n\t\t\t\t\tthis.data.ayanamsa\n\t\t\t\t\t\t? html`<span class=\"ayanamsa\">Ayanamsa: ${this.data.ayanamsa}</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\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\">Planet</th>\n\t\t\t\t\t\t<th scope=\"col\">Sign</th>\n\t\t\t\t\t\t<th scope=\"col\">Sign lord</th>\n\t\t\t\t\t\t<th scope=\"col\">Nakshatra</th>\n\t\t\t\t\t\t<th scope=\"col\">Star lord</th>\n\t\t\t\t\t\t<th scope=\"col\">Sub lord</th>\n\t\t\t\t\t\t<th scope=\"col\">Sub sub lord</th>\n\t\t\t\t\t\t<th scope=\"col\">KP no.</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${planets.map(\n\t\t\t\t\t\t(p) => html`<tr>\n\t\t\t\t\t\t\t<td class=\"planet\">\n\t\t\t\t\t\t\t\t${p.planet ?? p.name ?? ''}\n\t\t\t\t\t\t\t\t${p.retrograde ? html`<span class=\"retro\">R</span>` : nothing}\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td>${p.sign ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.signLord ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.nakshatra ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.starLord ?? p.nakshatraLord ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.subLord ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.subSubLord ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.kpNumber ?? ''}</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-kp-planets-table': RoxyKpPlanetsTable;\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"],
5
- "mappings": ";;;;;;;;;;;;AAAA,SAAS,OAAAA,MAAK,MAAM,YAAY,eAAe;AAC/C,SAAS,eAAe,gBAAgB;;;ACDxC,SAAS,WAAW;AAMb,IAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ADwBnB,IAAM,qBAAN,cAAiC,WAAW;AAAA,EAA5C;AAAA;AAkEN,gBAAsB;AAAA;AAAA,EAEtB,SAAS;AACR,QAAI,CAAC,KAAK;AACT,aAAO;AACR,UAAM,UAAU,KAAK,KAAK,WAAW,CAAC;AAEtC,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQJ,KAAK,KAAK,WACP,wCAAwC,KAAK,KAAK,QAAQ,YAC1D,OACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,OAgBG,QAAQ;AAAA,MACT,CAAC,MAAM;AAAA;AAAA,UAEH,EAAE,UAAU,EAAE,QAAQ,EAAE;AAAA,UACxB,EAAE,aAAa,qCAAqC,OAAO;AAAA;AAAA,aAExD,EAAE,QAAQ,EAAE;AAAA,aACZ,EAAE,YAAY,EAAE;AAAA,aAChB,EAAE,aAAa,EAAE;AAAA,aACjB,EAAE,YAAY,EAAE,iBAAiB,EAAE;AAAA,aACnC,EAAE,WAAW,EAAE;AAAA,aACf,EAAE,cAAc,EAAE;AAAA,aAClB,EAAE,YAAY,EAAE;AAAA;AAAA,IAExB,CAAC;AAAA;AAAA;AAAA;AAAA,EAIL;AACD;AAvHa,mBACL,SAAS;AAAA,EACf;AAAA,EACAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4DD;AAGA;AAAA,EADC,SAAS,EAAE,WAAW,MAAM,CAAC;AAAA,GAjElB,mBAkEZ;AAlEY,qBAAN;AAAA,EADN,cAAc,uBAAuB;AAAA,GACzB;",
3
+ "sources": ["../../src/components/kp-planets-table.ts", "../../src/utils/base-styles.ts", "../../src/utils/format.ts"],
4
+ "sourcesContent": ["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type { KpPlanetsResponse } from '../types/index.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatNumber } from '../utils/format.js';\n\n/**\n * KP planets table with sub-lord and sub-sub-lord columns. Renders\n * /vedic-astrology/kp/planets.\n */\n@customElement('roxy-kp-planets-table')\nexport class RoxyKpPlanetsTable 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\tdisplay: flex;\n\t\t\t\tjustify-content: space-between;\n\t\t\t\tflex-wrap: wrap;\n\t\t\t\tgap: var(--roxy-space-sm, 0.5rem);\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\t.ayanamsa {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\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: 560px;\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\ttd.planet {\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.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\tmargin-left: 4px;\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ attribute: false })\n\tdata: KpPlanetsResponse | null = null;\n\n\trender() {\n\t\tif (!this.data)\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No KP data</div>`;\n\t\tconst planets = this.data.planets ?? [];\n\n\t\treturn html`<div\n\t\t\tclass=\"wrap\"\n\t\t\taria-label=\"KP planets table\"\n\t\t\ttabindex=\"0\"\n\t\t>\n\t\t\t<header class=\"head\">\n\t\t\t\t<h2 class=\"title\">KP planets</h2>\n\t\t\t\t${\n\t\t\t\t\ttypeof this.data.ayanamsa === 'number'\n\t\t\t\t\t\t? html`<span class=\"ayanamsa\">Ayanamsa: ${formatNumber(this.data.ayanamsa, 2)}\u00B0</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\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\">Planet</th>\n\t\t\t\t\t\t<th scope=\"col\">Sign</th>\n\t\t\t\t\t\t<th scope=\"col\">Sign lord</th>\n\t\t\t\t\t\t<th scope=\"col\">Nakshatra</th>\n\t\t\t\t\t\t<th scope=\"col\">Star lord</th>\n\t\t\t\t\t\t<th scope=\"col\">Sub lord</th>\n\t\t\t\t\t\t<th scope=\"col\">Sub sub lord</th>\n\t\t\t\t\t\t<th scope=\"col\">KP no.</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${planets.map(\n\t\t\t\t\t\t(p) => html`<tr>\n\t\t\t\t\t\t\t<td class=\"planet\">\n\t\t\t\t\t\t\t\t${p.planet}\n\t\t\t\t\t\t\t\t${p.retrograde ? html`<span class=\"retro\">R</span>` : nothing}\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td>${p.sign ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.signLord ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.nakshatra ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.nakshatraLord ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.subLord ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.subSubLord ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.kpNumber ?? ''}</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-kp-planets-table': RoxyKpPlanetsTable;\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", "/**\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\nexport function formatLongitude(value: unknown): string {\n\tif (typeof value !== 'number' || !Number.isFinite(value)) return '';\n\treturn `${formatNumber(value, 2)}\u00B0`;\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;AAAA,SAAS,OAAAA,MAAK,MAAM,YAAY,eAAe;AAC/C,SAAS,eAAe,gBAAgB;;;ACDxC,SAAS,WAAW;AAMb,IAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACqCnB,SAAS,aAAa,OAAgB,KAAK,GAAW;AAC5D,MAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK,EAAG,QAAO;AACjE,SAAO,MAAM,QAAQ,EAAE,EAAE,QAAQ,UAAU,EAAE;AAC9C;;;AFnCO,IAAM,qBAAN,cAAiC,WAAW;AAAA,EAA5C;AAAA;AAkEN,gBAAiC;AAAA;AAAA,EAEjC,SAAS;AACR,QAAI,CAAC,KAAK;AACT,aAAO;AACR,UAAM,UAAU,KAAK,KAAK,WAAW,CAAC;AAEtC,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQJ,OAAO,KAAK,KAAK,aAAa,WAC3B,wCAAwC,aAAa,KAAK,KAAK,UAAU,CAAC,CAAC,aAC3E,OACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,OAgBG,QAAQ;AAAA,MACT,CAAC,MAAM;AAAA;AAAA,UAEH,EAAE,MAAM;AAAA,UACR,EAAE,aAAa,qCAAqC,OAAO;AAAA;AAAA,aAExD,EAAE,QAAQ,EAAE;AAAA,aACZ,EAAE,YAAY,EAAE;AAAA,aAChB,EAAE,aAAa,EAAE;AAAA,aACjB,EAAE,iBAAiB,EAAE;AAAA,aACrB,EAAE,WAAW,EAAE;AAAA,aACf,EAAE,cAAc,EAAE;AAAA,aAClB,EAAE,YAAY,EAAE;AAAA;AAAA,IAExB,CAAC;AAAA;AAAA;AAAA;AAAA,EAIL;AACD;AAvHa,mBACL,SAAS;AAAA,EACf;AAAA,EACAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4DD;AAGA;AAAA,EADC,SAAS,EAAE,WAAW,MAAM,CAAC;AAAA,GAjElB,mBAkEZ;AAlEY,qBAAN;AAAA,EADN,cAAc,uBAAuB;AAAA,GACzB;",
6
6
  "names": ["css", "css"]
7
7
  }
@@ -1,15 +1,4 @@
1
1
  import { LitElement } from 'lit';
2
- export interface CityResult {
3
- city: string;
4
- province?: string;
5
- country: string;
6
- iso2?: string;
7
- latitude: number;
8
- longitude: number;
9
- timezone: string;
10
- utcOffset: number;
11
- population?: number;
12
- }
13
2
  /**
14
3
  * Stateful location search input. Calls /location/search and emits
15
4
  * `roxy-location-select` CustomEvent with the chosen city. Required for any
@@ -39,9 +28,12 @@ export declare class RoxyLocationSearch extends LitElement {
39
28
  private isLoading;
40
29
  private highlight;
41
30
  private clickOutsideHandler?;
31
+ private abortController?;
32
+ private secretKeyWarned;
42
33
  private debouncedFetch;
43
34
  connectedCallback(): void;
44
35
  disconnectedCallback(): void;
36
+ private warnIfSecretKey;
45
37
  private fetchResults;
46
38
  private onInput;
47
39
  private select;
@@ -1 +1 @@
1
- {"version":3,"file":"location-search.d.ts","sourceRoot":"","sources":["../../src/components/location-search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAW,MAAM,KAAK,CAAC;AAKrD,MAAM,WAAW,UAAU;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAOD;;;;;;;;;;;;;;;GAeG;AACH,qBACa,kBAAmB,SAAQ,UAAU;IACjD,MAAM,CAAC,MAAM,4BAwGX;IAGF,MAAM,CAAC,EAAE,MAAM,CAAC;IAGhB,cAAc,CAAC,EAAE,MAAM,CAAC;IAGxB,QAAQ,SAAgD;IAGxD,WAAW,SAAiB;IAG5B,YAAY,SAAM;IAGlB,OAAO,CAAC,KAAK,CAAM;IAGnB,OAAO,CAAC,OAAO,CAAoB;IAGnC,OAAO,CAAC,MAAM,CAAS;IAGvB,OAAO,CAAC,SAAS,CAAS;IAG1B,OAAO,CAAC,SAAS,CAAM;IAEvB,OAAO,CAAC,mBAAmB,CAAC,CAA0B;IACtD,OAAO,CAAC,cAAc,CAEd;IAER,iBAAiB,IAAI,IAAI;IAUzB,oBAAoB,IAAI,IAAI;YAOd,YAAY;IAyB1B,OAAO,CAAC,OAAO,CAUb;IAEF,OAAO,CAAC,MAAM;IAad,OAAO,CAAC,SAAS,CAsBf;IAEF,MAAM;CAwDN;AAED,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,qBAAqB;QAC9B,sBAAsB,EAAE,kBAAkB,CAAC;KAC3C;CACD"}
1
+ {"version":3,"file":"location-search.d.ts","sourceRoot":"","sources":["../../src/components/location-search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAW,MAAM,KAAK,CAAC;AAQrD;;;;;;;;;;;;;;;GAeG;AACH,qBACa,kBAAmB,SAAQ,UAAU;IACjD,MAAM,CAAC,MAAM,4BAwGX;IAGF,MAAM,CAAC,EAAE,MAAM,CAAC;IAGhB,cAAc,CAAC,EAAE,MAAM,CAAC;IAGxB,QAAQ,SAAgD;IAGxD,WAAW,SAAiB;IAG5B,YAAY,SAAM;IAGlB,OAAO,CAAC,KAAK,CAAM;IAGnB,OAAO,CAAC,OAAO,CAAoB;IAGnC,OAAO,CAAC,MAAM,CAAS;IAGvB,OAAO,CAAC,SAAS,CAAS;IAG1B,OAAO,CAAC,SAAS,CAAM;IAEvB,OAAO,CAAC,mBAAmB,CAAC,CAA0B;IACtD,OAAO,CAAC,eAAe,CAAC,CAAkB;IAC1C,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,cAAc,CAEd;IAER,iBAAiB,IAAI,IAAI;IAUzB,oBAAoB,IAAI,IAAI;IAY5B,OAAO,CAAC,eAAe;YAqBT,YAAY;IAoC1B,OAAO,CAAC,OAAO,CAUb;IAEF,OAAO,CAAC,MAAM;IAad,OAAO,CAAC,SAAS,CAsBf;IAEF,MAAM;CAwDN;AAED,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,qBAAqB;QAC9B,sBAAsB,EAAE,kBAAkB,CAAC;KAC3C;CACD"}
@@ -102,10 +102,20 @@ var baseStyles = css`
102
102
  // packages/ui/src/utils/debounce.ts
103
103
  function debounce(fn, wait) {
104
104
  let timer;
105
- return ((...args) => {
105
+ const debounced = ((...args) => {
106
106
  if (timer) clearTimeout(timer);
107
- timer = setTimeout(() => fn(...args), wait);
107
+ timer = setTimeout(() => {
108
+ timer = void 0;
109
+ fn(...args);
110
+ }, wait);
108
111
  });
112
+ debounced.cancel = () => {
113
+ if (timer) {
114
+ clearTimeout(timer);
115
+ timer = void 0;
116
+ }
117
+ };
118
+ return debounced;
109
119
  }
110
120
 
111
121
  // packages/ui/src/components/location-search.ts
@@ -120,6 +130,7 @@ var RoxyLocationSearch = class extends LitElement {
120
130
  this.isOpen = false;
121
131
  this.isLoading = false;
122
132
  this.highlight = -1;
133
+ this.secretKeyWarned = false;
123
134
  this.debouncedFetch = debounce((q) => {
124
135
  void this.fetchResults(q);
125
136
  }, 300);
@@ -171,8 +182,32 @@ var RoxyLocationSearch = class extends LitElement {
171
182
  if (this.clickOutsideHandler) {
172
183
  document.removeEventListener("mousedown", this.clickOutsideHandler);
173
184
  }
185
+ this.debouncedFetch.cancel();
186
+ if (this.abortController) {
187
+ this.abortController.abort();
188
+ this.abortController = void 0;
189
+ }
190
+ }
191
+ warnIfSecretKey() {
192
+ if (this.secretKeyWarned) return;
193
+ if (!this.apiKey) return;
194
+ if (this.apiKey.startsWith("pk_")) return;
195
+ this.secretKeyWarned = true;
196
+ const message = "Possible secret key in client-side <roxy-location-search>; use a `pk_` publishable key with origin allowlist instead.";
197
+ console.warn(message);
198
+ this.dispatchEvent(
199
+ new CustomEvent("roxy-validation-error", {
200
+ detail: { reason: "possible-secret-key", message },
201
+ bubbles: true,
202
+ composed: true
203
+ })
204
+ );
174
205
  }
175
206
  async fetchResults(q) {
207
+ this.warnIfSecretKey();
208
+ if (this.abortController) this.abortController.abort();
209
+ const controller = new AbortController();
210
+ this.abortController = controller;
176
211
  this.isLoading = true;
177
212
  try {
178
213
  const url = new URL(this.endpoint);
@@ -183,17 +218,22 @@ var RoxyLocationSearch = class extends LitElement {
183
218
  };
184
219
  if (this.apiKey) headers["X-API-Key"] = this.apiKey;
185
220
  if (this.publishableKey) headers["X-API-Key"] = this.publishableKey;
186
- const res = await fetch(url, { headers });
221
+ const res = await fetch(url, { headers, signal: controller.signal });
187
222
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
188
223
  const json = await res.json();
224
+ if (controller.signal.aborted) return;
189
225
  this.results = json.cities ?? [];
190
226
  this.isOpen = this.results.length > 0;
191
227
  this.highlight = this.results.length > 0 ? 0 : -1;
192
- } catch (_err) {
228
+ } catch (err) {
229
+ if (err?.name === "AbortError") return;
193
230
  this.results = [];
194
231
  this.isOpen = false;
195
232
  } finally {
196
- this.isLoading = false;
233
+ if (this.abortController === controller) {
234
+ this.abortController = void 0;
235
+ }
236
+ if (!controller.signal.aborted) this.isLoading = false;
197
237
  }
198
238
  }
199
239
  select(city) {