@roxyapi/ui 0.11.0 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/AGENTS.md +6 -0
  2. package/README.md +7 -1
  3. package/components-catalog.json +111 -1
  4. package/dist/cdn/components/astrocartography-map.js +58 -0
  5. package/dist/cdn/components/astrocartography-map.js.map +7 -0
  6. package/dist/cdn/components/divisional-chart.js +7 -7
  7. package/dist/cdn/components/divisional-chart.js.map +1 -1
  8. package/dist/cdn/components/dosha-card.js +2 -2
  9. package/dist/cdn/components/dosha-card.js.map +3 -3
  10. package/dist/cdn/components/fixed-stars.js +52 -0
  11. package/dist/cdn/components/fixed-stars.js.map +7 -0
  12. package/dist/cdn/components/hd-variables.js +2 -2
  13. package/dist/cdn/components/hd-variables.js.map +3 -3
  14. package/dist/cdn/components/hexagram.js +3 -3
  15. package/dist/cdn/components/hexagram.js.map +3 -3
  16. package/dist/cdn/components/local-space-compass.js +58 -0
  17. package/dist/cdn/components/local-space-compass.js.map +7 -0
  18. package/dist/cdn/components/moon-phase.js +3 -3
  19. package/dist/cdn/components/moon-phase.js.map +3 -3
  20. package/dist/cdn/components/natal-chart.js +8 -8
  21. package/dist/cdn/components/natal-chart.js.map +2 -2
  22. package/dist/cdn/components/positions-table.js +52 -0
  23. package/dist/cdn/components/positions-table.js.map +7 -0
  24. package/dist/cdn/components/profection-card.js +52 -0
  25. package/dist/cdn/components/profection-card.js.map +7 -0
  26. package/dist/cdn/components/reference-card.js +3 -3
  27. package/dist/cdn/components/reference-card.js.map +3 -3
  28. package/dist/cdn/components/relocation-wheel.js +61 -0
  29. package/dist/cdn/components/relocation-wheel.js.map +7 -0
  30. package/dist/cdn/components/synastry-chart.js +4 -4
  31. package/dist/cdn/components/synastry-chart.js.map +2 -2
  32. package/dist/cdn/components/vedic-kundli.js +5 -5
  33. package/dist/cdn/components/vedic-kundli.js.map +1 -1
  34. package/dist/cdn/components/vedic-planets-table.js +2 -2
  35. package/dist/cdn/components/vedic-planets-table.js.map +1 -1
  36. package/dist/cdn/components/western-planets-table.js +2 -2
  37. package/dist/cdn/components/western-planets-table.js.map +1 -1
  38. package/dist/cdn/components/yoga-list.js +3 -3
  39. package/dist/cdn/components/yoga-list.js.map +3 -3
  40. package/dist/cdn/roxy-ui.js +84 -72
  41. package/dist/cdn/roxy-ui.js.map +4 -4
  42. package/dist/components/astrocartography-map.d.ts +27 -0
  43. package/dist/components/astrocartography-map.d.ts.map +1 -0
  44. package/dist/components/astrocartography-map.js +8 -0
  45. package/dist/components/astrocartography-map.js.map +7 -0
  46. package/dist/components/divisional-chart.js +22 -22
  47. package/dist/components/divisional-chart.js.map +1 -1
  48. package/dist/components/dosha-card.d.ts.map +1 -1
  49. package/dist/components/dosha-card.js +1 -1
  50. package/dist/components/dosha-card.js.map +3 -3
  51. package/dist/components/fixed-stars.d.ts +21 -0
  52. package/dist/components/fixed-stars.d.ts.map +1 -0
  53. package/dist/components/fixed-stars.js +2 -0
  54. package/dist/components/fixed-stars.js.map +7 -0
  55. package/dist/components/hd-variables.d.ts.map +1 -1
  56. package/dist/components/hd-variables.js +1 -1
  57. package/dist/components/hd-variables.js.map +3 -3
  58. package/dist/components/hexagram.d.ts +3 -1
  59. package/dist/components/hexagram.d.ts.map +1 -1
  60. package/dist/components/hexagram.js +1 -1
  61. package/dist/components/hexagram.js.map +3 -3
  62. package/dist/components/local-space-compass.d.ts +23 -0
  63. package/dist/components/local-space-compass.d.ts.map +1 -0
  64. package/dist/components/local-space-compass.js +8 -0
  65. package/dist/components/local-space-compass.js.map +7 -0
  66. package/dist/components/moon-phase.d.ts.map +1 -1
  67. package/dist/components/moon-phase.js +1 -1
  68. package/dist/components/moon-phase.js.map +3 -3
  69. package/dist/components/natal-chart.d.ts +2 -0
  70. package/dist/components/natal-chart.d.ts.map +1 -1
  71. package/dist/components/natal-chart.js +6 -6
  72. package/dist/components/natal-chart.js.map +2 -2
  73. package/dist/components/positions-table.d.ts +34 -0
  74. package/dist/components/positions-table.d.ts.map +1 -0
  75. package/dist/components/positions-table.js +2 -0
  76. package/dist/components/positions-table.js.map +7 -0
  77. package/dist/components/profection-card.d.ts +18 -0
  78. package/dist/components/profection-card.d.ts.map +1 -0
  79. package/dist/components/profection-card.js +2 -0
  80. package/dist/components/profection-card.js.map +7 -0
  81. package/dist/components/reference-card.d.ts.map +1 -1
  82. package/dist/components/reference-card.js +1 -1
  83. package/dist/components/reference-card.js.map +3 -3
  84. package/dist/components/relocation-wheel.d.ts +21 -0
  85. package/dist/components/relocation-wheel.d.ts.map +1 -0
  86. package/dist/components/relocation-wheel.js +11 -0
  87. package/dist/components/relocation-wheel.js.map +7 -0
  88. package/dist/components/synastry-chart.js +3 -3
  89. package/dist/components/synastry-chart.js.map +2 -2
  90. package/dist/components/vedic-kundli.js +14 -14
  91. package/dist/components/vedic-kundli.js.map +1 -1
  92. package/dist/components/vedic-planets-table.js +1 -1
  93. package/dist/components/vedic-planets-table.js.map +1 -1
  94. package/dist/components/western-planets-table.js +1 -1
  95. package/dist/components/western-planets-table.js.map +1 -1
  96. package/dist/components/yoga-list.d.ts +5 -2
  97. package/dist/components/yoga-list.d.ts.map +1 -1
  98. package/dist/components/yoga-list.js +1 -1
  99. package/dist/components/yoga-list.js.map +3 -3
  100. package/dist/generated/endpoint-bindings.d.ts.map +1 -1
  101. package/dist/index.cjs +55 -43
  102. package/dist/index.cjs.map +4 -4
  103. package/dist/index.d.ts +6 -0
  104. package/dist/index.d.ts.map +1 -1
  105. package/dist/index.js +63 -51
  106. package/dist/index.js.map +4 -4
  107. package/dist/manifest.d.ts.map +1 -1
  108. package/dist/manifest.json +6 -0
  109. package/dist/types/index.d.ts +1 -1
  110. package/dist/types/index.d.ts.map +1 -1
  111. package/dist/types/types.gen.d.ts +7864 -5381
  112. package/dist/types/types.gen.d.ts.map +1 -1
  113. package/dist/utils/degree.d.ts +2 -0
  114. package/dist/utils/degree.d.ts.map +1 -1
  115. package/dist/utils/planet-color.d.ts +3 -0
  116. package/dist/utils/planet-color.d.ts.map +1 -0
  117. package/dist/utils/world-map.d.ts +8 -0
  118. package/dist/utils/world-map.d.ts.map +1 -0
  119. package/dist/version.d.ts +1 -1
  120. package/package.json +2 -1
  121. package/src/components/astrocartography-map.ts +442 -0
  122. package/src/components/dosha-card.ts +48 -16
  123. package/src/components/fixed-stars.ts +254 -0
  124. package/src/components/hd-variables.ts +30 -2
  125. package/src/components/hexagram.ts +11 -11
  126. package/src/components/local-space-compass.ts +299 -0
  127. package/src/components/moon-phase.ts +21 -2
  128. package/src/components/natal-chart.ts +36 -24
  129. package/src/components/positions-table.ts +442 -0
  130. package/src/components/profection-card.ts +173 -0
  131. package/src/components/reference-card.ts +40 -8
  132. package/src/components/relocation-wheel.ts +170 -0
  133. package/src/components/yoga-list.ts +95 -2
  134. package/src/generated/endpoint-bindings.ts +62 -0
  135. package/src/index.ts +6 -0
  136. package/src/manifest.ts +79 -0
  137. package/src/types/index.ts +1 -1
  138. package/src/types/types.gen.ts +7814 -5263
  139. package/src/utils/degree.ts +11 -0
  140. package/src/utils/planet-color.ts +45 -0
  141. package/src/utils/world-map.ts +8 -0
  142. package/src/version.ts +1 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/index.ts", "../src/components/angel-number-card.ts", "../src/utils/angel-sections.ts", "../src/utils/base-element.ts", "../src/utils/base-styles.ts", "../src/utils/fetch-controller.ts", "../src/utils/markup-data.ts", "../src/components/angel-number-lookup.ts", "../src/components/ashtakavarga-grid.ts", "../src/tokens/index.ts", "../src/components/aspects-table.ts", "../src/utils/disclosure.ts", "../src/utils/format.ts", "../src/utils/string.ts", "../src/components/biorhythm-chart.ts", "../src/components/bodygraph.ts", "../src/utils/bodygraph-render.ts", "../src/components/choghadiya-grid.ts", "../src/components/compatibility-card.ts", "../src/components/crystal-card.ts", "../src/components/crystal-grid.ts", "../src/components/dasha-timeline.ts", "../src/components/data.ts", "../src/components/divisional-chart.ts", "../src/utils/kundli-render.ts", "../src/utils/degree.ts", "../src/utils/tablist.ts", "../src/utils/kundli-styles.ts", "../src/components/dosha-card.ts", "../src/components/dream-card.ts", "../src/components/dream-search.ts", "../src/components/endpoint-form.ts", "../src/components/forecast-digest.ts", "../src/components/forecast-timeline.ts", "../src/components/guna-milan.ts", "../src/components/hd-connection.ts", "../src/components/hd-penta.ts", "../src/components/hd-variables.ts", "../src/components/hexagram.ts", "../src/components/hora-table.ts", "../src/components/horoscope-card.ts", "../src/components/kp-chart.ts", "../src/components/kp-planets-table.ts", "../src/components/kp-ruling-planets.ts", "../src/components/location-search.ts", "../src/utils/debounce.ts", "../src/components/moon-phase.ts", "../src/components/nakshatra-card.ts", "../src/components/natal-chart.ts", "../src/components/numerology-card.ts", "../src/components/panchang-table.ts", "../src/components/reference-card.ts", "../src/components/shadbala-table.ts", "../src/components/synastry-chart.ts", "../src/components/tarot-card.ts", "../src/components/tarot-catalog.ts", "../src/components/tarot-spread.ts", "../src/components/transits-table.ts", "../src/components/vedic-aspects.ts", "../src/components/vedic-kundli.ts", "../src/components/vedic-planets-table.ts", "../src/components/western-planets-table.ts", "../src/components/yoga-list.ts", "../src/manifest.ts", "../src/version.ts"],
4
- "sourcesContent": ["/**\n * @roxyapi/ui main entry. Importing this file registers every custom element.\n *\n * For tree-shake friendly usage, import per-component:\n * import '@roxyapi/ui/components/natal-chart';\n */\n\n// Angel numbers\nexport { RoxyAngelNumberCard } from './components/angel-number-card.js';\nexport { RoxyAngelNumberLookup } from './components/angel-number-lookup.js';\nexport { RoxyAshtakavargaGrid } from './components/ashtakavarga-grid.js';\n// Western astrology\nexport { RoxyAspectsTable } from './components/aspects-table.js';\n// Biorhythm\nexport { RoxyBiorhythmChart } from './components/biorhythm-chart.js';\n// Human Design\nexport { RoxyBodygraph } from './components/bodygraph.js';\nexport { RoxyChoghadiyaGrid } from './components/choghadiya-grid.js';\nexport { RoxyCompatibilityCard } from './components/compatibility-card.js';\n// Crystals\nexport { RoxyCrystalCard } from './components/crystal-card.js';\nexport { RoxyCrystalGrid } from './components/crystal-grid.js';\nexport { RoxyDashaTimeline } from './components/dasha-timeline.js';\n// Generic fallback first so it is always available for nested rendering\nexport { RoxyData } from './components/data.js';\nexport { RoxyDivisionalChart } from './components/divisional-chart.js';\nexport { RoxyDoshaCard } from './components/dosha-card.js';\n// Dreams\nexport { RoxyDreamCard } from './components/dream-card.js';\nexport { RoxyDreamSearch } from './components/dream-search.js';\n// Helpers\nexport { RoxyEndpointForm } from './components/endpoint-form.js';\n// Forecast\nexport { RoxyForecastDigest } from './components/forecast-digest.js';\nexport { RoxyForecastTimeline } from './components/forecast-timeline.js';\nexport { RoxyGunaMilan } from './components/guna-milan.js';\n// Human Design\nexport { RoxyHdConnection } from './components/hd-connection.js';\nexport { RoxyHdPenta } from './components/hd-penta.js';\nexport { RoxyHdVariables } from './components/hd-variables.js';\n// I Ching\nexport { RoxyHexagram } from './components/hexagram.js';\nexport { RoxyHoraTable } from './components/hora-table.js';\nexport { RoxyHoroscopeCard } from './components/horoscope-card.js';\nexport { RoxyKpChart } from './components/kp-chart.js';\nexport { RoxyKpPlanetsTable } from './components/kp-planets-table.js';\nexport { RoxyKpRulingPlanets } from './components/kp-ruling-planets.js';\nexport { RoxyLocationSearch } from './components/location-search.js';\nexport { RoxyMoonPhase } from './components/moon-phase.js';\nexport { RoxyNakshatraCard } from './components/nakshatra-card.js';\n// Western astrology\nexport { RoxyNatalChart } from './components/natal-chart.js';\n// Numerology\nexport { RoxyNumerologyCard } from './components/numerology-card.js';\nexport { RoxyPanchangTable } from './components/panchang-table.js';\nexport { RoxyReferenceCard } from './components/reference-card.js';\nexport { RoxyShadbalaTable } from './components/shadbala-table.js';\nexport { RoxySynastryChart } from './components/synastry-chart.js';\n// Tarot\nexport { RoxyTarotCard } from './components/tarot-card.js';\nexport { RoxyTarotCatalog } from './components/tarot-catalog.js';\nexport { RoxyTarotSpread } from './components/tarot-spread.js';\nexport { RoxyTransitsTable } from './components/transits-table.js';\n// Vedic astrology\nexport { RoxyVedicAspects } from './components/vedic-aspects.js';\nexport { RoxyVedicKundli } from './components/vedic-kundli.js';\nexport { RoxyVedicPlanetsTable } from './components/vedic-planets-table.js';\nexport { RoxyWesternPlanetsTable } from './components/western-planets-table.js';\nexport { RoxyYogaList } from './components/yoga-list.js';\n\n// SSR helpers for the server-rendered hydration path (Pattern 7). Safe writers\n// for the inline <script class=\"roxy-data\"> the MarkupDataController reads.\nexport {\n\troxyDataScript,\n\tserializeRoxyData,\n} from './utils/markup-data.js';\n\nimport { ROXY_COMPONENTS, type RoxyComponentSlug } from './manifest.js';\n\nexport {\n\tROXY_COMPONENTS,\n\ttype RoxyComponent,\n\ttype RoxyComponentSlug,\n} from './manifest.js';\nexport { ROXY_UI_VERSION } from './version.js';\n\n/** Slugs in declaration order. Kept for the auto-mount widgets script and downstream codegen. */\nexport const ROXY_UI_COMPONENTS: readonly RoxyComponentSlug[] =\n\tROXY_COMPONENTS.map((c) => c.slug) as RoxyComponentSlug[];\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { GetAngelNumberResponse } from '../types/index.js';\nimport { buildMeaningSections } from '../utils/angel-sections.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\n/**\n * Angel number card. Renders /angel-numbers/numbers/{number}: the number as a hero numeral, its title and core message, the pattern type / digit root / energy badges, keyword chips, the life-area interpretations (spiritual, love, career, money, twin flame) plus the biblical and shadow readings as an exclusive accordion, the affirmation, and the action steps.\n */\n@customElement('roxy-angel-number-card')\nexport class RoxyAngelNumberCard extends RoxyDataElement<GetAngelNumberResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.card{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.hero{align-items:center;gap:var(--roxy-space-md,1rem);display:flex}.numeral{font-size:3rem;line-height:1;font-weight:var(--roxy-weight-bold,600);color:var(--roxy-accent-ink,#b45309);font-variant-numeric:tabular-nums}.label{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;margin:0}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.core{color:var(--roxy-fg,#0a0a0a);margin:0;line-height:1.6}.badges{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;display:flex}.badge{align-items:center;gap:var(--roxy-space-xs,.25rem);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 35%, transparent);color:var(--roxy-fg,#0a0a0a);text-transform:capitalize;padding:3px 10px;display:inline-flex}.badge.positive{background:color-mix(in srgb, var(--roxy-success,#16a34a) 16%, transparent);color:var(--roxy-success-fg,#166534)}.badge.cautionary{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 16%, transparent);color:var(--roxy-danger-fg,#991b1b)}.badge.neutral{background:color-mix(in srgb, var(--roxy-info,#0284c7) 16%, transparent);color:var(--roxy-info-fg,#075985)}.chips{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;display:flex}.chips span{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 14%, transparent);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);padding:2px 8px}.sections{gap:var(--roxy-space-xs,.25rem);border-top:1px solid var(--roxy-border,#e4e4e7);padding-top:var(--roxy-space-md,1rem);display:grid}details{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-sm,4px);overflow:hidden}summary{cursor:pointer;padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);font-weight:var(--roxy-weight-bold,600);font-size:var(--roxy-text-sm,.875rem);list-style-position:inside}details p{padding:0 var(--roxy-space-md,1rem) var(--roxy-space-md,1rem);font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);margin:0;line-height:1.6}.affirmation{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 12%, transparent);border-left:3px solid var(--roxy-accent,#f59e0b);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);border-radius:var(--roxy-radius-sm,4px);color:var(--roxy-fg,#0a0a0a);margin:0;font-style:italic}.steps h3{margin:0 0 var(--roxy-space-xs,.25rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em}.steps ul{padding-left:var(--roxy-space-md,1rem);font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);gap:2px;margin:0;display:grid}`,\n\t];\n\n\tprotected renderData(d: GetAngelNumberResponse) {\n\t\tconst energy = (d.energy ?? '').toLowerCase();\n\t\tconst energyClass =\n\t\t\tenergy === 'positive' || energy === 'cautionary' || energy === 'neutral'\n\t\t\t\t? energy\n\t\t\t\t: '';\n\t\tconst keywords = d.keywords ?? [];\n\t\tconst steps = d.actionSteps ?? [];\n\n\t\treturn html`<article class=\"card\" aria-label=\"${`Angel number ${d.number ?? ''}`}\"><div class=\"hero\">${d.number ? html`<div class=\"numeral\">${d.number}</div>` : nothing}<div><p class=\"label\">Angel number</p>${d.title ? html`<h2 class=\"title\">${d.title}</h2>` : nothing}</div></div>${d.coreMessage ? html`<p class=\"core\">${d.coreMessage}</p>` : nothing}<div class=\"badges\">${d.type ? html`<span class=\"badge\">${d.type}</span>` : nothing} ${typeof d.digitRoot === 'number' ? html`<span class=\"badge\">Digit root ${d.digitRoot}</span>` : nothing} ${d.energy ? html`<span class=\"${`badge ${energyClass}`}\">${d.energy}</span>` : nothing}</div>${\n\t\t\t\tkeywords.length > 0\n\t\t\t\t\t? html`<div class=\"chips\">${keywords.map((k) => html`<span>${k}</span>`)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${this.renderSections(d)} ${d.affirmation ? html`<p class=\"affirmation\">${d.affirmation}</p>` : nothing} ${\n\t\t\t\tsteps.length > 0\n\t\t\t\t\t? html`<div class=\"steps\"><h3>Action steps</h3><ul>${steps.map((s) => html`<li>${s}</li>`)}</ul></div>`\n\t\t\t\t\t: nothing\n\t\t\t}</article>`;\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No angel number</div>`;\n\t}\n\n\tprivate renderSections(d: NonNullable<GetAngelNumberResponse>) {\n\t\tconst sections = buildMeaningSections(d.meaning, d.biblical, d.shadow);\n\t\tif (sections.length === 0) return nothing;\n\t\treturn html`<div class=\"sections\">${sections.map(\n\t\t\t\t(s, i) => html`<details name=\"angel-meaning\" ?open=\"${i === 0}\"><summary>${s.label}</summary><p>${s.body}</p></details>`,\n\t\t\t)}</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-angel-number-card': RoxyAngelNumberCard;\n\t}\n}\n", "/**\n * Ordered angel-number interpretation sections, shared by the angel-number card and lookup components so the field list, labels, and display order live in one place instead of being duplicated per component.\n *\n * @remarks The life-area keys (`spiritual`, `love`, `career`, `money`, `twinFlame`) mirror the `meaning` object in the angel-numbers OpenAPI response; `biblical` and `shadow` are top-level siblings present only on a known meaning, not on the digit-root fallback. Any absent field is skipped, so the one builder serves a full known meaning and the leaner digit-root reading alike.\n */\n\nexport interface MeaningSection {\n\tlabel: string;\n\tbody: string;\n}\n\nconst LIFE_AREA_SECTIONS: ReadonlyArray<{ key: string; label: string }> = [\n\t{ key: 'spiritual', label: 'Spiritual' },\n\t{ key: 'love', label: 'Love' },\n\t{ key: 'career', label: 'Career' },\n\t{ key: 'money', label: 'Money' },\n\t{ key: 'twinFlame', label: 'Twin flame' },\n];\n\n/**\n * Build the present-only interpretation sections in canonical order: the life areas first, then the optional `biblical` and `shadow` readings. An empty or missing field is omitted so the caller can render whatever the response actually carries.\n */\nexport function buildMeaningSections(\n\tmeaning: Record<string, string> | undefined,\n\tbiblical?: string,\n\tshadow?: string,\n): MeaningSection[] {\n\tconst sections: MeaningSection[] = [];\n\tif (meaning) {\n\t\tfor (const s of LIFE_AREA_SECTIONS) {\n\t\t\tconst body = meaning[s.key];\n\t\t\tif (body) sections.push({ label: s.label, body });\n\t\t}\n\t}\n\tif (biblical) sections.push({ label: 'Biblical', body: biblical });\n\tif (shadow) sections.push({ label: 'Shadow', body: shadow });\n\treturn sections;\n}\n", "import {\n\ttype CSSResultGroup,\n\thtml,\n\tLitElement,\n\ttype PropertyValues,\n} from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { baseStyles } from './base-styles.js';\nimport { buildRequest, FetchController } from './fetch-controller.js';\nimport { MarkupDataController } from './markup-data.js';\n\n/**\n * Shared base for every data-driven Roxy component. Consolidates the things every component used to repeat by hand and adds the self-contained, drop-in behavior: controlled-mode hydration, an opt-in self-fetch (form, request, loading, error, empty), the typed `data` slot, and the render switch. A subclass implements one method, {@link RoxyDataElement.renderData}.\n *\n * @remarks\n * Two render modes, one component, which is the whole drop-in contract:\n *\n * - Controlled: a server (WordPress, JSX SSR, static HTML) fetches the response and injects it as a direct-child `<script type=\"application/json\" class=\"roxy-data\">`. {@link MarkupDataController} hydrates `data` from it on connect. No key reaches the browser. This is the path the WordPress plugin drives, and it is unchanged by the base class.\n * - Uncontrolled: no data is injected, but a `data-endpoint` and a `pk_` `publishable-key` are set. The component renders its own `<roxy-endpoint-form>` (an internal detail, never placed by the consumer), and on submit fetches through {@link FetchController}, which refuses any non-publishable key. The result populates `data` and the component renders it.\n *\n * The JavaScript `data` property always wins over markup, so a host that assigns `el.data = \u2026` after upgrade is authoritative.\n *\n * Self-fetch needs `<roxy-endpoint-form>` (and `<roxy-location-search>`) registered. The CDN bundle and the full `@roxyapi/ui` entry register everything; per-component ESM consumers that want self-fetch import the form component too.\n *\n * @example\n * ```ts\n * @customElement('roxy-dream-card')\n * export class RoxyDreamCard extends RoxyDataElement<GetDreamSymbolResponse> {\n * static styles = [baseStyles, css`.card { \u2026 }`];\n * protected renderData(d: GetDreamSymbolResponse) {\n * return html`<article class=\"card\">\u2026</article>`;\n * }\n * protected renderEmpty() {\n * return html`<div class=\"roxy-empty\" role=\"status\">No dream symbol</div>`;\n * }\n * }\n * ```\n */\nexport abstract class RoxyDataElement<T = unknown> extends LitElement {\n\tstatic styles: CSSResultGroup = [baseStyles];\n\n\t/** Typed RoxyAPI response. Assigned in JavaScript, hydrated from the roxy-data island, or set by a self-fetch. */\n\t@property({ attribute: false })\n\tdata: T | null = null;\n\n\t/** Endpoint path for self-fetch, e.g. \"astrology/natal-chart\" or \"dreams/symbols/{id}\". Empty disables self-fetch (controlled mode only). */\n\t@property({ type: String, attribute: 'data-endpoint' })\n\tendpoint = '';\n\n\t/** HTTP method for self-fetch. */\n\t@property({ type: String })\n\tmethod: 'GET' | 'POST' = 'POST';\n\n\t/** Browser-safe publishable key (pk_) for self-fetch. A secret key is refused client-side. */\n\t@property({ type: String, attribute: 'publishable-key' })\n\tpublishableKey?: string;\n\n\t/** Override the API origin for self-hosted or proxied deployments. */\n\t@property({ type: String, attribute: 'base-url' })\n\tbaseUrl?: string;\n\n\t/** Override the OpenAPI spec URL the self-fetch form introspects. */\n\t@property({ type: String, attribute: 'spec-url' })\n\tspecUrl?: string;\n\n\t/** Consumer backend route that proxies the request (holds the secret key). When set, self-fetch POSTs the request here instead of calling RoxyAPI directly, so no key reaches the browser. The server-rendered (WordPress) path. */\n\t@property({ type: String, attribute: 'submit-url' })\n\tsubmitUrl?: string;\n\n\t/** Persist the last self-fetch form values in sessionStorage (keyed by endpoint) and prefill the form on reload. */\n\t@property({ type: Boolean })\n\tremember = false;\n\n\t/** True while an uncontrolled self-fetch is in flight. Public so {@link FetchController} can drive it. */\n\t@state()\n\tloading = false;\n\n\t/** Message from a failed self-fetch, or null. Public so {@link FetchController} can drive it. */\n\t@state()\n\terror: string | null = null;\n\n\tprivate fetcher: FetchController<T>;\n\n\tconstructor() {\n\t\tsuper();\n\t\t// Controlled mode: hydrate `data` from a direct-child roxy-data island when\n\t\t// no JS property was assigned. Keyless; the server already fetched.\n\t\tnew MarkupDataController<T>(this);\n\t\tthis.fetcher = new FetchController<T>(this);\n\t}\n\n\tprotected willUpdate(changed: PropertyValues): void {\n\t\tif (changed.has('publishableKey')) {\n\t\t\tthis.fetcher.publishableKey = this.publishableKey;\n\t\t}\n\t\tif (changed.has('baseUrl') && this.baseUrl) {\n\t\t\tthis.fetcher.baseUrl = this.baseUrl;\n\t\t}\n\t\tif (changed.has('submitUrl')) {\n\t\t\tthis.fetcher.submitUrl = this.submitUrl;\n\t\t}\n\t}\n\n\trender(): unknown {\n\t\tif (this.loading) return this.renderLoading();\n\t\tif (this.error != null) return this.renderError(this.error);\n\t\tif (this.data != null) return this.renderData(this.data);\n\t\treturn this.renderNoData();\n\t}\n\n\t/** Render the populated response. The single method every component implements. */\n\tprotected abstract renderData(data: T): unknown;\n\n\t/** The data-absent branch: the self-fetch form when an endpoint is set, otherwise the empty state. */\n\tprotected renderNoData(): unknown {\n\t\treturn this.endpoint ? this.renderForm() : this.renderEmpty();\n\t}\n\n\t/** Internal self-fetch form. Reuses the introspecting `<roxy-endpoint-form>`; the consumer never places it. */\n\tprotected renderForm(): unknown {\n\t\treturn html`<roxy-endpoint-form data-endpoint=\"${this.endpoint}\" method=\"${this.method}\" spec-url=\"${ifDefined(this.specUrl)}\" .initialValues=\"${this.remember ? this.readRemembered() : undefined}\" @roxy-submit=\"${this.onFormSubmit}\"></roxy-endpoint-form>`;\n\t}\n\n\tprivate onFormSubmit = (e: Event) => {\n\t\tconst detail = (e as CustomEvent).detail as {\n\t\t\tvalues: Record<string, unknown>;\n\t\t};\n\t\tif (this.remember) this.writeRemembered(detail.values);\n\t\tvoid this.fetcher.run(\n\t\t\tbuildRequest(this.endpoint, this.method, detail.values),\n\t\t);\n\t};\n\n\t/** sessionStorage key for this component's remembered form values, scoped by endpoint. */\n\tprivate rememberKey(): string {\n\t\treturn `roxy-ui:form:${this.endpoint}`;\n\t}\n\n\tprivate readRemembered(): Record<string, unknown> | undefined {\n\t\ttry {\n\t\t\tconst raw = sessionStorage.getItem(this.rememberKey());\n\t\t\treturn raw ? (JSON.parse(raw) as Record<string, unknown>) : undefined;\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tprivate writeRemembered(values: Record<string, unknown>): void {\n\t\ttry {\n\t\t\tsessionStorage.setItem(this.rememberKey(), JSON.stringify(values));\n\t\t} catch {\n\t\t\t// Private mode / disabled storage: remembering is best-effort, never fatal.\n\t\t}\n\t}\n\n\t/** Terminal empty state. Subclasses override for a domain-specific message. */\n\tprotected renderEmpty(): unknown {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No data</div>`;\n\t}\n\n\t/** Loading placeholder shown during a self-fetch. */\n\tprotected renderLoading(): unknown {\n\t\treturn html`<div class=\"roxy-skeleton\" style=\"height:8rem\" role=\"status\" aria-label=\"Loading\"></div>`;\n\t}\n\n\t/** Error state shown when a self-fetch fails. Keeps the form in view so the request can be retried. */\n\tprotected renderError(message: string): unknown {\n\t\tconst banner = html`<div class=\"roxy-error\" role=\"alert\">${message}</div>`;\n\t\treturn this.endpoint ? html`${banner}${this.renderForm()}` : banner;\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`:host{font-family:var(--roxy-font-sans,system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif);color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-base,1rem);line-height:var(--roxy-leading-normal,1.5);animation:roxy-fade-in var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,cubic-bezier(.4, 0, .2, 1)) both;background:0 0;display:block;container-type:inline-size}:host([bare]){--roxy-surface:transparent;--roxy-shadow-sm:none;--roxy-shadow-md:none}*,:before,:after{box-sizing:border-box}@keyframes roxy-fade-in{0%{opacity:0;transform:translateY(2px)}to{opacity:1;transform:translateY(0)}}@media (prefers-reduced-motion:reduce){:host{animation:none}}.roxy-skeleton{background:linear-gradient(90deg, var(--roxy-border,#e4e4e7) 0%, color-mix(in srgb, var(--roxy-border,#e4e4e7) 60%, transparent) 50%, var(--roxy-border,#e4e4e7) 100%);border-radius:var(--roxy-radius-md,8px);background-size:200% 100%;animation:1.4s ease-in-out infinite roxy-shimmer}@keyframes roxy-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}@media (prefers-reduced-motion:reduce){.roxy-skeleton{animation:none}}.roxy-empty{padding:var(--roxy-space-lg,1.5rem);color:var(--roxy-muted,#71717a);text-align:center;font-size:var(--roxy-text-sm,.875rem)}.roxy-error{gap:var(--roxy-space-sm,.5rem);padding:var(--roxy-space-lg,1.5rem);background:var(--roxy-surface,#fff);border:1px solid var(--roxy-danger,#dc2626);border-radius:var(--roxy-radius-md,8px);color:var(--roxy-danger-fg,#991b1b);font-size:var(--roxy-text-sm,.875rem);justify-items:start;display:grid}.roxy-surface{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a)}:host(:focus-within) .roxy-card{outline:2px solid var(--roxy-ring,#f59e0b66);outline-offset:2px}:host{font-variant-emoji:text}`;\n", "import type { ReactiveController, ReactiveControllerHost } from 'lit';\n\n/**\n * Host slots the controller drives. {@link RoxyDataElement} satisfies this, so\n * the form mixin can attach a controller without the component wiring state by hand.\n */\ninterface FetchHost<T> extends ReactiveControllerHost {\n\tdata: T | null;\n\tloading: boolean;\n\terror: string | null;\n}\n\n/** Default RoxyAPI v2 origin. A component overrides it per instance via its `base-url` attribute. */\nconst DEFAULT_BASE_URL = 'https://roxyapi.com/api/v2';\n\n/** A single request the controller issues on the component's behalf. */\nexport interface RoxyRequest {\n\t/** Path under the API base, e.g. \"/dreams/symbols/water\" or \"/astrology/natal-chart\". */\n\tpath: string;\n\tmethod?: 'GET' | 'POST';\n\t/** JSON body for POST endpoints. */\n\tbody?: unknown;\n\t/** Query string parameters; nullish values are dropped. */\n\tquery?: Record<string, string | number | undefined>;\n}\n\n/**\n * Client-side fetch for uncontrolled (self-fetching) components: drives `host.data` / `host.loading` / `host.error` and cancels a stale request when a newer one starts or the host disconnects.\n *\n * @remarks\n * Security boundary. The only credential this ever sends is a `pk_` publishable key, which carries a server-side origin allowlist. A secret (`sk_`) or legacy unprefixed key is refused before any network call and surfaced as an error, so a server secret cannot leak into a browser request. This centralizes the guard that originated in `<roxy-location-search>` so every self-fetching component enforces it identically.\n *\n * Controlled-mode components never construct this. When a server injects the response as a `<script class=\"roxy-data\">` island, there is no key and no fetch, which is the path server-rendered consumers (WordPress, JSX SSR, static HTML) rely on.\n */\nexport class FetchController<T = unknown> implements ReactiveController {\n\tprivate readonly host: FetchHost<T>;\n\tprivate abort?: AbortController;\n\n\t/** Browser-safe publishable key. Set by the host from its `publishable-key` attribute. */\n\tpublishableKey?: string;\n\t/** API origin, overridable for self-hosted or proxied deployments. */\n\tbaseUrl = DEFAULT_BASE_URL;\n\t/**\n\t * Consumer backend route that holds the secret key. When set, the request is POSTed here as `{ path, method, body, query }` instead of called against RoxyAPI directly, so no key (publishable or secret) is sent from the browser. This is the canonical path for server-rendered hosts (WordPress); the backend proxies the request with its own `sk_` key and returns the JSON response.\n\t */\n\tsubmitUrl?: string;\n\n\tconstructor(host: FetchHost<T>) {\n\t\tthis.host = host;\n\t\thost.addController(this);\n\t}\n\n\thostDisconnected() {\n\t\tthis.abort?.abort();\n\t\tthis.abort = undefined;\n\t}\n\n\t/**\n\t * Issue the request and resolve once `host.data` (success) or `host.error`\n\t * (failure) is set. A no-op return when a non-publishable key is present:\n\t * the error is already surfaced and nothing is sent.\n\t */\n\tasync run(req: RoxyRequest): Promise<void> {\n\t\t// submit-url proxy: no key leaves the browser; the consumer's backend holds it.\n\t\tif (!this.submitUrl && this.secretKeyRefused()) return;\n\t\tthis.abort?.abort();\n\t\tconst controller = new AbortController();\n\t\tthis.abort = controller;\n\t\tthis.host.loading = true;\n\t\tthis.host.error = null;\n\t\ttry {\n\t\t\tconst res = this.submitUrl\n\t\t\t\t? await fetch(this.submitUrl, {\n\t\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\tAccept: 'application/json',\n\t\t\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t\t\t},\n\t\t\t\t\t\tbody: JSON.stringify(req),\n\t\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t\t})\n\t\t\t\t: await this.callApi(req, controller.signal);\n\t\t\tif (!res.ok) throw new Error(await this.readError(res));\n\t\t\tconst json = (await res.json()) as T;\n\t\t\tif (controller.signal.aborted) return;\n\t\t\tthis.host.data = json;\n\t\t} catch (err) {\n\t\t\tif ((err as { name?: string })?.name === 'AbortError') return;\n\t\t\tthis.host.error = err instanceof Error ? err.message : String(err);\n\t\t} finally {\n\t\t\tif (this.abort === controller) this.abort = undefined;\n\t\t\tif (!controller.signal.aborted) this.host.loading = false;\n\t\t}\n\t}\n\n\t/** Direct call against RoxyAPI with the publishable key (the no-backend path). */\n\tprivate callApi(req: RoxyRequest, signal: AbortSignal): Promise<Response> {\n\t\tconst url = new URL(`${this.baseUrl}${req.path}`);\n\t\tfor (const [k, v] of Object.entries(req.query ?? {})) {\n\t\t\tif (v != null) url.searchParams.set(k, String(v));\n\t\t}\n\t\tconst headers: Record<string, string> = { Accept: 'application/json' };\n\t\tif (this.publishableKey) headers['X-API-Key'] = this.publishableKey;\n\t\tif (req.body != null) headers['Content-Type'] = 'application/json';\n\t\treturn fetch(url, {\n\t\t\tmethod: req.method ?? 'GET',\n\t\t\theaders,\n\t\t\tbody: req.body != null ? JSON.stringify(req.body) : undefined,\n\t\t\tsignal,\n\t\t});\n\t}\n\n\t/** True when a key is set and it is not a browser-safe `pk_` publishable key. Surfaces the error and refuses to send. */\n\tprivate secretKeyRefused(): boolean {\n\t\tconst key = this.publishableKey;\n\t\tif (!key || key.startsWith('pk_')) return false;\n\t\tthis.host.error =\n\t\t\t'Client-side components accept a pk_ publishable key only. Use a publishable key with an origin allowlist, or render server-side.';\n\t\t(this.host as unknown as EventTarget).dispatchEvent(\n\t\t\tnew CustomEvent('roxy-validation-error', {\n\t\t\t\tdetail: { reason: 'possible-secret-key' },\n\t\t\t\tbubbles: true,\n\t\t\t\tcomposed: true,\n\t\t\t}),\n\t\t);\n\t\treturn true;\n\t}\n\n\t/** Surface the `{ error, code }` message the API returns on failure, falling back to the status code. */\n\tprivate async readError(res: Response): Promise<string> {\n\t\ttry {\n\t\t\tconst body = (await res.json()) as { error?: string };\n\t\t\tif (body?.error) return body.error;\n\t\t} catch {\n\t\t\t// Non-JSON error body: fall through to the status line.\n\t\t}\n\t\treturn `Request failed (${res.status})`;\n\t}\n}\n\n/**\n * Translate flat form values into a {@link RoxyRequest} for an endpoint. The `{name}` segments in the endpoint template are substituted from the values and removed; the rest become the JSON body for POST or query parameters for GET. This is the spec-light request builder the base element uses to turn a `<roxy-endpoint-form>` submission into a self-fetch, so a component needs no per-endpoint glue.\n */\nexport function buildRequest(\n\tendpoint: string,\n\tmethod: 'GET' | 'POST',\n\tvalues: Record<string, unknown>,\n): RoxyRequest {\n\tconst rest: Record<string, unknown> = { ...values };\n\tconst path = `/${endpoint.replace(/^\\//, '')}`.replace(\n\t\t/\\{([^}]+)\\}/g,\n\t\t(_match, name: string) => {\n\t\t\tconst v = rest[name];\n\t\t\tdelete rest[name];\n\t\t\treturn encodeURIComponent(String(v ?? ''));\n\t\t},\n\t);\n\tconst query: Record<string, string | number | undefined> = {};\n\tconst body: Record<string, unknown> = {};\n\tfor (const [k, v] of Object.entries(rest)) {\n\t\tif (v === undefined || v === '') continue;\n\t\tif (method === 'GET') query[k] = v as string | number;\n\t\telse body[k] = v;\n\t}\n\treturn { path, method, query, body: method === 'POST' ? body : undefined };\n}\n", "import type { ReactiveController, ReactiveControllerHost } from 'lit';\n\n/**\n * Marker class on the inline JSON script a server emits inside a component.\n *\n * @example\n * ```html\n * <roxy-natal-chart>\n * <script type=\"application/json\" class=\"roxy-data\">{ ...response... }</script>\n * </roxy-natal-chart>\n * ```\n */\nconst ROXY_DATA_CLASS = 'roxy-data';\n\n/**\n * Serialize a RoxyAPI response for embedding inside an inline `<script type=\"application/json\" class=\"roxy-data\">`. This is the safe writer counterpart to {@link MarkupDataController}, the reader: server-rendered and cached consumers (WordPress, JSX SSR, static HTML) emit the script with this, and the component hydrates `data` from it on connect.\n *\n * @remarks\n * Use this instead of a bare `JSON.stringify`. A raw stringify of a response that contains the literal text `</script>` (common in long interpretation prose) closes the script element early, corrupting the page and creating an HTML-injection vector. This escapes the script-unsafe characters to their `\\uXXXX` JSON escapes, which `JSON.parse` restores to the original characters, so the value the component receives is identical to the response you passed.\n *\n * `<` is the load-bearing escape (it defeats `</script>` and `<!--`). `>` and `&` are escaped for defence in depth, and U+2028 / U+2029 because they are valid in JSON yet are line terminators in a `<script>` context and break some parsers. The escapes introduce only `\\uXXXX` sequences, so the replacements never feed each other and order is irrelevant.\n *\n * Pass the unwrapped RoxyAPI response, the same shape you would assign to `element.data`. Do not pass the SDK envelope (`{ data, error, request, response }`).\n *\n * @example\n * ```ts\n * import { serializeRoxyData } from '@roxyapi/ui';\n *\n * const { data } = await roxy.dreams.getDreamSymbol({ path: { id: 'water' } });\n * const html = `<roxy-dream-card><script type=\"application/json\" class=\"roxy-data\">${serializeRoxyData(data)}</script></roxy-dream-card>`;\n * ```\n */\nexport function serializeRoxyData(data: unknown): string {\n\treturn JSON.stringify(data)\n\t\t.replace(/</g, '\\\\u003c')\n\t\t.replace(/>/g, '\\\\u003e')\n\t\t.replace(/&/g, '\\\\u0026')\n\t\t.replace(/\\u2028/g, '\\\\u2028')\n\t\t.replace(/\\u2029/g, '\\\\u2029');\n}\n\n/**\n * Build the complete `<script type=\"application/json\" class=\"roxy-data\">\u2026</script>` element a server nests inside a `roxy-*` component for the no-JavaScript hydration path. The payload is escaped via {@link serializeRoxyData}, so it is safe to drop straight into HTML output.\n *\n * @remarks\n * The element carries both `type=\"application/json\"` and `class=\"roxy-data\"` because {@link MarkupDataController} reads only a direct-child script that has both. Emit one of these inside the target component; the JavaScript `data` property still wins if it is later assigned.\n *\n * @example\n * ```ts\n * import { roxyDataScript } from '@roxyapi/ui';\n *\n * const { data } = await roxy.crystals.getCrystal({ path: { id: 'amethyst' } });\n * const html = `<roxy-crystal-grid>${roxyDataScript(data)}</roxy-crystal-grid>`;\n * ```\n */\nexport function roxyDataScript(data: unknown): string {\n\treturn `<script type=\"application/json\" class=\"${ROXY_DATA_CLASS}\">${serializeRoxyData(data)}</script>`;\n}\n\n/**\n * True when the element is a `<script type=\"application/json\">`. Uses tag name and attribute rather than `instanceof HTMLScriptElement` so the check holds in every DOM implementation, including server-rendered and hydration runtimes where the constructor global may be absent.\n */\nfunction isJsonScript(el: Element): boolean {\n\treturn (\n\t\tel.nodeName === 'SCRIPT' && el.getAttribute('type') === 'application/json'\n\t);\n}\n\n/**\n * Host shape the controller drives: any reactive element that exposes a public `data` slot. The controller only writes `data` when the host left it unset, so the JavaScript property path always wins.\n */\ninterface DataHost extends ReactiveControllerHost, HTMLElement {\n\tdata?: unknown;\n}\n\n/**\n * Reactive controller that lets a component hydrate its `data` from embedded markup when no `data` property was assigned in JavaScript.\n *\n * @remarks\n * The server-side and cached-render model: a backend renders the RoxyAPI response into a direct-child `<script type=\"application/json\" class=\"roxy-data\">` element, ships static HTML, and never runs per-element JavaScript to assign a property. On connect this controller reads that script, parses it, and feeds the result to the host. The JavaScript property path is untouched and authoritative: if `host.data` already holds a value when the host connects, the controller does nothing and the markup is ignored.\n *\n * Source resolution order on connect, first hit wins:\n *\n * 1. `host.data` already set in JavaScript -> leave it, read nothing.\n * 2. A direct-child `<script type=\"application/json\" class=\"roxy-data\">` -> parse and use. Direct-child only, so a nested component's own script is never read by an ancestor.\n *\n * Fetching from a URL is intentionally unsupported: that would require a browser-visible key and breaks the server-rendered, cached model these consumers rely on.\n *\n * Timing: {@link hostConnected} runs inside the host `connectedCallback`. For an element parsed from server HTML, its direct children are present by the time the custom element upgrades and connects, so the script is readable here. For an element created with `document.createElement` and connected before any child is appended, there is nothing to read and the property path is the only source, which is exactly the existing behavior.\n *\n * Failure is safe: malformed JSON or a missing script leaves `host.data` untouched, so the host renders its normal empty state.\n *\n * Reading the script never mutates it, and only the marked script is touched, so any sibling fallback markup a server nested inside the element (for no-JavaScript, AMP, or crawler rendering) is left in place.\n *\n * @example\n * ```ts\n * import { MarkupDataController } from '../utils/markup-data.js';\n *\n * export class RoxyExample extends LitElement {\n * constructor() {\n * super();\n * new MarkupDataController(this);\n * }\n *\n * @property({ attribute: false })\n * data: ExampleResponse | null = null;\n * }\n * ```\n */\nexport class MarkupDataController<T = unknown> implements ReactiveController {\n\tprivate readonly host: DataHost;\n\n\tconstructor(host: DataHost) {\n\t\tthis.host = host;\n\t\thost.addController(this);\n\t}\n\n\thostConnected() {\n\t\t// Property path wins. If the consumer (React, vanilla `.data =`, the\n\t\t// widgets script, an MCP agent) already set data, never look at markup.\n\t\tif (this.host.data != null) return;\n\n\t\tconst parsed = this.read();\n\t\tif (parsed === undefined) return;\n\n\t\tthis.host.data = parsed as T;\n\t\tthis.host.requestUpdate();\n\t}\n\n\t/**\n\t * Resolve the embedded payload. Returns `undefined` when there is nothing valid to read so the caller can leave `host.data` untouched.\n\t */\n\tprivate read(): T | undefined {\n\t\tconst inline = this.findInlineScript();\n\t\treturn inline ? this.parse(inline.textContent) : undefined;\n\t}\n\n\t/**\n\t * Direct-child `<script type=\"application/json\" class=\"roxy-data\">`. Scoped to immediate children so a nested data-driven component never has its script read by an ancestor, and so sibling fallback markup is ignored.\n\t */\n\tprivate findInlineScript(): Element | null {\n\t\tfor (const child of Array.from(this.host.children)) {\n\t\t\tif (isJsonScript(child) && child.classList.contains(ROXY_DATA_CLASS)) {\n\t\t\t\treturn child;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate parse(text: string | null): T | undefined {\n\t\tif (!text?.trim()) return undefined;\n\t\ttry {\n\t\t\treturn JSON.parse(text) as T;\n\t\t} catch {\n\t\t\t// Malformed embedded JSON: fail safe, leave the host empty state in\n\t\t\t// place rather than throwing during connect.\n\t\t\treturn undefined;\n\t\t}\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { AnalyzeNumberSequenceResponse } from '../types/index.js';\nimport { buildMeaningSections } from '../utils/angel-sections.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\n/**\n * Angel number lookup card. Renders /angel-numbers/lookup: the analysed sequence with its pattern classification (type, digit count, unique digits, palindrome, repeating), the known angel-number meaning when the sequence is in the database, and the foundational digit-root meaning that interprets any sequence. Built for synchronicity trackers where users enter arbitrary numbers.\n */\n@customElement('roxy-angel-number-lookup')\nexport class RoxyAngelNumberLookup extends RoxyDataElement<AnalyzeNumberSequenceResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.card{background:var(--roxy-surface,#fff);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.hero{align-items:center;gap:var(--roxy-space-md,1rem);display:flex}.numeral{font-size:3rem;line-height:1;font-weight:var(--roxy-weight-bold,600);color:var(--roxy-accent-ink,#b45309);font-variant-numeric:tabular-nums}.label{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;margin:0}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.badges{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;display:flex}.badge{border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 35%, transparent);color:var(--roxy-fg,#0a0a0a);text-transform:capitalize;align-items:center;padding:3px 10px;display:inline-flex}.badge.flag{background:color-mix(in srgb, var(--roxy-info,#0284c7) 16%, transparent);color:var(--roxy-info-fg,#075985)}.section{border-top:1px solid var(--roxy-border,#e4e4e7);padding-top:var(--roxy-space-md,1rem);gap:var(--roxy-space-sm,.5rem);display:grid}.section>.label{margin:0}.section h3{font-size:var(--roxy-text-base,1rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-fg,#0a0a0a);margin:0}.section p{color:var(--roxy-fg,#0a0a0a);line-height:1.6;font-size:var(--roxy-text-sm,.875rem);margin:0}.chips{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;display:flex}.chips span{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 14%, transparent);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);padding:2px 8px}details{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-sm,4px);overflow:hidden}summary{cursor:pointer;padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);font-weight:var(--roxy-weight-bold,600);font-size:var(--roxy-text-sm,.875rem);list-style-position:inside}details p{padding:0 var(--roxy-space-md,1rem) var(--roxy-space-md,1rem)}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No number analysis</div>`;\n\t}\n\n\tprotected renderData(d: AnalyzeNumberSequenceResponse) {\n\t\tconst known = d.knownMeaning;\n\t\tconst root = d.digitRootMeaning;\n\t\tconst heading = known?.title ?? 'Number analysis';\n\n\t\treturn html`<article class=\"card\" aria-label=\"${`Number ${d.number ?? ''}`}\"><div class=\"hero\">${d.number ? html`<div class=\"numeral\">${d.number}</div>` : nothing}<div><p class=\"label\">Number analysis</p><h2 class=\"title\">${heading}</h2></div></div><div class=\"badges\">${d.type ? html`<span class=\"badge\">${d.type}</span>` : nothing} ${typeof d.digits === 'number' ? html`<span class=\"badge\">${d.digits} digits</span>` : nothing} ${typeof d.uniqueDigits === 'number' ? html`<span class=\"badge\">${d.uniqueDigits} unique</span>` : nothing} ${typeof d.digitRoot === 'number' ? html`<span class=\"badge\">Digit root ${d.digitRoot}</span>` : nothing} ${d.isPalindrome ? html`<span class=\"badge flag\">Palindrome</span>` : nothing} ${d.isRepeating ? html`<span class=\"badge flag\">Repeating</span>` : nothing}</div>${\n\t\t\t\tknown\n\t\t\t\t\t? html`<div class=\"section\"><p class=\"label\">Known angel number</p>${known.coreMessage ? html`<p>${known.coreMessage}</p>` : nothing} ${\n\t\t\t\t\t\t\tknown.keywords && known.keywords.length > 0\n\t\t\t\t\t\t\t\t? html`<div class=\"chips\">${known.keywords.map((k) => html`<span>${k}</span>`)}</div>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t} ${this.renderMeaning(known.meaning, known.biblical, known.shadow)} ${known.affirmation ? html`<p><em>${known.affirmation}</em></p>` : nothing}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\troot\n\t\t\t\t\t? html`<div class=\"section\"><p class=\"label\">Foundational digit root${root.number ? ` (${root.number})` : ''}</p>${root.title ? html`<h3>${root.title}</h3>` : nothing} ${root.coreMessage ? html`<p>${root.coreMessage}</p>` : nothing} ${!known ? this.renderRootMeaning(root) : nothing}</div>`\n\t\t\t\t\t: nothing\n\t\t\t}</article>`;\n\t}\n\n\tprivate renderMeaning(\n\t\tmeaning: Record<string, string> | undefined,\n\t\tbiblical?: string,\n\t\tshadow?: string,\n\t) {\n\t\tconst sections = buildMeaningSections(meaning, biblical, shadow);\n\t\tif (sections.length === 0) return nothing;\n\t\treturn html`${sections.map(\n\t\t\t(s, i) => html`<details name=\"lookup-meaning\" ?open=\"${i === 0}\"><summary>${s.label}</summary><p>${s.body}</p></details>`,\n\t\t)}`;\n\t}\n\n\t/**\n\t * Render the foundational digit-root reading for an unknown sequence: keyword chips, the full life-area accordion (including money), and the affirmation. The digit-root meaning carries no biblical or shadow field, so only the life areas are passed through.\n\t */\n\tprivate renderRootMeaning(\n\t\troot: NonNullable<AnalyzeNumberSequenceResponse['digitRootMeaning']>,\n\t) {\n\t\treturn html`${\n\t\t\troot.keywords && root.keywords.length > 0\n\t\t\t\t? html`<div class=\"chips\">${root.keywords.map((k) => html`<span>${k}</span>`)}</div>`\n\t\t\t\t: nothing\n\t\t}${this.renderMeaning(root.meaning)}${\n\t\t\troot.affirmation ? html`<p><em>${root.affirmation}</em></p>` : nothing\n\t\t}`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-angel-number-lookup': RoxyAngelNumberLookup;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\nimport { SIGN_GLYPH } from '../tokens/index.js';\nimport type { AshtakavargaResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\ntype Tab = 'sarva' | 'bhinna' | 'pinda';\n\nconst TAB_LABELS: Record<Tab, string> = {\n\tsarva: 'Sarvashtakavarga',\n\tbhinna: 'Bhinnashtakavarga',\n\tpinda: 'Shodhya Pinda',\n};\n\nconst TABS: Tab[] = ['sarva', 'bhinna', 'pinda'];\n\n/**\n * Ashtakavarga grid with three tabbed views: Sarvashtakavarga, Bhinnashtakavarga,\n * and Shodhya Pinda. Pass `data` from /vedic-astrology/ashtakavarga.\n */\n@customElement('roxy-ashtakavarga-grid')\nexport class RoxyAshtakavargaGrid extends RoxyDataElement<AshtakavargaResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-md,1rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.subtitle{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem);margin:0}.tablist{border-bottom:2px solid var(--roxy-border,#e4e4e7);gap:2px;display:flex}.tab{padding:var(--roxy-space-xs,.25rem) var(--roxy-space-md,1rem);font-size:var(--roxy-text-sm,.875rem);cursor:pointer;color:var(--roxy-muted,#71717a);transition:color var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,ease);background:0 0;border:none;border-bottom:2px solid #0000;margin-bottom:-2px;font-family:inherit}.tab[aria-selected=true]{color:var(--roxy-accent-ink,#b45309);border-bottom-color:var(--roxy-accent,#f59e0b);font-weight:var(--roxy-weight-bold,600)}.tab:hover:not([aria-selected=true]){color:var(--roxy-fg,#0a0a0a)}.overflow-scroll{-webkit-overflow-scrolling:touch;overflow-x:auto}table{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem)}th,td{padding:var(--roxy-space-sm,.5rem);border-bottom:1px solid var(--roxy-border,#e4e4e7);text-align:center}th{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;font-size:var(--roxy-text-xs,.75rem);letter-spacing:.06em}td:first-child,th:first-child{text-align:left}.glyph{margin-right:3px;font-size:1.1em;line-height:1}.planet-cell{white-space:nowrap;align-items:center;gap:4px;display:flex}.total-row td{font-weight:var(--roxy-weight-bold,600);border-top:2px solid var(--roxy-border,#e4e4e7);border-bottom:none}.heat-cell{border-radius:var(--roxy-radius-sm,4px);font-weight:var(--roxy-weight-bold,600);font-variant-numeric:tabular-nums;min-width:2rem;color:var(--roxy-fg,currentColor)}.heat-1{background:color-mix(in srgb, var(--roxy-heat,#ef4444) 6%, transparent)}.heat-2{background:color-mix(in srgb, var(--roxy-heat,#ef4444) 14%, transparent)}.heat-3{background:color-mix(in srgb, var(--roxy-heat,#ef4444) 26%, transparent)}.heat-4{background:color-mix(in srgb, var(--roxy-heat,#ef4444) 40%, transparent)}.heat-5{background:color-mix(in srgb, var(--roxy-heat,#ef4444) 55%, transparent)}.heat-6{background:color-mix(in srgb, var(--roxy-heat,#ef4444) 72%, transparent)}.heat-7{background:color-mix(in srgb, var(--roxy-heat,#ef4444) 90%, transparent)}.bhinna-table th:first-child,.bhinna-table td:first-child{min-width:5rem}@container (width<=480px){.bhinna-table th,.bhinna-table td{font-size:var(--roxy-text-xs,.75rem);padding:.3rem .35rem}.bhinna-table th:first-child,.bhinna-table td:first-child{min-width:3.5rem}.heat-cell{min-width:1.5rem}}.overflow-scroll{-webkit-mask-image:linear-gradient(90deg,#0000 0,#000 .5rem calc(100% - 1rem),#0000 100%);mask-image:linear-gradient(90deg,#0000 0,#000 .5rem calc(100% - 1rem),#0000 100%)}`,\n\t];\n\n\t@state()\n\tactiveTab: Tab = 'sarva';\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No ashtakavarga data</div>`;\n\t}\n\n\tprotected renderData(d: AshtakavargaResponse) {\n\t\tconst signs = d.signs ?? [];\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Ashtakavarga grid\"><div class=\"head\"><h2 class=\"title\">Ashtakavarga</h2>${\n\t\t\t\t\tsigns.length\n\t\t\t\t\t\t? html`<p class=\"subtitle\">${signs.length} signs</p>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</div><div class=\"tablist\" role=\"tablist\" aria-label=\"Ashtakavarga views\" @keydown=\"${this.onTabKeyDown}\">${TABS.map(\n\t\t\t\t\t(tab) => html`<button class=\"tab\" role=\"tab\" id=\"tab-${tab}\" aria-selected=\"${this.activeTab === tab ? 'true' : 'false'}\" aria-controls=\"panel-${tab}\" tabindex=\"${this.activeTab === tab ? '0' : '-1'}\" @click=\"${() => {\n\t\t\t\t\t\t\tthis.activeTab = tab;\n\t\t\t\t\t\t}}\">${TAB_LABELS[tab]}</button>`,\n\t\t\t\t)}</div><div id=\"panel-${this.activeTab}\" role=\"tabpanel\" aria-labelledby=\"tab-${this.activeTab}\">${\n\t\t\t\t\tthis.activeTab === 'sarva'\n\t\t\t\t\t\t? this.renderSarva(signs)\n\t\t\t\t\t\t: this.activeTab === 'bhinna'\n\t\t\t\t\t\t\t? this.renderBhinna(signs)\n\t\t\t\t\t\t\t: this.renderPinda()\n\t\t\t\t}</div></div>`;\n\t}\n\n\tprivate onTabKeyDown(e: KeyboardEvent) {\n\t\tconst idx = TABS.indexOf(this.activeTab);\n\t\tif (e.key === 'ArrowRight') {\n\t\t\te.preventDefault();\n\t\t\tthis.activeTab = TABS[(idx + 1) % TABS.length];\n\t\t\tthis.focusActiveTab();\n\t\t} else if (e.key === 'ArrowLeft') {\n\t\t\te.preventDefault();\n\t\t\tthis.activeTab = TABS[(idx - 1 + TABS.length) % TABS.length];\n\t\t\tthis.focusActiveTab();\n\t\t}\n\t}\n\n\tprivate focusActiveTab() {\n\t\trequestAnimationFrame(() => {\n\t\t\tconst btn = this.shadowRoot?.querySelector<HTMLButtonElement>(\n\t\t\t\t`#tab-${this.activeTab}`,\n\t\t\t);\n\t\t\tbtn?.focus();\n\t\t});\n\t}\n\n\t/**\n\t * Bhinna bindus per planet per sign run 0..8 (sum of 0/1 contributions\n\t * from each of the 8 reference points). Bucket directly by raw count.\n\t */\n\tprivate bhinnaHeat(count: number): string {\n\t\tif (count <= 1) return 'heat-1';\n\t\tif (count <= 2) return 'heat-2';\n\t\tif (count <= 3) return 'heat-3';\n\t\tif (count <= 4) return 'heat-4';\n\t\tif (count <= 5) return 'heat-5';\n\t\tif (count <= 6) return 'heat-6';\n\t\treturn 'heat-7';\n\t}\n\n\t/**\n\t * Sarva bindus per sign are the column total across all 7 planets, range\n\t * roughly 0..56 with typical values 20..40. Bucketed per classical\n\t * interpretation: 25 below par, 25..30 average, 30..40 strong, 40+ very\n\t * strong. Bucket spans intentionally widen at the extremes so a single\n\t * outlier sign reads as exceptional.\n\t */\n\tprivate sarvaHeat(count: number): string {\n\t\tif (count <= 18) return 'heat-1';\n\t\tif (count <= 23) return 'heat-2';\n\t\tif (count <= 28) return 'heat-3';\n\t\tif (count <= 32) return 'heat-4';\n\t\tif (count <= 37) return 'heat-5';\n\t\tif (count <= 42) return 'heat-6';\n\t\treturn 'heat-7';\n\t}\n\n\tprivate renderSarva(signs: AshtakavargaResponse['signs']) {\n\t\tconst sav = this.data!.sarvashtakavarga;\n\t\tif (!sav) return html`<p class=\"roxy-empty\">No sarvashtakavarga data</p>`;\n\n\t\treturn html`<div class=\"overflow-scroll\"><table aria-label=\"Sarvashtakavarga bindu counts per sign\"><thead><tr><th scope=\"col\">Sign</th><th scope=\"col\">Bindus</th></tr></thead><tbody>${signs.map((sign, i) => {\n\t\t\t\t\t\tconst count = sav.bindus[i] ?? 0;\n\t\t\t\t\t\tconst hc = this.sarvaHeat(count);\n\t\t\t\t\t\treturn html`<tr><td><div class=\"planet-cell\"><span class=\"glyph\" aria-hidden=\"true\">${SIGN_GLYPH[sign] ?? ''}</span> ${sign}</div></td><td class=\"${`heat-cell ${hc}`}\">${count}</td></tr>`;\n\t\t\t\t\t})}</tbody><tfoot><tr class=\"total-row\"><td>Total</td><td>${sav.total}</td></tr></tfoot></table></div>`;\n\t}\n\n\tprivate renderBhinna(signs: AshtakavargaResponse['signs']) {\n\t\tconst bhinna = this.data!.bhinnashtakavarga;\n\t\tif (!bhinna?.length)\n\t\t\treturn html`<p class=\"roxy-empty\">No bhinnashtakavarga data</p>`;\n\n\t\treturn html`<div class=\"overflow-scroll\"><table class=\"bhinna-table\" aria-label=\"Bhinnashtakavarga planet-by-sign grid\"><thead><tr><th scope=\"col\">Planet</th>${signs.map(\n\t\t\t\t\t\t\t(s) =>\n\t\t\t\t\t\t\t\thtml`<th scope=\"col\" title=\"${s}\">${SIGN_GLYPH[s] ?? s.slice(0, 2)}</th>`,\n\t\t\t\t\t\t)}<th scope=\"col\">Total</th></tr></thead><tbody>${bhinna.map(\n\t\t\t\t\t\t(row) => html`<tr><td>${row.planet}</td>${row.bindus.map((count) => {\n\t\t\t\t\t\t\tconst hc = this.bhinnaHeat(count);\n\t\t\t\t\t\t\treturn html`<td class=\"${`heat-cell ${hc}`}\">${count}</td>`;\n\t\t\t\t\t\t})}<td>${row.total}</td></tr>`,\n\t\t\t\t\t)}</tbody></table></div>`;\n\t}\n\n\tprivate renderPinda() {\n\t\tconst pinda = this.data!.shodhyaPinda;\n\t\tif (!pinda?.length)\n\t\t\treturn html`<p class=\"roxy-empty\">No shodhya pinda data</p>`;\n\n\t\treturn html`<div class=\"overflow-scroll\"><table aria-label=\"Shodhya Pinda planet strength scores\"><thead><tr><th scope=\"col\">Planet</th><th scope=\"col\">Rashi Pinda</th><th scope=\"col\">Graha Pinda</th><th scope=\"col\">Shodhya Pinda</th></tr></thead><tbody>${pinda.map(\n\t\t\t\t\t\t(row) => html`<tr><td>${row.planet}</td><td>${row.rashiPinda}</td><td>${row.grahaPinda}</td><td>${row.shodhyaPinda}</td></tr>`,\n\t\t\t\t\t)}</tbody></table></div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-ashtakavarga-grid': RoxyAshtakavargaGrid;\n\t}\n}\n", "/**\n * Symbol constants used across components. Single source of truth so chart\n * wheels, card headers, hexagram displays, and panchang tables stay visually\n * consistent.\n */\n\nexport const PLANET_GLYPH: Record<string, string> = {\n\tSun: '\u2609',\n\tMoon: '\u263D',\n\tMercury: '\u263F',\n\tVenus: '\u2640',\n\tEarth: '\u2641',\n\tMars: '\u2642',\n\tJupiter: '\u2643',\n\tSaturn: '\u2644',\n\tUranus: '\u2645',\n\tNeptune: '\u2646',\n\tPluto: '\u2647',\n\tRahu: '\u260A',\n\tKetu: '\u260B',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n\tNorthNode: '\u260A',\n\tSouthNode: '\u260B',\n\t'North node': '\u260A',\n\t'South node': '\u260B',\n\tChiron: '\u26B7',\n\tLilith: '\u26B8',\n\t'Black moon lilith': '\u26B8',\n};\n\nexport const PLANET_ABBR: Record<string, string> = {\n\tSun: 'Su',\n\tMoon: 'Mo',\n\tMercury: 'Me',\n\tVenus: 'Ve',\n\tMars: 'Ma',\n\tJupiter: 'Ju',\n\tSaturn: 'Sa',\n\tUranus: 'Ur',\n\tNeptune: 'Ne',\n\tPluto: 'Pl',\n\tRahu: 'Ra',\n\tKetu: 'Ke',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n};\n\nexport const SIGN_GLYPH: Record<string, string> = {\n\tAries: '\u2648',\n\tTaurus: '\u2649',\n\tGemini: '\u264A',\n\tCancer: '\u264B',\n\tLeo: '\u264C',\n\tVirgo: '\u264D',\n\tLibra: '\u264E',\n\tScorpio: '\u264F',\n\tSagittarius: '\u2650',\n\tCapricorn: '\u2651',\n\tAquarius: '\u2652',\n\tPisces: '\u2653',\n};\n\nexport const SIGN_ABBR: Record<string, string> = {\n\tAries: 'Ar',\n\tTaurus: 'Ta',\n\tGemini: 'Ge',\n\tCancer: 'Cn',\n\tLeo: 'Le',\n\tVirgo: 'Vi',\n\tLibra: 'Li',\n\tScorpio: 'Sc',\n\tSagittarius: 'Sg',\n\tCapricorn: 'Cp',\n\tAquarius: 'Aq',\n\tPisces: 'Pi',\n};\n\nexport const SIGNS_ORDER = [\n\t'Aries',\n\t'Taurus',\n\t'Gemini',\n\t'Cancer',\n\t'Leo',\n\t'Virgo',\n\t'Libra',\n\t'Scorpio',\n\t'Sagittarius',\n\t'Capricorn',\n\t'Aquarius',\n\t'Pisces',\n] as const;\n\n/**\n * Lowercase rashi keys in canonical zodiac order. Derived from `SIGNS_ORDER`\n * so the two stay in lockstep. The /vedic-astrology/birth-chart response\n * carries planet buckets keyed by these names.\n */\nexport const RASHI_KEYS = SIGNS_ORDER.map((s) =>\n\ts.toLowerCase(),\n) as readonly Lowercase<(typeof SIGNS_ORDER)[number]>[];\n\n/** Aspect symbols. Used by synastry and natal chart aspect tables. */\nexport const ASPECT_SYMBOL: Record<string, string> = {\n\tconjunction: '\u260C',\n\topposition: '\u260D',\n\ttrine: '\u25B3',\n\tsquare: '\u25A1',\n\tsextile: '\u2731',\n\tquincunx: '\u22BB',\n\tsemisextile: '\u22BC',\n};\n\n/** Trigrams used by I Ching hexagrams. Eight trigrams compose 64 hexagrams. */\nexport const TRIGRAM_GLYPH: Record<string, string> = {\n\theaven: '\u2630',\n\tlake: '\u2631',\n\tfire: '\u2632',\n\tthunder: '\u2633',\n\twind: '\u2634',\n\twater: '\u2635',\n\tmountain: '\u2636',\n\tearth: '\u2637',\n\tHeaven: '\u2630',\n\tLake: '\u2631',\n\tFire: '\u2632',\n\tThunder: '\u2633',\n\tWind: '\u2634',\n\tWater: '\u2635',\n\tMountain: '\u2636',\n\tEarth: '\u2637',\n};\n\n/** Moon phase emoji set. Used by moon phase card. */\nexport const MOON_PHASE_EMOJI: Record<string, string> = {\n\t'new moon': '\uD83C\uDF11',\n\t'waxing crescent': '\uD83C\uDF12',\n\t'first quarter': '\uD83C\uDF13',\n\t'waxing gibbous': '\uD83C\uDF14',\n\t'full moon': '\uD83C\uDF15',\n\t'waning gibbous': '\uD83C\uDF16',\n\t'last quarter': '\uD83C\uDF17',\n\t'waning crescent': '\uD83C\uDF18',\n};\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { PLANET_GLYPH } from '../tokens/index.js';\nimport type {\n\tCalculateAspectsResponse,\n\tCalculateTransitAspectsResponse,\n\tDetectAspectPatternsResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { chevron, disclosureStyles } from '../utils/disclosure.js';\nimport { formatNumber } from '../utils/format.js';\nimport { capitalize } from '../utils/string.js';\n\n/**\n * Natal + transit aspect grid with chart-pattern detection. Renders three endpoints that share an aspects/patterns shape: /astrology/aspects (natal aspects + patterns + a harmonious/challenging summary), /astrology/transit-aspects (transiting-to-natal aspects with timing guidance), and /astrology/aspect-patterns (patterns only: grand trines, t-squares, stelliums, yods, kites). Each aspect row shows the two bodies, the aspect type coloured by nature, its orb and strength, and an expandable interpretation; patterns render as labelled cards listing the planets they bind.\n */\ntype AspectsData =\n\t| CalculateAspectsResponse\n\t| CalculateTransitAspectsResponse\n\t| DetectAspectPatternsResponse;\n\n@customElement('roxy-aspects-table')\nexport class RoxyAspectsTable extends RoxyDataElement<AspectsData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tdisclosureStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-md,1rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.subtitle{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem);margin:0}.summary-pills{gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.pill{padding:2px var(--roxy-space-sm,.5rem);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);border:1px solid;align-items:center;gap:4px;display:inline-flex}.pill--muted{color:var(--roxy-fg,#0a0a0a);background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 60%, transparent)}.pill--success{color:var(--roxy-success-fg,#166534);background:color-mix(in srgb, var(--roxy-success,#16a34a) 10%, transparent)}.pill--danger{color:var(--roxy-danger-fg,#991b1b);background:color-mix(in srgb, var(--roxy-danger,#dc2626) 10%, transparent)}.section-label{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;font-weight:var(--roxy-weight-bold,600);margin:0 0 var(--roxy-space-xs,.25rem) 0}.aspect-card{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);margin-bottom:var(--roxy-space-xs,.25rem)}.aspect-card summary{cursor:pointer;color:var(--roxy-fg,#0a0a0a);flex-wrap:wrap;align-items:center;gap:.5em;font-weight:500;display:flex}.aspect-card summary .meta{color:var(--roxy-muted,#71717a);font-weight:400;font-size:var(--roxy-text-xs,.75rem);font-variant-numeric:tabular-nums;margin-left:auto}.interp-body{margin-top:var(--roxy-space-xs,.25rem);color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);line-height:1.45}.interp-body p{margin:0 0 var(--roxy-space-xs,.25rem)}.interp-keywords{flex-wrap:wrap;gap:.25rem;margin-top:.5rem;display:flex}.kw{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 14%, transparent);color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-xs,.75rem);border-radius:9999px;padding:1px 8px}.glyph{font-size:1.1em;line-height:1}.nature-badge{font-size:var(--roxy-text-xs,.75rem);text-transform:capitalize;border-radius:9999px;padding:1px 8px;font-weight:600;display:inline-block}.nature-badge.harmonious{background:color-mix(in srgb, var(--roxy-success,#16a34a) 12%, transparent);color:var(--roxy-success-fg,#166534)}.nature-badge.challenging{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 12%, transparent);color:var(--roxy-danger-fg,#991b1b)}.nature-badge.neutral{background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 60%, transparent);color:var(--roxy-fg,#0a0a0a)}.pattern{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);margin-bottom:var(--roxy-space-xs,.25rem);gap:.35rem;display:grid}.pattern-head{flex-wrap:wrap;align-items:baseline;gap:.5rem;display:flex}.pattern-name{font-weight:var(--roxy-weight-bold,600)}.pattern-planets{color:var(--roxy-accent-ink,#b45309);font-size:var(--roxy-text-sm,.875rem)}.pattern-tight{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);font-variant-numeric:tabular-nums;margin-left:auto}.pattern-interp{color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);margin:0;line-height:1.45}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No aspect data</div>`;\n\t}\n\n\tprotected renderData(d: AspectsData) {\n\t\tconst aspects = 'aspects' in d ? (d.aspects ?? []) : [];\n\t\tconst patterns = 'patterns' in d ? (d.patterns ?? []) : [];\n\t\tconst summary = 'summary' in d ? d.summary : undefined;\n\t\tif (aspects.length === 0 && patterns.length === 0)\n\t\t\treturn this.renderEmpty();\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Aspects\"><div class=\"head\"><h2 class=\"title\">Aspects</h2>${aspects.length > 0 ? html`<p class=\"subtitle\">${aspects.length} aspects</p>` : nothing}</div>${summary ? this.renderSummary(summary) : nothing} ${\n\t\t\t\taspects.length > 0\n\t\t\t\t\t? html`<div role=\"list\" aria-label=\"Aspect list\">${aspects.map((a, i) => this.renderAspect(a, i))}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tpatterns.length > 0\n\t\t\t\t\t? html`<div><p class=\"section-label\">Patterns</p>${patterns.map((p) => this.renderPattern(p))}</div>`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n\n\tprivate renderSummary(\n\t\ts:\n\t\t\t| NonNullable<CalculateAspectsResponse['summary']>\n\t\t\t| NonNullable<CalculateTransitAspectsResponse['summary']>,\n\t) {\n\t\tconst total = 'totalAspects' in s ? s.totalAspects : s.total;\n\t\treturn html`<div class=\"summary-pills\" role=\"region\" aria-label=\"Aspect summary\">${typeof total === 'number' ? html`<span class=\"pill pill--muted\">Total: ${total}</span>` : nothing} <span class=\"pill pill--success\">Harmonious: ${s.harmonious}</span> <span class=\"pill pill--danger\">Challenging: ${s.challenging}</span> <span class=\"pill pill--muted\">Neutral: ${s.neutral}</span></div>`;\n\t}\n\n\tprivate renderAspect(\n\t\ta:\n\t\t\t| NonNullable<CalculateAspectsResponse['aspects']>[number]\n\t\t\t| NonNullable<CalculateTransitAspectsResponse['aspects']>[number],\n\t\tidx: number,\n\t) {\n\t\tconst g1 = PLANET_GLYPH[capitalize(a.planet1)] ?? '';\n\t\tconst g2 = PLANET_GLYPH[capitalize(a.planet2)] ?? '';\n\t\tconst nature = (a.interpretation ?? 'neutral').toLowerCase();\n\t\tconst type = (a.type ?? '').toLowerCase().replace(/_/g, ' ');\n\t\tconst status = a.isApplying ? 'Applying' : 'Separating';\n\t\t// Natal aspects carry `meaning` (static aspect lore); transits carry `transitInterpretation` (timed guidance).\n\t\tconst meaning = 'meaning' in a ? a.meaning : undefined;\n\t\tconst transit =\n\t\t\t'transitInterpretation' in a ? a.transitInterpretation : undefined;\n\t\tconst hasBody = Boolean(meaning || transit);\n\t\tconst header = html`<span aria-hidden=\"true\" class=\"glyph\">${g1}</span>${a.planet1} <span class=\"nature-badge ${nature}\">${type}</span> <span aria-hidden=\"true\" class=\"glyph\">${g2}</span>${a.planet2} <span class=\"meta\">${status} \u00B7 orb ${formatNumber(a.orb, 2)}\u00B0 \u00B7 str ${formatNumber(a.strength, 0)}</span>`;\n\t\tif (!hasBody) {\n\t\t\treturn html`<div class=\"aspect-card\" role=\"listitem\"><div class=\"summary\" style=\"cursor:default\">${header}</div></div>`;\n\t\t}\n\t\treturn html`<details class=\"aspect-card\" role=\"listitem\" name=\"aspects\" ?open=\"${idx === 0}\"><summary>${header}${chevron()}</summary><div class=\"interp-body\">${meaning ? this.renderMeaning(meaning) : nothing} ${transit ? this.renderTransit(transit) : nothing}</div></details>`;\n\t}\n\n\tprivate renderMeaning(\n\t\tm: NonNullable<\n\t\t\tNonNullable<CalculateAspectsResponse['aspects']>[number]['meaning']\n\t\t>,\n\t) {\n\t\tconst text = m.description?.short ?? m.description?.long;\n\t\treturn html`${text ? html`<p>${text}</p>` : nothing} ${\n\t\t\t\tm.keywords?.length\n\t\t\t\t\t? html`<div class=\"interp-keywords\">${m.keywords.map((k) => html`<span class=\"kw\">${k}</span>`)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t}`;\n\t}\n\n\tprivate renderTransit(\n\t\tt: NonNullable<\n\t\t\tNonNullable<\n\t\t\t\tCalculateTransitAspectsResponse['aspects']\n\t\t\t>[number]['transitInterpretation']\n\t\t>,\n\t) {\n\t\treturn html`${t.summary ? html`<p>${t.summary}</p>` : nothing} ${t.impact ? html`<p><strong>Impact:</strong> ${t.impact}</p>` : nothing} ${t.timing ? html`<p><strong>Timing:</strong> ${t.timing}</p>` : nothing} ${t.guidance ? html`<p><strong>Guidance:</strong> ${t.guidance}</p>` : nothing} ${\n\t\t\t\tt.keywords?.length\n\t\t\t\t\t? html`<div class=\"interp-keywords\">${t.keywords.map((k) => html`<span class=\"kw\">${k}</span>`)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t}`;\n\t}\n\n\tprivate renderPattern(\n\t\tp: NonNullable<DetectAspectPatternsResponse['patterns']>[number],\n\t) {\n\t\tconst planets = p.planets ?? [];\n\t\treturn html`<div class=\"pattern\"><div class=\"pattern-head\"><span class=\"pattern-name\">${p.name ?? p.kind ?? 'Pattern'}</span> ${planets.length ? html`<span class=\"pattern-planets\">${planets.join(', ')}</span>` : nothing} ${typeof p.tightness === 'number' ? html`<span class=\"pattern-tight\">${formatNumber(p.tightness, 0)}% tight</span>` : nothing}</div>${p.interpretation ? html`<p class=\"pattern-interp\">${p.interpretation}</p>` : nothing}</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-aspects-table': RoxyAspectsTable;\n\t}\n}\n", "import type { TemplateResult } from 'lit';\nimport { css, html } from 'lit';\n\n/**\n * Disclosure chevron for `<details>`/`<summary>` accordions. Replaces the\n * browser default triangle with a thin chevron that rotates when the host\n * `<details>` opens. Render it inside the `<summary>` and pair with\n * {@link disclosureStyles}.\n */\nexport function chevron(): TemplateResult {\n\treturn html`<svg class=\"roxy-chevron\" viewBox=\"0 0 16 16\" width=\"14\" height=\"14\" aria-hidden=\"true\"><path d=\"M4 6l4 4 4-4\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>`;\n}\n\n/**\n * Shared `<details>` accordion styling: hides the native disclosure triangle\n * and rotates the {@link chevron} 180 degrees when the accordion is open.\n * Import into any component that renders disclosure accordions so the chevron\n * looks and behaves identically.\n */\nexport const disclosureStyles = css`summary{list-style:none}summary::-webkit-details-marker{display:none}.roxy-chevron{aspect-ratio:auto;width:14px;height:14px;color:var(--roxy-muted,#71717a);transition:transform var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,ease);flex-shrink:0}details[open]>summary .roxy-chevron{transform:rotate(180deg)}@media (prefers-reduced-motion:reduce){.roxy-chevron{transition:none}}`;\n", "/**\n * Display formatters for ISO timestamps and floats coming back from the API.\n * Every helper returns \"\" for nullish or unparseable input so it falls out of\n * template literals cleanly.\n */\n\nexport function formatTime(input: unknown): string {\n\tif (typeof input !== 'string' || input.length === 0) return '';\n\tif (/^\\d{4}-\\d{2}-\\d{2}$/.test(input)) return '';\n\tconst bareTime = /^\\d{2}:\\d{2}(:\\d{2})?$/.test(input);\n\tconst iso = bareTime ? `1970-01-01T${input}` : input;\n\tconst d = new Date(iso);\n\tif (Number.isNaN(d.getTime())) return input;\n\treturn d.toLocaleTimeString(undefined, {\n\t\thour: 'numeric',\n\t\tminute: '2-digit',\n\t\thour12: true,\n\t});\n}\n\nexport function formatDate(input: unknown): string {\n\tif (typeof input !== 'string' || input.length === 0) return '';\n\tconst d = new Date(\n\t\t/^\\d{4}-\\d{2}-\\d{2}$/.test(input) ? `${input}T00:00:00` : input,\n\t);\n\tif (Number.isNaN(d.getTime())) return input;\n\treturn d.toLocaleDateString(undefined, {\n\t\tmonth: 'short',\n\t\tday: 'numeric',\n\t\tyear: 'numeric',\n\t});\n}\n\nexport function formatTimeRange(\n\tt: { start?: string; end?: string } | undefined,\n): string {\n\tif (!t) return '';\n\tconst start = formatTime(t.start);\n\tconst end = formatTime(t.end);\n\tif (start && end) return `${start} - ${end}`;\n\treturn start || end || '';\n}\n\nexport function formatNumber(value: unknown, dp = 1): string {\n\tif (typeof value !== 'number' || !Number.isFinite(value)) return '';\n\treturn value.toFixed(dp).replace(/\\.?0+$/, '');\n}\n\nexport function formatPercent(value: unknown, dp = 1): string {\n\tconst n = formatNumber(value, dp);\n\treturn n ? `${n}%` : '';\n}\n\n/**\n * CSS class name per aspect type. Used by natal and synastry chart aspect\n * lines so the same color encoding (harmonious vs challenging) applies in\n * both wheels. Keys are lowercase canonical names, values are CSS class\n * suffixes the chart components define in their `:host` styles.\n */\nexport const ASPECT_CLASS: Record<string, string> = {\n\tconjunction: 'aspect-conjunction',\n\tsextile: 'aspect-sextile',\n\tsquare: 'aspect-square',\n\ttrine: 'aspect-trine',\n\topposition: 'aspect-opposition',\n};\n\n/**\n * Normalize the `type` field on an aspect entry to a lowercase, hyphen-separated\n * canonical name (`SEMI_SEXTILE` \u2192 `semi-sextile`). Accepts any aspect-shaped\n * object so both natal and synastry inter-aspect entries can share this.\n */\nexport function normalizeAspect(a: { type?: string }): string {\n\treturn (a.type ?? '').toLowerCase().replace(/_/g, '-');\n}\n", "/**\n * Shared string helpers used across components. Single source of truth so the\n * same formatting rules apply to every key/label/title that surfaces in the\n * shadow tree.\n *\n * - `capitalize`: title-cases the first character, lowercases the rest. Used\n * when matching API-supplied planet/sign names against the glyph maps in\n * `tokens/index.ts`, which use canonical TitleCase keys.\n * - `humanize`: turns an API key (`birth_date`, `birthDate`, `mahadasha-end`)\n * into a label suitable for display (\"Birth date\", \"Mahadasha end\").\n */\n\nexport function capitalize(s: string): string {\n\tif (!s) return '';\n\treturn s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();\n}\n\nexport function humanize(s: string): string {\n\treturn s\n\t\t.replace(/[_-]+/g, ' ')\n\t\t.replace(/([a-z])([A-Z])/g, '$1 $2')\n\t\t.replace(/^\\w/, (c) => c.toUpperCase());\n}\n", "import { css, html, nothing, svg } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type {\n\tGetCriticalDaysResponse,\n\tGetDailyBiorhythmResponse,\n\tGetForecastResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\ntype BiorhythmData =\n\t| GetDailyBiorhythmResponse\n\t| GetForecastResponse\n\t| GetCriticalDaysResponse;\n\nconst CYCLE_COLOR: Record<string, string> = {\n\tphysical: '#dc2626',\n\temotional: '#0284c7',\n\tintellectual: '#16a34a',\n\tintuitive: '#a855f7',\n\taesthetic: '#f59e0b',\n\tawareness: '#ec4899',\n\tspiritual: '#14b8a6',\n\tpassion: '#ef4444',\n\tmastery: '#6366f1',\n\twisdom: '#475569',\n};\n\n/**\n * Biorhythm chart. Renders /biorhythm/{daily,forecast,critical-days}.\n */\n@customElement('roxy-biorhythm-chart')\nexport class RoxyBiorhythmChart extends RoxyDataElement<BiorhythmData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:center;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.energy{font-variant-numeric:tabular-nums;color:var(--roxy-accent-ink,#b45309);font-weight:var(--roxy-weight-bold,600)}.bars{gap:var(--roxy-space-xs,.25rem);display:grid}.bar{gap:var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-sm,.875rem);grid-template-columns:8rem 1fr 3.5rem;align-items:center;display:grid}.track{background:var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-full,9999px);height:14px;position:relative;overflow:hidden}.fill{height:100%;transition:width var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,cubic-bezier(.4, 0, .2, 1));display:block}.value{font-variant-numeric:tabular-nums;text-align:right;color:var(--roxy-muted,#71717a)}.advice{color:var(--roxy-fg,#0a0a0a)}.alert{background:color-mix(in srgb, var(--roxy-warning,#ea580c) 12%, transparent);border:1px solid color-mix(in srgb, var(--roxy-warning,#ea580c) 32%, transparent);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-sm,.875rem);margin:0}svg{width:100%;max-width:var(--roxy-chart-max-width,600px);height:auto;display:block}.crit{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 12%, transparent);border-radius:var(--roxy-radius-sm,4px);font-size:var(--roxy-text-xs,.75rem);margin:2px;padding:4px 8px;display:inline-block}`,\n\t];\n\n\t@property({ type: String, reflect: true })\n\tmode: 'daily' | 'forecast' | 'critical-days' = 'daily';\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No biorhythm data</div>`;\n\t}\n\n\tprotected renderData(d: BiorhythmData) {\n\t\tif (this.mode === 'critical-days' && 'criticalDays' in d) {\n\t\t\treturn this.renderCritical(d as GetCriticalDaysResponse);\n\t\t}\n\t\tif (this.mode === 'forecast' && 'days' in d) {\n\t\t\treturn this.renderForecast(d as GetForecastResponse);\n\t\t}\n\t\treturn this.renderDaily(d as GetDailyBiorhythmResponse);\n\t}\n\n\tprivate renderDaily(d: GetDailyBiorhythmResponse) {\n\t\tconst raw = d.quickRead ?? {};\n\t\tconst entries = Object.entries(raw).map(([cycle, value]) => {\n\t\t\tconst v = typeof value === 'number' ? value : 0;\n\t\t\tconst normalized = Math.abs(v) > 1 ? v / 100 : v;\n\t\t\treturn [cycle, normalized] as const;\n\t\t});\n\t\treturn html`<section class=\"wrap\" aria-label=\"Daily biorhythm\"><header class=\"head\"><h2 class=\"title\">Biorhythm</h2>${\n\t\t\t\t\ttypeof d.energyRating === 'number'\n\t\t\t\t\t\t? html`<span class=\"energy\">Energy ${d.energyRating}/10</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</header><div class=\"bars\" role=\"list\">${entries.map(([cycle, v]) => {\n\t\t\t\t\tconst pct = ((v + 1) / 2) * 100; // -1..1 -> 0..100\n\t\t\t\t\tconst color = CYCLE_COLOR[cycle] ?? 'var(--roxy-accent, #f59e0b)';\n\t\t\t\t\treturn html`<div class=\"bar\" role=\"listitem\"><span style=\"text-transform:capitalize\">${cycle}</span> <span class=\"track\"><span class=\"fill\" style=\"width:${pct}%;background:${color}\"></span> </span><span class=\"value\">${Math.round(v * 100)}%</span></div>`;\n\t\t\t\t})}</div>${d.dailyMessage ? html`<p class=\"advice\">${d.dailyMessage}</p>` : nothing} ${d.advice ? html`<p class=\"advice\">${d.advice}</p>` : nothing}</section>`;\n\t}\n\n\tprivate renderForecast(d: GetForecastResponse) {\n\t\tconst days = d.days ?? [];\n\t\tif (days.length === 0)\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No forecast</div>`;\n\t\tconst w = 600;\n\t\tconst h = 160;\n\t\tconst xStep = w / Math.max(days.length - 1, 1);\n\t\tconst cycleKeys = [\n\t\t\t'physical',\n\t\t\t'emotional',\n\t\t\t'intellectual',\n\t\t\t'intuitive',\n\t\t] as const;\n\t\treturn html`<section class=\"wrap\" aria-label=\"Biorhythm forecast\"><header class=\"head\"><h2 class=\"title\">Forecast</h2><span class=\"energy\">${d.startDate} - ${d.endDate}</span></header><svg viewBox=\"0 0 ${w} ${h}\" role=\"img\" aria-label=\"Biorhythm cycle lines across the forecast window\"><title>Biorhythm forecast</title><line x1=\"0\" y1=\"${h / 2}\" x2=\"${w}\" y2=\"${h / 2}\" stroke=\"var(--roxy-border, #e4e4e7)\" stroke-width=\"1\"/>${cycleKeys.map((cycle) => {\n\t\t\t\t\tconst points = days\n\t\t\t\t\t\t.map((day, i) => {\n\t\t\t\t\t\t\tconst v = day[cycle] ?? 0;\n\t\t\t\t\t\t\tconst x = i * xStep;\n\t\t\t\t\t\t\tconst y = h / 2 - (v / 100) * (h / 2 - 8);\n\t\t\t\t\t\t\treturn `${x.toFixed(2)},${y.toFixed(2)}`;\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.join(' ');\n\t\t\t\t\tconst color = CYCLE_COLOR[cycle] ?? '#475569';\n\t\t\t\t\treturn svg`<polyline points=${points} fill=\"none\" stroke=${color} stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />`;\n\t\t\t\t})}</svg> ${\n\t\t\t\td.summary?.periodAdvice\n\t\t\t\t\t? html`<p class=\"advice\">${d.summary.periodAdvice}</p>`\n\t\t\t\t\t: nothing\n\t\t\t}</section>`;\n\t}\n\n\tprivate renderCritical(d: GetCriticalDaysResponse) {\n\t\treturn html`<section class=\"wrap\" aria-label=\"Critical days\"><header class=\"head\"><h2 class=\"title\">Critical days</h2><span class=\"energy\">${d.totalCriticalDays} total</span></header><div>${d.criticalDays.map(\n\t\t\t\t\t(day) => html`<span class=\"crit\">${day.date} \u00B7 ${day.cycle} ${day.severity}</span>`,\n\t\t\t\t)}</div></section>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-biorhythm-chart': RoxyBiorhythmChart;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { PLANET_GLYPH } from '../tokens/index.js';\nimport type { GenerateBodygraphResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport {\n\tBODYGRAPH_VIEWBOX,\n\ttype BodygraphCenterId,\n\tchannelKey,\n\trenderBodygraphSvg,\n} from '../utils/bodygraph-render.js';\nimport { capitalize } from '../utils/string.js';\n\ntype GateActivation = GenerateBodygraphResponse['gates'][number];\n\n/**\n * Human Design bodygraph. Pass `data` from /human-design/bodygraph. Renders the\n * nine centers in their canonical positions and shapes, filled when defined and\n * outlined when open, the 36 channels as wiring between gates with active\n * channels emphasized, and the activated gate numbers. A summary block lists\n * type, strategy, authority, profile, definition, incarnation cross, signature,\n * and not-self theme.\n *\n * The chart is theme-driven through `--roxy-*` custom properties on `:host`, so\n * it adopts the host palette in light and dark without runtime color probing.\n */\n@customElement('roxy-bodygraph')\nexport class RoxyBodygraph extends RoxyDataElement<GenerateBodygraphResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.type-line{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}.layout{gap:var(--roxy-space-lg,1.5rem);grid-template-columns:minmax(0,1fr);align-items:start;display:grid}@container (width>=520px){.layout{grid-template-columns:minmax(0,340px) minmax(0,1fr)}}svg{width:100%;max-width:var(--roxy-chart-max-width,340px);height:auto;margin:0 auto;display:block}.bg-body{fill:color-mix(in srgb, var(--roxy-secondary,#475569) 8%, transparent);stroke:var(--roxy-border,#e4e4e7);stroke-width:1px}.bg-channel{stroke:var(--roxy-secondary,#475569);stroke-width:1.6px;opacity:.3}.bg-channel.on{stroke-width:3.4px;stroke-linecap:round;opacity:1}.bg-half{stroke:var(--roxy-secondary,#475569);stroke-width:3.2px;stroke-linecap:round;opacity:.9}.bg-leader{stroke:var(--roxy-muted,#71717a);stroke-width:1px;opacity:.5}.bg-center{fill:#0000;stroke:var(--roxy-secondary,#475569);stroke-width:1.8px}.bg-center.defined{stroke:#00000073}.bg-center.bg-gold.defined{fill:#e0a200}.bg-center.bg-green.defined{fill:#2f8f00}.bg-center.bg-red.defined{fill:#c41f1f}.bg-center.bg-brown.defined{fill:#76502f}.bg-center-label{fill:var(--roxy-muted,#71717a);font-size:11px;font-family:var(--roxy-font-sans)}.bg-gate{fill:var(--roxy-fg,#0a0a0a);font-size:8px;font-weight:600;font-family:var(--roxy-font-sans);paint-order:stroke;stroke:var(--roxy-bg,#fff);stroke-width:1.6px;stroke-linejoin:round}.summary{gap:var(--roxy-space-md,1rem);display:grid}.facts{gap:var(--roxy-space-sm,.5rem);grid-template-columns:repeat(auto-fit,minmax(8rem,1fr));display:grid}.fact{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);background:var(--roxy-surface,#fff)}.fact span{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);text-transform:uppercase;letter-spacing:.06em;display:block}.fact strong{font-size:var(--roxy-text-base,1rem);color:var(--roxy-fg,#0a0a0a)}.cross{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);border-left:2px solid var(--roxy-accent,#f59e0b);padding-left:var(--roxy-space-sm,.5rem);margin:0}.cross .gates{color:var(--roxy-muted,#71717a);font-variant-numeric:tabular-nums}.themes{gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.pill{border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);padding:2px 10px}.pill--good{background:color-mix(in srgb, var(--roxy-success,#16a34a) 16%, transparent);color:var(--roxy-success-fg,#166534)}.pill--shadow{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 16%, transparent);color:var(--roxy-danger-fg,#991b1b)}.legend{gap:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);flex-wrap:wrap;display:flex}.legend-caption{color:var(--roxy-muted,#71717a);flex-basis:100%}.legend .swatch{vertical-align:middle;border:1px solid var(--roxy-secondary,#475569);border-radius:2px;width:10px;height:10px;margin-right:4px;display:inline-block}.legend .swatch.defined{border-color:#00000073}.legend .swatch.bg-gold{background:#e0a200}.legend .swatch.bg-green{background:#2f8f00}.legend .swatch.bg-red{background:#c41f1f}.legend .swatch.bg-brown{background:#76502f}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No bodygraph data</div>`;\n\t}\n\n\tprotected renderData(d: GenerateBodygraphResponse) {\n\t\tconst definedCenters = new Set<BodygraphCenterId>(\n\t\t\t(d.centers ?? [])\n\t\t\t\t.filter((c) => c.defined)\n\t\t\t\t.map((c) => c.id as BodygraphCenterId),\n\t\t);\n\t\tconst activeGates = new Set<number>(\n\t\t\t(d.gates ?? []).map((g) => g.gate).filter((n): n is number => n != null),\n\t\t);\n\t\tconst activeChannels = new Set<string>(\n\t\t\t(d.channels ?? []).map((c) => channelKey(c.gateA, c.gateB)),\n\t\t);\n\t\tconst gateTitles = this.buildGateTitles(d.gates ?? []);\n\n\t\treturn html`<div class=\"wrap\"><header class=\"head\"><h2 class=\"title\">Bodygraph</h2>${\n\t\t\t\t\td.type\n\t\t\t\t\t\t? html`<div class=\"type-line\">${d.type}${d.profile ? html`\u00B7 Profile ${d.profile}` : nothing}</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</header><div class=\"layout\"><svg viewBox=\"${BODYGRAPH_VIEWBOX}\" preserveAspectRatio=\"xMidYMid meet\" role=\"img\" aria-label=\"Human Design bodygraph with nine centers, channels, and activated gates overlaid on a human silhouette\"><title>Human Design bodygraph</title><desc>Nine energy centers in their canonical positions over a human silhouette, each filled with its traditional color when defined and outlined when open, wired by channels between activated gates.</desc>${renderBodygraphSvg({\n\t\t\t\t\t\tdefinedCenters,\n\t\t\t\t\t\tactiveChannels,\n\t\t\t\t\t\tactiveGates,\n\t\t\t\t\t\tgateTitles,\n\t\t\t\t\t})}</svg> ${this.renderSummary(d)}</div></div>`;\n\t}\n\n\tprivate buildGateTitles(gates: GateActivation[]): Map<number, string> {\n\t\tconst titles = new Map<number, string>();\n\t\tfor (const g of gates) {\n\t\t\tif (g.gate == null) continue;\n\t\t\tconst parts: string[] = [`Gate ${g.gate}`];\n\t\t\tif (g.line != null) parts[0] += `.${g.line}`;\n\t\t\tif (g.gateName) parts.push(g.gateName);\n\t\t\tconst planet = g.planet ? capitalize(g.planet) : '';\n\t\t\tconst glyph = planet ? (PLANET_GLYPH[planet] ?? planet) : '';\n\t\t\tif (glyph) parts.push(`${glyph} ${g.side ?? ''}`.trim());\n\t\t\ttitles.set(g.gate, parts.join(' \u00B7 '));\n\t\t}\n\t\treturn titles;\n\t}\n\n\tprivate renderSummary(d: GenerateBodygraphResponse) {\n\t\tconst facts: Array<{ label: string; value?: string }> = [\n\t\t\t{ label: 'Type', value: d.type },\n\t\t\t{ label: 'Strategy', value: d.strategy },\n\t\t\t{ label: 'Authority', value: d.authority },\n\t\t\t{ label: 'Profile', value: d.profile },\n\t\t\t{ label: 'Definition', value: d.definition },\n\t\t];\n\t\tconst ic = d.incarnationCross;\n\t\treturn html`<div class=\"summary\"><div class=\"facts\">${facts.map((f) =>\n\t\t\t\t\tf.value\n\t\t\t\t\t\t? html`<div class=\"fact\"><span>${f.label}</span> <strong>${f.value}</strong></div>`\n\t\t\t\t\t\t: nothing,\n\t\t\t\t)}</div>${\n\t\t\t\tic?.name\n\t\t\t\t\t? html`<p class=\"cross\">${ic.name} ${\n\t\t\t\t\t\t\tic.gates?.length\n\t\t\t\t\t\t\t\t? html`<span class=\"gates\">(${ic.gates.join(', ')})</span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}</p>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\td.signature || d.notSelf\n\t\t\t\t\t? html`<div class=\"themes\">${d.signature ? html`<span class=\"pill pill--good\">Signature: ${d.signature}</span>` : nothing} ${d.notSelf ? html`<span class=\"pill pill--shadow\">Not-self: ${d.notSelf}</span>` : nothing}</div>`\n\t\t\t\t\t: nothing\n\t\t\t}<div class=\"legend\"><span class=\"legend-caption\">Center colors when defined. Open centers are outlined.</span> <span><span class=\"swatch bg-gold defined\"></span>Head, G</span> <span><span class=\"swatch bg-green defined\"></span>Ajna</span> <span><span class=\"swatch bg-brown defined\"></span>Throat, Spleen, Solar Plexus, Root</span> <span><span class=\"swatch bg-red defined\"></span>Heart, Sacral</span> <span><span class=\"swatch\"></span>Open center</span></div></div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-bodygraph': RoxyBodygraph;\n\t}\n}\n", "import type { TemplateResult } from 'lit';\nimport { nothing, svg } from 'lit';\n\n/**\n * Fixed geometry and renderer for the Human Design bodygraph. The diagram is a\n * standard, invariant layout: nine centers in canonical positions and shapes,\n * wired by 36 channels that each join two gates, with the 64 gates at fixed\n * points on the center edges, all overlaid on a front-facing human silhouette so\n * each center lands on the body part it governs. Only which centers are defined\n * and which channels and gates are active changes per chart, so this module holds\n * the geometry and the {@link RoxyBodygraph} component supplies the live state\n * from the /human-design/bodygraph response.\n *\n * @remarks Every point is authored in one normalized 0 to 100 canonical grid (x\n * left to right, y top to bottom) taken from the reference Jovian Archive\n * bodygraph, then scaled into {@link BODYGRAPH_VIEWBOX} by a single transform so\n * the chart and the body share one coordinate space and scale together. The grid\n * is sized so the nine centers fill the figure exactly as in the canonical\n * \"nine centers on the human body\" diagram: the Head center at the crown, Ajna at\n * the forehead, Throat at the neck, G at the chest, Heart at the right chest,\n * Spleen on the left torso, Solar Plexus on the right torso (its mirror), Sacral\n * at the lower abdomen, and Root at the pelvis. Two structural truths the layout\n * preserves: the Spleen (left) and the Solar Plexus (right) are mirror images at\n * the Sacral height, so the chart is narrow at the top and wide at the bottom;\n * and the Heart sits low and to the right of the G center, above the Solar\n * Plexus. The reference chart spreads the two side centers to the page edge for\n * channel clarity; here they are shifted inward by a fixed amount so they rest on\n * the torso sides inside the figure, with every channel topology preserved. Center shapes follow the canonical orientations (Head triangle\n * up, Ajna triangle down, Throat and Sacral and Root squares, G diamond, Heart\n * triangle pointing right, Spleen triangle pointing right with its base on the\n * far-left edge, Solar Plexus its mirror). The 36 channel gate pairs are the\n * gold-standard set used by the RoxyAPI Human Design engine.\n */\n\nexport type BodygraphCenterId =\n\t| 'head'\n\t| 'ajna'\n\t| 'throat'\n\t| 'g'\n\t| 'heart'\n\t| 'sacral'\n\t| 'solar-plexus'\n\t| 'spleen'\n\t| 'root';\n\ninterface Point {\n\tx: number;\n\ty: number;\n}\n\n/**\n * One center's drawable geometry: its semantic traditional color, the polygon\n * point list of its canonical shape, and the anchor where its name label sits.\n * Shapes are explicit point lists so the triangle and diamond orientations match\n * the canonical diagram exactly. Label anchors sit in the empty margins outside\n * each shape so they never collide with the gate numbers printed on the edges.\n */\ninterface CenterGeometry {\n\tid: BodygraphCenterId;\n\tlabel: string;\n\tcolor: CenterColor;\n\tpoints: Point[];\n\tlabelAnchor: Point;\n\tlabelAlign: 'start' | 'middle' | 'end';\n}\n\n/**\n * Traditional Human Design center color group. A defined center is filled with\n * this semantic color (constant across light and dark, like chart data colors);\n * an open center is left transparent with a thin theme-aware outline. The four\n * groups mirror the canonical scheme: gold for the identity and inspiration\n * centers (Head, G), green for the mental awareness center (Ajna), red for the\n * life-force motors of will and vitality (Heart, Sacral), brown for the\n * pressure, expression, and remaining awareness centers (Throat, Spleen, Solar\n * Plexus, Root).\n */\nexport type CenterColor = 'gold' | 'green' | 'red' | 'brown';\n\n/**\n * Viewport mapping from the normalized 0 to 100 grid into the SVG viewBox. The\n * chart proper occupies the inner grid; {@link PAD} is the slim margin (in grid\n * units) the body silhouette extends past the centers on every side, so the head\n * rises just above the Head center, the hips sit just below Root, and the\n * shoulders spread just outside Spleen and Solar Plexus. UNIT scales grid units\n * to viewBox units; the chart keeps its natural narrow-top, wide-bottom shape\n * because x and y share one scale.\n */\nconst UNIT = 4;\nconst PAD = 9;\nconst VIEW_W = (100 + 2 * PAD) * UNIT;\nconst VIEW_H = (100 + 2 * PAD) * UNIT;\n\n/** Map a normalized grid point (0 to 100) into viewBox units. */\nfunction g(x: number, y: number): Point {\n\treturn { x: (x + PAD) * UNIT, y: (y + PAD) * UNIT };\n}\n\n/** Chart horizontal center, the axis of symmetry for the body and the side centers. */\nconst AXIS = 50;\n\n/** Reflect a normalized grid x across {@link AXIS}, the vertical axis of symmetry. */\nconst mirrorX = (x: number): number => 2 * AXIS - x;\n\n/**\n * Gate positions authored per center in the normalized 0 to 100 grid, before the\n * mapping through {@link g}. Symmetry is structural, not hand-typed: every center\n * on the central column is authored balanced about {@link AXIS}; the Spleen is\n * authored once on the left torso and the Solar Plexus is derived as its exact\n * mirror in {@link buildGatePoints}, so the two side centers can never drift out\n * of alignment. The Heart is the one center the canonical bodygraph places off\n * the axis (low and to the right of the G center, with no left counterpart).\n * Within each center the gates follow the canonical reading order so the numbers\n * print where a printed chart shows them.\n *\n * @remarks Solar Plexus is intentionally empty here and filled by reflecting\n * Spleen; {@link SPLEEN_TO_SOLAR_PLEXUS} pairs each Spleen gate with the Solar\n * Plexus gate at its mirror position (base-top to base-top, apex to apex).\n */\nconst GATES_BY_CENTER: Record<\n\tBodygraphCenterId,\n\tRecord<number, [number, number]>\n> = {\n\thead: { 64: [45.5, 11.2], 61: [50, 11.2], 63: [54.5, 11.2] },\n\tajna: {\n\t\t47: [45.3, 18.0],\n\t\t24: [50, 18.0],\n\t\t4: [54.7, 18.0],\n\t\t17: [45.6, 20.6],\n\t\t11: [54.4, 20.6],\n\t\t43: [50, 25.3],\n\t},\n\tthroat: {\n\t\t62: [45.5, 32.3],\n\t\t23: [50, 32.3],\n\t\t56: [54.5, 32.3],\n\t\t16: [42, 34.6],\n\t\t35: [58, 34.6],\n\t\t12: [58, 37.6],\n\t\t20: [42, 40.6],\n\t\t45: [58, 40.6],\n\t\t31: [46, 42.4],\n\t\t8: [50, 42.4],\n\t\t33: [54, 42.4],\n\t},\n\tg: {\n\t\t1: [50, 47.5],\n\t\t7: [45.6, 50.3],\n\t\t13: [54.4, 50.3],\n\t\t10: [40, 53.3],\n\t\t25: [60, 53.3],\n\t\t15: [45.6, 56.6],\n\t\t46: [54.4, 56.6],\n\t\t2: [50, 59.0],\n\t},\n\theart: {\n\t\t21: [62.5, 58.5],\n\t\t51: [62.5, 61.3],\n\t\t26: [62.5, 64.1],\n\t\t40: [73, 61.3],\n\t},\n\tspleen: {\n\t\t48: [20, 70.6],\n\t\t57: [24, 72.3],\n\t\t44: [28, 74.0],\n\t\t50: [32, 75.6],\n\t\t32: [28, 77.2],\n\t\t28: [24, 78.9],\n\t\t18: [20, 80.6],\n\t},\n\tsacral: {\n\t\t5: [45.5, 72.5],\n\t\t14: [50, 72.5],\n\t\t29: [54.5, 72.5],\n\t\t34: [42, 75.6],\n\t\t27: [42, 79.0],\n\t\t59: [58, 79.0],\n\t\t42: [45.5, 81.4],\n\t\t3: [50, 81.4],\n\t\t9: [54.5, 81.4],\n\t},\n\t'solar-plexus': {},\n\troot: {\n\t\t53: [45.5, 89.9],\n\t\t60: [50, 89.9],\n\t\t52: [54.5, 89.9],\n\t\t54: [42, 92.7],\n\t\t19: [58, 92.7],\n\t\t38: [42, 95.3],\n\t\t39: [58, 95.3],\n\t\t58: [42, 98.0],\n\t\t41: [58, 98.0],\n\t},\n};\n\n/** Spleen gate to the Solar Plexus gate at its mirror position (base-top, ..., apex, ..., base-bottom). */\nconst SPLEEN_TO_SOLAR_PLEXUS: Record<number, number> = {\n\t48: 36,\n\t57: 22,\n\t44: 37,\n\t50: 6,\n\t32: 49,\n\t28: 55,\n\t18: 30,\n};\n\n/**\n * Assemble the viewBox-space gate anchors and the gate to center index from\n * {@link GATES_BY_CENTER}, filling the Solar Plexus by reflecting the Spleen so\n * the two side centers are guaranteed mirror images. Each gate sits on the\n * canonical edge of its center where its channels connect, so channel lines join\n * gate to gate cleanly and the activated numbers print in their traditional spots.\n */\nfunction buildGatePoints(): {\n\tpoints: Record<number, Point>;\n\tcenterOf: Record<number, BodygraphCenterId>;\n} {\n\tconst points: Record<number, Point> = {};\n\tconst centerOf: Record<number, BodygraphCenterId> = {};\n\tfor (const [spleenGate, [x, y]] of Object.entries(GATES_BY_CENTER.spleen)) {\n\t\tGATES_BY_CENTER['solar-plexus'][\n\t\t\tSPLEEN_TO_SOLAR_PLEXUS[Number(spleenGate)]\n\t\t] = [mirrorX(x), y];\n\t}\n\tfor (const [center, gates] of Object.entries(GATES_BY_CENTER) as Array<\n\t\t[BodygraphCenterId, Record<number, [number, number]>]\n\t>) {\n\t\tfor (const [gate, [x, y]] of Object.entries(gates)) {\n\t\t\tpoints[Number(gate)] = g(x, y);\n\t\t\tcenterOf[Number(gate)] = center;\n\t\t}\n\t}\n\treturn { points, centerOf };\n}\n\n/**\n * The viewBox-space gate anchors ({@link GATE_POINTS}) and the gate to center\n * index ({@link GATE_CENTER}). Exported so the geometry tests can assert the\n * layout invariants (side-center mirror symmetry, central-column balance, gates\n * inside their centers) without rendering.\n */\nexport const { points: GATE_POINTS, centerOf: GATE_CENTER } = buildGatePoints();\n\n/** Horizontal axis of symmetry in viewBox units, the reflection axis for geometry tests. */\nexport const CHART_AXIS_X = VIEW_W / 2;\n\n/** Build a polygon from normalized grid corner pairs, mapping each through {@link g}. */\nfunction shape(corners: ReadonlyArray<readonly [number, number]>): Point[] {\n\treturn corners.map(([x, y]) => g(x, y));\n}\n\n/** A square center, centered on {@link AXIS}, spanning the given half-width and y range. */\nfunction squareShape(halfWidth: number, top: number, bottom: number): Point[] {\n\treturn shape([\n\t\t[AXIS - halfWidth, top],\n\t\t[AXIS + halfWidth, top],\n\t\t[AXIS + halfWidth, bottom],\n\t\t[AXIS - halfWidth, bottom],\n\t]);\n}\n\n/** The Spleen triangle (base on the far-left edge, apex pointing right toward center). */\nconst SPLEEN_SHAPE: ReadonlyArray<readonly [number, number]> = [\n\t[18.4, 68.0],\n\t[18.4, 81.8],\n\t[34.7, 74.9],\n];\n\n/**\n * Center shapes in canonical orientation and color, labels anchored in the\n * margins. Central-column centers are built centered on {@link AXIS}; the Solar\n * Plexus shape is the Spleen reflected across the axis, so the side centers stay\n * exact mirrors. The Heart is the deliberate off-axis exception.\n */\nexport const CENTER_GEOMETRY: readonly CenterGeometry[] = [\n\t{\n\t\tid: 'head',\n\t\tlabel: 'Head',\n\t\tcolor: 'gold',\n\t\tpoints: shape([\n\t\t\t[40.0, 14.3],\n\t\t\t[60.0, 14.3],\n\t\t\t[50.0, 6.0],\n\t\t]),\n\t\tlabelAnchor: g(63, 9),\n\t\tlabelAlign: 'start',\n\t},\n\t{\n\t\tid: 'ajna',\n\t\tlabel: 'Ajna',\n\t\tcolor: 'green',\n\t\tpoints: shape([\n\t\t\t[40.0, 15.6],\n\t\t\t[60.0, 15.6],\n\t\t\t[50.0, 27.6],\n\t\t]),\n\t\tlabelAnchor: g(62, 21),\n\t\tlabelAlign: 'start',\n\t},\n\t{\n\t\tid: 'throat',\n\t\tlabel: 'Throat',\n\t\tcolor: 'brown',\n\t\tpoints: squareShape(9.5, 30.4, 43.6),\n\t\tlabelAnchor: g(83, 34),\n\t\tlabelAlign: 'start',\n\t},\n\t{\n\t\tid: 'g',\n\t\tlabel: 'G',\n\t\tcolor: 'gold',\n\t\tpoints: shape([\n\t\t\t[50.0, 45.0],\n\t\t\t[60.7, 53.3],\n\t\t\t[50.0, 61.6],\n\t\t\t[39.3, 53.3],\n\t\t]),\n\t\tlabelAnchor: g(13, 51),\n\t\tlabelAlign: 'end',\n\t},\n\t{\n\t\tid: 'heart',\n\t\tlabel: 'Heart',\n\t\tcolor: 'red',\n\t\tpoints: shape([\n\t\t\t[61.5, 57.0],\n\t\t\t[76.5, 61.3],\n\t\t\t[61.5, 65.6],\n\t\t]),\n\t\tlabelAnchor: g(85, 56),\n\t\tlabelAlign: 'start',\n\t},\n\t{\n\t\tid: 'spleen',\n\t\tlabel: 'Spleen',\n\t\tcolor: 'brown',\n\t\tpoints: shape(SPLEEN_SHAPE),\n\t\tlabelAnchor: g(13, 70),\n\t\tlabelAlign: 'end',\n\t},\n\t{\n\t\tid: 'sacral',\n\t\tlabel: 'Sacral',\n\t\tcolor: 'red',\n\t\tpoints: squareShape(9.5, 70.6, 83.6),\n\t\t// Lower-right, below the Solar Plexus: a left-side leader would clip the\n\t\t// Spleen, which sits at the same height as the Sacral.\n\t\tlabelAnchor: g(85, 88),\n\t\tlabelAlign: 'start',\n\t},\n\t{\n\t\tid: 'solar-plexus',\n\t\tlabel: 'Solar Plexus',\n\t\tcolor: 'brown',\n\t\tpoints: shape(\n\t\t\tSPLEEN_SHAPE.map(([x, y]) => [mirrorX(x), y] as [number, number]),\n\t\t),\n\t\tlabelAnchor: g(87, 73),\n\t\tlabelAlign: 'start',\n\t},\n\t{\n\t\tid: 'root',\n\t\tlabel: 'Root',\n\t\tcolor: 'brown',\n\t\tpoints: squareShape(9.5, 87.9, 99.9),\n\t\tlabelAnchor: g(50, 103),\n\t\tlabelAlign: 'middle',\n\t},\n];\n\n/**\n * The 36 channels as ordered gate pairs. This is the canonical Human Design\n * channel set; a channel is active only when both of its gates are activated,\n * which the live response reports in its `channels` array. The static list lets\n * the renderer draw every channel as a hanging (inactive) line and overlay the\n * active ones, so an open bodygraph still shows its full wiring skeleton.\n */\nexport const CHANNEL_PAIRS: ReadonlyArray<readonly [number, number]> = [\n\t[64, 47],\n\t[61, 24],\n\t[63, 4],\n\t[17, 62],\n\t[11, 56],\n\t[43, 23],\n\t[16, 48],\n\t[20, 34],\n\t[20, 10],\n\t[7, 31],\n\t[1, 8],\n\t[13, 33],\n\t[21, 45],\n\t[12, 22],\n\t[35, 36],\n\t[57, 20],\n\t[15, 5],\n\t[2, 14],\n\t[46, 29],\n\t[34, 10],\n\t[10, 57],\n\t[25, 51],\n\t[27, 50],\n\t[57, 34],\n\t[26, 44],\n\t[18, 58],\n\t[28, 38],\n\t[32, 54],\n\t[3, 60],\n\t[9, 52],\n\t[42, 53],\n\t[59, 6],\n\t[19, 49],\n\t[39, 55],\n\t[41, 30],\n\t[37, 40],\n];\n\n/**\n * Front-facing standing figure behind the chart, mirror-symmetric about\n * {@link AXIS}. Authored in the same normalized grid as the centers, so it scales\n * with the chart and frames it as in the canonical \"nine centers on the human\n * body\" diagram: a rounded head holding the Head center, a short neck at the\n * Throat, shoulders that slope to arms hanging down the outside of the torso so\n * their span frames the Spleen (left) and Solar Plexus (right), a torso that\n * narrows at the waist below the chest, then hips ending at the pelvis just below\n * the Root center. The outline is one closed loop: crown, temple, jaw, neck,\n * shoulder, down the outer arm to the hand beside the hip, in under the hip to\n * the pelvis hem, mirrored back up the left side. The right half is built from\n * cubic beziers and reflected so the figure is exactly symmetric. Drawn first and\n * behind everything so the centers, wiring, and gate numbers stay legible on top.\n */\nconst BODY_PATH = buildBodyPath();\n\nfunction buildBodyPath(): string {\n\tconst m = mirrorX;\n\t// Right-side outline in grid units (x, y) from the crown down to the\n\t// pelvis-right corner: a start point, then triples of (ctrl1, ctrl2, end). A\n\t// rounded head hugging the Head and Ajna centers, a narrowed neck, shoulders at\n\t// their widest, the outer torso running just past the Spleen and Solar Plexus\n\t// (right edges near x 82 at y 74), then waist and hip to a flat pelvis hem. The\n\t// left side is the mirror and the hem is a straight line, so the figure reads as\n\t// a torso, not a point.\n\tconst r: Array<[number, number]> = [\n\t\t[50, -2], // crown apex (start)\n\t\t[60, -2], // crown round (ctrl)\n\t\t[60.5, 9], // head side (ctrl)\n\t\t[57, 18], // brow, head holds Head + Ajna (end)\n\t\t[56, 21], // cheek (ctrl)\n\t\t[54, 24], // jaw (ctrl)\n\t\t[52, 27], // neck right, narrowed (end)\n\t\t[54, 28], // neck base (ctrl)\n\t\t[64, 30], // trapezius slope (ctrl)\n\t\t[80, 34], // shoulder / deltoid, the widest point (end)\n\t\t[83.5, 40], // upper torso side (ctrl)\n\t\t[84, 56], // outer torso, frames the side centers (ctrl)\n\t\t[83, 74], // torso side past Spleen / Solar Plexus (end)\n\t\t[82, 84], // waist (ctrl)\n\t\t[76, 92], // hip (ctrl)\n\t\t[68, 97], // hip (end)\n\t\t[64, 99], // toward the pelvis (ctrl)\n\t\t[62, 100], // pelvis (ctrl)\n\t\t[60, 100], // pelvis-right corner (end)\n\t];\n\tconst segs: string[] = [`M ${pt(r[0])}`];\n\t// Walk the right side as cubic beziers, three points per segment.\n\tfor (let i = 1; i + 2 < r.length; i += 3) {\n\t\tsegs.push(`C ${pt(r[i])} ${pt(r[i + 1])} ${pt(r[i + 2])}`);\n\t}\n\t// Flat pelvis hem across to the mirrored corner.\n\tsegs.push(`L ${ptm(r[r.length - 1], m)}`);\n\t// Mirror the right walk back up the left side to the crown.\n\tfor (let i = r.length - 3; i >= 1; i -= 3) {\n\t\tsegs.push(`C ${ptm(r[i + 1], m)} ${ptm(r[i], m)} ${ptm(r[i - 1], m)}`);\n\t}\n\tsegs.push('Z');\n\treturn segs.join(' ');\n}\n\nfunction pt([x, y]: [number, number]): string {\n\tconst p = g(x, y);\n\treturn `${p.x} ${p.y}`;\n}\n\nfunction ptm([x, y]: [number, number], m: (x: number) => number): string {\n\tconst p = g(m(x), y);\n\treturn `${p.x} ${p.y}`;\n}\n\nfunction polygonPoints(pts: Point[]): string {\n\treturn pts.map((p) => `${p.x},${p.y}`).join(' ');\n}\n\nfunction pairKey(a: number, b: number): string {\n\treturn a < b ? `${a}-${b}` : `${b}-${a}`;\n}\n\n/** Render the body silhouette behind the chart. */\nfunction renderBody(): TemplateResult {\n\treturn svg`<path class=\"bg-body\" d=${BODY_PATH} />`;\n}\n\n/**\n * Render every channel as a single line joining its two gates, so the wiring\n * always reads as a connected diagram rather than stubs poking out of centers.\n * Each of the 36 channels draws a faint full-length connector; a channel with\n * both gates active is redrawn thick and solid (a defined channel); a channel\n * with only one gate active lights that gate's half toward the midpoint over the\n * connector (a hanging gate). This mirrors how a printed bodygraph colors a full\n * channel only when both gates are active and shows a single hanging gate\n * otherwise, while keeping every connection visible.\n */\nfunction renderChannels(\n\tactiveChannels: Set<string>,\n\tactiveGates: Set<number>,\n): TemplateResult[] {\n\tconst lines: TemplateResult[] = [];\n\tfor (const [a, b] of CHANNEL_PAIRS) {\n\t\tconst pa = GATE_POINTS[a];\n\t\tconst pb = GATE_POINTS[b];\n\t\tif (!pa || !pb) continue;\n\t\tlines.push(\n\t\t\tsvg`<line class=\"bg-channel\" x1=${pa.x} y1=${pa.y} x2=${pb.x} y2=${pb.y} />`,\n\t\t);\n\t\tif (activeChannels.has(pairKey(a, b))) {\n\t\t\tlines.push(\n\t\t\t\tsvg`<line class=\"bg-channel on\" x1=${pa.x} y1=${pa.y} x2=${pb.x} y2=${pb.y} />`,\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\t\tconst mid = { x: (pa.x + pb.x) / 2, y: (pa.y + pb.y) / 2 };\n\t\tif (activeGates.has(a)) {\n\t\t\tlines.push(\n\t\t\t\tsvg`<line class=\"bg-half\" x1=${pa.x} y1=${pa.y} x2=${mid.x} y2=${mid.y} />`,\n\t\t\t);\n\t\t}\n\t\tif (activeGates.has(b)) {\n\t\t\tlines.push(\n\t\t\t\tsvg`<line class=\"bg-half\" x1=${pb.x} y1=${pb.y} x2=${mid.x} y2=${mid.y} />`,\n\t\t\t);\n\t\t}\n\t}\n\treturn lines;\n}\n\n/** Closest point to `p` on segment `a`-`b`, clamped to the segment ends. */\nfunction closestPointOnSegment(p: Point, a: Point, b: Point): Point {\n\tconst dx = b.x - a.x;\n\tconst dy = b.y - a.y;\n\tconst len2 = dx * dx + dy * dy;\n\tif (len2 === 0) return a;\n\tconst t = Math.max(\n\t\t0,\n\t\tMath.min(1, ((p.x - a.x) * dx + (p.y - a.y) * dy) / len2),\n\t);\n\treturn { x: a.x + t * dx, y: a.y + t * dy };\n}\n\n/** Closest point on a closed polygon's perimeter to `p`, where a label leader should land. */\nfunction closestPointOnPolygon(p: Point, poly: readonly Point[]): Point {\n\tlet best = poly[0];\n\tlet bestDist = Number.POSITIVE_INFINITY;\n\tfor (let i = 0; i < poly.length; i++) {\n\t\tconst q = closestPointOnSegment(p, poly[i], poly[(i + 1) % poly.length]);\n\t\tconst d = (q.x - p.x) ** 2 + (q.y - p.y) ** 2;\n\t\tif (d < bestDist) {\n\t\t\tbestDist = d;\n\t\t\tbest = q;\n\t\t}\n\t}\n\treturn best;\n}\n\n/**\n * Render the nine center shapes, filled with their semantic color when defined\n * and outlined when open, each with a margin label tied to its shape by a thin\n * leader line so the Heart and every other center is unambiguous regardless of\n * whether it is defined.\n */\nfunction renderCenters(defined: Set<BodygraphCenterId>): TemplateResult[] {\n\treturn CENTER_GEOMETRY.map((c) => {\n\t\tconst isDefined = defined.has(c.id);\n\t\tconst cls = `bg-center bg-${c.color}${isDefined ? ' defined' : ''}`;\n\t\tconst edge = closestPointOnPolygon(c.labelAnchor, c.points);\n\t\treturn svg`<g>\n\t\t\t<line class=\"bg-leader\" x1=${c.labelAnchor.x} y1=${c.labelAnchor.y} x2=${edge.x} y2=${edge.y} />\n\t\t\t<polygon class=${cls} points=${polygonPoints(c.points)}><title>${c.label}: ${isDefined ? 'defined' : 'open'}</title></polygon>\n\t\t\t<text class=\"bg-center-label\" x=${c.labelAnchor.x} y=${c.labelAnchor.y} text-anchor=${c.labelAlign} dominant-baseline=\"central\">${c.label}</text>\n\t\t</g>`;\n\t});\n}\n\n/**\n * Render the activated gate numbers at their fixed points. Numbers sit on top of\n * the filled centers, so a halo (a wider, background-colored stroke under the\n * fill) keeps them legible against any center color in both themes.\n */\nfunction renderGateNumbers(\n\tactiveGates: Set<number>,\n\ttitles: Map<number, string>,\n): TemplateResult[] {\n\tconst out: TemplateResult[] = [];\n\tfor (const [gate, p] of Object.entries(GATE_POINTS)) {\n\t\tconst num = Number(gate);\n\t\tif (!activeGates.has(num)) continue;\n\t\tconst title = titles.get(num);\n\t\tout.push(\n\t\t\tsvg`<text class=\"bg-gate\" x=${p.x} y=${p.y} text-anchor=\"middle\" dominant-baseline=\"central\">${num}${title ? svg`<title>${title}</title>` : nothing}</text>`,\n\t\t);\n\t}\n\treturn out;\n}\n\nexport interface BodygraphRenderInput {\n\tdefinedCenters: Set<BodygraphCenterId>;\n\tactiveChannels: Set<string>;\n\tactiveGates: Set<number>;\n\tgateTitles: Map<number, string>;\n}\n\n/** Build the lookup key for an active channel from its two gate numbers. */\nexport function channelKey(a: number, b: number): string {\n\treturn pairKey(a, b);\n}\n\nexport const BODYGRAPH_VIEWBOX = `0 0 ${VIEW_W} ${VIEW_H}`;\n\n/**\n * Render the full bodygraph SVG inner content for the given live state. The\n * caller wraps it in an `<svg>` with {@link BODYGRAPH_VIEWBOX} and applies its\n * own theming CSS. Draw order: body silhouette under channels under centers\n * under gate numbers, so the body is the backdrop, the wiring sits behind the\n * shapes, and the numbers stay legible on top.\n */\nexport function renderBodygraphSvg(\n\tinput: BodygraphRenderInput,\n): TemplateResult {\n\treturn svg`\n\t\t${renderBody()}\n\t\t${renderChannels(input.activeChannels, input.activeGates)}\n\t\t${renderCenters(input.definedCenters)}\n\t\t${renderGateNumbers(input.activeGates, input.gateTitles)}\n\t`;\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { PLANET_GLYPH } from '../tokens/index.js';\nimport type { GetChoghadiyaResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { capitalize } from '../utils/string.js';\n\ntype ChoghadiyaPeriod = GetChoghadiyaResponse['dayChoghadiya'][number];\n\n/**\n * Format an ISO 8601 datetime string to a short local time (HH:MM).\n * Falls back to the raw string when parsing fails.\n */\nfunction fmtTime(iso: string): string {\n\ttry {\n\t\tconst d = new Date(iso);\n\t\tif (Number.isNaN(d.getTime())) return iso;\n\t\treturn d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });\n\t} catch {\n\t\treturn iso;\n\t}\n}\n\n/**\n * Choghadiya muhurta grid. Accepts a GetChoghadiyaResponse and renders\n * 8 daytime and 8 nighttime muhurta tiles in a two-column responsive layout.\n * Good periods are highlighted in green, Bad periods in red.\n */\n@customElement('roxy-choghadiya-grid')\nexport class RoxyChoghadiyaGrid extends RoxyDataElement<GetChoghadiyaResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.header{gap:var(--roxy-space-xs,.25rem);display:grid}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.subtitle{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-muted,#71717a);margin:0}.cho-grid{gap:var(--roxy-space-md,1rem);grid-template-columns:1fr;display:grid}@media (width>=720px){.cho-grid{grid-template-columns:1fr 1fr}}.period-col{gap:var(--roxy-space-xs,.25rem);display:grid}.period-heading{font-size:var(--roxy-text-base,1rem);font-weight:var(--roxy-weight-bold,600);margin:0 0 var(--roxy-space-xs,.25rem);color:var(--roxy-fg,#0a0a0a)}.cho-tile{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);grid-template-columns:1fr auto;align-items:center;gap:.25em .75em;padding:.55em .85em;display:grid}.cho-tile.good{background:color-mix(in srgb, var(--roxy-success,#22c55e) 18%, transparent);border-color:color-mix(in srgb, var(--roxy-success,#22c55e) 45%, transparent);color:var(--roxy-fg,#0a0a0a)}.cho-tile.bad{background:color-mix(in srgb, var(--roxy-danger,#ef4444) 18%, transparent);border-color:color-mix(in srgb, var(--roxy-danger,#ef4444) 45%, transparent);color:var(--roxy-fg,#0a0a0a)}.cho-tile.neutral{color:var(--roxy-fg,#0a0a0a);background:0 0}.cho-tile.now{outline:2px solid var(--roxy-accent,#f59e0b);outline-offset:1px;box-shadow:0 0 0 4px color-mix(in srgb, var(--roxy-accent,#f59e0b) 18%, transparent)}.now-badge{font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-accent-ink,#b45309);text-transform:uppercase;letter-spacing:.06em;margin-left:.4em;display:inline-block}.tile-name{font-size:var(--roxy-text-base,1rem);font-weight:var(--roxy-weight-bold,600);grid-column:1}.tile-time{font-size:var(--roxy-text-xs,.75rem);opacity:.8;white-space:nowrap;text-align:right;grid-area:1/2/3;align-self:center}.tile-lord{font-size:var(--roxy-text-sm,.875rem);opacity:.85;grid-column:1;align-items:center;gap:.25em;display:flex}`,\n\t];\n\n\t/**\n\t * True when the current wall-clock time falls inside this period. Both\n\t * `start` and `end` are ISO 8601 with timezone, so the comparison is\n\t * timezone-aware via the host's `Date` parsing.\n\t */\n\tprivate isCurrent(period: ChoghadiyaPeriod): boolean {\n\t\tconst now = Date.now();\n\t\tconst start = Date.parse(period.start);\n\t\tconst end = Date.parse(period.end);\n\t\tif (Number.isNaN(start) || Number.isNaN(end)) return false;\n\t\treturn now >= start && now < end;\n\t}\n\n\tprivate renderTile(period: ChoghadiyaPeriod) {\n\t\tconst effectClass =\n\t\t\tperiod.effect === 'Good'\n\t\t\t\t? 'good'\n\t\t\t\t: period.effect === 'Bad'\n\t\t\t\t\t? 'bad'\n\t\t\t\t\t: 'neutral';\n\t\tconst current = this.isCurrent(period);\n\t\tconst lordGlyph = PLANET_GLYPH[capitalize(period.lord)] ?? '';\n\t\tconst timeRange = `${fmtTime(period.start)} - ${fmtTime(period.end)}`;\n\t\treturn html`<div class=\"cho-tile ${effectClass}${current ? ' now' : ''}\" role=\"listitem\" aria-current=\"${current ? 'time' : 'false'}\"><span class=\"tile-name\">${period.name}${current ? html`<span class=\"now-badge\">Now</span>` : nothing} </span><span class=\"tile-time\" aria-label=\"Time range\">${timeRange}</span> <span class=\"tile-lord\">${lordGlyph ? html`<span aria-hidden=\"true\">${lordGlyph}</span>` : nothing} ${period.lord}</span></div>`;\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No choghadiya data</div>`;\n\t}\n\n\tprotected renderData(d: GetChoghadiyaResponse) {\n\t\tconst { date, dayChoghadiya, nightChoghadiya } = d;\n\n\t\treturn html`<div class=\"wrap\"><div class=\"header\"><h2 class=\"title\">Choghadiya</h2>${date ? html`<p class=\"subtitle\">${date}</p>` : nothing}</div><div class=\"cho-grid\"><section class=\"period-col\" aria-label=\"Day muhurta periods\"><h3 class=\"period-heading\">Day</h3><div role=\"list\" aria-label=\"Daytime choghadiya\">${\n\t\t\t\t\t\t\tdayChoghadiya && dayChoghadiya.length > 0\n\t\t\t\t\t\t\t\t? dayChoghadiya.map((p) => this.renderTile(p))\n\t\t\t\t\t\t\t\t: html`<p class=\"roxy-empty\" role=\"status\">No daytime periods</p>`\n\t\t\t\t\t\t}</div></section><section class=\"period-col\" aria-label=\"Night muhurta periods\"><h3 class=\"period-heading\">Night</h3><div role=\"list\" aria-label=\"Nighttime choghadiya\">${\n\t\t\t\t\t\t\tnightChoghadiya && nightChoghadiya.length > 0\n\t\t\t\t\t\t\t\t? nightChoghadiya.map((p) => this.renderTile(p))\n\t\t\t\t\t\t\t\t: html`<p class=\"roxy-empty\" role=\"status\">No nighttime periods</p>`\n\t\t\t\t\t\t}</div></section></div></div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-choghadiya-grid': RoxyChoghadiyaGrid;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type {\n\tCalculateBioCompatibilityResponse,\n\tCalculateCompatibilityResponse,\n\tCalculateNumCompatibilityResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatNumber } from '../utils/format.js';\n\ntype CompatibilityData =\n\t| CalculateCompatibilityResponse\n\t| CalculateNumCompatibilityResponse\n\t| CalculateBioCompatibilityResponse;\n\n/**\n * Cross-domain compatibility card. Renders /astrology/compatibility-score,\n * /numerology/compatibility, or /biorhythm/compatibility responses.\n */\n@customElement('roxy-compatibility-card')\nexport class RoxyCompatibilityCard extends RoxyDataElement<CompatibilityData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.card{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{align-items:center;gap:var(--roxy-space-md,1rem);grid-template-columns:1fr auto;display:grid}.head h2{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);text-transform:capitalize;margin:0}.score{font-variant-numeric:tabular-nums;font-size:2rem;font-weight:var(--roxy-weight-bold,600);color:var(--roxy-accent-ink,#b45309);line-height:1}.rating{color:var(--roxy-secondary,#475569);font-size:var(--roxy-text-sm,.875rem)}.bar-row{gap:var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-sm,.875rem);grid-template-columns:8rem 1fr 3.5rem;align-items:center;display:grid}.bar{background:var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-full,9999px);height:8px;overflow:hidden}.bar>span{background:var(--roxy-accent,#f59e0b);height:100%;transition:width var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,cubic-bezier(.4, 0, .2, 1));display:block}.bar-row>span:last-child{font-variant-numeric:tabular-nums;color:var(--roxy-muted,#71717a);text-align:right}.archetype{color:var(--roxy-accent-ink,#b45309);font-weight:var(--roxy-weight-bold,600)}.lists{gap:var(--roxy-space-md,1rem);grid-template-columns:repeat(auto-fit,minmax(12rem,1fr));display:grid}.lists h3{margin:0 0 var(--roxy-space-xs,.25rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em}.lists ul{padding-left:var(--roxy-space-md,1rem);margin:0}`,\n\t];\n\n\t@property({ type: String, reflect: true })\n\tmode: 'astrology' | 'numerology' | 'biorhythm' = 'astrology';\n\n\tprivate getBreakdown(): Record<string, number> {\n\t\tconst d = this.data;\n\t\tif (!d) return {};\n\t\tif ('categories' in d && d.categories) {\n\t\t\tconst out: Record<string, number> = {};\n\t\t\tfor (const [k, v] of Object.entries(d.categories)) {\n\t\t\t\tif (typeof v === 'number' && Number.isFinite(v)) out[k] = v;\n\t\t\t}\n\t\t\treturn out;\n\t\t}\n\t\treturn {};\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No compatibility data</div>`;\n\t}\n\n\tprotected renderData(d: CompatibilityData) {\n\t\tconst score = d.overallScore;\n\t\tconst breakdown = this.getBreakdown();\n\t\tconst rating =\n\t\t\t'rating' in d\n\t\t\t\t? (d as CalculateNumCompatibilityResponse).rating\n\t\t\t\t: undefined;\n\t\tconst archetype =\n\t\t\t'archetype' in d\n\t\t\t\t? (d as CalculateCompatibilityResponse).archetype\n\t\t\t\t: undefined;\n\t\tconst advice =\n\t\t\t'advice' in d\n\t\t\t\t? (d as CalculateNumCompatibilityResponse).advice\n\t\t\t\t: undefined;\n\t\tconst summary =\n\t\t\t'summary' in d\n\t\t\t\t? (d as CalculateCompatibilityResponse).summary\n\t\t\t\t: undefined;\n\t\tconst interpretation =\n\t\t\t'interpretation' in d\n\t\t\t\t? (d as CalculateCompatibilityResponse).interpretation\n\t\t\t\t: undefined;\n\t\tconst strengths = 'strengths' in d ? d.strengths : undefined;\n\t\tconst challenges = 'challenges' in d ? d.challenges : undefined;\n\t\tconst keyAspects =\n\t\t\t'keyAspects' in d\n\t\t\t\t? (d as CalculateCompatibilityResponse).keyAspects\n\t\t\t\t: undefined;\n\n\t\treturn html`<article class=\"card\" aria-label=\"${`Compatibility (${this.mode})`}\"><div class=\"head\"><h2>${this.mode} compatibility</h2><div>${\n\t\t\t\t\t\ttypeof score === 'number'\n\t\t\t\t\t\t\t? html`<div class=\"score\">${formatNumber(score, 0)}</div>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t} ${rating ? html`<div class=\"rating\">${rating}</div>` : nothing}</div></div>${\n\t\t\t\tObject.keys(breakdown).length > 0\n\t\t\t\t\t? html`<div role=\"list\">${Object.entries(breakdown).map(\n\t\t\t\t\t\t\t([k, v]) => html`<div class=\"bar-row\" role=\"listitem\"><span style=\"text-transform:capitalize\">${k}</span> <span class=\"bar\"><span style=\"width:${Math.max(0, Math.min(100, v))}%\"></span></span> <span>${formatNumber(v, 0)}</span></div>`,\n\t\t\t\t\t\t)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tarchetype\n\t\t\t\t\t? html`<p><span class=\"archetype\">${archetype.label}</span> ${archetype.description ? html`\u00B7 ${archetype.description}` : nothing}</p>`\n\t\t\t\t\t: nothing\n\t\t\t} ${summary ? html`<p>${summary}</p>` : nothing} ${interpretation && !summary ? html`<p>${interpretation}</p>` : nothing} ${advice ? html`<p>${advice}</p>` : nothing} ${\n\t\t\t\t(strengths?.length ?? 0) > 0 || (challenges?.length ?? 0) > 0\n\t\t\t\t\t? html`<div class=\"lists\">${\n\t\t\t\t\t\t\tstrengths?.length\n\t\t\t\t\t\t\t\t? html`<div><h3>Strengths</h3><ul>${strengths.map((s) => html`<li>${s}</li>`)}</ul></div>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t} ${\n\t\t\t\t\t\t\tchallenges?.length\n\t\t\t\t\t\t\t\t? html`<div><h3>Challenges</h3><ul>${challenges.map((s) => html`<li>${s}</li>`)}</ul></div>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tkeyAspects?.length\n\t\t\t\t\t? html`<div><h3 style=\"margin:0 0 .25rem;font-size:var(--roxy-text-xs);color:var(--roxy-muted);text-transform:uppercase;letter-spacing:.06em\">Key aspects</h3><ul style=\"margin:0;padding-left:1rem;font-size:var(--roxy-text-sm)\">${keyAspects.slice(0, 6).map((a) => html`<li>${formatAspect(a)}</li>`)}</ul></div>`\n\t\t\t\t\t: nothing\n\t\t\t}</article>`;\n\t}\n}\n\ntype KeyAspect = CalculateCompatibilityResponse extends {\n\tkeyAspects: Array<infer T>;\n}\n\t? T\n\t: never;\n\nfunction formatAspect(a: KeyAspect): string {\n\tconst aspect = a.type.toLowerCase().replace(/_/g, '-');\n\tconst orb =\n\t\ttypeof a.orb === 'number' ? ` (orb ${formatNumber(a.orb, 1)}\u00B0)` : '';\n\tconst head = [a.planet1, aspect, a.planet2].filter(Boolean).join(' ');\n\treturn a.description ? `${head}${orb} \u00B7 ${a.description}` : `${head}${orb}`;\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-compatibility-card': RoxyCompatibilityCard;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { GetCrystalResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\nconst MONTHS = [\n\t'January',\n\t'February',\n\t'March',\n\t'April',\n\t'May',\n\t'June',\n\t'July',\n\t'August',\n\t'September',\n\t'October',\n\t'November',\n\t'December',\n];\n\n/**\n * Single-crystal detail card. Renders /crystals/{id}: the stone's photo, description, and full metaphysical profile (spiritual / emotional / physical meaning, governing chakras, zodiac signs, planet, elements, colours, Mohs hardness, numerical vibration, birthstone month), plus its affirmation and the crystals it pairs with. This is the detail view; roxy-crystal-grid is the gallery.\n */\n@customElement('roxy-crystal-card')\nexport class RoxyCrystalCard extends RoxyDataElement<GetCrystalResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.hero{gap:var(--roxy-space-md,1rem);align-items:flex-start;display:flex}.photo{border-radius:var(--roxy-radius-md,8px);object-fit:cover;background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 35%, transparent);flex:none;width:96px;height:96px}.title{margin:0 0 var(--roxy-space-xs,.25rem) 0;font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600)}.desc{line-height:1.55;font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);margin:0}.attrs{gap:var(--roxy-space-sm,.5rem);grid-template-columns:repeat(auto-fit,minmax(7rem,1fr));display:grid}.attr{gap:2px;display:grid}.attr dt{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.05em}.attr dd{font-size:var(--roxy-text-sm,.875rem);margin:0;font-weight:500}.colors{flex-wrap:wrap;gap:.4rem;display:flex}.color{font-size:var(--roxy-text-xs,.75rem);text-transform:capitalize;align-items:center;gap:.3rem;display:inline-flex}.dot{border-radius:var(--roxy-radius-full,9999px);border:1px solid color-mix(in srgb, var(--roxy-fg,#0a0a0a) 18%, transparent);width:.7rem;height:.7rem}.meaning h3{margin:0 0 var(--roxy-space-xs,.25rem) 0;font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.05em}.meaning p{margin:0 0 var(--roxy-space-sm,.5rem) 0;font-size:var(--roxy-text-sm,.875rem);line-height:1.55}.chips{flex-wrap:wrap;gap:.3rem;display:flex}.chip{border-radius:var(--roxy-radius-full,9999px);background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 14%, transparent);color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-xs,.75rem);text-transform:capitalize;padding:1px 8px}.section-label{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;font-weight:var(--roxy-weight-bold,600);margin:0 0 var(--roxy-space-xs,.25rem) 0}.affirmation{padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);border-left:3px solid var(--roxy-accent,#f59e0b);background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 8%, transparent);font-style:italic;font-size:var(--roxy-text-sm,.875rem);border-radius:0 var(--roxy-radius-sm,4px) var(--roxy-radius-sm,4px) 0;margin:0}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No crystal data</div>`;\n\t}\n\n\tprotected renderData(d: GetCrystalResponse) {\n\t\tconst colors = d.colors ?? [];\n\t\tconst keywords = d.keywords ?? [];\n\t\tconst pairs = d.pairsWith ?? [];\n\t\tconst month =\n\t\t\ttypeof d.birthMonth === 'number' ? MONTHS[d.birthMonth - 1] : undefined;\n\n\t\treturn html`<article class=\"wrap\" aria-label=\"${d.name ?? 'Crystal'}\"><div class=\"hero\">${d.imageUrl ? html`<img class=\"photo\" src=\"${d.imageUrl}\" alt=\"${d.name ?? 'Crystal'}\" loading=\"lazy\">` : nothing}<div><h2 class=\"title\">${d.name}</h2>${d.description ? html`<p class=\"desc\">${d.description}</p>` : nothing}</div></div><dl class=\"attrs\">${this.attr('Planet', d.planet)} ${this.attr('Hardness', typeof d.hardness === 'number' ? `${d.hardness} Mohs` : undefined)} ${this.attr('Vibration', d.numericalVibration)} ${this.attr('Birthstone', month)} ${this.list('Chakras', d.chakras)} ${this.list('Zodiac', d.zodiacSigns)} ${this.list('Elements', d.elements)} ${\n\t\t\t\t\tcolors.length\n\t\t\t\t\t\t? html`<div class=\"attr\"><dt>Colors</dt><dd><div class=\"colors\">${colors.map((c) => html`<span class=\"color\"><span class=\"dot\" style=\"background:${c}\"></span>${c}</span>`)}</div></dd></div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</dl>${this.renderMeaning(d.meaning)} ${\n\t\t\t\tkeywords.length\n\t\t\t\t\t? html`<div><p class=\"section-label\">Keywords</p><div class=\"chips\">${keywords.map((k) => html`<span class=\"chip\">${k}</span>`)}</div></div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${d.affirmation ? html`<p class=\"affirmation\">${d.affirmation}</p>` : nothing} ${\n\t\t\t\tpairs.length\n\t\t\t\t\t? html`<div><p class=\"section-label\">Pairs with</p><div class=\"chips\">${pairs.map((p) => html`<span class=\"chip\">${String(p).replace(/-/g, ' ')}</span>`)}</div></div>`\n\t\t\t\t\t: nothing\n\t\t\t}</article>`;\n\t}\n\n\tprivate attr(label: string, value: string | number | undefined) {\n\t\tif (value === undefined || value === null || value === '') return nothing;\n\t\treturn html`<div class=\"attr\"><dt>${label}</dt><dd>${value}</dd></div>`;\n\t}\n\n\tprivate list(label: string, values: readonly string[] | undefined) {\n\t\tif (!values?.length) return nothing;\n\t\treturn html`<div class=\"attr\"><dt>${label}</dt><dd>${values.join(', ')}</dd></div>`;\n\t}\n\n\tprivate renderMeaning(m: GetCrystalResponse['meaning'] | undefined) {\n\t\tif (!m) return nothing;\n\t\tconst rows: Array<[string, string | undefined]> = [\n\t\t\t['Spiritual', m.spiritual],\n\t\t\t['Emotional', m.emotional],\n\t\t\t['Physical', m.physical],\n\t\t];\n\t\tconst present = rows.filter(([, v]) => Boolean(v));\n\t\tif (present.length === 0) return nothing;\n\t\treturn html`<div class=\"meaning\">${present.map(([label, text]) => html`<h3>${label}</h3><p>${text}</p>`)}</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-crystal-card': RoxyCrystalCard;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type {\n\tGetBirthstonesResponse,\n\tGetCrystalsByChakraResponse,\n\tGetCrystalsByElementResponse,\n\tGetCrystalsByZodiacResponse,\n\tListCrystalsResponse,\n\tSearchCrystalsResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\n/**\n * Any crystal list response that carries a `crystals` summary array. Every crystals endpoint that returns more than one stone shares the `{ name, id, imageUrl, colors }` item shape, so one grid renders them all.\n */\ntype CrystalGridData =\n\t| ListCrystalsResponse\n\t| GetCrystalsByChakraResponse\n\t| GetCrystalsByElementResponse\n\t| GetCrystalsByZodiacResponse\n\t| GetBirthstonesResponse\n\t| SearchCrystalsResponse;\n\n/**\n * Month number to birthstone month name for the derived heading.\n */\nconst MONTHS = [\n\t'January',\n\t'February',\n\t'March',\n\t'April',\n\t'May',\n\t'June',\n\t'July',\n\t'August',\n\t'September',\n\t'October',\n\t'November',\n\t'December',\n];\n\n/**\n * Crystal grid. Renders any crystals list response (/crystals, /crystals/chakra/{chakra}, /crystals/element/{element}, /crystals/zodiac/{sign}, /crystals/birthstone/{month}, /crystals/search) as a responsive gallery of crystal tiles with photo, name, and colour swatches. The heading is derived from the response filter (chakra, element, zodiac sign, or birth month) or set explicitly via the `heading` attribute.\n */\n@customElement('roxy-crystal-grid')\nexport class RoxyCrystalGrid extends RoxyDataElement<CrystalGridData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-fg,#0a0a0a);margin:0}.count{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}.grid{gap:var(--roxy-space-md,1rem);grid-template-columns:repeat(auto-fill,minmax(8rem,1fr));margin:0;padding:0;list-style:none;display:grid}.tile{gap:var(--roxy-space-xs,.25rem);background:var(--roxy-surface,#fff);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-sm,.5rem);box-shadow:var(--roxy-shadow-sm);display:grid}.photo{aspect-ratio:1;border-radius:var(--roxy-radius-sm,4px);object-fit:cover;background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 35%, transparent);width:100%}.name{font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-fg,#0a0a0a);margin:0}.colors{flex-wrap:wrap;gap:4px;display:flex}.swatch{border-radius:var(--roxy-radius-full,9999px);border:1px solid color-mix(in srgb, var(--roxy-fg,#0a0a0a) 18%, transparent);width:10px;height:10px}`,\n\t];\n\n\t/**\n\t * Override the auto-derived grid heading. Empty by default, in which case the heading comes from the response filter (chakra, element, zodiac, or birth month) or falls back to \"Crystals\".\n\t */\n\t@property({ type: String, reflect: true })\n\theading = '';\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No crystals</div>`;\n\t}\n\n\tprotected renderData(d: CrystalGridData) {\n\t\tconst crystals = d.crystals ?? [];\n\t\tif (crystals.length === 0) return this.renderEmpty();\n\n\t\tconst title = this.heading || this.deriveHeading(d);\n\t\tconst total =\n\t\t\t'total' in d && typeof d.total === 'number' ? d.total : crystals.length;\n\n\t\treturn html`<section class=\"wrap\" aria-label=\"${title}\"><header class=\"head\"><h2 class=\"title\">${title}</h2><span class=\"count\">${total} ${total === 1 ? 'crystal' : 'crystals'}</span></header><ul class=\"grid\">${crystals.map(\n\t\t\t\t\t(c) => html`<li class=\"tile\">${\n\t\t\t\t\t\t\tc.imageUrl\n\t\t\t\t\t\t\t\t? html`<img class=\"photo\" src=\"${c.imageUrl}\" alt=\"${c.name ?? 'Crystal'}\" loading=\"lazy\">`\n\t\t\t\t\t\t\t\t: html`<div class=\"photo\" aria-hidden=\"true\"></div>`\n\t\t\t\t\t\t}<p class=\"name\">${c.name}</p>${\n\t\t\t\t\t\t\tc.colors && c.colors.length > 0\n\t\t\t\t\t\t\t\t? html`<div class=\"colors\" aria-label=\"${`Colours: ${c.colors.join(', ')}`}\">${c.colors.map((col) => html`<span class=\"swatch\" style=\"${`background:${cssColor(col)}`}\" title=\"${col}\"></span>`)}</div>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}</li>`,\n\t\t\t\t)}</ul></section>`;\n\t}\n\n\tprivate deriveHeading(d: CrystalGridData): string {\n\t\tif ('chakra' in d && d.chakra) return `${d.chakra} chakra crystals`;\n\t\tif ('element' in d && d.element) return `${d.element} element crystals`;\n\t\tif ('sign' in d && d.sign) return `Crystals for ${d.sign}`;\n\t\tif ('month' in d && typeof d.month === 'number')\n\t\t\treturn `${MONTHS[d.month - 1] ?? ''} birthstones`.trim();\n\t\treturn 'Crystals';\n\t}\n}\n\n/**\n * Map an API colour keyword to a CSS colour. Most crystal colours (violet, purple, green, blue) are valid CSS named colours; multi-word or non-standard values (blue-green, lavender) fall back to the keyword and, if the browser cannot resolve it, the swatch border still renders. Lower-cased and space-stripped so \"Blue Green\" resolves to the CSS hyphen form where it exists.\n */\nfunction cssColor(name: string): string {\n\treturn name.trim().toLowerCase().replace(/\\s+/g, '');\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-crystal-grid': RoxyCrystalGrid;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type {\n\tGetCurrentDashaResponse,\n\tGetMajorDashasResponse,\n\tGetSubDashasResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatNumber } from '../utils/format.js';\n\ntype DashaData =\n\t| GetCurrentDashaResponse\n\t| GetMajorDashasResponse\n\t| GetSubDashasResponse;\n\ntype DashaPeriod = GetMajorDashasResponse['mahadashas'][number];\n\n/**\n * Dasha timeline. Renders /vedic-astrology/dasha/{current,major,sub/{...}}.\n * Default mode shows the active mahadasha + antardasha + pratyantardasha.\n * Switch to period=\"major\" for the full 120-year Vimshottari timeline.\n */\n@customElement('roxy-dasha-timeline')\nexport class RoxyDashaTimeline extends RoxyDataElement<DashaData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:center;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.nakshatra{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}.current{gap:var(--roxy-space-md,1rem);background:var(--roxy-surface,#fff);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-md,1rem);box-shadow:var(--roxy-shadow-sm);grid-template-columns:repeat(auto-fit,minmax(10rem,1fr));display:grid}.current div span:first-child{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);text-transform:uppercase;letter-spacing:.06em;display:block}.current div strong{font-size:var(--roxy-text-base,1rem);color:var(--roxy-fg,#0a0a0a)}.balance{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-muted,#71717a);border-left:2px solid var(--roxy-border,#e4e4e7);padding-left:var(--roxy-space-sm,.5rem);margin:0}.timeline{gap:var(--roxy-space-xs,.25rem);display:grid}.bar{gap:var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-sm,.875rem);grid-template-columns:5rem 1fr 8rem;align-items:center;display:grid}.bar.now strong{color:var(--roxy-accent-ink,#b45309)}.now-badge{font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-accent-ink,#b45309);text-transform:uppercase;letter-spacing:.06em;margin-left:.4em;display:inline-block}.bar-track{background:var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-full,9999px);height:14px;position:relative;overflow:hidden}.bar-fill{background:var(--roxy-accent,#f59e0b);opacity:.45;height:100%;transition:width var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,cubic-bezier(.4, 0, .2, 1));display:block}.bar-now .bar-fill{opacity:1}.bar-progress{background:var(--roxy-accent-ink,#b45309);width:2px;box-shadow:0 0 0 2px color-mix(in srgb, var(--roxy-accent,#f59e0b) 35%, transparent);border-radius:2px;position:absolute;top:-2px;bottom:-2px}.dates{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);font-variant-numeric:tabular-nums;text-align:right}.interp{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);background:var(--roxy-surface,#fff)}.interp h3{font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);margin:0}.interp p{margin:var(--roxy-space-sm,.5rem) 0 0;font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-muted,#71717a)}`,\n\t];\n\n\t@property({ type: String, reflect: true })\n\tperiod: 'current' | 'major' | 'sub' = 'current';\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No dasha data</div>`;\n\t}\n\n\tprotected renderData(d: DashaData) {\n\t\tconst periods = this.collectPeriods(d);\n\t\tconst maxYears = periods.length\n\t\t\t? Math.max(...periods.map((p) => p.durationYears))\n\t\t\t: 0;\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Dasha timeline\"><header class=\"head\"><h2 class=\"title\">${\n\t\t\t\t\t\tthis.period === 'major'\n\t\t\t\t\t\t\t? 'Vimshottari Mahadasha'\n\t\t\t\t\t\t\t: this.period === 'sub'\n\t\t\t\t\t\t\t\t? 'Antardasha'\n\t\t\t\t\t\t\t\t: 'Active dashas'\n\t\t\t\t\t}</h2>${\n\t\t\t\t\t'nakshatraName' in d && d.nakshatraName\n\t\t\t\t\t\t? html`<div class=\"nakshatra\">Moon nakshatra: ${d.nakshatraName} ${'nakshatraLord' in d && d.nakshatraLord ? html`(lord ${d.nakshatraLord})` : nothing}</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</header>${this.renderBirthBalance(d)} ${this.period === 'current' ? this.renderCurrent(d) : nothing} ${\n\t\t\t\tperiods.length > 0\n\t\t\t\t\t? html`<div class=\"timeline\" role=\"list\">${periods.map((p) => this.renderBar(p, maxYears))}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${this.renderActiveInterpretation(periods)}</div>`;\n\t}\n\n\tprivate renderBirthBalance(d: DashaData) {\n\t\tif (!('birthDashaBalance' in d) || !d.birthDashaBalance) return nothing;\n\t\tconst b = d.birthDashaBalance;\n\t\tconst lord = 'nakshatraLord' in d && d.nakshatraLord ? d.nakshatraLord : '';\n\t\tconst yrs = b.years ?? 0;\n\t\tconst mo = b.months ?? 0;\n\t\tconst da = b.days ?? 0;\n\t\tconst parts: string[] = [];\n\t\tif (yrs) parts.push(`${yrs}y`);\n\t\tif (mo) parts.push(`${mo}m`);\n\t\tif (da) parts.push(`${da}d`);\n\t\tconst remaining = parts.length ? parts.join(' ') : '0d';\n\t\treturn html`<p class=\"balance\">Birth dasha balance: ${remaining} of ${lord ? html`<strong>${lord}</strong>` : 'the opening mahadasha'} remained at birth.</p>`;\n\t}\n\n\tprivate renderActiveInterpretation(periods: DashaPeriod[]) {\n\t\tconst active = periods.find((p) => this.isCurrent(p));\n\t\tif (!active?.interpretation) return nothing;\n\t\treturn html`<div class=\"interp\"><h3>${active.planet} mahadasha</h3><p>${active.interpretation}</p></div>`;\n\t}\n\n\tprivate renderCurrent(d: DashaData) {\n\t\tif (!('mahadasha' in d)) return nothing;\n\t\treturn html`<div class=\"current\">${\n\t\t\t\t'mahadasha' in d && d.mahadasha\n\t\t\t\t\t? html`<div><span>Mahadasha</span> <strong>${d.mahadasha.planet}</strong> ${\n\t\t\t\t\t\t'remainingInMahadasha' in d && d.remainingInMahadasha\n\t\t\t\t\t\t\t? html`<small>${formatNumber(d.remainingInMahadasha.years + d.remainingInMahadasha.months / 12, 1)} years left</small>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\t'antardasha' in d && d.antardasha\n\t\t\t\t\t? html`<div><span>Antardasha</span> <strong>${d.antardasha.planet}</strong> ${\n\t\t\t\t\t\t'remainingInAntardasha' in d && d.remainingInAntardasha\n\t\t\t\t\t\t\t? html`<small>${formatNumber(d.remainingInAntardasha.years + d.remainingInAntardasha.months / 12, 1)} years left</small>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\t'pratyantardasha' in d && d.pratyantardasha\n\t\t\t\t\t? html`<div><span>Pratyantardasha</span> <strong>${d.pratyantardasha.planet}</strong> ${\n\t\t\t\t\t\t'remainingInPratyantardasha' in d && d.remainingInPratyantardasha\n\t\t\t\t\t\t\t? html`<small>${formatNumber(d.remainingInPratyantardasha.years + d.remainingInPratyantardasha.months / 12, 1)} years left</small>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}</div>`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n\n\tprivate collectPeriods(d: DashaData): DashaPeriod[] {\n\t\tif ('mahadashas' in d && d.mahadashas?.length) return d.mahadashas;\n\t\tif ('antardashas' in d && d.antardashas?.length) return d.antardashas;\n\t\treturn [];\n\t}\n\n\t/** True when the current wall-clock time falls between the period's start and end. */\n\tprivate isCurrent(p: DashaPeriod): boolean {\n\t\tif (!p.startDate || !p.endDate) return false;\n\t\tconst now = Date.now();\n\t\tconst start = Date.parse(p.startDate);\n\t\tconst end = Date.parse(p.endDate);\n\t\tif (Number.isNaN(start) || Number.isNaN(end)) return false;\n\t\treturn now >= start && now < end;\n\t}\n\n\t/**\n\t * Fractional progress (0..1) through a period at the current time. Used to\n\t * draw a vertical \"now\" marker inside the active bar. Returns -1 outside the\n\t * period so the caller can skip the marker.\n\t */\n\tprivate progressIn(p: DashaPeriod): number {\n\t\tif (!p.startDate || !p.endDate) return -1;\n\t\tconst start = Date.parse(p.startDate);\n\t\tconst end = Date.parse(p.endDate);\n\t\tconst now = Date.now();\n\t\tif (\n\t\t\tNumber.isNaN(start) ||\n\t\t\tNumber.isNaN(end) ||\n\t\t\tnow < start ||\n\t\t\tnow >= end ||\n\t\t\tend <= start\n\t\t) {\n\t\t\treturn -1;\n\t\t}\n\t\treturn (now - start) / (end - start);\n\t}\n\n\tprivate renderBar(p: DashaPeriod, max: number) {\n\t\tconst years = p.durationYears;\n\t\tconst width = max > 0 ? (years / max) * 100 : 0;\n\t\tconst current = this.isCurrent(p);\n\t\tconst progress = current ? this.progressIn(p) : -1;\n\t\tconst trackClass = current ? 'bar-track bar-now' : 'bar-track';\n\t\treturn html`<div class=\"${current ? 'bar now' : 'bar'}\" role=\"listitem\" aria-current=\"${current ? 'time' : 'false'}\"><span><strong>${p.planet}</strong>${current ? html`<span class=\"now-badge\">Now</span>` : nothing} </span><span class=\"${trackClass}\"><span class=\"bar-fill\" style=\"width:${width}%\"></span> ${\n\t\t\t\t\tprogress >= 0\n\t\t\t\t\t\t? html`<span class=\"bar-progress\" style=\"left:${progress * width}%\" aria-hidden=\"true\"></span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} </span><span class=\"dates\">${p.startDate ? formatYear(p.startDate) : ''} ${p.endDate ? html`- ${formatYear(p.endDate)}` : ''}</span></div>`;\n\t}\n}\n\nfunction formatYear(s: string): string {\n\tconst m = s.match(/^(\\d{4})/);\n\treturn m ? m[1] : s;\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-dasha-timeline': RoxyDashaTimeline;\n\t}\n}\n", "import { css, html, nothing, type TemplateResult } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { humanize } from '../utils/string.js';\n\n/**\n * Generic fallback renderer. Accepts ANY OpenAPI response shape and renders\n * it via field-name heuristics so future spec additions render reasonably\n * without hand-wired components.\n *\n * Heuristic order:\n * 1. Primitive (string, number, boolean) -> single line.\n * 2. Array of primitives -> chip list.\n * 3. Array of objects with shared keys -> table.\n * 4. Object with title-like field -> card with key/value rows.\n * 5. Otherwise -> definition list of all keys.\n *\n * When a schema declares an `x-roxy-ui` hint, a future dispatcher can opt\n * into a hand-tuned component instead of this fallback.\n */\n\ntype Json = string | number | boolean | null | Json[] | { [key: string]: Json };\n\nconst TITLE_KEYS = ['title', 'name', 'label', 'heading', 'overview', 'summary'];\nconst IMAGE_KEYS = ['imageUrl', 'image', 'icon', 'symbol'];\nconst SKIP_KEYS = ['imageUrl', 'image']; // rendered separately, not in body rows\n\n// Hard cap on recursion. Real RoxyAPI responses nest at most 5-6 deep; anything\n// deeper is either a circular reference (which would otherwise infinite-loop)\n// or a payload too rich for the generic fallback to render usefully. The\n// recursion is otherwise safe: <roxy-data> is registered globally by its\n// `@customElement` decorator on import, so the nested template resolves to\n// this same class without a separate import.\nconst MAX_DEPTH = 6;\n\n@customElement('roxy-data')\nexport class RoxyData extends RoxyDataElement<Json> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.roxy-card{background:var(--roxy-surface,#fff);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-md,1rem);box-shadow:var(--roxy-shadow-sm)}.roxy-title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0 0 var(--roxy-space-sm,.5rem) 0;color:var(--roxy-primary,#0f172a);letter-spacing:var(--roxy-tracking-tight)}.roxy-summary{color:var(--roxy-secondary,#475569);margin:0 0 var(--roxy-space-md,1rem) 0;font-size:var(--roxy-text-sm,.875rem)}dl.roxy-rows{gap:var(--roxy-space-xs,.25rem) var(--roxy-space-md,1rem);grid-template-columns:minmax(8ch,max-content) 1fr;margin:0;display:grid}dl.roxy-rows dt{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem);text-transform:capitalize}dl.roxy-rows dd{color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);word-break:break-word;margin:0}ul.roxy-chips{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;margin:0;padding:0;list-style:none;display:flex}ul.roxy-chips li{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 14%, transparent);color:var(--roxy-fg,#0a0a0a);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);padding:2px 8px}table.roxy-table{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem)}table.roxy-table th,table.roxy-table td{border-bottom:1px solid var(--roxy-border,#e4e4e7);padding:var(--roxy-space-sm,.5rem);text-align:left;text-transform:none}table.roxy-table th{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:capitalize;font-size:var(--roxy-text-xs,.75rem);letter-spacing:.04em}.roxy-image{border-radius:var(--roxy-radius-md,8px);max-width:100%;height:auto;margin-bottom:var(--roxy-space-md,1rem)}.roxy-section{margin-bottom:var(--roxy-space-md,1rem)}.roxy-section h4{font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-secondary,#475569);margin:0 0 var(--roxy-space-xs,.25rem) 0;text-transform:capitalize}`,\n\t];\n\n\t/**\n\t * Internal recursion depth. Nested <roxy-data> instances inherit this from the parent and increment to guard against circular references in the input. Not part of the public API; do not set from consumer code.\n\t */\n\t@property({ attribute: false })\n\tdepth = 0;\n\n\tprotected renderData(data: Json) {\n\t\tif (this.depth >= MAX_DEPTH) {\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">\u2026</div>`;\n\t\t}\n\t\treturn html`<div class=\"roxy-card\" aria-label=\"Generic data display\">${this.renderValue(data)}</div>`;\n\t}\n\n\tprivate renderValue(value: Json): TemplateResult | typeof nothing {\n\t\tif (value === null || value === undefined) return nothing;\n\t\tif (typeof value === 'string') return html`<p>${value}</p>`;\n\t\tif (typeof value === 'number' || typeof value === 'boolean') {\n\t\t\treturn html`<p>${String(value)}</p>`;\n\t\t}\n\t\tif (Array.isArray(value)) return this.renderArray(value);\n\t\treturn this.renderObject(value as Record<string, Json>);\n\t}\n\n\tprivate renderArray(arr: Json[]): TemplateResult {\n\t\tif (arr.length === 0) {\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">Empty list</div>`;\n\t\t}\n\t\tconst allPrimitive = arr.every(\n\t\t\t(v) => v === null || ['string', 'number', 'boolean'].includes(typeof v),\n\t\t);\n\t\tif (allPrimitive) {\n\t\t\treturn html`<ul class=\"roxy-chips\">${arr.map((v) => html`<li>${String(v)}</li>`)}</ul>`;\n\t\t}\n\t\tconst allObjects = arr.every(\n\t\t\t(v) => v !== null && typeof v === 'object' && !Array.isArray(v),\n\t\t);\n\t\tif (allObjects) return this.renderTable(arr as Record<string, Json>[]);\n\t\treturn html`<ol>${arr.map((v) => html`<li>${this.renderValue(v)}</li>`)}</ol>`;\n\t}\n\n\tprivate renderTable(rows: Record<string, Json>[]): TemplateResult {\n\t\tconst keys = this.collectKeys(rows);\n\t\treturn html`<table class=\"roxy-table\" role=\"table\"><thead><tr>${keys.map((k) => html`<th>${humanize(k)}</th>`)}</tr></thead><tbody>${rows.map(\n\t\t\t\t\t(row) => html`<tr>${keys.map((k) => html`<td>${this.formatPrimitive(row[k])}</td>`)}</tr>`,\n\t\t\t\t)}</tbody></table>`;\n\t}\n\n\tprivate renderObject(obj: Record<string, Json>): TemplateResult {\n\t\tconst titleKey = TITLE_KEYS.find((k) => typeof obj[k] === 'string');\n\t\tconst imageKey = IMAGE_KEYS.find(\n\t\t\t(k) =>\n\t\t\t\ttypeof obj[k] === 'string' && (obj[k] as string).startsWith('http'),\n\t\t);\n\t\tconst summaryKey =\n\t\t\ttitleKey !== 'summary' && typeof obj.summary === 'string'\n\t\t\t\t? 'summary'\n\t\t\t\t: null;\n\t\tconst rows = Object.entries(obj).filter(\n\t\t\t([k, v]) =>\n\t\t\t\tk !== titleKey &&\n\t\t\t\tk !== summaryKey &&\n\t\t\t\t!SKIP_KEYS.includes(k) &&\n\t\t\t\tv !== null &&\n\t\t\t\tv !== undefined,\n\t\t);\n\n\t\treturn html`${\n\t\t\t\timageKey\n\t\t\t\t\t? html`<img class=\"roxy-image\" src=\"${String(obj[imageKey])}\" alt=\"${titleKey ? String(obj[titleKey]) : 'illustration'}\" loading=\"lazy\">`\n\t\t\t\t\t: nothing\n\t\t\t} ${titleKey ? html`<h3 class=\"roxy-title\">${obj[titleKey]}</h3>` : nothing} ${summaryKey ? html`<p class=\"roxy-summary\">${obj[summaryKey]}</p>` : nothing} ${\n\t\t\t\trows.length > 0\n\t\t\t\t\t? html`<dl class=\"roxy-rows\">${rows.map(\n\t\t\t\t\t\t\t([k, v]) => html`<dt>${humanize(k)}</dt><dd>${this.renderField(v)}</dd>`,\n\t\t\t\t\t\t)}</dl>`\n\t\t\t\t\t: nothing\n\t\t\t}`;\n\t}\n\n\tprivate renderField(value: Json): TemplateResult | string {\n\t\tif (value === null || value === undefined) return '';\n\t\tif (typeof value === 'string') return value;\n\t\tif (typeof value === 'number' || typeof value === 'boolean')\n\t\t\treturn String(value);\n\t\tif (Array.isArray(value)) {\n\t\t\tconst allPrimitive = value.every((v) =>\n\t\t\t\t['string', 'number', 'boolean'].includes(typeof v),\n\t\t\t);\n\t\t\tif (allPrimitive) {\n\t\t\t\treturn html`<ul class=\"roxy-chips\">${value.map((v) => html`<li>${String(v)}</li>`)}</ul>`;\n\t\t\t}\n\t\t}\n\t\treturn html`<roxy-data .data=\"${value}\" .depth=\"${this.depth + 1}\"></roxy-data>`;\n\t}\n\n\tprivate formatPrimitive(value: Json | undefined): string {\n\t\tif (value === null || value === undefined) return '';\n\t\tif (typeof value === 'string') return value;\n\t\tif (typeof value === 'number' || typeof value === 'boolean')\n\t\t\treturn String(value);\n\t\tif (Array.isArray(value)) return value.map(String).join(', ');\n\t\treturn JSON.stringify(value);\n\t}\n\n\tprivate collectKeys(rows: Record<string, Json>[]): string[] {\n\t\tconst seen = new Set<string>();\n\t\tfor (const row of rows) {\n\t\t\tfor (const k of Object.keys(row)) seen.add(k);\n\t\t}\n\t\treturn Array.from(seen);\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-data': RoxyData;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { PLANET_GLYPH } from '../tokens/index.js';\nimport type { DivisionalChartResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport {\n\ttype ChartStyle,\n\ttype KundliViewModel,\n\trenderKundliStyleTablist,\n\trenderKundliSvg,\n\ttoKundliViewModel,\n} from '../utils/kundli-render.js';\nimport { kundliStyles } from '../utils/kundli-styles.js';\nimport { tablistStyles } from '../utils/tablist.js';\n\n/**\n * Divisional chart renderer (D2-D60). Accepts a DivisionalChartResponse and\n * renders the same South / North / East kundli grid as the birth chart, plus\n * division metadata and Vargottama planet pills. A visible tablist lets the\n * end user switch styles at runtime. The varga response carries a graha-keyed\n * `chart.meta` map (no per-rashi buckets), so houses are bucketed from that\n * map.\n */\n@customElement('roxy-divisional-chart')\nexport class RoxyDivisionalChart extends RoxyDataElement<DivisionalChartResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tkundliStyles,\n\t\ttablistStyles,\n\t\tcss`.division-meta{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-muted,#71717a);margin:0}.significance{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-muted,#71717a);border-left:2px solid var(--roxy-border,#e4e4e7);padding-left:var(--roxy-space-sm,.5rem);margin:0}.vargottama-row{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;align-items:center;display:flex}.vargottama-label{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-muted,#71717a);margin-right:var(--roxy-space-xs,.25rem);font-weight:500}.vargottama-pill{font-size:var(--roxy-text-sm,.875rem);background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 22%, transparent);color:var(--roxy-fg,#0a0a0a);border:1px solid color-mix(in srgb, var(--roxy-accent,#f59e0b) 45%, transparent);border-radius:999px;align-items:center;gap:.2em;padding:.15em .6em;font-weight:600;display:inline-flex}`,\n\t];\n\n\t@property({ type: String, reflect: true, attribute: 'chart-style' })\n\tchartStyle: ChartStyle = 'north';\n\n\tprivate setStyle = (next: ChartStyle) => {\n\t\tthis.chartStyle = next;\n\t};\n\n\tprivate viewModel(): KundliViewModel | null {\n\t\tif (!this.data?.chart?.meta) return null;\n\t\tconst { division } = this.data;\n\t\tconst label = `D${division.number} ${division.name}`;\n\t\treturn toKundliViewModel(this.data.chart.meta, label);\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No divisional chart data</div>`;\n\t}\n\n\tprotected renderData(d: DivisionalChartResponse) {\n\t\tconst vm = this.viewModel();\n\t\tif (!vm) return this.renderEmpty();\n\n\t\tconst { division, vargottama } = d;\n\n\t\treturn html`<div class=\"wrap\"><div class=\"header\"><div><h2 class=\"title\">D${division.number} ${division.name} ${\n\t\t\t\t\t\t\tdivision.sanskritName && division.sanskritName !== division.name\n\t\t\t\t\t\t\t\t? html`<span class=\"division-meta\">\u00B7 ${division.sanskritName}</span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}</h2>${\n\t\t\t\t\t\tdivision.significance\n\t\t\t\t\t\t\t? html`<p class=\"significance\">${division.significance}</p>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}</div>${renderKundliStyleTablist(this.chartStyle, this.setStyle)}</div><svg viewBox=\"0 0 400 400\" preserveAspectRatio=\"xMidYMid meet\" role=\"img\" aria-label=\"D${division.number} ${division.name} divisional chart with twelve sign houses\"><title>D${division.number} ${division.name}</title>${renderKundliSvg(vm, this.chartStyle)}</svg> ${\n\t\t\t\tvargottama && vargottama.length > 0\n\t\t\t\t\t? html`<div class=\"vargottama-row\" role=\"list\" aria-label=\"Vargottama planets\"><span class=\"vargottama-label\">Vargottama:</span> ${vargottama.map(\n\t\t\t\t\t\t\t(planet) =>\n\t\t\t\t\t\t\t\thtml`<span class=\"vargottama-pill\" role=\"listitem\">${PLANET_GLYPH[planet] ?? ''} ${planet}</span>`,\n\t\t\t\t\t\t)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-divisional-chart': RoxyDivisionalChart;\n\t}\n}\n", "import type { TemplateResult } from 'lit';\nimport { nothing, svg } from 'lit';\nimport { PLANET_ABBR, SIGN_ABBR, SIGNS_ORDER } from '../tokens/index.js';\nimport { longitudeToSignPosition } from './degree.js';\nimport { capitalize } from './string.js';\nimport { renderTablist } from './tablist.js';\n\n/**\n * Canonical viewBox geometry for every kundli style. The chart is drawn into a\n * 360-unit square centred in a 400-unit viewBox, leaving a 20-unit gutter for\n * outer labels. All coordinates below are derived from these constants; change\n * them and every cell relocates correctly.\n *\n * @remarks SVG is vector-only and scales without raster loss, so the chart\n * remains crisp from a phone screen to a wall projector. Hosts size the chart\n * by setting `width` on the surrounding container; the SVG keeps a 1:1 aspect\n * ratio via the viewBox.\n */\nconst VIEW_BOX = 400;\nconst MARGIN = 20;\nconst INNER = VIEW_BOX - 2 * MARGIN; // 360\nconst CENTRE = VIEW_BOX / 2; // 200\n\n/**\n * Lowercase rashi key (`\"aries\"`) to canonical title-cased sign name (`\"Aries\"`).\n * Bridges API lowercase rashi strings to the SIGNS_ORDER tokens used everywhere\n * else in the render.\n */\nconst RASHI_TO_SIGN: Record<string, string> = Object.fromEntries(\n\tSIGNS_ORDER.map((s) => [s.toLowerCase(), s] as const),\n);\n\n/**\n * A graha placed inside a kundli cell. Render-only view model fed from a\n * `meta` map on the API response. Carries enough detail to draw a compact\n * in-cell label (abbreviation, whole degree, retrograde mark) and a rich SVG\n * `<title>` tooltip (exact position, nakshatra, pada, avastha).\n */\nexport interface PlacedGraha {\n\tgraha: string;\n\tlongitude?: number;\n\tnakshatra?: { name?: string; pada?: number; lord?: string };\n\tisRetrograde?: boolean;\n\tawastha?: string;\n}\n\n/**\n * Unified view model used by every kundli style. Caller passes a graha-keyed\n * `meta` map (from `/vedic-astrology/birth-chart`, `/divisional-chart`, or\n * `/navamsa`) through {@link toKundliViewModel} to produce this shape.\n *\n * `placements` is keyed by lowercase rashi name (`\"aries\"`, `\"taurus\"`, ...)\n * so the sign-fixed styles can index directly. The Lagna entry is not\n * counted as a planet; it only flags the ascendant cell.\n */\nexport interface KundliViewModel {\n\tlagnaSign: string;\n\tplacements: Record<string, PlacedGraha[]>;\n\tdivisionLabel?: string;\n}\n\n/**\n * Kundli regional styles. Sign-fixed (south, east) and house-fixed (north).\n * Exposed so consumers can type their own `chart-style` attribute reflection.\n */\nexport type ChartStyle = 'south' | 'north' | 'east';\n\nconst CHART_STYLES: ReadonlyArray<{ id: ChartStyle; label: string }> = [\n\t{ id: 'north', label: 'North' },\n\t{ id: 'south', label: 'South' },\n\t{ id: 'east', label: 'East' },\n];\n\nconst RETRO_MARK = '\u02B3';\n\n/**\n * True when the placed graha's longitude maps to a sign other than the cell\n * it occupies. The API preserves the D1 sidereal longitude on every chart, so\n * inside a D2..D60 cell that longitude refers to the D1 sign, not the cell's\n * divisional sign. In that case the degree-within-sign is not meaningful and\n * must be hidden from the in-cell label.\n */\nfunction isDivisionalPlacement(p: PlacedGraha, cellSign: string): boolean {\n\tif (typeof p.longitude !== 'number' || !Number.isFinite(p.longitude)) {\n\t\treturn false;\n\t}\n\treturn (\n\t\tlongitudeToSignPosition(p.longitude).sign.toLowerCase() !==\n\t\tcellSign.toLowerCase()\n\t);\n}\n\n/**\n * Compact in-cell graha label: abbreviation, optional whole-degree, retrograde\n * mark. The degree is shown only when the longitude actually maps to the cell\n * the graha is rendered in (the D1 case); divisional placements show the\n * abbreviation alone since the API longitude refers to D1, not the divisional\n * sign.\n */\nfunction grahaLabel(p: PlacedGraha, cellSign: string): string {\n\tconst abbr = PLANET_ABBR[capitalize(p.graha)] ?? p.graha.slice(0, 2);\n\tconst retro = p.isRetrograde ? RETRO_MARK : '';\n\tif (\n\t\ttypeof p.longitude !== 'number' ||\n\t\t!Number.isFinite(p.longitude) ||\n\t\tisDivisionalPlacement(p, cellSign)\n\t) {\n\t\treturn `${abbr}${retro}`;\n\t}\n\tconst { degree } = longitudeToSignPosition(p.longitude);\n\treturn `${abbr} ${degree}\u00B0${retro}`;\n}\n\n/**\n * Full-detail tooltip surfaced via the SVG `<title>` for each planet label.\n * Includes planet name, the divisional placement (when the longitude does not\n * match the cell, the cell's rashi is preferred), the exact D1 longitude as\n * the original reference, nakshatra and pada, avastha, and the retrograde\n * flag. Surfaces on hover or long-press without crowding the cell.\n */\nfunction grahaTitle(p: PlacedGraha, cellSign: string): string {\n\tconst parts: string[] = [capitalize(p.graha)];\n\tconst divisional = isDivisionalPlacement(p, cellSign);\n\tif (divisional) {\n\t\tparts.push(`in ${cellSign}`);\n\t}\n\tif (typeof p.longitude === 'number' && Number.isFinite(p.longitude)) {\n\t\tconst sp = longitudeToSignPosition(p.longitude);\n\t\tconst minute = String(sp.minute).padStart(2, '0');\n\t\tparts.push(\n\t\t\tdivisional\n\t\t\t\t? `D1: ${sp.degree}\u00B0${minute}' ${sp.sign}`\n\t\t\t\t: `${sp.degree}\u00B0${minute}' ${sp.sign}`,\n\t\t);\n\t}\n\tif (p.nakshatra?.name) {\n\t\tconst pada = p.nakshatra.pada ? ` pada ${p.nakshatra.pada}` : '';\n\t\tparts.push(`${p.nakshatra.name}${pada}`);\n\t}\n\tif (p.awastha) parts.push(p.awastha);\n\tif (p.isRetrograde) parts.push('retrograde');\n\treturn parts.join(' \u00B7 ');\n}\n\n/**\n * Render a vertically centred stack of planet labels at `(cx, baseY)`, one\n * line per planet, with an SVG `<title>` per line carrying the full tooltip.\n * The stack auto-centres on `baseY` regardless of count so a 1-planet cell\n * and a 5-planet cell both look intentional.\n */\nfunction renderPlanetStack(\n\tplanets: PlacedGraha[],\n\tcellSign: string,\n\tcx: number,\n\tbaseY: number,\n\tlineHeight: number,\n): TemplateResult[] {\n\tconst startY = baseY - ((planets.length - 1) * lineHeight) / 2;\n\treturn planets.map((p, j) => {\n\t\tconst yPos = startY + j * lineHeight;\n\t\treturn svg`<text class=\"planet-text\" x=${cx} y=${yPos} text-anchor=\"middle\" dominant-baseline=\"central\">${grahaLabel(\n\t\t\tp,\n\t\t\tcellSign,\n\t\t)}<title>${grahaTitle(p, cellSign)}</title></text>`;\n\t});\n}\n\n/**\n * Bucket a graha-keyed `meta` map (D1 birth chart or D2..D60 divisional\n * chart) into the unified {@link KundliViewModel} the renderer consumes. The\n * Lagna entry is recognised by `graha === 'Lagna'` (or key `\"Lagna\"`) and\n * sets `lagnaSign`; it is not bucketed as a placed planet.\n *\n * @param meta - Graha-keyed map; missing rashi entries are skipped.\n * @param divisionLabel - Optional title written inside the chart centre.\n * @param lagnaOverride - Optional rashi/sign name (case-insensitive, e.g. `\"cancer\"`) that replaces the `meta.Lagna`-derived ascendant. Drives the Chandra Lagna (Moon-as-ascendant) and other reference-point views: the `meta` of a `/birth-chart` response always carries the Janma Lagna as its `Lagna` key, so this is the only way to pivot the houses without a second request. Ignored when it does not resolve to a known sign.\n */\nexport function toKundliViewModel(\n\tmeta: Record<\n\t\tstring,\n\t\t{\n\t\t\tgraha?: string;\n\t\t\trashi?: string;\n\t\t\tlongitude?: number;\n\t\t\tnakshatra?: { name?: string; pada?: number; lord?: string };\n\t\t\tisRetrograde?: boolean;\n\t\t\tawastha?: string;\n\t\t}\n\t>,\n\tdivisionLabel?: string,\n\tlagnaOverride?: string,\n): KundliViewModel {\n\tconst placements: Record<string, PlacedGraha[]> = {};\n\tfor (const sign of SIGNS_ORDER) placements[sign.toLowerCase()] = [];\n\tconst override = lagnaOverride\n\t\t? (RASHI_TO_SIGN[lagnaOverride.toLowerCase()] ?? '')\n\t\t: '';\n\tlet lagnaSign = override;\n\tfor (const [name, pos] of Object.entries(meta ?? {})) {\n\t\tconst rashiKey = (pos?.rashi ?? '').toLowerCase();\n\t\tif (name === 'Lagna' || pos?.graha === 'Lagna') {\n\t\t\t// An explicit override pins the ascendant; otherwise the Janma Lagna\n\t\t\t// from meta is the reference point.\n\t\t\tif (!override) lagnaSign = RASHI_TO_SIGN[rashiKey] ?? '';\n\t\t\tcontinue;\n\t\t}\n\t\tif (!rashiKey || !(rashiKey in placements)) continue;\n\t\tplacements[rashiKey]?.push({\n\t\t\tgraha: pos.graha ?? name,\n\t\t\tlongitude: pos.longitude,\n\t\t\tnakshatra: pos.nakshatra,\n\t\t\tisRetrograde: pos.isRetrograde,\n\t\t\tawastha: pos.awastha,\n\t\t});\n\t}\n\treturn { lagnaSign, placements, divisionLabel };\n}\n\n// ---------------------------------------------------------------------------\n// South Indian: 4x4 grid with central 2x2 hollow. Signs are FIXED to cells\n// (Pisces top-left corner, clockwise); houses rotate from the Lagna cell.\n// ---------------------------------------------------------------------------\n\nconst SOUTH_CELL = INNER / 4; // 90\n\n/**\n * Sign-to-cell column/row in the South Indian fixed-sign grid. Pisces sits in\n * the top-left corner and the remaining signs proceed clockwise around the\n * 12 perimeter cells. (col, row) origin is the chart top-left.\n */\nconst SOUTH_CELL_GRID: Record<string, { col: number; row: number }> = {\n\tPisces: { col: 0, row: 0 },\n\tAries: { col: 1, row: 0 },\n\tTaurus: { col: 2, row: 0 },\n\tGemini: { col: 3, row: 0 },\n\tCancer: { col: 3, row: 1 },\n\tLeo: { col: 3, row: 2 },\n\tVirgo: { col: 3, row: 3 },\n\tLibra: { col: 2, row: 3 },\n\tScorpio: { col: 1, row: 3 },\n\tSagittarius: { col: 0, row: 3 },\n\tCapricorn: { col: 0, row: 2 },\n\tAquarius: { col: 0, row: 1 },\n};\n\nfunction southCellRect(sign: string): {\n\tx: number;\n\ty: number;\n\tw: number;\n\th: number;\n} {\n\tconst g = SOUTH_CELL_GRID[sign] ?? { col: 0, row: 0 };\n\treturn {\n\t\tx: MARGIN + g.col * SOUTH_CELL,\n\t\ty: MARGIN + g.row * SOUTH_CELL,\n\t\tw: SOUTH_CELL,\n\t\th: SOUTH_CELL,\n\t};\n}\n\n/**\n * South Indian frame: outer square, the two full-span grid lines, and the\n * partial inner lines that bound the central 2x2 hollow on each edge.\n */\nfunction renderSouthFrame(divisionLabel?: string): TemplateResult {\n\tconst a = MARGIN;\n\tconst b = MARGIN + SOUTH_CELL; // 110\n\tconst c = MARGIN + 2 * SOUTH_CELL; // 200\n\tconst d = MARGIN + 3 * SOUTH_CELL; // 290\n\tconst e = VIEW_BOX - MARGIN; // 380\n\treturn svg`\n\t\t<rect class=\"line\" x=${a} y=${a} width=${INNER} height=${INNER} stroke-width=\"1.5\" fill=\"none\" />\n\t\t<line class=\"line\" x1=${a} y1=${b} x2=${e} y2=${b} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${a} y1=${d} x2=${e} y2=${d} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${b} y1=${a} x2=${b} y2=${e} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${d} y1=${a} x2=${d} y2=${e} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${a} y1=${c} x2=${b} y2=${c} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${d} y1=${c} x2=${e} y2=${c} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${c} y1=${a} x2=${c} y2=${b} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${c} y1=${d} x2=${c} y2=${e} stroke-width=\"1\" />\n\t\t${\n\t\t\tdivisionLabel\n\t\t\t\t? svg`<text class=\"centre-label\" x=${CENTRE} y=${CENTRE} text-anchor=\"middle\" dominant-baseline=\"central\">${divisionLabel}</text>`\n\t\t\t\t: nothing\n\t\t}\n\t`;\n}\n\n/**\n * House number for a given sign relative to a Lagna sign. House 1 is the\n * Lagna cell; subsequent houses follow the zodiac in order. Returns 0 when\n * the Lagna sign is unknown so the caller can skip rendering the badge.\n */\nfunction houseNumberInSign(sign: string, lagnaSign: string): number {\n\tconst lagnaIdx = SIGNS_ORDER.findIndex((s) => s === lagnaSign);\n\tconst signIdx = SIGNS_ORDER.findIndex((s) => s === sign);\n\tif (lagnaIdx === -1 || signIdx === -1) return 0;\n\treturn ((signIdx - lagnaIdx + 12) % 12) + 1;\n}\n\nfunction renderSouthCell(\n\tsign: string,\n\tplanets: PlacedGraha[],\n\tisLagna: boolean,\n\thouseNum: number,\n): TemplateResult {\n\tconst r = southCellRect(sign);\n\tconst cx = r.x + r.w / 2;\n\tconst cy = r.y + r.h / 2;\n\tconst signAbbr = SIGN_ABBR[sign] ?? sign.slice(0, 2);\n\t// Inset the Lagna diagonal so it does not collide with the chart frame on\n\t// corner cells (Pisces, Gemini, Virgo, Sagittarius) or with the sign label\n\t// in the top-left of every cell.\n\tconst slashInset = 14;\n\treturn svg`\n\t\t<g class=${isLagna ? 'cell lagna' : 'cell'}>\n\t\t\t${\n\t\t\t\tisLagna\n\t\t\t\t\t? svg`\n\t\t\t\t\t\t<rect class=\"lagna-bg\" x=${r.x} y=${r.y} width=${r.w} height=${r.h} />\n\t\t\t\t\t\t<line class=\"lagna-slash\" x1=${r.x + r.w - slashInset} y1=${r.y + slashInset} x2=${r.x + slashInset} y2=${r.y + r.h - slashInset} stroke-width=\"1.2\" />\n\t\t\t\t\t`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t<text class=\"sign-text\" x=${r.x + 6} y=${r.y + 12} text-anchor=\"start\" dominant-baseline=\"central\">${signAbbr}</text>\n\t\t\t${\n\t\t\t\thouseNum > 0\n\t\t\t\t\t? svg`<text class=\"house-num\" x=${r.x + r.w - 6} y=${r.y + 12} text-anchor=\"end\" dominant-baseline=\"central\">${houseNum}</text>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t${\n\t\t\t\tisLagna\n\t\t\t\t\t? svg`<text class=\"lagna-marker\" x=${cx} y=${r.y + 26} text-anchor=\"middle\" dominant-baseline=\"central\">Asc</text>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t${planets.length ? renderPlanetStack(planets, sign, cx, cy + 4, 14) : nothing}\n\t\t</g>\n\t`;\n}\n\nfunction renderSouthSvg(vm: KundliViewModel): TemplateResult {\n\tconst lagnaKey = vm.lagnaSign.toLowerCase();\n\treturn svg`\n\t\t${renderSouthFrame(vm.divisionLabel)}\n\t\t${SIGNS_ORDER.map((sign) =>\n\t\t\trenderSouthCell(\n\t\t\t\tsign,\n\t\t\t\tvm.placements[sign.toLowerCase()] ?? [],\n\t\t\t\tsign.toLowerCase() === lagnaKey,\n\t\t\t\thouseNumberInSign(sign, vm.lagnaSign),\n\t\t\t),\n\t\t)}\n\t`;\n}\n\n// ---------------------------------------------------------------------------\n// North Indian: outer square + inscribed midpoint diamond + both outer\n// diagonals. 12 cells: 4 cardinal diamonds + 8 corner triangles. Houses are\n// FIXED (H1 always top-centre); signs rotate from the Lagna sign.\n// ---------------------------------------------------------------------------\n\nconst NORTH_VERTICES = {\n\ttl: { x: MARGIN, y: MARGIN },\n\ttr: { x: VIEW_BOX - MARGIN, y: MARGIN },\n\tbr: { x: VIEW_BOX - MARGIN, y: VIEW_BOX - MARGIN },\n\tbl: { x: MARGIN, y: VIEW_BOX - MARGIN },\n\ttop: { x: CENTRE, y: MARGIN },\n\tright: { x: VIEW_BOX - MARGIN, y: CENTRE },\n\tbottom: { x: CENTRE, y: VIEW_BOX - MARGIN },\n\tleft: { x: MARGIN, y: CENTRE },\n\ttlMid: { x: CENTRE - INNER / 4, y: CENTRE - INNER / 4 },\n\ttrMid: { x: CENTRE + INNER / 4, y: CENTRE - INNER / 4 },\n\tbrMid: { x: CENTRE + INNER / 4, y: CENTRE + INNER / 4 },\n\tblMid: { x: CENTRE - INNER / 4, y: CENTRE + INNER / 4 },\n} as const;\n\n/**\n * Centroid (geometric mean) of an arbitrary set of polygon vertices. Used by\n * every cell that needs a label-anchor point; defining it once keeps the\n * North diamond and East triangle math identical.\n */\nfunction centroidOf(pts: Array<{ x: number; y: number }>): {\n\tx: number;\n\ty: number;\n} {\n\tconst x = pts.reduce((s, p) => s + p.x, 0) / pts.length;\n\tconst y = pts.reduce((s, p) => s + p.y, 0) / pts.length;\n\treturn { x, y };\n}\n\n/**\n * House centres for the North Indian diamond. Numbered 1..12 counter-clockwise\n * from the top diamond (H1 is always the ascendant cell). Centroids derived\n * from the canonical geometry above; do not edit by eye, recompute if you\n * change `VIEW_BOX` or `MARGIN`.\n */\nconst NORTH_HOUSE_CENTERS: Record<number, { x: number; y: number }> = {\n\t1: { x: CENTRE, y: NORTH_VERTICES.tlMid.y },\n\t2: centroidOf([NORTH_VERTICES.tl, NORTH_VERTICES.top, NORTH_VERTICES.tlMid]),\n\t3: centroidOf([NORTH_VERTICES.tl, NORTH_VERTICES.left, NORTH_VERTICES.tlMid]),\n\t4: { x: NORTH_VERTICES.tlMid.x, y: CENTRE },\n\t5: centroidOf([NORTH_VERTICES.bl, NORTH_VERTICES.left, NORTH_VERTICES.blMid]),\n\t6: centroidOf([\n\t\tNORTH_VERTICES.bl,\n\t\tNORTH_VERTICES.bottom,\n\t\tNORTH_VERTICES.blMid,\n\t]),\n\t7: { x: CENTRE, y: NORTH_VERTICES.blMid.y },\n\t8: centroidOf([\n\t\tNORTH_VERTICES.br,\n\t\tNORTH_VERTICES.bottom,\n\t\tNORTH_VERTICES.brMid,\n\t]),\n\t9: centroidOf([\n\t\tNORTH_VERTICES.br,\n\t\tNORTH_VERTICES.right,\n\t\tNORTH_VERTICES.brMid,\n\t]),\n\t10: { x: NORTH_VERTICES.brMid.x, y: CENTRE },\n\t11: centroidOf([\n\t\tNORTH_VERTICES.tr,\n\t\tNORTH_VERTICES.right,\n\t\tNORTH_VERTICES.trMid,\n\t]),\n\t12: centroidOf([NORTH_VERTICES.tr, NORTH_VERTICES.top, NORTH_VERTICES.trMid]),\n};\n\n/**\n * Rashi number (1..12, Aries=1) occupying the given house when the Lagna sits\n * in `lagnaSign`. House 1 is the Lagna sign; subsequent houses follow the\n * zodiac in order.\n */\nfunction rashiInHouse(houseNum: number, lagnaSign: string): number {\n\tconst lagnaIdx = SIGNS_ORDER.findIndex((s) => s === lagnaSign);\n\tif (lagnaIdx === -1) return houseNum;\n\treturn ((lagnaIdx + houseNum - 1) % 12) + 1;\n}\n\nfunction renderNorthFrame(divisionLabel?: string): TemplateResult {\n\tconst { tl, tr, br, bl, top, right, bottom, left } = NORTH_VERTICES;\n\treturn svg`\n\t\t<rect class=\"line\" x=${tl.x} y=${tl.y} width=${INNER} height=${INNER} stroke-width=\"1.5\" fill=\"none\" />\n\t\t<polygon class=\"line\" points=\"${top.x},${top.y} ${right.x},${right.y} ${bottom.x},${bottom.y} ${left.x},${left.y}\" stroke-width=\"1\" fill=\"none\" />\n\t\t<line class=\"line\" x1=${tl.x} y1=${tl.y} x2=${br.x} y2=${br.y} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${tr.x} y1=${tr.y} x2=${bl.x} y2=${bl.y} stroke-width=\"1\" />\n\t\t${\n\t\t\tdivisionLabel\n\t\t\t\t? svg`<text class=\"centre-label\" x=${CENTRE} y=${CENTRE} text-anchor=\"middle\" dominant-baseline=\"central\">${divisionLabel}</text>`\n\t\t\t\t: nothing\n\t\t}\n\t`;\n}\n\nfunction renderNorthCell(\n\thouseNum: number,\n\trashiNum: number,\n\tsign: string,\n\tplanets: PlacedGraha[],\n\tisLagna: boolean,\n): TemplateResult {\n\tconst c = NORTH_HOUSE_CENTERS[houseNum];\n\tif (!c) return svg``;\n\t// Tight cells (H2/3/5/6/8/9/11/12 corner triangles) clip the rasi number\n\t// when it sits too high above the centroid. Clamp the upward offset based\n\t// on the cell's distance from the chart vertical centre so the label\n\t// always stays comfortably inside its triangle or diamond.\n\tconst rashiOffsetY = Math.min(14, Math.abs(c.y - CENTRE) * 0.45 + 6);\n\tconst ascOffsetY = rashiOffsetY + 12;\n\t// North cells carry only a rasi number by convention. The ascendant also\n\t// names its sign so the reader can see which sign rises without translating\n\t// the number; other cells stay number-only.\n\tconst rashiLabel = isLagna\n\t\t? `${rashiNum} \u00B7 ${SIGN_ABBR[sign] ?? sign.slice(0, 2)}`\n\t\t: `${rashiNum}`;\n\treturn svg`\n\t\t<g class=${isLagna ? 'cell lagna' : 'cell'}>\n\t\t\t<text class=\"rashi-num\" x=${c.x} y=${c.y - rashiOffsetY} text-anchor=\"middle\" dominant-baseline=\"central\">${rashiLabel}</text>\n\t\t\t${\n\t\t\t\tisLagna\n\t\t\t\t\t? svg`<text class=\"lagna-marker\" x=${c.x} y=${c.y - ascOffsetY} text-anchor=\"middle\" dominant-baseline=\"central\">Asc</text>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t${planets.length ? renderPlanetStack(planets, sign, c.x, c.y + 8, 12) : nothing}\n\t\t</g>\n\t`;\n}\n\nfunction renderNorthSvg(vm: KundliViewModel): TemplateResult {\n\tconst lagnaSign = vm.lagnaSign || 'Aries';\n\treturn svg`\n\t\t${renderNorthFrame(vm.divisionLabel)}\n\t\t${Array.from({ length: 12 }, (_, i) => {\n\t\t\tconst houseNum = i + 1;\n\t\t\tconst rashiNum = rashiInHouse(houseNum, lagnaSign);\n\t\t\tconst sign = SIGNS_ORDER[rashiNum - 1] ?? 'Aries';\n\t\t\treturn renderNorthCell(\n\t\t\t\thouseNum,\n\t\t\t\trashiNum,\n\t\t\t\tsign,\n\t\t\t\tvm.placements[sign.toLowerCase()] ?? [],\n\t\t\t\thouseNum === 1,\n\t\t\t);\n\t\t})}\n\t`;\n}\n\n// ---------------------------------------------------------------------------\n// East Indian (Bengali / Maithili): 3x3 underlying grid, 4 edge rectangles +\n// 4 corner cells each split by a diagonal from the outer chart corner to the\n// inner corner of the centre cell. Aries fixed top-centre; signs proceed\n// counter-clockwise. Houses rotate from the Lagna.\n// ---------------------------------------------------------------------------\n\nconst EAST_CELL = INNER / 3; // 120\n\ninterface EastCell {\n\t/** Vertices of the cell polygon, in viewBox units. */\n\tpoints: Array<{ x: number; y: number }>;\n\t/** Visual centroid for label placement. */\n\tcentroid: { x: number; y: number };\n}\n\nfunction eastCells(): Record<string, EastCell> {\n\tconst a = MARGIN; // 20\n\tconst b = MARGIN + EAST_CELL; // 140\n\tconst c = MARGIN + 2 * EAST_CELL; // 260\n\tconst d = VIEW_BOX - MARGIN; // 380\n\tconst aries = [\n\t\t{ x: b, y: a },\n\t\t{ x: c, y: a },\n\t\t{ x: c, y: b },\n\t\t{ x: b, y: b },\n\t];\n\tconst cancer = [\n\t\t{ x: a, y: b },\n\t\t{ x: b, y: b },\n\t\t{ x: b, y: c },\n\t\t{ x: a, y: c },\n\t];\n\tconst libra = [\n\t\t{ x: b, y: c },\n\t\t{ x: c, y: c },\n\t\t{ x: c, y: d },\n\t\t{ x: b, y: d },\n\t];\n\tconst capricorn = [\n\t\t{ x: c, y: b },\n\t\t{ x: d, y: b },\n\t\t{ x: d, y: c },\n\t\t{ x: c, y: c },\n\t];\n\tconst taurus = [\n\t\t{ x: a, y: a },\n\t\t{ x: b, y: a },\n\t\t{ x: b, y: b },\n\t];\n\tconst gemini = [\n\t\t{ x: a, y: a },\n\t\t{ x: b, y: b },\n\t\t{ x: a, y: b },\n\t];\n\tconst leo = [\n\t\t{ x: a, y: c },\n\t\t{ x: b, y: c },\n\t\t{ x: a, y: d },\n\t];\n\tconst virgo = [\n\t\t{ x: b, y: c },\n\t\t{ x: b, y: d },\n\t\t{ x: a, y: d },\n\t];\n\tconst scorpio = [\n\t\t{ x: c, y: c },\n\t\t{ x: c, y: d },\n\t\t{ x: d, y: d },\n\t];\n\tconst sagittarius = [\n\t\t{ x: c, y: c },\n\t\t{ x: d, y: d },\n\t\t{ x: d, y: c },\n\t];\n\tconst aquarius = [\n\t\t{ x: d, y: a },\n\t\t{ x: d, y: b },\n\t\t{ x: c, y: b },\n\t];\n\tconst pisces = [\n\t\t{ x: c, y: a },\n\t\t{ x: d, y: a },\n\t\t{ x: c, y: b },\n\t];\n\tconst polys = {\n\t\tAries: aries,\n\t\tTaurus: taurus,\n\t\tGemini: gemini,\n\t\tCancer: cancer,\n\t\tLeo: leo,\n\t\tVirgo: virgo,\n\t\tLibra: libra,\n\t\tScorpio: scorpio,\n\t\tSagittarius: sagittarius,\n\t\tCapricorn: capricorn,\n\t\tAquarius: aquarius,\n\t\tPisces: pisces,\n\t} as const;\n\tconst out: Record<string, EastCell> = {};\n\tfor (const [sign, points] of Object.entries(polys)) {\n\t\tout[sign] = { points: [...points], centroid: centroidOf(points) };\n\t}\n\treturn out;\n}\n\nconst EAST_CELLS = eastCells();\n\nfunction renderEastFrame(divisionLabel?: string): TemplateResult {\n\tconst a = MARGIN;\n\tconst b = MARGIN + EAST_CELL;\n\tconst c = MARGIN + 2 * EAST_CELL;\n\tconst d = VIEW_BOX - MARGIN;\n\treturn svg`\n\t\t<rect class=\"line\" x=${a} y=${a} width=${INNER} height=${INNER} stroke-width=\"1.5\" fill=\"none\" />\n\t\t<line class=\"line\" x1=${a} y1=${b} x2=${b} y2=${b} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${c} y1=${b} x2=${d} y2=${b} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${a} y1=${c} x2=${b} y2=${c} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${c} y1=${c} x2=${d} y2=${c} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${b} y1=${a} x2=${b} y2=${b} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${b} y1=${c} x2=${b} y2=${d} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${c} y1=${a} x2=${c} y2=${b} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${c} y1=${c} x2=${c} y2=${d} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${a} y1=${a} x2=${b} y2=${b} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${d} y1=${a} x2=${c} y2=${b} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${d} y1=${d} x2=${c} y2=${c} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${a} y1=${d} x2=${b} y2=${c} stroke-width=\"1\" />\n\t\t${\n\t\t\tdivisionLabel\n\t\t\t\t? svg`<text class=\"centre-label\" x=${CENTRE} y=${CENTRE} text-anchor=\"middle\" dominant-baseline=\"central\">${divisionLabel}</text>`\n\t\t\t\t: nothing\n\t\t}\n\t`;\n}\n\nfunction renderEastCell(\n\tsign: string,\n\tplanets: PlacedGraha[],\n\tisLagna: boolean,\n\thouseNum: number,\n): TemplateResult {\n\tconst cell = EAST_CELLS[sign];\n\tif (!cell) return svg``;\n\tconst { centroid: cen, points } = cell;\n\tconst signAbbr = SIGN_ABBR[sign] ?? sign.slice(0, 2);\n\tconst polyPoints = points.map((p) => `${p.x},${p.y}`).join(' ');\n\treturn svg`\n\t\t<g class=${isLagna ? 'cell lagna' : 'cell'}>\n\t\t\t${\n\t\t\t\tisLagna\n\t\t\t\t\t? svg`<polygon class=\"lagna-bg\" points=${polyPoints} />`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t<text class=\"sign-text\" x=${cen.x} y=${cen.y - 16} text-anchor=\"middle\" dominant-baseline=\"central\">${signAbbr}</text>\n\t\t\t${\n\t\t\t\thouseNum > 0\n\t\t\t\t\t? svg`<text class=\"house-num\" x=${cen.x + 18} y=${cen.y - 16} text-anchor=\"start\" dominant-baseline=\"central\">${houseNum}</text>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t${\n\t\t\t\tisLagna\n\t\t\t\t\t? svg`<text class=\"lagna-marker\" x=${cen.x} y=${cen.y - 30} text-anchor=\"middle\" dominant-baseline=\"central\">Asc</text>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t${planets.length ? renderPlanetStack(planets, sign, cen.x, cen.y + 4, 12) : nothing}\n\t\t</g>\n\t`;\n}\n\nfunction renderEastSvg(vm: KundliViewModel): TemplateResult {\n\tconst lagnaKey = vm.lagnaSign.toLowerCase();\n\treturn svg`\n\t\t${renderEastFrame(vm.divisionLabel)}\n\t\t${SIGNS_ORDER.map((sign) =>\n\t\t\trenderEastCell(\n\t\t\t\tsign,\n\t\t\t\tvm.placements[sign.toLowerCase()] ?? [],\n\t\t\t\tsign.toLowerCase() === lagnaKey,\n\t\t\t\thouseNumberInSign(sign, vm.lagnaSign),\n\t\t\t),\n\t\t)}\n\t`;\n}\n\n// ---------------------------------------------------------------------------\n// Public entry point\n// ---------------------------------------------------------------------------\n\n/**\n * Render the kundli body for the requested style. Returns the SVG inner\n * content; the caller wraps it in an `<svg>` element with the canonical\n * viewBox `0 0 400 400` and applies its own theming CSS.\n */\nexport function renderKundliSvg(\n\tvm: KundliViewModel,\n\tstyle: ChartStyle,\n): TemplateResult {\n\tswitch (style) {\n\t\tcase 'north':\n\t\t\treturn renderNorthSvg(vm);\n\t\tcase 'east':\n\t\t\treturn renderEastSvg(vm);\n\t\tdefault:\n\t\t\treturn renderSouthSvg(vm);\n\t}\n}\n\n/**\n * Render a WAI-ARIA-compliant tablist that lets the end user switch between\n * South / North / East kundli styles at runtime. The hosting component owns\n * the `chartStyle` state; this helper renders the buttons and wires the\n * arrow-key navigation plus click handler.\n *\n * @param active - The currently selected style.\n * @param setStyle - Callback the host component uses to update its state.\n */\nexport function renderKundliStyleTablist(\n\tactive: ChartStyle,\n\tsetStyle: (next: ChartStyle) => void,\n): TemplateResult {\n\treturn renderTablist({\n\t\titems: CHART_STYLES,\n\t\tactive,\n\t\tonSelect: setStyle,\n\t\tlabel: 'Kundli style',\n\t\tidPrefix: 'kundli',\n\t});\n}\n", "/**\n * Math helpers for converting raw ecliptic longitude decimals into the\n * sign / degree / minute / second triplet used across chart components.\n */\n\nimport { SIGNS_ORDER } from '../tokens/index.js';\n\nexport interface SignPosition {\n\tsign: string;\n\tsignIndex: number;\n\tdegree: number;\n\tminute: number;\n\tsecond: number;\n}\n\n/**\n * Wrap longitude into [0, 360) so negative or out-of-range values still\n * resolve to a real sign. Robust to wonky upstream data.\n */\nexport function normalizeLongitude(lon: number): number {\n\tconst wrapped = lon % 360;\n\treturn wrapped < 0 ? wrapped + 360 : wrapped;\n}\n\n/**\n * Convert decimal ecliptic longitude (0-360) into sign/degree/minute/second.\n * Used by every chart wheel and aspect table.\n */\nexport function longitudeToSignPosition(longitude: number): SignPosition {\n\tconst lon = normalizeLongitude(longitude);\n\tconst signIndex = Math.floor(lon / 30) % 12;\n\tconst within = lon % 30;\n\tconst degree = Math.floor(within);\n\tconst minuteFloat = (within - degree) * 60;\n\tconst minute = Math.floor(minuteFloat);\n\tconst second = Math.round((minuteFloat - minute) * 60);\n\treturn {\n\t\tsign: SIGNS_ORDER[signIndex] ?? 'Aries',\n\t\tsignIndex,\n\t\tdegree,\n\t\tminute,\n\t\tsecond,\n\t};\n}\n\n/** Compact display string like \"12\u00B0 Leo 34'\". Used in chart labels. */\nexport function formatSignPosition(longitude: number): string {\n\tconst { sign, degree, minute } = longitudeToSignPosition(longitude);\n\treturn `${degree}\u00B0 ${sign} ${String(minute).padStart(2, '0')}'`;\n}\n\n/**\n * The point diametrically opposite a longitude (e.g. Descendant from\n * Ascendant, IC from MC). Exact derivation, always 180 degrees away.\n */\nexport function oppositePoint(longitude: number): number {\n\treturn normalizeLongitude(longitude + 180);\n}\n\n/**\n * Midpoint of the forward arc from `start` to `end` (both ecliptic\n * longitudes). Handles the 360/0 wrap, so a house spanning 350 to 20 degrees\n * yields a midpoint of 5, not 185. Used to place house numbers between two\n * cusps regardless of how unequal the house is.\n */\nexport function arcMidpoint(start: number, end: number): number {\n\tconst s = normalizeLongitude(start);\n\tlet span = normalizeLongitude(end) - s;\n\tif (span < 0) span += 360;\n\treturn normalizeLongitude(s + span / 2);\n}\n\n/** Polar to cartesian for SVG wheel positioning. Angle in degrees, 0 at 3 o'clock. */\nexport function polarToCartesian(\n\tcx: number,\n\tcy: number,\n\tradius: number,\n\tangleDeg: number,\n): { x: number; y: number } {\n\tconst angleRad = (angleDeg * Math.PI) / 180;\n\treturn {\n\t\tx: cx + radius * Math.cos(angleRad),\n\t\ty: cy + radius * Math.sin(angleRad),\n\t};\n}\n", "import type { TemplateResult } from 'lit';\nimport { css, html, nothing } from 'lit';\n\n/** A single tab in a {@link renderTablist} strip. */\nexport interface TablistItem<T extends string = string> {\n\tid: T;\n\tlabel: string;\n}\n\n/**\n * Shared styling for every horizontal tab strip in the library (natal chart\n * views, transits, kundli styles). Keeping one rule set means the tabs look\n * identical everywhere and theme through the same --roxy-* tokens.\n */\nexport const tablistStyles = css`.roxy-tablist{border-bottom:2px solid var(--roxy-border,#e4e4e7);gap:2px;display:flex}.roxy-tab{padding:var(--roxy-space-xs,.25rem) var(--roxy-space-md,1rem);font-size:var(--roxy-text-sm,.875rem);cursor:pointer;color:var(--roxy-muted,#71717a);transition:color var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,ease);background:0 0;border:none;border-bottom:2px solid #0000;margin-bottom:-2px;font-family:inherit}.roxy-tab[aria-selected=true]{color:var(--roxy-accent-ink,#b45309);border-bottom-color:var(--roxy-accent,#f59e0b);font-weight:var(--roxy-weight-bold,600)}.roxy-tab:hover:not([aria-selected=true]){color:var(--roxy-fg,#0a0a0a)}.roxy-tab:focus-visible{outline:2px solid var(--roxy-ring,#f59e0b66);outline-offset:2px;border-radius:4px}`;\n\n/**\n * Render a WAI-ARIA tablist. The host component owns the active-tab state; this\n * helper draws the buttons, wires click plus Left/Right arrow navigation with a\n * roving tabindex, and moves focus to the newly selected tab. Pair with\n * {@link tablistStyles}.\n *\n * Pass `controls: true` when each tab governs a sibling\n * `<div role=\"tabpanel\" id=\"${idPrefix}-panel-${id}\">` so the buttons advertise\n * `aria-controls`. Omit it for tablists that swap a single rendered view in\n * place with no separate panel element (the kundli style switch).\n *\n * @example\n * ```ts\n * renderTablist({\n * items: [{ id: 'wheel', label: 'Wheel' }, { id: 'grid', label: 'Aspect grid' }],\n * active: this.view,\n * onSelect: (v) => { this.view = v; },\n * label: 'Natal chart views',\n * idPrefix: 'natal',\n * controls: true,\n * })\n * ```\n */\nexport function renderTablist<T extends string>(opts: {\n\titems: ReadonlyArray<TablistItem<T>>;\n\tactive: T;\n\tonSelect: (id: T) => void;\n\tlabel: string;\n\tidPrefix: string;\n\tcontrols?: boolean;\n}): TemplateResult {\n\tconst { items, active, onSelect, label, idPrefix, controls = false } = opts;\n\tconst onKeyDown = (e: KeyboardEvent) => {\n\t\tif (e.key !== 'ArrowRight' && e.key !== 'ArrowLeft') return;\n\t\te.preventDefault();\n\t\tconst idx = items.findIndex((it) => it.id === active);\n\t\tif (idx === -1) return;\n\t\tconst delta = e.key === 'ArrowRight' ? 1 : -1;\n\t\tconst next = items[(idx + delta + items.length) % items.length];\n\t\tif (!next) return;\n\t\tonSelect(next.id);\n\t\tconst root = (e.currentTarget as HTMLElement).getRootNode() as\n\t\t\t| ShadowRoot\n\t\t\t| Document;\n\t\trequestAnimationFrame(() => {\n\t\t\troot\n\t\t\t\t.querySelector<HTMLButtonElement>(`#${idPrefix}-tab-${next.id}`)\n\t\t\t\t?.focus();\n\t\t});\n\t};\n\treturn html`<div class=\"roxy-tablist\" role=\"tablist\" aria-label=\"${label}\" @keydown=\"${onKeyDown}\">${items.map(\n\t\t\t(it) => html`<button type=\"button\" class=\"roxy-tab\" role=\"tab\" id=\"${idPrefix}-tab-${it.id}\" aria-selected=\"${active === it.id ? 'true' : 'false'}\" aria-controls=\"${\n\t\t\t\t\t// Only the active panel is rendered, so only the active tab points\n\t\t\t\t\t// at a live element; otherwise aria-controls would dangle.\n\t\t\t\t\tcontrols && active === it.id ? `${idPrefix}-panel-${it.id}` : nothing\n\t\t\t\t}\" tabindex=\"${active === it.id ? '0' : '-1'}\" @click=\"${() => onSelect(it.id)}\">${it.label}</button>`,\n\t\t)}</div>`;\n}\n", "import { css } from 'lit';\n\n/**\n * Shared CSS for every kundli renderer (`<roxy-vedic-kundli>`,\n * `<roxy-divisional-chart>`, and any future `<roxy-navamsa-chart>`). Centralises\n * the SVG layout (responsive viewBox + aspect ratio), the line/text classes,\n * and the Lagna highlight so the three components stay visually identical.\n *\n * @remarks Font sizes are written in viewBox user units (the chart is 400\u00D7400\n * inside a 1:1 aspect-ratio container), so they scale linearly from a 320px\n * phone surface to a wall projector without raster loss. The Lagna palette\n * tracks `--roxy-accent` so host themes flow through unchanged.\n */\nexport const kundliStyles = css`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.header{justify-content:space-between;align-items:center;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}svg{width:100%;max-width:var(--roxy-chart-max-width,560px);aspect-ratio:1;height:auto;margin:0 auto;display:block}.line{fill:#0000;stroke:var(--roxy-border,#d4d4d8)}.sign-text{fill:var(--roxy-muted,#71717a);font-size:11px;font-weight:500;font-family:var(--roxy-font-sans);text-transform:uppercase;letter-spacing:.04em}.rashi-num{fill:var(--roxy-muted,#71717a);font-size:12px;font-weight:500;font-family:var(--roxy-font-sans)}.house-num{fill:var(--roxy-accent-ink,#b45309);font-size:11px;font-weight:600;font-family:var(--roxy-font-sans);opacity:.85}.planet-text{fill:var(--roxy-fg,#0a0a0a);font-size:13px;font-weight:600;font-family:var(--roxy-font-sans)}.centre-label{fill:var(--roxy-muted,#71717a);font-size:14px;font-weight:600;font-family:var(--roxy-font-sans);letter-spacing:.02em}.lagna-marker{fill:var(--roxy-accent-ink,#b45309);font-size:10px;font-weight:700;font-family:var(--roxy-font-sans);letter-spacing:.08em;text-transform:uppercase}.lagna-bg{fill:color-mix(in srgb, var(--roxy-accent,#f59e0b) 14%, transparent)}.lagna-slash{stroke:var(--roxy-accent,#f59e0b);stroke-linecap:round;opacity:.7}`;\n", "import { css, html, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type {\n\tKalsarpaResponse,\n\tManglikResponse,\n\tSadhesatiResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\ntype DoshaData = ManglikResponse | KalsarpaResponse | SadhesatiResponse;\n\nconst DOSHA_LABELS: Record<string, string> = {\n\tmanglik: 'Mangal Dosha',\n\tkalsarpa: 'Kaal Sarp Dosha',\n\tsadhesati: 'Sade Sati',\n};\n\n/**\n * Dosha presence card. Renders /vedic-astrology/dosha/{manglik,kalsarpa,sadhesati}.\n * Visual severity indicator + remedies + scoped effects.\n */\n@customElement('roxy-dosha-card')\nexport class RoxyDoshaCard extends RoxyDataElement<DoshaData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.card{background:var(--roxy-surface,#fff);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:center;gap:var(--roxy-space-md,1rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);text-transform:capitalize;margin:0}.badge{align-items:center;gap:var(--roxy-space-xs,.25rem);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;letter-spacing:.06em;padding:4px 10px;display:inline-flex}.badge.absent{background:color-mix(in srgb, var(--roxy-success,#16a34a) 16%, transparent);color:var(--roxy-success-fg,#166534)}.badge.present{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 16%, transparent);color:var(--roxy-danger-fg,#991b1b)}.severity-bar{background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 30%, transparent);border-radius:4px;width:100%;height:8px;position:relative;overflow:hidden}.severity-fill{height:100%;transition:width var(--roxy-motion-duration,.2s) ease-out;border-radius:4px;display:block}@media (prefers-reduced-motion:reduce){.severity-fill{transition:none}}.description{color:var(--roxy-fg,#0a0a0a);margin:0}h3{margin:0 0 var(--roxy-space-xs,.25rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em}ul{padding-left:var(--roxy-space-md,1rem);font-size:var(--roxy-text-sm,.875rem);margin:0}.effects{gap:var(--roxy-space-md,1rem);grid-template-columns:repeat(auto-fit,minmax(12rem,1fr));display:grid}.effects p{font-size:var(--roxy-text-sm,.875rem);margin:0}`,\n\t];\n\n\t@property({ type: String, reflect: true })\n\ttype: 'manglik' | 'kalsarpa' | 'sadhesati' | string = 'manglik';\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No dosha data</div>`;\n\t}\n\n\tprotected renderData(d: DoshaData) {\n\t\tconst present = !!d.present;\n\t\tconst label = DOSHA_LABELS[this.type] ?? this.type;\n\t\tconst sevLower = (d.severity ?? '').toLowerCase();\n\t\tconst tier =\n\t\t\tsevLower === 'severe'\n\t\t\t\t? 3\n\t\t\t\t: sevLower === 'moderate'\n\t\t\t\t\t? 2\n\t\t\t\t\t: sevLower === 'mild'\n\t\t\t\t\t\t? 1\n\t\t\t\t\t\t: 0;\n\t\tconst pct = tier * 33;\n\t\tconst barColor =\n\t\t\ttier === 3\n\t\t\t\t? 'var(--roxy-danger)'\n\t\t\t\t: tier === 2\n\t\t\t\t\t? 'var(--roxy-warning)'\n\t\t\t\t\t: tier === 1\n\t\t\t\t\t\t? 'var(--roxy-success)'\n\t\t\t\t\t\t: 'transparent';\n\n\t\treturn html`<article class=\"card\" aria-label=\"${label}\"><header class=\"head\"><h2 class=\"title\">${label}</h2><span class=\"${`badge ${present ? 'present' : 'absent'}`}\">${present ? 'Present' : 'Absent'}</span></header>${\n\t\t\t\td.severity\n\t\t\t\t\t? html`<div class=\"severity-bar\" role=\"meter\" aria-valuemin=\"0\" aria-valuemax=\"3\" aria-valuenow=\"${tier}\" aria-label=\"Severity ${d.severity}\"><span class=\"severity-fill\" style=\"width:${pct}%;background:${barColor}\"></span></div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${d.description ? html`<p class=\"description\">${d.description}</p>` : nothing} ${this.renderEffects(d)} ${\n\t\t\t\td.remedies && d.remedies.length > 0\n\t\t\t\t\t? html`<div><h3>Remedies</h3><ul>${d.remedies.map((r) => html`<li>${r}</li>`)}</ul></div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\t'exceptions' in d && d.exceptions && d.exceptions.length > 0\n\t\t\t\t\t? html`<div><h3>Exceptions</h3><ul>${d.exceptions.map((r) => html`<li>${r}</li>`)}</ul></div>`\n\t\t\t\t\t: nothing\n\t\t\t}</article>`;\n\t}\n\n\tprivate renderEffects(d: DoshaData) {\n\t\tif (!d.effects) return nothing;\n\t\tconst entries = Object.entries(d.effects).filter(\n\t\t\t([, v]) => typeof v === 'string' && v.length > 0,\n\t\t);\n\t\tif (entries.length === 0) return nothing;\n\t\treturn html`<div class=\"effects\">${entries.map(\n\t\t\t\t([k, v]) => html`<div><h3>${k}</h3><p>${v}</p></div>`,\n\t\t\t)}</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-dosha-card': RoxyDoshaCard;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { GetDreamSymbolResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\n/**\n * Dream symbol card. Renders /dreams/symbols/{id}: the symbol name as a heading, the full psychological interpretation as the body, and the dictionary letter as a chip for alphabetical context.\n */\n@customElement('roxy-dream-card')\nexport class RoxyDreamCard extends RoxyDataElement<GetDreamSymbolResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.card{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{align-items:center;gap:var(--roxy-space-md,1rem);display:flex}.letter{border-radius:var(--roxy-radius-full,9999px);background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 16%, transparent);width:2.5rem;height:2.5rem;color:var(--roxy-accent-ink,#b45309);font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;font-variant-numeric:tabular-nums;flex:none;justify-content:center;align-items:center;display:inline-flex}.label{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;margin:0}.name{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-fg,#0a0a0a);margin:0}.meaning{color:var(--roxy-fg,#0a0a0a);margin:0;line-height:1.6}`,\n\t];\n\n\tprotected renderData(d: GetDreamSymbolResponse) {\n\t\treturn html`<article class=\"card\" aria-label=\"${d.name ?? 'Dream symbol'}\"><header class=\"head\">${d.letter ? html`<span class=\"letter\" aria-hidden=\"true\">${d.letter}</span>` : nothing}<div><p class=\"label\">Dream symbol</p>${d.name ? html`<h2 class=\"name\">${d.name}</h2>` : nothing}</div></header>${d.meaning ? html`<p class=\"meaning\">${d.meaning}</p>` : nothing}</article>`;\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No dream symbol</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-dream-card': RoxyDreamCard;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { SearchDreamSymbolsResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\ntype DreamSymbol = NonNullable<SearchDreamSymbolsResponse['symbols']>[number];\n\n/**\n * Dream-symbol search results. Renders /dreams/symbols (the `q` search): the matched symbols as selectable tiles. In self-fetch mode the base renders the search input and this lists the matches. Selecting a result emits a `roxy-symbol-select` CustomEvent ({ id, name, letter }) that bubbles and is composed, so a host pairs it with a roxy-dream-card to show the full meaning. This is the dreams form-mode analog of roxy-location-search.\n */\n@customElement('roxy-dream-search')\nexport class RoxyDreamSearch extends RoxyDataElement<SearchDreamSymbolsResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-md,1rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.count{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}.grid{gap:var(--roxy-space-sm,.5rem);grid-template-columns:repeat(auto-fill,minmax(8rem,1fr));margin:0;padding:0;list-style:none;display:grid}.result{align-items:center;gap:var(--roxy-space-sm,.5rem);text-align:left;width:100%;font:inherit;color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);cursor:pointer;background:0 0;transition:border-color .12s,background .12s;display:flex}.result:hover,.result:focus-visible{border-color:var(--roxy-accent,#f59e0b);background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 8%, transparent);outline:none}.letter{border-radius:var(--roxy-radius-full,9999px);background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 16%, transparent);width:1.6rem;height:1.6rem;color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;flex:none;place-items:center;display:grid}.name{font-size:var(--roxy-text-sm,.875rem);font-weight:500}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No symbols match</div>`;\n\t}\n\n\tprotected renderData(d: SearchDreamSymbolsResponse) {\n\t\tconst symbols = d.symbols ?? [];\n\t\tif (symbols.length === 0) return this.renderEmpty();\n\t\tconst total = typeof d.total === 'number' ? d.total : symbols.length;\n\n\t\treturn html`<section class=\"wrap\" aria-label=\"Dream symbols\"><header class=\"head\"><h2 class=\"title\">Dream Symbols</h2><span class=\"count\">${total} match${total === 1 ? '' : 'es'}</span></header><ul class=\"grid\">${symbols.map(\n\t\t\t\t\t(s) => html`<li><button type=\"button\" class=\"result\" @click=\"${() => this.select(s)}\">${s.letter ? html`<span class=\"letter\" aria-hidden=\"true\">${s.letter}</span>` : nothing} <span class=\"name\">${s.name}</span></button></li>`,\n\t\t\t\t)}</ul></section>`;\n\t}\n\n\t/** Emit the chosen symbol so a host can load its detail (e.g. into a roxy-dream-card). */\n\tprivate select(s: DreamSymbol) {\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('roxy-symbol-select', {\n\t\t\t\tdetail: { id: s.id, name: s.name, letter: s.letter },\n\t\t\t\tbubbles: true,\n\t\t\t\tcomposed: true,\n\t\t\t}),\n\t\t);\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-dream-search': RoxyDreamSearch;\n\t}\n}\n", "import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { humanize } from '../utils/string.js';\n\ninterface OpenApiSchemaRef {\n\t$ref?: string;\n}\n\ninterface OpenApiSchema extends OpenApiSchemaRef {\n\ttype?: string;\n\tformat?: string;\n\tdescription?: string;\n\tenum?: string[];\n\tdefault?: unknown;\n\tminimum?: number;\n\tmaximum?: number;\n\tproperties?: Record<string, OpenApiSchema>;\n\trequired?: string[];\n\titems?: OpenApiSchema;\n\texample?: unknown;\n}\n\ninterface FieldDef {\n\t/** Unique storage + input key: the property name, or \"group.name\" for a nested object field. */\n\tkey: string;\n\t/** Schema property name (the label source), e.g. \"date\". */\n\tname: string;\n\t/** Parent object key for a nested schema (person1/person2); undefined for a flat field. */\n\tgroup?: string;\n\ttype: string;\n\trequired: boolean;\n\tdescription?: string;\n\tenum?: string[];\n\tmin?: number;\n\tmax?: number;\n\tdefault?: unknown;\n}\n\ninterface OpenApiDoc {\n\tpaths?: Record<string, Record<string, unknown>>;\n\tcomponents?: { schemas?: Record<string, OpenApiSchema> };\n}\n\nconst specCache = new Map<string, Promise<OpenApiDoc>>();\n\nasync function loadSpec(url: string): Promise<OpenApiDoc> {\n\tlet pending = specCache.get(url);\n\tif (!pending) {\n\t\tpending = fetch(url)\n\t\t\t.then(async (res) => {\n\t\t\t\tif (!res.ok) throw new Error(`HTTP ${res.status}`);\n\t\t\t\treturn (await res.json()) as OpenApiDoc;\n\t\t\t})\n\t\t\t.catch((err) => {\n\t\t\t\t// Evict the rejected promise BEFORE rethrowing so subsequent\n\t\t\t\t// callers (the user clicking Retry, a remount) hit the network\n\t\t\t\t// again instead of replaying the cached failure forever.\n\t\t\t\tspecCache.delete(url);\n\t\t\t\tthrow err;\n\t\t\t});\n\t\tspecCache.set(url, pending);\n\t}\n\treturn pending;\n}\n\n/**\n * Schema-driven form. Pass `endpoint` (e.g. \"vedic-astrology/birth-chart\").\n * The form introspects the cached OpenAPI spec, slots a roxy-location-search\n * when latitude+longitude+timezone fields are present, and emits a\n * `roxy-submit` CustomEvent with the validated payload on submit. The caller\n * decides what to do (call the SDK, render a chart, navigate).\n *\n * At runtime the component fetches the OpenAPI spec (its `spec-url`, default\n * /api/v2/openapi.json) and builds the fields from the operation's request\n * schema: types, enums, required flags, and property order all come from the\n * spec, so a new endpoint gets a working form with no per-endpoint code.\n */\n@customElement('roxy-endpoint-form')\nexport class RoxyEndpointForm extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`form{gap:var(--roxy-space-md,1rem);background:var(--roxy-bg,#fff);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);display:grid}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.fields{align-items:start;gap:var(--roxy-space-md,1rem);grid-template-columns:repeat(auto-fit,minmax(12rem,1fr));display:grid}.person-group{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-md,1rem);margin:0 0 var(--roxy-space-md,1rem);gap:var(--roxy-space-md,1rem);min-inline-size:0;display:grid}.person-group legend{padding:0 var(--roxy-space-xs,.25rem);font-weight:var(--roxy-weight-bold,600);text-transform:capitalize}.field{gap:var(--roxy-space-xs,.25rem);flex-direction:column;min-width:0;display:flex}label{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-secondary,#475569)}label .req{color:var(--roxy-danger-fg,#991b1b);margin-left:4px}input,select{box-sizing:border-box;width:100%;padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);font-size:var(--roxy-text-base,1rem);color:var(--roxy-fg,#0a0a0a);background:var(--roxy-bg,#fff);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);font-family:inherit}input:focus,select:focus{outline:2px solid var(--roxy-ring,#f59e0b66);outline-offset:2px;border-color:var(--roxy-accent-ink,#b45309)}.help{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem)}.location-block{gap:var(--roxy-space-xs,.25rem);grid-column:1/-1;display:grid}.coords{gap:var(--roxy-space-sm,.5rem);grid-template-columns:repeat(3,1fr);display:grid}.coords input{font-size:var(--roxy-text-sm,.875rem)}button.submit{background:var(--roxy-accent-ink,#b45309);color:var(--roxy-bg,#fff);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-lg,1.5rem);font-size:var(--roxy-text-base,1rem);font-weight:var(--roxy-weight-bold,600);cursor:pointer;transition:transform var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,cubic-bezier(.4, 0, .2, 1));border:0;justify-self:start}button.submit:hover{transform:scale(1.02)}button.submit:focus-visible{outline:2px solid var(--roxy-ring,#f59e0b66);outline-offset:2px}.spec-error{gap:var(--roxy-space-md,1rem);background:var(--roxy-bg,#fff);border:1px solid var(--roxy-danger,#dc2626);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);color:var(--roxy-danger-fg,#991b1b);font-size:var(--roxy-text-sm,.875rem);justify-items:start;display:grid}`,\n\t];\n\n\t@property({ type: String, attribute: 'data-endpoint' })\n\tendpoint = 'vedic-astrology/birth-chart';\n\n\t@property({ type: String })\n\tmethod: 'GET' | 'POST' = 'POST';\n\n\t@property({ type: String, attribute: 'spec-url' })\n\tspecUrl = 'https://roxyapi.com/api/v2/openapi.json';\n\n\t@property({ type: String, attribute: 'submit-label' })\n\tsubmitLabel = 'Submit';\n\n\t/** Prefill values, keyed by field name. Used by `remember` mode to restore the last submission. JS property only. */\n\t@property({ attribute: false })\n\tinitialValues?: Record<string, unknown>;\n\n\t@state()\n\tprivate fields: FieldDef[] = [];\n\n\t@state()\n\tprivate values: Record<string, unknown> = {};\n\n\t@state()\n\tprivate loaded = false;\n\n\t@state()\n\tprivate specError: string | null = null;\n\n\tconnectedCallback(): void {\n\t\tsuper.connectedCallback();\n\t\tvoid this.loadSchema();\n\t}\n\n\tprivate async loadSchema() {\n\t\tthis.specError = null;\n\t\ttry {\n\t\t\tconst spec = await loadSpec(this.specUrl);\n\t\t\tconst path = `/${this.endpoint.replace(/^\\//, '')}`;\n\t\t\tconst op = spec.paths?.[path]?.[this.method.toLowerCase()] as\n\t\t\t\t| {\n\t\t\t\t\t\trequestBody?: {\n\t\t\t\t\t\t\tcontent?: Record<\n\t\t\t\t\t\t\t\tstring,\n\t\t\t\t\t\t\t\t{ schema?: OpenApiSchema | OpenApiSchemaRef }\n\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t};\n\t\t\t\t\t\tparameters?: Array<{\n\t\t\t\t\t\t\tname: string;\n\t\t\t\t\t\t\tin: string;\n\t\t\t\t\t\t\trequired?: boolean;\n\t\t\t\t\t\t\tschema?: OpenApiSchema;\n\t\t\t\t\t\t}>;\n\t\t\t\t }\n\t\t\t\t| undefined;\n\t\t\tif (!op) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Endpoint ${this.method} ${path} not found in OpenAPI spec`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst schemas = spec.components?.schemas ?? {};\n\t\t\tconst fields: FieldDef[] = [];\n\t\t\tlet bodySchema: OpenApiSchema | undefined;\n\n\t\t\tif (op.requestBody) {\n\t\t\t\tconst ref = op.requestBody.content?.['application/json']?.schema;\n\t\t\t\tbodySchema = this.resolve(ref, schemas);\n\t\t\t}\n\n\t\t\tif (bodySchema?.properties) {\n\t\t\t\tconst required = new Set(bodySchema.required ?? []);\n\t\t\t\tfor (const [name, sub] of Object.entries(bodySchema.properties)) {\n\t\t\t\t\tconst resolved = this.resolve(sub, schemas) ?? {};\n\t\t\t\t\t// Nested object (e.g. person1/person2 on synastry / guna-milan):\n\t\t\t\t\t// expand into a labelled group of sub-fields keyed \"group.sub\".\n\t\t\t\t\tif (resolved.type === 'object' && resolved.properties) {\n\t\t\t\t\t\tconst subRequired = new Set(resolved.required ?? []);\n\t\t\t\t\t\tfor (const [subName, subSchema] of Object.entries(\n\t\t\t\t\t\t\tresolved.properties,\n\t\t\t\t\t\t)) {\n\t\t\t\t\t\t\tconst r = this.resolve(subSchema, schemas) ?? {};\n\t\t\t\t\t\t\tfields.push({\n\t\t\t\t\t\t\t\tkey: `${name}.${subName}`,\n\t\t\t\t\t\t\t\tname: subName,\n\t\t\t\t\t\t\t\tgroup: name,\n\t\t\t\t\t\t\t\ttype: this.fieldType(r),\n\t\t\t\t\t\t\t\trequired: required.has(name) && subRequired.has(subName),\n\t\t\t\t\t\t\t\tdescription: r.description,\n\t\t\t\t\t\t\t\tenum: r.enum,\n\t\t\t\t\t\t\t\tmin: r.minimum,\n\t\t\t\t\t\t\t\tmax: r.maximum,\n\t\t\t\t\t\t\t\tdefault: r.default,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfields.push({\n\t\t\t\t\t\t\tkey: name,\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\ttype: this.fieldType(resolved),\n\t\t\t\t\t\t\trequired: required.has(name),\n\t\t\t\t\t\t\tdescription: resolved.description,\n\t\t\t\t\t\t\tenum: resolved.enum,\n\t\t\t\t\t\t\tmin: resolved.minimum,\n\t\t\t\t\t\t\tmax: resolved.maximum,\n\t\t\t\t\t\t\tdefault: resolved.default,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const param of op.parameters ?? []) {\n\t\t\t\tif (param.in === 'path' || param.in === 'query') {\n\t\t\t\t\tconst resolved = this.resolve(param.schema, schemas) ?? {};\n\t\t\t\t\tfields.push({\n\t\t\t\t\t\tkey: param.name,\n\t\t\t\t\t\tname: param.name,\n\t\t\t\t\t\ttype: this.fieldType(resolved),\n\t\t\t\t\t\trequired: !!param.required,\n\t\t\t\t\t\tdescription: resolved.description,\n\t\t\t\t\t\tenum: resolved.enum,\n\t\t\t\t\t\tdefault: resolved.default,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.fields = fields;\n\n\t\t\t// Pre-fill: schema defaults first, then any remembered/initial values\n\t\t\t// (only for fields this endpoint has) so a stale stored payload from\n\t\t\t// another endpoint cannot inject unknown keys. Remembered values are the\n\t\t\t// previously-submitted shape (nested per group), so read them by group.\n\t\t\tconst init: Record<string, unknown> = {};\n\t\t\tfor (const f of fields) {\n\t\t\t\tif (f.default !== undefined) init[f.key] = f.default;\n\t\t\t\tconst remembered = f.group\n\t\t\t\t\t? (\n\t\t\t\t\t\t\tthis.initialValues?.[f.group] as\n\t\t\t\t\t\t\t\t| Record<string, unknown>\n\t\t\t\t\t\t\t\t| undefined\n\t\t\t\t\t\t)?.[f.name]\n\t\t\t\t\t: this.initialValues?.[f.name];\n\t\t\t\tif (remembered !== undefined) init[f.key] = remembered;\n\t\t\t}\n\t\t\tthis.values = init;\n\t\t\tthis.loaded = true;\n\t\t} catch (err) {\n\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\tthis.specError = message;\n\t\t\tthis.loaded = true;\n\t\t\tthis.dispatchEvent(\n\t\t\t\tnew CustomEvent('roxy-spec-error', {\n\t\t\t\t\tdetail: { url: this.specUrl, message },\n\t\t\t\t\tbubbles: true,\n\t\t\t\t\tcomposed: true,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate retryLoadSchema = () => {\n\t\tthis.loaded = false;\n\t\tthis.specError = null;\n\t\tvoid this.loadSchema();\n\t};\n\n\tprivate resolve(\n\t\tschema: OpenApiSchema | OpenApiSchemaRef | undefined,\n\t\tall: Record<string, OpenApiSchema>,\n\t): OpenApiSchema | undefined {\n\t\tif (!schema) return undefined;\n\t\tif ('$ref' in schema && schema.$ref) {\n\t\t\tconst name = schema.$ref.split('/').pop();\n\t\t\treturn name ? all[name] : undefined;\n\t\t}\n\t\treturn schema as OpenApiSchema;\n\t}\n\n\tprivate fieldType(s: OpenApiSchema): string {\n\t\tif (s.enum) return 'enum';\n\t\tif (s.format === 'date') return 'date';\n\t\tif (s.format === 'time') return 'time';\n\t\tif (s.format === 'date-time') return 'datetime';\n\t\tif (s.type === 'integer' || s.type === 'number') return 'number';\n\t\treturn 'text';\n\t}\n\n\tprivate setValue(name: string, value: unknown) {\n\t\tthis.values = { ...this.values, [name]: value };\n\t}\n\n\t/** True when the fields in `group` (or the flat top level) carry latitude+longitude+timezone, so a location-search can autofill them. */\n\tprivate groupHasLocation(group?: string): boolean {\n\t\tconst inGroup = this.fields.filter((f) => f.group === group);\n\t\treturn (['latitude', 'longitude', 'timezone'] as const).every((n) =>\n\t\t\tinGroup.some((f) => f.name === n),\n\t\t);\n\t}\n\n\t/** Location-select handler bound to a group: fills that group's lat/lng/timezone keys (flat top level when group is undefined). */\n\tprivate onLocationFor(group?: string) {\n\t\tconst prefix = group ? `${group}.` : '';\n\t\treturn (e: Event) => {\n\t\t\tconst detail = (e as CustomEvent).detail as {\n\t\t\t\tlatitude?: number;\n\t\t\t\tlongitude?: number;\n\t\t\t\ttimezone?: string;\n\t\t\t\tutcOffset?: number;\n\t\t\t};\n\t\t\tif (!detail) return;\n\t\t\tthis.values = {\n\t\t\t\t...this.values,\n\t\t\t\t[`${prefix}latitude`]: detail.latitude,\n\t\t\t\t[`${prefix}longitude`]: detail.longitude,\n\t\t\t\t[`${prefix}timezone`]: detail.timezone ?? detail.utcOffset,\n\t\t\t};\n\t\t};\n\t}\n\n\tprivate onSubmit = (e: Event) => {\n\t\te.preventDefault();\n\t\tconst missing = this.fields\n\t\t\t.filter((f) => f.required)\n\t\t\t.filter(\n\t\t\t\t(f) => this.values[f.key] === undefined || this.values[f.key] === '',\n\t\t\t);\n\t\tif (missing.length > 0) {\n\t\t\tthis.dispatchEvent(\n\t\t\t\tnew CustomEvent('roxy-validation-error', {\n\t\t\t\t\tdetail: { missing: missing.map((m) => m.key) },\n\t\t\t\t\tbubbles: true,\n\t\t\t\t\tcomposed: true,\n\t\t\t\t}),\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\t// Reconstruct the request shape: grouped fields nest as { group: { name: value } }.\n\t\tconst out: Record<string, unknown> = {};\n\t\tfor (const f of this.fields) {\n\t\t\tconst v = this.values[f.key];\n\t\t\tif (v === undefined || v === '') continue;\n\t\t\tif (f.group) {\n\t\t\t\tconst g = (out[f.group] as Record<string, unknown> | undefined) ?? {};\n\t\t\t\tg[f.name] = v;\n\t\t\t\tout[f.group] = g;\n\t\t\t} else {\n\t\t\t\tout[f.name] = v;\n\t\t\t}\n\t\t}\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('roxy-submit', {\n\t\t\t\tdetail: { endpoint: this.endpoint, values: out },\n\t\t\t\tbubbles: true,\n\t\t\t\tcomposed: true,\n\t\t\t}),\n\t\t);\n\t};\n\n\trender() {\n\t\tif (!this.loaded) {\n\t\t\treturn html`<form><div class=\"roxy-skeleton\" style=\"height:8rem\"></div></form>`;\n\t\t}\n\n\t\tif (this.specError) {\n\t\t\treturn html`<div class=\"spec-error\" role=\"alert\">Schema load failed: ${this.specError} <button type=\"button\" class=\"submit\" @click=\"${this.retryLoadSchema}\">Retry</button></div>`;\n\t\t}\n\n\t\tconst renderField = (f: FieldDef) => {\n\t\t\tif (\n\t\t\t\tthis.groupHasLocation(f.group) &&\n\t\t\t\t(f.name === 'latitude' ||\n\t\t\t\t\tf.name === 'longitude' ||\n\t\t\t\t\tf.name === 'timezone')\n\t\t\t) {\n\t\t\t\treturn nothing;\n\t\t\t}\n\t\t\tconst inputId = `roxy-form-${f.key}`;\n\t\t\treturn html`<div class=\"field\"><label for=\"${inputId}\">${humanize(f.name)}${f.required ? html`<span class=\"req\" aria-hidden=\"true\">*</span>` : nothing}</label> ${\n\t\t\t\t\tf.enum\n\t\t\t\t\t\t? html`<select id=\"${inputId}\" ?required=\"${f.required}\" @change=\"${(e: Event) => this.setValue(f.key, (e.target as HTMLSelectElement).value)}\"><option value=\"\">Choose</option>${f.enum.map(\n\t\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\t\topt,\n\t\t\t\t\t\t\t\t) => html`<option value=\"${opt}\" ?selected=\"${this.values[f.key] === opt}\">${opt}</option>`,\n\t\t\t\t\t\t\t)}</select>`\n\t\t\t\t\t\t: html`<input id=\"${inputId}\" type=\"${this.htmlType(f.type)}\" ?required=\"${f.required}\" min=\"${f.min ?? ''}\" max=\"${f.max ?? ''}\" step=\"${f.type === 'number' ? 'any' : ''}\" .value=\"${(this.values[f.key] ?? '') as string}\" @input=\"${(e: Event) =>\n\t\t\t\t\t\t\t\tthis.setValue(\n\t\t\t\t\t\t\t\t\tf.key,\n\t\t\t\t\t\t\t\t\tthis.coerce(f.type, (e.target as HTMLInputElement).value),\n\t\t\t\t\t\t\t\t)}\">`\n\t\t\t\t} ${f.description ? html`<small class=\"help\">${f.description}</small>` : nothing}</div>`;\n\t\t};\n\n\t\t// Ordered list of field groups: the flat top level (undefined) plus each\n\t\t// nested object (person1/person2). Order follows first appearance.\n\t\tconst groups: (string | undefined)[] = [];\n\t\tfor (const f of this.fields) {\n\t\t\tif (!groups.includes(f.group)) groups.push(f.group);\n\t\t}\n\n\t\tconst locationBlock = (group?: string) =>\n\t\t\tthis.groupHasLocation(group)\n\t\t\t\t? html`<div class=\"location-block\"><label>${group ? `${humanize(group)} location` : 'Birth location'}</label><roxy-location-search @roxy-location-select=\"${this.onLocationFor(group)}\" placeholder=\"City of birth\"></roxy-location-search><small class=\"help\">Required: latitude, longitude, timezone. Pick a city to autofill.</small></div>`\n\t\t\t\t: nothing;\n\n\t\tconst groupBody = (group?: string) => html`${locationBlock(group)}<div class=\"fields\">${this.fields.filter((f) => f.group === group).map((f) => renderField(f))}</div>`;\n\n\t\treturn html`<form @submit=\"${this.onSubmit}\"><h2 class=\"title\">${humanize(this.endpoint.split('/').pop() ?? '')}</h2>${groups.map((g) =>\n\t\t\t\tg === undefined\n\t\t\t\t\t? groupBody(undefined)\n\t\t\t\t\t: html`<fieldset class=\"person-group\"><legend>${humanize(g)}</legend>${groupBody(g)}</fieldset>`,\n\t\t\t)} <button class=\"submit\" type=\"submit\">${this.submitLabel}</button></form>`;\n\t}\n\n\tprivate htmlType(t: string): string {\n\t\tswitch (t) {\n\t\t\tcase 'date':\n\t\t\t\treturn 'date';\n\t\t\tcase 'time':\n\t\t\t\treturn 'time';\n\t\t\tcase 'datetime':\n\t\t\t\treturn 'datetime-local';\n\t\t\tcase 'number':\n\t\t\t\treturn 'number';\n\t\t\tdefault:\n\t\t\t\treturn 'text';\n\t\t}\n\t}\n\n\tprivate coerce(t: string, v: string): unknown {\n\t\tif (v === '') return undefined;\n\t\tif (t === 'number') {\n\t\t\tconst n = Number(v);\n\t\t\treturn Number.isFinite(n) ? n : undefined;\n\t\t}\n\t\treturn v;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-endpoint-form': RoxyEndpointForm;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { GenerateDigestResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatDate, formatNumber } from '../utils/format.js';\nimport { humanize } from '../utils/string.js';\n\ntype DigestWindow = NonNullable<GenerateDigestResponse['windows']>[number];\ntype DigestEvent = NonNullable<DigestWindow['top']>[number];\n\n/**\n * Forecast digest: the rolled-up reading across the next 24 hours, 7, 30, and 90 days. Renders /forecast/digest. Each window shows how many events fall in it, a per-domain breakdown (western, vedic, biorhythm), and the few highest-significance events with a significance bar coloured by domain. Use it as the at-a-glance period summary that pairs with the day-by-day roxy-forecast-timeline.\n */\n@customElement('roxy-forecast-digest')\nexport class RoxyForecastDigest extends RoxyDataElement<GenerateDigestResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-md,1rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.subtitle{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem);margin:0}.window{gap:var(--roxy-space-sm,.5rem);padding-top:var(--roxy-space-md,1rem);border-top:1px solid var(--roxy-border,#e4e4e7);display:grid}.window:first-of-type{border-top:none;padding-top:0}.window-head{flex-wrap:wrap;align-items:baseline;gap:.5rem;display:flex}.window-label{font-weight:var(--roxy-weight-bold,600)}.window-count{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);font-variant-numeric:tabular-nums;margin-left:auto}.domains{flex-wrap:wrap;gap:.4rem;display:flex}.domain-chip{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);align-items:center;gap:.35rem;display:inline-flex}.swatch{border-radius:2px;width:.65rem;height:.65rem;display:inline-block}.sw-western{background:var(--roxy-accent,#f59e0b)}.sw-vedic{background:var(--roxy-info,#2563eb)}.sw-biorhythm{background:var(--roxy-success,#16a34a)}.event{grid-template-columns:auto 1fr;align-items:baseline;gap:.25rem .6rem;display:grid}.event-date{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);font-variant-numeric:tabular-nums;white-space:nowrap}.event-desc{font-size:var(--roxy-text-sm,.875rem);line-height:1.4}.sig{background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 60%, transparent);border-radius:2px;grid-column:2;height:4px;overflow:hidden}.sig-fill{border-radius:2px;height:100%;display:block}.sig-fill.western{background:var(--roxy-accent,#f59e0b)}.sig-fill.vedic{background:var(--roxy-info,#2563eb)}.sig-fill.biorhythm{background:var(--roxy-success,#16a34a)}.quiet{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem);font-style:italic}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No digest data</div>`;\n\t}\n\n\tprotected renderData(d: GenerateDigestResponse) {\n\t\tconst windows = d.windows ?? [];\n\t\tif (windows.length === 0) return this.renderEmpty();\n\t\tconst range = [formatDate(d.startDate), formatDate(d.endDate)]\n\t\t\t.filter(Boolean)\n\t\t\t.join(' \u2013 ');\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Forecast digest\"><div class=\"head\"><h2 class=\"title\">Forecast Digest</h2>${range ? html`<p class=\"subtitle\">${range}</p>` : nothing}</div>${windows.map((w) => this.renderWindow(w))}</div>`;\n\t}\n\n\tprivate windowLabel(days: number | undefined): string {\n\t\tif (days === 1) return 'Next 24 hours';\n\t\treturn typeof days === 'number' ? `Next ${days} days` : 'Window';\n\t}\n\n\tprivate renderWindow(w: DigestWindow) {\n\t\tconst top = w.top ?? [];\n\t\tconst byDomain = w.byDomain ?? {};\n\t\tconst domains = Object.entries(byDomain) as Array<[string, number]>;\n\t\treturn html`<section class=\"window\"><div class=\"window-head\"><span class=\"window-label\">${this.windowLabel(w.days)}</span> <span class=\"window-count\">${w.count ?? 0} event${w.count === 1 ? '' : 's'}</span></div>${\n\t\t\t\tdomains.length > 0\n\t\t\t\t\t? html`<div class=\"domains\">${domains.map(\n\t\t\t\t\t\t\t([dom, n]) => html`<span class=\"domain-chip\"><span class=\"swatch sw-${dom}\"></span>${humanize(dom)} ${n}</span>`,\n\t\t\t\t\t\t)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\ttop.length > 0\n\t\t\t\t\t? html`<div role=\"list\">${top.map((e) => this.renderEvent(e))}</div>`\n\t\t\t\t\t: html`<p class=\"quiet\">No notable events.</p>`\n\t\t\t}</section>`;\n\t}\n\n\tprivate renderEvent(e: DigestEvent) {\n\t\tconst sig = typeof e.significance === 'number' ? e.significance : 0;\n\t\treturn html`<div class=\"event\" role=\"listitem\"><span class=\"event-date\">${formatDate(e.date)}</span> <span class=\"event-desc\">${e.description ?? humanize(e.type ?? '')}</span> <span class=\"sig\" role=\"img\" aria-label=\"significance ${formatNumber(sig, 0)} of 100\"><span class=\"sig-fill ${e.domain}\" style=\"width:${Math.max(0, Math.min(100, sig))}%\"></span></span></div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-forecast-digest': RoxyForecastDigest;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { ASPECT_SYMBOL } from '../tokens/index.js';\nimport type {\n\tFindSignificantDatesResponse,\n\tForecastTransitsResponse,\n\tGenerateTimelineResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { ASPECT_CLASS, formatDate, formatNumber } from '../utils/format.js';\nimport { capitalize, humanize } from '../utils/string.js';\n\n/** Timeline, significant-dates, and forecast-transits all return the same `{ events, startDate, endDate, birthData, count }` shape. */\ntype ForecastTimelineData =\n\t| GenerateTimelineResponse\n\t| FindSignificantDatesResponse\n\t| ForecastTransitsResponse;\n\ntype ForecastEvent = GenerateTimelineResponse['events'][number];\ntype ForecastDomain = ForecastEvent['domain'];\n\n/**\n * Display label per forecast domain. Keyed by the spec `domain` union so a new\n * domain in the spec surfaces as a typecheck failure here rather than an\n * unlabeled swatch.\n */\nconst DOMAIN_LABEL: Record<ForecastDomain, string> = {\n\twestern: 'Western',\n\tvedic: 'Vedic',\n\tbiorhythm: 'Biorhythm',\n};\n\nconst DOMAIN_ORDER: readonly ForecastDomain[] = [\n\t'western',\n\t'vedic',\n\t'biorhythm',\n];\n\n/**\n * Cross-domain forecast timeline. Pass `data` from /forecast/timeline. Events\n * are grouped by calendar date down a vertical axis, each colored by its domain\n * and weighted by significance (0-100), showing the event type, body, target,\n * aspect, and description. The visual language matches the dasha timeline: a\n * left rail of dates, a significance bar per event, and a colored marker for\n * the domain.\n *\n * Theming flows through `--roxy-*` custom properties on `:host`.\n */\n@customElement('roxy-forecast-timeline')\nexport class RoxyForecastTimeline extends RoxyDataElement<ForecastTimelineData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.range{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem);font-variant-numeric:tabular-nums}.legend{gap:var(--roxy-space-md,1rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);flex-wrap:wrap;display:flex}.legend .swatch{vertical-align:middle;border-radius:50%;width:10px;height:10px;margin-right:4px;display:inline-block}.swatch-western{background:var(--roxy-accent,#f59e0b)}.swatch-vedic{background:var(--roxy-info,#2563eb)}.swatch-biorhythm{background:var(--roxy-success,#16a34a)}.day{gap:var(--roxy-space-md,1rem);padding-block:var(--roxy-space-sm,.5rem);border-top:1px solid var(--roxy-border,#e4e4e7);grid-template-columns:4.5rem 1fr;display:grid}.day:first-of-type{border-top:none}.day-date{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);font-variant-numeric:tabular-nums;padding-top:2px}.events{gap:var(--roxy-space-sm,.5rem);display:grid}.event{gap:var(--roxy-space-sm,.5rem);grid-template-columns:.6rem 1fr;align-items:start;display:grid}.dot{border-radius:50%;width:.6rem;height:.6rem;margin-top:4px}.dot-western{background:var(--roxy-accent,#f59e0b)}.dot-vedic{background:var(--roxy-info,#2563eb)}.dot-biorhythm{background:var(--roxy-success,#16a34a)}.event-body{min-width:0}.event-line{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a)}.event-line .aspect-trine,.event-line .aspect-sextile{color:var(--roxy-success-fg,#166534)}.event-line .aspect-square,.event-line .aspect-opposition{color:var(--roxy-danger-fg,#991b1b)}.event-line .aspect-conjunction{color:var(--roxy-accent-ink,#b45309)}.event-line .kind{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);text-transform:uppercase;letter-spacing:.04em;margin-left:.35em}.event-desc{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);margin:2px 0 0}.sig{align-items:center;gap:.4rem;margin-top:4px;display:flex}.sig-track{background:var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-full,9999px);flex:1;max-width:8rem;height:4px;overflow:hidden}.sig-fill{border-radius:var(--roxy-radius-full,9999px);height:100%;display:block}.sig-fill-western{background:var(--roxy-accent,#f59e0b)}.sig-fill-vedic{background:var(--roxy-info,#2563eb)}.sig-fill-biorhythm{background:var(--roxy-success,#16a34a)}.sig-val{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);font-variant-numeric:tabular-nums}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No forecast data</div>`;\n\t}\n\n\tprotected renderData(d: ForecastTimelineData) {\n\t\tconst events = d.events ?? [];\n\t\tconst grouped = this.groupByDate(events);\n\t\tconst present = DOMAIN_ORDER.filter((dom) =>\n\t\t\tevents.some((e) => e.domain === dom),\n\t\t);\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Forecast timeline\"><header class=\"head\"><h2 class=\"title\">Forecast timeline</h2>${\n\t\t\t\t\td.startDate && d.endDate\n\t\t\t\t\t\t? html`<div class=\"range\">${formatDate(d.startDate)} - ${formatDate(d.endDate)} \u00B7 ${d.count ?? events.length} events</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</header>${\n\t\t\t\tpresent.length\n\t\t\t\t\t? html`<div class=\"legend\">${present.map(\n\t\t\t\t\t\t\t(dom) =>\n\t\t\t\t\t\t\t\thtml`<span><span class=\"swatch swatch-${dom}\"></span>${DOMAIN_LABEL[dom]}</span>`,\n\t\t\t\t\t\t)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tgrouped.length\n\t\t\t\t\t? html`<div class=\"days\" role=\"list\">${grouped.map(([date, dayEvents]) => this.renderDay(date, dayEvents))}</div>`\n\t\t\t\t\t: html`<p class=\"roxy-empty\" role=\"status\">No events in this window</p>`\n\t\t\t}</div>`;\n\t}\n\n\t/** Group events by their calendar date, preserving response order. */\n\tprivate groupByDate(\n\t\tevents: ForecastEvent[],\n\t): Array<[string, ForecastEvent[]]> {\n\t\tconst map = new Map<string, ForecastEvent[]>();\n\t\tfor (const e of events) {\n\t\t\tconst key = e.date ?? '';\n\t\t\tconst list = map.get(key) ?? [];\n\t\t\tlist.push(e);\n\t\t\tmap.set(key, list);\n\t\t}\n\t\treturn [...map.entries()];\n\t}\n\n\tprivate renderDay(date: string, events: ForecastEvent[]) {\n\t\treturn html`<div class=\"day\" role=\"listitem\"><div class=\"day-date\">${formatDate(date)}</div><div class=\"events\">${events.map((e) => this.renderEvent(e))}</div></div>`;\n\t}\n\n\tprivate renderEvent(e: ForecastEvent) {\n\t\tconst sig = typeof e.significance === 'number' ? e.significance : 0;\n\t\tconst width = Math.max(0, Math.min(100, sig));\n\t\treturn html`<div class=\"event\"><span class=\"dot dot-${e.domain}\" aria-hidden=\"true\"></span><div class=\"event-body\"><div class=\"event-line\">${this.renderHeadline(e)}</div>${e.description ? html`<p class=\"event-desc\">${e.description}</p>` : nothing}<div class=\"sig\" title=\"Significance ${width} of 100\"><span class=\"sig-track\"><span class=\"sig-fill sig-fill-${e.domain}\" style=\"width:${width}%\"></span> </span><span class=\"sig-val\">${width}</span></div></div></div>`;\n\t}\n\n\t/**\n\t * Compact event headline built from the spec fields. Transit aspects read\n\t * \"body aspect target\"; ingresses, stations, eclipses, dasha changes, and\n\t * critical days fall back to \"body\" plus the qualifier the spec carries for\n\t * that type (station direction, eclipse kind). The aspect symbol is colored\n\t * by nature, matching the chart aspect encoding.\n\t */\n\tprivate renderHeadline(e: ForecastEvent) {\n\t\tconst body = e.body ? capitalize(e.body) : '';\n\t\tconst target = e.target ? capitalize(e.target) : '';\n\t\tconst aspect = e.aspect ? e.aspect.toLowerCase() : '';\n\t\tconst aspectClass = ASPECT_CLASS[aspect] ?? '';\n\t\tconst aspectSym = aspect ? (ASPECT_SYMBOL[aspect] ?? aspect) : '';\n\t\tconst orb = typeof e.orb === 'number' ? formatNumber(e.orb, 1) : '';\n\t\tconst qualifier = this.typeQualifier(e);\n\n\t\tif (aspect && target) {\n\t\t\treturn html`<strong>${body}</strong> <span class=\"${aspectClass}\">${aspectSym}</span> <strong>${target}</strong>${orb ? html`<span class=\"kind\">orb ${orb}\u00B0</span>` : nothing}`;\n\t\t}\n\t\treturn html`<strong>${body || humanize(e.type ?? '')}</strong>${\n\t\t\tqualifier ? html`<span class=\"kind\">${qualifier}</span>` : nothing\n\t\t}`;\n\t}\n\n\t/** Type-specific qualifier text from the optional spec fields. */\n\tprivate typeQualifier(e: ForecastEvent): string {\n\t\tif (e.type === 'sign-ingress' && e.target)\n\t\t\treturn `enters ${capitalize(e.target)}`;\n\t\tif (e.type === 'retrograde-station' && e.station) return e.station;\n\t\tif (e.type === 'eclipse')\n\t\t\treturn [e.kind, 'eclipse'].filter(Boolean).join(' ');\n\t\tif (e.type === 'critical-day') return 'critical day';\n\t\tif (e.type === 'dasha-change' && e.target)\n\t\t\treturn `dasha ${capitalize(e.target)}`;\n\t\treturn humanize(e.type ?? '');\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-forecast-timeline': RoxyForecastTimeline;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { CompatibilityResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatNumber, formatPercent } from '../utils/format.js';\n\nconst STANDARD_CATEGORIES = [\n\t'Varna',\n\t'Vasya',\n\t'Tara',\n\t'Yoni',\n\t'Maitri',\n\t'Gana',\n\t'Bhakoot',\n\t'Nadi',\n];\n\n/**\n * 36-point Ashtakoota score card. Renders /vedic-astrology/compatibility.\n */\n@customElement('roxy-guna-milan')\nexport class RoxyGunaMilan extends RoxyDataElement<CompatibilityResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.card{background:var(--roxy-surface,#fff);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.score-header{align-items:center;gap:1rem;display:flex}.score-info{flex:1}.score-bar{align-items:center;gap:var(--roxy-space-md,1rem);grid-template-columns:1fr auto;display:grid}.total{font-size:2.25rem;font-weight:var(--roxy-weight-bold,600);color:var(--roxy-accent-ink,#b45309);font-variant-numeric:tabular-nums;line-height:1}.over{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-base,1rem)}.recommendation{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-secondary,#475569)}.score-ring{flex-shrink:0;width:120px;height:120px}.score-ring svg{width:100%;height:100%}.score-ring .ring-text{fill:var(--roxy-fg,#0a0a0a);font-size:22px;font-weight:700;font-family:var(--roxy-font-sans)}.score-ring .ring-max{fill:var(--roxy-muted,#71717a);font-size:10px;font-family:var(--roxy-font-sans)}table{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem)}th,td{padding:var(--roxy-space-sm,.5rem);border-bottom:1px solid var(--roxy-border,#e4e4e7);text-align:left}th{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;font-size:var(--roxy-text-xs,.75rem);letter-spacing:.06em}td.score{text-align:right;font-variant-numeric:tabular-nums;color:var(--roxy-fg,#0a0a0a);font-weight:var(--roxy-weight-bold,600)}td.bar-cell{width:30%}.mini-bar{background:var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-full,9999px);height:8px;overflow:hidden}.mini-bar>span{background:var(--roxy-accent,#f59e0b);height:100%;transition:width var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,cubic-bezier(.4, 0, .2, 1));display:block}.tags{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;display:flex}.tags span{border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);padding:2px 8px}.tags .dosha{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 16%, transparent);color:var(--roxy-danger-fg,#991b1b)}.tags .cancel{background:color-mix(in srgb, var(--roxy-success,#16a34a) 18%, transparent);color:var(--roxy-success-fg,#166534)}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No Guna Milan data</div>`;\n\t}\n\n\tprotected renderData(d: CompatibilityResponse) {\n\t\tconst breakdown = (d.breakdown ?? []).filter(\n\t\t\t(b) => b?.category !== undefined,\n\t\t);\n\n\t\tconst score = d.total ?? 0;\n\t\tconst max = d.maxScore ?? 36;\n\t\tconst pct = (score / max) * 100;\n\t\tconst trackColor =\n\t\t\t'color-mix(in srgb, var(--roxy-border) 50%, transparent)';\n\t\tconst fillColor =\n\t\t\tpct >= 70\n\t\t\t\t? 'var(--roxy-success)'\n\t\t\t\t: pct >= 50\n\t\t\t\t\t? 'var(--roxy-warning)'\n\t\t\t\t\t: 'var(--roxy-danger)';\n\t\t// SVG circle with r=45: circumference = 2 * pi * 45 = 282.74\n\t\t// dasharray segments = pct * 2.827, (100 - pct) * 2.827\n\t\tconst dashFill = pct * 2.827;\n\t\tconst dashGap = (100 - pct) * 2.827;\n\n\t\treturn html`<article class=\"card\" aria-label=\"Guna Milan score\"><div class=\"score-header\"><div class=\"score-info\"><div class=\"score-bar\"><div><span class=\"total\">${formatNumber(d.total, 1)}</span> <span class=\"over\">/ ${d.maxScore}</span> ${\n\t\t\t\t\t\t\t\ttypeof d.percentage === 'number'\n\t\t\t\t\t\t\t\t\t? html`<small style=\"margin-left:.5rem;color:var(--roxy-muted)\">${formatPercent(d.percentage, 1)}</small>`\n\t\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t\t}</div>${\n\t\t\t\t\t\t\td.recommendation\n\t\t\t\t\t\t\t\t? html`<span class=\"recommendation\">${d.recommendation}</span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}</div></div><div class=\"score-ring\" role=\"meter\" aria-label=\"Guna milan score\" aria-valuemin=\"0\" aria-valuemax=\"36\" aria-valuenow=\"${score}\"><svg viewBox=\"0 0 100 100\" aria-hidden=\"true\"><circle class=\"ring-track\" cx=\"50\" cy=\"50\" r=\"45\" fill=\"none\" stroke=\"${trackColor}\" stroke-width=\"8\"/><circle class=\"ring-fill\" cx=\"50\" cy=\"50\" r=\"45\" fill=\"none\" stroke=\"${fillColor}\" stroke-width=\"8\" stroke-dasharray=\"${dashFill},${dashGap}\" stroke-linecap=\"round\" transform=\"rotate(-90 50 50)\"/><text x=\"50\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\" class=\"ring-text\">${score}</text><text x=\"50\" y=\"64\" text-anchor=\"middle\" dominant-baseline=\"central\" class=\"ring-max\">/${max}</text></svg></div></div>${\n\t\t\t\tbreakdown.length > 0\n\t\t\t\t\t? html`<table><thead><tr><th>Category</th><th>Progress</th><th class=\"score\">Score</th></tr></thead><tbody>${breakdown.map((b) => {\n\t\t\t\t\t\t\t\tconst score = b.score ?? 0;\n\t\t\t\t\t\t\t\tconst maxScore = b.maxScore ?? defaultMax(b.category);\n\t\t\t\t\t\t\t\tconst pct = maxScore ? (score / maxScore) * 100 : 0;\n\t\t\t\t\t\t\t\treturn html`<tr><td>${b.category}</td><td class=\"bar-cell\"><div class=\"mini-bar\"><span style=\"width:${pct}%\"></span></div></td><td class=\"score\">${formatNumber(score, 1)} / ${maxScore}</td></tr>`;\n\t\t\t\t\t\t\t})}</tbody></table>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\t(d.doshas?.length ?? 0) > 0 || (d.doshaCancellations?.length ?? 0) > 0\n\t\t\t\t\t? html`<div class=\"tags\">${d.doshas?.map((x) => html`<span class=\"dosha\">${x}</span>`)} ${d.doshaCancellations?.map(\n\t\t\t\t\t\t\t(x) =>\n\t\t\t\t\t\t\t\thtml`<span class=\"cancel\" title=\"${x.reason}\">${x.dosha} cancelled</span>`,\n\t\t\t\t\t\t)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t}</article>`;\n\t}\n}\n\nfunction defaultMax(name?: string): number {\n\tif (!name) return 1;\n\tswitch (name.toLowerCase()) {\n\t\tcase 'varna':\n\t\t\treturn 1;\n\t\tcase 'vasya':\n\t\t\treturn 2;\n\t\tcase 'tara':\n\t\t\treturn 3;\n\t\tcase 'yoni':\n\t\t\treturn 4;\n\t\tcase 'maitri':\n\t\t\treturn 5;\n\t\tcase 'gana':\n\t\t\treturn 6;\n\t\tcase 'bhakoot':\n\t\t\treturn 7;\n\t\tcase 'nadi':\n\t\t\treturn 8;\n\t\tdefault:\n\t\t\treturn 1;\n\t}\n}\n\nexport const GUNA_CATEGORIES = STANDARD_CATEGORIES;\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-guna-milan': RoxyGunaMilan;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { CalculateConnectionResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { humanize } from '../utils/string.js';\n\n/**\n * Human Design connection chart. Renders /human-design/connection: the composite of two charts as the electromagnetic / compromise / dominance channels they form together, plus the combined definition and a summary. The HD analog of synastry. Each channel row shows its two gates, name, circuit, the relationship dynamic, and which person carries which gate.\n */\n@customElement('roxy-hd-connection')\nexport class RoxyHdConnection extends RoxyDataElement<CalculateConnectionResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.count{color:var(--roxy-accent-ink,#b45309);font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);font-variant-numeric:tabular-nums}.def{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-muted,#71717a)}.def strong{color:var(--roxy-fg,#0a0a0a);text-transform:capitalize}.stats{gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.stat{border-radius:var(--roxy-radius-full,9999px);background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 12%, transparent);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-fg,#0a0a0a);align-items:baseline;gap:.35rem;padding:2px 10px;display:inline-flex}.stat b{color:var(--roxy-fg,#0a0a0a);font-variant-numeric:tabular-nums}table{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem)}th,td{text-align:left;padding:var(--roxy-space-sm,.5rem);border-bottom:1px solid var(--roxy-border,#e4e4e7);white-space:nowrap}th{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;font-size:var(--roxy-text-xs,.75rem);letter-spacing:.04em}tbody tr:last-child td{border-bottom:none}.gates{font-variant-numeric:tabular-nums;color:var(--roxy-accent-ink,#b45309);font-weight:var(--roxy-weight-bold,600)}.dyn{border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 16%, transparent);color:var(--roxy-fg,#0a0a0a);padding:1px 8px;display:inline-block}.who{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem)}.scroll{overflow-x:auto}`,\n\t];\n\n\tprotected renderData(d: CalculateConnectionResponse) {\n\t\tconst channels = d.channels ?? [];\n\t\treturn html`<div class=\"wrap\" aria-label=\"Human Design connection\"><header class=\"head\"><h2 class=\"title\">Connection</h2>${typeof d.totalChannels === 'number' ? html`<span class=\"count\">${d.totalChannels} channels</span>` : nothing}</header>${d.combinedDefinition ? html`<p class=\"def\">Combined definition: <strong>${humanize(String(d.combinedDefinition))}</strong></p>` : nothing} ${this.renderSummary(d.summary)} ${\n\t\t\t\tchannels.length > 0\n\t\t\t\t\t? html`<div class=\"scroll\"><table role=\"table\" aria-label=\"Connection channels\"><thead><tr><th scope=\"col\">Channel</th><th scope=\"col\">Gates</th><th scope=\"col\">Circuit</th><th scope=\"col\">Dynamic</th><th scope=\"col\">Held by</th></tr></thead><tbody>${channels.map((c) => this.renderChannel(c))}</tbody></table></div>`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n\n\tprivate renderSummary(s: CalculateConnectionResponse['summary'] | undefined) {\n\t\tif (!s) return nothing;\n\t\t// The four ways two charts meet in a channel, in canonical HD order.\n\t\tconst rows: Array<[string, number | undefined]> = [\n\t\t\t['Electromagnetic', s.electromagnetic],\n\t\t\t['Dominance', s.dominance],\n\t\t\t['Compromise', s.compromise],\n\t\t\t['Companionship', s.companionship],\n\t\t];\n\t\treturn html`<div class=\"stats\" aria-label=\"Channel dynamics\">${rows.map(([label, n]) => (typeof n === 'number' ? html`<span class=\"stat\">${label} <b>${n}</b></span>` : nothing))}</div>`;\n\t}\n\n\tprivate renderChannel(\n\t\tc: NonNullable<CalculateConnectionResponse['channels']>[number],\n\t) {\n\t\tconst a = c.personAGates ?? [];\n\t\tconst b = c.personBGates ?? [];\n\t\tconst held =\n\t\t\t[a.length ? 'A' : '', b.length ? 'B' : ''].filter(Boolean).join(' + ') ||\n\t\t\t'-';\n\t\treturn html`<tr><td>${c.name ?? ''}</td><td class=\"gates\">${c.gateA}-${c.gateB}</td><td>${c.circuit ?? ''}</td><td>${c.dynamic ? html`<span class=\"dyn\">${c.dynamic}</span>` : ''}</td><td class=\"who\">${held}</td></tr>`;\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No connection data</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-hd-connection': RoxyHdConnection;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { CalculatePentaResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\n/**\n * Human Design penta. Renders /human-design/penta: the group field (3 to 5 people) as the penta channels they form, split into the upper (direction) and lower (execution) triangles, with each channel marked defined or open and core or not, and which members hold each gate. The team/business chart.\n */\n@customElement('roxy-hd-penta')\nexport class RoxyHdPenta extends RoxyDataElement<CalculatePentaResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.count{color:var(--roxy-accent-ink,#b45309);font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600)}.stats{gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.stat{border-radius:var(--roxy-radius-full,9999px);background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 12%, transparent);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-fg,#0a0a0a);align-items:baseline;gap:.35rem;padding:2px 10px;display:inline-flex}.stat b{color:var(--roxy-fg,#0a0a0a);font-variant-numeric:tabular-nums}.section h3{margin:0 0 var(--roxy-space-xs,.25rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em}.row{align-items:center;gap:var(--roxy-space-sm,.5rem);padding:var(--roxy-space-sm,.5rem) 0;border-bottom:1px solid var(--roxy-border,#e4e4e7);font-size:var(--roxy-text-sm,.875rem);flex-wrap:wrap;display:flex}.row:last-child{border-bottom:none}.gates{font-variant-numeric:tabular-nums;color:var(--roxy-accent-ink,#b45309);font-weight:var(--roxy-weight-bold,600);min-width:3.5rem}.cname{flex:1;min-width:8rem}.badge{border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);padding:1px 8px;display:inline-flex}.badge.defined{background:color-mix(in srgb, var(--roxy-success,#16a34a) 16%, transparent);color:var(--roxy-success-fg,#166534)}.badge.open{background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 45%, transparent);color:var(--roxy-fg,#0a0a0a)}.badge.core{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 18%, transparent);color:var(--roxy-fg,#0a0a0a)}`,\n\t];\n\n\tprotected renderData(d: CalculatePentaResponse) {\n\t\tconst channels = d.channels ?? [];\n\t\tconst upper = channels.filter((c) => c.position === 'upper');\n\t\tconst lower = channels.filter((c) => c.position === 'lower');\n\t\treturn html`<div class=\"wrap\" aria-label=\"Human Design penta\"><header class=\"head\"><h2 class=\"title\">Penta</h2>${typeof d.memberCount === 'number' ? html`<span class=\"count\">${d.memberCount} members</span>` : nothing}</header>${this.renderSummary(d.summary)} ${this.renderGroup('Upper (direction)', upper)} ${this.renderGroup('Lower (execution)', lower)}</div>`;\n\t}\n\n\tprivate renderSummary(s: CalculatePentaResponse['summary'] | undefined) {\n\t\tif (!s) return nothing;\n\t\tconst gaps = s.gapGates ?? [];\n\t\treturn html`<div class=\"stats\" aria-label=\"Penta summary\">${typeof s.definedChannels === 'number' ? html`<span class=\"stat\">Defined channels <b>${s.definedChannels}</b></span>` : nothing} ${typeof s.filledGates === 'number' ? html`<span class=\"stat\">Filled gates <b>${s.filledGates}</b></span>` : nothing} ${gaps.length > 0 ? html`<span class=\"stat\">Gap gates <b>${gaps.join(', ')}</b></span>` : nothing} ${typeof s.coreDefined === 'boolean' ? html`<span class=\"stat\">${s.coreDefined ? 'Core defined' : 'Core open'}</span>` : nothing}</div>`;\n\t}\n\n\tprivate renderGroup(\n\t\tlabel: string,\n\t\tchannels: NonNullable<CalculatePentaResponse['channels']>,\n\t) {\n\t\tif (channels.length === 0) return nothing;\n\t\treturn html`<div class=\"section\"><h3>${label}</h3>${channels.map(\n\t\t\t\t(c) => html`<div class=\"row\"><span class=\"gates\">${c.gateA}-${c.gateB}</span> <span class=\"cname\">${c.name ?? ''}</span> <span class=\"badge ${c.defined ? 'defined' : 'open'}\">${c.defined ? 'Defined' : 'Open'}</span> ${c.isCore ? html`<span class=\"badge core\">Core</span>` : nothing}</div>`,\n\t\t\t)}</div>`;\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No penta data</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-hd-penta': RoxyHdPenta;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { CalculateVariablesResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\n/**\n * Human Design variables (the four arrows / PHS). Renders /human-design/variables: the four transformation arrows laid out as they sit on the bodygraph head (top-left/right Determination + Motivation, bottom-left/right Environment + Perspective), each showing its left/right direction, the digestion/environment/awareness/perspective labels, and its color/tone/base. A low-confidence calculation (near a color/tone boundary) is flagged.\n */\n@customElement('roxy-hd-variables')\nexport class RoxyHdVariables extends RoxyDataElement<CalculateVariablesResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.grid{gap:var(--roxy-space-md,1rem);grid-template-columns:repeat(2,1fr);display:grid}.arrow{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-md,1rem);gap:var(--roxy-space-xs,.25rem);display:grid}.arrow-head{align-items:center;gap:var(--roxy-space-sm,.5rem);display:flex}.glyph{color:var(--roxy-accent-ink,#b45309);font-size:1.75rem;line-height:1}.name{font-weight:var(--roxy-weight-bold,600)}.layer{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.05em}.labels{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a)}.ctb{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);font-variant-numeric:tabular-nums}.note{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-warning-fg,#9a3412)}@container (width<=28rem){.grid{grid-template-columns:1fr}}`,\n\t];\n\n\tprotected renderData(d: CalculateVariablesResponse) {\n\t\tconst arrows = d.arrows ?? [];\n\t\treturn html`<div class=\"wrap\" aria-label=\"Human Design variables\"><h2 class=\"title\">Variables</h2><div class=\"grid\">${arrows.map((a) => this.renderArrow(a))}</div>${\n\t\t\t\td.confident === false\n\t\t\t\t\t? html`<p class=\"note\" role=\"note\">Low confidence: a birth time near a color or tone boundary${typeof d.confidenceMarginDeg === 'number' ? ` (within ${d.confidenceMarginDeg}\u00B0)` : ''}. Verify the exact birth time.</p>`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n\n\tprivate renderArrow(\n\t\ta: NonNullable<CalculateVariablesResponse['arrows']>[number],\n\t) {\n\t\t// A left arrow is strategic/active, a right arrow receptive/passive in HD.\n\t\tconst glyph = a.direction === 'left' ? '\u2190' : '\u2192';\n\t\treturn html`<div class=\"arrow\"><div class=\"arrow-head\"><span class=\"glyph\" aria-hidden=\"true\">${glyph}</span> <span class=\"name\">${a.name ?? ''}</span></div>${a.layer ? html`<span class=\"layer\">${a.layer}</span>` : nothing} <span class=\"labels\">${[a.directionLabel, a.colorLabel].filter(Boolean).join(' \u00B7 ')} </span>${\n\t\t\t\ttypeof a.color === 'number'\n\t\t\t\t\t? html`<span class=\"ctb\">Color ${a.color} \u00B7 Tone ${a.tone} \u00B7 Base ${a.base}</span>`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No variables data</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-hd-variables': RoxyHdVariables;\n\t}\n}\n", "import { css, html, 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 { RoxyDataElement } from '../utils/base-element.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 RoxyDataElement<HexagramData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.card{background:var(--roxy-surface,#fff);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-lg,1.5rem);grid-template-columns:6rem 1fr;display:grid}@container (width<=480px){.card{grid-template-columns:1fr}}.glyphs{gap:var(--roxy-space-md,1rem);justify-items:center;display:grid}.symbol{color:var(--roxy-accent-ink,#b45309);font-size:3rem;line-height:1}.lines{gap:4px;width:4rem;display:grid}.line{justify-content:center;align-items:center;gap:4px;height:8px;display:flex}.seg{background:var(--roxy-fg,#0a0a0a);border-radius:1px;height:6px;display:block}.line.broken .seg{width:1.4rem}.line.solid .seg{width:3rem}.line.changing .seg{background:var(--roxy-accent,#f59e0b)}.title{font-size:var(--roxy-text-xl,1.5rem);font-weight:var(--roxy-weight-bold,600);letter-spacing:var(--roxy-tracking-tight);margin:0}.subtitle{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem);margin:0 0 var(--roxy-space-sm,.5rem)}.trigrams{gap:var(--roxy-space-md,1rem);margin-bottom:var(--roxy-space-sm,.5rem);color:var(--roxy-secondary,#475569);font-size:var(--roxy-text-xs,.75rem);text-transform:uppercase;letter-spacing:.06em;display:flex}.tri-glyph{font-size:var(--roxy-text-xl,1.5rem);color:var(--roxy-accent-ink,#b45309);vertical-align:middle;margin-right:4px}.judgment,.image,.message{margin:0 0 var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a)}.judgment:before{content:\"Judgment. \";font-weight:var(--roxy-weight-bold,600);color:var(--roxy-secondary,#475569)}.image:before{content:\"Image. \";font-weight:var(--roxy-weight-bold,600);color:var(--roxy-secondary,#475569)}.changing{margin-top:var(--roxy-space-md,1rem);padding-top:var(--roxy-space-md,1rem);border-top:1px solid var(--roxy-border,#e4e4e7);color:var(--roxy-accent-ink,#b45309);font-size:var(--roxy-text-sm,.875rem)}`,\n\t];\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\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No hexagram data</div>`;\n\t}\n\n\tprotected renderData() {\n\t\tconst resolved = this.resolveHexagram();\n\t\tif (!resolved) return this.renderEmpty();\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\"><div class=\"glyphs\">${h.symbol ? html`<div class=\"symbol\">${h.symbol}</div>` : nothing}<div class=\"lines\" aria-hidden=\"true\">${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\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}</div>`;\n\t\t\t\t\t\t})}</div></div><div><h2 class=\"title\">${h.number ? html`${h.number}.` : nothing}${h.english ?? h.chinese ?? 'Hexagram'}</h2><p class=\"subtitle\">${h.chinese ? html`${h.chinese}` : nothing} ${h.pinyin ? html`\u00B7 ${h.pinyin}` : nothing}</p><div class=\"trigrams\">${\n\t\t\t\t\t\th.upperTrigram\n\t\t\t\t\t\t\t? html`<div>Upper <span class=\"tri-glyph\">${TRIGRAM_GLYPH[h.upperTrigram] ?? ''}</span>${h.upperTrigram}</div>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t} ${\n\t\t\t\t\t\th.lowerTrigram\n\t\t\t\t\t\t\t? html`<div>Lower <span class=\"tri-glyph\">${TRIGRAM_GLYPH[h.lowerTrigram] ?? ''}</span>${h.lowerTrigram}</div>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}</div>${h.judgment ? html`<p class=\"judgment\">${h.judgment}</p>` : nothing} ${h.image ? html`<p class=\"image\">${h.image}</p>` : nothing} ${dailyMessage ? html`<p class=\"message\">${dailyMessage}</p>` : nothing} ${\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\tchanging.size > 0\n\t\t\t\t\t\t? html`<div class=\"changing\">Changing 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\tresultingHexagram?.english\n\t\t\t\t\t\t\t\t\t? html`Becomes hexagram ${resultingHexagram.number} ${resultingHexagram.english}.`\n\t\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t\t}</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</div></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", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { PLANET_GLYPH } from '../tokens/index.js';\nimport type { GetHoraResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { capitalize } from '../utils/string.js';\n\n/** HH:MM from a tz-naive ISO local datetime, without reparsing (the times are already wall-clock in the requested timezone). */\nfunction clockTime(iso: string | undefined): string {\n\tif (!iso) return '';\n\tconst t = String(iso).slice(11, 16);\n\treturn t || String(iso);\n}\n\ntype HoraPeriod = NonNullable<GetHoraResponse['dayHoras']>[number];\n\n/**\n * Vedic Hora (planetary hours) table. Renders /vedic-astrology/panchang/hora: the 12 daytime and 12 nighttime horas, each ruled by one of the seven classical planets in the Chaldean order, used for electional timing (start a venture in the hora of the planet that favours it). Day horas run sunrise to sunset, night horas sunset to next sunrise; each tile shows the ruling planet and its wall-clock window.\n */\n@customElement('roxy-hora-table')\nexport class RoxyHoraTable extends RoxyDataElement<GetHoraResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-md,1rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.subtitle{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem);margin:0}.cols{gap:var(--roxy-space-md,1rem);grid-template-columns:repeat(2,1fr);display:grid}.section-label{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;font-weight:var(--roxy-weight-bold,600);margin:0 0 var(--roxy-space-xs,.25rem) 0}.row{align-items:center;gap:var(--roxy-space-sm,.5rem);padding:var(--roxy-space-xs,.25rem) 0;border-bottom:1px solid var(--roxy-border,#e4e4e7);font-size:var(--roxy-text-sm,.875rem);display:flex}.row:last-child{border-bottom:none}.glyph{color:var(--roxy-accent-ink,#b45309);text-align:center;width:1.25em;font-size:1.15em;line-height:1}.planet{flex:1;font-weight:500}.time{color:var(--roxy-muted,#71717a);font-variant-numeric:tabular-nums;white-space:nowrap}.num{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);font-variant-numeric:tabular-nums;text-align:right;width:1.5em}@container (width<=30rem){.cols{grid-template-columns:1fr}}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No hora data</div>`;\n\t}\n\n\tprotected renderData(d: GetHoraResponse) {\n\t\tconst day = d.dayHoras ?? [];\n\t\tconst night = d.nightHoras ?? [];\n\t\tif (day.length === 0 && night.length === 0) return this.renderEmpty();\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Hora periods\"><div class=\"head\"><h2 class=\"title\">Hora</h2>${d.date ? html`<p class=\"subtitle\">${d.date}</p>` : nothing}</div><div class=\"cols\">${this.renderColumn('Day', day)} ${this.renderColumn('Night', night)}</div></div>`;\n\t}\n\n\tprivate renderColumn(label: string, horas: HoraPeriod[]) {\n\t\tif (horas.length === 0) return nothing;\n\t\treturn html`<div class=\"col\"><p class=\"section-label\">${label}</p>${horas.map(\n\t\t\t\t(h) => html`<div class=\"row\"><span class=\"glyph\" aria-hidden=\"true\">${PLANET_GLYPH[capitalize(h.planet ?? '')] ?? '\u00B7'}</span> <span class=\"planet\">${h.planet}</span> <span class=\"time\">${clockTime(h.start)}-${clockTime(h.end)}</span> ${typeof h.number === 'number' ? html`<span class=\"num\">${h.number}</span>` : nothing}</div>`,\n\t\t\t)}</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-hora-table': RoxyHoraTable;\n\t}\n}\n", "import { css, html, 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 { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { capitalize } from '../utils/string.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 RoxyDataElement<HoroscopeData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.card{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{align-items:center;gap:var(--roxy-space-md,1rem);display:flex}.glyph{color:var(--roxy-accent-ink,#b45309);font-size:2.25rem;line-height:1}.title{font-size:var(--roxy-text-xl,1.5rem);font-weight:var(--roxy-weight-bold,600);letter-spacing:var(--roxy-tracking-tight);text-transform:capitalize;margin:0}.date{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-muted,#71717a)}.energy{font-variant-numeric:tabular-nums;font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-secondary,#475569);margin-left:auto}.energy-bar{background:var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-full,9999px);vertical-align:middle;width:6rem;height:6px;margin-left:6px;display:inline-block;overflow:hidden}.energy-bar>span{background:var(--roxy-accent,#f59e0b);height:100%;transition:width var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,cubic-bezier(.4, 0, .2, 1));display:block}.overview{font-size:var(--roxy-text-base,1rem);color:var(--roxy-fg,#0a0a0a);margin:0}.sections{gap:var(--roxy-space-md,1rem);grid-template-columns:repeat(auto-fit,minmax(12rem,1fr));display:grid}.section h3{margin:0 0 var(--roxy-space-xs,.25rem) 0;font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;letter-spacing:.06em}.section p{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);margin:0}.lucky{gap:var(--roxy-space-sm,.5rem);border-top:1px solid var(--roxy-border,#e4e4e7);padding-top:var(--roxy-space-md,1rem);font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-secondary,#475569);flex-wrap:wrap;display:flex}.lucky strong{color:var(--roxy-fg,#0a0a0a);font-weight:var(--roxy-weight-bold,600)}.compat-wrap{align-items:center;gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;width:100%;display:flex}.compat{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;display:flex}.compat span{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 16%, transparent);color:var(--roxy-fg,#0a0a0a);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);text-transform:capitalize;padding:2px 8px}`,\n\t];\n\n\t@property({ type: String, reflect: true })\n\tperiod: 'daily' | 'weekly' | 'monthly' = 'daily';\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No horoscope data</div>`;\n\t}\n\n\tprotected renderData(d: HoroscopeData) {\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 class=\"card\" aria-label=\"${`${this.period} horoscope for ${sign}`}\"><header class=\"head\"><span class=\"glyph\" aria-hidden=\"true\">${glyph}</span><div><h2 class=\"title\">${sign} ${this.period}</h2>${dateLabel ? html`<div class=\"date\">${dateLabel}</div>` : nothing}</div>${\n\t\t\t\t\tenergy !== null\n\t\t\t\t\t\t? html`<span class=\"energy\" aria-label=\"${`Energy ${energy} of 10`}\">Energy ${energy}/10 <span class=\"energy-bar\"><span style=\"width:${(energy / 10) * 100}%\"></span></span></span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</header>${d.overview ? html`<p class=\"overview\">${d.overview}</p>` : nothing}<div class=\"sections\">${\n\t\t\t\t\td.love\n\t\t\t\t\t\t? html`<div class=\"section\"><h3>Love</h3><p>${d.love}</p></div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} ${\n\t\t\t\t\td.career\n\t\t\t\t\t\t? html`<div class=\"section\"><h3>Career</h3><p>${d.career}</p></div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} ${\n\t\t\t\t\td.health\n\t\t\t\t\t\t? html`<div class=\"section\"><h3>Health</h3><p>${d.health}</p></div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} ${\n\t\t\t\t\td.finance\n\t\t\t\t\t\t? html`<div class=\"section\"><h3>Finance</h3><p>${d.finance}</p></div>`\n\t\t\t\t\t\t: nothing\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\"><h3>Advice</h3><p>${d.advice}</p></div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</div>${(() => {\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\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\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\tluckyNumbers.length\n\t\t\t\t\t\t\t\t? html`<span>Lucky numbers <strong>${luckyNumbers.join(', ')}</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\tluckyDays.length\n\t\t\t\t\t\t\t\t? html`<span>Lucky days <strong>${luckyDays.join(', ')}</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\tcompatibleSigns.length\n\t\t\t\t\t\t\t\t? html`<span class=\"compat-wrap\">Best with <span class=\"compat\">${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></span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}</div>`;\n\t\t\t})()}</article>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-horoscope-card': RoxyHoroscopeCard;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\nimport type { KpChartResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatNumber } from '../utils/format.js';\n\ntype Tab = 'planets' | 'cusps';\n\n/** A planet or node row, normalized so planets and Rahu/Ketu share a table. */\ninterface KpBody {\n\tname: string;\n\tsign?: string;\n\thouse?: number;\n\tnakshatra?: string;\n\tstarLord?: string;\n\tsubLord?: string;\n\tsubSubLord?: string;\n\tkpNumber?: number;\n\tretrograde?: boolean;\n}\n\n/**\n * KP (Krishnamurti Paddhati) chart. Renders /vedic-astrology/kp/chart: the\n * Ascendant with its full stellar hierarchy, a planets-and-nodes table, and a\n * Placidus cusps table. The cusp and planet sub lords are the primary\n * predictive surface in KP astrology, so each row carries star lord, sub lord,\n * sub-sub lord, and KP number (1-249).\n */\n@customElement('roxy-kp-chart')\nexport class RoxyKpChart extends RoxyDataElement<KpChartResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);background:var(--roxy-surface,#fff);box-shadow:var(--roxy-shadow-sm);width:100%;overflow:auto}.head{padding:var(--roxy-space-md,1rem);border-bottom:1px solid var(--roxy-border,#e4e4e7);gap:var(--roxy-space-xs,.25rem);display:grid}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.asc,.ayan{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}.asc strong{color:var(--roxy-fg,#0a0a0a)}.tablist{padding:0 var(--roxy-space-md,1rem);border-bottom:2px solid var(--roxy-border,#e4e4e7);gap:2px;display:flex}.tab{padding:var(--roxy-space-xs,.25rem) var(--roxy-space-md,1rem);font-size:var(--roxy-text-sm,.875rem);cursor:pointer;color:var(--roxy-muted,#71717a);background:0 0;border:none;border-bottom:2px solid #0000;margin-bottom:-2px;font-family:inherit}.tab[aria-selected=true]{color:var(--roxy-accent-ink,#b45309);border-bottom-color:var(--roxy-accent,#f59e0b);font-weight:var(--roxy-weight-bold,600)}.tab:hover:not([aria-selected=true]){color:var(--roxy-fg,#0a0a0a)}table{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem);min-width:620px}thead{background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 20%, transparent)}th,td{padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);text-align:left;white-space:nowrap}th{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;font-size:var(--roxy-text-xs,.75rem);letter-spacing:.04em}tbody tr{border-top:1px solid var(--roxy-border,#e4e4e7)}td.body{font-weight:var(--roxy-weight-bold,600);color:var(--roxy-fg,#0a0a0a)}.retro{color:var(--roxy-warning-fg,#9a3412);font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);margin-left:4px}.num{font-variant-numeric:tabular-nums}`,\n\t];\n\n\t@state()\n\tprivate activeTab: Tab = 'planets';\n\n\t/** Merge the 7 planets and the two nodes into one ordered body list. */\n\tprivate bodies(): KpBody[] {\n\t\tconst d = this.data;\n\t\tif (!d) return [];\n\t\tconst rows: KpBody[] = (d.planets ?? []).map((p) => ({\n\t\t\tname: p.planet,\n\t\t\tsign: p.sign,\n\t\t\thouse: p.house,\n\t\t\tnakshatra: p.nakshatra,\n\t\t\tstarLord: p.starLord,\n\t\t\tsubLord: p.subLord,\n\t\t\tsubSubLord: p.subSubLord,\n\t\t\tkpNumber: p.kpNumber,\n\t\t\tretrograde: p.retrograde,\n\t\t}));\n\t\tconst nodes = d.nodes;\n\t\tfor (const [name, node] of [\n\t\t\t['Rahu', nodes?.rahu],\n\t\t\t['Ketu', nodes?.ketu],\n\t\t] as const) {\n\t\t\tif (node) {\n\t\t\t\trows.push({\n\t\t\t\t\tname,\n\t\t\t\t\tsign: node.sign,\n\t\t\t\t\thouse: node.house,\n\t\t\t\t\tnakshatra: node.nakshatra,\n\t\t\t\t\tstarLord: node.starLord,\n\t\t\t\t\tsubLord: node.subLord,\n\t\t\t\t\tsubSubLord: node.subSubLord,\n\t\t\t\t\tretrograde: true,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn rows;\n\t}\n\n\tprivate onTabKeyDown(e: KeyboardEvent) {\n\t\tif (e.key !== 'ArrowRight' && e.key !== 'ArrowLeft') return;\n\t\te.preventDefault();\n\t\tthis.activeTab = this.activeTab === 'planets' ? 'cusps' : 'planets';\n\t\tconst next = this.activeTab;\n\t\trequestAnimationFrame(() => {\n\t\t\tthis.shadowRoot\n\t\t\t\t?.querySelector<HTMLButtonElement>(`#tab-${next}`)\n\t\t\t\t?.focus();\n\t\t});\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No KP chart data</div>`;\n\t}\n\n\tprotected renderData(d: KpChartResponse) {\n\t\tconst asc = d.ascendant;\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"KP chart\" tabindex=\"0\"><header class=\"head\"><h2 class=\"title\">KP chart</h2>${\n\t\t\t\t\tasc\n\t\t\t\t\t\t? html`<div class=\"asc\">Ascendant: <strong>${asc.sign ?? ''}</strong> ${asc.nakshatra ? html`\u00B7 ${asc.nakshatra}` : nothing} ${asc.subLord ? html`\u00B7 sub lord ${asc.subLord}` : nothing} ${typeof asc.kpNumber === 'number' ? html`\u00B7 KP ${asc.kpNumber}` : nothing}</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} ${\n\t\t\t\t\ttypeof d.meta?.ayanamsa === 'number'\n\t\t\t\t\t\t? html`<div class=\"ayan\">${d.meta.ayanamsaType ?? 'Ayanamsa'}: ${formatNumber(d.meta.ayanamsa, 4)}\u00B0 ${d.meta.houseSystem ? html`\u00B7 ${d.meta.houseSystem} houses` : nothing}</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</header><div class=\"tablist\" role=\"tablist\" aria-label=\"KP chart views\" @keydown=\"${this.onTabKeyDown}\">${(['planets', 'cusps'] as const).map(\n\t\t\t\t\t(t) => html`<button class=\"tab\" role=\"tab\" id=\"tab-${t}\" aria-selected=\"${this.activeTab === t ? 'true' : 'false'}\" aria-controls=\"panel-${t}\" tabindex=\"${this.activeTab === t ? '0' : '-1'}\" @click=\"${() => {\n\t\t\t\t\t\t\tthis.activeTab = t;\n\t\t\t\t\t\t}}\">${t === 'planets' ? 'Planets' : 'Cusps'}</button>`,\n\t\t\t\t)}</div><div id=\"panel-${this.activeTab}\" role=\"tabpanel\" aria-labelledby=\"tab-${this.activeTab}\">${this.activeTab === 'planets' ? this.renderPlanets() : this.renderCusps()}</div></div>`;\n\t}\n\n\tprivate renderPlanets() {\n\t\tconst bodies = this.bodies();\n\t\tif (!bodies.length)\n\t\t\treturn html`<p class=\"roxy-empty\" role=\"status\">No planets</p>`;\n\t\treturn html`<table role=\"table\" aria-label=\"KP planets and nodes\"><thead><tr><th scope=\"col\">Body</th><th scope=\"col\">Sign</th><th scope=\"col\">House</th><th scope=\"col\">Nakshatra</th><th scope=\"col\">Star lord</th><th scope=\"col\">Sub lord</th><th scope=\"col\">Sub sub lord</th><th scope=\"col\">KP no.</th></tr></thead><tbody>${bodies.map(\n\t\t\t\t\t(b) => html`<tr><td class=\"body\">${b.name}${b.retrograde ? html`<span class=\"retro\">R</span>` : nothing}</td><td>${b.sign ?? ''}</td><td class=\"num\">${typeof b.house === 'number' ? b.house : ''}</td><td>${b.nakshatra ?? ''}</td><td>${b.starLord ?? ''}</td><td>${b.subLord ?? ''}</td><td>${b.subSubLord ?? ''}</td><td class=\"num\">${typeof b.kpNumber === 'number' ? b.kpNumber : ''}</td></tr>`,\n\t\t\t\t)}</tbody></table>`;\n\t}\n\n\tprivate renderCusps() {\n\t\tconst cusps = this.data?.cusps ?? [];\n\t\tif (!cusps.length)\n\t\t\treturn html`<p class=\"roxy-empty\" role=\"status\">No cusps</p>`;\n\t\treturn html`<table role=\"table\" aria-label=\"KP Placidus cusps\"><thead><tr><th scope=\"col\">House</th><th scope=\"col\">Sign</th><th scope=\"col\">Sign lord</th><th scope=\"col\">Nakshatra</th><th scope=\"col\">Star lord</th><th scope=\"col\">Sub lord</th><th scope=\"col\">Sub sub lord</th><th scope=\"col\">KP no.</th></tr></thead><tbody>${cusps.map(\n\t\t\t\t\t(c) => html`<tr><td class=\"body num\">${c.house}</td><td>${c.sign ?? ''}</td><td>${c.signLord ?? ''}</td><td>${c.nakshatra ?? ''}</td><td>${c.starLord ?? ''}</td><td>${c.subLord ?? ''}</td><td>${c.subSubLord ?? ''}</td><td class=\"num\">${typeof c.kpNumber === 'number' ? c.kpNumber : ''}</td></tr>`,\n\t\t\t\t)}</tbody></table>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-kp-chart': RoxyKpChart;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { KpPlanetsResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.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 RoxyDataElement<KpPlanetsResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);background:var(--roxy-surface,#fff);box-shadow:var(--roxy-shadow-sm);overflow:auto}.head{padding:var(--roxy-space-md,1rem);border-bottom:1px solid var(--roxy-border,#e4e4e7);justify-content:space-between;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.ayanamsa{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}table{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem);min-width:560px}thead{background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 20%, transparent)}th,td{padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);text-align:left;white-space:nowrap}th{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;font-size:var(--roxy-text-xs,.75rem);letter-spacing:.04em}tbody tr{border-top:1px solid var(--roxy-border,#e4e4e7)}td.planet{font-weight:var(--roxy-weight-bold,600);color:var(--roxy-fg,#0a0a0a)}.retro{color:var(--roxy-warning-fg,#9a3412);font-size:var(--roxy-text-xs,.75rem);margin-left:4px}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No KP data</div>`;\n\t}\n\n\tprotected renderData(d: KpPlanetsResponse) {\n\t\tconst planets = d.planets ?? [];\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"KP planets table\" tabindex=\"0\"><header class=\"head\"><h2 class=\"title\">KP planets</h2>${\n\t\t\t\t\ttypeof d.ayanamsa === 'number'\n\t\t\t\t\t\t? html`<span class=\"ayanamsa\">Ayanamsa: ${formatNumber(d.ayanamsa, 2)}\u00B0</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</header><table role=\"table\"><thead><tr><th scope=\"col\">Planet</th><th scope=\"col\">Sign</th><th scope=\"col\">Sign lord</th><th scope=\"col\">Nakshatra</th><th scope=\"col\">Star lord</th><th scope=\"col\">Sub lord</th><th scope=\"col\">Sub sub lord</th><th scope=\"col\">KP no.</th></tr></thead><tbody>${planets.map(\n\t\t\t\t\t\t(p) => html`<tr><td class=\"planet\">${p.planet} ${p.retrograde ? html`<span class=\"retro\">R</span>` : nothing}</td><td>${p.sign ?? ''}</td><td>${p.signLord ?? ''}</td><td>${p.nakshatra ?? ''}</td><td>${p.nakshatraLord ?? ''}</td><td>${p.subLord ?? ''}</td><td>${p.subSubLord ?? ''}</td><td>${p.kpNumber ?? ''}</td></tr>`,\n\t\t\t\t\t)}</tbody></table></div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-kp-planets-table': RoxyKpPlanetsTable;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { KpRulingPlanetsResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\n/**\n * KP ruling planets card. Renders /vedic-astrology/kp/ruling-planets: the day\n * lord, the Moon and Lagna stellar hierarchies (sign lord, star lord, sub\n * lord, sub-sub lord), the consolidated ruling-planet list ordered by\n * strength, and, when birth data is supplied, the house significators per\n * planet. The primary horary timing tool in KP astrology.\n */\n@customElement('roxy-kp-ruling-planets')\nexport class RoxyKpRulingPlanets extends RoxyDataElement<KpRulingPlanetsResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);background:var(--roxy-surface,#fff);padding:var(--roxy-space-md,1rem);gap:var(--roxy-space-md,1rem);box-shadow:var(--roxy-shadow-sm);display:grid}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.day-lord{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}.day-lord strong{color:var(--roxy-fg,#0a0a0a)}.groups{gap:var(--roxy-space-md,1rem);grid-template-columns:repeat(auto-fit,minmax(11rem,1fr));display:grid}.group h3{margin:0 0 var(--roxy-space-xs,.25rem);font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.05em}.group dl{gap:2px var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-sm,.875rem);grid-template-columns:auto 1fr;margin:0;display:grid}.group dt{color:var(--roxy-muted,#71717a)}.group dd{color:var(--roxy-fg,#0a0a0a);font-weight:var(--roxy-weight-bold,600);margin:0}.rp-list{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;align-items:center;display:flex}.rp-label{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.05em;margin-right:var(--roxy-space-xs,.25rem)}.rp{font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 18%, transparent);color:var(--roxy-fg,#0a0a0a);border-radius:999px;align-items:center;gap:.3em;padding:.15em .6em;display:inline-flex}.rp .rank{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-accent-ink,#b45309)}table{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem)}th,td{padding:var(--roxy-space-xs,.25rem) var(--roxy-space-sm,.5rem);text-align:left;border-bottom:1px solid var(--roxy-border,#e4e4e7)}th{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;font-size:var(--roxy-text-xs,.75rem);letter-spacing:.04em}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No ruling planets data</div>`;\n\t}\n\n\tprotected renderData(d: KpRulingPlanetsResponse) {\n\t\tconst significators = d.significators ?? [];\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"KP ruling planets\"><header><h2 class=\"title\">KP ruling planets</h2>${\n\t\t\t\t\td.dayLord\n\t\t\t\t\t\t? html`<div class=\"day-lord\">Day lord: <strong>${d.dayLord}</strong></div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</header><div class=\"groups\"><div class=\"group\"><h3>Moon</h3><dl><dt>Sign lord</dt><dd>${d.moonSignLord ?? ''}</dd><dt>Star lord</dt><dd>${d.moonStarLord ?? ''}</dd><dt>Sub lord</dt><dd>${d.moonSublord ?? ''}</dd><dt>Sub-sub lord</dt><dd>${d.moonSubSublord ?? ''}</dd></dl></div><div class=\"group\"><h3>Lagna</h3><dl><dt>Sign lord</dt><dd>${d.lagnaSignLord ?? ''}</dd><dt>Star lord</dt><dd>${d.lagnaStarLord ?? ''}</dd><dt>Sub lord</dt><dd>${d.lagnaSublord ?? ''}</dd><dt>Sub-sub lord</dt><dd>${d.lagnaSubSublord ?? ''}</dd></dl></div></div>${\n\t\t\t\td.rulingPlanets?.length\n\t\t\t\t\t? html`<div class=\"rp-list\" role=\"list\" aria-label=\"Ruling planets by strength\"><span class=\"rp-label\">Ruling planets</span> ${d.rulingPlanets.map(\n\t\t\t\t\t\t\t(p, i) =>\n\t\t\t\t\t\t\t\thtml`<span class=\"rp\" role=\"listitem\"><span class=\"rank\">${i + 1}</span> ${p}</span>`,\n\t\t\t\t\t\t)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tsignificators.length\n\t\t\t\t\t? html`<table aria-label=\"House significators\"><thead><tr><th scope=\"col\">Planet</th><th scope=\"col\">Signifies houses</th></tr></thead><tbody>${significators.map(\n\t\t\t\t\t\t\t\t(s) => html`<tr><td>${s.planet}</td><td>${(s.signifies ?? []).join(', ')}</td></tr>`,\n\t\t\t\t\t\t\t)}</tbody></table>`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-kp-ruling-planets': RoxyKpRulingPlanets;\n\t}\n}\n", "import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport type { SearchCitiesResponse } from '../types/index.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { debounce } from '../utils/debounce.js';\n\ntype CityResult = SearchCitiesResponse['cities'][number];\n\n/**\n * Stateful location search input. Calls /location/search and emits\n * `roxy-location-select` CustomEvent with the chosen city. Required for any\n * chart endpoint.\n *\n * Behavior: 300ms input debounce, click-outside dismiss, keyboard navigation\n * with arrow keys / Enter / Escape, AbortController on stale requests.\n *\n * Attributes:\n * api-key optional. Direct call to roxyapi.com when set.\n * publishable-key optional. Browser-safe pk_* key with allowed_origins.\n * endpoint optional. Override URL (default https://roxyapi.com/api/v2/location/search).\n * placeholder optional. Input placeholder.\n * default-value optional. Pre-filled query.\n */\n@customElement('roxy-location-search')\nexport class RoxyLocationSearch extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`:host{display:block;position:relative}.field{position:relative}input{width:100%;padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);font-size:var(--roxy-text-base,1rem);color:var(--roxy-fg,#0a0a0a);background:var(--roxy-bg,#fff);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);transition:border-color var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,cubic-bezier(.4, 0, .2, 1));box-sizing:border-box;font-family:inherit}input:focus{outline:2px solid var(--roxy-ring,#f59e0b66);outline-offset:2px;border-color:var(--roxy-accent-ink,#b45309)}.spinner{border:2px solid var(--roxy-muted,#71717a);border-top-color:#0000;border-radius:50%;width:14px;height:14px;animation:.7s linear infinite roxy-spin;position:absolute;top:50%;right:12px;transform:translateY(-50%)}@keyframes roxy-spin{to{transform:translateY(-50%)rotate(360deg)}}@media (prefers-reduced-motion:reduce){.spinner{animation:none}}.results{z-index:50;background:var(--roxy-bg,#fff);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);box-shadow:var(--roxy-shadow-md);max-height:22rem;animation:roxy-fade-in var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,cubic-bezier(.4, 0, .2, 1));position:absolute;top:calc(100% + 4px);left:0;right:0;overflow-y:auto}.option{align-items:baseline;gap:var(--roxy-space-sm,.5rem);width:100%;padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);text-align:left;font-family:inherit;font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);cursor:pointer;transition:background-color var(--roxy-motion-duration,.2s);background:0 0;border:0;display:flex}.option:hover,.option[aria-selected=true]{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 10%, transparent)}.option .city{font-weight:var(--roxy-weight-bold,600)}.option .where{color:var(--roxy-muted,#71717a);flex-grow:1}.option .tz{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);font-variant-numeric:tabular-nums}.empty{padding:var(--roxy-space-md,1rem);color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}`,\n\t];\n\n\t@property({ type: String, attribute: 'api-key' })\n\tapiKey?: string;\n\n\t@property({ type: String, attribute: 'publishable-key' })\n\tpublishableKey?: string;\n\n\t@property({ type: String })\n\tendpoint = 'https://roxyapi.com/api/v2/location/search';\n\n\t@property({ type: String })\n\tplaceholder = 'Search city';\n\n\t@property({ type: String, attribute: 'default-value' })\n\tdefaultValue = '';\n\n\t@state()\n\tprivate query = '';\n\n\t@state()\n\tprivate results: CityResult[] = [];\n\n\t@state()\n\tprivate isOpen = false;\n\n\t@state()\n\tprivate isLoading = false;\n\n\t@state()\n\tprivate highlight = -1;\n\n\tprivate clickOutsideHandler?: (e: MouseEvent) => void;\n\tprivate abortController?: AbortController;\n\tprivate secretKeyWarned = false;\n\tprivate debouncedFetch = debounce((q: string) => {\n\t\tvoid this.fetchResults(q);\n\t}, 300);\n\n\tconnectedCallback(): void {\n\t\tsuper.connectedCallback();\n\t\tthis.query = this.defaultValue;\n\t\tthis.clickOutsideHandler = (e: MouseEvent) => {\n\t\t\tconst path = e.composedPath();\n\t\t\tif (!path.includes(this)) this.isOpen = false;\n\t\t};\n\t\tdocument.addEventListener('mousedown', this.clickOutsideHandler);\n\t}\n\n\tdisconnectedCallback(): void {\n\t\tsuper.disconnectedCallback();\n\t\tif (this.clickOutsideHandler) {\n\t\t\tdocument.removeEventListener('mousedown', this.clickOutsideHandler);\n\t\t}\n\t\tthis.debouncedFetch.cancel();\n\t\tif (this.abortController) {\n\t\t\tthis.abortController.abort();\n\t\t\tthis.abortController = undefined;\n\t\t}\n\t}\n\n\tprivate warnIfSecretKey() {\n\t\tif (this.secretKeyWarned) return;\n\t\tif (!this.apiKey) return;\n\t\t// Browser-safe publishable keys carry the `pk_` prefix and a server-side\n\t\t// origin allowlist. Anything else (a raw secret key, UUID-style token)\n\t\t// must not ship to the browser.\n\t\tif (this.apiKey.startsWith('pk_')) return;\n\t\tthis.secretKeyWarned = true;\n\t\tconst message =\n\t\t\t'Possible secret key in client-side <roxy-location-search>; use a `pk_` publishable key with origin allowlist instead.';\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.warn(message);\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('roxy-validation-error', {\n\t\t\t\tdetail: { reason: 'possible-secret-key', message },\n\t\t\t\tbubbles: true,\n\t\t\t\tcomposed: true,\n\t\t\t}),\n\t\t);\n\t}\n\n\tprivate async fetchResults(q: string) {\n\t\tthis.warnIfSecretKey();\n\t\t// Abort any in-flight request so a stale response cannot overwrite a\n\t\t// fresher one (debounced typing) or land after disconnect.\n\t\tif (this.abortController) this.abortController.abort();\n\t\tconst controller = new AbortController();\n\t\tthis.abortController = controller;\n\t\tthis.isLoading = true;\n\t\ttry {\n\t\t\tconst url = new URL(this.endpoint);\n\t\t\turl.searchParams.set('q', q);\n\t\t\turl.searchParams.set('limit', '8');\n\t\t\tconst headers: Record<string, string> = {\n\t\t\t\tAccept: 'application/json',\n\t\t\t};\n\t\t\t// publishable-key wins when both are set. Surfacing the conflict at the\n\t\t\t// console (not as a thrown error) avoids breaking widgets that legitimately\n\t\t\t// have a stale secret key around while migrating to publishable.\n\t\t\tif (this.apiKey && this.publishableKey) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t'[roxy-location-search] both api-key and publishable-key set; using publishable-key. Remove api-key from your widget markup.',\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst key = this.publishableKey ?? this.apiKey;\n\t\t\tif (key) headers['X-API-Key'] = key;\n\t\t\tconst res = await fetch(url, { headers, signal: controller.signal });\n\t\t\tif (!res.ok) throw new Error(`HTTP ${res.status}`);\n\t\t\tconst json = (await res.json()) as SearchCitiesResponse;\n\t\t\tif (controller.signal.aborted) return;\n\t\t\tthis.results = json.cities ?? [];\n\t\t\tthis.isOpen = this.results.length > 0;\n\t\t\tthis.highlight = this.results.length > 0 ? 0 : -1;\n\t\t} catch (err) {\n\t\t\tif ((err as { name?: string })?.name === 'AbortError') return;\n\t\t\tthis.results = [];\n\t\t\tthis.isOpen = false;\n\t\t} finally {\n\t\t\tif (this.abortController === controller) {\n\t\t\t\tthis.abortController = undefined;\n\t\t\t}\n\t\t\tif (!controller.signal.aborted) this.isLoading = false;\n\t\t}\n\t}\n\n\tprivate onInput = (e: Event) => {\n\t\tconst value = (e.target as HTMLInputElement).value;\n\t\tthis.query = value;\n\t\tif (value.length < 2) {\n\t\t\tthis.results = [];\n\t\t\tthis.isOpen = false;\n\t\t\tthis.highlight = -1;\n\t\t\treturn;\n\t\t}\n\t\tthis.debouncedFetch(value);\n\t};\n\n\tprivate select(city: CityResult) {\n\t\tthis.query = `${city.city}${city.province ? `, ${city.province}` : ''}, ${city.country}`;\n\t\tthis.isOpen = false;\n\t\tthis.results = [];\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('roxy-location-select', {\n\t\t\t\tdetail: city,\n\t\t\t\tbubbles: true,\n\t\t\t\tcomposed: true,\n\t\t\t}),\n\t\t);\n\t}\n\n\tprivate onKeyDown = (e: KeyboardEvent) => {\n\t\tif (!this.isOpen || this.results.length === 0) {\n\t\t\tif (e.key === 'ArrowDown' && this.query.length >= 2) {\n\t\t\t\tvoid this.fetchResults(this.query);\n\t\t\t\te.preventDefault();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (e.key === 'ArrowDown') {\n\t\t\te.preventDefault();\n\t\t\tthis.highlight = (this.highlight + 1) % this.results.length;\n\t\t} else if (e.key === 'ArrowUp') {\n\t\t\te.preventDefault();\n\t\t\tthis.highlight =\n\t\t\t\t(this.highlight - 1 + this.results.length) % this.results.length;\n\t\t} else if (e.key === 'Enter') {\n\t\t\te.preventDefault();\n\t\t\tconst target = this.results[this.highlight] ?? this.results[0];\n\t\t\tif (target) this.select(target);\n\t\t} else if (e.key === 'Escape') {\n\t\t\tthis.isOpen = false;\n\t\t}\n\t};\n\n\trender() {\n\t\treturn html`<div class=\"field\"><input type=\"text\" role=\"combobox\" aria-expanded=\"${this.isOpen ? 'true' : 'false'}\" aria-controls=\"roxy-location-listbox\" aria-activedescendant=\"${\n\t\t\t\t\tthis.isOpen && this.highlight >= 0\n\t\t\t\t\t\t? `roxy-location-option-${this.highlight}`\n\t\t\t\t\t\t: ''\n\t\t\t\t}\" aria-autocomplete=\"list\" autocomplete=\"off\" placeholder=\"${this.placeholder}\" .value=\"${this.query}\" @input=\"${this.onInput}\" @keydown=\"${this.onKeyDown}\" @focus=\"${() => {\n\t\t\t\t\tif (this.results.length > 0) this.isOpen = true;\n\t\t\t\t}}\"> ${this.isLoading ? html`<span class=\"spinner\" role=\"status\" aria-label=\"Loading\"></span>` : nothing} ${\n\t\t\t\tthis.isOpen\n\t\t\t\t\t? html`<ul id=\"roxy-location-listbox\" class=\"results\" role=\"listbox\">${\n\t\t\t\t\t\t\tthis.results.length === 0\n\t\t\t\t\t\t\t\t? html`<li class=\"empty\" role=\"status\">No cities found</li>`\n\t\t\t\t\t\t\t\t: this.results.map(\n\t\t\t\t\t\t\t\t\t\t(city, idx) => html`<li role=\"presentation\"><button type=\"button\" class=\"option\" role=\"option\" id=\"${`roxy-location-option-${idx}`}\" aria-selected=\"${this.highlight === idx ? 'true' : 'false'}\" @click=\"${() => this.select(city)}\" @mouseenter=\"${() => {\n\t\t\t\t\t\t\t\t\t\t\t\tthis.highlight = idx;\n\t\t\t\t\t\t\t\t\t\t\t}}\"><span class=\"city\">${city.city}</span> <span class=\"where\">${city.province ? html`${city.province},` : ''}${city.country}</span> <span class=\"tz\">UTC${city.utcOffset >= 0 ? '+' : ''}${city.utcOffset}</span></button></li>`,\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}</ul>`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-location-search': RoxyLocationSearch;\n\t}\n}\n", "/**\n * Lightweight debounce for input handlers. Used by location search.\n *\n * The returned function exposes a `.cancel()` method so callers can clear a\n * pending invocation when the host element disconnects, preventing the timer\n * from firing on a detached node and mutating reactive state after teardown.\n */\nexport interface Debounced<F extends (...args: never[]) => unknown> {\n\t(...args: Parameters<F>): void;\n\tcancel: () => void;\n}\n\nexport function debounce<F extends (...args: never[]) => unknown>(\n\tfn: F,\n\twait: number,\n): Debounced<F> {\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\tconst debounced = ((...args: Parameters<F>) => {\n\t\tif (timer) clearTimeout(timer);\n\t\ttimer = setTimeout(() => {\n\t\t\ttimer = undefined;\n\t\t\tfn(...args);\n\t\t}, wait);\n\t}) as Debounced<F>;\n\tdebounced.cancel = () => {\n\t\tif (timer) {\n\t\t\tclearTimeout(timer);\n\t\t\ttimer = undefined;\n\t\t}\n\t};\n\treturn debounced;\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { MOON_PHASE_EMOJI } from '../tokens/index.js';\nimport type {\n\tGetCurrentMoonPhaseResponse,\n\tGetMoonCalendarResponse,\n\tGetUpcomingMoonPhasesResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatNumber } from '../utils/format.js';\n\ntype MoonPhaseData =\n\t| GetCurrentMoonPhaseResponse\n\t| GetUpcomingMoonPhasesResponse\n\t| GetMoonCalendarResponse;\ntype MoonListEntry =\n\t| GetUpcomingMoonPhasesResponse['phases'][number]\n\t| GetMoonCalendarResponse['calendar'][number];\n\n/**\n * Moon phase card. Renders /astrology/moon-phase/{current,upcoming,calendar/...}.\n */\n@customElement('roxy-moon-phase')\nexport class RoxyMoonPhase extends RoxyDataElement<MoonPhaseData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.card{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.hero{align-items:center;gap:var(--roxy-space-md,1rem);display:flex}.emoji{font-size:3rem;line-height:1}.label{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);text-transform:capitalize;margin:0}.date{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}.stats{gap:var(--roxy-space-md,1rem);font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-secondary,#475569);grid-template-columns:repeat(auto-fit,minmax(8rem,1fr));display:grid}.stats div span:first-child{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);text-transform:uppercase;letter-spacing:.06em;display:block}.stats strong{color:var(--roxy-fg,#0a0a0a);font-variant-numeric:tabular-nums}.meaning{color:var(--roxy-fg,#0a0a0a)}.keywords{gap:var(--roxy-space-xs,.25rem);margin-top:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.keywords span{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 14%, transparent);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);padding:2px 8px}.list{gap:var(--roxy-space-sm,.5rem);display:grid}.list-item{gap:var(--roxy-space-sm,.5rem);border-bottom:1px solid var(--roxy-border,#e4e4e7);padding:var(--roxy-space-sm,.5rem) 0;font-size:var(--roxy-text-sm,.875rem);grid-template-columns:2.5rem 1fr auto;align-items:center;display:grid}.list-item:last-child{border-bottom:none}`,\n\t];\n\n\t@property({ type: String, reflect: true })\n\tmode: 'current' | 'upcoming' | 'calendar' = 'current';\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No moon phase data</div>`;\n\t}\n\n\tprotected renderData(d: MoonPhaseData) {\n\t\tconst list: MoonListEntry[] =\n\t\t\t'phases' in d ? d.phases : 'calendar' in d ? d.calendar : [];\n\t\tif (this.mode !== 'current' && list.length > 0) {\n\t\t\tconst month = 'month' in d ? d.month : undefined;\n\t\t\tconst year = 'year' in d ? d.year : undefined;\n\t\t\treturn html`<article class=\"card\" aria-label=\"Moon phase calendar\"><h2 class=\"label\">${month ?? 'Moon phases'} ${year ?? ''}</h2><div class=\"list\" role=\"list\">${list.map((phase) => this.renderListItem(phase))}</div></article>`;\n\t\t}\n\t\tif (!('phase' in d)) return nothing;\n\t\treturn this.renderSingle(d);\n\t}\n\n\tprivate renderSingle(d: GetCurrentMoonPhaseResponse) {\n\t\tconst emoji = phaseEmoji(d.phase);\n\t\treturn html`<article class=\"card\" aria-label=\"Current moon phase\"><div class=\"hero\"><span class=\"emoji\" aria-hidden=\"true\">${emoji}</span><div><h2 class=\"label\">${d.phase ?? 'Moon'}</h2>${d.date ? html`<div class=\"date\">${d.date}</div>` : nothing}</div></div><div class=\"stats\">${\n\t\t\t\t\ttypeof d.illumination === 'number'\n\t\t\t\t\t\t? html`<div><span>Illumination</span> <strong>${formatIllumination(d.illumination)}</strong></div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} ${\n\t\t\t\t\ttypeof d.age === 'number'\n\t\t\t\t\t\t? html`<div><span>Age</span> <strong>${formatNumber(d.age, 1)} days</strong></div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} ${\n\t\t\t\t\td.sign\n\t\t\t\t\t\t? html`<div><span>Sign</span> <strong>${d.sign}</strong></div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} ${\n\t\t\t\t\ttypeof d.distance === 'number'\n\t\t\t\t\t\t? html`<div><span>Distance</span> <strong>${(d.distance / 1000).toFixed(0)}k km</strong></div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</div>${\n\t\t\t\td.meaning?.description\n\t\t\t\t\t? html`<p class=\"meaning\">${d.meaning.description}</p>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\td.meaning?.keywords?.length\n\t\t\t\t\t? html`<div class=\"keywords\">${d.meaning.keywords.map((k) => html`<span>${k}</span>`)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t}</article>`;\n\t}\n\n\tprivate renderListItem(p: MoonListEntry) {\n\t\tconst emoji = phaseEmoji(p.phase);\n\t\treturn html`<div class=\"list-item\" role=\"listitem\"><span aria-hidden=\"true\">${emoji}</span> <span>${p.phase}</span> <span>${p.date ?? ''}</span></div>`;\n\t}\n}\n\nfunction phaseEmoji(phase: string | undefined): string {\n\tif (!phase) return '\uD83C\uDF19';\n\treturn MOON_PHASE_EMOJI[phase.toLowerCase()] ?? '\uD83C\uDF19';\n}\n\nfunction formatIllumination(v: number): string {\n\tconst pct = v <= 1 ? v * 100 : v;\n\treturn `${Math.round(pct)}%`;\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-moon-phase': RoxyMoonPhase;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { NakshatraResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\n/**\n * Nakshatra reference card. Renders /vedic-astrology/nakshatras/{id}: the\n * lunar mansion number, longitude range, ruling planet, presiding deity,\n * symbol, native characteristics, and traditional remedies.\n */\n@customElement('roxy-nakshatra-card')\nexport class RoxyNakshatraCard extends RoxyDataElement<NakshatraResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);padding:var(--roxy-space-md,1rem);gap:var(--roxy-space-md,1rem);box-shadow:var(--roxy-shadow-sm);display:grid}.head{align-items:baseline;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.name{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.number{color:var(--roxy-accent-ink,#b45309);font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600)}.range{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}.facts{gap:var(--roxy-space-sm,.5rem);grid-template-columns:repeat(auto-fit,minmax(8rem,1fr));display:grid}.fact{gap:2px;display:grid}.fact dt{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);text-transform:uppercase;letter-spacing:.05em}.fact dd{color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);margin:0}.section h3{margin:0 0 var(--roxy-space-xs,.25rem);font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.05em}.section p{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);margin:0;line-height:1.5}.remedies{gap:var(--roxy-space-xs,.25rem);display:grid}.remedy{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a)}.remedy strong{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600)}`,\n\t];\n\n\tprotected renderData(n: NakshatraResponse) {\n\t\tconst remedies = n.remedies;\n\n\t\treturn html`<article class=\"wrap\" aria-label=\"${`Nakshatra ${n.name}`}\"><header class=\"head\"><h2 class=\"name\">${n.name}</h2>${\n\t\t\t\t\ttypeof n.number === 'number'\n\t\t\t\t\t\t? html`<span class=\"number\">Nakshatra ${n.number} of 27</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} ${n.range ? html`<span class=\"range\">${n.range}</span>` : nothing}</header><dl class=\"facts\">${n.lord ? html`<div class=\"fact\"><dt>Lord</dt><dd>${n.lord}</dd></div>` : nothing} ${n.deity ? html`<div class=\"fact\"><dt>Deity</dt><dd>${n.deity}</dd></div>` : nothing} ${n.symbol ? html`<div class=\"fact\"><dt>Symbol</dt><dd>${n.symbol}</dd></div>` : nothing}</dl>${\n\t\t\t\tn.characteristics\n\t\t\t\t\t? html`<div class=\"section\"><h3>Characteristics</h3><p>${n.characteristics}</p></div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tremedies\n\t\t\t\t\t? html`<div class=\"section\"><h3>Remedies</h3><div class=\"remedies\">${remedies.mantras ? html`<div class=\"remedy\"><strong>Mantras:</strong> ${remedies.mantras}</div>` : nothing} ${remedies.gemstones ? html`<div class=\"remedy\"><strong>Gemstones:</strong> ${remedies.gemstones}</div>` : nothing} ${remedies.rituals ? html`<div class=\"remedy\"><strong>Rituals:</strong> ${remedies.rituals}</div>` : nothing}</div></div>`\n\t\t\t\t\t: nothing\n\t\t\t}</article>`;\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No nakshatra data</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-nakshatra-card': RoxyNakshatraCard;\n\t}\n}\n", "import { css, html, nothing, svg } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport {\n\tASPECT_SYMBOL,\n\tPLANET_GLYPH,\n\tSIGN_GLYPH,\n\tSIGNS_ORDER,\n} from '../tokens/index.js';\nimport type { NatalChartResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport {\n\tarcMidpoint,\n\tlongitudeToSignPosition,\n\tnormalizeLongitude,\n\toppositePoint,\n\tpolarToCartesian,\n} from '../utils/degree.js';\nimport { chevron, disclosureStyles } from '../utils/disclosure.js';\nimport {\n\tASPECT_CLASS,\n\tformatNumber,\n\tnormalizeAspect,\n} from '../utils/format.js';\nimport { capitalize } from '../utils/string.js';\nimport { renderTablist, tablistStyles } from '../utils/tablist.js';\n\ntype PlanetEntry = NatalChartResponse['planets'][number];\ntype AspectEntry = NatalChartResponse['aspects'][number];\n\nconst SIZE = 420;\nconst CENTER = SIZE / 2;\nconst OUTER_R = 164;\nconst SIGN_R = 146;\nconst HOUSE_R = 120;\nconst PLANET_R = 96;\nconst ANGLE_TICK_R = 178;\nconst ANGLE_LABEL_R = 196;\n\n/**\n * Western natal chart wheel. Renders the 12 zodiac signs, 12 houses, planet\n * markers, and aspect lines from a /astrology/natal-chart response.\n */\n@customElement('roxy-natal-chart')\nexport class RoxyNatalChart extends RoxyDataElement<NatalChartResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\ttablistStyles,\n\t\tdisclosureStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);width:100%;color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-primary,#0f172a);margin:0}.meta{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}svg{width:100%;max-width:var(--roxy-chart-max-width,560px);aspect-ratio:1;height:auto;margin:0 auto;display:block}.wheel-line{fill:none;stroke:var(--roxy-border,#e4e4e7)}.sign-glyph{fill:var(--roxy-secondary,#475569);font-size:14px;font-family:var(--roxy-font-sans)}.planet-glyph{fill:var(--roxy-accent,#f59e0b);font-size:14px;font-weight:600;font-family:var(--roxy-font-sans)}.planet-deg{fill:var(--roxy-fg,#0a0a0a);font-size:7px;font-family:var(--roxy-font-sans)}@container (width<=480px){.sign-glyph,.planet-glyph{font-size:18px}.planet-deg{font-size:10px}.house-num{font-size:12px}}.planet-deg .retro{fill:var(--roxy-danger,#dc2626)}.planet-leader{stroke:var(--roxy-accent,#f59e0b);stroke-width:.5px;opacity:.55}.house-num{fill:var(--roxy-muted,#71717a);font-size:9px;font-family:var(--roxy-font-sans)}.cusp-deg{fill:var(--roxy-muted,#71717a);font-size:6px;font-family:var(--roxy-font-sans)}.tick{stroke:var(--roxy-border,#e4e4e7)}.tick-major{stroke:var(--roxy-secondary,#475569)}.aspect{stroke-width:.8px;fill:none;opacity:.55}.aspect-trine,.aspect-sextile{stroke:var(--roxy-success,#16a34a)}.aspect-square,.aspect-opposition{stroke:var(--roxy-danger,#dc2626)}.aspect-conjunction{stroke:var(--roxy-accent-ink,#b45309)}.aspect-other{stroke:var(--roxy-muted,#71717a);opacity:.4}.angle-marker{fill:var(--roxy-accent-ink,#b45309);font-size:10px;font-weight:700;font-family:var(--roxy-font-sans);letter-spacing:.04em}.angle-tick{stroke:var(--roxy-accent-ink,#b45309);stroke-width:1.5px}.legend{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);gap:var(--roxy-space-md,1rem);flex-wrap:wrap;display:flex}.legend-swatch{vertical-align:middle;border-radius:50%;width:8px;height:8px;margin-right:4px;display:inline-block}.grid-scroll{-webkit-overflow-scrolling:touch;overflow-x:auto}table.aspect-grid{border-collapse:collapse;font-size:var(--roxy-text-xs,.75rem);margin:0 auto}table.aspect-grid th,table.aspect-grid td{text-align:center;border:1px solid var(--roxy-border,#e4e4e7);width:1.6rem;height:1.6rem;padding:0}table.aspect-grid th{color:var(--roxy-secondary,#475569);font-weight:var(--roxy-weight-bold,600)}table.aspect-grid td.cell{cursor:default}table.aspect-grid td.empty{background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 18%, transparent)}table.aspect-grid td .asp{font-size:.95em;line-height:1}table.aspect-grid td.aspect-trine .asp,table.aspect-grid td.aspect-sextile .asp{color:var(--roxy-success,#16a34a)}table.aspect-grid td.aspect-square .asp,table.aspect-grid td.aspect-opposition .asp{color:var(--roxy-danger,#dc2626)}table.aspect-grid td.aspect-conjunction .asp{color:var(--roxy-accent-ink,#b45309)}table.aspect-grid td.aspect-other .asp{color:var(--roxy-muted,#71717a)}.details{margin-top:var(--roxy-space-md,1rem)}.pill-row{gap:var(--roxy-space-xs,.25rem);margin-bottom:var(--roxy-space-xs,.25rem);flex-wrap:wrap;display:flex}.pill{border-radius:var(--roxy-radius-sm,4px);font-size:var(--roxy-text-xs,.75rem);background:color-mix(in srgb, var(--roxy-fg,#0f172a) 8%, transparent);color:var(--roxy-fg,#0f172a);padding:2px 8px}.pill--success{background:color-mix(in srgb, var(--roxy-success,#16a34a) 15%, transparent);color:var(--roxy-success,#16a34a)}.pill--danger{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 15%, transparent);color:var(--roxy-danger,#dc2626)}.pill--muted{background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 60%, transparent);color:var(--roxy-fg,#0a0a0a)}.summary{color:var(--roxy-fg,#0f172a);font-size:var(--roxy-text-sm,.875rem);margin:var(--roxy-space-md,1rem) 0}.em-grid{border-collapse:collapse;font-size:var(--roxy-text-xs,.75rem);width:100%}.em-grid th,.em-grid td{border:1px solid var(--roxy-border,#e4e4e7);text-align:center;vertical-align:middle;padding:3px 5px}.em-grid th{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;letter-spacing:.04em}.em-grid th[scope=row]{text-align:left}.em-grid td{color:var(--roxy-accent,#f59e0b);min-width:1.4rem;font-size:.95em;line-height:1.4}.em-grid .em-total{color:var(--roxy-fg,#0a0a0a);font-weight:var(--roxy-weight-bold,600);background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 25%, transparent)}.interpretations{margin-top:var(--roxy-space-md,1rem)}.interpretations h3{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;margin:0 0 var(--roxy-space-sm,.5rem);font-weight:600}.interp-card{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);margin-bottom:var(--roxy-space-xs,.25rem)}.interp-card summary{cursor:pointer;color:var(--roxy-fg,#0f172a);justify-content:space-between;align-items:center;gap:var(--roxy-space-md,1rem);font-weight:500;display:flex}.interp-aside{align-items:center;gap:.6em;display:inline-flex}.interp-aside small{color:var(--roxy-muted,#71717a);font-weight:400}.interp-body{margin-top:var(--roxy-space-xs,.25rem);color:var(--roxy-fg,#0f172a);font-size:var(--roxy-text-sm,.875rem)}.interp-keywords{flex-wrap:wrap;gap:.25rem;margin-top:.5rem;display:flex}.interp-keywords .kw{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 14%, transparent);color:var(--roxy-accent-ink,#b45309);font-size:var(--roxy-text-xs,.75rem);border-radius:9999px;padding:1px 8px}`,\n\t];\n\n\t@property({ type: String, attribute: 'house-system', reflect: true })\n\thouseSystem: 'placidus' | 'whole-sign' | 'equal' | 'koch' = 'placidus';\n\n\t/** Which view is showing: the wheel or the planet-by-planet aspect grid. */\n\t@state()\n\tprivate view: 'wheel' | 'grid' = 'wheel';\n\n\tprivate getPlanets(): PlanetEntry[] {\n\t\treturn this.data?.planets ?? [];\n\t}\n\n\tprivate getAscendant(): number {\n\t\treturn this.data?.ascendant?.longitude ?? 0;\n\t}\n\n\tprivate getMidheaven(): number | null {\n\t\tconst m = this.data?.midheaven?.longitude;\n\t\treturn typeof m === 'number' ? m : null;\n\t}\n\n\tprivate toAngle(lon: number): number {\n\t\treturn 180 + this.getAscendant() - lon;\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No chart data</div>`;\n\t}\n\n\tprotected renderData(data: NatalChartResponse) {\n\t\tconst planets = this.getPlanets();\n\t\tconst aspects = data.aspects ?? [];\n\t\tconst view = this.view;\n\n\t\treturn html`<div class=\"wrap\"><header><h2 class=\"title\">Natal chart</h2>${\n\t\t\t\t\tdata.birthDetails\n\t\t\t\t\t\t? html`<div class=\"meta\">${[data.birthDetails.date, data.birthDetails.time]\n\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t.join(' \u00B7 ')}</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</header>${renderTablist({\n\t\t\t\titems: [\n\t\t\t\t\t{ id: 'wheel', label: 'Wheel' },\n\t\t\t\t\t{ id: 'grid', label: 'Aspect grid' },\n\t\t\t\t],\n\t\t\t\tactive: view,\n\t\t\t\tonSelect: (v) => {\n\t\t\t\t\tthis.view = v;\n\t\t\t\t},\n\t\t\t\tlabel: 'Natal chart views',\n\t\t\t\tidPrefix: 'natal',\n\t\t\t\tcontrols: true,\n\t\t\t})}<div id=\"natal-panel-${view}\" role=\"tabpanel\" aria-labelledby=\"natal-tab-${view}\">${view === 'wheel' ? this.renderWheel(planets, aspects) : this.renderAspectGrid(planets, aspects)}</div><div class=\"legend\"><span>${planets.length} planets</span> <span>${aspects.length} aspects</span> ${\n\t\t\t\t\tdata.houseSystem\n\t\t\t\t\t\t? html`<span>${data.houseSystem} houses</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} <span><span class=\"legend-swatch\" style=\"background:var(--roxy-success)\"></span>harmonious</span> <span><span class=\"legend-swatch\" style=\"background:var(--roxy-danger)\"></span>challenging</span></div>${this.renderDetails()} ${this.renderInterpretations()}</div>`;\n\t}\n\n\tprivate renderWheel(planets: PlanetEntry[], aspects: AspectEntry[]) {\n\t\treturn html`<svg viewBox=\"0 0 ${SIZE} ${SIZE}\" role=\"img\" aria-label=\"Natal chart wheel with twelve houses, planets, and aspects\"><title>Natal chart wheel</title><desc>Twelve zodiac sign segments around a circular wheel. Planet glyphs are placed at their ecliptic longitudes. Aspect lines connect related planets.</desc><circle class=\"wheel-line\" cx=\"${CENTER}\" cy=\"${CENTER}\" r=\"${OUTER_R}\" stroke-width=\"1.5\"/><circle class=\"wheel-line\" cx=\"${CENTER}\" cy=\"${CENTER}\" r=\"${SIGN_R - 14}\" stroke-width=\"0.8\"/><circle class=\"wheel-line\" cx=\"${CENTER}\" cy=\"${CENTER}\" r=\"${HOUSE_R}\" stroke-width=\"1\"/><circle class=\"wheel-line\" cx=\"${CENTER}\" cy=\"${CENTER}\" r=\"${PLANET_R - 16}\" stroke-width=\"0.5\"/>${this.renderTicks()} ${this.renderSpokes()} ${this.renderSigns()} ${this.renderHouseNumbers()} ${this.renderCuspDegrees()} ${this.renderAspects(planets, aspects)} ${this.renderPlanets(planets)} ${this.renderAngles()}</svg>`;\n\t}\n\n\t/**\n\t * Planet-by-planet aspect grid: the lower-triangular matrix astrologers read\n\t * alongside the wheel. Each filled cell shows the aspect glyph colored by\n\t * nature, with the exact orb in the SVG-free `<title>` tooltip.\n\t */\n\tprivate renderAspectGrid(planets: PlanetEntry[], aspects: AspectEntry[]) {\n\t\tconst names = planets.map((p) => capitalize(p.name));\n\t\t// Lookup aspects by unordered planet pair.\n\t\tconst byPair = new Map<string, AspectEntry>();\n\t\tfor (const a of aspects) {\n\t\t\tconst k = [capitalize(a.planet1), capitalize(a.planet2)].sort().join('|');\n\t\t\tbyPair.set(k, a);\n\t\t}\n\t\tif (names.length === 0)\n\t\t\treturn html`<p class=\"roxy-empty\" role=\"status\">No planets to grid</p>`;\n\n\t\treturn html`<div class=\"grid-scroll\"><table class=\"aspect-grid\" aria-label=\"Planet by planet aspect grid\"><thead><tr><th></th>${names.slice(0, -1).map((n) => {\n\t\t\t\t\t\t\tconst g = PLANET_GLYPH[n] ?? n.slice(0, 2);\n\t\t\t\t\t\t\treturn html`<th scope=\"col\" title=\"${n}\">${g}</th>`;\n\t\t\t\t\t\t})}</tr></thead><tbody>${names.slice(1).map((rowName, ri) => {\n\t\t\t\t\t\tconst rowGlyph = PLANET_GLYPH[rowName] ?? rowName.slice(0, 2);\n\t\t\t\t\t\t// Row i (1-based) pairs with columns 0..i-1.\n\t\t\t\t\t\treturn html`<tr><th scope=\"row\" title=\"${rowName}\">${rowGlyph}</th>${names.slice(0, ri + 1).map((colName) => {\n\t\t\t\t\t\t\t\tconst a = byPair.get([rowName, colName].sort().join('|'));\n\t\t\t\t\t\t\t\tif (!a) return html`<td class=\"empty\"></td>`;\n\t\t\t\t\t\t\t\tconst name = normalizeAspect(a);\n\t\t\t\t\t\t\t\tconst sym =\n\t\t\t\t\t\t\t\t\tASPECT_SYMBOL[name] ??\n\t\t\t\t\t\t\t\t\tASPECT_SYMBOL[name.replace(/-/g, '')] ??\n\t\t\t\t\t\t\t\t\tname.slice(0, 3);\n\t\t\t\t\t\t\t\tconst cls = ASPECT_CLASS[name] ?? 'aspect-other';\n\t\t\t\t\t\t\t\tconst orb = formatNumber(a.orb, 1);\n\t\t\t\t\t\t\t\treturn html`<td class=\"${`cell ${cls}`}\" title=\"${`${rowName} ${name} ${colName}${orb ? ` (orb ${orb}\u00B0)` : ''}`}\"><span class=\"asp\">${sym}</span></td>`;\n\t\t\t\t\t\t\t})} ${names.slice(ri + 1, -1).map(() => html`<td class=\"empty\"></td>`)}</tr>`;\n\t\t\t\t\t})}</tbody></table></div>`;\n\t}\n\n\tprivate renderAngles() {\n\t\tconst asc = this.getAscendant();\n\t\tconst mc = this.getMidheaven();\n\t\t// ASC/DESC and MC/IC are exact axes; DESC and IC are the opposite points.\n\t\tconst items = [\n\t\t\tthis.renderAngleMark(asc, 'ASC'),\n\t\t\tthis.renderAngleMark(oppositePoint(asc), 'DSC'),\n\t\t];\n\t\tif (mc !== null) {\n\t\t\titems.push(this.renderAngleMark(mc, 'MC'));\n\t\t\titems.push(this.renderAngleMark(oppositePoint(mc), 'IC'));\n\t\t}\n\t\tconst pof = this.data?.partOfFortune?.longitude;\n\t\tif (typeof pof === 'number') {\n\t\t\titems.push(this.renderAngleMark(normalizeLongitude(pof), 'PoF'));\n\t\t}\n\t\tconst vertex = this.data?.vertex?.longitude;\n\t\tif (typeof vertex === 'number') {\n\t\t\titems.push(this.renderAngleMark(normalizeLongitude(vertex), 'Vtx'));\n\t\t}\n\t\treturn items;\n\t}\n\n\tprivate renderAngleMark(longitude: number, label: string) {\n\t\t// Tick AND label share the same angle so the label sits right at the\n\t\t// tip of the arrow, where a practitioner expects to find it. The label\n\t\t// halo at radius ANGLE_LABEL_R is clear of the wheel rim, so there is\n\t\t// no overlap with house dividers despite the shared angle.\n\t\tconst angle = this.toAngle(longitude);\n\t\tconst tickInner = polarToCartesian(CENTER, CENTER, OUTER_R, angle);\n\t\tconst tickOuter = polarToCartesian(CENTER, CENTER, ANGLE_TICK_R, angle);\n\t\tconst labelPos = polarToCartesian(CENTER, CENTER, ANGLE_LABEL_R, angle);\n\t\treturn svg`\n\t\t\t<g>\n\t\t\t\t<line class=\"angle-tick\" x1=${tickInner.x} y1=${tickInner.y} x2=${tickOuter.x} y2=${tickOuter.y} />\n\t\t\t\t<text class=\"angle-marker\" x=${labelPos.x} y=${labelPos.y} text-anchor=\"middle\" dominant-baseline=\"central\">${label}</text>\n\t\t\t</g>\n\t\t`;\n\t}\n\n\tprivate renderSpokes() {\n\t\t// Draw a spoke at each real house cusp longitude so Placidus / Koch\n\t\t// unequal houses render correctly. Fall back to 12 equal spokes from the\n\t\t// Ascendant only when the response carries no houses array.\n\t\tconst houses = this.data?.houses ?? [];\n\t\tconst cuspLongitudes =\n\t\t\thouses.length === 12\n\t\t\t\t? houses.map((h) => h.longitude)\n\t\t\t\t: Array.from({ length: 12 }, (_, i) => this.getAscendant() + i * 30);\n\t\treturn cuspLongitudes.map((lon) => {\n\t\t\tconst angle = this.toAngle(lon);\n\t\t\tconst start = polarToCartesian(CENTER, CENTER, HOUSE_R, angle);\n\t\t\tconst end = polarToCartesian(CENTER, CENTER, OUTER_R, angle);\n\t\t\treturn svg`<line class=\"wheel-line\" x1=${start.x} y1=${start.y} x2=${end.x} y2=${end.y} stroke-width=\"0.8\" />`;\n\t\t});\n\t}\n\n\tprivate renderSigns() {\n\t\treturn SIGNS_ORDER.map((sign, i) => {\n\t\t\tconst angle = this.toAngle(i * 30 + 15);\n\t\t\tconst pos = polarToCartesian(CENTER, CENTER, SIGN_R, angle);\n\t\t\treturn svg`<text class=\"sign-glyph\" x=${pos.x} y=${pos.y} text-anchor=\"middle\" dominant-baseline=\"central\">${SIGN_GLYPH[sign]}</text>`;\n\t\t});\n\t}\n\n\tprivate renderHouseNumbers() {\n\t\tconst houses = this.data?.houses ?? [];\n\t\t// Place each house number at the angular midpoint between its cusp and\n\t\t// the next, so the label sits inside the house even when houses are\n\t\t// unequal. Fall back to equal 30-degree sectors when houses are absent.\n\t\tif (houses.length === 12) {\n\t\t\treturn houses.map((house, i) => {\n\t\t\t\tconst next = houses[(i + 1) % 12];\n\t\t\t\tconst mid = arcMidpoint(\n\t\t\t\t\thouse.longitude,\n\t\t\t\t\tnext ? next.longitude : house.longitude + 30,\n\t\t\t\t);\n\t\t\t\tconst pos = polarToCartesian(\n\t\t\t\t\tCENTER,\n\t\t\t\t\tCENTER,\n\t\t\t\t\tHOUSE_R - 12,\n\t\t\t\t\tthis.toAngle(mid),\n\t\t\t\t);\n\t\t\t\treturn svg`<text class=\"house-num\" x=${pos.x} y=${pos.y} text-anchor=\"middle\" dominant-baseline=\"central\">${house.number}</text>`;\n\t\t\t});\n\t\t}\n\t\tconst ascSignIndex = Math.floor(this.getAscendant() / 30);\n\t\treturn Array.from({ length: 12 }, (_, i) => {\n\t\t\tconst angle = this.toAngle(i * 30 + 15);\n\t\t\tconst pos = polarToCartesian(CENTER, CENTER, HOUSE_R - 12, angle);\n\t\t\tconst houseNum = ((i - ascSignIndex + 12) % 12) + 1;\n\t\t\treturn svg`<text class=\"house-num\" x=${pos.x} y=${pos.y} text-anchor=\"middle\" dominant-baseline=\"central\">${houseNum}</text>`;\n\t\t});\n\t}\n\n\t/**\n\t * Degree ticks on the outer zodiac band: a short mark every 5 degrees and a\n\t * longer one on each 30-degree sign cusp, so the wheel reads like a\n\t * reference-grade chart rather than a bare ring of glyphs.\n\t */\n\tprivate renderTicks() {\n\t\tconst ticks = [];\n\t\tfor (let deg = 0; deg < 360; deg += 5) {\n\t\t\tconst angle = this.toAngle(deg);\n\t\t\tconst isMajor = deg % 30 === 0;\n\t\t\tconst inner = isMajor ? SIGN_R - 14 : OUTER_R - 5;\n\t\t\tconst a = polarToCartesian(CENTER, CENTER, inner, angle);\n\t\t\tconst b = polarToCartesian(CENTER, CENTER, OUTER_R, angle);\n\t\t\tticks.push(\n\t\t\t\tsvg`<line class=${isMajor ? 'tick tick-major' : 'tick'} x1=${a.x} y1=${a.y} x2=${b.x} y2=${b.y} stroke-width=${isMajor ? 1 : 0.5} />`,\n\t\t\t);\n\t\t}\n\t\treturn ticks;\n\t}\n\n\t/**\n\t * Degree-and-minute label printed next to each house cusp on the wheel, so\n\t * the exact cusp position is readable without leaving the chart.\n\t */\n\tprivate renderCuspDegrees() {\n\t\tconst houses = this.data?.houses ?? [];\n\t\tif (houses.length !== 12) return nothing;\n\t\treturn houses.map((house) => {\n\t\t\tconst angle = this.toAngle(house.longitude);\n\t\t\tconst pos = polarToCartesian(CENTER, CENTER, HOUSE_R + 9, angle);\n\t\t\tconst sp = longitudeToSignPosition(house.longitude);\n\t\t\treturn svg`<text class=\"cusp-deg\" x=${pos.x} y=${pos.y} text-anchor=\"middle\" dominant-baseline=\"central\">${sp.degree}\u00B0${String(sp.minute).padStart(2, '0')}'</text>`;\n\t\t});\n\t}\n\n\tprivate renderPlanets(planets: PlanetEntry[]) {\n\t\t// Stellium-aware angular fan-out. Conjunctions within 8\u00B0 are the norm\n\t\t// in professional natal charts (Sun-Mercury-Venus cluster, outer-planet\n\t\t// stacks). To keep every glyph legible without losing precision, sort\n\t\t// by longitude and push later members forward in angle until they\n\t\t// clear a minimum separation, then draw a thin leader line from each\n\t\t// displaced glyph back to the planet's true position on the outer\n\t\t// rim. Conventional approach used by professional Western natal\n\t\t// software; preserves both readability and astronomical accuracy.\n\t\tconst MIN_SEPARATION = 7;\n\t\ttype Placed = {\n\t\t\tp: PlanetEntry;\n\t\t\ttrueLon: number;\n\t\t\tdisplayLon: number;\n\t\t};\n\t\tconst sorted: Placed[] = planets\n\t\t\t.filter((p) => Number.isFinite(p.longitude))\n\t\t\t.map((p) => ({\n\t\t\t\tp,\n\t\t\t\ttrueLon: normalizeLongitude(p.longitude),\n\t\t\t\tdisplayLon: normalizeLongitude(p.longitude),\n\t\t\t}))\n\t\t\t.sort((a, b) => a.trueLon - b.trueLon);\n\t\t// Forward sweep: clamp each to at least prev + MIN_SEPARATION.\n\t\tfor (let i = 1; i < sorted.length; i++) {\n\t\t\tconst prev = sorted[i - 1];\n\t\t\tconst cur = sorted[i];\n\t\t\tif (!prev || !cur) continue;\n\t\t\tconst wanted = prev.displayLon + MIN_SEPARATION;\n\t\t\tif (cur.displayLon < wanted) cur.displayLon = wanted;\n\t\t}\n\t\t// If the cluster overshot 360\u00B0, slide everything back equally so the\n\t\t// stack stays anchored near the original longitudes.\n\t\tconst last = sorted[sorted.length - 1];\n\t\tif (last && last.displayLon > 360) {\n\t\t\tconst shift = last.displayLon - 360;\n\t\t\tfor (const s of sorted) s.displayLon -= shift;\n\t\t}\n\t\treturn sorted.map(({ p, trueLon, displayLon }) => {\n\t\t\tconst trueAngle = this.toAngle(trueLon);\n\t\t\tconst displayAngle = this.toAngle(displayLon);\n\t\t\tconst glyphPos = polarToCartesian(CENTER, CENTER, PLANET_R, displayAngle);\n\t\t\tconst degPos = polarToCartesian(\n\t\t\t\tCENTER,\n\t\t\t\tCENTER,\n\t\t\t\tPLANET_R - 13,\n\t\t\t\tdisplayAngle,\n\t\t\t);\n\t\t\tconst rimPos = polarToCartesian(CENTER, CENTER, OUTER_R - 4, trueAngle);\n\t\t\tconst leaderInner = polarToCartesian(\n\t\t\t\tCENTER,\n\t\t\t\tCENTER,\n\t\t\t\tPLANET_R + 8,\n\t\t\t\tdisplayAngle,\n\t\t\t);\n\t\t\tconst glyph = PLANET_GLYPH[capitalize(p.name)] ?? p.name.slice(0, 2);\n\t\t\tconst sp = longitudeToSignPosition(p.longitude);\n\t\t\tconst retro = p.isRetrograde === true;\n\t\t\tconst degLabel = `${sp.degree}\u00B0${String(sp.minute).padStart(2, '0')}'`;\n\t\t\tconst offset = Math.abs(displayLon - trueLon) > 0.5;\n\t\t\treturn svg`<g>\n\t\t\t\t${\n\t\t\t\t\toffset\n\t\t\t\t\t\t? svg`<line class=\"planet-leader\" x1=${rimPos.x} y1=${rimPos.y} x2=${leaderInner.x} y2=${leaderInner.y} />`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t<text class=\"planet-glyph\" x=${glyphPos.x} y=${glyphPos.y} text-anchor=\"middle\" dominant-baseline=\"central\"><title>${p.name}${retro ? ' retrograde' : ''} - ${degLabel} ${p.sign ?? ''}</title>${glyph}</text>\n\t\t\t\t<text class=\"planet-deg\" x=${degPos.x} y=${degPos.y} text-anchor=\"middle\" dominant-baseline=\"central\">${degLabel}${retro ? svg`<tspan class=\"retro\"> \u211E</tspan>` : nothing}</text>\n\t\t\t</g>`;\n\t\t});\n\t}\n\n\tprivate renderDetails() {\n\t\tconst summary = this.data?.summary;\n\t\tconst ai = this.data?.aspectsInterpretation;\n\t\tif (!summary && !ai) return nothing;\n\n\t\tconst retrogrades = summary?.retrogradePlanets ?? [];\n\n\t\treturn html`<div class=\"details\">${\n\t\t\t\tsummary?.dominantElement || summary?.dominantModality\n\t\t\t\t\t? html`<div class=\"pill-row\">${summary.dominantElement ? html`<span class=\"pill\">Dominant element: ${summary.dominantElement}</span>` : nothing} ${summary.dominantModality ? html`<span class=\"pill\">Dominant modality: ${summary.dominantModality}</span>` : nothing}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tai\n\t\t\t\t\t? html`<div class=\"pill-row\"><span class=\"pill pill--success\">Harmonious ${ai.harmonious}</span> <span class=\"pill pill--danger\">Challenging ${ai.challenging}</span> <span class=\"pill pill--muted\">Neutral ${ai.neutral}</span></div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tretrogrades.length > 0\n\t\t\t\t\t? html`<div class=\"pill-row\">${retrogrades.map((p) => {\n\t\t\t\t\t\t\tconst glyph = PLANET_GLYPH[p] ?? p.slice(0, 2);\n\t\t\t\t\t\t\treturn html`<span class=\"pill pill--muted\">${glyph} ${p} R</span>`;\n\t\t\t\t\t\t})}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${ai?.summary ? html`<p class=\"summary\">${ai.summary}</p>` : nothing} ${this.renderElementModalityGrid()}</div>`;\n\t}\n\n\t/**\n\t * Element by modality grid: the 4x3 cross-tab astrologers read for chart\n\t * balance. Each planet is placed by its sign into one cell (Fire/Earth/Air/\n\t * Water row, Cardinal/Fixed/Mutable column). Derived purely from the planet\n\t * signs, with row, column, and grand totals.\n\t */\n\tprivate renderElementModalityGrid() {\n\t\tconst planets = this.getPlanets();\n\t\tif (planets.length === 0) return nothing;\n\t\tconst ELEMENTS = ['Fire', 'Earth', 'Air', 'Water'] as const;\n\t\tconst MODALITIES = ['Cardinal', 'Fixed', 'Mutable'] as const;\n\t\tconst order = SIGNS_ORDER as readonly string[];\n\n\t\tconst cells: Record<string, Record<string, string[]>> = {};\n\t\tfor (const el of ELEMENTS)\n\t\t\tcells[el] = { Cardinal: [], Fixed: [], Mutable: [] };\n\t\tfor (const p of planets) {\n\t\t\tconst idx = order.indexOf(capitalize(p.sign ?? ''));\n\t\t\tif (idx < 0) continue;\n\t\t\tconst el = ELEMENTS[idx % 4];\n\t\t\tconst mod = MODALITIES[idx % 3];\n\t\t\tconst glyph =\n\t\t\t\tPLANET_GLYPH[capitalize(p.name)] ?? capitalize(p.name).slice(0, 2);\n\t\t\tcells[el]?.[mod]?.push(glyph);\n\t\t}\n\n\t\treturn html`<table class=\"em-grid\" aria-label=\"Element and modality distribution\"><thead><tr><th></th>${MODALITIES.map((m) => html`<th scope=\"col\">${m.slice(0, 3)}</th>`)}<th scope=\"col\">Total</th></tr></thead><tbody>${ELEMENTS.map((el) => {\n\t\t\t\t\tconst rowTotal = MODALITIES.reduce(\n\t\t\t\t\t\t(s, m) => s + (cells[el]?.[m]?.length ?? 0),\n\t\t\t\t\t\t0,\n\t\t\t\t\t);\n\t\t\t\t\treturn html`<tr><th scope=\"row\">${el}</th>${MODALITIES.map(\n\t\t\t\t\t\t\t(m) => html`<td>${(cells[el]?.[m] ?? []).join(' ')}</td>`,\n\t\t\t\t\t\t)}<td class=\"em-total\">${rowTotal}</td></tr>`;\n\t\t\t\t})}<tr><th scope=\"row\">Total</th>${MODALITIES.map(\n\t\t\t\t\t\t(m) =>\n\t\t\t\t\t\t\thtml`<td class=\"em-total\">${ELEMENTS.reduce((s, el) => s + (cells[el]?.[m]?.length ?? 0), 0)}</td>`,\n\t\t\t\t\t)}<td class=\"em-total\">${planets.length}</td></tr></tbody></table>`;\n\t}\n\n\tprivate renderInterpretations() {\n\t\tconst planets = this.getPlanets().filter((p) => p.interpretation);\n\t\tif (planets.length === 0) return nothing;\n\t\treturn html`<section class=\"interpretations\"><h3>Planet readings</h3>${planets.map((p, idx) => {\n\t\t\t\tconst interp = p.interpretation!;\n\t\t\t\tconst glyph = PLANET_GLYPH[capitalize(p.name)] ?? '';\n\t\t\t\tconst deg = formatNumber(p.degree ?? 0, 1);\n\t\t\t\treturn html`<details class=\"interp-card\" name=\"natal-planet-readings\" ?open=\"${idx === 0}\"><summary><span>${glyph} ${p.name}</span> <span class=\"interp-aside\"><small>${p.sign ?? ''} ${deg}</small> ${chevron()}</span></summary><div class=\"interp-body\">${interp.summary ? html`<p class=\"interp-summary\">${interp.summary}</p>` : nothing} ${interp.detailed ? html`<p class=\"interp-detail\">${interp.detailed}</p>` : nothing} ${\n\t\t\t\t\t\t\tinterp.keywords?.length\n\t\t\t\t\t\t\t\t? html`<div class=\"interp-keywords\">${interp.keywords.map((k) => html`<span class=\"kw\">${k}</span>`)}</div>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}</div></details>`;\n\t\t\t})}</section>`;\n\t}\n\n\tprivate renderAspects(planets: PlanetEntry[], aspects: AspectEntry[]) {\n\t\tconst planetMap = new Map<string, number>();\n\t\tfor (const p of planets) {\n\t\t\tif (typeof p.longitude !== 'number') continue;\n\t\t\tconst name = capitalize(p.name);\n\t\t\tif (name) planetMap.set(name, p.longitude);\n\t\t}\n\t\treturn aspects.map((a) => {\n\t\t\tconst l1 = planetMap.get(capitalize(a.planet1));\n\t\t\tconst l2 = planetMap.get(capitalize(a.planet2));\n\t\t\tif (l1 === undefined || l2 === undefined) return nothing;\n\t\t\tconst p1 = polarToCartesian(\n\t\t\t\tCENTER,\n\t\t\t\tCENTER,\n\t\t\t\tPLANET_R - 18,\n\t\t\t\tthis.toAngle(l1),\n\t\t\t);\n\t\t\tconst p2 = polarToCartesian(\n\t\t\t\tCENTER,\n\t\t\t\tCENTER,\n\t\t\t\tPLANET_R - 18,\n\t\t\t\tthis.toAngle(l2),\n\t\t\t);\n\t\t\tconst aspectName = normalizeAspect(a);\n\t\t\tconst aspectClass = ASPECT_CLASS[aspectName] ?? 'aspect-other';\n\t\t\tconst orbLabel = formatNumber(a.orb, 1);\n\t\t\treturn svg`<line class=${`aspect ${aspectClass}`} x1=${p1.x} y1=${p1.y} x2=${p2.x} y2=${p2.y}><title>${a.planet1} ${aspectName || ''} ${a.planet2}${orbLabel ? ` (orb ${orbLabel}\u00B0)` : ''}</title></line>`;\n\t\t});\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-natal-chart': RoxyNatalChart;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type {\n\tCalculateBirthDayResponse,\n\tCalculateExpressionResponse,\n\tCalculateLifePathResponse,\n\tCalculateMaturityResponse,\n\tCalculatePersonalDayResponse,\n\tCalculatePersonalityResponse,\n\tCalculatePersonalMonthResponse,\n\tCalculatePersonalYearResponse,\n\tCalculateSoulUrgeResponse,\n\tGenerateNumerologyChartResponse,\n\tGetDailyNumberResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { humanize } from '../utils/string.js';\n\n/**\n * Single-number numerology responses that share the number + meaning + calculation + karmic-debt shape. {@link RoxyNumerologyCard.renderNumberCard} renders any of them; the `type` attribute selects only the heading label.\n */\ntype NumberCardData =\n\t| CalculateLifePathResponse\n\t| CalculateExpressionResponse\n\t| CalculateSoulUrgeResponse\n\t| CalculatePersonalityResponse\n\t| CalculateBirthDayResponse\n\t| CalculateMaturityResponse;\n\ntype NumerologyData =\n\t| NumberCardData\n\t| CalculatePersonalYearResponse\n\t| CalculatePersonalDayResponse\n\t| CalculatePersonalMonthResponse\n\t| GetDailyNumberResponse\n\t| GenerateNumerologyChartResponse;\n\n/**\n * Numerology card. Renders /numerology/{life-path,expression,soul-urge,personality,birth-day,maturity,personal-year,chart}.\n * Use the `type` attribute to switch the heading; the single-number types all share one layout.\n */\n@customElement('roxy-numerology-card')\nexport class RoxyNumerologyCard extends RoxyDataElement<NumerologyData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.card{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.hero{align-items:center;gap:var(--roxy-space-md,1rem);display:flex}.numeral{font-size:4rem;line-height:1;font-weight:var(--roxy-weight-bold,600);color:var(--roxy-accent-ink,#b45309);font-variant-numeric:tabular-nums}.label{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;margin:0}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.meaning{color:var(--roxy-fg,#0a0a0a);margin:0}.calc{font-family:var(--roxy-font-mono);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 30%, transparent);padding:var(--roxy-space-sm,.5rem);border-radius:var(--roxy-radius-sm,4px);white-space:pre-wrap;overflow-wrap:anywhere;margin:0}.chips{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;display:flex}.chips span{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 14%, transparent);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);padding:2px 8px}.cores{gap:var(--roxy-space-sm,.5rem);border-top:1px solid var(--roxy-border,#e4e4e7);padding-top:var(--roxy-space-md,1rem);grid-template-columns:repeat(auto-fit,minmax(8rem,1fr));display:grid}.cores .item{align-items:baseline;gap:var(--roxy-space-xs,.25rem);font-size:var(--roxy-text-sm,.875rem);display:flex}.cores .item span:first-child{color:var(--roxy-muted,#71717a);text-transform:capitalize}.cores .item strong{color:var(--roxy-accent-ink,#b45309);font-variant-numeric:tabular-nums;font-size:var(--roxy-text-base,1rem);font-weight:var(--roxy-weight-bold,600)}.karmic{background:color-mix(in srgb, var(--roxy-warning,#ea580c) 12%, transparent);border:1px solid color-mix(in srgb, var(--roxy-warning,#ea580c) 32%, transparent);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);border-radius:var(--roxy-radius-md,8px);font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a)}`,\n\t];\n\n\t@property({ type: String, reflect: true })\n\ttype:\n\t\t| 'life-path'\n\t\t| 'expression'\n\t\t| 'soul-urge'\n\t\t| 'personality'\n\t\t| 'birth-day'\n\t\t| 'maturity'\n\t\t| 'daily'\n\t\t| 'personal-day'\n\t\t| 'personal-month'\n\t\t| 'personal-year'\n\t\t| 'chart' = 'life-path';\n\n\tprotected renderData(d: NumerologyData) {\n\t\tconst headerLabel = LABELS[this.type] ?? this.type;\n\t\tif ('coreNumbers' in d) return this.renderChart(d, headerLabel);\n\t\t// Period reads share a number+theme+body shape but differ in field names;\n\t\t// check the most specific key first (a personal-day response also carries\n\t\t// personalMonth/personalYear), so the order is day -> month -> year.\n\t\tif ('personalDay' in d) {\n\t\t\treturn this.renderPeriod(headerLabel, d.personalDay, d.theme, d.guidance);\n\t\t}\n\t\tif ('personalMonth' in d) {\n\t\t\treturn this.renderPeriod(headerLabel, d.personalMonth, d.theme, d.focus);\n\t\t}\n\t\tif ('personalYear' in d) return this.renderPersonalYear(d, headerLabel);\n\t\t// Daily number: number + meaning, no calculation/karmic-debt; show the\n\t\t// meaning title as the heading and the daily message as the body.\n\t\tif ('dailyMessage' in d) {\n\t\t\treturn this.renderPeriod(\n\t\t\t\theaderLabel,\n\t\t\t\td.number,\n\t\t\t\td.meaning?.title,\n\t\t\t\td.dailyMessage,\n\t\t\t);\n\t\t}\n\t\treturn this.renderNumberCard(d as NumberCardData, headerLabel);\n\t}\n\n\t/** Shared layout for a single period number (day/month): a hero numeral, theme heading, and guidance/focus body. */\n\tprivate renderPeriod(\n\t\theaderLabel: string,\n\t\tnum: number | undefined,\n\t\ttheme: string | undefined,\n\t\tbody: string | undefined,\n\t) {\n\t\treturn html`<article class=\"card\" aria-label=\"${headerLabel}\"><div class=\"hero\">${typeof num === 'number' ? html`<div class=\"numeral\">${num}</div>` : nothing}<div><p class=\"label\">${headerLabel}</p>${theme ? html`<h2 class=\"title\">${theme}</h2>` : nothing}</div></div>${body ? html`<p class=\"meaning\">${body}</p>` : nothing}</article>`;\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No numerology data</div>`;\n\t}\n\n\tprivate renderNumberCard(d: NumberCardData, headerLabel: string) {\n\t\tconst keywords = d.meaning?.keywords ?? [];\n\t\treturn html`<article class=\"card\" aria-label=\"${headerLabel}\"><div class=\"hero\">${typeof d.number === 'number' ? html`<div class=\"numeral\">${d.number}</div>` : nothing}<div><p class=\"label\">${headerLabel}</p>${d.meaning?.title ? html`<h2 class=\"title\">${d.meaning.title}</h2>` : nothing}</div></div>${d.meaning?.description ? html`<p class=\"meaning\">${d.meaning.description}</p>` : nothing} ${d.calculation ? html`<pre class=\"calc\">${d.calculation}</pre>` : nothing} ${\n\t\t\t\tkeywords.length > 0\n\t\t\t\t\t? html`<div class=\"chips\">${keywords.map((k) => html`<span>${k}</span>`)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\td.hasKarmicDebt && d.karmicDebtNumber\n\t\t\t\t\t? html`<div class=\"karmic\">Karmic debt ${d.karmicDebtNumber}. ${karmicDebtText(d.karmicDebtMeaning)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t}</article>`;\n\t}\n\n\tprivate renderPersonalYear(\n\t\td: CalculatePersonalYearResponse,\n\t\theaderLabel: string,\n\t) {\n\t\treturn html`<article class=\"card\" aria-label=\"${headerLabel}\"><div class=\"hero\">${typeof d.personalYear === 'number' ? html`<div class=\"numeral\">${d.personalYear}</div>` : nothing}<div><p class=\"label\">${headerLabel}</p>${d.theme ? html`<h2 class=\"title\">${d.theme}</h2>` : nothing}</div></div>${d.forecast ? html`<p class=\"meaning\">${d.forecast}</p>` : nothing} ${d.advice ? html`<p>${d.advice}</p>` : nothing}</article>`;\n\t}\n\n\tprivate renderChart(d: GenerateNumerologyChartResponse, headerLabel: string) {\n\t\tconst cores = Object.entries(d.coreNumbers).filter(\n\t\t\t([, v]) => v !== null && v !== undefined,\n\t\t);\n\t\treturn html`<article class=\"card\" aria-label=\"${headerLabel}\"><div><p class=\"label\">${headerLabel}</p>${d.profile?.name ? html`<h2 class=\"title\">${d.profile.name}</h2>` : nothing}</div>${\n\t\t\t\tcores.length > 0\n\t\t\t\t\t? html`<div class=\"cores\">${cores.map(\n\t\t\t\t\t\t\t([k, v]) => html`<div class=\"item\"><span>${humanize(k)}</span> <strong>${v.number ?? ''}</strong></div>`,\n\t\t\t\t\t\t)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t}</article>`;\n\t}\n}\n\nconst LABELS: Record<string, string> = {\n\t'life-path': 'Life Path',\n\texpression: 'Expression',\n\t'soul-urge': 'Soul Urge',\n\tpersonality: 'Personality',\n\t'birth-day': 'Birth Day',\n\tmaturity: 'Maturity',\n\tdaily: 'Daily Number',\n\t'personal-day': 'Personal Day',\n\t'personal-month': 'Personal Month',\n\t'personal-year': 'Personal Year',\n\tchart: 'Numerology chart',\n};\n\ntype KarmicDebtMeaning = CalculateLifePathResponse['karmicDebtMeaning'];\n\nfunction karmicDebtText(value: KarmicDebtMeaning | undefined): string {\n\tif (!value) return '';\n\treturn [value.description, value.challenge, value.resolution]\n\t\t.filter(Boolean)\n\t\t.join(' ');\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-numerology-card': RoxyNumerologyCard;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type {\n\tGetBasicPanchangResponse,\n\tGetDetailedPanchangResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatDate, formatTime, formatTimeRange } from '../utils/format.js';\n\ntype PanchangData = GetBasicPanchangResponse | GetDetailedPanchangResponse;\ntype PanchangTime = GetDetailedPanchangResponse['rahuKaal'];\n\n/**\n * Panchang table for /vedic-astrology/panchang/{basic,detailed}.\n *\n * @remarks\n * The main grid lists the five limbs (tithi, nakshatra, yoga, karana, vara),\n * sun and moon timings, and, in detailed mode, the sunrise placements a reader\n * scans first: Moon rashi, Sun rashi, Sun nakshatra, and the current hora. The\n * detailed mode then groups every timed window into two sections, auspicious\n * (the fixed muhurtas plus each Amrit Kalam) and inauspicious (Rahu Kaal,\n * Yamaganda, Gulika, plus each Dur Muhurta and Varjyam), so a consumer can act\n * on timing without parsing the raw response.\n */\n@customElement('roxy-panchang-table')\nexport class RoxyPanchangTable extends RoxyDataElement<PanchangData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);background:var(--roxy-surface,#fff);box-shadow:var(--roxy-shadow-sm);overflow:hidden}.head{padding:var(--roxy-space-md,1rem);border-bottom:1px solid var(--roxy-border,#e4e4e7);justify-content:space-between;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.date{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}table{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem)}tbody tr:nth-child(odd){background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 24%, transparent)}th,td{padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);text-align:left;vertical-align:top}th{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:capitalize;width:38%}td{color:var(--roxy-fg,#0a0a0a);font-variant-numeric:tabular-nums}.section{border-top:1px solid var(--roxy-border,#e4e4e7);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;letter-spacing:.06em}`,\n\t];\n\n\t@property({ type: String, reflect: true })\n\tdetail: 'basic' | 'detailed' = 'detailed';\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No panchang data</div>`;\n\t}\n\n\tprotected renderData(d: PanchangData) {\n\t\tconst detailed = 'sunrise' in d ? d : null;\n\n\t\tconst fivefold: Array<[string, string]> = [\n\t\t\t['Tithi', this.formatPart(d.tithi)],\n\t\t\t['Nakshatra', this.formatPart(d.nakshatra)],\n\t\t\t['Yoga', this.formatPart(d.yoga)],\n\t\t\t['Karana', this.formatPart(d.karana)],\n\t\t];\n\t\tif (detailed) fivefold.push(['Vara', this.formatPart(detailed.vara)]);\n\n\t\tconst placements: Array<[string, string]> = detailed\n\t\t\t? [\n\t\t\t\t\t['Moon sign', this.formatRashi(detailed.moonSign)],\n\t\t\t\t\t['Sun sign', this.formatRashi(detailed.sunSign)],\n\t\t\t\t\t['Sun nakshatra', this.formatSunNakshatra(detailed.sunNakshatra)],\n\t\t\t\t\t['Hora', this.formatHora(detailed.hora)],\n\t\t\t\t].filter((row): row is [string, string] => Boolean(row[1]))\n\t\t\t: [];\n\n\t\tconst muhurtas: Array<[string, PanchangTime | undefined]> = detailed\n\t\t\t? [\n\t\t\t\t\t['Brahma Muhurta', detailed.brahmaMuhurta],\n\t\t\t\t\t['Abhijit Muhurta', detailed.abhijitMuhurta],\n\t\t\t\t\t['Vijaya Muhurta', detailed.vijayaMuhurta],\n\t\t\t\t\t['Godhuli Muhurta', detailed.godhuliMuhurta],\n\t\t\t\t\t['Nishita Muhurta', detailed.nishitaMuhurta],\n\t\t\t\t\t['Pratah Sandhya', detailed.pratahSandhya],\n\t\t\t\t\t['Sayahna Sandhya', detailed.sayahnaSandhya],\n\t\t\t\t]\n\t\t\t: [];\n\n\t\tconst auspiciousWindows: Array<[string, PanchangTime]> = detailed\n\t\t\t? this.expandWindows('Amrit Kalam', detailed.amritKalam)\n\t\t\t: [];\n\n\t\tconst inauspicious: Array<[string, PanchangTime | undefined]> = detailed\n\t\t\t? [\n\t\t\t\t\t['Rahu Kaal', detailed.rahuKaal],\n\t\t\t\t\t['Yamaganda', detailed.yamaganda],\n\t\t\t\t\t['Gulika', detailed.gulika],\n\t\t\t\t]\n\t\t\t: [];\n\n\t\tconst inauspiciousWindows: Array<[string, PanchangTime]> = detailed\n\t\t\t? [\n\t\t\t\t\t...this.expandWindows('Dur Muhurta', detailed.durMuhurta),\n\t\t\t\t\t...this.expandWindows('Varjyam', detailed.varjyam),\n\t\t\t\t]\n\t\t\t: [];\n\n\t\tconst transitions =\n\t\t\tdetailed && 'transitions' in detailed ? detailed.transitions : undefined;\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Panchang\"><header class=\"head\"><h2 class=\"title\">Panchang</h2><span class=\"date\">${detailed ? formatDate(detailed.date) : ''}</span></header><table><tbody>${fivefold.map(\n\t\t\t\t\t\t([k, v]) => html`<tr><th>${k}</th><td>${v}</td></tr>`,\n\t\t\t\t\t)} ${\n\t\t\t\t\t\tdetailed?.sunrise\n\t\t\t\t\t\t\t? html`<tr><th>Sunrise</th><td>${formatTime(detailed.sunrise)}</td></tr>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t} ${\n\t\t\t\t\t\tdetailed?.sunset\n\t\t\t\t\t\t\t? html`<tr><th>Sunset</th><td>${formatTime(detailed.sunset)}</td></tr>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t} ${\n\t\t\t\t\t\tdetailed?.moonrise\n\t\t\t\t\t\t\t? html`<tr><th>Moonrise</th><td>${formatTime(detailed.moonrise)}</td></tr>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t} ${\n\t\t\t\t\t\tdetailed?.moonset\n\t\t\t\t\t\t\t? html`<tr><th>Moonset</th><td>${formatTime(detailed.moonset)}</td></tr>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t} ${placements.map(\n\t\t\t\t\t\t([k, v]) => html`<tr><th>${k}</th><td>${v}</td></tr>`,\n\t\t\t\t\t)}</tbody></table>${\n\t\t\t\ttransitions\n\t\t\t\t\t? html`<div class=\"section\">Next transitions</div><table><tbody>${this.renderTransitionRow('Tithi', transitions.tithi)} ${this.renderTransitionRow('Nakshatra', transitions.nakshatra)} ${this.renderTransitionRow('Yoga', transitions.yoga)} ${this.renderTransitionRow('Karana', transitions.karana)}</tbody></table>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tthis.detail === 'detailed' &&\n\t\t\t\t(\n\t\t\t\t\tmuhurtas.some((m) => !!m[1]) ||\n\t\t\t\t\t\tauspiciousWindows.length > 0 ||\n\t\t\t\t\t\tinauspicious.some((m) => !!m[1]) ||\n\t\t\t\t\t\tinauspiciousWindows.length > 0\n\t\t\t\t)\n\t\t\t\t\t? html`<div class=\"section\">Auspicious muhurtas</div><table><tbody>${this.renderPeriodRows([\n\t\t\t\t\t\t\t\t\t...muhurtas.filter(\n\t\t\t\t\t\t\t\t\t\t(m): m is [string, PanchangTime] => !!m[1],\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t...auspiciousWindows,\n\t\t\t\t\t\t\t\t])}</tbody></table><div class=\"section\">Inauspicious periods</div><table><tbody>${this.renderPeriodRows([\n\t\t\t\t\t\t\t\t\t...inauspicious.filter(\n\t\t\t\t\t\t\t\t\t\t(m): m is [string, PanchangTime] => !!m[1],\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t...inauspiciousWindows,\n\t\t\t\t\t\t\t\t])}</tbody></table>`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n\n\t/** Renders one row per [label, period] pair, dropping any with no range. */\n\tprivate renderPeriodRows(rows: Array<[string, PanchangTime]>) {\n\t\treturn rows.map(([k, v]) => {\n\t\t\tconst range = formatTimeRange(v);\n\t\t\treturn range\n\t\t\t\t? html`<tr><th>${k}</th><td>${range}</td></tr>`\n\t\t\t\t: nothing;\n\t\t});\n\t}\n\n\t/** Expands an array of periods into labeled rows, numbering when more than one. */\n\tprivate expandWindows(\n\t\tlabel: string,\n\t\twindows: PanchangTime[] | undefined,\n\t): Array<[string, PanchangTime]> {\n\t\tif (!windows || windows.length === 0) return [];\n\t\treturn windows.map((w, i) => [\n\t\t\twindows.length > 1 ? `${label} ${i + 1}` : label,\n\t\t\tw,\n\t\t]);\n\t}\n\n\tprivate renderTransitionRow(\n\t\tlabel: string,\n\t\tt: { endsAt?: string; next?: string } | undefined,\n\t) {\n\t\tif (!t?.endsAt) return nothing;\n\t\tconst when = formatTime(t.endsAt);\n\t\tconst next = t.next ? ` \u2192 ${t.next}` : '';\n\t\treturn html`<tr><th>${label}</th><td>ends ${when}${next}</td></tr>`;\n\t}\n\n\tprivate formatPart(v: unknown): string {\n\t\tif (!v) return '';\n\t\tif (typeof v === 'string') return v;\n\t\tif (typeof v === 'object') {\n\t\t\tconst obj = v as {\n\t\t\t\tname?: string;\n\t\t\t\tlord?: string;\n\t\t\t\tphase?: string;\n\t\t\t\tpaksha?: string;\n\t\t\t\tend?: string;\n\t\t\t};\n\t\t\tconst parts = [\n\t\t\t\tobj.name,\n\t\t\t\tobj.paksha ? `(${obj.paksha} paksha)` : '',\n\t\t\t\tobj.lord ? `\u00B7 ${obj.lord}` : '',\n\t\t\t\tobj.phase,\n\t\t\t].filter(Boolean);\n\t\t\treturn parts.join(' ');\n\t\t}\n\t\treturn String(v);\n\t}\n\n\t/** \"English (Sanskrit)\" label for the Moon or Sun rashi at sunrise. */\n\tprivate formatRashi(r: RashiPlacement | undefined): string {\n\t\tif (!r?.name) return '';\n\t\treturn r.sanskritName && r.sanskritName !== r.name\n\t\t\t? `${r.name} (${r.sanskritName})`\n\t\t\t: r.name;\n\t}\n\n\t/** Sun nakshatra with pada and lord, the form a panchang reader expects. */\n\tprivate formatSunNakshatra(n: SunNakshatra | undefined): string {\n\t\tif (!n?.name) return '';\n\t\tconst parts = [\n\t\t\tn.name,\n\t\t\ttypeof n.pada === 'number' ? `pada ${n.pada}` : '',\n\t\t\tn.lord ? `\u00B7 ${n.lord}` : '',\n\t\t].filter(Boolean);\n\t\treturn parts.join(' ');\n\t}\n\n\t/** Current planetary hora with its active window. */\n\tprivate formatHora(h: Hora | undefined): string {\n\t\tif (!h?.current) return '';\n\t\tconst range = formatTimeRange(h);\n\t\treturn range ? `${h.current} (${range})` : h.current;\n\t}\n}\n\ntype PanchangPlacements = GetDetailedPanchangResponse;\ntype RashiPlacement = PanchangPlacements['moonSign'];\ntype SunNakshatra = PanchangPlacements['sunNakshatra'];\ntype Hora = PanchangPlacements['hora'];\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-panchang-table': RoxyPanchangTable;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type {\n\tGetCenterResponse,\n\tGetCompoundNumberResponse,\n\tGetGateResponse,\n\tGetNumberMeaningResponse,\n\tGetPlanetMeaningResponse,\n\tGetRashiResponse,\n\tGetTrigramResponse,\n\tGetZodiacSignResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { humanize } from '../utils/string.js';\n\n/**\n * Every reference / glossary lookup this card renders. They do NOT share field names (a zodiac sign has 17 fields, a number meaning has 3), so the card renders heuristically rather than by fixed keys: a symbol + title hero, the prose fields as labelled paragraphs, keyword and string-list fields as chips, and every remaining scalar as an attribute grid. One card replaces eight near-identical bespoke ones.\n */\ntype ReferenceData =\n\t| GetZodiacSignResponse\n\t| GetPlanetMeaningResponse\n\t| GetRashiResponse\n\t| GetTrigramResponse\n\t| GetGateResponse\n\t| GetCenterResponse\n\t| GetNumberMeaningResponse\n\t| GetCompoundNumberResponse;\n\n/** Keys used to derive the title, in priority order. */\nconst TITLE_KEYS = ['name', 'english', 'title'];\n/** Keys whose string value is always treated as prose, even when short. */\nconst PROSE_KEYS = new Set([\n\t'description',\n\t'meaning',\n\t'characteristics',\n\t'tagline',\n\t'definedMeaning',\n\t'undefinedMeaning',\n\t'motto',\n]);\n/** Keys never shown as their own row/section (rendered elsewhere or noise). */\nconst SKIP_KEYS = new Set(['id', 'symbol', 'keywords', ...TITLE_KEYS]);\n\n@customElement('roxy-reference-card')\nexport class RoxyReferenceCard extends RoxyDataElement<ReferenceData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.card{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{align-items:center;gap:var(--roxy-space-md,1rem);display:flex}.symbol{color:var(--roxy-accent-ink,#b45309);flex:none;font-size:2.5rem;line-height:1}.label{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;margin:0}.name{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.prose{margin:0;line-height:1.6}.prose .prose-label{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.05em;margin-bottom:2px;display:block}.chips{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;display:flex}.chips span{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 14%, transparent);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);padding:2px 8px}.list h3,.facts-wrap h3{margin:0 0 var(--roxy-space-xs,.25rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em}.facts{gap:var(--roxy-space-sm,.5rem);grid-template-columns:repeat(auto-fit,minmax(9rem,1fr));margin:0;display:grid}.fact dt{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);text-transform:capitalize}.fact dd{font-size:var(--roxy-text-sm,.875rem);margin:0}`,\n\t];\n\n\tprotected renderData(d: ReferenceData) {\n\t\tconst rec = d as Record<string, unknown>;\n\t\tconst title = this.deriveTitle(rec);\n\t\tconst symbol = typeof rec.symbol === 'string' ? rec.symbol : undefined;\n\t\tconst keywords = Array.isArray(rec.keywords)\n\t\t\t? (rec.keywords as unknown[]).map(String)\n\t\t\t: [];\n\n\t\tconst prose: Array<[string, string]> = [];\n\t\tconst lists: Array<[string, string[]]> = [];\n\t\tconst facts: Array<[string, string]> = [];\n\t\tfor (const [key, value] of Object.entries(rec)) {\n\t\t\tif (SKIP_KEYS.has(key) || value == null) continue;\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\tconst items = value.filter((v) => v != null).map(String);\n\t\t\t\tif (items.length > 0) lists.push([key, items]);\n\t\t\t} else if (typeof value === 'string') {\n\t\t\t\tif (PROSE_KEYS.has(key) || value.length > 48) prose.push([key, value]);\n\t\t\t\telse facts.push([key, value]);\n\t\t\t} else if (typeof value === 'number' || typeof value === 'boolean') {\n\t\t\t\tfacts.push([key, String(value)]);\n\t\t\t}\n\t\t}\n\n\t\treturn html`<article class=\"card\" aria-label=\"${title}\"><header class=\"head\">${symbol ? html`<span class=\"symbol\" aria-hidden=\"true\">${symbol}</span>` : nothing}<div><p class=\"label\">Reference</p><h2 class=\"name\">${title}</h2></div></header>${keywords.length > 0 ? html`<div class=\"chips\">${keywords.map((k) => html`<span>${k}</span>`)}</div>` : nothing} ${prose.map(\n\t\t\t\t([key, text]) => html`<p class=\"prose\"><span class=\"prose-label\">${humanize(key)}</span>${text}</p>`,\n\t\t\t)} ${\n\t\t\t\tfacts.length > 0\n\t\t\t\t\t? html`<div class=\"facts-wrap\"><dl class=\"facts\">${facts.map(\n\t\t\t\t\t\t\t\t([key, value]) => html`<div class=\"fact\"><dt>${humanize(key)}</dt><dd>${value}</dd></div>`,\n\t\t\t\t\t\t\t)}</dl></div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${lists.map(\n\t\t\t\t([key, items]) => html`<div class=\"list\"><h3>${humanize(key)}</h3><div class=\"chips\">${items.map((i) => html`<span>${i}</span>`)}</div></div>`,\n\t\t\t)}</article>`;\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No reference data</div>`;\n\t}\n\n\tprivate deriveTitle(rec: Record<string, unknown>): string {\n\t\tfor (const key of TITLE_KEYS) {\n\t\t\tif (typeof rec[key] === 'string') return rec[key] as string;\n\t\t}\n\t\tconst type = typeof rec.type === 'string' ? humanize(rec.type) : '';\n\t\tconst number = rec.number;\n\t\tif (number != null) return `${type} ${number}`.trim();\n\t\treturn 'Reference';\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-reference-card': RoxyReferenceCard;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { PLANET_GLYPH } from '../tokens/index.js';\nimport type { ShadbalaResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatNumber } from '../utils/format.js';\nimport { capitalize } from '../utils/string.js';\n\ntype Planet = ShadbalaResponse['planets'][number];\n\n/** CSS variable and display name for each of the 6 bala components. */\nconst BALA_COMPONENTS: Array<{\n\tkey: keyof Pick<\n\t\tPlanet,\n\t\t| 'sthanaBala'\n\t\t| 'digBala'\n\t\t| 'kalaBala'\n\t\t| 'chestaBala'\n\t\t| 'naisargikaBala'\n\t\t| 'drikBala'\n\t>;\n\tlabel: string;\n\tcolor: string;\n}> = [\n\t{ key: 'sthanaBala', label: 'Sthana', color: 'var(--roxy-info, #0284c7)' },\n\t{ key: 'digBala', label: 'Dig', color: 'var(--roxy-success, #16a34a)' },\n\t{ key: 'kalaBala', label: 'Kala', color: 'var(--roxy-warning, #ea580c)' },\n\t{ key: 'chestaBala', label: 'Chesta', color: 'var(--roxy-accent, #f59e0b)' },\n\t{\n\t\tkey: 'naisargikaBala',\n\t\tlabel: 'Naisargika',\n\t\tcolor: 'var(--roxy-secondary, #475569)',\n\t},\n\t{ key: 'drikBala', label: 'Drik', color: 'var(--roxy-danger, #dc2626)' },\n];\n\n/**\n * Shadbala six-fold planetary strength table with stacked bar visualization.\n * Pass `data` from /vedic-astrology/shadbala.\n */\n@customElement('roxy-shadbala-table')\nexport class RoxyShadbalaTable extends RoxyDataElement<ShadbalaResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-md,1rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.subtitle{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem);margin:0}.planet-row{align-items:center;gap:var(--roxy-space-sm,.5rem);padding:var(--roxy-space-sm,.5rem) 0;border-bottom:1px solid var(--roxy-border,#e4e4e7);grid-template-columns:8rem 1fr auto;display:grid}.planet-row:last-of-type{border-bottom:none}.planet-label{font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);align-items:center;gap:6px;display:flex}.glyph{font-size:1.2em;line-height:1}.bar-wrap{flex-direction:column;gap:4px;display:flex}.bar{border-radius:var(--roxy-radius-sm,4px);background:var(--roxy-border,#e4e4e7);height:12px;display:flex;overflow:hidden}.bar-segment{height:100%;transition:flex-grow var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,cubic-bezier(.4, 0, .2, 1))}.pills{flex-direction:column;align-items:flex-end;gap:4px;display:flex}.rupas-label{font-variant-numeric:tabular-nums;font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);white-space:nowrap}.adequacy-badge{border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);padding:1px 6px;display:inline-block}.adequacy-badge--adequate{background:color-mix(in srgb, var(--roxy-success,#16a34a) 12%, transparent);color:var(--roxy-success-fg,#166534)}.adequacy-badge--weak{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 12%, transparent);color:var(--roxy-danger-fg,#991b1b)}.rank-badge{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-accent-ink,#b45309);font-weight:var(--roxy-weight-bold,600)}.legend{gap:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);border-top:1px solid var(--roxy-border,#e4e4e7);padding-top:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.legend-row{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);align-items:center;gap:6px;display:flex}.legend-swatch{border-radius:var(--roxy-radius-sm,4px);flex-shrink:0;width:10px;height:10px;display:inline-block}@container (width<=480px){.planet-row{grid-template-rows:auto auto;grid-template-columns:6rem 1fr}.pills{flex-direction:row;grid-column:1/-1;justify-content:flex-start;align-items:center}}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No shadbala data</div>`;\n\t}\n\n\tprotected renderData(d: ShadbalaResponse) {\n\t\tif (!d.planets?.length) return this.renderEmpty();\n\n\t\tconst sorted = [...d.planets].sort(\n\t\t\t(a, b) => a.relativeRank - b.relativeRank,\n\t\t);\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Shadbala planetary strength\"><div class=\"head\"><h2 class=\"title\">Shadbala</h2><p class=\"subtitle\">${sorted.length} planets ranked by strength</p></div><div role=\"list\" aria-label=\"Planet strength bars\">${sorted.map((p) => this.renderPlanetRow(p))}</div><div class=\"legend\" aria-label=\"Strength component legend\">${BALA_COMPONENTS.map(\n\t\t\t\t\t(b) => html`<div class=\"legend-row\"><span class=\"legend-swatch\" style=\"background:${b.color}\" aria-hidden=\"true\"></span> ${b.label}</div>`,\n\t\t\t\t)}</div></div>`;\n\t}\n\n\tprivate renderPlanetRow(p: Planet) {\n\t\tconst glyph = PLANET_GLYPH[capitalize(p.planet)] ?? '';\n\n\t\t// Compute positive component values (drikBala can be negative)\n\t\tconst values = BALA_COMPONENTS.map((b) => Math.max(0, p[b.key] as number));\n\t\tconst total = values.reduce((s, v) => s + v, 0);\n\n\t\tconst isAdequate =\n\t\t\ttypeof p.strengthRatio === 'number' && p.strengthRatio >= 1;\n\t\tconst badgeClass = isAdequate\n\t\t\t? 'adequacy-badge--adequate'\n\t\t\t: 'adequacy-badge--weak';\n\t\tconst badgeLabel = isAdequate ? 'adequate' : 'weak';\n\n\t\tconst rupasStr =\n\t\t\tformatNumber(p.totalRupas, 2) && formatNumber(p.minRequired, 2)\n\t\t\t\t? `${formatNumber(p.totalRupas, 2)} / ${formatNumber(p.minRequired, 2)} R`\n\t\t\t\t: '';\n\n\t\treturn html`<div class=\"planet-row\" role=\"listitem\" aria-label=\"${p.planet} shadbala\"><div class=\"planet-label\"><span class=\"glyph\" aria-hidden=\"true\">${glyph}</span> ${p.planet} <span class=\"rank-badge\" aria-label=\"rank ${p.relativeRank}\">#${p.relativeRank}</span></div><div class=\"bar-wrap\"><div class=\"bar\" role=\"img\" aria-label=\"Strength components for ${p.planet}\">${\n\t\t\t\t\t\ttotal > 0\n\t\t\t\t\t\t\t? BALA_COMPONENTS.map((b, i) => {\n\t\t\t\t\t\t\t\t\tconst v = values[i];\n\t\t\t\t\t\t\t\t\tif (v <= 0) return nothing;\n\t\t\t\t\t\t\t\t\tconst grow = (v / total) * 100;\n\t\t\t\t\t\t\t\t\treturn html`<div class=\"bar-segment\" style=\"flex-grow:${grow};background:${b.color}\" title=\"${b.label}: ${formatNumber(v, 1)}\"></div>`;\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}</div></div><div class=\"pills\">${rupasStr ? html`<span class=\"rupas-label\">${rupasStr}</span>` : nothing} <span class=\"${`adequacy-badge ${badgeClass}`}\">${badgeLabel}</span></div></div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-shadbala-table': RoxyShadbalaTable;\n\t}\n}\n", "import { css, html, nothing, svg } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { PLANET_GLYPH, SIGN_GLYPH, SIGNS_ORDER } from '../tokens/index.js';\nimport type {\n\tCalculateSynastryResponse,\n\tNatalChartResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { longitudeToSignPosition, polarToCartesian } from '../utils/degree.js';\nimport {\n\tASPECT_CLASS,\n\tformatNumber,\n\tnormalizeAspect,\n} from '../utils/format.js';\nimport { capitalize } from '../utils/string.js';\n\ntype PlanetEntry = NatalChartResponse['planets'][number];\ntype InterAspect = CalculateSynastryResponse['interAspects'][number];\n\n// Drawing the dual wheel requires per-person planet longitudes alongside\n// the synastry response. Callers can merge planet arrays from\n// /astrology/natal-chart into `person1.planets` and `person2.planets`\n// before passing the payload in; without them, the component falls back\n// to the inter-aspects table and a status note instead of an empty wheel.\ntype SynastryWithPlanets = CalculateSynastryResponse & {\n\tperson1?: { planets?: PlanetEntry[] };\n\tperson2?: { planets?: PlanetEntry[] };\n};\n\nconst SIZE = 360;\nconst CENTER = SIZE / 2;\nconst OUTER_R = 170;\nconst SIGN_R = 154;\nconst P1_R = 124;\nconst P2_R = 96;\n\n/**\n * Dual-wheel synastry chart with inter-aspects table. Pass `data` from\n * /astrology/synastry.\n */\n@customElement('roxy-synastry-chart')\nexport class RoxySynastryChart extends RoxyDataElement<SynastryWithPlanets> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:center;gap:var(--roxy-space-md,1rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.score{font-variant-numeric:tabular-nums;font-weight:var(--roxy-weight-bold,600);color:var(--roxy-accent-ink,#b45309);font-size:var(--roxy-text-xl,1.5rem)}svg{width:100%;max-width:var(--roxy-chart-max-width,560px);aspect-ratio:1;height:auto;margin:0 auto;display:block}.wheel-line{fill:none;stroke:var(--roxy-border,#e4e4e7)}.sign{fill:var(--roxy-secondary,#475569);font-size:14px}.p1{fill:var(--roxy-accent,#f59e0b);font-size:13px;font-weight:600}.p2{fill:var(--roxy-info,#0284c7);font-size:13px;font-weight:600}.person-tag{opacity:.85;font-size:7px;font-weight:700}.planet-deg{fill:var(--roxy-muted,#71717a);font-size:7px;font-family:var(--roxy-font-sans)}.planet-deg .retro{fill:var(--roxy-danger,#dc2626)}.asc-tick{stroke:var(--roxy-accent-ink,#b45309);stroke-width:1px;opacity:.75}.asc-label{fill:var(--roxy-accent-ink,#b45309);font-size:9px;font-weight:700;font-family:var(--roxy-font-sans);letter-spacing:.04em}.aspect{stroke-width:.8px;fill:none;opacity:.5}.aspect-trine,.aspect-sextile{stroke:var(--roxy-success,#16a34a)}.aspect-square,.aspect-opposition{stroke:var(--roxy-danger,#dc2626)}.aspect-conjunction{stroke:var(--roxy-accent-ink,#b45309)}.aspect-other{stroke:var(--roxy-muted,#71717a);opacity:.35}.legend-row{gap:var(--roxy-space-md,1rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);margin-top:calc(var(--roxy-space-xs,.25rem) * -1);flex-wrap:wrap;display:flex}.legend-row .swatch{vertical-align:middle;border-radius:50%;width:8px;height:8px;margin-right:4px;display:inline-block}.summary{color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-base,1rem);margin:0}table{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem)}th,td{padding:var(--roxy-space-sm,.5rem);border-bottom:1px solid var(--roxy-border,#e4e4e7);text-align:left}th{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;font-size:var(--roxy-text-xs,.75rem);letter-spacing:.06em}td.orb{font-variant-numeric:tabular-nums;color:var(--roxy-muted,#71717a)}.lists{gap:var(--roxy-space-md,1rem);grid-template-columns:repeat(auto-fit,minmax(14rem,1fr));display:grid}.lists h3{margin:0 0 var(--roxy-space-xs,.25rem) 0;font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em}.lists ul{padding-left:var(--roxy-space-md,1rem);font-size:var(--roxy-text-sm,.875rem);margin:0}.missing-planets{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 8%, transparent);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-md,1rem);color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);line-height:1.5}.missing-planets code{font-family:var(--roxy-font-mono,ui-monospace, SFMono-Regular, Menlo, monospace);background:color-mix(in srgb, var(--roxy-fg,#0a0a0a) 6%, transparent);border-radius:4px;padding:0 4px;font-size:.95em}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No synastry data</div>`;\n\t}\n\n\tprotected renderData(d: SynastryWithPlanets) {\n\t\tconst { person1, person2, compatibilityScore, analysis } = d;\n\t\tconst interAspects = d.interAspects ?? [];\n\t\tconst p1Planets = person1?.planets ?? [];\n\t\tconst p2Planets = person2?.planets ?? [];\n\n\t\tconst score =\n\t\t\ttypeof compatibilityScore === 'number'\n\t\t\t\t? Math.round(compatibilityScore)\n\t\t\t\t: undefined;\n\t\tconst summaryText = analysis?.overall;\n\t\tconst strengths = analysis?.strengths ?? [];\n\t\tconst challenges = analysis?.challenges ?? [];\n\n\t\t// /astrology/synastry does not return per-person planet positions, so the\n\t\t// dual-wheel cannot be drawn from a bare synastry response. Surface this\n\t\t// explicitly instead of rendering a blank wheel; keep the inter-aspects\n\t\t// table when it is present so callers still get useful output.\n\t\tconst hasPlanets = p1Planets.length > 0 && p2Planets.length > 0;\n\t\tif (!hasPlanets) {\n\t\t\treturn html`<div class=\"wrap\" aria-label=\"Synastry compatibility chart\"><div class=\"head\"><h2 class=\"title\">Synastry</h2>${\n\t\t\t\t\t\ttypeof score === 'number'\n\t\t\t\t\t\t\t? html`<span class=\"score\" aria-label=\"${`Score ${score} of 100`}\">${score} / 100</span>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}</div><div class=\"missing-planets\" role=\"status\">Synastry response missing planet positions. Pass <code>data</code> with <code>person1.planets</code> and <code>person2.planets</code> arrays from the natal-chart endpoint, or use the <code>&lt;roxy-data></code> fallback.</div>${summaryText ? html`<p class=\"summary\">${summaryText}</p>` : nothing} ${interAspects.length > 0 ? this.renderAspects(interAspects) : nothing} ${\n\t\t\t\t\tstrengths.length > 0 || challenges.length > 0\n\t\t\t\t\t\t? html`<div class=\"lists\">${\n\t\t\t\t\t\t\t\tstrengths.length\n\t\t\t\t\t\t\t\t\t? html`<div><h3>Strengths</h3><ul>${strengths.map((s) => html`<li>${s}</li>`)}</ul></div>`\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\t\tchallenges.length\n\t\t\t\t\t\t\t\t\t? html`<div><h3>Challenges</h3><ul>${challenges.map((s) => html`<li>${s}</li>`)}</ul></div>`\n\t\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t\t}</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</div>`;\n\t\t}\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Synastry compatibility chart\"><div class=\"head\"><h2 class=\"title\">Synastry</h2>${\n\t\t\t\t\ttypeof score === 'number'\n\t\t\t\t\t\t? html`<span class=\"score\" aria-label=\"${`Score ${score} of 100`}\">${score} / 100</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</div><svg viewBox=\"0 0 ${SIZE} ${SIZE}\" role=\"img\" aria-label=\"Dual chart wheel comparing two natal charts\"><title>Synastry dual wheel</title><circle class=\"wheel-line\" cx=\"${CENTER}\" cy=\"${CENTER}\" r=\"${OUTER_R}\" stroke-width=\"1.5\"/><circle class=\"wheel-line\" cx=\"${CENTER}\" cy=\"${CENTER}\" r=\"${P2_R + 14}\" stroke-width=\"0.8\"/><circle class=\"wheel-line\" cx=\"${CENTER}\" cy=\"${CENTER}\" r=\"${P2_R - 14}\" stroke-width=\"0.6\"/>${this.renderSpokes()} ${this.renderSigns()} ${this.renderInterAspectLines(p1Planets, p2Planets, interAspects)} ${this.renderRing(p1Planets, P1_R, 'p1', 1)} ${this.renderRing(p2Planets, P2_R, 'p2', 2)} ${this.renderAscendants(d)}</svg><div class=\"legend-row\"><span><span class=\"swatch\" style=\"background:var(--roxy-accent)\"></span>Person 1</span> <span><span class=\"swatch\" style=\"background:var(--roxy-info)\"></span>Person 2</span> <span><span class=\"swatch\" style=\"background:var(--roxy-success)\"></span>harmonious</span> <span><span class=\"swatch\" style=\"background:var(--roxy-danger)\"></span>challenging</span></div>${summaryText ? html`<p class=\"summary\">${summaryText}</p>` : nothing} ${interAspects.length > 0 ? this.renderAspects(interAspects) : nothing} ${\n\t\t\t\tstrengths.length > 0 || challenges.length > 0\n\t\t\t\t\t? html`<div class=\"lists\">${\n\t\t\t\t\t\t\tstrengths.length\n\t\t\t\t\t\t\t\t? html`<div><h3>Strengths</h3><ul>${strengths.map((s) => html`<li>${s}</li>`)}</ul></div>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t} ${\n\t\t\t\t\t\t\tchallenges.length\n\t\t\t\t\t\t\t\t? html`<div><h3>Challenges</h3><ul>${challenges.map((s) => html`<li>${s}</li>`)}</ul></div>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}</div>`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n\n\tprivate toAngle(longitude: number): number {\n\t\treturn 180 - longitude;\n\t}\n\n\tprivate renderSpokes() {\n\t\treturn Array.from({ length: 12 }, (_, i) => {\n\t\t\tconst angle = this.toAngle(i * 30);\n\t\t\tconst start = polarToCartesian(CENTER, CENTER, P2_R - 14, angle);\n\t\t\tconst end = polarToCartesian(CENTER, CENTER, OUTER_R, angle);\n\t\t\treturn svg`<line class=\"wheel-line\" x1=${start.x} y1=${start.y} x2=${end.x} y2=${end.y} stroke-width=\"0.6\" />`;\n\t\t});\n\t}\n\n\tprivate renderSigns() {\n\t\treturn SIGNS_ORDER.map((s, i) => {\n\t\t\tconst angle = this.toAngle(i * 30 + 15);\n\t\t\tconst pos = polarToCartesian(CENTER, CENTER, SIGN_R, angle);\n\t\t\treturn svg`<text class=\"sign\" x=${pos.x} y=${pos.y} text-anchor=\"middle\" dominant-baseline=\"central\">${SIGN_GLYPH[s]}</text>`;\n\t\t});\n\t}\n\n\tprivate renderRing(\n\t\tplanets: PlanetEntry[],\n\t\tradius: number,\n\t\tcls: string,\n\t\tpersonIndex: 1 | 2,\n\t) {\n\t\treturn planets.map((p) => {\n\t\t\tif (!Number.isFinite(p.longitude)) return nothing;\n\t\t\tconst angle = this.toAngle(p.longitude);\n\t\t\tconst pos = polarToCartesian(CENTER, CENTER, radius, angle);\n\t\t\t// Degree label sits one tier inward from the glyph so the two\n\t\t\t// concentric rings never blur their numbers into the aspect lines.\n\t\t\tconst degOffset = personIndex === 1 ? -12 : -10;\n\t\t\tconst degPos = polarToCartesian(\n\t\t\t\tCENTER,\n\t\t\t\tCENTER,\n\t\t\t\tradius + degOffset,\n\t\t\t\tangle,\n\t\t\t);\n\t\t\tconst glyph = PLANET_GLYPH[capitalize(p.name)] ?? p.name.slice(0, 2);\n\t\t\tconst sp = longitudeToSignPosition(p.longitude);\n\t\t\tconst retro = p.isRetrograde === true;\n\t\t\tconst degLabel = `${sp.degree}\u00B0${String(sp.minute).padStart(2, '0')}'`;\n\t\t\tconst tooltip = `${p.name}${retro ? ' retrograde' : ''} - ${degLabel} ${sp.sign}`;\n\t\t\treturn svg`<g>\n\t\t\t\t<text class=${cls} x=${pos.x} y=${pos.y} text-anchor=\"middle\" dominant-baseline=\"central\"><title>${tooltip}</title>${glyph}<tspan class=\"person-tag\" dy=\"-0.55em\" dx=\"0.15em\">${personIndex}</tspan></text>\n\t\t\t\t<text class=\"planet-deg\" x=${degPos.x} y=${degPos.y} text-anchor=\"middle\" dominant-baseline=\"central\">${sp.degree}\u00B0${retro ? svg`<tspan class=\"retro\"> \u211E</tspan>` : nothing}</text>\n\t\t\t</g>`;\n\t\t});\n\t}\n\n\t/**\n\t * Ascendant markers for both people. Drawn as small spokes at the inner\n\t * rim with the label outside, so the two rising signs are immediately\n\t * scannable on the wheel without depending on tooltips.\n\t */\n\tprivate renderAscendants(data: SynastryWithPlanets) {\n\t\tconst items: ReturnType<typeof svg>[] = [];\n\t\tconst make = (\n\t\t\tasc: { sign: string; degree: number } | undefined,\n\t\t\tpersonIndex: 1 | 2,\n\t\t) => {\n\t\t\tif (!asc) return;\n\t\t\tconst signIdx = SIGNS_ORDER.findIndex(\n\t\t\t\t(s) => s.toLowerCase() === asc.sign.toLowerCase(),\n\t\t\t);\n\t\t\tif (signIdx === -1) return;\n\t\t\tconst longitude = signIdx * 30 + asc.degree;\n\t\t\tconst angle = this.toAngle(longitude);\n\t\t\tconst innerR = personIndex === 1 ? P1_R + 14 : P2_R + 14;\n\t\t\tconst tickPos = polarToCartesian(CENTER, CENTER, innerR, angle);\n\t\t\tconst labelPos = polarToCartesian(CENTER, CENTER, OUTER_R + 14, angle);\n\t\t\titems.push(svg`<g>\n\t\t\t\t<line class=\"asc-tick\" x1=${tickPos.x} y1=${tickPos.y} x2=${labelPos.x} y2=${labelPos.y} />\n\t\t\t\t<text class=\"asc-label\" x=${labelPos.x} y=${labelPos.y} text-anchor=\"middle\" dominant-baseline=\"central\">Asc${personIndex}</text>\n\t\t\t</g>`);\n\t\t};\n\t\tmake(data.person1?.ascendant, 1);\n\t\tmake(data.person2?.ascendant, 2);\n\t\treturn items;\n\t}\n\n\tprivate renderInterAspectLines(\n\t\tp1: PlanetEntry[],\n\t\tp2: PlanetEntry[],\n\t\taspects: InterAspect[],\n\t) {\n\t\tconst longitudeOf = (\n\t\t\tlist: PlanetEntry[],\n\t\t\tname: string,\n\t\t): number | undefined => {\n\t\t\tconst target = capitalize(name);\n\t\t\tfor (const p of list) {\n\t\t\t\tif (capitalize(p.name) !== target) continue;\n\t\t\t\tif (typeof p.longitude === 'number') return p.longitude;\n\t\t\t}\n\t\t\treturn undefined;\n\t\t};\n\t\treturn aspects.map((a) => {\n\t\t\tconst l1 = longitudeOf(p1, a.planet1);\n\t\t\tconst l2 = longitudeOf(p2, a.planet2);\n\t\t\tif (l1 === undefined || l2 === undefined) return nothing;\n\t\t\tconst out = polarToCartesian(CENTER, CENTER, P1_R - 12, this.toAngle(l1));\n\t\t\tconst inn = polarToCartesian(CENTER, CENTER, P2_R + 8, this.toAngle(l2));\n\t\t\tconst aspectName = normalizeAspect(a);\n\t\t\tconst cls = ASPECT_CLASS[aspectName] ?? 'aspect-other';\n\t\t\tconst orbLabel = formatNumber(a.orb, 1);\n\t\t\treturn svg`<line class=${`aspect ${cls}`} x1=${out.x} y1=${out.y} x2=${inn.x} y2=${inn.y}><title>${a.planet1} ${aspectName} ${a.planet2}${orbLabel ? ` (orb ${orbLabel}\u00B0)` : ''}</title></line>`;\n\t\t});\n\t}\n\n\tprivate renderAspects(aspects: InterAspect[]) {\n\t\treturn html`<table><thead><tr><th>Planet 1</th><th>Planet 2</th><th>Aspect</th><th>Orb</th><th>Strength</th></tr></thead><tbody>${aspects.slice(0, 12).map(\n\t\t\t\t\t(a) => html`<tr><td>${a.planet1}</td><td>${a.planet2}</td><td>${normalizeAspect(a) || ''}</td><td class=\"orb\">${formatNumber(a.orb, 1)}</td><td>${formatStrength(a.strength)}</td></tr>`,\n\t\t\t\t)}</tbody></table>`;\n\t}\n}\n\nfunction formatStrength(s: number | undefined): string {\n\tif (typeof s === 'number') return Math.round(s).toString();\n\treturn '';\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-synastry-chart': RoxySynastryChart;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\nimport type { GetCardResponse, GetDailyCardResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\ntype TarotData = GetCardResponse | GetDailyCardResponse;\n\n/**\n * Tarot card. Renders /tarot/cards/{id} or /tarot/daily. Click to flip\n * between upright and reversed where the data shape supports it.\n */\n@customElement('roxy-tarot-card')\nexport class RoxyTarotCard extends RoxyDataElement<TarotData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.card{background:var(--roxy-surface,#fff);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-lg,1.5rem);grid-template-columns:minmax(0,9rem) 1fr;align-items:start;display:grid}@container (width<=480px){.card{grid-template-columns:1fr}}.image-wrap{perspective:800px}.image{border-radius:var(--roxy-radius-md,8px);background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 60%, transparent);width:100%;height:auto;transition:transform var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,cubic-bezier(.4, 0, .2, 1));cursor:pointer;display:block}.image.reversed{transform:rotate(180deg)}.image:focus-visible{outline:2px solid var(--roxy-ring,#f59e0b66);outline-offset:2px}.title{font-size:var(--roxy-text-xl,1.5rem);font-weight:var(--roxy-weight-bold,600);letter-spacing:var(--roxy-tracking-tight);margin:0}.meta{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem);text-transform:uppercase;letter-spacing:.06em;margin-bottom:var(--roxy-space-sm,.5rem)}.message{color:var(--roxy-fg,#0a0a0a);margin:var(--roxy-space-sm,.5rem) 0 var(--roxy-space-md,1rem)}.chips{gap:var(--roxy-space-xs,.25rem);margin-top:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.chips span{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 14%, transparent);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);padding:2px 8px}.flip{margin-top:var(--roxy-space-sm,.5rem);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);font-family:inherit;font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-secondary,#475569);cursor:pointer;transition:transform var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,cubic-bezier(.4, 0, .2, 1));background:0 0;padding:4px 12px}.flip:hover{transform:scale(1.02)}`,\n\t];\n\n\t@state()\n\tprivate flipped = false;\n\n\tprivate toggleFlip = () => {\n\t\tthis.flipped = !this.flipped;\n\t};\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No tarot data</div>`;\n\t}\n\n\tprotected renderData(d: TarotData) {\n\t\tif ('card' in d) return this.renderDailyCard(d);\n\t\treturn this.renderFullCard(d);\n\t}\n\n\tprivate renderDailyCard(d: GetDailyCardResponse) {\n\t\tconst card = d.card;\n\t\tconst isReversed = this.flipped !== Boolean(card.reversed);\n\t\tconst keywords = card.keywords ?? [];\n\n\t\treturn html`<article class=\"card\" aria-label=\"${card.name ?? 'Tarot card'}\"><div class=\"image-wrap\">${\n\t\t\t\t\tcard.imageUrl\n\t\t\t\t\t\t? html`<img class=\"${`image ${isReversed ? 'reversed' : ''}`}\" src=\"${card.imageUrl}\" alt=\"${card.name ?? 'Tarot card'}\" tabindex=\"0\" @click=\"${this.toggleFlip}\" @keydown=\"${(e: KeyboardEvent) => {\n\t\t\t\t\t\t\t\tif (e.key === 'Enter' || e.key === ' ') {\n\t\t\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t\t\tthis.toggleFlip();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}}\">`\n\t\t\t\t\t\t: html`<div class=\"${`image ${isReversed ? 'reversed' : ''}`}\" style=\"aspect-ratio:0.6;display:flex;align-items:center;justify-content:center;color:var(--roxy-muted)\">${card.name ?? '?'}</div>`\n\t\t\t\t}</div><div><div class=\"meta\">${card.arcana ? html`${card.arcana} arcana` : nothing} ${isReversed ? html`\u00B7 reversed` : nothing}</div><h2 class=\"title\">${card.name ?? 'Tarot card'}</h2>${d.dailyMessage ? html`<p class=\"message\">${d.dailyMessage}</p>` : nothing} ${card.meaning ? html`<p>${card.meaning}</p>` : nothing} ${\n\t\t\t\t\tkeywords.length > 0\n\t\t\t\t\t\t? html`<div class=\"chips\">${keywords.map((k) => html`<span>${k}</span>`)}</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} <button class=\"flip\" type=\"button\" @click=\"${this.toggleFlip}\" aria-pressed=\"${this.flipped ? 'true' : 'false'}\">Flip card</button></div></article>`;\n\t}\n\n\tprivate renderFullCard(d: GetCardResponse) {\n\t\tconst isReversed = this.flipped;\n\t\tconst orientedMeaning = isReversed ? d.reversed : d.upright;\n\t\tconst keywords = isReversed\n\t\t\t? (d.keywords?.reversed ?? [])\n\t\t\t: (d.keywords?.upright ?? []);\n\n\t\treturn html`<article class=\"card\" aria-label=\"${d.name ?? 'Tarot card'}\"><div class=\"image-wrap\">${\n\t\t\t\t\td.imageUrl\n\t\t\t\t\t\t? html`<img class=\"${`image ${isReversed ? 'reversed' : ''}`}\" src=\"${d.imageUrl}\" alt=\"${d.name ?? 'Tarot card'}\" tabindex=\"0\" @click=\"${this.toggleFlip}\" @keydown=\"${(e: KeyboardEvent) => {\n\t\t\t\t\t\t\t\tif (e.key === 'Enter' || e.key === ' ') {\n\t\t\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t\t\tthis.toggleFlip();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}}\">`\n\t\t\t\t\t\t: html`<div class=\"${`image ${isReversed ? 'reversed' : ''}`}\" style=\"aspect-ratio:0.6;display:flex;align-items:center;justify-content:center;color:var(--roxy-muted)\">${d.name ?? '?'}</div>`\n\t\t\t\t}</div><div><div class=\"meta\">${d.arcana ? html`${d.arcana} arcana` : nothing} ${d.number !== undefined && d.number !== null ? html`\u00B7 ${d.number}` : nothing} ${isReversed ? html`\u00B7 reversed` : nothing}</div><h2 class=\"title\">${d.name ?? 'Tarot card'}</h2>${orientedMeaning?.description ? html`<p>${orientedMeaning.description}</p>` : nothing} ${\n\t\t\t\t\tkeywords.length > 0\n\t\t\t\t\t\t? html`<div class=\"chips\">${keywords.map((k) => html`<span>${k}</span>`)}</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} <button class=\"flip\" type=\"button\" @click=\"${this.toggleFlip}\" aria-pressed=\"${this.flipped ? 'true' : 'false'}\">Flip card</button></div></article>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-tarot-card': RoxyTarotCard;\n\t}\n}\n", "import { css, html } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type { ListCardsResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { capitalize } from '../utils/string.js';\n\n/** A single card row from the catalog response. Kept spec-derived so the tile never reads a field the API does not return. */\ntype CatalogCard = ListCardsResponse['cards'][number];\n\n/**\n * Tarot catalog. Renders GET /tarot/cards as a responsive gallery of the deck: each tile carries the Rider-Waite-Smith artwork, the card name, and an arcana/suit caption. Filter the deck server-side (arcana, suit, number, paging) and pass the page response; the component renders whatever cards it carries. Pairs with `<roxy-tarot-card>` for a single-card detail view and `<roxy-tarot-spread>` for readings.\n */\n@customElement('roxy-tarot-catalog')\nexport class RoxyTarotCatalog extends RoxyDataElement<ListCardsResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-fg,#0a0a0a);margin:0}.count{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}.grid{gap:var(--roxy-space-md,1rem);grid-template-columns:repeat(auto-fill,minmax(7rem,1fr));margin:0;padding:0;list-style:none;display:grid}.tile{gap:var(--roxy-space-xs,.25rem);background:var(--roxy-surface,#fff);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-sm,.5rem);box-shadow:var(--roxy-shadow-sm);display:grid}.art{aspect-ratio:2/3;border-radius:var(--roxy-radius-sm,4px);object-fit:cover;background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 35%, transparent);width:100%}.name{font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-fg,#0a0a0a);margin:0}.meta{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);margin:0}`,\n\t];\n\n\t/**\n\t * Override the auto-derived gallery heading. Empty by default, in which case the heading is \"Tarot deck\".\n\t */\n\t@property({ type: String, reflect: true })\n\theading = '';\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No cards</div>`;\n\t}\n\n\tprotected renderData(d: ListCardsResponse) {\n\t\tconst cards = d.cards ?? [];\n\t\tif (cards.length === 0) return this.renderEmpty();\n\n\t\tconst title = this.heading || 'Tarot deck';\n\t\tconst total = typeof d.total === 'number' ? d.total : cards.length;\n\n\t\treturn html`<section class=\"wrap\" aria-label=\"${title}\"><header class=\"head\"><h2 class=\"title\">${title}</h2><span class=\"count\">${total} ${total === 1 ? 'card' : 'cards'}</span></header><ul class=\"grid\">${cards.map(\n\t\t\t\t\t(c) => html`<li class=\"tile\">${\n\t\t\t\t\t\t\tc.imageUrl\n\t\t\t\t\t\t\t\t? html`<img class=\"art\" src=\"${c.imageUrl}\" alt=\"${c.name ?? 'Tarot card'}\" loading=\"lazy\">`\n\t\t\t\t\t\t\t\t: html`<div class=\"art\" aria-hidden=\"true\"></div>`\n\t\t\t\t\t\t}<p class=\"name\">${c.name}</p><p class=\"meta\">${cardMeta(c)}</p></li>`,\n\t\t\t\t)}</ul></section>`;\n\t}\n}\n\n/**\n * Caption line for a catalog tile. Minor Arcana cards name their suit (`Minor \u00B7 Cups`); Major Arcana cards read `Major Arcana`. Both derive only from the spec `arcana` and `suit` fields.\n */\nfunction cardMeta(c: CatalogCard): string {\n\tif (c.suit) return `${capitalize(c.arcana)} \u00B7 ${capitalize(c.suit)}`;\n\treturn `${capitalize(c.arcana)} Arcana`;\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-tarot-catalog': RoxyTarotCatalog;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type {\n\tCastCareerSpreadResponse,\n\tCastCelticCrossResponse,\n\tCastCustomSpreadResponse,\n\tCastLoveSpreadResponse,\n\tCastReadingResponse,\n\tCastThreeCardResponse,\n\tCastYesNoResponse,\n\tDrawCardsResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\ntype TarotSpreadData =\n\t| CastThreeCardResponse\n\t| CastCelticCrossResponse\n\t| CastLoveSpreadResponse\n\t| CastYesNoResponse\n\t| CastReadingResponse\n\t| CastCareerSpreadResponse\n\t| CastCustomSpreadResponse\n\t| DrawCardsResponse;\n\n/**\n * Tarot spread card. Renders /tarot/spreads/{three-card,celtic-cross,love},\n * /tarot/yes-no, /tarot/draw responses.\n */\n@customElement('roxy-tarot-spread')\nexport class RoxyTarotSpread extends RoxyDataElement<TarotSpreadData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;gap:var(--roxy-space-md,1rem);flex-wrap:wrap;align-items:baseline;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);text-transform:capitalize;margin:0}.question{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem);font-style:italic}.answer{border-radius:var(--roxy-radius-full,9999px);font-weight:var(--roxy-weight-bold,600);font-size:var(--roxy-text-base,1rem);text-transform:uppercase;letter-spacing:.06em;padding:4px 14px;display:inline-block}.answer.yes{background:color-mix(in srgb, var(--roxy-success,#16a34a) 16%, transparent);color:var(--roxy-success-fg,#166534)}.answer.no{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 16%, transparent);color:var(--roxy-danger-fg,#991b1b)}.answer.maybe{background:color-mix(in srgb, var(--roxy-warning,#ea580c) 16%, transparent);color:var(--roxy-warning-fg,#9a3412)}.grid{gap:var(--roxy-space-md,1rem);grid-template-columns:repeat(auto-fit,minmax(8rem,1fr));display:grid}.card{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-sm,.5rem);background:var(--roxy-surface,#fff);gap:var(--roxy-space-xs,.25rem);display:grid}.label{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;margin:0}.image{aspect-ratio:.6;background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 60%, transparent);border-radius:var(--roxy-radius-sm,4px);width:100%;font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);justify-content:center;align-items:center;display:flex;overflow:hidden}.image img{object-fit:cover;width:100%;height:100%;transition:transform var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,cubic-bezier(.4, 0, .2, 1))}.image img.reversed{transform:rotate(180deg)}.name{font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);margin:0}.interp{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-secondary,#475569);margin:0}.reading{color:var(--roxy-fg,#0a0a0a);margin:0}`,\n\t];\n\n\t@property({ type: String, reflect: true })\n\tspread:\n\t\t| 'three-card'\n\t\t| 'celtic-cross'\n\t\t| 'love'\n\t\t| 'career'\n\t\t| 'custom'\n\t\t| 'yes-no'\n\t\t| 'draw' = 'three-card';\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No tarot spread</div>`;\n\t}\n\n\tprotected renderData(d: TarotSpreadData) {\n\t\tconst isYesNo = 'answer' in d;\n\t\tconst isDrawn = 'cards' in d && !('spread' in d);\n\t\tconst positions = isDrawn\n\t\t\t? []\n\t\t\t: 'positions' in d\n\t\t\t\t? (d.positions ?? [])\n\t\t\t\t: [];\n\t\tconst cards = isDrawn && 'cards' in d ? (d as DrawCardsResponse).cards : [];\n\t\tconst answer = isYesNo ? (d as CastYesNoResponse).answer : undefined;\n\t\tconst strength = isYesNo ? (d as CastYesNoResponse).strength : undefined;\n\t\tconst spreadLabel =\n\t\t\t'spread' in d\n\t\t\t\t? (d as CastThreeCardResponse).spread\n\t\t\t\t: this.spread.replace(/-/g, ' ');\n\t\tconst question =\n\t\t\t'question' in d ? (d as CastThreeCardResponse).question : undefined;\n\t\tconst summary =\n\t\t\t'summary' in d ? (d as CastThreeCardResponse).summary : undefined;\n\t\tconst yesNoInterp = isYesNo\n\t\t\t? (d as CastYesNoResponse).interpretation\n\t\t\t: undefined;\n\t\tconst answerClass = answer\n\t\t\t? answer.toLowerCase().replace(/[^a-z]/g, '')\n\t\t\t: '';\n\n\t\treturn html`<article class=\"wrap\" aria-label=\"Tarot spread\"><header class=\"head\"><h2 class=\"title\">${spreadLabel}</h2>${question ? html`<span class=\"question\">\"${question}\"</span>` : nothing}</header>${\n\t\t\t\tisYesNo\n\t\t\t\t\t? html`<div><span class=\"${`answer ${answerClass}`}\">${answer}</span> ${strength ? html`<small>\u00B7 ${strength}</small>` : nothing}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tpositions.length > 0\n\t\t\t\t\t? html`<div class=\"grid\">${positions.map(\n\t\t\t\t\t\t\t(p) => html`<div class=\"card\"><p class=\"label\">${p.name ?? ''}</p><div class=\"image\">${\n\t\t\t\t\t\t\t\t\t\tp.card?.imageUrl\n\t\t\t\t\t\t\t\t\t\t\t? html`<img src=\"${p.card.imageUrl}\" alt=\"${p.card.name ?? 'tarot card'}\" class=\"${p.card.reversed ? 'reversed' : ''}\">`\n\t\t\t\t\t\t\t\t\t\t\t: html`${p.card?.name ?? '?'}`\n\t\t\t\t\t\t\t\t\t}</div><p class=\"name\">${p.card?.name ?? ''} ${p.card?.reversed ? html`<small>(reversed)</small>` : nothing}</p>${p.interpretation ? html`<p class=\"interp\">${p.interpretation}</p>` : nothing}</div>`,\n\t\t\t\t\t\t)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tcards.length > 0\n\t\t\t\t\t? html`<div class=\"grid\">${cards.map(\n\t\t\t\t\t\t\t(c) => html`<div class=\"card\"><div class=\"image\">${\n\t\t\t\t\t\t\t\t\t\tc.imageUrl\n\t\t\t\t\t\t\t\t\t\t\t? html`<img src=\"${c.imageUrl}\" alt=\"${c.name ?? 'tarot card'}\" class=\"${c.reversed ? 'reversed' : ''}\">`\n\t\t\t\t\t\t\t\t\t\t\t: html`${c.name ?? '?'}`\n\t\t\t\t\t\t\t\t\t}</div><p class=\"name\">${c.name ?? ''} ${c.reversed ? html`<small>(reversed)</small>` : nothing}</p>${c.meaning ? html`<p class=\"interp\">${c.meaning}</p>` : nothing}</div>`,\n\t\t\t\t\t\t)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${summary ? html`<p class=\"reading\">${summary}</p>` : nothing} ${yesNoInterp ? html`<p class=\"reading\">${yesNoInterp}</p>` : nothing}</article>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-tarot-spread': RoxyTarotSpread;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\nimport { PLANET_GLYPH, SIGN_GLYPH } from '../tokens/index.js';\nimport type { TransitsResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { chevron, disclosureStyles } from '../utils/disclosure.js';\nimport { formatDate, formatNumber, formatTime } from '../utils/format.js';\nimport { capitalize } from '../utils/string.js';\nimport { renderTablist, tablistStyles } from '../utils/tablist.js';\n\n/**\n * Transit positions and aspect table. Pass `data` from /astrology/transits.\n * When natalChart is included in the request, `data.transitAspects` and\n * `data.summary` are present and rendered automatically.\n */\n@customElement('roxy-transits-table')\nexport class RoxyTransitsTable extends RoxyDataElement<TransitsResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\ttablistStyles,\n\t\tdisclosureStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-md,1rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.subtitle{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem);margin:0}.summary-pills{gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.pill{padding:2px var(--roxy-space-sm,.5rem);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);border:1px solid;align-items:center;gap:4px;display:inline-flex}.pill--muted{color:var(--roxy-fg,#0a0a0a);background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 60%, transparent)}.pill--success{color:var(--roxy-success-fg,#166534);background:color-mix(in srgb, var(--roxy-success,#16a34a) 10%, transparent)}.pill--danger{color:var(--roxy-danger-fg,#991b1b);background:color-mix(in srgb, var(--roxy-danger,#dc2626) 10%, transparent)}table{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem)}th,td{padding:var(--roxy-space-sm,.5rem);border-bottom:1px solid var(--roxy-border,#e4e4e7);text-align:left}th{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;font-size:var(--roxy-text-xs,.75rem);letter-spacing:.06em}.section-label{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;font-weight:var(--roxy-weight-bold,600);margin:0 0 var(--roxy-space-xs,.25rem) 0}.glyph{margin-right:2px;font-size:1.1em;line-height:1}.planet-cell{white-space:nowrap;align-items:center;gap:4px;display:flex}.retro-badge{border-radius:var(--roxy-radius-sm,4px);background:color-mix(in srgb, var(--roxy-warning,#ea580c) 12%, transparent);color:var(--roxy-warning-fg,#9a3412);font-size:.7em;font-weight:var(--roxy-weight-bold,600);vertical-align:middle;margin-left:2px;padding:1px 4px;display:inline-block}.speed{font-variant-numeric:tabular-nums;color:var(--roxy-muted,#71717a);white-space:nowrap}.speed-arrow{font-size:.85em}td.num{font-variant-numeric:tabular-nums;color:var(--roxy-muted,#71717a)}.overflow-scroll{-webkit-overflow-scrolling:touch;overflow-x:auto}.aspect-card{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);margin-bottom:var(--roxy-space-xs,.25rem)}.aspect-card summary{cursor:pointer;color:var(--roxy-fg,#0a0a0a);flex-wrap:wrap;align-items:center;gap:.5em;font-weight:500;display:flex}.aspect-card summary .meta{color:var(--roxy-muted,#71717a);font-weight:400;font-size:var(--roxy-text-xs,.75rem);font-variant-numeric:tabular-nums;margin-left:auto}.aspect-card .interp-body{margin-top:var(--roxy-space-xs,.25rem);color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);line-height:1.45}.aspect-card .interp-body p{margin:0 0 var(--roxy-space-xs,.25rem)}.interp-keywords{flex-wrap:wrap;gap:.25rem;margin-top:.5rem;display:flex}.interp-keywords .kw{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 14%, transparent);color:var(--roxy-accent-ink,#b45309);font-size:var(--roxy-text-xs,.75rem);border-radius:9999px;padding:1px 8px}.nature-badge{font-size:var(--roxy-text-xs,.75rem);border-radius:9999px;padding:1px 8px;font-weight:600;display:inline-block}.nature-badge.harmonious{background:color-mix(in srgb, var(--roxy-success,#16a34a) 12%, transparent);color:var(--roxy-success-fg,#166534)}.nature-badge.challenging{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 12%, transparent);color:var(--roxy-danger-fg,#991b1b)}.nature-badge.neutral{background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 60%, transparent);color:var(--roxy-fg,#0a0a0a)}`,\n\t];\n\n\t/** Which panel is showing: planet positions or the transit-to-natal aspects. */\n\t@state()\n\tprivate tab: 'positions' | 'aspects' = 'positions';\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No transits data</div>`;\n\t}\n\n\tprotected renderData(d: TransitsResponse) {\n\t\tif (!d.transitPlanets?.length) return this.renderEmpty();\n\n\t\tconst {\n\t\t\ttransitDate,\n\t\t\ttransitTime,\n\t\t\ttransitPlanets,\n\t\t\ttransitAspects,\n\t\t\tsummary,\n\t\t} = d;\n\n\t\tconst dateStr = [formatDate(transitDate), formatTime(transitTime)]\n\t\t\t.filter(Boolean)\n\t\t\t.join(' ');\n\t\tconst aspectCount = transitAspects?.length ?? 0;\n\t\tconst tab = this.tab;\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Transits\"><div class=\"head\"><h2 class=\"title\">Transits</h2>${dateStr ? html`<p class=\"subtitle\">${dateStr}</p>` : nothing}</div>${\n\t\t\t\taspectCount > 0\n\t\t\t\t\t? html`${renderTablist({\n\t\t\t\t\t\t\titems: [\n\t\t\t\t\t\t\t\t{ id: 'positions', label: 'Positions' },\n\t\t\t\t\t\t\t\t{ id: 'aspects', label: `Aspects (${aspectCount})` },\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tactive: tab,\n\t\t\t\t\t\t\tonSelect: (v) => {\n\t\t\t\t\t\t\t\tthis.tab = v;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tlabel: 'Transit views',\n\t\t\t\t\t\t\tidPrefix: 'transits',\n\t\t\t\t\t\t\tcontrols: true,\n\t\t\t\t\t\t})}<div id=\"transits-panel-${tab}\" role=\"tabpanel\" aria-labelledby=\"transits-tab-${tab}\">${\n\t\t\t\t\t\t\t\ttab === 'positions'\n\t\t\t\t\t\t\t\t\t? html`<div class=\"overflow-scroll\">${this.renderPlanetsTable(transitPlanets)}</div>`\n\t\t\t\t\t\t\t\t\t: html`${summary ? this.renderSummaryPills(summary) : nothing}<div class=\"overflow-scroll\">${this.renderAspectsList(transitAspects ?? [])}</div>`\n\t\t\t\t\t\t\t}</div>`\n\t\t\t\t\t: html`<div class=\"overflow-scroll\">${this.renderPlanetsTable(transitPlanets)}</div>`\n\t\t\t}</div>`;\n\t}\n\n\tprivate renderSummaryPills(\n\t\tsummary: NonNullable<TransitsResponse['summary']>,\n\t) {\n\t\treturn html`<div class=\"summary-pills\" role=\"region\" aria-label=\"Aspect summary\"><span class=\"pill pill--muted\">Total: ${summary.totalAspects} </span><span class=\"pill pill--success\">Harmonious: ${summary.harmonious} </span><span class=\"pill pill--danger\">Challenging: ${summary.challenging} </span><span class=\"pill pill--muted\">Neutral: ${summary.neutral}</span></div>`;\n\t}\n\n\tprivate renderPlanetsTable(planets: TransitsResponse['transitPlanets']) {\n\t\treturn html`<table class=\"planets-table\"><thead><tr><th scope=\"col\">Planet</th><th scope=\"col\">Sign</th><th scope=\"col\">Degree</th><th scope=\"col\">Speed</th></tr></thead><tbody>${planets.map((p) => {\n\t\t\t\t\tconst pGlyph = PLANET_GLYPH[capitalize(p.name)] ?? '';\n\t\t\t\t\tconst sGlyph = SIGN_GLYPH[capitalize(p.sign)] ?? '';\n\t\t\t\t\tconst speedArrow = p.speed >= 0 ? '\u2191' : '\u2193';\n\t\t\t\t\treturn html`<tr><td><div class=\"planet-cell\"><span class=\"glyph\" aria-hidden=\"true\">${pGlyph}</span> ${p.name} ${\n\t\t\t\t\t\t\t\t\tp.isRetrograde\n\t\t\t\t\t\t\t\t\t\t? html`<span class=\"retro-badge\" aria-label=\"retrograde\">R</span>`\n\t\t\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t\t\t}</div></td><td><div class=\"planet-cell\"><span class=\"glyph\" aria-hidden=\"true\">${sGlyph}</span> ${p.sign}</div></td><td class=\"num\">${formatNumber(p.degree, 2)}</td><td class=\"speed\"><span class=\"speed-arrow\" aria-hidden=\"true\">${speedArrow}</span> ${formatNumber(Math.abs(p.speed), 4)}</td></tr>`;\n\t\t\t\t})}</tbody></table>`;\n\t}\n\n\tprivate renderAspectsList(\n\t\taspects: NonNullable<TransitsResponse['transitAspects']>,\n\t) {\n\t\treturn html`<div role=\"list\" aria-label=\"Transit aspects\">${aspects.map((a, idx) => {\n\t\t\t\tconst tGlyph = PLANET_GLYPH[capitalize(a.transitPlanet)] ?? '';\n\t\t\t\tconst nGlyph = PLANET_GLYPH[capitalize(a.natalPlanet)] ?? '';\n\t\t\t\tconst nature = (a.nature ?? 'neutral').toLowerCase();\n\t\t\t\tconst interp = a.interpretation;\n\t\t\t\tconst type = (a.type ?? '').toLowerCase();\n\t\t\t\tconst status = a.isApplying ? 'Applying' : 'Separating';\n\t\t\t\treturn html`<details class=\"aspect-card\" role=\"listitem\" name=\"transit-aspects\" ?open=\"${idx === 0}\"><summary><span aria-hidden=\"true\">${tGlyph}</span> ${a.transitPlanet} <span class=\"nature-badge ${nature}\">${type}</span> <span aria-hidden=\"true\">${nGlyph}</span> ${a.natalPlanet} <span class=\"meta\">${status} \u00B7 orb ${formatNumber(a.orb, 2)}\u00B0 \u00B7 strength ${formatNumber(a.strength, 1)} </span>${chevron()}</summary><div class=\"interp-body\">${interp?.summary ? html`<p>${interp.summary}</p>` : nothing} ${interp?.impact ? html`<p><strong>Impact:</strong> ${interp.impact}</p>` : nothing} ${interp?.timing ? html`<p><strong>Timing:</strong> ${interp.timing}</p>` : nothing} ${interp?.guidance ? html`<p><strong>Guidance:</strong> ${interp.guidance}</p>` : nothing} ${\n\t\t\t\t\t\t\tinterp?.keywords?.length\n\t\t\t\t\t\t\t\t? html`<div class=\"interp-keywords\">${interp.keywords.map((k) => html`<span class=\"kw\">${k}</span>`)}</div>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}</div></details>`;\n\t\t\t})}</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-transits-table': RoxyTransitsTable;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { CalculateDrishtiResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatNumber } from '../utils/format.js';\n\n/**\n * Vedic graha drishti (planetary aspects) table. Renders /vedic-astrology/aspects: which planet casts an aspect on which, by special Vedic rules (every graha aspects the 7th; Mars the 4th and 8th, Jupiter the 5th and 9th, Saturn the 3rd and 10th). Mutual aspects (two planets aspecting each other) are surfaced first as they are the strongest sambandha. Each row shows the aspecting planet, the aspect kind, the aspected planet, its strength and orb.\n */\n@customElement('roxy-vedic-aspects')\nexport class RoxyVedicAspects extends RoxyDataElement<CalculateDrishtiResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-md,1rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.subtitle{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem);margin:0}.section-label{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;font-weight:var(--roxy-weight-bold,600);margin:0 0 var(--roxy-space-xs,.25rem) 0}.mutual{gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.mutual-pill{border-radius:var(--roxy-radius-full,9999px);background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 14%, transparent);color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);align-items:center;gap:.35rem;padding:2px 10px;display:inline-flex}.mutual-pill .rel{font-size:var(--roxy-text-xs,.75rem);font-weight:400}.overflow-scroll{-webkit-overflow-scrolling:touch;overflow-x:auto}table{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem)}th,td{padding:var(--roxy-space-sm,.5rem);border-bottom:1px solid var(--roxy-border,#e4e4e7);text-align:left;white-space:nowrap}th{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;font-size:var(--roxy-text-xs,.75rem);letter-spacing:.06em}tbody tr:last-child td{border-bottom:none}.kind{border-radius:var(--roxy-radius-full,9999px);background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 55%, transparent);font-size:var(--roxy-text-xs,.75rem);padding:1px 8px;font-weight:600;display:inline-block}.num{font-variant-numeric:tabular-nums;color:var(--roxy-muted,#71717a)}.bar{background:var(--roxy-accent,#f59e0b);vertical-align:middle;border-radius:3px;height:6px;margin-right:6px;display:inline-block}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No aspect data</div>`;\n\t}\n\n\tprotected renderData(d: CalculateDrishtiResponse) {\n\t\tconst aspects = d.aspects ?? [];\n\t\tconst mutual = d.mutualAspects ?? [];\n\t\tif (aspects.length === 0 && mutual.length === 0) return this.renderEmpty();\n\t\tconst date = d.datetime ? String(d.datetime).replace('T', ' ') : '';\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Vedic aspects\"><div class=\"head\"><h2 class=\"title\">Vedic Aspects</h2>${date ? html`<p class=\"subtitle\">${date}</p>` : nothing}</div>${\n\t\t\t\tmutual.length > 0\n\t\t\t\t\t? html`<div><p class=\"section-label\">Mutual aspects</p><div class=\"mutual\">${mutual.map(\n\t\t\t\t\t\t\t\t(m) => html`<span class=\"mutual-pill\">${m.planet1} \u27F7 ${m.planet2} ${m.aspectType ? html`<span class=\"rel\">${m.aspectType}</span>` : nothing}</span>`,\n\t\t\t\t\t\t\t)}</div></div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\taspects.length > 0\n\t\t\t\t\t? html`<div class=\"overflow-scroll\"><table><thead><tr><th scope=\"col\">From</th><th scope=\"col\">Aspect</th><th scope=\"col\">To</th><th scope=\"col\">Strength</th><th scope=\"col\">Orb</th></tr></thead><tbody>${aspects.map(\n\t\t\t\t\t\t\t\t\t(a) => html`<tr><td>${a.aspectingPlanet}</td><td><span class=\"kind\">${a.aspectType}</span></td><td>${a.aspectedPlanet}</td><td>${typeof a.strength === 'number' ? html`<span class=\"bar\" style=\"width:${Math.max(4, Math.min(100, a.strength) * 0.4)}px\"></span><span class=\"num\">${formatNumber(a.strength, 0)}</span>` : nothing}</td><td class=\"num\">${typeof a.orb === 'number' ? `${formatNumber(a.orb, 2)}\u00B0` : ''}</td></tr>`,\n\t\t\t\t\t\t\t\t)}</tbody></table></div>`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-vedic-aspects': RoxyVedicAspects;\n\t}\n}\n", "import { html } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type { BirthChartResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport {\n\ttype ChartStyle,\n\ttype KundliViewModel,\n\trenderKundliStyleTablist,\n\trenderKundliSvg,\n\ttoKundliViewModel,\n} from '../utils/kundli-render.js';\nimport { kundliStyles } from '../utils/kundli-styles.js';\nimport { tablistStyles } from '../utils/tablist.js';\n\n/**\n * Vedic kundli (D1 Rashi chart). Pass `data` from /vedic-astrology/birth-chart.\n * Three regional render styles are available; the visible tablist lets the\n * end user switch between South / North / East at any time. The same planet-\n * in-sign data feeds every style, so the toggle is purely a layout choice.\n *\n * Each planet shows its abbreviation and whole-degree-within-sign, with an\n * SVG tooltip carrying exact position, nakshatra, pada, and avastha. The host\n * page sets the initial style via `chart-style` attribute; from there the\n * user takes over.\n *\n * The ascendant (house 1) defaults to the Janma Lagna carried in the response\n * `meta`. Set `chart-reference=\"moon\"` to render the Chandra Lagna (Moon as\n * ascendant) from the same response, or `lagna-override=\"<rashi>\"` to pin the\n * reference to any sign (Surya Lagna, Arudha Lagna, a custom point). The same\n * planet-in-sign data feeds every reference; only the house numbering rotates.\n *\n * Theming flows through CSS custom properties on `:host`, so the chart\n * adopts the host page palette without runtime color probing.\n */\n@customElement('roxy-vedic-kundli')\nexport class RoxyVedicKundli extends RoxyDataElement<BirthChartResponse> {\n\tstatic styles = [baseStyles, kundliStyles, tablistStyles];\n\n\t@property({ type: String, reflect: true, attribute: 'chart-style' })\n\tchartStyle: ChartStyle = 'north';\n\n\t/**\n\t * Ascendant reference point. `'lagna'` (default) uses the Janma Lagna from the response; `'moon'` renders the Chandra Lagna (Moon sign as house 1) from the same response. An explicit {@link lagnaOverride} wins over this.\n\t */\n\t@property({ type: String, reflect: true, attribute: 'chart-reference' })\n\tchartReference: 'lagna' | 'moon' = 'lagna';\n\n\t/**\n\t * Explicit rashi/sign name (case-insensitive, e.g. `\"cancer\"`) to use as the ascendant, overriding both the Janma Lagna and {@link chartReference}. Empty by default (standard Janma Lagna). Use for Surya Lagna, Arudha Lagna, or any custom reference chart.\n\t */\n\t@property({ type: String, reflect: true, attribute: 'lagna-override' })\n\tlagnaOverride = '';\n\n\t/**\n\t * Resolve the ascendant override fed to {@link toKundliViewModel}. An explicit `lagna-override` wins; otherwise `chart-reference=\"moon\"` derives the Moon rashi from the response `meta`. Returns `undefined` for the default Janma Lagna path.\n\t */\n\tprivate resolveReference(): string | undefined {\n\t\tif (this.lagnaOverride) return this.lagnaOverride;\n\t\tif (this.chartReference === 'moon') return this.data?.meta?.Moon?.rashi;\n\t\treturn undefined;\n\t}\n\n\tprivate viewModel(): KundliViewModel | null {\n\t\tif (!this.data?.meta) return null;\n\t\treturn toKundliViewModel(\n\t\t\tthis.data.meta,\n\t\t\t'D1 Rashi',\n\t\t\tthis.resolveReference(),\n\t\t);\n\t}\n\n\tprivate setStyle = (next: ChartStyle) => {\n\t\tthis.chartStyle = next;\n\t};\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No kundli data</div>`;\n\t}\n\n\tprotected renderData(_d: BirthChartResponse) {\n\t\tconst vm = this.viewModel();\n\t\tif (!vm) return this.renderEmpty();\n\t\tconst title =\n\t\t\tthis.chartReference === 'moon' && !this.lagnaOverride\n\t\t\t\t? 'Chandra lagna'\n\t\t\t\t: 'Vedic kundli';\n\t\treturn html`<div class=\"wrap\"><div class=\"header\"><h2 class=\"title\">${title}</h2>${renderKundliStyleTablist(this.chartStyle, this.setStyle)}</div><svg viewBox=\"0 0 400 400\" preserveAspectRatio=\"xMidYMid meet\" role=\"img\" aria-label=\"Vedic birth chart with twelve sign houses\"><title>Vedic kundli</title>${renderKundliSvg(vm, this.chartStyle)}</svg></div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-vedic-kundli': RoxyVedicKundli;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { PLANET_GLYPH, SIGN_GLYPH } from '../tokens/index.js';\nimport type { BirthChartResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatSignPosition } from '../utils/degree.js';\nimport { chevron, disclosureStyles } from '../utils/disclosure.js';\nimport { formatNumber } from '../utils/format.js';\nimport { capitalize } from '../utils/string.js';\n\n/**\n * Fixed display order: Lagna pinned first as the chart frame, then the nine\n * grahas in classical sequence. Any graha not in this list is appended.\n */\nconst GRAHA_ORDER = [\n\t'Lagna',\n\t'Sun',\n\t'Moon',\n\t'Mars',\n\t'Mercury',\n\t'Jupiter',\n\t'Venus',\n\t'Saturn',\n\t'Rahu',\n\t'Ketu',\n];\n\ntype MetaEntry = BirthChartResponse['meta'][string];\n\n/**\n * Vedic planetary positions table. Renders /vedic-astrology/birth-chart `meta`\n * as the full reference-grade positions grid a practitioner reads alongside\n * the kundli wheel: graha, rashi, exact degree, nakshatra and pada, nakshatra\n * lord, bhava (house), Baladi avastha, and retrograde.\n *\n * @remarks\n * The positions grid is the default view. The same birth-chart response also\n * carries chart-wide conditions and readings, surfaced as collapsed accordions\n * below the grid so they never crowd the table: combust grahas (astangata),\n * planetary wars (graha yuddha), per-graha rashi and nakshatra interpretations,\n * the active classical yogas (present === true), and the twelve bhava\n * significations. Each accordion renders only when its source array or map is\n * non-empty.\n */\n@customElement('roxy-vedic-planets-table')\nexport class RoxyVedicPlanetsTable extends RoxyDataElement<BirthChartResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tdisclosureStyles,\n\t\tcss`.wrap{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);background:var(--roxy-surface,#fff);box-shadow:var(--roxy-shadow-sm);overflow:hidden}.head{padding:var(--roxy-space-md,1rem);border-bottom:1px solid var(--roxy-border,#e4e4e7)}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.scroll{overflow-x:auto}table{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem);min-width:620px}thead{background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 20%, transparent)}th,td{padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);text-align:left;white-space:nowrap}th{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;font-size:var(--roxy-text-xs,.75rem);letter-spacing:.04em}tbody tr{border-top:1px solid var(--roxy-border,#e4e4e7)}tbody tr.lagna{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 10%, transparent)}td.graha{font-weight:var(--roxy-weight-bold,600);color:var(--roxy-fg,#0a0a0a)}.glyph{color:var(--roxy-muted,#71717a);margin-right:.4em}tbody tr.lagna .glyph{color:var(--roxy-accent-ink,#b45309)}.retro{color:var(--roxy-warning-fg,#9a3412);font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600)}.num{font-variant-numeric:tabular-nums}details.panel{border-top:1px solid var(--roxy-border,#e4e4e7)}details.panel>summary{justify-content:space-between;align-items:center;gap:var(--roxy-space-sm,.5rem);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);cursor:pointer;font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-fg,#0a0a0a);display:flex}details.panel>summary:focus-visible{outline:2px solid var(--roxy-ring,#f59e0b66);outline-offset:-2px}.summary-count{margin-left:auto;margin-right:var(--roxy-space-xs,.25rem);font-weight:var(--roxy-weight-normal,400);color:var(--roxy-muted,#71717a);font-variant-numeric:tabular-nums}.panel-body{padding:0 var(--roxy-space-md,1rem) var(--roxy-space-md,1rem);gap:var(--roxy-space-sm,.5rem);display:grid}.condition{font-size:var(--roxy-text-sm,.875rem);flex-wrap:wrap;align-items:baseline;gap:.4em;display:flex}.condition .planet{font-weight:var(--roxy-weight-bold,600)}.condition .detail{color:var(--roxy-muted,#71717a);font-variant-numeric:tabular-nums}.condition .winner{color:var(--roxy-success-fg,#166534);font-weight:var(--roxy-weight-bold,600)}.interp{gap:.15em;display:grid}.interp .planet{font-weight:var(--roxy-weight-bold,600);font-size:var(--roxy-text-sm,.875rem)}.interp p{font-size:var(--roxy-text-sm,.875rem);line-height:var(--roxy-leading-normal,1.5);margin:0}.interp .label{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600)}.bhava{gap:.15em;display:grid}.bhava .name{font-weight:var(--roxy-weight-bold,600);font-size:var(--roxy-text-sm,.875rem)}.bhava .desc{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-muted,#71717a);line-height:var(--roxy-leading-normal,1.5);margin:0}.quality{font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;letter-spacing:.04em}.quality.positive{color:var(--roxy-success-fg,#166534)}.quality.negative{color:var(--roxy-danger-fg,#991b1b)}.quality.both{color:var(--roxy-muted,#71717a)}`,\n\t];\n\n\t/** Ordered [name, entry] pairs: GRAHA_ORDER first, then any extras. */\n\tprivate orderedRows(): Array<[string, MetaEntry]> {\n\t\tconst meta = this.data?.meta ?? {};\n\t\tconst seen = new Set<string>();\n\t\tconst rows: Array<[string, MetaEntry]> = [];\n\t\tfor (const name of GRAHA_ORDER) {\n\t\t\tconst entry = meta[name];\n\t\t\tif (entry) {\n\t\t\t\trows.push([name, entry]);\n\t\t\t\tseen.add(name);\n\t\t\t}\n\t\t}\n\t\tfor (const [name, entry] of Object.entries(meta)) {\n\t\t\tif (!seen.has(name)) rows.push([name, entry]);\n\t\t}\n\t\treturn rows;\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No chart data</div>`;\n\t}\n\n\tprotected renderData(d: BirthChartResponse) {\n\t\tif (!d.meta) return this.renderEmpty();\n\t\tconst rows = this.orderedRows();\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Vedic planetary positions\"><header class=\"head\"><h2 class=\"title\">Planetary positions</h2></header><div class=\"scroll\" tabindex=\"0\"><table role=\"table\"><thead><tr><th scope=\"col\">Graha</th><th scope=\"col\">Rashi</th><th scope=\"col\">Degree</th><th scope=\"col\">Nakshatra</th><th scope=\"col\">Pada</th><th scope=\"col\">Nak. lord</th><th scope=\"col\">House</th><th scope=\"col\">Avastha</th><th scope=\"col\">Retro</th></tr></thead><tbody>${rows.map(([name, p]) => {\n\t\t\t\t\t\tconst isLagna = (p.graha ?? name) === 'Lagna';\n\t\t\t\t\t\tconst glyph = PLANET_GLYPH[capitalize(p.graha ?? name)] ?? '';\n\t\t\t\t\t\tconst signGlyph = SIGN_GLYPH[capitalize(p.rashi ?? '')] ?? '';\n\t\t\t\t\t\treturn html`<tr class=\"${isLagna ? 'lagna' : ''}\"><td class=\"graha\">${glyph ? html`<span class=\"glyph\">${glyph}</span>` : nothing}${p.graha ?? name}</td><td>${signGlyph ? html`<span class=\"glyph\">${signGlyph}</span>` : nothing}${p.rashi ?? ''}</td><td class=\"num\">${typeof p.longitude === 'number' ? formatSignPosition(p.longitude) : ''}</td><td>${p.nakshatra?.name ?? ''}</td><td class=\"num\">${p.nakshatra?.pada ?? ''}</td><td>${p.nakshatra?.lord ?? ''}</td><td class=\"num\">${typeof p.house === 'number' ? p.house : ''}</td><td>${p.awastha ?? ''}</td><td>${p.isRetrograde ? html`<span class=\"retro\">R</span>` : nothing}</td></tr>`;\n\t\t\t\t\t})}</tbody></table></div>${this.renderCombustion()} ${this.renderPlanetaryWar()} ${this.renderInterpretations()} ${this.renderYogas()} ${this.renderHouses()}</div>`;\n\t}\n\n\tprivate renderCombustion() {\n\t\tconst combust = this.data?.combustion ?? [];\n\t\tif (combust.length === 0) return nothing;\n\t\treturn html`<details class=\"panel\"><summary>Combust grahas<span class=\"summary-count\">${combust.length}</span>${chevron()}</summary><div class=\"panel-body\">${combust.map((c) => {\n\t\t\t\t\tconst glyph = PLANET_GLYPH[capitalize(c.planet)] ?? '';\n\t\t\t\t\tconst dist = formatNumber(c.distanceFromSun, 2);\n\t\t\t\t\tconst orb = formatNumber(c.orb, 1);\n\t\t\t\t\treturn html`<div class=\"condition\"><span class=\"planet\">${glyph ? `${glyph} ` : ''}${c.planet}</span> <span class=\"detail\">${dist} deg from Sun, within ${orb} deg orb</span></div>`;\n\t\t\t\t})}</div></details>`;\n\t}\n\n\tprivate renderPlanetaryWar() {\n\t\tconst wars = this.data?.planetaryWar ?? [];\n\t\tif (wars.length === 0) return nothing;\n\t\treturn html`<details class=\"panel\"><summary>Planetary wars<span class=\"summary-count\">${wars.length}</span>${chevron()}</summary><div class=\"panel-body\">${wars.map((w) => {\n\t\t\t\t\tconst dist = formatNumber(w.distance, 2);\n\t\t\t\t\treturn html`<div class=\"condition\"><span class=\"planet\">${w.planet1} vs ${w.planet2}</span> <span class=\"detail\">${dist} deg apart</span> <span class=\"winner\">${w.winner} wins</span></div>`;\n\t\t\t\t})}</div></details>`;\n\t}\n\n\tprivate renderInterpretations() {\n\t\tconst interp = this.data?.interpretations ?? {};\n\t\tconst entries = this.orderedRows()\n\t\t\t.map(([name, p]) => [p.graha ?? name, interp[p.graha ?? name]] as const)\n\t\t\t.filter(([, v]) => v != null);\n\t\tif (entries.length === 0) return nothing;\n\t\treturn html`<details class=\"panel\"><summary>Interpretations<span class=\"summary-count\">${entries.length}</span>${chevron()}</summary><div class=\"panel-body\">${entries.map(([name, v]) => {\n\t\t\t\t\tconst glyph = PLANET_GLYPH[capitalize(name)] ?? '';\n\t\t\t\t\treturn html`<div class=\"interp\"><span class=\"planet\">${glyph ? `${glyph} ` : ''}${name}</span> ${v.rashi ? html`<p><span class=\"label\">Rashi.</span> ${v.rashi}</p>` : nothing} ${v.nakshatra ? html`<p><span class=\"label\">Nakshatra.</span> ${v.nakshatra}</p>` : nothing}</div>`;\n\t\t\t\t})}</div></details>`;\n\t}\n\n\tprivate renderHouses() {\n\t\tconst houses = (this.data?.houses ?? []).filter(\n\t\t\t(h) => h.name || h.description,\n\t\t);\n\t\tif (houses.length === 0) return nothing;\n\t\treturn html`<details class=\"panel\"><summary>Bhava significations<span class=\"summary-count\">${houses.length}</span>${chevron()}</summary><div class=\"panel-body\">${houses.map(\n\t\t\t\t\t(h) => html`<div class=\"bhava\"><span class=\"name\">${h.number}. ${h.name ?? ''}</span> ${h.description ? html`<p class=\"desc\">${h.description}</p>` : nothing}</div>`,\n\t\t\t\t)}</div></details>`;\n\t}\n\n\tprivate renderYogas() {\n\t\tconst yogas = (this.data?.yogas ?? []).filter((y) => y.present);\n\t\tif (yogas.length === 0) return nothing;\n\t\treturn html`<details class=\"panel\"><summary>Yogas<span class=\"summary-count\">${yogas.length}</span>${chevron()}</summary><div class=\"panel-body\">${yogas.map(\n\t\t\t\t\t(y) => html`<div class=\"bhava\"><span class=\"name\">${y.name} ${y.quality ? html`<span class=\"quality ${y.quality.toLowerCase()}\">${y.quality}</span>` : nothing}</span> ${y.result ? html`<p class=\"desc\">${y.result}</p>` : nothing}</div>`,\n\t\t\t\t)}</div></details>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-vedic-planets-table': RoxyVedicPlanetsTable;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { PLANET_GLYPH, SIGN_GLYPH } from '../tokens/index.js';\nimport type { NatalChartResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatSignPosition } from '../utils/degree.js';\nimport { formatNumber } from '../utils/format.js';\nimport { capitalize } from '../utils/string.js';\n\n/** A body or point row, normalized so planets and the four angles share a table. */\ninterface BodyRow {\n\tname: string;\n\tsign?: string;\n\tlongitude?: number;\n\thouse?: number;\n\tspeed?: number;\n\tisRetrograde?: boolean;\n\t/** True for the chart angles (ASC, MC, Part of Fortune, Vertex). */\n\tisPoint?: boolean;\n}\n\n/**\n * Western planetary positions table. Renders a /astrology/natal-chart response\n * as the reference-grade positions grid astrologers read alongside the wheel:\n * every body with its sign, exact degree, house, and daily motion, followed by\n * the four chart points (Ascendant, Midheaven, Part of Fortune, Vertex).\n */\n@customElement('roxy-western-planets-table')\nexport class RoxyWesternPlanetsTable extends RoxyDataElement<NatalChartResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);background:var(--roxy-surface,#fff);box-shadow:var(--roxy-shadow-sm);overflow:auto}.head{padding:var(--roxy-space-md,1rem);border-bottom:1px solid var(--roxy-border,#e4e4e7)}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}table{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem);min-width:460px}thead{background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 20%, transparent)}th,td{padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);text-align:left;white-space:nowrap}th{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;font-size:var(--roxy-text-xs,.75rem);letter-spacing:.04em}tbody tr{border-top:1px solid var(--roxy-border,#e4e4e7)}tbody tr.point{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 8%, transparent)}td.body{font-weight:var(--roxy-weight-bold,600);color:var(--roxy-fg,#0a0a0a)}.glyph{color:var(--roxy-muted,#71717a);margin-right:.4em}.retro{color:var(--roxy-danger,#dc2626);font-weight:var(--roxy-weight-bold,600)}.num{font-variant-numeric:tabular-nums}`,\n\t];\n\n\t/** Build the ordered row list: the planets array, then the four chart points. */\n\tprivate rows(): BodyRow[] {\n\t\tconst d = this.data;\n\t\tif (!d) return [];\n\t\tconst rows: BodyRow[] = (d.planets ?? []).map((p) => ({\n\t\t\tname: p.name,\n\t\t\tsign: p.sign,\n\t\t\tlongitude: p.longitude,\n\t\t\thouse: p.house,\n\t\t\tspeed: p.speed,\n\t\t\tisRetrograde: p.isRetrograde,\n\t\t}));\n\t\tfor (const [name, point] of [\n\t\t\t['Ascendant', d.ascendant],\n\t\t\t['Midheaven', d.midheaven],\n\t\t\t['Part of Fortune', d.partOfFortune],\n\t\t\t['Vertex', d.vertex],\n\t\t] as const) {\n\t\t\tif (point) {\n\t\t\t\trows.push({\n\t\t\t\t\tname,\n\t\t\t\t\tsign: point.sign,\n\t\t\t\t\tlongitude: point.longitude,\n\t\t\t\t\tisPoint: true,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn rows;\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No chart data</div>`;\n\t}\n\n\tprotected renderData(d: NatalChartResponse) {\n\t\tif (!d.planets) return this.renderEmpty();\n\t\tconst rows = this.rows();\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Western planetary positions\" tabindex=\"0\"><header class=\"head\"><h2 class=\"title\">Planetary positions</h2></header><table role=\"table\"><thead><tr><th scope=\"col\">Body</th><th scope=\"col\">Sign</th><th scope=\"col\">Degree</th><th scope=\"col\">House</th><th scope=\"col\">Motion</th></tr></thead><tbody>${rows.map((r) => {\n\t\t\t\t\t\tconst glyph = PLANET_GLYPH[capitalize(r.name)] ?? '';\n\t\t\t\t\t\tconst signGlyph = SIGN_GLYPH[capitalize(r.sign ?? '')] ?? '';\n\t\t\t\t\t\tconst speed =\n\t\t\t\t\t\t\ttypeof r.speed === 'number' ? formatNumber(r.speed, 3) : '';\n\t\t\t\t\t\treturn html`<tr class=\"${r.isPoint ? 'point' : ''}\"><td class=\"body\">${glyph ? html`<span class=\"glyph\">${glyph}</span>` : nothing}${r.name}</td><td>${signGlyph ? html`<span class=\"glyph\">${signGlyph}</span>` : nothing}${r.sign ?? ''}</td><td class=\"num\">${typeof r.longitude === 'number' ? formatSignPosition(r.longitude) : ''}</td><td class=\"num\">${typeof r.house === 'number' ? r.house : ''}</td><td class=\"num\">${speed ? html`${speed}\u00B0/day` : nothing} ${r.isRetrograde ? html`<span class=\"retro\">\u211E</span>` : nothing}</td></tr>`;\n\t\t\t\t\t})}</tbody></table></div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-western-planets-table': RoxyWesternPlanetsTable;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\nimport type {\n\tDetectYogasResponse,\n\tGetYogaResponse,\n\tListYogasResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\ntype YogaListData =\n\t| ListYogasResponse\n\t| GetYogaResponse\n\t| DetectYogasResponse\n\t| { yogas: Array<GetYogaResponse> };\n\n/**\n * Yoga catalog and detail renderer. Accepts three data modes:\n * - Catalog: ListYogasResponse (yogas array of {id, name} + total)\n * - Detail: GetYogaResponse (single yoga with description, result, quality)\n * - Detail array: { yogas: Array<GetYogaResponse> } for pre-filtered sets\n *\n * Catalog and detail-array modes include a live search filter.\n */\n@customElement('roxy-yoga-list')\nexport class RoxyYogaList extends RoxyDataElement<YogaListData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.count{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-muted,#71717a)}.search-wrap{align-items:center;gap:var(--roxy-space-sm,.5rem);display:flex}.search{width:100%;max-width:280px;font-size:var(--roxy-text-sm,.875rem);font-family:var(--roxy-font-sans);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);outline:none;padding:.35em .75em}.search::placeholder{color:var(--roxy-fg,#0a0a0a);opacity:.65}.search:focus{border-color:var(--roxy-accent,#f59e0b);box-shadow:0 0 0 2px color-mix(in srgb, var(--roxy-accent,#f59e0b) 30%, transparent)}.grid{gap:var(--roxy-space-sm,.5rem);grid-template-columns:repeat(auto-fill,minmax(180px,1fr));display:grid}.yoga-chip{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);font-size:var(--roxy-text-sm,.875rem);background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);word-break:break-word;padding:.4em .8em}.yoga-chip .yoga-id{color:var(--roxy-fg,#0a0a0a);opacity:.75;margin-top:.15em;font-size:.7em;display:block}.detail-card{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-md,1rem);background:var(--roxy-surface,#fff);gap:var(--roxy-space-sm,.5rem);display:grid}.detail-name{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);align-items:center;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;margin:0;display:flex}.quality-chip{font-size:var(--roxy-text-xs,.75rem);border-radius:999px;padding:.15em .6em;font-weight:600;display:inline-block}.quality-Positive{background:color-mix(in srgb, var(--roxy-success,#22c55e) 18%, transparent);color:var(--roxy-success-fg,#15803d);border:1px solid color-mix(in srgb, var(--roxy-success,#22c55e) 40%, transparent)}.quality-Negative{background:color-mix(in srgb, var(--roxy-danger,#ef4444) 18%, transparent);color:var(--roxy-danger-fg,#b91c1c);border:1px solid color-mix(in srgb, var(--roxy-danger,#ef4444) 40%, transparent)}.quality-Both{background:color-mix(in srgb, var(--roxy-warning,#f59e0b) 18%, transparent);color:var(--roxy-warning-fg,#b45309);border:1px solid color-mix(in srgb, var(--roxy-warning,#f59e0b) 40%, transparent)}.description{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-muted,#71717a);line-height:var(--roxy-leading-normal,1.5);margin:0}details{font-size:var(--roxy-text-sm,.875rem)}details summary{cursor:pointer;color:var(--roxy-accent-ink,#b45309);align-items:center;gap:.4em;padding:.25em 0;font-weight:500;list-style:none;display:flex}details summary:before{content:\"+\";font-size:1.1em;line-height:1}details[open] summary:before{content:\"-\"}details .result-body{padding-top:var(--roxy-space-xs,.25rem);color:var(--roxy-fg,#0a0a0a);line-height:var(--roxy-leading-normal,1.5)}.no-results{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem);padding:var(--roxy-space-md,1rem) 0;text-align:center}.detail-grid{gap:var(--roxy-space-sm,.5rem);display:grid}`,\n\t];\n\n\t@state()\n\tprivate filter = '';\n\n\tprivate readonly handleInput = (e: Event) => {\n\t\tthis.filter = (e.target as HTMLInputElement).value;\n\t};\n\n\tprivate renderQualityChip(quality: string) {\n\t\tconst cls = `quality-chip quality-${quality}`;\n\t\treturn html`<span class=\"${cls}\">${quality}</span>`;\n\t}\n\n\tprivate renderDetailCard(yoga: GetYogaResponse) {\n\t\treturn html`<div class=\"detail-card\"><p class=\"detail-name\">${yoga.name} ${yoga.quality ? this.renderQualityChip(yoga.quality) : nothing}</p>${\n\t\t\t\tyoga.description\n\t\t\t\t\t? html`<p class=\"description\">${yoga.description}</p>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tyoga.result\n\t\t\t\t\t? html`<details><summary>Effects</summary><div class=\"result-body\">${yoga.result}</div></details>`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No yoga data</div>`;\n\t}\n\n\tprotected renderData(d: YogaListData) {\n\t\tconst lc = this.filter.toLowerCase();\n\n\t\t// Detail mode: single GetYogaResponse\n\t\tif (\n\t\t\t'description' in d &&\n\t\t\ttypeof (d as GetYogaResponse).description === 'string'\n\t\t) {\n\t\t\tconst yoga = d as GetYogaResponse;\n\t\t\treturn html`<div class=\"wrap\">${this.renderDetailCard(yoga)}</div>`;\n\t\t}\n\n\t\t// Detail-array mode: { yogas: Array<GetYogaResponse> } where items have description\n\t\tif ('yogas' in d && Array.isArray((d as { yogas: unknown[] }).yogas)) {\n\t\t\tconst allYogas = (\n\t\t\t\td as { yogas: Array<GetYogaResponse | { id: string; name: string }> }\n\t\t\t).yogas;\n\t\t\tconst isDetailArray = allYogas.length > 0 && 'description' in allYogas[0];\n\n\t\t\tif (isDetailArray) {\n\t\t\t\tconst detailYogas = allYogas as GetYogaResponse[];\n\t\t\t\tconst filtered = lc\n\t\t\t\t\t? detailYogas.filter((y) => y.name.toLowerCase().includes(lc))\n\t\t\t\t\t: detailYogas;\n\t\t\t\tconst total = (d as ListYogasResponse).total;\n\t\t\t\treturn html`<div class=\"wrap\"><div class=\"head\"><h2 class=\"title\">Yoga catalog</h2>${\n\t\t\t\t\t\t\ttotal !== undefined\n\t\t\t\t\t\t\t\t? html`<span class=\"count\">${total} total</span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}</div><div class=\"search-wrap\"><input class=\"search\" type=\"search\" placeholder=\"Filter yogas...\" aria-label=\"Filter yoga list by name\" .value=\"${this.filter}\" @input=\"${this.handleInput}\"></div><div class=\"detail-grid\" role=\"region\" aria-live=\"polite\" aria-label=\"Yoga results\">${\n\t\t\t\t\t\t\tfiltered.length > 0\n\t\t\t\t\t\t\t\t? filtered.map((y) => this.renderDetailCard(y))\n\t\t\t\t\t\t\t\t: html`<p class=\"no-results\">No yogas match your search.</p>`\n\t\t\t\t\t\t}</div></div>`;\n\t\t\t}\n\n\t\t\t// Catalog mode: ListYogasResponse with {id, name} items\n\t\t\tconst catalogYogas = allYogas as Array<{ id: string; name: string }>;\n\t\t\tconst filtered = lc\n\t\t\t\t? catalogYogas.filter((y) => y.name.toLowerCase().includes(lc))\n\t\t\t\t: catalogYogas;\n\t\t\tconst total = (d as ListYogasResponse).total;\n\t\t\treturn html`<div class=\"wrap\"><div class=\"head\"><h2 class=\"title\">Yoga catalog</h2>${\n\t\t\t\t\t\ttotal !== undefined\n\t\t\t\t\t\t\t? html`<span class=\"count\">${total} total</span>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}</div><div class=\"search-wrap\"><input class=\"search\" type=\"search\" placeholder=\"Filter yogas...\" aria-label=\"Filter yoga list by name\" .value=\"${this.filter}\" @input=\"${this.handleInput}\"></div><div class=\"grid\" role=\"region\" aria-live=\"polite\" aria-label=\"Yoga results\">${\n\t\t\t\t\t\tfiltered.length > 0\n\t\t\t\t\t\t\t? filtered.map(\n\t\t\t\t\t\t\t\t\t(y) => html`<div class=\"yoga-chip\">${y.name} <span class=\"yoga-id\">${y.id}</span></div>`,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t: html`<p class=\"no-results\">No yogas match your search.</p>`\n\t\t\t\t\t}</div></div>`;\n\t\t}\n\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No yoga data</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-yoga-list': RoxyYogaList;\n\t}\n}\n", "/**\n * Single source of truth for component metadata. Every consumer that needs\n * the (tag, pascal, slug, description, heading) tuple reads from here:\n * scripts/build-react.ts, scripts/build-registry.ts, scripts/sync-docs.ts,\n * scripts/build-widgets.ts, and the browser-side apps/docs/manifest.js\n * (mirrored at build time).\n *\n * Hand-maintained. Add a component \u2192 add one entry here. The OpenAPI spec\n * does not yet carry component metadata, so this stays manual.\n */\n\nexport interface RoxyComponent {\n\t/** Pascal-case React export name, e.g. RoxyNatalChart */\n\tpascal: string;\n\t/** Custom-element tag, e.g. roxy-natal-chart */\n\ttag: string;\n\t/** Slug used in registry filenames and shadcn paths, e.g. natal-chart */\n\tslug: string;\n\t/** Short human-readable heading shown on demo cards. */\n\theading: string;\n\t/** One-line description for registry / docs / SEO meta. */\n\tdescription: string;\n\t/** Domain column label in the synced README/AGENTS table. */\n\tdocsLabel: string;\n\t/** Endpoint(s) column body in the synced README/AGENTS table. */\n\tendpointLabel: string;\n\t/** What-it-renders column body in the synced README/AGENTS table. */\n\tdocsSummary: string;\n\t/** Filter category in the browser demo grid. */\n\ttopic: string;\n\t/**\n\t * True when the component does not consume a typed RoxyAPI response from a\n\t * customer server route. Three cases today:\n\t * - <roxy-data>: pure renderer, accepts any shape, no fetch.\n\t * - <roxy-location-search>: calls /location/search itself via publishable key.\n\t * - <roxy-endpoint-form>: introspects the OpenAPI spec, emits roxy-submit.\n\t * The shadcn registry codegen emits a different doc body for these so we\n\t * never document a server route example with an undefined `data` reference.\n\t */\n\tselfFetching?: boolean;\n}\n\nexport const ROXY_COMPONENTS: readonly RoxyComponent[] = [\n\t{\n\t\tpascal: 'RoxyNatalChart',\n\t\ttag: 'roxy-natal-chart',\n\t\tslug: 'natal-chart',\n\t\theading: 'Natal chart',\n\t\tdescription:\n\t\t\t'Western natal chart wheel for /astrology/natal-chart responses',\n\t\tdocsLabel: 'Western',\n\t\tendpointLabel: 'POST /astrology/natal-chart',\n\t\tdocsSummary: 'Natal chart wheel with planet glyphs and aspect lines',\n\t\ttopic: 'Astrology',\n\t},\n\t{\n\t\tpascal: 'RoxySynastryChart',\n\t\ttag: 'roxy-synastry-chart',\n\t\tslug: 'synastry-chart',\n\t\theading: 'Synastry',\n\t\tdescription: 'Dual-wheel synastry chart with inter-aspects table',\n\t\tdocsLabel: 'Western',\n\t\tendpointLabel: 'POST /astrology/synastry',\n\t\tdocsSummary: 'Dual-wheel synastry with inter-aspects table',\n\t\ttopic: 'Astrology',\n\t},\n\t{\n\t\tpascal: 'RoxyWesternPlanetsTable',\n\t\ttag: 'roxy-western-planets-table',\n\t\tslug: 'western-planets-table',\n\t\theading: 'Western planets',\n\t\tdescription:\n\t\t\t'Western planetary positions table with sign, degree, house, and motion plus the chart angles',\n\t\tdocsLabel: 'Western',\n\t\tendpointLabel: 'POST /astrology/natal-chart',\n\t\tdocsSummary:\n\t\t\t'Sign, degree, house, motion columns plus ASC, MC, PoF, Vertex',\n\t\ttopic: 'Astrology',\n\t},\n\t{\n\t\tpascal: 'RoxyTransitsTable',\n\t\ttag: 'roxy-transits-table',\n\t\tslug: 'transits-table',\n\t\theading: 'Transits',\n\t\tdescription: 'Live planet positions plus aspects to a natal chart',\n\t\tdocsLabel: 'Western',\n\t\tendpointLabel: 'POST /astrology/transits',\n\t\tdocsSummary:\n\t\t\t'Transit planet positions plus optional aspects to a natal chart',\n\t\ttopic: 'Astrology',\n\t},\n\t{\n\t\tpascal: 'RoxyAspectsTable',\n\t\ttag: 'roxy-aspects-table',\n\t\tslug: 'aspects-table',\n\t\theading: 'Aspects',\n\t\tdescription:\n\t\t\t'Natal and transit aspect grid with chart-pattern detection (grand trines, t-squares, stelliums, yods)',\n\t\tdocsLabel: 'Western',\n\t\tendpointLabel:\n\t\t\t'POST /astrology/aspects, /astrology/transit-aspects, /astrology/aspect-patterns',\n\t\tdocsSummary:\n\t\t\t'Aspect rows coloured by nature with orb and strength, plus detected chart patterns',\n\t\ttopic: 'Astrology',\n\t},\n\t{\n\t\tpascal: 'RoxyMoonPhase',\n\t\ttag: 'roxy-moon-phase',\n\t\tslug: 'moon-phase',\n\t\theading: 'Moon phase',\n\t\tdescription: 'Moon phase card and calendar',\n\t\tdocsLabel: 'Western',\n\t\tendpointLabel: 'GET /astrology/moon-phase/{current,upcoming,calendar/...}',\n\t\tdocsSummary: 'Moon phase card and calendar',\n\t\ttopic: 'Astrology',\n\t},\n\t{\n\t\tpascal: 'RoxyHoroscopeCard',\n\t\ttag: 'roxy-horoscope-card',\n\t\tslug: 'horoscope-card',\n\t\theading: 'Daily horoscope',\n\t\tdescription:\n\t\t\t'Daily, weekly, or monthly horoscope card for /astrology/horoscope/...',\n\t\tdocsLabel: 'Western',\n\t\tendpointLabel: 'GET /astrology/horoscope/{sign}/{daily,weekly,monthly}',\n\t\tdocsSummary: 'Daily, weekly, or monthly horoscope card',\n\t\ttopic: 'Astrology',\n\t},\n\t{\n\t\tpascal: 'RoxyCompatibilityCard',\n\t\ttag: 'roxy-compatibility-card',\n\t\tslug: 'compatibility-card',\n\t\theading: 'Compatibility score',\n\t\tdescription: 'Cross-domain compatibility score card',\n\t\tdocsLabel: 'Cross',\n\t\tendpointLabel:\n\t\t\t'POST /astrology/compatibility-score, /numerology/compatibility, /biorhythm/compatibility',\n\t\tdocsSummary: 'Score card with category breakdown',\n\t\ttopic: 'Astrology',\n\t},\n\t{\n\t\tpascal: 'RoxyVedicKundli',\n\t\ttag: 'roxy-vedic-kundli',\n\t\tslug: 'vedic-kundli',\n\t\theading: 'Vedic kundli',\n\t\tdescription:\n\t\t\t'South, North, or East Indian Vedic kundli for /vedic-astrology/birth-chart with per-planet degree and nakshatra detail, plus an optional Chandra Lagna (Moon-as-ascendant) reference view',\n\t\tdocsLabel: 'Vedic',\n\t\tendpointLabel: 'POST /vedic-astrology/birth-chart',\n\t\tdocsSummary:\n\t\t\t'South, North, or East Indian kundli with degree detail and optional Chandra Lagna view',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyDivisionalChart',\n\t\ttag: 'roxy-divisional-chart',\n\t\tslug: 'divisional-chart',\n\t\theading: 'Divisional chart',\n\t\tdescription: 'D2 to D60 varga chart wheel with Vargottama markers',\n\t\tdocsLabel: 'Vedic',\n\t\tendpointLabel: 'POST /vedic-astrology/divisional-chart',\n\t\tdocsSummary:\n\t\t\t'Generic divisional varga wheel from D2 Hora to D60 Shashtiamsa',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyKpChart',\n\t\ttag: 'roxy-kp-chart',\n\t\tslug: 'kp-chart',\n\t\theading: 'KP chart',\n\t\tdescription:\n\t\t\t'Full KP chart with Ascendant, Placidus cusps, and planets in tabbed stellar-hierarchy tables',\n\t\tdocsLabel: 'Vedic (KP)',\n\t\tendpointLabel: 'POST /vedic-astrology/kp/chart',\n\t\tdocsSummary: 'Ascendant, cusps, and planets with KP stellar hierarchy',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyVedicPlanetsTable',\n\t\ttag: 'roxy-vedic-planets-table',\n\t\tslug: 'vedic-planets-table',\n\t\theading: 'Vedic planets',\n\t\tdescription:\n\t\t\t'Vedic planetary positions table with degree, nakshatra, pada, nakshatra lord, bhava, and avastha',\n\t\tdocsLabel: 'Vedic',\n\t\tendpointLabel: 'POST /vedic-astrology/birth-chart',\n\t\tdocsSummary: 'Degree, nakshatra, pada, lord, bhava, avastha columns',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyKpPlanetsTable',\n\t\ttag: 'roxy-kp-planets-table',\n\t\tslug: 'kp-planets-table',\n\t\theading: 'KP planets',\n\t\tdescription: 'KP planets table with sub-lord and sub-sub-lord columns',\n\t\tdocsLabel: 'Vedic (KP)',\n\t\tendpointLabel: 'POST /vedic-astrology/kp/planets',\n\t\tdocsSummary: 'Sub-lord and sub-sub-lord columns',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyKpRulingPlanets',\n\t\ttag: 'roxy-kp-ruling-planets',\n\t\tslug: 'kp-ruling-planets',\n\t\theading: 'KP ruling planets',\n\t\tdescription:\n\t\t\t'KP ruling planets with day lord, Moon and Lagna stellar hierarchies, and house significators',\n\t\tdocsLabel: 'Vedic (KP)',\n\t\tendpointLabel: 'POST /vedic-astrology/kp/ruling-planets',\n\t\tdocsSummary:\n\t\t\t'Day lord, Moon/Lagna hierarchies, ruling planets, significators',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyAshtakavargaGrid',\n\t\ttag: 'roxy-ashtakavarga-grid',\n\t\tslug: 'ashtakavarga-grid',\n\t\theading: 'Ashtakavarga',\n\t\tdescription: 'Sarva and Bhinna ashtakavarga heatmap with bindu scores',\n\t\tdocsLabel: 'Vedic',\n\t\tendpointLabel: 'POST /vedic-astrology/ashtakavarga',\n\t\tdocsSummary: 'Sarva, Bhinna, and Shodhya Pinda views in a tabbed heatmap',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyShadbalaTable',\n\t\ttag: 'roxy-shadbala-table',\n\t\tslug: 'shadbala-table',\n\t\theading: 'Shadbala',\n\t\tdescription: 'Six-fold planetary strength with adequacy badge per planet',\n\t\tdocsLabel: 'Vedic',\n\t\tendpointLabel: 'POST /vedic-astrology/shadbala',\n\t\tdocsSummary:\n\t\t\t'Six-fold planetary strength bar plus rupas and adequacy badge',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyDashaTimeline',\n\t\ttag: 'roxy-dasha-timeline',\n\t\tslug: 'dasha-timeline',\n\t\theading: 'Vimshottari dasha',\n\t\tdescription: 'Vimshottari dasha timeline with active mahadasha highlighted',\n\t\tdocsLabel: 'Vedic',\n\t\tendpointLabel: 'POST /vedic-astrology/dasha/{current,major,sub/...}',\n\t\tdocsSummary: 'Vimshottari mahadasha + antardasha + pratyantardasha',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyGunaMilan',\n\t\ttag: 'roxy-guna-milan',\n\t\tslug: 'guna-milan',\n\t\theading: 'Guna milan',\n\t\tdescription: '36-point Ashtakoota matrimonial compatibility breakdown',\n\t\tdocsLabel: 'Vedic',\n\t\tendpointLabel: 'POST /vedic-astrology/compatibility',\n\t\tdocsSummary: '36-point Ashtakoota with eight sub-scores',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyPanchangTable',\n\t\ttag: 'roxy-panchang-table',\n\t\tslug: 'panchang-table',\n\t\theading: 'Panchang',\n\t\tdescription:\n\t\t\t'Panchang muhurta table with auspicious and inauspicious periods',\n\t\tdocsLabel: 'Vedic',\n\t\tendpointLabel: 'POST /vedic-astrology/panchang/{basic,detailed}',\n\t\tdocsSummary: '15+ muhurtas in detailed mode',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyVedicAspects',\n\t\ttag: 'roxy-vedic-aspects',\n\t\tslug: 'vedic-aspects',\n\t\theading: 'Vedic aspects',\n\t\tdescription:\n\t\t\t'Vedic graha drishti table: which planet aspects which, with mutual aspects surfaced first',\n\t\tdocsLabel: 'Vedic',\n\t\tendpointLabel: 'POST /vedic-astrology/aspects',\n\t\tdocsSummary:\n\t\t\t'Graha drishti rows with aspect type, strength, and orb, plus mutual aspects',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyHoraTable',\n\t\ttag: 'roxy-hora-table',\n\t\tslug: 'hora-table',\n\t\theading: 'Hora',\n\t\tdescription:\n\t\t\t'Vedic Hora (planetary hours) table: 12 day and 12 night horas by ruling planet for electional timing',\n\t\tdocsLabel: 'Vedic',\n\t\tendpointLabel: 'POST /vedic-astrology/panchang/hora',\n\t\tdocsSummary: 'Day and night planetary hours with ruling planet and window',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyChoghadiyaGrid',\n\t\ttag: 'roxy-choghadiya-grid',\n\t\tslug: 'choghadiya-grid',\n\t\theading: 'Choghadiya',\n\t\tdescription: 'Day and night Choghadiya muhurta tiles for activity timing',\n\t\tdocsLabel: 'Vedic',\n\t\tendpointLabel: 'POST /vedic-astrology/panchang/choghadiya',\n\t\tdocsSummary: 'Day and night Choghadiya muhurta tiles colored by effect',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyYogaList',\n\t\ttag: 'roxy-yoga-list',\n\t\tslug: 'yoga-list',\n\t\theading: 'Yoga catalog',\n\t\tdescription:\n\t\t\t'Yoga reference cards from the catalog with optional detail mode',\n\t\tdocsLabel: 'Vedic',\n\t\tendpointLabel: 'GET /vedic-astrology/yoga, /yoga/{id}',\n\t\tdocsSummary: 'Filterable yoga cards from the 300 plus yoga catalog',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyNakshatraCard',\n\t\ttag: 'roxy-nakshatra-card',\n\t\tslug: 'nakshatra-card',\n\t\theading: 'Nakshatra',\n\t\tdescription:\n\t\t\t'Nakshatra reference card with lord, deity, symbol, characteristics, and remedies',\n\t\tdocsLabel: 'Vedic',\n\t\tendpointLabel: 'GET /vedic-astrology/nakshatras/{id}',\n\t\tdocsSummary: 'Lord, deity, symbol, characteristics, remedies',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyDoshaCard',\n\t\ttag: 'roxy-dosha-card',\n\t\tslug: 'dosha-card',\n\t\theading: 'Manglik dosha',\n\t\tdescription: 'Manglik, Kaal Sarp, or Sade Sati presence card',\n\t\tdocsLabel: 'Vedic',\n\t\tendpointLabel: 'POST /vedic-astrology/dosha/{manglik,kalsarpa,sadhesati}',\n\t\tdocsSummary: 'Presence, severity, remedies, scoped effects',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyNumerologyCard',\n\t\ttag: 'roxy-numerology-card',\n\t\tslug: 'numerology-card',\n\t\theading: 'Life path number',\n\t\tdescription:\n\t\t\t'Numerology card for life path, expression, soul urge, personality, personal year, or full chart',\n\t\tdocsLabel: 'Numerology',\n\t\tendpointLabel:\n\t\t\t'POST /numerology/{life-path,expression,soul-urge,personality,birth-day,maturity,daily,personal-day,personal-month,personal-year,chart}',\n\t\tdocsSummary:\n\t\t\t'Life path, expression, soul urge, personality, personal year, full chart',\n\t\ttopic: 'Numerology',\n\t},\n\t{\n\t\tpascal: 'RoxyTarotCard',\n\t\ttag: 'roxy-tarot-card',\n\t\tslug: 'tarot-card',\n\t\theading: 'Daily tarot card',\n\t\tdescription: 'Single tarot card with upright/reversed flip animation',\n\t\tdocsLabel: 'Tarot',\n\t\tendpointLabel: 'GET /tarot/cards/{id}, POST /tarot/daily',\n\t\tdocsSummary: 'Single card with upright and reversed flip',\n\t\ttopic: 'Tarot',\n\t},\n\t{\n\t\tpascal: 'RoxyTarotCatalog',\n\t\ttag: 'roxy-tarot-catalog',\n\t\tslug: 'tarot-catalog',\n\t\theading: 'Tarot deck',\n\t\tdescription:\n\t\t\t'Responsive tarot deck gallery with card art, name, and an arcana and suit caption from the tarot catalog response',\n\t\tdocsLabel: 'Tarot',\n\t\tendpointLabel: 'GET /tarot/cards',\n\t\tdocsSummary: 'Deck gallery tiles with card art, name, and arcana and suit',\n\t\ttopic: 'Tarot',\n\t},\n\t{\n\t\tpascal: 'RoxyTarotSpread',\n\t\ttag: 'roxy-tarot-spread',\n\t\tslug: 'tarot-spread',\n\t\theading: 'Three-card spread',\n\t\tdescription:\n\t\t\t'Tarot spread renderer for three-card, Celtic Cross, love, or yes/no',\n\t\tdocsLabel: 'Tarot',\n\t\tendpointLabel:\n\t\t\t'POST /tarot/spreads/{three-card,celtic-cross,love}, /tarot/yes-no, /tarot/draw',\n\t\tdocsSummary: 'Spreads with positions and reading',\n\t\ttopic: 'Tarot',\n\t},\n\t{\n\t\tpascal: 'RoxyBodygraph',\n\t\ttag: 'roxy-bodygraph',\n\t\tslug: 'bodygraph',\n\t\theading: 'Bodygraph',\n\t\tdescription:\n\t\t\t'Human Design bodygraph with nine centers, channels, and activated gates plus a type, authority, and profile summary',\n\t\tdocsLabel: 'Human Design',\n\t\tendpointLabel: 'POST /human-design/bodygraph',\n\t\tdocsSummary:\n\t\t\t'Nine-center chart with defined and open centers, active channels, gates, and a type and authority summary',\n\t\ttopic: 'Human Design',\n\t},\n\t{\n\t\tpascal: 'RoxyHdConnection',\n\t\ttag: 'roxy-hd-connection',\n\t\tslug: 'hd-connection',\n\t\theading: 'HD connection',\n\t\tdescription:\n\t\t\t'Human Design connection chart: the composite channels two people form, with circuit, dynamic, and which person holds each gate',\n\t\tdocsLabel: 'Human Design',\n\t\tendpointLabel: 'POST /human-design/connection',\n\t\tdocsSummary:\n\t\t\t'Electromagnetic, compromise, and dominance channels between two charts',\n\t\ttopic: 'Human Design',\n\t},\n\t{\n\t\tpascal: 'RoxyHdPenta',\n\t\ttag: 'roxy-hd-penta',\n\t\tslug: 'hd-penta',\n\t\theading: 'HD penta',\n\t\tdescription:\n\t\t\t'Human Design penta for a 3 to 5 person group: upper and lower triangle channels, defined or open, with core channels and member coverage',\n\t\tdocsLabel: 'Human Design',\n\t\tendpointLabel: 'POST /human-design/penta',\n\t\tdocsSummary: 'Group penta channels split into upper and lower triangles',\n\t\ttopic: 'Human Design',\n\t},\n\t{\n\t\tpascal: 'RoxyHdVariables',\n\t\ttag: 'roxy-hd-variables',\n\t\tslug: 'hd-variables',\n\t\theading: 'HD variables',\n\t\tdescription:\n\t\t\t'Human Design variables: the four PHS arrows (determination, environment, perspective, motivation) with left/right direction and color, tone, and base',\n\t\tdocsLabel: 'Human Design',\n\t\tendpointLabel: 'POST /human-design/variables',\n\t\tdocsSummary: 'The four transformation arrows with direction and PHS labels',\n\t\ttopic: 'Human Design',\n\t},\n\t{\n\t\tpascal: 'RoxyForecastTimeline',\n\t\ttag: 'roxy-forecast-timeline',\n\t\tslug: 'forecast-timeline',\n\t\theading: 'Forecast timeline',\n\t\tdescription:\n\t\t\t'Cross-domain forecast event strip colored by domain and weighted by significance',\n\t\tdocsLabel: 'Forecast',\n\t\tendpointLabel: 'POST /forecast/timeline',\n\t\tdocsSummary:\n\t\t\t'Date-grouped events across Western, Vedic, and biorhythm domains, weighted by significance',\n\t\ttopic: 'Forecast',\n\t},\n\t{\n\t\tpascal: 'RoxyForecastDigest',\n\t\ttag: 'roxy-forecast-digest',\n\t\tslug: 'forecast-digest',\n\t\theading: 'Forecast digest',\n\t\tdescription:\n\t\t\t'Rolled-up forecast across the next 24 hours, 7, 30, and 90 days with per-domain breakdown and top events',\n\t\tdocsLabel: 'Forecast',\n\t\tendpointLabel: 'POST /forecast/digest',\n\t\tdocsSummary:\n\t\t\t'Per-window event counts, domain breakdown, and the highest-significance events',\n\t\ttopic: 'Forecast',\n\t},\n\t{\n\t\tpascal: 'RoxyBiorhythmChart',\n\t\ttag: 'roxy-biorhythm-chart',\n\t\tslug: 'biorhythm-chart',\n\t\theading: 'Daily biorhythm',\n\t\tdescription: 'Daily biorhythm bars or multi-day forecast cycle lines',\n\t\tdocsLabel: 'Biorhythm',\n\t\tendpointLabel: 'POST /biorhythm/{daily,forecast,critical-days}',\n\t\tdocsSummary: 'Daily bars, forecast cycle lines, critical days',\n\t\ttopic: 'Biorhythm',\n\t},\n\t{\n\t\tpascal: 'RoxyHexagram',\n\t\ttag: 'roxy-hexagram',\n\t\tslug: 'hexagram',\n\t\theading: 'I Ching hexagram',\n\t\tdescription:\n\t\t\t'I Ching hexagram with trigram glyphs, judgment, image, and changing lines',\n\t\tdocsLabel: 'I Ching',\n\t\tendpointLabel:\n\t\t\t'GET /iching/hexagrams/{number}, /iching/cast, POST /iching/daily, /iching/daily/cast',\n\t\tdocsSummary: 'Hexagram with trigrams, judgment, image, changing lines',\n\t\ttopic: 'I Ching',\n\t},\n\t{\n\t\tpascal: 'RoxyCrystalCard',\n\t\ttag: 'roxy-crystal-card',\n\t\tslug: 'crystal-card',\n\t\theading: 'Crystal detail',\n\t\tdescription:\n\t\t\t'Single-crystal detail card with photo, spiritual, emotional, and physical meaning, metaphysical attributes, affirmation, and pairings',\n\t\tdocsLabel: 'Crystals',\n\t\tendpointLabel: 'GET /crystals/{id}',\n\t\tdocsSummary:\n\t\t\t'Photo, meaning sections, chakra, zodiac, element, hardness, keywords, and pairings',\n\t\ttopic: 'Crystals',\n\t},\n\t{\n\t\tpascal: 'RoxyCrystalGrid',\n\t\ttag: 'roxy-crystal-grid',\n\t\tslug: 'crystal-grid',\n\t\theading: 'Crystal grid',\n\t\tdescription:\n\t\t\t'Responsive crystal gallery with photo, name, and colour swatches from any crystals list response',\n\t\tdocsLabel: 'Crystals',\n\t\tendpointLabel:\n\t\t\t'GET /crystals, /crystals/chakra/{chakra}, /crystals/element/{element}, /crystals/zodiac/{sign}, /crystals/birthstone/{month}, /crystals/search',\n\t\tdocsSummary: 'Crystal gallery tiles with photo, name, and colour swatches',\n\t\ttopic: 'Crystals',\n\t},\n\t{\n\t\tpascal: 'RoxyDreamCard',\n\t\ttag: 'roxy-dream-card',\n\t\tslug: 'dream-card',\n\t\theading: 'Dream symbol',\n\t\tdescription:\n\t\t\t'Dream symbol card with the symbol name, full interpretation, and dictionary letter',\n\t\tdocsLabel: 'Dreams',\n\t\tendpointLabel: 'GET /dreams/symbols/{id}',\n\t\tdocsSummary: 'Symbol name, interpretation body, and letter chip',\n\t\ttopic: 'Dreams',\n\t},\n\t{\n\t\tpascal: 'RoxyDreamSearch',\n\t\ttag: 'roxy-dream-search',\n\t\tslug: 'dream-search',\n\t\theading: 'Dream search',\n\t\tdescription:\n\t\t\t'Dream-symbol search results as selectable tiles; emits roxy-symbol-select to pair with roxy-dream-card',\n\t\tdocsLabel: 'Dreams',\n\t\tendpointLabel: 'GET /dreams/symbols',\n\t\tdocsSummary: 'Matched dream symbols as selectable tiles with a letter chip',\n\t\ttopic: 'Dreams',\n\t},\n\t{\n\t\tpascal: 'RoxyAngelNumberCard',\n\t\ttag: 'roxy-angel-number-card',\n\t\tslug: 'angel-number-card',\n\t\theading: 'Angel number',\n\t\tdescription:\n\t\t\t'Angel number card with title, core message, badges, keywords, life-area interpretations, affirmation, and action steps',\n\t\tdocsLabel: 'Angel Numbers',\n\t\tendpointLabel: 'GET /angel-numbers/numbers/{number}',\n\t\tdocsSummary:\n\t\t\t'Number meaning with spiritual, love, career, money, twin flame, biblical, and shadow sections',\n\t\ttopic: 'Angel Numbers',\n\t},\n\t{\n\t\tpascal: 'RoxyAngelNumberLookup',\n\t\ttag: 'roxy-angel-number-lookup',\n\t\tslug: 'angel-number-lookup',\n\t\theading: 'Angel number lookup',\n\t\tdescription:\n\t\t\t'Angel number sequence analysis with pattern classification, the known meaning when present, and a digit-root fallback for any number',\n\t\tdocsLabel: 'Angel Numbers',\n\t\tendpointLabel: 'GET /angel-numbers/lookup',\n\t\tdocsSummary: 'Pattern analysis plus known meaning and digit-root fallback',\n\t\ttopic: 'Angel Numbers',\n\t},\n\t{\n\t\tpascal: 'RoxyReferenceCard',\n\t\ttag: 'roxy-reference-card',\n\t\tslug: 'reference-card',\n\t\theading: 'Reference card',\n\t\tdescription:\n\t\t\t'Glossary entry for any reference lookup: zodiac sign, planet meaning, rashi, I Ching trigram, Human Design gate or center, numerology number or compound number',\n\t\tdocsLabel: 'Reference',\n\t\tendpointLabel:\n\t\t\t'GET /astrology/{signs,planet-meanings}/{id}, /vedic-astrology/rashis/{id}, /iching/trigrams/{id}, /human-design/{gates,centers}/{id}, /numerology/{meanings,compound-number}/{number}',\n\t\tdocsSummary:\n\t\t\t'Symbol, name, description, keyword chips, and an attribute grid for any glossary lookup',\n\t\ttopic: 'Helpers',\n\t},\n\t{\n\t\tpascal: 'RoxyEndpointForm',\n\t\ttag: 'roxy-endpoint-form',\n\t\tslug: 'endpoint-form',\n\t\theading: 'Schema-driven form',\n\t\tdescription:\n\t\t\t'Schema-driven form that emits roxy-submit with a validated payload',\n\t\tdocsLabel: 'Helper',\n\t\tendpointLabel: 'Any endpoint, from the spec',\n\t\tdocsSummary: 'Schema-driven form, emits roxy-submit',\n\t\ttopic: 'Helpers',\n\t\tselfFetching: true,\n\t},\n\t{\n\t\tpascal: 'RoxyLocationSearch',\n\t\ttag: 'roxy-location-search',\n\t\tslug: 'location-search',\n\t\theading: 'City search',\n\t\tdescription: 'City search input with debounced /location/search calls',\n\t\tdocsLabel: 'Helper',\n\t\tendpointLabel: 'GET /location/search',\n\t\tdocsSummary: 'Debounced city search input, emits roxy-location-select',\n\t\ttopic: 'Helpers',\n\t\tselfFetching: true,\n\t},\n\t{\n\t\tpascal: 'RoxyData',\n\t\ttag: 'roxy-data',\n\t\tslug: 'data',\n\t\theading: 'Generic renderer',\n\t\tdescription: 'Generic fallback renderer for any OpenAPI response shape',\n\t\tdocsLabel: 'Helper',\n\t\tendpointLabel: 'Any response shape',\n\t\tdocsSummary: 'Generic fallback renderer for unknown shapes',\n\t\ttopic: 'Helpers',\n\t\tselfFetching: true,\n\t},\n];\n\nexport type RoxyComponentSlug = (typeof ROXY_COMPONENTS)[number]['slug'];\n", "// Generated by scripts/sync-version.ts. Do not edit.\nexport const ROXY_UI_VERSION = '0.11.0';\n"],
5
- "mappings": "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Cf,YAAa,+CACb,MAAO,WACR,EACA,CACC,OAAQ,0BACR,IAAK,6BACL,KAAM,wBACN,QAAS,kBACT,YACC,+FACD,UAAW,UACX,cAAe,8BACf,YACC,gEACD,MAAO,WACR,EACA,CACC,OAAQ,oBACR,IAAK,sBACL,KAAM,iBACN,QAAS,WACT,YAAa,sDACb,UAAW,UACX,cAAe,2BACf,YACC,kEACD,MAAO,WACR,EACA,CACC,OAAQ,mBACR,IAAK,qBACL,KAAM,gBACN,QAAS,UACT,YACC,wGACD,UAAW,UACX,cACC,kFACD,YACC,qFACD,MAAO,WACR,EACA,CACC,OAAQ,gBACR,IAAK,kBACL,KAAM,aACN,QAAS,aACT,YAAa,+BACb,UAAW,UACX,cAAe,4DACf,YAAa,+BACb,MAAO,WACR,EACA,CACC,OAAQ,oBACR,IAAK,sBACL,KAAM,iBACN,QAAS,kBACT,YACC,wEACD,UAAW,UACX,cAAe,yDACf,YAAa,2CACb,MAAO,WACR,EACA,CACC,OAAQ,wBACR,IAAK,0BACL,KAAM,qBACN,QAAS,sBACT,YAAa,wCACb,UAAW,QACX,cACC,2FACD,YAAa,qCACb,MAAO,WACR,EACA,CACC,OAAQ,kBACR,IAAK,oBACL,KAAM,eACN,QAAS,eACT,YACC,4LACD,UAAW,QACX,cAAe,oCACf,YACC,yFACD,MAAO,OACR,EACA,CACC,OAAQ,sBACR,IAAK,wBACL,KAAM,mBACN,QAAS,mBACT,YAAa,sDACb,UAAW,QACX,cAAe,yCACf,YACC,iEACD,MAAO,OACR,EACA,CACC,OAAQ,cACR,IAAK,gBACL,KAAM,WACN,QAAS,WACT,YACC,+FACD,UAAW,aACX,cAAe,iCACf,YAAa,0DACb,MAAO,OACR,EACA,CACC,OAAQ,wBACR,IAAK,2BACL,KAAM,sBACN,QAAS,gBACT,YACC,mGACD,UAAW,QACX,cAAe,oCACf,YAAa,wDACb,MAAO,OACR,EACA,CACC,OAAQ,qBACR,IAAK,wBACL,KAAM,mBACN,QAAS,aACT,YAAa,0DACb,UAAW,aACX,cAAe,mCACf,YAAa,oCACb,MAAO,OACR,EACA,CACC,OAAQ,sBACR,IAAK,yBACL,KAAM,oBACN,QAAS,oBACT,YACC,+FACD,UAAW,aACX,cAAe,0CACf,YACC,kEACD,MAAO,OACR,EACA,CACC,OAAQ,uBACR,IAAK,yBACL,KAAM,oBACN,QAAS,eACT,YAAa,0DACb,UAAW,QACX,cAAe,qCACf,YAAa,6DACb,MAAO,OACR,EACA,CACC,OAAQ,oBACR,IAAK,sBACL,KAAM,iBACN,QAAS,WACT,YAAa,6DACb,UAAW,QACX,cAAe,iCACf,YACC,gEACD,MAAO,OACR,EACA,CACC,OAAQ,oBACR,IAAK,sBACL,KAAM,iBACN,QAAS,oBACT,YAAa,+DACb,UAAW,QACX,cAAe,sDACf,YAAa,uDACb,MAAO,OACR,EACA,CACC,OAAQ,gBACR,IAAK,kBACL,KAAM,aACN,QAAS,aACT,YAAa,0DACb,UAAW,QACX,cAAe,sCACf,YAAa,4CACb,MAAO,OACR,EACA,CACC,OAAQ,oBACR,IAAK,sBACL,KAAM,iBACN,QAAS,WACT,YACC,kEACD,UAAW,QACX,cAAe,kDACf,YAAa,gCACb,MAAO,OACR,EACA,CACC,OAAQ,mBACR,IAAK,qBACL,KAAM,gBACN,QAAS,gBACT,YACC,4FACD,UAAW,QACX,cAAe,gCACf,YACC,8EACD,MAAO,OACR,EACA,CACC,OAAQ,gBACR,IAAK,kBACL,KAAM,aACN,QAAS,OACT,YACC,uGACD,UAAW,QACX,cAAe,sCACf,YAAa,8DACb,MAAO,OACR,EACA,CACC,OAAQ,qBACR,IAAK,uBACL,KAAM,kBACN,QAAS,aACT,YAAa,6DACb,UAAW,QACX,cAAe,4CACf,YAAa,2DACb,MAAO,OACR,EACA,CACC,OAAQ,eACR,IAAK,iBACL,KAAM,YACN,QAAS,eACT,YACC,kEACD,UAAW,QACX,cAAe,wCACf,YAAa,uDACb,MAAO,OACR,EACA,CACC,OAAQ,oBACR,IAAK,sBACL,KAAM,iBACN,QAAS,YACT,YACC,mFACD,UAAW,QACX,cAAe,uCACf,YAAa,iDACb,MAAO,OACR,EACA,CACC,OAAQ,gBACR,IAAK,kBACL,KAAM,aACN,QAAS,gBACT,YAAa,iDACb,UAAW,QACX,cAAe,2DACf,YAAa,+CACb,MAAO,OACR,EACA,CACC,OAAQ,qBACR,IAAK,uBACL,KAAM,kBACN,QAAS,mBACT,YACC,kGACD,UAAW,aACX,cACC,yIACD,YACC,2EACD,MAAO,YACR,EACA,CACC,OAAQ,gBACR,IAAK,kBACL,KAAM,aACN,QAAS,mBACT,YAAa,yDACb,UAAW,QACX,cAAe,2CACf,YAAa,6CACb,MAAO,OACR,EACA,CACC,OAAQ,mBACR,IAAK,qBACL,KAAM,gBACN,QAAS,aACT,YACC,oHACD,UAAW,QACX,cAAe,mBACf,YAAa,8DACb,MAAO,OACR,EACA,CACC,OAAQ,kBACR,IAAK,oBACL,KAAM,eACN,QAAS,oBACT,YACC,sEACD,UAAW,QACX,cACC,iFACD,YAAa,qCACb,MAAO,OACR,EACA,CACC,OAAQ,gBACR,IAAK,iBACL,KAAM,YACN,QAAS,YACT,YACC,sHACD,UAAW,eACX,cAAe,+BACf,YACC,4GACD,MAAO,cACR,EACA,CACC,OAAQ,mBACR,IAAK,qBACL,KAAM,gBACN,QAAS,gBACT,YACC,iIACD,UAAW,eACX,cAAe,gCACf,YACC,yEACD,MAAO,cACR,EACA,CACC,OAAQ,cACR,IAAK,gBACL,KAAM,WACN,QAAS,WACT,YACC,2IACD,UAAW,eACX,cAAe,2BACf,YAAa,4DACb,MAAO,cACR,EACA,CACC,OAAQ,kBACR,IAAK,oBACL,KAAM,eACN,QAAS,eACT,YACC,wJACD,UAAW,eACX,cAAe,+BACf,YAAa,+DACb,MAAO,cACR,EACA,CACC,OAAQ,uBACR,IAAK,yBACL,KAAM,oBACN,QAAS,oBACT,YACC,mFACD,UAAW,WACX,cAAe,0BACf,YACC,6FACD,MAAO,UACR,EACA,CACC,OAAQ,qBACR,IAAK,uBACL,KAAM,kBACN,QAAS,kBACT,YACC,2GACD,UAAW,WACX,cAAe,wBACf,YACC,iFACD,MAAO,UACR,EACA,CACC,OAAQ,qBACR,IAAK,uBACL,KAAM,kBACN,QAAS,kBACT,YAAa,yDACb,UAAW,YACX,cAAe,iDACf,YAAa,kDACb,MAAO,WACR,EACA,CACC,OAAQ,eACR,IAAK,gBACL,KAAM,WACN,QAAS,mBACT,YACC,4EACD,UAAW,UACX,cACC,uFACD,YAAa,0DACb,MAAO,SACR,EACA,CACC,OAAQ,kBACR,IAAK,oBACL,KAAM,eACN,QAAS,iBACT,YACC,wIACD,UAAW,WACX,cAAe,qBACf,YACC,qFACD,MAAO,UACR,EACA,CACC,OAAQ,kBACR,IAAK,oBACL,KAAM,eACN,QAAS,eACT,YACC,mGACD,UAAW,WACX,cACC,iJACD,YAAa,8DACb,MAAO,UACR,EACA,CACC,OAAQ,gBACR,IAAK,kBACL,KAAM,aACN,QAAS,eACT,YACC,qFACD,UAAW,SACX,cAAe,2BACf,YAAa,oDACb,MAAO,QACR,EACA,CACC,OAAQ,kBACR,IAAK,oBACL,KAAM,eACN,QAAS,eACT,YACC,yGACD,UAAW,SACX,cAAe,sBACf,YAAa,+DACb,MAAO,QACR,EACA,CACC,OAAQ,sBACR,IAAK,yBACL,KAAM,oBACN,QAAS,eACT,YACC,yHACD,UAAW,gBACX,cAAe,sCACf,YACC,gGACD,MAAO,eACR,EACA,CACC,OAAQ,wBACR,IAAK,2BACL,KAAM,sBACN,QAAS,sBACT,YACC,uIACD,UAAW,gBACX,cAAe,4BACf,YAAa,8DACb,MAAO,eACR,EACA,CACC,OAAQ,oBACR,IAAK,sBACL,KAAM,iBACN,QAAS,iBACT,YACC,kKACD,UAAW,YACX,cACC,wLACD,YACC,0FACD,MAAO,SACR,EACA,CACC,OAAQ,mBACR,IAAK,qBACL,KAAM,gBACN,QAAS,qBACT,YACC,qEACD,UAAW,SACX,cAAe,8BACf,YAAa,wCACb,MAAO,UACP,aAAc,EACf,EACA,CACC,OAAQ,qBACR,IAAK,uBACL,KAAM,kBACN,QAAS,cACT,YAAa,0DACb,UAAW,SACX,cAAe,uBACf,YAAa,0DACb,MAAO,UACP,aAAc,EACf,EACA,CACC,OAAQ,WACR,IAAK,YACL,KAAM,OACN,QAAS,mBACT,YAAa,2DACb,UAAW,SACX,cAAe,qBACf,YAAa,+CACb,MAAO,UACP,aAAc,EACf,CACD,ECxmBO,IAAMC,GAAkB,ShEsFxB,IAAMC,GACZC,GAAgB,IAAKC,GAAMA,EAAE,IAAI",
6
- "names": ["src_exports", "__export", "ROXY_COMPONENTS", "ROXY_UI_COMPONENTS", "ROXY_UI_VERSION", "RoxyAngelNumberCard", "RoxyAngelNumberLookup", "RoxyAshtakavargaGrid", "RoxyAspectsTable", "RoxyBiorhythmChart", "RoxyBodygraph", "RoxyChoghadiyaGrid", "RoxyCompatibilityCard", "RoxyCrystalCard", "RoxyCrystalGrid", "RoxyDashaTimeline", "RoxyData", "RoxyDivisionalChart", "RoxyDoshaCard", "RoxyDreamCard", "RoxyDreamSearch", "RoxyEndpointForm", "RoxyForecastDigest", "RoxyForecastTimeline", "RoxyGunaMilan", "RoxyHdConnection", "RoxyHdPenta", "RoxyHdVariables", "RoxyHexagram", "RoxyHoraTable", "RoxyHoroscopeCard", "RoxyKpChart", "RoxyKpPlanetsTable", "RoxyKpRulingPlanets", "RoxyLocationSearch", "RoxyMoonPhase", "RoxyNakshatraCard", "RoxyNatalChart", "RoxyNumerologyCard", "RoxyPanchangTable", "RoxyReferenceCard", "RoxyShadbalaTable", "RoxySynastryChart", "RoxyTarotCard", "RoxyTarotCatalog", "RoxyTarotSpread", "RoxyTransitsTable", "RoxyVedicAspects", "RoxyVedicKundli", "RoxyVedicPlanetsTable", "RoxyWesternPlanetsTable", "RoxyYogaList", "roxyDataScript", "serializeRoxyData", "__toCommonJS", "import_lit", "import_decorators", "LIFE_AREA_SECTIONS", "buildMeaningSections", "meaning", "biblical", "shadow", "sections", "s", "body", "import_lit", "import_decorators", "import_if_defined", "import_lit", "baseStyles", "DEFAULT_BASE_URL", "FetchController", "host", "req", "controller", "res", "json", "err", "signal", "url", "k", "v", "headers", "key", "body", "buildRequest", "endpoint", "method", "values", "rest", "path", "_match", "name", "query", "ROXY_DATA_CLASS", "serializeRoxyData", "data", "roxyDataScript", "isJsonScript", "el", "MarkupDataController", "host", "parsed", "inline", "child", "text", "RoxyDataElement", "detail", "buildRequest", "MarkupDataController", "FetchController", "baseStyles", "changed", "raw", "values", "message", "banner", "__decorateClass", "RoxyAngelNumberCard", "RoxyDataElement", "d", "energy", "energyClass", "keywords", "steps", "k", "s", "sections", "buildMeaningSections", "i", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyAngelNumberLookup", "RoxyDataElement", "d", "known", "root", "heading", "k", "meaning", "biblical", "shadow", "sections", "buildMeaningSections", "i", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "PLANET_GLYPH", "PLANET_ABBR", "SIGN_GLYPH", "SIGN_ABBR", "SIGNS_ORDER", "RASHI_KEYS", "s", "ASPECT_SYMBOL", "TRIGRAM_GLYPH", "MOON_PHASE_EMOJI", "TAB_LABELS", "TABS", "RoxyAshtakavargaGrid", "RoxyDataElement", "d", "signs", "tab", "idx", "count", "sav", "sign", "i", "hc", "SIGN_GLYPH", "bhinna", "s", "row", "pinda", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "import_lit", "chevron", "disclosureStyles", "formatTime", "input", "iso", "d", "formatDate", "formatTimeRange", "t", "start", "end", "formatNumber", "value", "dp", "formatPercent", "n", "ASPECT_CLASS", "normalizeAspect", "a", "capitalize", "s", "humanize", "c", "RoxyAspectsTable", "RoxyDataElement", "d", "aspects", "patterns", "summary", "a", "i", "p", "s", "total", "idx", "g1", "PLANET_GLYPH", "capitalize", "g2", "nature", "type", "status", "meaning", "transit", "hasBody", "header", "formatNumber", "chevron", "m", "text", "k", "t", "planets", "baseStyles", "disclosureStyles", "__decorateClass", "import_lit", "import_decorators", "CYCLE_COLOR", "RoxyBiorhythmChart", "RoxyDataElement", "d", "raw", "entries", "cycle", "value", "v", "normalized", "pct", "color", "days", "w", "h", "xStep", "cycleKeys", "points", "day", "i", "x", "y", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "import_lit", "UNIT", "PAD", "VIEW_W", "VIEW_H", "g", "x", "y", "AXIS", "mirrorX", "GATES_BY_CENTER", "SPLEEN_TO_SOLAR_PLEXUS", "buildGatePoints", "points", "centerOf", "spleenGate", "center", "gates", "gate", "GATE_POINTS", "GATE_CENTER", "CHART_AXIS_X", "shape", "corners", "squareShape", "halfWidth", "top", "bottom", "SPLEEN_SHAPE", "CENTER_GEOMETRY", "CHANNEL_PAIRS", "BODY_PATH", "buildBodyPath", "m", "r", "segs", "pt", "i", "ptm", "p", "polygonPoints", "pts", "pairKey", "a", "b", "renderBody", "renderChannels", "activeChannels", "activeGates", "lines", "pa", "pb", "mid", "closestPointOnSegment", "dx", "dy", "len2", "t", "closestPointOnPolygon", "poly", "best", "bestDist", "q", "d", "renderCenters", "defined", "c", "isDefined", "cls", "edge", "renderGateNumbers", "titles", "out", "num", "title", "channelKey", "BODYGRAPH_VIEWBOX", "renderBodygraphSvg", "input", "RoxyBodygraph", "RoxyDataElement", "d", "definedCenters", "c", "activeGates", "g", "n", "activeChannels", "channelKey", "gateTitles", "BODYGRAPH_VIEWBOX", "renderBodygraphSvg", "gates", "titles", "parts", "planet", "capitalize", "glyph", "PLANET_GLYPH", "facts", "ic", "f", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "fmtTime", "iso", "d", "RoxyChoghadiyaGrid", "RoxyDataElement", "period", "now", "start", "end", "effectClass", "current", "lordGlyph", "PLANET_GLYPH", "capitalize", "timeRange", "date", "dayChoghadiya", "nightChoghadiya", "p", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyCompatibilityCard", "RoxyDataElement", "d", "out", "k", "v", "score", "breakdown", "rating", "archetype", "advice", "summary", "interpretation", "strengths", "challenges", "keyAspects", "formatNumber", "s", "a", "formatAspect", "baseStyles", "__decorateClass", "aspect", "orb", "head", "import_lit", "import_decorators", "MONTHS", "RoxyCrystalCard", "RoxyDataElement", "d", "colors", "keywords", "pairs", "month", "c", "k", "p", "label", "value", "values", "m", "present", "v", "text", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "MONTHS", "RoxyCrystalGrid", "RoxyDataElement", "d", "crystals", "title", "total", "c", "col", "cssColor", "baseStyles", "__decorateClass", "name", "import_lit", "import_decorators", "RoxyDashaTimeline", "RoxyDataElement", "d", "periods", "maxYears", "p", "b", "lord", "yrs", "mo", "da", "parts", "remaining", "active", "formatNumber", "now", "start", "end", "max", "years", "width", "current", "progress", "trackClass", "formatYear", "baseStyles", "__decorateClass", "s", "m", "import_lit", "import_decorators", "TITLE_KEYS", "IMAGE_KEYS", "SKIP_KEYS", "MAX_DEPTH", "RoxyData", "RoxyDataElement", "data", "value", "arr", "v", "rows", "keys", "k", "humanize", "row", "obj", "titleKey", "imageKey", "summaryKey", "seen", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "import_lit", "normalizeLongitude", "lon", "wrapped", "longitudeToSignPosition", "longitude", "signIndex", "within", "degree", "minuteFloat", "minute", "second", "SIGNS_ORDER", "formatSignPosition", "sign", "oppositePoint", "arcMidpoint", "start", "end", "s", "span", "polarToCartesian", "cx", "cy", "radius", "angleDeg", "angleRad", "import_lit", "tablistStyles", "renderTablist", "opts", "items", "active", "onSelect", "label", "idPrefix", "controls", "e", "idx", "it", "delta", "next", "root", "VIEW_BOX", "MARGIN", "INNER", "CENTRE", "RASHI_TO_SIGN", "SIGNS_ORDER", "s", "CHART_STYLES", "RETRO_MARK", "isDivisionalPlacement", "p", "cellSign", "longitudeToSignPosition", "grahaLabel", "abbr", "PLANET_ABBR", "capitalize", "retro", "degree", "grahaTitle", "parts", "divisional", "sp", "minute", "pada", "renderPlanetStack", "planets", "cx", "baseY", "lineHeight", "startY", "j", "yPos", "toKundliViewModel", "meta", "divisionLabel", "lagnaOverride", "placements", "sign", "override", "lagnaSign", "name", "pos", "rashiKey", "SOUTH_CELL", "SOUTH_CELL_GRID", "southCellRect", "g", "renderSouthFrame", "b", "c", "d", "e", "houseNumberInSign", "lagnaIdx", "signIdx", "renderSouthCell", "isLagna", "houseNum", "r", "cy", "signAbbr", "SIGN_ABBR", "slashInset", "renderSouthSvg", "vm", "lagnaKey", "NORTH_VERTICES", "centroidOf", "pts", "x", "y", "NORTH_HOUSE_CENTERS", "rashiInHouse", "renderNorthFrame", "tl", "tr", "br", "bl", "top", "right", "bottom", "left", "renderNorthCell", "rashiNum", "rashiOffsetY", "ascOffsetY", "rashiLabel", "renderNorthSvg", "_", "i", "EAST_CELL", "eastCells", "a", "polys", "out", "points", "EAST_CELLS", "renderEastFrame", "renderEastCell", "cell", "cen", "polyPoints", "renderEastSvg", "renderKundliSvg", "style", "renderKundliStyleTablist", "active", "setStyle", "renderTablist", "import_lit", "kundliStyles", "RoxyDivisionalChart", "RoxyDataElement", "next", "division", "label", "toKundliViewModel", "d", "vm", "vargottama", "renderKundliStyleTablist", "renderKundliSvg", "planet", "PLANET_GLYPH", "baseStyles", "kundliStyles", "tablistStyles", "__decorateClass", "import_lit", "import_decorators", "DOSHA_LABELS", "RoxyDoshaCard", "RoxyDataElement", "d", "present", "label", "sevLower", "tier", "pct", "barColor", "r", "entries", "v", "k", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyDreamCard", "RoxyDataElement", "d", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyDreamSearch", "RoxyDataElement", "d", "symbols", "total", "s", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "specCache", "loadSpec", "url", "pending", "res", "err", "RoxyEndpointForm", "missing", "f", "m", "out", "v", "g", "spec", "path", "op", "schemas", "fields", "bodySchema", "ref", "required", "name", "sub", "resolved", "subRequired", "subName", "subSchema", "r", "param", "init", "remembered", "message", "schema", "all", "s", "value", "group", "inGroup", "n", "prefix", "e", "detail", "renderField", "inputId", "humanize", "opt", "groups", "locationBlock", "groupBody", "t", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyForecastDigest", "RoxyDataElement", "d", "windows", "range", "formatDate", "w", "days", "top", "byDomain", "domains", "dom", "n", "humanize", "e", "sig", "formatNumber", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "DOMAIN_LABEL", "DOMAIN_ORDER", "RoxyForecastTimeline", "RoxyDataElement", "d", "events", "grouped", "present", "dom", "e", "formatDate", "date", "dayEvents", "map", "key", "list", "sig", "width", "body", "capitalize", "target", "aspect", "aspectClass", "ASPECT_CLASS", "aspectSym", "ASPECT_SYMBOL", "orb", "formatNumber", "qualifier", "humanize", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyGunaMilan", "RoxyDataElement", "d", "breakdown", "b", "score", "max", "pct", "trackColor", "fillColor", "dashFill", "dashGap", "formatNumber", "formatPercent", "maxScore", "defaultMax", "x", "baseStyles", "__decorateClass", "name", "import_lit", "import_decorators", "RoxyHdConnection", "RoxyDataElement", "d", "channels", "humanize", "c", "s", "rows", "label", "n", "a", "b", "held", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyHdPenta", "RoxyDataElement", "d", "channels", "upper", "c", "lower", "s", "gaps", "label", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyHdVariables", "RoxyDataElement", "d", "arrows", "a", "glyph", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyHexagram", "RoxyDataElement", "d", "cast", "daily", "resolved", "h", "castLines", "changingLinePositions", "dailyMessage", "resultingHexagram", "lines", "changing", "l", "idx", "realIdx", "isChanging", "broken", "TRIGRAM_GLYPH", "a", "b", "cp", "offset", "i", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "clockTime", "iso", "RoxyHoraTable", "RoxyDataElement", "d", "day", "night", "label", "horas", "h", "PLANET_GLYPH", "capitalize", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyHoroscopeCard", "RoxyDataElement", "d", "sign", "glyph", "SIGN_GLYPH", "capitalize", "energy", "dateLabel", "luckyNumber", "luckyColor", "luckyNumbers", "luckyDays", "compatibleSigns", "s", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyKpChart", "RoxyDataElement", "d", "rows", "p", "nodes", "name", "node", "next", "asc", "formatNumber", "bodies", "b", "cusps", "c", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyKpPlanetsTable", "RoxyDataElement", "d", "planets", "formatNumber", "p", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyKpRulingPlanets", "RoxyDataElement", "d", "significators", "p", "i", "s", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "debounce", "fn", "wait", "timer", "debounced", "args", "RoxyLocationSearch", "debounce", "q", "value", "target", "message", "controller", "url", "headers", "key", "res", "json", "err", "city", "idx", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyMoonPhase", "RoxyDataElement", "d", "list", "month", "year", "phase", "emoji", "phaseEmoji", "formatIllumination", "formatNumber", "k", "p", "baseStyles", "__decorateClass", "MOON_PHASE_EMOJI", "v", "pct", "import_lit", "import_decorators", "RoxyNakshatraCard", "RoxyDataElement", "n", "remedies", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "SIZE", "CENTER", "OUTER_R", "SIGN_R", "HOUSE_R", "PLANET_R", "ANGLE_TICK_R", "ANGLE_LABEL_R", "RoxyNatalChart", "RoxyDataElement", "m", "lon", "data", "planets", "aspects", "view", "renderTablist", "v", "names", "p", "capitalize", "byPair", "a", "k", "n", "g", "PLANET_GLYPH", "rowName", "ri", "rowGlyph", "colName", "name", "normalizeAspect", "sym", "ASPECT_SYMBOL", "cls", "ASPECT_CLASS", "orb", "formatNumber", "asc", "mc", "items", "oppositePoint", "pof", "normalizeLongitude", "vertex", "longitude", "label", "angle", "tickInner", "polarToCartesian", "tickOuter", "labelPos", "houses", "h", "_", "i", "start", "end", "SIGNS_ORDER", "sign", "pos", "SIGN_GLYPH", "house", "next", "mid", "arcMidpoint", "ascSignIndex", "houseNum", "ticks", "deg", "isMajor", "inner", "b", "sp", "longitudeToSignPosition", "sorted", "prev", "cur", "wanted", "last", "shift", "s", "trueLon", "displayLon", "trueAngle", "displayAngle", "glyphPos", "degPos", "rimPos", "leaderInner", "glyph", "retro", "degLabel", "offset", "summary", "ai", "retrogrades", "ELEMENTS", "MODALITIES", "order", "cells", "el", "idx", "mod", "rowTotal", "interp", "chevron", "planetMap", "l1", "l2", "p1", "p2", "aspectName", "aspectClass", "orbLabel", "baseStyles", "tablistStyles", "disclosureStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyNumerologyCard", "RoxyDataElement", "d", "headerLabel", "LABELS", "num", "theme", "body", "keywords", "k", "karmicDebtText", "cores", "v", "humanize", "baseStyles", "__decorateClass", "value", "import_lit", "import_decorators", "RoxyPanchangTable", "RoxyDataElement", "d", "detailed", "fivefold", "placements", "row", "muhurtas", "auspiciousWindows", "inauspicious", "inauspiciousWindows", "transitions", "formatDate", "k", "v", "formatTime", "m", "rows", "range", "formatTimeRange", "label", "windows", "w", "i", "t", "when", "next", "obj", "r", "n", "h", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "TITLE_KEYS", "PROSE_KEYS", "SKIP_KEYS", "RoxyReferenceCard", "RoxyDataElement", "d", "rec", "title", "symbol", "keywords", "prose", "lists", "facts", "key", "value", "items", "v", "k", "text", "humanize", "i", "type", "number", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "BALA_COMPONENTS", "RoxyShadbalaTable", "RoxyDataElement", "d", "sorted", "a", "b", "p", "glyph", "PLANET_GLYPH", "capitalize", "values", "total", "s", "v", "isAdequate", "badgeClass", "badgeLabel", "rupasStr", "formatNumber", "i", "grow", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "SIZE", "CENTER", "OUTER_R", "SIGN_R", "P1_R", "P2_R", "RoxySynastryChart", "RoxyDataElement", "d", "person1", "person2", "compatibilityScore", "analysis", "interAspects", "p1Planets", "p2Planets", "score", "summaryText", "strengths", "challenges", "s", "longitude", "_", "i", "angle", "start", "polarToCartesian", "end", "SIGNS_ORDER", "pos", "SIGN_GLYPH", "planets", "radius", "cls", "personIndex", "p", "degPos", "glyph", "PLANET_GLYPH", "capitalize", "sp", "longitudeToSignPosition", "retro", "degLabel", "tooltip", "data", "items", "make", "asc", "signIdx", "innerR", "tickPos", "labelPos", "p1", "p2", "aspects", "longitudeOf", "list", "name", "target", "a", "l1", "l2", "out", "inn", "aspectName", "normalizeAspect", "ASPECT_CLASS", "orbLabel", "formatNumber", "formatStrength", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyTarotCard", "RoxyDataElement", "d", "card", "isReversed", "keywords", "e", "k", "orientedMeaning", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyTarotCatalog", "RoxyDataElement", "d", "cards", "title", "total", "c", "cardMeta", "baseStyles", "__decorateClass", "capitalize", "import_lit", "import_decorators", "RoxyTarotSpread", "RoxyDataElement", "d", "isYesNo", "isDrawn", "positions", "cards", "answer", "strength", "spreadLabel", "question", "summary", "yesNoInterp", "answerClass", "p", "c", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyTransitsTable", "RoxyDataElement", "d", "transitDate", "transitTime", "transitPlanets", "transitAspects", "summary", "dateStr", "formatDate", "formatTime", "aspectCount", "tab", "renderTablist", "v", "planets", "p", "pGlyph", "PLANET_GLYPH", "capitalize", "sGlyph", "SIGN_GLYPH", "speedArrow", "formatNumber", "aspects", "a", "idx", "tGlyph", "nGlyph", "nature", "interp", "type", "status", "chevron", "k", "baseStyles", "tablistStyles", "disclosureStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyVedicAspects", "RoxyDataElement", "d", "aspects", "mutual", "date", "m", "a", "formatNumber", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyVedicKundli", "RoxyDataElement", "next", "toKundliViewModel", "_d", "vm", "title", "renderKundliStyleTablist", "renderKundliSvg", "baseStyles", "kundliStyles", "tablistStyles", "__decorateClass", "import_lit", "import_decorators", "GRAHA_ORDER", "RoxyVedicPlanetsTable", "RoxyDataElement", "meta", "seen", "rows", "name", "entry", "d", "p", "isLagna", "glyph", "PLANET_GLYPH", "capitalize", "signGlyph", "SIGN_GLYPH", "formatSignPosition", "combust", "chevron", "c", "dist", "formatNumber", "orb", "wars", "w", "interp", "entries", "v", "houses", "h", "yogas", "y", "baseStyles", "disclosureStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyWesternPlanetsTable", "RoxyDataElement", "d", "rows", "p", "name", "point", "glyph", "PLANET_GLYPH", "capitalize", "signGlyph", "SIGN_GLYPH", "speed", "formatNumber", "formatSignPosition", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyYogaList", "RoxyDataElement", "quality", "cls", "yoga", "d", "lc", "allYogas", "detailYogas", "filtered", "y", "total", "catalogYogas", "baseStyles", "__decorateClass", "ROXY_COMPONENTS", "ROXY_UI_VERSION", "ROXY_UI_COMPONENTS", "ROXY_COMPONENTS", "c"]
3
+ "sources": ["../src/index.ts", "../src/components/angel-number-card.ts", "../src/utils/angel-sections.ts", "../src/utils/base-element.ts", "../src/utils/base-styles.ts", "../src/utils/fetch-controller.ts", "../src/utils/markup-data.ts", "../src/components/angel-number-lookup.ts", "../src/components/ashtakavarga-grid.ts", "../src/tokens/index.ts", "../src/components/aspects-table.ts", "../src/utils/disclosure.ts", "../src/utils/format.ts", "../src/utils/string.ts", "../src/components/astrocartography-map.ts", "../src/utils/planet-color.ts", "../src/utils/world-map.ts", "../src/components/biorhythm-chart.ts", "../src/components/bodygraph.ts", "../src/utils/bodygraph-render.ts", "../src/components/choghadiya-grid.ts", "../src/components/compatibility-card.ts", "../src/components/crystal-card.ts", "../src/components/crystal-grid.ts", "../src/components/dasha-timeline.ts", "../src/components/data.ts", "../src/components/divisional-chart.ts", "../src/utils/kundli-render.ts", "../src/utils/degree.ts", "../src/utils/tablist.ts", "../src/utils/kundli-styles.ts", "../src/components/dosha-card.ts", "../src/components/dream-card.ts", "../src/components/dream-search.ts", "../src/components/endpoint-form.ts", "../src/components/fixed-stars.ts", "../src/components/forecast-digest.ts", "../src/components/forecast-timeline.ts", "../src/components/guna-milan.ts", "../src/components/hd-connection.ts", "../src/components/hd-penta.ts", "../src/components/hd-variables.ts", "../src/components/hexagram.ts", "../src/components/hora-table.ts", "../src/components/horoscope-card.ts", "../src/components/kp-chart.ts", "../src/components/kp-planets-table.ts", "../src/components/kp-ruling-planets.ts", "../src/components/local-space-compass.ts", "../src/components/location-search.ts", "../src/utils/debounce.ts", "../src/components/moon-phase.ts", "../src/components/nakshatra-card.ts", "../src/components/natal-chart.ts", "../src/components/numerology-card.ts", "../src/components/panchang-table.ts", "../src/components/positions-table.ts", "../src/components/profection-card.ts", "../src/components/reference-card.ts", "../src/components/relocation-wheel.ts", "../src/components/shadbala-table.ts", "../src/components/synastry-chart.ts", "../src/components/tarot-card.ts", "../src/components/tarot-catalog.ts", "../src/components/tarot-spread.ts", "../src/components/transits-table.ts", "../src/components/vedic-aspects.ts", "../src/components/vedic-kundli.ts", "../src/components/vedic-planets-table.ts", "../src/components/western-planets-table.ts", "../src/components/yoga-list.ts", "../src/manifest.ts", "../src/version.ts"],
4
+ "sourcesContent": ["/**\n * @roxyapi/ui main entry. Importing this file registers every custom element.\n *\n * For tree-shake friendly usage, import per-component:\n * import '@roxyapi/ui/components/natal-chart';\n */\n\n// Angel numbers\nexport { RoxyAngelNumberCard } from './components/angel-number-card.js';\nexport { RoxyAngelNumberLookup } from './components/angel-number-lookup.js';\nexport { RoxyAshtakavargaGrid } from './components/ashtakavarga-grid.js';\n// Western astrology\nexport { RoxyAspectsTable } from './components/aspects-table.js';\nexport { RoxyAstrocartographyMap } from './components/astrocartography-map.js';\n// Biorhythm\nexport { RoxyBiorhythmChart } from './components/biorhythm-chart.js';\n// Human Design\nexport { RoxyBodygraph } from './components/bodygraph.js';\nexport { RoxyChoghadiyaGrid } from './components/choghadiya-grid.js';\nexport { RoxyCompatibilityCard } from './components/compatibility-card.js';\n// Crystals\nexport { RoxyCrystalCard } from './components/crystal-card.js';\nexport { RoxyCrystalGrid } from './components/crystal-grid.js';\nexport { RoxyDashaTimeline } from './components/dasha-timeline.js';\n// Generic fallback first so it is always available for nested rendering\nexport { RoxyData } from './components/data.js';\nexport { RoxyDivisionalChart } from './components/divisional-chart.js';\nexport { RoxyDoshaCard } from './components/dosha-card.js';\n// Dreams\nexport { RoxyDreamCard } from './components/dream-card.js';\nexport { RoxyDreamSearch } from './components/dream-search.js';\n// Helpers\nexport { RoxyEndpointForm } from './components/endpoint-form.js';\nexport { RoxyFixedStars } from './components/fixed-stars.js';\n// Forecast\nexport { RoxyForecastDigest } from './components/forecast-digest.js';\nexport { RoxyForecastTimeline } from './components/forecast-timeline.js';\nexport { RoxyGunaMilan } from './components/guna-milan.js';\n// Human Design\nexport { RoxyHdConnection } from './components/hd-connection.js';\nexport { RoxyHdPenta } from './components/hd-penta.js';\nexport { RoxyHdVariables } from './components/hd-variables.js';\n// I Ching\nexport { RoxyHexagram } from './components/hexagram.js';\nexport { RoxyHoraTable } from './components/hora-table.js';\nexport { RoxyHoroscopeCard } from './components/horoscope-card.js';\nexport { RoxyKpChart } from './components/kp-chart.js';\nexport { RoxyKpPlanetsTable } from './components/kp-planets-table.js';\nexport { RoxyKpRulingPlanets } from './components/kp-ruling-planets.js';\nexport { RoxyLocalSpaceCompass } from './components/local-space-compass.js';\nexport { RoxyLocationSearch } from './components/location-search.js';\nexport { RoxyMoonPhase } from './components/moon-phase.js';\nexport { RoxyNakshatraCard } from './components/nakshatra-card.js';\n// Western astrology\nexport { RoxyNatalChart } from './components/natal-chart.js';\n// Numerology\nexport { RoxyNumerologyCard } from './components/numerology-card.js';\nexport { RoxyPanchangTable } from './components/panchang-table.js';\nexport { RoxyPositionsTable } from './components/positions-table.js';\nexport { RoxyProfectionCard } from './components/profection-card.js';\nexport { RoxyReferenceCard } from './components/reference-card.js';\nexport { RoxyRelocationWheel } from './components/relocation-wheel.js';\nexport { RoxyShadbalaTable } from './components/shadbala-table.js';\nexport { RoxySynastryChart } from './components/synastry-chart.js';\n// Tarot\nexport { RoxyTarotCard } from './components/tarot-card.js';\nexport { RoxyTarotCatalog } from './components/tarot-catalog.js';\nexport { RoxyTarotSpread } from './components/tarot-spread.js';\nexport { RoxyTransitsTable } from './components/transits-table.js';\n// Vedic astrology\nexport { RoxyVedicAspects } from './components/vedic-aspects.js';\nexport { RoxyVedicKundli } from './components/vedic-kundli.js';\nexport { RoxyVedicPlanetsTable } from './components/vedic-planets-table.js';\nexport { RoxyWesternPlanetsTable } from './components/western-planets-table.js';\nexport { RoxyYogaList } from './components/yoga-list.js';\n\n// SSR helpers for the server-rendered hydration path (Pattern 7). Safe writers\n// for the inline <script class=\"roxy-data\"> the MarkupDataController reads.\nexport {\n\troxyDataScript,\n\tserializeRoxyData,\n} from './utils/markup-data.js';\n\nimport { ROXY_COMPONENTS, type RoxyComponentSlug } from './manifest.js';\n\nexport {\n\tROXY_COMPONENTS,\n\ttype RoxyComponent,\n\ttype RoxyComponentSlug,\n} from './manifest.js';\nexport { ROXY_UI_VERSION } from './version.js';\n\n/** Slugs in declaration order. Kept for the auto-mount widgets script and downstream codegen. */\nexport const ROXY_UI_COMPONENTS: readonly RoxyComponentSlug[] =\n\tROXY_COMPONENTS.map((c) => c.slug) as RoxyComponentSlug[];\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { GetAngelNumberResponse } from '../types/index.js';\nimport { buildMeaningSections } from '../utils/angel-sections.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\n/**\n * Angel number card. Renders /angel-numbers/numbers/{number}: the number as a hero numeral, its title and core message, the pattern type / digit root / energy badges, keyword chips, the life-area interpretations (spiritual, love, career, money, twin flame) plus the biblical and shadow readings as an exclusive accordion, the affirmation, and the action steps.\n */\n@customElement('roxy-angel-number-card')\nexport class RoxyAngelNumberCard extends RoxyDataElement<GetAngelNumberResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.card{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.hero{align-items:center;gap:var(--roxy-space-md,1rem);display:flex}.numeral{font-size:3rem;line-height:1;font-weight:var(--roxy-weight-bold,600);color:var(--roxy-accent-ink,#b45309);font-variant-numeric:tabular-nums}.label{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;margin:0}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.core{color:var(--roxy-fg,#0a0a0a);margin:0;line-height:1.6}.badges{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;display:flex}.badge{align-items:center;gap:var(--roxy-space-xs,.25rem);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 35%, transparent);color:var(--roxy-fg,#0a0a0a);text-transform:capitalize;padding:3px 10px;display:inline-flex}.badge.positive{background:color-mix(in srgb, var(--roxy-success,#16a34a) 16%, transparent);color:var(--roxy-success-fg,#166534)}.badge.cautionary{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 16%, transparent);color:var(--roxy-danger-fg,#991b1b)}.badge.neutral{background:color-mix(in srgb, var(--roxy-info,#0284c7) 16%, transparent);color:var(--roxy-info-fg,#075985)}.chips{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;display:flex}.chips span{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 14%, transparent);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);padding:2px 8px}.sections{gap:var(--roxy-space-xs,.25rem);border-top:1px solid var(--roxy-border,#e4e4e7);padding-top:var(--roxy-space-md,1rem);display:grid}details{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-sm,4px);overflow:hidden}summary{cursor:pointer;padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);font-weight:var(--roxy-weight-bold,600);font-size:var(--roxy-text-sm,.875rem);list-style-position:inside}details p{padding:0 var(--roxy-space-md,1rem) var(--roxy-space-md,1rem);font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);margin:0;line-height:1.6}.affirmation{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 12%, transparent);border-left:3px solid var(--roxy-accent,#f59e0b);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);border-radius:var(--roxy-radius-sm,4px);color:var(--roxy-fg,#0a0a0a);margin:0;font-style:italic}.steps h3{margin:0 0 var(--roxy-space-xs,.25rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em}.steps ul{padding-left:var(--roxy-space-md,1rem);font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);gap:2px;margin:0;display:grid}`,\n\t];\n\n\tprotected renderData(d: GetAngelNumberResponse) {\n\t\tconst energy = (d.energy ?? '').toLowerCase();\n\t\tconst energyClass =\n\t\t\tenergy === 'positive' || energy === 'cautionary' || energy === 'neutral'\n\t\t\t\t? energy\n\t\t\t\t: '';\n\t\tconst keywords = d.keywords ?? [];\n\t\tconst steps = d.actionSteps ?? [];\n\n\t\treturn html`<article class=\"card\" aria-label=\"${`Angel number ${d.number ?? ''}`}\"><div class=\"hero\">${d.number ? html`<div class=\"numeral\">${d.number}</div>` : nothing}<div><p class=\"label\">Angel number</p>${d.title ? html`<h2 class=\"title\">${d.title}</h2>` : nothing}</div></div>${d.coreMessage ? html`<p class=\"core\">${d.coreMessage}</p>` : nothing}<div class=\"badges\">${d.type ? html`<span class=\"badge\">${d.type}</span>` : nothing} ${typeof d.digitRoot === 'number' ? html`<span class=\"badge\">Digit root ${d.digitRoot}</span>` : nothing} ${d.energy ? html`<span class=\"${`badge ${energyClass}`}\">${d.energy}</span>` : nothing}</div>${\n\t\t\t\tkeywords.length > 0\n\t\t\t\t\t? html`<div class=\"chips\">${keywords.map((k) => html`<span>${k}</span>`)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${this.renderSections(d)} ${d.affirmation ? html`<p class=\"affirmation\">${d.affirmation}</p>` : nothing} ${\n\t\t\t\tsteps.length > 0\n\t\t\t\t\t? html`<div class=\"steps\"><h3>Action steps</h3><ul>${steps.map((s) => html`<li>${s}</li>`)}</ul></div>`\n\t\t\t\t\t: nothing\n\t\t\t}</article>`;\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No angel number</div>`;\n\t}\n\n\tprivate renderSections(d: NonNullable<GetAngelNumberResponse>) {\n\t\tconst sections = buildMeaningSections(d.meaning, d.biblical, d.shadow);\n\t\tif (sections.length === 0) return nothing;\n\t\treturn html`<div class=\"sections\">${sections.map(\n\t\t\t\t(s, i) => html`<details name=\"angel-meaning\" ?open=\"${i === 0}\"><summary>${s.label}</summary><p>${s.body}</p></details>`,\n\t\t\t)}</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-angel-number-card': RoxyAngelNumberCard;\n\t}\n}\n", "/**\n * Ordered angel-number interpretation sections, shared by the angel-number card and lookup components so the field list, labels, and display order live in one place instead of being duplicated per component.\n *\n * @remarks The life-area keys (`spiritual`, `love`, `career`, `money`, `twinFlame`) mirror the `meaning` object in the angel-numbers OpenAPI response; `biblical` and `shadow` are top-level siblings present only on a known meaning, not on the digit-root fallback. Any absent field is skipped, so the one builder serves a full known meaning and the leaner digit-root reading alike.\n */\n\nexport interface MeaningSection {\n\tlabel: string;\n\tbody: string;\n}\n\nconst LIFE_AREA_SECTIONS: ReadonlyArray<{ key: string; label: string }> = [\n\t{ key: 'spiritual', label: 'Spiritual' },\n\t{ key: 'love', label: 'Love' },\n\t{ key: 'career', label: 'Career' },\n\t{ key: 'money', label: 'Money' },\n\t{ key: 'twinFlame', label: 'Twin flame' },\n];\n\n/**\n * Build the present-only interpretation sections in canonical order: the life areas first, then the optional `biblical` and `shadow` readings. An empty or missing field is omitted so the caller can render whatever the response actually carries.\n */\nexport function buildMeaningSections(\n\tmeaning: Record<string, string> | undefined,\n\tbiblical?: string,\n\tshadow?: string,\n): MeaningSection[] {\n\tconst sections: MeaningSection[] = [];\n\tif (meaning) {\n\t\tfor (const s of LIFE_AREA_SECTIONS) {\n\t\t\tconst body = meaning[s.key];\n\t\t\tif (body) sections.push({ label: s.label, body });\n\t\t}\n\t}\n\tif (biblical) sections.push({ label: 'Biblical', body: biblical });\n\tif (shadow) sections.push({ label: 'Shadow', body: shadow });\n\treturn sections;\n}\n", "import {\n\ttype CSSResultGroup,\n\thtml,\n\tLitElement,\n\ttype PropertyValues,\n} from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { baseStyles } from './base-styles.js';\nimport { buildRequest, FetchController } from './fetch-controller.js';\nimport { MarkupDataController } from './markup-data.js';\n\n/**\n * Shared base for every data-driven Roxy component. Consolidates the things every component used to repeat by hand and adds the self-contained, drop-in behavior: controlled-mode hydration, an opt-in self-fetch (form, request, loading, error, empty), the typed `data` slot, and the render switch. A subclass implements one method, {@link RoxyDataElement.renderData}.\n *\n * @remarks\n * Two render modes, one component, which is the whole drop-in contract:\n *\n * - Controlled: a server (WordPress, JSX SSR, static HTML) fetches the response and injects it as a direct-child `<script type=\"application/json\" class=\"roxy-data\">`. {@link MarkupDataController} hydrates `data` from it on connect. No key reaches the browser. This is the path the WordPress plugin drives, and it is unchanged by the base class.\n * - Uncontrolled: no data is injected, but a `data-endpoint` and a `pk_` `publishable-key` are set. The component renders its own `<roxy-endpoint-form>` (an internal detail, never placed by the consumer), and on submit fetches through {@link FetchController}, which refuses any non-publishable key. The result populates `data` and the component renders it.\n *\n * The JavaScript `data` property always wins over markup, so a host that assigns `el.data = \u2026` after upgrade is authoritative.\n *\n * Self-fetch needs `<roxy-endpoint-form>` (and `<roxy-location-search>`) registered. The CDN bundle and the full `@roxyapi/ui` entry register everything; per-component ESM consumers that want self-fetch import the form component too.\n *\n * @example\n * ```ts\n * @customElement('roxy-dream-card')\n * export class RoxyDreamCard extends RoxyDataElement<GetDreamSymbolResponse> {\n * static styles = [baseStyles, css`.card { \u2026 }`];\n * protected renderData(d: GetDreamSymbolResponse) {\n * return html`<article class=\"card\">\u2026</article>`;\n * }\n * protected renderEmpty() {\n * return html`<div class=\"roxy-empty\" role=\"status\">No dream symbol</div>`;\n * }\n * }\n * ```\n */\nexport abstract class RoxyDataElement<T = unknown> extends LitElement {\n\tstatic styles: CSSResultGroup = [baseStyles];\n\n\t/** Typed RoxyAPI response. Assigned in JavaScript, hydrated from the roxy-data island, or set by a self-fetch. */\n\t@property({ attribute: false })\n\tdata: T | null = null;\n\n\t/** Endpoint path for self-fetch, e.g. \"astrology/natal-chart\" or \"dreams/symbols/{id}\". Empty disables self-fetch (controlled mode only). */\n\t@property({ type: String, attribute: 'data-endpoint' })\n\tendpoint = '';\n\n\t/** HTTP method for self-fetch. */\n\t@property({ type: String })\n\tmethod: 'GET' | 'POST' = 'POST';\n\n\t/** Browser-safe publishable key (pk_) for self-fetch. A secret key is refused client-side. */\n\t@property({ type: String, attribute: 'publishable-key' })\n\tpublishableKey?: string;\n\n\t/** Override the API origin for self-hosted or proxied deployments. */\n\t@property({ type: String, attribute: 'base-url' })\n\tbaseUrl?: string;\n\n\t/** Override the OpenAPI spec URL the self-fetch form introspects. */\n\t@property({ type: String, attribute: 'spec-url' })\n\tspecUrl?: string;\n\n\t/** Consumer backend route that proxies the request (holds the secret key). When set, self-fetch POSTs the request here instead of calling RoxyAPI directly, so no key reaches the browser. The server-rendered (WordPress) path. */\n\t@property({ type: String, attribute: 'submit-url' })\n\tsubmitUrl?: string;\n\n\t/** Persist the last self-fetch form values in sessionStorage (keyed by endpoint) and prefill the form on reload. */\n\t@property({ type: Boolean })\n\tremember = false;\n\n\t/** True while an uncontrolled self-fetch is in flight. Public so {@link FetchController} can drive it. */\n\t@state()\n\tloading = false;\n\n\t/** Message from a failed self-fetch, or null. Public so {@link FetchController} can drive it. */\n\t@state()\n\terror: string | null = null;\n\n\tprivate fetcher: FetchController<T>;\n\n\tconstructor() {\n\t\tsuper();\n\t\t// Controlled mode: hydrate `data` from a direct-child roxy-data island when\n\t\t// no JS property was assigned. Keyless; the server already fetched.\n\t\tnew MarkupDataController<T>(this);\n\t\tthis.fetcher = new FetchController<T>(this);\n\t}\n\n\tprotected willUpdate(changed: PropertyValues): void {\n\t\tif (changed.has('publishableKey')) {\n\t\t\tthis.fetcher.publishableKey = this.publishableKey;\n\t\t}\n\t\tif (changed.has('baseUrl') && this.baseUrl) {\n\t\t\tthis.fetcher.baseUrl = this.baseUrl;\n\t\t}\n\t\tif (changed.has('submitUrl')) {\n\t\t\tthis.fetcher.submitUrl = this.submitUrl;\n\t\t}\n\t}\n\n\trender(): unknown {\n\t\tif (this.loading) return this.renderLoading();\n\t\tif (this.error != null) return this.renderError(this.error);\n\t\tif (this.data != null) return this.renderData(this.data);\n\t\treturn this.renderNoData();\n\t}\n\n\t/** Render the populated response. The single method every component implements. */\n\tprotected abstract renderData(data: T): unknown;\n\n\t/** The data-absent branch: the self-fetch form when an endpoint is set, otherwise the empty state. */\n\tprotected renderNoData(): unknown {\n\t\treturn this.endpoint ? this.renderForm() : this.renderEmpty();\n\t}\n\n\t/** Internal self-fetch form. Reuses the introspecting `<roxy-endpoint-form>`; the consumer never places it. */\n\tprotected renderForm(): unknown {\n\t\treturn html`<roxy-endpoint-form data-endpoint=\"${this.endpoint}\" method=\"${this.method}\" spec-url=\"${ifDefined(this.specUrl)}\" .initialValues=\"${this.remember ? this.readRemembered() : undefined}\" @roxy-submit=\"${this.onFormSubmit}\"></roxy-endpoint-form>`;\n\t}\n\n\tprivate onFormSubmit = (e: Event) => {\n\t\tconst detail = (e as CustomEvent).detail as {\n\t\t\tvalues: Record<string, unknown>;\n\t\t};\n\t\tif (this.remember) this.writeRemembered(detail.values);\n\t\tvoid this.fetcher.run(\n\t\t\tbuildRequest(this.endpoint, this.method, detail.values),\n\t\t);\n\t};\n\n\t/** sessionStorage key for this component's remembered form values, scoped by endpoint. */\n\tprivate rememberKey(): string {\n\t\treturn `roxy-ui:form:${this.endpoint}`;\n\t}\n\n\tprivate readRemembered(): Record<string, unknown> | undefined {\n\t\ttry {\n\t\t\tconst raw = sessionStorage.getItem(this.rememberKey());\n\t\t\treturn raw ? (JSON.parse(raw) as Record<string, unknown>) : undefined;\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tprivate writeRemembered(values: Record<string, unknown>): void {\n\t\ttry {\n\t\t\tsessionStorage.setItem(this.rememberKey(), JSON.stringify(values));\n\t\t} catch {\n\t\t\t// Private mode / disabled storage: remembering is best-effort, never fatal.\n\t\t}\n\t}\n\n\t/** Terminal empty state. Subclasses override for a domain-specific message. */\n\tprotected renderEmpty(): unknown {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No data</div>`;\n\t}\n\n\t/** Loading placeholder shown during a self-fetch. */\n\tprotected renderLoading(): unknown {\n\t\treturn html`<div class=\"roxy-skeleton\" style=\"height:8rem\" role=\"status\" aria-label=\"Loading\"></div>`;\n\t}\n\n\t/** Error state shown when a self-fetch fails. Keeps the form in view so the request can be retried. */\n\tprotected renderError(message: string): unknown {\n\t\tconst banner = html`<div class=\"roxy-error\" role=\"alert\">${message}</div>`;\n\t\treturn this.endpoint ? html`${banner}${this.renderForm()}` : banner;\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`:host{font-family:var(--roxy-font-sans,system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif);color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-base,1rem);line-height:var(--roxy-leading-normal,1.5);animation:roxy-fade-in var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,cubic-bezier(.4, 0, .2, 1)) both;background:0 0;display:block;container-type:inline-size}:host([bare]){--roxy-surface:transparent;--roxy-shadow-sm:none;--roxy-shadow-md:none}*,:before,:after{box-sizing:border-box}@keyframes roxy-fade-in{0%{opacity:0;transform:translateY(2px)}to{opacity:1;transform:translateY(0)}}@media (prefers-reduced-motion:reduce){:host{animation:none}}.roxy-skeleton{background:linear-gradient(90deg, var(--roxy-border,#e4e4e7) 0%, color-mix(in srgb, var(--roxy-border,#e4e4e7) 60%, transparent) 50%, var(--roxy-border,#e4e4e7) 100%);border-radius:var(--roxy-radius-md,8px);background-size:200% 100%;animation:1.4s ease-in-out infinite roxy-shimmer}@keyframes roxy-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}@media (prefers-reduced-motion:reduce){.roxy-skeleton{animation:none}}.roxy-empty{padding:var(--roxy-space-lg,1.5rem);color:var(--roxy-muted,#71717a);text-align:center;font-size:var(--roxy-text-sm,.875rem)}.roxy-error{gap:var(--roxy-space-sm,.5rem);padding:var(--roxy-space-lg,1.5rem);background:var(--roxy-surface,#fff);border:1px solid var(--roxy-danger,#dc2626);border-radius:var(--roxy-radius-md,8px);color:var(--roxy-danger-fg,#991b1b);font-size:var(--roxy-text-sm,.875rem);justify-items:start;display:grid}.roxy-surface{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a)}:host(:focus-within) .roxy-card{outline:2px solid var(--roxy-ring,#f59e0b66);outline-offset:2px}:host{font-variant-emoji:text}`;\n", "import type { ReactiveController, ReactiveControllerHost } from 'lit';\n\n/**\n * Host slots the controller drives. {@link RoxyDataElement} satisfies this, so\n * the form mixin can attach a controller without the component wiring state by hand.\n */\ninterface FetchHost<T> extends ReactiveControllerHost {\n\tdata: T | null;\n\tloading: boolean;\n\terror: string | null;\n}\n\n/** Default RoxyAPI v2 origin. A component overrides it per instance via its `base-url` attribute. */\nconst DEFAULT_BASE_URL = 'https://roxyapi.com/api/v2';\n\n/** A single request the controller issues on the component's behalf. */\nexport interface RoxyRequest {\n\t/** Path under the API base, e.g. \"/dreams/symbols/water\" or \"/astrology/natal-chart\". */\n\tpath: string;\n\tmethod?: 'GET' | 'POST';\n\t/** JSON body for POST endpoints. */\n\tbody?: unknown;\n\t/** Query string parameters; nullish values are dropped. */\n\tquery?: Record<string, string | number | undefined>;\n}\n\n/**\n * Client-side fetch for uncontrolled (self-fetching) components: drives `host.data` / `host.loading` / `host.error` and cancels a stale request when a newer one starts or the host disconnects.\n *\n * @remarks\n * Security boundary. The only credential this ever sends is a `pk_` publishable key, which carries a server-side origin allowlist. A secret (`sk_`) or legacy unprefixed key is refused before any network call and surfaced as an error, so a server secret cannot leak into a browser request. This centralizes the guard that originated in `<roxy-location-search>` so every self-fetching component enforces it identically.\n *\n * Controlled-mode components never construct this. When a server injects the response as a `<script class=\"roxy-data\">` island, there is no key and no fetch, which is the path server-rendered consumers (WordPress, JSX SSR, static HTML) rely on.\n */\nexport class FetchController<T = unknown> implements ReactiveController {\n\tprivate readonly host: FetchHost<T>;\n\tprivate abort?: AbortController;\n\n\t/** Browser-safe publishable key. Set by the host from its `publishable-key` attribute. */\n\tpublishableKey?: string;\n\t/** API origin, overridable for self-hosted or proxied deployments. */\n\tbaseUrl = DEFAULT_BASE_URL;\n\t/**\n\t * Consumer backend route that holds the secret key. When set, the request is POSTed here as `{ path, method, body, query }` instead of called against RoxyAPI directly, so no key (publishable or secret) is sent from the browser. This is the canonical path for server-rendered hosts (WordPress); the backend proxies the request with its own `sk_` key and returns the JSON response.\n\t */\n\tsubmitUrl?: string;\n\n\tconstructor(host: FetchHost<T>) {\n\t\tthis.host = host;\n\t\thost.addController(this);\n\t}\n\n\thostDisconnected() {\n\t\tthis.abort?.abort();\n\t\tthis.abort = undefined;\n\t}\n\n\t/**\n\t * Issue the request and resolve once `host.data` (success) or `host.error`\n\t * (failure) is set. A no-op return when a non-publishable key is present:\n\t * the error is already surfaced and nothing is sent.\n\t */\n\tasync run(req: RoxyRequest): Promise<void> {\n\t\t// submit-url proxy: no key leaves the browser; the consumer's backend holds it.\n\t\tif (!this.submitUrl && this.secretKeyRefused()) return;\n\t\tthis.abort?.abort();\n\t\tconst controller = new AbortController();\n\t\tthis.abort = controller;\n\t\tthis.host.loading = true;\n\t\tthis.host.error = null;\n\t\ttry {\n\t\t\tconst res = this.submitUrl\n\t\t\t\t? await fetch(this.submitUrl, {\n\t\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\tAccept: 'application/json',\n\t\t\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t\t\t},\n\t\t\t\t\t\tbody: JSON.stringify(req),\n\t\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t\t})\n\t\t\t\t: await this.callApi(req, controller.signal);\n\t\t\tif (!res.ok) throw new Error(await this.readError(res));\n\t\t\tconst json = (await res.json()) as T;\n\t\t\tif (controller.signal.aborted) return;\n\t\t\tthis.host.data = json;\n\t\t} catch (err) {\n\t\t\tif ((err as { name?: string })?.name === 'AbortError') return;\n\t\t\tthis.host.error = err instanceof Error ? err.message : String(err);\n\t\t} finally {\n\t\t\tif (this.abort === controller) this.abort = undefined;\n\t\t\tif (!controller.signal.aborted) this.host.loading = false;\n\t\t}\n\t}\n\n\t/** Direct call against RoxyAPI with the publishable key (the no-backend path). */\n\tprivate callApi(req: RoxyRequest, signal: AbortSignal): Promise<Response> {\n\t\tconst url = new URL(`${this.baseUrl}${req.path}`);\n\t\tfor (const [k, v] of Object.entries(req.query ?? {})) {\n\t\t\tif (v != null) url.searchParams.set(k, String(v));\n\t\t}\n\t\tconst headers: Record<string, string> = { Accept: 'application/json' };\n\t\tif (this.publishableKey) headers['X-API-Key'] = this.publishableKey;\n\t\tif (req.body != null) headers['Content-Type'] = 'application/json';\n\t\treturn fetch(url, {\n\t\t\tmethod: req.method ?? 'GET',\n\t\t\theaders,\n\t\t\tbody: req.body != null ? JSON.stringify(req.body) : undefined,\n\t\t\tsignal,\n\t\t});\n\t}\n\n\t/** True when a key is set and it is not a browser-safe `pk_` publishable key. Surfaces the error and refuses to send. */\n\tprivate secretKeyRefused(): boolean {\n\t\tconst key = this.publishableKey;\n\t\tif (!key || key.startsWith('pk_')) return false;\n\t\tthis.host.error =\n\t\t\t'Client-side components accept a pk_ publishable key only. Use a publishable key with an origin allowlist, or render server-side.';\n\t\t(this.host as unknown as EventTarget).dispatchEvent(\n\t\t\tnew CustomEvent('roxy-validation-error', {\n\t\t\t\tdetail: { reason: 'possible-secret-key' },\n\t\t\t\tbubbles: true,\n\t\t\t\tcomposed: true,\n\t\t\t}),\n\t\t);\n\t\treturn true;\n\t}\n\n\t/** Surface the `{ error, code }` message the API returns on failure, falling back to the status code. */\n\tprivate async readError(res: Response): Promise<string> {\n\t\ttry {\n\t\t\tconst body = (await res.json()) as { error?: string };\n\t\t\tif (body?.error) return body.error;\n\t\t} catch {\n\t\t\t// Non-JSON error body: fall through to the status line.\n\t\t}\n\t\treturn `Request failed (${res.status})`;\n\t}\n}\n\n/**\n * Translate flat form values into a {@link RoxyRequest} for an endpoint. The `{name}` segments in the endpoint template are substituted from the values and removed; the rest become the JSON body for POST or query parameters for GET. This is the spec-light request builder the base element uses to turn a `<roxy-endpoint-form>` submission into a self-fetch, so a component needs no per-endpoint glue.\n */\nexport function buildRequest(\n\tendpoint: string,\n\tmethod: 'GET' | 'POST',\n\tvalues: Record<string, unknown>,\n): RoxyRequest {\n\tconst rest: Record<string, unknown> = { ...values };\n\tconst path = `/${endpoint.replace(/^\\//, '')}`.replace(\n\t\t/\\{([^}]+)\\}/g,\n\t\t(_match, name: string) => {\n\t\t\tconst v = rest[name];\n\t\t\tdelete rest[name];\n\t\t\treturn encodeURIComponent(String(v ?? ''));\n\t\t},\n\t);\n\tconst query: Record<string, string | number | undefined> = {};\n\tconst body: Record<string, unknown> = {};\n\tfor (const [k, v] of Object.entries(rest)) {\n\t\tif (v === undefined || v === '') continue;\n\t\tif (method === 'GET') query[k] = v as string | number;\n\t\telse body[k] = v;\n\t}\n\treturn { path, method, query, body: method === 'POST' ? body : undefined };\n}\n", "import type { ReactiveController, ReactiveControllerHost } from 'lit';\n\n/**\n * Marker class on the inline JSON script a server emits inside a component.\n *\n * @example\n * ```html\n * <roxy-natal-chart>\n * <script type=\"application/json\" class=\"roxy-data\">{ ...response... }</script>\n * </roxy-natal-chart>\n * ```\n */\nconst ROXY_DATA_CLASS = 'roxy-data';\n\n/**\n * Serialize a RoxyAPI response for embedding inside an inline `<script type=\"application/json\" class=\"roxy-data\">`. This is the safe writer counterpart to {@link MarkupDataController}, the reader: server-rendered and cached consumers (WordPress, JSX SSR, static HTML) emit the script with this, and the component hydrates `data` from it on connect.\n *\n * @remarks\n * Use this instead of a bare `JSON.stringify`. A raw stringify of a response that contains the literal text `</script>` (common in long interpretation prose) closes the script element early, corrupting the page and creating an HTML-injection vector. This escapes the script-unsafe characters to their `\\uXXXX` JSON escapes, which `JSON.parse` restores to the original characters, so the value the component receives is identical to the response you passed.\n *\n * `<` is the load-bearing escape (it defeats `</script>` and `<!--`). `>` and `&` are escaped for defence in depth, and U+2028 / U+2029 because they are valid in JSON yet are line terminators in a `<script>` context and break some parsers. The escapes introduce only `\\uXXXX` sequences, so the replacements never feed each other and order is irrelevant.\n *\n * Pass the unwrapped RoxyAPI response, the same shape you would assign to `element.data`. Do not pass the SDK envelope (`{ data, error, request, response }`).\n *\n * @example\n * ```ts\n * import { serializeRoxyData } from '@roxyapi/ui';\n *\n * const { data } = await roxy.dreams.getDreamSymbol({ path: { id: 'water' } });\n * const html = `<roxy-dream-card><script type=\"application/json\" class=\"roxy-data\">${serializeRoxyData(data)}</script></roxy-dream-card>`;\n * ```\n */\nexport function serializeRoxyData(data: unknown): string {\n\treturn JSON.stringify(data)\n\t\t.replace(/</g, '\\\\u003c')\n\t\t.replace(/>/g, '\\\\u003e')\n\t\t.replace(/&/g, '\\\\u0026')\n\t\t.replace(/\\u2028/g, '\\\\u2028')\n\t\t.replace(/\\u2029/g, '\\\\u2029');\n}\n\n/**\n * Build the complete `<script type=\"application/json\" class=\"roxy-data\">\u2026</script>` element a server nests inside a `roxy-*` component for the no-JavaScript hydration path. The payload is escaped via {@link serializeRoxyData}, so it is safe to drop straight into HTML output.\n *\n * @remarks\n * The element carries both `type=\"application/json\"` and `class=\"roxy-data\"` because {@link MarkupDataController} reads only a direct-child script that has both. Emit one of these inside the target component; the JavaScript `data` property still wins if it is later assigned.\n *\n * @example\n * ```ts\n * import { roxyDataScript } from '@roxyapi/ui';\n *\n * const { data } = await roxy.crystals.getCrystal({ path: { id: 'amethyst' } });\n * const html = `<roxy-crystal-grid>${roxyDataScript(data)}</roxy-crystal-grid>`;\n * ```\n */\nexport function roxyDataScript(data: unknown): string {\n\treturn `<script type=\"application/json\" class=\"${ROXY_DATA_CLASS}\">${serializeRoxyData(data)}</script>`;\n}\n\n/**\n * True when the element is a `<script type=\"application/json\">`. Uses tag name and attribute rather than `instanceof HTMLScriptElement` so the check holds in every DOM implementation, including server-rendered and hydration runtimes where the constructor global may be absent.\n */\nfunction isJsonScript(el: Element): boolean {\n\treturn (\n\t\tel.nodeName === 'SCRIPT' && el.getAttribute('type') === 'application/json'\n\t);\n}\n\n/**\n * Host shape the controller drives: any reactive element that exposes a public `data` slot. The controller only writes `data` when the host left it unset, so the JavaScript property path always wins.\n */\ninterface DataHost extends ReactiveControllerHost, HTMLElement {\n\tdata?: unknown;\n}\n\n/**\n * Reactive controller that lets a component hydrate its `data` from embedded markup when no `data` property was assigned in JavaScript.\n *\n * @remarks\n * The server-side and cached-render model: a backend renders the RoxyAPI response into a direct-child `<script type=\"application/json\" class=\"roxy-data\">` element, ships static HTML, and never runs per-element JavaScript to assign a property. On connect this controller reads that script, parses it, and feeds the result to the host. The JavaScript property path is untouched and authoritative: if `host.data` already holds a value when the host connects, the controller does nothing and the markup is ignored.\n *\n * Source resolution order on connect, first hit wins:\n *\n * 1. `host.data` already set in JavaScript -> leave it, read nothing.\n * 2. A direct-child `<script type=\"application/json\" class=\"roxy-data\">` -> parse and use. Direct-child only, so a nested component's own script is never read by an ancestor.\n *\n * Fetching from a URL is intentionally unsupported: that would require a browser-visible key and breaks the server-rendered, cached model these consumers rely on.\n *\n * Timing: {@link hostConnected} runs inside the host `connectedCallback`. For an element parsed from server HTML, its direct children are present by the time the custom element upgrades and connects, so the script is readable here. For an element created with `document.createElement` and connected before any child is appended, there is nothing to read and the property path is the only source, which is exactly the existing behavior.\n *\n * Failure is safe: malformed JSON or a missing script leaves `host.data` untouched, so the host renders its normal empty state.\n *\n * Reading the script never mutates it, and only the marked script is touched, so any sibling fallback markup a server nested inside the element (for no-JavaScript, AMP, or crawler rendering) is left in place.\n *\n * @example\n * ```ts\n * import { MarkupDataController } from '../utils/markup-data.js';\n *\n * export class RoxyExample extends LitElement {\n * constructor() {\n * super();\n * new MarkupDataController(this);\n * }\n *\n * @property({ attribute: false })\n * data: ExampleResponse | null = null;\n * }\n * ```\n */\nexport class MarkupDataController<T = unknown> implements ReactiveController {\n\tprivate readonly host: DataHost;\n\n\tconstructor(host: DataHost) {\n\t\tthis.host = host;\n\t\thost.addController(this);\n\t}\n\n\thostConnected() {\n\t\t// Property path wins. If the consumer (React, vanilla `.data =`, the\n\t\t// widgets script, an MCP agent) already set data, never look at markup.\n\t\tif (this.host.data != null) return;\n\n\t\tconst parsed = this.read();\n\t\tif (parsed === undefined) return;\n\n\t\tthis.host.data = parsed as T;\n\t\tthis.host.requestUpdate();\n\t}\n\n\t/**\n\t * Resolve the embedded payload. Returns `undefined` when there is nothing valid to read so the caller can leave `host.data` untouched.\n\t */\n\tprivate read(): T | undefined {\n\t\tconst inline = this.findInlineScript();\n\t\treturn inline ? this.parse(inline.textContent) : undefined;\n\t}\n\n\t/**\n\t * Direct-child `<script type=\"application/json\" class=\"roxy-data\">`. Scoped to immediate children so a nested data-driven component never has its script read by an ancestor, and so sibling fallback markup is ignored.\n\t */\n\tprivate findInlineScript(): Element | null {\n\t\tfor (const child of Array.from(this.host.children)) {\n\t\t\tif (isJsonScript(child) && child.classList.contains(ROXY_DATA_CLASS)) {\n\t\t\t\treturn child;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate parse(text: string | null): T | undefined {\n\t\tif (!text?.trim()) return undefined;\n\t\ttry {\n\t\t\treturn JSON.parse(text) as T;\n\t\t} catch {\n\t\t\t// Malformed embedded JSON: fail safe, leave the host empty state in\n\t\t\t// place rather than throwing during connect.\n\t\t\treturn undefined;\n\t\t}\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { AnalyzeNumberSequenceResponse } from '../types/index.js';\nimport { buildMeaningSections } from '../utils/angel-sections.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\n/**\n * Angel number lookup card. Renders /angel-numbers/lookup: the analysed sequence with its pattern classification (type, digit count, unique digits, palindrome, repeating), the known angel-number meaning when the sequence is in the database, and the foundational digit-root meaning that interprets any sequence. Built for synchronicity trackers where users enter arbitrary numbers.\n */\n@customElement('roxy-angel-number-lookup')\nexport class RoxyAngelNumberLookup extends RoxyDataElement<AnalyzeNumberSequenceResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.card{background:var(--roxy-surface,#fff);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.hero{align-items:center;gap:var(--roxy-space-md,1rem);display:flex}.numeral{font-size:3rem;line-height:1;font-weight:var(--roxy-weight-bold,600);color:var(--roxy-accent-ink,#b45309);font-variant-numeric:tabular-nums}.label{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;margin:0}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.badges{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;display:flex}.badge{border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 35%, transparent);color:var(--roxy-fg,#0a0a0a);text-transform:capitalize;align-items:center;padding:3px 10px;display:inline-flex}.badge.flag{background:color-mix(in srgb, var(--roxy-info,#0284c7) 16%, transparent);color:var(--roxy-info-fg,#075985)}.section{border-top:1px solid var(--roxy-border,#e4e4e7);padding-top:var(--roxy-space-md,1rem);gap:var(--roxy-space-sm,.5rem);display:grid}.section>.label{margin:0}.section h3{font-size:var(--roxy-text-base,1rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-fg,#0a0a0a);margin:0}.section p{color:var(--roxy-fg,#0a0a0a);line-height:1.6;font-size:var(--roxy-text-sm,.875rem);margin:0}.chips{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;display:flex}.chips span{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 14%, transparent);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);padding:2px 8px}details{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-sm,4px);overflow:hidden}summary{cursor:pointer;padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);font-weight:var(--roxy-weight-bold,600);font-size:var(--roxy-text-sm,.875rem);list-style-position:inside}details p{padding:0 var(--roxy-space-md,1rem) var(--roxy-space-md,1rem)}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No number analysis</div>`;\n\t}\n\n\tprotected renderData(d: AnalyzeNumberSequenceResponse) {\n\t\tconst known = d.knownMeaning;\n\t\tconst root = d.digitRootMeaning;\n\t\tconst heading = known?.title ?? 'Number analysis';\n\n\t\treturn html`<article class=\"card\" aria-label=\"${`Number ${d.number ?? ''}`}\"><div class=\"hero\">${d.number ? html`<div class=\"numeral\">${d.number}</div>` : nothing}<div><p class=\"label\">Number analysis</p><h2 class=\"title\">${heading}</h2></div></div><div class=\"badges\">${d.type ? html`<span class=\"badge\">${d.type}</span>` : nothing} ${typeof d.digits === 'number' ? html`<span class=\"badge\">${d.digits} digits</span>` : nothing} ${typeof d.uniqueDigits === 'number' ? html`<span class=\"badge\">${d.uniqueDigits} unique</span>` : nothing} ${typeof d.digitRoot === 'number' ? html`<span class=\"badge\">Digit root ${d.digitRoot}</span>` : nothing} ${d.isPalindrome ? html`<span class=\"badge flag\">Palindrome</span>` : nothing} ${d.isRepeating ? html`<span class=\"badge flag\">Repeating</span>` : nothing}</div>${\n\t\t\t\tknown\n\t\t\t\t\t? html`<div class=\"section\"><p class=\"label\">Known angel number</p>${known.coreMessage ? html`<p>${known.coreMessage}</p>` : nothing} ${\n\t\t\t\t\t\t\tknown.keywords && known.keywords.length > 0\n\t\t\t\t\t\t\t\t? html`<div class=\"chips\">${known.keywords.map((k) => html`<span>${k}</span>`)}</div>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t} ${this.renderMeaning(known.meaning, known.biblical, known.shadow)} ${known.affirmation ? html`<p><em>${known.affirmation}</em></p>` : nothing}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\troot\n\t\t\t\t\t? html`<div class=\"section\"><p class=\"label\">Foundational digit root${root.number ? ` (${root.number})` : ''}</p>${root.title ? html`<h3>${root.title}</h3>` : nothing} ${root.coreMessage ? html`<p>${root.coreMessage}</p>` : nothing} ${!known ? this.renderRootMeaning(root) : nothing}</div>`\n\t\t\t\t\t: nothing\n\t\t\t}</article>`;\n\t}\n\n\tprivate renderMeaning(\n\t\tmeaning: Record<string, string> | undefined,\n\t\tbiblical?: string,\n\t\tshadow?: string,\n\t) {\n\t\tconst sections = buildMeaningSections(meaning, biblical, shadow);\n\t\tif (sections.length === 0) return nothing;\n\t\treturn html`${sections.map(\n\t\t\t(s, i) => html`<details name=\"lookup-meaning\" ?open=\"${i === 0}\"><summary>${s.label}</summary><p>${s.body}</p></details>`,\n\t\t)}`;\n\t}\n\n\t/**\n\t * Render the foundational digit-root reading for an unknown sequence: keyword chips, the full life-area accordion (including money), and the affirmation. The digit-root meaning carries no biblical or shadow field, so only the life areas are passed through.\n\t */\n\tprivate renderRootMeaning(\n\t\troot: NonNullable<AnalyzeNumberSequenceResponse['digitRootMeaning']>,\n\t) {\n\t\treturn html`${\n\t\t\troot.keywords && root.keywords.length > 0\n\t\t\t\t? html`<div class=\"chips\">${root.keywords.map((k) => html`<span>${k}</span>`)}</div>`\n\t\t\t\t: nothing\n\t\t}${this.renderMeaning(root.meaning)}${\n\t\t\troot.affirmation ? html`<p><em>${root.affirmation}</em></p>` : nothing\n\t\t}`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-angel-number-lookup': RoxyAngelNumberLookup;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\nimport { SIGN_GLYPH } from '../tokens/index.js';\nimport type { AshtakavargaResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\ntype Tab = 'sarva' | 'bhinna' | 'pinda';\n\nconst TAB_LABELS: Record<Tab, string> = {\n\tsarva: 'Sarvashtakavarga',\n\tbhinna: 'Bhinnashtakavarga',\n\tpinda: 'Shodhya Pinda',\n};\n\nconst TABS: Tab[] = ['sarva', 'bhinna', 'pinda'];\n\n/**\n * Ashtakavarga grid with three tabbed views: Sarvashtakavarga, Bhinnashtakavarga,\n * and Shodhya Pinda. Pass `data` from /vedic-astrology/ashtakavarga.\n */\n@customElement('roxy-ashtakavarga-grid')\nexport class RoxyAshtakavargaGrid extends RoxyDataElement<AshtakavargaResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-md,1rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.subtitle{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem);margin:0}.tablist{border-bottom:2px solid var(--roxy-border,#e4e4e7);gap:2px;display:flex}.tab{padding:var(--roxy-space-xs,.25rem) var(--roxy-space-md,1rem);font-size:var(--roxy-text-sm,.875rem);cursor:pointer;color:var(--roxy-muted,#71717a);transition:color var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,ease);background:0 0;border:none;border-bottom:2px solid #0000;margin-bottom:-2px;font-family:inherit}.tab[aria-selected=true]{color:var(--roxy-accent-ink,#b45309);border-bottom-color:var(--roxy-accent,#f59e0b);font-weight:var(--roxy-weight-bold,600)}.tab:hover:not([aria-selected=true]){color:var(--roxy-fg,#0a0a0a)}.overflow-scroll{-webkit-overflow-scrolling:touch;overflow-x:auto}table{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem)}th,td{padding:var(--roxy-space-sm,.5rem);border-bottom:1px solid var(--roxy-border,#e4e4e7);text-align:center}th{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;font-size:var(--roxy-text-xs,.75rem);letter-spacing:.06em}td:first-child,th:first-child{text-align:left}.glyph{margin-right:3px;font-size:1.1em;line-height:1}.planet-cell{white-space:nowrap;align-items:center;gap:4px;display:flex}.total-row td{font-weight:var(--roxy-weight-bold,600);border-top:2px solid var(--roxy-border,#e4e4e7);border-bottom:none}.heat-cell{border-radius:var(--roxy-radius-sm,4px);font-weight:var(--roxy-weight-bold,600);font-variant-numeric:tabular-nums;min-width:2rem;color:var(--roxy-fg,currentColor)}.heat-1{background:color-mix(in srgb, var(--roxy-heat,#ef4444) 6%, transparent)}.heat-2{background:color-mix(in srgb, var(--roxy-heat,#ef4444) 14%, transparent)}.heat-3{background:color-mix(in srgb, var(--roxy-heat,#ef4444) 26%, transparent)}.heat-4{background:color-mix(in srgb, var(--roxy-heat,#ef4444) 40%, transparent)}.heat-5{background:color-mix(in srgb, var(--roxy-heat,#ef4444) 55%, transparent)}.heat-6{background:color-mix(in srgb, var(--roxy-heat,#ef4444) 72%, transparent)}.heat-7{background:color-mix(in srgb, var(--roxy-heat,#ef4444) 90%, transparent)}.bhinna-table th:first-child,.bhinna-table td:first-child{min-width:5rem}@container (width<=480px){.bhinna-table th,.bhinna-table td{font-size:var(--roxy-text-xs,.75rem);padding:.3rem .35rem}.bhinna-table th:first-child,.bhinna-table td:first-child{min-width:3.5rem}.heat-cell{min-width:1.5rem}}.overflow-scroll{-webkit-mask-image:linear-gradient(90deg,#0000 0,#000 .5rem calc(100% - 1rem),#0000 100%);mask-image:linear-gradient(90deg,#0000 0,#000 .5rem calc(100% - 1rem),#0000 100%)}`,\n\t];\n\n\t@state()\n\tactiveTab: Tab = 'sarva';\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No ashtakavarga data</div>`;\n\t}\n\n\tprotected renderData(d: AshtakavargaResponse) {\n\t\tconst signs = d.signs ?? [];\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Ashtakavarga grid\"><div class=\"head\"><h2 class=\"title\">Ashtakavarga</h2>${\n\t\t\t\t\tsigns.length\n\t\t\t\t\t\t? html`<p class=\"subtitle\">${signs.length} signs</p>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</div><div class=\"tablist\" role=\"tablist\" aria-label=\"Ashtakavarga views\" @keydown=\"${this.onTabKeyDown}\">${TABS.map(\n\t\t\t\t\t(tab) => html`<button class=\"tab\" role=\"tab\" id=\"tab-${tab}\" aria-selected=\"${this.activeTab === tab ? 'true' : 'false'}\" aria-controls=\"panel-${tab}\" tabindex=\"${this.activeTab === tab ? '0' : '-1'}\" @click=\"${() => {\n\t\t\t\t\t\t\tthis.activeTab = tab;\n\t\t\t\t\t\t}}\">${TAB_LABELS[tab]}</button>`,\n\t\t\t\t)}</div><div id=\"panel-${this.activeTab}\" role=\"tabpanel\" aria-labelledby=\"tab-${this.activeTab}\">${\n\t\t\t\t\tthis.activeTab === 'sarva'\n\t\t\t\t\t\t? this.renderSarva(signs)\n\t\t\t\t\t\t: this.activeTab === 'bhinna'\n\t\t\t\t\t\t\t? this.renderBhinna(signs)\n\t\t\t\t\t\t\t: this.renderPinda()\n\t\t\t\t}</div></div>`;\n\t}\n\n\tprivate onTabKeyDown(e: KeyboardEvent) {\n\t\tconst idx = TABS.indexOf(this.activeTab);\n\t\tif (e.key === 'ArrowRight') {\n\t\t\te.preventDefault();\n\t\t\tthis.activeTab = TABS[(idx + 1) % TABS.length];\n\t\t\tthis.focusActiveTab();\n\t\t} else if (e.key === 'ArrowLeft') {\n\t\t\te.preventDefault();\n\t\t\tthis.activeTab = TABS[(idx - 1 + TABS.length) % TABS.length];\n\t\t\tthis.focusActiveTab();\n\t\t}\n\t}\n\n\tprivate focusActiveTab() {\n\t\trequestAnimationFrame(() => {\n\t\t\tconst btn = this.shadowRoot?.querySelector<HTMLButtonElement>(\n\t\t\t\t`#tab-${this.activeTab}`,\n\t\t\t);\n\t\t\tbtn?.focus();\n\t\t});\n\t}\n\n\t/**\n\t * Bhinna bindus per planet per sign run 0..8 (sum of 0/1 contributions\n\t * from each of the 8 reference points). Bucket directly by raw count.\n\t */\n\tprivate bhinnaHeat(count: number): string {\n\t\tif (count <= 1) return 'heat-1';\n\t\tif (count <= 2) return 'heat-2';\n\t\tif (count <= 3) return 'heat-3';\n\t\tif (count <= 4) return 'heat-4';\n\t\tif (count <= 5) return 'heat-5';\n\t\tif (count <= 6) return 'heat-6';\n\t\treturn 'heat-7';\n\t}\n\n\t/**\n\t * Sarva bindus per sign are the column total across all 7 planets, range\n\t * roughly 0..56 with typical values 20..40. Bucketed per classical\n\t * interpretation: 25 below par, 25..30 average, 30..40 strong, 40+ very\n\t * strong. Bucket spans intentionally widen at the extremes so a single\n\t * outlier sign reads as exceptional.\n\t */\n\tprivate sarvaHeat(count: number): string {\n\t\tif (count <= 18) return 'heat-1';\n\t\tif (count <= 23) return 'heat-2';\n\t\tif (count <= 28) return 'heat-3';\n\t\tif (count <= 32) return 'heat-4';\n\t\tif (count <= 37) return 'heat-5';\n\t\tif (count <= 42) return 'heat-6';\n\t\treturn 'heat-7';\n\t}\n\n\tprivate renderSarva(signs: AshtakavargaResponse['signs']) {\n\t\tconst sav = this.data!.sarvashtakavarga;\n\t\tif (!sav) return html`<p class=\"roxy-empty\">No sarvashtakavarga data</p>`;\n\n\t\treturn html`<div class=\"overflow-scroll\"><table aria-label=\"Sarvashtakavarga bindu counts per sign\"><thead><tr><th scope=\"col\">Sign</th><th scope=\"col\">Bindus</th></tr></thead><tbody>${signs.map((sign, i) => {\n\t\t\t\t\t\tconst count = sav.bindus[i] ?? 0;\n\t\t\t\t\t\tconst hc = this.sarvaHeat(count);\n\t\t\t\t\t\treturn html`<tr><td><div class=\"planet-cell\"><span class=\"glyph\" aria-hidden=\"true\">${SIGN_GLYPH[sign] ?? ''}</span> ${sign}</div></td><td class=\"${`heat-cell ${hc}`}\">${count}</td></tr>`;\n\t\t\t\t\t})}</tbody><tfoot><tr class=\"total-row\"><td>Total</td><td>${sav.total}</td></tr></tfoot></table></div>`;\n\t}\n\n\tprivate renderBhinna(signs: AshtakavargaResponse['signs']) {\n\t\tconst bhinna = this.data!.bhinnashtakavarga;\n\t\tif (!bhinna?.length)\n\t\t\treturn html`<p class=\"roxy-empty\">No bhinnashtakavarga data</p>`;\n\n\t\treturn html`<div class=\"overflow-scroll\"><table class=\"bhinna-table\" aria-label=\"Bhinnashtakavarga planet-by-sign grid\"><thead><tr><th scope=\"col\">Planet</th>${signs.map(\n\t\t\t\t\t\t\t(s) =>\n\t\t\t\t\t\t\t\thtml`<th scope=\"col\" title=\"${s}\">${SIGN_GLYPH[s] ?? s.slice(0, 2)}</th>`,\n\t\t\t\t\t\t)}<th scope=\"col\">Total</th></tr></thead><tbody>${bhinna.map(\n\t\t\t\t\t\t(row) => html`<tr><td>${row.planet}</td>${row.bindus.map((count) => {\n\t\t\t\t\t\t\tconst hc = this.bhinnaHeat(count);\n\t\t\t\t\t\t\treturn html`<td class=\"${`heat-cell ${hc}`}\">${count}</td>`;\n\t\t\t\t\t\t})}<td>${row.total}</td></tr>`,\n\t\t\t\t\t)}</tbody></table></div>`;\n\t}\n\n\tprivate renderPinda() {\n\t\tconst pinda = this.data!.shodhyaPinda;\n\t\tif (!pinda?.length)\n\t\t\treturn html`<p class=\"roxy-empty\">No shodhya pinda data</p>`;\n\n\t\treturn html`<div class=\"overflow-scroll\"><table aria-label=\"Shodhya Pinda planet strength scores\"><thead><tr><th scope=\"col\">Planet</th><th scope=\"col\">Rashi Pinda</th><th scope=\"col\">Graha Pinda</th><th scope=\"col\">Shodhya Pinda</th></tr></thead><tbody>${pinda.map(\n\t\t\t\t\t\t(row) => html`<tr><td>${row.planet}</td><td>${row.rashiPinda}</td><td>${row.grahaPinda}</td><td>${row.shodhyaPinda}</td></tr>`,\n\t\t\t\t\t)}</tbody></table></div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-ashtakavarga-grid': RoxyAshtakavargaGrid;\n\t}\n}\n", "/**\n * Symbol constants used across components. Single source of truth so chart\n * wheels, card headers, hexagram displays, and panchang tables stay visually\n * consistent.\n */\n\nexport const PLANET_GLYPH: Record<string, string> = {\n\tSun: '\u2609',\n\tMoon: '\u263D',\n\tMercury: '\u263F',\n\tVenus: '\u2640',\n\tEarth: '\u2641',\n\tMars: '\u2642',\n\tJupiter: '\u2643',\n\tSaturn: '\u2644',\n\tUranus: '\u2645',\n\tNeptune: '\u2646',\n\tPluto: '\u2647',\n\tRahu: '\u260A',\n\tKetu: '\u260B',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n\tNorthNode: '\u260A',\n\tSouthNode: '\u260B',\n\t'North node': '\u260A',\n\t'South node': '\u260B',\n\tChiron: '\u26B7',\n\tLilith: '\u26B8',\n\t'Black moon lilith': '\u26B8',\n};\n\nexport const PLANET_ABBR: Record<string, string> = {\n\tSun: 'Su',\n\tMoon: 'Mo',\n\tMercury: 'Me',\n\tVenus: 'Ve',\n\tMars: 'Ma',\n\tJupiter: 'Ju',\n\tSaturn: 'Sa',\n\tUranus: 'Ur',\n\tNeptune: 'Ne',\n\tPluto: 'Pl',\n\tRahu: 'Ra',\n\tKetu: 'Ke',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n};\n\nexport const SIGN_GLYPH: Record<string, string> = {\n\tAries: '\u2648',\n\tTaurus: '\u2649',\n\tGemini: '\u264A',\n\tCancer: '\u264B',\n\tLeo: '\u264C',\n\tVirgo: '\u264D',\n\tLibra: '\u264E',\n\tScorpio: '\u264F',\n\tSagittarius: '\u2650',\n\tCapricorn: '\u2651',\n\tAquarius: '\u2652',\n\tPisces: '\u2653',\n};\n\nexport const SIGN_ABBR: Record<string, string> = {\n\tAries: 'Ar',\n\tTaurus: 'Ta',\n\tGemini: 'Ge',\n\tCancer: 'Cn',\n\tLeo: 'Le',\n\tVirgo: 'Vi',\n\tLibra: 'Li',\n\tScorpio: 'Sc',\n\tSagittarius: 'Sg',\n\tCapricorn: 'Cp',\n\tAquarius: 'Aq',\n\tPisces: 'Pi',\n};\n\nexport const SIGNS_ORDER = [\n\t'Aries',\n\t'Taurus',\n\t'Gemini',\n\t'Cancer',\n\t'Leo',\n\t'Virgo',\n\t'Libra',\n\t'Scorpio',\n\t'Sagittarius',\n\t'Capricorn',\n\t'Aquarius',\n\t'Pisces',\n] as const;\n\n/**\n * Lowercase rashi keys in canonical zodiac order. Derived from `SIGNS_ORDER`\n * so the two stay in lockstep. The /vedic-astrology/birth-chart response\n * carries planet buckets keyed by these names.\n */\nexport const RASHI_KEYS = SIGNS_ORDER.map((s) =>\n\ts.toLowerCase(),\n) as readonly Lowercase<(typeof SIGNS_ORDER)[number]>[];\n\n/** Aspect symbols. Used by synastry and natal chart aspect tables. */\nexport const ASPECT_SYMBOL: Record<string, string> = {\n\tconjunction: '\u260C',\n\topposition: '\u260D',\n\ttrine: '\u25B3',\n\tsquare: '\u25A1',\n\tsextile: '\u2731',\n\tquincunx: '\u22BB',\n\tsemisextile: '\u22BC',\n};\n\n/** Trigrams used by I Ching hexagrams. Eight trigrams compose 64 hexagrams. */\nexport const TRIGRAM_GLYPH: Record<string, string> = {\n\theaven: '\u2630',\n\tlake: '\u2631',\n\tfire: '\u2632',\n\tthunder: '\u2633',\n\twind: '\u2634',\n\twater: '\u2635',\n\tmountain: '\u2636',\n\tearth: '\u2637',\n\tHeaven: '\u2630',\n\tLake: '\u2631',\n\tFire: '\u2632',\n\tThunder: '\u2633',\n\tWind: '\u2634',\n\tWater: '\u2635',\n\tMountain: '\u2636',\n\tEarth: '\u2637',\n};\n\n/** Moon phase emoji set. Used by moon phase card. */\nexport const MOON_PHASE_EMOJI: Record<string, string> = {\n\t'new moon': '\uD83C\uDF11',\n\t'waxing crescent': '\uD83C\uDF12',\n\t'first quarter': '\uD83C\uDF13',\n\t'waxing gibbous': '\uD83C\uDF14',\n\t'full moon': '\uD83C\uDF15',\n\t'waning gibbous': '\uD83C\uDF16',\n\t'last quarter': '\uD83C\uDF17',\n\t'waning crescent': '\uD83C\uDF18',\n};\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { PLANET_GLYPH } from '../tokens/index.js';\nimport type {\n\tCalculateAspectsResponse,\n\tCalculateTransitAspectsResponse,\n\tDetectAspectPatternsResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { chevron, disclosureStyles } from '../utils/disclosure.js';\nimport { formatNumber } from '../utils/format.js';\nimport { capitalize } from '../utils/string.js';\n\n/**\n * Natal + transit aspect grid with chart-pattern detection. Renders three endpoints that share an aspects/patterns shape: /astrology/aspects (natal aspects + patterns + a harmonious/challenging summary), /astrology/transit-aspects (transiting-to-natal aspects with timing guidance), and /astrology/aspect-patterns (patterns only: grand trines, t-squares, stelliums, yods, kites). Each aspect row shows the two bodies, the aspect type coloured by nature, its orb and strength, and an expandable interpretation; patterns render as labelled cards listing the planets they bind.\n */\ntype AspectsData =\n\t| CalculateAspectsResponse\n\t| CalculateTransitAspectsResponse\n\t| DetectAspectPatternsResponse;\n\n@customElement('roxy-aspects-table')\nexport class RoxyAspectsTable extends RoxyDataElement<AspectsData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tdisclosureStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-md,1rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.subtitle{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem);margin:0}.summary-pills{gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.pill{padding:2px var(--roxy-space-sm,.5rem);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);border:1px solid;align-items:center;gap:4px;display:inline-flex}.pill--muted{color:var(--roxy-fg,#0a0a0a);background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 60%, transparent)}.pill--success{color:var(--roxy-success-fg,#166534);background:color-mix(in srgb, var(--roxy-success,#16a34a) 10%, transparent)}.pill--danger{color:var(--roxy-danger-fg,#991b1b);background:color-mix(in srgb, var(--roxy-danger,#dc2626) 10%, transparent)}.section-label{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;font-weight:var(--roxy-weight-bold,600);margin:0 0 var(--roxy-space-xs,.25rem) 0}.aspect-card{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);margin-bottom:var(--roxy-space-xs,.25rem)}.aspect-card summary{cursor:pointer;color:var(--roxy-fg,#0a0a0a);flex-wrap:wrap;align-items:center;gap:.5em;font-weight:500;display:flex}.aspect-card summary .meta{color:var(--roxy-muted,#71717a);font-weight:400;font-size:var(--roxy-text-xs,.75rem);font-variant-numeric:tabular-nums;margin-left:auto}.interp-body{margin-top:var(--roxy-space-xs,.25rem);color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);line-height:1.45}.interp-body p{margin:0 0 var(--roxy-space-xs,.25rem)}.interp-keywords{flex-wrap:wrap;gap:.25rem;margin-top:.5rem;display:flex}.kw{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 14%, transparent);color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-xs,.75rem);border-radius:9999px;padding:1px 8px}.glyph{font-size:1.1em;line-height:1}.nature-badge{font-size:var(--roxy-text-xs,.75rem);text-transform:capitalize;border-radius:9999px;padding:1px 8px;font-weight:600;display:inline-block}.nature-badge.harmonious{background:color-mix(in srgb, var(--roxy-success,#16a34a) 12%, transparent);color:var(--roxy-success-fg,#166534)}.nature-badge.challenging{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 12%, transparent);color:var(--roxy-danger-fg,#991b1b)}.nature-badge.neutral{background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 60%, transparent);color:var(--roxy-fg,#0a0a0a)}.pattern{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);margin-bottom:var(--roxy-space-xs,.25rem);gap:.35rem;display:grid}.pattern-head{flex-wrap:wrap;align-items:baseline;gap:.5rem;display:flex}.pattern-name{font-weight:var(--roxy-weight-bold,600)}.pattern-planets{color:var(--roxy-accent-ink,#b45309);font-size:var(--roxy-text-sm,.875rem)}.pattern-tight{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);font-variant-numeric:tabular-nums;margin-left:auto}.pattern-interp{color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);margin:0;line-height:1.45}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No aspect data</div>`;\n\t}\n\n\tprotected renderData(d: AspectsData) {\n\t\tconst aspects = 'aspects' in d ? (d.aspects ?? []) : [];\n\t\tconst patterns = 'patterns' in d ? (d.patterns ?? []) : [];\n\t\tconst summary = 'summary' in d ? d.summary : undefined;\n\t\tif (aspects.length === 0 && patterns.length === 0)\n\t\t\treturn this.renderEmpty();\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Aspects\"><div class=\"head\"><h2 class=\"title\">Aspects</h2>${aspects.length > 0 ? html`<p class=\"subtitle\">${aspects.length} aspects</p>` : nothing}</div>${summary ? this.renderSummary(summary) : nothing} ${\n\t\t\t\taspects.length > 0\n\t\t\t\t\t? html`<div role=\"list\" aria-label=\"Aspect list\">${aspects.map((a, i) => this.renderAspect(a, i))}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tpatterns.length > 0\n\t\t\t\t\t? html`<div><p class=\"section-label\">Patterns</p>${patterns.map((p) => this.renderPattern(p))}</div>`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n\n\tprivate renderSummary(\n\t\ts:\n\t\t\t| NonNullable<CalculateAspectsResponse['summary']>\n\t\t\t| NonNullable<CalculateTransitAspectsResponse['summary']>,\n\t) {\n\t\tconst total = 'totalAspects' in s ? s.totalAspects : s.total;\n\t\treturn html`<div class=\"summary-pills\" role=\"region\" aria-label=\"Aspect summary\">${typeof total === 'number' ? html`<span class=\"pill pill--muted\">Total: ${total}</span>` : nothing} <span class=\"pill pill--success\">Harmonious: ${s.harmonious}</span> <span class=\"pill pill--danger\">Challenging: ${s.challenging}</span> <span class=\"pill pill--muted\">Neutral: ${s.neutral}</span></div>`;\n\t}\n\n\tprivate renderAspect(\n\t\ta:\n\t\t\t| NonNullable<CalculateAspectsResponse['aspects']>[number]\n\t\t\t| NonNullable<CalculateTransitAspectsResponse['aspects']>[number],\n\t\tidx: number,\n\t) {\n\t\tconst g1 = PLANET_GLYPH[capitalize(a.planet1)] ?? '';\n\t\tconst g2 = PLANET_GLYPH[capitalize(a.planet2)] ?? '';\n\t\tconst nature = (a.interpretation ?? 'neutral').toLowerCase();\n\t\tconst type = (a.type ?? '').toLowerCase().replace(/_/g, ' ');\n\t\tconst status = a.isApplying ? 'Applying' : 'Separating';\n\t\t// Natal aspects carry `meaning` (static aspect lore); transits carry `transitInterpretation` (timed guidance).\n\t\tconst meaning = 'meaning' in a ? a.meaning : undefined;\n\t\tconst transit =\n\t\t\t'transitInterpretation' in a ? a.transitInterpretation : undefined;\n\t\tconst hasBody = Boolean(meaning || transit);\n\t\tconst header = html`<span aria-hidden=\"true\" class=\"glyph\">${g1}</span>${a.planet1} <span class=\"nature-badge ${nature}\">${type}</span> <span aria-hidden=\"true\" class=\"glyph\">${g2}</span>${a.planet2} <span class=\"meta\">${status} \u00B7 orb ${formatNumber(a.orb, 2)}\u00B0 \u00B7 str ${formatNumber(a.strength, 0)}</span>`;\n\t\tif (!hasBody) {\n\t\t\treturn html`<div class=\"aspect-card\" role=\"listitem\"><div class=\"summary\" style=\"cursor:default\">${header}</div></div>`;\n\t\t}\n\t\treturn html`<details class=\"aspect-card\" role=\"listitem\" name=\"aspects\" ?open=\"${idx === 0}\"><summary>${header}${chevron()}</summary><div class=\"interp-body\">${meaning ? this.renderMeaning(meaning) : nothing} ${transit ? this.renderTransit(transit) : nothing}</div></details>`;\n\t}\n\n\tprivate renderMeaning(\n\t\tm: NonNullable<\n\t\t\tNonNullable<CalculateAspectsResponse['aspects']>[number]['meaning']\n\t\t>,\n\t) {\n\t\tconst text = m.description?.short ?? m.description?.long;\n\t\treturn html`${text ? html`<p>${text}</p>` : nothing} ${\n\t\t\t\tm.keywords?.length\n\t\t\t\t\t? html`<div class=\"interp-keywords\">${m.keywords.map((k) => html`<span class=\"kw\">${k}</span>`)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t}`;\n\t}\n\n\tprivate renderTransit(\n\t\tt: NonNullable<\n\t\t\tNonNullable<\n\t\t\t\tCalculateTransitAspectsResponse['aspects']\n\t\t\t>[number]['transitInterpretation']\n\t\t>,\n\t) {\n\t\treturn html`${t.summary ? html`<p>${t.summary}</p>` : nothing} ${t.impact ? html`<p><strong>Impact:</strong> ${t.impact}</p>` : nothing} ${t.timing ? html`<p><strong>Timing:</strong> ${t.timing}</p>` : nothing} ${t.guidance ? html`<p><strong>Guidance:</strong> ${t.guidance}</p>` : nothing} ${\n\t\t\t\tt.keywords?.length\n\t\t\t\t\t? html`<div class=\"interp-keywords\">${t.keywords.map((k) => html`<span class=\"kw\">${k}</span>`)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t}`;\n\t}\n\n\tprivate renderPattern(\n\t\tp: NonNullable<DetectAspectPatternsResponse['patterns']>[number],\n\t) {\n\t\tconst planets = p.planets ?? [];\n\t\treturn html`<div class=\"pattern\"><div class=\"pattern-head\"><span class=\"pattern-name\">${p.name ?? p.kind ?? 'Pattern'}</span> ${planets.length ? html`<span class=\"pattern-planets\">${planets.join(', ')}</span>` : nothing} ${typeof p.tightness === 'number' ? html`<span class=\"pattern-tight\">${formatNumber(p.tightness, 0)}% tight</span>` : nothing}</div>${p.interpretation ? html`<p class=\"pattern-interp\">${p.interpretation}</p>` : nothing}</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-aspects-table': RoxyAspectsTable;\n\t}\n}\n", "import type { TemplateResult } from 'lit';\nimport { css, html } from 'lit';\n\n/**\n * Disclosure chevron for `<details>`/`<summary>` accordions. Replaces the\n * browser default triangle with a thin chevron that rotates when the host\n * `<details>` opens. Render it inside the `<summary>` and pair with\n * {@link disclosureStyles}.\n */\nexport function chevron(): TemplateResult {\n\treturn html`<svg class=\"roxy-chevron\" viewBox=\"0 0 16 16\" width=\"14\" height=\"14\" aria-hidden=\"true\"><path d=\"M4 6l4 4 4-4\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>`;\n}\n\n/**\n * Shared `<details>` accordion styling: hides the native disclosure triangle\n * and rotates the {@link chevron} 180 degrees when the accordion is open.\n * Import into any component that renders disclosure accordions so the chevron\n * looks and behaves identically.\n */\nexport const disclosureStyles = css`summary{list-style:none}summary::-webkit-details-marker{display:none}.roxy-chevron{aspect-ratio:auto;width:14px;height:14px;color:var(--roxy-muted,#71717a);transition:transform var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,ease);flex-shrink:0}details[open]>summary .roxy-chevron{transform:rotate(180deg)}@media (prefers-reduced-motion:reduce){.roxy-chevron{transition:none}}`;\n", "/**\n * Display formatters for ISO timestamps and floats coming back from the API.\n * Every helper returns \"\" for nullish or unparseable input so it falls out of\n * template literals cleanly.\n */\n\nexport function formatTime(input: unknown): string {\n\tif (typeof input !== 'string' || input.length === 0) return '';\n\tif (/^\\d{4}-\\d{2}-\\d{2}$/.test(input)) return '';\n\tconst bareTime = /^\\d{2}:\\d{2}(:\\d{2})?$/.test(input);\n\tconst iso = bareTime ? `1970-01-01T${input}` : input;\n\tconst d = new Date(iso);\n\tif (Number.isNaN(d.getTime())) return input;\n\treturn d.toLocaleTimeString(undefined, {\n\t\thour: 'numeric',\n\t\tminute: '2-digit',\n\t\thour12: true,\n\t});\n}\n\nexport function formatDate(input: unknown): string {\n\tif (typeof input !== 'string' || input.length === 0) return '';\n\tconst d = new Date(\n\t\t/^\\d{4}-\\d{2}-\\d{2}$/.test(input) ? `${input}T00:00:00` : input,\n\t);\n\tif (Number.isNaN(d.getTime())) return input;\n\treturn d.toLocaleDateString(undefined, {\n\t\tmonth: 'short',\n\t\tday: 'numeric',\n\t\tyear: 'numeric',\n\t});\n}\n\nexport function formatTimeRange(\n\tt: { start?: string; end?: string } | undefined,\n): string {\n\tif (!t) return '';\n\tconst start = formatTime(t.start);\n\tconst end = formatTime(t.end);\n\tif (start && end) return `${start} - ${end}`;\n\treturn start || end || '';\n}\n\nexport function formatNumber(value: unknown, dp = 1): string {\n\tif (typeof value !== 'number' || !Number.isFinite(value)) return '';\n\treturn value.toFixed(dp).replace(/\\.?0+$/, '');\n}\n\nexport function formatPercent(value: unknown, dp = 1): string {\n\tconst n = formatNumber(value, dp);\n\treturn n ? `${n}%` : '';\n}\n\n/**\n * CSS class name per aspect type. Used by natal and synastry chart aspect\n * lines so the same color encoding (harmonious vs challenging) applies in\n * both wheels. Keys are lowercase canonical names, values are CSS class\n * suffixes the chart components define in their `:host` styles.\n */\nexport const ASPECT_CLASS: Record<string, string> = {\n\tconjunction: 'aspect-conjunction',\n\tsextile: 'aspect-sextile',\n\tsquare: 'aspect-square',\n\ttrine: 'aspect-trine',\n\topposition: 'aspect-opposition',\n};\n\n/**\n * Normalize the `type` field on an aspect entry to a lowercase, hyphen-separated\n * canonical name (`SEMI_SEXTILE` \u2192 `semi-sextile`). Accepts any aspect-shaped\n * object so both natal and synastry inter-aspect entries can share this.\n */\nexport function normalizeAspect(a: { type?: string }): string {\n\treturn (a.type ?? '').toLowerCase().replace(/_/g, '-');\n}\n", "/**\n * Shared string helpers used across components. Single source of truth so the\n * same formatting rules apply to every key/label/title that surfaces in the\n * shadow tree.\n *\n * - `capitalize`: title-cases the first character, lowercases the rest. Used\n * when matching API-supplied planet/sign names against the glyph maps in\n * `tokens/index.ts`, which use canonical TitleCase keys.\n * - `humanize`: turns an API key (`birth_date`, `birthDate`, `mahadasha-end`)\n * into a label suitable for display (\"Birth date\", \"Mahadasha end\").\n */\n\nexport function capitalize(s: string): string {\n\tif (!s) return '';\n\treturn s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();\n}\n\nexport function humanize(s: string): string {\n\treturn s\n\t\t.replace(/[_-]+/g, ' ')\n\t\t.replace(/([a-z])([A-Z])/g, '$1 $2')\n\t\t.replace(/^\\w/, (c) => c.toUpperCase());\n}\n", "import { css, html, nothing, svg } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { AstrocartographyResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { chevron, disclosureStyles } from '../utils/disclosure.js';\nimport { planetColor } from '../utils/planet-color.js';\nimport { WORLD_LAND_PATH } from '../utils/world-map.js';\n\ntype LineSet = AstrocartographyResponse['lines'][number];\ntype GeoPoint = LineSet['ascendant']['points'][number];\n\n// Equirectangular (plate carree) projection in a 360x180 unit canvas: one unit\n// per degree. The SVG scales to the container width; the 2:1 aspect ratio holds.\nconst W = 360;\nconst H = 180;\nconst lonToX = (lon: number): number => lon + 180;\nconst latToY = (lat: number): number => 90 - lat;\n\n// Reference parallels (degrees). Tropics and polar circles use the current mean\n// obliquity; drawn as dashed guides so the curved rising/setting lines read\n// against real climate bands, not just a bare grid.\nconst TROPIC = 23.44;\nconst POLAR = 66.56;\n\nconst formatLon = (lon: number): string =>\n\tlon === 0 ? '0' : `${Math.abs(lon)}\u00B0${lon > 0 ? 'E' : 'W'}`;\nconst formatLat = (lat: number): string =>\n\tlat === 0 ? '0' : `${Math.abs(lat)}\u00B0${lat > 0 ? 'N' : 'S'}`;\n\n/**\n * Split a rising/setting line into screen polylines, breaking the path wherever\n * consecutive samples jump more than 180 degrees of longitude. Without the\n * split, a line that crosses the antimeridian draws a stray horizontal streak\n * straight across the whole map.\n */\nfunction toSegments(points: GeoPoint[]): string[] {\n\tconst segments: string[][] = [];\n\tlet current: string[] = [];\n\tlet prevLon: number | null = null;\n\tfor (const p of points) {\n\t\tif (prevLon !== null && Math.abs(p.longitude - prevLon) > 180) {\n\t\t\tif (current.length) segments.push(current);\n\t\t\tcurrent = [];\n\t\t}\n\t\tcurrent.push(`${lonToX(p.longitude)},${latToY(p.latitude)}`);\n\t\tprevLon = p.longitude;\n\t}\n\tif (current.length) segments.push(current);\n\treturn segments.filter((s) => s.length > 1).map((s) => s.join(' '));\n}\n\nconst ANGLE_LABEL: Record<string, string> = {\n\tmc: 'MC',\n\tic: 'IC',\n\tascendant: 'AC',\n\tdescendant: 'DC',\n};\n\n/**\n * Astrocartography (relocation) world map. Plots the four planetary lines for\n * every body from a /astrology/astrocartography response over a labeled\n * graticule: MC and IC as straight meridians, the Ascendant and Descendant as\n * latitude-sampled curves. Color is per body and theme-token driven; solid\n * lines are the Ascendant and Midheaven, dashed are the Descendant and IC.\n */\n@customElement('roxy-astrocartography-map')\nexport class RoxyAstrocartographyMap extends RoxyDataElement<AstrocartographyResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tdisclosureStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);width:100%;color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-primary,#0f172a);margin:0}.meta{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}svg{border-radius:var(--roxy-radius-sm,4px);width:100%;height:auto;display:block}.map-frame{fill:color-mix(in srgb, var(--roxy-border,#e4e4e7) 12%, transparent);stroke:var(--roxy-border,#e4e4e7);stroke-width:.8px}.land{fill:var(--roxy-secondary,#475569);opacity:.13}.grat{stroke:var(--roxy-border,#e4e4e7);stroke-width:.4px;fill:none}.grat-axis{stroke:var(--roxy-muted,#71717a);stroke-width:.6px;opacity:.6}.grat-ref{stroke:var(--roxy-secondary,#475569);stroke-width:.4px;stroke-dasharray:2 2;opacity:.5;fill:none}.axis-label{fill:var(--roxy-muted,#71717a);font-size:5px;font-family:var(--roxy-font-sans)}.acg-line{fill:none;stroke-width:1px;opacity:.95}.acg-line.dashed{stroke-dasharray:4 2.5}.acg-glyph{font-size:8px;font-family:var(--roxy-font-sans);font-weight:600}.birthplace{fill:var(--roxy-fg,#0a0a0a);font-size:9px}.legend{gap:var(--roxy-space-xs,.25rem) var(--roxy-space-md,1rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);flex-wrap:wrap;display:flex}.legend-item{align-items:center;gap:.3rem;display:inline-flex}.legend-swatch{border-top-style:solid;border-top-width:2px;width:14px;height:0}.legend-note{width:100%;color:var(--roxy-muted,#71717a)}.summary{color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);margin:0}.interpretations h3{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;margin:0 0 var(--roxy-space-sm,.5rem);font-weight:600}.interp-card{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);margin-bottom:var(--roxy-space-xs,.25rem)}.interp-card summary{cursor:pointer;color:var(--roxy-fg,#0a0a0a);justify-content:space-between;align-items:center;gap:var(--roxy-space-md,1rem);font-weight:500;display:flex}.interp-head{align-items:center;gap:.5rem;display:inline-flex}.interp-dot{border-radius:50%;width:10px;height:10px}.interp-body{margin-top:var(--roxy-space-sm,.5rem);gap:var(--roxy-space-xs,.25rem);display:grid}.interp-line{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a)}.interp-line .code{color:var(--roxy-accent-ink,#b45309);margin-right:.4rem;font-weight:600}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No astrocartography data</div>`;\n\t}\n\n\tprotected renderData(data: AstrocartographyResponse) {\n\t\tconst lines = data.lines ?? [];\n\t\tconst bd = data.birthDetails;\n\t\treturn html`<div class=\"wrap\"><header><h2 class=\"title\">Astrocartography</h2>${\n\t\t\t\t\tbd\n\t\t\t\t\t\t? html`<div class=\"meta\">${[bd.date, bd.time].filter(Boolean).join(' \u00B7 ')} \u00B7 ${formatLat(Math.round(bd.latitude))} ${formatLon(Math.round(bd.longitude))}</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</header>${this.renderMap(lines, bd)} ${this.renderLegend(lines)} ${data.summary ? html`<p class=\"summary\">${data.summary}</p>` : nothing} ${this.renderInterpretations(lines)}</div>`;\n\t}\n\n\tprivate renderMap(\n\t\tlines: LineSet[],\n\t\tbd: AstrocartographyResponse['birthDetails'],\n\t) {\n\t\treturn html`<svg viewBox=\"0 0 ${W} ${H}\" role=\"img\" aria-label=\"World map of planetary astrocartography lines\"><title>Astrocartography world map</title><desc>Equirectangular world map. Each body has a Midheaven and Imum Coeli meridian and a curved Ascendant and Descendant line, colored per body.</desc><rect class=\"map-frame\" x=\"0\" y=\"0\" width=\"${W}\" height=\"${H}\"/><path class=\"land\" d=\"${WORLD_LAND_PATH}\" fill-rule=\"evenodd\"/>${this.renderGraticule()} ${lines.map((l, i) => this.renderBodyLines(l, i))} ${\n\t\t\t\tbd\n\t\t\t\t\t? svg`<text class=\"birthplace\" x=${lonToX(bd.longitude)} y=${latToY(bd.latitude)} text-anchor=\"middle\" dominant-baseline=\"central\"><title>Birthplace</title>\u2605</text>`\n\t\t\t\t\t: nothing\n\t\t\t}</svg>`;\n\t}\n\n\tprivate renderGraticule() {\n\t\tconst meridians = [];\n\t\tfor (let lon = -150; lon <= 150; lon += 30) {\n\t\t\tconst x = lonToX(lon);\n\t\t\tconst axis = lon === 0;\n\t\t\tmeridians.push(\n\t\t\t\tsvg`<line class=${axis ? 'grat-axis' : 'grat'} x1=${x} y1=\"0\" x2=${x} y2=${H} />`,\n\t\t\t);\n\t\t\tmeridians.push(\n\t\t\t\tsvg`<text class=\"axis-label\" x=${x} y=${H - 2} text-anchor=\"middle\">${formatLon(lon)}</text>`,\n\t\t\t);\n\t\t}\n\t\tconst parallels = [];\n\t\tfor (let lat = -60; lat <= 60; lat += 30) {\n\t\t\tconst y = latToY(lat);\n\t\t\tconst axis = lat === 0;\n\t\t\tparallels.push(\n\t\t\t\tsvg`<line class=${axis ? 'grat-axis' : 'grat'} x1=\"0\" y1=${y} x2=${W} y2=${y} />`,\n\t\t\t);\n\t\t\tparallels.push(\n\t\t\t\tsvg`<text class=\"axis-label\" x=\"2\" y=${y - 1}>${formatLat(lat)}</text>`,\n\t\t\t);\n\t\t}\n\t\t// Tropics and polar circles as dashed climate-band references.\n\t\tconst refs = [TROPIC, -TROPIC, POLAR, -POLAR].map(\n\t\t\t(lat) =>\n\t\t\t\tsvg`<line class=\"grat-ref\" x1=\"0\" y1=${latToY(lat)} x2=${W} y2=${latToY(lat)} />`,\n\t\t);\n\t\treturn svg`${meridians}${parallels}${refs}`;\n\t}\n\n\tprivate renderBodyLines(line: LineSet, index: number) {\n\t\tconst color = planetColor(line.planet, index);\n\t\tconst glyph = line.symbol || line.planet.slice(0, 2);\n\t\tconst items = [\n\t\t\tthis.renderMeridian(\n\t\t\t\tline.mc.longitude,\n\t\t\t\tcolor,\n\t\t\t\tglyph,\n\t\t\t\tline.planet,\n\t\t\t\t'mc',\n\t\t\t\tfalse,\n\t\t\t),\n\t\t\tthis.renderMeridian(\n\t\t\t\tline.ic.longitude,\n\t\t\t\tcolor,\n\t\t\t\tglyph,\n\t\t\t\tline.planet,\n\t\t\t\t'ic',\n\t\t\t\ttrue,\n\t\t\t),\n\t\t\tthis.renderCurve(\n\t\t\t\tline.ascendant.points,\n\t\t\t\tcolor,\n\t\t\t\tglyph,\n\t\t\t\tline.planet,\n\t\t\t\t'ascendant',\n\t\t\t\tfalse,\n\t\t\t),\n\t\t\tthis.renderCurve(\n\t\t\t\tline.descendant.points,\n\t\t\t\tcolor,\n\t\t\t\tglyph,\n\t\t\t\tline.planet,\n\t\t\t\t'descendant',\n\t\t\t\ttrue,\n\t\t\t),\n\t\t];\n\t\treturn svg`${items}`;\n\t}\n\n\tprivate renderMeridian(\n\t\tlon: number,\n\t\tcolor: string,\n\t\tglyph: string,\n\t\tplanet: string,\n\t\tangle: string,\n\t\tdashed: boolean,\n\t) {\n\t\tconst x = lonToX(lon);\n\t\t// MC label rides the top edge, IC the bottom, so the two meridians of one\n\t\t// body never stack their glyphs at the same point.\n\t\tconst labelY = angle === 'ic' ? H - 7 : 9;\n\t\treturn svg`<g>\n\t\t\t<line class=${`acg-line${dashed ? ' dashed' : ''}`} stroke=${color} x1=${x} y1=\"0\" x2=${x} y2=${H}><title>${planet} ${ANGLE_LABEL[angle]} line</title></line>\n\t\t\t<text class=\"acg-glyph\" fill=${color} x=${x} y=${labelY} text-anchor=\"middle\" dominant-baseline=\"central\">${glyph}</text>\n\t\t</g>`;\n\t}\n\n\tprivate renderCurve(\n\t\tpoints: GeoPoint[],\n\t\tcolor: string,\n\t\tglyph: string,\n\t\tplanet: string,\n\t\tangle: string,\n\t\tdashed: boolean,\n\t) {\n\t\tconst segments = toSegments(points ?? []);\n\t\tif (segments.length === 0) return nothing;\n\t\t// Label at the sample nearest the equator, the most visible band.\n\t\tconst anchor = (points ?? []).reduce(\n\t\t\t(best, p) => (Math.abs(p.latitude) < Math.abs(best.latitude) ? p : best),\n\t\t\tpoints[0] ?? { latitude: 0, longitude: 0 },\n\t\t);\n\t\treturn svg`<g>\n\t\t\t${segments.map(\n\t\t\t\t(pts) =>\n\t\t\t\t\tsvg`<polyline class=${`acg-line${dashed ? ' dashed' : ''}`} stroke=${color} points=${pts}><title>${planet} ${ANGLE_LABEL[angle]} line</title></polyline>`,\n\t\t\t)}\n\t\t\t<text class=\"acg-glyph\" fill=${color} x=${lonToX(anchor.longitude)} y=${latToY(anchor.latitude)} text-anchor=\"middle\" dominant-baseline=\"central\">${glyph}</text>\n\t\t</g>`;\n\t}\n\n\tprivate renderLegend(lines: LineSet[]) {\n\t\tif (lines.length === 0) return nothing;\n\t\treturn html`<div class=\"legend\">${lines.map((l, i) => {\n\t\t\t\tconst color = planetColor(l.planet, i);\n\t\t\t\treturn html`<span class=\"legend-item\"><span class=\"legend-swatch\" style=\"${`border-top-color: ${color}`}\"></span> ${l.symbol ? html`${l.symbol}` : nothing}${l.planet}</span>`;\n\t\t\t})} <span class=\"legend-note\">Solid lines are the Ascendant and Midheaven, dashed are the Descendant and IC.</span></div>`;\n\t}\n\n\tprivate renderInterpretations(lines: LineSet[]) {\n\t\tif (lines.length === 0) return nothing;\n\t\treturn html`<section class=\"interpretations\"><h3>Planetary lines</h3>${lines.map((l, i) => {\n\t\t\t\tconst color = planetColor(l.planet, i);\n\t\t\t\tconst rows: Array<[string, string]> = [\n\t\t\t\t\t['MC', l.mc.interpretation],\n\t\t\t\t\t['IC', l.ic.interpretation],\n\t\t\t\t\t['AC', l.ascendant.interpretation],\n\t\t\t\t\t['DC', l.descendant.interpretation],\n\t\t\t\t];\n\t\t\t\treturn html`<details class=\"interp-card\" name=\"acg-lines\" ?open=\"${i === 0}\"><summary><span class=\"interp-head\"><span class=\"interp-dot\" style=\"${`background: ${color}`}\"></span> ${l.symbol ? html`${l.symbol}` : nothing}${l.planet} </span>${chevron()}</summary><div class=\"interp-body\">${rows\n\t\t\t\t\t\t\t.filter(([, text]) => text)\n\t\t\t\t\t\t\t.map(\n\t\t\t\t\t\t\t\t([code, text]) =>\n\t\t\t\t\t\t\t\t\thtml`<p class=\"interp-line\"><span class=\"code\">${code}</span>${text}</p>`,\n\t\t\t\t\t\t\t)}</div></details>`;\n\t\t\t})}</section>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-astrocartography-map': RoxyAstrocartographyMap;\n\t}\n}\n", "import { capitalize } from './string.js';\n\n/**\n * Stable, theme-token stroke color per celestial body, for the multi-line map components (astrocartography, local space) where every body needs a distinct line that still follows the host theme.\n *\n * @remarks\n * Values are `var(--roxy-*)` references, so light and dark both resolve through the design tokens and a host override repaints every line with no rebuild. Classical bodies map to a fixed semantic token; any body the map omits (localized names, asteroids, the lunar nodes, Chiron, Lilith) falls back to a deterministic cycle keyed by its index in the response, so colors stay stable across re-renders and do not collide within the common 14-body set. Strokes and glyph fills are non-text chart marks, so the brighter base tokens are used directly rather than the WCAG-AA text variants.\n */\nconst PLANET_COLOR: Record<string, string> = {\n\tSun: 'var(--roxy-accent)',\n\tMoon: 'var(--roxy-secondary)',\n\tMercury: 'var(--roxy-info)',\n\tVenus: 'var(--roxy-success)',\n\tMars: 'var(--roxy-danger)',\n\tJupiter: 'var(--roxy-warning)',\n\tSaturn: 'var(--roxy-muted)',\n\tUranus: 'var(--roxy-info-fg)',\n\tNeptune: 'var(--roxy-success-fg)',\n\tPluto: 'var(--roxy-danger-fg)',\n};\n\n/** Deterministic fallback palette for bodies outside {@link PLANET_COLOR} (nodes, Chiron, Lilith, asteroids, or localized names). Keyed by response index so a given body keeps one color. */\nconst CYCLE = [\n\t'var(--roxy-accent)',\n\t'var(--roxy-info)',\n\t'var(--roxy-success)',\n\t'var(--roxy-danger)',\n\t'var(--roxy-warning)',\n\t'var(--roxy-secondary)',\n\t'var(--roxy-info-fg)',\n\t'var(--roxy-success-fg)',\n\t'var(--roxy-danger-fg)',\n\t'var(--roxy-accent-ink)',\n\t'var(--roxy-warning-fg)',\n\t'var(--roxy-primary)',\n];\n\n/** Theme-token color for a body, by name with an index fallback. {@link capitalize} matches the canonical TitleCase keys; unmapped or localized names cycle by `index`. */\nexport function planetColor(name: string, index = 0): string {\n\treturn (\n\t\tPLANET_COLOR[capitalize(name)] ??\n\t\tCYCLE[index % CYCLE.length] ??\n\t\t'var(--roxy-accent)'\n\t);\n}\n", "/**\n * Simplified Natural Earth 110m land outline (public domain, no attribution required) projected into the astrocartography 360x180 plate-carree space: x = lon + 180, y = 90 - lat. It therefore aligns pixel for pixel with the graticule and the planetary lines drawn in that same space, with no nested-SVG transform.\n *\n * @remarks\n * Integer-degree precision and a tiny-island cull keep it light (about 9 KB gzipped) so it ships inside the per-component bundle as a faint background fill; the colored lines stay the focus. Use `fill-rule: evenodd` so inland holes render. Regenerate from `ne_110m_land.geojson` if the projection or precision changes.\n */\nexport const WORLD_LAND_PATH =\n\t'M120 170L120 171L118 171L116 171L114 171L114 170L116 170L118 170L119 170L120 170ZM21 169L19 170L18 169L17 169L16 169L17 168L19 168L20 169L21 169ZM135 168L136 168L137 169L137 170L135 170L133 171L132 171L130 171L127 171L126 171L126 170L128 170L129 170L130 169L131 168L132 168L133 168L135 168ZM59 164L60 164L61 163L61 164L60 164L58 164L57 164L58 163L59 164ZM54 163L56 164L55 164L54 164L53 163L54 163ZM81 162L82 162L83 162L84 163L83 162L82 162L81 162L79 163L78 162L80 162L81 162ZM112 161L111 162L110 162L109 163L108 162L107 162L106 162L105 162L106 161L107 161L108 161L108 160L109 159L110 159L111 160L111 161L112 161ZM121 154L120 154L119 154L119 155L118 155L117 155L117 156L118 156L117 156L116 157L115 157L114 158L115 158L115 159L116 159L117 159L117 160L118 160L118 161L119 162L119 163L119 164L118 164L117 165L116 165L114 166L113 166L112 166L110 166L109 167L108 167L106 167L104 167L103 167L105 167L106 168L105 168L104 168L102 168L102 169L103 170L105 170L107 170L109 171L110 171L112 171L114 171L117 172L118 172L120 172L121 173L122 173L123 173L125 173L126 172L128 172L130 172L133 172L135 172L137 172L138 172L139 171L142 171L144 171L146 171L148 171L150 171L151 170L150 170L150 169L148 169L146 169L144 169L144 168L145 168L146 168L148 168L149 167L150 167L151 167L152 166L154 166L155 166L156 166L158 166L159 166L160 166L161 165L162 165L163 165L164 164L165 164L164 164L164 163L165 163L166 163L167 163L168 162L169 162L170 161L171 161L171 162L173 162L173 161L174 161L176 161L177 161L178 161L179 161L180 162L181 161L182 161L183 161L184 161L185 161L186 160L187 160L188 160L190 160L191 161L192 161L192 160L193 160L195 160L196 160L197 160L198 160L199 160L200 160L201 160L202 160L203 161L204 161L205 160L206 160L207 160L208 160L209 160L210 160L211 160L212 160L213 159L214 159L215 159L216 159L217 159L218 160L219 160L220 160L220 159L221 159L222 159L223 158L224 158L225 158L226 158L227 158L228 157L229 157L230 157L231 157L232 156L233 156L234 156L235 156L236 156L237 156L237 157L238 157L239 157L240 157L241 158L242 158L243 158L244 157L245 158L246 158L247 158L248 158L249 158L250 159L250 160L249 160L248 160L248 161L249 161L248 161L248 162L249 162L250 162L251 162L252 162L252 161L253 161L253 160L254 160L256 160L257 160L258 159L259 158L260 158L261 158L262 157L263 157L264 157L265 157L266 157L267 157L268 156L269 157L270 157L271 157L272 157L273 157L274 157L275 157L276 157L277 157L278 157L279 157L280 157L281 157L282 156L283 156L284 156L285 156L286 157L287 157L288 157L289 157L290 157L291 156L292 156L293 156L294 156L295 156L296 157L297 157L299 157L300 157L301 157L302 157L303 156L304 157L305 157L306 157L307 157L308 157L309 157L310 157L311 156L312 156L313 156L314 156L315 156L315 155L316 156L317 157L319 157L320 157L321 157L322 157L323 157L324 157L325 157L326 157L326 158L327 158L328 158L329 158L330 159L331 159L333 159L334 159L335 159L336 159L337 159L338 159L339 160L340 160L341 160L342 161L343 161L344 161L345 161L346 161L347 161L348 161L349 161L351 161L351 162L350 163L349 164L348 164L347 164L346 164L346 165L345 165L344 165L344 166L343 167L344 167L344 168L345 168L347 168L347 169L345 169L344 169L342 169L341 170L340 171L341 171L342 172L344 172L345 173L347 173L349 173L349 174L352 174L353 174L356 174L358 174L360 175L360 180L0 180L0 175L1 174L3 174L4 174L6 175L7 174L10 174L11 174L13 175L16 175L18 175L22 175L25 175L29 175L31 176L34 175L37 175L33 175L30 174L29 174L26 174L27 173L27 172L25 172L25 171L23 171L26 171L28 171L29 171L31 171L33 171L34 170L33 170L32 170L30 169L28 169L27 169L25 169L24 169L23 168L22 168L22 167L23 167L25 167L26 167L27 167L29 167L30 167L31 167L32 167L34 166L34 165L35 165L36 166L37 165L38 165L40 165L41 165L42 165L44 165L45 164L46 164L48 164L49 164L50 164L52 164L53 164L55 165L56 164L57 164L59 165L60 164L61 164L63 164L64 164L65 164L66 164L67 164L68 165L69 164L70 165L71 165L72 165L74 165L75 165L77 165L78 165L79 165L80 165L79 165L79 164L77 164L77 163L76 163L77 163L78 163L80 163L81 163L82 163L82 164L84 164L85 163L86 163L88 163L89 163L90 163L91 163L92 163L93 163L94 163L95 163L96 164L97 164L99 164L99 163L100 163L101 164L102 163L103 164L104 164L105 164L106 164L107 163L108 163L110 163L111 163L112 163L113 162L112 161L112 160L111 160L112 159L113 158L112 158L112 157L113 157L114 156L115 156L116 155L117 155L118 155L119 154L120 154L121 154L121 153L122 153L123 154L122 154L121 154ZM112 144L114 144L115 145L114 145L113 145L112 146L111 145L110 145L109 145L108 144L107 144L105 143L106 143L108 144L109 144L110 143L111 143L112 143L112 144ZM121 141L122 142L121 142L120 142L119 142L120 141L121 142L121 141ZM250 140L249 140L249 139L250 139L251 139L250 140ZM325 131L326 131L327 131L328 131L328 132L328 133L327 134L326 134L325 133L325 132L325 131ZM353 131L354 131L354 132L353 133L353 134L352 134L351 134L351 135L351 136L350 136L349 137L348 137L348 136L347 136L347 135L348 134L349 134L350 134L351 133L352 132L352 131L353 130L353 131ZM355 126L355 127L356 127L356 128L357 128L358 128L359 128L358 129L357 129L357 130L357 131L356 131L355 132L355 131L355 130L354 130L354 129L355 129L355 128L355 127L354 127L354 126L353 125L353 124L354 125L355 126ZM347 112L346 112L345 112L345 111L344 110L345 110L345 111L346 111L347 112ZM358 107L359 108L358 108L357 108L358 107L358 108L358 107ZM359 107L359 106L360 106L360 107L359 107ZM230 104L230 105L230 106L230 105L230 106L230 107L229 107L229 108L229 109L229 110L228 112L228 114L227 115L226 115L225 116L225 115L224 115L224 114L223 113L223 112L223 111L224 111L224 110L224 109L224 108L224 107L224 106L225 106L226 106L227 105L228 105L228 104L229 103L229 102L230 102L230 103L230 104ZM324 104L324 105L325 104L325 105L325 106L326 107L326 108L326 109L327 109L328 110L329 110L329 111L330 112L330 113L331 112L331 113L332 114L333 115L333 116L333 117L334 118L334 119L333 119L333 120L333 121L333 122L332 123L331 124L331 125L330 126L330 127L329 128L328 128L327 128L327 129L326 129L325 129L325 128L324 128L324 129L323 129L322 128L321 128L320 127L320 126L319 126L318 126L318 125L318 124L318 125L317 125L318 124L318 123L317 124L316 124L316 125L315 124L315 123L314 123L313 122L312 122L311 121L310 122L308 122L307 122L306 122L305 123L304 123L304 124L303 124L302 124L301 124L300 124L299 125L299 124L299 125L298 125L297 125L296 124L295 124L296 123L296 122L295 121L295 120L295 119L294 118L294 117L293 117L293 116L294 117L293 116L294 116L294 115L293 114L294 114L294 113L294 112L294 113L295 112L295 111L296 111L297 111L298 110L299 110L300 110L301 110L301 109L302 109L302 108L302 107L303 106L303 107L304 107L304 106L305 105L306 105L306 104L307 104L308 104L308 105L309 105L310 105L309 104L310 104L310 103L311 103L311 102L312 102L313 102L312 101L313 101L314 102L315 102L316 102L317 102L317 103L316 103L316 104L315 105L316 105L316 106L317 106L318 106L318 107L319 107L320 108L321 107L321 106L322 105L322 104L322 103L322 102L322 101L323 101L323 102L324 103L324 104ZM301 100L300 100L299 100L300 99L300 100L301 100ZM341 100L340 100L340 99L341 100ZM342 100L341 99L341 98L341 99L342 100ZM304 100L303 100L304 100L304 99L305 99L306 98L307 98L307 99L306 99L305 99L304 100ZM298 98L299 98L299 99L298 99L297 99L297 98L298 98ZM303 98L303 99L301 99L300 99L300 98L301 98L301 99L302 98L303 98ZM340 98L340 99L339 98L338 97L339 98L340 98ZM289 97L291 97L291 96L293 97L293 98L294 98L296 98L295 99L293 98L292 98L291 98L289 98L288 98L286 97L285 97L286 96L287 96L288 96L289 97ZM315 96L314 97L314 96L314 95L315 96ZM336 97L335 97L335 96L335 95L335 96L336 96L336 97ZM332 95L331 96L330 96L329 96L328 96L328 95L329 96L330 96L330 95L330 96L331 95L332 95L332 94L332 95ZM307 93L307 94L306 94L306 93L307 93ZM310 93L311 94L310 93L309 93L308 93L309 93L310 93ZM333 94L333 95L333 94L332 94L332 93L331 93L332 93L333 94ZM314 91L314 93L315 93L316 92L317 92L318 92L319 92L320 92L321 93L323 93L325 94L326 95L328 96L328 97L327 97L328 98L329 99L329 100L330 100L331 100L331 101L330 101L330 100L329 100L328 100L327 99L326 98L325 98L324 98L323 98L323 99L322 99L321 99L320 98L319 98L318 98L319 97L318 96L318 95L316 95L315 94L314 94L313 94L313 93L312 93L313 92L314 92L312 92L311 91L312 91L312 90L314 91ZM305 89L304 90L303 90L301 90L300 90L300 91L301 91L303 91L302 92L302 93L302 94L303 95L303 96L302 95L303 94L302 95L301 95L302 94L301 94L301 93L300 93L300 94L300 96L299 95L300 94L299 93L299 92L299 91L300 90L300 89L301 89L302 89L303 89L304 89L305 88L305 89ZM309 89L309 90L308 90L308 91L308 90L307 89L308 88L309 88L309 89ZM286 96L285 96L284 95L283 94L282 94L281 93L281 92L280 91L279 90L279 89L279 88L278 88L277 87L276 86L275 85L276 85L277 85L278 86L279 86L280 87L281 88L282 88L282 89L283 89L284 90L283 91L284 91L285 92L286 92L286 93L286 94L286 96ZM298 88L299 89L298 89L297 90L298 91L297 91L297 92L296 94L295 94L294 93L293 93L292 93L291 93L290 93L290 92L290 91L289 90L289 89L290 88L291 88L291 87L292 87L293 87L294 86L294 85L295 85L296 84L297 83L298 84L299 85L298 85L299 86L298 86L297 87L298 88ZM306 82L307 83L306 84L306 83L305 83L306 84L305 84L304 84L304 83L304 82L303 83L302 83L302 82L303 82L303 81L304 82L305 81L305 80L306 81L306 82ZM261 84L260 84L260 83L260 82L260 80L261 81L262 82L262 84L261 84ZM304 80L303 81L302 80L303 80L303 79L303 80L304 79L304 80ZM299 81L297 82L298 81L298 80L299 80L300 79L299 80L299 81ZM302 78L303 78L303 79L302 80L302 79L302 78ZM306 78L306 79L305 79L305 80L305 79L304 79L305 79L305 78L304 77L305 77L306 78ZM302 77L301 78L301 77L300 77L301 77L302 77ZM301 71L302 72L303 73L302 74L302 75L302 76L303 76L304 76L304 77L303 77L303 76L303 77L302 76L301 76L301 75L301 76L300 75L300 74L300 72L301 71ZM114 72L113 72L113 71L114 71L114 72ZM103 72L102 72L102 71L102 72L103 72L104 72L103 72ZM107 70L108 70L109 70L110 70L110 71L111 71L112 71L111 72L110 72L109 72L108 72L107 72L106 72L106 71L107 71L107 72L108 71L107 71L107 70ZM290 71L289 72L289 71L289 70L290 70L291 70L291 71L290 71ZM24 71L24 70L25 70L25 71L24 71ZM100 67L101 68L102 67L102 68L103 68L103 69L104 69L105 69L106 70L105 70L104 70L102 70L103 70L103 69L102 69L101 68L100 68L99 68L98 68L98 67L97 67L97 68L96 68L95 68L96 68L96 67L97 67L98 67L99 67L100 67ZM102 66L102 65L102 66ZM301 67L301 68L300 67L300 66L301 65L302 65L302 66L301 67ZM315 56L314 57L314 56L313 57L312 57L313 56L314 56L315 56ZM215 54L214 55L213 55L212 55L213 55L214 55L215 54ZM204 54L204 55L205 55L206 55L205 55L204 55L204 54ZM196 52L195 53L194 53L192 52L193 52L194 52L195 52L196 52ZM189 49L190 49L190 51L189 51L188 51L188 50L188 49L189 49ZM321 53L321 54L320 55L319 55L317 55L316 57L315 56L315 55L313 56L312 56L311 56L312 57L311 59L310 59L310 58L310 57L309 57L310 56L311 56L312 55L313 55L315 54L316 54L317 53L319 52L320 51L320 49L321 49L322 50L322 51L321 52L321 53ZM190 48L189 49L189 48L189 47L190 48ZM324 46L325 46L326 47L324 47L323 48L322 47L321 48L320 48L320 47L321 47L322 45L322 44L323 45L324 46ZM116 43L117 44L118 44L117 44L116 44L116 43ZM118 41L116 41L115 40L116 40L117 40L118 41ZM56 41L56 42L54 41L53 40L52 40L52 39L53 39L53 40L54 40L55 40L55 41L56 41ZM124 39L123 40L124 40L125 40L124 40L125 41L126 40L127 41L126 41L127 41L127 42L127 43L126 43L126 42L125 43L124 43L125 43L124 42L123 42L121 42L121 41L122 41L123 39L124 38L125 38L124 39ZM47 36L48 36L48 37L49 38L48 38L48 37L47 37L47 36ZM324 39L325 41L323 41L323 42L324 43L324 44L323 43L322 44L322 43L322 42L322 41L322 40L322 39L322 38L322 37L323 36L322 36L323 36L323 37L323 38L324 39ZM173 38L171 38L170 38L171 37L170 36L172 35L173 35L174 35L174 36L174 37L173 38ZM193 34L192 35L191 35L191 34L192 34L193 34ZM27 33L26 33L25 33L26 32L27 32L28 32L27 33ZM177 31L176 32L177 32L178 32L178 33L177 34L178 34L179 35L180 36L180 37L182 37L182 38L181 38L181 39L179 39L178 39L177 39L176 40L175 40L174 40L176 39L177 39L175 38L176 38L175 37L177 37L177 36L176 35L175 35L175 34L174 35L174 34L174 33L174 32L175 31L176 31L177 31ZM14 30L13 30L14 30ZM98 27L97 28L96 28L97 27L98 27ZM8 26L9 26L10 26L10 27L11 27L10 27L9 27L8 27L8 26ZM95 24L95 25L96 25L97 25L98 26L99 26L100 26L99 27L97 26L96 26L94 27L94 26L93 26L94 26L94 25L94 24L95 24ZM165 24L166 25L165 26L162 26L161 27L160 26L157 26L158 26L156 25L158 25L156 24L158 24L159 24L161 24L162 24L164 23L165 24ZM104 23L103 23L103 22L104 22L105 22L105 23L104 23ZM5 23L6 24L5 23L8 23L10 24L9 24L7 25L7 26L6 26L5 25L4 25L3 24L2 25L1 24L0 24L1 25L0 25L0 21L2 22L5 23ZM84 21L82 21L80 21L81 20L82 20L83 20L84 21ZM360 19L359 19L360 18L360 19ZM1 19L0 19L0 18L1 18L2 19L1 19ZM89 21L89 22L91 21L92 21L92 22L93 23L94 22L94 21L94 20L96 20L97 20L99 21L98 22L99 22L99 23L97 24L95 24L94 23L94 24L93 25L92 26L90 26L89 26L89 27L88 27L87 28L86 29L85 30L85 31L87 31L87 32L88 33L89 33L91 33L92 34L93 34L94 34L95 35L97 35L98 35L98 36L98 37L99 38L100 39L101 38L101 37L101 36L100 35L102 35L103 34L103 33L103 32L101 31L103 30L102 29L102 28L103 27L104 28L105 28L106 28L107 28L108 28L109 29L110 29L110 30L111 31L112 31L112 32L114 31L115 30L116 31L117 32L119 33L118 34L120 34L120 35L122 35L123 35L123 36L124 36L124 37L124 38L123 39L121 39L120 40L118 40L116 40L115 40L114 40L113 40L111 41L110 42L109 43L110 43L111 42L113 41L115 41L116 41L115 42L115 43L116 44L117 44L118 44L119 43L120 44L119 45L117 45L116 46L115 46L114 46L116 45L114 45L113 45L112 46L111 46L110 46L109 47L109 48L110 48L109 49L108 49L107 49L106 49L108 49L107 49L106 49L106 50L105 51L104 51L105 51L105 52L104 53L104 52L104 51L103 51L104 52L103 52L104 52L104 53L104 54L104 55L103 55L102 56L101 56L101 57L100 57L99 58L99 59L99 60L99 61L99 62L100 63L100 64L100 65L99 65L99 64L98 64L98 63L97 63L97 62L97 61L96 60L95 60L94 60L92 60L91 60L90 60L91 60L91 61L90 61L89 61L88 60L87 60L86 60L85 61L84 61L83 62L83 63L83 64L82 65L82 66L82 67L82 68L83 69L83 70L84 71L85 71L86 72L87 71L88 71L89 71L89 70L90 69L91 69L92 69L93 68L93 69L93 70L92 70L93 71L92 71L92 72L92 71L92 72L92 73L91 74L92 74L93 74L94 74L95 74L96 74L96 75L97 75L97 76L96 76L96 77L97 77L97 78L96 78L96 79L97 80L98 81L99 81L100 81L100 80L101 80L101 81L102 81L103 81L104 81L104 80L105 79L106 79L107 79L107 78L108 78L109 78L108 79L108 80L108 81L109 81L109 80L109 79L110 79L110 78L110 79L111 79L112 79L113 79L114 79L114 80L115 80L116 80L116 79L117 79L118 79L117 80L118 80L119 81L120 81L120 82L121 82L122 83L122 84L123 84L124 84L125 84L126 84L127 85L128 85L128 86L129 86L129 88L130 88L130 89L129 90L130 90L131 90L131 91L132 91L133 91L135 92L136 92L135 93L137 92L139 93L140 93L141 94L143 95L144 95L145 95L145 97L145 99L144 100L143 101L142 102L142 103L141 103L141 104L141 106L141 107L141 108L140 108L140 110L139 111L139 112L138 112L138 113L137 113L135 113L135 114L134 114L132 115L132 116L131 117L132 117L131 118L131 119L130 119L129 121L128 122L127 123L127 124L126 124L125 125L124 125L123 124L122 124L123 125L123 126L123 127L122 128L121 129L119 129L118 129L118 130L118 131L117 131L116 131L115 131L115 132L116 132L117 133L116 133L115 133L115 135L114 135L113 135L113 136L112 136L113 137L114 137L114 138L113 139L112 140L111 140L111 141L111 142L112 142L111 142L110 143L109 143L109 144L107 144L106 143L105 142L105 141L105 140L104 139L105 138L106 137L104 137L105 136L106 134L107 134L107 132L106 133L106 132L106 130L107 129L106 128L106 127L107 127L107 126L108 124L109 122L108 121L109 120L109 119L109 118L109 116L110 114L110 111L110 110L110 108L109 108L109 107L107 106L105 105L104 105L104 104L103 102L102 100L101 98L100 97L99 97L99 96L99 95L99 94L100 93L100 92L100 93L99 92L99 91L100 90L100 89L101 89L101 88L102 87L103 86L103 85L102 84L103 84L103 83L102 83L102 82L101 81L100 81L100 82L100 83L99 83L99 82L98 82L97 82L96 82L96 81L95 80L94 80L94 79L93 78L92 77L93 77L92 77L91 77L90 76L89 76L88 76L88 75L87 74L86 74L85 74L84 74L83 74L82 74L81 73L80 73L79 73L78 72L76 72L76 71L75 71L75 70L74 70L75 69L74 69L75 69L74 68L74 67L73 66L72 65L71 64L70 63L69 62L68 62L68 61L67 60L67 59L66 58L65 58L65 59L65 60L66 60L66 61L67 61L67 62L68 62L68 63L69 64L69 65L69 66L70 66L71 67L70 67L69 66L68 66L68 65L68 64L67 64L67 63L66 63L65 62L66 62L66 61L65 61L64 60L64 59L63 58L63 57L62 56L61 56L60 56L59 55L58 54L57 52L56 51L56 50L56 49L56 48L55 47L56 46L56 44L56 43L56 42L55 42L57 42L57 43L58 43L58 42L57 41L55 40L54 40L53 39L52 38L51 37L51 36L49 36L49 35L48 35L48 34L46 33L46 32L45 32L43 32L42 31L40 30L39 30L37 30L36 30L34 30L33 29L32 29L32 30L31 30L30 30L29 31L28 31L28 30L29 29L30 29L29 29L28 29L27 30L26 31L27 31L26 32L25 32L24 33L23 33L22 34L20 34L19 35L18 35L17 35L15 36L15 35L16 35L17 35L18 34L19 34L20 34L21 33L22 33L22 32L23 31L22 31L21 31L21 32L20 31L19 31L18 31L18 30L17 30L16 30L15 30L15 29L14 28L15 27L16 27L17 27L18 26L18 27L19 26L18 26L19 25L18 25L17 26L16 25L15 26L14 25L13 25L12 24L13 24L16 23L16 24L18 24L18 23L16 23L16 22L15 22L13 22L14 21L16 21L17 21L17 20L18 20L19 20L21 19L22 19L23 19L25 19L26 19L28 19L29 20L30 19L32 20L34 20L35 20L36 20L38 20L39 20L41 21L42 21L43 21L44 21L46 20L47 20L49 20L50 20L51 20L52 20L53 20L54 21L56 20L56 21L57 20L59 20L60 21L62 21L64 21L65 21L66 22L65 22L67 22L69 22L70 22L71 23L72 22L71 22L72 21L73 21L74 21L75 21L76 22L77 22L79 22L80 22L82 22L81 22L82 21L84 22L84 23L85 22L86 21L85 20L84 20L84 19L85 18L86 18L87 19L88 20L89 21ZM66 17L65 17L68 17L69 18L70 17L71 17L72 18L72 17L73 17L75 17L75 18L76 19L77 20L79 20L77 20L78 21L76 21L74 21L73 21L71 21L68 21L67 21L66 21L65 21L64 21L63 20L65 20L66 20L68 20L66 19L64 19L62 19L64 19L62 19L61 18L62 17L65 17L66 17ZM76 17L75 17L73 17L73 16L75 16L76 17ZM104 17L103 17L102 17L101 17L100 17L99 17L99 16L100 16L102 16L104 17ZM93 17L94 17L95 17L98 16L99 17L99 18L101 18L102 17L104 18L106 18L106 19L108 18L109 19L111 19L112 20L113 21L111 21L114 22L115 22L117 23L118 23L118 24L116 25L115 25L113 24L112 24L113 25L114 25L115 26L115 27L114 27L111 26L113 27L114 28L111 28L109 27L108 27L108 26L107 26L105 25L105 26L102 26L101 25L102 25L104 25L106 25L106 24L107 23L107 22L105 21L103 21L104 21L103 20L102 20L101 20L99 20L95 20L93 20L91 20L90 19L92 19L90 19L90 18L91 17L92 16L94 16L93 17ZM80 16L81 16L83 16L83 17L82 17L83 17L83 18L82 19L81 19L80 18L78 17L80 17L78 17L80 16ZM324 17L322 17L320 17L321 16L322 16L323 17L324 17ZM87 17L86 18L85 18L84 17L85 16L88 16L89 16L88 17L87 17ZM60 19L57 19L56 19L54 18L55 17L56 16L55 16L58 16L60 16L62 16L63 16L64 17L63 17L61 17L60 18L60 19ZM331 15L330 15L328 15L326 15L328 15L331 15ZM86 15L84 15L83 15L84 15L85 14L86 15ZM325 14L324 15L321 15L319 15L317 15L318 14L319 14L321 14L325 14ZM82 13L82 14L82 15L80 15L79 15L79 14L77 14L79 14L80 13L81 13L82 13ZM72 14L73 14L74 14L74 15L70 15L68 16L66 16L66 15L68 15L64 15L62 15L64 14L65 14L67 14L69 14L71 15L70 14L70 13L71 13L72 14ZM238 19L237 19L234 19L233 19L232 19L231 18L232 18L232 17L234 16L236 15L238 14L241 14L244 14L246 13L248 13L249 13L248 14L245 14L242 15L238 16L237 17L235 18L236 18L238 19ZM85 13L86 13L88 13L89 14L90 14L91 14L92 14L94 15L95 14L97 14L99 14L100 15L98 16L97 15L94 16L92 16L90 15L88 15L87 15L87 14L86 14L84 14L83 13L85 13ZM64 12L64 13L63 13L62 14L60 14L59 14L57 14L59 13L61 12L62 13L64 12ZM287 13L287 14L288 13L291 13L293 14L294 14L294 15L293 15L290 16L289 16L291 16L292 16L293 16L294 17L294 16L296 16L299 16L299 17L303 17L303 16L305 16L307 16L309 17L309 18L308 18L310 19L311 19L312 18L314 19L316 18L317 19L318 18L320 19L319 18L320 17L330 18L333 19L337 19L339 19L340 20L341 21L342 20L344 20L346 21L348 20L350 21L351 21L350 20L354 20L356 20L359 21L360 21L360 25L359 25L357 25L358 26L359 27L359 28L357 27L355 28L354 28L352 29L351 30L350 30L349 29L346 30L345 30L344 30L343 31L342 32L343 32L343 34L342 34L342 35L340 36L340 37L339 37L338 38L337 39L336 38L336 37L335 35L336 33L337 33L337 32L338 32L340 31L342 30L344 29L344 27L343 28L340 29L339 28L337 29L334 30L335 31L333 31L331 31L331 30L330 30L329 31L325 31L322 31L319 33L315 35L317 35L317 36L318 36L319 36L320 36L321 37L321 38L321 39L321 40L320 42L319 43L318 44L317 45L316 46L315 47L314 47L313 47L312 47L311 47L311 48L310 48L310 49L309 49L309 50L308 50L308 51L307 51L308 51L309 53L309 54L309 55L308 55L307 56L306 56L306 55L307 54L306 53L307 53L306 52L305 52L305 51L305 50L304 50L303 50L302 51L301 51L302 51L301 50L302 50L302 49L301 49L300 50L299 51L298 51L298 52L299 52L299 53L300 53L301 52L302 53L303 53L301 53L301 54L300 54L299 55L300 56L301 57L301 58L302 58L302 59L301 59L302 60L302 61L302 62L301 62L300 63L300 64L299 65L297 66L296 67L295 67L294 68L294 67L293 68L292 68L291 69L290 70L290 69L289 68L288 68L287 69L286 70L286 71L286 72L287 73L288 74L289 75L289 77L289 78L288 79L287 80L286 80L285 81L285 80L284 80L283 79L283 78L282 77L281 77L280 77L280 78L279 79L279 80L279 81L280 81L280 82L280 83L281 83L282 83L282 84L283 84L283 85L283 86L283 87L284 87L284 88L284 89L283 88L281 87L281 86L281 85L280 85L280 84L280 83L279 82L278 82L278 81L279 80L278 79L279 79L278 78L279 77L278 76L278 75L278 74L277 73L277 74L275 74L274 74L275 73L274 72L274 71L274 70L273 70L272 69L272 68L271 67L270 67L271 68L270 68L269 68L268 68L267 69L266 70L265 71L264 72L263 72L262 73L262 74L261 74L260 74L260 75L260 76L260 77L260 78L260 80L259 80L259 81L258 81L258 82L257 81L256 80L256 79L255 78L255 77L255 76L254 75L254 74L253 72L253 71L253 70L253 69L251 69L250 69L249 68L250 68L249 67L248 66L247 66L247 65L246 65L245 65L243 65L241 65L240 65L239 64L237 64L237 63L236 63L235 64L233 63L232 62L231 61L230 60L229 60L228 60L228 61L229 62L229 63L230 63L230 64L231 65L231 64L232 64L232 65L231 65L232 66L233 66L234 66L235 65L236 64L236 65L237 66L238 66L239 66L239 67L240 67L240 68L239 68L239 69L238 70L238 71L237 71L237 72L236 72L235 72L235 73L234 73L233 73L232 74L231 75L230 75L229 76L228 76L227 76L227 77L226 77L225 77L224 77L223 77L223 76L223 75L223 74L223 73L222 73L222 72L221 71L220 70L219 69L219 68L219 67L218 66L217 66L217 65L217 64L216 63L215 62L215 61L215 60L215 61L214 62L213 62L212 60L213 61L213 62L214 64L215 65L216 66L215 66L216 67L217 68L217 69L217 70L217 71L218 72L219 73L219 74L220 75L221 76L222 76L222 77L223 77L223 78L223 79L224 79L224 80L225 80L226 79L227 79L228 79L229 79L230 78L231 78L231 79L231 80L231 81L230 82L229 83L229 85L228 86L227 87L226 88L224 89L223 90L222 91L222 92L221 92L220 93L220 94L219 95L219 96L219 97L219 98L220 99L220 100L220 101L220 102L221 103L221 104L221 105L220 105L220 106L219 107L217 108L216 109L215 110L215 111L215 112L216 112L216 113L215 114L216 114L215 114L214 115L213 115L213 116L213 117L212 118L212 119L211 119L211 120L210 121L209 122L208 123L207 123L206 124L205 124L204 124L203 124L202 124L201 124L200 125L199 124L198 124L198 123L198 122L198 121L197 120L196 119L196 118L195 117L195 116L195 115L194 114L194 113L194 112L193 111L193 110L193 109L192 108L192 107L192 106L192 105L192 104L193 104L193 103L193 102L194 102L194 101L193 100L193 99L193 98L193 97L192 96L192 95L191 94L190 93L189 92L189 91L189 90L189 89L190 88L190 87L189 86L188 86L189 85L187 86L186 86L185 85L185 84L184 84L183 84L182 84L181 84L179 85L178 85L177 85L176 85L175 85L174 85L173 85L172 86L171 85L170 84L169 84L169 83L168 83L167 82L167 81L166 81L166 80L165 80L165 79L164 79L164 78L163 78L163 77L163 76L162 75L163 75L163 74L164 74L163 73L164 73L164 72L164 71L164 70L163 69L163 68L164 67L164 66L165 66L165 65L165 64L166 64L166 63L167 62L168 62L169 61L170 61L170 60L170 59L171 58L171 57L172 56L173 56L174 55L174 54L175 54L175 55L176 55L177 55L178 55L179 54L180 54L181 54L181 53L183 53L185 53L186 53L187 53L188 53L190 53L191 53L191 54L191 55L190 56L191 56L191 57L193 57L194 57L195 58L196 59L197 59L198 59L199 60L200 59L200 58L201 57L202 57L203 57L203 58L204 58L205 58L206 58L207 59L208 59L209 59L210 59L211 58L212 59L213 59L214 59L215 58L214 58L215 58L215 57L215 56L216 55L216 54L216 53L215 53L214 54L213 54L212 53L211 53L210 54L209 53L208 53L207 52L206 52L207 51L206 51L207 50L209 50L209 49L211 49L212 48L214 48L215 48L217 49L218 49L220 49L222 48L221 47L220 47L219 46L218 45L217 45L218 44L218 43L219 43L218 43L217 43L216 43L215 44L216 45L217 45L216 45L215 45L214 46L213 45L214 45L212 45L213 44L214 44L213 44L212 44L212 43L211 43L210 44L210 45L209 45L209 46L208 47L208 48L209 49L208 49L207 49L206 50L206 49L205 49L204 49L204 50L203 50L203 51L204 51L204 52L203 52L203 53L203 54L202 54L202 53L201 52L201 51L200 51L200 50L199 50L199 49L200 48L199 48L198 48L198 47L197 47L196 46L195 46L195 45L194 45L194 44L193 44L192 45L193 46L194 46L194 47L195 48L196 48L197 49L198 49L198 50L197 50L196 50L197 51L196 52L196 51L196 50L195 50L195 49L194 49L193 49L192 48L191 48L191 47L190 46L189 46L188 46L187 46L187 47L185 47L183 47L183 48L182 49L181 49L180 50L180 51L180 52L179 52L179 53L178 53L177 53L176 53L175 54L174 54L173 53L172 53L171 53L171 52L170 51L171 51L171 50L171 49L171 48L171 47L172 46L173 46L175 46L176 47L178 47L179 46L179 44L178 43L177 42L176 42L175 41L177 41L178 41L178 40L179 41L181 40L182 39L183 39L184 38L185 37L186 36L187 37L187 36L188 36L189 36L189 35L188 34L188 33L189 33L190 33L191 32L191 33L190 33L191 34L190 34L190 35L191 36L192 36L193 36L194 36L195 36L196 35L198 35L199 35L199 36L200 36L200 35L201 35L201 34L201 33L202 33L203 32L203 33L204 33L204 32L203 31L205 31L206 30L207 31L208 31L209 30L208 29L206 30L204 30L203 30L202 30L201 29L202 28L201 27L202 27L202 26L205 25L205 24L204 24L202 24L201 25L201 26L200 26L198 27L197 29L198 29L199 30L198 31L197 31L196 33L196 34L195 34L194 35L193 35L193 34L192 33L191 31L190 31L188 32L187 32L186 31L185 30L185 28L186 27L189 27L191 26L192 24L195 22L196 21L199 20L201 20L203 20L205 19L206 19L208 19L211 20L210 20L211 20L212 20L214 21L217 21L220 22L221 23L220 24L218 24L214 23L213 23L215 24L215 26L216 26L217 26L217 25L220 25L222 24L223 24L224 24L225 23L224 23L224 22L223 21L226 22L227 22L226 22L226 23L228 23L228 22L230 22L234 21L233 22L235 22L237 22L239 21L240 22L241 21L240 20L241 20L244 20L245 21L249 22L249 21L248 21L247 21L247 20L247 19L249 18L249 17L250 17L253 17L253 18L252 19L253 20L253 21L254 22L253 22L251 24L252 24L253 23L254 23L255 22L254 22L255 21L254 21L254 20L254 19L253 19L255 18L255 17L256 18L255 19L256 19L256 18L258 18L260 18L262 18L261 17L261 16L262 16L265 16L267 16L266 16L267 15L268 15L270 14L273 14L276 14L277 14L279 14L281 14L281 13L282 13L284 12L286 13L285 13L287 13ZM229 49L230 49L230 50L229 51L229 52L230 53L231 53L232 53L234 53L234 52L234 51L233 51L233 50L233 49L234 49L235 49L234 48L233 48L233 49L233 48L232 48L233 48L233 47L231 47L231 46L230 46L230 45L231 45L232 45L233 45L233 44L233 43L232 43L231 43L230 43L229 44L228 44L227 45L228 46L227 47L229 48L229 49ZM86 12L86 13L84 12L86 12ZM70 12L68 13L66 12L67 12L69 12L70 12ZM205 12L202 13L201 12L203 12L205 12ZM70 11L69 12L67 12L67 11L68 11L69 11L70 11ZM84 12L83 12L82 12L81 12L81 11L83 11L84 12ZM80 12L79 12L77 12L75 12L76 11L75 11L76 11L79 11L80 12ZM285 12L279 12L281 11L282 11L283 11L285 11L285 12ZM198 10L202 11L199 11L198 12L197 13L196 13L194 13L195 12L193 12L191 11L190 10L193 10L194 10L195 10L196 10L197 10L198 10ZM205 10L207 10L206 10L203 11L200 10L198 10L197 10L200 9L202 10L203 9L205 10ZM231 9L230 10L229 10L228 10L227 10L227 9L225 9L227 9L228 9L229 9L230 9L232 9L231 9ZM280 11L278 11L275 11L273 11L273 10L271 10L274 9L276 9L278 9L280 10L280 11ZM93 10L94 11L93 11L91 12L89 12L87 12L86 11L87 11L85 11L84 10L83 10L84 9L85 9L86 9L85 9L88 9L89 9L91 9L92 10L93 10ZM112 7L114 7L116 7L118 7L118 8L116 8L113 8L112 8L115 8L112 9L111 9L109 10L107 10L106 11L103 11L104 11L105 11L104 12L102 12L100 13L102 13L99 14L97 14L94 14L92 14L91 14L90 13L92 13L92 12L95 12L94 12L92 12L93 11L95 11L93 10L96 10L97 10L98 10L96 9L92 9L91 9L90 9L89 8L88 8L90 8L91 8L93 8L95 7L96 7L97 8L98 7L99 7L101 7L104 7L107 7L109 7L112 7ZM153 6L159 7L157 8L153 8L148 8L149 8L152 8L155 8L157 8L158 8L157 9L159 8L164 8L167 8L168 9L164 9L163 10L160 10L162 10L161 11L160 11L160 12L162 13L160 13L158 13L160 14L160 15L159 15L161 16L158 16L160 16L159 17L158 17L156 17L158 17L158 18L156 17L155 18L157 18L158 19L156 20L156 19L154 19L155 19L154 20L156 20L158 20L155 21L152 22L149 22L148 22L147 22L146 23L144 24L143 24L142 24L140 25L139 25L139 26L139 27L137 27L138 28L137 29L137 30L135 30L134 29L132 29L131 29L130 28L128 26L128 25L126 24L127 23L126 23L127 22L129 21L129 20L128 20L127 21L125 20L126 19L127 19L129 19L127 19L126 18L125 19L124 18L125 17L124 16L123 15L121 15L121 14L119 14L117 14L114 14L111 14L110 14L109 13L111 13L113 13L109 12L107 12L111 11L114 11L115 10L112 10L113 9L116 9L118 9L117 8L120 8L123 8L126 8L127 8L130 8L132 8L133 8L135 8L133 8L133 7L137 7L140 7L141 6L145 6L153 6Z';\n", "import { css, html, nothing, svg } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type {\n\tGetCriticalDaysResponse,\n\tGetDailyBiorhythmResponse,\n\tGetForecastResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\ntype BiorhythmData =\n\t| GetDailyBiorhythmResponse\n\t| GetForecastResponse\n\t| GetCriticalDaysResponse;\n\nconst CYCLE_COLOR: Record<string, string> = {\n\tphysical: '#dc2626',\n\temotional: '#0284c7',\n\tintellectual: '#16a34a',\n\tintuitive: '#a855f7',\n\taesthetic: '#f59e0b',\n\tawareness: '#ec4899',\n\tspiritual: '#14b8a6',\n\tpassion: '#ef4444',\n\tmastery: '#6366f1',\n\twisdom: '#475569',\n};\n\n/**\n * Biorhythm chart. Renders /biorhythm/{daily,forecast,critical-days}.\n */\n@customElement('roxy-biorhythm-chart')\nexport class RoxyBiorhythmChart extends RoxyDataElement<BiorhythmData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:center;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.energy{font-variant-numeric:tabular-nums;color:var(--roxy-accent-ink,#b45309);font-weight:var(--roxy-weight-bold,600)}.bars{gap:var(--roxy-space-xs,.25rem);display:grid}.bar{gap:var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-sm,.875rem);grid-template-columns:8rem 1fr 3.5rem;align-items:center;display:grid}.track{background:var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-full,9999px);height:14px;position:relative;overflow:hidden}.fill{height:100%;transition:width var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,cubic-bezier(.4, 0, .2, 1));display:block}.value{font-variant-numeric:tabular-nums;text-align:right;color:var(--roxy-muted,#71717a)}.advice{color:var(--roxy-fg,#0a0a0a)}.alert{background:color-mix(in srgb, var(--roxy-warning,#ea580c) 12%, transparent);border:1px solid color-mix(in srgb, var(--roxy-warning,#ea580c) 32%, transparent);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-sm,.875rem);margin:0}svg{width:100%;max-width:var(--roxy-chart-max-width,600px);height:auto;display:block}.crit{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 12%, transparent);border-radius:var(--roxy-radius-sm,4px);font-size:var(--roxy-text-xs,.75rem);margin:2px;padding:4px 8px;display:inline-block}`,\n\t];\n\n\t@property({ type: String, reflect: true })\n\tmode: 'daily' | 'forecast' | 'critical-days' = 'daily';\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No biorhythm data</div>`;\n\t}\n\n\tprotected renderData(d: BiorhythmData) {\n\t\tif (this.mode === 'critical-days' && 'criticalDays' in d) {\n\t\t\treturn this.renderCritical(d as GetCriticalDaysResponse);\n\t\t}\n\t\tif (this.mode === 'forecast' && 'days' in d) {\n\t\t\treturn this.renderForecast(d as GetForecastResponse);\n\t\t}\n\t\treturn this.renderDaily(d as GetDailyBiorhythmResponse);\n\t}\n\n\tprivate renderDaily(d: GetDailyBiorhythmResponse) {\n\t\tconst raw = d.quickRead ?? {};\n\t\tconst entries = Object.entries(raw).map(([cycle, value]) => {\n\t\t\tconst v = typeof value === 'number' ? value : 0;\n\t\t\tconst normalized = Math.abs(v) > 1 ? v / 100 : v;\n\t\t\treturn [cycle, normalized] as const;\n\t\t});\n\t\treturn html`<section class=\"wrap\" aria-label=\"Daily biorhythm\"><header class=\"head\"><h2 class=\"title\">Biorhythm</h2>${\n\t\t\t\t\ttypeof d.energyRating === 'number'\n\t\t\t\t\t\t? html`<span class=\"energy\">Energy ${d.energyRating}/10</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</header><div class=\"bars\" role=\"list\">${entries.map(([cycle, v]) => {\n\t\t\t\t\tconst pct = ((v + 1) / 2) * 100; // -1..1 -> 0..100\n\t\t\t\t\tconst color = CYCLE_COLOR[cycle] ?? 'var(--roxy-accent, #f59e0b)';\n\t\t\t\t\treturn html`<div class=\"bar\" role=\"listitem\"><span style=\"text-transform:capitalize\">${cycle}</span> <span class=\"track\"><span class=\"fill\" style=\"width:${pct}%;background:${color}\"></span> </span><span class=\"value\">${Math.round(v * 100)}%</span></div>`;\n\t\t\t\t})}</div>${d.dailyMessage ? html`<p class=\"advice\">${d.dailyMessage}</p>` : nothing} ${d.advice ? html`<p class=\"advice\">${d.advice}</p>` : nothing}</section>`;\n\t}\n\n\tprivate renderForecast(d: GetForecastResponse) {\n\t\tconst days = d.days ?? [];\n\t\tif (days.length === 0)\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No forecast</div>`;\n\t\tconst w = 600;\n\t\tconst h = 160;\n\t\tconst xStep = w / Math.max(days.length - 1, 1);\n\t\tconst cycleKeys = [\n\t\t\t'physical',\n\t\t\t'emotional',\n\t\t\t'intellectual',\n\t\t\t'intuitive',\n\t\t] as const;\n\t\treturn html`<section class=\"wrap\" aria-label=\"Biorhythm forecast\"><header class=\"head\"><h2 class=\"title\">Forecast</h2><span class=\"energy\">${d.startDate} - ${d.endDate}</span></header><svg viewBox=\"0 0 ${w} ${h}\" role=\"img\" aria-label=\"Biorhythm cycle lines across the forecast window\"><title>Biorhythm forecast</title><line x1=\"0\" y1=\"${h / 2}\" x2=\"${w}\" y2=\"${h / 2}\" stroke=\"var(--roxy-border, #e4e4e7)\" stroke-width=\"1\"/>${cycleKeys.map((cycle) => {\n\t\t\t\t\tconst points = days\n\t\t\t\t\t\t.map((day, i) => {\n\t\t\t\t\t\t\tconst v = day[cycle] ?? 0;\n\t\t\t\t\t\t\tconst x = i * xStep;\n\t\t\t\t\t\t\tconst y = h / 2 - (v / 100) * (h / 2 - 8);\n\t\t\t\t\t\t\treturn `${x.toFixed(2)},${y.toFixed(2)}`;\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.join(' ');\n\t\t\t\t\tconst color = CYCLE_COLOR[cycle] ?? '#475569';\n\t\t\t\t\treturn svg`<polyline points=${points} fill=\"none\" stroke=${color} stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />`;\n\t\t\t\t})}</svg> ${\n\t\t\t\td.summary?.periodAdvice\n\t\t\t\t\t? html`<p class=\"advice\">${d.summary.periodAdvice}</p>`\n\t\t\t\t\t: nothing\n\t\t\t}</section>`;\n\t}\n\n\tprivate renderCritical(d: GetCriticalDaysResponse) {\n\t\treturn html`<section class=\"wrap\" aria-label=\"Critical days\"><header class=\"head\"><h2 class=\"title\">Critical days</h2><span class=\"energy\">${d.totalCriticalDays} total</span></header><div>${d.criticalDays.map(\n\t\t\t\t\t(day) => html`<span class=\"crit\">${day.date} \u00B7 ${day.cycle} ${day.severity}</span>`,\n\t\t\t\t)}</div></section>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-biorhythm-chart': RoxyBiorhythmChart;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { PLANET_GLYPH } from '../tokens/index.js';\nimport type { GenerateBodygraphResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport {\n\tBODYGRAPH_VIEWBOX,\n\ttype BodygraphCenterId,\n\tchannelKey,\n\trenderBodygraphSvg,\n} from '../utils/bodygraph-render.js';\nimport { capitalize } from '../utils/string.js';\n\ntype GateActivation = GenerateBodygraphResponse['gates'][number];\n\n/**\n * Human Design bodygraph. Pass `data` from /human-design/bodygraph. Renders the\n * nine centers in their canonical positions and shapes, filled when defined and\n * outlined when open, the 36 channels as wiring between gates with active\n * channels emphasized, and the activated gate numbers. A summary block lists\n * type, strategy, authority, profile, definition, incarnation cross, signature,\n * and not-self theme.\n *\n * The chart is theme-driven through `--roxy-*` custom properties on `:host`, so\n * it adopts the host palette in light and dark without runtime color probing.\n */\n@customElement('roxy-bodygraph')\nexport class RoxyBodygraph extends RoxyDataElement<GenerateBodygraphResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.type-line{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}.layout{gap:var(--roxy-space-lg,1.5rem);grid-template-columns:minmax(0,1fr);align-items:start;display:grid}@container (width>=520px){.layout{grid-template-columns:minmax(0,340px) minmax(0,1fr)}}svg{width:100%;max-width:var(--roxy-chart-max-width,340px);height:auto;margin:0 auto;display:block}.bg-body{fill:color-mix(in srgb, var(--roxy-secondary,#475569) 8%, transparent);stroke:var(--roxy-border,#e4e4e7);stroke-width:1px}.bg-channel{stroke:var(--roxy-secondary,#475569);stroke-width:1.6px;opacity:.3}.bg-channel.on{stroke-width:3.4px;stroke-linecap:round;opacity:1}.bg-half{stroke:var(--roxy-secondary,#475569);stroke-width:3.2px;stroke-linecap:round;opacity:.9}.bg-leader{stroke:var(--roxy-muted,#71717a);stroke-width:1px;opacity:.5}.bg-center{fill:#0000;stroke:var(--roxy-secondary,#475569);stroke-width:1.8px}.bg-center.defined{stroke:#00000073}.bg-center.bg-gold.defined{fill:#e0a200}.bg-center.bg-green.defined{fill:#2f8f00}.bg-center.bg-red.defined{fill:#c41f1f}.bg-center.bg-brown.defined{fill:#76502f}.bg-center-label{fill:var(--roxy-muted,#71717a);font-size:11px;font-family:var(--roxy-font-sans)}.bg-gate{fill:var(--roxy-fg,#0a0a0a);font-size:8px;font-weight:600;font-family:var(--roxy-font-sans);paint-order:stroke;stroke:var(--roxy-bg,#fff);stroke-width:1.6px;stroke-linejoin:round}.summary{gap:var(--roxy-space-md,1rem);display:grid}.facts{gap:var(--roxy-space-sm,.5rem);grid-template-columns:repeat(auto-fit,minmax(8rem,1fr));display:grid}.fact{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);background:var(--roxy-surface,#fff)}.fact span{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);text-transform:uppercase;letter-spacing:.06em;display:block}.fact strong{font-size:var(--roxy-text-base,1rem);color:var(--roxy-fg,#0a0a0a)}.cross{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);border-left:2px solid var(--roxy-accent,#f59e0b);padding-left:var(--roxy-space-sm,.5rem);margin:0}.cross .gates{color:var(--roxy-muted,#71717a);font-variant-numeric:tabular-nums}.themes{gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.pill{border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);padding:2px 10px}.pill--good{background:color-mix(in srgb, var(--roxy-success,#16a34a) 16%, transparent);color:var(--roxy-success-fg,#166534)}.pill--shadow{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 16%, transparent);color:var(--roxy-danger-fg,#991b1b)}.legend{gap:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);flex-wrap:wrap;display:flex}.legend-caption{color:var(--roxy-muted,#71717a);flex-basis:100%}.legend .swatch{vertical-align:middle;border:1px solid var(--roxy-secondary,#475569);border-radius:2px;width:10px;height:10px;margin-right:4px;display:inline-block}.legend .swatch.defined{border-color:#00000073}.legend .swatch.bg-gold{background:#e0a200}.legend .swatch.bg-green{background:#2f8f00}.legend .swatch.bg-red{background:#c41f1f}.legend .swatch.bg-brown{background:#76502f}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No bodygraph data</div>`;\n\t}\n\n\tprotected renderData(d: GenerateBodygraphResponse) {\n\t\tconst definedCenters = new Set<BodygraphCenterId>(\n\t\t\t(d.centers ?? [])\n\t\t\t\t.filter((c) => c.defined)\n\t\t\t\t.map((c) => c.id as BodygraphCenterId),\n\t\t);\n\t\tconst activeGates = new Set<number>(\n\t\t\t(d.gates ?? []).map((g) => g.gate).filter((n): n is number => n != null),\n\t\t);\n\t\tconst activeChannels = new Set<string>(\n\t\t\t(d.channels ?? []).map((c) => channelKey(c.gateA, c.gateB)),\n\t\t);\n\t\tconst gateTitles = this.buildGateTitles(d.gates ?? []);\n\n\t\treturn html`<div class=\"wrap\"><header class=\"head\"><h2 class=\"title\">Bodygraph</h2>${\n\t\t\t\t\td.type\n\t\t\t\t\t\t? html`<div class=\"type-line\">${d.type}${d.profile ? html`\u00B7 Profile ${d.profile}` : nothing}</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</header><div class=\"layout\"><svg viewBox=\"${BODYGRAPH_VIEWBOX}\" preserveAspectRatio=\"xMidYMid meet\" role=\"img\" aria-label=\"Human Design bodygraph with nine centers, channels, and activated gates overlaid on a human silhouette\"><title>Human Design bodygraph</title><desc>Nine energy centers in their canonical positions over a human silhouette, each filled with its traditional color when defined and outlined when open, wired by channels between activated gates.</desc>${renderBodygraphSvg({\n\t\t\t\t\t\tdefinedCenters,\n\t\t\t\t\t\tactiveChannels,\n\t\t\t\t\t\tactiveGates,\n\t\t\t\t\t\tgateTitles,\n\t\t\t\t\t})}</svg> ${this.renderSummary(d)}</div></div>`;\n\t}\n\n\tprivate buildGateTitles(gates: GateActivation[]): Map<number, string> {\n\t\tconst titles = new Map<number, string>();\n\t\tfor (const g of gates) {\n\t\t\tif (g.gate == null) continue;\n\t\t\tconst parts: string[] = [`Gate ${g.gate}`];\n\t\t\tif (g.line != null) parts[0] += `.${g.line}`;\n\t\t\tif (g.gateName) parts.push(g.gateName);\n\t\t\tconst planet = g.planet ? capitalize(g.planet) : '';\n\t\t\tconst glyph = planet ? (PLANET_GLYPH[planet] ?? planet) : '';\n\t\t\tif (glyph) parts.push(`${glyph} ${g.side ?? ''}`.trim());\n\t\t\ttitles.set(g.gate, parts.join(' \u00B7 '));\n\t\t}\n\t\treturn titles;\n\t}\n\n\tprivate renderSummary(d: GenerateBodygraphResponse) {\n\t\tconst facts: Array<{ label: string; value?: string }> = [\n\t\t\t{ label: 'Type', value: d.type },\n\t\t\t{ label: 'Strategy', value: d.strategy },\n\t\t\t{ label: 'Authority', value: d.authority },\n\t\t\t{ label: 'Profile', value: d.profile },\n\t\t\t{ label: 'Definition', value: d.definition },\n\t\t];\n\t\tconst ic = d.incarnationCross;\n\t\treturn html`<div class=\"summary\"><div class=\"facts\">${facts.map((f) =>\n\t\t\t\t\tf.value\n\t\t\t\t\t\t? html`<div class=\"fact\"><span>${f.label}</span> <strong>${f.value}</strong></div>`\n\t\t\t\t\t\t: nothing,\n\t\t\t\t)}</div>${\n\t\t\t\tic?.name\n\t\t\t\t\t? html`<p class=\"cross\">${ic.name} ${\n\t\t\t\t\t\t\tic.gates?.length\n\t\t\t\t\t\t\t\t? html`<span class=\"gates\">(${ic.gates.join(', ')})</span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}</p>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\td.signature || d.notSelf\n\t\t\t\t\t? html`<div class=\"themes\">${d.signature ? html`<span class=\"pill pill--good\">Signature: ${d.signature}</span>` : nothing} ${d.notSelf ? html`<span class=\"pill pill--shadow\">Not-self: ${d.notSelf}</span>` : nothing}</div>`\n\t\t\t\t\t: nothing\n\t\t\t}<div class=\"legend\"><span class=\"legend-caption\">Center colors when defined. Open centers are outlined.</span> <span><span class=\"swatch bg-gold defined\"></span>Head, G</span> <span><span class=\"swatch bg-green defined\"></span>Ajna</span> <span><span class=\"swatch bg-brown defined\"></span>Throat, Spleen, Solar Plexus, Root</span> <span><span class=\"swatch bg-red defined\"></span>Heart, Sacral</span> <span><span class=\"swatch\"></span>Open center</span></div></div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-bodygraph': RoxyBodygraph;\n\t}\n}\n", "import type { TemplateResult } from 'lit';\nimport { nothing, svg } from 'lit';\n\n/**\n * Fixed geometry and renderer for the Human Design bodygraph. The diagram is a\n * standard, invariant layout: nine centers in canonical positions and shapes,\n * wired by 36 channels that each join two gates, with the 64 gates at fixed\n * points on the center edges, all overlaid on a front-facing human silhouette so\n * each center lands on the body part it governs. Only which centers are defined\n * and which channels and gates are active changes per chart, so this module holds\n * the geometry and the {@link RoxyBodygraph} component supplies the live state\n * from the /human-design/bodygraph response.\n *\n * @remarks Every point is authored in one normalized 0 to 100 canonical grid (x\n * left to right, y top to bottom) taken from the reference Jovian Archive\n * bodygraph, then scaled into {@link BODYGRAPH_VIEWBOX} by a single transform so\n * the chart and the body share one coordinate space and scale together. The grid\n * is sized so the nine centers fill the figure exactly as in the canonical\n * \"nine centers on the human body\" diagram: the Head center at the crown, Ajna at\n * the forehead, Throat at the neck, G at the chest, Heart at the right chest,\n * Spleen on the left torso, Solar Plexus on the right torso (its mirror), Sacral\n * at the lower abdomen, and Root at the pelvis. Two structural truths the layout\n * preserves: the Spleen (left) and the Solar Plexus (right) are mirror images at\n * the Sacral height, so the chart is narrow at the top and wide at the bottom;\n * and the Heart sits low and to the right of the G center, above the Solar\n * Plexus. The reference chart spreads the two side centers to the page edge for\n * channel clarity; here they are shifted inward by a fixed amount so they rest on\n * the torso sides inside the figure, with every channel topology preserved. Center shapes follow the canonical orientations (Head triangle\n * up, Ajna triangle down, Throat and Sacral and Root squares, G diamond, Heart\n * triangle pointing right, Spleen triangle pointing right with its base on the\n * far-left edge, Solar Plexus its mirror). The 36 channel gate pairs are the\n * gold-standard set used by the RoxyAPI Human Design engine.\n */\n\nexport type BodygraphCenterId =\n\t| 'head'\n\t| 'ajna'\n\t| 'throat'\n\t| 'g'\n\t| 'heart'\n\t| 'sacral'\n\t| 'solar-plexus'\n\t| 'spleen'\n\t| 'root';\n\ninterface Point {\n\tx: number;\n\ty: number;\n}\n\n/**\n * One center's drawable geometry: its semantic traditional color, the polygon\n * point list of its canonical shape, and the anchor where its name label sits.\n * Shapes are explicit point lists so the triangle and diamond orientations match\n * the canonical diagram exactly. Label anchors sit in the empty margins outside\n * each shape so they never collide with the gate numbers printed on the edges.\n */\ninterface CenterGeometry {\n\tid: BodygraphCenterId;\n\tlabel: string;\n\tcolor: CenterColor;\n\tpoints: Point[];\n\tlabelAnchor: Point;\n\tlabelAlign: 'start' | 'middle' | 'end';\n}\n\n/**\n * Traditional Human Design center color group. A defined center is filled with\n * this semantic color (constant across light and dark, like chart data colors);\n * an open center is left transparent with a thin theme-aware outline. The four\n * groups mirror the canonical scheme: gold for the identity and inspiration\n * centers (Head, G), green for the mental awareness center (Ajna), red for the\n * life-force motors of will and vitality (Heart, Sacral), brown for the\n * pressure, expression, and remaining awareness centers (Throat, Spleen, Solar\n * Plexus, Root).\n */\nexport type CenterColor = 'gold' | 'green' | 'red' | 'brown';\n\n/**\n * Viewport mapping from the normalized 0 to 100 grid into the SVG viewBox. The\n * chart proper occupies the inner grid; {@link PAD} is the slim margin (in grid\n * units) the body silhouette extends past the centers on every side, so the head\n * rises just above the Head center, the hips sit just below Root, and the\n * shoulders spread just outside Spleen and Solar Plexus. UNIT scales grid units\n * to viewBox units; the chart keeps its natural narrow-top, wide-bottom shape\n * because x and y share one scale.\n */\nconst UNIT = 4;\nconst PAD = 9;\nconst VIEW_W = (100 + 2 * PAD) * UNIT;\nconst VIEW_H = (100 + 2 * PAD) * UNIT;\n\n/** Map a normalized grid point (0 to 100) into viewBox units. */\nfunction g(x: number, y: number): Point {\n\treturn { x: (x + PAD) * UNIT, y: (y + PAD) * UNIT };\n}\n\n/** Chart horizontal center, the axis of symmetry for the body and the side centers. */\nconst AXIS = 50;\n\n/** Reflect a normalized grid x across {@link AXIS}, the vertical axis of symmetry. */\nconst mirrorX = (x: number): number => 2 * AXIS - x;\n\n/**\n * Gate positions authored per center in the normalized 0 to 100 grid, before the\n * mapping through {@link g}. Symmetry is structural, not hand-typed: every center\n * on the central column is authored balanced about {@link AXIS}; the Spleen is\n * authored once on the left torso and the Solar Plexus is derived as its exact\n * mirror in {@link buildGatePoints}, so the two side centers can never drift out\n * of alignment. The Heart is the one center the canonical bodygraph places off\n * the axis (low and to the right of the G center, with no left counterpart).\n * Within each center the gates follow the canonical reading order so the numbers\n * print where a printed chart shows them.\n *\n * @remarks Solar Plexus is intentionally empty here and filled by reflecting\n * Spleen; {@link SPLEEN_TO_SOLAR_PLEXUS} pairs each Spleen gate with the Solar\n * Plexus gate at its mirror position (base-top to base-top, apex to apex).\n */\nconst GATES_BY_CENTER: Record<\n\tBodygraphCenterId,\n\tRecord<number, [number, number]>\n> = {\n\thead: { 64: [45.5, 11.2], 61: [50, 11.2], 63: [54.5, 11.2] },\n\tajna: {\n\t\t47: [45.3, 18.0],\n\t\t24: [50, 18.0],\n\t\t4: [54.7, 18.0],\n\t\t17: [45.6, 20.6],\n\t\t11: [54.4, 20.6],\n\t\t43: [50, 25.3],\n\t},\n\tthroat: {\n\t\t62: [45.5, 32.3],\n\t\t23: [50, 32.3],\n\t\t56: [54.5, 32.3],\n\t\t16: [42, 34.6],\n\t\t35: [58, 34.6],\n\t\t12: [58, 37.6],\n\t\t20: [42, 40.6],\n\t\t45: [58, 40.6],\n\t\t31: [46, 42.4],\n\t\t8: [50, 42.4],\n\t\t33: [54, 42.4],\n\t},\n\tg: {\n\t\t1: [50, 47.5],\n\t\t7: [45.6, 50.3],\n\t\t13: [54.4, 50.3],\n\t\t10: [40, 53.3],\n\t\t25: [60, 53.3],\n\t\t15: [45.6, 56.6],\n\t\t46: [54.4, 56.6],\n\t\t2: [50, 59.0],\n\t},\n\theart: {\n\t\t21: [62.5, 58.5],\n\t\t51: [62.5, 61.3],\n\t\t26: [62.5, 64.1],\n\t\t40: [73, 61.3],\n\t},\n\tspleen: {\n\t\t48: [20, 70.6],\n\t\t57: [24, 72.3],\n\t\t44: [28, 74.0],\n\t\t50: [32, 75.6],\n\t\t32: [28, 77.2],\n\t\t28: [24, 78.9],\n\t\t18: [20, 80.6],\n\t},\n\tsacral: {\n\t\t5: [45.5, 72.5],\n\t\t14: [50, 72.5],\n\t\t29: [54.5, 72.5],\n\t\t34: [42, 75.6],\n\t\t27: [42, 79.0],\n\t\t59: [58, 79.0],\n\t\t42: [45.5, 81.4],\n\t\t3: [50, 81.4],\n\t\t9: [54.5, 81.4],\n\t},\n\t'solar-plexus': {},\n\troot: {\n\t\t53: [45.5, 89.9],\n\t\t60: [50, 89.9],\n\t\t52: [54.5, 89.9],\n\t\t54: [42, 92.7],\n\t\t19: [58, 92.7],\n\t\t38: [42, 95.3],\n\t\t39: [58, 95.3],\n\t\t58: [42, 98.0],\n\t\t41: [58, 98.0],\n\t},\n};\n\n/** Spleen gate to the Solar Plexus gate at its mirror position (base-top, ..., apex, ..., base-bottom). */\nconst SPLEEN_TO_SOLAR_PLEXUS: Record<number, number> = {\n\t48: 36,\n\t57: 22,\n\t44: 37,\n\t50: 6,\n\t32: 49,\n\t28: 55,\n\t18: 30,\n};\n\n/**\n * Assemble the viewBox-space gate anchors and the gate to center index from\n * {@link GATES_BY_CENTER}, filling the Solar Plexus by reflecting the Spleen so\n * the two side centers are guaranteed mirror images. Each gate sits on the\n * canonical edge of its center where its channels connect, so channel lines join\n * gate to gate cleanly and the activated numbers print in their traditional spots.\n */\nfunction buildGatePoints(): {\n\tpoints: Record<number, Point>;\n\tcenterOf: Record<number, BodygraphCenterId>;\n} {\n\tconst points: Record<number, Point> = {};\n\tconst centerOf: Record<number, BodygraphCenterId> = {};\n\tfor (const [spleenGate, [x, y]] of Object.entries(GATES_BY_CENTER.spleen)) {\n\t\tGATES_BY_CENTER['solar-plexus'][\n\t\t\tSPLEEN_TO_SOLAR_PLEXUS[Number(spleenGate)]\n\t\t] = [mirrorX(x), y];\n\t}\n\tfor (const [center, gates] of Object.entries(GATES_BY_CENTER) as Array<\n\t\t[BodygraphCenterId, Record<number, [number, number]>]\n\t>) {\n\t\tfor (const [gate, [x, y]] of Object.entries(gates)) {\n\t\t\tpoints[Number(gate)] = g(x, y);\n\t\t\tcenterOf[Number(gate)] = center;\n\t\t}\n\t}\n\treturn { points, centerOf };\n}\n\n/**\n * The viewBox-space gate anchors ({@link GATE_POINTS}) and the gate to center\n * index ({@link GATE_CENTER}). Exported so the geometry tests can assert the\n * layout invariants (side-center mirror symmetry, central-column balance, gates\n * inside their centers) without rendering.\n */\nexport const { points: GATE_POINTS, centerOf: GATE_CENTER } = buildGatePoints();\n\n/** Horizontal axis of symmetry in viewBox units, the reflection axis for geometry tests. */\nexport const CHART_AXIS_X = VIEW_W / 2;\n\n/** Build a polygon from normalized grid corner pairs, mapping each through {@link g}. */\nfunction shape(corners: ReadonlyArray<readonly [number, number]>): Point[] {\n\treturn corners.map(([x, y]) => g(x, y));\n}\n\n/** A square center, centered on {@link AXIS}, spanning the given half-width and y range. */\nfunction squareShape(halfWidth: number, top: number, bottom: number): Point[] {\n\treturn shape([\n\t\t[AXIS - halfWidth, top],\n\t\t[AXIS + halfWidth, top],\n\t\t[AXIS + halfWidth, bottom],\n\t\t[AXIS - halfWidth, bottom],\n\t]);\n}\n\n/** The Spleen triangle (base on the far-left edge, apex pointing right toward center). */\nconst SPLEEN_SHAPE: ReadonlyArray<readonly [number, number]> = [\n\t[18.4, 68.0],\n\t[18.4, 81.8],\n\t[34.7, 74.9],\n];\n\n/**\n * Center shapes in canonical orientation and color, labels anchored in the\n * margins. Central-column centers are built centered on {@link AXIS}; the Solar\n * Plexus shape is the Spleen reflected across the axis, so the side centers stay\n * exact mirrors. The Heart is the deliberate off-axis exception.\n */\nexport const CENTER_GEOMETRY: readonly CenterGeometry[] = [\n\t{\n\t\tid: 'head',\n\t\tlabel: 'Head',\n\t\tcolor: 'gold',\n\t\tpoints: shape([\n\t\t\t[40.0, 14.3],\n\t\t\t[60.0, 14.3],\n\t\t\t[50.0, 6.0],\n\t\t]),\n\t\tlabelAnchor: g(63, 9),\n\t\tlabelAlign: 'start',\n\t},\n\t{\n\t\tid: 'ajna',\n\t\tlabel: 'Ajna',\n\t\tcolor: 'green',\n\t\tpoints: shape([\n\t\t\t[40.0, 15.6],\n\t\t\t[60.0, 15.6],\n\t\t\t[50.0, 27.6],\n\t\t]),\n\t\tlabelAnchor: g(62, 21),\n\t\tlabelAlign: 'start',\n\t},\n\t{\n\t\tid: 'throat',\n\t\tlabel: 'Throat',\n\t\tcolor: 'brown',\n\t\tpoints: squareShape(9.5, 30.4, 43.6),\n\t\tlabelAnchor: g(83, 34),\n\t\tlabelAlign: 'start',\n\t},\n\t{\n\t\tid: 'g',\n\t\tlabel: 'G',\n\t\tcolor: 'gold',\n\t\tpoints: shape([\n\t\t\t[50.0, 45.0],\n\t\t\t[60.7, 53.3],\n\t\t\t[50.0, 61.6],\n\t\t\t[39.3, 53.3],\n\t\t]),\n\t\tlabelAnchor: g(13, 51),\n\t\tlabelAlign: 'end',\n\t},\n\t{\n\t\tid: 'heart',\n\t\tlabel: 'Heart',\n\t\tcolor: 'red',\n\t\tpoints: shape([\n\t\t\t[61.5, 57.0],\n\t\t\t[76.5, 61.3],\n\t\t\t[61.5, 65.6],\n\t\t]),\n\t\tlabelAnchor: g(85, 56),\n\t\tlabelAlign: 'start',\n\t},\n\t{\n\t\tid: 'spleen',\n\t\tlabel: 'Spleen',\n\t\tcolor: 'brown',\n\t\tpoints: shape(SPLEEN_SHAPE),\n\t\tlabelAnchor: g(13, 70),\n\t\tlabelAlign: 'end',\n\t},\n\t{\n\t\tid: 'sacral',\n\t\tlabel: 'Sacral',\n\t\tcolor: 'red',\n\t\tpoints: squareShape(9.5, 70.6, 83.6),\n\t\t// Lower-right, below the Solar Plexus: a left-side leader would clip the\n\t\t// Spleen, which sits at the same height as the Sacral.\n\t\tlabelAnchor: g(85, 88),\n\t\tlabelAlign: 'start',\n\t},\n\t{\n\t\tid: 'solar-plexus',\n\t\tlabel: 'Solar Plexus',\n\t\tcolor: 'brown',\n\t\tpoints: shape(\n\t\t\tSPLEEN_SHAPE.map(([x, y]) => [mirrorX(x), y] as [number, number]),\n\t\t),\n\t\tlabelAnchor: g(87, 73),\n\t\tlabelAlign: 'start',\n\t},\n\t{\n\t\tid: 'root',\n\t\tlabel: 'Root',\n\t\tcolor: 'brown',\n\t\tpoints: squareShape(9.5, 87.9, 99.9),\n\t\tlabelAnchor: g(50, 103),\n\t\tlabelAlign: 'middle',\n\t},\n];\n\n/**\n * The 36 channels as ordered gate pairs. This is the canonical Human Design\n * channel set; a channel is active only when both of its gates are activated,\n * which the live response reports in its `channels` array. The static list lets\n * the renderer draw every channel as a hanging (inactive) line and overlay the\n * active ones, so an open bodygraph still shows its full wiring skeleton.\n */\nexport const CHANNEL_PAIRS: ReadonlyArray<readonly [number, number]> = [\n\t[64, 47],\n\t[61, 24],\n\t[63, 4],\n\t[17, 62],\n\t[11, 56],\n\t[43, 23],\n\t[16, 48],\n\t[20, 34],\n\t[20, 10],\n\t[7, 31],\n\t[1, 8],\n\t[13, 33],\n\t[21, 45],\n\t[12, 22],\n\t[35, 36],\n\t[57, 20],\n\t[15, 5],\n\t[2, 14],\n\t[46, 29],\n\t[34, 10],\n\t[10, 57],\n\t[25, 51],\n\t[27, 50],\n\t[57, 34],\n\t[26, 44],\n\t[18, 58],\n\t[28, 38],\n\t[32, 54],\n\t[3, 60],\n\t[9, 52],\n\t[42, 53],\n\t[59, 6],\n\t[19, 49],\n\t[39, 55],\n\t[41, 30],\n\t[37, 40],\n];\n\n/**\n * Front-facing standing figure behind the chart, mirror-symmetric about\n * {@link AXIS}. Authored in the same normalized grid as the centers, so it scales\n * with the chart and frames it as in the canonical \"nine centers on the human\n * body\" diagram: a rounded head holding the Head center, a short neck at the\n * Throat, shoulders that slope to arms hanging down the outside of the torso so\n * their span frames the Spleen (left) and Solar Plexus (right), a torso that\n * narrows at the waist below the chest, then hips ending at the pelvis just below\n * the Root center. The outline is one closed loop: crown, temple, jaw, neck,\n * shoulder, down the outer arm to the hand beside the hip, in under the hip to\n * the pelvis hem, mirrored back up the left side. The right half is built from\n * cubic beziers and reflected so the figure is exactly symmetric. Drawn first and\n * behind everything so the centers, wiring, and gate numbers stay legible on top.\n */\nconst BODY_PATH = buildBodyPath();\n\nfunction buildBodyPath(): string {\n\tconst m = mirrorX;\n\t// Right-side outline in grid units (x, y) from the crown down to the\n\t// pelvis-right corner: a start point, then triples of (ctrl1, ctrl2, end). A\n\t// rounded head hugging the Head and Ajna centers, a narrowed neck, shoulders at\n\t// their widest, the outer torso running just past the Spleen and Solar Plexus\n\t// (right edges near x 82 at y 74), then waist and hip to a flat pelvis hem. The\n\t// left side is the mirror and the hem is a straight line, so the figure reads as\n\t// a torso, not a point.\n\tconst r: Array<[number, number]> = [\n\t\t[50, -2], // crown apex (start)\n\t\t[60, -2], // crown round (ctrl)\n\t\t[60.5, 9], // head side (ctrl)\n\t\t[57, 18], // brow, head holds Head + Ajna (end)\n\t\t[56, 21], // cheek (ctrl)\n\t\t[54, 24], // jaw (ctrl)\n\t\t[52, 27], // neck right, narrowed (end)\n\t\t[54, 28], // neck base (ctrl)\n\t\t[64, 30], // trapezius slope (ctrl)\n\t\t[80, 34], // shoulder / deltoid, the widest point (end)\n\t\t[83.5, 40], // upper torso side (ctrl)\n\t\t[84, 56], // outer torso, frames the side centers (ctrl)\n\t\t[83, 74], // torso side past Spleen / Solar Plexus (end)\n\t\t[82, 84], // waist (ctrl)\n\t\t[76, 92], // hip (ctrl)\n\t\t[68, 97], // hip (end)\n\t\t[64, 99], // toward the pelvis (ctrl)\n\t\t[62, 100], // pelvis (ctrl)\n\t\t[60, 100], // pelvis-right corner (end)\n\t];\n\tconst segs: string[] = [`M ${pt(r[0])}`];\n\t// Walk the right side as cubic beziers, three points per segment.\n\tfor (let i = 1; i + 2 < r.length; i += 3) {\n\t\tsegs.push(`C ${pt(r[i])} ${pt(r[i + 1])} ${pt(r[i + 2])}`);\n\t}\n\t// Flat pelvis hem across to the mirrored corner.\n\tsegs.push(`L ${ptm(r[r.length - 1], m)}`);\n\t// Mirror the right walk back up the left side to the crown.\n\tfor (let i = r.length - 3; i >= 1; i -= 3) {\n\t\tsegs.push(`C ${ptm(r[i + 1], m)} ${ptm(r[i], m)} ${ptm(r[i - 1], m)}`);\n\t}\n\tsegs.push('Z');\n\treturn segs.join(' ');\n}\n\nfunction pt([x, y]: [number, number]): string {\n\tconst p = g(x, y);\n\treturn `${p.x} ${p.y}`;\n}\n\nfunction ptm([x, y]: [number, number], m: (x: number) => number): string {\n\tconst p = g(m(x), y);\n\treturn `${p.x} ${p.y}`;\n}\n\nfunction polygonPoints(pts: Point[]): string {\n\treturn pts.map((p) => `${p.x},${p.y}`).join(' ');\n}\n\nfunction pairKey(a: number, b: number): string {\n\treturn a < b ? `${a}-${b}` : `${b}-${a}`;\n}\n\n/** Render the body silhouette behind the chart. */\nfunction renderBody(): TemplateResult {\n\treturn svg`<path class=\"bg-body\" d=${BODY_PATH} />`;\n}\n\n/**\n * Render every channel as a single line joining its two gates, so the wiring\n * always reads as a connected diagram rather than stubs poking out of centers.\n * Each of the 36 channels draws a faint full-length connector; a channel with\n * both gates active is redrawn thick and solid (a defined channel); a channel\n * with only one gate active lights that gate's half toward the midpoint over the\n * connector (a hanging gate). This mirrors how a printed bodygraph colors a full\n * channel only when both gates are active and shows a single hanging gate\n * otherwise, while keeping every connection visible.\n */\nfunction renderChannels(\n\tactiveChannels: Set<string>,\n\tactiveGates: Set<number>,\n): TemplateResult[] {\n\tconst lines: TemplateResult[] = [];\n\tfor (const [a, b] of CHANNEL_PAIRS) {\n\t\tconst pa = GATE_POINTS[a];\n\t\tconst pb = GATE_POINTS[b];\n\t\tif (!pa || !pb) continue;\n\t\tlines.push(\n\t\t\tsvg`<line class=\"bg-channel\" x1=${pa.x} y1=${pa.y} x2=${pb.x} y2=${pb.y} />`,\n\t\t);\n\t\tif (activeChannels.has(pairKey(a, b))) {\n\t\t\tlines.push(\n\t\t\t\tsvg`<line class=\"bg-channel on\" x1=${pa.x} y1=${pa.y} x2=${pb.x} y2=${pb.y} />`,\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\t\tconst mid = { x: (pa.x + pb.x) / 2, y: (pa.y + pb.y) / 2 };\n\t\tif (activeGates.has(a)) {\n\t\t\tlines.push(\n\t\t\t\tsvg`<line class=\"bg-half\" x1=${pa.x} y1=${pa.y} x2=${mid.x} y2=${mid.y} />`,\n\t\t\t);\n\t\t}\n\t\tif (activeGates.has(b)) {\n\t\t\tlines.push(\n\t\t\t\tsvg`<line class=\"bg-half\" x1=${pb.x} y1=${pb.y} x2=${mid.x} y2=${mid.y} />`,\n\t\t\t);\n\t\t}\n\t}\n\treturn lines;\n}\n\n/** Closest point to `p` on segment `a`-`b`, clamped to the segment ends. */\nfunction closestPointOnSegment(p: Point, a: Point, b: Point): Point {\n\tconst dx = b.x - a.x;\n\tconst dy = b.y - a.y;\n\tconst len2 = dx * dx + dy * dy;\n\tif (len2 === 0) return a;\n\tconst t = Math.max(\n\t\t0,\n\t\tMath.min(1, ((p.x - a.x) * dx + (p.y - a.y) * dy) / len2),\n\t);\n\treturn { x: a.x + t * dx, y: a.y + t * dy };\n}\n\n/** Closest point on a closed polygon's perimeter to `p`, where a label leader should land. */\nfunction closestPointOnPolygon(p: Point, poly: readonly Point[]): Point {\n\tlet best = poly[0];\n\tlet bestDist = Number.POSITIVE_INFINITY;\n\tfor (let i = 0; i < poly.length; i++) {\n\t\tconst q = closestPointOnSegment(p, poly[i], poly[(i + 1) % poly.length]);\n\t\tconst d = (q.x - p.x) ** 2 + (q.y - p.y) ** 2;\n\t\tif (d < bestDist) {\n\t\t\tbestDist = d;\n\t\t\tbest = q;\n\t\t}\n\t}\n\treturn best;\n}\n\n/**\n * Render the nine center shapes, filled with their semantic color when defined\n * and outlined when open, each with a margin label tied to its shape by a thin\n * leader line so the Heart and every other center is unambiguous regardless of\n * whether it is defined.\n */\nfunction renderCenters(defined: Set<BodygraphCenterId>): TemplateResult[] {\n\treturn CENTER_GEOMETRY.map((c) => {\n\t\tconst isDefined = defined.has(c.id);\n\t\tconst cls = `bg-center bg-${c.color}${isDefined ? ' defined' : ''}`;\n\t\tconst edge = closestPointOnPolygon(c.labelAnchor, c.points);\n\t\treturn svg`<g>\n\t\t\t<line class=\"bg-leader\" x1=${c.labelAnchor.x} y1=${c.labelAnchor.y} x2=${edge.x} y2=${edge.y} />\n\t\t\t<polygon class=${cls} points=${polygonPoints(c.points)}><title>${c.label}: ${isDefined ? 'defined' : 'open'}</title></polygon>\n\t\t\t<text class=\"bg-center-label\" x=${c.labelAnchor.x} y=${c.labelAnchor.y} text-anchor=${c.labelAlign} dominant-baseline=\"central\">${c.label}</text>\n\t\t</g>`;\n\t});\n}\n\n/**\n * Render the activated gate numbers at their fixed points. Numbers sit on top of\n * the filled centers, so a halo (a wider, background-colored stroke under the\n * fill) keeps them legible against any center color in both themes.\n */\nfunction renderGateNumbers(\n\tactiveGates: Set<number>,\n\ttitles: Map<number, string>,\n): TemplateResult[] {\n\tconst out: TemplateResult[] = [];\n\tfor (const [gate, p] of Object.entries(GATE_POINTS)) {\n\t\tconst num = Number(gate);\n\t\tif (!activeGates.has(num)) continue;\n\t\tconst title = titles.get(num);\n\t\tout.push(\n\t\t\tsvg`<text class=\"bg-gate\" x=${p.x} y=${p.y} text-anchor=\"middle\" dominant-baseline=\"central\">${num}${title ? svg`<title>${title}</title>` : nothing}</text>`,\n\t\t);\n\t}\n\treturn out;\n}\n\nexport interface BodygraphRenderInput {\n\tdefinedCenters: Set<BodygraphCenterId>;\n\tactiveChannels: Set<string>;\n\tactiveGates: Set<number>;\n\tgateTitles: Map<number, string>;\n}\n\n/** Build the lookup key for an active channel from its two gate numbers. */\nexport function channelKey(a: number, b: number): string {\n\treturn pairKey(a, b);\n}\n\nexport const BODYGRAPH_VIEWBOX = `0 0 ${VIEW_W} ${VIEW_H}`;\n\n/**\n * Render the full bodygraph SVG inner content for the given live state. The\n * caller wraps it in an `<svg>` with {@link BODYGRAPH_VIEWBOX} and applies its\n * own theming CSS. Draw order: body silhouette under channels under centers\n * under gate numbers, so the body is the backdrop, the wiring sits behind the\n * shapes, and the numbers stay legible on top.\n */\nexport function renderBodygraphSvg(\n\tinput: BodygraphRenderInput,\n): TemplateResult {\n\treturn svg`\n\t\t${renderBody()}\n\t\t${renderChannels(input.activeChannels, input.activeGates)}\n\t\t${renderCenters(input.definedCenters)}\n\t\t${renderGateNumbers(input.activeGates, input.gateTitles)}\n\t`;\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { PLANET_GLYPH } from '../tokens/index.js';\nimport type { GetChoghadiyaResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { capitalize } from '../utils/string.js';\n\ntype ChoghadiyaPeriod = GetChoghadiyaResponse['dayChoghadiya'][number];\n\n/**\n * Format an ISO 8601 datetime string to a short local time (HH:MM).\n * Falls back to the raw string when parsing fails.\n */\nfunction fmtTime(iso: string): string {\n\ttry {\n\t\tconst d = new Date(iso);\n\t\tif (Number.isNaN(d.getTime())) return iso;\n\t\treturn d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });\n\t} catch {\n\t\treturn iso;\n\t}\n}\n\n/**\n * Choghadiya muhurta grid. Accepts a GetChoghadiyaResponse and renders\n * 8 daytime and 8 nighttime muhurta tiles in a two-column responsive layout.\n * Good periods are highlighted in green, Bad periods in red.\n */\n@customElement('roxy-choghadiya-grid')\nexport class RoxyChoghadiyaGrid extends RoxyDataElement<GetChoghadiyaResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.header{gap:var(--roxy-space-xs,.25rem);display:grid}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.subtitle{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-muted,#71717a);margin:0}.cho-grid{gap:var(--roxy-space-md,1rem);grid-template-columns:1fr;display:grid}@media (width>=720px){.cho-grid{grid-template-columns:1fr 1fr}}.period-col{gap:var(--roxy-space-xs,.25rem);display:grid}.period-heading{font-size:var(--roxy-text-base,1rem);font-weight:var(--roxy-weight-bold,600);margin:0 0 var(--roxy-space-xs,.25rem);color:var(--roxy-fg,#0a0a0a)}.cho-tile{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);grid-template-columns:1fr auto;align-items:center;gap:.25em .75em;padding:.55em .85em;display:grid}.cho-tile.good{background:color-mix(in srgb, var(--roxy-success,#22c55e) 18%, transparent);border-color:color-mix(in srgb, var(--roxy-success,#22c55e) 45%, transparent);color:var(--roxy-fg,#0a0a0a)}.cho-tile.bad{background:color-mix(in srgb, var(--roxy-danger,#ef4444) 18%, transparent);border-color:color-mix(in srgb, var(--roxy-danger,#ef4444) 45%, transparent);color:var(--roxy-fg,#0a0a0a)}.cho-tile.neutral{color:var(--roxy-fg,#0a0a0a);background:0 0}.cho-tile.now{outline:2px solid var(--roxy-accent,#f59e0b);outline-offset:1px;box-shadow:0 0 0 4px color-mix(in srgb, var(--roxy-accent,#f59e0b) 18%, transparent)}.now-badge{font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-accent-ink,#b45309);text-transform:uppercase;letter-spacing:.06em;margin-left:.4em;display:inline-block}.tile-name{font-size:var(--roxy-text-base,1rem);font-weight:var(--roxy-weight-bold,600);grid-column:1}.tile-time{font-size:var(--roxy-text-xs,.75rem);opacity:.8;white-space:nowrap;text-align:right;grid-area:1/2/3;align-self:center}.tile-lord{font-size:var(--roxy-text-sm,.875rem);opacity:.85;grid-column:1;align-items:center;gap:.25em;display:flex}`,\n\t];\n\n\t/**\n\t * True when the current wall-clock time falls inside this period. Both\n\t * `start` and `end` are ISO 8601 with timezone, so the comparison is\n\t * timezone-aware via the host's `Date` parsing.\n\t */\n\tprivate isCurrent(period: ChoghadiyaPeriod): boolean {\n\t\tconst now = Date.now();\n\t\tconst start = Date.parse(period.start);\n\t\tconst end = Date.parse(period.end);\n\t\tif (Number.isNaN(start) || Number.isNaN(end)) return false;\n\t\treturn now >= start && now < end;\n\t}\n\n\tprivate renderTile(period: ChoghadiyaPeriod) {\n\t\tconst effectClass =\n\t\t\tperiod.effect === 'Good'\n\t\t\t\t? 'good'\n\t\t\t\t: period.effect === 'Bad'\n\t\t\t\t\t? 'bad'\n\t\t\t\t\t: 'neutral';\n\t\tconst current = this.isCurrent(period);\n\t\tconst lordGlyph = PLANET_GLYPH[capitalize(period.lord)] ?? '';\n\t\tconst timeRange = `${fmtTime(period.start)} - ${fmtTime(period.end)}`;\n\t\treturn html`<div class=\"cho-tile ${effectClass}${current ? ' now' : ''}\" role=\"listitem\" aria-current=\"${current ? 'time' : 'false'}\"><span class=\"tile-name\">${period.name}${current ? html`<span class=\"now-badge\">Now</span>` : nothing} </span><span class=\"tile-time\" aria-label=\"Time range\">${timeRange}</span> <span class=\"tile-lord\">${lordGlyph ? html`<span aria-hidden=\"true\">${lordGlyph}</span>` : nothing} ${period.lord}</span></div>`;\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No choghadiya data</div>`;\n\t}\n\n\tprotected renderData(d: GetChoghadiyaResponse) {\n\t\tconst { date, dayChoghadiya, nightChoghadiya } = d;\n\n\t\treturn html`<div class=\"wrap\"><div class=\"header\"><h2 class=\"title\">Choghadiya</h2>${date ? html`<p class=\"subtitle\">${date}</p>` : nothing}</div><div class=\"cho-grid\"><section class=\"period-col\" aria-label=\"Day muhurta periods\"><h3 class=\"period-heading\">Day</h3><div role=\"list\" aria-label=\"Daytime choghadiya\">${\n\t\t\t\t\t\t\tdayChoghadiya && dayChoghadiya.length > 0\n\t\t\t\t\t\t\t\t? dayChoghadiya.map((p) => this.renderTile(p))\n\t\t\t\t\t\t\t\t: html`<p class=\"roxy-empty\" role=\"status\">No daytime periods</p>`\n\t\t\t\t\t\t}</div></section><section class=\"period-col\" aria-label=\"Night muhurta periods\"><h3 class=\"period-heading\">Night</h3><div role=\"list\" aria-label=\"Nighttime choghadiya\">${\n\t\t\t\t\t\t\tnightChoghadiya && nightChoghadiya.length > 0\n\t\t\t\t\t\t\t\t? nightChoghadiya.map((p) => this.renderTile(p))\n\t\t\t\t\t\t\t\t: html`<p class=\"roxy-empty\" role=\"status\">No nighttime periods</p>`\n\t\t\t\t\t\t}</div></section></div></div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-choghadiya-grid': RoxyChoghadiyaGrid;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type {\n\tCalculateBioCompatibilityResponse,\n\tCalculateCompatibilityResponse,\n\tCalculateNumCompatibilityResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatNumber } from '../utils/format.js';\n\ntype CompatibilityData =\n\t| CalculateCompatibilityResponse\n\t| CalculateNumCompatibilityResponse\n\t| CalculateBioCompatibilityResponse;\n\n/**\n * Cross-domain compatibility card. Renders /astrology/compatibility-score,\n * /numerology/compatibility, or /biorhythm/compatibility responses.\n */\n@customElement('roxy-compatibility-card')\nexport class RoxyCompatibilityCard extends RoxyDataElement<CompatibilityData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.card{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{align-items:center;gap:var(--roxy-space-md,1rem);grid-template-columns:1fr auto;display:grid}.head h2{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);text-transform:capitalize;margin:0}.score{font-variant-numeric:tabular-nums;font-size:2rem;font-weight:var(--roxy-weight-bold,600);color:var(--roxy-accent-ink,#b45309);line-height:1}.rating{color:var(--roxy-secondary,#475569);font-size:var(--roxy-text-sm,.875rem)}.bar-row{gap:var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-sm,.875rem);grid-template-columns:8rem 1fr 3.5rem;align-items:center;display:grid}.bar{background:var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-full,9999px);height:8px;overflow:hidden}.bar>span{background:var(--roxy-accent,#f59e0b);height:100%;transition:width var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,cubic-bezier(.4, 0, .2, 1));display:block}.bar-row>span:last-child{font-variant-numeric:tabular-nums;color:var(--roxy-muted,#71717a);text-align:right}.archetype{color:var(--roxy-accent-ink,#b45309);font-weight:var(--roxy-weight-bold,600)}.lists{gap:var(--roxy-space-md,1rem);grid-template-columns:repeat(auto-fit,minmax(12rem,1fr));display:grid}.lists h3{margin:0 0 var(--roxy-space-xs,.25rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em}.lists ul{padding-left:var(--roxy-space-md,1rem);margin:0}`,\n\t];\n\n\t@property({ type: String, reflect: true })\n\tmode: 'astrology' | 'numerology' | 'biorhythm' = 'astrology';\n\n\tprivate getBreakdown(): Record<string, number> {\n\t\tconst d = this.data;\n\t\tif (!d) return {};\n\t\tif ('categories' in d && d.categories) {\n\t\t\tconst out: Record<string, number> = {};\n\t\t\tfor (const [k, v] of Object.entries(d.categories)) {\n\t\t\t\tif (typeof v === 'number' && Number.isFinite(v)) out[k] = v;\n\t\t\t}\n\t\t\treturn out;\n\t\t}\n\t\treturn {};\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No compatibility data</div>`;\n\t}\n\n\tprotected renderData(d: CompatibilityData) {\n\t\tconst score = d.overallScore;\n\t\tconst breakdown = this.getBreakdown();\n\t\tconst rating =\n\t\t\t'rating' in d\n\t\t\t\t? (d as CalculateNumCompatibilityResponse).rating\n\t\t\t\t: undefined;\n\t\tconst archetype =\n\t\t\t'archetype' in d\n\t\t\t\t? (d as CalculateCompatibilityResponse).archetype\n\t\t\t\t: undefined;\n\t\tconst advice =\n\t\t\t'advice' in d\n\t\t\t\t? (d as CalculateNumCompatibilityResponse).advice\n\t\t\t\t: undefined;\n\t\tconst summary =\n\t\t\t'summary' in d\n\t\t\t\t? (d as CalculateCompatibilityResponse).summary\n\t\t\t\t: undefined;\n\t\tconst interpretation =\n\t\t\t'interpretation' in d\n\t\t\t\t? (d as CalculateCompatibilityResponse).interpretation\n\t\t\t\t: undefined;\n\t\tconst strengths = 'strengths' in d ? d.strengths : undefined;\n\t\tconst challenges = 'challenges' in d ? d.challenges : undefined;\n\t\tconst keyAspects =\n\t\t\t'keyAspects' in d\n\t\t\t\t? (d as CalculateCompatibilityResponse).keyAspects\n\t\t\t\t: undefined;\n\n\t\treturn html`<article class=\"card\" aria-label=\"${`Compatibility (${this.mode})`}\"><div class=\"head\"><h2>${this.mode} compatibility</h2><div>${\n\t\t\t\t\t\ttypeof score === 'number'\n\t\t\t\t\t\t\t? html`<div class=\"score\">${formatNumber(score, 0)}</div>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t} ${rating ? html`<div class=\"rating\">${rating}</div>` : nothing}</div></div>${\n\t\t\t\tObject.keys(breakdown).length > 0\n\t\t\t\t\t? html`<div role=\"list\">${Object.entries(breakdown).map(\n\t\t\t\t\t\t\t([k, v]) => html`<div class=\"bar-row\" role=\"listitem\"><span style=\"text-transform:capitalize\">${k}</span> <span class=\"bar\"><span style=\"width:${Math.max(0, Math.min(100, v))}%\"></span></span> <span>${formatNumber(v, 0)}</span></div>`,\n\t\t\t\t\t\t)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tarchetype\n\t\t\t\t\t? html`<p><span class=\"archetype\">${archetype.label}</span> ${archetype.description ? html`\u00B7 ${archetype.description}` : nothing}</p>`\n\t\t\t\t\t: nothing\n\t\t\t} ${summary ? html`<p>${summary}</p>` : nothing} ${interpretation && !summary ? html`<p>${interpretation}</p>` : nothing} ${advice ? html`<p>${advice}</p>` : nothing} ${\n\t\t\t\t(strengths?.length ?? 0) > 0 || (challenges?.length ?? 0) > 0\n\t\t\t\t\t? html`<div class=\"lists\">${\n\t\t\t\t\t\t\tstrengths?.length\n\t\t\t\t\t\t\t\t? html`<div><h3>Strengths</h3><ul>${strengths.map((s) => html`<li>${s}</li>`)}</ul></div>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t} ${\n\t\t\t\t\t\t\tchallenges?.length\n\t\t\t\t\t\t\t\t? html`<div><h3>Challenges</h3><ul>${challenges.map((s) => html`<li>${s}</li>`)}</ul></div>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tkeyAspects?.length\n\t\t\t\t\t? html`<div><h3 style=\"margin:0 0 .25rem;font-size:var(--roxy-text-xs);color:var(--roxy-muted);text-transform:uppercase;letter-spacing:.06em\">Key aspects</h3><ul style=\"margin:0;padding-left:1rem;font-size:var(--roxy-text-sm)\">${keyAspects.slice(0, 6).map((a) => html`<li>${formatAspect(a)}</li>`)}</ul></div>`\n\t\t\t\t\t: nothing\n\t\t\t}</article>`;\n\t}\n}\n\ntype KeyAspect = CalculateCompatibilityResponse extends {\n\tkeyAspects: Array<infer T>;\n}\n\t? T\n\t: never;\n\nfunction formatAspect(a: KeyAspect): string {\n\tconst aspect = a.type.toLowerCase().replace(/_/g, '-');\n\tconst orb =\n\t\ttypeof a.orb === 'number' ? ` (orb ${formatNumber(a.orb, 1)}\u00B0)` : '';\n\tconst head = [a.planet1, aspect, a.planet2].filter(Boolean).join(' ');\n\treturn a.description ? `${head}${orb} \u00B7 ${a.description}` : `${head}${orb}`;\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-compatibility-card': RoxyCompatibilityCard;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { GetCrystalResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\nconst MONTHS = [\n\t'January',\n\t'February',\n\t'March',\n\t'April',\n\t'May',\n\t'June',\n\t'July',\n\t'August',\n\t'September',\n\t'October',\n\t'November',\n\t'December',\n];\n\n/**\n * Single-crystal detail card. Renders /crystals/{id}: the stone's photo, description, and full metaphysical profile (spiritual / emotional / physical meaning, governing chakras, zodiac signs, planet, elements, colours, Mohs hardness, numerical vibration, birthstone month), plus its affirmation and the crystals it pairs with. This is the detail view; roxy-crystal-grid is the gallery.\n */\n@customElement('roxy-crystal-card')\nexport class RoxyCrystalCard extends RoxyDataElement<GetCrystalResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.hero{gap:var(--roxy-space-md,1rem);align-items:flex-start;display:flex}.photo{border-radius:var(--roxy-radius-md,8px);object-fit:cover;background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 35%, transparent);flex:none;width:96px;height:96px}.title{margin:0 0 var(--roxy-space-xs,.25rem) 0;font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600)}.desc{line-height:1.55;font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);margin:0}.attrs{gap:var(--roxy-space-sm,.5rem);grid-template-columns:repeat(auto-fit,minmax(7rem,1fr));display:grid}.attr{gap:2px;display:grid}.attr dt{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.05em}.attr dd{font-size:var(--roxy-text-sm,.875rem);margin:0;font-weight:500}.colors{flex-wrap:wrap;gap:.4rem;display:flex}.color{font-size:var(--roxy-text-xs,.75rem);text-transform:capitalize;align-items:center;gap:.3rem;display:inline-flex}.dot{border-radius:var(--roxy-radius-full,9999px);border:1px solid color-mix(in srgb, var(--roxy-fg,#0a0a0a) 18%, transparent);width:.7rem;height:.7rem}.meaning h3{margin:0 0 var(--roxy-space-xs,.25rem) 0;font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.05em}.meaning p{margin:0 0 var(--roxy-space-sm,.5rem) 0;font-size:var(--roxy-text-sm,.875rem);line-height:1.55}.chips{flex-wrap:wrap;gap:.3rem;display:flex}.chip{border-radius:var(--roxy-radius-full,9999px);background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 14%, transparent);color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-xs,.75rem);text-transform:capitalize;padding:1px 8px}.section-label{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;font-weight:var(--roxy-weight-bold,600);margin:0 0 var(--roxy-space-xs,.25rem) 0}.affirmation{padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);border-left:3px solid var(--roxy-accent,#f59e0b);background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 8%, transparent);font-style:italic;font-size:var(--roxy-text-sm,.875rem);border-radius:0 var(--roxy-radius-sm,4px) var(--roxy-radius-sm,4px) 0;margin:0}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No crystal data</div>`;\n\t}\n\n\tprotected renderData(d: GetCrystalResponse) {\n\t\tconst colors = d.colors ?? [];\n\t\tconst keywords = d.keywords ?? [];\n\t\tconst pairs = d.pairsWith ?? [];\n\t\tconst month =\n\t\t\ttypeof d.birthMonth === 'number' ? MONTHS[d.birthMonth - 1] : undefined;\n\n\t\treturn html`<article class=\"wrap\" aria-label=\"${d.name ?? 'Crystal'}\"><div class=\"hero\">${d.imageUrl ? html`<img class=\"photo\" src=\"${d.imageUrl}\" alt=\"${d.name ?? 'Crystal'}\" loading=\"lazy\">` : nothing}<div><h2 class=\"title\">${d.name}</h2>${d.description ? html`<p class=\"desc\">${d.description}</p>` : nothing}</div></div><dl class=\"attrs\">${this.attr('Planet', d.planet)} ${this.attr('Hardness', typeof d.hardness === 'number' ? `${d.hardness} Mohs` : undefined)} ${this.attr('Vibration', d.numericalVibration)} ${this.attr('Birthstone', month)} ${this.list('Chakras', d.chakras)} ${this.list('Zodiac', d.zodiacSigns)} ${this.list('Elements', d.elements)} ${\n\t\t\t\t\tcolors.length\n\t\t\t\t\t\t? html`<div class=\"attr\"><dt>Colors</dt><dd><div class=\"colors\">${colors.map((c) => html`<span class=\"color\"><span class=\"dot\" style=\"background:${c}\"></span>${c}</span>`)}</div></dd></div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</dl>${this.renderMeaning(d.meaning)} ${\n\t\t\t\tkeywords.length\n\t\t\t\t\t? html`<div><p class=\"section-label\">Keywords</p><div class=\"chips\">${keywords.map((k) => html`<span class=\"chip\">${k}</span>`)}</div></div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${d.affirmation ? html`<p class=\"affirmation\">${d.affirmation}</p>` : nothing} ${\n\t\t\t\tpairs.length\n\t\t\t\t\t? html`<div><p class=\"section-label\">Pairs with</p><div class=\"chips\">${pairs.map((p) => html`<span class=\"chip\">${String(p).replace(/-/g, ' ')}</span>`)}</div></div>`\n\t\t\t\t\t: nothing\n\t\t\t}</article>`;\n\t}\n\n\tprivate attr(label: string, value: string | number | undefined) {\n\t\tif (value === undefined || value === null || value === '') return nothing;\n\t\treturn html`<div class=\"attr\"><dt>${label}</dt><dd>${value}</dd></div>`;\n\t}\n\n\tprivate list(label: string, values: readonly string[] | undefined) {\n\t\tif (!values?.length) return nothing;\n\t\treturn html`<div class=\"attr\"><dt>${label}</dt><dd>${values.join(', ')}</dd></div>`;\n\t}\n\n\tprivate renderMeaning(m: GetCrystalResponse['meaning'] | undefined) {\n\t\tif (!m) return nothing;\n\t\tconst rows: Array<[string, string | undefined]> = [\n\t\t\t['Spiritual', m.spiritual],\n\t\t\t['Emotional', m.emotional],\n\t\t\t['Physical', m.physical],\n\t\t];\n\t\tconst present = rows.filter(([, v]) => Boolean(v));\n\t\tif (present.length === 0) return nothing;\n\t\treturn html`<div class=\"meaning\">${present.map(([label, text]) => html`<h3>${label}</h3><p>${text}</p>`)}</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-crystal-card': RoxyCrystalCard;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type {\n\tGetBirthstonesResponse,\n\tGetCrystalsByChakraResponse,\n\tGetCrystalsByElementResponse,\n\tGetCrystalsByZodiacResponse,\n\tListCrystalsResponse,\n\tSearchCrystalsResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\n/**\n * Any crystal list response that carries a `crystals` summary array. Every crystals endpoint that returns more than one stone shares the `{ name, id, imageUrl, colors }` item shape, so one grid renders them all.\n */\ntype CrystalGridData =\n\t| ListCrystalsResponse\n\t| GetCrystalsByChakraResponse\n\t| GetCrystalsByElementResponse\n\t| GetCrystalsByZodiacResponse\n\t| GetBirthstonesResponse\n\t| SearchCrystalsResponse;\n\n/**\n * Month number to birthstone month name for the derived heading.\n */\nconst MONTHS = [\n\t'January',\n\t'February',\n\t'March',\n\t'April',\n\t'May',\n\t'June',\n\t'July',\n\t'August',\n\t'September',\n\t'October',\n\t'November',\n\t'December',\n];\n\n/**\n * Crystal grid. Renders any crystals list response (/crystals, /crystals/chakra/{chakra}, /crystals/element/{element}, /crystals/zodiac/{sign}, /crystals/birthstone/{month}, /crystals/search) as a responsive gallery of crystal tiles with photo, name, and colour swatches. The heading is derived from the response filter (chakra, element, zodiac sign, or birth month) or set explicitly via the `heading` attribute.\n */\n@customElement('roxy-crystal-grid')\nexport class RoxyCrystalGrid extends RoxyDataElement<CrystalGridData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-fg,#0a0a0a);margin:0}.count{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}.grid{gap:var(--roxy-space-md,1rem);grid-template-columns:repeat(auto-fill,minmax(8rem,1fr));margin:0;padding:0;list-style:none;display:grid}.tile{gap:var(--roxy-space-xs,.25rem);background:var(--roxy-surface,#fff);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-sm,.5rem);box-shadow:var(--roxy-shadow-sm);display:grid}.photo{aspect-ratio:1;border-radius:var(--roxy-radius-sm,4px);object-fit:cover;background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 35%, transparent);width:100%}.name{font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-fg,#0a0a0a);margin:0}.colors{flex-wrap:wrap;gap:4px;display:flex}.swatch{border-radius:var(--roxy-radius-full,9999px);border:1px solid color-mix(in srgb, var(--roxy-fg,#0a0a0a) 18%, transparent);width:10px;height:10px}`,\n\t];\n\n\t/**\n\t * Override the auto-derived grid heading. Empty by default, in which case the heading comes from the response filter (chakra, element, zodiac, or birth month) or falls back to \"Crystals\".\n\t */\n\t@property({ type: String, reflect: true })\n\theading = '';\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No crystals</div>`;\n\t}\n\n\tprotected renderData(d: CrystalGridData) {\n\t\tconst crystals = d.crystals ?? [];\n\t\tif (crystals.length === 0) return this.renderEmpty();\n\n\t\tconst title = this.heading || this.deriveHeading(d);\n\t\tconst total =\n\t\t\t'total' in d && typeof d.total === 'number' ? d.total : crystals.length;\n\n\t\treturn html`<section class=\"wrap\" aria-label=\"${title}\"><header class=\"head\"><h2 class=\"title\">${title}</h2><span class=\"count\">${total} ${total === 1 ? 'crystal' : 'crystals'}</span></header><ul class=\"grid\">${crystals.map(\n\t\t\t\t\t(c) => html`<li class=\"tile\">${\n\t\t\t\t\t\t\tc.imageUrl\n\t\t\t\t\t\t\t\t? html`<img class=\"photo\" src=\"${c.imageUrl}\" alt=\"${c.name ?? 'Crystal'}\" loading=\"lazy\">`\n\t\t\t\t\t\t\t\t: html`<div class=\"photo\" aria-hidden=\"true\"></div>`\n\t\t\t\t\t\t}<p class=\"name\">${c.name}</p>${\n\t\t\t\t\t\t\tc.colors && c.colors.length > 0\n\t\t\t\t\t\t\t\t? html`<div class=\"colors\" aria-label=\"${`Colours: ${c.colors.join(', ')}`}\">${c.colors.map((col) => html`<span class=\"swatch\" style=\"${`background:${cssColor(col)}`}\" title=\"${col}\"></span>`)}</div>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}</li>`,\n\t\t\t\t)}</ul></section>`;\n\t}\n\n\tprivate deriveHeading(d: CrystalGridData): string {\n\t\tif ('chakra' in d && d.chakra) return `${d.chakra} chakra crystals`;\n\t\tif ('element' in d && d.element) return `${d.element} element crystals`;\n\t\tif ('sign' in d && d.sign) return `Crystals for ${d.sign}`;\n\t\tif ('month' in d && typeof d.month === 'number')\n\t\t\treturn `${MONTHS[d.month - 1] ?? ''} birthstones`.trim();\n\t\treturn 'Crystals';\n\t}\n}\n\n/**\n * Map an API colour keyword to a CSS colour. Most crystal colours (violet, purple, green, blue) are valid CSS named colours; multi-word or non-standard values (blue-green, lavender) fall back to the keyword and, if the browser cannot resolve it, the swatch border still renders. Lower-cased and space-stripped so \"Blue Green\" resolves to the CSS hyphen form where it exists.\n */\nfunction cssColor(name: string): string {\n\treturn name.trim().toLowerCase().replace(/\\s+/g, '');\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-crystal-grid': RoxyCrystalGrid;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type {\n\tGetCurrentDashaResponse,\n\tGetMajorDashasResponse,\n\tGetSubDashasResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatNumber } from '../utils/format.js';\n\ntype DashaData =\n\t| GetCurrentDashaResponse\n\t| GetMajorDashasResponse\n\t| GetSubDashasResponse;\n\ntype DashaPeriod = GetMajorDashasResponse['mahadashas'][number];\n\n/**\n * Dasha timeline. Renders /vedic-astrology/dasha/{current,major,sub/{...}}.\n * Default mode shows the active mahadasha + antardasha + pratyantardasha.\n * Switch to period=\"major\" for the full 120-year Vimshottari timeline.\n */\n@customElement('roxy-dasha-timeline')\nexport class RoxyDashaTimeline extends RoxyDataElement<DashaData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:center;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.nakshatra{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}.current{gap:var(--roxy-space-md,1rem);background:var(--roxy-surface,#fff);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-md,1rem);box-shadow:var(--roxy-shadow-sm);grid-template-columns:repeat(auto-fit,minmax(10rem,1fr));display:grid}.current div span:first-child{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);text-transform:uppercase;letter-spacing:.06em;display:block}.current div strong{font-size:var(--roxy-text-base,1rem);color:var(--roxy-fg,#0a0a0a)}.balance{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-muted,#71717a);border-left:2px solid var(--roxy-border,#e4e4e7);padding-left:var(--roxy-space-sm,.5rem);margin:0}.timeline{gap:var(--roxy-space-xs,.25rem);display:grid}.bar{gap:var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-sm,.875rem);grid-template-columns:5rem 1fr 8rem;align-items:center;display:grid}.bar.now strong{color:var(--roxy-accent-ink,#b45309)}.now-badge{font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-accent-ink,#b45309);text-transform:uppercase;letter-spacing:.06em;margin-left:.4em;display:inline-block}.bar-track{background:var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-full,9999px);height:14px;position:relative;overflow:hidden}.bar-fill{background:var(--roxy-accent,#f59e0b);opacity:.45;height:100%;transition:width var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,cubic-bezier(.4, 0, .2, 1));display:block}.bar-now .bar-fill{opacity:1}.bar-progress{background:var(--roxy-accent-ink,#b45309);width:2px;box-shadow:0 0 0 2px color-mix(in srgb, var(--roxy-accent,#f59e0b) 35%, transparent);border-radius:2px;position:absolute;top:-2px;bottom:-2px}.dates{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);font-variant-numeric:tabular-nums;text-align:right}.interp{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);background:var(--roxy-surface,#fff)}.interp h3{font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);margin:0}.interp p{margin:var(--roxy-space-sm,.5rem) 0 0;font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-muted,#71717a)}`,\n\t];\n\n\t@property({ type: String, reflect: true })\n\tperiod: 'current' | 'major' | 'sub' = 'current';\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No dasha data</div>`;\n\t}\n\n\tprotected renderData(d: DashaData) {\n\t\tconst periods = this.collectPeriods(d);\n\t\tconst maxYears = periods.length\n\t\t\t? Math.max(...periods.map((p) => p.durationYears))\n\t\t\t: 0;\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Dasha timeline\"><header class=\"head\"><h2 class=\"title\">${\n\t\t\t\t\t\tthis.period === 'major'\n\t\t\t\t\t\t\t? 'Vimshottari Mahadasha'\n\t\t\t\t\t\t\t: this.period === 'sub'\n\t\t\t\t\t\t\t\t? 'Antardasha'\n\t\t\t\t\t\t\t\t: 'Active dashas'\n\t\t\t\t\t}</h2>${\n\t\t\t\t\t'nakshatraName' in d && d.nakshatraName\n\t\t\t\t\t\t? html`<div class=\"nakshatra\">Moon nakshatra: ${d.nakshatraName} ${'nakshatraLord' in d && d.nakshatraLord ? html`(lord ${d.nakshatraLord})` : nothing}</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</header>${this.renderBirthBalance(d)} ${this.period === 'current' ? this.renderCurrent(d) : nothing} ${\n\t\t\t\tperiods.length > 0\n\t\t\t\t\t? html`<div class=\"timeline\" role=\"list\">${periods.map((p) => this.renderBar(p, maxYears))}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${this.renderActiveInterpretation(periods)}</div>`;\n\t}\n\n\tprivate renderBirthBalance(d: DashaData) {\n\t\tif (!('birthDashaBalance' in d) || !d.birthDashaBalance) return nothing;\n\t\tconst b = d.birthDashaBalance;\n\t\tconst lord = 'nakshatraLord' in d && d.nakshatraLord ? d.nakshatraLord : '';\n\t\tconst yrs = b.years ?? 0;\n\t\tconst mo = b.months ?? 0;\n\t\tconst da = b.days ?? 0;\n\t\tconst parts: string[] = [];\n\t\tif (yrs) parts.push(`${yrs}y`);\n\t\tif (mo) parts.push(`${mo}m`);\n\t\tif (da) parts.push(`${da}d`);\n\t\tconst remaining = parts.length ? parts.join(' ') : '0d';\n\t\treturn html`<p class=\"balance\">Birth dasha balance: ${remaining} of ${lord ? html`<strong>${lord}</strong>` : 'the opening mahadasha'} remained at birth.</p>`;\n\t}\n\n\tprivate renderActiveInterpretation(periods: DashaPeriod[]) {\n\t\tconst active = periods.find((p) => this.isCurrent(p));\n\t\tif (!active?.interpretation) return nothing;\n\t\treturn html`<div class=\"interp\"><h3>${active.planet} mahadasha</h3><p>${active.interpretation}</p></div>`;\n\t}\n\n\tprivate renderCurrent(d: DashaData) {\n\t\tif (!('mahadasha' in d)) return nothing;\n\t\treturn html`<div class=\"current\">${\n\t\t\t\t'mahadasha' in d && d.mahadasha\n\t\t\t\t\t? html`<div><span>Mahadasha</span> <strong>${d.mahadasha.planet}</strong> ${\n\t\t\t\t\t\t'remainingInMahadasha' in d && d.remainingInMahadasha\n\t\t\t\t\t\t\t? html`<small>${formatNumber(d.remainingInMahadasha.years + d.remainingInMahadasha.months / 12, 1)} years left</small>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\t'antardasha' in d && d.antardasha\n\t\t\t\t\t? html`<div><span>Antardasha</span> <strong>${d.antardasha.planet}</strong> ${\n\t\t\t\t\t\t'remainingInAntardasha' in d && d.remainingInAntardasha\n\t\t\t\t\t\t\t? html`<small>${formatNumber(d.remainingInAntardasha.years + d.remainingInAntardasha.months / 12, 1)} years left</small>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\t'pratyantardasha' in d && d.pratyantardasha\n\t\t\t\t\t? html`<div><span>Pratyantardasha</span> <strong>${d.pratyantardasha.planet}</strong> ${\n\t\t\t\t\t\t'remainingInPratyantardasha' in d && d.remainingInPratyantardasha\n\t\t\t\t\t\t\t? html`<small>${formatNumber(d.remainingInPratyantardasha.years + d.remainingInPratyantardasha.months / 12, 1)} years left</small>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}</div>`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n\n\tprivate collectPeriods(d: DashaData): DashaPeriod[] {\n\t\tif ('mahadashas' in d && d.mahadashas?.length) return d.mahadashas;\n\t\tif ('antardashas' in d && d.antardashas?.length) return d.antardashas;\n\t\treturn [];\n\t}\n\n\t/** True when the current wall-clock time falls between the period's start and end. */\n\tprivate isCurrent(p: DashaPeriod): boolean {\n\t\tif (!p.startDate || !p.endDate) return false;\n\t\tconst now = Date.now();\n\t\tconst start = Date.parse(p.startDate);\n\t\tconst end = Date.parse(p.endDate);\n\t\tif (Number.isNaN(start) || Number.isNaN(end)) return false;\n\t\treturn now >= start && now < end;\n\t}\n\n\t/**\n\t * Fractional progress (0..1) through a period at the current time. Used to\n\t * draw a vertical \"now\" marker inside the active bar. Returns -1 outside the\n\t * period so the caller can skip the marker.\n\t */\n\tprivate progressIn(p: DashaPeriod): number {\n\t\tif (!p.startDate || !p.endDate) return -1;\n\t\tconst start = Date.parse(p.startDate);\n\t\tconst end = Date.parse(p.endDate);\n\t\tconst now = Date.now();\n\t\tif (\n\t\t\tNumber.isNaN(start) ||\n\t\t\tNumber.isNaN(end) ||\n\t\t\tnow < start ||\n\t\t\tnow >= end ||\n\t\t\tend <= start\n\t\t) {\n\t\t\treturn -1;\n\t\t}\n\t\treturn (now - start) / (end - start);\n\t}\n\n\tprivate renderBar(p: DashaPeriod, max: number) {\n\t\tconst years = p.durationYears;\n\t\tconst width = max > 0 ? (years / max) * 100 : 0;\n\t\tconst current = this.isCurrent(p);\n\t\tconst progress = current ? this.progressIn(p) : -1;\n\t\tconst trackClass = current ? 'bar-track bar-now' : 'bar-track';\n\t\treturn html`<div class=\"${current ? 'bar now' : 'bar'}\" role=\"listitem\" aria-current=\"${current ? 'time' : 'false'}\"><span><strong>${p.planet}</strong>${current ? html`<span class=\"now-badge\">Now</span>` : nothing} </span><span class=\"${trackClass}\"><span class=\"bar-fill\" style=\"width:${width}%\"></span> ${\n\t\t\t\t\tprogress >= 0\n\t\t\t\t\t\t? html`<span class=\"bar-progress\" style=\"left:${progress * width}%\" aria-hidden=\"true\"></span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} </span><span class=\"dates\">${p.startDate ? formatYear(p.startDate) : ''} ${p.endDate ? html`- ${formatYear(p.endDate)}` : ''}</span></div>`;\n\t}\n}\n\nfunction formatYear(s: string): string {\n\tconst m = s.match(/^(\\d{4})/);\n\treturn m ? m[1] : s;\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-dasha-timeline': RoxyDashaTimeline;\n\t}\n}\n", "import { css, html, nothing, type TemplateResult } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { humanize } from '../utils/string.js';\n\n/**\n * Generic fallback renderer. Accepts ANY OpenAPI response shape and renders\n * it via field-name heuristics so future spec additions render reasonably\n * without hand-wired components.\n *\n * Heuristic order:\n * 1. Primitive (string, number, boolean) -> single line.\n * 2. Array of primitives -> chip list.\n * 3. Array of objects with shared keys -> table.\n * 4. Object with title-like field -> card with key/value rows.\n * 5. Otherwise -> definition list of all keys.\n *\n * When a schema declares an `x-roxy-ui` hint, a future dispatcher can opt\n * into a hand-tuned component instead of this fallback.\n */\n\ntype Json = string | number | boolean | null | Json[] | { [key: string]: Json };\n\nconst TITLE_KEYS = ['title', 'name', 'label', 'heading', 'overview', 'summary'];\nconst IMAGE_KEYS = ['imageUrl', 'image', 'icon', 'symbol'];\nconst SKIP_KEYS = ['imageUrl', 'image']; // rendered separately, not in body rows\n\n// Hard cap on recursion. Real RoxyAPI responses nest at most 5-6 deep; anything\n// deeper is either a circular reference (which would otherwise infinite-loop)\n// or a payload too rich for the generic fallback to render usefully. The\n// recursion is otherwise safe: <roxy-data> is registered globally by its\n// `@customElement` decorator on import, so the nested template resolves to\n// this same class without a separate import.\nconst MAX_DEPTH = 6;\n\n@customElement('roxy-data')\nexport class RoxyData extends RoxyDataElement<Json> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.roxy-card{background:var(--roxy-surface,#fff);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-md,1rem);box-shadow:var(--roxy-shadow-sm)}.roxy-title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0 0 var(--roxy-space-sm,.5rem) 0;color:var(--roxy-primary,#0f172a);letter-spacing:var(--roxy-tracking-tight)}.roxy-summary{color:var(--roxy-secondary,#475569);margin:0 0 var(--roxy-space-md,1rem) 0;font-size:var(--roxy-text-sm,.875rem)}dl.roxy-rows{gap:var(--roxy-space-xs,.25rem) var(--roxy-space-md,1rem);grid-template-columns:minmax(8ch,max-content) 1fr;margin:0;display:grid}dl.roxy-rows dt{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem);text-transform:capitalize}dl.roxy-rows dd{color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);word-break:break-word;margin:0}ul.roxy-chips{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;margin:0;padding:0;list-style:none;display:flex}ul.roxy-chips li{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 14%, transparent);color:var(--roxy-fg,#0a0a0a);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);padding:2px 8px}table.roxy-table{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem)}table.roxy-table th,table.roxy-table td{border-bottom:1px solid var(--roxy-border,#e4e4e7);padding:var(--roxy-space-sm,.5rem);text-align:left;text-transform:none}table.roxy-table th{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:capitalize;font-size:var(--roxy-text-xs,.75rem);letter-spacing:.04em}.roxy-image{border-radius:var(--roxy-radius-md,8px);max-width:100%;height:auto;margin-bottom:var(--roxy-space-md,1rem)}.roxy-section{margin-bottom:var(--roxy-space-md,1rem)}.roxy-section h4{font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-secondary,#475569);margin:0 0 var(--roxy-space-xs,.25rem) 0;text-transform:capitalize}`,\n\t];\n\n\t/**\n\t * Internal recursion depth. Nested <roxy-data> instances inherit this from the parent and increment to guard against circular references in the input. Not part of the public API; do not set from consumer code.\n\t */\n\t@property({ attribute: false })\n\tdepth = 0;\n\n\tprotected renderData(data: Json) {\n\t\tif (this.depth >= MAX_DEPTH) {\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">\u2026</div>`;\n\t\t}\n\t\treturn html`<div class=\"roxy-card\" aria-label=\"Generic data display\">${this.renderValue(data)}</div>`;\n\t}\n\n\tprivate renderValue(value: Json): TemplateResult | typeof nothing {\n\t\tif (value === null || value === undefined) return nothing;\n\t\tif (typeof value === 'string') return html`<p>${value}</p>`;\n\t\tif (typeof value === 'number' || typeof value === 'boolean') {\n\t\t\treturn html`<p>${String(value)}</p>`;\n\t\t}\n\t\tif (Array.isArray(value)) return this.renderArray(value);\n\t\treturn this.renderObject(value as Record<string, Json>);\n\t}\n\n\tprivate renderArray(arr: Json[]): TemplateResult {\n\t\tif (arr.length === 0) {\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">Empty list</div>`;\n\t\t}\n\t\tconst allPrimitive = arr.every(\n\t\t\t(v) => v === null || ['string', 'number', 'boolean'].includes(typeof v),\n\t\t);\n\t\tif (allPrimitive) {\n\t\t\treturn html`<ul class=\"roxy-chips\">${arr.map((v) => html`<li>${String(v)}</li>`)}</ul>`;\n\t\t}\n\t\tconst allObjects = arr.every(\n\t\t\t(v) => v !== null && typeof v === 'object' && !Array.isArray(v),\n\t\t);\n\t\tif (allObjects) return this.renderTable(arr as Record<string, Json>[]);\n\t\treturn html`<ol>${arr.map((v) => html`<li>${this.renderValue(v)}</li>`)}</ol>`;\n\t}\n\n\tprivate renderTable(rows: Record<string, Json>[]): TemplateResult {\n\t\tconst keys = this.collectKeys(rows);\n\t\treturn html`<table class=\"roxy-table\" role=\"table\"><thead><tr>${keys.map((k) => html`<th>${humanize(k)}</th>`)}</tr></thead><tbody>${rows.map(\n\t\t\t\t\t(row) => html`<tr>${keys.map((k) => html`<td>${this.formatPrimitive(row[k])}</td>`)}</tr>`,\n\t\t\t\t)}</tbody></table>`;\n\t}\n\n\tprivate renderObject(obj: Record<string, Json>): TemplateResult {\n\t\tconst titleKey = TITLE_KEYS.find((k) => typeof obj[k] === 'string');\n\t\tconst imageKey = IMAGE_KEYS.find(\n\t\t\t(k) =>\n\t\t\t\ttypeof obj[k] === 'string' && (obj[k] as string).startsWith('http'),\n\t\t);\n\t\tconst summaryKey =\n\t\t\ttitleKey !== 'summary' && typeof obj.summary === 'string'\n\t\t\t\t? 'summary'\n\t\t\t\t: null;\n\t\tconst rows = Object.entries(obj).filter(\n\t\t\t([k, v]) =>\n\t\t\t\tk !== titleKey &&\n\t\t\t\tk !== summaryKey &&\n\t\t\t\t!SKIP_KEYS.includes(k) &&\n\t\t\t\tv !== null &&\n\t\t\t\tv !== undefined,\n\t\t);\n\n\t\treturn html`${\n\t\t\t\timageKey\n\t\t\t\t\t? html`<img class=\"roxy-image\" src=\"${String(obj[imageKey])}\" alt=\"${titleKey ? String(obj[titleKey]) : 'illustration'}\" loading=\"lazy\">`\n\t\t\t\t\t: nothing\n\t\t\t} ${titleKey ? html`<h3 class=\"roxy-title\">${obj[titleKey]}</h3>` : nothing} ${summaryKey ? html`<p class=\"roxy-summary\">${obj[summaryKey]}</p>` : nothing} ${\n\t\t\t\trows.length > 0\n\t\t\t\t\t? html`<dl class=\"roxy-rows\">${rows.map(\n\t\t\t\t\t\t\t([k, v]) => html`<dt>${humanize(k)}</dt><dd>${this.renderField(v)}</dd>`,\n\t\t\t\t\t\t)}</dl>`\n\t\t\t\t\t: nothing\n\t\t\t}`;\n\t}\n\n\tprivate renderField(value: Json): TemplateResult | string {\n\t\tif (value === null || value === undefined) return '';\n\t\tif (typeof value === 'string') return value;\n\t\tif (typeof value === 'number' || typeof value === 'boolean')\n\t\t\treturn String(value);\n\t\tif (Array.isArray(value)) {\n\t\t\tconst allPrimitive = value.every((v) =>\n\t\t\t\t['string', 'number', 'boolean'].includes(typeof v),\n\t\t\t);\n\t\t\tif (allPrimitive) {\n\t\t\t\treturn html`<ul class=\"roxy-chips\">${value.map((v) => html`<li>${String(v)}</li>`)}</ul>`;\n\t\t\t}\n\t\t}\n\t\treturn html`<roxy-data .data=\"${value}\" .depth=\"${this.depth + 1}\"></roxy-data>`;\n\t}\n\n\tprivate formatPrimitive(value: Json | undefined): string {\n\t\tif (value === null || value === undefined) return '';\n\t\tif (typeof value === 'string') return value;\n\t\tif (typeof value === 'number' || typeof value === 'boolean')\n\t\t\treturn String(value);\n\t\tif (Array.isArray(value)) return value.map(String).join(', ');\n\t\treturn JSON.stringify(value);\n\t}\n\n\tprivate collectKeys(rows: Record<string, Json>[]): string[] {\n\t\tconst seen = new Set<string>();\n\t\tfor (const row of rows) {\n\t\t\tfor (const k of Object.keys(row)) seen.add(k);\n\t\t}\n\t\treturn Array.from(seen);\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-data': RoxyData;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { PLANET_GLYPH } from '../tokens/index.js';\nimport type { DivisionalChartResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport {\n\ttype ChartStyle,\n\ttype KundliViewModel,\n\trenderKundliStyleTablist,\n\trenderKundliSvg,\n\ttoKundliViewModel,\n} from '../utils/kundli-render.js';\nimport { kundliStyles } from '../utils/kundli-styles.js';\nimport { tablistStyles } from '../utils/tablist.js';\n\n/**\n * Divisional chart renderer (D2-D60). Accepts a DivisionalChartResponse and\n * renders the same South / North / East kundli grid as the birth chart, plus\n * division metadata and Vargottama planet pills. A visible tablist lets the\n * end user switch styles at runtime. The varga response carries a graha-keyed\n * `chart.meta` map (no per-rashi buckets), so houses are bucketed from that\n * map.\n */\n@customElement('roxy-divisional-chart')\nexport class RoxyDivisionalChart extends RoxyDataElement<DivisionalChartResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tkundliStyles,\n\t\ttablistStyles,\n\t\tcss`.division-meta{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-muted,#71717a);margin:0}.significance{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-muted,#71717a);border-left:2px solid var(--roxy-border,#e4e4e7);padding-left:var(--roxy-space-sm,.5rem);margin:0}.vargottama-row{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;align-items:center;display:flex}.vargottama-label{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-muted,#71717a);margin-right:var(--roxy-space-xs,.25rem);font-weight:500}.vargottama-pill{font-size:var(--roxy-text-sm,.875rem);background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 22%, transparent);color:var(--roxy-fg,#0a0a0a);border:1px solid color-mix(in srgb, var(--roxy-accent,#f59e0b) 45%, transparent);border-radius:999px;align-items:center;gap:.2em;padding:.15em .6em;font-weight:600;display:inline-flex}`,\n\t];\n\n\t@property({ type: String, reflect: true, attribute: 'chart-style' })\n\tchartStyle: ChartStyle = 'north';\n\n\tprivate setStyle = (next: ChartStyle) => {\n\t\tthis.chartStyle = next;\n\t};\n\n\tprivate viewModel(): KundliViewModel | null {\n\t\tif (!this.data?.chart?.meta) return null;\n\t\tconst { division } = this.data;\n\t\tconst label = `D${division.number} ${division.name}`;\n\t\treturn toKundliViewModel(this.data.chart.meta, label);\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No divisional chart data</div>`;\n\t}\n\n\tprotected renderData(d: DivisionalChartResponse) {\n\t\tconst vm = this.viewModel();\n\t\tif (!vm) return this.renderEmpty();\n\n\t\tconst { division, vargottama } = d;\n\n\t\treturn html`<div class=\"wrap\"><div class=\"header\"><div><h2 class=\"title\">D${division.number} ${division.name} ${\n\t\t\t\t\t\t\tdivision.sanskritName && division.sanskritName !== division.name\n\t\t\t\t\t\t\t\t? html`<span class=\"division-meta\">\u00B7 ${division.sanskritName}</span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}</h2>${\n\t\t\t\t\t\tdivision.significance\n\t\t\t\t\t\t\t? html`<p class=\"significance\">${division.significance}</p>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}</div>${renderKundliStyleTablist(this.chartStyle, this.setStyle)}</div><svg viewBox=\"0 0 400 400\" preserveAspectRatio=\"xMidYMid meet\" role=\"img\" aria-label=\"D${division.number} ${division.name} divisional chart with twelve sign houses\"><title>D${division.number} ${division.name}</title>${renderKundliSvg(vm, this.chartStyle)}</svg> ${\n\t\t\t\tvargottama && vargottama.length > 0\n\t\t\t\t\t? html`<div class=\"vargottama-row\" role=\"list\" aria-label=\"Vargottama planets\"><span class=\"vargottama-label\">Vargottama:</span> ${vargottama.map(\n\t\t\t\t\t\t\t(planet) =>\n\t\t\t\t\t\t\t\thtml`<span class=\"vargottama-pill\" role=\"listitem\">${PLANET_GLYPH[planet] ?? ''} ${planet}</span>`,\n\t\t\t\t\t\t)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-divisional-chart': RoxyDivisionalChart;\n\t}\n}\n", "import type { TemplateResult } from 'lit';\nimport { nothing, svg } from 'lit';\nimport { PLANET_ABBR, SIGN_ABBR, SIGNS_ORDER } from '../tokens/index.js';\nimport { longitudeToSignPosition } from './degree.js';\nimport { capitalize } from './string.js';\nimport { renderTablist } from './tablist.js';\n\n/**\n * Canonical viewBox geometry for every kundli style. The chart is drawn into a\n * 360-unit square centred in a 400-unit viewBox, leaving a 20-unit gutter for\n * outer labels. All coordinates below are derived from these constants; change\n * them and every cell relocates correctly.\n *\n * @remarks SVG is vector-only and scales without raster loss, so the chart\n * remains crisp from a phone screen to a wall projector. Hosts size the chart\n * by setting `width` on the surrounding container; the SVG keeps a 1:1 aspect\n * ratio via the viewBox.\n */\nconst VIEW_BOX = 400;\nconst MARGIN = 20;\nconst INNER = VIEW_BOX - 2 * MARGIN; // 360\nconst CENTRE = VIEW_BOX / 2; // 200\n\n/**\n * Lowercase rashi key (`\"aries\"`) to canonical title-cased sign name (`\"Aries\"`).\n * Bridges API lowercase rashi strings to the SIGNS_ORDER tokens used everywhere\n * else in the render.\n */\nconst RASHI_TO_SIGN: Record<string, string> = Object.fromEntries(\n\tSIGNS_ORDER.map((s) => [s.toLowerCase(), s] as const),\n);\n\n/**\n * A graha placed inside a kundli cell. Render-only view model fed from a\n * `meta` map on the API response. Carries enough detail to draw a compact\n * in-cell label (abbreviation, whole degree, retrograde mark) and a rich SVG\n * `<title>` tooltip (exact position, nakshatra, pada, avastha).\n */\nexport interface PlacedGraha {\n\tgraha: string;\n\tlongitude?: number;\n\tnakshatra?: { name?: string; pada?: number; lord?: string };\n\tisRetrograde?: boolean;\n\tawastha?: string;\n}\n\n/**\n * Unified view model used by every kundli style. Caller passes a graha-keyed\n * `meta` map (from `/vedic-astrology/birth-chart`, `/divisional-chart`, or\n * `/navamsa`) through {@link toKundliViewModel} to produce this shape.\n *\n * `placements` is keyed by lowercase rashi name (`\"aries\"`, `\"taurus\"`, ...)\n * so the sign-fixed styles can index directly. The Lagna entry is not\n * counted as a planet; it only flags the ascendant cell.\n */\nexport interface KundliViewModel {\n\tlagnaSign: string;\n\tplacements: Record<string, PlacedGraha[]>;\n\tdivisionLabel?: string;\n}\n\n/**\n * Kundli regional styles. Sign-fixed (south, east) and house-fixed (north).\n * Exposed so consumers can type their own `chart-style` attribute reflection.\n */\nexport type ChartStyle = 'south' | 'north' | 'east';\n\nconst CHART_STYLES: ReadonlyArray<{ id: ChartStyle; label: string }> = [\n\t{ id: 'north', label: 'North' },\n\t{ id: 'south', label: 'South' },\n\t{ id: 'east', label: 'East' },\n];\n\nconst RETRO_MARK = '\u02B3';\n\n/**\n * True when the placed graha's longitude maps to a sign other than the cell\n * it occupies. The API preserves the D1 sidereal longitude on every chart, so\n * inside a D2..D60 cell that longitude refers to the D1 sign, not the cell's\n * divisional sign. In that case the degree-within-sign is not meaningful and\n * must be hidden from the in-cell label.\n */\nfunction isDivisionalPlacement(p: PlacedGraha, cellSign: string): boolean {\n\tif (typeof p.longitude !== 'number' || !Number.isFinite(p.longitude)) {\n\t\treturn false;\n\t}\n\treturn (\n\t\tlongitudeToSignPosition(p.longitude).sign.toLowerCase() !==\n\t\tcellSign.toLowerCase()\n\t);\n}\n\n/**\n * Compact in-cell graha label: abbreviation, optional whole-degree, retrograde\n * mark. The degree is shown only when the longitude actually maps to the cell\n * the graha is rendered in (the D1 case); divisional placements show the\n * abbreviation alone since the API longitude refers to D1, not the divisional\n * sign.\n */\nfunction grahaLabel(p: PlacedGraha, cellSign: string): string {\n\tconst abbr = PLANET_ABBR[capitalize(p.graha)] ?? p.graha.slice(0, 2);\n\tconst retro = p.isRetrograde ? RETRO_MARK : '';\n\tif (\n\t\ttypeof p.longitude !== 'number' ||\n\t\t!Number.isFinite(p.longitude) ||\n\t\tisDivisionalPlacement(p, cellSign)\n\t) {\n\t\treturn `${abbr}${retro}`;\n\t}\n\tconst { degree } = longitudeToSignPosition(p.longitude);\n\treturn `${abbr} ${degree}\u00B0${retro}`;\n}\n\n/**\n * Full-detail tooltip surfaced via the SVG `<title>` for each planet label.\n * Includes planet name, the divisional placement (when the longitude does not\n * match the cell, the cell's rashi is preferred), the exact D1 longitude as\n * the original reference, nakshatra and pada, avastha, and the retrograde\n * flag. Surfaces on hover or long-press without crowding the cell.\n */\nfunction grahaTitle(p: PlacedGraha, cellSign: string): string {\n\tconst parts: string[] = [capitalize(p.graha)];\n\tconst divisional = isDivisionalPlacement(p, cellSign);\n\tif (divisional) {\n\t\tparts.push(`in ${cellSign}`);\n\t}\n\tif (typeof p.longitude === 'number' && Number.isFinite(p.longitude)) {\n\t\tconst sp = longitudeToSignPosition(p.longitude);\n\t\tconst minute = String(sp.minute).padStart(2, '0');\n\t\tparts.push(\n\t\t\tdivisional\n\t\t\t\t? `D1: ${sp.degree}\u00B0${minute}' ${sp.sign}`\n\t\t\t\t: `${sp.degree}\u00B0${minute}' ${sp.sign}`,\n\t\t);\n\t}\n\tif (p.nakshatra?.name) {\n\t\tconst pada = p.nakshatra.pada ? ` pada ${p.nakshatra.pada}` : '';\n\t\tparts.push(`${p.nakshatra.name}${pada}`);\n\t}\n\tif (p.awastha) parts.push(p.awastha);\n\tif (p.isRetrograde) parts.push('retrograde');\n\treturn parts.join(' \u00B7 ');\n}\n\n/**\n * Render a vertically centred stack of planet labels at `(cx, baseY)`, one\n * line per planet, with an SVG `<title>` per line carrying the full tooltip.\n * The stack auto-centres on `baseY` regardless of count so a 1-planet cell\n * and a 5-planet cell both look intentional.\n */\nfunction renderPlanetStack(\n\tplanets: PlacedGraha[],\n\tcellSign: string,\n\tcx: number,\n\tbaseY: number,\n\tlineHeight: number,\n): TemplateResult[] {\n\tconst startY = baseY - ((planets.length - 1) * lineHeight) / 2;\n\treturn planets.map((p, j) => {\n\t\tconst yPos = startY + j * lineHeight;\n\t\treturn svg`<text class=\"planet-text\" x=${cx} y=${yPos} text-anchor=\"middle\" dominant-baseline=\"central\">${grahaLabel(\n\t\t\tp,\n\t\t\tcellSign,\n\t\t)}<title>${grahaTitle(p, cellSign)}</title></text>`;\n\t});\n}\n\n/**\n * Bucket a graha-keyed `meta` map (D1 birth chart or D2..D60 divisional\n * chart) into the unified {@link KundliViewModel} the renderer consumes. The\n * Lagna entry is recognised by `graha === 'Lagna'` (or key `\"Lagna\"`) and\n * sets `lagnaSign`; it is not bucketed as a placed planet.\n *\n * @param meta - Graha-keyed map; missing rashi entries are skipped.\n * @param divisionLabel - Optional title written inside the chart centre.\n * @param lagnaOverride - Optional rashi/sign name (case-insensitive, e.g. `\"cancer\"`) that replaces the `meta.Lagna`-derived ascendant. Drives the Chandra Lagna (Moon-as-ascendant) and other reference-point views: the `meta` of a `/birth-chart` response always carries the Janma Lagna as its `Lagna` key, so this is the only way to pivot the houses without a second request. Ignored when it does not resolve to a known sign.\n */\nexport function toKundliViewModel(\n\tmeta: Record<\n\t\tstring,\n\t\t{\n\t\t\tgraha?: string;\n\t\t\trashi?: string;\n\t\t\tlongitude?: number;\n\t\t\tnakshatra?: { name?: string; pada?: number; lord?: string };\n\t\t\tisRetrograde?: boolean;\n\t\t\tawastha?: string;\n\t\t}\n\t>,\n\tdivisionLabel?: string,\n\tlagnaOverride?: string,\n): KundliViewModel {\n\tconst placements: Record<string, PlacedGraha[]> = {};\n\tfor (const sign of SIGNS_ORDER) placements[sign.toLowerCase()] = [];\n\tconst override = lagnaOverride\n\t\t? (RASHI_TO_SIGN[lagnaOverride.toLowerCase()] ?? '')\n\t\t: '';\n\tlet lagnaSign = override;\n\tfor (const [name, pos] of Object.entries(meta ?? {})) {\n\t\tconst rashiKey = (pos?.rashi ?? '').toLowerCase();\n\t\tif (name === 'Lagna' || pos?.graha === 'Lagna') {\n\t\t\t// An explicit override pins the ascendant; otherwise the Janma Lagna\n\t\t\t// from meta is the reference point.\n\t\t\tif (!override) lagnaSign = RASHI_TO_SIGN[rashiKey] ?? '';\n\t\t\tcontinue;\n\t\t}\n\t\tif (!rashiKey || !(rashiKey in placements)) continue;\n\t\tplacements[rashiKey]?.push({\n\t\t\tgraha: pos.graha ?? name,\n\t\t\tlongitude: pos.longitude,\n\t\t\tnakshatra: pos.nakshatra,\n\t\t\tisRetrograde: pos.isRetrograde,\n\t\t\tawastha: pos.awastha,\n\t\t});\n\t}\n\treturn { lagnaSign, placements, divisionLabel };\n}\n\n// ---------------------------------------------------------------------------\n// South Indian: 4x4 grid with central 2x2 hollow. Signs are FIXED to cells\n// (Pisces top-left corner, clockwise); houses rotate from the Lagna cell.\n// ---------------------------------------------------------------------------\n\nconst SOUTH_CELL = INNER / 4; // 90\n\n/**\n * Sign-to-cell column/row in the South Indian fixed-sign grid. Pisces sits in\n * the top-left corner and the remaining signs proceed clockwise around the\n * 12 perimeter cells. (col, row) origin is the chart top-left.\n */\nconst SOUTH_CELL_GRID: Record<string, { col: number; row: number }> = {\n\tPisces: { col: 0, row: 0 },\n\tAries: { col: 1, row: 0 },\n\tTaurus: { col: 2, row: 0 },\n\tGemini: { col: 3, row: 0 },\n\tCancer: { col: 3, row: 1 },\n\tLeo: { col: 3, row: 2 },\n\tVirgo: { col: 3, row: 3 },\n\tLibra: { col: 2, row: 3 },\n\tScorpio: { col: 1, row: 3 },\n\tSagittarius: { col: 0, row: 3 },\n\tCapricorn: { col: 0, row: 2 },\n\tAquarius: { col: 0, row: 1 },\n};\n\nfunction southCellRect(sign: string): {\n\tx: number;\n\ty: number;\n\tw: number;\n\th: number;\n} {\n\tconst g = SOUTH_CELL_GRID[sign] ?? { col: 0, row: 0 };\n\treturn {\n\t\tx: MARGIN + g.col * SOUTH_CELL,\n\t\ty: MARGIN + g.row * SOUTH_CELL,\n\t\tw: SOUTH_CELL,\n\t\th: SOUTH_CELL,\n\t};\n}\n\n/**\n * South Indian frame: outer square, the two full-span grid lines, and the\n * partial inner lines that bound the central 2x2 hollow on each edge.\n */\nfunction renderSouthFrame(divisionLabel?: string): TemplateResult {\n\tconst a = MARGIN;\n\tconst b = MARGIN + SOUTH_CELL; // 110\n\tconst c = MARGIN + 2 * SOUTH_CELL; // 200\n\tconst d = MARGIN + 3 * SOUTH_CELL; // 290\n\tconst e = VIEW_BOX - MARGIN; // 380\n\treturn svg`\n\t\t<rect class=\"line\" x=${a} y=${a} width=${INNER} height=${INNER} stroke-width=\"1.5\" fill=\"none\" />\n\t\t<line class=\"line\" x1=${a} y1=${b} x2=${e} y2=${b} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${a} y1=${d} x2=${e} y2=${d} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${b} y1=${a} x2=${b} y2=${e} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${d} y1=${a} x2=${d} y2=${e} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${a} y1=${c} x2=${b} y2=${c} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${d} y1=${c} x2=${e} y2=${c} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${c} y1=${a} x2=${c} y2=${b} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${c} y1=${d} x2=${c} y2=${e} stroke-width=\"1\" />\n\t\t${\n\t\t\tdivisionLabel\n\t\t\t\t? svg`<text class=\"centre-label\" x=${CENTRE} y=${CENTRE} text-anchor=\"middle\" dominant-baseline=\"central\">${divisionLabel}</text>`\n\t\t\t\t: nothing\n\t\t}\n\t`;\n}\n\n/**\n * House number for a given sign relative to a Lagna sign. House 1 is the\n * Lagna cell; subsequent houses follow the zodiac in order. Returns 0 when\n * the Lagna sign is unknown so the caller can skip rendering the badge.\n */\nfunction houseNumberInSign(sign: string, lagnaSign: string): number {\n\tconst lagnaIdx = SIGNS_ORDER.findIndex((s) => s === lagnaSign);\n\tconst signIdx = SIGNS_ORDER.findIndex((s) => s === sign);\n\tif (lagnaIdx === -1 || signIdx === -1) return 0;\n\treturn ((signIdx - lagnaIdx + 12) % 12) + 1;\n}\n\nfunction renderSouthCell(\n\tsign: string,\n\tplanets: PlacedGraha[],\n\tisLagna: boolean,\n\thouseNum: number,\n): TemplateResult {\n\tconst r = southCellRect(sign);\n\tconst cx = r.x + r.w / 2;\n\tconst cy = r.y + r.h / 2;\n\tconst signAbbr = SIGN_ABBR[sign] ?? sign.slice(0, 2);\n\t// Inset the Lagna diagonal so it does not collide with the chart frame on\n\t// corner cells (Pisces, Gemini, Virgo, Sagittarius) or with the sign label\n\t// in the top-left of every cell.\n\tconst slashInset = 14;\n\treturn svg`\n\t\t<g class=${isLagna ? 'cell lagna' : 'cell'}>\n\t\t\t${\n\t\t\t\tisLagna\n\t\t\t\t\t? svg`\n\t\t\t\t\t\t<rect class=\"lagna-bg\" x=${r.x} y=${r.y} width=${r.w} height=${r.h} />\n\t\t\t\t\t\t<line class=\"lagna-slash\" x1=${r.x + r.w - slashInset} y1=${r.y + slashInset} x2=${r.x + slashInset} y2=${r.y + r.h - slashInset} stroke-width=\"1.2\" />\n\t\t\t\t\t`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t<text class=\"sign-text\" x=${r.x + 6} y=${r.y + 12} text-anchor=\"start\" dominant-baseline=\"central\">${signAbbr}</text>\n\t\t\t${\n\t\t\t\thouseNum > 0\n\t\t\t\t\t? svg`<text class=\"house-num\" x=${r.x + r.w - 6} y=${r.y + 12} text-anchor=\"end\" dominant-baseline=\"central\">${houseNum}</text>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t${\n\t\t\t\tisLagna\n\t\t\t\t\t? svg`<text class=\"lagna-marker\" x=${cx} y=${r.y + 26} text-anchor=\"middle\" dominant-baseline=\"central\">Asc</text>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t${planets.length ? renderPlanetStack(planets, sign, cx, cy + 4, 14) : nothing}\n\t\t</g>\n\t`;\n}\n\nfunction renderSouthSvg(vm: KundliViewModel): TemplateResult {\n\tconst lagnaKey = vm.lagnaSign.toLowerCase();\n\treturn svg`\n\t\t${renderSouthFrame(vm.divisionLabel)}\n\t\t${SIGNS_ORDER.map((sign) =>\n\t\t\trenderSouthCell(\n\t\t\t\tsign,\n\t\t\t\tvm.placements[sign.toLowerCase()] ?? [],\n\t\t\t\tsign.toLowerCase() === lagnaKey,\n\t\t\t\thouseNumberInSign(sign, vm.lagnaSign),\n\t\t\t),\n\t\t)}\n\t`;\n}\n\n// ---------------------------------------------------------------------------\n// North Indian: outer square + inscribed midpoint diamond + both outer\n// diagonals. 12 cells: 4 cardinal diamonds + 8 corner triangles. Houses are\n// FIXED (H1 always top-centre); signs rotate from the Lagna sign.\n// ---------------------------------------------------------------------------\n\nconst NORTH_VERTICES = {\n\ttl: { x: MARGIN, y: MARGIN },\n\ttr: { x: VIEW_BOX - MARGIN, y: MARGIN },\n\tbr: { x: VIEW_BOX - MARGIN, y: VIEW_BOX - MARGIN },\n\tbl: { x: MARGIN, y: VIEW_BOX - MARGIN },\n\ttop: { x: CENTRE, y: MARGIN },\n\tright: { x: VIEW_BOX - MARGIN, y: CENTRE },\n\tbottom: { x: CENTRE, y: VIEW_BOX - MARGIN },\n\tleft: { x: MARGIN, y: CENTRE },\n\ttlMid: { x: CENTRE - INNER / 4, y: CENTRE - INNER / 4 },\n\ttrMid: { x: CENTRE + INNER / 4, y: CENTRE - INNER / 4 },\n\tbrMid: { x: CENTRE + INNER / 4, y: CENTRE + INNER / 4 },\n\tblMid: { x: CENTRE - INNER / 4, y: CENTRE + INNER / 4 },\n} as const;\n\n/**\n * Centroid (geometric mean) of an arbitrary set of polygon vertices. Used by\n * every cell that needs a label-anchor point; defining it once keeps the\n * North diamond and East triangle math identical.\n */\nfunction centroidOf(pts: Array<{ x: number; y: number }>): {\n\tx: number;\n\ty: number;\n} {\n\tconst x = pts.reduce((s, p) => s + p.x, 0) / pts.length;\n\tconst y = pts.reduce((s, p) => s + p.y, 0) / pts.length;\n\treturn { x, y };\n}\n\n/**\n * House centres for the North Indian diamond. Numbered 1..12 counter-clockwise\n * from the top diamond (H1 is always the ascendant cell). Centroids derived\n * from the canonical geometry above; do not edit by eye, recompute if you\n * change `VIEW_BOX` or `MARGIN`.\n */\nconst NORTH_HOUSE_CENTERS: Record<number, { x: number; y: number }> = {\n\t1: { x: CENTRE, y: NORTH_VERTICES.tlMid.y },\n\t2: centroidOf([NORTH_VERTICES.tl, NORTH_VERTICES.top, NORTH_VERTICES.tlMid]),\n\t3: centroidOf([NORTH_VERTICES.tl, NORTH_VERTICES.left, NORTH_VERTICES.tlMid]),\n\t4: { x: NORTH_VERTICES.tlMid.x, y: CENTRE },\n\t5: centroidOf([NORTH_VERTICES.bl, NORTH_VERTICES.left, NORTH_VERTICES.blMid]),\n\t6: centroidOf([\n\t\tNORTH_VERTICES.bl,\n\t\tNORTH_VERTICES.bottom,\n\t\tNORTH_VERTICES.blMid,\n\t]),\n\t7: { x: CENTRE, y: NORTH_VERTICES.blMid.y },\n\t8: centroidOf([\n\t\tNORTH_VERTICES.br,\n\t\tNORTH_VERTICES.bottom,\n\t\tNORTH_VERTICES.brMid,\n\t]),\n\t9: centroidOf([\n\t\tNORTH_VERTICES.br,\n\t\tNORTH_VERTICES.right,\n\t\tNORTH_VERTICES.brMid,\n\t]),\n\t10: { x: NORTH_VERTICES.brMid.x, y: CENTRE },\n\t11: centroidOf([\n\t\tNORTH_VERTICES.tr,\n\t\tNORTH_VERTICES.right,\n\t\tNORTH_VERTICES.trMid,\n\t]),\n\t12: centroidOf([NORTH_VERTICES.tr, NORTH_VERTICES.top, NORTH_VERTICES.trMid]),\n};\n\n/**\n * Rashi number (1..12, Aries=1) occupying the given house when the Lagna sits\n * in `lagnaSign`. House 1 is the Lagna sign; subsequent houses follow the\n * zodiac in order.\n */\nfunction rashiInHouse(houseNum: number, lagnaSign: string): number {\n\tconst lagnaIdx = SIGNS_ORDER.findIndex((s) => s === lagnaSign);\n\tif (lagnaIdx === -1) return houseNum;\n\treturn ((lagnaIdx + houseNum - 1) % 12) + 1;\n}\n\nfunction renderNorthFrame(divisionLabel?: string): TemplateResult {\n\tconst { tl, tr, br, bl, top, right, bottom, left } = NORTH_VERTICES;\n\treturn svg`\n\t\t<rect class=\"line\" x=${tl.x} y=${tl.y} width=${INNER} height=${INNER} stroke-width=\"1.5\" fill=\"none\" />\n\t\t<polygon class=\"line\" points=\"${top.x},${top.y} ${right.x},${right.y} ${bottom.x},${bottom.y} ${left.x},${left.y}\" stroke-width=\"1\" fill=\"none\" />\n\t\t<line class=\"line\" x1=${tl.x} y1=${tl.y} x2=${br.x} y2=${br.y} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${tr.x} y1=${tr.y} x2=${bl.x} y2=${bl.y} stroke-width=\"1\" />\n\t\t${\n\t\t\tdivisionLabel\n\t\t\t\t? svg`<text class=\"centre-label\" x=${CENTRE} y=${CENTRE} text-anchor=\"middle\" dominant-baseline=\"central\">${divisionLabel}</text>`\n\t\t\t\t: nothing\n\t\t}\n\t`;\n}\n\nfunction renderNorthCell(\n\thouseNum: number,\n\trashiNum: number,\n\tsign: string,\n\tplanets: PlacedGraha[],\n\tisLagna: boolean,\n): TemplateResult {\n\tconst c = NORTH_HOUSE_CENTERS[houseNum];\n\tif (!c) return svg``;\n\t// Tight cells (H2/3/5/6/8/9/11/12 corner triangles) clip the rasi number\n\t// when it sits too high above the centroid. Clamp the upward offset based\n\t// on the cell's distance from the chart vertical centre so the label\n\t// always stays comfortably inside its triangle or diamond.\n\tconst rashiOffsetY = Math.min(14, Math.abs(c.y - CENTRE) * 0.45 + 6);\n\tconst ascOffsetY = rashiOffsetY + 12;\n\t// North cells carry only a rasi number by convention. The ascendant also\n\t// names its sign so the reader can see which sign rises without translating\n\t// the number; other cells stay number-only.\n\tconst rashiLabel = isLagna\n\t\t? `${rashiNum} \u00B7 ${SIGN_ABBR[sign] ?? sign.slice(0, 2)}`\n\t\t: `${rashiNum}`;\n\treturn svg`\n\t\t<g class=${isLagna ? 'cell lagna' : 'cell'}>\n\t\t\t<text class=\"rashi-num\" x=${c.x} y=${c.y - rashiOffsetY} text-anchor=\"middle\" dominant-baseline=\"central\">${rashiLabel}</text>\n\t\t\t${\n\t\t\t\tisLagna\n\t\t\t\t\t? svg`<text class=\"lagna-marker\" x=${c.x} y=${c.y - ascOffsetY} text-anchor=\"middle\" dominant-baseline=\"central\">Asc</text>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t${planets.length ? renderPlanetStack(planets, sign, c.x, c.y + 8, 12) : nothing}\n\t\t</g>\n\t`;\n}\n\nfunction renderNorthSvg(vm: KundliViewModel): TemplateResult {\n\tconst lagnaSign = vm.lagnaSign || 'Aries';\n\treturn svg`\n\t\t${renderNorthFrame(vm.divisionLabel)}\n\t\t${Array.from({ length: 12 }, (_, i) => {\n\t\t\tconst houseNum = i + 1;\n\t\t\tconst rashiNum = rashiInHouse(houseNum, lagnaSign);\n\t\t\tconst sign = SIGNS_ORDER[rashiNum - 1] ?? 'Aries';\n\t\t\treturn renderNorthCell(\n\t\t\t\thouseNum,\n\t\t\t\trashiNum,\n\t\t\t\tsign,\n\t\t\t\tvm.placements[sign.toLowerCase()] ?? [],\n\t\t\t\thouseNum === 1,\n\t\t\t);\n\t\t})}\n\t`;\n}\n\n// ---------------------------------------------------------------------------\n// East Indian (Bengali / Maithili): 3x3 underlying grid, 4 edge rectangles +\n// 4 corner cells each split by a diagonal from the outer chart corner to the\n// inner corner of the centre cell. Aries fixed top-centre; signs proceed\n// counter-clockwise. Houses rotate from the Lagna.\n// ---------------------------------------------------------------------------\n\nconst EAST_CELL = INNER / 3; // 120\n\ninterface EastCell {\n\t/** Vertices of the cell polygon, in viewBox units. */\n\tpoints: Array<{ x: number; y: number }>;\n\t/** Visual centroid for label placement. */\n\tcentroid: { x: number; y: number };\n}\n\nfunction eastCells(): Record<string, EastCell> {\n\tconst a = MARGIN; // 20\n\tconst b = MARGIN + EAST_CELL; // 140\n\tconst c = MARGIN + 2 * EAST_CELL; // 260\n\tconst d = VIEW_BOX - MARGIN; // 380\n\tconst aries = [\n\t\t{ x: b, y: a },\n\t\t{ x: c, y: a },\n\t\t{ x: c, y: b },\n\t\t{ x: b, y: b },\n\t];\n\tconst cancer = [\n\t\t{ x: a, y: b },\n\t\t{ x: b, y: b },\n\t\t{ x: b, y: c },\n\t\t{ x: a, y: c },\n\t];\n\tconst libra = [\n\t\t{ x: b, y: c },\n\t\t{ x: c, y: c },\n\t\t{ x: c, y: d },\n\t\t{ x: b, y: d },\n\t];\n\tconst capricorn = [\n\t\t{ x: c, y: b },\n\t\t{ x: d, y: b },\n\t\t{ x: d, y: c },\n\t\t{ x: c, y: c },\n\t];\n\tconst taurus = [\n\t\t{ x: a, y: a },\n\t\t{ x: b, y: a },\n\t\t{ x: b, y: b },\n\t];\n\tconst gemini = [\n\t\t{ x: a, y: a },\n\t\t{ x: b, y: b },\n\t\t{ x: a, y: b },\n\t];\n\tconst leo = [\n\t\t{ x: a, y: c },\n\t\t{ x: b, y: c },\n\t\t{ x: a, y: d },\n\t];\n\tconst virgo = [\n\t\t{ x: b, y: c },\n\t\t{ x: b, y: d },\n\t\t{ x: a, y: d },\n\t];\n\tconst scorpio = [\n\t\t{ x: c, y: c },\n\t\t{ x: c, y: d },\n\t\t{ x: d, y: d },\n\t];\n\tconst sagittarius = [\n\t\t{ x: c, y: c },\n\t\t{ x: d, y: d },\n\t\t{ x: d, y: c },\n\t];\n\tconst aquarius = [\n\t\t{ x: d, y: a },\n\t\t{ x: d, y: b },\n\t\t{ x: c, y: b },\n\t];\n\tconst pisces = [\n\t\t{ x: c, y: a },\n\t\t{ x: d, y: a },\n\t\t{ x: c, y: b },\n\t];\n\tconst polys = {\n\t\tAries: aries,\n\t\tTaurus: taurus,\n\t\tGemini: gemini,\n\t\tCancer: cancer,\n\t\tLeo: leo,\n\t\tVirgo: virgo,\n\t\tLibra: libra,\n\t\tScorpio: scorpio,\n\t\tSagittarius: sagittarius,\n\t\tCapricorn: capricorn,\n\t\tAquarius: aquarius,\n\t\tPisces: pisces,\n\t} as const;\n\tconst out: Record<string, EastCell> = {};\n\tfor (const [sign, points] of Object.entries(polys)) {\n\t\tout[sign] = { points: [...points], centroid: centroidOf(points) };\n\t}\n\treturn out;\n}\n\nconst EAST_CELLS = eastCells();\n\nfunction renderEastFrame(divisionLabel?: string): TemplateResult {\n\tconst a = MARGIN;\n\tconst b = MARGIN + EAST_CELL;\n\tconst c = MARGIN + 2 * EAST_CELL;\n\tconst d = VIEW_BOX - MARGIN;\n\treturn svg`\n\t\t<rect class=\"line\" x=${a} y=${a} width=${INNER} height=${INNER} stroke-width=\"1.5\" fill=\"none\" />\n\t\t<line class=\"line\" x1=${a} y1=${b} x2=${b} y2=${b} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${c} y1=${b} x2=${d} y2=${b} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${a} y1=${c} x2=${b} y2=${c} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${c} y1=${c} x2=${d} y2=${c} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${b} y1=${a} x2=${b} y2=${b} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${b} y1=${c} x2=${b} y2=${d} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${c} y1=${a} x2=${c} y2=${b} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${c} y1=${c} x2=${c} y2=${d} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${a} y1=${a} x2=${b} y2=${b} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${d} y1=${a} x2=${c} y2=${b} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${d} y1=${d} x2=${c} y2=${c} stroke-width=\"1\" />\n\t\t<line class=\"line\" x1=${a} y1=${d} x2=${b} y2=${c} stroke-width=\"1\" />\n\t\t${\n\t\t\tdivisionLabel\n\t\t\t\t? svg`<text class=\"centre-label\" x=${CENTRE} y=${CENTRE} text-anchor=\"middle\" dominant-baseline=\"central\">${divisionLabel}</text>`\n\t\t\t\t: nothing\n\t\t}\n\t`;\n}\n\nfunction renderEastCell(\n\tsign: string,\n\tplanets: PlacedGraha[],\n\tisLagna: boolean,\n\thouseNum: number,\n): TemplateResult {\n\tconst cell = EAST_CELLS[sign];\n\tif (!cell) return svg``;\n\tconst { centroid: cen, points } = cell;\n\tconst signAbbr = SIGN_ABBR[sign] ?? sign.slice(0, 2);\n\tconst polyPoints = points.map((p) => `${p.x},${p.y}`).join(' ');\n\treturn svg`\n\t\t<g class=${isLagna ? 'cell lagna' : 'cell'}>\n\t\t\t${\n\t\t\t\tisLagna\n\t\t\t\t\t? svg`<polygon class=\"lagna-bg\" points=${polyPoints} />`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t<text class=\"sign-text\" x=${cen.x} y=${cen.y - 16} text-anchor=\"middle\" dominant-baseline=\"central\">${signAbbr}</text>\n\t\t\t${\n\t\t\t\thouseNum > 0\n\t\t\t\t\t? svg`<text class=\"house-num\" x=${cen.x + 18} y=${cen.y - 16} text-anchor=\"start\" dominant-baseline=\"central\">${houseNum}</text>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t${\n\t\t\t\tisLagna\n\t\t\t\t\t? svg`<text class=\"lagna-marker\" x=${cen.x} y=${cen.y - 30} text-anchor=\"middle\" dominant-baseline=\"central\">Asc</text>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t${planets.length ? renderPlanetStack(planets, sign, cen.x, cen.y + 4, 12) : nothing}\n\t\t</g>\n\t`;\n}\n\nfunction renderEastSvg(vm: KundliViewModel): TemplateResult {\n\tconst lagnaKey = vm.lagnaSign.toLowerCase();\n\treturn svg`\n\t\t${renderEastFrame(vm.divisionLabel)}\n\t\t${SIGNS_ORDER.map((sign) =>\n\t\t\trenderEastCell(\n\t\t\t\tsign,\n\t\t\t\tvm.placements[sign.toLowerCase()] ?? [],\n\t\t\t\tsign.toLowerCase() === lagnaKey,\n\t\t\t\thouseNumberInSign(sign, vm.lagnaSign),\n\t\t\t),\n\t\t)}\n\t`;\n}\n\n// ---------------------------------------------------------------------------\n// Public entry point\n// ---------------------------------------------------------------------------\n\n/**\n * Render the kundli body for the requested style. Returns the SVG inner\n * content; the caller wraps it in an `<svg>` element with the canonical\n * viewBox `0 0 400 400` and applies its own theming CSS.\n */\nexport function renderKundliSvg(\n\tvm: KundliViewModel,\n\tstyle: ChartStyle,\n): TemplateResult {\n\tswitch (style) {\n\t\tcase 'north':\n\t\t\treturn renderNorthSvg(vm);\n\t\tcase 'east':\n\t\t\treturn renderEastSvg(vm);\n\t\tdefault:\n\t\t\treturn renderSouthSvg(vm);\n\t}\n}\n\n/**\n * Render a WAI-ARIA-compliant tablist that lets the end user switch between\n * South / North / East kundli styles at runtime. The hosting component owns\n * the `chartStyle` state; this helper renders the buttons and wires the\n * arrow-key navigation plus click handler.\n *\n * @param active - The currently selected style.\n * @param setStyle - Callback the host component uses to update its state.\n */\nexport function renderKundliStyleTablist(\n\tactive: ChartStyle,\n\tsetStyle: (next: ChartStyle) => void,\n): TemplateResult {\n\treturn renderTablist({\n\t\titems: CHART_STYLES,\n\t\tactive,\n\t\tonSelect: setStyle,\n\t\tlabel: 'Kundli style',\n\t\tidPrefix: 'kundli',\n\t});\n}\n", "/**\n * Math helpers for converting raw ecliptic longitude decimals into the\n * sign / degree / minute / second triplet used across chart components.\n */\n\nimport { SIGNS_ORDER } from '../tokens/index.js';\n\nexport interface SignPosition {\n\tsign: string;\n\tsignIndex: number;\n\tdegree: number;\n\tminute: number;\n\tsecond: number;\n}\n\n/**\n * Wrap longitude into [0, 360) so negative or out-of-range values still\n * resolve to a real sign. Robust to wonky upstream data.\n */\nexport function normalizeLongitude(lon: number): number {\n\tconst wrapped = lon % 360;\n\treturn wrapped < 0 ? wrapped + 360 : wrapped;\n}\n\n/**\n * Convert decimal ecliptic longitude (0-360) into sign/degree/minute/second.\n * Used by every chart wheel and aspect table.\n */\nexport function longitudeToSignPosition(longitude: number): SignPosition {\n\tconst lon = normalizeLongitude(longitude);\n\tconst signIndex = Math.floor(lon / 30) % 12;\n\tconst within = lon % 30;\n\tconst degree = Math.floor(within);\n\tconst minuteFloat = (within - degree) * 60;\n\tconst minute = Math.floor(minuteFloat);\n\tconst second = Math.round((minuteFloat - minute) * 60);\n\treturn {\n\t\tsign: SIGNS_ORDER[signIndex] ?? 'Aries',\n\t\tsignIndex,\n\t\tdegree,\n\t\tminute,\n\t\tsecond,\n\t};\n}\n\n/** Compact display string like \"12\u00B0 Leo 34'\". Used in chart labels. */\nexport function formatSignPosition(longitude: number): string {\n\tconst { sign, degree, minute } = longitudeToSignPosition(longitude);\n\treturn `${degree}\u00B0 ${sign} ${String(minute).padStart(2, '0')}'`;\n}\n\n/** Format a within-sign decimal degree (0-30) as degree-and-minute, e.g. 17.99 to \"17\u00B059'\". The reference-grade form astrologers read when the sign is already known (asteroids, lots, directed points, fixed stars). */\nexport function formatDegreeInSign(deg: number): string {\n\tlet d = Math.floor(deg);\n\tlet m = Math.round((deg - d) * 60);\n\tif (m === 60) {\n\t\tm = 0;\n\t\td += 1;\n\t}\n\treturn `${d}\u00B0${String(m).padStart(2, '0')}'`;\n}\n\n/**\n * The point diametrically opposite a longitude (e.g. Descendant from\n * Ascendant, IC from MC). Exact derivation, always 180 degrees away.\n */\nexport function oppositePoint(longitude: number): number {\n\treturn normalizeLongitude(longitude + 180);\n}\n\n/**\n * Midpoint of the forward arc from `start` to `end` (both ecliptic\n * longitudes). Handles the 360/0 wrap, so a house spanning 350 to 20 degrees\n * yields a midpoint of 5, not 185. Used to place house numbers between two\n * cusps regardless of how unequal the house is.\n */\nexport function arcMidpoint(start: number, end: number): number {\n\tconst s = normalizeLongitude(start);\n\tlet span = normalizeLongitude(end) - s;\n\tif (span < 0) span += 360;\n\treturn normalizeLongitude(s + span / 2);\n}\n\n/** Polar to cartesian for SVG wheel positioning. Angle in degrees, 0 at 3 o'clock. */\nexport function polarToCartesian(\n\tcx: number,\n\tcy: number,\n\tradius: number,\n\tangleDeg: number,\n): { x: number; y: number } {\n\tconst angleRad = (angleDeg * Math.PI) / 180;\n\treturn {\n\t\tx: cx + radius * Math.cos(angleRad),\n\t\ty: cy + radius * Math.sin(angleRad),\n\t};\n}\n", "import type { TemplateResult } from 'lit';\nimport { css, html, nothing } from 'lit';\n\n/** A single tab in a {@link renderTablist} strip. */\nexport interface TablistItem<T extends string = string> {\n\tid: T;\n\tlabel: string;\n}\n\n/**\n * Shared styling for every horizontal tab strip in the library (natal chart\n * views, transits, kundli styles). Keeping one rule set means the tabs look\n * identical everywhere and theme through the same --roxy-* tokens.\n */\nexport const tablistStyles = css`.roxy-tablist{border-bottom:2px solid var(--roxy-border,#e4e4e7);gap:2px;display:flex}.roxy-tab{padding:var(--roxy-space-xs,.25rem) var(--roxy-space-md,1rem);font-size:var(--roxy-text-sm,.875rem);cursor:pointer;color:var(--roxy-muted,#71717a);transition:color var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,ease);background:0 0;border:none;border-bottom:2px solid #0000;margin-bottom:-2px;font-family:inherit}.roxy-tab[aria-selected=true]{color:var(--roxy-accent-ink,#b45309);border-bottom-color:var(--roxy-accent,#f59e0b);font-weight:var(--roxy-weight-bold,600)}.roxy-tab:hover:not([aria-selected=true]){color:var(--roxy-fg,#0a0a0a)}.roxy-tab:focus-visible{outline:2px solid var(--roxy-ring,#f59e0b66);outline-offset:2px;border-radius:4px}`;\n\n/**\n * Render a WAI-ARIA tablist. The host component owns the active-tab state; this\n * helper draws the buttons, wires click plus Left/Right arrow navigation with a\n * roving tabindex, and moves focus to the newly selected tab. Pair with\n * {@link tablistStyles}.\n *\n * Pass `controls: true` when each tab governs a sibling\n * `<div role=\"tabpanel\" id=\"${idPrefix}-panel-${id}\">` so the buttons advertise\n * `aria-controls`. Omit it for tablists that swap a single rendered view in\n * place with no separate panel element (the kundli style switch).\n *\n * @example\n * ```ts\n * renderTablist({\n * items: [{ id: 'wheel', label: 'Wheel' }, { id: 'grid', label: 'Aspect grid' }],\n * active: this.view,\n * onSelect: (v) => { this.view = v; },\n * label: 'Natal chart views',\n * idPrefix: 'natal',\n * controls: true,\n * })\n * ```\n */\nexport function renderTablist<T extends string>(opts: {\n\titems: ReadonlyArray<TablistItem<T>>;\n\tactive: T;\n\tonSelect: (id: T) => void;\n\tlabel: string;\n\tidPrefix: string;\n\tcontrols?: boolean;\n}): TemplateResult {\n\tconst { items, active, onSelect, label, idPrefix, controls = false } = opts;\n\tconst onKeyDown = (e: KeyboardEvent) => {\n\t\tif (e.key !== 'ArrowRight' && e.key !== 'ArrowLeft') return;\n\t\te.preventDefault();\n\t\tconst idx = items.findIndex((it) => it.id === active);\n\t\tif (idx === -1) return;\n\t\tconst delta = e.key === 'ArrowRight' ? 1 : -1;\n\t\tconst next = items[(idx + delta + items.length) % items.length];\n\t\tif (!next) return;\n\t\tonSelect(next.id);\n\t\tconst root = (e.currentTarget as HTMLElement).getRootNode() as\n\t\t\t| ShadowRoot\n\t\t\t| Document;\n\t\trequestAnimationFrame(() => {\n\t\t\troot\n\t\t\t\t.querySelector<HTMLButtonElement>(`#${idPrefix}-tab-${next.id}`)\n\t\t\t\t?.focus();\n\t\t});\n\t};\n\treturn html`<div class=\"roxy-tablist\" role=\"tablist\" aria-label=\"${label}\" @keydown=\"${onKeyDown}\">${items.map(\n\t\t\t(it) => html`<button type=\"button\" class=\"roxy-tab\" role=\"tab\" id=\"${idPrefix}-tab-${it.id}\" aria-selected=\"${active === it.id ? 'true' : 'false'}\" aria-controls=\"${\n\t\t\t\t\t// Only the active panel is rendered, so only the active tab points\n\t\t\t\t\t// at a live element; otherwise aria-controls would dangle.\n\t\t\t\t\tcontrols && active === it.id ? `${idPrefix}-panel-${it.id}` : nothing\n\t\t\t\t}\" tabindex=\"${active === it.id ? '0' : '-1'}\" @click=\"${() => onSelect(it.id)}\">${it.label}</button>`,\n\t\t)}</div>`;\n}\n", "import { css } from 'lit';\n\n/**\n * Shared CSS for every kundli renderer (`<roxy-vedic-kundli>`,\n * `<roxy-divisional-chart>`, and any future `<roxy-navamsa-chart>`). Centralises\n * the SVG layout (responsive viewBox + aspect ratio), the line/text classes,\n * and the Lagna highlight so the three components stay visually identical.\n *\n * @remarks Font sizes are written in viewBox user units (the chart is 400\u00D7400\n * inside a 1:1 aspect-ratio container), so they scale linearly from a 320px\n * phone surface to a wall projector without raster loss. The Lagna palette\n * tracks `--roxy-accent` so host themes flow through unchanged.\n */\nexport const kundliStyles = css`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.header{justify-content:space-between;align-items:center;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}svg{width:100%;max-width:var(--roxy-chart-max-width,560px);aspect-ratio:1;height:auto;margin:0 auto;display:block}.line{fill:#0000;stroke:var(--roxy-border,#d4d4d8)}.sign-text{fill:var(--roxy-muted,#71717a);font-size:11px;font-weight:500;font-family:var(--roxy-font-sans);text-transform:uppercase;letter-spacing:.04em}.rashi-num{fill:var(--roxy-muted,#71717a);font-size:12px;font-weight:500;font-family:var(--roxy-font-sans)}.house-num{fill:var(--roxy-accent-ink,#b45309);font-size:11px;font-weight:600;font-family:var(--roxy-font-sans);opacity:.85}.planet-text{fill:var(--roxy-fg,#0a0a0a);font-size:13px;font-weight:600;font-family:var(--roxy-font-sans)}.centre-label{fill:var(--roxy-muted,#71717a);font-size:14px;font-weight:600;font-family:var(--roxy-font-sans);letter-spacing:.02em}.lagna-marker{fill:var(--roxy-accent-ink,#b45309);font-size:10px;font-weight:700;font-family:var(--roxy-font-sans);letter-spacing:.08em;text-transform:uppercase}.lagna-bg{fill:color-mix(in srgb, var(--roxy-accent,#f59e0b) 14%, transparent)}.lagna-slash{stroke:var(--roxy-accent,#f59e0b);stroke-linecap:round;opacity:.7}`;\n", "import { css, html, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type {\n\tKalsarpaResponse,\n\tManglikResponse,\n\tSadhesatiResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\ntype DoshaData = ManglikResponse | KalsarpaResponse | SadhesatiResponse;\n\nconst DOSHA_LABELS: Record<string, string> = {\n\tmanglik: 'Mangal Dosha',\n\tkalsarpa: 'Kaal Sarp Dosha',\n\tsadhesati: 'Sade Sati',\n};\n\n/**\n * Dosha presence card. Renders /vedic-astrology/dosha/{manglik,kalsarpa,sadhesati}.\n * Visual severity indicator + remedies + scoped effects.\n */\n@customElement('roxy-dosha-card')\nexport class RoxyDoshaCard extends RoxyDataElement<DoshaData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.card{background:var(--roxy-surface,#fff);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:center;gap:var(--roxy-space-md,1rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);text-transform:capitalize;margin:0}.subtype{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);margin:0}.subtype .subtype-label{color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;font-size:var(--roxy-text-xs,.75rem);margin-right:.4rem}.badge{align-items:center;gap:var(--roxy-space-xs,.25rem);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;letter-spacing:.06em;padding:4px 10px;display:inline-flex}.badge.absent{background:color-mix(in srgb, var(--roxy-success,#16a34a) 16%, transparent);color:var(--roxy-success-fg,#166534)}.badge.present{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 16%, transparent);color:var(--roxy-danger-fg,#991b1b)}.severity-bar{background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 30%, transparent);border-radius:4px;width:100%;height:8px;position:relative;overflow:hidden}.severity-fill{height:100%;transition:width var(--roxy-motion-duration,.2s) ease-out;border-radius:4px;display:block}@media (prefers-reduced-motion:reduce){.severity-fill{transition:none}}.description{color:var(--roxy-fg,#0a0a0a);margin:0}h3{margin:0 0 var(--roxy-space-xs,.25rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em}ul{padding-left:var(--roxy-space-md,1rem);font-size:var(--roxy-text-sm,.875rem);margin:0}.effects{gap:var(--roxy-space-md,1rem);grid-template-columns:repeat(auto-fit,minmax(12rem,1fr));display:grid}.effects p{font-size:var(--roxy-text-sm,.875rem);margin:0}`,\n\t];\n\n\t@property({ type: String, reflect: true })\n\ttype: 'manglik' | 'kalsarpa' | 'sadhesati' | string = 'manglik';\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No dosha data</div>`;\n\t}\n\n\tprotected renderData(d: DoshaData) {\n\t\tconst present = !!d.present;\n\t\tconst label = DOSHA_LABELS[this.type] ?? this.type;\n\t\tconst sevLower = (d.severity ?? '').toLowerCase();\n\t\tconst tier =\n\t\t\tsevLower === 'severe'\n\t\t\t\t? 3\n\t\t\t\t: sevLower === 'moderate'\n\t\t\t\t\t? 2\n\t\t\t\t\t: sevLower === 'mild'\n\t\t\t\t\t\t? 1\n\t\t\t\t\t\t: 0;\n\t\tconst pct = tier * 33;\n\t\t// A present dosha is never \"good news\": keep the ramp in the warning/danger\n\t\t// family so a Mild severity does not paint green and read as benign. The bar\n\t\t// width already conveys the tier.\n\t\tconst barColor =\n\t\t\ttier === 3\n\t\t\t\t? 'var(--roxy-danger)'\n\t\t\t\t: tier >= 1\n\t\t\t\t\t? 'var(--roxy-warning)'\n\t\t\t\t\t: 'transparent';\n\n\t\treturn html`<article class=\"card\" aria-label=\"${label}\"><header class=\"head\"><h2 class=\"title\">${label}</h2><span class=\"${`badge ${present ? 'present' : 'absent'}`}\">${present ? 'Present' : 'Absent'}</span></header>${\n\t\t\t\t'type' in d && d.type\n\t\t\t\t\t? html`<p class=\"subtype\"><span class=\"subtype-label\">${this.type === 'sadhesati' ? 'Current phase' : 'Type'}</span>${d.type}</p>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\td.severity\n\t\t\t\t\t? html`<div class=\"severity-bar\" role=\"meter\" aria-valuemin=\"0\" aria-valuemax=\"3\" aria-valuenow=\"${tier}\" aria-label=\"Severity ${d.severity}\"><span class=\"severity-fill\" style=\"width:${pct}%;background:${barColor}\"></span></div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${d.description ? html`<p class=\"description\">${d.description}</p>` : nothing} ${this.renderEffects(d)} ${\n\t\t\t\td.remedies && d.remedies.length > 0\n\t\t\t\t\t? html`<div><h3>Remedies</h3><ul>${d.remedies.map((r) => html`<li>${r}</li>`)}</ul></div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\t'exceptions' in d && d.exceptions && d.exceptions.length > 0\n\t\t\t\t\t? html`<div><h3>Exceptions</h3><ul>${d.exceptions.map((r) => html`<li>${r}</li>`)}</ul></div>`\n\t\t\t\t\t: nothing\n\t\t\t}</article>`;\n\t}\n\n\tprivate renderEffects(d: DoshaData) {\n\t\tif (!d.effects) return nothing;\n\t\t// Effects mix flat string fields (marriage, career...) with a nested map\n\t\t// (Sadhesati effects.phases: { Rising, Peak, Setting }). Render both; the\n\t\t// old string-only filter silently dropped the phase-specific effects, which\n\t\t// are the substance of a Sade Sati reading.\n\t\tconst sections: unknown[] = [];\n\t\tfor (const [key, value] of Object.entries(\n\t\t\td.effects as Record<string, unknown>,\n\t\t)) {\n\t\t\tif (typeof value === 'string' && value.length > 0) {\n\t\t\t\tsections.push(html`<div><h3>${key}</h3><p>${value}</p></div>`);\n\t\t\t} else if (value && typeof value === 'object') {\n\t\t\t\tfor (const [nestedKey, nestedValue] of Object.entries(\n\t\t\t\t\tvalue as Record<string, unknown>,\n\t\t\t\t)) {\n\t\t\t\t\tif (typeof nestedValue === 'string' && nestedValue.length > 0) {\n\t\t\t\t\t\tsections.push(\n\t\t\t\t\t\t\thtml`<div><h3>${nestedKey}</h3><p>${nestedValue}</p></div>`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (sections.length === 0) return nothing;\n\t\treturn html`<div class=\"effects\">${sections}</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-dosha-card': RoxyDoshaCard;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { GetDreamSymbolResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\n/**\n * Dream symbol card. Renders /dreams/symbols/{id}: the symbol name as a heading, the full psychological interpretation as the body, and the dictionary letter as a chip for alphabetical context.\n */\n@customElement('roxy-dream-card')\nexport class RoxyDreamCard extends RoxyDataElement<GetDreamSymbolResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.card{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{align-items:center;gap:var(--roxy-space-md,1rem);display:flex}.letter{border-radius:var(--roxy-radius-full,9999px);background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 16%, transparent);width:2.5rem;height:2.5rem;color:var(--roxy-accent-ink,#b45309);font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;font-variant-numeric:tabular-nums;flex:none;justify-content:center;align-items:center;display:inline-flex}.label{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;margin:0}.name{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-fg,#0a0a0a);margin:0}.meaning{color:var(--roxy-fg,#0a0a0a);margin:0;line-height:1.6}`,\n\t];\n\n\tprotected renderData(d: GetDreamSymbolResponse) {\n\t\treturn html`<article class=\"card\" aria-label=\"${d.name ?? 'Dream symbol'}\"><header class=\"head\">${d.letter ? html`<span class=\"letter\" aria-hidden=\"true\">${d.letter}</span>` : nothing}<div><p class=\"label\">Dream symbol</p>${d.name ? html`<h2 class=\"name\">${d.name}</h2>` : nothing}</div></header>${d.meaning ? html`<p class=\"meaning\">${d.meaning}</p>` : nothing}</article>`;\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No dream symbol</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-dream-card': RoxyDreamCard;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { SearchDreamSymbolsResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\ntype DreamSymbol = NonNullable<SearchDreamSymbolsResponse['symbols']>[number];\n\n/**\n * Dream-symbol search results. Renders /dreams/symbols (the `q` search): the matched symbols as selectable tiles. In self-fetch mode the base renders the search input and this lists the matches. Selecting a result emits a `roxy-symbol-select` CustomEvent ({ id, name, letter }) that bubbles and is composed, so a host pairs it with a roxy-dream-card to show the full meaning. This is the dreams form-mode analog of roxy-location-search.\n */\n@customElement('roxy-dream-search')\nexport class RoxyDreamSearch extends RoxyDataElement<SearchDreamSymbolsResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-md,1rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.count{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}.grid{gap:var(--roxy-space-sm,.5rem);grid-template-columns:repeat(auto-fill,minmax(8rem,1fr));margin:0;padding:0;list-style:none;display:grid}.result{align-items:center;gap:var(--roxy-space-sm,.5rem);text-align:left;width:100%;font:inherit;color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);cursor:pointer;background:0 0;transition:border-color .12s,background .12s;display:flex}.result:hover,.result:focus-visible{border-color:var(--roxy-accent,#f59e0b);background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 8%, transparent);outline:none}.letter{border-radius:var(--roxy-radius-full,9999px);background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 16%, transparent);width:1.6rem;height:1.6rem;color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;flex:none;place-items:center;display:grid}.name{font-size:var(--roxy-text-sm,.875rem);font-weight:500}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No symbols match</div>`;\n\t}\n\n\tprotected renderData(d: SearchDreamSymbolsResponse) {\n\t\tconst symbols = d.symbols ?? [];\n\t\tif (symbols.length === 0) return this.renderEmpty();\n\t\tconst total = typeof d.total === 'number' ? d.total : symbols.length;\n\n\t\treturn html`<section class=\"wrap\" aria-label=\"Dream symbols\"><header class=\"head\"><h2 class=\"title\">Dream Symbols</h2><span class=\"count\">${total} match${total === 1 ? '' : 'es'}</span></header><ul class=\"grid\">${symbols.map(\n\t\t\t\t\t(s) => html`<li><button type=\"button\" class=\"result\" @click=\"${() => this.select(s)}\">${s.letter ? html`<span class=\"letter\" aria-hidden=\"true\">${s.letter}</span>` : nothing} <span class=\"name\">${s.name}</span></button></li>`,\n\t\t\t\t)}</ul></section>`;\n\t}\n\n\t/** Emit the chosen symbol so a host can load its detail (e.g. into a roxy-dream-card). */\n\tprivate select(s: DreamSymbol) {\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('roxy-symbol-select', {\n\t\t\t\tdetail: { id: s.id, name: s.name, letter: s.letter },\n\t\t\t\tbubbles: true,\n\t\t\t\tcomposed: true,\n\t\t\t}),\n\t\t);\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-dream-search': RoxyDreamSearch;\n\t}\n}\n", "import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { humanize } from '../utils/string.js';\n\ninterface OpenApiSchemaRef {\n\t$ref?: string;\n}\n\ninterface OpenApiSchema extends OpenApiSchemaRef {\n\ttype?: string;\n\tformat?: string;\n\tdescription?: string;\n\tenum?: string[];\n\tdefault?: unknown;\n\tminimum?: number;\n\tmaximum?: number;\n\tproperties?: Record<string, OpenApiSchema>;\n\trequired?: string[];\n\titems?: OpenApiSchema;\n\texample?: unknown;\n}\n\ninterface FieldDef {\n\t/** Unique storage + input key: the property name, or \"group.name\" for a nested object field. */\n\tkey: string;\n\t/** Schema property name (the label source), e.g. \"date\". */\n\tname: string;\n\t/** Parent object key for a nested schema (person1/person2); undefined for a flat field. */\n\tgroup?: string;\n\ttype: string;\n\trequired: boolean;\n\tdescription?: string;\n\tenum?: string[];\n\tmin?: number;\n\tmax?: number;\n\tdefault?: unknown;\n}\n\ninterface OpenApiDoc {\n\tpaths?: Record<string, Record<string, unknown>>;\n\tcomponents?: { schemas?: Record<string, OpenApiSchema> };\n}\n\nconst specCache = new Map<string, Promise<OpenApiDoc>>();\n\nasync function loadSpec(url: string): Promise<OpenApiDoc> {\n\tlet pending = specCache.get(url);\n\tif (!pending) {\n\t\tpending = fetch(url)\n\t\t\t.then(async (res) => {\n\t\t\t\tif (!res.ok) throw new Error(`HTTP ${res.status}`);\n\t\t\t\treturn (await res.json()) as OpenApiDoc;\n\t\t\t})\n\t\t\t.catch((err) => {\n\t\t\t\t// Evict the rejected promise BEFORE rethrowing so subsequent\n\t\t\t\t// callers (the user clicking Retry, a remount) hit the network\n\t\t\t\t// again instead of replaying the cached failure forever.\n\t\t\t\tspecCache.delete(url);\n\t\t\t\tthrow err;\n\t\t\t});\n\t\tspecCache.set(url, pending);\n\t}\n\treturn pending;\n}\n\n/**\n * Schema-driven form. Pass `endpoint` (e.g. \"vedic-astrology/birth-chart\").\n * The form introspects the cached OpenAPI spec, slots a roxy-location-search\n * when latitude+longitude+timezone fields are present, and emits a\n * `roxy-submit` CustomEvent with the validated payload on submit. The caller\n * decides what to do (call the SDK, render a chart, navigate).\n *\n * At runtime the component fetches the OpenAPI spec (its `spec-url`, default\n * /api/v2/openapi.json) and builds the fields from the operation's request\n * schema: types, enums, required flags, and property order all come from the\n * spec, so a new endpoint gets a working form with no per-endpoint code.\n */\n@customElement('roxy-endpoint-form')\nexport class RoxyEndpointForm extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`form{gap:var(--roxy-space-md,1rem);background:var(--roxy-bg,#fff);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);display:grid}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.fields{align-items:start;gap:var(--roxy-space-md,1rem);grid-template-columns:repeat(auto-fit,minmax(12rem,1fr));display:grid}.person-group{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-md,1rem);margin:0 0 var(--roxy-space-md,1rem);gap:var(--roxy-space-md,1rem);min-inline-size:0;display:grid}.person-group legend{padding:0 var(--roxy-space-xs,.25rem);font-weight:var(--roxy-weight-bold,600);text-transform:capitalize}.field{gap:var(--roxy-space-xs,.25rem);flex-direction:column;min-width:0;display:flex}label{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-secondary,#475569)}label .req{color:var(--roxy-danger-fg,#991b1b);margin-left:4px}input,select{box-sizing:border-box;width:100%;padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);font-size:var(--roxy-text-base,1rem);color:var(--roxy-fg,#0a0a0a);background:var(--roxy-bg,#fff);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);font-family:inherit}input:focus,select:focus{outline:2px solid var(--roxy-ring,#f59e0b66);outline-offset:2px;border-color:var(--roxy-accent-ink,#b45309)}.help{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem)}.location-block{gap:var(--roxy-space-xs,.25rem);grid-column:1/-1;display:grid}.coords{gap:var(--roxy-space-sm,.5rem);grid-template-columns:repeat(3,1fr);display:grid}.coords input{font-size:var(--roxy-text-sm,.875rem)}button.submit{background:var(--roxy-accent-ink,#b45309);color:var(--roxy-bg,#fff);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-lg,1.5rem);font-size:var(--roxy-text-base,1rem);font-weight:var(--roxy-weight-bold,600);cursor:pointer;transition:transform var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,cubic-bezier(.4, 0, .2, 1));border:0;justify-self:start}button.submit:hover{transform:scale(1.02)}button.submit:focus-visible{outline:2px solid var(--roxy-ring,#f59e0b66);outline-offset:2px}.spec-error{gap:var(--roxy-space-md,1rem);background:var(--roxy-bg,#fff);border:1px solid var(--roxy-danger,#dc2626);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);color:var(--roxy-danger-fg,#991b1b);font-size:var(--roxy-text-sm,.875rem);justify-items:start;display:grid}`,\n\t];\n\n\t@property({ type: String, attribute: 'data-endpoint' })\n\tendpoint = 'vedic-astrology/birth-chart';\n\n\t@property({ type: String })\n\tmethod: 'GET' | 'POST' = 'POST';\n\n\t@property({ type: String, attribute: 'spec-url' })\n\tspecUrl = 'https://roxyapi.com/api/v2/openapi.json';\n\n\t@property({ type: String, attribute: 'submit-label' })\n\tsubmitLabel = 'Submit';\n\n\t/** Prefill values, keyed by field name. Used by `remember` mode to restore the last submission. JS property only. */\n\t@property({ attribute: false })\n\tinitialValues?: Record<string, unknown>;\n\n\t@state()\n\tprivate fields: FieldDef[] = [];\n\n\t@state()\n\tprivate values: Record<string, unknown> = {};\n\n\t@state()\n\tprivate loaded = false;\n\n\t@state()\n\tprivate specError: string | null = null;\n\n\tconnectedCallback(): void {\n\t\tsuper.connectedCallback();\n\t\tvoid this.loadSchema();\n\t}\n\n\tprivate async loadSchema() {\n\t\tthis.specError = null;\n\t\ttry {\n\t\t\tconst spec = await loadSpec(this.specUrl);\n\t\t\tconst path = `/${this.endpoint.replace(/^\\//, '')}`;\n\t\t\tconst op = spec.paths?.[path]?.[this.method.toLowerCase()] as\n\t\t\t\t| {\n\t\t\t\t\t\trequestBody?: {\n\t\t\t\t\t\t\tcontent?: Record<\n\t\t\t\t\t\t\t\tstring,\n\t\t\t\t\t\t\t\t{ schema?: OpenApiSchema | OpenApiSchemaRef }\n\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t};\n\t\t\t\t\t\tparameters?: Array<{\n\t\t\t\t\t\t\tname: string;\n\t\t\t\t\t\t\tin: string;\n\t\t\t\t\t\t\trequired?: boolean;\n\t\t\t\t\t\t\tschema?: OpenApiSchema;\n\t\t\t\t\t\t}>;\n\t\t\t\t }\n\t\t\t\t| undefined;\n\t\t\tif (!op) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Endpoint ${this.method} ${path} not found in OpenAPI spec`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst schemas = spec.components?.schemas ?? {};\n\t\t\tconst fields: FieldDef[] = [];\n\t\t\tlet bodySchema: OpenApiSchema | undefined;\n\n\t\t\tif (op.requestBody) {\n\t\t\t\tconst ref = op.requestBody.content?.['application/json']?.schema;\n\t\t\t\tbodySchema = this.resolve(ref, schemas);\n\t\t\t}\n\n\t\t\tif (bodySchema?.properties) {\n\t\t\t\tconst required = new Set(bodySchema.required ?? []);\n\t\t\t\tfor (const [name, sub] of Object.entries(bodySchema.properties)) {\n\t\t\t\t\tconst resolved = this.resolve(sub, schemas) ?? {};\n\t\t\t\t\t// Nested object (e.g. person1/person2 on synastry / guna-milan):\n\t\t\t\t\t// expand into a labelled group of sub-fields keyed \"group.sub\".\n\t\t\t\t\tif (resolved.type === 'object' && resolved.properties) {\n\t\t\t\t\t\tconst subRequired = new Set(resolved.required ?? []);\n\t\t\t\t\t\tfor (const [subName, subSchema] of Object.entries(\n\t\t\t\t\t\t\tresolved.properties,\n\t\t\t\t\t\t)) {\n\t\t\t\t\t\t\tconst r = this.resolve(subSchema, schemas) ?? {};\n\t\t\t\t\t\t\tfields.push({\n\t\t\t\t\t\t\t\tkey: `${name}.${subName}`,\n\t\t\t\t\t\t\t\tname: subName,\n\t\t\t\t\t\t\t\tgroup: name,\n\t\t\t\t\t\t\t\ttype: this.fieldType(r),\n\t\t\t\t\t\t\t\trequired: required.has(name) && subRequired.has(subName),\n\t\t\t\t\t\t\t\tdescription: r.description,\n\t\t\t\t\t\t\t\tenum: r.enum,\n\t\t\t\t\t\t\t\tmin: r.minimum,\n\t\t\t\t\t\t\t\tmax: r.maximum,\n\t\t\t\t\t\t\t\tdefault: r.default,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfields.push({\n\t\t\t\t\t\t\tkey: name,\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\ttype: this.fieldType(resolved),\n\t\t\t\t\t\t\trequired: required.has(name),\n\t\t\t\t\t\t\tdescription: resolved.description,\n\t\t\t\t\t\t\tenum: resolved.enum,\n\t\t\t\t\t\t\tmin: resolved.minimum,\n\t\t\t\t\t\t\tmax: resolved.maximum,\n\t\t\t\t\t\t\tdefault: resolved.default,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const param of op.parameters ?? []) {\n\t\t\t\tif (param.in === 'path' || param.in === 'query') {\n\t\t\t\t\tconst resolved = this.resolve(param.schema, schemas) ?? {};\n\t\t\t\t\tfields.push({\n\t\t\t\t\t\tkey: param.name,\n\t\t\t\t\t\tname: param.name,\n\t\t\t\t\t\ttype: this.fieldType(resolved),\n\t\t\t\t\t\trequired: !!param.required,\n\t\t\t\t\t\tdescription: resolved.description,\n\t\t\t\t\t\tenum: resolved.enum,\n\t\t\t\t\t\tdefault: resolved.default,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.fields = fields;\n\n\t\t\t// Pre-fill: schema defaults first, then any remembered/initial values\n\t\t\t// (only for fields this endpoint has) so a stale stored payload from\n\t\t\t// another endpoint cannot inject unknown keys. Remembered values are the\n\t\t\t// previously-submitted shape (nested per group), so read them by group.\n\t\t\tconst init: Record<string, unknown> = {};\n\t\t\tfor (const f of fields) {\n\t\t\t\tif (f.default !== undefined) init[f.key] = f.default;\n\t\t\t\tconst remembered = f.group\n\t\t\t\t\t? (\n\t\t\t\t\t\t\tthis.initialValues?.[f.group] as\n\t\t\t\t\t\t\t\t| Record<string, unknown>\n\t\t\t\t\t\t\t\t| undefined\n\t\t\t\t\t\t)?.[f.name]\n\t\t\t\t\t: this.initialValues?.[f.name];\n\t\t\t\tif (remembered !== undefined) init[f.key] = remembered;\n\t\t\t}\n\t\t\tthis.values = init;\n\t\t\tthis.loaded = true;\n\t\t} catch (err) {\n\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\tthis.specError = message;\n\t\t\tthis.loaded = true;\n\t\t\tthis.dispatchEvent(\n\t\t\t\tnew CustomEvent('roxy-spec-error', {\n\t\t\t\t\tdetail: { url: this.specUrl, message },\n\t\t\t\t\tbubbles: true,\n\t\t\t\t\tcomposed: true,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate retryLoadSchema = () => {\n\t\tthis.loaded = false;\n\t\tthis.specError = null;\n\t\tvoid this.loadSchema();\n\t};\n\n\tprivate resolve(\n\t\tschema: OpenApiSchema | OpenApiSchemaRef | undefined,\n\t\tall: Record<string, OpenApiSchema>,\n\t): OpenApiSchema | undefined {\n\t\tif (!schema) return undefined;\n\t\tif ('$ref' in schema && schema.$ref) {\n\t\t\tconst name = schema.$ref.split('/').pop();\n\t\t\treturn name ? all[name] : undefined;\n\t\t}\n\t\treturn schema as OpenApiSchema;\n\t}\n\n\tprivate fieldType(s: OpenApiSchema): string {\n\t\tif (s.enum) return 'enum';\n\t\tif (s.format === 'date') return 'date';\n\t\tif (s.format === 'time') return 'time';\n\t\tif (s.format === 'date-time') return 'datetime';\n\t\tif (s.type === 'integer' || s.type === 'number') return 'number';\n\t\treturn 'text';\n\t}\n\n\tprivate setValue(name: string, value: unknown) {\n\t\tthis.values = { ...this.values, [name]: value };\n\t}\n\n\t/** True when the fields in `group` (or the flat top level) carry latitude+longitude+timezone, so a location-search can autofill them. */\n\tprivate groupHasLocation(group?: string): boolean {\n\t\tconst inGroup = this.fields.filter((f) => f.group === group);\n\t\treturn (['latitude', 'longitude', 'timezone'] as const).every((n) =>\n\t\t\tinGroup.some((f) => f.name === n),\n\t\t);\n\t}\n\n\t/** Location-select handler bound to a group: fills that group's lat/lng/timezone keys (flat top level when group is undefined). */\n\tprivate onLocationFor(group?: string) {\n\t\tconst prefix = group ? `${group}.` : '';\n\t\treturn (e: Event) => {\n\t\t\tconst detail = (e as CustomEvent).detail as {\n\t\t\t\tlatitude?: number;\n\t\t\t\tlongitude?: number;\n\t\t\t\ttimezone?: string;\n\t\t\t\tutcOffset?: number;\n\t\t\t};\n\t\t\tif (!detail) return;\n\t\t\tthis.values = {\n\t\t\t\t...this.values,\n\t\t\t\t[`${prefix}latitude`]: detail.latitude,\n\t\t\t\t[`${prefix}longitude`]: detail.longitude,\n\t\t\t\t[`${prefix}timezone`]: detail.timezone ?? detail.utcOffset,\n\t\t\t};\n\t\t};\n\t}\n\n\tprivate onSubmit = (e: Event) => {\n\t\te.preventDefault();\n\t\tconst missing = this.fields\n\t\t\t.filter((f) => f.required)\n\t\t\t.filter(\n\t\t\t\t(f) => this.values[f.key] === undefined || this.values[f.key] === '',\n\t\t\t);\n\t\tif (missing.length > 0) {\n\t\t\tthis.dispatchEvent(\n\t\t\t\tnew CustomEvent('roxy-validation-error', {\n\t\t\t\t\tdetail: { missing: missing.map((m) => m.key) },\n\t\t\t\t\tbubbles: true,\n\t\t\t\t\tcomposed: true,\n\t\t\t\t}),\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\t// Reconstruct the request shape: grouped fields nest as { group: { name: value } }.\n\t\tconst out: Record<string, unknown> = {};\n\t\tfor (const f of this.fields) {\n\t\t\tconst v = this.values[f.key];\n\t\t\tif (v === undefined || v === '') continue;\n\t\t\tif (f.group) {\n\t\t\t\tconst g = (out[f.group] as Record<string, unknown> | undefined) ?? {};\n\t\t\t\tg[f.name] = v;\n\t\t\t\tout[f.group] = g;\n\t\t\t} else {\n\t\t\t\tout[f.name] = v;\n\t\t\t}\n\t\t}\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('roxy-submit', {\n\t\t\t\tdetail: { endpoint: this.endpoint, values: out },\n\t\t\t\tbubbles: true,\n\t\t\t\tcomposed: true,\n\t\t\t}),\n\t\t);\n\t};\n\n\trender() {\n\t\tif (!this.loaded) {\n\t\t\treturn html`<form><div class=\"roxy-skeleton\" style=\"height:8rem\"></div></form>`;\n\t\t}\n\n\t\tif (this.specError) {\n\t\t\treturn html`<div class=\"spec-error\" role=\"alert\">Schema load failed: ${this.specError} <button type=\"button\" class=\"submit\" @click=\"${this.retryLoadSchema}\">Retry</button></div>`;\n\t\t}\n\n\t\tconst renderField = (f: FieldDef) => {\n\t\t\tif (\n\t\t\t\tthis.groupHasLocation(f.group) &&\n\t\t\t\t(f.name === 'latitude' ||\n\t\t\t\t\tf.name === 'longitude' ||\n\t\t\t\t\tf.name === 'timezone')\n\t\t\t) {\n\t\t\t\treturn nothing;\n\t\t\t}\n\t\t\tconst inputId = `roxy-form-${f.key}`;\n\t\t\treturn html`<div class=\"field\"><label for=\"${inputId}\">${humanize(f.name)}${f.required ? html`<span class=\"req\" aria-hidden=\"true\">*</span>` : nothing}</label> ${\n\t\t\t\t\tf.enum\n\t\t\t\t\t\t? html`<select id=\"${inputId}\" ?required=\"${f.required}\" @change=\"${(e: Event) => this.setValue(f.key, (e.target as HTMLSelectElement).value)}\"><option value=\"\">Choose</option>${f.enum.map(\n\t\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\t\topt,\n\t\t\t\t\t\t\t\t) => html`<option value=\"${opt}\" ?selected=\"${this.values[f.key] === opt}\">${opt}</option>`,\n\t\t\t\t\t\t\t)}</select>`\n\t\t\t\t\t\t: html`<input id=\"${inputId}\" type=\"${this.htmlType(f.type)}\" ?required=\"${f.required}\" min=\"${f.min ?? ''}\" max=\"${f.max ?? ''}\" step=\"${f.type === 'number' ? 'any' : ''}\" .value=\"${(this.values[f.key] ?? '') as string}\" @input=\"${(e: Event) =>\n\t\t\t\t\t\t\t\tthis.setValue(\n\t\t\t\t\t\t\t\t\tf.key,\n\t\t\t\t\t\t\t\t\tthis.coerce(f.type, (e.target as HTMLInputElement).value),\n\t\t\t\t\t\t\t\t)}\">`\n\t\t\t\t} ${f.description ? html`<small class=\"help\">${f.description}</small>` : nothing}</div>`;\n\t\t};\n\n\t\t// Ordered list of field groups: the flat top level (undefined) plus each\n\t\t// nested object (person1/person2). Order follows first appearance.\n\t\tconst groups: (string | undefined)[] = [];\n\t\tfor (const f of this.fields) {\n\t\t\tif (!groups.includes(f.group)) groups.push(f.group);\n\t\t}\n\n\t\tconst locationBlock = (group?: string) =>\n\t\t\tthis.groupHasLocation(group)\n\t\t\t\t? html`<div class=\"location-block\"><label>${group ? `${humanize(group)} location` : 'Birth location'}</label><roxy-location-search @roxy-location-select=\"${this.onLocationFor(group)}\" placeholder=\"City of birth\"></roxy-location-search><small class=\"help\">Required: latitude, longitude, timezone. Pick a city to autofill.</small></div>`\n\t\t\t\t: nothing;\n\n\t\tconst groupBody = (group?: string) => html`${locationBlock(group)}<div class=\"fields\">${this.fields.filter((f) => f.group === group).map((f) => renderField(f))}</div>`;\n\n\t\treturn html`<form @submit=\"${this.onSubmit}\"><h2 class=\"title\">${humanize(this.endpoint.split('/').pop() ?? '')}</h2>${groups.map((g) =>\n\t\t\t\tg === undefined\n\t\t\t\t\t? groupBody(undefined)\n\t\t\t\t\t: html`<fieldset class=\"person-group\"><legend>${humanize(g)}</legend>${groupBody(g)}</fieldset>`,\n\t\t\t)} <button class=\"submit\" type=\"submit\">${this.submitLabel}</button></form>`;\n\t}\n\n\tprivate htmlType(t: string): string {\n\t\tswitch (t) {\n\t\t\tcase 'date':\n\t\t\t\treturn 'date';\n\t\t\tcase 'time':\n\t\t\t\treturn 'time';\n\t\t\tcase 'datetime':\n\t\t\t\treturn 'datetime-local';\n\t\t\tcase 'number':\n\t\t\t\treturn 'number';\n\t\t\tdefault:\n\t\t\t\treturn 'text';\n\t\t}\n\t}\n\n\tprivate coerce(t: string, v: string): unknown {\n\t\tif (v === '') return undefined;\n\t\tif (t === 'number') {\n\t\t\tconst n = Number(v);\n\t\t\treturn Number.isFinite(n) ? n : undefined;\n\t\t}\n\t\treturn v;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-endpoint-form': RoxyEndpointForm;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { SIGN_GLYPH } from '../tokens/index.js';\nimport type { FixedStarsResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatDegreeInSign } from '../utils/degree.js';\nimport { chevron, disclosureStyles } from '../utils/disclosure.js';\nimport { formatNumber } from '../utils/format.js';\nimport { capitalize } from '../utils/string.js';\n\ntype Star = FixedStarsResponse['stars'][number];\n\n/**\n * Fixed stars table. Leads with the high-value view from a\n * /astrology/fixed-stars response: every star-to-natal-point conjunction sorted\n * tightest first, each with its reading. The full precessed star catalog\n * (position, magnitude, traditional nature, keywords) sits in a secondary\n * disclosure so the contacts stay front and center.\n */\n@customElement('roxy-fixed-stars')\nexport class RoxyFixedStars extends RoxyDataElement<FixedStarsResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tdisclosureStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);width:100%;color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}header{align-items:baseline;gap:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-primary,#0f172a);margin:0}.badge{border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 14%, transparent);color:var(--roxy-fg,#0a0a0a);padding:2px 8px}.badge b{color:var(--roxy-accent-ink,#b45309);font-weight:600}.summary{color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);margin:0}.empty-note{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem);margin:0}.subhead{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;margin:0 0 var(--roxy-space-sm,.5rem);font-weight:600}.interp-card{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);margin-bottom:var(--roxy-space-xs,.25rem)}.interp-card summary{cursor:pointer;color:var(--roxy-fg,#0a0a0a);justify-content:space-between;align-items:center;gap:var(--roxy-space-md,1rem);font-weight:500;display:flex}.contact{align-items:baseline;gap:.4rem;display:inline-flex}.contact .point{color:var(--roxy-accent-ink,#b45309);font-weight:600}.interp-aside{align-items:center;gap:.5rem;display:inline-flex}.interp-aside small{color:var(--roxy-muted,#71717a);font-variant-numeric:tabular-nums;font-weight:400}.interp-body{margin-top:var(--roxy-space-xs,.25rem);color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem)}.catalog summary{cursor:pointer;color:var(--roxy-fg,#0a0a0a);align-items:center;gap:.5rem;font-weight:600;display:flex}.scroll{margin-top:var(--roxy-space-sm,.5rem);overflow-x:auto}table{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem)}th,td{text-align:left;border-bottom:1px solid var(--roxy-border,#e4e4e7);white-space:nowrap;vertical-align:top;padding:6px 10px}th{color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.04em;font-weight:600;font-size:var(--roxy-text-xs,.75rem)}td.num{text-align:right;font-variant-numeric:tabular-nums}.sg{color:var(--roxy-secondary,#475569);margin-right:.3rem}.kw{white-space:normal;flex-wrap:wrap;gap:.2rem;max-width:18rem;display:flex}.kw span{border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 45%, transparent);color:var(--roxy-fg,#0a0a0a);padding:0 6px}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No fixed star data</div>`;\n\t}\n\n\tprotected renderData(data: FixedStarsResponse) {\n\t\tconst conjunctions = data.conjunctions ?? [];\n\t\tconst stars = data.stars ?? [];\n\t\treturn html`<div class=\"wrap\"><header><h2 class=\"title\">Fixed stars</h2>${\n\t\t\t\t\ttypeof data.orb === 'number'\n\t\t\t\t\t\t? html`<span class=\"badge\"><b>Orb</b> ${formatNumber(data.orb, 1)}\u00B0</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</header>${data.summary ? html`<p class=\"summary\">${data.summary}</p>` : nothing} ${\n\t\t\t\tconjunctions.length\n\t\t\t\t\t? html`<section><p class=\"subhead\">Conjunctions to the chart</p>${conjunctions.map((c, i) => {\n\t\t\t\t\t\t\treturn html`<details class=\"interp-card\" name=\"fixed-star-contacts\" ?open=\"${i === 0}\"><summary><span class=\"contact\"><span class=\"point\">${c.point}</span> conjunct ${c.star}</span> <span class=\"interp-aside\"><small>orb ${formatNumber(c.orb, 2)}\u00B0</small> ${chevron()}</span></summary>${c.interpretation ? html`<div class=\"interp-body\">${c.interpretation}</div>` : nothing}</details>`;\n\t\t\t\t\t\t})}</section>`\n\t\t\t\t\t: html`<p class=\"empty-note\">No star sits within the orb of a natal point.</p>`\n\t\t\t} ${stars.length ? this.renderCatalog(stars) : nothing}</div>`;\n\t}\n\n\tprivate renderCatalog(stars: Star[]) {\n\t\treturn html`<details class=\"catalog\"><summary>${chevron()} Star catalog (${stars.length})</summary><div class=\"scroll\"><table><caption class=\"subhead\">Precessed positions for the chart date</caption><thead><tr><th scope=\"col\">Star</th><th scope=\"col\">Position</th><th scope=\"col\" class=\"num\">Mag</th><th scope=\"col\">Nature</th><th scope=\"col\">Keywords</th></tr></thead><tbody>${stars.map((s) => {\n\t\t\t\t\t\t\tconst g = SIGN_GLYPH[capitalize(s.sign)];\n\t\t\t\t\t\t\treturn html`<tr><td>${s.name}</td><td>${g ? html`<span class=\"sg\">${g}</span>` : nothing}${formatDegreeInSign(s.degree)} ${s.sign}</td><td class=\"num\">${formatNumber(s.magnitude, 1)}</td><td>${s.nature}</td><td><div class=\"kw\">${(s.keywords ?? []).map((k) => html`<span>${k}</span>`)}</div></td></tr>`;\n\t\t\t\t\t\t})}</tbody></table></div></details>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-fixed-stars': RoxyFixedStars;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { GenerateDigestResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatDate, formatNumber } from '../utils/format.js';\nimport { humanize } from '../utils/string.js';\n\ntype DigestWindow = NonNullable<GenerateDigestResponse['windows']>[number];\ntype DigestEvent = NonNullable<DigestWindow['top']>[number];\n\n/**\n * Forecast digest: the rolled-up reading across the next 24 hours, 7, 30, and 90 days. Renders /forecast/digest. Each window shows how many events fall in it, a per-domain breakdown (western, vedic, biorhythm), and the few highest-significance events with a significance bar coloured by domain. Use it as the at-a-glance period summary that pairs with the day-by-day roxy-forecast-timeline.\n */\n@customElement('roxy-forecast-digest')\nexport class RoxyForecastDigest extends RoxyDataElement<GenerateDigestResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-md,1rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.subtitle{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem);margin:0}.window{gap:var(--roxy-space-sm,.5rem);padding-top:var(--roxy-space-md,1rem);border-top:1px solid var(--roxy-border,#e4e4e7);display:grid}.window:first-of-type{border-top:none;padding-top:0}.window-head{flex-wrap:wrap;align-items:baseline;gap:.5rem;display:flex}.window-label{font-weight:var(--roxy-weight-bold,600)}.window-count{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);font-variant-numeric:tabular-nums;margin-left:auto}.domains{flex-wrap:wrap;gap:.4rem;display:flex}.domain-chip{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);align-items:center;gap:.35rem;display:inline-flex}.swatch{border-radius:2px;width:.65rem;height:.65rem;display:inline-block}.sw-western{background:var(--roxy-accent,#f59e0b)}.sw-vedic{background:var(--roxy-info,#2563eb)}.sw-biorhythm{background:var(--roxy-success,#16a34a)}.event{grid-template-columns:auto 1fr;align-items:baseline;gap:.25rem .6rem;display:grid}.event-date{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);font-variant-numeric:tabular-nums;white-space:nowrap}.event-desc{font-size:var(--roxy-text-sm,.875rem);line-height:1.4}.sig{background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 60%, transparent);border-radius:2px;grid-column:2;height:4px;overflow:hidden}.sig-fill{border-radius:2px;height:100%;display:block}.sig-fill.western{background:var(--roxy-accent,#f59e0b)}.sig-fill.vedic{background:var(--roxy-info,#2563eb)}.sig-fill.biorhythm{background:var(--roxy-success,#16a34a)}.quiet{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem);font-style:italic}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No digest data</div>`;\n\t}\n\n\tprotected renderData(d: GenerateDigestResponse) {\n\t\tconst windows = d.windows ?? [];\n\t\tif (windows.length === 0) return this.renderEmpty();\n\t\tconst range = [formatDate(d.startDate), formatDate(d.endDate)]\n\t\t\t.filter(Boolean)\n\t\t\t.join(' \u2013 ');\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Forecast digest\"><div class=\"head\"><h2 class=\"title\">Forecast Digest</h2>${range ? html`<p class=\"subtitle\">${range}</p>` : nothing}</div>${windows.map((w) => this.renderWindow(w))}</div>`;\n\t}\n\n\tprivate windowLabel(days: number | undefined): string {\n\t\tif (days === 1) return 'Next 24 hours';\n\t\treturn typeof days === 'number' ? `Next ${days} days` : 'Window';\n\t}\n\n\tprivate renderWindow(w: DigestWindow) {\n\t\tconst top = w.top ?? [];\n\t\tconst byDomain = w.byDomain ?? {};\n\t\tconst domains = Object.entries(byDomain) as Array<[string, number]>;\n\t\treturn html`<section class=\"window\"><div class=\"window-head\"><span class=\"window-label\">${this.windowLabel(w.days)}</span> <span class=\"window-count\">${w.count ?? 0} event${w.count === 1 ? '' : 's'}</span></div>${\n\t\t\t\tdomains.length > 0\n\t\t\t\t\t? html`<div class=\"domains\">${domains.map(\n\t\t\t\t\t\t\t([dom, n]) => html`<span class=\"domain-chip\"><span class=\"swatch sw-${dom}\"></span>${humanize(dom)} ${n}</span>`,\n\t\t\t\t\t\t)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\ttop.length > 0\n\t\t\t\t\t? html`<div role=\"list\">${top.map((e) => this.renderEvent(e))}</div>`\n\t\t\t\t\t: html`<p class=\"quiet\">No notable events.</p>`\n\t\t\t}</section>`;\n\t}\n\n\tprivate renderEvent(e: DigestEvent) {\n\t\tconst sig = typeof e.significance === 'number' ? e.significance : 0;\n\t\treturn html`<div class=\"event\" role=\"listitem\"><span class=\"event-date\">${formatDate(e.date)}</span> <span class=\"event-desc\">${e.description ?? humanize(e.type ?? '')}</span> <span class=\"sig\" role=\"img\" aria-label=\"significance ${formatNumber(sig, 0)} of 100\"><span class=\"sig-fill ${e.domain}\" style=\"width:${Math.max(0, Math.min(100, sig))}%\"></span></span></div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-forecast-digest': RoxyForecastDigest;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { ASPECT_SYMBOL } from '../tokens/index.js';\nimport type {\n\tFindSignificantDatesResponse,\n\tForecastTransitsResponse,\n\tGenerateTimelineResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { ASPECT_CLASS, formatDate, formatNumber } from '../utils/format.js';\nimport { capitalize, humanize } from '../utils/string.js';\n\n/** Timeline, significant-dates, and forecast-transits all return the same `{ events, startDate, endDate, birthData, count }` shape. */\ntype ForecastTimelineData =\n\t| GenerateTimelineResponse\n\t| FindSignificantDatesResponse\n\t| ForecastTransitsResponse;\n\ntype ForecastEvent = GenerateTimelineResponse['events'][number];\ntype ForecastDomain = ForecastEvent['domain'];\n\n/**\n * Display label per forecast domain. Keyed by the spec `domain` union so a new\n * domain in the spec surfaces as a typecheck failure here rather than an\n * unlabeled swatch.\n */\nconst DOMAIN_LABEL: Record<ForecastDomain, string> = {\n\twestern: 'Western',\n\tvedic: 'Vedic',\n\tbiorhythm: 'Biorhythm',\n};\n\nconst DOMAIN_ORDER: readonly ForecastDomain[] = [\n\t'western',\n\t'vedic',\n\t'biorhythm',\n];\n\n/**\n * Cross-domain forecast timeline. Pass `data` from /forecast/timeline. Events\n * are grouped by calendar date down a vertical axis, each colored by its domain\n * and weighted by significance (0-100), showing the event type, body, target,\n * aspect, and description. The visual language matches the dasha timeline: a\n * left rail of dates, a significance bar per event, and a colored marker for\n * the domain.\n *\n * Theming flows through `--roxy-*` custom properties on `:host`.\n */\n@customElement('roxy-forecast-timeline')\nexport class RoxyForecastTimeline extends RoxyDataElement<ForecastTimelineData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.range{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem);font-variant-numeric:tabular-nums}.legend{gap:var(--roxy-space-md,1rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);flex-wrap:wrap;display:flex}.legend .swatch{vertical-align:middle;border-radius:50%;width:10px;height:10px;margin-right:4px;display:inline-block}.swatch-western{background:var(--roxy-accent,#f59e0b)}.swatch-vedic{background:var(--roxy-info,#2563eb)}.swatch-biorhythm{background:var(--roxy-success,#16a34a)}.day{gap:var(--roxy-space-md,1rem);padding-block:var(--roxy-space-sm,.5rem);border-top:1px solid var(--roxy-border,#e4e4e7);grid-template-columns:4.5rem 1fr;display:grid}.day:first-of-type{border-top:none}.day-date{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);font-variant-numeric:tabular-nums;padding-top:2px}.events{gap:var(--roxy-space-sm,.5rem);display:grid}.event{gap:var(--roxy-space-sm,.5rem);grid-template-columns:.6rem 1fr;align-items:start;display:grid}.dot{border-radius:50%;width:.6rem;height:.6rem;margin-top:4px}.dot-western{background:var(--roxy-accent,#f59e0b)}.dot-vedic{background:var(--roxy-info,#2563eb)}.dot-biorhythm{background:var(--roxy-success,#16a34a)}.event-body{min-width:0}.event-line{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a)}.event-line .aspect-trine,.event-line .aspect-sextile{color:var(--roxy-success-fg,#166534)}.event-line .aspect-square,.event-line .aspect-opposition{color:var(--roxy-danger-fg,#991b1b)}.event-line .aspect-conjunction{color:var(--roxy-accent-ink,#b45309)}.event-line .kind{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);text-transform:uppercase;letter-spacing:.04em;margin-left:.35em}.event-desc{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);margin:2px 0 0}.sig{align-items:center;gap:.4rem;margin-top:4px;display:flex}.sig-track{background:var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-full,9999px);flex:1;max-width:8rem;height:4px;overflow:hidden}.sig-fill{border-radius:var(--roxy-radius-full,9999px);height:100%;display:block}.sig-fill-western{background:var(--roxy-accent,#f59e0b)}.sig-fill-vedic{background:var(--roxy-info,#2563eb)}.sig-fill-biorhythm{background:var(--roxy-success,#16a34a)}.sig-val{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);font-variant-numeric:tabular-nums}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No forecast data</div>`;\n\t}\n\n\tprotected renderData(d: ForecastTimelineData) {\n\t\tconst events = d.events ?? [];\n\t\tconst grouped = this.groupByDate(events);\n\t\tconst present = DOMAIN_ORDER.filter((dom) =>\n\t\t\tevents.some((e) => e.domain === dom),\n\t\t);\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Forecast timeline\"><header class=\"head\"><h2 class=\"title\">Forecast timeline</h2>${\n\t\t\t\t\td.startDate && d.endDate\n\t\t\t\t\t\t? html`<div class=\"range\">${formatDate(d.startDate)} - ${formatDate(d.endDate)} \u00B7 ${d.count ?? events.length} events</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</header>${\n\t\t\t\tpresent.length\n\t\t\t\t\t? html`<div class=\"legend\">${present.map(\n\t\t\t\t\t\t\t(dom) =>\n\t\t\t\t\t\t\t\thtml`<span><span class=\"swatch swatch-${dom}\"></span>${DOMAIN_LABEL[dom]}</span>`,\n\t\t\t\t\t\t)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tgrouped.length\n\t\t\t\t\t? html`<div class=\"days\" role=\"list\">${grouped.map(([date, dayEvents]) => this.renderDay(date, dayEvents))}</div>`\n\t\t\t\t\t: html`<p class=\"roxy-empty\" role=\"status\">No events in this window</p>`\n\t\t\t}</div>`;\n\t}\n\n\t/** Group events by their calendar date, preserving response order. */\n\tprivate groupByDate(\n\t\tevents: ForecastEvent[],\n\t): Array<[string, ForecastEvent[]]> {\n\t\tconst map = new Map<string, ForecastEvent[]>();\n\t\tfor (const e of events) {\n\t\t\tconst key = e.date ?? '';\n\t\t\tconst list = map.get(key) ?? [];\n\t\t\tlist.push(e);\n\t\t\tmap.set(key, list);\n\t\t}\n\t\treturn [...map.entries()];\n\t}\n\n\tprivate renderDay(date: string, events: ForecastEvent[]) {\n\t\treturn html`<div class=\"day\" role=\"listitem\"><div class=\"day-date\">${formatDate(date)}</div><div class=\"events\">${events.map((e) => this.renderEvent(e))}</div></div>`;\n\t}\n\n\tprivate renderEvent(e: ForecastEvent) {\n\t\tconst sig = typeof e.significance === 'number' ? e.significance : 0;\n\t\tconst width = Math.max(0, Math.min(100, sig));\n\t\treturn html`<div class=\"event\"><span class=\"dot dot-${e.domain}\" aria-hidden=\"true\"></span><div class=\"event-body\"><div class=\"event-line\">${this.renderHeadline(e)}</div>${e.description ? html`<p class=\"event-desc\">${e.description}</p>` : nothing}<div class=\"sig\" title=\"Significance ${width} of 100\"><span class=\"sig-track\"><span class=\"sig-fill sig-fill-${e.domain}\" style=\"width:${width}%\"></span> </span><span class=\"sig-val\">${width}</span></div></div></div>`;\n\t}\n\n\t/**\n\t * Compact event headline built from the spec fields. Transit aspects read\n\t * \"body aspect target\"; ingresses, stations, eclipses, dasha changes, and\n\t * critical days fall back to \"body\" plus the qualifier the spec carries for\n\t * that type (station direction, eclipse kind). The aspect symbol is colored\n\t * by nature, matching the chart aspect encoding.\n\t */\n\tprivate renderHeadline(e: ForecastEvent) {\n\t\tconst body = e.body ? capitalize(e.body) : '';\n\t\tconst target = e.target ? capitalize(e.target) : '';\n\t\tconst aspect = e.aspect ? e.aspect.toLowerCase() : '';\n\t\tconst aspectClass = ASPECT_CLASS[aspect] ?? '';\n\t\tconst aspectSym = aspect ? (ASPECT_SYMBOL[aspect] ?? aspect) : '';\n\t\tconst orb = typeof e.orb === 'number' ? formatNumber(e.orb, 1) : '';\n\t\tconst qualifier = this.typeQualifier(e);\n\n\t\tif (aspect && target) {\n\t\t\treturn html`<strong>${body}</strong> <span class=\"${aspectClass}\">${aspectSym}</span> <strong>${target}</strong>${orb ? html`<span class=\"kind\">orb ${orb}\u00B0</span>` : nothing}`;\n\t\t}\n\t\treturn html`<strong>${body || humanize(e.type ?? '')}</strong>${\n\t\t\tqualifier ? html`<span class=\"kind\">${qualifier}</span>` : nothing\n\t\t}`;\n\t}\n\n\t/** Type-specific qualifier text from the optional spec fields. */\n\tprivate typeQualifier(e: ForecastEvent): string {\n\t\tif (e.type === 'sign-ingress' && e.target)\n\t\t\treturn `enters ${capitalize(e.target)}`;\n\t\tif (e.type === 'retrograde-station' && e.station) return e.station;\n\t\tif (e.type === 'eclipse')\n\t\t\treturn [e.kind, 'eclipse'].filter(Boolean).join(' ');\n\t\tif (e.type === 'critical-day') return 'critical day';\n\t\tif (e.type === 'dasha-change' && e.target)\n\t\t\treturn `dasha ${capitalize(e.target)}`;\n\t\treturn humanize(e.type ?? '');\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-forecast-timeline': RoxyForecastTimeline;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { CompatibilityResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatNumber, formatPercent } from '../utils/format.js';\n\nconst STANDARD_CATEGORIES = [\n\t'Varna',\n\t'Vasya',\n\t'Tara',\n\t'Yoni',\n\t'Maitri',\n\t'Gana',\n\t'Bhakoot',\n\t'Nadi',\n];\n\n/**\n * 36-point Ashtakoota score card. Renders /vedic-astrology/compatibility.\n */\n@customElement('roxy-guna-milan')\nexport class RoxyGunaMilan extends RoxyDataElement<CompatibilityResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.card{background:var(--roxy-surface,#fff);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.score-header{align-items:center;gap:1rem;display:flex}.score-info{flex:1}.score-bar{align-items:center;gap:var(--roxy-space-md,1rem);grid-template-columns:1fr auto;display:grid}.total{font-size:2.25rem;font-weight:var(--roxy-weight-bold,600);color:var(--roxy-accent-ink,#b45309);font-variant-numeric:tabular-nums;line-height:1}.over{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-base,1rem)}.recommendation{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-secondary,#475569)}.score-ring{flex-shrink:0;width:120px;height:120px}.score-ring svg{width:100%;height:100%}.score-ring .ring-text{fill:var(--roxy-fg,#0a0a0a);font-size:22px;font-weight:700;font-family:var(--roxy-font-sans)}.score-ring .ring-max{fill:var(--roxy-muted,#71717a);font-size:10px;font-family:var(--roxy-font-sans)}table{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem)}th,td{padding:var(--roxy-space-sm,.5rem);border-bottom:1px solid var(--roxy-border,#e4e4e7);text-align:left}th{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;font-size:var(--roxy-text-xs,.75rem);letter-spacing:.06em}td.score{text-align:right;font-variant-numeric:tabular-nums;color:var(--roxy-fg,#0a0a0a);font-weight:var(--roxy-weight-bold,600)}td.bar-cell{width:30%}.mini-bar{background:var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-full,9999px);height:8px;overflow:hidden}.mini-bar>span{background:var(--roxy-accent,#f59e0b);height:100%;transition:width var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,cubic-bezier(.4, 0, .2, 1));display:block}.tags{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;display:flex}.tags span{border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);padding:2px 8px}.tags .dosha{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 16%, transparent);color:var(--roxy-danger-fg,#991b1b)}.tags .cancel{background:color-mix(in srgb, var(--roxy-success,#16a34a) 18%, transparent);color:var(--roxy-success-fg,#166534)}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No Guna Milan data</div>`;\n\t}\n\n\tprotected renderData(d: CompatibilityResponse) {\n\t\tconst breakdown = (d.breakdown ?? []).filter(\n\t\t\t(b) => b?.category !== undefined,\n\t\t);\n\n\t\tconst score = d.total ?? 0;\n\t\tconst max = d.maxScore ?? 36;\n\t\tconst pct = (score / max) * 100;\n\t\tconst trackColor =\n\t\t\t'color-mix(in srgb, var(--roxy-border) 50%, transparent)';\n\t\tconst fillColor =\n\t\t\tpct >= 70\n\t\t\t\t? 'var(--roxy-success)'\n\t\t\t\t: pct >= 50\n\t\t\t\t\t? 'var(--roxy-warning)'\n\t\t\t\t\t: 'var(--roxy-danger)';\n\t\t// SVG circle with r=45: circumference = 2 * pi * 45 = 282.74\n\t\t// dasharray segments = pct * 2.827, (100 - pct) * 2.827\n\t\tconst dashFill = pct * 2.827;\n\t\tconst dashGap = (100 - pct) * 2.827;\n\n\t\treturn html`<article class=\"card\" aria-label=\"Guna Milan score\"><div class=\"score-header\"><div class=\"score-info\"><div class=\"score-bar\"><div><span class=\"total\">${formatNumber(d.total, 1)}</span> <span class=\"over\">/ ${d.maxScore}</span> ${\n\t\t\t\t\t\t\t\ttypeof d.percentage === 'number'\n\t\t\t\t\t\t\t\t\t? html`<small style=\"margin-left:.5rem;color:var(--roxy-muted)\">${formatPercent(d.percentage, 1)}</small>`\n\t\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t\t}</div>${\n\t\t\t\t\t\t\td.recommendation\n\t\t\t\t\t\t\t\t? html`<span class=\"recommendation\">${d.recommendation}</span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}</div></div><div class=\"score-ring\" role=\"meter\" aria-label=\"Guna milan score\" aria-valuemin=\"0\" aria-valuemax=\"36\" aria-valuenow=\"${score}\"><svg viewBox=\"0 0 100 100\" aria-hidden=\"true\"><circle class=\"ring-track\" cx=\"50\" cy=\"50\" r=\"45\" fill=\"none\" stroke=\"${trackColor}\" stroke-width=\"8\"/><circle class=\"ring-fill\" cx=\"50\" cy=\"50\" r=\"45\" fill=\"none\" stroke=\"${fillColor}\" stroke-width=\"8\" stroke-dasharray=\"${dashFill},${dashGap}\" stroke-linecap=\"round\" transform=\"rotate(-90 50 50)\"/><text x=\"50\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\" class=\"ring-text\">${score}</text><text x=\"50\" y=\"64\" text-anchor=\"middle\" dominant-baseline=\"central\" class=\"ring-max\">/${max}</text></svg></div></div>${\n\t\t\t\tbreakdown.length > 0\n\t\t\t\t\t? html`<table><thead><tr><th>Category</th><th>Progress</th><th class=\"score\">Score</th></tr></thead><tbody>${breakdown.map((b) => {\n\t\t\t\t\t\t\t\tconst score = b.score ?? 0;\n\t\t\t\t\t\t\t\tconst maxScore = b.maxScore ?? defaultMax(b.category);\n\t\t\t\t\t\t\t\tconst pct = maxScore ? (score / maxScore) * 100 : 0;\n\t\t\t\t\t\t\t\treturn html`<tr><td>${b.category}</td><td class=\"bar-cell\"><div class=\"mini-bar\"><span style=\"width:${pct}%\"></span></div></td><td class=\"score\">${formatNumber(score, 1)} / ${maxScore}</td></tr>`;\n\t\t\t\t\t\t\t})}</tbody></table>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\t(d.doshas?.length ?? 0) > 0 || (d.doshaCancellations?.length ?? 0) > 0\n\t\t\t\t\t? html`<div class=\"tags\">${d.doshas?.map((x) => html`<span class=\"dosha\">${x}</span>`)} ${d.doshaCancellations?.map(\n\t\t\t\t\t\t\t(x) =>\n\t\t\t\t\t\t\t\thtml`<span class=\"cancel\" title=\"${x.reason}\">${x.dosha} cancelled</span>`,\n\t\t\t\t\t\t)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t}</article>`;\n\t}\n}\n\nfunction defaultMax(name?: string): number {\n\tif (!name) return 1;\n\tswitch (name.toLowerCase()) {\n\t\tcase 'varna':\n\t\t\treturn 1;\n\t\tcase 'vasya':\n\t\t\treturn 2;\n\t\tcase 'tara':\n\t\t\treturn 3;\n\t\tcase 'yoni':\n\t\t\treturn 4;\n\t\tcase 'maitri':\n\t\t\treturn 5;\n\t\tcase 'gana':\n\t\t\treturn 6;\n\t\tcase 'bhakoot':\n\t\t\treturn 7;\n\t\tcase 'nadi':\n\t\t\treturn 8;\n\t\tdefault:\n\t\t\treturn 1;\n\t}\n}\n\nexport const GUNA_CATEGORIES = STANDARD_CATEGORIES;\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-guna-milan': RoxyGunaMilan;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { CalculateConnectionResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { humanize } from '../utils/string.js';\n\n/**\n * Human Design connection chart. Renders /human-design/connection: the composite of two charts as the electromagnetic / compromise / dominance channels they form together, plus the combined definition and a summary. The HD analog of synastry. Each channel row shows its two gates, name, circuit, the relationship dynamic, and which person carries which gate.\n */\n@customElement('roxy-hd-connection')\nexport class RoxyHdConnection extends RoxyDataElement<CalculateConnectionResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.count{color:var(--roxy-accent-ink,#b45309);font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);font-variant-numeric:tabular-nums}.def{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-muted,#71717a)}.def strong{color:var(--roxy-fg,#0a0a0a);text-transform:capitalize}.stats{gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.stat{border-radius:var(--roxy-radius-full,9999px);background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 12%, transparent);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-fg,#0a0a0a);align-items:baseline;gap:.35rem;padding:2px 10px;display:inline-flex}.stat b{color:var(--roxy-fg,#0a0a0a);font-variant-numeric:tabular-nums}table{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem)}th,td{text-align:left;padding:var(--roxy-space-sm,.5rem);border-bottom:1px solid var(--roxy-border,#e4e4e7);white-space:nowrap}th{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;font-size:var(--roxy-text-xs,.75rem);letter-spacing:.04em}tbody tr:last-child td{border-bottom:none}.gates{font-variant-numeric:tabular-nums;color:var(--roxy-accent-ink,#b45309);font-weight:var(--roxy-weight-bold,600)}.dyn{border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 16%, transparent);color:var(--roxy-fg,#0a0a0a);padding:1px 8px;display:inline-block}.who{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem)}.scroll{overflow-x:auto}`,\n\t];\n\n\tprotected renderData(d: CalculateConnectionResponse) {\n\t\tconst channels = d.channels ?? [];\n\t\treturn html`<div class=\"wrap\" aria-label=\"Human Design connection\"><header class=\"head\"><h2 class=\"title\">Connection</h2>${typeof d.totalChannels === 'number' ? html`<span class=\"count\">${d.totalChannels} channels</span>` : nothing}</header>${d.combinedDefinition ? html`<p class=\"def\">Combined definition: <strong>${humanize(String(d.combinedDefinition))}</strong></p>` : nothing} ${this.renderSummary(d.summary)} ${\n\t\t\t\tchannels.length > 0\n\t\t\t\t\t? html`<div class=\"scroll\"><table role=\"table\" aria-label=\"Connection channels\"><thead><tr><th scope=\"col\">Channel</th><th scope=\"col\">Gates</th><th scope=\"col\">Circuit</th><th scope=\"col\">Dynamic</th><th scope=\"col\">Held by</th></tr></thead><tbody>${channels.map((c) => this.renderChannel(c))}</tbody></table></div>`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n\n\tprivate renderSummary(s: CalculateConnectionResponse['summary'] | undefined) {\n\t\tif (!s) return nothing;\n\t\t// The four ways two charts meet in a channel, in canonical HD order.\n\t\tconst rows: Array<[string, number | undefined]> = [\n\t\t\t['Electromagnetic', s.electromagnetic],\n\t\t\t['Dominance', s.dominance],\n\t\t\t['Compromise', s.compromise],\n\t\t\t['Companionship', s.companionship],\n\t\t];\n\t\treturn html`<div class=\"stats\" aria-label=\"Channel dynamics\">${rows.map(([label, n]) => (typeof n === 'number' ? html`<span class=\"stat\">${label} <b>${n}</b></span>` : nothing))}</div>`;\n\t}\n\n\tprivate renderChannel(\n\t\tc: NonNullable<CalculateConnectionResponse['channels']>[number],\n\t) {\n\t\tconst a = c.personAGates ?? [];\n\t\tconst b = c.personBGates ?? [];\n\t\tconst held =\n\t\t\t[a.length ? 'A' : '', b.length ? 'B' : ''].filter(Boolean).join(' + ') ||\n\t\t\t'-';\n\t\treturn html`<tr><td>${c.name ?? ''}</td><td class=\"gates\">${c.gateA}-${c.gateB}</td><td>${c.circuit ?? ''}</td><td>${c.dynamic ? html`<span class=\"dyn\">${c.dynamic}</span>` : ''}</td><td class=\"who\">${held}</td></tr>`;\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No connection data</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-hd-connection': RoxyHdConnection;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { CalculatePentaResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\n/**\n * Human Design penta. Renders /human-design/penta: the group field (3 to 5 people) as the penta channels they form, split into the upper (direction) and lower (execution) triangles, with each channel marked defined or open and core or not, and which members hold each gate. The team/business chart.\n */\n@customElement('roxy-hd-penta')\nexport class RoxyHdPenta extends RoxyDataElement<CalculatePentaResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.count{color:var(--roxy-accent-ink,#b45309);font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600)}.stats{gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.stat{border-radius:var(--roxy-radius-full,9999px);background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 12%, transparent);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-fg,#0a0a0a);align-items:baseline;gap:.35rem;padding:2px 10px;display:inline-flex}.stat b{color:var(--roxy-fg,#0a0a0a);font-variant-numeric:tabular-nums}.section h3{margin:0 0 var(--roxy-space-xs,.25rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em}.row{align-items:center;gap:var(--roxy-space-sm,.5rem);padding:var(--roxy-space-sm,.5rem) 0;border-bottom:1px solid var(--roxy-border,#e4e4e7);font-size:var(--roxy-text-sm,.875rem);flex-wrap:wrap;display:flex}.row:last-child{border-bottom:none}.gates{font-variant-numeric:tabular-nums;color:var(--roxy-accent-ink,#b45309);font-weight:var(--roxy-weight-bold,600);min-width:3.5rem}.cname{flex:1;min-width:8rem}.badge{border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);padding:1px 8px;display:inline-flex}.badge.defined{background:color-mix(in srgb, var(--roxy-success,#16a34a) 16%, transparent);color:var(--roxy-success-fg,#166534)}.badge.open{background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 45%, transparent);color:var(--roxy-fg,#0a0a0a)}.badge.core{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 18%, transparent);color:var(--roxy-fg,#0a0a0a)}`,\n\t];\n\n\tprotected renderData(d: CalculatePentaResponse) {\n\t\tconst channels = d.channels ?? [];\n\t\tconst upper = channels.filter((c) => c.position === 'upper');\n\t\tconst lower = channels.filter((c) => c.position === 'lower');\n\t\treturn html`<div class=\"wrap\" aria-label=\"Human Design penta\"><header class=\"head\"><h2 class=\"title\">Penta</h2>${typeof d.memberCount === 'number' ? html`<span class=\"count\">${d.memberCount} members</span>` : nothing}</header>${this.renderSummary(d.summary)} ${this.renderGroup('Upper (direction)', upper)} ${this.renderGroup('Lower (execution)', lower)}</div>`;\n\t}\n\n\tprivate renderSummary(s: CalculatePentaResponse['summary'] | undefined) {\n\t\tif (!s) return nothing;\n\t\tconst gaps = s.gapGates ?? [];\n\t\treturn html`<div class=\"stats\" aria-label=\"Penta summary\">${typeof s.definedChannels === 'number' ? html`<span class=\"stat\">Defined channels <b>${s.definedChannels}</b></span>` : nothing} ${typeof s.filledGates === 'number' ? html`<span class=\"stat\">Filled gates <b>${s.filledGates}</b></span>` : nothing} ${gaps.length > 0 ? html`<span class=\"stat\">Gap gates <b>${gaps.join(', ')}</b></span>` : nothing} ${typeof s.coreDefined === 'boolean' ? html`<span class=\"stat\">${s.coreDefined ? 'Core defined' : 'Core open'}</span>` : nothing}</div>`;\n\t}\n\n\tprivate renderGroup(\n\t\tlabel: string,\n\t\tchannels: NonNullable<CalculatePentaResponse['channels']>,\n\t) {\n\t\tif (channels.length === 0) return nothing;\n\t\treturn html`<div class=\"section\"><h3>${label}</h3>${channels.map(\n\t\t\t\t(c) => html`<div class=\"row\"><span class=\"gates\">${c.gateA}-${c.gateB}</span> <span class=\"cname\">${c.name ?? ''}</span> <span class=\"badge ${c.defined ? 'defined' : 'open'}\">${c.defined ? 'Defined' : 'Open'}</span> ${c.isCore ? html`<span class=\"badge core\">Core</span>` : nothing}</div>`,\n\t\t\t)}</div>`;\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No penta data</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-hd-penta': RoxyHdPenta;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { CalculateVariablesResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\n/**\n * Human Design variables (the four arrows / PHS). Renders /human-design/variables: the four transformation arrows laid out as they sit on the bodygraph head (top-left/right Determination + Motivation, bottom-left/right Environment + Perspective), each showing its left/right direction, the digestion/environment/awareness/perspective labels, and its color/tone/base. A low-confidence calculation (near a color/tone boundary) is flagged.\n */\n@customElement('roxy-hd-variables')\nexport class RoxyHdVariables extends RoxyDataElement<CalculateVariablesResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.grid{gap:var(--roxy-space-md,1rem);grid-template-columns:repeat(2,1fr);display:grid}.arrow{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-md,1rem);gap:var(--roxy-space-xs,.25rem);display:grid}.arrow-head{align-items:center;gap:var(--roxy-space-sm,.5rem);display:flex}.glyph{color:var(--roxy-accent-ink,#b45309);font-size:1.75rem;line-height:1}.name{font-weight:var(--roxy-weight-bold,600)}.layer{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.05em}.labels{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a)}.ctb{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);font-variant-numeric:tabular-nums}.note{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-warning-fg,#9a3412)}@container (width<=28rem){.grid{grid-template-columns:1fr}}`,\n\t];\n\n\tprotected renderData(d: CalculateVariablesResponse) {\n\t\t// Place the arrows by their bodygraph `position`, not response order: the\n\t\t// 2-col grid fills row-major, so sorting to Top left, Top right, Bottom left,\n\t\t// Bottom right keeps the design column (Determination + Environment) on the\n\t\t// left and the personality column (Motivation + Perspective) on the right,\n\t\t// which is the whole point of the four-arrow layout.\n\t\tconst arrows = [...(d.arrows ?? [])].sort(\n\t\t\t(a, b) => quadrantOrder(a.position) - quadrantOrder(b.position),\n\t\t);\n\t\treturn html`<div class=\"wrap\" aria-label=\"Human Design variables\"><h2 class=\"title\">Variables</h2><div class=\"grid\">${arrows.map((a) => this.renderArrow(a))}</div>${\n\t\t\t\td.confident === false\n\t\t\t\t\t? html`<p class=\"note\" role=\"note\">Low confidence: a birth time near a color or tone boundary${typeof d.confidenceMarginDeg === 'number' ? ` (within ${d.confidenceMarginDeg}\u00B0)` : ''}. Verify the exact birth time.</p>`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n\n\tprivate renderArrow(\n\t\ta: NonNullable<CalculateVariablesResponse['arrows']>[number],\n\t) {\n\t\t// A left arrow is strategic/active, a right arrow receptive/passive in HD.\n\t\tconst glyph = a.direction === 'left' ? '\u2190' : '\u2192';\n\t\treturn html`<div class=\"arrow\"><div class=\"arrow-head\"><span class=\"glyph\" aria-hidden=\"true\">${glyph}</span> <span class=\"name\">${a.name ?? ''}</span></div>${a.layer ? html`<span class=\"layer\">${a.layer}</span>` : nothing} <span class=\"labels\">${[a.directionLabel, a.colorLabel].filter(Boolean).join(' \u00B7 ')} </span>${\n\t\t\t\ttypeof a.color === 'number'\n\t\t\t\t\t? html`<span class=\"ctb\">Color ${a.color} \u00B7 Tone ${a.tone} \u00B7 Base ${a.base}${a.activation?.planet ? ` \u00B7 ${a.activation.planet}${a.activation.side ? ` (${a.activation.side})` : ''}` : ''}</span>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\ta.confident === false\n\t\t\t\t\t? html`<span class=\"note\" role=\"note\">Knife-edge: could flip with a more precise birth time.</span>`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No variables data</div>`;\n\t}\n}\n\n/** Canonical bodygraph reading order for the four arrows, so the 2-col grid lays them out by quadrant. Unknown positions sort last. */\nfunction quadrantOrder(position: string | undefined): number {\n\tswitch (position) {\n\t\tcase 'Top left':\n\t\t\treturn 0;\n\t\tcase 'Top right':\n\t\t\treturn 1;\n\t\tcase 'Bottom left':\n\t\t\treturn 2;\n\t\tcase 'Bottom right':\n\t\t\treturn 3;\n\t\tdefault:\n\t\t\treturn 99;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-hd-variables': RoxyHdVariables;\n\t}\n}\n", "import { css, html, 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 { RoxyDataElement } from '../utils/base-element.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 RoxyDataElement<HexagramData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.card{background:var(--roxy-surface,#fff);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-lg,1.5rem);grid-template-columns:6rem 1fr;display:grid}@container (width<=480px){.card{grid-template-columns:1fr}}.glyphs{gap:var(--roxy-space-md,1rem);justify-items:center;display:grid}.symbol{color:var(--roxy-accent-ink,#b45309);font-size:3rem;line-height:1}.lines{gap:4px;width:4rem;display:grid}.line{justify-content:center;align-items:center;gap:4px;height:8px;display:flex}.seg{background:var(--roxy-fg,#0a0a0a);border-radius:1px;height:6px;display:block}.line.broken .seg{width:1.4rem}.line.solid .seg{width:3rem}.line.changing .seg{background:var(--roxy-accent,#f59e0b)}.title{font-size:var(--roxy-text-xl,1.5rem);font-weight:var(--roxy-weight-bold,600);letter-spacing:var(--roxy-tracking-tight);margin:0}.subtitle{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem);margin:0 0 var(--roxy-space-sm,.5rem)}.trigrams{gap:var(--roxy-space-md,1rem);margin-bottom:var(--roxy-space-sm,.5rem);color:var(--roxy-secondary,#475569);font-size:var(--roxy-text-xs,.75rem);text-transform:uppercase;letter-spacing:.06em;display:flex}.tri-glyph{font-size:var(--roxy-text-xl,1.5rem);color:var(--roxy-accent-ink,#b45309);vertical-align:middle;margin-right:4px}.judgment,.image,.message{margin:0 0 var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a)}.judgment:before{content:\"Judgment. \";font-weight:var(--roxy-weight-bold,600);color:var(--roxy-secondary,#475569)}.image:before{content:\"Image. \";font-weight:var(--roxy-weight-bold,600);color:var(--roxy-secondary,#475569)}.changing{margin-top:var(--roxy-space-md,1rem);padding-top:var(--roxy-space-md,1rem);border-top:1px solid var(--roxy-border,#e4e4e7);color:var(--roxy-accent-ink,#b45309);font-size:var(--roxy-text-sm,.875rem)}`,\n\t];\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\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No hexagram data</div>`;\n\t}\n\n\tprotected renderData() {\n\t\tconst resolved = this.resolveHexagram();\n\t\tif (!resolved) return this.renderEmpty();\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\"><div class=\"glyphs\">${h.symbol ? html`<div class=\"symbol\">${h.symbol}</div>` : nothing}<div class=\"lines\" aria-hidden=\"true\">${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\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}</div>`;\n\t\t\t\t\t\t})}</div></div><div><h2 class=\"title\">${h.number ? html`${h.number}.` : nothing}${h.english ?? h.chinese ?? 'Hexagram'}</h2><p class=\"subtitle\">${h.chinese ? html`${h.chinese}` : nothing} ${h.pinyin ? html`\u00B7 ${h.pinyin}` : nothing}</p><div class=\"trigrams\">${\n\t\t\t\t\t\th.upperTrigram\n\t\t\t\t\t\t\t? html`<div>Upper <span class=\"tri-glyph\">${TRIGRAM_GLYPH[h.upperTrigram] ?? ''}</span>${h.upperTrigram}</div>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t} ${\n\t\t\t\t\t\th.lowerTrigram\n\t\t\t\t\t\t\t? html`<div>Lower <span class=\"tri-glyph\">${TRIGRAM_GLYPH[h.lowerTrigram] ?? ''}</span>${h.lowerTrigram}</div>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}</div>${h.judgment ? html`<p class=\"judgment\">${h.judgment}</p>` : nothing} ${h.image ? html`<p class=\"image\">${h.image}</p>` : nothing} ${dailyMessage ? html`<p class=\"message\">${dailyMessage}</p>` : nothing} ${\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\tchanging.size > 0\n\t\t\t\t\t\t? html`<div class=\"changing\">Changing 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\tresultingHexagram?.english\n\t\t\t\t\t\t\t\t\t? html`Becomes hexagram ${resultingHexagram.number} ${resultingHexagram.english}.`\n\t\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t\t}</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</div></article>`;\n\t}\n\n\t/**\n\t * Lines for a static hexagram (lookup/random/daily, which carry no cast `lines` array): read the `binary` pattern. Per the spec it is 6 digits bottom to top, 1 = yang (solid), 0 = yin (broken), so index 0 is line 1 (bottom). Mapped to the same 7 = solid / 8 = broken code the renderer uses for cast lines. Falls back to all-yang only if `binary` is malformed. The Unicode `symbol` block (U+4DC0) is in King Wen order, NOT line order, so it must never be used to derive the lines.\n\t */\n\tprivate derivedLines(h: Hexagram): number[] {\n\t\tconst binary = h.binary ?? '';\n\t\tif (/^[01]{6}$/.test(binary)) {\n\t\t\t// `binary` is top to bottom (index 0 = line 6), verified against the\n\t\t\t// canonical encoding: hexagram 46 (Earth over Wind) is \"000110\", which is\n\t\t\t// Earth/Wind only when read top down. The renderer expects bottom to top\n\t\t\t// (line 1 first, like the cast `lines` array), so reverse. 1 = yang\n\t\t\t// (solid, 7), 0 = yin (broken, 8).\n\t\t\treturn Array.from(binary, (c) => (c === '1' ? 7 : 8)).reverse();\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", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { PLANET_GLYPH } from '../tokens/index.js';\nimport type { GetHoraResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { capitalize } from '../utils/string.js';\n\n/** HH:MM from a tz-naive ISO local datetime, without reparsing (the times are already wall-clock in the requested timezone). */\nfunction clockTime(iso: string | undefined): string {\n\tif (!iso) return '';\n\tconst t = String(iso).slice(11, 16);\n\treturn t || String(iso);\n}\n\ntype HoraPeriod = NonNullable<GetHoraResponse['dayHoras']>[number];\n\n/**\n * Vedic Hora (planetary hours) table. Renders /vedic-astrology/panchang/hora: the 12 daytime and 12 nighttime horas, each ruled by one of the seven classical planets in the Chaldean order, used for electional timing (start a venture in the hora of the planet that favours it). Day horas run sunrise to sunset, night horas sunset to next sunrise; each tile shows the ruling planet and its wall-clock window.\n */\n@customElement('roxy-hora-table')\nexport class RoxyHoraTable extends RoxyDataElement<GetHoraResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-md,1rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.subtitle{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem);margin:0}.cols{gap:var(--roxy-space-md,1rem);grid-template-columns:repeat(2,1fr);display:grid}.section-label{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;font-weight:var(--roxy-weight-bold,600);margin:0 0 var(--roxy-space-xs,.25rem) 0}.row{align-items:center;gap:var(--roxy-space-sm,.5rem);padding:var(--roxy-space-xs,.25rem) 0;border-bottom:1px solid var(--roxy-border,#e4e4e7);font-size:var(--roxy-text-sm,.875rem);display:flex}.row:last-child{border-bottom:none}.glyph{color:var(--roxy-accent-ink,#b45309);text-align:center;width:1.25em;font-size:1.15em;line-height:1}.planet{flex:1;font-weight:500}.time{color:var(--roxy-muted,#71717a);font-variant-numeric:tabular-nums;white-space:nowrap}.num{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);font-variant-numeric:tabular-nums;text-align:right;width:1.5em}@container (width<=30rem){.cols{grid-template-columns:1fr}}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No hora data</div>`;\n\t}\n\n\tprotected renderData(d: GetHoraResponse) {\n\t\tconst day = d.dayHoras ?? [];\n\t\tconst night = d.nightHoras ?? [];\n\t\tif (day.length === 0 && night.length === 0) return this.renderEmpty();\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Hora periods\"><div class=\"head\"><h2 class=\"title\">Hora</h2>${d.date ? html`<p class=\"subtitle\">${d.date}</p>` : nothing}</div><div class=\"cols\">${this.renderColumn('Day', day)} ${this.renderColumn('Night', night)}</div></div>`;\n\t}\n\n\tprivate renderColumn(label: string, horas: HoraPeriod[]) {\n\t\tif (horas.length === 0) return nothing;\n\t\treturn html`<div class=\"col\"><p class=\"section-label\">${label}</p>${horas.map(\n\t\t\t\t(h) => html`<div class=\"row\"><span class=\"glyph\" aria-hidden=\"true\">${PLANET_GLYPH[capitalize(h.planet ?? '')] ?? '\u00B7'}</span> <span class=\"planet\">${h.planet}</span> <span class=\"time\">${clockTime(h.start)}-${clockTime(h.end)}</span> ${typeof h.number === 'number' ? html`<span class=\"num\">${h.number}</span>` : nothing}</div>`,\n\t\t\t)}</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-hora-table': RoxyHoraTable;\n\t}\n}\n", "import { css, html, 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 { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { capitalize } from '../utils/string.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 RoxyDataElement<HoroscopeData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.card{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{align-items:center;gap:var(--roxy-space-md,1rem);display:flex}.glyph{color:var(--roxy-accent-ink,#b45309);font-size:2.25rem;line-height:1}.title{font-size:var(--roxy-text-xl,1.5rem);font-weight:var(--roxy-weight-bold,600);letter-spacing:var(--roxy-tracking-tight);text-transform:capitalize;margin:0}.date{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-muted,#71717a)}.energy{font-variant-numeric:tabular-nums;font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-secondary,#475569);margin-left:auto}.energy-bar{background:var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-full,9999px);vertical-align:middle;width:6rem;height:6px;margin-left:6px;display:inline-block;overflow:hidden}.energy-bar>span{background:var(--roxy-accent,#f59e0b);height:100%;transition:width var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,cubic-bezier(.4, 0, .2, 1));display:block}.overview{font-size:var(--roxy-text-base,1rem);color:var(--roxy-fg,#0a0a0a);margin:0}.sections{gap:var(--roxy-space-md,1rem);grid-template-columns:repeat(auto-fit,minmax(12rem,1fr));display:grid}.section h3{margin:0 0 var(--roxy-space-xs,.25rem) 0;font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;letter-spacing:.06em}.section p{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);margin:0}.lucky{gap:var(--roxy-space-sm,.5rem);border-top:1px solid var(--roxy-border,#e4e4e7);padding-top:var(--roxy-space-md,1rem);font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-secondary,#475569);flex-wrap:wrap;display:flex}.lucky strong{color:var(--roxy-fg,#0a0a0a);font-weight:var(--roxy-weight-bold,600)}.compat-wrap{align-items:center;gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;width:100%;display:flex}.compat{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;display:flex}.compat span{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 16%, transparent);color:var(--roxy-fg,#0a0a0a);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);text-transform:capitalize;padding:2px 8px}`,\n\t];\n\n\t@property({ type: String, reflect: true })\n\tperiod: 'daily' | 'weekly' | 'monthly' = 'daily';\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No horoscope data</div>`;\n\t}\n\n\tprotected renderData(d: HoroscopeData) {\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 class=\"card\" aria-label=\"${`${this.period} horoscope for ${sign}`}\"><header class=\"head\"><span class=\"glyph\" aria-hidden=\"true\">${glyph}</span><div><h2 class=\"title\">${sign} ${this.period}</h2>${dateLabel ? html`<div class=\"date\">${dateLabel}</div>` : nothing}</div>${\n\t\t\t\t\tenergy !== null\n\t\t\t\t\t\t? html`<span class=\"energy\" aria-label=\"${`Energy ${energy} of 10`}\">Energy ${energy}/10 <span class=\"energy-bar\"><span style=\"width:${(energy / 10) * 100}%\"></span></span></span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</header>${d.overview ? html`<p class=\"overview\">${d.overview}</p>` : nothing}<div class=\"sections\">${\n\t\t\t\t\td.love\n\t\t\t\t\t\t? html`<div class=\"section\"><h3>Love</h3><p>${d.love}</p></div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} ${\n\t\t\t\t\td.career\n\t\t\t\t\t\t? html`<div class=\"section\"><h3>Career</h3><p>${d.career}</p></div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} ${\n\t\t\t\t\td.health\n\t\t\t\t\t\t? html`<div class=\"section\"><h3>Health</h3><p>${d.health}</p></div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} ${\n\t\t\t\t\td.finance\n\t\t\t\t\t\t? html`<div class=\"section\"><h3>Finance</h3><p>${d.finance}</p></div>`\n\t\t\t\t\t\t: nothing\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\"><h3>Advice</h3><p>${d.advice}</p></div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</div>${(() => {\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\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\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\tluckyNumbers.length\n\t\t\t\t\t\t\t\t? html`<span>Lucky numbers <strong>${luckyNumbers.join(', ')}</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\tluckyDays.length\n\t\t\t\t\t\t\t\t? html`<span>Lucky days <strong>${luckyDays.join(', ')}</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\tcompatibleSigns.length\n\t\t\t\t\t\t\t\t? html`<span class=\"compat-wrap\">Best with <span class=\"compat\">${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></span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}</div>`;\n\t\t\t})()}</article>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-horoscope-card': RoxyHoroscopeCard;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\nimport type { KpChartResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatNumber } from '../utils/format.js';\n\ntype Tab = 'planets' | 'cusps';\n\n/** A planet or node row, normalized so planets and Rahu/Ketu share a table. */\ninterface KpBody {\n\tname: string;\n\tsign?: string;\n\thouse?: number;\n\tnakshatra?: string;\n\tstarLord?: string;\n\tsubLord?: string;\n\tsubSubLord?: string;\n\tkpNumber?: number;\n\tretrograde?: boolean;\n}\n\n/**\n * KP (Krishnamurti Paddhati) chart. Renders /vedic-astrology/kp/chart: the\n * Ascendant with its full stellar hierarchy, a planets-and-nodes table, and a\n * Placidus cusps table. The cusp and planet sub lords are the primary\n * predictive surface in KP astrology, so each row carries star lord, sub lord,\n * sub-sub lord, and KP number (1-249).\n */\n@customElement('roxy-kp-chart')\nexport class RoxyKpChart extends RoxyDataElement<KpChartResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);background:var(--roxy-surface,#fff);box-shadow:var(--roxy-shadow-sm);width:100%;overflow:auto}.head{padding:var(--roxy-space-md,1rem);border-bottom:1px solid var(--roxy-border,#e4e4e7);gap:var(--roxy-space-xs,.25rem);display:grid}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.asc,.ayan{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}.asc strong{color:var(--roxy-fg,#0a0a0a)}.tablist{padding:0 var(--roxy-space-md,1rem);border-bottom:2px solid var(--roxy-border,#e4e4e7);gap:2px;display:flex}.tab{padding:var(--roxy-space-xs,.25rem) var(--roxy-space-md,1rem);font-size:var(--roxy-text-sm,.875rem);cursor:pointer;color:var(--roxy-muted,#71717a);background:0 0;border:none;border-bottom:2px solid #0000;margin-bottom:-2px;font-family:inherit}.tab[aria-selected=true]{color:var(--roxy-accent-ink,#b45309);border-bottom-color:var(--roxy-accent,#f59e0b);font-weight:var(--roxy-weight-bold,600)}.tab:hover:not([aria-selected=true]){color:var(--roxy-fg,#0a0a0a)}table{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem);min-width:620px}thead{background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 20%, transparent)}th,td{padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);text-align:left;white-space:nowrap}th{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;font-size:var(--roxy-text-xs,.75rem);letter-spacing:.04em}tbody tr{border-top:1px solid var(--roxy-border,#e4e4e7)}td.body{font-weight:var(--roxy-weight-bold,600);color:var(--roxy-fg,#0a0a0a)}.retro{color:var(--roxy-warning-fg,#9a3412);font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);margin-left:4px}.num{font-variant-numeric:tabular-nums}`,\n\t];\n\n\t@state()\n\tprivate activeTab: Tab = 'planets';\n\n\t/** Merge the 7 planets and the two nodes into one ordered body list. */\n\tprivate bodies(): KpBody[] {\n\t\tconst d = this.data;\n\t\tif (!d) return [];\n\t\tconst rows: KpBody[] = (d.planets ?? []).map((p) => ({\n\t\t\tname: p.planet,\n\t\t\tsign: p.sign,\n\t\t\thouse: p.house,\n\t\t\tnakshatra: p.nakshatra,\n\t\t\tstarLord: p.starLord,\n\t\t\tsubLord: p.subLord,\n\t\t\tsubSubLord: p.subSubLord,\n\t\t\tkpNumber: p.kpNumber,\n\t\t\tretrograde: p.retrograde,\n\t\t}));\n\t\tconst nodes = d.nodes;\n\t\tfor (const [name, node] of [\n\t\t\t['Rahu', nodes?.rahu],\n\t\t\t['Ketu', nodes?.ketu],\n\t\t] as const) {\n\t\t\tif (node) {\n\t\t\t\trows.push({\n\t\t\t\t\tname,\n\t\t\t\t\tsign: node.sign,\n\t\t\t\t\thouse: node.house,\n\t\t\t\t\tnakshatra: node.nakshatra,\n\t\t\t\t\tstarLord: node.starLord,\n\t\t\t\t\tsubLord: node.subLord,\n\t\t\t\t\tsubSubLord: node.subSubLord,\n\t\t\t\t\tretrograde: true,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn rows;\n\t}\n\n\tprivate onTabKeyDown(e: KeyboardEvent) {\n\t\tif (e.key !== 'ArrowRight' && e.key !== 'ArrowLeft') return;\n\t\te.preventDefault();\n\t\tthis.activeTab = this.activeTab === 'planets' ? 'cusps' : 'planets';\n\t\tconst next = this.activeTab;\n\t\trequestAnimationFrame(() => {\n\t\t\tthis.shadowRoot\n\t\t\t\t?.querySelector<HTMLButtonElement>(`#tab-${next}`)\n\t\t\t\t?.focus();\n\t\t});\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No KP chart data</div>`;\n\t}\n\n\tprotected renderData(d: KpChartResponse) {\n\t\tconst asc = d.ascendant;\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"KP chart\" tabindex=\"0\"><header class=\"head\"><h2 class=\"title\">KP chart</h2>${\n\t\t\t\t\tasc\n\t\t\t\t\t\t? html`<div class=\"asc\">Ascendant: <strong>${asc.sign ?? ''}</strong> ${asc.nakshatra ? html`\u00B7 ${asc.nakshatra}` : nothing} ${asc.subLord ? html`\u00B7 sub lord ${asc.subLord}` : nothing} ${typeof asc.kpNumber === 'number' ? html`\u00B7 KP ${asc.kpNumber}` : nothing}</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} ${\n\t\t\t\t\ttypeof d.meta?.ayanamsa === 'number'\n\t\t\t\t\t\t? html`<div class=\"ayan\">${d.meta.ayanamsaType ?? 'Ayanamsa'}: ${formatNumber(d.meta.ayanamsa, 4)}\u00B0 ${d.meta.houseSystem ? html`\u00B7 ${d.meta.houseSystem} houses` : nothing}</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</header><div class=\"tablist\" role=\"tablist\" aria-label=\"KP chart views\" @keydown=\"${this.onTabKeyDown}\">${(['planets', 'cusps'] as const).map(\n\t\t\t\t\t(t) => html`<button class=\"tab\" role=\"tab\" id=\"tab-${t}\" aria-selected=\"${this.activeTab === t ? 'true' : 'false'}\" aria-controls=\"panel-${t}\" tabindex=\"${this.activeTab === t ? '0' : '-1'}\" @click=\"${() => {\n\t\t\t\t\t\t\tthis.activeTab = t;\n\t\t\t\t\t\t}}\">${t === 'planets' ? 'Planets' : 'Cusps'}</button>`,\n\t\t\t\t)}</div><div id=\"panel-${this.activeTab}\" role=\"tabpanel\" aria-labelledby=\"tab-${this.activeTab}\">${this.activeTab === 'planets' ? this.renderPlanets() : this.renderCusps()}</div></div>`;\n\t}\n\n\tprivate renderPlanets() {\n\t\tconst bodies = this.bodies();\n\t\tif (!bodies.length)\n\t\t\treturn html`<p class=\"roxy-empty\" role=\"status\">No planets</p>`;\n\t\treturn html`<table role=\"table\" aria-label=\"KP planets and nodes\"><thead><tr><th scope=\"col\">Body</th><th scope=\"col\">Sign</th><th scope=\"col\">House</th><th scope=\"col\">Nakshatra</th><th scope=\"col\">Star lord</th><th scope=\"col\">Sub lord</th><th scope=\"col\">Sub sub lord</th><th scope=\"col\">KP no.</th></tr></thead><tbody>${bodies.map(\n\t\t\t\t\t(b) => html`<tr><td class=\"body\">${b.name}${b.retrograde ? html`<span class=\"retro\">R</span>` : nothing}</td><td>${b.sign ?? ''}</td><td class=\"num\">${typeof b.house === 'number' ? b.house : ''}</td><td>${b.nakshatra ?? ''}</td><td>${b.starLord ?? ''}</td><td>${b.subLord ?? ''}</td><td>${b.subSubLord ?? ''}</td><td class=\"num\">${typeof b.kpNumber === 'number' ? b.kpNumber : ''}</td></tr>`,\n\t\t\t\t)}</tbody></table>`;\n\t}\n\n\tprivate renderCusps() {\n\t\tconst cusps = this.data?.cusps ?? [];\n\t\tif (!cusps.length)\n\t\t\treturn html`<p class=\"roxy-empty\" role=\"status\">No cusps</p>`;\n\t\treturn html`<table role=\"table\" aria-label=\"KP Placidus cusps\"><thead><tr><th scope=\"col\">House</th><th scope=\"col\">Sign</th><th scope=\"col\">Sign lord</th><th scope=\"col\">Nakshatra</th><th scope=\"col\">Star lord</th><th scope=\"col\">Sub lord</th><th scope=\"col\">Sub sub lord</th><th scope=\"col\">KP no.</th></tr></thead><tbody>${cusps.map(\n\t\t\t\t\t(c) => html`<tr><td class=\"body num\">${c.house}</td><td>${c.sign ?? ''}</td><td>${c.signLord ?? ''}</td><td>${c.nakshatra ?? ''}</td><td>${c.starLord ?? ''}</td><td>${c.subLord ?? ''}</td><td>${c.subSubLord ?? ''}</td><td class=\"num\">${typeof c.kpNumber === 'number' ? c.kpNumber : ''}</td></tr>`,\n\t\t\t\t)}</tbody></table>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-kp-chart': RoxyKpChart;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { KpPlanetsResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.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 RoxyDataElement<KpPlanetsResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);background:var(--roxy-surface,#fff);box-shadow:var(--roxy-shadow-sm);overflow:auto}.head{padding:var(--roxy-space-md,1rem);border-bottom:1px solid var(--roxy-border,#e4e4e7);justify-content:space-between;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.ayanamsa{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}table{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem);min-width:560px}thead{background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 20%, transparent)}th,td{padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);text-align:left;white-space:nowrap}th{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;font-size:var(--roxy-text-xs,.75rem);letter-spacing:.04em}tbody tr{border-top:1px solid var(--roxy-border,#e4e4e7)}td.planet{font-weight:var(--roxy-weight-bold,600);color:var(--roxy-fg,#0a0a0a)}.retro{color:var(--roxy-warning-fg,#9a3412);font-size:var(--roxy-text-xs,.75rem);margin-left:4px}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No KP data</div>`;\n\t}\n\n\tprotected renderData(d: KpPlanetsResponse) {\n\t\tconst planets = d.planets ?? [];\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"KP planets table\" tabindex=\"0\"><header class=\"head\"><h2 class=\"title\">KP planets</h2>${\n\t\t\t\t\ttypeof d.ayanamsa === 'number'\n\t\t\t\t\t\t? html`<span class=\"ayanamsa\">Ayanamsa: ${formatNumber(d.ayanamsa, 2)}\u00B0</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</header><table role=\"table\"><thead><tr><th scope=\"col\">Planet</th><th scope=\"col\">Sign</th><th scope=\"col\">Sign lord</th><th scope=\"col\">Nakshatra</th><th scope=\"col\">Star lord</th><th scope=\"col\">Sub lord</th><th scope=\"col\">Sub sub lord</th><th scope=\"col\">KP no.</th></tr></thead><tbody>${planets.map(\n\t\t\t\t\t\t(p) => html`<tr><td class=\"planet\">${p.planet} ${p.retrograde ? html`<span class=\"retro\">R</span>` : nothing}</td><td>${p.sign ?? ''}</td><td>${p.signLord ?? ''}</td><td>${p.nakshatra ?? ''}</td><td>${p.nakshatraLord ?? ''}</td><td>${p.subLord ?? ''}</td><td>${p.subSubLord ?? ''}</td><td>${p.kpNumber ?? ''}</td></tr>`,\n\t\t\t\t\t)}</tbody></table></div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-kp-planets-table': RoxyKpPlanetsTable;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { KpRulingPlanetsResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\n/**\n * KP ruling planets card. Renders /vedic-astrology/kp/ruling-planets: the day\n * lord, the Moon and Lagna stellar hierarchies (sign lord, star lord, sub\n * lord, sub-sub lord), the consolidated ruling-planet list ordered by\n * strength, and, when birth data is supplied, the house significators per\n * planet. The primary horary timing tool in KP astrology.\n */\n@customElement('roxy-kp-ruling-planets')\nexport class RoxyKpRulingPlanets extends RoxyDataElement<KpRulingPlanetsResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);background:var(--roxy-surface,#fff);padding:var(--roxy-space-md,1rem);gap:var(--roxy-space-md,1rem);box-shadow:var(--roxy-shadow-sm);display:grid}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.day-lord{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}.day-lord strong{color:var(--roxy-fg,#0a0a0a)}.groups{gap:var(--roxy-space-md,1rem);grid-template-columns:repeat(auto-fit,minmax(11rem,1fr));display:grid}.group h3{margin:0 0 var(--roxy-space-xs,.25rem);font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.05em}.group dl{gap:2px var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-sm,.875rem);grid-template-columns:auto 1fr;margin:0;display:grid}.group dt{color:var(--roxy-muted,#71717a)}.group dd{color:var(--roxy-fg,#0a0a0a);font-weight:var(--roxy-weight-bold,600);margin:0}.rp-list{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;align-items:center;display:flex}.rp-label{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.05em;margin-right:var(--roxy-space-xs,.25rem)}.rp{font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 18%, transparent);color:var(--roxy-fg,#0a0a0a);border-radius:999px;align-items:center;gap:.3em;padding:.15em .6em;display:inline-flex}.rp .rank{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-accent-ink,#b45309)}table{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem)}th,td{padding:var(--roxy-space-xs,.25rem) var(--roxy-space-sm,.5rem);text-align:left;border-bottom:1px solid var(--roxy-border,#e4e4e7)}th{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;font-size:var(--roxy-text-xs,.75rem);letter-spacing:.04em}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No ruling planets data</div>`;\n\t}\n\n\tprotected renderData(d: KpRulingPlanetsResponse) {\n\t\tconst significators = d.significators ?? [];\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"KP ruling planets\"><header><h2 class=\"title\">KP ruling planets</h2>${\n\t\t\t\t\td.dayLord\n\t\t\t\t\t\t? html`<div class=\"day-lord\">Day lord: <strong>${d.dayLord}</strong></div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</header><div class=\"groups\"><div class=\"group\"><h3>Moon</h3><dl><dt>Sign lord</dt><dd>${d.moonSignLord ?? ''}</dd><dt>Star lord</dt><dd>${d.moonStarLord ?? ''}</dd><dt>Sub lord</dt><dd>${d.moonSublord ?? ''}</dd><dt>Sub-sub lord</dt><dd>${d.moonSubSublord ?? ''}</dd></dl></div><div class=\"group\"><h3>Lagna</h3><dl><dt>Sign lord</dt><dd>${d.lagnaSignLord ?? ''}</dd><dt>Star lord</dt><dd>${d.lagnaStarLord ?? ''}</dd><dt>Sub lord</dt><dd>${d.lagnaSublord ?? ''}</dd><dt>Sub-sub lord</dt><dd>${d.lagnaSubSublord ?? ''}</dd></dl></div></div>${\n\t\t\t\td.rulingPlanets?.length\n\t\t\t\t\t? html`<div class=\"rp-list\" role=\"list\" aria-label=\"Ruling planets by strength\"><span class=\"rp-label\">Ruling planets</span> ${d.rulingPlanets.map(\n\t\t\t\t\t\t\t(p, i) =>\n\t\t\t\t\t\t\t\thtml`<span class=\"rp\" role=\"listitem\"><span class=\"rank\">${i + 1}</span> ${p}</span>`,\n\t\t\t\t\t\t)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tsignificators.length\n\t\t\t\t\t? html`<table aria-label=\"House significators\"><thead><tr><th scope=\"col\">Planet</th><th scope=\"col\">Signifies houses</th></tr></thead><tbody>${significators.map(\n\t\t\t\t\t\t\t\t(s) => html`<tr><td>${s.planet}</td><td>${(s.signifies ?? []).join(', ')}</td></tr>`,\n\t\t\t\t\t\t\t)}</tbody></table>`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-kp-ruling-planets': RoxyKpRulingPlanets;\n\t}\n}\n", "import { css, html, nothing, svg } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { LocalSpaceResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { planetColor } from '../utils/planet-color.js';\n\ntype Body = LocalSpaceResponse['bodies'][number];\n\nconst SIZE = 320;\nconst CENTER = SIZE / 2;\nconst RIM = 128;\nconst SPOKE = 118;\nconst GLYPH_R = 140;\nconst TICK_LABEL_R = 150;\n\n// Compass azimuth (0 = north, clockwise) to a screen point. North is up, east\n// is right, matching how the local space line is read off a real compass.\nfunction azimuthPoint(az: number, r: number): { x: number; y: number } {\n\tconst rad = (az * Math.PI) / 180;\n\treturn { x: CENTER + r * Math.sin(rad), y: CENTER - r * Math.cos(rad) };\n}\n\nconst PRINCIPAL = [\n\t{ az: 0, label: 'N' },\n\t{ az: 45, label: 'NE' },\n\t{ az: 90, label: 'E' },\n\t{ az: 135, label: 'SE' },\n\t{ az: 180, label: 'S' },\n\t{ az: 225, label: 'SW' },\n\t{ az: 270, label: 'W' },\n\t{ az: 315, label: 'NW' },\n];\n\n/**\n * Local space compass. Plots each body from a /astrology/local-space response as\n * a directional line radiating from the birthplace at its azimuth (0 = north,\n * clockwise), with a 16-point ring. Bodies below the horizon are dimmed. Color\n * is per body and theme-token driven.\n */\n@customElement('roxy-local-space-compass')\nexport class RoxyLocalSpaceCompass extends RoxyDataElement<LocalSpaceResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);width:100%;color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-primary,#0f172a);margin:0}.meta{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}svg{width:100%;max-width:var(--roxy-chart-max-width,480px);aspect-ratio:1;height:auto;margin:0 auto;display:block}.dial{fill:none;stroke:var(--roxy-border,#e4e4e7)}.dial-fill{fill:color-mix(in srgb, var(--roxy-border,#e4e4e7) 10%, transparent);stroke:var(--roxy-border,#e4e4e7);stroke-width:1px}.cardinal-axis{stroke:var(--roxy-border,#e4e4e7);stroke-width:.5px}.tick{stroke:var(--roxy-secondary,#475569);stroke-width:.6px;opacity:.5}.compass-label{fill:var(--roxy-secondary,#475569);font-size:9px;font-weight:600;font-family:var(--roxy-font-sans)}.compass-label.cardinal,.center-dot{fill:var(--roxy-fg,#0a0a0a)}.spoke{stroke-width:1.4px}.spoke.below{stroke-dasharray:3 3;opacity:.4}.body-glyph{font-size:11px;font-weight:600;font-family:var(--roxy-font-sans)}.body-glyph.below{opacity:.45}.list{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem)}.list th,.list td{text-align:left;border-bottom:1px solid var(--roxy-border,#e4e4e7);padding:4px 8px}.list th{color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.04em;font-weight:600;font-size:var(--roxy-text-xs,.75rem)}.list td.num{text-align:right;font-variant-numeric:tabular-nums}.body-cell{align-items:center;gap:.4rem;display:inline-flex}.body-dot{border-radius:50%;flex-shrink:0;width:10px;height:10px}.horizon-pill{border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);padding:1px 7px}.horizon-pill.up{background:color-mix(in srgb, var(--roxy-success,#16a34a) 16%, transparent);color:var(--roxy-success-fg,#166534)}.horizon-pill.down{background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 55%, transparent);color:var(--roxy-fg,#0a0a0a)}.summary{color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);margin:0}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No local space data</div>`;\n\t}\n\n\tprotected renderData(data: LocalSpaceResponse) {\n\t\tconst bodies = data.bodies ?? [];\n\t\tconst bd = data.birthDetails;\n\t\treturn html`<div class=\"wrap\"><header><h2 class=\"title\">Local space</h2>${\n\t\t\t\t\tbd\n\t\t\t\t\t\t? html`<div class=\"meta\">${[bd.date, bd.time].filter(Boolean).join(' \u00B7 ')}</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</header>${this.renderDial(bodies)} ${data.summary ? html`<p class=\"summary\">${data.summary}</p>` : nothing} ${this.renderList(bodies)}</div>`;\n\t}\n\n\tprivate renderDial(bodies: Body[]) {\n\t\treturn html`<svg viewBox=\"0 0 ${SIZE} ${SIZE}\" role=\"img\" aria-label=\"Local space compass of planetary directions from the birthplace\"><title>Local space compass</title><desc>A compass centered on the birthplace. Each body is a line pointing to its azimuth, clockwise from north. Bodies below the horizon are dimmed.</desc><circle class=\"dial-fill\" cx=\"${CENTER}\" cy=\"${CENTER}\" r=\"${RIM}\"/><circle class=\"dial\" cx=\"${CENTER}\" cy=\"${CENTER}\" r=\"${RIM * 0.66}\" stroke-width=\"0.5\"/><circle class=\"dial\" cx=\"${CENTER}\" cy=\"${CENTER}\" r=\"${RIM * 0.33}\" stroke-width=\"0.5\"/>${this.renderCompassRing()} ${this.renderSpokes(bodies)}<circle class=\"center-dot\" cx=\"${CENTER}\" cy=\"${CENTER}\" r=\"2.5\"/></svg>`;\n\t}\n\n\tprivate renderCompassRing() {\n\t\tconst ticks = [];\n\t\t// 16-point ring: a tick every 22.5 degrees.\n\t\tfor (let az = 0; az < 360; az += 22.5) {\n\t\t\tconst outer = azimuthPoint(az, RIM);\n\t\t\tconst inner = azimuthPoint(az, RIM - (az % 45 === 0 ? 8 : 4));\n\t\t\tticks.push(\n\t\t\t\tsvg`<line class=\"tick\" x1=${inner.x} y1=${inner.y} x2=${outer.x} y2=${outer.y} />`,\n\t\t\t);\n\t\t}\n\t\t// Cardinal cross.\n\t\tconst ns1 = azimuthPoint(0, RIM);\n\t\tconst ns2 = azimuthPoint(180, RIM);\n\t\tconst ew1 = azimuthPoint(90, RIM);\n\t\tconst ew2 = azimuthPoint(270, RIM);\n\t\tconst labels = PRINCIPAL.map(({ az, label }) => {\n\t\t\tconst pos = azimuthPoint(az, TICK_LABEL_R);\n\t\t\tconst cardinal = az % 90 === 0;\n\t\t\treturn svg`<text class=${`compass-label${cardinal ? ' cardinal' : ''}`} x=${pos.x} y=${pos.y} text-anchor=\"middle\" dominant-baseline=\"central\">${label}</text>`;\n\t\t});\n\t\treturn svg`\n\t\t\t<line class=\"cardinal-axis\" x1=${ns1.x} y1=${ns1.y} x2=${ns2.x} y2=${ns2.y} />\n\t\t\t<line class=\"cardinal-axis\" x1=${ew1.x} y1=${ew1.y} x2=${ew2.x} y2=${ew2.y} />\n\t\t\t${ticks}${labels}`;\n\t}\n\n\tprivate renderSpokes(bodies: Body[]) {\n\t\treturn bodies.map((b, i) => {\n\t\t\tconst color = planetColor(b.planet, i);\n\t\t\tconst below = b.aboveHorizon === false;\n\t\t\tconst end = azimuthPoint(b.azimuth, SPOKE);\n\t\t\tconst glyphPos = azimuthPoint(b.azimuth, GLYPH_R);\n\t\t\tconst glyph = b.symbol || b.planet.slice(0, 2);\n\t\t\tconst altLabel = `${b.altitude > 0 ? '+' : ''}${Math.round(b.altitude)}\u00B0`;\n\t\t\treturn svg`<g>\n\t\t\t\t<line class=${`spoke${below ? ' below' : ''}`} stroke=${color} x1=${CENTER} y1=${CENTER} x2=${end.x} y2=${end.y}><title>${b.planet} ${b.compassDirection} ${Math.round(b.azimuth)}\u00B0 altitude ${altLabel}</title></line>\n\t\t\t\t<text class=${`body-glyph${below ? ' below' : ''}`} fill=${color} x=${glyphPos.x} y=${glyphPos.y} text-anchor=\"middle\" dominant-baseline=\"central\">${glyph}</text>\n\t\t\t</g>`;\n\t\t});\n\t}\n\n\tprivate renderList(bodies: Body[]) {\n\t\tif (bodies.length === 0) return nothing;\n\t\treturn html`<table class=\"list\"><thead><tr><th>Body</th><th>Direction</th><th class=\"num\">Azimuth</th><th class=\"num\">Altitude</th><th>Horizon</th></tr></thead><tbody>${bodies.map((b, i) => {\n\t\t\t\t\tconst color = planetColor(b.planet, i);\n\t\t\t\t\tconst below = b.aboveHorizon === false;\n\t\t\t\t\treturn html`<tr><td><span class=\"body-cell\"><span class=\"body-dot\" style=\"${`background: ${color}`}\"></span> ${b.symbol ? html`${b.symbol}` : nothing}${b.planet}</span></td><td>${b.compassDirection}</td><td class=\"num\">${Math.round(b.azimuth)}\u00B0</td><td class=\"num\">${b.altitude > 0 ? '+' : ''}${Math.round(b.altitude)}\u00B0</td><td><span class=\"${`horizon-pill ${below ? 'down' : 'up'}`}\">${below ? 'Below' : 'Above'}</span></td></tr>`;\n\t\t\t\t})}</tbody></table>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-local-space-compass': RoxyLocalSpaceCompass;\n\t}\n}\n", "import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport type { SearchCitiesResponse } from '../types/index.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { debounce } from '../utils/debounce.js';\n\ntype CityResult = SearchCitiesResponse['cities'][number];\n\n/**\n * Stateful location search input. Calls /location/search and emits\n * `roxy-location-select` CustomEvent with the chosen city. Required for any\n * chart endpoint.\n *\n * Behavior: 300ms input debounce, click-outside dismiss, keyboard navigation\n * with arrow keys / Enter / Escape, AbortController on stale requests.\n *\n * Attributes:\n * api-key optional. Direct call to roxyapi.com when set.\n * publishable-key optional. Browser-safe pk_* key with allowed_origins.\n * endpoint optional. Override URL (default https://roxyapi.com/api/v2/location/search).\n * placeholder optional. Input placeholder.\n * default-value optional. Pre-filled query.\n */\n@customElement('roxy-location-search')\nexport class RoxyLocationSearch extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`:host{display:block;position:relative}.field{position:relative}input{width:100%;padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);font-size:var(--roxy-text-base,1rem);color:var(--roxy-fg,#0a0a0a);background:var(--roxy-bg,#fff);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);transition:border-color var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,cubic-bezier(.4, 0, .2, 1));box-sizing:border-box;font-family:inherit}input:focus{outline:2px solid var(--roxy-ring,#f59e0b66);outline-offset:2px;border-color:var(--roxy-accent-ink,#b45309)}.spinner{border:2px solid var(--roxy-muted,#71717a);border-top-color:#0000;border-radius:50%;width:14px;height:14px;animation:.7s linear infinite roxy-spin;position:absolute;top:50%;right:12px;transform:translateY(-50%)}@keyframes roxy-spin{to{transform:translateY(-50%)rotate(360deg)}}@media (prefers-reduced-motion:reduce){.spinner{animation:none}}.results{z-index:50;background:var(--roxy-bg,#fff);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);box-shadow:var(--roxy-shadow-md);max-height:22rem;animation:roxy-fade-in var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,cubic-bezier(.4, 0, .2, 1));position:absolute;top:calc(100% + 4px);left:0;right:0;overflow-y:auto}.option{align-items:baseline;gap:var(--roxy-space-sm,.5rem);width:100%;padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);text-align:left;font-family:inherit;font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);cursor:pointer;transition:background-color var(--roxy-motion-duration,.2s);background:0 0;border:0;display:flex}.option:hover,.option[aria-selected=true]{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 10%, transparent)}.option .city{font-weight:var(--roxy-weight-bold,600)}.option .where{color:var(--roxy-muted,#71717a);flex-grow:1}.option .tz{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);font-variant-numeric:tabular-nums}.empty{padding:var(--roxy-space-md,1rem);color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}`,\n\t];\n\n\t@property({ type: String, attribute: 'api-key' })\n\tapiKey?: string;\n\n\t@property({ type: String, attribute: 'publishable-key' })\n\tpublishableKey?: string;\n\n\t@property({ type: String })\n\tendpoint = 'https://roxyapi.com/api/v2/location/search';\n\n\t@property({ type: String })\n\tplaceholder = 'Search city';\n\n\t@property({ type: String, attribute: 'default-value' })\n\tdefaultValue = '';\n\n\t@state()\n\tprivate query = '';\n\n\t@state()\n\tprivate results: CityResult[] = [];\n\n\t@state()\n\tprivate isOpen = false;\n\n\t@state()\n\tprivate isLoading = false;\n\n\t@state()\n\tprivate highlight = -1;\n\n\tprivate clickOutsideHandler?: (e: MouseEvent) => void;\n\tprivate abortController?: AbortController;\n\tprivate secretKeyWarned = false;\n\tprivate debouncedFetch = debounce((q: string) => {\n\t\tvoid this.fetchResults(q);\n\t}, 300);\n\n\tconnectedCallback(): void {\n\t\tsuper.connectedCallback();\n\t\tthis.query = this.defaultValue;\n\t\tthis.clickOutsideHandler = (e: MouseEvent) => {\n\t\t\tconst path = e.composedPath();\n\t\t\tif (!path.includes(this)) this.isOpen = false;\n\t\t};\n\t\tdocument.addEventListener('mousedown', this.clickOutsideHandler);\n\t}\n\n\tdisconnectedCallback(): void {\n\t\tsuper.disconnectedCallback();\n\t\tif (this.clickOutsideHandler) {\n\t\t\tdocument.removeEventListener('mousedown', this.clickOutsideHandler);\n\t\t}\n\t\tthis.debouncedFetch.cancel();\n\t\tif (this.abortController) {\n\t\t\tthis.abortController.abort();\n\t\t\tthis.abortController = undefined;\n\t\t}\n\t}\n\n\tprivate warnIfSecretKey() {\n\t\tif (this.secretKeyWarned) return;\n\t\tif (!this.apiKey) return;\n\t\t// Browser-safe publishable keys carry the `pk_` prefix and a server-side\n\t\t// origin allowlist. Anything else (a raw secret key, UUID-style token)\n\t\t// must not ship to the browser.\n\t\tif (this.apiKey.startsWith('pk_')) return;\n\t\tthis.secretKeyWarned = true;\n\t\tconst message =\n\t\t\t'Possible secret key in client-side <roxy-location-search>; use a `pk_` publishable key with origin allowlist instead.';\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.warn(message);\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('roxy-validation-error', {\n\t\t\t\tdetail: { reason: 'possible-secret-key', message },\n\t\t\t\tbubbles: true,\n\t\t\t\tcomposed: true,\n\t\t\t}),\n\t\t);\n\t}\n\n\tprivate async fetchResults(q: string) {\n\t\tthis.warnIfSecretKey();\n\t\t// Abort any in-flight request so a stale response cannot overwrite a\n\t\t// fresher one (debounced typing) or land after disconnect.\n\t\tif (this.abortController) this.abortController.abort();\n\t\tconst controller = new AbortController();\n\t\tthis.abortController = controller;\n\t\tthis.isLoading = true;\n\t\ttry {\n\t\t\tconst url = new URL(this.endpoint);\n\t\t\turl.searchParams.set('q', q);\n\t\t\turl.searchParams.set('limit', '8');\n\t\t\tconst headers: Record<string, string> = {\n\t\t\t\tAccept: 'application/json',\n\t\t\t};\n\t\t\t// publishable-key wins when both are set. Surfacing the conflict at the\n\t\t\t// console (not as a thrown error) avoids breaking widgets that legitimately\n\t\t\t// have a stale secret key around while migrating to publishable.\n\t\t\tif (this.apiKey && this.publishableKey) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t'[roxy-location-search] both api-key and publishable-key set; using publishable-key. Remove api-key from your widget markup.',\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst key = this.publishableKey ?? this.apiKey;\n\t\t\tif (key) headers['X-API-Key'] = key;\n\t\t\tconst res = await fetch(url, { headers, signal: controller.signal });\n\t\t\tif (!res.ok) throw new Error(`HTTP ${res.status}`);\n\t\t\tconst json = (await res.json()) as SearchCitiesResponse;\n\t\t\tif (controller.signal.aborted) return;\n\t\t\tthis.results = json.cities ?? [];\n\t\t\tthis.isOpen = this.results.length > 0;\n\t\t\tthis.highlight = this.results.length > 0 ? 0 : -1;\n\t\t} catch (err) {\n\t\t\tif ((err as { name?: string })?.name === 'AbortError') return;\n\t\t\tthis.results = [];\n\t\t\tthis.isOpen = false;\n\t\t} finally {\n\t\t\tif (this.abortController === controller) {\n\t\t\t\tthis.abortController = undefined;\n\t\t\t}\n\t\t\tif (!controller.signal.aborted) this.isLoading = false;\n\t\t}\n\t}\n\n\tprivate onInput = (e: Event) => {\n\t\tconst value = (e.target as HTMLInputElement).value;\n\t\tthis.query = value;\n\t\tif (value.length < 2) {\n\t\t\tthis.results = [];\n\t\t\tthis.isOpen = false;\n\t\t\tthis.highlight = -1;\n\t\t\treturn;\n\t\t}\n\t\tthis.debouncedFetch(value);\n\t};\n\n\tprivate select(city: CityResult) {\n\t\tthis.query = `${city.city}${city.province ? `, ${city.province}` : ''}, ${city.country}`;\n\t\tthis.isOpen = false;\n\t\tthis.results = [];\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('roxy-location-select', {\n\t\t\t\tdetail: city,\n\t\t\t\tbubbles: true,\n\t\t\t\tcomposed: true,\n\t\t\t}),\n\t\t);\n\t}\n\n\tprivate onKeyDown = (e: KeyboardEvent) => {\n\t\tif (!this.isOpen || this.results.length === 0) {\n\t\t\tif (e.key === 'ArrowDown' && this.query.length >= 2) {\n\t\t\t\tvoid this.fetchResults(this.query);\n\t\t\t\te.preventDefault();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (e.key === 'ArrowDown') {\n\t\t\te.preventDefault();\n\t\t\tthis.highlight = (this.highlight + 1) % this.results.length;\n\t\t} else if (e.key === 'ArrowUp') {\n\t\t\te.preventDefault();\n\t\t\tthis.highlight =\n\t\t\t\t(this.highlight - 1 + this.results.length) % this.results.length;\n\t\t} else if (e.key === 'Enter') {\n\t\t\te.preventDefault();\n\t\t\tconst target = this.results[this.highlight] ?? this.results[0];\n\t\t\tif (target) this.select(target);\n\t\t} else if (e.key === 'Escape') {\n\t\t\tthis.isOpen = false;\n\t\t}\n\t};\n\n\trender() {\n\t\treturn html`<div class=\"field\"><input type=\"text\" role=\"combobox\" aria-expanded=\"${this.isOpen ? 'true' : 'false'}\" aria-controls=\"roxy-location-listbox\" aria-activedescendant=\"${\n\t\t\t\t\tthis.isOpen && this.highlight >= 0\n\t\t\t\t\t\t? `roxy-location-option-${this.highlight}`\n\t\t\t\t\t\t: ''\n\t\t\t\t}\" aria-autocomplete=\"list\" autocomplete=\"off\" placeholder=\"${this.placeholder}\" .value=\"${this.query}\" @input=\"${this.onInput}\" @keydown=\"${this.onKeyDown}\" @focus=\"${() => {\n\t\t\t\t\tif (this.results.length > 0) this.isOpen = true;\n\t\t\t\t}}\"> ${this.isLoading ? html`<span class=\"spinner\" role=\"status\" aria-label=\"Loading\"></span>` : nothing} ${\n\t\t\t\tthis.isOpen\n\t\t\t\t\t? html`<ul id=\"roxy-location-listbox\" class=\"results\" role=\"listbox\">${\n\t\t\t\t\t\t\tthis.results.length === 0\n\t\t\t\t\t\t\t\t? html`<li class=\"empty\" role=\"status\">No cities found</li>`\n\t\t\t\t\t\t\t\t: this.results.map(\n\t\t\t\t\t\t\t\t\t\t(city, idx) => html`<li role=\"presentation\"><button type=\"button\" class=\"option\" role=\"option\" id=\"${`roxy-location-option-${idx}`}\" aria-selected=\"${this.highlight === idx ? 'true' : 'false'}\" @click=\"${() => this.select(city)}\" @mouseenter=\"${() => {\n\t\t\t\t\t\t\t\t\t\t\t\tthis.highlight = idx;\n\t\t\t\t\t\t\t\t\t\t\t}}\"><span class=\"city\">${city.city}</span> <span class=\"where\">${city.province ? html`${city.province},` : ''}${city.country}</span> <span class=\"tz\">UTC${city.utcOffset >= 0 ? '+' : ''}${city.utcOffset}</span></button></li>`,\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}</ul>`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-location-search': RoxyLocationSearch;\n\t}\n}\n", "/**\n * Lightweight debounce for input handlers. Used by location search.\n *\n * The returned function exposes a `.cancel()` method so callers can clear a\n * pending invocation when the host element disconnects, preventing the timer\n * from firing on a detached node and mutating reactive state after teardown.\n */\nexport interface Debounced<F extends (...args: never[]) => unknown> {\n\t(...args: Parameters<F>): void;\n\tcancel: () => void;\n}\n\nexport function debounce<F extends (...args: never[]) => unknown>(\n\tfn: F,\n\twait: number,\n): Debounced<F> {\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\tconst debounced = ((...args: Parameters<F>) => {\n\t\tif (timer) clearTimeout(timer);\n\t\ttimer = setTimeout(() => {\n\t\t\ttimer = undefined;\n\t\t\tfn(...args);\n\t\t}, wait);\n\t}) as Debounced<F>;\n\tdebounced.cancel = () => {\n\t\tif (timer) {\n\t\t\tclearTimeout(timer);\n\t\t\ttimer = undefined;\n\t\t}\n\t};\n\treturn debounced;\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { MOON_PHASE_EMOJI } from '../tokens/index.js';\nimport type {\n\tGetCurrentMoonPhaseResponse,\n\tGetMoonCalendarResponse,\n\tGetUpcomingMoonPhasesResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatNumber } from '../utils/format.js';\n\ntype MoonPhaseData =\n\t| GetCurrentMoonPhaseResponse\n\t| GetUpcomingMoonPhasesResponse\n\t| GetMoonCalendarResponse;\ntype MoonListEntry =\n\t| GetUpcomingMoonPhasesResponse['phases'][number]\n\t| GetMoonCalendarResponse['calendar'][number];\n\n/**\n * Moon phase card. Renders /astrology/moon-phase/{current,upcoming,calendar/...}.\n */\n@customElement('roxy-moon-phase')\nexport class RoxyMoonPhase extends RoxyDataElement<MoonPhaseData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.card{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.hero{align-items:center;gap:var(--roxy-space-md,1rem);display:flex}.emoji{font-size:3rem;line-height:1}.label{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);text-transform:capitalize;margin:0}.date{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}.stats{gap:var(--roxy-space-md,1rem);font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-secondary,#475569);grid-template-columns:repeat(auto-fit,minmax(8rem,1fr));display:grid}.stats div span:first-child{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);text-transform:uppercase;letter-spacing:.06em;display:block}.stats strong{color:var(--roxy-fg,#0a0a0a);font-variant-numeric:tabular-nums}.meaning{color:var(--roxy-fg,#0a0a0a)}.keywords{gap:var(--roxy-space-xs,.25rem);margin-top:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.keywords span{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 14%, transparent);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);padding:2px 8px}.list{gap:var(--roxy-space-sm,.5rem);display:grid}.list-item{gap:var(--roxy-space-sm,.5rem);border-bottom:1px solid var(--roxy-border,#e4e4e7);padding:var(--roxy-space-sm,.5rem) 0;font-size:var(--roxy-text-sm,.875rem);grid-template-columns:2.5rem 1fr auto;align-items:center;display:grid}.list-item:last-child{border-bottom:none}`,\n\t];\n\n\t@property({ type: String, reflect: true })\n\tmode: 'current' | 'upcoming' | 'calendar' = 'current';\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No moon phase data</div>`;\n\t}\n\n\tprotected renderData(d: MoonPhaseData) {\n\t\tconst list: MoonListEntry[] =\n\t\t\t'phases' in d ? d.phases : 'calendar' in d ? d.calendar : [];\n\t\tif (this.mode !== 'current' && list.length > 0) {\n\t\t\tconst month = 'month' in d ? d.month : undefined;\n\t\t\tconst year = 'year' in d ? d.year : undefined;\n\t\t\treturn html`<article class=\"card\" aria-label=\"Moon phase calendar\"><h2 class=\"label\">${month ?? 'Moon phases'} ${year ?? ''}</h2><div class=\"list\" role=\"list\">${list.map((phase) => this.renderListItem(phase))}</div></article>`;\n\t\t}\n\t\tif (!('phase' in d)) return nothing;\n\t\treturn this.renderSingle(d);\n\t}\n\n\tprivate renderSingle(d: GetCurrentMoonPhaseResponse) {\n\t\t// The API ships the exact phase emoji in meaning.symbol; prefer it and fall\n\t\t// back to the name-derived glyph for the list endpoints that omit meaning.\n\t\tconst emoji = d.meaning?.symbol || phaseEmoji(d.phase);\n\t\treturn html`<article class=\"card\" aria-label=\"Current moon phase\"><div class=\"hero\"><span class=\"emoji\" aria-hidden=\"true\">${emoji}</span><div><h2 class=\"label\">${d.phase ?? 'Moon'}</h2>${d.date ? html`<div class=\"date\">${d.date}</div>` : nothing}</div></div><div class=\"stats\">${\n\t\t\t\t\ttypeof d.illumination === 'number'\n\t\t\t\t\t\t? html`<div><span>Illumination</span> <strong>${formatIllumination(d.illumination)}</strong></div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} ${\n\t\t\t\t\ttypeof d.age === 'number'\n\t\t\t\t\t\t? html`<div><span>Age</span> <strong>${formatNumber(d.age, 1)} days</strong></div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} ${\n\t\t\t\t\td.sign\n\t\t\t\t\t\t? html`<div><span>Sign</span> <strong>${d.sign}</strong></div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} ${\n\t\t\t\t\ttypeof d.distance === 'number'\n\t\t\t\t\t\t? html`<div><span>Distance</span> <strong>${(d.distance / 1000).toFixed(0)}k km</strong></div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</div>${\n\t\t\t\td.meaning?.description\n\t\t\t\t\t? html`<p class=\"meaning\">${d.meaning.description}</p>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\td.meaning?.keywords?.length\n\t\t\t\t\t? html`<div class=\"keywords\">${d.meaning.keywords.map((k) => html`<span>${k}</span>`)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t}</article>`;\n\t}\n\n\tprivate renderListItem(p: MoonListEntry) {\n\t\tconst emoji = phaseEmoji(p.phase);\n\t\treturn html`<div class=\"list-item\" role=\"listitem\"><span aria-hidden=\"true\">${emoji}</span> <span>${p.phase}</span> <span>${p.date ?? ''}</span></div>`;\n\t}\n}\n\n/**\n * Map a phase name to its emoji, tolerant of the live API naming. The API sends\n * suffixed names (\"Waxing Gibbous Moon\") and \"Third Quarter Moon\" where the map\n * keys are unsuffixed and use \"last quarter\"; only \"new moon\"/\"full moon\" keep\n * the suffix. Try the raw lowercase, then the suffix stripped, then the\n * third->last quarter alias, then the alias re-suffixed, so every one of the\n * eight phases resolves in both the suffixed and unsuffixed forms.\n */\nfunction phaseEmoji(phase: string | undefined): string {\n\tif (!phase) return '\uD83C\uDF19';\n\tconst lc = phase.toLowerCase().trim();\n\tconst noMoon = lc.replace(/\\s*moon$/, '').trim();\n\tconst alias = noMoon === 'third quarter' ? 'last quarter' : noMoon;\n\treturn (\n\t\tMOON_PHASE_EMOJI[lc] ??\n\t\tMOON_PHASE_EMOJI[noMoon] ??\n\t\tMOON_PHASE_EMOJI[alias] ??\n\t\tMOON_PHASE_EMOJI[`${alias} moon`] ??\n\t\t'\uD83C\uDF19'\n\t);\n}\n\nfunction formatIllumination(v: number): string {\n\tconst pct = v <= 1 ? v * 100 : v;\n\treturn `${Math.round(pct)}%`;\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-moon-phase': RoxyMoonPhase;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { NakshatraResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\n/**\n * Nakshatra reference card. Renders /vedic-astrology/nakshatras/{id}: the\n * lunar mansion number, longitude range, ruling planet, presiding deity,\n * symbol, native characteristics, and traditional remedies.\n */\n@customElement('roxy-nakshatra-card')\nexport class RoxyNakshatraCard extends RoxyDataElement<NakshatraResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);padding:var(--roxy-space-md,1rem);gap:var(--roxy-space-md,1rem);box-shadow:var(--roxy-shadow-sm);display:grid}.head{align-items:baseline;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.name{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.number{color:var(--roxy-accent-ink,#b45309);font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600)}.range{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}.facts{gap:var(--roxy-space-sm,.5rem);grid-template-columns:repeat(auto-fit,minmax(8rem,1fr));display:grid}.fact{gap:2px;display:grid}.fact dt{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);text-transform:uppercase;letter-spacing:.05em}.fact dd{color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);margin:0}.section h3{margin:0 0 var(--roxy-space-xs,.25rem);font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.05em}.section p{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);margin:0;line-height:1.5}.remedies{gap:var(--roxy-space-xs,.25rem);display:grid}.remedy{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a)}.remedy strong{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600)}`,\n\t];\n\n\tprotected renderData(n: NakshatraResponse) {\n\t\tconst remedies = n.remedies;\n\n\t\treturn html`<article class=\"wrap\" aria-label=\"${`Nakshatra ${n.name}`}\"><header class=\"head\"><h2 class=\"name\">${n.name}</h2>${\n\t\t\t\t\ttypeof n.number === 'number'\n\t\t\t\t\t\t? html`<span class=\"number\">Nakshatra ${n.number} of 27</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} ${n.range ? html`<span class=\"range\">${n.range}</span>` : nothing}</header><dl class=\"facts\">${n.lord ? html`<div class=\"fact\"><dt>Lord</dt><dd>${n.lord}</dd></div>` : nothing} ${n.deity ? html`<div class=\"fact\"><dt>Deity</dt><dd>${n.deity}</dd></div>` : nothing} ${n.symbol ? html`<div class=\"fact\"><dt>Symbol</dt><dd>${n.symbol}</dd></div>` : nothing}</dl>${\n\t\t\t\tn.characteristics\n\t\t\t\t\t? html`<div class=\"section\"><h3>Characteristics</h3><p>${n.characteristics}</p></div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tremedies\n\t\t\t\t\t? html`<div class=\"section\"><h3>Remedies</h3><div class=\"remedies\">${remedies.mantras ? html`<div class=\"remedy\"><strong>Mantras:</strong> ${remedies.mantras}</div>` : nothing} ${remedies.gemstones ? html`<div class=\"remedy\"><strong>Gemstones:</strong> ${remedies.gemstones}</div>` : nothing} ${remedies.rituals ? html`<div class=\"remedy\"><strong>Rituals:</strong> ${remedies.rituals}</div>` : nothing}</div></div>`\n\t\t\t\t\t: nothing\n\t\t\t}</article>`;\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No nakshatra data</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-nakshatra-card': RoxyNakshatraCard;\n\t}\n}\n", "import { css, html, nothing, svg } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport {\n\tASPECT_SYMBOL,\n\tPLANET_GLYPH,\n\tSIGN_GLYPH,\n\tSIGNS_ORDER,\n} from '../tokens/index.js';\nimport type { NatalChartResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport {\n\tarcMidpoint,\n\tlongitudeToSignPosition,\n\tnormalizeLongitude,\n\toppositePoint,\n\tpolarToCartesian,\n} from '../utils/degree.js';\nimport { chevron, disclosureStyles } from '../utils/disclosure.js';\nimport {\n\tASPECT_CLASS,\n\tformatNumber,\n\tnormalizeAspect,\n} from '../utils/format.js';\nimport { capitalize } from '../utils/string.js';\nimport { renderTablist, tablistStyles } from '../utils/tablist.js';\n\ntype PlanetEntry = NatalChartResponse['planets'][number];\ntype AspectEntry = NatalChartResponse['aspects'][number];\n\nconst SIZE = 420;\nconst CENTER = SIZE / 2;\nconst OUTER_R = 164;\nconst SIGN_R = 146;\nconst HOUSE_R = 120;\nconst PLANET_R = 96;\nconst ANGLE_TICK_R = 178;\nconst ANGLE_LABEL_R = 196;\n\n/**\n * Western natal chart wheel. Renders the 12 zodiac signs, 12 houses, planet\n * markers, and aspect lines from a /astrology/natal-chart response.\n */\n@customElement('roxy-natal-chart')\nexport class RoxyNatalChart extends RoxyDataElement<NatalChartResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\ttablistStyles,\n\t\tdisclosureStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);width:100%;color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-primary,#0f172a);margin:0}.meta{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}svg{width:100%;max-width:var(--roxy-chart-max-width,560px);aspect-ratio:1;height:auto;margin:0 auto;display:block}.wheel-line{fill:none;stroke:var(--roxy-border,#e4e4e7)}.sign-glyph{fill:var(--roxy-secondary,#475569);font-size:14px;font-family:var(--roxy-font-sans)}.planet-glyph{fill:var(--roxy-accent,#f59e0b);font-size:14px;font-weight:600;font-family:var(--roxy-font-sans)}.planet-deg{fill:var(--roxy-fg,#0a0a0a);font-size:7px;font-family:var(--roxy-font-sans)}@container (width<=480px){.sign-glyph,.planet-glyph{font-size:18px}.planet-deg{font-size:10px}.house-num{font-size:12px}}.planet-deg .retro{fill:var(--roxy-danger,#dc2626)}.planet-leader{stroke:var(--roxy-accent,#f59e0b);stroke-width:.5px;opacity:.55}.house-num{fill:var(--roxy-muted,#71717a);font-size:9px;font-family:var(--roxy-font-sans)}.cusp-deg{fill:var(--roxy-muted,#71717a);font-size:6px;font-family:var(--roxy-font-sans)}.tick{stroke:var(--roxy-border,#e4e4e7)}.tick-major{stroke:var(--roxy-secondary,#475569)}.aspect{stroke-width:.8px;fill:none;opacity:.55}.aspect-trine,.aspect-sextile{stroke:var(--roxy-success,#16a34a)}.aspect-square,.aspect-opposition{stroke:var(--roxy-danger,#dc2626)}.aspect-conjunction{stroke:var(--roxy-accent-ink,#b45309)}.aspect-other{stroke:var(--roxy-muted,#71717a);opacity:.4}.angle-marker{fill:var(--roxy-accent-ink,#b45309);font-size:10px;font-weight:700;font-family:var(--roxy-font-sans);letter-spacing:.04em}.angle-tick{stroke:var(--roxy-accent-ink,#b45309);stroke-width:1.5px}.legend{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);gap:var(--roxy-space-md,1rem);flex-wrap:wrap;display:flex}.legend-swatch{vertical-align:middle;border-radius:50%;width:8px;height:8px;margin-right:4px;display:inline-block}.grid-scroll{-webkit-overflow-scrolling:touch;overflow-x:auto}table.aspect-grid{border-collapse:collapse;font-size:var(--roxy-text-xs,.75rem);margin:0 auto}table.aspect-grid th,table.aspect-grid td{text-align:center;border:1px solid var(--roxy-border,#e4e4e7);width:1.6rem;height:1.6rem;padding:0}table.aspect-grid th{color:var(--roxy-secondary,#475569);font-weight:var(--roxy-weight-bold,600)}table.aspect-grid td.cell{cursor:default}table.aspect-grid td.empty{background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 18%, transparent)}table.aspect-grid td .asp{font-size:.95em;line-height:1}table.aspect-grid td.aspect-trine .asp,table.aspect-grid td.aspect-sextile .asp{color:var(--roxy-success,#16a34a)}table.aspect-grid td.aspect-square .asp,table.aspect-grid td.aspect-opposition .asp{color:var(--roxy-danger,#dc2626)}table.aspect-grid td.aspect-conjunction .asp{color:var(--roxy-accent-ink,#b45309)}table.aspect-grid td.aspect-other .asp{color:var(--roxy-muted,#71717a)}.details{margin-top:var(--roxy-space-md,1rem)}.pill-row{gap:var(--roxy-space-xs,.25rem);margin-bottom:var(--roxy-space-xs,.25rem);flex-wrap:wrap;display:flex}.pill{border-radius:var(--roxy-radius-sm,4px);font-size:var(--roxy-text-xs,.75rem);background:color-mix(in srgb, var(--roxy-fg,#0f172a) 8%, transparent);color:var(--roxy-fg,#0f172a);padding:2px 8px}.pill--success{background:color-mix(in srgb, var(--roxy-success,#16a34a) 15%, transparent);color:var(--roxy-success,#16a34a)}.pill--danger{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 15%, transparent);color:var(--roxy-danger,#dc2626)}.pill--muted{background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 60%, transparent);color:var(--roxy-fg,#0a0a0a)}.summary{color:var(--roxy-fg,#0f172a);font-size:var(--roxy-text-sm,.875rem);margin:var(--roxy-space-md,1rem) 0}.em-grid{border-collapse:collapse;font-size:var(--roxy-text-xs,.75rem);width:100%}.em-grid th,.em-grid td{border:1px solid var(--roxy-border,#e4e4e7);text-align:center;vertical-align:middle;padding:3px 5px}.em-grid th{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;letter-spacing:.04em}.em-grid th[scope=row]{text-align:left}.em-grid td{color:var(--roxy-accent,#f59e0b);min-width:1.4rem;font-size:.95em;line-height:1.4}.em-grid .em-total{color:var(--roxy-fg,#0a0a0a);font-weight:var(--roxy-weight-bold,600);background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 25%, transparent)}.interpretations{margin-top:var(--roxy-space-md,1rem)}.interpretations h3{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;margin:0 0 var(--roxy-space-sm,.5rem);font-weight:600}.interp-card{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);margin-bottom:var(--roxy-space-xs,.25rem)}.interp-card summary{cursor:pointer;color:var(--roxy-fg,#0f172a);justify-content:space-between;align-items:center;gap:var(--roxy-space-md,1rem);font-weight:500;display:flex}.interp-aside{align-items:center;gap:.6em;display:inline-flex}.interp-aside small{color:var(--roxy-muted,#71717a);font-weight:400}.interp-body{margin-top:var(--roxy-space-xs,.25rem);color:var(--roxy-fg,#0f172a);font-size:var(--roxy-text-sm,.875rem)}.interp-keywords{flex-wrap:wrap;gap:.25rem;margin-top:.5rem;display:flex}.interp-keywords .kw{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 14%, transparent);color:var(--roxy-accent-ink,#b45309);font-size:var(--roxy-text-xs,.75rem);border-radius:9999px;padding:1px 8px}`,\n\t];\n\n\t@property({ type: String, attribute: 'house-system', reflect: true })\n\thouseSystem: 'placidus' | 'whole-sign' | 'equal' | 'koch' = 'placidus';\n\n\t/** Heading above the wheel. Defaults to \"Natal chart\"; reuse (e.g. the relocation wheel) sets its own. */\n\t@property({ type: String })\n\theading = 'Natal chart';\n\n\t/** Which view is showing: the wheel or the planet-by-planet aspect grid. */\n\t@state()\n\tprivate view: 'wheel' | 'grid' = 'wheel';\n\n\tprivate getPlanets(): PlanetEntry[] {\n\t\treturn this.data?.planets ?? [];\n\t}\n\n\tprivate getAscendant(): number {\n\t\treturn this.data?.ascendant?.longitude ?? 0;\n\t}\n\n\tprivate getMidheaven(): number | null {\n\t\tconst m = this.data?.midheaven?.longitude;\n\t\treturn typeof m === 'number' ? m : null;\n\t}\n\n\tprivate toAngle(lon: number): number {\n\t\treturn 180 + this.getAscendant() - lon;\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No chart data</div>`;\n\t}\n\n\tprotected renderData(data: NatalChartResponse) {\n\t\tconst planets = this.getPlanets();\n\t\tconst aspects = data.aspects ?? [];\n\t\tconst view = this.view;\n\n\t\treturn html`<div class=\"wrap\"><header><h2 class=\"title\">${this.heading}</h2>${\n\t\t\t\t\tdata.birthDetails\n\t\t\t\t\t\t? html`<div class=\"meta\">${[data.birthDetails.date, data.birthDetails.time]\n\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t.join(' \u00B7 ')}</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</header>${\n\t\t\t\taspects.length > 0\n\t\t\t\t\t? html`${renderTablist({\n\t\t\t\t\t\t\titems: [\n\t\t\t\t\t\t\t\t{ id: 'wheel', label: 'Wheel' },\n\t\t\t\t\t\t\t\t{ id: 'grid', label: 'Aspect grid' },\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tactive: view,\n\t\t\t\t\t\t\tonSelect: (v) => {\n\t\t\t\t\t\t\t\tthis.view = v;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tlabel: 'Natal chart views',\n\t\t\t\t\t\t\tidPrefix: 'natal',\n\t\t\t\t\t\t\tcontrols: true,\n\t\t\t\t\t\t})}<div id=\"natal-panel-${view}\" role=\"tabpanel\" aria-labelledby=\"natal-tab-${view}\">${view === 'wheel' ? this.renderWheel(planets, aspects) : this.renderAspectGrid(planets, aspects)}</div>`\n\t\t\t\t\t: this.renderWheel(planets, aspects)\n\t\t\t}<div class=\"legend\"><span>${planets.length} planets</span> ${aspects.length > 0 ? html`<span>${aspects.length} aspects</span>` : nothing} ${\n\t\t\t\t\tdata.houseSystem\n\t\t\t\t\t\t? html`<span>${data.houseSystem} houses</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} ${\n\t\t\t\t\taspects.length > 0\n\t\t\t\t\t\t? html`<span><span class=\"legend-swatch\" style=\"background:var(--roxy-success)\"></span>harmonious</span> <span><span class=\"legend-swatch\" style=\"background:var(--roxy-danger)\"></span>challenging</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</div>${this.renderDetails()} ${this.renderInterpretations()}</div>`;\n\t}\n\n\tprivate renderWheel(planets: PlanetEntry[], aspects: AspectEntry[]) {\n\t\treturn html`<svg viewBox=\"0 0 ${SIZE} ${SIZE}\" role=\"img\" aria-label=\"Natal chart wheel with twelve houses, planets, and aspects\"><title>Natal chart wheel</title><desc>Twelve zodiac sign segments around a circular wheel. Planet glyphs are placed at their ecliptic longitudes. Aspect lines connect related planets.</desc><circle class=\"wheel-line\" cx=\"${CENTER}\" cy=\"${CENTER}\" r=\"${OUTER_R}\" stroke-width=\"1.5\"/><circle class=\"wheel-line\" cx=\"${CENTER}\" cy=\"${CENTER}\" r=\"${SIGN_R - 14}\" stroke-width=\"0.8\"/><circle class=\"wheel-line\" cx=\"${CENTER}\" cy=\"${CENTER}\" r=\"${HOUSE_R}\" stroke-width=\"1\"/><circle class=\"wheel-line\" cx=\"${CENTER}\" cy=\"${CENTER}\" r=\"${PLANET_R - 16}\" stroke-width=\"0.5\"/>${this.renderTicks()} ${this.renderSpokes()} ${this.renderSigns()} ${this.renderHouseNumbers()} ${this.renderCuspDegrees()} ${this.renderAspects(planets, aspects)} ${this.renderPlanets(planets)} ${this.renderAngles()}</svg>`;\n\t}\n\n\t/**\n\t * Planet-by-planet aspect grid: the lower-triangular matrix astrologers read\n\t * alongside the wheel. Each filled cell shows the aspect glyph colored by\n\t * nature, with the exact orb in the SVG-free `<title>` tooltip.\n\t */\n\tprivate renderAspectGrid(planets: PlanetEntry[], aspects: AspectEntry[]) {\n\t\tconst names = planets.map((p) => capitalize(p.name));\n\t\t// Lookup aspects by unordered planet pair.\n\t\tconst byPair = new Map<string, AspectEntry>();\n\t\tfor (const a of aspects) {\n\t\t\tconst k = [capitalize(a.planet1), capitalize(a.planet2)].sort().join('|');\n\t\t\tbyPair.set(k, a);\n\t\t}\n\t\tif (names.length === 0)\n\t\t\treturn html`<p class=\"roxy-empty\" role=\"status\">No planets to grid</p>`;\n\n\t\treturn html`<div class=\"grid-scroll\"><table class=\"aspect-grid\" aria-label=\"Planet by planet aspect grid\"><thead><tr><th></th>${names.slice(0, -1).map((n) => {\n\t\t\t\t\t\t\tconst g = PLANET_GLYPH[n] ?? n.slice(0, 2);\n\t\t\t\t\t\t\treturn html`<th scope=\"col\" title=\"${n}\">${g}</th>`;\n\t\t\t\t\t\t})}</tr></thead><tbody>${names.slice(1).map((rowName, ri) => {\n\t\t\t\t\t\tconst rowGlyph = PLANET_GLYPH[rowName] ?? rowName.slice(0, 2);\n\t\t\t\t\t\t// Row i (1-based) pairs with columns 0..i-1.\n\t\t\t\t\t\treturn html`<tr><th scope=\"row\" title=\"${rowName}\">${rowGlyph}</th>${names.slice(0, ri + 1).map((colName) => {\n\t\t\t\t\t\t\t\tconst a = byPair.get([rowName, colName].sort().join('|'));\n\t\t\t\t\t\t\t\tif (!a) return html`<td class=\"empty\"></td>`;\n\t\t\t\t\t\t\t\tconst name = normalizeAspect(a);\n\t\t\t\t\t\t\t\tconst sym =\n\t\t\t\t\t\t\t\t\tASPECT_SYMBOL[name] ??\n\t\t\t\t\t\t\t\t\tASPECT_SYMBOL[name.replace(/-/g, '')] ??\n\t\t\t\t\t\t\t\t\tname.slice(0, 3);\n\t\t\t\t\t\t\t\tconst cls = ASPECT_CLASS[name] ?? 'aspect-other';\n\t\t\t\t\t\t\t\tconst orb = formatNumber(a.orb, 1);\n\t\t\t\t\t\t\t\treturn html`<td class=\"${`cell ${cls}`}\" title=\"${`${rowName} ${name} ${colName}${orb ? ` (orb ${orb}\u00B0)` : ''}`}\"><span class=\"asp\">${sym}</span></td>`;\n\t\t\t\t\t\t\t})} ${names.slice(ri + 1, -1).map(() => html`<td class=\"empty\"></td>`)}</tr>`;\n\t\t\t\t\t})}</tbody></table></div>`;\n\t}\n\n\tprivate renderAngles() {\n\t\tconst asc = this.getAscendant();\n\t\tconst mc = this.getMidheaven();\n\t\t// ASC/DESC and MC/IC are exact axes; DESC and IC are the opposite points.\n\t\tconst items = [\n\t\t\tthis.renderAngleMark(asc, 'ASC'),\n\t\t\tthis.renderAngleMark(oppositePoint(asc), 'DSC'),\n\t\t];\n\t\tif (mc !== null) {\n\t\t\titems.push(this.renderAngleMark(mc, 'MC'));\n\t\t\titems.push(this.renderAngleMark(oppositePoint(mc), 'IC'));\n\t\t}\n\t\tconst pof = this.data?.partOfFortune?.longitude;\n\t\tif (typeof pof === 'number') {\n\t\t\titems.push(this.renderAngleMark(normalizeLongitude(pof), 'PoF'));\n\t\t}\n\t\tconst vertex = this.data?.vertex?.longitude;\n\t\tif (typeof vertex === 'number') {\n\t\t\titems.push(this.renderAngleMark(normalizeLongitude(vertex), 'Vtx'));\n\t\t}\n\t\treturn items;\n\t}\n\n\tprivate renderAngleMark(longitude: number, label: string) {\n\t\t// Tick AND label share the same angle so the label sits right at the\n\t\t// tip of the arrow, where a practitioner expects to find it. The label\n\t\t// halo at radius ANGLE_LABEL_R is clear of the wheel rim, so there is\n\t\t// no overlap with house dividers despite the shared angle.\n\t\tconst angle = this.toAngle(longitude);\n\t\tconst tickInner = polarToCartesian(CENTER, CENTER, OUTER_R, angle);\n\t\tconst tickOuter = polarToCartesian(CENTER, CENTER, ANGLE_TICK_R, angle);\n\t\tconst labelPos = polarToCartesian(CENTER, CENTER, ANGLE_LABEL_R, angle);\n\t\treturn svg`\n\t\t\t<g>\n\t\t\t\t<line class=\"angle-tick\" x1=${tickInner.x} y1=${tickInner.y} x2=${tickOuter.x} y2=${tickOuter.y} />\n\t\t\t\t<text class=\"angle-marker\" x=${labelPos.x} y=${labelPos.y} text-anchor=\"middle\" dominant-baseline=\"central\">${label}</text>\n\t\t\t</g>\n\t\t`;\n\t}\n\n\tprivate renderSpokes() {\n\t\t// Draw a spoke at each real house cusp longitude so Placidus / Koch\n\t\t// unequal houses render correctly. Fall back to 12 equal spokes from the\n\t\t// Ascendant only when the response carries no houses array.\n\t\tconst houses = this.data?.houses ?? [];\n\t\tconst cuspLongitudes =\n\t\t\thouses.length === 12\n\t\t\t\t? houses.map((h) => h.longitude)\n\t\t\t\t: Array.from({ length: 12 }, (_, i) => this.getAscendant() + i * 30);\n\t\treturn cuspLongitudes.map((lon) => {\n\t\t\tconst angle = this.toAngle(lon);\n\t\t\tconst start = polarToCartesian(CENTER, CENTER, HOUSE_R, angle);\n\t\t\tconst end = polarToCartesian(CENTER, CENTER, OUTER_R, angle);\n\t\t\treturn svg`<line class=\"wheel-line\" x1=${start.x} y1=${start.y} x2=${end.x} y2=${end.y} stroke-width=\"0.8\" />`;\n\t\t});\n\t}\n\n\tprivate renderSigns() {\n\t\treturn SIGNS_ORDER.map((sign, i) => {\n\t\t\tconst angle = this.toAngle(i * 30 + 15);\n\t\t\tconst pos = polarToCartesian(CENTER, CENTER, SIGN_R, angle);\n\t\t\treturn svg`<text class=\"sign-glyph\" x=${pos.x} y=${pos.y} text-anchor=\"middle\" dominant-baseline=\"central\">${SIGN_GLYPH[sign]}</text>`;\n\t\t});\n\t}\n\n\tprivate renderHouseNumbers() {\n\t\tconst houses = this.data?.houses ?? [];\n\t\t// Place each house number at the angular midpoint between its cusp and\n\t\t// the next, so the label sits inside the house even when houses are\n\t\t// unequal. Fall back to equal 30-degree sectors when houses are absent.\n\t\tif (houses.length === 12) {\n\t\t\treturn houses.map((house, i) => {\n\t\t\t\tconst next = houses[(i + 1) % 12];\n\t\t\t\tconst mid = arcMidpoint(\n\t\t\t\t\thouse.longitude,\n\t\t\t\t\tnext ? next.longitude : house.longitude + 30,\n\t\t\t\t);\n\t\t\t\tconst pos = polarToCartesian(\n\t\t\t\t\tCENTER,\n\t\t\t\t\tCENTER,\n\t\t\t\t\tHOUSE_R - 12,\n\t\t\t\t\tthis.toAngle(mid),\n\t\t\t\t);\n\t\t\t\treturn svg`<text class=\"house-num\" x=${pos.x} y=${pos.y} text-anchor=\"middle\" dominant-baseline=\"central\">${house.number}</text>`;\n\t\t\t});\n\t\t}\n\t\tconst ascSignIndex = Math.floor(this.getAscendant() / 30);\n\t\treturn Array.from({ length: 12 }, (_, i) => {\n\t\t\tconst angle = this.toAngle(i * 30 + 15);\n\t\t\tconst pos = polarToCartesian(CENTER, CENTER, HOUSE_R - 12, angle);\n\t\t\tconst houseNum = ((i - ascSignIndex + 12) % 12) + 1;\n\t\t\treturn svg`<text class=\"house-num\" x=${pos.x} y=${pos.y} text-anchor=\"middle\" dominant-baseline=\"central\">${houseNum}</text>`;\n\t\t});\n\t}\n\n\t/**\n\t * Degree ticks on the outer zodiac band: a short mark every 5 degrees and a\n\t * longer one on each 30-degree sign cusp, so the wheel reads like a\n\t * reference-grade chart rather than a bare ring of glyphs.\n\t */\n\tprivate renderTicks() {\n\t\tconst ticks = [];\n\t\tfor (let deg = 0; deg < 360; deg += 5) {\n\t\t\tconst angle = this.toAngle(deg);\n\t\t\tconst isMajor = deg % 30 === 0;\n\t\t\tconst inner = isMajor ? SIGN_R - 14 : OUTER_R - 5;\n\t\t\tconst a = polarToCartesian(CENTER, CENTER, inner, angle);\n\t\t\tconst b = polarToCartesian(CENTER, CENTER, OUTER_R, angle);\n\t\t\tticks.push(\n\t\t\t\tsvg`<line class=${isMajor ? 'tick tick-major' : 'tick'} x1=${a.x} y1=${a.y} x2=${b.x} y2=${b.y} stroke-width=${isMajor ? 1 : 0.5} />`,\n\t\t\t);\n\t\t}\n\t\treturn ticks;\n\t}\n\n\t/**\n\t * Degree-and-minute label printed next to each house cusp on the wheel, so\n\t * the exact cusp position is readable without leaving the chart.\n\t */\n\tprivate renderCuspDegrees() {\n\t\tconst houses = this.data?.houses ?? [];\n\t\tif (houses.length !== 12) return nothing;\n\t\treturn houses.map((house) => {\n\t\t\tconst angle = this.toAngle(house.longitude);\n\t\t\tconst pos = polarToCartesian(CENTER, CENTER, HOUSE_R + 9, angle);\n\t\t\tconst sp = longitudeToSignPosition(house.longitude);\n\t\t\treturn svg`<text class=\"cusp-deg\" x=${pos.x} y=${pos.y} text-anchor=\"middle\" dominant-baseline=\"central\">${sp.degree}\u00B0${String(sp.minute).padStart(2, '0')}'</text>`;\n\t\t});\n\t}\n\n\tprivate renderPlanets(planets: PlanetEntry[]) {\n\t\t// Stellium-aware angular fan-out. Conjunctions within 8\u00B0 are the norm\n\t\t// in professional natal charts (Sun-Mercury-Venus cluster, outer-planet\n\t\t// stacks). To keep every glyph legible without losing precision, sort\n\t\t// by longitude and push later members forward in angle until they\n\t\t// clear a minimum separation, then draw a thin leader line from each\n\t\t// displaced glyph back to the planet's true position on the outer\n\t\t// rim. Conventional approach used by professional Western natal\n\t\t// software; preserves both readability and astronomical accuracy.\n\t\tconst MIN_SEPARATION = 7;\n\t\ttype Placed = {\n\t\t\tp: PlanetEntry;\n\t\t\ttrueLon: number;\n\t\t\tdisplayLon: number;\n\t\t};\n\t\tconst sorted: Placed[] = planets\n\t\t\t.filter((p) => Number.isFinite(p.longitude))\n\t\t\t.map((p) => ({\n\t\t\t\tp,\n\t\t\t\ttrueLon: normalizeLongitude(p.longitude),\n\t\t\t\tdisplayLon: normalizeLongitude(p.longitude),\n\t\t\t}))\n\t\t\t.sort((a, b) => a.trueLon - b.trueLon);\n\t\t// Forward sweep: clamp each to at least prev + MIN_SEPARATION.\n\t\tfor (let i = 1; i < sorted.length; i++) {\n\t\t\tconst prev = sorted[i - 1];\n\t\t\tconst cur = sorted[i];\n\t\t\tif (!prev || !cur) continue;\n\t\t\tconst wanted = prev.displayLon + MIN_SEPARATION;\n\t\t\tif (cur.displayLon < wanted) cur.displayLon = wanted;\n\t\t}\n\t\t// If the cluster overshot 360\u00B0, slide everything back equally so the\n\t\t// stack stays anchored near the original longitudes.\n\t\tconst last = sorted[sorted.length - 1];\n\t\tif (last && last.displayLon > 360) {\n\t\t\tconst shift = last.displayLon - 360;\n\t\t\tfor (const s of sorted) s.displayLon -= shift;\n\t\t}\n\t\treturn sorted.map(({ p, trueLon, displayLon }) => {\n\t\t\tconst trueAngle = this.toAngle(trueLon);\n\t\t\tconst displayAngle = this.toAngle(displayLon);\n\t\t\tconst glyphPos = polarToCartesian(CENTER, CENTER, PLANET_R, displayAngle);\n\t\t\tconst degPos = polarToCartesian(\n\t\t\t\tCENTER,\n\t\t\t\tCENTER,\n\t\t\t\tPLANET_R - 13,\n\t\t\t\tdisplayAngle,\n\t\t\t);\n\t\t\tconst rimPos = polarToCartesian(CENTER, CENTER, OUTER_R - 4, trueAngle);\n\t\t\tconst leaderInner = polarToCartesian(\n\t\t\t\tCENTER,\n\t\t\t\tCENTER,\n\t\t\t\tPLANET_R + 8,\n\t\t\t\tdisplayAngle,\n\t\t\t);\n\t\t\tconst glyph = PLANET_GLYPH[capitalize(p.name)] ?? p.name.slice(0, 2);\n\t\t\tconst sp = longitudeToSignPosition(p.longitude);\n\t\t\tconst retro = p.isRetrograde === true;\n\t\t\tconst degLabel = `${sp.degree}\u00B0${String(sp.minute).padStart(2, '0')}'`;\n\t\t\tconst offset = Math.abs(displayLon - trueLon) > 0.5;\n\t\t\treturn svg`<g>\n\t\t\t\t${\n\t\t\t\t\toffset\n\t\t\t\t\t\t? svg`<line class=\"planet-leader\" x1=${rimPos.x} y1=${rimPos.y} x2=${leaderInner.x} y2=${leaderInner.y} />`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t<text class=\"planet-glyph\" x=${glyphPos.x} y=${glyphPos.y} text-anchor=\"middle\" dominant-baseline=\"central\"><title>${p.name}${retro ? ' retrograde' : ''} - ${degLabel} ${p.sign ?? ''}</title>${glyph}</text>\n\t\t\t\t<text class=\"planet-deg\" x=${degPos.x} y=${degPos.y} text-anchor=\"middle\" dominant-baseline=\"central\">${degLabel}${retro ? svg`<tspan class=\"retro\"> \u211E</tspan>` : nothing}</text>\n\t\t\t</g>`;\n\t\t});\n\t}\n\n\tprivate renderDetails() {\n\t\tconst summary = this.data?.summary;\n\t\tconst ai = this.data?.aspectsInterpretation;\n\t\tif (!summary && !ai) return nothing;\n\n\t\tconst retrogrades = summary?.retrogradePlanets ?? [];\n\n\t\treturn html`<div class=\"details\">${\n\t\t\t\tsummary?.dominantElement || summary?.dominantModality\n\t\t\t\t\t? html`<div class=\"pill-row\">${summary.dominantElement ? html`<span class=\"pill\">Dominant element: ${summary.dominantElement}</span>` : nothing} ${summary.dominantModality ? html`<span class=\"pill\">Dominant modality: ${summary.dominantModality}</span>` : nothing}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tai\n\t\t\t\t\t? html`<div class=\"pill-row\"><span class=\"pill pill--success\">Harmonious ${ai.harmonious}</span> <span class=\"pill pill--danger\">Challenging ${ai.challenging}</span> <span class=\"pill pill--muted\">Neutral ${ai.neutral}</span></div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tretrogrades.length > 0\n\t\t\t\t\t? html`<div class=\"pill-row\">${retrogrades.map((p) => {\n\t\t\t\t\t\t\tconst glyph = PLANET_GLYPH[p] ?? p.slice(0, 2);\n\t\t\t\t\t\t\treturn html`<span class=\"pill pill--muted\">${glyph} ${p} R</span>`;\n\t\t\t\t\t\t})}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${ai?.summary ? html`<p class=\"summary\">${ai.summary}</p>` : nothing} ${this.renderElementModalityGrid()}</div>`;\n\t}\n\n\t/**\n\t * Element by modality grid: the 4x3 cross-tab astrologers read for chart\n\t * balance. Each planet is placed by its sign into one cell (Fire/Earth/Air/\n\t * Water row, Cardinal/Fixed/Mutable column). Derived purely from the planet\n\t * signs, with row, column, and grand totals.\n\t */\n\tprivate renderElementModalityGrid() {\n\t\tconst planets = this.getPlanets();\n\t\tif (planets.length === 0) return nothing;\n\t\tconst ELEMENTS = ['Fire', 'Earth', 'Air', 'Water'] as const;\n\t\tconst MODALITIES = ['Cardinal', 'Fixed', 'Mutable'] as const;\n\t\tconst order = SIGNS_ORDER as readonly string[];\n\n\t\tconst cells: Record<string, Record<string, string[]>> = {};\n\t\tfor (const el of ELEMENTS)\n\t\t\tcells[el] = { Cardinal: [], Fixed: [], Mutable: [] };\n\t\tfor (const p of planets) {\n\t\t\tconst idx = order.indexOf(capitalize(p.sign ?? ''));\n\t\t\tif (idx < 0) continue;\n\t\t\tconst el = ELEMENTS[idx % 4];\n\t\t\tconst mod = MODALITIES[idx % 3];\n\t\t\tconst glyph =\n\t\t\t\tPLANET_GLYPH[capitalize(p.name)] ?? capitalize(p.name).slice(0, 2);\n\t\t\tcells[el]?.[mod]?.push(glyph);\n\t\t}\n\n\t\treturn html`<table class=\"em-grid\" aria-label=\"Element and modality distribution\"><thead><tr><th></th>${MODALITIES.map((m) => html`<th scope=\"col\">${m.slice(0, 3)}</th>`)}<th scope=\"col\">Total</th></tr></thead><tbody>${ELEMENTS.map((el) => {\n\t\t\t\t\tconst rowTotal = MODALITIES.reduce(\n\t\t\t\t\t\t(s, m) => s + (cells[el]?.[m]?.length ?? 0),\n\t\t\t\t\t\t0,\n\t\t\t\t\t);\n\t\t\t\t\treturn html`<tr><th scope=\"row\">${el}</th>${MODALITIES.map(\n\t\t\t\t\t\t\t(m) => html`<td>${(cells[el]?.[m] ?? []).join(' ')}</td>`,\n\t\t\t\t\t\t)}<td class=\"em-total\">${rowTotal}</td></tr>`;\n\t\t\t\t})}<tr><th scope=\"row\">Total</th>${MODALITIES.map(\n\t\t\t\t\t\t(m) =>\n\t\t\t\t\t\t\thtml`<td class=\"em-total\">${ELEMENTS.reduce((s, el) => s + (cells[el]?.[m]?.length ?? 0), 0)}</td>`,\n\t\t\t\t\t)}<td class=\"em-total\">${planets.length}</td></tr></tbody></table>`;\n\t}\n\n\tprivate renderInterpretations() {\n\t\tconst planets = this.getPlanets().filter((p) => p.interpretation);\n\t\tif (planets.length === 0) return nothing;\n\t\treturn html`<section class=\"interpretations\"><h3>Planet readings</h3>${planets.map((p, idx) => {\n\t\t\t\tconst interp = p.interpretation!;\n\t\t\t\tconst glyph = PLANET_GLYPH[capitalize(p.name)] ?? '';\n\t\t\t\tconst deg = formatNumber(p.degree ?? 0, 1);\n\t\t\t\treturn html`<details class=\"interp-card\" name=\"natal-planet-readings\" ?open=\"${idx === 0}\"><summary><span>${glyph} ${p.name}</span> <span class=\"interp-aside\"><small>${p.sign ?? ''} ${deg}</small> ${chevron()}</span></summary><div class=\"interp-body\">${interp.summary ? html`<p class=\"interp-summary\">${interp.summary}</p>` : nothing} ${interp.detailed ? html`<p class=\"interp-detail\">${interp.detailed}</p>` : nothing} ${\n\t\t\t\t\t\t\tinterp.keywords?.length\n\t\t\t\t\t\t\t\t? html`<div class=\"interp-keywords\">${interp.keywords.map((k) => html`<span class=\"kw\">${k}</span>`)}</div>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}</div></details>`;\n\t\t\t})}</section>`;\n\t}\n\n\tprivate renderAspects(planets: PlanetEntry[], aspects: AspectEntry[]) {\n\t\tconst planetMap = new Map<string, number>();\n\t\tfor (const p of planets) {\n\t\t\tif (typeof p.longitude !== 'number') continue;\n\t\t\tconst name = capitalize(p.name);\n\t\t\tif (name) planetMap.set(name, p.longitude);\n\t\t}\n\t\treturn aspects.map((a) => {\n\t\t\tconst l1 = planetMap.get(capitalize(a.planet1));\n\t\t\tconst l2 = planetMap.get(capitalize(a.planet2));\n\t\t\tif (l1 === undefined || l2 === undefined) return nothing;\n\t\t\tconst p1 = polarToCartesian(\n\t\t\t\tCENTER,\n\t\t\t\tCENTER,\n\t\t\t\tPLANET_R - 18,\n\t\t\t\tthis.toAngle(l1),\n\t\t\t);\n\t\t\tconst p2 = polarToCartesian(\n\t\t\t\tCENTER,\n\t\t\t\tCENTER,\n\t\t\t\tPLANET_R - 18,\n\t\t\t\tthis.toAngle(l2),\n\t\t\t);\n\t\t\tconst aspectName = normalizeAspect(a);\n\t\t\tconst aspectClass = ASPECT_CLASS[aspectName] ?? 'aspect-other';\n\t\t\tconst orbLabel = formatNumber(a.orb, 1);\n\t\t\treturn svg`<line class=${`aspect ${aspectClass}`} x1=${p1.x} y1=${p1.y} x2=${p2.x} y2=${p2.y}><title>${a.planet1} ${aspectName || ''} ${a.planet2}${orbLabel ? ` (orb ${orbLabel}\u00B0)` : ''}</title></line>`;\n\t\t});\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-natal-chart': RoxyNatalChart;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type {\n\tCalculateBirthDayResponse,\n\tCalculateExpressionResponse,\n\tCalculateLifePathResponse,\n\tCalculateMaturityResponse,\n\tCalculatePersonalDayResponse,\n\tCalculatePersonalityResponse,\n\tCalculatePersonalMonthResponse,\n\tCalculatePersonalYearResponse,\n\tCalculateSoulUrgeResponse,\n\tGenerateNumerologyChartResponse,\n\tGetDailyNumberResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { humanize } from '../utils/string.js';\n\n/**\n * Single-number numerology responses that share the number + meaning + calculation + karmic-debt shape. {@link RoxyNumerologyCard.renderNumberCard} renders any of them; the `type` attribute selects only the heading label.\n */\ntype NumberCardData =\n\t| CalculateLifePathResponse\n\t| CalculateExpressionResponse\n\t| CalculateSoulUrgeResponse\n\t| CalculatePersonalityResponse\n\t| CalculateBirthDayResponse\n\t| CalculateMaturityResponse;\n\ntype NumerologyData =\n\t| NumberCardData\n\t| CalculatePersonalYearResponse\n\t| CalculatePersonalDayResponse\n\t| CalculatePersonalMonthResponse\n\t| GetDailyNumberResponse\n\t| GenerateNumerologyChartResponse;\n\n/**\n * Numerology card. Renders /numerology/{life-path,expression,soul-urge,personality,birth-day,maturity,personal-year,chart}.\n * Use the `type` attribute to switch the heading; the single-number types all share one layout.\n */\n@customElement('roxy-numerology-card')\nexport class RoxyNumerologyCard extends RoxyDataElement<NumerologyData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.card{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.hero{align-items:center;gap:var(--roxy-space-md,1rem);display:flex}.numeral{font-size:4rem;line-height:1;font-weight:var(--roxy-weight-bold,600);color:var(--roxy-accent-ink,#b45309);font-variant-numeric:tabular-nums}.label{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;margin:0}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.meaning{color:var(--roxy-fg,#0a0a0a);margin:0}.calc{font-family:var(--roxy-font-mono);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 30%, transparent);padding:var(--roxy-space-sm,.5rem);border-radius:var(--roxy-radius-sm,4px);white-space:pre-wrap;overflow-wrap:anywhere;margin:0}.chips{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;display:flex}.chips span{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 14%, transparent);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);padding:2px 8px}.cores{gap:var(--roxy-space-sm,.5rem);border-top:1px solid var(--roxy-border,#e4e4e7);padding-top:var(--roxy-space-md,1rem);grid-template-columns:repeat(auto-fit,minmax(8rem,1fr));display:grid}.cores .item{align-items:baseline;gap:var(--roxy-space-xs,.25rem);font-size:var(--roxy-text-sm,.875rem);display:flex}.cores .item span:first-child{color:var(--roxy-muted,#71717a);text-transform:capitalize}.cores .item strong{color:var(--roxy-accent-ink,#b45309);font-variant-numeric:tabular-nums;font-size:var(--roxy-text-base,1rem);font-weight:var(--roxy-weight-bold,600)}.karmic{background:color-mix(in srgb, var(--roxy-warning,#ea580c) 12%, transparent);border:1px solid color-mix(in srgb, var(--roxy-warning,#ea580c) 32%, transparent);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);border-radius:var(--roxy-radius-md,8px);font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a)}`,\n\t];\n\n\t@property({ type: String, reflect: true })\n\ttype:\n\t\t| 'life-path'\n\t\t| 'expression'\n\t\t| 'soul-urge'\n\t\t| 'personality'\n\t\t| 'birth-day'\n\t\t| 'maturity'\n\t\t| 'daily'\n\t\t| 'personal-day'\n\t\t| 'personal-month'\n\t\t| 'personal-year'\n\t\t| 'chart' = 'life-path';\n\n\tprotected renderData(d: NumerologyData) {\n\t\tconst headerLabel = LABELS[this.type] ?? this.type;\n\t\tif ('coreNumbers' in d) return this.renderChart(d, headerLabel);\n\t\t// Period reads share a number+theme+body shape but differ in field names;\n\t\t// check the most specific key first (a personal-day response also carries\n\t\t// personalMonth/personalYear), so the order is day -> month -> year.\n\t\tif ('personalDay' in d) {\n\t\t\treturn this.renderPeriod(headerLabel, d.personalDay, d.theme, d.guidance);\n\t\t}\n\t\tif ('personalMonth' in d) {\n\t\t\treturn this.renderPeriod(headerLabel, d.personalMonth, d.theme, d.focus);\n\t\t}\n\t\tif ('personalYear' in d) return this.renderPersonalYear(d, headerLabel);\n\t\t// Daily number: number + meaning, no calculation/karmic-debt; show the\n\t\t// meaning title as the heading and the daily message as the body.\n\t\tif ('dailyMessage' in d) {\n\t\t\treturn this.renderPeriod(\n\t\t\t\theaderLabel,\n\t\t\t\td.number,\n\t\t\t\td.meaning?.title,\n\t\t\t\td.dailyMessage,\n\t\t\t);\n\t\t}\n\t\treturn this.renderNumberCard(d as NumberCardData, headerLabel);\n\t}\n\n\t/** Shared layout for a single period number (day/month): a hero numeral, theme heading, and guidance/focus body. */\n\tprivate renderPeriod(\n\t\theaderLabel: string,\n\t\tnum: number | undefined,\n\t\ttheme: string | undefined,\n\t\tbody: string | undefined,\n\t) {\n\t\treturn html`<article class=\"card\" aria-label=\"${headerLabel}\"><div class=\"hero\">${typeof num === 'number' ? html`<div class=\"numeral\">${num}</div>` : nothing}<div><p class=\"label\">${headerLabel}</p>${theme ? html`<h2 class=\"title\">${theme}</h2>` : nothing}</div></div>${body ? html`<p class=\"meaning\">${body}</p>` : nothing}</article>`;\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No numerology data</div>`;\n\t}\n\n\tprivate renderNumberCard(d: NumberCardData, headerLabel: string) {\n\t\tconst keywords = d.meaning?.keywords ?? [];\n\t\treturn html`<article class=\"card\" aria-label=\"${headerLabel}\"><div class=\"hero\">${typeof d.number === 'number' ? html`<div class=\"numeral\">${d.number}</div>` : nothing}<div><p class=\"label\">${headerLabel}</p>${d.meaning?.title ? html`<h2 class=\"title\">${d.meaning.title}</h2>` : nothing}</div></div>${d.meaning?.description ? html`<p class=\"meaning\">${d.meaning.description}</p>` : nothing} ${d.calculation ? html`<pre class=\"calc\">${d.calculation}</pre>` : nothing} ${\n\t\t\t\tkeywords.length > 0\n\t\t\t\t\t? html`<div class=\"chips\">${keywords.map((k) => html`<span>${k}</span>`)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\td.hasKarmicDebt && d.karmicDebtNumber\n\t\t\t\t\t? html`<div class=\"karmic\">Karmic debt ${d.karmicDebtNumber}. ${karmicDebtText(d.karmicDebtMeaning)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t}</article>`;\n\t}\n\n\tprivate renderPersonalYear(\n\t\td: CalculatePersonalYearResponse,\n\t\theaderLabel: string,\n\t) {\n\t\treturn html`<article class=\"card\" aria-label=\"${headerLabel}\"><div class=\"hero\">${typeof d.personalYear === 'number' ? html`<div class=\"numeral\">${d.personalYear}</div>` : nothing}<div><p class=\"label\">${headerLabel}</p>${d.theme ? html`<h2 class=\"title\">${d.theme}</h2>` : nothing}</div></div>${d.forecast ? html`<p class=\"meaning\">${d.forecast}</p>` : nothing} ${d.advice ? html`<p>${d.advice}</p>` : nothing}</article>`;\n\t}\n\n\tprivate renderChart(d: GenerateNumerologyChartResponse, headerLabel: string) {\n\t\tconst cores = Object.entries(d.coreNumbers).filter(\n\t\t\t([, v]) => v !== null && v !== undefined,\n\t\t);\n\t\treturn html`<article class=\"card\" aria-label=\"${headerLabel}\"><div><p class=\"label\">${headerLabel}</p>${d.profile?.name ? html`<h2 class=\"title\">${d.profile.name}</h2>` : nothing}</div>${\n\t\t\t\tcores.length > 0\n\t\t\t\t\t? html`<div class=\"cores\">${cores.map(\n\t\t\t\t\t\t\t([k, v]) => html`<div class=\"item\"><span>${humanize(k)}</span> <strong>${v.number ?? ''}</strong></div>`,\n\t\t\t\t\t\t)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t}</article>`;\n\t}\n}\n\nconst LABELS: Record<string, string> = {\n\t'life-path': 'Life Path',\n\texpression: 'Expression',\n\t'soul-urge': 'Soul Urge',\n\tpersonality: 'Personality',\n\t'birth-day': 'Birth Day',\n\tmaturity: 'Maturity',\n\tdaily: 'Daily Number',\n\t'personal-day': 'Personal Day',\n\t'personal-month': 'Personal Month',\n\t'personal-year': 'Personal Year',\n\tchart: 'Numerology chart',\n};\n\ntype KarmicDebtMeaning = CalculateLifePathResponse['karmicDebtMeaning'];\n\nfunction karmicDebtText(value: KarmicDebtMeaning | undefined): string {\n\tif (!value) return '';\n\treturn [value.description, value.challenge, value.resolution]\n\t\t.filter(Boolean)\n\t\t.join(' ');\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-numerology-card': RoxyNumerologyCard;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type {\n\tGetBasicPanchangResponse,\n\tGetDetailedPanchangResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatDate, formatTime, formatTimeRange } from '../utils/format.js';\n\ntype PanchangData = GetBasicPanchangResponse | GetDetailedPanchangResponse;\ntype PanchangTime = GetDetailedPanchangResponse['rahuKaal'];\n\n/**\n * Panchang table for /vedic-astrology/panchang/{basic,detailed}.\n *\n * @remarks\n * The main grid lists the five limbs (tithi, nakshatra, yoga, karana, vara),\n * sun and moon timings, and, in detailed mode, the sunrise placements a reader\n * scans first: Moon rashi, Sun rashi, Sun nakshatra, and the current hora. The\n * detailed mode then groups every timed window into two sections, auspicious\n * (the fixed muhurtas plus each Amrit Kalam) and inauspicious (Rahu Kaal,\n * Yamaganda, Gulika, plus each Dur Muhurta and Varjyam), so a consumer can act\n * on timing without parsing the raw response.\n */\n@customElement('roxy-panchang-table')\nexport class RoxyPanchangTable extends RoxyDataElement<PanchangData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);background:var(--roxy-surface,#fff);box-shadow:var(--roxy-shadow-sm);overflow:hidden}.head{padding:var(--roxy-space-md,1rem);border-bottom:1px solid var(--roxy-border,#e4e4e7);justify-content:space-between;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.date{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}table{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem)}tbody tr:nth-child(odd){background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 24%, transparent)}th,td{padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);text-align:left;vertical-align:top}th{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:capitalize;width:38%}td{color:var(--roxy-fg,#0a0a0a);font-variant-numeric:tabular-nums}.section{border-top:1px solid var(--roxy-border,#e4e4e7);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;letter-spacing:.06em}`,\n\t];\n\n\t@property({ type: String, reflect: true })\n\tdetail: 'basic' | 'detailed' = 'detailed';\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No panchang data</div>`;\n\t}\n\n\tprotected renderData(d: PanchangData) {\n\t\tconst detailed = 'sunrise' in d ? d : null;\n\n\t\tconst fivefold: Array<[string, string]> = [\n\t\t\t['Tithi', this.formatPart(d.tithi)],\n\t\t\t['Nakshatra', this.formatPart(d.nakshatra)],\n\t\t\t['Yoga', this.formatPart(d.yoga)],\n\t\t\t['Karana', this.formatPart(d.karana)],\n\t\t];\n\t\tif (detailed) fivefold.push(['Vara', this.formatPart(detailed.vara)]);\n\n\t\tconst placements: Array<[string, string]> = detailed\n\t\t\t? [\n\t\t\t\t\t['Moon sign', this.formatRashi(detailed.moonSign)],\n\t\t\t\t\t['Sun sign', this.formatRashi(detailed.sunSign)],\n\t\t\t\t\t['Sun nakshatra', this.formatSunNakshatra(detailed.sunNakshatra)],\n\t\t\t\t\t['Hora', this.formatHora(detailed.hora)],\n\t\t\t\t].filter((row): row is [string, string] => Boolean(row[1]))\n\t\t\t: [];\n\n\t\tconst muhurtas: Array<[string, PanchangTime | undefined]> = detailed\n\t\t\t? [\n\t\t\t\t\t['Brahma Muhurta', detailed.brahmaMuhurta],\n\t\t\t\t\t['Abhijit Muhurta', detailed.abhijitMuhurta],\n\t\t\t\t\t['Vijaya Muhurta', detailed.vijayaMuhurta],\n\t\t\t\t\t['Godhuli Muhurta', detailed.godhuliMuhurta],\n\t\t\t\t\t['Nishita Muhurta', detailed.nishitaMuhurta],\n\t\t\t\t\t['Pratah Sandhya', detailed.pratahSandhya],\n\t\t\t\t\t['Sayahna Sandhya', detailed.sayahnaSandhya],\n\t\t\t\t]\n\t\t\t: [];\n\n\t\tconst auspiciousWindows: Array<[string, PanchangTime]> = detailed\n\t\t\t? this.expandWindows('Amrit Kalam', detailed.amritKalam)\n\t\t\t: [];\n\n\t\tconst inauspicious: Array<[string, PanchangTime | undefined]> = detailed\n\t\t\t? [\n\t\t\t\t\t['Rahu Kaal', detailed.rahuKaal],\n\t\t\t\t\t['Yamaganda', detailed.yamaganda],\n\t\t\t\t\t['Gulika', detailed.gulika],\n\t\t\t\t]\n\t\t\t: [];\n\n\t\tconst inauspiciousWindows: Array<[string, PanchangTime]> = detailed\n\t\t\t? [\n\t\t\t\t\t...this.expandWindows('Dur Muhurta', detailed.durMuhurta),\n\t\t\t\t\t...this.expandWindows('Varjyam', detailed.varjyam),\n\t\t\t\t]\n\t\t\t: [];\n\n\t\tconst transitions =\n\t\t\tdetailed && 'transitions' in detailed ? detailed.transitions : undefined;\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Panchang\"><header class=\"head\"><h2 class=\"title\">Panchang</h2><span class=\"date\">${detailed ? formatDate(detailed.date) : ''}</span></header><table><tbody>${fivefold.map(\n\t\t\t\t\t\t([k, v]) => html`<tr><th>${k}</th><td>${v}</td></tr>`,\n\t\t\t\t\t)} ${\n\t\t\t\t\t\tdetailed?.sunrise\n\t\t\t\t\t\t\t? html`<tr><th>Sunrise</th><td>${formatTime(detailed.sunrise)}</td></tr>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t} ${\n\t\t\t\t\t\tdetailed?.sunset\n\t\t\t\t\t\t\t? html`<tr><th>Sunset</th><td>${formatTime(detailed.sunset)}</td></tr>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t} ${\n\t\t\t\t\t\tdetailed?.moonrise\n\t\t\t\t\t\t\t? html`<tr><th>Moonrise</th><td>${formatTime(detailed.moonrise)}</td></tr>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t} ${\n\t\t\t\t\t\tdetailed?.moonset\n\t\t\t\t\t\t\t? html`<tr><th>Moonset</th><td>${formatTime(detailed.moonset)}</td></tr>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t} ${placements.map(\n\t\t\t\t\t\t([k, v]) => html`<tr><th>${k}</th><td>${v}</td></tr>`,\n\t\t\t\t\t)}</tbody></table>${\n\t\t\t\ttransitions\n\t\t\t\t\t? html`<div class=\"section\">Next transitions</div><table><tbody>${this.renderTransitionRow('Tithi', transitions.tithi)} ${this.renderTransitionRow('Nakshatra', transitions.nakshatra)} ${this.renderTransitionRow('Yoga', transitions.yoga)} ${this.renderTransitionRow('Karana', transitions.karana)}</tbody></table>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tthis.detail === 'detailed' &&\n\t\t\t\t(\n\t\t\t\t\tmuhurtas.some((m) => !!m[1]) ||\n\t\t\t\t\t\tauspiciousWindows.length > 0 ||\n\t\t\t\t\t\tinauspicious.some((m) => !!m[1]) ||\n\t\t\t\t\t\tinauspiciousWindows.length > 0\n\t\t\t\t)\n\t\t\t\t\t? html`<div class=\"section\">Auspicious muhurtas</div><table><tbody>${this.renderPeriodRows([\n\t\t\t\t\t\t\t\t\t...muhurtas.filter(\n\t\t\t\t\t\t\t\t\t\t(m): m is [string, PanchangTime] => !!m[1],\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t...auspiciousWindows,\n\t\t\t\t\t\t\t\t])}</tbody></table><div class=\"section\">Inauspicious periods</div><table><tbody>${this.renderPeriodRows([\n\t\t\t\t\t\t\t\t\t...inauspicious.filter(\n\t\t\t\t\t\t\t\t\t\t(m): m is [string, PanchangTime] => !!m[1],\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t...inauspiciousWindows,\n\t\t\t\t\t\t\t\t])}</tbody></table>`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n\n\t/** Renders one row per [label, period] pair, dropping any with no range. */\n\tprivate renderPeriodRows(rows: Array<[string, PanchangTime]>) {\n\t\treturn rows.map(([k, v]) => {\n\t\t\tconst range = formatTimeRange(v);\n\t\t\treturn range\n\t\t\t\t? html`<tr><th>${k}</th><td>${range}</td></tr>`\n\t\t\t\t: nothing;\n\t\t});\n\t}\n\n\t/** Expands an array of periods into labeled rows, numbering when more than one. */\n\tprivate expandWindows(\n\t\tlabel: string,\n\t\twindows: PanchangTime[] | undefined,\n\t): Array<[string, PanchangTime]> {\n\t\tif (!windows || windows.length === 0) return [];\n\t\treturn windows.map((w, i) => [\n\t\t\twindows.length > 1 ? `${label} ${i + 1}` : label,\n\t\t\tw,\n\t\t]);\n\t}\n\n\tprivate renderTransitionRow(\n\t\tlabel: string,\n\t\tt: { endsAt?: string; next?: string } | undefined,\n\t) {\n\t\tif (!t?.endsAt) return nothing;\n\t\tconst when = formatTime(t.endsAt);\n\t\tconst next = t.next ? ` \u2192 ${t.next}` : '';\n\t\treturn html`<tr><th>${label}</th><td>ends ${when}${next}</td></tr>`;\n\t}\n\n\tprivate formatPart(v: unknown): string {\n\t\tif (!v) return '';\n\t\tif (typeof v === 'string') return v;\n\t\tif (typeof v === 'object') {\n\t\t\tconst obj = v as {\n\t\t\t\tname?: string;\n\t\t\t\tlord?: string;\n\t\t\t\tphase?: string;\n\t\t\t\tpaksha?: string;\n\t\t\t\tend?: string;\n\t\t\t};\n\t\t\tconst parts = [\n\t\t\t\tobj.name,\n\t\t\t\tobj.paksha ? `(${obj.paksha} paksha)` : '',\n\t\t\t\tobj.lord ? `\u00B7 ${obj.lord}` : '',\n\t\t\t\tobj.phase,\n\t\t\t].filter(Boolean);\n\t\t\treturn parts.join(' ');\n\t\t}\n\t\treturn String(v);\n\t}\n\n\t/** \"English (Sanskrit)\" label for the Moon or Sun rashi at sunrise. */\n\tprivate formatRashi(r: RashiPlacement | undefined): string {\n\t\tif (!r?.name) return '';\n\t\treturn r.sanskritName && r.sanskritName !== r.name\n\t\t\t? `${r.name} (${r.sanskritName})`\n\t\t\t: r.name;\n\t}\n\n\t/** Sun nakshatra with pada and lord, the form a panchang reader expects. */\n\tprivate formatSunNakshatra(n: SunNakshatra | undefined): string {\n\t\tif (!n?.name) return '';\n\t\tconst parts = [\n\t\t\tn.name,\n\t\t\ttypeof n.pada === 'number' ? `pada ${n.pada}` : '',\n\t\t\tn.lord ? `\u00B7 ${n.lord}` : '',\n\t\t].filter(Boolean);\n\t\treturn parts.join(' ');\n\t}\n\n\t/** Current planetary hora with its active window. */\n\tprivate formatHora(h: Hora | undefined): string {\n\t\tif (!h?.current) return '';\n\t\tconst range = formatTimeRange(h);\n\t\treturn range ? `${h.current} (${range})` : h.current;\n\t}\n}\n\ntype PanchangPlacements = GetDetailedPanchangResponse;\ntype RashiPlacement = PanchangPlacements['moonSign'];\ntype SunNakshatra = PanchangPlacements['sunNakshatra'];\ntype Hora = PanchangPlacements['hora'];\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-panchang-table': RoxyPanchangTable;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { PLANET_GLYPH, SIGN_GLYPH } from '../tokens/index.js';\nimport type {\n\tArabicLotsResponse,\n\tAsteroidsResponse,\n\tLilithResponse,\n\tProgressionsResponse,\n\tSolarArcResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport {\n\tformatDegreeInSign,\n\tlongitudeToSignPosition,\n} from '../utils/degree.js';\nimport { chevron, disclosureStyles } from '../utils/disclosure.js';\nimport { formatNumber } from '../utils/format.js';\nimport { capitalize } from '../utils/string.js';\n\n/**\n * Union of the position-list Western responses this one editorial table renders.\n * Each carries an array of bodies in zodiac signs plus a per-body\n * interpretation; the table discriminates on which array key is present.\n */\ntype PositionsResponse =\n\t| AsteroidsResponse\n\t| LilithResponse\n\t| ProgressionsResponse\n\t| SolarArcResponse\n\t| ArabicLotsResponse;\n\ninterface Row {\n\tlabel: string;\n\tsign: string;\n\tdegree: number;\n\thouse?: number;\n\tspeed?: number;\n\tisRetrograde?: boolean;\n\tformula?: string;\n\tnatalLongitude?: number;\n\tinterpretation?: string;\n\tisAngle?: boolean;\n}\n\ninterface ViewModel {\n\ttitle: string;\n\tbadges: Array<{ label: string; value: string }>;\n\tsummary?: string;\n\trows: Row[];\n\tcols: { house: boolean; motion: boolean; formula: boolean; natal: boolean };\n}\n\n/**\n * Editorial positions table for the Western point-list endpoints: asteroids,\n * Black Moon Lilith, secondary progressions, solar arc directions, and the\n * Arabic lots. One component, five shapes: it detects the response by its array\n * key and shows only the columns that response carries (house, motion, formula,\n * or a natal-to-directed comparison), then lists each body reading below.\n */\n@customElement('roxy-positions-table')\nexport class RoxyPositionsTable extends RoxyDataElement<PositionsResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tdisclosureStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);width:100%;color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}header{align-items:baseline;gap:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-primary,#0f172a);margin:0}.badges{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;display:flex}.badge{border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 14%, transparent);color:var(--roxy-fg,#0a0a0a);padding:2px 8px}.badge b{color:var(--roxy-accent-ink,#b45309);font-weight:600}.summary{color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);margin:0}.scroll{-webkit-overflow-scrolling:touch;overflow-x:auto}table{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem)}caption{text-align:left;color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);padding-bottom:var(--roxy-space-xs,.25rem)}th,td{text-align:left;border-bottom:1px solid var(--roxy-border,#e4e4e7);white-space:nowrap;padding:6px 10px}th{color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.04em;font-weight:600;font-size:var(--roxy-text-xs,.75rem)}td.num{text-align:right;font-variant-numeric:tabular-nums}.body-cell{color:var(--roxy-fg,#0a0a0a);font-weight:500}.body-cell .glyph{color:var(--roxy-accent-ink,#b45309);margin-right:.35rem}tr.angle td{color:var(--roxy-secondary,#475569)}.sign{align-items:baseline;gap:.3rem;display:inline-flex}.sign .sg{color:var(--roxy-secondary,#475569)}.retro{color:var(--roxy-danger,#dc2626);font-weight:600}.formula{color:var(--roxy-muted,#71717a);font-variant-numeric:tabular-nums;white-space:normal}.readings h3{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;margin:0 0 var(--roxy-space-sm,.5rem);font-weight:600}.interp-card{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);margin-bottom:var(--roxy-space-xs,.25rem)}.interp-card summary{cursor:pointer;color:var(--roxy-fg,#0a0a0a);justify-content:space-between;align-items:center;gap:var(--roxy-space-md,1rem);font-weight:500;display:flex}.interp-aside{align-items:center;gap:.5rem;display:inline-flex}.interp-aside small{color:var(--roxy-muted,#71717a);font-weight:400}.interp-body{margin-top:var(--roxy-space-xs,.25rem);color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem)}`,\n\t];\n\n\t/** Override the auto-derived heading. Empty keeps the per-shape default (e.g. \"Asteroids\"). */\n\t@property({ type: String })\n\theading = '';\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No positions data</div>`;\n\t}\n\n\tprotected renderData(data: PositionsResponse) {\n\t\tconst vm = this.toViewModel(data);\n\t\tconst cols = vm.cols;\n\t\tconst readings = vm.rows.filter((r) => r.interpretation);\n\t\treturn html`<div class=\"wrap\"><header><h2 class=\"title\">${this.heading || vm.title}</h2>${\n\t\t\t\t\tvm.badges.length\n\t\t\t\t\t\t? html`<div class=\"badges\">${vm.badges.map((b) => html`<span class=\"badge\"><b>${b.label}</b> ${b.value}</span>`)}</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</header>${vm.summary ? html`<p class=\"summary\">${vm.summary}</p>` : nothing}<div class=\"scroll\"><table><caption>${vm.title}</caption><thead><tr><th scope=\"col\">Body</th><th scope=\"col\">Position</th>${cols.natal ? html`<th scope=\"col\">Natal</th>` : nothing} ${cols.house ? html`<th scope=\"col\" class=\"num\">House</th>` : nothing} ${cols.motion ? html`<th scope=\"col\">Motion</th>` : nothing} ${cols.formula ? html`<th scope=\"col\">Formula</th>` : nothing}</tr></thead><tbody>${vm.rows.map((r) => this.renderRow(r, cols))}</tbody></table></div>${\n\t\t\t\treadings.length\n\t\t\t\t\t? html`<section class=\"readings\"><h3>Readings</h3>${readings.map((r, i) => this.renderReading(r, i === 0))}</section>`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n\n\tprivate renderRow(r: Row, cols: ViewModel['cols']) {\n\t\tconst glyph = PLANET_GLYPH[capitalize(r.label)];\n\t\treturn html`<tr class=\"${r.isAngle ? 'angle' : ''}\"><td class=\"body-cell\">${glyph ? html`<span class=\"glyph\">${glyph}</span>` : nothing}${r.label}</td><td>${this.signCell(r.sign, r.degree)}</td>${\n\t\t\t\tcols.natal\n\t\t\t\t\t? html`<td>${r.natalLongitude != null ? this.signFromLongitude(r.natalLongitude) : html`\u2014`}</td>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tcols.house\n\t\t\t\t\t? html`<td class=\"num\">${r.house != null ? r.house : html`\u2014`}</td>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tcols.motion\n\t\t\t\t\t? html`<td>${\n\t\t\t\t\t\t\tr.speed != null\n\t\t\t\t\t\t\t\t? html`${formatNumber(r.speed, 3)}\u00B0/day${r.isRetrograde ? html`<span class=\"retro\">\u211E</span>` : nothing}`\n\t\t\t\t\t\t\t\t: html`\u2014`\n\t\t\t\t\t\t}</td>`\n\t\t\t\t\t: nothing\n\t\t\t} ${cols.formula ? html`<td class=\"formula\">${r.formula ?? html`\u2014`}</td>` : nothing}</tr>`;\n\t}\n\n\tprivate signCell(sign: string, degree: number) {\n\t\tconst g = SIGN_GLYPH[capitalize(sign)];\n\t\treturn html`<span class=\"sign\">${g ? html`<span class=\"sg\">${g}</span>` : nothing}${formatDegreeInSign(degree)} ${sign}</span>`;\n\t}\n\n\tprivate signFromLongitude(longitude: number) {\n\t\tconst p = longitudeToSignPosition(longitude);\n\t\treturn this.signCell(p.sign, p.degree + p.minute / 60);\n\t}\n\n\tprivate renderReading(r: Row, open: boolean) {\n\t\tconst glyph = PLANET_GLYPH[capitalize(r.label)] ?? '';\n\t\treturn html`<details class=\"interp-card\" name=\"positions-readings\" ?open=\"${open}\"><summary><span>${glyph ? html`${glyph}` : nothing}${r.label}</span> <span class=\"interp-aside\"><small>${r.sign} ${formatDegreeInSign(r.degree)}</small> ${chevron()}</span></summary><div class=\"interp-body\">${r.interpretation}</div></details>`;\n\t}\n\n\tprivate toViewModel(data: PositionsResponse): ViewModel {\n\t\tif ('asteroids' in data) {\n\t\t\treturn {\n\t\t\t\ttitle: 'Asteroids',\n\t\t\t\tbadges: data.houseSystem\n\t\t\t\t\t? [{ label: 'Houses', value: data.houseSystem }]\n\t\t\t\t\t: [],\n\t\t\t\tsummary: data.summary,\n\t\t\t\tcols: { house: true, motion: true, formula: false, natal: false },\n\t\t\t\trows: data.asteroids.map((a) => ({\n\t\t\t\t\tlabel: a.name,\n\t\t\t\t\tsign: a.sign,\n\t\t\t\t\tdegree: a.degree,\n\t\t\t\t\thouse: a.house,\n\t\t\t\t\tspeed: a.speed,\n\t\t\t\t\tisRetrograde: a.isRetrograde,\n\t\t\t\t\tinterpretation: a.interpretation,\n\t\t\t\t})),\n\t\t\t};\n\t\t}\n\t\tif ('lilith' in data) {\n\t\t\treturn {\n\t\t\t\ttitle: 'Black Moon Lilith',\n\t\t\t\tbadges: data.houseSystem\n\t\t\t\t\t? [{ label: 'Houses', value: data.houseSystem }]\n\t\t\t\t\t: [],\n\t\t\t\tsummary: data.summary,\n\t\t\t\tcols: { house: true, motion: true, formula: false, natal: false },\n\t\t\t\trows: data.lilith.map((l) => ({\n\t\t\t\t\tlabel: `${capitalize(l.variant)} apogee`,\n\t\t\t\t\tsign: l.sign,\n\t\t\t\t\tdegree: l.degree,\n\t\t\t\t\thouse: l.house,\n\t\t\t\t\tspeed: l.speed,\n\t\t\t\t\tisRetrograde: l.isRetrograde,\n\t\t\t\t\tinterpretation: l.interpretation,\n\t\t\t\t})),\n\t\t\t};\n\t\t}\n\t\tif ('directed' in data) {\n\t\t\treturn {\n\t\t\t\ttitle: 'Solar arc directions',\n\t\t\t\tbadges: [\n\t\t\t\t\t{ label: 'Arc', value: `${formatNumber(data.solarArc, 2)}\u00B0` },\n\t\t\t\t\t{ label: 'Directed to', value: data.targetDate },\n\t\t\t\t],\n\t\t\t\tsummary: data.summary,\n\t\t\t\tcols: { house: false, motion: false, formula: false, natal: true },\n\t\t\t\trows: data.directed.map((d) => ({\n\t\t\t\t\tlabel: d.name,\n\t\t\t\t\tsign: d.sign,\n\t\t\t\t\tdegree: d.degree,\n\t\t\t\t\tnatalLongitude: d.natalLongitude,\n\t\t\t\t\tinterpretation: d.interpretation,\n\t\t\t\t})),\n\t\t\t};\n\t\t}\n\t\tif ('lots' in data) {\n\t\t\treturn {\n\t\t\t\ttitle: 'Arabic lots',\n\t\t\t\tbadges: data.sect\n\t\t\t\t\t? [{ label: 'Sect', value: capitalize(data.sect) }]\n\t\t\t\t\t: [],\n\t\t\t\tsummary: data.summary,\n\t\t\t\tcols: { house: false, motion: false, formula: true, natal: false },\n\t\t\t\trows: data.lots.map((l) => ({\n\t\t\t\t\tlabel: l.name,\n\t\t\t\t\tsign: l.sign,\n\t\t\t\t\tdegree: l.degree,\n\t\t\t\t\tformula: l.formula,\n\t\t\t\t\tinterpretation: l.interpretation,\n\t\t\t\t})),\n\t\t\t};\n\t\t}\n\t\t// Secondary progressions: planets plus the progressed angles.\n\t\tconst angleRows: Row[] = [];\n\t\tif (data.ascendant) {\n\t\t\tangleRows.push({\n\t\t\t\tlabel: 'Ascendant',\n\t\t\t\tsign: data.ascendant.sign,\n\t\t\t\tdegree: data.ascendant.degree,\n\t\t\t\tisAngle: true,\n\t\t\t});\n\t\t}\n\t\tif (data.midheaven) {\n\t\t\tangleRows.push({\n\t\t\t\tlabel: 'Midheaven',\n\t\t\t\tsign: data.midheaven.sign,\n\t\t\t\tdegree: data.midheaven.degree,\n\t\t\t\tisAngle: true,\n\t\t\t});\n\t\t}\n\t\treturn {\n\t\t\ttitle: 'Secondary progressions',\n\t\t\tbadges: [\n\t\t\t\t{ label: 'Progressed to', value: data.targetDate },\n\t\t\t\t{\n\t\t\t\t\tlabel: 'Elapsed',\n\t\t\t\t\tvalue: `${formatNumber(data.elapsedYears, 1)} yrs`,\n\t\t\t\t},\n\t\t\t],\n\t\t\tsummary: data.summary,\n\t\t\tcols: { house: true, motion: true, formula: false, natal: false },\n\t\t\trows: [\n\t\t\t\t...angleRows,\n\t\t\t\t...data.planets.map((p) => ({\n\t\t\t\t\tlabel: p.name,\n\t\t\t\t\tsign: p.sign,\n\t\t\t\t\tdegree: p.degree,\n\t\t\t\t\thouse: p.house,\n\t\t\t\t\tspeed: p.speed,\n\t\t\t\t\tisRetrograde: p.isRetrograde,\n\t\t\t\t\tinterpretation: p.interpretation,\n\t\t\t\t})),\n\t\t\t],\n\t\t};\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-positions-table': RoxyPositionsTable;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { PLANET_GLYPH, SIGN_GLYPH } from '../tokens/index.js';\nimport type { ProfectionsResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { capitalize } from '../utils/string.js';\n\n/**\n * Annual profection card. Renders a /astrology/profections response: the year's\n * profected whole-sign house and sign, the lord of the year and where it sits in\n * the natal chart, and the reading. A single focal card, not a table.\n */\n@customElement('roxy-profection-card')\nexport class RoxyProfectionCard extends RoxyDataElement<ProfectionsResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);width:100%;color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}header{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-primary,#0f172a);margin:0}.badge{border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 14%, transparent);color:var(--roxy-fg,#0a0a0a);padding:2px 8px}.badge b{color:var(--roxy-accent-ink,#b45309);font-weight:600}.focus{align-items:center;gap:var(--roxy-space-md,1rem);padding:var(--roxy-space-md,1rem);border-radius:var(--roxy-radius-md,8px);background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 9%, transparent);flex-wrap:wrap;display:flex}.age{justify-items:center;min-width:4.5rem;display:grid}.age .n{color:var(--roxy-accent-ink,#b45309);font-variant-numeric:tabular-nums;font-size:2rem;font-weight:700;line-height:1}.age .l{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em}.arrow{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}.house{gap:2px;display:grid}.house .h{font-size:var(--roxy-text-lg,1.125rem);color:var(--roxy-fg,#0a0a0a);font-weight:600}.house .sign{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-secondary,#475569)}.house .sign .sg{margin-right:.3rem}.lord{font-size:var(--roxy-text-sm,.875rem);flex-wrap:wrap;align-items:baseline;gap:.4rem .75rem;display:flex}.lord .label{color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;font-size:var(--roxy-text-xs,.75rem)}.lord .value{color:var(--roxy-fg,#0a0a0a);font-weight:600}.lord .sub{color:var(--roxy-muted,#71717a)}.interp{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);line-height:var(--roxy-leading-normal,1.5);margin:0}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No profection data</div>`;\n\t}\n\n\tprotected renderData(data: ProfectionsResponse) {\n\t\tconst signGlyph = SIGN_GLYPH[capitalize(data.profectedSign ?? '')];\n\t\tconst lordGlyph = PLANET_GLYPH[capitalize(data.lordOfYear ?? '')];\n\t\tconst lordNatalGlyph =\n\t\t\tSIGN_GLYPH[capitalize(data.lordNatalPosition?.sign ?? '')];\n\t\treturn html`<div class=\"wrap\"><header><h2 class=\"title\">Annual profection</h2>${data.targetDate ? html`<span class=\"badge\"><b>For</b> ${data.targetDate}</span>` : nothing}</header><div class=\"focus\"><div class=\"age\"><span class=\"n\">${data.age}</span> <span class=\"l\">Age</span></div><span class=\"arrow\">activates</span><div class=\"house\"><span class=\"h\">House ${data.profectedHouse}</span> <span class=\"sign\">${signGlyph ? html`<span class=\"sg\">${signGlyph}</span>` : nothing}${data.profectedSign}</span></div></div><div class=\"lord\"><span class=\"label\">Lord of the year</span> <span class=\"value\">${lordGlyph ? html`${lordGlyph}` : nothing}${data.lordOfYear}</span> ${\n\t\t\t\t\tdata.lordNatalPosition\n\t\t\t\t\t\t? html`<span class=\"sub\">natal ${lordNatalGlyph ? html`<span>${lordNatalGlyph}</span>` : nothing}${data.lordNatalPosition.sign} \u00B7 house ${data.lordNatalPosition.house}</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</div>${data.interpretation ? html`<p class=\"interp\">${data.interpretation}</p>` : nothing}</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-profection-card': RoxyProfectionCard;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type {\n\tGetCenterResponse,\n\tGetCompoundNumberResponse,\n\tGetGateResponse,\n\tGetNumberMeaningResponse,\n\tGetPlanetMeaningResponse,\n\tGetRashiResponse,\n\tGetTrigramResponse,\n\tGetZodiacSignResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { humanize } from '../utils/string.js';\n\n/**\n * Every reference / glossary lookup this card renders. They do NOT share field names (a zodiac sign has 17 fields, a number meaning has 3), so the card renders heuristically rather than by fixed keys: a symbol + title hero, the prose fields as labelled paragraphs, keyword and string-list fields as chips, and every remaining scalar as an attribute grid. One card replaces eight near-identical bespoke ones.\n */\ntype ReferenceData =\n\t| GetZodiacSignResponse\n\t| GetPlanetMeaningResponse\n\t| GetRashiResponse\n\t| GetTrigramResponse\n\t| GetGateResponse\n\t| GetCenterResponse\n\t| GetNumberMeaningResponse\n\t| GetCompoundNumberResponse;\n\n/** Keys used to derive the title, in priority order. */\nconst TITLE_KEYS = ['name', 'english', 'title'];\n/** Keys whose string value is always treated as prose, even when short. */\nconst PROSE_KEYS = new Set([\n\t'description',\n\t'meaning',\n\t'characteristics',\n\t'tagline',\n\t'definedMeaning',\n\t'undefinedMeaning',\n\t'motto',\n]);\n/** Keys never shown as their own row/section (rendered elsewhere or noise). */\nconst SKIP_KEYS = new Set(['id', 'symbol', ...TITLE_KEYS]);\n\n/** Best-effort one-line label for an object inside an array (e.g. a gate channel partner), joining its primitive values so it never renders as [object Object]. */\nfunction objectLabel(obj: Record<string, unknown>): string {\n\treturn Object.values(obj)\n\t\t.filter((v) => typeof v === 'string' || typeof v === 'number')\n\t\t.map(String)\n\t\t.join(' \u00B7 ');\n}\n\n@customElement('roxy-reference-card')\nexport class RoxyReferenceCard extends RoxyDataElement<ReferenceData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.card{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{align-items:center;gap:var(--roxy-space-md,1rem);display:flex}.symbol{color:var(--roxy-accent-ink,#b45309);flex:none;font-size:2.5rem;line-height:1}.label{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;margin:0}.name{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.prose{margin:0;line-height:1.6}.prose .prose-label{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.05em;margin-bottom:2px;display:block}.chips{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;display:flex}.chips span{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 14%, transparent);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);padding:2px 8px}.list h3,.facts-wrap h3{margin:0 0 var(--roxy-space-xs,.25rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em}.facts{gap:var(--roxy-space-sm,.5rem);grid-template-columns:repeat(auto-fit,minmax(9rem,1fr));margin:0;display:grid}.fact dt{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);text-transform:capitalize}.fact dd{font-size:var(--roxy-text-sm,.875rem);margin:0}`,\n\t];\n\n\tprotected renderData(d: ReferenceData) {\n\t\tconst rec = d as Record<string, unknown>;\n\t\tconst title = this.deriveTitle(rec);\n\t\tconst symbol = typeof rec.symbol === 'string' ? rec.symbol : undefined;\n\t\tconst keywords = Array.isArray(rec.keywords)\n\t\t\t? (rec.keywords as unknown[]).map(String)\n\t\t\t: [];\n\n\t\tconst prose: Array<[string, string]> = [];\n\t\tconst lists: Array<[string, string[]]> = [];\n\t\tconst facts: Array<[string, string]> = [];\n\t\t// Bucket each field into prose / chip-list / fact. Recurses one level into\n\t\t// nested objects (description {short,long}, keywords {positive,negative},\n\t\t// meaning {...}, ichingHexagram {number,english}) and labels object-array\n\t\t// items by their primitives, so nested content is never dropped and an array\n\t\t// of objects never stringifies to [object Object].\n\t\tconst collect = (label: string, value: unknown, depth: number): void => {\n\t\t\tif (value == null) return;\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\tconst items = value\n\t\t\t\t\t.filter((v) => v != null)\n\t\t\t\t\t.map((v) =>\n\t\t\t\t\t\ttypeof v === 'object'\n\t\t\t\t\t\t\t? objectLabel(v as Record<string, unknown>)\n\t\t\t\t\t\t\t: String(v),\n\t\t\t\t\t)\n\t\t\t\t\t.filter((s) => s.length > 0);\n\t\t\t\tif (items.length > 0) lists.push([label, items]);\n\t\t\t} else if (typeof value === 'string') {\n\t\t\t\tif (PROSE_KEYS.has(label) || value.length > 48)\n\t\t\t\t\tprose.push([label, value]);\n\t\t\t\telse facts.push([label, value]);\n\t\t\t} else if (typeof value === 'number' || typeof value === 'boolean') {\n\t\t\t\tfacts.push([label, String(value)]);\n\t\t\t} else if (typeof value === 'object' && depth < 2) {\n\t\t\t\tfor (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n\t\t\t\t\tcollect(`${label} ${k}`, v, depth + 1);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tfor (const [key, value] of Object.entries(rec)) {\n\t\t\tif (SKIP_KEYS.has(key)) continue;\n\t\t\t// The hero chip row already shows a top-level keywords ARRAY; an object\n\t\t\t// keywords ({positive,negative}) falls through to collect() instead.\n\t\t\tif (key === 'keywords' && Array.isArray(value)) continue;\n\t\t\tcollect(key, value, 0);\n\t\t}\n\n\t\treturn html`<article class=\"card\" aria-label=\"${title}\"><header class=\"head\">${symbol ? html`<span class=\"symbol\" aria-hidden=\"true\">${symbol}</span>` : nothing}<div><p class=\"label\">Reference</p><h2 class=\"name\">${title}</h2></div></header>${keywords.length > 0 ? html`<div class=\"chips\">${keywords.map((k) => html`<span>${k}</span>`)}</div>` : nothing} ${prose.map(\n\t\t\t\t([key, text]) => html`<p class=\"prose\"><span class=\"prose-label\">${humanize(key)}</span>${text}</p>`,\n\t\t\t)} ${\n\t\t\t\tfacts.length > 0\n\t\t\t\t\t? html`<div class=\"facts-wrap\"><dl class=\"facts\">${facts.map(\n\t\t\t\t\t\t\t\t([key, value]) => html`<div class=\"fact\"><dt>${humanize(key)}</dt><dd>${value}</dd></div>`,\n\t\t\t\t\t\t\t)}</dl></div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${lists.map(\n\t\t\t\t([key, items]) => html`<div class=\"list\"><h3>${humanize(key)}</h3><div class=\"chips\">${items.map((i) => html`<span>${i}</span>`)}</div></div>`,\n\t\t\t)}</article>`;\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No reference data</div>`;\n\t}\n\n\tprivate deriveTitle(rec: Record<string, unknown>): string {\n\t\tfor (const key of TITLE_KEYS) {\n\t\t\tif (typeof rec[key] === 'string') return rec[key] as string;\n\t\t}\n\t\tconst type = typeof rec.type === 'string' ? humanize(rec.type) : '';\n\t\tconst number = rec.number;\n\t\tif (number != null) return `${type} ${number}`.trim();\n\t\treturn 'Reference';\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-reference-card': RoxyReferenceCard;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\n// Registers <roxy-natal-chart>, reused below as the wheel renderer. The\n// relocation response is structurally a natal chart (same planets, houses, and\n// angles), so the wheel is shared rather than duplicated.\nimport './natal-chart.js';\nimport { PLANET_GLYPH } from '../tokens/index.js';\nimport type {\n\tNatalChartResponse,\n\tRelocationChartResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { capitalize } from '../utils/string.js';\n\ntype HouseChange =\n\tRelocationChartResponse['changes']['planetsChangedHouse'][number];\n\nconst glyphFor = (name: string): string =>\n\tPLANET_GLYPH[capitalize(name)] ?? PLANET_GLYPH[name] ?? '';\n\n/**\n * Relocation chart. The birth instant is unchanged, so every planet keeps its\n * natal sign and degree while the houses and angles are recomputed for a new\n * place. Reuses {@link RoxyNatalChart} for the wheel (identical data shape) and\n * adds the relocation read: the move geometry, the planets that change house,\n * and the bodies pulled onto a relocated angle.\n */\n@customElement('roxy-relocation-wheel')\nexport class RoxyRelocationWheel extends RoxyDataElement<RelocationChartResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.stack{gap:var(--roxy-space-md,1rem);display:grid}.changes{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-primary,#0f172a);margin:0}.move{gap:var(--roxy-space-xs,.25rem) var(--roxy-space-md,1rem);font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-muted,#71717a);flex-wrap:wrap;display:flex}.summary{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);margin:0}.block-label{font-size:var(--roxy-text-xs,.75rem);text-transform:uppercase;letter-spacing:.06em;color:var(--roxy-muted,#71717a);margin:0 0 var(--roxy-space-xs,.25rem);font-weight:600}.chips{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;display:flex}.chip{border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 16%, transparent);color:var(--roxy-fg,#0a0a0a);padding:2px 10px}.moves-list{gap:2px;margin:0;padding:0;list-style:none;display:grid}.moves-list li{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a)}.moves-list .arrow{color:var(--roxy-muted,#71717a)}.empty-note{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-muted,#71717a);margin:0}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No relocation data</div>`;\n\t}\n\n\tprotected renderData(data: RelocationChartResponse) {\n\t\tconst c = data.changes;\n\t\treturn html`<div class=\"stack\"><roxy-natal-chart heading=\"Relocation chart\" .data=\"${data as unknown as NatalChartResponse}\"></roxy-natal-chart><section class=\"changes\"><h3 class=\"title\">What changes at this location</h3><div class=\"move\">${\n\t\t\t\t\t\ttypeof c?.distanceKm === 'number'\n\t\t\t\t\t\t\t? html`<span>${Math.round(c.distanceKm).toLocaleString()} km ${c.direction ?? ''} of birthplace</span>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t} ${\n\t\t\t\t\t\tc\n\t\t\t\t\t\t\t? html`<span>Ascendant ${c.ascendantSignChanged ? 'changes sign' : 'keeps its sign'}</span>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}</div>${\n\t\t\t\t\tdata.interpretation?.summary\n\t\t\t\t\t\t? html`<p class=\"summary\">${data.interpretation.summary}</p>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} ${\n\t\t\t\t\tc?.angularPlanets?.length\n\t\t\t\t\t\t? html`<div><p class=\"block-label\">Angular planets here</p><div class=\"chips\">${c.angularPlanets.map((p) => html`<span class=\"chip\">${glyphFor(p)} ${p}</span>`)}</div></div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}<div><p class=\"block-label\">Planets that change house</p>${\n\t\t\t\t\t\tc?.planetsChangedHouse?.length\n\t\t\t\t\t\t\t? html`<ul class=\"moves-list\">${c.planetsChangedHouse.map(\n\t\t\t\t\t\t\t\t\t(m: HouseChange) =>\n\t\t\t\t\t\t\t\t\t\thtml`<li>${glyphFor(m.planet)} ${m.planet}: house ${m.natalHouse} <span class=\"arrow\">to</span> ${m.relocatedHouse}</li>`,\n\t\t\t\t\t\t\t\t)}</ul>`\n\t\t\t\t\t\t\t: html`<p class=\"empty-note\">No planet changes house at this location.</p>`\n\t\t\t\t\t}</div></section></div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-relocation-wheel': RoxyRelocationWheel;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { PLANET_GLYPH } from '../tokens/index.js';\nimport type { ShadbalaResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatNumber } from '../utils/format.js';\nimport { capitalize } from '../utils/string.js';\n\ntype Planet = ShadbalaResponse['planets'][number];\n\n/** CSS variable and display name for each of the 6 bala components. */\nconst BALA_COMPONENTS: Array<{\n\tkey: keyof Pick<\n\t\tPlanet,\n\t\t| 'sthanaBala'\n\t\t| 'digBala'\n\t\t| 'kalaBala'\n\t\t| 'chestaBala'\n\t\t| 'naisargikaBala'\n\t\t| 'drikBala'\n\t>;\n\tlabel: string;\n\tcolor: string;\n}> = [\n\t{ key: 'sthanaBala', label: 'Sthana', color: 'var(--roxy-info, #0284c7)' },\n\t{ key: 'digBala', label: 'Dig', color: 'var(--roxy-success, #16a34a)' },\n\t{ key: 'kalaBala', label: 'Kala', color: 'var(--roxy-warning, #ea580c)' },\n\t{ key: 'chestaBala', label: 'Chesta', color: 'var(--roxy-accent, #f59e0b)' },\n\t{\n\t\tkey: 'naisargikaBala',\n\t\tlabel: 'Naisargika',\n\t\tcolor: 'var(--roxy-secondary, #475569)',\n\t},\n\t{ key: 'drikBala', label: 'Drik', color: 'var(--roxy-danger, #dc2626)' },\n];\n\n/**\n * Shadbala six-fold planetary strength table with stacked bar visualization.\n * Pass `data` from /vedic-astrology/shadbala.\n */\n@customElement('roxy-shadbala-table')\nexport class RoxyShadbalaTable extends RoxyDataElement<ShadbalaResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-md,1rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.subtitle{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem);margin:0}.planet-row{align-items:center;gap:var(--roxy-space-sm,.5rem);padding:var(--roxy-space-sm,.5rem) 0;border-bottom:1px solid var(--roxy-border,#e4e4e7);grid-template-columns:8rem 1fr auto;display:grid}.planet-row:last-of-type{border-bottom:none}.planet-label{font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);align-items:center;gap:6px;display:flex}.glyph{font-size:1.2em;line-height:1}.bar-wrap{flex-direction:column;gap:4px;display:flex}.bar{border-radius:var(--roxy-radius-sm,4px);background:var(--roxy-border,#e4e4e7);height:12px;display:flex;overflow:hidden}.bar-segment{height:100%;transition:flex-grow var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,cubic-bezier(.4, 0, .2, 1))}.pills{flex-direction:column;align-items:flex-end;gap:4px;display:flex}.rupas-label{font-variant-numeric:tabular-nums;font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);white-space:nowrap}.adequacy-badge{border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);padding:1px 6px;display:inline-block}.adequacy-badge--adequate{background:color-mix(in srgb, var(--roxy-success,#16a34a) 12%, transparent);color:var(--roxy-success-fg,#166534)}.adequacy-badge--weak{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 12%, transparent);color:var(--roxy-danger-fg,#991b1b)}.rank-badge{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-accent-ink,#b45309);font-weight:var(--roxy-weight-bold,600)}.legend{gap:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);border-top:1px solid var(--roxy-border,#e4e4e7);padding-top:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.legend-row{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);align-items:center;gap:6px;display:flex}.legend-swatch{border-radius:var(--roxy-radius-sm,4px);flex-shrink:0;width:10px;height:10px;display:inline-block}@container (width<=480px){.planet-row{grid-template-rows:auto auto;grid-template-columns:6rem 1fr}.pills{flex-direction:row;grid-column:1/-1;justify-content:flex-start;align-items:center}}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No shadbala data</div>`;\n\t}\n\n\tprotected renderData(d: ShadbalaResponse) {\n\t\tif (!d.planets?.length) return this.renderEmpty();\n\n\t\tconst sorted = [...d.planets].sort(\n\t\t\t(a, b) => a.relativeRank - b.relativeRank,\n\t\t);\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Shadbala planetary strength\"><div class=\"head\"><h2 class=\"title\">Shadbala</h2><p class=\"subtitle\">${sorted.length} planets ranked by strength</p></div><div role=\"list\" aria-label=\"Planet strength bars\">${sorted.map((p) => this.renderPlanetRow(p))}</div><div class=\"legend\" aria-label=\"Strength component legend\">${BALA_COMPONENTS.map(\n\t\t\t\t\t(b) => html`<div class=\"legend-row\"><span class=\"legend-swatch\" style=\"background:${b.color}\" aria-hidden=\"true\"></span> ${b.label}</div>`,\n\t\t\t\t)}</div></div>`;\n\t}\n\n\tprivate renderPlanetRow(p: Planet) {\n\t\tconst glyph = PLANET_GLYPH[capitalize(p.planet)] ?? '';\n\n\t\t// Compute positive component values (drikBala can be negative)\n\t\tconst values = BALA_COMPONENTS.map((b) => Math.max(0, p[b.key] as number));\n\t\tconst total = values.reduce((s, v) => s + v, 0);\n\n\t\tconst isAdequate =\n\t\t\ttypeof p.strengthRatio === 'number' && p.strengthRatio >= 1;\n\t\tconst badgeClass = isAdequate\n\t\t\t? 'adequacy-badge--adequate'\n\t\t\t: 'adequacy-badge--weak';\n\t\tconst badgeLabel = isAdequate ? 'adequate' : 'weak';\n\n\t\tconst rupasStr =\n\t\t\tformatNumber(p.totalRupas, 2) && formatNumber(p.minRequired, 2)\n\t\t\t\t? `${formatNumber(p.totalRupas, 2)} / ${formatNumber(p.minRequired, 2)} R`\n\t\t\t\t: '';\n\n\t\treturn html`<div class=\"planet-row\" role=\"listitem\" aria-label=\"${p.planet} shadbala\"><div class=\"planet-label\"><span class=\"glyph\" aria-hidden=\"true\">${glyph}</span> ${p.planet} <span class=\"rank-badge\" aria-label=\"rank ${p.relativeRank}\">#${p.relativeRank}</span></div><div class=\"bar-wrap\"><div class=\"bar\" role=\"img\" aria-label=\"Strength components for ${p.planet}\">${\n\t\t\t\t\t\ttotal > 0\n\t\t\t\t\t\t\t? BALA_COMPONENTS.map((b, i) => {\n\t\t\t\t\t\t\t\t\tconst v = values[i];\n\t\t\t\t\t\t\t\t\tif (v <= 0) return nothing;\n\t\t\t\t\t\t\t\t\tconst grow = (v / total) * 100;\n\t\t\t\t\t\t\t\t\treturn html`<div class=\"bar-segment\" style=\"flex-grow:${grow};background:${b.color}\" title=\"${b.label}: ${formatNumber(v, 1)}\"></div>`;\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}</div></div><div class=\"pills\">${rupasStr ? html`<span class=\"rupas-label\">${rupasStr}</span>` : nothing} <span class=\"${`adequacy-badge ${badgeClass}`}\">${badgeLabel}</span></div></div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-shadbala-table': RoxyShadbalaTable;\n\t}\n}\n", "import { css, html, nothing, svg } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { PLANET_GLYPH, SIGN_GLYPH, SIGNS_ORDER } from '../tokens/index.js';\nimport type {\n\tCalculateSynastryResponse,\n\tNatalChartResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { longitudeToSignPosition, polarToCartesian } from '../utils/degree.js';\nimport {\n\tASPECT_CLASS,\n\tformatNumber,\n\tnormalizeAspect,\n} from '../utils/format.js';\nimport { capitalize } from '../utils/string.js';\n\ntype PlanetEntry = NatalChartResponse['planets'][number];\ntype InterAspect = CalculateSynastryResponse['interAspects'][number];\n\n// Drawing the dual wheel requires per-person planet longitudes alongside\n// the synastry response. Callers can merge planet arrays from\n// /astrology/natal-chart into `person1.planets` and `person2.planets`\n// before passing the payload in; without them, the component falls back\n// to the inter-aspects table and a status note instead of an empty wheel.\ntype SynastryWithPlanets = CalculateSynastryResponse & {\n\tperson1?: { planets?: PlanetEntry[] };\n\tperson2?: { planets?: PlanetEntry[] };\n};\n\nconst SIZE = 360;\nconst CENTER = SIZE / 2;\nconst OUTER_R = 170;\nconst SIGN_R = 154;\nconst P1_R = 124;\nconst P2_R = 96;\n\n/**\n * Dual-wheel synastry chart with inter-aspects table. Pass `data` from\n * /astrology/synastry.\n */\n@customElement('roxy-synastry-chart')\nexport class RoxySynastryChart extends RoxyDataElement<SynastryWithPlanets> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:center;gap:var(--roxy-space-md,1rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.score{font-variant-numeric:tabular-nums;font-weight:var(--roxy-weight-bold,600);color:var(--roxy-accent-ink,#b45309);font-size:var(--roxy-text-xl,1.5rem)}svg{width:100%;max-width:var(--roxy-chart-max-width,560px);aspect-ratio:1;height:auto;margin:0 auto;display:block}.wheel-line{fill:none;stroke:var(--roxy-border,#e4e4e7)}.sign{fill:var(--roxy-secondary,#475569);font-size:14px}.p1{fill:var(--roxy-accent,#f59e0b);font-size:13px;font-weight:600}.p2{fill:var(--roxy-info,#0284c7);font-size:13px;font-weight:600}.person-tag{opacity:.85;font-size:7px;font-weight:700}.planet-deg{fill:var(--roxy-muted,#71717a);font-size:7px;font-family:var(--roxy-font-sans)}.planet-deg .retro{fill:var(--roxy-danger,#dc2626)}.asc-tick{stroke:var(--roxy-accent-ink,#b45309);stroke-width:1px;opacity:.75}.asc-label{fill:var(--roxy-accent-ink,#b45309);font-size:9px;font-weight:700;font-family:var(--roxy-font-sans);letter-spacing:.04em}.aspect{stroke-width:.8px;fill:none;opacity:.5}.aspect-trine,.aspect-sextile{stroke:var(--roxy-success,#16a34a)}.aspect-square,.aspect-opposition{stroke:var(--roxy-danger,#dc2626)}.aspect-conjunction{stroke:var(--roxy-accent-ink,#b45309)}.aspect-other{stroke:var(--roxy-muted,#71717a);opacity:.35}.legend-row{gap:var(--roxy-space-md,1rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);margin-top:calc(var(--roxy-space-xs,.25rem) * -1);flex-wrap:wrap;display:flex}.legend-row .swatch{vertical-align:middle;border-radius:50%;width:8px;height:8px;margin-right:4px;display:inline-block}.summary{color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-base,1rem);margin:0}table{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem)}th,td{padding:var(--roxy-space-sm,.5rem);border-bottom:1px solid var(--roxy-border,#e4e4e7);text-align:left}th{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;font-size:var(--roxy-text-xs,.75rem);letter-spacing:.06em}td.orb{font-variant-numeric:tabular-nums;color:var(--roxy-muted,#71717a)}.lists{gap:var(--roxy-space-md,1rem);grid-template-columns:repeat(auto-fit,minmax(14rem,1fr));display:grid}.lists h3{margin:0 0 var(--roxy-space-xs,.25rem) 0;font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em}.lists ul{padding-left:var(--roxy-space-md,1rem);font-size:var(--roxy-text-sm,.875rem);margin:0}.missing-planets{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 8%, transparent);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-md,1rem);color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);line-height:1.5}.missing-planets code{font-family:var(--roxy-font-mono,ui-monospace, SFMono-Regular, Menlo, monospace);background:color-mix(in srgb, var(--roxy-fg,#0a0a0a) 6%, transparent);border-radius:4px;padding:0 4px;font-size:.95em}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No synastry data</div>`;\n\t}\n\n\tprotected renderData(d: SynastryWithPlanets) {\n\t\tconst { person1, person2, compatibilityScore, analysis } = d;\n\t\tconst interAspects = d.interAspects ?? [];\n\t\tconst p1Planets = person1?.planets ?? [];\n\t\tconst p2Planets = person2?.planets ?? [];\n\n\t\tconst score =\n\t\t\ttypeof compatibilityScore === 'number'\n\t\t\t\t? Math.round(compatibilityScore)\n\t\t\t\t: undefined;\n\t\tconst summaryText = analysis?.overall;\n\t\tconst strengths = analysis?.strengths ?? [];\n\t\tconst challenges = analysis?.challenges ?? [];\n\n\t\t// /astrology/synastry does not return per-person planet positions, so the\n\t\t// dual-wheel cannot be drawn from a bare synastry response. Surface this\n\t\t// explicitly instead of rendering a blank wheel; keep the inter-aspects\n\t\t// table when it is present so callers still get useful output.\n\t\tconst hasPlanets = p1Planets.length > 0 && p2Planets.length > 0;\n\t\tif (!hasPlanets) {\n\t\t\treturn html`<div class=\"wrap\" aria-label=\"Synastry compatibility chart\"><div class=\"head\"><h2 class=\"title\">Synastry</h2>${\n\t\t\t\t\t\ttypeof score === 'number'\n\t\t\t\t\t\t\t? html`<span class=\"score\" aria-label=\"${`Score ${score} of 100`}\">${score} / 100</span>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}</div><div class=\"missing-planets\" role=\"status\">Synastry response missing planet positions. Pass <code>data</code> with <code>person1.planets</code> and <code>person2.planets</code> arrays from the natal-chart endpoint, or use the <code>&lt;roxy-data></code> fallback.</div>${summaryText ? html`<p class=\"summary\">${summaryText}</p>` : nothing} ${interAspects.length > 0 ? this.renderAspects(interAspects) : nothing} ${\n\t\t\t\t\tstrengths.length > 0 || challenges.length > 0\n\t\t\t\t\t\t? html`<div class=\"lists\">${\n\t\t\t\t\t\t\t\tstrengths.length\n\t\t\t\t\t\t\t\t\t? html`<div><h3>Strengths</h3><ul>${strengths.map((s) => html`<li>${s}</li>`)}</ul></div>`\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\t\tchallenges.length\n\t\t\t\t\t\t\t\t\t? html`<div><h3>Challenges</h3><ul>${challenges.map((s) => html`<li>${s}</li>`)}</ul></div>`\n\t\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t\t}</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</div>`;\n\t\t}\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Synastry compatibility chart\"><div class=\"head\"><h2 class=\"title\">Synastry</h2>${\n\t\t\t\t\ttypeof score === 'number'\n\t\t\t\t\t\t? html`<span class=\"score\" aria-label=\"${`Score ${score} of 100`}\">${score} / 100</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</div><svg viewBox=\"0 0 ${SIZE} ${SIZE}\" role=\"img\" aria-label=\"Dual chart wheel comparing two natal charts\"><title>Synastry dual wheel</title><circle class=\"wheel-line\" cx=\"${CENTER}\" cy=\"${CENTER}\" r=\"${OUTER_R}\" stroke-width=\"1.5\"/><circle class=\"wheel-line\" cx=\"${CENTER}\" cy=\"${CENTER}\" r=\"${P2_R + 14}\" stroke-width=\"0.8\"/><circle class=\"wheel-line\" cx=\"${CENTER}\" cy=\"${CENTER}\" r=\"${P2_R - 14}\" stroke-width=\"0.6\"/>${this.renderSpokes()} ${this.renderSigns()} ${this.renderInterAspectLines(p1Planets, p2Planets, interAspects)} ${this.renderRing(p1Planets, P1_R, 'p1', 1)} ${this.renderRing(p2Planets, P2_R, 'p2', 2)} ${this.renderAscendants(d)}</svg><div class=\"legend-row\"><span><span class=\"swatch\" style=\"background:var(--roxy-accent)\"></span>Person 1</span> <span><span class=\"swatch\" style=\"background:var(--roxy-info)\"></span>Person 2</span> <span><span class=\"swatch\" style=\"background:var(--roxy-success)\"></span>harmonious</span> <span><span class=\"swatch\" style=\"background:var(--roxy-danger)\"></span>challenging</span></div>${summaryText ? html`<p class=\"summary\">${summaryText}</p>` : nothing} ${interAspects.length > 0 ? this.renderAspects(interAspects) : nothing} ${\n\t\t\t\tstrengths.length > 0 || challenges.length > 0\n\t\t\t\t\t? html`<div class=\"lists\">${\n\t\t\t\t\t\t\tstrengths.length\n\t\t\t\t\t\t\t\t? html`<div><h3>Strengths</h3><ul>${strengths.map((s) => html`<li>${s}</li>`)}</ul></div>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t} ${\n\t\t\t\t\t\t\tchallenges.length\n\t\t\t\t\t\t\t\t? html`<div><h3>Challenges</h3><ul>${challenges.map((s) => html`<li>${s}</li>`)}</ul></div>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}</div>`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n\n\tprivate toAngle(longitude: number): number {\n\t\treturn 180 - longitude;\n\t}\n\n\tprivate renderSpokes() {\n\t\treturn Array.from({ length: 12 }, (_, i) => {\n\t\t\tconst angle = this.toAngle(i * 30);\n\t\t\tconst start = polarToCartesian(CENTER, CENTER, P2_R - 14, angle);\n\t\t\tconst end = polarToCartesian(CENTER, CENTER, OUTER_R, angle);\n\t\t\treturn svg`<line class=\"wheel-line\" x1=${start.x} y1=${start.y} x2=${end.x} y2=${end.y} stroke-width=\"0.6\" />`;\n\t\t});\n\t}\n\n\tprivate renderSigns() {\n\t\treturn SIGNS_ORDER.map((s, i) => {\n\t\t\tconst angle = this.toAngle(i * 30 + 15);\n\t\t\tconst pos = polarToCartesian(CENTER, CENTER, SIGN_R, angle);\n\t\t\treturn svg`<text class=\"sign\" x=${pos.x} y=${pos.y} text-anchor=\"middle\" dominant-baseline=\"central\">${SIGN_GLYPH[s]}</text>`;\n\t\t});\n\t}\n\n\tprivate renderRing(\n\t\tplanets: PlanetEntry[],\n\t\tradius: number,\n\t\tcls: string,\n\t\tpersonIndex: 1 | 2,\n\t) {\n\t\treturn planets.map((p) => {\n\t\t\tif (!Number.isFinite(p.longitude)) return nothing;\n\t\t\tconst angle = this.toAngle(p.longitude);\n\t\t\tconst pos = polarToCartesian(CENTER, CENTER, radius, angle);\n\t\t\t// Degree label sits one tier inward from the glyph so the two\n\t\t\t// concentric rings never blur their numbers into the aspect lines.\n\t\t\tconst degOffset = personIndex === 1 ? -12 : -10;\n\t\t\tconst degPos = polarToCartesian(\n\t\t\t\tCENTER,\n\t\t\t\tCENTER,\n\t\t\t\tradius + degOffset,\n\t\t\t\tangle,\n\t\t\t);\n\t\t\tconst glyph = PLANET_GLYPH[capitalize(p.name)] ?? p.name.slice(0, 2);\n\t\t\tconst sp = longitudeToSignPosition(p.longitude);\n\t\t\tconst retro = p.isRetrograde === true;\n\t\t\tconst degLabel = `${sp.degree}\u00B0${String(sp.minute).padStart(2, '0')}'`;\n\t\t\tconst tooltip = `${p.name}${retro ? ' retrograde' : ''} - ${degLabel} ${sp.sign}`;\n\t\t\treturn svg`<g>\n\t\t\t\t<text class=${cls} x=${pos.x} y=${pos.y} text-anchor=\"middle\" dominant-baseline=\"central\"><title>${tooltip}</title>${glyph}<tspan class=\"person-tag\" dy=\"-0.55em\" dx=\"0.15em\">${personIndex}</tspan></text>\n\t\t\t\t<text class=\"planet-deg\" x=${degPos.x} y=${degPos.y} text-anchor=\"middle\" dominant-baseline=\"central\">${sp.degree}\u00B0${retro ? svg`<tspan class=\"retro\"> \u211E</tspan>` : nothing}</text>\n\t\t\t</g>`;\n\t\t});\n\t}\n\n\t/**\n\t * Ascendant markers for both people. Drawn as small spokes at the inner\n\t * rim with the label outside, so the two rising signs are immediately\n\t * scannable on the wheel without depending on tooltips.\n\t */\n\tprivate renderAscendants(data: SynastryWithPlanets) {\n\t\tconst items: ReturnType<typeof svg>[] = [];\n\t\tconst make = (\n\t\t\tasc: { sign: string; degree: number } | undefined,\n\t\t\tpersonIndex: 1 | 2,\n\t\t) => {\n\t\t\tif (!asc) return;\n\t\t\tconst signIdx = SIGNS_ORDER.findIndex(\n\t\t\t\t(s) => s.toLowerCase() === asc.sign.toLowerCase(),\n\t\t\t);\n\t\t\tif (signIdx === -1) return;\n\t\t\tconst longitude = signIdx * 30 + asc.degree;\n\t\t\tconst angle = this.toAngle(longitude);\n\t\t\tconst innerR = personIndex === 1 ? P1_R + 14 : P2_R + 14;\n\t\t\tconst tickPos = polarToCartesian(CENTER, CENTER, innerR, angle);\n\t\t\tconst labelPos = polarToCartesian(CENTER, CENTER, OUTER_R + 14, angle);\n\t\t\titems.push(svg`<g>\n\t\t\t\t<line class=\"asc-tick\" x1=${tickPos.x} y1=${tickPos.y} x2=${labelPos.x} y2=${labelPos.y} />\n\t\t\t\t<text class=\"asc-label\" x=${labelPos.x} y=${labelPos.y} text-anchor=\"middle\" dominant-baseline=\"central\">Asc${personIndex}</text>\n\t\t\t</g>`);\n\t\t};\n\t\tmake(data.person1?.ascendant, 1);\n\t\tmake(data.person2?.ascendant, 2);\n\t\treturn items;\n\t}\n\n\tprivate renderInterAspectLines(\n\t\tp1: PlanetEntry[],\n\t\tp2: PlanetEntry[],\n\t\taspects: InterAspect[],\n\t) {\n\t\tconst longitudeOf = (\n\t\t\tlist: PlanetEntry[],\n\t\t\tname: string,\n\t\t): number | undefined => {\n\t\t\tconst target = capitalize(name);\n\t\t\tfor (const p of list) {\n\t\t\t\tif (capitalize(p.name) !== target) continue;\n\t\t\t\tif (typeof p.longitude === 'number') return p.longitude;\n\t\t\t}\n\t\t\treturn undefined;\n\t\t};\n\t\treturn aspects.map((a) => {\n\t\t\tconst l1 = longitudeOf(p1, a.planet1);\n\t\t\tconst l2 = longitudeOf(p2, a.planet2);\n\t\t\tif (l1 === undefined || l2 === undefined) return nothing;\n\t\t\tconst out = polarToCartesian(CENTER, CENTER, P1_R - 12, this.toAngle(l1));\n\t\t\tconst inn = polarToCartesian(CENTER, CENTER, P2_R + 8, this.toAngle(l2));\n\t\t\tconst aspectName = normalizeAspect(a);\n\t\t\tconst cls = ASPECT_CLASS[aspectName] ?? 'aspect-other';\n\t\t\tconst orbLabel = formatNumber(a.orb, 1);\n\t\t\treturn svg`<line class=${`aspect ${cls}`} x1=${out.x} y1=${out.y} x2=${inn.x} y2=${inn.y}><title>${a.planet1} ${aspectName} ${a.planet2}${orbLabel ? ` (orb ${orbLabel}\u00B0)` : ''}</title></line>`;\n\t\t});\n\t}\n\n\tprivate renderAspects(aspects: InterAspect[]) {\n\t\treturn html`<table><thead><tr><th>Planet 1</th><th>Planet 2</th><th>Aspect</th><th>Orb</th><th>Strength</th></tr></thead><tbody>${aspects.slice(0, 12).map(\n\t\t\t\t\t(a) => html`<tr><td>${a.planet1}</td><td>${a.planet2}</td><td>${normalizeAspect(a) || ''}</td><td class=\"orb\">${formatNumber(a.orb, 1)}</td><td>${formatStrength(a.strength)}</td></tr>`,\n\t\t\t\t)}</tbody></table>`;\n\t}\n}\n\nfunction formatStrength(s: number | undefined): string {\n\tif (typeof s === 'number') return Math.round(s).toString();\n\treturn '';\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-synastry-chart': RoxySynastryChart;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\nimport type { GetCardResponse, GetDailyCardResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\ntype TarotData = GetCardResponse | GetDailyCardResponse;\n\n/**\n * Tarot card. Renders /tarot/cards/{id} or /tarot/daily. Click to flip\n * between upright and reversed where the data shape supports it.\n */\n@customElement('roxy-tarot-card')\nexport class RoxyTarotCard extends RoxyDataElement<TarotData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.card{background:var(--roxy-surface,#fff);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-lg,1.5rem);grid-template-columns:minmax(0,9rem) 1fr;align-items:start;display:grid}@container (width<=480px){.card{grid-template-columns:1fr}}.image-wrap{perspective:800px}.image{border-radius:var(--roxy-radius-md,8px);background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 60%, transparent);width:100%;height:auto;transition:transform var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,cubic-bezier(.4, 0, .2, 1));cursor:pointer;display:block}.image.reversed{transform:rotate(180deg)}.image:focus-visible{outline:2px solid var(--roxy-ring,#f59e0b66);outline-offset:2px}.title{font-size:var(--roxy-text-xl,1.5rem);font-weight:var(--roxy-weight-bold,600);letter-spacing:var(--roxy-tracking-tight);margin:0}.meta{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem);text-transform:uppercase;letter-spacing:.06em;margin-bottom:var(--roxy-space-sm,.5rem)}.message{color:var(--roxy-fg,#0a0a0a);margin:var(--roxy-space-sm,.5rem) 0 var(--roxy-space-md,1rem)}.chips{gap:var(--roxy-space-xs,.25rem);margin-top:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.chips span{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 14%, transparent);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);padding:2px 8px}.flip{margin-top:var(--roxy-space-sm,.5rem);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);font-family:inherit;font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-secondary,#475569);cursor:pointer;transition:transform var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,cubic-bezier(.4, 0, .2, 1));background:0 0;padding:4px 12px}.flip:hover{transform:scale(1.02)}`,\n\t];\n\n\t@state()\n\tprivate flipped = false;\n\n\tprivate toggleFlip = () => {\n\t\tthis.flipped = !this.flipped;\n\t};\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No tarot data</div>`;\n\t}\n\n\tprotected renderData(d: TarotData) {\n\t\tif ('card' in d) return this.renderDailyCard(d);\n\t\treturn this.renderFullCard(d);\n\t}\n\n\tprivate renderDailyCard(d: GetDailyCardResponse) {\n\t\tconst card = d.card;\n\t\tconst isReversed = this.flipped !== Boolean(card.reversed);\n\t\tconst keywords = card.keywords ?? [];\n\n\t\treturn html`<article class=\"card\" aria-label=\"${card.name ?? 'Tarot card'}\"><div class=\"image-wrap\">${\n\t\t\t\t\tcard.imageUrl\n\t\t\t\t\t\t? html`<img class=\"${`image ${isReversed ? 'reversed' : ''}`}\" src=\"${card.imageUrl}\" alt=\"${card.name ?? 'Tarot card'}\" tabindex=\"0\" @click=\"${this.toggleFlip}\" @keydown=\"${(e: KeyboardEvent) => {\n\t\t\t\t\t\t\t\tif (e.key === 'Enter' || e.key === ' ') {\n\t\t\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t\t\tthis.toggleFlip();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}}\">`\n\t\t\t\t\t\t: html`<div class=\"${`image ${isReversed ? 'reversed' : ''}`}\" style=\"aspect-ratio:0.6;display:flex;align-items:center;justify-content:center;color:var(--roxy-muted)\">${card.name ?? '?'}</div>`\n\t\t\t\t}</div><div><div class=\"meta\">${card.arcana ? html`${card.arcana} arcana` : nothing} ${isReversed ? html`\u00B7 reversed` : nothing}</div><h2 class=\"title\">${card.name ?? 'Tarot card'}</h2>${d.dailyMessage ? html`<p class=\"message\">${d.dailyMessage}</p>` : nothing} ${card.meaning ? html`<p>${card.meaning}</p>` : nothing} ${\n\t\t\t\t\tkeywords.length > 0\n\t\t\t\t\t\t? html`<div class=\"chips\">${keywords.map((k) => html`<span>${k}</span>`)}</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} <button class=\"flip\" type=\"button\" @click=\"${this.toggleFlip}\" aria-pressed=\"${this.flipped ? 'true' : 'false'}\">Flip card</button></div></article>`;\n\t}\n\n\tprivate renderFullCard(d: GetCardResponse) {\n\t\tconst isReversed = this.flipped;\n\t\tconst orientedMeaning = isReversed ? d.reversed : d.upright;\n\t\tconst keywords = isReversed\n\t\t\t? (d.keywords?.reversed ?? [])\n\t\t\t: (d.keywords?.upright ?? []);\n\n\t\treturn html`<article class=\"card\" aria-label=\"${d.name ?? 'Tarot card'}\"><div class=\"image-wrap\">${\n\t\t\t\t\td.imageUrl\n\t\t\t\t\t\t? html`<img class=\"${`image ${isReversed ? 'reversed' : ''}`}\" src=\"${d.imageUrl}\" alt=\"${d.name ?? 'Tarot card'}\" tabindex=\"0\" @click=\"${this.toggleFlip}\" @keydown=\"${(e: KeyboardEvent) => {\n\t\t\t\t\t\t\t\tif (e.key === 'Enter' || e.key === ' ') {\n\t\t\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t\t\tthis.toggleFlip();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}}\">`\n\t\t\t\t\t\t: html`<div class=\"${`image ${isReversed ? 'reversed' : ''}`}\" style=\"aspect-ratio:0.6;display:flex;align-items:center;justify-content:center;color:var(--roxy-muted)\">${d.name ?? '?'}</div>`\n\t\t\t\t}</div><div><div class=\"meta\">${d.arcana ? html`${d.arcana} arcana` : nothing} ${d.number !== undefined && d.number !== null ? html`\u00B7 ${d.number}` : nothing} ${isReversed ? html`\u00B7 reversed` : nothing}</div><h2 class=\"title\">${d.name ?? 'Tarot card'}</h2>${orientedMeaning?.description ? html`<p>${orientedMeaning.description}</p>` : nothing} ${\n\t\t\t\t\tkeywords.length > 0\n\t\t\t\t\t\t? html`<div class=\"chips\">${keywords.map((k) => html`<span>${k}</span>`)}</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} <button class=\"flip\" type=\"button\" @click=\"${this.toggleFlip}\" aria-pressed=\"${this.flipped ? 'true' : 'false'}\">Flip card</button></div></article>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-tarot-card': RoxyTarotCard;\n\t}\n}\n", "import { css, html } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type { ListCardsResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { capitalize } from '../utils/string.js';\n\n/** A single card row from the catalog response. Kept spec-derived so the tile never reads a field the API does not return. */\ntype CatalogCard = ListCardsResponse['cards'][number];\n\n/**\n * Tarot catalog. Renders GET /tarot/cards as a responsive gallery of the deck: each tile carries the Rider-Waite-Smith artwork, the card name, and an arcana/suit caption. Filter the deck server-side (arcana, suit, number, paging) and pass the page response; the component renders whatever cards it carries. Pairs with `<roxy-tarot-card>` for a single-card detail view and `<roxy-tarot-spread>` for readings.\n */\n@customElement('roxy-tarot-catalog')\nexport class RoxyTarotCatalog extends RoxyDataElement<ListCardsResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-fg,#0a0a0a);margin:0}.count{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}.grid{gap:var(--roxy-space-md,1rem);grid-template-columns:repeat(auto-fill,minmax(7rem,1fr));margin:0;padding:0;list-style:none;display:grid}.tile{gap:var(--roxy-space-xs,.25rem);background:var(--roxy-surface,#fff);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-sm,.5rem);box-shadow:var(--roxy-shadow-sm);display:grid}.art{aspect-ratio:2/3;border-radius:var(--roxy-radius-sm,4px);object-fit:cover;background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 35%, transparent);width:100%}.name{font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-fg,#0a0a0a);margin:0}.meta{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);margin:0}`,\n\t];\n\n\t/**\n\t * Override the auto-derived gallery heading. Empty by default, in which case the heading is \"Tarot deck\".\n\t */\n\t@property({ type: String, reflect: true })\n\theading = '';\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No cards</div>`;\n\t}\n\n\tprotected renderData(d: ListCardsResponse) {\n\t\tconst cards = d.cards ?? [];\n\t\tif (cards.length === 0) return this.renderEmpty();\n\n\t\tconst title = this.heading || 'Tarot deck';\n\t\tconst total = typeof d.total === 'number' ? d.total : cards.length;\n\n\t\treturn html`<section class=\"wrap\" aria-label=\"${title}\"><header class=\"head\"><h2 class=\"title\">${title}</h2><span class=\"count\">${total} ${total === 1 ? 'card' : 'cards'}</span></header><ul class=\"grid\">${cards.map(\n\t\t\t\t\t(c) => html`<li class=\"tile\">${\n\t\t\t\t\t\t\tc.imageUrl\n\t\t\t\t\t\t\t\t? html`<img class=\"art\" src=\"${c.imageUrl}\" alt=\"${c.name ?? 'Tarot card'}\" loading=\"lazy\">`\n\t\t\t\t\t\t\t\t: html`<div class=\"art\" aria-hidden=\"true\"></div>`\n\t\t\t\t\t\t}<p class=\"name\">${c.name}</p><p class=\"meta\">${cardMeta(c)}</p></li>`,\n\t\t\t\t)}</ul></section>`;\n\t}\n}\n\n/**\n * Caption line for a catalog tile. Minor Arcana cards name their suit (`Minor \u00B7 Cups`); Major Arcana cards read `Major Arcana`. Both derive only from the spec `arcana` and `suit` fields.\n */\nfunction cardMeta(c: CatalogCard): string {\n\tif (c.suit) return `${capitalize(c.arcana)} \u00B7 ${capitalize(c.suit)}`;\n\treturn `${capitalize(c.arcana)} Arcana`;\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-tarot-catalog': RoxyTarotCatalog;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type {\n\tCastCareerSpreadResponse,\n\tCastCelticCrossResponse,\n\tCastCustomSpreadResponse,\n\tCastLoveSpreadResponse,\n\tCastReadingResponse,\n\tCastThreeCardResponse,\n\tCastYesNoResponse,\n\tDrawCardsResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\ntype TarotSpreadData =\n\t| CastThreeCardResponse\n\t| CastCelticCrossResponse\n\t| CastLoveSpreadResponse\n\t| CastYesNoResponse\n\t| CastReadingResponse\n\t| CastCareerSpreadResponse\n\t| CastCustomSpreadResponse\n\t| DrawCardsResponse;\n\n/**\n * Tarot spread card. Renders /tarot/spreads/{three-card,celtic-cross,love},\n * /tarot/yes-no, /tarot/draw responses.\n */\n@customElement('roxy-tarot-spread')\nexport class RoxyTarotSpread extends RoxyDataElement<TarotSpreadData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;gap:var(--roxy-space-md,1rem);flex-wrap:wrap;align-items:baseline;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);text-transform:capitalize;margin:0}.question{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem);font-style:italic}.answer{border-radius:var(--roxy-radius-full,9999px);font-weight:var(--roxy-weight-bold,600);font-size:var(--roxy-text-base,1rem);text-transform:uppercase;letter-spacing:.06em;padding:4px 14px;display:inline-block}.answer.yes{background:color-mix(in srgb, var(--roxy-success,#16a34a) 16%, transparent);color:var(--roxy-success-fg,#166534)}.answer.no{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 16%, transparent);color:var(--roxy-danger-fg,#991b1b)}.answer.maybe{background:color-mix(in srgb, var(--roxy-warning,#ea580c) 16%, transparent);color:var(--roxy-warning-fg,#9a3412)}.grid{gap:var(--roxy-space-md,1rem);grid-template-columns:repeat(auto-fit,minmax(8rem,1fr));display:grid}.card{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-sm,.5rem);background:var(--roxy-surface,#fff);gap:var(--roxy-space-xs,.25rem);display:grid}.label{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;margin:0}.image{aspect-ratio:.6;background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 60%, transparent);border-radius:var(--roxy-radius-sm,4px);width:100%;font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);justify-content:center;align-items:center;display:flex;overflow:hidden}.image img{object-fit:cover;width:100%;height:100%;transition:transform var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,cubic-bezier(.4, 0, .2, 1))}.image img.reversed{transform:rotate(180deg)}.name{font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);margin:0}.interp{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-secondary,#475569);margin:0}.reading{color:var(--roxy-fg,#0a0a0a);margin:0}`,\n\t];\n\n\t@property({ type: String, reflect: true })\n\tspread:\n\t\t| 'three-card'\n\t\t| 'celtic-cross'\n\t\t| 'love'\n\t\t| 'career'\n\t\t| 'custom'\n\t\t| 'yes-no'\n\t\t| 'draw' = 'three-card';\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No tarot spread</div>`;\n\t}\n\n\tprotected renderData(d: TarotSpreadData) {\n\t\tconst isYesNo = 'answer' in d;\n\t\tconst isDrawn = 'cards' in d && !('spread' in d);\n\t\tconst positions = isDrawn\n\t\t\t? []\n\t\t\t: 'positions' in d\n\t\t\t\t? (d.positions ?? [])\n\t\t\t\t: [];\n\t\tconst cards = isDrawn && 'cards' in d ? (d as DrawCardsResponse).cards : [];\n\t\tconst answer = isYesNo ? (d as CastYesNoResponse).answer : undefined;\n\t\tconst strength = isYesNo ? (d as CastYesNoResponse).strength : undefined;\n\t\tconst spreadLabel =\n\t\t\t'spread' in d\n\t\t\t\t? (d as CastThreeCardResponse).spread\n\t\t\t\t: this.spread.replace(/-/g, ' ');\n\t\tconst question =\n\t\t\t'question' in d ? (d as CastThreeCardResponse).question : undefined;\n\t\tconst summary =\n\t\t\t'summary' in d ? (d as CastThreeCardResponse).summary : undefined;\n\t\tconst yesNoInterp = isYesNo\n\t\t\t? (d as CastYesNoResponse).interpretation\n\t\t\t: undefined;\n\t\tconst answerClass = answer\n\t\t\t? answer.toLowerCase().replace(/[^a-z]/g, '')\n\t\t\t: '';\n\n\t\treturn html`<article class=\"wrap\" aria-label=\"Tarot spread\"><header class=\"head\"><h2 class=\"title\">${spreadLabel}</h2>${question ? html`<span class=\"question\">\"${question}\"</span>` : nothing}</header>${\n\t\t\t\tisYesNo\n\t\t\t\t\t? html`<div><span class=\"${`answer ${answerClass}`}\">${answer}</span> ${strength ? html`<small>\u00B7 ${strength}</small>` : nothing}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tpositions.length > 0\n\t\t\t\t\t? html`<div class=\"grid\">${positions.map(\n\t\t\t\t\t\t\t(p) => html`<div class=\"card\"><p class=\"label\">${p.name ?? ''}</p><div class=\"image\">${\n\t\t\t\t\t\t\t\t\t\tp.card?.imageUrl\n\t\t\t\t\t\t\t\t\t\t\t? html`<img src=\"${p.card.imageUrl}\" alt=\"${p.card.name ?? 'tarot card'}\" class=\"${p.card.reversed ? 'reversed' : ''}\">`\n\t\t\t\t\t\t\t\t\t\t\t: html`${p.card?.name ?? '?'}`\n\t\t\t\t\t\t\t\t\t}</div><p class=\"name\">${p.card?.name ?? ''} ${p.card?.reversed ? html`<small>(reversed)</small>` : nothing}</p>${p.interpretation ? html`<p class=\"interp\">${p.interpretation}</p>` : nothing}</div>`,\n\t\t\t\t\t\t)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tcards.length > 0\n\t\t\t\t\t? html`<div class=\"grid\">${cards.map(\n\t\t\t\t\t\t\t(c) => html`<div class=\"card\"><div class=\"image\">${\n\t\t\t\t\t\t\t\t\t\tc.imageUrl\n\t\t\t\t\t\t\t\t\t\t\t? html`<img src=\"${c.imageUrl}\" alt=\"${c.name ?? 'tarot card'}\" class=\"${c.reversed ? 'reversed' : ''}\">`\n\t\t\t\t\t\t\t\t\t\t\t: html`${c.name ?? '?'}`\n\t\t\t\t\t\t\t\t\t}</div><p class=\"name\">${c.name ?? ''} ${c.reversed ? html`<small>(reversed)</small>` : nothing}</p>${c.meaning ? html`<p class=\"interp\">${c.meaning}</p>` : nothing}</div>`,\n\t\t\t\t\t\t)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${summary ? html`<p class=\"reading\">${summary}</p>` : nothing} ${yesNoInterp ? html`<p class=\"reading\">${yesNoInterp}</p>` : nothing}</article>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-tarot-spread': RoxyTarotSpread;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\nimport { PLANET_GLYPH, SIGN_GLYPH } from '../tokens/index.js';\nimport type { TransitsResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { chevron, disclosureStyles } from '../utils/disclosure.js';\nimport { formatDate, formatNumber, formatTime } from '../utils/format.js';\nimport { capitalize } from '../utils/string.js';\nimport { renderTablist, tablistStyles } from '../utils/tablist.js';\n\n/**\n * Transit positions and aspect table. Pass `data` from /astrology/transits.\n * When natalChart is included in the request, `data.transitAspects` and\n * `data.summary` are present and rendered automatically.\n */\n@customElement('roxy-transits-table')\nexport class RoxyTransitsTable extends RoxyDataElement<TransitsResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\ttablistStyles,\n\t\tdisclosureStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-md,1rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.subtitle{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem);margin:0}.summary-pills{gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.pill{padding:2px var(--roxy-space-sm,.5rem);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);border:1px solid;align-items:center;gap:4px;display:inline-flex}.pill--muted{color:var(--roxy-fg,#0a0a0a);background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 60%, transparent)}.pill--success{color:var(--roxy-success-fg,#166534);background:color-mix(in srgb, var(--roxy-success,#16a34a) 10%, transparent)}.pill--danger{color:var(--roxy-danger-fg,#991b1b);background:color-mix(in srgb, var(--roxy-danger,#dc2626) 10%, transparent)}table{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem)}th,td{padding:var(--roxy-space-sm,.5rem);border-bottom:1px solid var(--roxy-border,#e4e4e7);text-align:left}th{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;font-size:var(--roxy-text-xs,.75rem);letter-spacing:.06em}.section-label{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;font-weight:var(--roxy-weight-bold,600);margin:0 0 var(--roxy-space-xs,.25rem) 0}.glyph{margin-right:2px;font-size:1.1em;line-height:1}.planet-cell{white-space:nowrap;align-items:center;gap:4px;display:flex}.retro-badge{border-radius:var(--roxy-radius-sm,4px);background:color-mix(in srgb, var(--roxy-warning,#ea580c) 12%, transparent);color:var(--roxy-warning-fg,#9a3412);font-size:.7em;font-weight:var(--roxy-weight-bold,600);vertical-align:middle;margin-left:2px;padding:1px 4px;display:inline-block}.speed{font-variant-numeric:tabular-nums;color:var(--roxy-muted,#71717a);white-space:nowrap}.speed-arrow{font-size:.85em}td.num{font-variant-numeric:tabular-nums;color:var(--roxy-muted,#71717a)}.overflow-scroll{-webkit-overflow-scrolling:touch;overflow-x:auto}.aspect-card{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);margin-bottom:var(--roxy-space-xs,.25rem)}.aspect-card summary{cursor:pointer;color:var(--roxy-fg,#0a0a0a);flex-wrap:wrap;align-items:center;gap:.5em;font-weight:500;display:flex}.aspect-card summary .meta{color:var(--roxy-muted,#71717a);font-weight:400;font-size:var(--roxy-text-xs,.75rem);font-variant-numeric:tabular-nums;margin-left:auto}.aspect-card .interp-body{margin-top:var(--roxy-space-xs,.25rem);color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);line-height:1.45}.aspect-card .interp-body p{margin:0 0 var(--roxy-space-xs,.25rem)}.interp-keywords{flex-wrap:wrap;gap:.25rem;margin-top:.5rem;display:flex}.interp-keywords .kw{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 14%, transparent);color:var(--roxy-accent-ink,#b45309);font-size:var(--roxy-text-xs,.75rem);border-radius:9999px;padding:1px 8px}.nature-badge{font-size:var(--roxy-text-xs,.75rem);border-radius:9999px;padding:1px 8px;font-weight:600;display:inline-block}.nature-badge.harmonious{background:color-mix(in srgb, var(--roxy-success,#16a34a) 12%, transparent);color:var(--roxy-success-fg,#166534)}.nature-badge.challenging{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 12%, transparent);color:var(--roxy-danger-fg,#991b1b)}.nature-badge.neutral{background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 60%, transparent);color:var(--roxy-fg,#0a0a0a)}`,\n\t];\n\n\t/** Which panel is showing: planet positions or the transit-to-natal aspects. */\n\t@state()\n\tprivate tab: 'positions' | 'aspects' = 'positions';\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No transits data</div>`;\n\t}\n\n\tprotected renderData(d: TransitsResponse) {\n\t\tif (!d.transitPlanets?.length) return this.renderEmpty();\n\n\t\tconst {\n\t\t\ttransitDate,\n\t\t\ttransitTime,\n\t\t\ttransitPlanets,\n\t\t\ttransitAspects,\n\t\t\tsummary,\n\t\t} = d;\n\n\t\tconst dateStr = [formatDate(transitDate), formatTime(transitTime)]\n\t\t\t.filter(Boolean)\n\t\t\t.join(' ');\n\t\tconst aspectCount = transitAspects?.length ?? 0;\n\t\tconst tab = this.tab;\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Transits\"><div class=\"head\"><h2 class=\"title\">Transits</h2>${dateStr ? html`<p class=\"subtitle\">${dateStr}</p>` : nothing}</div>${\n\t\t\t\taspectCount > 0\n\t\t\t\t\t? html`${renderTablist({\n\t\t\t\t\t\t\titems: [\n\t\t\t\t\t\t\t\t{ id: 'positions', label: 'Positions' },\n\t\t\t\t\t\t\t\t{ id: 'aspects', label: `Aspects (${aspectCount})` },\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tactive: tab,\n\t\t\t\t\t\t\tonSelect: (v) => {\n\t\t\t\t\t\t\t\tthis.tab = v;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tlabel: 'Transit views',\n\t\t\t\t\t\t\tidPrefix: 'transits',\n\t\t\t\t\t\t\tcontrols: true,\n\t\t\t\t\t\t})}<div id=\"transits-panel-${tab}\" role=\"tabpanel\" aria-labelledby=\"transits-tab-${tab}\">${\n\t\t\t\t\t\t\t\ttab === 'positions'\n\t\t\t\t\t\t\t\t\t? html`<div class=\"overflow-scroll\">${this.renderPlanetsTable(transitPlanets)}</div>`\n\t\t\t\t\t\t\t\t\t: html`${summary ? this.renderSummaryPills(summary) : nothing}<div class=\"overflow-scroll\">${this.renderAspectsList(transitAspects ?? [])}</div>`\n\t\t\t\t\t\t\t}</div>`\n\t\t\t\t\t: html`<div class=\"overflow-scroll\">${this.renderPlanetsTable(transitPlanets)}</div>`\n\t\t\t}</div>`;\n\t}\n\n\tprivate renderSummaryPills(\n\t\tsummary: NonNullable<TransitsResponse['summary']>,\n\t) {\n\t\treturn html`<div class=\"summary-pills\" role=\"region\" aria-label=\"Aspect summary\"><span class=\"pill pill--muted\">Total: ${summary.totalAspects} </span><span class=\"pill pill--success\">Harmonious: ${summary.harmonious} </span><span class=\"pill pill--danger\">Challenging: ${summary.challenging} </span><span class=\"pill pill--muted\">Neutral: ${summary.neutral}</span></div>`;\n\t}\n\n\tprivate renderPlanetsTable(planets: TransitsResponse['transitPlanets']) {\n\t\treturn html`<table class=\"planets-table\"><thead><tr><th scope=\"col\">Planet</th><th scope=\"col\">Sign</th><th scope=\"col\">Degree</th><th scope=\"col\">Speed</th></tr></thead><tbody>${planets.map((p) => {\n\t\t\t\t\tconst pGlyph = PLANET_GLYPH[capitalize(p.name)] ?? '';\n\t\t\t\t\tconst sGlyph = SIGN_GLYPH[capitalize(p.sign)] ?? '';\n\t\t\t\t\tconst speedArrow = p.speed >= 0 ? '\u2191' : '\u2193';\n\t\t\t\t\treturn html`<tr><td><div class=\"planet-cell\"><span class=\"glyph\" aria-hidden=\"true\">${pGlyph}</span> ${p.name} ${\n\t\t\t\t\t\t\t\t\tp.isRetrograde\n\t\t\t\t\t\t\t\t\t\t? html`<span class=\"retro-badge\" aria-label=\"retrograde\">R</span>`\n\t\t\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t\t\t}</div></td><td><div class=\"planet-cell\"><span class=\"glyph\" aria-hidden=\"true\">${sGlyph}</span> ${p.sign}</div></td><td class=\"num\">${formatNumber(p.degree, 2)}</td><td class=\"speed\"><span class=\"speed-arrow\" aria-hidden=\"true\">${speedArrow}</span> ${formatNumber(Math.abs(p.speed), 4)}</td></tr>`;\n\t\t\t\t})}</tbody></table>`;\n\t}\n\n\tprivate renderAspectsList(\n\t\taspects: NonNullable<TransitsResponse['transitAspects']>,\n\t) {\n\t\treturn html`<div role=\"list\" aria-label=\"Transit aspects\">${aspects.map((a, idx) => {\n\t\t\t\tconst tGlyph = PLANET_GLYPH[capitalize(a.transitPlanet)] ?? '';\n\t\t\t\tconst nGlyph = PLANET_GLYPH[capitalize(a.natalPlanet)] ?? '';\n\t\t\t\tconst nature = (a.nature ?? 'neutral').toLowerCase();\n\t\t\t\tconst interp = a.interpretation;\n\t\t\t\tconst type = (a.type ?? '').toLowerCase();\n\t\t\t\tconst status = a.isApplying ? 'Applying' : 'Separating';\n\t\t\t\treturn html`<details class=\"aspect-card\" role=\"listitem\" name=\"transit-aspects\" ?open=\"${idx === 0}\"><summary><span aria-hidden=\"true\">${tGlyph}</span> ${a.transitPlanet} <span class=\"nature-badge ${nature}\">${type}</span> <span aria-hidden=\"true\">${nGlyph}</span> ${a.natalPlanet} <span class=\"meta\">${status} \u00B7 orb ${formatNumber(a.orb, 2)}\u00B0 \u00B7 strength ${formatNumber(a.strength, 1)} </span>${chevron()}</summary><div class=\"interp-body\">${interp?.summary ? html`<p>${interp.summary}</p>` : nothing} ${interp?.impact ? html`<p><strong>Impact:</strong> ${interp.impact}</p>` : nothing} ${interp?.timing ? html`<p><strong>Timing:</strong> ${interp.timing}</p>` : nothing} ${interp?.guidance ? html`<p><strong>Guidance:</strong> ${interp.guidance}</p>` : nothing} ${\n\t\t\t\t\t\t\tinterp?.keywords?.length\n\t\t\t\t\t\t\t\t? html`<div class=\"interp-keywords\">${interp.keywords.map((k) => html`<span class=\"kw\">${k}</span>`)}</div>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}</div></details>`;\n\t\t\t})}</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-transits-table': RoxyTransitsTable;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport type { CalculateDrishtiResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatNumber } from '../utils/format.js';\n\n/**\n * Vedic graha drishti (planetary aspects) table. Renders /vedic-astrology/aspects: which planet casts an aspect on which, by special Vedic rules (every graha aspects the 7th; Mars the 4th and 8th, Jupiter the 5th and 9th, Saturn the 3rd and 10th). Mutual aspects (two planets aspecting each other) are surfaced first as they are the strongest sambandha. Each row shows the aspecting planet, the aspect kind, the aspected planet, its strength and orb.\n */\n@customElement('roxy-vedic-aspects')\nexport class RoxyVedicAspects extends RoxyDataElement<CalculateDrishtiResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-md,1rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.subtitle{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem);margin:0}.section-label{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;font-weight:var(--roxy-weight-bold,600);margin:0 0 var(--roxy-space-xs,.25rem) 0}.mutual{gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.mutual-pill{border-radius:var(--roxy-radius-full,9999px);background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 14%, transparent);color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);align-items:center;gap:.35rem;padding:2px 10px;display:inline-flex}.mutual-pill .rel{font-size:var(--roxy-text-xs,.75rem);font-weight:400}.overflow-scroll{-webkit-overflow-scrolling:touch;overflow-x:auto}table{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem)}th,td{padding:var(--roxy-space-sm,.5rem);border-bottom:1px solid var(--roxy-border,#e4e4e7);text-align:left;white-space:nowrap}th{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;font-size:var(--roxy-text-xs,.75rem);letter-spacing:.06em}tbody tr:last-child td{border-bottom:none}.kind{border-radius:var(--roxy-radius-full,9999px);background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 55%, transparent);font-size:var(--roxy-text-xs,.75rem);padding:1px 8px;font-weight:600;display:inline-block}.num{font-variant-numeric:tabular-nums;color:var(--roxy-muted,#71717a)}.bar{background:var(--roxy-accent,#f59e0b);vertical-align:middle;border-radius:3px;height:6px;margin-right:6px;display:inline-block}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No aspect data</div>`;\n\t}\n\n\tprotected renderData(d: CalculateDrishtiResponse) {\n\t\tconst aspects = d.aspects ?? [];\n\t\tconst mutual = d.mutualAspects ?? [];\n\t\tif (aspects.length === 0 && mutual.length === 0) return this.renderEmpty();\n\t\tconst date = d.datetime ? String(d.datetime).replace('T', ' ') : '';\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Vedic aspects\"><div class=\"head\"><h2 class=\"title\">Vedic Aspects</h2>${date ? html`<p class=\"subtitle\">${date}</p>` : nothing}</div>${\n\t\t\t\tmutual.length > 0\n\t\t\t\t\t? html`<div><p class=\"section-label\">Mutual aspects</p><div class=\"mutual\">${mutual.map(\n\t\t\t\t\t\t\t\t(m) => html`<span class=\"mutual-pill\">${m.planet1} \u27F7 ${m.planet2} ${m.aspectType ? html`<span class=\"rel\">${m.aspectType}</span>` : nothing}</span>`,\n\t\t\t\t\t\t\t)}</div></div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\taspects.length > 0\n\t\t\t\t\t? html`<div class=\"overflow-scroll\"><table><thead><tr><th scope=\"col\">From</th><th scope=\"col\">Aspect</th><th scope=\"col\">To</th><th scope=\"col\">Strength</th><th scope=\"col\">Orb</th></tr></thead><tbody>${aspects.map(\n\t\t\t\t\t\t\t\t\t(a) => html`<tr><td>${a.aspectingPlanet}</td><td><span class=\"kind\">${a.aspectType}</span></td><td>${a.aspectedPlanet}</td><td>${typeof a.strength === 'number' ? html`<span class=\"bar\" style=\"width:${Math.max(4, Math.min(100, a.strength) * 0.4)}px\"></span><span class=\"num\">${formatNumber(a.strength, 0)}</span>` : nothing}</td><td class=\"num\">${typeof a.orb === 'number' ? `${formatNumber(a.orb, 2)}\u00B0` : ''}</td></tr>`,\n\t\t\t\t\t\t\t\t)}</tbody></table></div>`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-vedic-aspects': RoxyVedicAspects;\n\t}\n}\n", "import { html } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type { BirthChartResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport {\n\ttype ChartStyle,\n\ttype KundliViewModel,\n\trenderKundliStyleTablist,\n\trenderKundliSvg,\n\ttoKundliViewModel,\n} from '../utils/kundli-render.js';\nimport { kundliStyles } from '../utils/kundli-styles.js';\nimport { tablistStyles } from '../utils/tablist.js';\n\n/**\n * Vedic kundli (D1 Rashi chart). Pass `data` from /vedic-astrology/birth-chart.\n * Three regional render styles are available; the visible tablist lets the\n * end user switch between South / North / East at any time. The same planet-\n * in-sign data feeds every style, so the toggle is purely a layout choice.\n *\n * Each planet shows its abbreviation and whole-degree-within-sign, with an\n * SVG tooltip carrying exact position, nakshatra, pada, and avastha. The host\n * page sets the initial style via `chart-style` attribute; from there the\n * user takes over.\n *\n * The ascendant (house 1) defaults to the Janma Lagna carried in the response\n * `meta`. Set `chart-reference=\"moon\"` to render the Chandra Lagna (Moon as\n * ascendant) from the same response, or `lagna-override=\"<rashi>\"` to pin the\n * reference to any sign (Surya Lagna, Arudha Lagna, a custom point). The same\n * planet-in-sign data feeds every reference; only the house numbering rotates.\n *\n * Theming flows through CSS custom properties on `:host`, so the chart\n * adopts the host page palette without runtime color probing.\n */\n@customElement('roxy-vedic-kundli')\nexport class RoxyVedicKundli extends RoxyDataElement<BirthChartResponse> {\n\tstatic styles = [baseStyles, kundliStyles, tablistStyles];\n\n\t@property({ type: String, reflect: true, attribute: 'chart-style' })\n\tchartStyle: ChartStyle = 'north';\n\n\t/**\n\t * Ascendant reference point. `'lagna'` (default) uses the Janma Lagna from the response; `'moon'` renders the Chandra Lagna (Moon sign as house 1) from the same response. An explicit {@link lagnaOverride} wins over this.\n\t */\n\t@property({ type: String, reflect: true, attribute: 'chart-reference' })\n\tchartReference: 'lagna' | 'moon' = 'lagna';\n\n\t/**\n\t * Explicit rashi/sign name (case-insensitive, e.g. `\"cancer\"`) to use as the ascendant, overriding both the Janma Lagna and {@link chartReference}. Empty by default (standard Janma Lagna). Use for Surya Lagna, Arudha Lagna, or any custom reference chart.\n\t */\n\t@property({ type: String, reflect: true, attribute: 'lagna-override' })\n\tlagnaOverride = '';\n\n\t/**\n\t * Resolve the ascendant override fed to {@link toKundliViewModel}. An explicit `lagna-override` wins; otherwise `chart-reference=\"moon\"` derives the Moon rashi from the response `meta`. Returns `undefined` for the default Janma Lagna path.\n\t */\n\tprivate resolveReference(): string | undefined {\n\t\tif (this.lagnaOverride) return this.lagnaOverride;\n\t\tif (this.chartReference === 'moon') return this.data?.meta?.Moon?.rashi;\n\t\treturn undefined;\n\t}\n\n\tprivate viewModel(): KundliViewModel | null {\n\t\tif (!this.data?.meta) return null;\n\t\treturn toKundliViewModel(\n\t\t\tthis.data.meta,\n\t\t\t'D1 Rashi',\n\t\t\tthis.resolveReference(),\n\t\t);\n\t}\n\n\tprivate setStyle = (next: ChartStyle) => {\n\t\tthis.chartStyle = next;\n\t};\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No kundli data</div>`;\n\t}\n\n\tprotected renderData(_d: BirthChartResponse) {\n\t\tconst vm = this.viewModel();\n\t\tif (!vm) return this.renderEmpty();\n\t\tconst title =\n\t\t\tthis.chartReference === 'moon' && !this.lagnaOverride\n\t\t\t\t? 'Chandra lagna'\n\t\t\t\t: 'Vedic kundli';\n\t\treturn html`<div class=\"wrap\"><div class=\"header\"><h2 class=\"title\">${title}</h2>${renderKundliStyleTablist(this.chartStyle, this.setStyle)}</div><svg viewBox=\"0 0 400 400\" preserveAspectRatio=\"xMidYMid meet\" role=\"img\" aria-label=\"Vedic birth chart with twelve sign houses\"><title>Vedic kundli</title>${renderKundliSvg(vm, this.chartStyle)}</svg></div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-vedic-kundli': RoxyVedicKundli;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { PLANET_GLYPH, SIGN_GLYPH } from '../tokens/index.js';\nimport type { BirthChartResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatSignPosition } from '../utils/degree.js';\nimport { chevron, disclosureStyles } from '../utils/disclosure.js';\nimport { formatNumber } from '../utils/format.js';\nimport { capitalize } from '../utils/string.js';\n\n/**\n * Fixed display order: Lagna pinned first as the chart frame, then the nine\n * grahas in classical sequence. Any graha not in this list is appended.\n */\nconst GRAHA_ORDER = [\n\t'Lagna',\n\t'Sun',\n\t'Moon',\n\t'Mars',\n\t'Mercury',\n\t'Jupiter',\n\t'Venus',\n\t'Saturn',\n\t'Rahu',\n\t'Ketu',\n];\n\ntype MetaEntry = BirthChartResponse['meta'][string];\n\n/**\n * Vedic planetary positions table. Renders /vedic-astrology/birth-chart `meta`\n * as the full reference-grade positions grid a practitioner reads alongside\n * the kundli wheel: graha, rashi, exact degree, nakshatra and pada, nakshatra\n * lord, bhava (house), Baladi avastha, and retrograde.\n *\n * @remarks\n * The positions grid is the default view. The same birth-chart response also\n * carries chart-wide conditions and readings, surfaced as collapsed accordions\n * below the grid so they never crowd the table: combust grahas (astangata),\n * planetary wars (graha yuddha), per-graha rashi and nakshatra interpretations,\n * the active classical yogas (present === true), and the twelve bhava\n * significations. Each accordion renders only when its source array or map is\n * non-empty.\n */\n@customElement('roxy-vedic-planets-table')\nexport class RoxyVedicPlanetsTable extends RoxyDataElement<BirthChartResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tdisclosureStyles,\n\t\tcss`.wrap{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);background:var(--roxy-surface,#fff);box-shadow:var(--roxy-shadow-sm);overflow:hidden}.head{padding:var(--roxy-space-md,1rem);border-bottom:1px solid var(--roxy-border,#e4e4e7)}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.scroll{overflow-x:auto}table{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem);min-width:620px}thead{background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 20%, transparent)}th,td{padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);text-align:left;white-space:nowrap}th{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;font-size:var(--roxy-text-xs,.75rem);letter-spacing:.04em}tbody tr{border-top:1px solid var(--roxy-border,#e4e4e7)}tbody tr.lagna{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 10%, transparent)}td.graha{font-weight:var(--roxy-weight-bold,600);color:var(--roxy-fg,#0a0a0a)}.glyph{color:var(--roxy-muted,#71717a);margin-right:.4em}tbody tr.lagna .glyph{color:var(--roxy-accent-ink,#b45309)}.retro{color:var(--roxy-warning-fg,#9a3412);font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600)}.num{font-variant-numeric:tabular-nums}details.panel{border-top:1px solid var(--roxy-border,#e4e4e7)}details.panel>summary{justify-content:space-between;align-items:center;gap:var(--roxy-space-sm,.5rem);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);cursor:pointer;font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-fg,#0a0a0a);display:flex}details.panel>summary:focus-visible{outline:2px solid var(--roxy-ring,#f59e0b66);outline-offset:-2px}.summary-count{margin-left:auto;margin-right:var(--roxy-space-xs,.25rem);font-weight:var(--roxy-weight-normal,400);color:var(--roxy-muted,#71717a);font-variant-numeric:tabular-nums}.panel-body{padding:0 var(--roxy-space-md,1rem) var(--roxy-space-md,1rem);gap:var(--roxy-space-sm,.5rem);display:grid}.condition{font-size:var(--roxy-text-sm,.875rem);flex-wrap:wrap;align-items:baseline;gap:.4em;display:flex}.condition .planet{font-weight:var(--roxy-weight-bold,600)}.condition .detail{color:var(--roxy-muted,#71717a);font-variant-numeric:tabular-nums}.condition .winner{color:var(--roxy-success-fg,#166534);font-weight:var(--roxy-weight-bold,600)}.interp{gap:.15em;display:grid}.interp .planet{font-weight:var(--roxy-weight-bold,600);font-size:var(--roxy-text-sm,.875rem)}.interp p{font-size:var(--roxy-text-sm,.875rem);line-height:var(--roxy-leading-normal,1.5);margin:0}.interp .label{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600)}.bhava{gap:.15em;display:grid}.bhava .name{font-weight:var(--roxy-weight-bold,600);font-size:var(--roxy-text-sm,.875rem)}.bhava .desc{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-muted,#71717a);line-height:var(--roxy-leading-normal,1.5);margin:0}.quality{font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;letter-spacing:.04em}.quality.positive{color:var(--roxy-success-fg,#166534)}.quality.negative{color:var(--roxy-danger-fg,#991b1b)}.quality.both{color:var(--roxy-muted,#71717a)}`,\n\t];\n\n\t/** Ordered [name, entry] pairs: GRAHA_ORDER first, then any extras. */\n\tprivate orderedRows(): Array<[string, MetaEntry]> {\n\t\tconst meta = this.data?.meta ?? {};\n\t\tconst seen = new Set<string>();\n\t\tconst rows: Array<[string, MetaEntry]> = [];\n\t\tfor (const name of GRAHA_ORDER) {\n\t\t\tconst entry = meta[name];\n\t\t\tif (entry) {\n\t\t\t\trows.push([name, entry]);\n\t\t\t\tseen.add(name);\n\t\t\t}\n\t\t}\n\t\tfor (const [name, entry] of Object.entries(meta)) {\n\t\t\tif (!seen.has(name)) rows.push([name, entry]);\n\t\t}\n\t\treturn rows;\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No chart data</div>`;\n\t}\n\n\tprotected renderData(d: BirthChartResponse) {\n\t\tif (!d.meta) return this.renderEmpty();\n\t\tconst rows = this.orderedRows();\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Vedic planetary positions\"><header class=\"head\"><h2 class=\"title\">Planetary positions</h2></header><div class=\"scroll\" tabindex=\"0\"><table role=\"table\"><thead><tr><th scope=\"col\">Graha</th><th scope=\"col\">Rashi</th><th scope=\"col\">Degree</th><th scope=\"col\">Nakshatra</th><th scope=\"col\">Pada</th><th scope=\"col\">Nak. lord</th><th scope=\"col\">House</th><th scope=\"col\">Avastha</th><th scope=\"col\">Retro</th></tr></thead><tbody>${rows.map(([name, p]) => {\n\t\t\t\t\t\tconst isLagna = (p.graha ?? name) === 'Lagna';\n\t\t\t\t\t\tconst glyph = PLANET_GLYPH[capitalize(p.graha ?? name)] ?? '';\n\t\t\t\t\t\tconst signGlyph = SIGN_GLYPH[capitalize(p.rashi ?? '')] ?? '';\n\t\t\t\t\t\treturn html`<tr class=\"${isLagna ? 'lagna' : ''}\"><td class=\"graha\">${glyph ? html`<span class=\"glyph\">${glyph}</span>` : nothing}${p.graha ?? name}</td><td>${signGlyph ? html`<span class=\"glyph\">${signGlyph}</span>` : nothing}${p.rashi ?? ''}</td><td class=\"num\">${typeof p.longitude === 'number' ? formatSignPosition(p.longitude) : ''}</td><td>${p.nakshatra?.name ?? ''}</td><td class=\"num\">${p.nakshatra?.pada ?? ''}</td><td>${p.nakshatra?.lord ?? ''}</td><td class=\"num\">${typeof p.house === 'number' ? p.house : ''}</td><td>${p.awastha ?? ''}</td><td>${p.isRetrograde ? html`<span class=\"retro\">R</span>` : nothing}</td></tr>`;\n\t\t\t\t\t})}</tbody></table></div>${this.renderCombustion()} ${this.renderPlanetaryWar()} ${this.renderInterpretations()} ${this.renderYogas()} ${this.renderHouses()}</div>`;\n\t}\n\n\tprivate renderCombustion() {\n\t\tconst combust = this.data?.combustion ?? [];\n\t\tif (combust.length === 0) return nothing;\n\t\treturn html`<details class=\"panel\"><summary>Combust grahas<span class=\"summary-count\">${combust.length}</span>${chevron()}</summary><div class=\"panel-body\">${combust.map((c) => {\n\t\t\t\t\tconst glyph = PLANET_GLYPH[capitalize(c.planet)] ?? '';\n\t\t\t\t\tconst dist = formatNumber(c.distanceFromSun, 2);\n\t\t\t\t\tconst orb = formatNumber(c.orb, 1);\n\t\t\t\t\treturn html`<div class=\"condition\"><span class=\"planet\">${glyph ? `${glyph} ` : ''}${c.planet}</span> <span class=\"detail\">${dist} deg from Sun, within ${orb} deg orb</span></div>`;\n\t\t\t\t})}</div></details>`;\n\t}\n\n\tprivate renderPlanetaryWar() {\n\t\tconst wars = this.data?.planetaryWar ?? [];\n\t\tif (wars.length === 0) return nothing;\n\t\treturn html`<details class=\"panel\"><summary>Planetary wars<span class=\"summary-count\">${wars.length}</span>${chevron()}</summary><div class=\"panel-body\">${wars.map((w) => {\n\t\t\t\t\tconst dist = formatNumber(w.distance, 2);\n\t\t\t\t\treturn html`<div class=\"condition\"><span class=\"planet\">${w.planet1} vs ${w.planet2}</span> <span class=\"detail\">${dist} deg apart</span> <span class=\"winner\">${w.winner} wins</span></div>`;\n\t\t\t\t})}</div></details>`;\n\t}\n\n\tprivate renderInterpretations() {\n\t\tconst interp = this.data?.interpretations ?? {};\n\t\tconst entries = this.orderedRows()\n\t\t\t.map(([name, p]) => [p.graha ?? name, interp[p.graha ?? name]] as const)\n\t\t\t.filter(([, v]) => v != null);\n\t\tif (entries.length === 0) return nothing;\n\t\treturn html`<details class=\"panel\"><summary>Interpretations<span class=\"summary-count\">${entries.length}</span>${chevron()}</summary><div class=\"panel-body\">${entries.map(([name, v]) => {\n\t\t\t\t\tconst glyph = PLANET_GLYPH[capitalize(name)] ?? '';\n\t\t\t\t\treturn html`<div class=\"interp\"><span class=\"planet\">${glyph ? `${glyph} ` : ''}${name}</span> ${v.rashi ? html`<p><span class=\"label\">Rashi.</span> ${v.rashi}</p>` : nothing} ${v.nakshatra ? html`<p><span class=\"label\">Nakshatra.</span> ${v.nakshatra}</p>` : nothing}</div>`;\n\t\t\t\t})}</div></details>`;\n\t}\n\n\tprivate renderHouses() {\n\t\tconst houses = (this.data?.houses ?? []).filter(\n\t\t\t(h) => h.name || h.description,\n\t\t);\n\t\tif (houses.length === 0) return nothing;\n\t\treturn html`<details class=\"panel\"><summary>Bhava significations<span class=\"summary-count\">${houses.length}</span>${chevron()}</summary><div class=\"panel-body\">${houses.map(\n\t\t\t\t\t(h) => html`<div class=\"bhava\"><span class=\"name\">${h.number}. ${h.name ?? ''}</span> ${h.description ? html`<p class=\"desc\">${h.description}</p>` : nothing}</div>`,\n\t\t\t\t)}</div></details>`;\n\t}\n\n\tprivate renderYogas() {\n\t\tconst yogas = (this.data?.yogas ?? []).filter((y) => y.present);\n\t\tif (yogas.length === 0) return nothing;\n\t\treturn html`<details class=\"panel\"><summary>Yogas<span class=\"summary-count\">${yogas.length}</span>${chevron()}</summary><div class=\"panel-body\">${yogas.map(\n\t\t\t\t\t(y) => html`<div class=\"bhava\"><span class=\"name\">${y.name} ${y.quality ? html`<span class=\"quality ${y.quality.toLowerCase()}\">${y.quality}</span>` : nothing}</span> ${y.result ? html`<p class=\"desc\">${y.result}</p>` : nothing}</div>`,\n\t\t\t\t)}</div></details>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-vedic-planets-table': RoxyVedicPlanetsTable;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { PLANET_GLYPH, SIGN_GLYPH } from '../tokens/index.js';\nimport type { NatalChartResponse } from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatSignPosition } from '../utils/degree.js';\nimport { formatNumber } from '../utils/format.js';\nimport { capitalize } from '../utils/string.js';\n\n/** A body or point row, normalized so planets and the four angles share a table. */\ninterface BodyRow {\n\tname: string;\n\tsign?: string;\n\tlongitude?: number;\n\thouse?: number;\n\tspeed?: number;\n\tisRetrograde?: boolean;\n\t/** True for the chart angles (ASC, MC, Part of Fortune, Vertex). */\n\tisPoint?: boolean;\n}\n\n/**\n * Western planetary positions table. Renders a /astrology/natal-chart response\n * as the reference-grade positions grid astrologers read alongside the wheel:\n * every body with its sign, exact degree, house, and daily motion, followed by\n * the four chart points (Ascendant, Midheaven, Part of Fortune, Vertex).\n */\n@customElement('roxy-western-planets-table')\nexport class RoxyWesternPlanetsTable extends RoxyDataElement<NatalChartResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);background:var(--roxy-surface,#fff);box-shadow:var(--roxy-shadow-sm);overflow:auto}.head{padding:var(--roxy-space-md,1rem);border-bottom:1px solid var(--roxy-border,#e4e4e7)}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}table{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem);min-width:460px}thead{background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 20%, transparent)}th,td{padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);text-align:left;white-space:nowrap}th{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;font-size:var(--roxy-text-xs,.75rem);letter-spacing:.04em}tbody tr{border-top:1px solid var(--roxy-border,#e4e4e7)}tbody tr.point{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 8%, transparent)}td.body{font-weight:var(--roxy-weight-bold,600);color:var(--roxy-fg,#0a0a0a)}.glyph{color:var(--roxy-muted,#71717a);margin-right:.4em}.retro{color:var(--roxy-danger,#dc2626);font-weight:var(--roxy-weight-bold,600)}.num{font-variant-numeric:tabular-nums}`,\n\t];\n\n\t/** Build the ordered row list: the planets array, then the four chart points. */\n\tprivate rows(): BodyRow[] {\n\t\tconst d = this.data;\n\t\tif (!d) return [];\n\t\tconst rows: BodyRow[] = (d.planets ?? []).map((p) => ({\n\t\t\tname: p.name,\n\t\t\tsign: p.sign,\n\t\t\tlongitude: p.longitude,\n\t\t\thouse: p.house,\n\t\t\tspeed: p.speed,\n\t\t\tisRetrograde: p.isRetrograde,\n\t\t}));\n\t\tfor (const [name, point] of [\n\t\t\t['Ascendant', d.ascendant],\n\t\t\t['Midheaven', d.midheaven],\n\t\t\t['Part of Fortune', d.partOfFortune],\n\t\t\t['Vertex', d.vertex],\n\t\t] as const) {\n\t\t\tif (point) {\n\t\t\t\trows.push({\n\t\t\t\t\tname,\n\t\t\t\t\tsign: point.sign,\n\t\t\t\t\tlongitude: point.longitude,\n\t\t\t\t\tisPoint: true,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn rows;\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No chart data</div>`;\n\t}\n\n\tprotected renderData(d: NatalChartResponse) {\n\t\tif (!d.planets) return this.renderEmpty();\n\t\tconst rows = this.rows();\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Western planetary positions\" tabindex=\"0\"><header class=\"head\"><h2 class=\"title\">Planetary positions</h2></header><table role=\"table\"><thead><tr><th scope=\"col\">Body</th><th scope=\"col\">Sign</th><th scope=\"col\">Degree</th><th scope=\"col\">House</th><th scope=\"col\">Motion</th></tr></thead><tbody>${rows.map((r) => {\n\t\t\t\t\t\tconst glyph = PLANET_GLYPH[capitalize(r.name)] ?? '';\n\t\t\t\t\t\tconst signGlyph = SIGN_GLYPH[capitalize(r.sign ?? '')] ?? '';\n\t\t\t\t\t\tconst speed =\n\t\t\t\t\t\t\ttypeof r.speed === 'number' ? formatNumber(r.speed, 3) : '';\n\t\t\t\t\t\treturn html`<tr class=\"${r.isPoint ? 'point' : ''}\"><td class=\"body\">${glyph ? html`<span class=\"glyph\">${glyph}</span>` : nothing}${r.name}</td><td>${signGlyph ? html`<span class=\"glyph\">${signGlyph}</span>` : nothing}${r.sign ?? ''}</td><td class=\"num\">${typeof r.longitude === 'number' ? formatSignPosition(r.longitude) : ''}</td><td class=\"num\">${typeof r.house === 'number' ? r.house : ''}</td><td class=\"num\">${speed ? html`${speed}\u00B0/day` : nothing} ${r.isRetrograde ? html`<span class=\"retro\">\u211E</span>` : nothing}</td></tr>`;\n\t\t\t\t\t})}</tbody></table></div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-western-planets-table': RoxyWesternPlanetsTable;\n\t}\n}\n", "import { css, html, nothing } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\nimport type {\n\tDetectYogasResponse,\n\tGetYogaResponse,\n\tListYogasResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\ntype YogaListData =\n\t| ListYogasResponse\n\t| GetYogaResponse\n\t| DetectYogasResponse\n\t| { yogas: Array<GetYogaResponse> };\n\n/**\n * Yoga catalog and detail renderer. Accepts four data modes:\n * - Catalog: ListYogasResponse (yogas array of {id, name} + total)\n * - Detail: GetYogaResponse (single yoga with description, result, quality)\n * - Detail array: { yogas: Array<GetYogaResponse> } for pre-filtered sets\n * - Detect: DetectYogasResponse (each yoga carries a present verdict + evidence); present yogas render first, each badged present/absent with its classical evidence\n *\n * All multi-item modes include a live search filter.\n */\n@customElement('roxy-yoga-list')\nexport class RoxyYogaList extends RoxyDataElement<YogaListData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`.wrap{gap:var(--roxy-space-md,1rem);display:grid}.head{justify-content:space-between;align-items:baseline;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.count{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-muted,#71717a)}.search-wrap{align-items:center;gap:var(--roxy-space-sm,.5rem);display:flex}.search{width:100%;max-width:280px;font-size:var(--roxy-text-sm,.875rem);font-family:var(--roxy-font-sans);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);outline:none;padding:.35em .75em}.search::placeholder{color:var(--roxy-fg,#0a0a0a);opacity:.65}.search:focus{border-color:var(--roxy-accent,#f59e0b);box-shadow:0 0 0 2px color-mix(in srgb, var(--roxy-accent,#f59e0b) 30%, transparent)}.grid{gap:var(--roxy-space-sm,.5rem);grid-template-columns:repeat(auto-fill,minmax(180px,1fr));display:grid}.yoga-chip{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);font-size:var(--roxy-text-sm,.875rem);background:var(--roxy-surface,#fff);color:var(--roxy-fg,#0a0a0a);word-break:break-word;padding:.4em .8em}.yoga-chip .yoga-id{color:var(--roxy-fg,#0a0a0a);opacity:.75;margin-top:.15em;font-size:.7em;display:block}.detail-card{border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-md,1rem);background:var(--roxy-surface,#fff);gap:var(--roxy-space-sm,.5rem);display:grid}.detail-name{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);align-items:center;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;margin:0;display:flex}.quality-chip{font-size:var(--roxy-text-xs,.75rem);border-radius:999px;padding:.15em .6em;font-weight:600;display:inline-block}.quality-Positive{background:color-mix(in srgb, var(--roxy-success,#22c55e) 18%, transparent);color:var(--roxy-success-fg,#15803d);border:1px solid color-mix(in srgb, var(--roxy-success,#22c55e) 40%, transparent)}.quality-Negative{background:color-mix(in srgb, var(--roxy-danger,#ef4444) 18%, transparent);color:var(--roxy-danger-fg,#b91c1c);border:1px solid color-mix(in srgb, var(--roxy-danger,#ef4444) 40%, transparent)}.quality-Both{background:color-mix(in srgb, var(--roxy-warning,#f59e0b) 18%, transparent);color:var(--roxy-warning-fg,#b45309);border:1px solid color-mix(in srgb, var(--roxy-warning,#f59e0b) 40%, transparent)}.present-badge{font-size:var(--roxy-text-xs,.75rem);border-radius:999px;padding:.15em .6em;font-weight:600;display:inline-block}.present-badge.is-present{background:color-mix(in srgb, var(--roxy-success,#16a34a) 16%, transparent);color:var(--roxy-success-fg,#166534)}.present-badge.is-absent{background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 55%, transparent);color:var(--roxy-fg,#0a0a0a)}.detail-card.absent{opacity:.72}.evidence{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);line-height:var(--roxy-leading-normal,1.5);margin:0}.description{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-muted,#71717a);line-height:var(--roxy-leading-normal,1.5);margin:0}details{font-size:var(--roxy-text-sm,.875rem)}details summary{cursor:pointer;color:var(--roxy-accent-ink,#b45309);align-items:center;gap:.4em;padding:.25em 0;font-weight:500;list-style:none;display:flex}details summary:before{content:\"+\";font-size:1.1em;line-height:1}details[open] summary:before{content:\"-\"}details .result-body{padding-top:var(--roxy-space-xs,.25rem);color:var(--roxy-fg,#0a0a0a);line-height:var(--roxy-leading-normal,1.5)}.no-results{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem);padding:var(--roxy-space-md,1rem) 0;text-align:center}.detail-grid{gap:var(--roxy-space-sm,.5rem);display:grid}`,\n\t];\n\n\t@state()\n\tprivate filter = '';\n\n\tprivate readonly handleInput = (e: Event) => {\n\t\tthis.filter = (e.target as HTMLInputElement).value;\n\t};\n\n\tprivate renderQualityChip(quality: string) {\n\t\tconst cls = `quality-chip quality-${quality}`;\n\t\treturn html`<span class=\"${cls}\">${quality}</span>`;\n\t}\n\n\tprivate renderDetailCard(yoga: GetYogaResponse) {\n\t\treturn html`<div class=\"detail-card\"><p class=\"detail-name\">${yoga.name} ${yoga.quality ? this.renderQualityChip(yoga.quality) : nothing}</p>${\n\t\t\t\tyoga.description\n\t\t\t\t\t? html`<p class=\"description\">${yoga.description}</p>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tyoga.result\n\t\t\t\t\t? html`<details><summary>Effects</summary><div class=\"result-body\">${yoga.result}</div></details>`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n\n\t/** Detect-mode card: shows the present/absent verdict and the classical evidence that triggered or failed it. */\n\tprivate renderDetectCard(y: DetectYogasResponse['yogas'][number]) {\n\t\treturn html`<div class=\"detail-card ${y.present ? '' : 'absent'}\"><p class=\"detail-name\">${y.name} ${y.quality ? this.renderQualityChip(y.quality) : nothing} <span class=\"present-badge ${y.present ? 'is-present' : 'is-absent'}\">${y.present ? 'Present' : 'Not present'}</span></p>${y.description ? html`<p class=\"description\">${y.description}</p>` : nothing} ${\n\t\t\t\ty.present && y.result\n\t\t\t\t\t? html`<details><summary>Effects</summary><div class=\"result-body\">${y.result}</div></details>`\n\t\t\t\t\t: nothing\n\t\t\t} ${y.evidence ? html`<p class=\"evidence\">${y.evidence}</p>` : nothing}</div>`;\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No yoga data</div>`;\n\t}\n\n\tprotected renderData(d: YogaListData) {\n\t\tconst lc = this.filter.toLowerCase();\n\n\t\t// Detail mode: single GetYogaResponse\n\t\tif (\n\t\t\t'description' in d &&\n\t\t\ttypeof (d as GetYogaResponse).description === 'string'\n\t\t) {\n\t\t\tconst yoga = d as GetYogaResponse;\n\t\t\treturn html`<div class=\"wrap\">${this.renderDetailCard(yoga)}</div>`;\n\t\t}\n\n\t\t// Detail-array mode: { yogas: Array<GetYogaResponse> } where items have description\n\t\tif ('yogas' in d && Array.isArray((d as { yogas: unknown[] }).yogas)) {\n\t\t\tconst allYogas = (\n\t\t\t\td as { yogas: Array<GetYogaResponse | { id: string; name: string }> }\n\t\t\t).yogas;\n\n\t\t\t// Detect mode: every entry carries a `present` verdict. Render present\n\t\t\t// yogas first, mark each present/absent, and surface the classical\n\t\t\t// evidence. Must precede the detail-array check because detect entries\n\t\t\t// also carry `description`.\n\t\t\tif (allYogas.length > 0 && 'present' in allYogas[0]) {\n\t\t\t\tconst detected = allYogas as DetectYogasResponse['yogas'];\n\t\t\t\tconst filtered = lc\n\t\t\t\t\t? detected.filter((y) => y.name.toLowerCase().includes(lc))\n\t\t\t\t\t: detected;\n\t\t\t\tconst ordered = [\n\t\t\t\t\t...filtered.filter((y) => y.present),\n\t\t\t\t\t...filtered.filter((y) => !y.present),\n\t\t\t\t];\n\t\t\t\tconst presentCount =\n\t\t\t\t\t(d as DetectYogasResponse).total ??\n\t\t\t\t\tdetected.filter((y) => y.present).length;\n\t\t\t\treturn html`<div class=\"wrap\"><div class=\"head\"><h2 class=\"title\">Detected yogas</h2><span class=\"count\">${presentCount} of ${detected.length} present</span></div><div class=\"search-wrap\"><input class=\"search\" type=\"search\" placeholder=\"Filter yogas...\" aria-label=\"Filter detected yogas by name\" .value=\"${this.filter}\" @input=\"${this.handleInput}\"></div><div class=\"detail-grid\" role=\"region\" aria-live=\"polite\" aria-label=\"Detected yogas\">${\n\t\t\t\t\t\t\tordered.length > 0\n\t\t\t\t\t\t\t\t? ordered.map((y) => this.renderDetectCard(y))\n\t\t\t\t\t\t\t\t: html`<p class=\"no-results\">No yogas match your search.</p>`\n\t\t\t\t\t\t}</div></div>`;\n\t\t\t}\n\n\t\t\tconst isDetailArray = allYogas.length > 0 && 'description' in allYogas[0];\n\n\t\t\tif (isDetailArray) {\n\t\t\t\tconst detailYogas = allYogas as GetYogaResponse[];\n\t\t\t\tconst filtered = lc\n\t\t\t\t\t? detailYogas.filter((y) => y.name.toLowerCase().includes(lc))\n\t\t\t\t\t: detailYogas;\n\t\t\t\tconst total = (d as ListYogasResponse).total;\n\t\t\t\treturn html`<div class=\"wrap\"><div class=\"head\"><h2 class=\"title\">Yoga catalog</h2>${\n\t\t\t\t\t\t\ttotal !== undefined\n\t\t\t\t\t\t\t\t? html`<span class=\"count\">${total} total</span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}</div><div class=\"search-wrap\"><input class=\"search\" type=\"search\" placeholder=\"Filter yogas...\" aria-label=\"Filter yoga list by name\" .value=\"${this.filter}\" @input=\"${this.handleInput}\"></div><div class=\"detail-grid\" role=\"region\" aria-live=\"polite\" aria-label=\"Yoga results\">${\n\t\t\t\t\t\t\tfiltered.length > 0\n\t\t\t\t\t\t\t\t? filtered.map((y) => this.renderDetailCard(y))\n\t\t\t\t\t\t\t\t: html`<p class=\"no-results\">No yogas match your search.</p>`\n\t\t\t\t\t\t}</div></div>`;\n\t\t\t}\n\n\t\t\t// Catalog mode: ListYogasResponse with {id, name} items\n\t\t\tconst catalogYogas = allYogas as Array<{ id: string; name: string }>;\n\t\t\tconst filtered = lc\n\t\t\t\t? catalogYogas.filter((y) => y.name.toLowerCase().includes(lc))\n\t\t\t\t: catalogYogas;\n\t\t\tconst total = (d as ListYogasResponse).total;\n\t\t\treturn html`<div class=\"wrap\"><div class=\"head\"><h2 class=\"title\">Yoga catalog</h2>${\n\t\t\t\t\t\ttotal !== undefined\n\t\t\t\t\t\t\t? html`<span class=\"count\">${total} total</span>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}</div><div class=\"search-wrap\"><input class=\"search\" type=\"search\" placeholder=\"Filter yogas...\" aria-label=\"Filter yoga list by name\" .value=\"${this.filter}\" @input=\"${this.handleInput}\"></div><div class=\"grid\" role=\"region\" aria-live=\"polite\" aria-label=\"Yoga results\">${\n\t\t\t\t\t\tfiltered.length > 0\n\t\t\t\t\t\t\t? filtered.map(\n\t\t\t\t\t\t\t\t\t(y) => html`<div class=\"yoga-chip\">${y.name} <span class=\"yoga-id\">${y.id}</span></div>`,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t: html`<p class=\"no-results\">No yogas match your search.</p>`\n\t\t\t\t\t}</div></div>`;\n\t\t}\n\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No yoga data</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-yoga-list': RoxyYogaList;\n\t}\n}\n", "/**\n * Single source of truth for component metadata. Every consumer that needs\n * the (tag, pascal, slug, description, heading) tuple reads from here:\n * scripts/build-react.ts, scripts/build-registry.ts, scripts/sync-docs.ts,\n * scripts/build-widgets.ts, and the browser-side apps/docs/manifest.js\n * (mirrored at build time).\n *\n * Hand-maintained. Add a component \u2192 add one entry here. The OpenAPI spec\n * does not yet carry component metadata, so this stays manual.\n */\n\nexport interface RoxyComponent {\n\t/** Pascal-case React export name, e.g. RoxyNatalChart */\n\tpascal: string;\n\t/** Custom-element tag, e.g. roxy-natal-chart */\n\ttag: string;\n\t/** Slug used in registry filenames and shadcn paths, e.g. natal-chart */\n\tslug: string;\n\t/** Short human-readable heading shown on demo cards. */\n\theading: string;\n\t/** One-line description for registry / docs / SEO meta. */\n\tdescription: string;\n\t/** Domain column label in the synced README/AGENTS table. */\n\tdocsLabel: string;\n\t/** Endpoint(s) column body in the synced README/AGENTS table. */\n\tendpointLabel: string;\n\t/** What-it-renders column body in the synced README/AGENTS table. */\n\tdocsSummary: string;\n\t/** Filter category in the browser demo grid. */\n\ttopic: string;\n\t/**\n\t * True when the component does not consume a typed RoxyAPI response from a\n\t * customer server route. Three cases today:\n\t * - <roxy-data>: pure renderer, accepts any shape, no fetch.\n\t * - <roxy-location-search>: calls /location/search itself via publishable key.\n\t * - <roxy-endpoint-form>: introspects the OpenAPI spec, emits roxy-submit.\n\t * The shadcn registry codegen emits a different doc body for these so we\n\t * never document a server route example with an undefined `data` reference.\n\t */\n\tselfFetching?: boolean;\n}\n\nexport const ROXY_COMPONENTS: readonly RoxyComponent[] = [\n\t{\n\t\tpascal: 'RoxyNatalChart',\n\t\ttag: 'roxy-natal-chart',\n\t\tslug: 'natal-chart',\n\t\theading: 'Natal chart',\n\t\tdescription:\n\t\t\t'Western natal chart wheel for /astrology/natal-chart responses',\n\t\tdocsLabel: 'Western',\n\t\tendpointLabel: 'POST /astrology/natal-chart',\n\t\tdocsSummary: 'Natal chart wheel with planet glyphs and aspect lines',\n\t\ttopic: 'Astrology',\n\t},\n\t{\n\t\tpascal: 'RoxySynastryChart',\n\t\ttag: 'roxy-synastry-chart',\n\t\tslug: 'synastry-chart',\n\t\theading: 'Synastry',\n\t\tdescription: 'Dual-wheel synastry chart with inter-aspects table',\n\t\tdocsLabel: 'Western',\n\t\tendpointLabel: 'POST /astrology/synastry',\n\t\tdocsSummary: 'Dual-wheel synastry with inter-aspects table',\n\t\ttopic: 'Astrology',\n\t},\n\t{\n\t\tpascal: 'RoxyWesternPlanetsTable',\n\t\ttag: 'roxy-western-planets-table',\n\t\tslug: 'western-planets-table',\n\t\theading: 'Western planets',\n\t\tdescription:\n\t\t\t'Western planetary positions table with sign, degree, house, and motion plus the chart angles',\n\t\tdocsLabel: 'Western',\n\t\tendpointLabel: 'POST /astrology/natal-chart',\n\t\tdocsSummary:\n\t\t\t'Sign, degree, house, motion columns plus ASC, MC, PoF, Vertex',\n\t\ttopic: 'Astrology',\n\t},\n\t{\n\t\tpascal: 'RoxyTransitsTable',\n\t\ttag: 'roxy-transits-table',\n\t\tslug: 'transits-table',\n\t\theading: 'Transits',\n\t\tdescription: 'Live planet positions plus aspects to a natal chart',\n\t\tdocsLabel: 'Western',\n\t\tendpointLabel: 'POST /astrology/transits',\n\t\tdocsSummary:\n\t\t\t'Transit planet positions plus optional aspects to a natal chart',\n\t\ttopic: 'Astrology',\n\t},\n\t{\n\t\tpascal: 'RoxyAspectsTable',\n\t\ttag: 'roxy-aspects-table',\n\t\tslug: 'aspects-table',\n\t\theading: 'Aspects',\n\t\tdescription:\n\t\t\t'Natal and transit aspect grid with chart-pattern detection (grand trines, t-squares, stelliums, yods)',\n\t\tdocsLabel: 'Western',\n\t\tendpointLabel:\n\t\t\t'POST /astrology/aspects, /astrology/transit-aspects, /astrology/aspect-patterns',\n\t\tdocsSummary:\n\t\t\t'Aspect rows coloured by nature with orb and strength, plus detected chart patterns',\n\t\ttopic: 'Astrology',\n\t},\n\t{\n\t\tpascal: 'RoxyMoonPhase',\n\t\ttag: 'roxy-moon-phase',\n\t\tslug: 'moon-phase',\n\t\theading: 'Moon phase',\n\t\tdescription: 'Moon phase card and calendar',\n\t\tdocsLabel: 'Western',\n\t\tendpointLabel: 'GET /astrology/moon-phase/{current,upcoming,calendar/...}',\n\t\tdocsSummary: 'Moon phase card and calendar',\n\t\ttopic: 'Astrology',\n\t},\n\t{\n\t\tpascal: 'RoxyHoroscopeCard',\n\t\ttag: 'roxy-horoscope-card',\n\t\tslug: 'horoscope-card',\n\t\theading: 'Daily horoscope',\n\t\tdescription:\n\t\t\t'Daily, weekly, or monthly horoscope card for /astrology/horoscope/...',\n\t\tdocsLabel: 'Western',\n\t\tendpointLabel: 'GET /astrology/horoscope/{sign}/{daily,weekly,monthly}',\n\t\tdocsSummary: 'Daily, weekly, or monthly horoscope card',\n\t\ttopic: 'Astrology',\n\t},\n\t{\n\t\tpascal: 'RoxyAstrocartographyMap',\n\t\ttag: 'roxy-astrocartography-map',\n\t\tslug: 'astrocartography-map',\n\t\theading: 'Astrocartography',\n\t\tdescription:\n\t\t\t'Astrocartography world map plotting each body Midheaven, IC, Ascendant, and Descendant relocation lines',\n\t\tdocsLabel: 'Western',\n\t\tendpointLabel: 'POST /astrology/astrocartography',\n\t\tdocsSummary:\n\t\t\t'World map of planetary MC, IC, Ascendant, and Descendant lines with per-line interpretations',\n\t\ttopic: 'Astrology',\n\t},\n\t{\n\t\tpascal: 'RoxyLocalSpaceCompass',\n\t\ttag: 'roxy-local-space-compass',\n\t\tslug: 'local-space-compass',\n\t\theading: 'Local space',\n\t\tdescription:\n\t\t\t'Local space compass plotting each body direction from the birthplace by azimuth and altitude',\n\t\tdocsLabel: 'Western',\n\t\tendpointLabel: 'POST /astrology/local-space',\n\t\tdocsSummary:\n\t\t\t'Compass dial of planetary azimuth lines from the birthplace, dimmed below the horizon',\n\t\ttopic: 'Astrology',\n\t},\n\t{\n\t\tpascal: 'RoxyRelocationWheel',\n\t\ttag: 'roxy-relocation-wheel',\n\t\tslug: 'relocation-wheel',\n\t\theading: 'Relocation chart',\n\t\tdescription:\n\t\t\t'Relocation chart wheel recomputing houses and angles for a new place, with the planets that change house',\n\t\tdocsLabel: 'Western',\n\t\tendpointLabel: 'POST /astrology/relocation-chart',\n\t\tdocsSummary:\n\t\t\t'Relocated chart wheel plus the move geometry, angular planets, and planets that change house',\n\t\ttopic: 'Astrology',\n\t},\n\t{\n\t\tpascal: 'RoxyPositionsTable',\n\t\ttag: 'roxy-positions-table',\n\t\tslug: 'positions-table',\n\t\theading: 'Positions table',\n\t\tdescription:\n\t\t\t'Editorial positions table for asteroids, Black Moon Lilith, secondary progressions, solar arc directions, and the Arabic lots',\n\t\tdocsLabel: 'Western',\n\t\tendpointLabel:\n\t\t\t'POST /astrology/asteroids, /astrology/lilith, /astrology/progressions, /astrology/solar-arc, /astrology/arabic-lots',\n\t\tdocsSummary:\n\t\t\t'Body, sign, degree, and per-shape columns (house, motion, formula, or natal arc) plus each reading',\n\t\ttopic: 'Astrology',\n\t},\n\t{\n\t\tpascal: 'RoxyFixedStars',\n\t\ttag: 'roxy-fixed-stars',\n\t\tslug: 'fixed-stars',\n\t\theading: 'Fixed stars',\n\t\tdescription:\n\t\t\t'Fixed star conjunctions to the natal chart, tightest first, with the precessed star catalog',\n\t\tdocsLabel: 'Western',\n\t\tendpointLabel: 'POST /astrology/fixed-stars',\n\t\tdocsSummary:\n\t\t\t'Star to natal point conjunctions with readings, plus a catalog of position, magnitude, nature, and keywords',\n\t\ttopic: 'Astrology',\n\t},\n\t{\n\t\tpascal: 'RoxyProfectionCard',\n\t\ttag: 'roxy-profection-card',\n\t\tslug: 'profection-card',\n\t\theading: 'Annual profection',\n\t\tdescription:\n\t\t\t'Annual profection card with the profected house and sign, the lord of the year, and its natal placement',\n\t\tdocsLabel: 'Western',\n\t\tendpointLabel: 'POST /astrology/profections',\n\t\tdocsSummary:\n\t\t\t'Profected house and sign for the year, the lord of the year, its natal placement, and the reading',\n\t\ttopic: 'Astrology',\n\t},\n\t{\n\t\tpascal: 'RoxyCompatibilityCard',\n\t\ttag: 'roxy-compatibility-card',\n\t\tslug: 'compatibility-card',\n\t\theading: 'Compatibility score',\n\t\tdescription: 'Cross-domain compatibility score card',\n\t\tdocsLabel: 'Cross',\n\t\tendpointLabel:\n\t\t\t'POST /astrology/compatibility-score, /numerology/compatibility, /biorhythm/compatibility',\n\t\tdocsSummary: 'Score card with category breakdown',\n\t\ttopic: 'Astrology',\n\t},\n\t{\n\t\tpascal: 'RoxyVedicKundli',\n\t\ttag: 'roxy-vedic-kundli',\n\t\tslug: 'vedic-kundli',\n\t\theading: 'Vedic kundli',\n\t\tdescription:\n\t\t\t'South, North, or East Indian Vedic kundli for /vedic-astrology/birth-chart with per-planet degree and nakshatra detail, plus an optional Chandra Lagna (Moon-as-ascendant) reference view',\n\t\tdocsLabel: 'Vedic',\n\t\tendpointLabel: 'POST /vedic-astrology/birth-chart',\n\t\tdocsSummary:\n\t\t\t'South, North, or East Indian kundli with degree detail and optional Chandra Lagna view',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyDivisionalChart',\n\t\ttag: 'roxy-divisional-chart',\n\t\tslug: 'divisional-chart',\n\t\theading: 'Divisional chart',\n\t\tdescription: 'D2 to D60 varga chart wheel with Vargottama markers',\n\t\tdocsLabel: 'Vedic',\n\t\tendpointLabel: 'POST /vedic-astrology/divisional-chart',\n\t\tdocsSummary:\n\t\t\t'Generic divisional varga wheel from D2 Hora to D60 Shashtiamsa',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyKpChart',\n\t\ttag: 'roxy-kp-chart',\n\t\tslug: 'kp-chart',\n\t\theading: 'KP chart',\n\t\tdescription:\n\t\t\t'Full KP chart with Ascendant, Placidus cusps, and planets in tabbed stellar-hierarchy tables',\n\t\tdocsLabel: 'Vedic (KP)',\n\t\tendpointLabel: 'POST /vedic-astrology/kp/chart',\n\t\tdocsSummary: 'Ascendant, cusps, and planets with KP stellar hierarchy',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyVedicPlanetsTable',\n\t\ttag: 'roxy-vedic-planets-table',\n\t\tslug: 'vedic-planets-table',\n\t\theading: 'Vedic planets',\n\t\tdescription:\n\t\t\t'Vedic planetary positions table with degree, nakshatra, pada, nakshatra lord, bhava, and avastha',\n\t\tdocsLabel: 'Vedic',\n\t\tendpointLabel: 'POST /vedic-astrology/birth-chart',\n\t\tdocsSummary: 'Degree, nakshatra, pada, lord, bhava, avastha columns',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyKpPlanetsTable',\n\t\ttag: 'roxy-kp-planets-table',\n\t\tslug: 'kp-planets-table',\n\t\theading: 'KP planets',\n\t\tdescription: 'KP planets table with sub-lord and sub-sub-lord columns',\n\t\tdocsLabel: 'Vedic (KP)',\n\t\tendpointLabel: 'POST /vedic-astrology/kp/planets',\n\t\tdocsSummary: 'Sub-lord and sub-sub-lord columns',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyKpRulingPlanets',\n\t\ttag: 'roxy-kp-ruling-planets',\n\t\tslug: 'kp-ruling-planets',\n\t\theading: 'KP ruling planets',\n\t\tdescription:\n\t\t\t'KP ruling planets with day lord, Moon and Lagna stellar hierarchies, and house significators',\n\t\tdocsLabel: 'Vedic (KP)',\n\t\tendpointLabel: 'POST /vedic-astrology/kp/ruling-planets',\n\t\tdocsSummary:\n\t\t\t'Day lord, Moon/Lagna hierarchies, ruling planets, significators',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyAshtakavargaGrid',\n\t\ttag: 'roxy-ashtakavarga-grid',\n\t\tslug: 'ashtakavarga-grid',\n\t\theading: 'Ashtakavarga',\n\t\tdescription: 'Sarva and Bhinna ashtakavarga heatmap with bindu scores',\n\t\tdocsLabel: 'Vedic',\n\t\tendpointLabel: 'POST /vedic-astrology/ashtakavarga',\n\t\tdocsSummary: 'Sarva, Bhinna, and Shodhya Pinda views in a tabbed heatmap',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyShadbalaTable',\n\t\ttag: 'roxy-shadbala-table',\n\t\tslug: 'shadbala-table',\n\t\theading: 'Shadbala',\n\t\tdescription: 'Six-fold planetary strength with adequacy badge per planet',\n\t\tdocsLabel: 'Vedic',\n\t\tendpointLabel: 'POST /vedic-astrology/shadbala',\n\t\tdocsSummary:\n\t\t\t'Six-fold planetary strength bar plus rupas and adequacy badge',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyDashaTimeline',\n\t\ttag: 'roxy-dasha-timeline',\n\t\tslug: 'dasha-timeline',\n\t\theading: 'Vimshottari dasha',\n\t\tdescription: 'Vimshottari dasha timeline with active mahadasha highlighted',\n\t\tdocsLabel: 'Vedic',\n\t\tendpointLabel: 'POST /vedic-astrology/dasha/{current,major,sub/...}',\n\t\tdocsSummary: 'Vimshottari mahadasha + antardasha + pratyantardasha',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyGunaMilan',\n\t\ttag: 'roxy-guna-milan',\n\t\tslug: 'guna-milan',\n\t\theading: 'Guna milan',\n\t\tdescription: '36-point Ashtakoota matrimonial compatibility breakdown',\n\t\tdocsLabel: 'Vedic',\n\t\tendpointLabel: 'POST /vedic-astrology/compatibility',\n\t\tdocsSummary: '36-point Ashtakoota with eight sub-scores',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyPanchangTable',\n\t\ttag: 'roxy-panchang-table',\n\t\tslug: 'panchang-table',\n\t\theading: 'Panchang',\n\t\tdescription:\n\t\t\t'Panchang muhurta table with auspicious and inauspicious periods',\n\t\tdocsLabel: 'Vedic',\n\t\tendpointLabel: 'POST /vedic-astrology/panchang/{basic,detailed}',\n\t\tdocsSummary: '15+ muhurtas in detailed mode',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyVedicAspects',\n\t\ttag: 'roxy-vedic-aspects',\n\t\tslug: 'vedic-aspects',\n\t\theading: 'Vedic aspects',\n\t\tdescription:\n\t\t\t'Vedic graha drishti table: which planet aspects which, with mutual aspects surfaced first',\n\t\tdocsLabel: 'Vedic',\n\t\tendpointLabel: 'POST /vedic-astrology/aspects',\n\t\tdocsSummary:\n\t\t\t'Graha drishti rows with aspect type, strength, and orb, plus mutual aspects',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyHoraTable',\n\t\ttag: 'roxy-hora-table',\n\t\tslug: 'hora-table',\n\t\theading: 'Hora',\n\t\tdescription:\n\t\t\t'Vedic Hora (planetary hours) table: 12 day and 12 night horas by ruling planet for electional timing',\n\t\tdocsLabel: 'Vedic',\n\t\tendpointLabel: 'POST /vedic-astrology/panchang/hora',\n\t\tdocsSummary: 'Day and night planetary hours with ruling planet and window',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyChoghadiyaGrid',\n\t\ttag: 'roxy-choghadiya-grid',\n\t\tslug: 'choghadiya-grid',\n\t\theading: 'Choghadiya',\n\t\tdescription: 'Day and night Choghadiya muhurta tiles for activity timing',\n\t\tdocsLabel: 'Vedic',\n\t\tendpointLabel: 'POST /vedic-astrology/panchang/choghadiya',\n\t\tdocsSummary: 'Day and night Choghadiya muhurta tiles colored by effect',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyYogaList',\n\t\ttag: 'roxy-yoga-list',\n\t\tslug: 'yoga-list',\n\t\theading: 'Yoga catalog',\n\t\tdescription:\n\t\t\t'Yoga reference cards from the catalog with optional detail mode',\n\t\tdocsLabel: 'Vedic',\n\t\tendpointLabel: 'GET /vedic-astrology/yoga, /yoga/{id}',\n\t\tdocsSummary: 'Filterable yoga cards from the 300 plus yoga catalog',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyNakshatraCard',\n\t\ttag: 'roxy-nakshatra-card',\n\t\tslug: 'nakshatra-card',\n\t\theading: 'Nakshatra',\n\t\tdescription:\n\t\t\t'Nakshatra reference card with lord, deity, symbol, characteristics, and remedies',\n\t\tdocsLabel: 'Vedic',\n\t\tendpointLabel: 'GET /vedic-astrology/nakshatras/{id}',\n\t\tdocsSummary: 'Lord, deity, symbol, characteristics, remedies',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyDoshaCard',\n\t\ttag: 'roxy-dosha-card',\n\t\tslug: 'dosha-card',\n\t\theading: 'Manglik dosha',\n\t\tdescription: 'Manglik, Kaal Sarp, or Sade Sati presence card',\n\t\tdocsLabel: 'Vedic',\n\t\tendpointLabel: 'POST /vedic-astrology/dosha/{manglik,kalsarpa,sadhesati}',\n\t\tdocsSummary: 'Presence, severity, remedies, scoped effects',\n\t\ttopic: 'Vedic',\n\t},\n\t{\n\t\tpascal: 'RoxyNumerologyCard',\n\t\ttag: 'roxy-numerology-card',\n\t\tslug: 'numerology-card',\n\t\theading: 'Life path number',\n\t\tdescription:\n\t\t\t'Numerology card for life path, expression, soul urge, personality, personal year, or full chart',\n\t\tdocsLabel: 'Numerology',\n\t\tendpointLabel:\n\t\t\t'POST /numerology/{life-path,expression,soul-urge,personality,birth-day,maturity,daily,personal-day,personal-month,personal-year,chart}',\n\t\tdocsSummary:\n\t\t\t'Life path, expression, soul urge, personality, personal year, full chart',\n\t\ttopic: 'Numerology',\n\t},\n\t{\n\t\tpascal: 'RoxyTarotCard',\n\t\ttag: 'roxy-tarot-card',\n\t\tslug: 'tarot-card',\n\t\theading: 'Daily tarot card',\n\t\tdescription: 'Single tarot card with upright/reversed flip animation',\n\t\tdocsLabel: 'Tarot',\n\t\tendpointLabel: 'GET /tarot/cards/{id}, POST /tarot/daily',\n\t\tdocsSummary: 'Single card with upright and reversed flip',\n\t\ttopic: 'Tarot',\n\t},\n\t{\n\t\tpascal: 'RoxyTarotCatalog',\n\t\ttag: 'roxy-tarot-catalog',\n\t\tslug: 'tarot-catalog',\n\t\theading: 'Tarot deck',\n\t\tdescription:\n\t\t\t'Responsive tarot deck gallery with card art, name, and an arcana and suit caption from the tarot catalog response',\n\t\tdocsLabel: 'Tarot',\n\t\tendpointLabel: 'GET /tarot/cards',\n\t\tdocsSummary: 'Deck gallery tiles with card art, name, and arcana and suit',\n\t\ttopic: 'Tarot',\n\t},\n\t{\n\t\tpascal: 'RoxyTarotSpread',\n\t\ttag: 'roxy-tarot-spread',\n\t\tslug: 'tarot-spread',\n\t\theading: 'Three-card spread',\n\t\tdescription:\n\t\t\t'Tarot spread renderer for three-card, Celtic Cross, love, or yes/no',\n\t\tdocsLabel: 'Tarot',\n\t\tendpointLabel:\n\t\t\t'POST /tarot/spreads/{three-card,celtic-cross,love}, /tarot/yes-no, /tarot/draw',\n\t\tdocsSummary: 'Spreads with positions and reading',\n\t\ttopic: 'Tarot',\n\t},\n\t{\n\t\tpascal: 'RoxyBodygraph',\n\t\ttag: 'roxy-bodygraph',\n\t\tslug: 'bodygraph',\n\t\theading: 'Bodygraph',\n\t\tdescription:\n\t\t\t'Human Design bodygraph with nine centers, channels, and activated gates plus a type, authority, and profile summary',\n\t\tdocsLabel: 'Human Design',\n\t\tendpointLabel: 'POST /human-design/bodygraph',\n\t\tdocsSummary:\n\t\t\t'Nine-center chart with defined and open centers, active channels, gates, and a type and authority summary',\n\t\ttopic: 'Human Design',\n\t},\n\t{\n\t\tpascal: 'RoxyHdConnection',\n\t\ttag: 'roxy-hd-connection',\n\t\tslug: 'hd-connection',\n\t\theading: 'HD connection',\n\t\tdescription:\n\t\t\t'Human Design connection chart: the composite channels two people form, with circuit, dynamic, and which person holds each gate',\n\t\tdocsLabel: 'Human Design',\n\t\tendpointLabel: 'POST /human-design/connection',\n\t\tdocsSummary:\n\t\t\t'Electromagnetic, compromise, and dominance channels between two charts',\n\t\ttopic: 'Human Design',\n\t},\n\t{\n\t\tpascal: 'RoxyHdPenta',\n\t\ttag: 'roxy-hd-penta',\n\t\tslug: 'hd-penta',\n\t\theading: 'HD penta',\n\t\tdescription:\n\t\t\t'Human Design penta for a 3 to 5 person group: upper and lower triangle channels, defined or open, with core channels and member coverage',\n\t\tdocsLabel: 'Human Design',\n\t\tendpointLabel: 'POST /human-design/penta',\n\t\tdocsSummary: 'Group penta channels split into upper and lower triangles',\n\t\ttopic: 'Human Design',\n\t},\n\t{\n\t\tpascal: 'RoxyHdVariables',\n\t\ttag: 'roxy-hd-variables',\n\t\tslug: 'hd-variables',\n\t\theading: 'HD variables',\n\t\tdescription:\n\t\t\t'Human Design variables: the four PHS arrows (determination, environment, perspective, motivation) with left/right direction and color, tone, and base',\n\t\tdocsLabel: 'Human Design',\n\t\tendpointLabel: 'POST /human-design/variables',\n\t\tdocsSummary: 'The four transformation arrows with direction and PHS labels',\n\t\ttopic: 'Human Design',\n\t},\n\t{\n\t\tpascal: 'RoxyForecastTimeline',\n\t\ttag: 'roxy-forecast-timeline',\n\t\tslug: 'forecast-timeline',\n\t\theading: 'Forecast timeline',\n\t\tdescription:\n\t\t\t'Cross-domain forecast event strip colored by domain and weighted by significance',\n\t\tdocsLabel: 'Forecast',\n\t\tendpointLabel: 'POST /forecast/timeline',\n\t\tdocsSummary:\n\t\t\t'Date-grouped events across Western, Vedic, and biorhythm domains, weighted by significance',\n\t\ttopic: 'Forecast',\n\t},\n\t{\n\t\tpascal: 'RoxyForecastDigest',\n\t\ttag: 'roxy-forecast-digest',\n\t\tslug: 'forecast-digest',\n\t\theading: 'Forecast digest',\n\t\tdescription:\n\t\t\t'Rolled-up forecast across the next 24 hours, 7, 30, and 90 days with per-domain breakdown and top events',\n\t\tdocsLabel: 'Forecast',\n\t\tendpointLabel: 'POST /forecast/digest',\n\t\tdocsSummary:\n\t\t\t'Per-window event counts, domain breakdown, and the highest-significance events',\n\t\ttopic: 'Forecast',\n\t},\n\t{\n\t\tpascal: 'RoxyBiorhythmChart',\n\t\ttag: 'roxy-biorhythm-chart',\n\t\tslug: 'biorhythm-chart',\n\t\theading: 'Daily biorhythm',\n\t\tdescription: 'Daily biorhythm bars or multi-day forecast cycle lines',\n\t\tdocsLabel: 'Biorhythm',\n\t\tendpointLabel: 'POST /biorhythm/{daily,forecast,critical-days}',\n\t\tdocsSummary: 'Daily bars, forecast cycle lines, critical days',\n\t\ttopic: 'Biorhythm',\n\t},\n\t{\n\t\tpascal: 'RoxyHexagram',\n\t\ttag: 'roxy-hexagram',\n\t\tslug: 'hexagram',\n\t\theading: 'I Ching hexagram',\n\t\tdescription:\n\t\t\t'I Ching hexagram with trigram glyphs, judgment, image, and changing lines',\n\t\tdocsLabel: 'I Ching',\n\t\tendpointLabel:\n\t\t\t'GET /iching/hexagrams/{number}, /iching/cast, POST /iching/daily, /iching/daily/cast',\n\t\tdocsSummary: 'Hexagram with trigrams, judgment, image, changing lines',\n\t\ttopic: 'I Ching',\n\t},\n\t{\n\t\tpascal: 'RoxyCrystalCard',\n\t\ttag: 'roxy-crystal-card',\n\t\tslug: 'crystal-card',\n\t\theading: 'Crystal detail',\n\t\tdescription:\n\t\t\t'Single-crystal detail card with photo, spiritual, emotional, and physical meaning, metaphysical attributes, affirmation, and pairings',\n\t\tdocsLabel: 'Crystals',\n\t\tendpointLabel: 'GET /crystals/{id}',\n\t\tdocsSummary:\n\t\t\t'Photo, meaning sections, chakra, zodiac, element, hardness, keywords, and pairings',\n\t\ttopic: 'Crystals',\n\t},\n\t{\n\t\tpascal: 'RoxyCrystalGrid',\n\t\ttag: 'roxy-crystal-grid',\n\t\tslug: 'crystal-grid',\n\t\theading: 'Crystal grid',\n\t\tdescription:\n\t\t\t'Responsive crystal gallery with photo, name, and colour swatches from any crystals list response',\n\t\tdocsLabel: 'Crystals',\n\t\tendpointLabel:\n\t\t\t'GET /crystals, /crystals/chakra/{chakra}, /crystals/element/{element}, /crystals/zodiac/{sign}, /crystals/birthstone/{month}, /crystals/search',\n\t\tdocsSummary: 'Crystal gallery tiles with photo, name, and colour swatches',\n\t\ttopic: 'Crystals',\n\t},\n\t{\n\t\tpascal: 'RoxyDreamCard',\n\t\ttag: 'roxy-dream-card',\n\t\tslug: 'dream-card',\n\t\theading: 'Dream symbol',\n\t\tdescription:\n\t\t\t'Dream symbol card with the symbol name, full interpretation, and dictionary letter',\n\t\tdocsLabel: 'Dreams',\n\t\tendpointLabel: 'GET /dreams/symbols/{id}',\n\t\tdocsSummary: 'Symbol name, interpretation body, and letter chip',\n\t\ttopic: 'Dreams',\n\t},\n\t{\n\t\tpascal: 'RoxyDreamSearch',\n\t\ttag: 'roxy-dream-search',\n\t\tslug: 'dream-search',\n\t\theading: 'Dream search',\n\t\tdescription:\n\t\t\t'Dream-symbol search results as selectable tiles; emits roxy-symbol-select to pair with roxy-dream-card',\n\t\tdocsLabel: 'Dreams',\n\t\tendpointLabel: 'GET /dreams/symbols',\n\t\tdocsSummary: 'Matched dream symbols as selectable tiles with a letter chip',\n\t\ttopic: 'Dreams',\n\t},\n\t{\n\t\tpascal: 'RoxyAngelNumberCard',\n\t\ttag: 'roxy-angel-number-card',\n\t\tslug: 'angel-number-card',\n\t\theading: 'Angel number',\n\t\tdescription:\n\t\t\t'Angel number card with title, core message, badges, keywords, life-area interpretations, affirmation, and action steps',\n\t\tdocsLabel: 'Angel Numbers',\n\t\tendpointLabel: 'GET /angel-numbers/numbers/{number}',\n\t\tdocsSummary:\n\t\t\t'Number meaning with spiritual, love, career, money, twin flame, biblical, and shadow sections',\n\t\ttopic: 'Angel Numbers',\n\t},\n\t{\n\t\tpascal: 'RoxyAngelNumberLookup',\n\t\ttag: 'roxy-angel-number-lookup',\n\t\tslug: 'angel-number-lookup',\n\t\theading: 'Angel number lookup',\n\t\tdescription:\n\t\t\t'Angel number sequence analysis with pattern classification, the known meaning when present, and a digit-root fallback for any number',\n\t\tdocsLabel: 'Angel Numbers',\n\t\tendpointLabel: 'GET /angel-numbers/lookup',\n\t\tdocsSummary: 'Pattern analysis plus known meaning and digit-root fallback',\n\t\ttopic: 'Angel Numbers',\n\t},\n\t{\n\t\tpascal: 'RoxyReferenceCard',\n\t\ttag: 'roxy-reference-card',\n\t\tslug: 'reference-card',\n\t\theading: 'Reference card',\n\t\tdescription:\n\t\t\t'Glossary entry for any reference lookup: zodiac sign, planet meaning, rashi, I Ching trigram, Human Design gate or center, numerology number or compound number',\n\t\tdocsLabel: 'Reference',\n\t\tendpointLabel:\n\t\t\t'GET /astrology/{signs,planet-meanings}/{id}, /vedic-astrology/rashis/{id}, /iching/trigrams/{id}, /human-design/{gates,centers}/{id}, /numerology/{meanings,compound-number}/{number}',\n\t\tdocsSummary:\n\t\t\t'Symbol, name, description, keyword chips, and an attribute grid for any glossary lookup',\n\t\ttopic: 'Helpers',\n\t},\n\t{\n\t\tpascal: 'RoxyEndpointForm',\n\t\ttag: 'roxy-endpoint-form',\n\t\tslug: 'endpoint-form',\n\t\theading: 'Schema-driven form',\n\t\tdescription:\n\t\t\t'Schema-driven form that emits roxy-submit with a validated payload',\n\t\tdocsLabel: 'Helper',\n\t\tendpointLabel: 'Any endpoint, from the spec',\n\t\tdocsSummary: 'Schema-driven form, emits roxy-submit',\n\t\ttopic: 'Helpers',\n\t\tselfFetching: true,\n\t},\n\t{\n\t\tpascal: 'RoxyLocationSearch',\n\t\ttag: 'roxy-location-search',\n\t\tslug: 'location-search',\n\t\theading: 'City search',\n\t\tdescription: 'City search input with debounced /location/search calls',\n\t\tdocsLabel: 'Helper',\n\t\tendpointLabel: 'GET /location/search',\n\t\tdocsSummary: 'Debounced city search input, emits roxy-location-select',\n\t\ttopic: 'Helpers',\n\t\tselfFetching: true,\n\t},\n\t{\n\t\tpascal: 'RoxyData',\n\t\ttag: 'roxy-data',\n\t\tslug: 'data',\n\t\theading: 'Generic renderer',\n\t\tdescription: 'Generic fallback renderer for any OpenAPI response shape',\n\t\tdocsLabel: 'Helper',\n\t\tendpointLabel: 'Any response shape',\n\t\tdocsSummary: 'Generic fallback renderer for unknown shapes',\n\t\ttopic: 'Helpers',\n\t\tselfFetching: true,\n\t},\n];\n\nexport type RoxyComponentSlug = (typeof ROXY_COMPONENTS)[number]['slug'];\n", "// Generated by scripts/sync-version.ts. Do not edit.\nexport const ROXY_UI_VERSION = '0.12.1';\n"],
5
+ "mappings": "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AAW,UACX,cAAe,2BACf,YACC,kEACD,MAAO,WACR,EACA,CACC,OAAQ,mBACR,IAAK,qBACL,KAAM,gBACN,QAAS,UACT,YACC,wGACD,UAAW,UACX,cACC,kFACD,YACC,qFACD,MAAO,WACR,EACA,CACC,OAAQ,gBACR,IAAK,kBACL,KAAM,aACN,QAAS,aACT,YAAa,+BACb,UAAW,UACX,cAAe,4DACf,YAAa,+BACb,MAAO,WACR,EACA,CACC,OAAQ,oBACR,IAAK,sBACL,KAAM,iBACN,QAAS,kBACT,YACC,wEACD,UAAW,UACX,cAAe,yDACf,YAAa,2CACb,MAAO,WACR,EACA,CACC,OAAQ,0BACR,IAAK,4BACL,KAAM,uBACN,QAAS,mBACT,YACC,0GACD,UAAW,UACX,cAAe,mCACf,YACC,+FACD,MAAO,WACR,EACA,CACC,OAAQ,wBACR,IAAK,2BACL,KAAM,sBACN,QAAS,cACT,YACC,+FACD,UAAW,UACX,cAAe,8BACf,YACC,wFACD,MAAO,WACR,EACA,CACC,OAAQ,sBACR,IAAK,wBACL,KAAM,mBACN,QAAS,mBACT,YACC,2GACD,UAAW,UACX,cAAe,mCACf,YACC,+FACD,MAAO,WACR,EACA,CACC,OAAQ,qBACR,IAAK,uBACL,KAAM,kBACN,QAAS,kBACT,YACC,gIACD,UAAW,UACX,cACC,sHACD,YACC,qGACD,MAAO,WACR,EACA,CACC,OAAQ,iBACR,IAAK,mBACL,KAAM,cACN,QAAS,cACT,YACC,8FACD,UAAW,UACX,cAAe,8BACf,YACC,8GACD,MAAO,WACR,EACA,CACC,OAAQ,qBACR,IAAK,uBACL,KAAM,kBACN,QAAS,oBACT,YACC,0GACD,UAAW,UACX,cAAe,8BACf,YACC,oGACD,MAAO,WACR,EACA,CACC,OAAQ,wBACR,IAAK,0BACL,KAAM,qBACN,QAAS,sBACT,YAAa,wCACb,UAAW,QACX,cACC,2FACD,YAAa,qCACb,MAAO,WACR,EACA,CACC,OAAQ,kBACR,IAAK,oBACL,KAAM,eACN,QAAS,eACT,YACC,4LACD,UAAW,QACX,cAAe,oCACf,YACC,yFACD,MAAO,OACR,EACA,CACC,OAAQ,sBACR,IAAK,wBACL,KAAM,mBACN,QAAS,mBACT,YAAa,sDACb,UAAW,QACX,cAAe,yCACf,YACC,iEACD,MAAO,OACR,EACA,CACC,OAAQ,cACR,IAAK,gBACL,KAAM,WACN,QAAS,WACT,YACC,+FACD,UAAW,aACX,cAAe,iCACf,YAAa,0DACb,MAAO,OACR,EACA,CACC,OAAQ,wBACR,IAAK,2BACL,KAAM,sBACN,QAAS,gBACT,YACC,mGACD,UAAW,QACX,cAAe,oCACf,YAAa,wDACb,MAAO,OACR,EACA,CACC,OAAQ,qBACR,IAAK,wBACL,KAAM,mBACN,QAAS,aACT,YAAa,0DACb,UAAW,aACX,cAAe,mCACf,YAAa,oCACb,MAAO,OACR,EACA,CACC,OAAQ,sBACR,IAAK,yBACL,KAAM,oBACN,QAAS,oBACT,YACC,+FACD,UAAW,aACX,cAAe,0CACf,YACC,kEACD,MAAO,OACR,EACA,CACC,OAAQ,uBACR,IAAK,yBACL,KAAM,oBACN,QAAS,eACT,YAAa,0DACb,UAAW,QACX,cAAe,qCACf,YAAa,6DACb,MAAO,OACR,EACA,CACC,OAAQ,oBACR,IAAK,sBACL,KAAM,iBACN,QAAS,WACT,YAAa,6DACb,UAAW,QACX,cAAe,iCACf,YACC,gEACD,MAAO,OACR,EACA,CACC,OAAQ,oBACR,IAAK,sBACL,KAAM,iBACN,QAAS,oBACT,YAAa,+DACb,UAAW,QACX,cAAe,sDACf,YAAa,uDACb,MAAO,OACR,EACA,CACC,OAAQ,gBACR,IAAK,kBACL,KAAM,aACN,QAAS,aACT,YAAa,0DACb,UAAW,QACX,cAAe,sCACf,YAAa,4CACb,MAAO,OACR,EACA,CACC,OAAQ,oBACR,IAAK,sBACL,KAAM,iBACN,QAAS,WACT,YACC,kEACD,UAAW,QACX,cAAe,kDACf,YAAa,gCACb,MAAO,OACR,EACA,CACC,OAAQ,mBACR,IAAK,qBACL,KAAM,gBACN,QAAS,gBACT,YACC,4FACD,UAAW,QACX,cAAe,gCACf,YACC,8EACD,MAAO,OACR,EACA,CACC,OAAQ,gBACR,IAAK,kBACL,KAAM,aACN,QAAS,OACT,YACC,uGACD,UAAW,QACX,cAAe,sCACf,YAAa,8DACb,MAAO,OACR,EACA,CACC,OAAQ,qBACR,IAAK,uBACL,KAAM,kBACN,QAAS,aACT,YAAa,6DACb,UAAW,QACX,cAAe,4CACf,YAAa,2DACb,MAAO,OACR,EACA,CACC,OAAQ,eACR,IAAK,iBACL,KAAM,YACN,QAAS,eACT,YACC,kEACD,UAAW,QACX,cAAe,wCACf,YAAa,uDACb,MAAO,OACR,EACA,CACC,OAAQ,oBACR,IAAK,sBACL,KAAM,iBACN,QAAS,YACT,YACC,mFACD,UAAW,QACX,cAAe,uCACf,YAAa,iDACb,MAAO,OACR,EACA,CACC,OAAQ,gBACR,IAAK,kBACL,KAAM,aACN,QAAS,gBACT,YAAa,iDACb,UAAW,QACX,cAAe,2DACf,YAAa,+CACb,MAAO,OACR,EACA,CACC,OAAQ,qBACR,IAAK,uBACL,KAAM,kBACN,QAAS,mBACT,YACC,kGACD,UAAW,aACX,cACC,yIACD,YACC,2EACD,MAAO,YACR,EACA,CACC,OAAQ,gBACR,IAAK,kBACL,KAAM,aACN,QAAS,mBACT,YAAa,yDACb,UAAW,QACX,cAAe,2CACf,YAAa,6CACb,MAAO,OACR,EACA,CACC,OAAQ,mBACR,IAAK,qBACL,KAAM,gBACN,QAAS,aACT,YACC,oHACD,UAAW,QACX,cAAe,mBACf,YAAa,8DACb,MAAO,OACR,EACA,CACC,OAAQ,kBACR,IAAK,oBACL,KAAM,eACN,QAAS,oBACT,YACC,sEACD,UAAW,QACX,cACC,iFACD,YAAa,qCACb,MAAO,OACR,EACA,CACC,OAAQ,gBACR,IAAK,iBACL,KAAM,YACN,QAAS,YACT,YACC,sHACD,UAAW,eACX,cAAe,+BACf,YACC,4GACD,MAAO,cACR,EACA,CACC,OAAQ,mBACR,IAAK,qBACL,KAAM,gBACN,QAAS,gBACT,YACC,iIACD,UAAW,eACX,cAAe,gCACf,YACC,yEACD,MAAO,cACR,EACA,CACC,OAAQ,cACR,IAAK,gBACL,KAAM,WACN,QAAS,WACT,YACC,2IACD,UAAW,eACX,cAAe,2BACf,YAAa,4DACb,MAAO,cACR,EACA,CACC,OAAQ,kBACR,IAAK,oBACL,KAAM,eACN,QAAS,eACT,YACC,wJACD,UAAW,eACX,cAAe,+BACf,YAAa,+DACb,MAAO,cACR,EACA,CACC,OAAQ,uBACR,IAAK,yBACL,KAAM,oBACN,QAAS,oBACT,YACC,mFACD,UAAW,WACX,cAAe,0BACf,YACC,6FACD,MAAO,UACR,EACA,CACC,OAAQ,qBACR,IAAK,uBACL,KAAM,kBACN,QAAS,kBACT,YACC,2GACD,UAAW,WACX,cAAe,wBACf,YACC,iFACD,MAAO,UACR,EACA,CACC,OAAQ,qBACR,IAAK,uBACL,KAAM,kBACN,QAAS,kBACT,YAAa,yDACb,UAAW,YACX,cAAe,iDACf,YAAa,kDACb,MAAO,WACR,EACA,CACC,OAAQ,eACR,IAAK,gBACL,KAAM,WACN,QAAS,mBACT,YACC,4EACD,UAAW,UACX,cACC,uFACD,YAAa,0DACb,MAAO,SACR,EACA,CACC,OAAQ,kBACR,IAAK,oBACL,KAAM,eACN,QAAS,iBACT,YACC,wIACD,UAAW,WACX,cAAe,qBACf,YACC,qFACD,MAAO,UACR,EACA,CACC,OAAQ,kBACR,IAAK,oBACL,KAAM,eACN,QAAS,eACT,YACC,mGACD,UAAW,WACX,cACC,iJACD,YAAa,8DACb,MAAO,UACR,EACA,CACC,OAAQ,gBACR,IAAK,kBACL,KAAM,aACN,QAAS,eACT,YACC,qFACD,UAAW,SACX,cAAe,2BACf,YAAa,oDACb,MAAO,QACR,EACA,CACC,OAAQ,kBACR,IAAK,oBACL,KAAM,eACN,QAAS,eACT,YACC,yGACD,UAAW,SACX,cAAe,sBACf,YAAa,+DACb,MAAO,QACR,EACA,CACC,OAAQ,sBACR,IAAK,yBACL,KAAM,oBACN,QAAS,eACT,YACC,yHACD,UAAW,gBACX,cAAe,sCACf,YACC,gGACD,MAAO,eACR,EACA,CACC,OAAQ,wBACR,IAAK,2BACL,KAAM,sBACN,QAAS,sBACT,YACC,uIACD,UAAW,gBACX,cAAe,4BACf,YAAa,8DACb,MAAO,eACR,EACA,CACC,OAAQ,oBACR,IAAK,sBACL,KAAM,iBACN,QAAS,iBACT,YACC,kKACD,UAAW,YACX,cACC,wLACD,YACC,0FACD,MAAO,SACR,EACA,CACC,OAAQ,mBACR,IAAK,qBACL,KAAM,gBACN,QAAS,qBACT,YACC,qEACD,UAAW,SACX,cAAe,8BACf,YAAa,wCACb,MAAO,UACP,aAAc,EACf,EACA,CACC,OAAQ,qBACR,IAAK,uBACL,KAAM,kBACN,QAAS,cACT,YAAa,0DACb,UAAW,SACX,cAAe,uBACf,YAAa,0DACb,MAAO,UACP,aAAc,EACf,EACA,CACC,OAAQ,WACR,IAAK,YACL,KAAM,OACN,QAAS,mBACT,YAAa,2DACb,UAAW,SACX,cAAe,qBACf,YAAa,+CACb,MAAO,UACP,aAAc,EACf,CACD,ECvrBO,IAAMC,GAAkB,SxE4FxB,IAAMC,GACZC,GAAgB,IAAKC,GAAMA,EAAE,IAAI",
6
+ "names": ["src_exports", "__export", "ROXY_COMPONENTS", "ROXY_UI_COMPONENTS", "ROXY_UI_VERSION", "RoxyAngelNumberCard", "RoxyAngelNumberLookup", "RoxyAshtakavargaGrid", "RoxyAspectsTable", "RoxyAstrocartographyMap", "RoxyBiorhythmChart", "RoxyBodygraph", "RoxyChoghadiyaGrid", "RoxyCompatibilityCard", "RoxyCrystalCard", "RoxyCrystalGrid", "RoxyDashaTimeline", "RoxyData", "RoxyDivisionalChart", "RoxyDoshaCard", "RoxyDreamCard", "RoxyDreamSearch", "RoxyEndpointForm", "RoxyFixedStars", "RoxyForecastDigest", "RoxyForecastTimeline", "RoxyGunaMilan", "RoxyHdConnection", "RoxyHdPenta", "RoxyHdVariables", "RoxyHexagram", "RoxyHoraTable", "RoxyHoroscopeCard", "RoxyKpChart", "RoxyKpPlanetsTable", "RoxyKpRulingPlanets", "RoxyLocalSpaceCompass", "RoxyLocationSearch", "RoxyMoonPhase", "RoxyNakshatraCard", "RoxyNatalChart", "RoxyNumerologyCard", "RoxyPanchangTable", "RoxyPositionsTable", "RoxyProfectionCard", "RoxyReferenceCard", "RoxyRelocationWheel", "RoxyShadbalaTable", "RoxySynastryChart", "RoxyTarotCard", "RoxyTarotCatalog", "RoxyTarotSpread", "RoxyTransitsTable", "RoxyVedicAspects", "RoxyVedicKundli", "RoxyVedicPlanetsTable", "RoxyWesternPlanetsTable", "RoxyYogaList", "roxyDataScript", "serializeRoxyData", "__toCommonJS", "import_lit", "import_decorators", "LIFE_AREA_SECTIONS", "buildMeaningSections", "meaning", "biblical", "shadow", "sections", "s", "body", "import_lit", "import_decorators", "import_if_defined", "import_lit", "baseStyles", "DEFAULT_BASE_URL", "FetchController", "host", "req", "controller", "res", "json", "err", "signal", "url", "k", "v", "headers", "key", "body", "buildRequest", "endpoint", "method", "values", "rest", "path", "_match", "name", "query", "ROXY_DATA_CLASS", "serializeRoxyData", "data", "roxyDataScript", "isJsonScript", "el", "MarkupDataController", "host", "parsed", "inline", "child", "text", "RoxyDataElement", "detail", "buildRequest", "MarkupDataController", "FetchController", "baseStyles", "changed", "raw", "values", "message", "banner", "__decorateClass", "RoxyAngelNumberCard", "RoxyDataElement", "d", "energy", "energyClass", "keywords", "steps", "k", "s", "sections", "buildMeaningSections", "i", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyAngelNumberLookup", "RoxyDataElement", "d", "known", "root", "heading", "k", "meaning", "biblical", "shadow", "sections", "buildMeaningSections", "i", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "PLANET_GLYPH", "PLANET_ABBR", "SIGN_GLYPH", "SIGN_ABBR", "SIGNS_ORDER", "RASHI_KEYS", "s", "ASPECT_SYMBOL", "TRIGRAM_GLYPH", "MOON_PHASE_EMOJI", "TAB_LABELS", "TABS", "RoxyAshtakavargaGrid", "RoxyDataElement", "d", "signs", "tab", "idx", "count", "sav", "sign", "i", "hc", "SIGN_GLYPH", "bhinna", "s", "row", "pinda", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "import_lit", "chevron", "disclosureStyles", "formatTime", "input", "iso", "d", "formatDate", "formatTimeRange", "t", "start", "end", "formatNumber", "value", "dp", "formatPercent", "n", "ASPECT_CLASS", "normalizeAspect", "a", "capitalize", "s", "humanize", "c", "RoxyAspectsTable", "RoxyDataElement", "d", "aspects", "patterns", "summary", "a", "i", "p", "s", "total", "idx", "g1", "PLANET_GLYPH", "capitalize", "g2", "nature", "type", "status", "meaning", "transit", "hasBody", "header", "formatNumber", "chevron", "m", "text", "k", "t", "planets", "baseStyles", "disclosureStyles", "__decorateClass", "import_lit", "import_decorators", "PLANET_COLOR", "CYCLE", "planetColor", "name", "index", "capitalize", "WORLD_LAND_PATH", "W", "H", "lonToX", "lon", "latToY", "lat", "TROPIC", "POLAR", "formatLon", "formatLat", "toSegments", "points", "segments", "current", "prevLon", "p", "s", "ANGLE_LABEL", "RoxyAstrocartographyMap", "RoxyDataElement", "data", "lines", "bd", "WORLD_LAND_PATH", "l", "i", "meridians", "x", "axis", "parallels", "y", "refs", "line", "index", "color", "planetColor", "glyph", "items", "planet", "angle", "dashed", "labelY", "anchor", "best", "pts", "rows", "chevron", "text", "code", "baseStyles", "disclosureStyles", "__decorateClass", "import_lit", "import_decorators", "CYCLE_COLOR", "RoxyBiorhythmChart", "RoxyDataElement", "d", "raw", "entries", "cycle", "value", "v", "normalized", "pct", "color", "days", "w", "h", "xStep", "cycleKeys", "points", "day", "i", "x", "y", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "import_lit", "UNIT", "PAD", "VIEW_W", "VIEW_H", "g", "x", "y", "AXIS", "mirrorX", "GATES_BY_CENTER", "SPLEEN_TO_SOLAR_PLEXUS", "buildGatePoints", "points", "centerOf", "spleenGate", "center", "gates", "gate", "GATE_POINTS", "GATE_CENTER", "CHART_AXIS_X", "shape", "corners", "squareShape", "halfWidth", "top", "bottom", "SPLEEN_SHAPE", "CENTER_GEOMETRY", "CHANNEL_PAIRS", "BODY_PATH", "buildBodyPath", "m", "r", "segs", "pt", "i", "ptm", "p", "polygonPoints", "pts", "pairKey", "a", "b", "renderBody", "renderChannels", "activeChannels", "activeGates", "lines", "pa", "pb", "mid", "closestPointOnSegment", "dx", "dy", "len2", "t", "closestPointOnPolygon", "poly", "best", "bestDist", "q", "d", "renderCenters", "defined", "c", "isDefined", "cls", "edge", "renderGateNumbers", "titles", "out", "num", "title", "channelKey", "BODYGRAPH_VIEWBOX", "renderBodygraphSvg", "input", "RoxyBodygraph", "RoxyDataElement", "d", "definedCenters", "c", "activeGates", "g", "n", "activeChannels", "channelKey", "gateTitles", "BODYGRAPH_VIEWBOX", "renderBodygraphSvg", "gates", "titles", "parts", "planet", "capitalize", "glyph", "PLANET_GLYPH", "facts", "ic", "f", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "fmtTime", "iso", "d", "RoxyChoghadiyaGrid", "RoxyDataElement", "period", "now", "start", "end", "effectClass", "current", "lordGlyph", "PLANET_GLYPH", "capitalize", "timeRange", "date", "dayChoghadiya", "nightChoghadiya", "p", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyCompatibilityCard", "RoxyDataElement", "d", "out", "k", "v", "score", "breakdown", "rating", "archetype", "advice", "summary", "interpretation", "strengths", "challenges", "keyAspects", "formatNumber", "s", "a", "formatAspect", "baseStyles", "__decorateClass", "aspect", "orb", "head", "import_lit", "import_decorators", "MONTHS", "RoxyCrystalCard", "RoxyDataElement", "d", "colors", "keywords", "pairs", "month", "c", "k", "p", "label", "value", "values", "m", "present", "v", "text", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "MONTHS", "RoxyCrystalGrid", "RoxyDataElement", "d", "crystals", "title", "total", "c", "col", "cssColor", "baseStyles", "__decorateClass", "name", "import_lit", "import_decorators", "RoxyDashaTimeline", "RoxyDataElement", "d", "periods", "maxYears", "p", "b", "lord", "yrs", "mo", "da", "parts", "remaining", "active", "formatNumber", "now", "start", "end", "max", "years", "width", "current", "progress", "trackClass", "formatYear", "baseStyles", "__decorateClass", "s", "m", "import_lit", "import_decorators", "TITLE_KEYS", "IMAGE_KEYS", "SKIP_KEYS", "MAX_DEPTH", "RoxyData", "RoxyDataElement", "data", "value", "arr", "v", "rows", "keys", "k", "humanize", "row", "obj", "titleKey", "imageKey", "summaryKey", "seen", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "import_lit", "normalizeLongitude", "lon", "wrapped", "longitudeToSignPosition", "longitude", "signIndex", "within", "degree", "minuteFloat", "minute", "second", "SIGNS_ORDER", "formatSignPosition", "sign", "formatDegreeInSign", "deg", "d", "m", "oppositePoint", "arcMidpoint", "start", "end", "s", "span", "polarToCartesian", "cx", "cy", "radius", "angleDeg", "angleRad", "import_lit", "tablistStyles", "renderTablist", "opts", "items", "active", "onSelect", "label", "idPrefix", "controls", "e", "idx", "it", "delta", "next", "root", "VIEW_BOX", "MARGIN", "INNER", "CENTRE", "RASHI_TO_SIGN", "SIGNS_ORDER", "s", "CHART_STYLES", "RETRO_MARK", "isDivisionalPlacement", "p", "cellSign", "longitudeToSignPosition", "grahaLabel", "abbr", "PLANET_ABBR", "capitalize", "retro", "degree", "grahaTitle", "parts", "divisional", "sp", "minute", "pada", "renderPlanetStack", "planets", "cx", "baseY", "lineHeight", "startY", "j", "yPos", "toKundliViewModel", "meta", "divisionLabel", "lagnaOverride", "placements", "sign", "override", "lagnaSign", "name", "pos", "rashiKey", "SOUTH_CELL", "SOUTH_CELL_GRID", "southCellRect", "g", "renderSouthFrame", "b", "c", "d", "e", "houseNumberInSign", "lagnaIdx", "signIdx", "renderSouthCell", "isLagna", "houseNum", "r", "cy", "signAbbr", "SIGN_ABBR", "slashInset", "renderSouthSvg", "vm", "lagnaKey", "NORTH_VERTICES", "centroidOf", "pts", "x", "y", "NORTH_HOUSE_CENTERS", "rashiInHouse", "renderNorthFrame", "tl", "tr", "br", "bl", "top", "right", "bottom", "left", "renderNorthCell", "rashiNum", "rashiOffsetY", "ascOffsetY", "rashiLabel", "renderNorthSvg", "_", "i", "EAST_CELL", "eastCells", "a", "polys", "out", "points", "EAST_CELLS", "renderEastFrame", "renderEastCell", "cell", "cen", "polyPoints", "renderEastSvg", "renderKundliSvg", "style", "renderKundliStyleTablist", "active", "setStyle", "renderTablist", "import_lit", "kundliStyles", "RoxyDivisionalChart", "RoxyDataElement", "next", "division", "label", "toKundliViewModel", "d", "vm", "vargottama", "renderKundliStyleTablist", "renderKundliSvg", "planet", "PLANET_GLYPH", "baseStyles", "kundliStyles", "tablistStyles", "__decorateClass", "import_lit", "import_decorators", "DOSHA_LABELS", "RoxyDoshaCard", "RoxyDataElement", "d", "present", "label", "sevLower", "tier", "pct", "barColor", "r", "sections", "key", "value", "nestedKey", "nestedValue", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyDreamCard", "RoxyDataElement", "d", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyDreamSearch", "RoxyDataElement", "d", "symbols", "total", "s", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "specCache", "loadSpec", "url", "pending", "res", "err", "RoxyEndpointForm", "missing", "f", "m", "out", "v", "g", "spec", "path", "op", "schemas", "fields", "bodySchema", "ref", "required", "name", "sub", "resolved", "subRequired", "subName", "subSchema", "r", "param", "init", "remembered", "message", "schema", "all", "s", "value", "group", "inGroup", "n", "prefix", "e", "detail", "renderField", "inputId", "humanize", "opt", "groups", "locationBlock", "groupBody", "t", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyFixedStars", "RoxyDataElement", "data", "conjunctions", "stars", "formatNumber", "c", "i", "chevron", "s", "g", "SIGN_GLYPH", "capitalize", "formatDegreeInSign", "k", "baseStyles", "disclosureStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyForecastDigest", "RoxyDataElement", "d", "windows", "range", "formatDate", "w", "days", "top", "byDomain", "domains", "dom", "n", "humanize", "e", "sig", "formatNumber", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "DOMAIN_LABEL", "DOMAIN_ORDER", "RoxyForecastTimeline", "RoxyDataElement", "d", "events", "grouped", "present", "dom", "e", "formatDate", "date", "dayEvents", "map", "key", "list", "sig", "width", "body", "capitalize", "target", "aspect", "aspectClass", "ASPECT_CLASS", "aspectSym", "ASPECT_SYMBOL", "orb", "formatNumber", "qualifier", "humanize", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyGunaMilan", "RoxyDataElement", "d", "breakdown", "b", "score", "max", "pct", "trackColor", "fillColor", "dashFill", "dashGap", "formatNumber", "formatPercent", "maxScore", "defaultMax", "x", "baseStyles", "__decorateClass", "name", "import_lit", "import_decorators", "RoxyHdConnection", "RoxyDataElement", "d", "channels", "humanize", "c", "s", "rows", "label", "n", "a", "b", "held", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyHdPenta", "RoxyDataElement", "d", "channels", "upper", "c", "lower", "s", "gaps", "label", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyHdVariables", "RoxyDataElement", "d", "arrows", "a", "b", "quadrantOrder", "glyph", "baseStyles", "__decorateClass", "position", "import_lit", "import_decorators", "RoxyHexagram", "RoxyDataElement", "d", "cast", "daily", "resolved", "h", "castLines", "changingLinePositions", "dailyMessage", "resultingHexagram", "lines", "changing", "l", "idx", "realIdx", "isChanging", "broken", "TRIGRAM_GLYPH", "a", "b", "binary", "c", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "clockTime", "iso", "RoxyHoraTable", "RoxyDataElement", "d", "day", "night", "label", "horas", "h", "PLANET_GLYPH", "capitalize", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyHoroscopeCard", "RoxyDataElement", "d", "sign", "glyph", "SIGN_GLYPH", "capitalize", "energy", "dateLabel", "luckyNumber", "luckyColor", "luckyNumbers", "luckyDays", "compatibleSigns", "s", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyKpChart", "RoxyDataElement", "d", "rows", "p", "nodes", "name", "node", "next", "asc", "formatNumber", "bodies", "b", "cusps", "c", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyKpPlanetsTable", "RoxyDataElement", "d", "planets", "formatNumber", "p", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyKpRulingPlanets", "RoxyDataElement", "d", "significators", "p", "i", "s", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "SIZE", "CENTER", "RIM", "SPOKE", "GLYPH_R", "TICK_LABEL_R", "azimuthPoint", "az", "r", "rad", "PRINCIPAL", "RoxyLocalSpaceCompass", "RoxyDataElement", "data", "bodies", "bd", "ticks", "outer", "inner", "ns1", "ns2", "ew1", "ew2", "labels", "label", "pos", "cardinal", "b", "i", "color", "planetColor", "below", "end", "glyphPos", "glyph", "altLabel", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "debounce", "fn", "wait", "timer", "debounced", "args", "RoxyLocationSearch", "debounce", "q", "value", "target", "message", "controller", "url", "headers", "key", "res", "json", "err", "city", "idx", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyMoonPhase", "RoxyDataElement", "d", "list", "month", "year", "phase", "emoji", "phaseEmoji", "formatIllumination", "formatNumber", "k", "p", "baseStyles", "__decorateClass", "lc", "noMoon", "alias", "MOON_PHASE_EMOJI", "v", "pct", "import_lit", "import_decorators", "RoxyNakshatraCard", "RoxyDataElement", "n", "remedies", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "SIZE", "CENTER", "OUTER_R", "SIGN_R", "HOUSE_R", "PLANET_R", "ANGLE_TICK_R", "ANGLE_LABEL_R", "RoxyNatalChart", "RoxyDataElement", "m", "lon", "data", "planets", "aspects", "view", "renderTablist", "v", "names", "p", "capitalize", "byPair", "a", "k", "n", "g", "PLANET_GLYPH", "rowName", "ri", "rowGlyph", "colName", "name", "normalizeAspect", "sym", "ASPECT_SYMBOL", "cls", "ASPECT_CLASS", "orb", "formatNumber", "asc", "mc", "items", "oppositePoint", "pof", "normalizeLongitude", "vertex", "longitude", "label", "angle", "tickInner", "polarToCartesian", "tickOuter", "labelPos", "houses", "h", "_", "i", "start", "end", "SIGNS_ORDER", "sign", "pos", "SIGN_GLYPH", "house", "next", "mid", "arcMidpoint", "ascSignIndex", "houseNum", "ticks", "deg", "isMajor", "inner", "b", "sp", "longitudeToSignPosition", "sorted", "prev", "cur", "wanted", "last", "shift", "s", "trueLon", "displayLon", "trueAngle", "displayAngle", "glyphPos", "degPos", "rimPos", "leaderInner", "glyph", "retro", "degLabel", "offset", "summary", "ai", "retrogrades", "ELEMENTS", "MODALITIES", "order", "cells", "el", "idx", "mod", "rowTotal", "interp", "chevron", "planetMap", "l1", "l2", "p1", "p2", "aspectName", "aspectClass", "orbLabel", "baseStyles", "tablistStyles", "disclosureStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyNumerologyCard", "RoxyDataElement", "d", "headerLabel", "LABELS", "num", "theme", "body", "keywords", "k", "karmicDebtText", "cores", "v", "humanize", "baseStyles", "__decorateClass", "value", "import_lit", "import_decorators", "RoxyPanchangTable", "RoxyDataElement", "d", "detailed", "fivefold", "placements", "row", "muhurtas", "auspiciousWindows", "inauspicious", "inauspiciousWindows", "transitions", "formatDate", "k", "v", "formatTime", "m", "rows", "range", "formatTimeRange", "label", "windows", "w", "i", "t", "when", "next", "obj", "r", "n", "h", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyPositionsTable", "RoxyDataElement", "data", "vm", "cols", "readings", "r", "b", "glyph", "PLANET_GLYPH", "capitalize", "formatNumber", "sign", "degree", "g", "SIGN_GLYPH", "formatDegreeInSign", "longitude", "p", "longitudeToSignPosition", "open", "chevron", "a", "l", "d", "angleRows", "baseStyles", "disclosureStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyProfectionCard", "RoxyDataElement", "data", "signGlyph", "SIGN_GLYPH", "capitalize", "lordGlyph", "PLANET_GLYPH", "lordNatalGlyph", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "TITLE_KEYS", "PROSE_KEYS", "SKIP_KEYS", "objectLabel", "obj", "v", "RoxyReferenceCard", "RoxyDataElement", "d", "rec", "title", "symbol", "keywords", "prose", "lists", "facts", "collect", "label", "value", "depth", "items", "s", "key", "k", "text", "humanize", "i", "type", "number", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "glyphFor", "name", "PLANET_GLYPH", "capitalize", "RoxyRelocationWheel", "RoxyDataElement", "data", "c", "p", "m", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "BALA_COMPONENTS", "RoxyShadbalaTable", "RoxyDataElement", "d", "sorted", "a", "b", "p", "glyph", "PLANET_GLYPH", "capitalize", "values", "total", "s", "v", "isAdequate", "badgeClass", "badgeLabel", "rupasStr", "formatNumber", "i", "grow", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "SIZE", "CENTER", "OUTER_R", "SIGN_R", "P1_R", "P2_R", "RoxySynastryChart", "RoxyDataElement", "d", "person1", "person2", "compatibilityScore", "analysis", "interAspects", "p1Planets", "p2Planets", "score", "summaryText", "strengths", "challenges", "s", "longitude", "_", "i", "angle", "start", "polarToCartesian", "end", "SIGNS_ORDER", "pos", "SIGN_GLYPH", "planets", "radius", "cls", "personIndex", "p", "degPos", "glyph", "PLANET_GLYPH", "capitalize", "sp", "longitudeToSignPosition", "retro", "degLabel", "tooltip", "data", "items", "make", "asc", "signIdx", "innerR", "tickPos", "labelPos", "p1", "p2", "aspects", "longitudeOf", "list", "name", "target", "a", "l1", "l2", "out", "inn", "aspectName", "normalizeAspect", "ASPECT_CLASS", "orbLabel", "formatNumber", "formatStrength", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyTarotCard", "RoxyDataElement", "d", "card", "isReversed", "keywords", "e", "k", "orientedMeaning", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyTarotCatalog", "RoxyDataElement", "d", "cards", "title", "total", "c", "cardMeta", "baseStyles", "__decorateClass", "capitalize", "import_lit", "import_decorators", "RoxyTarotSpread", "RoxyDataElement", "d", "isYesNo", "isDrawn", "positions", "cards", "answer", "strength", "spreadLabel", "question", "summary", "yesNoInterp", "answerClass", "p", "c", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyTransitsTable", "RoxyDataElement", "d", "transitDate", "transitTime", "transitPlanets", "transitAspects", "summary", "dateStr", "formatDate", "formatTime", "aspectCount", "tab", "renderTablist", "v", "planets", "p", "pGlyph", "PLANET_GLYPH", "capitalize", "sGlyph", "SIGN_GLYPH", "speedArrow", "formatNumber", "aspects", "a", "idx", "tGlyph", "nGlyph", "nature", "interp", "type", "status", "chevron", "k", "baseStyles", "tablistStyles", "disclosureStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyVedicAspects", "RoxyDataElement", "d", "aspects", "mutual", "date", "m", "a", "formatNumber", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyVedicKundli", "RoxyDataElement", "next", "toKundliViewModel", "_d", "vm", "title", "renderKundliStyleTablist", "renderKundliSvg", "baseStyles", "kundliStyles", "tablistStyles", "__decorateClass", "import_lit", "import_decorators", "GRAHA_ORDER", "RoxyVedicPlanetsTable", "RoxyDataElement", "meta", "seen", "rows", "name", "entry", "d", "p", "isLagna", "glyph", "PLANET_GLYPH", "capitalize", "signGlyph", "SIGN_GLYPH", "formatSignPosition", "combust", "chevron", "c", "dist", "formatNumber", "orb", "wars", "w", "interp", "entries", "v", "houses", "h", "yogas", "y", "baseStyles", "disclosureStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyWesternPlanetsTable", "RoxyDataElement", "d", "rows", "p", "name", "point", "glyph", "PLANET_GLYPH", "capitalize", "signGlyph", "SIGN_GLYPH", "speed", "formatNumber", "formatSignPosition", "baseStyles", "__decorateClass", "import_lit", "import_decorators", "RoxyYogaList", "RoxyDataElement", "quality", "cls", "yoga", "y", "d", "lc", "allYogas", "detected", "filtered", "ordered", "presentCount", "detailYogas", "total", "catalogYogas", "baseStyles", "__decorateClass", "ROXY_COMPONENTS", "ROXY_UI_VERSION", "ROXY_UI_COMPONENTS", "ROXY_COMPONENTS", "c"]
7
7
  }