@roxyapi/ui 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +6 -0
- package/README.md +6 -0
- package/components-catalog.json +111 -1
- package/dist/cdn/components/astrocartography-map.js +58 -0
- package/dist/cdn/components/astrocartography-map.js.map +7 -0
- package/dist/cdn/components/divisional-chart.js +7 -7
- package/dist/cdn/components/divisional-chart.js.map +1 -1
- package/dist/cdn/components/dosha-card.js +2 -2
- package/dist/cdn/components/dosha-card.js.map +3 -3
- package/dist/cdn/components/fixed-stars.js +52 -0
- package/dist/cdn/components/fixed-stars.js.map +7 -0
- package/dist/cdn/components/hd-variables.js +2 -2
- package/dist/cdn/components/hd-variables.js.map +3 -3
- package/dist/cdn/components/hexagram.js +3 -3
- package/dist/cdn/components/hexagram.js.map +3 -3
- package/dist/cdn/components/local-space-compass.js +58 -0
- package/dist/cdn/components/local-space-compass.js.map +7 -0
- package/dist/cdn/components/moon-phase.js +3 -3
- package/dist/cdn/components/moon-phase.js.map +3 -3
- package/dist/cdn/components/natal-chart.js +8 -8
- package/dist/cdn/components/natal-chart.js.map +2 -2
- package/dist/cdn/components/positions-table.js +52 -0
- package/dist/cdn/components/positions-table.js.map +7 -0
- package/dist/cdn/components/profection-card.js +52 -0
- package/dist/cdn/components/profection-card.js.map +7 -0
- package/dist/cdn/components/reference-card.js +3 -3
- package/dist/cdn/components/reference-card.js.map +3 -3
- package/dist/cdn/components/relocation-wheel.js +61 -0
- package/dist/cdn/components/relocation-wheel.js.map +7 -0
- package/dist/cdn/components/synastry-chart.js +4 -4
- package/dist/cdn/components/synastry-chart.js.map +2 -2
- package/dist/cdn/components/vedic-kundli.js +5 -5
- package/dist/cdn/components/vedic-kundli.js.map +1 -1
- package/dist/cdn/components/vedic-planets-table.js +2 -2
- package/dist/cdn/components/vedic-planets-table.js.map +1 -1
- package/dist/cdn/components/western-planets-table.js +2 -2
- package/dist/cdn/components/western-planets-table.js.map +1 -1
- package/dist/cdn/components/yoga-list.js +3 -3
- package/dist/cdn/components/yoga-list.js.map +3 -3
- package/dist/cdn/roxy-ui.js +83 -71
- package/dist/cdn/roxy-ui.js.map +4 -4
- package/dist/components/astrocartography-map.d.ts +27 -0
- package/dist/components/astrocartography-map.d.ts.map +1 -0
- package/dist/components/astrocartography-map.js +8 -0
- package/dist/components/astrocartography-map.js.map +7 -0
- package/dist/components/divisional-chart.js +22 -22
- package/dist/components/divisional-chart.js.map +1 -1
- package/dist/components/dosha-card.d.ts.map +1 -1
- package/dist/components/dosha-card.js +1 -1
- package/dist/components/dosha-card.js.map +3 -3
- package/dist/components/fixed-stars.d.ts +21 -0
- package/dist/components/fixed-stars.d.ts.map +1 -0
- package/dist/components/fixed-stars.js +2 -0
- package/dist/components/fixed-stars.js.map +7 -0
- package/dist/components/hd-variables.d.ts.map +1 -1
- package/dist/components/hd-variables.js +1 -1
- package/dist/components/hd-variables.js.map +3 -3
- package/dist/components/hexagram.d.ts +3 -1
- package/dist/components/hexagram.d.ts.map +1 -1
- package/dist/components/hexagram.js +1 -1
- package/dist/components/hexagram.js.map +3 -3
- package/dist/components/local-space-compass.d.ts +23 -0
- package/dist/components/local-space-compass.d.ts.map +1 -0
- package/dist/components/local-space-compass.js +8 -0
- package/dist/components/local-space-compass.js.map +7 -0
- package/dist/components/moon-phase.d.ts.map +1 -1
- package/dist/components/moon-phase.js +1 -1
- package/dist/components/moon-phase.js.map +3 -3
- package/dist/components/natal-chart.d.ts +2 -0
- package/dist/components/natal-chart.d.ts.map +1 -1
- package/dist/components/natal-chart.js +6 -6
- package/dist/components/natal-chart.js.map +2 -2
- package/dist/components/positions-table.d.ts +34 -0
- package/dist/components/positions-table.d.ts.map +1 -0
- package/dist/components/positions-table.js +2 -0
- package/dist/components/positions-table.js.map +7 -0
- package/dist/components/profection-card.d.ts +18 -0
- package/dist/components/profection-card.d.ts.map +1 -0
- package/dist/components/profection-card.js +2 -0
- package/dist/components/profection-card.js.map +7 -0
- package/dist/components/reference-card.d.ts.map +1 -1
- package/dist/components/reference-card.js +1 -1
- package/dist/components/reference-card.js.map +3 -3
- package/dist/components/relocation-wheel.d.ts +21 -0
- package/dist/components/relocation-wheel.d.ts.map +1 -0
- package/dist/components/relocation-wheel.js +11 -0
- package/dist/components/relocation-wheel.js.map +7 -0
- package/dist/components/synastry-chart.js +3 -3
- package/dist/components/synastry-chart.js.map +2 -2
- package/dist/components/vedic-kundli.js +14 -14
- package/dist/components/vedic-kundli.js.map +1 -1
- package/dist/components/vedic-planets-table.js +1 -1
- package/dist/components/vedic-planets-table.js.map +1 -1
- package/dist/components/western-planets-table.js +1 -1
- package/dist/components/western-planets-table.js.map +1 -1
- package/dist/components/yoga-list.d.ts +5 -2
- package/dist/components/yoga-list.d.ts.map +1 -1
- package/dist/components/yoga-list.js +1 -1
- package/dist/components/yoga-list.js.map +3 -3
- package/dist/generated/endpoint-bindings.d.ts.map +1 -1
- package/dist/index.cjs +62 -50
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +62 -50
- package/dist/index.js.map +4 -4
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.json +6 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/types.gen.d.ts +7864 -5381
- package/dist/types/types.gen.d.ts.map +1 -1
- package/dist/utils/degree.d.ts +2 -0
- package/dist/utils/degree.d.ts.map +1 -1
- package/dist/utils/planet-color.d.ts +3 -0
- package/dist/utils/planet-color.d.ts.map +1 -0
- package/dist/version.d.ts +1 -1
- package/package.json +2 -1
- package/src/components/astrocartography-map.ts +436 -0
- package/src/components/dosha-card.ts +48 -16
- package/src/components/fixed-stars.ts +254 -0
- package/src/components/hd-variables.ts +30 -2
- package/src/components/hexagram.ts +11 -11
- package/src/components/local-space-compass.ts +299 -0
- package/src/components/moon-phase.ts +21 -2
- package/src/components/natal-chart.ts +36 -24
- package/src/components/positions-table.ts +442 -0
- package/src/components/profection-card.ts +173 -0
- package/src/components/reference-card.ts +40 -8
- package/src/components/relocation-wheel.ts +170 -0
- package/src/components/yoga-list.ts +95 -2
- package/src/generated/endpoint-bindings.ts +62 -0
- package/src/index.ts +6 -0
- package/src/manifest.ts +79 -0
- package/src/types/index.ts +1 -1
- package/src/types/types.gen.ts +7814 -5263
- package/src/utils/degree.ts +11 -0
- package/src/utils/planet-color.ts +45 -0
- package/src/version.ts +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -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><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/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';\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}.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}\"/>${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", "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><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.0';\n"],
|
|
5
|
+
"mappings": "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CD,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,SvE4FxB,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", "W", "H", "lonToX", "lon", "latToY", "lat", "TROPIC", "POLAR", "formatLon", "formatLat", "toSegments", "points", "segments", "current", "prevLon", "p", "s", "ANGLE_LABEL", "RoxyAstrocartographyMap", "RoxyDataElement", "data", "lines", "bd", "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", "k", "key", "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
|
}
|