@roxyapi/ui 0.15.0 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../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/utils/disclosure.ts", "../src/utils/interp-accordion.ts", "../src/components/ashtakavarga-grid.ts", "../src/tokens/index.ts", "../src/utils/tablist.ts", "../src/components/aspects-table.ts", "../src/utils/format.ts", "../src/utils/string.ts", "../src/components/astrocartography-map.ts", "../src/utils/planet-color.ts", "../src/utils/world-map.ts", "../src/components/biorhythm-chart.ts", "../src/components/bodygraph.ts", "../src/utils/bodygraph-render.ts", "../src/utils/hd-reading.ts", "../src/components/choghadiya-grid.ts", "../src/components/compatibility-card.ts", "../src/components/crystal-card.ts", "../src/utils/css-color.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/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-type-card.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", "../src/index.ts"],
4
- "sourcesContent": ["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\tqueryKeys?: string[];\n\t\t};\n\t\tif (this.remember) this.writeRemembered(detail.values);\n\t\tvoid this.fetcher.run(\n\t\t\tbuildRequest(\n\t\t\t\tthis.endpoint,\n\t\t\t\tthis.method,\n\t\t\t\tdetail.values,\n\t\t\t\tdetail.queryKeys ?? [],\n\t\t\t),\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-sr-only{clip-path:inset(50%);white-space:nowrap;border:0;width:1px;height:1px;margin:0;padding:0;position:absolute;overflow:hidden}.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 the form mixin can attach a controller without the component wiring state by hand.\n *\n * @remarks\n * Intersected with `HTMLElement` because the controller dispatches events on the host. Lit's `ReactiveControllerHost` is the update-lifecycle contract only (`addController`, `requestUpdate`, `updateComplete`) and carries no DOM surface, even though every real host is a `LitElement` and therefore an `HTMLElement`. Declaring the DOM half is what the controller actually needs; it used to reach it through a `this.host as unknown as EventTarget` double cast instead, which asserted a capability the type never promised.\n */\ntype FetchHost<T> = ReactiveControllerHost &\n\tHTMLElement & {\n\t\tdata: T | null;\n\t\tloading: boolean;\n\t\terror: string | null;\n\t};\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\tthis.host.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 *\n * @param queryKeys - Names the spec declares as `in: query` for this operation, which `<roxy-endpoint-form>` reports on its `roxy-submit` event. A POST operation can still take query parameters (every localized endpoint takes `?lang=`), and sending one in the JSON body silently drops it, so those names are routed to the query string on POST as well as GET.\n */\nexport function buildRequest(\n\tendpoint: string,\n\tmethod: 'GET' | 'POST',\n\tvalues: Record<string, unknown>,\n\tqueryKeys: readonly string[] = [],\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 inQuery = new Set(queryKeys);\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' || inQuery.has(k)) 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';\nimport { disclosureStyles } from '../utils/disclosure.js';\nimport {\n\tinterpAccordionStyles,\n\trenderInterpAccordion,\n} from '../utils/interp-accordion.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 context note when the caller said where the number was seen, 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\tdisclosureStyles,\n\t\tinterpAccordionStyles,\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)}.badge.energy-positive{background:color-mix(in srgb, var(--roxy-success,#16a34a) 18%, transparent)}.badge.energy-cautionary{background:color-mix(in srgb, var(--roxy-warning,#ea580c) 18%, transparent)}.context{gap:var(--roxy-space-xs,.25rem);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);border-radius:0 var(--roxy-radius-sm,4px) var(--roxy-radius-sm,4px) 0;display:grid}.steps{gap:var(--roxy-space-xs,.25rem);color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);margin:0;padding-left:1.1rem;line-height:1.6;display:grid}.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}`,\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\t\tconst steps = known?.actionSteps ?? [];\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} ${known?.energy ? html`<span class=\"${`badge energy-${known.energy}`}\">${known.energy} energy</span>` : nothing}</div>${\n\t\t\t\td.contextNote\n\t\t\t\t\t? html`<div class=\"context\"><p class=\"label\">Where you saw it</p><p>${d.contextNote}</p></div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\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, 'lookup-known', known.biblical, known.shadow)} ${known.affirmation ? html`<p><em>${known.affirmation}</em></p>` : nothing} ${\n\t\t\t\t\t\t\tsteps.length > 0\n\t\t\t\t\t\t\t\t? html`<p class=\"label\">What to do next</p><ol class=\"steps\">${steps.map((s) => html`<li>${s}</li>`)}</ol>`\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\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\tname: string,\n\t\tbiblical?: string,\n\t\tshadow?: string,\n\t) {\n\t\treturn renderInterpAccordion(\n\t\t\tbuildMeaningSections(meaning, biblical, shadow),\n\t\t\tname,\n\t\t\t'Reading',\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, 'lookup-root')}${\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 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 * The interpretation accordion: the one way this library shows a label, a short value, and a body of prose behind a disclosure.\n *\n * @remarks\n * Exclusive by construction (`<details name>`), so a card grows by at most one open section and never becomes a wall of text. Callers pass their own group `name` so two accordions on one page do not fight over which section is open.\n *\n * This lives here rather than in a component because the same accordion is the right shape wherever an endpoint returns a labelled reading: the Human Design bodygraph and type card use it for strategy, authority, and aura; `roxy-hexagram` uses it for the changing lines. The CSS was copy-pasted into six components before 2026-07 and had already drifted (`.interp-body` had five distinct definitions), which is the drift this exists to stop. Migrate the remaining copies to it when they are next touched.\n */\n\nimport { css, html, nothing } from 'lit';\nimport { chevron } from './disclosure.js';\n\n/** One row: the label, the short value shown as the aside, and the interpretation body. `extra` renders under the body for a section that carries more than prose. */\nexport interface InterpSection {\n\tlabel: string;\n\taside?: string;\n\tbody: string;\n\textra?: unknown;\n}\n\nexport const interpAccordionStyles = css`.block{border-top:1px solid var(--roxy-border,#e4e4e7);padding-top:var(--roxy-space-md,1rem)}.block h3{margin:0 0 var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em}.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);align-items:center;gap:var(--roxy-space-sm,.5rem);font-weight:500;font-size:var(--roxy-text-sm,.875rem);display:flex}.interp-card summary:focus-visible{outline:2px solid var(--roxy-ring,#f59e0b66);outline-offset:2px;border-radius:var(--roxy-radius-sm,4px)}.interp-lead{flex-wrap:wrap;flex:auto;order:1;align-items:baseline;gap:.4rem;min-width:0;display:inline-flex}.interp-aside{flex-shrink:0;order:2;align-items:center;gap:.5rem;display:inline-flex}.roxy-chevron{order:3}.interp-aside small{color:var(--roxy-muted,#71717a);white-space:nowrap;font-weight:400}@container (width<=26rem){.interp-card summary{flex-wrap:wrap}.roxy-chevron{order:2}.interp-aside{flex-basis:100%;order:3;justify-content:flex-end}}.interp-body{margin-top:var(--roxy-space-sm,.5rem);gap:var(--roxy-space-sm,.5rem);color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);overflow-wrap:anywhere;line-height:1.6;display:grid}.interp-body p{margin:0}`;\n\n/**\n * Render the accordion. Sections with no body are dropped, so a caller can pass the full set and let a narrower response render only what it carries. `name` groups the `<details>` exclusively, so opening one closes the last.\n */\nexport function renderInterpAccordion(\n\tsections: InterpSection[],\n\tname: string,\n\theading = 'Reading',\n) {\n\tconst shown = sections.filter((s) => Boolean(s.body));\n\tif (shown.length === 0) return nothing;\n\n\treturn html`<section class=\"block\"><h3>${heading}</h3>${shown.map(\n\t\t\t(s, i) => html`<details class=\"interp-card\" name=\"${name}\" ?open=\"${i === 0}\"><summary><span class=\"interp-lead\">${s.label}</span> ${chevron()} ${s.aside ? html`<span class=\"interp-aside\"><small>${s.aside}</small></span>` : nothing}</summary><div class=\"interp-body\"><p>${s.body}</p>${s.extra ?? nothing}</div></details>`,\n\t\t)}</section>`;\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';\nimport {\n\trenderTablist,\n\ttype TablistItem,\n\ttablistStyles,\n} from '../utils/tablist.js';\n\ntype Tab = 'sarva' | 'bhinna' | 'reduced' | 'pinda';\n\nconst TABS: ReadonlyArray<TablistItem<Tab>> = [\n\t{ id: 'sarva', label: 'Sarvashtakavarga' },\n\t{ id: 'bhinna', label: 'Bhinnashtakavarga' },\n\t{ id: 'reduced', label: 'Reduced' },\n\t{ id: 'pinda', label: 'Shodhya Pinda' },\n];\n\ntype Signs = AshtakavargaResponse['signs'];\ntype BhinnaRow = AshtakavargaResponse['bhinnashtakavarga'][number];\ntype SarvaRow = AshtakavargaResponse['sarvashtakavarga'];\n\n/**\n * Ashtakavarga grid: Sarvashtakavarga, Bhinnashtakavarga, the Shodhana-reduced\n * grid, and Shodhya Pinda. Pass `data` from /vedic-astrology/ashtakavarga.\n *\n * @remarks\n * Bindus are benefic points, so MORE is better in every view here. The colour\n * ramp is therefore diverging, not a single hot hue: a weak count tints toward\n * --roxy-heat (which resolves to the danger token), the classical average stays\n * neutral, a strong count tints toward --roxy-success, and each tab states its\n * own scale in a legend. The previous single-hue ramp painted the best signs the\n * most alarming shade, the exact opposite of what the numbers mean.\n */\n@customElement('roxy-ashtakavarga-grid')\nexport class RoxyAshtakavargaGrid extends RoxyDataElement<AshtakavargaResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\ttablistStyles,\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);grid-template-columns:minmax(0,1fr);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}.overflow-scroll{-webkit-overflow-scrolling:touch;min-width:0;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}.bindu-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)}.tier-1{background:color-mix(in srgb, var(--roxy-heat,#ef4444) 30%, transparent)}.tier-2{background:color-mix(in srgb, var(--roxy-heat,#ef4444) 17%, transparent)}.tier-3{background:color-mix(in srgb, var(--roxy-heat,#ef4444) 7%, transparent)}.tier-4{background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 45%, transparent)}.tier-5{background:color-mix(in srgb, var(--roxy-success,#16a34a) 16%, transparent)}.tier-6{background:color-mix(in srgb, var(--roxy-success,#16a34a) 32%, transparent)}.tier-7{background:color-mix(in srgb, var(--roxy-success,#16a34a) 50%, transparent)}.legend{align-items:center;gap:var(--roxy-space-xs,.25rem) var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);flex-wrap:wrap;display:flex}.legend-scale{gap:2px;display:flex}.legend-swatch{border-radius:2px;width:16px;height:10px}.legend-note{flex:12rem}.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}.bindu-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>${renderTablist({\n\t\t\t\titems: TABS,\n\t\t\t\tactive: this.activeTab,\n\t\t\t\tonSelect: (id) => {\n\t\t\t\t\tthis.activeTab = id;\n\t\t\t\t},\n\t\t\t\tlabel: 'Ashtakavarga views',\n\t\t\t\tidPrefix: 'ashtakavarga',\n\t\t\t\tcontrols: true,\n\t\t\t})}<div id=\"ashtakavarga-panel-${this.activeTab}\" role=\"tabpanel\" aria-labelledby=\"ashtakavarga-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.activeTab === 'reduced'\n\t\t\t\t\t\t\t\t? this.renderReduced(signs)\n\t\t\t\t\t\t\t\t: this.renderPinda()\n\t\t\t\t}</div></div>`;\n\t}\n\n\t/**\n\t * Bhinna bindus per planet per sign run 0..8 (one 0/1 contribution from each\n\t * of the 8 reference points). 4 is the mid, so it holds the neutral tier and\n\t * anything above it reads as support. The reduced grid uses the same 0..8\n\t * units, so it shares this scale.\n\t */\n\tprivate bhinnaTier(count: number): string {\n\t\tif (count <= 1) return 'tier-1';\n\t\tif (count <= 2) return 'tier-2';\n\t\tif (count <= 3) return 'tier-3';\n\t\tif (count <= 4) return 'tier-4';\n\t\tif (count <= 5) return 'tier-5';\n\t\tif (count <= 6) return 'tier-6';\n\t\treturn 'tier-7';\n\t}\n\n\t/**\n\t * Sarva bindus per sign are the column total across the 7 planets. The grand\n\t * total is always 337, so the classical average is 337/12 = 28.08 and the\n\t * bands used by readers are: under 25 weak, 25 to 29 average, 30 and above\n\t * strong, with the highest signs carrying transits best. The tiers follow\n\t * those bands rather than an even split, so 28 sits on the neutral tier.\n\t */\n\tprivate sarvaTier(count: number): string {\n\t\tif (count <= 20) return 'tier-1';\n\t\tif (count <= 24) return 'tier-2';\n\t\tif (count <= 27) return 'tier-3';\n\t\tif (count <= 29) return 'tier-4';\n\t\tif (count <= 32) return 'tier-5';\n\t\tif (count <= 36) return 'tier-6';\n\t\treturn 'tier-7';\n\t}\n\n\t/**\n\t * The scale, stated. Without this a reader has to guess whether a saturated\n\t * cell is good or bad, and in a bindu grid the answer is always \"good\".\n\t */\n\tprivate renderLegend(note: string) {\n\t\treturn html`<div class=\"legend\"><span>Fewer bindus</span> <span class=\"legend-scale\" aria-hidden=\"true\">${[1, 2, 3, 4, 5, 6, 7].map(\n\t\t\t\t\t(t) => html`<span class=\"legend-swatch tier-${t}\"></span>`,\n\t\t\t\t)} </span><span>More bindus</span> <span class=\"legend-note\">${note}</span></div>`;\n\t}\n\n\tprivate renderSarva(signs: 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><caption class=\"roxy-sr-only\">Sarvashtakavarga: each of the twelve signs and the bindus all planets contribute to it, with a grand total.</caption><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\t\tconst count = sav.bindus[i] ?? 0;\n\t\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=\"${`bindu-cell ${this.sarvaTier(count)}`}\">${count}</td></tr>`;\n\t\t\t\t\t\t})}</tbody><tfoot><tr class=\"total-row\"><td>Total</td><td>${sav.total}</td></tr></tfoot></table></div>${this.renderLegend(\n\t\t\t\t'Under 25 is a weak sign, 25 to 29 average, 30 and above strong. The 12 signs always total 337.',\n\t\t\t)}`;\n\t}\n\n\tprivate renderBhinna(signs: 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`${this.renderBinduGrid(\n\t\t\tsigns,\n\t\t\tbhinna,\n\t\t\t'Bhinnashtakavarga: the bindus each planet scores in every one of the twelve signs, with a row total.',\n\t\t)} ${this.renderLegend(\n\t\t\t'Each planet scores 0 to 8 bindus per sign. 4 is the mid, 5 and above is strong support for that planet in that sign.',\n\t\t)}`;\n\t}\n\n\t/**\n\t * The Shodhana-purified grid (Trikona then Ekadipati), which is what Shodhya\n\t * Pinda is computed from. The column totals are the Reduced Sarvashtakavarga,\n\t * so they are shown as the total row rather than as a second table.\n\t */\n\tprivate renderReduced(signs: Signs) {\n\t\tconst reduced = this.data?.reducedBhinnashtakavarga;\n\t\tconst rsav = this.data?.reducedSarvashtakavarga;\n\t\tif (!reduced?.length && !rsav)\n\t\t\treturn html`<p class=\"roxy-empty\">No reduced ashtakavarga data</p>`;\n\n\t\treturn html`${this.renderBinduGrid(\n\t\t\tsigns,\n\t\t\treduced ?? [],\n\t\t\t'Reduced Bhinnashtakavarga after Shodhana: the bindus each planet keeps in every one of the twelve signs, with a row total and a Reduced Sarvashtakavarga totals row.',\n\t\t\trsav,\n\t\t)} ${this.renderLegend(\n\t\t\t'Bindus left after Trikona and Ekadipati Shodhana, the input to Shodhya Pinda. The Reduced SAV row totals the seven planets only, so it does not include the Lagna row above it.',\n\t\t)}`;\n\t}\n\n\t/**\n\t * The planet-by-sign grid both the bhinna and the reduced tabs draw. The rows\n\t * are the 7 planets plus Lagna, but a Sarva total counts the 7 planets only\n\t * (which is why the classical SAV grand total is 337), so the totals row is\n\t * named for what it is rather than left to read as a column sum.\n\t */\n\tprivate renderBinduGrid(\n\t\tsigns: Signs,\n\t\trows: BhinnaRow[],\n\t\tcaption: string,\n\t\ttotals?: SarvaRow,\n\t) {\n\t\tif (!rows.length) return html`<p class=\"roxy-empty\">No bindu data</p>`;\n\t\treturn html`<div class=\"overflow-scroll\"><table class=\"bhinna-table\"><caption class=\"roxy-sr-only\">${caption}</caption><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>${rows.map(\n\t\t\t\t\t\t(row) => html`<tr><td>${row.planet}</td>${row.bindus.map(\n\t\t\t\t\t\t\t(count) =>\n\t\t\t\t\t\t\t\thtml`<td class=\"${`bindu-cell ${this.bhinnaTier(count)}`}\">${count}</td>`,\n\t\t\t\t\t\t)}<td>${row.total}</td></tr>`,\n\t\t\t\t\t)}</tbody>${\n\t\t\t\t\ttotals\n\t\t\t\t\t\t? html`<tfoot><tr class=\"total-row\"><td>Reduced SAV</td>${signs.map((_, i) => html`<td>${totals.bindus[i] ?? 0}</td>`)}<td>${totals.total}</td></tr></tfoot>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</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><caption class=\"roxy-sr-only\">Shodhya Pinda: each planet with its Rashi Pinda, Graha Pinda and Shodhya Pinda strength scores.</caption><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 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);scrollbar-width:thin;gap:2px;min-width:0;display:flex;overflow-x:auto}.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;flex-shrink:0;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, 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, normalizeAspect } from '../utils/format.js';\nimport { interpAccordionStyles } from '../utils/interp-accordion.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, apex first.\n */\ntype AspectsData =\n\t| CalculateAspectsResponse\n\t| CalculateTransitAspectsResponse\n\t| DetectAspectPatternsResponse;\n\ntype PatternEntry = NonNullable<\n\tDetectAspectPatternsResponse['patterns']\n>[number];\n\n/**\n * Round a 0-100 score for display.\n *\n * @remarks\n * Not `formatNumber(v, 0)`: that helper strips trailing zeros from the formatted string, so a strength of 100 renders as \"1\" and 90 as \"9\". Kept local until `utils/format.ts` is fixed.\n */\nfunction score(v: unknown): string {\n\treturn typeof v === 'number' && Number.isFinite(v)\n\t\t? String(Math.round(v))\n\t\t: '';\n}\n\n/**\n * One line naming the orb budget and the body set a pattern run used, so a reader can reproduce the detection. Built as a string, not a template: interpolating the clauses in markup leaves a space before the comma.\n */\nfunction provenance(o: NonNullable<DetectAspectPatternsResponse['options']>) {\n\tconst orbs = o.strictOrbs ? 'strict' : 'industry-standard';\n\tconst bodies = o.include?.length\n\t\t? `including ${o.include.join(' and ')}`\n\t\t: 'classical bodies only';\n\treturn `Detected with ${orbs} orbs, ${bodies}.`;\n}\n\n/** Reading order for detected configurations: the rare, chart-defining figures first, then by tightness. Mirrors `roxy-natal-chart`, which renders the same `patterns` shape. */\nconst PATTERN_ORDER: Record<string, number> = {\n\tGRAND_CROSS: 0,\n\tGRAND_TRINE: 1,\n\tKITE: 2,\n\tT_SQUARE: 3,\n\tYOD: 4,\n\tMYSTIC_RECTANGLE: 5,\n\tSTELLIUM: 6,\n};\n\n@customElement('roxy-aspects-table')\nexport class RoxyAspectsTable extends RoxyDataElement<AspectsData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tdisclosureStyles,\n\t\tinterpAccordionStyles,\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}.interp-card summary{flex-wrap:wrap;gap:.5em}.interp-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}.static-head{font-size:var(--roxy-text-sm,.875rem);flex-wrap:wrap;align-items:center;gap:.5em;font-weight:500;display:flex}.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-tag{border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 55%, transparent);color:var(--roxy-fg,#0a0a0a);text-transform:capitalize;padding:1px 8px}.pattern-planets{flex-wrap:wrap;gap:.25rem;display:flex}.planet-chip{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);align-items:baseline;gap:.3rem;padding:1px 8px;display:inline-flex}.planet-chip.apex{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 20%, transparent);font-weight:var(--roxy-weight-bold,600)}.planet-chip .apex-tag{text-transform:uppercase;letter-spacing:.04em;font-size:.85em;font-weight:400}.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}.strongest{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);font-size:var(--roxy-text-sm,.875rem);flex-wrap:wrap;align-items:baseline;gap:.4rem;display:flex}.strongest .label{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);text-transform:uppercase;letter-spacing:.06em;font-weight:var(--roxy-weight-bold,600)}.strongest .meta{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);font-variant-numeric:tabular-nums;margin-left:auto}.provenance{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);margin:0}`,\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\t// Natal aspects date the chart, transits date the sky.\n\t\tconst date = 'transitDate' in d ? d.transitDate : 'date' in d ? d.date : '';\n\t\tconst options = 'options' in d ? d.options : undefined;\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Aspects\"><div class=\"head\"><h2 class=\"title\">${aspects.length === 0 ? 'Aspect patterns' : 'Aspects'}</h2>${\n\t\t\t\t\taspects.length > 0 || date\n\t\t\t\t\t\t? html`<p class=\"subtitle\">${[\n\t\t\t\t\t\t\t\taspects.length > 0\n\t\t\t\t\t\t\t\t\t? `${aspects.length} aspect${aspects.length === 1 ? '' : 's'}`\n\t\t\t\t\t\t\t\t\t: '',\n\t\t\t\t\t\t\t\tdate,\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t.join(' \u00B7 ')}</p>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</div>${summary ? this.renderSummary(summary) : nothing} ${summary && 'strongest' in summary && summary.strongest ? this.renderStrongest(summary.strongest) : 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]\n\t\t\t\t\t\t\t.sort(\n\t\t\t\t\t\t\t\t(a, b) =>\n\t\t\t\t\t\t\t\t\t(PATTERN_ORDER[a.kind] ?? 9) - (PATTERN_ORDER[b.kind] ?? 9) ||\n\t\t\t\t\t\t\t\t\t(b.tightness ?? 0) - (a.tightness ?? 0),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.map((p) => this.renderPattern(p))}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${options ? html`<p class=\"provenance\">${provenance(options)}</p>` : nothing}</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\t// byType is a map, not a list: render the pairs, never the object.\n\t\tconst byType = Object.entries(s.byType ?? {}).sort((a, b) => b[1] - a[1]);\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> ${byType.map(\n\t\t\t\t([type, count]) =>\n\t\t\t\t\thtml`<span class=\"pill pill--muted\">${capitalize(type.replace(/_/g, ' '))}: ${count}</span>`,\n\t\t\t)}</div>`;\n\t}\n\n\t/**\n\t * The tightest transit by orb: the one aspect the client is most likely to\n\t * feel today. Lifted out of the list so it is not buried among the rest.\n\t */\n\tprivate renderStrongest(\n\t\ts: NonNullable<\n\t\t\tNonNullable<CalculateTransitAspectsResponse['summary']>['strongest']\n\t\t>,\n\t) {\n\t\tconst g1 = PLANET_GLYPH[capitalize(s.planet1)] ?? '';\n\t\tconst g2 = PLANET_GLYPH[capitalize(s.planet2)] ?? '';\n\t\tconst nature = (s.interpretation ?? 'neutral').toLowerCase();\n\t\treturn html`<div class=\"strongest\"><span class=\"label\">Strongest</span> <span aria-hidden=\"true\" class=\"glyph\">${g1}</span>${s.planet1} <span class=\"nature-badge ${nature}\">${normalizeAspect(s)}</span> <span aria-hidden=\"true\" class=\"glyph\">${g2}</span>${s.planet2} <span class=\"meta\">${s.isApplying ? 'Applying' : 'Separating'} \u00B7 orb ${formatNumber(s.orb, 2)}\u00B0 \u00B7 str ${score(s.strength)}</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 ${score(a.strength)}</span>`;\n\t\tif (!hasBody) {\n\t\t\treturn html`<div class=\"interp-card\" role=\"listitem\"><div class=\"static-head\">${header}</div></div>`;\n\t\t}\n\t\treturn html`<details class=\"interp-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\t/**\n\t * One detected configuration. The apex (the focal planet a Kite, T-Square, or Yod discharges through) leads the chip row and is called out, since a T-Square read without its apex is not a reading. `element` and `modality` only appear on the kinds whose meaning pivots on them, so they are tags rather than columns.\n\t */\n\tprivate renderPattern(p: PatternEntry) {\n\t\tconst planets = p.planets ?? [];\n\t\tconst ordered = p.apex\n\t\t\t? [...planets].sort((a, b) => Number(b === p.apex) - Number(a === p.apex))\n\t\t\t: planets;\n\t\treturn html`<div class=\"pattern\"><div class=\"pattern-head\"><span class=\"pattern-name\">${p.name ?? p.kind ?? 'Pattern'}</span> ${p.element ? html`<span class=\"pattern-tag\">${p.element}</span>` : nothing} ${p.modality ? html`<span class=\"pattern-tag\">${p.modality}</span>` : nothing} ${\n\t\t\t\t\tp.dissociate\n\t\t\t\t\t\t? html`<span class=\"pattern-tag\" title=\"Out of sign: one or more planets sit outside the pattern element or modality, so the theme holds but runs weaker.\">Dissociate</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} ${typeof p.tightness === 'number' ? html`<span class=\"pattern-tight\">${Math.round(p.tightness)}% tight</span>` : nothing}</div>${\n\t\t\t\tordered.length\n\t\t\t\t\t? html`<div class=\"pattern-planets\">${ordered.map((name) => {\n\t\t\t\t\t\t\tconst glyph = PLANET_GLYPH[capitalize(name)];\n\t\t\t\t\t\t\tconst isApex = Boolean(p.apex) && name === p.apex;\n\t\t\t\t\t\t\treturn html`<span class=\"${isApex ? 'planet-chip apex' : 'planet-chip'}\">${glyph ? html`<span aria-hidden=\"true\">${glyph}</span>` : nothing}${name}${isApex ? html`<span class=\"apex-tag\">apex</span>` : nothing}</span>`;\n\t\t\t\t\t\t})}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${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", "/**\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\nconst DATE_ONLY = /^\\d{4}-\\d{2}-\\d{2}$/;\nconst BARE_TIME = /^\\d{2}:\\d{2}(:\\d{2})?$/;\n/** An ISO datetime with NO timezone designator: a wall clock, not an instant. */\nconst NAIVE_DATETIME = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(:\\d{2}(\\.\\d+)?)?$/;\n\n/**\n * Resolve an API timestamp to a Date plus the timezone it must be RENDERED in.\n *\n * @remarks\n * The API returns chart times naive (`2026-07-13T04:36:00`): that is 04:36 in the CHART's timezone, not UTC and not the viewer's. A wall clock must read the same for every viewer on earth, so hora at sunrise says 04:36 in Tokyo and in Chicago alike.\n *\n * Handing a naive string to `new Date()` makes the runtime interpret it in the VIEWER's zone, which is a silent corruption whenever that wall clock lands in the viewer's DST gap. In America/New_York `2026-03-08T02:30:00` does not exist, so the clock jumps and it renders as `3:30 AM`. Pinning the wall clock to UTC, which has no DST and therefore no gap, preserves the digits exactly while Intl still applies the viewer's locale conventions.\n *\n * An offset-bearing timestamp (`...Z`, `...+05:30`) IS a real instant, so it keeps the normal behaviour and converts to the viewer's local time.\n */\nfunction resolve(input: string): { d: Date; timeZone?: string } {\n\tconst naive = BARE_TIME.test(input)\n\t\t? `1970-01-01T${input}`\n\t\t: NAIVE_DATETIME.test(input)\n\t\t\t? input\n\t\t\t: null;\n\treturn naive\n\t\t? { d: new Date(`${naive}Z`), timeZone: 'UTC' }\n\t\t: { d: new Date(input) };\n}\n\nexport function formatTime(input: unknown): string {\n\tif (typeof input !== 'string' || input.length === 0) return '';\n\tif (DATE_ONLY.test(input)) return '';\n\tconst { d, timeZone } = resolve(input);\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\ttimeZone,\n\t});\n}\n\nexport function formatDate(input: unknown): string {\n\tif (typeof input !== 'string' || input.length === 0) return '';\n\tconst { d, timeZone } = resolve(\n\t\tDATE_ONLY.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\ttimeZone,\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\n/**\n * Format a number, dropping trailing zeros in the FRACTIONAL part only: `2.50` becomes `2.5`, `2.0` becomes `2`, and `100` stays `100`.\n *\n * @remarks\n * The old implementation ran `.replace(/\\.?0+$/, '')` against the whole string, which happily ate zeros off the INTEGER when there was no decimal point. At `dp = 0` that meant `100` rendered as `1`, `90` as `9`, `20` as `2`, and `0` as the empty string. It shipped: a 100 percent tight stellium displayed as \"1% tight\", and an aspect of strength 100 as \"str 1\". Guard on the decimal point, and never strip from the integer side.\n *\n * @example\n * ```ts\n * formatNumber(100, 0); // '100'\n * formatNumber(2.5, 1); // '2.5'\n * formatNumber(2, 1); // '2'\n * formatNumber(0, 0); // '0'\n * ```\n */\nexport function formatNumber(value: unknown, dp = 1): string {\n\tif (typeof value !== 'number' || !Number.isFinite(value)) return '';\n\tconst fixed = value.toFixed(dp);\n\treturn fixed.includes('.') ? fixed.replace(/\\.?0+$/, '') : fixed;\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 { interpAccordionStyles } from '../utils/interp-accordion.js';\nimport { planetColor } from '../utils/planet-color.js';\nimport { WORLD_LAND_PATH } from '../utils/world-map.js';\n\ntype LineSet = AstrocartographyResponse['lines'][number];\ntype GeoPoint = LineSet['ascendant']['points'][number];\n\n// Equirectangular (plate carree) projection in a 360x180 unit canvas: one unit\n// per degree. The SVG scales to the container width; the 2:1 aspect ratio holds.\nconst W = 360;\nconst H = 180;\nconst lonToX = (lon: number): number => lon + 180;\nconst latToY = (lat: number): number => 90 - lat;\n\n// Reference parallels (degrees). Tropics and polar circles use the current mean\n// obliquity; drawn as dashed guides so the curved rising/setting lines read\n// against real climate bands, not just a bare grid.\nconst TROPIC = 23.44;\nconst POLAR = 66.56;\n\nconst formatLon = (lon: number): string =>\n\tlon === 0 ? '0' : `${Math.abs(lon)}\u00B0${lon > 0 ? 'E' : 'W'}`;\nconst formatLat = (lat: number): string =>\n\tlat === 0 ? '0' : `${Math.abs(lat)}\u00B0${lat > 0 ? 'N' : 'S'}`;\n\n/**\n * Split a rising/setting line into screen polylines, breaking the path wherever\n * consecutive samples jump more than 180 degrees of longitude. Without the\n * split, a line that crosses the antimeridian draws a stray horizontal streak\n * straight across the whole map.\n */\nfunction toSegments(points: GeoPoint[]): string[] {\n\tconst segments: string[][] = [];\n\tlet current: string[] = [];\n\tlet prevLon: number | null = null;\n\tfor (const p of points) {\n\t\tif (prevLon !== null && Math.abs(p.longitude - prevLon) > 180) {\n\t\t\tif (current.length) segments.push(current);\n\t\t\tcurrent = [];\n\t\t}\n\t\tcurrent.push(`${lonToX(p.longitude)},${latToY(p.latitude)}`);\n\t\tprevLon = p.longitude;\n\t}\n\tif (current.length) segments.push(current);\n\treturn segments.filter((s) => s.length > 1).map((s) => s.join(' '));\n}\n\nconst ANGLE_LABEL: Record<string, string> = {\n\tmc: 'MC',\n\tic: 'IC',\n\tascendant: 'AC',\n\tdescendant: 'DC',\n};\n\n/**\n * Astrocartography (relocation) world map. Plots the four planetary lines for\n * every body from a /astrology/astrocartography response over a labeled\n * graticule: MC and IC as straight meridians, the Ascendant and Descendant as\n * latitude-sampled curves. Color is per body and theme-token driven; solid\n * lines are the Ascendant and Midheaven, dashed are the Descendant and IC.\n */\n@customElement('roxy-astrocartography-map')\nexport class RoxyAstrocartographyMap extends RoxyDataElement<AstrocartographyResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tdisclosureStyles,\n\t\tinterpAccordionStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);width:100%;color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-primary,#0f172a);margin:0}.meta{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}svg{border-radius:var(--roxy-radius-sm,4px);width:100%;height:auto;display:block}.map-frame{fill:color-mix(in srgb, var(--roxy-border,#e4e4e7) 12%, transparent);stroke:var(--roxy-border,#e4e4e7);stroke-width:.8px}.land{fill:var(--roxy-secondary,#475569);opacity:.13}.grat{stroke:var(--roxy-border,#e4e4e7);stroke-width:.4px;fill:none}.grat-axis{stroke:var(--roxy-muted,#71717a);stroke-width:.6px;opacity:.6}.grat-ref{stroke:var(--roxy-secondary,#475569);stroke-width:.4px;stroke-dasharray:2 2;opacity:.5;fill:none}.axis-label{fill:var(--roxy-muted,#71717a);font-size:5px;font-family:var(--roxy-font-sans)}.acg-line{fill:none;stroke-width:1px;opacity:.95}.acg-line.dashed{stroke-dasharray:4 2.5}.acg-glyph{font-size:8px;font-family:var(--roxy-font-sans);font-weight:600}.birthplace{fill:var(--roxy-fg,#0a0a0a);font-size:9px}.legend{gap:var(--roxy-space-xs,.25rem) var(--roxy-space-md,1rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);flex-wrap:wrap;display:flex}.legend-item{align-items:center;gap:.3rem;display:inline-flex}.legend-swatch{border-top-style:solid;border-top-width:2px;width:14px;height:0}.legend-note{width:100%;color:var(--roxy-muted,#71717a)}.summary{color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);margin:0}.interp-dot{border-radius:50%;flex-shrink:0;align-self:center;width:10px;height:10px}.interp-line{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);margin:0}.interp-line .code{color:var(--roxy-accent-ink,#b45309);margin-right:.4rem;font-weight:600}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No astrocartography data</div>`;\n\t}\n\n\tprotected renderData(data: AstrocartographyResponse) {\n\t\tconst lines = data.lines ?? [];\n\t\tconst bd = data.birthDetails;\n\t\treturn html`<div class=\"wrap\"><header><h2 class=\"title\">Astrocartography</h2>${\n\t\t\t\t\tbd\n\t\t\t\t\t\t? html`<div class=\"meta\">${[bd.date, bd.time].filter(Boolean).join(' \u00B7 ')} \u00B7 ${formatLat(Math.round(bd.latitude))} ${formatLon(Math.round(bd.longitude))}</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</header>${this.renderMap(lines, bd)} ${this.renderLegend(lines)} ${data.summary ? html`<p class=\"summary\">${data.summary}</p>` : nothing} ${this.renderInterpretations(lines)}</div>`;\n\t}\n\n\tprivate renderMap(\n\t\tlines: LineSet[],\n\t\tbd: AstrocartographyResponse['birthDetails'],\n\t) {\n\t\treturn html`<svg viewBox=\"0 0 ${W} ${H}\" role=\"img\" aria-label=\"World map of planetary astrocartography lines\"><title>Astrocartography world map</title><desc>Equirectangular world map. Each body has a Midheaven and Imum Coeli meridian and a curved Ascendant and Descendant line, colored per body.</desc><rect class=\"map-frame\" x=\"0\" y=\"0\" width=\"${W}\" height=\"${H}\"/><path class=\"land\" d=\"${WORLD_LAND_PATH}\" fill-rule=\"evenodd\"/>${this.renderGraticule()} ${lines.map((l, i) => this.renderBodyLines(l, i))} ${\n\t\t\t\tbd\n\t\t\t\t\t? svg`<text class=\"birthplace\" x=${lonToX(bd.longitude)} y=${latToY(bd.latitude)} text-anchor=\"middle\" dominant-baseline=\"central\"><title>Birthplace</title>\u2605</text>`\n\t\t\t\t\t: nothing\n\t\t\t}</svg>`;\n\t}\n\n\tprivate renderGraticule() {\n\t\tconst meridians = [];\n\t\tfor (let lon = -150; lon <= 150; lon += 30) {\n\t\t\tconst x = lonToX(lon);\n\t\t\tconst axis = lon === 0;\n\t\t\tmeridians.push(\n\t\t\t\tsvg`<line class=${axis ? 'grat-axis' : 'grat'} x1=${x} y1=\"0\" x2=${x} y2=${H} />`,\n\t\t\t);\n\t\t\tmeridians.push(\n\t\t\t\tsvg`<text class=\"axis-label\" x=${x} y=${H - 2} text-anchor=\"middle\">${formatLon(lon)}</text>`,\n\t\t\t);\n\t\t}\n\t\tconst parallels = [];\n\t\tfor (let lat = -60; lat <= 60; lat += 30) {\n\t\t\tconst y = latToY(lat);\n\t\t\tconst axis = lat === 0;\n\t\t\tparallels.push(\n\t\t\t\tsvg`<line class=${axis ? 'grat-axis' : 'grat'} x1=\"0\" y1=${y} x2=${W} y2=${y} />`,\n\t\t\t);\n\t\t\tparallels.push(\n\t\t\t\tsvg`<text class=\"axis-label\" x=\"2\" y=${y - 1}>${formatLat(lat)}</text>`,\n\t\t\t);\n\t\t}\n\t\t// Tropics and polar circles as dashed climate-band references.\n\t\tconst refs = [TROPIC, -TROPIC, POLAR, -POLAR].map(\n\t\t\t(lat) =>\n\t\t\t\tsvg`<line class=\"grat-ref\" x1=\"0\" y1=${latToY(lat)} x2=${W} y2=${latToY(lat)} />`,\n\t\t);\n\t\treturn svg`${meridians}${parallels}${refs}`;\n\t}\n\n\tprivate renderBodyLines(line: LineSet, index: number) {\n\t\tconst color = planetColor(line.planet, index);\n\t\tconst glyph = line.symbol || line.planet.slice(0, 2);\n\t\tconst items = [\n\t\t\tthis.renderMeridian(\n\t\t\t\tline.mc.longitude,\n\t\t\t\tcolor,\n\t\t\t\tglyph,\n\t\t\t\tline.planet,\n\t\t\t\t'mc',\n\t\t\t\tfalse,\n\t\t\t),\n\t\t\tthis.renderMeridian(\n\t\t\t\tline.ic.longitude,\n\t\t\t\tcolor,\n\t\t\t\tglyph,\n\t\t\t\tline.planet,\n\t\t\t\t'ic',\n\t\t\t\ttrue,\n\t\t\t),\n\t\t\tthis.renderCurve(\n\t\t\t\tline.ascendant.points,\n\t\t\t\tcolor,\n\t\t\t\tglyph,\n\t\t\t\tline.planet,\n\t\t\t\t'ascendant',\n\t\t\t\tfalse,\n\t\t\t),\n\t\t\tthis.renderCurve(\n\t\t\t\tline.descendant.points,\n\t\t\t\tcolor,\n\t\t\t\tglyph,\n\t\t\t\tline.planet,\n\t\t\t\t'descendant',\n\t\t\t\ttrue,\n\t\t\t),\n\t\t];\n\t\treturn svg`${items}`;\n\t}\n\n\tprivate renderMeridian(\n\t\tlon: number,\n\t\tcolor: string,\n\t\tglyph: string,\n\t\tplanet: string,\n\t\tangle: string,\n\t\tdashed: boolean,\n\t) {\n\t\tconst x = lonToX(lon);\n\t\t// MC label rides the top edge, IC the bottom, so the two meridians of one\n\t\t// body never stack their glyphs at the same point.\n\t\tconst labelY = angle === 'ic' ? H - 7 : 9;\n\t\treturn svg`<g>\n\t\t\t<line class=${`acg-line${dashed ? ' dashed' : ''}`} stroke=${color} x1=${x} y1=\"0\" x2=${x} y2=${H}><title>${planet} ${ANGLE_LABEL[angle]} line</title></line>\n\t\t\t<text class=\"acg-glyph\" fill=${color} x=${x} y=${labelY} text-anchor=\"middle\" dominant-baseline=\"central\">${glyph}</text>\n\t\t</g>`;\n\t}\n\n\tprivate renderCurve(\n\t\tpoints: GeoPoint[],\n\t\tcolor: string,\n\t\tglyph: string,\n\t\tplanet: string,\n\t\tangle: string,\n\t\tdashed: boolean,\n\t) {\n\t\tconst segments = toSegments(points ?? []);\n\t\tif (segments.length === 0) return nothing;\n\t\t// Label at the sample nearest the equator, the most visible band.\n\t\tconst anchor = (points ?? []).reduce(\n\t\t\t(best, p) => (Math.abs(p.latitude) < Math.abs(best.latitude) ? p : best),\n\t\t\tpoints[0] ?? { latitude: 0, longitude: 0 },\n\t\t);\n\t\treturn svg`<g>\n\t\t\t${segments.map(\n\t\t\t\t(pts) =>\n\t\t\t\t\tsvg`<polyline class=${`acg-line${dashed ? ' dashed' : ''}`} stroke=${color} points=${pts}><title>${planet} ${ANGLE_LABEL[angle]} line</title></polyline>`,\n\t\t\t)}\n\t\t\t<text class=\"acg-glyph\" fill=${color} x=${lonToX(anchor.longitude)} y=${latToY(anchor.latitude)} text-anchor=\"middle\" dominant-baseline=\"central\">${glyph}</text>\n\t\t</g>`;\n\t}\n\n\tprivate renderLegend(lines: LineSet[]) {\n\t\tif (lines.length === 0) return nothing;\n\t\treturn html`<div class=\"legend\">${lines.map((l, i) => {\n\t\t\t\tconst color = planetColor(l.planet, i);\n\t\t\t\treturn html`<span class=\"legend-item\"><span class=\"legend-swatch\" style=\"${`border-top-color: ${color}`}\"></span> ${l.symbol ? html`${l.symbol}` : nothing}${l.planet}</span>`;\n\t\t\t})} <span class=\"legend-note\">Solid lines are the Ascendant and Midheaven, dashed are the Descendant and IC.</span></div>`;\n\t}\n\n\tprivate renderInterpretations(lines: LineSet[]) {\n\t\tif (lines.length === 0) return nothing;\n\t\treturn html`<section class=\"block\"><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-lead\"><span class=\"interp-dot\" style=\"${`background: ${color}`}\"></span> ${l.symbol ? html`${l.symbol}` : nothing}${l.planet} </span>${chevron()}</summary><div class=\"interp-body\">${rows\n\t\t\t\t\t\t\t.filter(([, text]) => text)\n\t\t\t\t\t\t\t.map(\n\t\t\t\t\t\t\t\t([code, text]) =>\n\t\t\t\t\t\t\t\t\thtml`<p class=\"interp-line\"><span class=\"code\">${code}</span>${text}</p>`,\n\t\t\t\t\t\t\t)}</div></details>`;\n\t\t\t})}</section>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-astrocartography-map': RoxyAstrocartographyMap;\n\t}\n}\n", "import { capitalize } from './string.js';\n\n/**\n * Stable, theme-token stroke color per celestial body, for the multi-line map components (astrocartography, local space) where every body needs a distinct line that still follows the host theme.\n *\n * @remarks\n * Values are `var(--roxy-*)` references, so light and dark both resolve through the design tokens and a host override repaints every line with no rebuild. Classical bodies map to a fixed semantic token; any body the map omits (localized names, asteroids, the lunar nodes, Chiron, Lilith) falls back to a deterministic cycle keyed by its index in the response, so colors stay stable across re-renders and do not collide within the common 14-body set. Strokes and glyph fills are non-text chart marks, so the brighter base tokens are used directly rather than the WCAG-AA text variants.\n */\nconst PLANET_COLOR: Record<string, string> = {\n\tSun: 'var(--roxy-accent)',\n\tMoon: 'var(--roxy-secondary)',\n\tMercury: 'var(--roxy-info)',\n\tVenus: 'var(--roxy-success)',\n\tMars: 'var(--roxy-danger)',\n\tJupiter: 'var(--roxy-warning)',\n\tSaturn: 'var(--roxy-muted)',\n\tUranus: 'var(--roxy-info-fg)',\n\tNeptune: 'var(--roxy-success-fg)',\n\tPluto: 'var(--roxy-danger-fg)',\n};\n\n/** Deterministic fallback palette for bodies outside {@link PLANET_COLOR} (nodes, Chiron, Lilith, asteroids, or localized names). Keyed by response index so a given body keeps one color. */\nconst CYCLE = [\n\t'var(--roxy-accent)',\n\t'var(--roxy-info)',\n\t'var(--roxy-success)',\n\t'var(--roxy-danger)',\n\t'var(--roxy-warning)',\n\t'var(--roxy-secondary)',\n\t'var(--roxy-info-fg)',\n\t'var(--roxy-success-fg)',\n\t'var(--roxy-danger-fg)',\n\t'var(--roxy-accent-ink)',\n\t'var(--roxy-warning-fg)',\n\t'var(--roxy-primary)',\n];\n\n/** Theme-token color for a body, by name with an index fallback. {@link capitalize} matches the canonical TitleCase keys; unmapped or localized names cycle by `index`. */\nexport function planetColor(name: string, index = 0): string {\n\treturn (\n\t\tPLANET_COLOR[capitalize(name)] ??\n\t\tCYCLE[index % CYCLE.length] ??\n\t\t'var(--roxy-accent)'\n\t);\n}\n", "/**\n * Simplified Natural Earth 110m land outline (public domain, no attribution required) projected into the astrocartography 360x180 plate-carree space: x = lon + 180, y = 90 - lat. It therefore aligns pixel for pixel with the graticule and the planetary lines drawn in that same space, with no nested-SVG transform.\n *\n * @remarks\n * Integer-degree precision and a tiny-island cull keep it light (about 9 KB gzipped) so it ships inside the per-component bundle as a faint background fill; the colored lines stay the focus. Use `fill-rule: evenodd` so inland holes render. Regenerate from `ne_110m_land.geojson` if the projection or precision changes.\n */\nexport const WORLD_LAND_PATH =\n\t'M120 170L120 171L118 171L116 171L114 171L114 170L116 170L118 170L119 170L120 170ZM21 169L19 170L18 169L17 169L16 169L17 168L19 168L20 169L21 169ZM135 168L136 168L137 169L137 170L135 170L133 171L132 171L130 171L127 171L126 171L126 170L128 170L129 170L130 169L131 168L132 168L133 168L135 168ZM59 164L60 164L61 163L61 164L60 164L58 164L57 164L58 163L59 164ZM54 163L56 164L55 164L54 164L53 163L54 163ZM81 162L82 162L83 162L84 163L83 162L82 162L81 162L79 163L78 162L80 162L81 162ZM112 161L111 162L110 162L109 163L108 162L107 162L106 162L105 162L106 161L107 161L108 161L108 160L109 159L110 159L111 160L111 161L112 161ZM121 154L120 154L119 154L119 155L118 155L117 155L117 156L118 156L117 156L116 157L115 157L114 158L115 158L115 159L116 159L117 159L117 160L118 160L118 161L119 162L119 163L119 164L118 164L117 165L116 165L114 166L113 166L112 166L110 166L109 167L108 167L106 167L104 167L103 167L105 167L106 168L105 168L104 168L102 168L102 169L103 170L105 170L107 170L109 171L110 171L112 171L114 171L117 172L118 172L120 172L121 173L122 173L123 173L125 173L126 172L128 172L130 172L133 172L135 172L137 172L138 172L139 171L142 171L144 171L146 171L148 171L150 171L151 170L150 170L150 169L148 169L146 169L144 169L144 168L145 168L146 168L148 168L149 167L150 167L151 167L152 166L154 166L155 166L156 166L158 166L159 166L160 166L161 165L162 165L163 165L164 164L165 164L164 164L164 163L165 163L166 163L167 163L168 162L169 162L170 161L171 161L171 162L173 162L173 161L174 161L176 161L177 161L178 161L179 161L180 162L181 161L182 161L183 161L184 161L185 161L186 160L187 160L188 160L190 160L191 161L192 161L192 160L193 160L195 160L196 160L197 160L198 160L199 160L200 160L201 160L202 160L203 161L204 161L205 160L206 160L207 160L208 160L209 160L210 160L211 160L212 160L213 159L214 159L215 159L216 159L217 159L218 160L219 160L220 160L220 159L221 159L222 159L223 158L224 158L225 158L226 158L227 158L228 157L229 157L230 157L231 157L232 156L233 156L234 156L235 156L236 156L237 156L237 157L238 157L239 157L240 157L241 158L242 158L243 158L244 157L245 158L246 158L247 158L248 158L249 158L250 159L250 160L249 160L248 160L248 161L249 161L248 161L248 162L249 162L250 162L251 162L252 162L252 161L253 161L253 160L254 160L256 160L257 160L258 159L259 158L260 158L261 158L262 157L263 157L264 157L265 157L266 157L267 157L268 156L269 157L270 157L271 157L272 157L273 157L274 157L275 157L276 157L277 157L278 157L279 157L280 157L281 157L282 156L283 156L284 156L285 156L286 157L287 157L288 157L289 157L290 157L291 156L292 156L293 156L294 156L295 156L296 157L297 157L299 157L300 157L301 157L302 157L303 156L304 157L305 157L306 157L307 157L308 157L309 157L310 157L311 156L312 156L313 156L314 156L315 156L315 155L316 156L317 157L319 157L320 157L321 157L322 157L323 157L324 157L325 157L326 157L326 158L327 158L328 158L329 158L330 159L331 159L333 159L334 159L335 159L336 159L337 159L338 159L339 160L340 160L341 160L342 161L343 161L344 161L345 161L346 161L347 161L348 161L349 161L351 161L351 162L350 163L349 164L348 164L347 164L346 164L346 165L345 165L344 165L344 166L343 167L344 167L344 168L345 168L347 168L347 169L345 169L344 169L342 169L341 170L340 171L341 171L342 172L344 172L345 173L347 173L349 173L349 174L352 174L353 174L356 174L358 174L360 175L360 180L0 180L0 175L1 174L3 174L4 174L6 175L7 174L10 174L11 174L13 175L16 175L18 175L22 175L25 175L29 175L31 176L34 175L37 175L33 175L30 174L29 174L26 174L27 173L27 172L25 172L25 171L23 171L26 171L28 171L29 171L31 171L33 171L34 170L33 170L32 170L30 169L28 169L27 169L25 169L24 169L23 168L22 168L22 167L23 167L25 167L26 167L27 167L29 167L30 167L31 167L32 167L34 166L34 165L35 165L36 166L37 165L38 165L40 165L41 165L42 165L44 165L45 164L46 164L48 164L49 164L50 164L52 164L53 164L55 165L56 164L57 164L59 165L60 164L61 164L63 164L64 164L65 164L66 164L67 164L68 165L69 164L70 165L71 165L72 165L74 165L75 165L77 165L78 165L79 165L80 165L79 165L79 164L77 164L77 163L76 163L77 163L78 163L80 163L81 163L82 163L82 164L84 164L85 163L86 163L88 163L89 163L90 163L91 163L92 163L93 163L94 163L95 163L96 164L97 164L99 164L99 163L100 163L101 164L102 163L103 164L104 164L105 164L106 164L107 163L108 163L110 163L111 163L112 163L113 162L112 161L112 160L111 160L112 159L113 158L112 158L112 157L113 157L114 156L115 156L116 155L117 155L118 155L119 154L120 154L121 154L121 153L122 153L123 154L122 154L121 154ZM112 144L114 144L115 145L114 145L113 145L112 146L111 145L110 145L109 145L108 144L107 144L105 143L106 143L108 144L109 144L110 143L111 143L112 143L112 144ZM121 141L122 142L121 142L120 142L119 142L120 141L121 142L121 141ZM250 140L249 140L249 139L250 139L251 139L250 140ZM325 131L326 131L327 131L328 131L328 132L328 133L327 134L326 134L325 133L325 132L325 131ZM353 131L354 131L354 132L353 133L353 134L352 134L351 134L351 135L351 136L350 136L349 137L348 137L348 136L347 136L347 135L348 134L349 134L350 134L351 133L352 132L352 131L353 130L353 131ZM355 126L355 127L356 127L356 128L357 128L358 128L359 128L358 129L357 129L357 130L357 131L356 131L355 132L355 131L355 130L354 130L354 129L355 129L355 128L355 127L354 127L354 126L353 125L353 124L354 125L355 126ZM347 112L346 112L345 112L345 111L344 110L345 110L345 111L346 111L347 112ZM358 107L359 108L358 108L357 108L358 107L358 108L358 107ZM359 107L359 106L360 106L360 107L359 107ZM230 104L230 105L230 106L230 105L230 106L230 107L229 107L229 108L229 109L229 110L228 112L228 114L227 115L226 115L225 116L225 115L224 115L224 114L223 113L223 112L223 111L224 111L224 110L224 109L224 108L224 107L224 106L225 106L226 106L227 105L228 105L228 104L229 103L229 102L230 102L230 103L230 104ZM324 104L324 105L325 104L325 105L325 106L326 107L326 108L326 109L327 109L328 110L329 110L329 111L330 112L330 113L331 112L331 113L332 114L333 115L333 116L333 117L334 118L334 119L333 119L333 120L333 121L333 122L332 123L331 124L331 125L330 126L330 127L329 128L328 128L327 128L327 129L326 129L325 129L325 128L324 128L324 129L323 129L322 128L321 128L320 127L320 126L319 126L318 126L318 125L318 124L318 125L317 125L318 124L318 123L317 124L316 124L316 125L315 124L315 123L314 123L313 122L312 122L311 121L310 122L308 122L307 122L306 122L305 123L304 123L304 124L303 124L302 124L301 124L300 124L299 125L299 124L299 125L298 125L297 125L296 124L295 124L296 123L296 122L295 121L295 120L295 119L294 118L294 117L293 117L293 116L294 117L293 116L294 116L294 115L293 114L294 114L294 113L294 112L294 113L295 112L295 111L296 111L297 111L298 110L299 110L300 110L301 110L301 109L302 109L302 108L302 107L303 106L303 107L304 107L304 106L305 105L306 105L306 104L307 104L308 104L308 105L309 105L310 105L309 104L310 104L310 103L311 103L311 102L312 102L313 102L312 101L313 101L314 102L315 102L316 102L317 102L317 103L316 103L316 104L315 105L316 105L316 106L317 106L318 106L318 107L319 107L320 108L321 107L321 106L322 105L322 104L322 103L322 102L322 101L323 101L323 102L324 103L324 104ZM301 100L300 100L299 100L300 99L300 100L301 100ZM341 100L340 100L340 99L341 100ZM342 100L341 99L341 98L341 99L342 100ZM304 100L303 100L304 100L304 99L305 99L306 98L307 98L307 99L306 99L305 99L304 100ZM298 98L299 98L299 99L298 99L297 99L297 98L298 98ZM303 98L303 99L301 99L300 99L300 98L301 98L301 99L302 98L303 98ZM340 98L340 99L339 98L338 97L339 98L340 98ZM289 97L291 97L291 96L293 97L293 98L294 98L296 98L295 99L293 98L292 98L291 98L289 98L288 98L286 97L285 97L286 96L287 96L288 96L289 97ZM315 96L314 97L314 96L314 95L315 96ZM336 97L335 97L335 96L335 95L335 96L336 96L336 97ZM332 95L331 96L330 96L329 96L328 96L328 95L329 96L330 96L330 95L330 96L331 95L332 95L332 94L332 95ZM307 93L307 94L306 94L306 93L307 93ZM310 93L311 94L310 93L309 93L308 93L309 93L310 93ZM333 94L333 95L333 94L332 94L332 93L331 93L332 93L333 94ZM314 91L314 93L315 93L316 92L317 92L318 92L319 92L320 92L321 93L323 93L325 94L326 95L328 96L328 97L327 97L328 98L329 99L329 100L330 100L331 100L331 101L330 101L330 100L329 100L328 100L327 99L326 98L325 98L324 98L323 98L323 99L322 99L321 99L320 98L319 98L318 98L319 97L318 96L318 95L316 95L315 94L314 94L313 94L313 93L312 93L313 92L314 92L312 92L311 91L312 91L312 90L314 91ZM305 89L304 90L303 90L301 90L300 90L300 91L301 91L303 91L302 92L302 93L302 94L303 95L303 96L302 95L303 94L302 95L301 95L302 94L301 94L301 93L300 93L300 94L300 96L299 95L300 94L299 93L299 92L299 91L300 90L300 89L301 89L302 89L303 89L304 89L305 88L305 89ZM309 89L309 90L308 90L308 91L308 90L307 89L308 88L309 88L309 89ZM286 96L285 96L284 95L283 94L282 94L281 93L281 92L280 91L279 90L279 89L279 88L278 88L277 87L276 86L275 85L276 85L277 85L278 86L279 86L280 87L281 88L282 88L282 89L283 89L284 90L283 91L284 91L285 92L286 92L286 93L286 94L286 96ZM298 88L299 89L298 89L297 90L298 91L297 91L297 92L296 94L295 94L294 93L293 93L292 93L291 93L290 93L290 92L290 91L289 90L289 89L290 88L291 88L291 87L292 87L293 87L294 86L294 85L295 85L296 84L297 83L298 84L299 85L298 85L299 86L298 86L297 87L298 88ZM306 82L307 83L306 84L306 83L305 83L306 84L305 84L304 84L304 83L304 82L303 83L302 83L302 82L303 82L303 81L304 82L305 81L305 80L306 81L306 82ZM261 84L260 84L260 83L260 82L260 80L261 81L262 82L262 84L261 84ZM304 80L303 81L302 80L303 80L303 79L303 80L304 79L304 80ZM299 81L297 82L298 81L298 80L299 80L300 79L299 80L299 81ZM302 78L303 78L303 79L302 80L302 79L302 78ZM306 78L306 79L305 79L305 80L305 79L304 79L305 79L305 78L304 77L305 77L306 78ZM302 77L301 78L301 77L300 77L301 77L302 77ZM301 71L302 72L303 73L302 74L302 75L302 76L303 76L304 76L304 77L303 77L303 76L303 77L302 76L301 76L301 75L301 76L300 75L300 74L300 72L301 71ZM114 72L113 72L113 71L114 71L114 72ZM103 72L102 72L102 71L102 72L103 72L104 72L103 72ZM107 70L108 70L109 70L110 70L110 71L111 71L112 71L111 72L110 72L109 72L108 72L107 72L106 72L106 71L107 71L107 72L108 71L107 71L107 70ZM290 71L289 72L289 71L289 70L290 70L291 70L291 71L290 71ZM24 71L24 70L25 70L25 71L24 71ZM100 67L101 68L102 67L102 68L103 68L103 69L104 69L105 69L106 70L105 70L104 70L102 70L103 70L103 69L102 69L101 68L100 68L99 68L98 68L98 67L97 67L97 68L96 68L95 68L96 68L96 67L97 67L98 67L99 67L100 67ZM102 66L102 65L102 66ZM301 67L301 68L300 67L300 66L301 65L302 65L302 66L301 67ZM315 56L314 57L314 56L313 57L312 57L313 56L314 56L315 56ZM215 54L214 55L213 55L212 55L213 55L214 55L215 54ZM204 54L204 55L205 55L206 55L205 55L204 55L204 54ZM196 52L195 53L194 53L192 52L193 52L194 52L195 52L196 52ZM189 49L190 49L190 51L189 51L188 51L188 50L188 49L189 49ZM321 53L321 54L320 55L319 55L317 55L316 57L315 56L315 55L313 56L312 56L311 56L312 57L311 59L310 59L310 58L310 57L309 57L310 56L311 56L312 55L313 55L315 54L316 54L317 53L319 52L320 51L320 49L321 49L322 50L322 51L321 52L321 53ZM190 48L189 49L189 48L189 47L190 48ZM324 46L325 46L326 47L324 47L323 48L322 47L321 48L320 48L320 47L321 47L322 45L322 44L323 45L324 46ZM116 43L117 44L118 44L117 44L116 44L116 43ZM118 41L116 41L115 40L116 40L117 40L118 41ZM56 41L56 42L54 41L53 40L52 40L52 39L53 39L53 40L54 40L55 40L55 41L56 41ZM124 39L123 40L124 40L125 40L124 40L125 41L126 40L127 41L126 41L127 41L127 42L127 43L126 43L126 42L125 43L124 43L125 43L124 42L123 42L121 42L121 41L122 41L123 39L124 38L125 38L124 39ZM47 36L48 36L48 37L49 38L48 38L48 37L47 37L47 36ZM324 39L325 41L323 41L323 42L324 43L324 44L323 43L322 44L322 43L322 42L322 41L322 40L322 39L322 38L322 37L323 36L322 36L323 36L323 37L323 38L324 39ZM173 38L171 38L170 38L171 37L170 36L172 35L173 35L174 35L174 36L174 37L173 38ZM193 34L192 35L191 35L191 34L192 34L193 34ZM27 33L26 33L25 33L26 32L27 32L28 32L27 33ZM177 31L176 32L177 32L178 32L178 33L177 34L178 34L179 35L180 36L180 37L182 37L182 38L181 38L181 39L179 39L178 39L177 39L176 40L175 40L174 40L176 39L177 39L175 38L176 38L175 37L177 37L177 36L176 35L175 35L175 34L174 35L174 34L174 33L174 32L175 31L176 31L177 31ZM14 30L13 30L14 30ZM98 27L97 28L96 28L97 27L98 27ZM8 26L9 26L10 26L10 27L11 27L10 27L9 27L8 27L8 26ZM95 24L95 25L96 25L97 25L98 26L99 26L100 26L99 27L97 26L96 26L94 27L94 26L93 26L94 26L94 25L94 24L95 24ZM165 24L166 25L165 26L162 26L161 27L160 26L157 26L158 26L156 25L158 25L156 24L158 24L159 24L161 24L162 24L164 23L165 24ZM104 23L103 23L103 22L104 22L105 22L105 23L104 23ZM5 23L6 24L5 23L8 23L10 24L9 24L7 25L7 26L6 26L5 25L4 25L3 24L2 25L1 24L0 24L1 25L0 25L0 21L2 22L5 23ZM84 21L82 21L80 21L81 20L82 20L83 20L84 21ZM360 19L359 19L360 18L360 19ZM1 19L0 19L0 18L1 18L2 19L1 19ZM89 21L89 22L91 21L92 21L92 22L93 23L94 22L94 21L94 20L96 20L97 20L99 21L98 22L99 22L99 23L97 24L95 24L94 23L94 24L93 25L92 26L90 26L89 26L89 27L88 27L87 28L86 29L85 30L85 31L87 31L87 32L88 33L89 33L91 33L92 34L93 34L94 34L95 35L97 35L98 35L98 36L98 37L99 38L100 39L101 38L101 37L101 36L100 35L102 35L103 34L103 33L103 32L101 31L103 30L102 29L102 28L103 27L104 28L105 28L106 28L107 28L108 28L109 29L110 29L110 30L111 31L112 31L112 32L114 31L115 30L116 31L117 32L119 33L118 34L120 34L120 35L122 35L123 35L123 36L124 36L124 37L124 38L123 39L121 39L120 40L118 40L116 40L115 40L114 40L113 40L111 41L110 42L109 43L110 43L111 42L113 41L115 41L116 41L115 42L115 43L116 44L117 44L118 44L119 43L120 44L119 45L117 45L116 46L115 46L114 46L116 45L114 45L113 45L112 46L111 46L110 46L109 47L109 48L110 48L109 49L108 49L107 49L106 49L108 49L107 49L106 49L106 50L105 51L104 51L105 51L105 52L104 53L104 52L104 51L103 51L104 52L103 52L104 52L104 53L104 54L104 55L103 55L102 56L101 56L101 57L100 57L99 58L99 59L99 60L99 61L99 62L100 63L100 64L100 65L99 65L99 64L98 64L98 63L97 63L97 62L97 61L96 60L95 60L94 60L92 60L91 60L90 60L91 60L91 61L90 61L89 61L88 60L87 60L86 60L85 61L84 61L83 62L83 63L83 64L82 65L82 66L82 67L82 68L83 69L83 70L84 71L85 71L86 72L87 71L88 71L89 71L89 70L90 69L91 69L92 69L93 68L93 69L93 70L92 70L93 71L92 71L92 72L92 71L92 72L92 73L91 74L92 74L93 74L94 74L95 74L96 74L96 75L97 75L97 76L96 76L96 77L97 77L97 78L96 78L96 79L97 80L98 81L99 81L100 81L100 80L101 80L101 81L102 81L103 81L104 81L104 80L105 79L106 79L107 79L107 78L108 78L109 78L108 79L108 80L108 81L109 81L109 80L109 79L110 79L110 78L110 79L111 79L112 79L113 79L114 79L114 80L115 80L116 80L116 79L117 79L118 79L117 80L118 80L119 81L120 81L120 82L121 82L122 83L122 84L123 84L124 84L125 84L126 84L127 85L128 85L128 86L129 86L129 88L130 88L130 89L129 90L130 90L131 90L131 91L132 91L133 91L135 92L136 92L135 93L137 92L139 93L140 93L141 94L143 95L144 95L145 95L145 97L145 99L144 100L143 101L142 102L142 103L141 103L141 104L141 106L141 107L141 108L140 108L140 110L139 111L139 112L138 112L138 113L137 113L135 113L135 114L134 114L132 115L132 116L131 117L132 117L131 118L131 119L130 119L129 121L128 122L127 123L127 124L126 124L125 125L124 125L123 124L122 124L123 125L123 126L123 127L122 128L121 129L119 129L118 129L118 130L118 131L117 131L116 131L115 131L115 132L116 132L117 133L116 133L115 133L115 135L114 135L113 135L113 136L112 136L113 137L114 137L114 138L113 139L112 140L111 140L111 141L111 142L112 142L111 142L110 143L109 143L109 144L107 144L106 143L105 142L105 141L105 140L104 139L105 138L106 137L104 137L105 136L106 134L107 134L107 132L106 133L106 132L106 130L107 129L106 128L106 127L107 127L107 126L108 124L109 122L108 121L109 120L109 119L109 118L109 116L110 114L110 111L110 110L110 108L109 108L109 107L107 106L105 105L104 105L104 104L103 102L102 100L101 98L100 97L99 97L99 96L99 95L99 94L100 93L100 92L100 93L99 92L99 91L100 90L100 89L101 89L101 88L102 87L103 86L103 85L102 84L103 84L103 83L102 83L102 82L101 81L100 81L100 82L100 83L99 83L99 82L98 82L97 82L96 82L96 81L95 80L94 80L94 79L93 78L92 77L93 77L92 77L91 77L90 76L89 76L88 76L88 75L87 74L86 74L85 74L84 74L83 74L82 74L81 73L80 73L79 73L78 72L76 72L76 71L75 71L75 70L74 70L75 69L74 69L75 69L74 68L74 67L73 66L72 65L71 64L70 63L69 62L68 62L68 61L67 60L67 59L66 58L65 58L65 59L65 60L66 60L66 61L67 61L67 62L68 62L68 63L69 64L69 65L69 66L70 66L71 67L70 67L69 66L68 66L68 65L68 64L67 64L67 63L66 63L65 62L66 62L66 61L65 61L64 60L64 59L63 58L63 57L62 56L61 56L60 56L59 55L58 54L57 52L56 51L56 50L56 49L56 48L55 47L56 46L56 44L56 43L56 42L55 42L57 42L57 43L58 43L58 42L57 41L55 40L54 40L53 39L52 38L51 37L51 36L49 36L49 35L48 35L48 34L46 33L46 32L45 32L43 32L42 31L40 30L39 30L37 30L36 30L34 30L33 29L32 29L32 30L31 30L30 30L29 31L28 31L28 30L29 29L30 29L29 29L28 29L27 30L26 31L27 31L26 32L25 32L24 33L23 33L22 34L20 34L19 35L18 35L17 35L15 36L15 35L16 35L17 35L18 34L19 34L20 34L21 33L22 33L22 32L23 31L22 31L21 31L21 32L20 31L19 31L18 31L18 30L17 30L16 30L15 30L15 29L14 28L15 27L16 27L17 27L18 26L18 27L19 26L18 26L19 25L18 25L17 26L16 25L15 26L14 25L13 25L12 24L13 24L16 23L16 24L18 24L18 23L16 23L16 22L15 22L13 22L14 21L16 21L17 21L17 20L18 20L19 20L21 19L22 19L23 19L25 19L26 19L28 19L29 20L30 19L32 20L34 20L35 20L36 20L38 20L39 20L41 21L42 21L43 21L44 21L46 20L47 20L49 20L50 20L51 20L52 20L53 20L54 21L56 20L56 21L57 20L59 20L60 21L62 21L64 21L65 21L66 22L65 22L67 22L69 22L70 22L71 23L72 22L71 22L72 21L73 21L74 21L75 21L76 22L77 22L79 22L80 22L82 22L81 22L82 21L84 22L84 23L85 22L86 21L85 20L84 20L84 19L85 18L86 18L87 19L88 20L89 21ZM66 17L65 17L68 17L69 18L70 17L71 17L72 18L72 17L73 17L75 17L75 18L76 19L77 20L79 20L77 20L78 21L76 21L74 21L73 21L71 21L68 21L67 21L66 21L65 21L64 21L63 20L65 20L66 20L68 20L66 19L64 19L62 19L64 19L62 19L61 18L62 17L65 17L66 17ZM76 17L75 17L73 17L73 16L75 16L76 17ZM104 17L103 17L102 17L101 17L100 17L99 17L99 16L100 16L102 16L104 17ZM93 17L94 17L95 17L98 16L99 17L99 18L101 18L102 17L104 18L106 18L106 19L108 18L109 19L111 19L112 20L113 21L111 21L114 22L115 22L117 23L118 23L118 24L116 25L115 25L113 24L112 24L113 25L114 25L115 26L115 27L114 27L111 26L113 27L114 28L111 28L109 27L108 27L108 26L107 26L105 25L105 26L102 26L101 25L102 25L104 25L106 25L106 24L107 23L107 22L105 21L103 21L104 21L103 20L102 20L101 20L99 20L95 20L93 20L91 20L90 19L92 19L90 19L90 18L91 17L92 16L94 16L93 17ZM80 16L81 16L83 16L83 17L82 17L83 17L83 18L82 19L81 19L80 18L78 17L80 17L78 17L80 16ZM324 17L322 17L320 17L321 16L322 16L323 17L324 17ZM87 17L86 18L85 18L84 17L85 16L88 16L89 16L88 17L87 17ZM60 19L57 19L56 19L54 18L55 17L56 16L55 16L58 16L60 16L62 16L63 16L64 17L63 17L61 17L60 18L60 19ZM331 15L330 15L328 15L326 15L328 15L331 15ZM86 15L84 15L83 15L84 15L85 14L86 15ZM325 14L324 15L321 15L319 15L317 15L318 14L319 14L321 14L325 14ZM82 13L82 14L82 15L80 15L79 15L79 14L77 14L79 14L80 13L81 13L82 13ZM72 14L73 14L74 14L74 15L70 15L68 16L66 16L66 15L68 15L64 15L62 15L64 14L65 14L67 14L69 14L71 15L70 14L70 13L71 13L72 14ZM238 19L237 19L234 19L233 19L232 19L231 18L232 18L232 17L234 16L236 15L238 14L241 14L244 14L246 13L248 13L249 13L248 14L245 14L242 15L238 16L237 17L235 18L236 18L238 19ZM85 13L86 13L88 13L89 14L90 14L91 14L92 14L94 15L95 14L97 14L99 14L100 15L98 16L97 15L94 16L92 16L90 15L88 15L87 15L87 14L86 14L84 14L83 13L85 13ZM64 12L64 13L63 13L62 14L60 14L59 14L57 14L59 13L61 12L62 13L64 12ZM287 13L287 14L288 13L291 13L293 14L294 14L294 15L293 15L290 16L289 16L291 16L292 16L293 16L294 17L294 16L296 16L299 16L299 17L303 17L303 16L305 16L307 16L309 17L309 18L308 18L310 19L311 19L312 18L314 19L316 18L317 19L318 18L320 19L319 18L320 17L330 18L333 19L337 19L339 19L340 20L341 21L342 20L344 20L346 21L348 20L350 21L351 21L350 20L354 20L356 20L359 21L360 21L360 25L359 25L357 25L358 26L359 27L359 28L357 27L355 28L354 28L352 29L351 30L350 30L349 29L346 30L345 30L344 30L343 31L342 32L343 32L343 34L342 34L342 35L340 36L340 37L339 37L338 38L337 39L336 38L336 37L335 35L336 33L337 33L337 32L338 32L340 31L342 30L344 29L344 27L343 28L340 29L339 28L337 29L334 30L335 31L333 31L331 31L331 30L330 30L329 31L325 31L322 31L319 33L315 35L317 35L317 36L318 36L319 36L320 36L321 37L321 38L321 39L321 40L320 42L319 43L318 44L317 45L316 46L315 47L314 47L313 47L312 47L311 47L311 48L310 48L310 49L309 49L309 50L308 50L308 51L307 51L308 51L309 53L309 54L309 55L308 55L307 56L306 56L306 55L307 54L306 53L307 53L306 52L305 52L305 51L305 50L304 50L303 50L302 51L301 51L302 51L301 50L302 50L302 49L301 49L300 50L299 51L298 51L298 52L299 52L299 53L300 53L301 52L302 53L303 53L301 53L301 54L300 54L299 55L300 56L301 57L301 58L302 58L302 59L301 59L302 60L302 61L302 62L301 62L300 63L300 64L299 65L297 66L296 67L295 67L294 68L294 67L293 68L292 68L291 69L290 70L290 69L289 68L288 68L287 69L286 70L286 71L286 72L287 73L288 74L289 75L289 77L289 78L288 79L287 80L286 80L285 81L285 80L284 80L283 79L283 78L282 77L281 77L280 77L280 78L279 79L279 80L279 81L280 81L280 82L280 83L281 83L282 83L282 84L283 84L283 85L283 86L283 87L284 87L284 88L284 89L283 88L281 87L281 86L281 85L280 85L280 84L280 83L279 82L278 82L278 81L279 80L278 79L279 79L278 78L279 77L278 76L278 75L278 74L277 73L277 74L275 74L274 74L275 73L274 72L274 71L274 70L273 70L272 69L272 68L271 67L270 67L271 68L270 68L269 68L268 68L267 69L266 70L265 71L264 72L263 72L262 73L262 74L261 74L260 74L260 75L260 76L260 77L260 78L260 80L259 80L259 81L258 81L258 82L257 81L256 80L256 79L255 78L255 77L255 76L254 75L254 74L253 72L253 71L253 70L253 69L251 69L250 69L249 68L250 68L249 67L248 66L247 66L247 65L246 65L245 65L243 65L241 65L240 65L239 64L237 64L237 63L236 63L235 64L233 63L232 62L231 61L230 60L229 60L228 60L228 61L229 62L229 63L230 63L230 64L231 65L231 64L232 64L232 65L231 65L232 66L233 66L234 66L235 65L236 64L236 65L237 66L238 66L239 66L239 67L240 67L240 68L239 68L239 69L238 70L238 71L237 71L237 72L236 72L235 72L235 73L234 73L233 73L232 74L231 75L230 75L229 76L228 76L227 76L227 77L226 77L225 77L224 77L223 77L223 76L223 75L223 74L223 73L222 73L222 72L221 71L220 70L219 69L219 68L219 67L218 66L217 66L217 65L217 64L216 63L215 62L215 61L215 60L215 61L214 62L213 62L212 60L213 61L213 62L214 64L215 65L216 66L215 66L216 67L217 68L217 69L217 70L217 71L218 72L219 73L219 74L220 75L221 76L222 76L222 77L223 77L223 78L223 79L224 79L224 80L225 80L226 79L227 79L228 79L229 79L230 78L231 78L231 79L231 80L231 81L230 82L229 83L229 85L228 86L227 87L226 88L224 89L223 90L222 91L222 92L221 92L220 93L220 94L219 95L219 96L219 97L219 98L220 99L220 100L220 101L220 102L221 103L221 104L221 105L220 105L220 106L219 107L217 108L216 109L215 110L215 111L215 112L216 112L216 113L215 114L216 114L215 114L214 115L213 115L213 116L213 117L212 118L212 119L211 119L211 120L210 121L209 122L208 123L207 123L206 124L205 124L204 124L203 124L202 124L201 124L200 125L199 124L198 124L198 123L198 122L198 121L197 120L196 119L196 118L195 117L195 116L195 115L194 114L194 113L194 112L193 111L193 110L193 109L192 108L192 107L192 106L192 105L192 104L193 104L193 103L193 102L194 102L194 101L193 100L193 99L193 98L193 97L192 96L192 95L191 94L190 93L189 92L189 91L189 90L189 89L190 88L190 87L189 86L188 86L189 85L187 86L186 86L185 85L185 84L184 84L183 84L182 84L181 84L179 85L178 85L177 85L176 85L175 85L174 85L173 85L172 86L171 85L170 84L169 84L169 83L168 83L167 82L167 81L166 81L166 80L165 80L165 79L164 79L164 78L163 78L163 77L163 76L162 75L163 75L163 74L164 74L163 73L164 73L164 72L164 71L164 70L163 69L163 68L164 67L164 66L165 66L165 65L165 64L166 64L166 63L167 62L168 62L169 61L170 61L170 60L170 59L171 58L171 57L172 56L173 56L174 55L174 54L175 54L175 55L176 55L177 55L178 55L179 54L180 54L181 54L181 53L183 53L185 53L186 53L187 53L188 53L190 53L191 53L191 54L191 55L190 56L191 56L191 57L193 57L194 57L195 58L196 59L197 59L198 59L199 60L200 59L200 58L201 57L202 57L203 57L203 58L204 58L205 58L206 58L207 59L208 59L209 59L210 59L211 58L212 59L213 59L214 59L215 58L214 58L215 58L215 57L215 56L216 55L216 54L216 53L215 53L214 54L213 54L212 53L211 53L210 54L209 53L208 53L207 52L206 52L207 51L206 51L207 50L209 50L209 49L211 49L212 48L214 48L215 48L217 49L218 49L220 49L222 48L221 47L220 47L219 46L218 45L217 45L218 44L218 43L219 43L218 43L217 43L216 43L215 44L216 45L217 45L216 45L215 45L214 46L213 45L214 45L212 45L213 44L214 44L213 44L212 44L212 43L211 43L210 44L210 45L209 45L209 46L208 47L208 48L209 49L208 49L207 49L206 50L206 49L205 49L204 49L204 50L203 50L203 51L204 51L204 52L203 52L203 53L203 54L202 54L202 53L201 52L201 51L200 51L200 50L199 50L199 49L200 48L199 48L198 48L198 47L197 47L196 46L195 46L195 45L194 45L194 44L193 44L192 45L193 46L194 46L194 47L195 48L196 48L197 49L198 49L198 50L197 50L196 50L197 51L196 52L196 51L196 50L195 50L195 49L194 49L193 49L192 48L191 48L191 47L190 46L189 46L188 46L187 46L187 47L185 47L183 47L183 48L182 49L181 49L180 50L180 51L180 52L179 52L179 53L178 53L177 53L176 53L175 54L174 54L173 53L172 53L171 53L171 52L170 51L171 51L171 50L171 49L171 48L171 47L172 46L173 46L175 46L176 47L178 47L179 46L179 44L178 43L177 42L176 42L175 41L177 41L178 41L178 40L179 41L181 40L182 39L183 39L184 38L185 37L186 36L187 37L187 36L188 36L189 36L189 35L188 34L188 33L189 33L190 33L191 32L191 33L190 33L191 34L190 34L190 35L191 36L192 36L193 36L194 36L195 36L196 35L198 35L199 35L199 36L200 36L200 35L201 35L201 34L201 33L202 33L203 32L203 33L204 33L204 32L203 31L205 31L206 30L207 31L208 31L209 30L208 29L206 30L204 30L203 30L202 30L201 29L202 28L201 27L202 27L202 26L205 25L205 24L204 24L202 24L201 25L201 26L200 26L198 27L197 29L198 29L199 30L198 31L197 31L196 33L196 34L195 34L194 35L193 35L193 34L192 33L191 31L190 31L188 32L187 32L186 31L185 30L185 28L186 27L189 27L191 26L192 24L195 22L196 21L199 20L201 20L203 20L205 19L206 19L208 19L211 20L210 20L211 20L212 20L214 21L217 21L220 22L221 23L220 24L218 24L214 23L213 23L215 24L215 26L216 26L217 26L217 25L220 25L222 24L223 24L224 24L225 23L224 23L224 22L223 21L226 22L227 22L226 22L226 23L228 23L228 22L230 22L234 21L233 22L235 22L237 22L239 21L240 22L241 21L240 20L241 20L244 20L245 21L249 22L249 21L248 21L247 21L247 20L247 19L249 18L249 17L250 17L253 17L253 18L252 19L253 20L253 21L254 22L253 22L251 24L252 24L253 23L254 23L255 22L254 22L255 21L254 21L254 20L254 19L253 19L255 18L255 17L256 18L255 19L256 19L256 18L258 18L260 18L262 18L261 17L261 16L262 16L265 16L267 16L266 16L267 15L268 15L270 14L273 14L276 14L277 14L279 14L281 14L281 13L282 13L284 12L286 13L285 13L287 13ZM229 49L230 49L230 50L229 51L229 52L230 53L231 53L232 53L234 53L234 52L234 51L233 51L233 50L233 49L234 49L235 49L234 48L233 48L233 49L233 48L232 48L233 48L233 47L231 47L231 46L230 46L230 45L231 45L232 45L233 45L233 44L233 43L232 43L231 43L230 43L229 44L228 44L227 45L228 46L227 47L229 48L229 49ZM86 12L86 13L84 12L86 12ZM70 12L68 13L66 12L67 12L69 12L70 12ZM205 12L202 13L201 12L203 12L205 12ZM70 11L69 12L67 12L67 11L68 11L69 11L70 11ZM84 12L83 12L82 12L81 12L81 11L83 11L84 12ZM80 12L79 12L77 12L75 12L76 11L75 11L76 11L79 11L80 12ZM285 12L279 12L281 11L282 11L283 11L285 11L285 12ZM198 10L202 11L199 11L198 12L197 13L196 13L194 13L195 12L193 12L191 11L190 10L193 10L194 10L195 10L196 10L197 10L198 10ZM205 10L207 10L206 10L203 11L200 10L198 10L197 10L200 9L202 10L203 9L205 10ZM231 9L230 10L229 10L228 10L227 10L227 9L225 9L227 9L228 9L229 9L230 9L232 9L231 9ZM280 11L278 11L275 11L273 11L273 10L271 10L274 9L276 9L278 9L280 10L280 11ZM93 10L94 11L93 11L91 12L89 12L87 12L86 11L87 11L85 11L84 10L83 10L84 9L85 9L86 9L85 9L88 9L89 9L91 9L92 10L93 10ZM112 7L114 7L116 7L118 7L118 8L116 8L113 8L112 8L115 8L112 9L111 9L109 10L107 10L106 11L103 11L104 11L105 11L104 12L102 12L100 13L102 13L99 14L97 14L94 14L92 14L91 14L90 13L92 13L92 12L95 12L94 12L92 12L93 11L95 11L93 10L96 10L97 10L98 10L96 9L92 9L91 9L90 9L89 8L88 8L90 8L91 8L93 8L95 7L96 7L97 8L98 7L99 7L101 7L104 7L107 7L109 7L112 7ZM153 6L159 7L157 8L153 8L148 8L149 8L152 8L155 8L157 8L158 8L157 9L159 8L164 8L167 8L168 9L164 9L163 10L160 10L162 10L161 11L160 11L160 12L162 13L160 13L158 13L160 14L160 15L159 15L161 16L158 16L160 16L159 17L158 17L156 17L158 17L158 18L156 17L155 18L157 18L158 19L156 20L156 19L154 19L155 19L154 20L156 20L158 20L155 21L152 22L149 22L148 22L147 22L146 23L144 24L143 24L142 24L140 25L139 25L139 26L139 27L137 27L138 28L137 29L137 30L135 30L134 29L132 29L131 29L130 28L128 26L128 25L126 24L127 23L126 23L127 22L129 21L129 20L128 20L127 21L125 20L126 19L127 19L129 19L127 19L126 18L125 19L124 18L125 17L124 16L123 15L121 15L121 14L119 14L117 14L114 14L111 14L110 14L109 13L111 13L113 13L109 12L107 12L111 11L114 11L115 10L112 10L113 9L116 9L118 9L117 8L120 8L123 8L126 8L127 8L130 8L132 8L133 8L135 8L133 8L133 7L137 7L140 7L141 6L145 6L153 6Z';\n", "import { css, html, nothing, svg } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type {\n\tGetCriticalDaysResponse,\n\tGetDailyBiorhythmResponse,\n\tGetForecastResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { disclosureStyles } from '../utils/disclosure.js';\nimport { formatDate } from '../utils/format.js';\nimport {\n\ttype InterpSection,\n\tinterpAccordionStyles,\n\trenderInterpAccordion,\n} from '../utils/interp-accordion.js';\nimport { humanize } from '../utils/string.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/** The cycles a forecast day carries, in the order they are plotted and keyed in the legend. */\nconst FORECAST_CYCLES = [\n\t'physical',\n\t'emotional',\n\t'intellectual',\n\t'intuitive',\n] as const;\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\tdisclosureStyles,\n\t\tinterpAccordionStyles,\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}.head-meta{align-items:center;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.energy{font-variant-numeric:tabular-nums;color:var(--roxy-accent-ink,#b45309);font-weight:var(--roxy-weight-bold,600)}.phase{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);font-weight:var(--roxy-weight-bold,600);padding:2px 10px}.spotlight{gap:var(--roxy-space-xs,.25rem);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-border,#e4e4e7) 22%, transparent);border-radius:0 var(--roxy-radius-sm,4px) var(--roxy-radius-sm,4px) 0;display:grid}.spotlight .label{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;margin:0}.spotlight .lead{align-items:baseline;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.spotlight strong{text-transform:capitalize}.spotlight p{font-size:var(--roxy-text-sm,.875rem);margin:0;line-height:1.6}.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);margin:0}svg{width:100%;max-width:var(--roxy-chart-max-width,600px);height:auto;display:block}.legend{gap:var(--roxy-space-md,1rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-fg,#0a0a0a);flex-wrap:wrap;display:flex}.key{text-transform:capitalize;align-items:center;gap:.35rem;display:inline-flex}.dot{border-radius:var(--roxy-radius-full,9999px);width:.6rem;height:.6rem}.dot.critical{background:var(--roxy-danger,#dc2626)}.stats{gap:var(--roxy-space-sm,.5rem);grid-template-columns:repeat(auto-fit,minmax(7rem,1fr));margin:0;display:grid}.stat{gap:2px;display:grid}.stat dt{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.05em}.stat dd{font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);font-variant-numeric:tabular-nums;margin:0}.crit-note{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);background:color-mix(in srgb, var(--roxy-danger,#dc2626) 10%, transparent);border-radius:var(--roxy-radius-sm,4px);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);margin:0}.crit-meta{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);margin:0}`,\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\tconst spot = d.spotlight;\n\n\t\treturn html`<section class=\"wrap\" aria-label=\"Daily biorhythm\"><header class=\"head\"><h2 class=\"title\">Biorhythm</h2><div class=\"head-meta\">${d.overallPhase ? html`<span class=\"phase\">${humanize(d.overallPhase)}</span>` : nothing} ${\n\t\t\t\t\t\ttypeof d.energyRating === 'number'\n\t\t\t\t\t\t\t? html`<span class=\"energy\">Energy ${d.energyRating}/10</span>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}</div></header>${\n\t\t\t\tspot\n\t\t\t\t\t? html`<div class=\"spotlight\" style=\"${`border-left-color: ${CYCLE_COLOR[spot.cycle] ?? 'var(--roxy-accent, #f59e0b)'}`}\"><p class=\"label\">Spotlight cycle</p><div class=\"lead\"><strong>${spot.cycle}</strong> ${typeof spot.value === 'number' ? html`<span class=\"energy\">${spot.value}%</span>` : nothing} ${spot.phase ? html`<span class=\"phase\">${humanize(spot.phase)}</span>` : nothing}</div>${spot.message ? html`<p>${spot.message}</p>` : nothing}</div>`\n\t\t\t\t\t: nothing\n\t\t\t}<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 s = d.summary;\n\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].filter(Boolean).join(' - ')}</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\"/>${FORECAST_CYCLES.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})} ${days.map((day, i) =>\n\t\t\t\t\t// A critical day is a zero crossing, so it sits on the midline by\n\t\t\t\t\t// definition: mark it there rather than hiding it in the curves.\n\t\t\t\t\tday.isCritical\n\t\t\t\t\t\t? svg`<circle cx=${(i * xStep).toFixed(2)} cy=${h / 2} r=\"3\" fill=\"var(--roxy-danger, #dc2626)\"><title>${[\n\t\t\t\t\t\t\t\tformatDate(day.date),\n\t\t\t\t\t\t\t\tday.criticalCycles?.length\n\t\t\t\t\t\t\t\t\t? `${day.criticalCycles.join(', ')} critical`\n\t\t\t\t\t\t\t\t\t: 'critical',\n\t\t\t\t\t\t\t\ttypeof day.energyRating === 'number'\n\t\t\t\t\t\t\t\t\t? `energy ${day.energyRating}/10`\n\t\t\t\t\t\t\t\t\t: '',\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t.join(' \u00B7 ')}</title></circle>`\n\t\t\t\t\t\t: nothing,\n\t\t\t\t)}</svg><div class=\"legend\">${FORECAST_CYCLES.map(\n\t\t\t\t\t(cycle) => html`<span class=\"key\"><span class=\"dot\" style=\"${`background: ${CYCLE_COLOR[cycle]}`}\"></span>${cycle}</span>`,\n\t\t\t\t)} <span class=\"key\"><span class=\"dot critical\"></span>critical day</span></div>${\n\t\t\t\ts\n\t\t\t\t\t? html`<dl class=\"stats\">${this.stat('Best day', formatDate(s.bestDay))} ${this.stat('Worst day', formatDate(s.worstDay))} ${this.stat(\n\t\t\t\t\t\t\t'Average energy',\n\t\t\t\t\t\t\ttypeof s.averageEnergy === 'number'\n\t\t\t\t\t\t\t\t? `${s.averageEnergy}/10`\n\t\t\t\t\t\t\t\t: '',\n\t\t\t\t\t\t)} ${this.stat(\n\t\t\t\t\t\t\t'Critical days',\n\t\t\t\t\t\t\ttypeof s.criticalDayCount === 'number'\n\t\t\t\t\t\t\t\t? `${s.criticalDayCount}`\n\t\t\t\t\t\t\t\t: '',\n\t\t\t\t\t\t)}</dl>`\n\t\t\t\t\t: nothing\n\t\t\t} ${s?.periodAdvice ? html`<p class=\"advice\">${s.periodAdvice}</p>` : nothing}</section>`;\n\t}\n\n\tprivate renderCritical(d: GetCriticalDaysResponse) {\n\t\tconst days = d.criticalDays ?? [];\n\t\tconst doubles = d.doubleCriticalDays ?? [];\n\t\tconst sections: InterpSection[] = days.map((day) => ({\n\t\t\tlabel: formatDate(day.date) || day.date,\n\t\t\taside: [day.cycle, day.severity].filter(Boolean).join(' \u00B7 '),\n\t\t\tbody: day.advisory ?? '',\n\t\t\textra: html`<p class=\"crit-meta\">${[\n\t\t\t\t\tday.direction ? `${day.direction} through zero` : '',\n\t\t\t\t\ttypeof day.period === 'number' ? `${day.period} day cycle` : '',\n\t\t\t\t]\n\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t.join(' \u00B7 ')}</p>`,\n\t\t}));\n\n\t\treturn html`<section class=\"wrap\" aria-label=\"Critical days\"><header class=\"head\"><h2 class=\"title\">Critical days</h2><span class=\"energy\">${[d.startDate, d.endDate].filter(Boolean).join(' - ')}</span></header><dl class=\"stats\">${this.stat('Events', typeof d.totalCriticalDays === 'number' ? `${d.totalCriticalDays}` : '')} ${this.stat('Double days', doubles.length ? `${doubles.length}` : '0')} ${this.stat('Triple day', d.tripleCriticalDay ? formatDate(d.tripleCriticalDay) : 'none')}</dl>${\n\t\t\t\tdoubles.length > 0\n\t\t\t\t\t? html`<p class=\"crit-note\">Two or more cycles cross zero on ${doubles.map((x) => formatDate(x) || x).join(', ')}. Take extra care on these dates.</p>`\n\t\t\t\t\t: nothing\n\t\t\t} ${renderInterpAccordion(sections, 'biorhythm-critical', 'Advisories')}</section>`;\n\t}\n\n\tprivate stat(label: string, value: string) {\n\t\tif (!value) return nothing;\n\t\treturn html`<div class=\"stat\"><dt>${label}</dt><dd>${value}</dd></div>`;\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, state } 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 { chevron, disclosureStyles } from '../utils/disclosure.js';\nimport {\n\thdReadingStyles,\n\ttype ReadingSection,\n\trenderHdFacts,\n\trenderHdKeynotes,\n\trenderHdReading,\n\trenderHdThemes,\n} from '../utils/hd-reading.js';\nimport { interpAccordionStyles } from '../utils/interp-accordion.js';\nimport { capitalize } from '../utils/string.js';\nimport { renderTablist, tablistStyles } from '../utils/tablist.js';\n\ntype Bodygraph = GenerateBodygraphResponse;\ntype GateActivation = Bodygraph['gates'][number];\ntype CenterEntry = Bodygraph['centers'][number];\ntype ChannelEntry = Bodygraph['channels'][number];\n\n/**\n * Human Design bodygraph. Pass `data` from /human-design/bodygraph. Renders the nine centers in their canonical positions and shapes, filled when defined and outlined when open, the 36 channels as wiring between gates with active channels emphasized, and the activated gate numbers.\n *\n * @remarks\n * The response carries a full interpretation, not just labels, so the card is laid out in four passes from identity down to detail. Identity sits beside the chart and is always visible: the type, strategy, authority, profile, and definition tiles, the type description as the lead paragraph, the incarnation cross, and the signature and not-self themes. Everything below is progressive disclosure through the shared exclusive-accordion pattern, so only one body of prose is ever open at a time and the card never becomes a wall of text: the reading (strategy, authority, profile, definition, aura, cross), the defined channels grouped by circuit, the nine centers, and the 26 gate activations split by chart side.\n *\n * A center returns `notSelfQuestion` whatever its state, but the question describes the conditioning of an OPEN center, so it is rendered only when the center is open. `theme` already tracks the defined or open state and is always shown.\n *\n * The chart is theme-driven through `--roxy-*` custom properties on `:host`, so it adopts the host palette in light and dark without runtime color probing.\n */\n@customElement('roxy-bodygraph')\nexport class RoxyBodygraph extends RoxyDataElement<Bodygraph> {\n\t/** Which chart side the activations panel is showing. View state, not configuration: the response always carries both sides. */\n\t@state()\n\tprivate side: 'personality' | 'design' = 'personality';\n\n\tstatic styles = [\n\t\tbaseStyles,\n\t\ttablistStyles,\n\t\tdisclosureStyles,\n\t\tinterpAccordionStyles,\n\t\thdReadingStyles,\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}.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>=40rem){.layout{grid-template-columns:minmax(0,340px) minmax(0,1fr)}}.chart{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}.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}.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}.group{margin-bottom:var(--roxy-space-md,1rem)}.group:last-child{margin-bottom:0}.group-head{font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-fg,#0a0a0a);margin:0}.group-note{margin:0 0 var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);line-height:1.6}.footnote{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);margin:0;line-height:1.6}.chip{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:1px 8px;display:inline-block}.chip--on{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 18%, transparent)}.chips{flex-wrap:wrap;gap:.25rem;display:inline-flex}.gate-id,.chan-gates{font-variant-numeric:tabular-nums;font-weight:var(--roxy-weight-bold,600);color:var(--roxy-accent-ink,#b45309)}.glyph{color:var(--roxy-accent-ink,#b45309)}.side-note{margin:0 0 var(--roxy-space-sm,.5rem);padding-top:var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);line-height:1.6}`,\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: Bodygraph) {\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\t// One text node, not two: the markup minifier collapses the leading\n\t\t\t\t\t// space of an adjacent template and the separator would lose it.\n\t\t\t\t\td.type || d.profile\n\t\t\t\t\t\t? html`<div class=\"type-line\">${[d.type, d.profile ? `Profile ${d.profile}` : ''].filter(Boolean).join(' \u00B7 ')}</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</header><div class=\"layout\"><svg class=\"chart\" 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>${this.renderReading(d)} ${this.renderChannels(d.channels ?? [])} ${this.renderCenters(d.centers ?? [])} ${this.renderActivations(d)}</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 glyph = this.planetGlyph(g.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\t/** Monochrome planet glyph for an API planet name, or the name itself when the wheel has no glyph for it. */\n\tprivate planetGlyph(planet: string | undefined): string {\n\t\tif (!planet) return '';\n\t\tconst name = capitalize(planet);\n\t\treturn PLANET_GLYPH[name] ?? planet;\n\t}\n\n\tprivate renderSummary(d: Bodygraph) {\n\t\tconst ic = d.incarnationCross;\n\t\treturn html`<div class=\"summary\">${renderHdFacts([\n\t\t\t\t{ label: 'Type', value: d.type },\n\t\t\t\t{ label: 'Strategy', value: d.strategy },\n\t\t\t\t{ label: 'Authority', value: d.authority },\n\t\t\t\t{ label: 'Profile', value: d.profile },\n\t\t\t\t{ label: 'Definition', value: d.definition },\n\t\t\t])} ${d.typeDescription ? html`<p class=\"lead\">${d.typeDescription}</p>` : nothing} ${\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} ${renderHdThemes(d.signature, d.notSelf)}<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\t/**\n\t * The mechanics of the design, in the order a reader needs them: how to engage (strategy), how to decide (authority), the role played (profile), how the definition hangs together, the aura, and the life theme of the incarnation cross. The cross name and gates already sit beside the chart, so only its description is repeated here.\n\t */\n\tprivate renderReading(d: Bodygraph) {\n\t\tconst ic = d.incarnationCross;\n\t\tconst sections: ReadingSection[] = [\n\t\t\t{ label: 'Strategy', aside: d.strategy, body: d.strategyDescription },\n\t\t\t{ label: 'Authority', aside: d.authority, body: d.authorityDescription },\n\t\t\t{\n\t\t\t\tlabel: 'Profile',\n\t\t\t\taside: d.profile,\n\t\t\t\tbody: d.profileDescription,\n\t\t\t\textra: renderHdKeynotes(d.profileKeynotes),\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: 'Definition',\n\t\t\t\taside: d.definition,\n\t\t\t\tbody: d.definitionDescription,\n\t\t\t},\n\t\t\t{ label: 'Aura', body: d.aura },\n\t\t\t{\n\t\t\t\tlabel: 'Incarnation cross',\n\t\t\t\taside: ic?.angle,\n\t\t\t\tbody: ic?.description ?? '',\n\t\t\t},\n\t\t];\n\t\treturn renderHdReading(sections, 'hd-reading');\n\t}\n\n\t/**\n\t * Defined channels, grouped by circuit. The circuit description is the same\n\t * text for every channel that belongs to it, so it is lifted to the group\n\t * intro instead of repeating inside each row. Groups keep response order, which\n\t * is gate order; no circuit ranking is invented.\n\t */\n\tprivate renderChannels(channels: ChannelEntry[]) {\n\t\tif (channels.length === 0) return nothing;\n\t\tconst groups = new Map<string, ChannelEntry[]>();\n\t\tfor (const c of channels) {\n\t\t\tconst key = c.circuit ?? '';\n\t\t\tconst bucket = groups.get(key);\n\t\t\tif (bucket) bucket.push(c);\n\t\t\telse groups.set(key, [c]);\n\t\t}\n\t\t// One accordion group spans every circuit, so the open row is the first\n\t\t// channel overall, not the first of each circuit.\n\t\tlet index = 0;\n\n\t\treturn html`<section class=\"block\"><h3>Defined channels (${channels.length})</h3>${[...groups].map(\n\t\t\t\t([circuit, list]) => html`<div class=\"group\">${circuit ? html`<p class=\"group-head\">${circuit} circuit</p>` : nothing} ${\n\t\t\t\t\t\tlist[0]?.circuitDescription\n\t\t\t\t\t\t\t? html`<p class=\"group-note\">${list[0].circuitDescription}</p>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t} ${list.map(\n\t\t\t\t\t\t(\n\t\t\t\t\t\t\tc,\n\t\t\t\t\t\t) => html`<details class=\"interp-card\" name=\"hd-channel\" ?open=\"${index++ === 0}\"><summary><span class=\"interp-lead\"><span class=\"chan-gates\">${c.gateA}-${c.gateB}</span> <span>${c.name ?? ''}</span> </span>${chevron()}</summary><div class=\"interp-body\">${c.description ? html`<p>${c.description}</p>` : nothing}</div></details>`,\n\t\t\t\t\t)}</div>`,\n\t\t\t)}</section>`;\n\t}\n\n\t/**\n\t * The nine centers. `theme` already reflects whether the center came back\n\t * defined or open, so it always shows. `notSelfQuestion` is written for the\n\t * OPEN state (\"the open Spleen clings to...\"), so showing it on a defined\n\t * center would state the opposite of the chart; it is rendered for open\n\t * centers only.\n\t */\n\tprivate renderCenters(centers: CenterEntry[]) {\n\t\tif (centers.length === 0) return nothing;\n\t\tconst definedCount = centers.filter((c) => c.defined).length;\n\t\treturn html`<section class=\"block\"><h3>Centers (${definedCount} defined, ${centers.length - definedCount} open)</h3>${centers.map(\n\t\t\t\t(\n\t\t\t\t\tc,\n\t\t\t\t\ti,\n\t\t\t\t) => html`<details class=\"interp-card\" name=\"hd-center\" ?open=\"${i === 0}\"><summary><span class=\"interp-lead\">${c.name ?? ''}</span> ${chevron()} <span class=\"interp-aside\"><span class=\"chips\"><span class=\"chip ${c.defined ? 'chip--on' : ''}\">${c.defined ? 'Defined' : 'Open'}</span> ${c.motor ? html`<span class=\"chip\">Motor</span>` : nothing} ${c.awareness ? html`<span class=\"chip\">Awareness</span>` : nothing}</span></span></summary><div class=\"interp-body\">${c.theme ? html`<p>${c.theme}</p>` : nothing} ${\n\t\t\t\t\t\t\t!c.defined && c.notSelfQuestion\n\t\t\t\t\t\t\t\t? html`<dl class=\"keynotes\"><dt>Not-self question</dt><dd>${c.notSelfQuestion}</dd></dl>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t} ${c.biology ? html`<p class=\"footnote\">Biology. ${c.biology}</p>` : nothing} ${\n\t\t\t\t\t\t\tc.gates?.length\n\t\t\t\t\t\t\t\t? html`<p class=\"footnote\">Gates ${c.gates.join(', ')}</p>`\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\t/**\n\t * The 26 activations, split by chart side. Personality is the conscious side\n\t * printed in black, design the unconscious side printed in red, and the\n\t * response describes each once at the top level, so the side description\n\t * becomes the panel intro rather than an orphan glossary entry. Splitting the\n\t * list in two also halves what a reader scans: 13 rows per side, in the\n\t * canonical planet order the response returns.\n\t */\n\tprivate renderActivations(d: Bodygraph) {\n\t\tconst gates = d.gates ?? [];\n\t\tif (gates.length === 0) return nothing;\n\n\t\tconst personality = gates.filter((g) => g.side === 'personality');\n\t\tconst design = gates.filter((g) => g.side === 'design');\n\t\t// A response with only one side (or an unrecognized side value) still\n\t\t// renders: fall back to the flat list and drop the tabs.\n\t\tconst split = personality.length > 0 && design.length > 0;\n\t\tconst side = this.side;\n\t\tconst shown = split ? (side === 'design' ? design : personality) : gates;\n\t\tconst sideNote = split ? d.sides?.[side] : undefined;\n\n\t\treturn html`<section class=\"block\"><h3>Activations (${gates.length})</h3>${\n\t\t\t\tsplit\n\t\t\t\t\t? renderTablist({\n\t\t\t\t\t\t\titems: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tid: 'personality' as const,\n\t\t\t\t\t\t\t\t\tlabel: `Personality (${personality.length})`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{ id: 'design' as const, label: `Design (${design.length})` },\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tactive: side,\n\t\t\t\t\t\t\tonSelect: (v) => {\n\t\t\t\t\t\t\t\tthis.side = v;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tlabel: 'Chart sides',\n\t\t\t\t\t\t\tidPrefix: 'hd',\n\t\t\t\t\t\t\tcontrols: true,\n\t\t\t\t\t\t})\n\t\t\t\t\t: nothing\n\t\t\t}<div id=\"${split ? `hd-panel-${side}` : nothing}\" role=\"${split ? 'tabpanel' : nothing}\" aria-labelledby=\"${split ? `hd-tab-${side}` : nothing}\">${sideNote ? html`<p class=\"side-note\">${sideNote}</p>` : nothing} ${shown.map((g, i) => this.renderGate(g, i === 0))}</div></section>`;\n\t}\n\n\tprivate renderGate(g: GateActivation, open: boolean) {\n\t\tconst glyph = this.planetGlyph(g.planet);\n\t\tconst hex = g.ichingHexagram;\n\t\treturn html`<details class=\"interp-card\" name=\"hd-gate\" ?open=\"${open}\"><summary><span class=\"interp-lead\">${glyph ? html`<span class=\"glyph\" aria-hidden=\"true\">${glyph}</span>` : nothing} <span class=\"gate-id\">${g.gate}${g.line != null ? `.${g.line}` : ''}</span> <span>${g.gateName ?? ''}</span> </span>${chevron()} ${g.planet ? html`<span class=\"interp-aside\"><small>${g.planet}</small></span>` : nothing}</summary><div class=\"interp-body\">${g.gateDescription ? html`<p>${g.gateDescription}</p>` : nothing} ${\n\t\t\t\t\tg.lineMeaning\n\t\t\t\t\t\t? html`<dl class=\"keynotes\"><dt>Line ${g.line ?? ''}</dt><dd>${g.lineMeaning}</dd></dl>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} ${\n\t\t\t\t\tg.planetDescription\n\t\t\t\t\t\t? html`<p class=\"footnote\">${g.planet}. ${g.planetDescription}</p>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} ${\n\t\t\t\t\thex?.number\n\t\t\t\t\t\t? html`<p class=\"footnote\">I Ching hexagram ${hex.number}${hex.english ? `, ${hex.english}` : ''}</p>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</div></details>`;\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", "/**\n * The Human Design reading surface: the fact tiles, the lead paragraph, the signature and not-self pills, and the profile keynotes.\n *\n * @remarks\n * `/human-design/type` returns a strict subset of the `/human-design/bodygraph` interpretation fields (type, aura, strategy, authority, their descriptions, signature, not-self, profile), so `roxy-bodygraph` and `roxy-hd-type-card` would otherwise render the same markup and carry the same CSS twice. Both import from here instead: the bodygraph wraps the chart around it, the type card is the reading on its own.\n *\n * The disclosure accordion itself is NOT here. It lives in `utils/interp-accordion.ts`, because the same accordion serves any endpoint that returns a labelled reading (`roxy-hexagram` uses it for the changing lines). Import `interpAccordionStyles` alongside `hdReadingStyles`.\n */\n\nimport { css, html, nothing } from 'lit';\nimport {\n\ttype InterpSection,\n\trenderInterpAccordion,\n} from './interp-accordion.js';\n\n/** One row of the reading accordion. Alias of the shared {@link InterpSection} so HD call sites keep reading naturally. */\nexport type ReadingSection = InterpSection;\n\n/** A labelled value tile. A fact with no value is dropped, so a narrower response renders fewer tiles rather than empty ones. */\nexport interface Fact {\n\tlabel: string;\n\tvalue?: string;\n}\n\n/** The two profile lines with the keynote of each. Normalized: the bodygraph nests these under `profileKeynotes`, `/human-design/profile` returns them flat, and both map onto this. */\nexport interface ProfileKeynotes {\n\tpersonality?: string;\n\tpersonalityLine?: number;\n\tdesign?: string;\n\tdesignLine?: number;\n}\n\nexport const hdReadingStyles = css`.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)}.lead{color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);margin:0;line-height:1.6}.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)}.keynotes{gap:var(--roxy-space-xs,.25rem);margin:0;display:grid}.keynotes dt{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.05em}.keynotes dd{margin:0}`;\n\n/** The labelled value tiles. Values the response does not carry are dropped rather than rendered empty. */\nexport function renderHdFacts(facts: Fact[]) {\n\tconst shown = facts.filter((f) => Boolean(f.value));\n\tif (shown.length === 0) return nothing;\n\treturn html`<div class=\"facts\">${shown.map(\n\t\t\t(f) => html`<div class=\"fact\"><span>${f.label}</span> <strong>${f.value}</strong></div>`,\n\t\t)}</div>`;\n}\n\n/** The signature and not-self pills: the feeling of being in alignment, and the one that signals being out of it. */\nexport function renderHdThemes(signature?: string, notSelf?: string) {\n\tif (!signature && !notSelf) return nothing;\n\treturn html`<div class=\"themes\">${signature ? html`<span class=\"pill pill--good\">Signature: ${signature}</span>` : nothing} ${notSelf ? html`<span class=\"pill pill--shadow\">Not-self: ${notSelf}</span>` : nothing}</div>`;\n}\n\n/** The reading accordion. Thin pass-through to the shared renderer so the HD components keep a domain-named call site while the markup and CSS live in one place. */\nexport function renderHdReading(\n\tsections: ReadingSection[],\n\tname: string,\n\theading = 'Reading',\n) {\n\treturn renderInterpAccordion(sections, name, heading);\n}\n\n/** The two profile lines, each with the keynote of the line. Personality first: it is the conscious line and the one the profile is read from. */\nexport function renderHdKeynotes(k: ProfileKeynotes | undefined) {\n\tif (!k?.personality && !k?.design) return nothing;\n\treturn html`<dl class=\"keynotes\">${\n\t\t\tk.personality\n\t\t\t\t? html`<dt>Line ${k.personalityLine ?? ''} \u00B7 Personality</dt><dd>${k.personality}</dd>`\n\t\t\t\t: nothing\n\t\t} ${\n\t\t\tk.design\n\t\t\t\t? html`<dt>Line ${k.designLine ?? ''} \u00B7 Design</dt><dd>${k.design}</dd>`\n\t\t\t\t: nothing\n\t\t}</dl>`;\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 { formatTimeRange } from '../utils/format.js';\nimport { capitalize } from '../utils/string.js';\n\ntype ChoghadiyaPeriod = GetChoghadiyaResponse['dayChoghadiya'][number];\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 = formatTimeRange(period);\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 { PLANET_GLYPH, SIGN_GLYPH } from '../tokens/index.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 { disclosureStyles } from '../utils/disclosure.js';\nimport { formatNumber } from '../utils/format.js';\nimport {\n\ttype InterpSection,\n\tinterpAccordionStyles,\n\trenderInterpAccordion,\n} from '../utils/interp-accordion.js';\nimport { capitalize } from '../utils/string.js';\n\ntype CompatibilityData =\n\t| CalculateCompatibilityResponse\n\t| CalculateNumCompatibilityResponse\n\t| CalculateBioCompatibilityResponse;\n\ntype AstroCompat = CalculateCompatibilityResponse;\n\n/** The four relationship planets, in the order a synastry reading works them: identity, feeling, love, desire. */\nconst RELATIONSHIP_PLANETS = ['sun', 'moon', 'venus', 'mars'] as const;\nconst ELEMENTS = ['fire', 'earth', 'air', 'water'] as const;\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\tdisclosureStyles,\n\t\tinterpAccordionStyles,\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}.lead{color:var(--roxy-fg,#0a0a0a);margin:0;font-weight:500}p.body{color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);margin:0;line-height:1.6}.pills{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;display:flex}.pill{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) 60%, transparent);color:var(--roxy-fg,#0a0a0a);padding:2px 8px}.pill--success{background:color-mix(in srgb, var(--roxy-success,#16a34a) 12%, transparent);color:var(--roxy-success-fg,#166534)}.pill--danger{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 12%, transparent);color:var(--roxy-danger-fg,#991b1b)}.elements{gap:var(--roxy-space-sm,.5rem);display:grid}.el-row{align-items:center;gap:var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-sm,.875rem);grid-template-columns:4rem 1fr 1fr;display:grid}.el-row .el-name{text-transform:capitalize;color:var(--roxy-fg,#0a0a0a)}.el-row.head span{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);text-transform:uppercase;letter-spacing:.06em;font-weight:var(--roxy-weight-bold,600)}.el-row.head span:nth-child(2){text-align:right}.el-bar{font-variant-numeric:tabular-nums;color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);align-items:center;gap:.4rem;display:flex}.el-bar.p1{flex-direction:row-reverse}.el-bar .track{background:var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-full,9999px);flex:auto;height:8px;display:flex;overflow:hidden}.el-bar.p1 .track{justify-content:flex-end}.el-bar .track>span{background:var(--roxy-accent,#f59e0b);height:100%;display:block}.el-bar.p2 .track>span{background:var(--roxy-info,#0284c7)}.el-row.shared .el-name{font-weight:var(--roxy-weight-bold,600)}.shared-note{margin:var(--roxy-space-sm,.5rem) 0 0;font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a)}.key-aspects{padding-left:var(--roxy-space-md,1rem);font-size:var(--roxy-text-sm,.875rem);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\">${Math.round(score)}</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>${Math.round(v)}</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 class=\"lead\">${summary}</p>` : nothing} ${interpretation ? html`<p class=\"body\">${interpretation}</p>` : nothing} ${advice ? html`<p class=\"body\">${advice}</p>` : nothing} ${this.renderAspectBreakdown()} ${this.renderSignCompatibility()} ${this.renderElementBalance()} ${this.renderSubScores()} ${\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 class=\"lists\"><div><h3>Key aspects</h3><ul class=\"key-aspects\">${keyAspects.slice(0, 6).map((a) => html`<li>${formatAspect(a)}</li>`)}</ul></div></div>`\n\t\t\t\t\t: nothing\n\t\t\t}</article>`;\n\t}\n\n\t/** Contact balance behind the score. Astrology only. */\n\tprivate renderAspectBreakdown() {\n\t\tconst b = this.astro()?.aspectBreakdown;\n\t\tif (!b) return nothing;\n\t\treturn html`<div class=\"pills\" role=\"region\" aria-label=\"Aspect breakdown\">${typeof b.total === 'number' ? html`<span class=\"pill\">Total: ${b.total}</span>` : nothing} <span class=\"pill pill--success\">Harmonious: ${b.harmonious}</span> <span class=\"pill pill--danger\">Challenging: ${b.challenging}</span> <span class=\"pill\">Neutral: ${b.neutral}</span></div>`;\n\t}\n\n\t/**\n\t * Sign-by-sign reading for the four relationship planets. The aside pairs the two signs (with degrees from `persons`, which would otherwise be dropped) so the header answers \"which signs\" before the body answers \"and so what\".\n\t */\n\tprivate renderSignCompatibility() {\n\t\tconst d = this.astro();\n\t\tconst sc = d?.signCompatibility;\n\t\tif (!sc) return nothing;\n\t\tconst persons = d?.persons;\n\t\tconst sections = RELATIONSHIP_PLANETS.map(\n\t\t\t(planet): InterpSection | null => {\n\t\t\t\tconst pair = sc[planet];\n\t\t\t\tif (!pair) return null;\n\t\t\t\tconst at = (p: 'person1' | 'person2'): string => {\n\t\t\t\t\tconst sign = capitalize(\n\t\t\t\t\t\t(p === 'person1' ? pair.person1Sign : pair.person2Sign) ?? '',\n\t\t\t\t\t);\n\t\t\t\t\tconst deg = persons?.[p]?.[planet]?.degree;\n\t\t\t\t\tconst glyph = SIGN_GLYPH[sign] ?? '';\n\t\t\t\t\tconst degree = typeof deg === 'number' ? ` ${Math.round(deg)}\u00B0` : '';\n\t\t\t\t\treturn `${glyph} ${sign}${degree}`.trim();\n\t\t\t\t};\n\t\t\t\treturn {\n\t\t\t\t\tlabel:\n\t\t\t\t\t\t`${PLANET_GLYPH[capitalize(planet)] ?? ''} ${capitalize(planet)}`.trim(),\n\t\t\t\t\taside: `${at('person1')} and ${at('person2')}`,\n\t\t\t\t\tbody: pair.description ?? '',\n\t\t\t\t};\n\t\t\t},\n\t\t).filter((s): s is InterpSection => s !== null);\n\t\treturn renderInterpAccordion(\n\t\t\tsections,\n\t\t\t'compat-signs',\n\t\t\t'Sign compatibility',\n\t\t);\n\t}\n\n\t/**\n\t * Elemental weight of both charts, mirrored around the element name so a shared emphasis reads as a matched pair. The shared element (or its absence) is the headline the API computes, so it is stated rather than left for the reader to spot.\n\t */\n\tprivate renderElementBalance() {\n\t\tconst eb = this.astro()?.elementBalance;\n\t\tif (!eb) return nothing;\n\t\tconst p1 = eb.person1;\n\t\tconst p2 = eb.person2;\n\t\tconst max = Math.max(\n\t\t\t1,\n\t\t\t...ELEMENTS.map((e) => Math.max(p1?.[e] ?? 0, p2?.[e] ?? 0)),\n\t\t);\n\t\tconst shared = eb.sharedElement?.toLowerCase();\n\t\treturn html`<section class=\"block\"><h3>Element balance</h3><div class=\"elements\"><div class=\"el-row head\"><span></span> <span>Person 1</span> <span>Person 2</span></div>${ELEMENTS.map((el) => {\n\t\t\t\t\tconst a = p1?.[el] ?? 0;\n\t\t\t\t\tconst b = p2?.[el] ?? 0;\n\t\t\t\t\treturn html`<div class=\"${el === shared ? 'el-row shared' : 'el-row'}\"><span class=\"el-name\">${el}</span> <span class=\"el-bar p1\"><span>${a}</span> <span class=\"track\"><span style=\"width:${(a / max) * 100}%\"></span></span> </span><span class=\"el-bar p2\"><span class=\"track\"><span style=\"width:${(b / max) * 100}%\"></span></span> <span>${b}</span></span></div>`;\n\t\t\t\t})}</div>${eb.description ? html`<p class=\"shared-note\">${eb.description}</p>` : nothing}</section>`;\n\t}\n\n\t/**\n\t * Per-cycle readings the other two domains carry instead of astrology categories: the numerology core numbers (Life Path, Expression, Soul Urge) and the biorhythm cycle alignments. Both are labelled score-plus-prose, which is exactly what the interpretation accordion is for.\n\t */\n\tprivate renderSubScores() {\n\t\tconst d = this.data;\n\t\tif (!d) return nothing;\n\t\tconst sections: InterpSection[] = [];\n\t\tif ('lifePath' in d) {\n\t\t\tconst cores: Array<[string, typeof d.lifePath]> = [\n\t\t\t\t['Life Path', d.lifePath],\n\t\t\t\t['Expression', d.expression],\n\t\t\t\t['Soul Urge', d.soulUrge],\n\t\t\t];\n\t\t\tfor (const [label, core] of cores) {\n\t\t\t\tif (!core) continue;\n\t\t\t\tsections.push({\n\t\t\t\t\tlabel,\n\t\t\t\t\taside: `${core.person1} and ${core.person2} \u00B7 ${formatNumber(core.compatibility, 0)}%`,\n\t\t\t\t\tbody: core.description ?? '',\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tif ('cycles' in d && d.cycles) {\n\t\t\tfor (const [name, cycle] of Object.entries(d.cycles)) {\n\t\t\t\tif (!cycle) continue;\n\t\t\t\tsections.push({\n\t\t\t\t\tlabel: capitalize(name),\n\t\t\t\t\taside: `${formatNumber(cycle.alignment, 0)}% in step \u00B7 ${cycle.phase?.replace(/_/g, ' ')}`,\n\t\t\t\t\tbody: cycle.description ?? '',\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn renderInterpAccordion(sections, 'compat-sub-scores', 'Breakdown');\n\t}\n\n\t/** The astrology response, or undefined when the card is showing another domain. `signCompatibility` is unique to it, so it is the discriminator. */\n\tprivate astro(): AstroCompat | undefined {\n\t\tconst d = this.data;\n\t\treturn d && 'signCompatibility' in d ? (d as AstroCompat) : undefined;\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';\nimport { cssColor } from '../utils/css-color.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:${cssColor(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", "/**\n * Resolve a crystal colour keyword to a paintable CSS colour.\n *\n * @remarks\n * Two thirds of the 92 colour values the crystals API serves are COMPOUNDS (\"blue-green\", \"pale brass-yellow\", \"deep brownish red\"), and a compound is never a valid CSS colour, so painting the raw string leaves the swatch blank. Both crystal components used to carry their own copy that merely lowercased and stripped spaces, which turns \"apple green\" into `applegreen` and blanks just the same. One resolver now serves both.\n */\n\n/**\n * Colour words the crystals API returns that CSS cannot resolve, mapped to their closest CSS value. Also collapses the `-ish` and plural forms onto their base word, so \"bluish\" and \"browns\" resolve like \"blue\" and \"brown\".\n */\nconst COLOR_WORDS: Record<string, string> = {\n\tapple: '#8db600',\n\tazure: '#007fff',\n\tblackish: 'black',\n\tbluish: 'blue',\n\tbottle: '#006a4e',\n\tbrass: '#b5a642',\n\tbrick: '#b22222',\n\tbrownish: 'brown',\n\tbrowns: 'brown',\n\tburgundy: '#800020',\n\tclear: '#eef2f6',\n\tcolorless: '#eef2f6',\n\tcolourless: '#eef2f6',\n\tcream: '#fffdd0',\n\tcreamy: '#fffdd0',\n\temerald: '#50c878',\n\tgolden: 'gold',\n\tgreenish: 'green',\n\tlilac: '#c8a2c8',\n\tmauve: '#e0b0ff',\n\tpeach: 'peachpuff',\n\tpinkish: 'pink',\n\treddish: 'red',\n\trose: '#f4a6b7',\n\troyal: 'royalblue',\n\tsilvery: 'silver',\n\tsky: 'skyblue',\n\tyellowish: 'yellow',\n};\n\n/** CSS named colours the crystals vocabulary uses verbatim. A word outside this set and {@link COLOR_WORDS} is not a colour, so it is dropped rather than passed through: one unresolvable token would otherwise invalidate the whole color-mix and blank the swatch. */\nconst CSS_COLORS = new Set([\n\t'beige',\n\t'black',\n\t'blue',\n\t'brown',\n\t'crimson',\n\t'cyan',\n\t'gold',\n\t'gray',\n\t'green',\n\t'grey',\n\t'indigo',\n\t'lavender',\n\t'magenta',\n\t'maroon',\n\t'navy',\n\t'olive',\n\t'orange',\n\t'pink',\n\t'purple',\n\t'red',\n\t'salmon',\n\t'silver',\n\t'tan',\n\t'teal',\n\t'turquoise',\n\t'violet',\n\t'white',\n\t'yellow',\n]);\n\n/** Qualifiers that shade a base colour instead of naming one: the mix partner, and how much of the base survives the mix. */\nconst COLOR_QUALIFIERS: Record<string, [partner: string, keepPct: number]> = {\n\tbright: ['white', 85],\n\tdark: ['black', 60],\n\tdeep: ['black', 70],\n\tfaintly: ['white', 30],\n\tlight: ['white', 55],\n\tpale: ['white', 45],\n\trich: ['black', 80],\n};\n\n/**\n * Resolve a crystal colour keyword to a paintable CSS colour.\n *\n * @remarks\n * Two thirds of the 92 colour values the crystals API serves are compounds (\"blue-green\", \"pale brass-yellow\", \"deep brownish red\"), and a compound is never a CSS colour, so painting the raw string leaves the swatch blank. Split on spaces and hyphens instead: qualifiers ({@link COLOR_QUALIFIERS}) shade, the first two colour words mix, and anything unrecognised is dropped. A value with no colour word at all (\"banded\") falls back to the border token rather than painting nothing.\n *\n *\n * @example\n * ```ts\n * cssColor('blue-green'); // color-mix(in srgb, blue, green)\n * cssColor('pale yellow'); // color-mix(in srgb, yellow 45%, white)\n * ```\n */\nexport function cssColor(name: string): string {\n\tconst bases: string[] = [];\n\tconst qualifiers: Array<[string, number]> = [];\n\tfor (const word of name.toLowerCase().split(/[\\s-]+/)) {\n\t\tconst qualifier = COLOR_QUALIFIERS[word];\n\t\tif (qualifier) {\n\t\t\tqualifiers.push(qualifier);\n\t\t\tcontinue;\n\t\t}\n\t\tconst base = COLOR_WORDS[word] ?? (CSS_COLORS.has(word) ? word : '');\n\t\tif (base) bases.push(base);\n\t}\n\n\tconst [first, second] = bases;\n\tif (!first) return 'var(--roxy-border, #e4e4e7)';\n\tlet color = second ? `color-mix(in srgb, ${first}, ${second})` : first;\n\tfor (const [partner, keepPct] of qualifiers) {\n\t\tcolor = `color-mix(in srgb, ${color} ${keepPct}%, ${partner})`;\n\t}\n\treturn color;\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';\nimport { cssColor } from '../utils/css-color.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\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 { disclosureStyles } from '../utils/disclosure.js';\nimport { formatDate, formatNumber } from '../utils/format.js';\nimport {\n\ttype InterpSection,\n\tinterpAccordionStyles,\n\trenderInterpAccordion,\n} from '../utils/interp-accordion.js';\n\ntype DashaData =\n\t| GetCurrentDashaResponse\n\t| GetMajorDashasResponse\n\t| GetSubDashasResponse;\n\ntype DashaPeriod = GetMajorDashasResponse['mahadashas'][number];\ntype Remaining = GetCurrentDashaResponse['remainingInMahadasha'];\n\n/** The level a period sits at, so no view ever labels an antardasha a mahadasha. */\nconst LEVEL_LABEL = {\n\tcurrent: 'Mahadasha',\n\tmajor: 'Mahadasha',\n\tsub: 'Antardasha',\n} as const;\n\n/** \"8y 11m 5d\", the form a dasha reader expects for a remaining balance. */\nfunction formatBalance(b: Remaining | undefined): string {\n\tif (!b) return '';\n\tconst parts: string[] = [];\n\tif (b.years) parts.push(`${b.years}y`);\n\tif (b.months) parts.push(`${b.months}m`);\n\tif (b.days) parts.push(`${b.days}d`);\n\treturn parts.length ? parts.join(' ') : '0d';\n}\n\n/** \"Jun 17, 2018 to Jun 17, 2035\" for the accordion aside. */\nfunction formatSpan(p: { startDate?: string; endDate?: string }): string {\n\tconst start = p.startDate ? formatDate(p.startDate) : '';\n\tconst end = p.endDate ? formatDate(p.endDate) : '';\n\tif (start && end) return `${start} to ${end}`;\n\treturn start || end;\n}\n\n/**\n * Dasha timeline. Renders /vedic-astrology/dasha/{current,major,sub/{...}}.\n *\n * @remarks\n * Default mode shows the active mahadasha, antardasha and pratyantardasha with\n * the reading each one carries. `period=\"major\"` draws the full 120-year\n * Vimshottari timeline; `period=\"sub\"` draws the antardashas inside one\n * mahadasha and states which mahadasha they sit in, since an antardasha means\n * nothing without its parent lord.\n */\n@customElement('roxy-dasha-timeline')\nexport class RoxyDashaTimeline extends RoxyDataElement<DashaData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tdisclosureStyles,\n\t\tinterpAccordionStyles,\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)}.current div small{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);display:block}.balance,.parent{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}.block{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)}`,\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\">${this.heading(d)}</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.renderParentMahadasha(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} ${renderInterpAccordion(this.readings(d, periods), 'roxy-dasha', 'Reading')}</div>`;\n\t}\n\n\tprivate heading(d: DashaData): string {\n\t\tif (this.period === 'major') return 'Vimshottari Mahadasha';\n\t\tif (this.period === 'sub') {\n\t\t\tconst lord = 'mahadashaLord' in d ? d.mahadashaLord : '';\n\t\t\treturn lord ? `Antardashas in ${lord} Mahadasha` : 'Antardashas';\n\t\t}\n\t\treturn 'Active dashas';\n\t}\n\n\tprivate renderBirthBalance(d: DashaData) {\n\t\tif (!('birthDashaBalance' in d) || !d.birthDashaBalance) return nothing;\n\t\tconst lord = 'nakshatraLord' in d && d.nakshatraLord ? d.nakshatraLord : '';\n\t\tconst remaining = formatBalance(d.birthDashaBalance);\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\t/** Sub mode lists antardashas inside one mahadasha, so name the parent and its span. */\n\tprivate renderParentMahadasha(d: DashaData) {\n\t\tif (!('mahadashaPeriod' in d) || !d.mahadashaPeriod) return nothing;\n\t\tconst p = d.mahadashaPeriod;\n\t\tconst span = formatSpan(p);\n\t\treturn html`<p class=\"parent\">Inside the <strong>${p.planet}</strong> Mahadasha${span ? `, ${span}` : ''} ${typeof p.durationYears === 'number' ? `(${formatNumber(p.durationYears, 1)} years)` : ''}.</p>`;\n\t}\n\n\t/**\n\t * Every reading the response carries, behind one exclusive accordion. Current\n\t * mode has three (mahadasha, antardasha, pratyantardasha); sub mode leads with\n\t * the parent mahadasha reading, then the antardasha running now; major mode\n\t * shows the mahadasha running now.\n\t */\n\tprivate readings(d: DashaData, periods: DashaPeriod[]): InterpSection[] {\n\t\tconst sections: InterpSection[] = [];\n\n\t\tif ('mahadashaPeriod' in d && d.mahadashaPeriod?.interpretation) {\n\t\t\tsections.push({\n\t\t\t\tlabel: `${d.mahadashaPeriod.planet} Mahadasha`,\n\t\t\t\taside: formatSpan(d.mahadashaPeriod),\n\t\t\t\tbody: d.mahadashaPeriod.interpretation,\n\t\t\t});\n\t\t}\n\n\t\tif ('mahadasha' in d) {\n\t\t\tconst levels = [\n\t\t\t\t['Mahadasha', d.mahadasha, d.remainingInMahadasha],\n\t\t\t\t['Antardasha', d.antardasha, d.remainingInAntardasha],\n\t\t\t\t['Pratyantardasha', d.pratyantardasha, d.remainingInPratyantardasha],\n\t\t\t] as const;\n\t\t\tfor (const [label, period, remaining] of levels) {\n\t\t\t\tif (!period?.interpretation) continue;\n\t\t\t\tconst left = formatBalance(remaining);\n\t\t\t\tsections.push({\n\t\t\t\t\tlabel: `${period.planet} ${label}`,\n\t\t\t\t\taside: left ? `${left} left` : formatSpan(period),\n\t\t\t\t\tbody: period.interpretation,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tconst active = periods.find((p) => this.isCurrent(p));\n\t\tif (active?.interpretation) {\n\t\t\tsections.push({\n\t\t\t\tlabel: `${active.planet} ${LEVEL_LABEL[this.period]}`,\n\t\t\t\taside: formatSpan(active),\n\t\t\t\tbody: active.interpretation,\n\t\t\t});\n\t\t}\n\n\t\treturn sections;\n\t}\n\n\tprivate renderCurrent(d: DashaData) {\n\t\tif (!('mahadasha' in d)) return nothing;\n\t\tconst levels = [\n\t\t\t['Mahadasha', d.mahadasha, d.remainingInMahadasha],\n\t\t\t['Antardasha', d.antardasha, d.remainingInAntardasha],\n\t\t\t['Pratyantardasha', d.pratyantardasha, d.remainingInPratyantardasha],\n\t\t] as const;\n\t\treturn html`<div class=\"current\">${levels.map(([label, period, remaining]) => {\n\t\t\t\tif (!period) return nothing;\n\t\t\t\tconst left = formatBalance(remaining);\n\t\t\t\treturn html`<div><span>${label}</span> <strong>${period.planet}</strong> ${left ? html`<small>${left} left</small>` : nothing}</div>`;\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 { formatDate, formatNumber, formatTime } from '../utils/format.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; object and\n * object-array values promote to full-width sections below the rows so\n * nested tables keep the whole container width.\n * 5. Otherwise -> definition list of all keys.\n *\n * Scalar display rules (shared by rows, chips, and table cells): numbers\n * round to 2 decimals, booleans read Yes/No, ISO dates and datetimes format\n * for the locale, SCREAMING_SNAKE enums humanize, http(s) strings link out.\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 };\ntype Scalar = string | number | boolean;\n\nconst TITLE_KEYS = ['title', 'name', 'label', 'heading', 'overview', 'summary'];\n/** A title is a label, not a paragraph. `overview`/`summary` are only title candidates when a response carries no real name, and a whole paragraph promoted to an <h3> is worse than no title at all. */\nconst MAX_TITLE_LEN = 80;\nconst IMAGE_KEYS = ['imageUrl', 'image', 'icon', 'symbol'];\nconst SKIP_KEYS = ['imageUrl', 'image']; // rendered separately, not in body rows\nconst QUOTE_KEYS = ['affirmation', 'mantra', 'motto', 'quote'];\n\n/**\n * Response fields that are engineer-facing noise on a reading card, and the rules for hiding them.\n *\n * @remarks\n * This mirrors `SUPPRESS_*` in the WordPress plugin's `src/Support/GenericRenderer.php`. Both render the SAME API responses for the same visitor: `roxy-data` when JavaScript runs, the PHP renderer when it does not. If the two disagree the page visibly changes content on hydration, so they must be kept in sync.\n *\n * Without this, a real `/numerology/life-path` card printed \"Calculation: Month: 6, Day: 15 -> 1+5 = 6, Year: 1990 -> ...\", \"Type: Single\", and a list endpoint printed \"Total: 78, Limit: 3, Offset: 0\". That is how the number was derived and how the API paginates: it is not the reading the visitor asked for.\n */\nconst SUPPRESS_ALWAYS = new Set(['seed']);\n/** Suppressed only when the object carries a title: an untitled record still needs its identifier. */\nconst SUPPRESS_NAMED = new Set(['id', 'slug', 'key']);\nconst SUPPRESS_NOISE = new Set([\n\t'calculation',\n\t'calculations',\n\t'type', // schema discriminator (\"single\", \"general\"): indexes a polymorphic shape, means nothing on a card\n\t'position', // pinnacle/challenge index: already carried by the row order\n\t'count',\n\t'totalcount',\n\t'total',\n\t'limit',\n\t'offset',\n\t'page',\n\t'pagesize',\n\t'perpage',\n]);\n\n/** Sections with more keys than this, and tables with more rows than this, collapse into `<details>`. */\nconst DETAILS_KEYS = 8;\n/** Depth at which a section folds shut by default rather than rendering open. */\nconst DEEP_DEPTH = 1;\nconst DETAILS_ROWS = 12;\n\nconst normKey = (k: string): string => k.toLowerCase().replace(/[_-]/g, '');\n\n/**\n * `hasKarmicDebt` / `is_master`: a true reads better as a badge than as the row \"Has karmic debt: Yes\".\n *\n * @remarks\n * Presentation only. The PHP twin also DROPS the false case as \"silence, not data\", and this deliberately does not follow it there: a generic renderer must never lose a fact the response carries, and `isRetrograde: false` (a planet in direct motion) is a real reading, not an absence. Suppression is reserved for fields that are provably not part of the reading at all, which is what {@link SUPPRESS_NOISE} enumerates.\n *\n * Matching on the camel boundary rejects `island` / `issue` / `history`, which a bare `startsWith('is')` would swallow. The PHP twin tests `strpos($key, 'has_')` against a camelCase key, so its badge branch never actually fires; it hard-suppresses the three keys it knew about instead.\n */\nconst isBadgeKey = (k: string): boolean => /^(has|is)([A-Z_]|$)/.test(k);\n\nconst ISO_DATE =\n\t/^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}(:\\d{2}(\\.\\d+)?)?(Z|[+-]\\d{2}:\\d{2})?)?$/;\nconst ENUM_STRING = /^[A-Z0-9]+(_[A-Z0-9]+)+$/;\nconst LINK_STRING = /^https?:\\/\\//;\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\nfunction isPrimitive(value: Json | undefined): value is Scalar | null {\n\treturn (\n\t\tvalue === null || ['string', 'number', 'boolean'].includes(typeof value)\n\t);\n}\n\n/** Object or object-bearing array: needs full width, never fits a dl value cell. */\nfunction isComplex(value: Json): boolean {\n\treturn (\n\t\tvalue !== null &&\n\t\ttypeof value === 'object' &&\n\t\t!(Array.isArray(value) && value.every(isPrimitive))\n\t);\n}\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-card a{color:var(--roxy-accent-ink,#b45309)}.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{grid-template-columns:minmax(8ch, min(30%, max-content)) minmax(0, 1fr);gap:var(--roxy-space-xs,.25rem) var(--roxy-space-md,1rem);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}.roxy-table-wrap{min-width:0;overflow-x:auto}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;word-break:normal;overflow-wrap:normal}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;white-space:nowrap}table.roxy-table th.col-tight,table.roxy-table td.col-tight{white-space:nowrap;width:1%}table.roxy-table th.col-wide,table.roxy-table td.col-wide{width:auto}.roxy-image{border-radius:var(--roxy-radius-md,8px);max-width:100%;height:auto;margin-bottom:var(--roxy-space-md,1rem)}.roxy-section{margin-top: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}blockquote.roxy-quote{margin:var(--roxy-space-md,1rem) 0;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);color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);font-style:italic}.roxy-badge{border-radius:var(--roxy-radius-full,9999px);background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 18%, transparent);color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);padding:1px 8px;display:inline-block}details.roxy-section,details.roxy-table-details{margin-top:var(--roxy-space-md,1rem)}details.roxy-section>summary,details.roxy-table-details>summary{cursor:pointer;font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-secondary,#475569);text-transform:capitalize}details.roxy-section>summary:focus-visible,details.roxy-table-details>summary:focus-visible{outline:2px solid var(--roxy-ring,#f59e0b66);outline-offset:2px;border-radius:4px}`,\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\">Nested data omitted</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 (isPrimitive(value)) return html`<p>${this.scalarTemplate(value)}</p>`;\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\tif (arr.every(isPrimitive)) {\n\t\t\treturn this.renderChips(arr as (Scalar | null)[]);\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 renderChips(arr: (Scalar | null)[]): TemplateResult {\n\t\treturn html`<ul class=\"roxy-chips\">${arr\n\t\t\t\t.filter((v): v is Scalar => v !== null)\n\t\t\t\t.map((v) => html`<li>${this.formatScalar(v)}</li>`)}</ul>`;\n\t}\n\n\tprivate renderTable(rows: Record<string, Json>[]): TemplateResult {\n\t\tconst clean = rows.map((r) => this.suppress(r));\n\t\tconst keys = this.collectKeys(clean);\n\n\t\t/**\n\t\t * A column holding nested data needs the width; a column holding a short scalar does not.\n\t\t *\n\t\t * @remarks\n\t\t * Browsers lay an auto table out by content, so a `date` column of ten characters and a `positions` column holding a whole nested table settle at roughly half the width each, and the nested one is the one that ends up cramped. Marking each column by what it actually CONTAINS lets the scalar columns collapse to their content (`width: 1%` is the standard way to say \"as narrow as your content allows\") and the nested column absorb everything left over. No fixed percentage: the split follows the data.\n\t\t *\n\t\t * Only worth doing when the row is mixed. If every column is scalar, or every column is nested, there is nothing to bias toward and the browser's own distribution is already right.\n\t\t */\n\t\tconst complex = new Set(\n\t\t\tkeys.filter((k) => clean.some((r) => isComplex(r[k] ?? null))),\n\t\t);\n\t\tconst mixed = complex.size > 0 && complex.size < keys.length;\n\t\tconst colClass = (k: string) =>\n\t\t\tmixed ? (complex.has(k) ? 'col-wide' : 'col-tight') : '';\n\n\t\tconst table = html`<div class=\"roxy-table-wrap\" role=\"group\" aria-label=\"Data table\" tabindex=\"0\"><table class=\"roxy-table\" role=\"table\"><thead><tr>${keys.map(\n\t\t\t\t\t\t\t(k) => html`<th class=\"${colClass(k)}\">${humanize(k)}</th>`,\n\t\t\t\t\t\t)}</tr></thead><tbody>${clean.map(\n\t\t\t\t\t\t(row) => html`<tr>${keys.map(\n\t\t\t\t\t\t\t\t(k) =>\n\t\t\t\t\t\t\t\t\thtml`<td class=\"${colClass(k)}\">${this.renderCell(row[k], k)}</td>`,\n\t\t\t\t\t\t\t)}</tr>`,\n\t\t\t\t\t)}</tbody></table></div>`;\n\t\t// A 78-row angel-number list or a 27-row nakshatra table is a scroll trap\n\t\t// inline. Past the threshold it folds away behind its own row count.\n\t\tif (clean.length > DETAILS_ROWS) {\n\t\t\treturn html`<details class=\"roxy-table-details\"><summary>${clean.length} rows</summary>${table}</details>`;\n\t\t}\n\t\treturn table;\n\t}\n\n\t/** Drop the fields that are noise on a reading card. See {@link SUPPRESS_NOISE}. */\n\tprivate suppress(obj: Record<string, Json>): Record<string, Json> {\n\t\tconst titled = TITLE_KEYS.some((k) => typeof obj[k] === 'string');\n\t\treturn Object.fromEntries(\n\t\t\tObject.entries(obj).filter(([k]) => {\n\t\t\t\tconst n = normKey(k);\n\t\t\t\tif (SUPPRESS_ALWAYS.has(n)) return false;\n\t\t\t\tif (titled && SUPPRESS_NAMED.has(n)) return false;\n\t\t\t\treturn !SUPPRESS_NOISE.has(n);\n\t\t\t}),\n\t\t);\n\t}\n\n\tprivate renderObject(input: Record<string, Json>): TemplateResult {\n\t\tconst obj = this.suppress(input);\n\t\tconst titleKey = TITLE_KEYS.find(\n\t\t\t(k) =>\n\t\t\t\ttypeof obj[k] === 'string' &&\n\t\t\t\t(obj[k] as string).length <= MAX_TITLE_LEN,\n\t\t);\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 quoteKey = QUOTE_KEYS.find((k) => typeof obj[k] === 'string');\n\t\tconst entries = 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\tk !== quoteKey &&\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\t\t// Scalars and primitive arrays fit the two-column rows; objects and\n\t\t// object arrays promote to full-width sections so nested tables are\n\t\t// not squeezed into the value column.\n\t\tconst rows = entries.filter(([, v]) => !isComplex(v));\n\t\tconst sections = entries.filter(([, v]) => isComplex(v));\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} ${quoteKey ? html`<blockquote class=\"roxy-quote\">${obj[quoteKey]}</blockquote>` : 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, k)}</dd>`,\n\t\t\t\t\t\t)}</dl>`\n\t\t\t\t\t: nothing\n\t\t\t} ${sections.map(([k, v]) => this.renderSection(k, v))}`;\n\t}\n\n\t/**\n\t * A named block of nested data. Collapses into `<details>` once it carries more than {@link DETAILS_KEYS} keys, so one fat object (a 27-nakshatra map, a 12-house table) cannot bury the rest of the card under a wall of rows.\n\t */\n\tprivate renderSection(key: string, value: Json): TemplateResult {\n\t\tconst size =\n\t\t\tvalue !== null && typeof value === 'object'\n\t\t\t\t? Array.isArray(value)\n\t\t\t\t\t? value.length\n\t\t\t\t\t: Object.keys(value).length\n\t\t\t\t: 0;\n\t\tconst body = this.renderField(value, key);\n\t\tconst heading = humanize(key);\n\t\t// Past depth 1 a section folds shut by default. A real /numerology/chart response\n\t\t// rendered every level open and grew to a 29,933px-tall element, about thirty\n\t\t// screens of correct but unusable output. The reader opens what they want.\n\t\tif (size > DETAILS_KEYS || this.depth >= DEEP_DEPTH) {\n\t\t\treturn html`<details class=\"roxy-section\" ?open=\"${this.depth < DEEP_DEPTH}\"><summary>${heading}</summary>${body}</details>`;\n\t\t}\n\t\treturn html`<div class=\"roxy-section\"><h4>${heading}</h4>${body}</div>`;\n\t}\n\n\tprivate renderField(value: Json, key?: string): TemplateResult | string {\n\t\tif (value === null || value === undefined) return '';\n\t\tif (value === true && key !== undefined && isBadgeKey(key)) {\n\t\t\treturn html`<span class=\"roxy-badge\">Yes</span>`;\n\t\t}\n\t\tif (isPrimitive(value)) return html`${this.scalarTemplate(value)}`;\n\t\tif (Array.isArray(value) && value.every(isPrimitive)) {\n\t\t\treturn this.renderChips(value as (Scalar | null)[]);\n\t\t}\n\t\t// `bare`: a nested card inside a card compounds padding and border at every\n\t\t// level, and by depth 3 the innermost object was rendering into a fraction of the\n\t\t// width with prose wrapping to two words a line.\n\t\treturn html`<roxy-data bare .data=\"${value}\" .depth=\"${this.depth + 1}\"></roxy-data>`;\n\t}\n\n\tprivate renderCell(\n\t\tvalue: Json | undefined,\n\t\tkey?: string,\n\t): TemplateResult | string {\n\t\tif (value === null || value === undefined) return '';\n\t\tif (value === true && key !== undefined && isBadgeKey(key)) {\n\t\t\treturn html`<span class=\"roxy-badge\">Yes</span>`;\n\t\t}\n\t\tif (isPrimitive(value)) return this.scalarTemplate(value);\n\t\tif (Array.isArray(value) && value.every(isPrimitive)) {\n\t\t\treturn (value as (Scalar | null)[])\n\t\t\t\t.filter((v): v is Scalar => v !== null)\n\t\t\t\t.map((v) => this.formatScalar(v))\n\t\t\t\t.join(', ');\n\t\t}\n\t\t// Nested object or object array inside a row: recurse instead of\n\t\t// stringifying to [object Object]. `bare` drops the card surface so\n\t\t// the cell does not paint a card inside a cell.\n\t\treturn html`<roxy-data bare .data=\"${value}\" .depth=\"${this.depth + 1}\"></roxy-data>`;\n\t}\n\n\tprivate scalarTemplate(value: Scalar): TemplateResult | string {\n\t\tif (typeof value === 'string' && LINK_STRING.test(value)) {\n\t\t\treturn html`<a href=\"${value}\" target=\"_blank\" rel=\"noopener noreferrer\">${value}</a>`;\n\t\t}\n\t\treturn this.formatScalar(value);\n\t}\n\n\tprivate formatScalar(value: Scalar): string {\n\t\tif (typeof value === 'number') {\n\t\t\treturn formatNumber(value, 2) || String(value);\n\t\t}\n\t\tif (typeof value === 'boolean') return value ? 'Yes' : 'No';\n\t\tif (ISO_DATE.test(value)) {\n\t\t\tconst time = formatTime(value);\n\t\t\tconst date = formatDate(value);\n\t\t\treturn time ? `${date}, ${time}` : date;\n\t\t}\n\t\tif (ENUM_STRING.test(value)) return humanize(value.toLowerCase());\n\t\treturn 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 { 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\t/** True when the spec declares the field as `in: query`, so it belongs in the query string even on a POST (`?lang=` is the one every localized endpoint carries). */\n\tinQuery?: boolean;\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\t// A path param is substituted into the URL template by name, so only\n\t\t\t\t\t\t// a true query param needs the query-string routing flag.\n\t\t\t\t\t\tinQuery: param.in === 'query',\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: {\n\t\t\t\t\tendpoint: this.endpoint,\n\t\t\t\t\tvalues: out,\n\t\t\t\t\t// The spec knows which of these belong in the query string; the\n\t\t\t\t\t// listener does not. Report them so a POST with `?lang=` reaches the\n\t\t\t\t\t// API as a query parameter instead of an ignored body key.\n\t\t\t\t\tqueryKeys: this.fields.filter((f) => f.inQuery).map((f) => f.name),\n\t\t\t\t},\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 { interpAccordionStyles } from '../utils/interp-accordion.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\tinterpAccordionStyles,\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);grid-template-columns:minmax(0,1fr);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-lead .point{color:var(--roxy-accent-ink,#b45309);font-weight:var(--roxy-weight-bold,600)}.interp-aside small{font-variant-numeric:tabular-nums}.catalog summary{cursor:pointer;color:var(--roxy-fg,#0a0a0a);align-items:center;gap:.5rem;font-weight:600;display:flex}.scroll{min-width:0;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(\n\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\tc,\n\t\t\t\t\t\t\t\ti,\n\t\t\t\t\t\t\t) => html`<details class=\"interp-card\" name=\"fixed-star-contacts\" ?open=\"${i === 0}\"><summary><span class=\"interp-lead\"><span class=\"point\">${c.point}</span> conjunct ${c.star}</span> ${chevron()} <span class=\"interp-aside\"><small>orb ${formatNumber(c.orb, 2)}\u00B0</small></span></summary>${c.interpretation ? html`<div class=\"interp-body\"><p>${c.interpretation}</p></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\n/**\n * The eight kootas and the points each carries, in the classical order the API\n * returns them. Used only as a fallback when a payload omits `maxScore`; the\n * spec marks it required. The names are the canonical ones (Vashya, Graha\n * Maitri), not the shortened forms.\n */\nconst KOOTA_MAX: Record<string, number> = {\n\tvarna: 1,\n\tvashya: 2,\n\ttara: 3,\n\tyoni: 4,\n\t'graha maitri': 5,\n\tgana: 6,\n\tbhakoot: 7,\n\tnadi: 8,\n};\n\n/**\n * 36-point Ashtakoota score card. Renders /vedic-astrology/compatibility.\n *\n * @remarks\n * Each koota row carries what it actually evaluates and how each person\n * classifies under it (Varna: Shudra against Shudra, Yoni: Sheep against Horse),\n * because the point total alone tells a couple nothing about WHY a koota scored\n * as it did.\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)}.verdict-wrap{justify-items:end;gap:var(--roxy-space-xs,.25rem);text-align:right;display:grid}.verdict{border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);padding:1px 10px}.verdict.yes{background:color-mix(in srgb, var(--roxy-success,#16a34a) 16%, transparent);color:var(--roxy-success-fg,#166534)}.verdict.no{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 16%, transparent);color:var(--roxy-danger-fg,#991b1b)}.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 small{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);margin-top:2px;line-height:1.5;display:block}td.classification{color:var(--roxy-secondary,#475569);white-space:nowrap}th.score{text-align:right}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:22%}@container (width<=32rem){.bar-col{display:none}}.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><div class=\"verdict-wrap\">${\n\t\t\t\t\t\t\t\ttypeof d.isCompatible === 'boolean'\n\t\t\t\t\t\t\t\t\t? html`<span class=\"verdict ${d.isCompatible ? 'yes' : 'no'}\">${d.isCompatible ? 'Compatible' : 'Not compatible'}</span>`\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\td.recommendation\n\t\t\t\t\t\t\t\t\t? html`<span class=\"recommendation\">${d.recommendation}</span>`\n\t\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t\t}</div></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><caption class=\"roxy-sr-only\">Guna Milan breakdown: each koota with the classification of person 1 and person 2, and the score it earned out of its maximum.</caption><thead><tr><th scope=\"col\">Koota</th><th scope=\"col\">Person 1</th><th scope=\"col\">Person 2</th><th scope=\"col\" class=\"bar-col\">Progress</th><th scope=\"col\" 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} ${b.description ? html`<small>${b.description}</small>` : nothing}</td><td class=\"classification\">${b.person1 ?? ''}</td><td class=\"classification\">${b.person2 ?? ''}</td><td class=\"bar-cell bar-col\"><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\treturn (name && KOOTA_MAX[name.toLowerCase()]) || 1;\n}\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 { disclosureStyles } from '../utils/disclosure.js';\nimport { hdReadingStyles, renderHdFacts } from '../utils/hd-reading.js';\nimport {\n\ttype InterpSection,\n\tinterpAccordionStyles,\n\trenderInterpAccordion,\n} from '../utils/interp-accordion.js';\nimport { humanize } from '../utils/string.js';\n\ntype Connection = CalculateConnectionResponse;\ntype ConnectionChannel = Connection['channels'][number];\ntype CombinedCenter = Connection['centers'][number];\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 * @remarks\n * The chart answers one question: what exists between these two that does not exist in either of them alone. So the combined centers are the lead, not the channel list. `defined` is the state of the COMBINED bodygraph, `definedBy` names who already defines that center in their own chart, and the gap between the two is the reading: a center that comes back defined with an empty `definedBy` is defined by the connection itself, present when the two are together and absent when they are apart.\n *\n * The four dynamics are the taxonomy the summary counts, and a bare count of \"Dominance: 2\" means nothing to a reader who does not already know the system, so each one carries its definition behind the shared disclosure rather than shipping as a bare label.\n */\n@customElement('roxy-hd-connection')\nexport class RoxyHdConnection extends RoxyDataElement<Connection> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tdisclosureStyles,\n\t\tinterpAccordionStyles,\n\t\thdReadingStyles,\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);grid-template-columns:minmax(0,1fr);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}.note{margin:0 0 var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);line-height:1.6}.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}.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.together{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 18%, transparent);color:var(--roxy-fg,#0a0a0a)}.who{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem)}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}.held{font-variant-numeric:tabular-nums}.scroll{min-width:0;overflow-x:auto}`,\n\t];\n\n\tprotected renderData(d: Connection) {\n\t\tconst channels = d.channels ?? [];\n\t\tconst centers = d.centers ?? [];\n\t\tconst definedCenters = centers.filter((c) => c.defined).length;\n\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>${renderHdFacts([\n\t\t\t\t{ label: 'Channels', value: d.totalChannels?.toString() },\n\t\t\t\t{\n\t\t\t\t\tlabel: 'Combined definition',\n\t\t\t\t\tvalue: d.combinedDefinition\n\t\t\t\t\t\t? humanize(String(d.combinedDefinition))\n\t\t\t\t\t\t: undefined,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: 'Centers defined',\n\t\t\t\t\tvalue:\n\t\t\t\t\t\tcenters.length > 0\n\t\t\t\t\t\t\t? `${definedCenters} of ${centers.length}`\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t},\n\t\t\t])}<p class=\"lead\">A connection chart reads the two charts as one bodygraph. Wherever the two of them together hold both gates of a channel, that channel is defined between them, and the centers it joins are defined in the connection whether or not either person defines them alone.</p>${this.renderDynamics(d.summary)} ${this.renderCenters(centers)} ${this.renderChannels(channels, centers)}</div>`;\n\t}\n\n\t/**\n\t * The four ways two charts can meet in a channel, in canonical order, each with what it means. The count is the aside, so the taxonomy and the tally read as one thing: a dynamic with no channels still shows, because its absence is as much a fact of the connection as its presence.\n\t */\n\tprivate renderDynamics(s: Connection['summary'] | undefined) {\n\t\tif (!s) return nothing;\n\t\tconst sections: InterpSection[] = [\n\t\t\t{\n\t\t\t\tlabel: 'Electromagnetic',\n\t\t\t\taside: channelCount(s.electromagnetic),\n\t\t\t\tbody: 'Each person holds one of the two gates, so the channel completes only when they are together. The classic point of attraction.',\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: 'Dominance',\n\t\t\t\taside: channelCount(s.dominance),\n\t\t\t\tbody: 'One person holds both gates and the other holds neither, so the conditioning runs one way, from the person who carries the channel to the person who does not.',\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: 'Compromise',\n\t\t\t\taside: channelCount(s.compromise),\n\t\t\t\tbody: 'One person holds both gates and the other holds a single hanging gate of the same channel, so the channel is complete for one of them and half open for the other.',\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: 'Companionship',\n\t\t\t\taside: channelCount(s.companionship),\n\t\t\t\tbody: 'Both people independently hold both gates, so neither needs the other to complete it. A shared and familiar frequency rather than an attraction.',\n\t\t\t},\n\t\t];\n\t\treturn renderInterpAccordion(sections, 'hd-connection-dynamic', 'Dynamics');\n\t}\n\n\t/**\n\t * The nine centers of the combined chart. `defined` is the combined state and `definedBy` is who carries it alone, so the two together say whether a center is brought to the connection or created by it.\n\t */\n\tprivate renderCenters(centers: CombinedCenter[]) {\n\t\tif (centers.length === 0) return nothing;\n\t\treturn html`<section class=\"block\"><h3>Centers</h3><p class=\"note\">Defined is the state of the combined chart. Beside it is who already defines that center in their own chart. A center defined only together is what the connection itself creates: it is there when the two are together and gone when they are apart. The combined definition counts how the defined centers hang together, so Single is one connected piece and a split is more than one.</p>${centers.map((c) => {\n\t\t\t\tconst by = c.definedBy ?? [];\n\t\t\t\tconst a = by.includes('A');\n\t\t\t\tconst b = by.includes('B');\n\t\t\t\t// Only the connection defines it: defined in the combined chart, and in\n\t\t\t\t// neither chart on its own.\n\t\t\t\tconst together = Boolean(c.defined) && !a && !b;\n\t\t\t\treturn html`<div class=\"row\"><span class=\"cname\">${c.name ?? humanize(String(c.id ?? ''))}</span> <span class=\"badge ${c.defined ? (together ? 'together' : 'defined') : 'open'}\">${c.defined ? (together ? 'Only together' : 'Defined') : 'Open'} </span><span class=\"who\">${centerWho(Boolean(c.defined), a, b)}</span></div>`;\n\t\t\t})}</section>`;\n\t}\n\n\t/**\n\t * Every connected channel. The centers a channel joins are named, not left as ids, because the row is what explains a defined center in the block above: this is the wiring that produced it.\n\t */\n\tprivate renderChannels(\n\t\tchannels: ConnectionChannel[],\n\t\tcenters: CombinedCenter[],\n\t) {\n\t\tif (channels.length === 0) return nothing;\n\t\tconst names = new Map(\n\t\t\tcenters.map((c) => [String(c.id ?? ''), c.name ?? ''] as const),\n\t\t);\n\t\tconst centerName = (id: string) => names.get(id) || humanize(id);\n\n\t\treturn html`<section class=\"block\"><h3>Channels</h3><div class=\"scroll\" tabindex=\"0\" role=\"region\" aria-label=\"Connection channels\"><table role=\"table\"><caption class=\"roxy-sr-only\">Connection channels: each channel with its gates, the centers it links, its circuit and dynamic, and the gates person A and person B each hold.</caption><thead><tr><th scope=\"col\">Channel</th><th scope=\"col\">Gates</th><th scope=\"col\">Centers</th><th scope=\"col\">Circuit</th><th scope=\"col\">Dynamic</th><th scope=\"col\">Person A holds</th><th scope=\"col\">Person B holds</th></tr></thead><tbody>${channels.map(\n\t\t\t\t\t\t\t(c) => html`<tr><td>${c.name ?? ''}</td><td class=\"gates\">${c.gateA}-${c.gateB}</td><td>${(c.centers ?? []).map(centerName).join(' to ')}</td><td>${c.circuit ?? ''}</td><td>${c.dynamic ? html`<span class=\"dyn\">${c.dynamic}</span>` : nothing}</td><td class=\"held\">${gateList(c.personAGates)}</td><td class=\"held\">${gateList(c.personBGates)}</td></tr>`,\n\t\t\t\t\t\t)}</tbody></table></div></section>`;\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No connection data</div>`;\n\t}\n}\n\n/** The aside of a dynamic. A zero is stated rather than hidden: no companionship channels is a finding about the pair. */\nfunction channelCount(n: number | undefined): string | undefined {\n\tif (typeof n !== 'number') return undefined;\n\tif (n === 0) return 'None';\n\treturn n === 1 ? '1 channel' : `${n} channels`;\n}\n\n/** Which gates of the channel this person carries. Neither is possible: a dominance channel is held entirely by the other person. */\nfunction gateList(gates: number[] | undefined): string {\n\tconst list = gates ?? [];\n\treturn list.length > 0 ? list.join(', ') : 'Neither';\n}\n\n/** Who defines the center in their own chart, spelled out. `definedBy` is empty both when the center is open in both charts and when only the connection defines it, so the combined state has to disambiguate. */\nfunction centerWho(defined: boolean, a: boolean, b: boolean): string {\n\tif (a && b) return 'Defined in both charts';\n\tif (a) return 'Defined by A';\n\tif (b) return 'Defined by B';\n\treturn defined\n\t\t? 'Defined by neither alone, only by the connection'\n\t\t: 'Open in both charts';\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';\nimport { hdReadingStyles, renderHdFacts } from '../utils/hd-reading.js';\n\ntype Penta = CalculatePentaResponse;\ntype PentaChannel = Penta['channels'][number];\ntype PentaGate = Penta['gates'][number];\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 * @remarks\n * The penta is the only Human Design chart whose subject is a group rather than a person, so every row answers \"who supplies this\" as well as \"is it there\". The response reports that as zero-based indices into the member list that was sent, which is the one thing a card must not print raw: members are lettered instead, A for the first member sent, and the footnote says so.\n *\n * Read in two passes. The channels are the functions the group performs, and a channel is a defined Strength only when both of its gates are held somewhere in the group, so the attribution line under each one shows which member carries which end. The twelve gates below are the same data seen per role, and they are where a gap shows up as itself: a gate held by nobody, which the summary also counts.\n */\n@customElement('roxy-hd-penta')\nexport class RoxyHdPenta extends RoxyDataElement<Penta> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\thdReadingStyles,\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)}.section{border-top:1px solid var(--roxy-border,#e4e4e7);padding-top:var(--roxy-space-md,1rem)}.section h3{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;margin:0}.note{margin:var(--roxy-space-xs,.25rem) 0 0;font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);line-height:1.6}.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,.gate-id{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}.circuit{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);display:block}.held{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);flex-basis:100%;line-height:1.6}.who{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem)}.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)}.badge.gap{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 16%, transparent);color:var(--roxy-danger-fg,#991b1b)}.footnote{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);margin:0;line-height:1.6}`,\n\t];\n\n\tprotected renderData(d: Penta) {\n\t\tconst channels = d.channels ?? [];\n\t\tconst gates = d.gates ?? [];\n\t\tconst s = d.summary;\n\t\tconst gaps = s?.gapGates ?? [];\n\t\tconst hasCore = channels.some((c) => c.isCore);\n\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>${renderHdFacts([\n\t\t\t\t{ label: 'Members', value: d.memberCount?.toString() },\n\t\t\t\t{\n\t\t\t\t\tlabel: 'Defined channels',\n\t\t\t\t\tvalue:\n\t\t\t\t\t\ttypeof s?.definedChannels === 'number' && channels.length > 0\n\t\t\t\t\t\t\t? `${s.definedChannels} of ${channels.length}`\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: 'Filled gates',\n\t\t\t\t\tvalue:\n\t\t\t\t\t\ttypeof s?.filledGates === 'number' && gates.length > 0\n\t\t\t\t\t\t\t? `${s.filledGates} of ${gates.length}`\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: 'Core',\n\t\t\t\t\tvalue:\n\t\t\t\t\t\ttypeof s?.coreDefined === 'boolean'\n\t\t\t\t\t\t\t? s.coreDefined\n\t\t\t\t\t\t\t\t? 'Defined'\n\t\t\t\t\t\t\t\t: 'Open'\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: 'Gap gates',\n\t\t\t\t\tvalue: gaps.length > 0 ? gaps.join(', ') : undefined,\n\t\t\t\t},\n\t\t\t])}<p class=\"lead\">A penta is the field three to five people form when they work as a group. It is read from the twelve penta gates the members bring between them: a channel with both of its gates held somewhere in the group is a defined Strength, and a gate no member holds is a gap the group has to compensate for.</p>${this.renderGroup(\n\t\t\t\t'Upper (direction)',\n\t\t\t\tchannels.filter((c) => c.position === 'upper'),\n\t\t\t\t'Upper channels run from the G Center to the Throat. They carry the leadership of the group and how it presents itself.',\n\t\t\t)} ${this.renderGroup(\n\t\t\t\t'Lower (execution)',\n\t\t\t\tchannels.filter((c) => c.position === 'lower'),\n\t\t\t\t'Lower channels run from the G Center to the Sacral. They carry the managed, generative, resource work.',\n\t\t\t)} ${\n\t\t\t\t// A position the API adds later must not silently drop the channel from\n\t\t\t\t// the card: anything that is neither triangle still renders.\n\t\t\t\tthis.renderGroup(\n\t\t\t\t\t'Channels',\n\t\t\t\t\tchannels.filter(\n\t\t\t\t\t\t(c) => c.position !== 'upper' && c.position !== 'lower',\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t} ${\n\t\t\t\thasCore\n\t\t\t\t\t? html`<p class=\"footnote\">Core is the 2/14 Channel of the Beat, the material core of the penta: gate 2 sets the direction for resources, gate 14 is the resources themselves.</p>`\n\t\t\t\t\t: nothing\n\t\t\t} ${this.renderGates(gates)} ${\n\t\t\t\tchannels.length > 0 || gates.length > 0\n\t\t\t\t\t? html`<p class=\"footnote\">Members are lettered in the order they were sent, so A is the first member of the group.</p>`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n\n\t/**\n\t * One triangle of the penta. The note is what the triangle does, so it sits with the heading rather than being repeated on each of its three channels.\n\t */\n\tprivate renderGroup(label: string, channels: PentaChannel[], note?: string) {\n\t\tif (channels.length === 0) return nothing;\n\t\treturn html`<div class=\"section\"><h3>${label}</h3>${note ? html`<p class=\"note\">${note}</p>` : nothing} ${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 ?? ''} ${c.circuit ? html`<span class=\"circuit\">${c.circuit} circuit</span>` : nothing} </span><span class=\"badge ${c.defined ? 'defined' : 'open'}\">${c.defined ? 'Defined' : 'Open'}</span> ${c.isCore ? html`<span class=\"badge core\">Core</span>` : nothing} <span class=\"held\">Gate ${c.gateA} held by ${members(c.gateAHeldBy)}. Gate ${c.gateB} held by ${members(c.gateBHeldBy)}.</span></div>`,\n\t\t\t)}</div>`;\n\t}\n\n\t/**\n\t * The twelve penta gates, each with the role it brings and the members who carry it. A gate nobody holds is the gap the summary counts, so it is flagged rather than left as an empty attribution.\n\t */\n\tprivate renderGates(gates: PentaGate[]) {\n\t\tif (gates.length === 0) return nothing;\n\t\tconst filled = gates.filter((g) => g.filled).length;\n\t\treturn html`<div class=\"section\"><h3>Gates (${filled} of ${gates.length} filled)</h3><p class=\"note\">The role each gate brings to the group, and who carries it. A gap is a role no member holds, so the group compensates for it.</p>${gates.map(\n\t\t\t\t(g) => html`<div class=\"row\"><span class=\"gate-id\">${g.gate}</span> <span class=\"cname\">${g.gateName ?? ''}</span> ${\n\t\t\t\t\t\tg.filled\n\t\t\t\t\t\t\t? html`<span class=\"who\">Held by ${members(g.heldBy)}</span>`\n\t\t\t\t\t\t\t: html`<span class=\"badge gap\">Gap</span>`\n\t\t\t\t\t}</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\n/**\n * Members are lettered, not numbered. The response reports them as zero-based indices into the member list that was sent, and printing a raw \"0\" on a card reads as a bug; \"Member 1\" for index 0 would contradict the API the developer is reading beside it. A letter is unambiguous either way, and it matches how `roxy-hd-connection` names person A and person B. Five is the ceiling: the endpoint takes 3 to 5 members.\n */\nconst MEMBER_LETTERS = 'ABCDE';\n\nfunction members(indices: number[] | undefined): string {\n\tconst held = (indices ?? []).map((i) => MEMBER_LETTERS[i] ?? String(i + 1));\n\treturn held.length > 0 ? held.join(', ') : 'nobody';\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 {\n\tCalculateProfileResponse,\n\tCalculateTypeResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { disclosureStyles } from '../utils/disclosure.js';\nimport {\n\thdReadingStyles,\n\trenderHdFacts,\n\trenderHdKeynotes,\n\trenderHdReading,\n\trenderHdThemes,\n} from '../utils/hd-reading.js';\nimport { interpAccordionStyles } from '../utils/interp-accordion.js';\n\ntype HdIdentity = CalculateTypeResponse | CalculateProfileResponse;\n\n/**\n * The Human Design identity read on its own, without the chart. Pass `data` from `/human-design/type` or `/human-design/profile`.\n *\n * @remarks\n * Both endpoints answer \"who is this person\" rather than \"how is the chart wired\", so one card serves both and detects which it was given: the type response leads with the type and carries the strategy, authority, and aura readings; the profile response carries the two lines and their keynotes. This is the same shape-detecting pattern `roxy-positions-table` uses across the five Western point-list endpoints.\n *\n * The interpretation surface (fact tiles, lead paragraph, signature and not-self pills, the exclusive reading accordion, the line keynotes) is shared with `roxy-bodygraph` through `utils/hd-reading.ts`, because `/human-design/type` returns a strict subset of the bodygraph interpretation fields. Reach for `roxy-bodygraph` when the chart itself is wanted; reach for this when only the reading is.\n */\n@customElement('roxy-hd-type-card')\nexport class RoxyHdTypeCard extends RoxyDataElement<HdIdentity> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tdisclosureStyles,\n\t\tinterpAccordionStyles,\n\t\thdReadingStyles,\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}.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)}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No Human Design data</div>`;\n\t}\n\n\tprotected renderData(d: HdIdentity) {\n\t\treturn isTypeShape(d) ? this.renderType(d) : this.renderProfile(d);\n\t}\n\n\t/**\n\t * The type read. The tiles answer it at a glance, the lead paragraph grounds the type label in what the aura actually does, and the accordion carries the three interpretations that make the chart actionable: how to engage (strategy), how to decide (authority), and how the field is felt by others (aura).\n\t */\n\tprivate renderType(d: CalculateTypeResponse) {\n\t\treturn html`<div class=\"wrap\"><header class=\"head\"><h2 class=\"title\">Type</h2>${\n\t\t\t\t\td.type || d.profile\n\t\t\t\t\t\t? html`<div class=\"type-line\">${[d.type, d.profile ? `Profile ${d.profile}` : ''].filter(Boolean).join(' \u00B7 ')}</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</header>${renderHdFacts([\n\t\t\t\t{ label: 'Type', value: d.type },\n\t\t\t\t{ label: 'Strategy', value: d.strategy },\n\t\t\t\t{ label: 'Authority', value: d.authority },\n\t\t\t\t{ label: 'Profile', value: d.profile },\n\t\t\t])} ${d.typeDescription ? html`<p class=\"lead\">${d.typeDescription}</p>` : nothing} ${renderHdThemes(d.signature, d.notSelf)} ${renderHdReading(\n\t\t\t\t[\n\t\t\t\t\t{ label: 'Strategy', aside: d.strategy, body: d.strategyDescription },\n\t\t\t\t\t{\n\t\t\t\t\t\tlabel: 'Authority',\n\t\t\t\t\t\taside: d.authority,\n\t\t\t\t\t\tbody: d.authorityDescription,\n\t\t\t\t\t},\n\t\t\t\t\t{ label: 'Aura', body: d.aura },\n\t\t\t\t],\n\t\t\t\t'hd-type-reading',\n\t\t\t)}</div>`;\n\t}\n\n\t/**\n\t * The profile read. Two keynote sentences, so they render open as a definition list rather than behind a disclosure: putting a single sentence behind a click costs the reader more than it saves.\n\t */\n\tprivate renderProfile(d: CalculateProfileResponse) {\n\t\treturn html`<div class=\"wrap\"><header class=\"head\"><h2 class=\"title\">Profile</h2>${d.profile ? html`<div class=\"type-line\">${d.profile}</div>` : nothing}</header>${renderHdFacts([\n\t\t\t\t{ label: 'Profile', value: d.profile },\n\t\t\t\t{ label: 'Personality line', value: d.personalityLine?.toString() },\n\t\t\t\t{ label: 'Design line', value: d.designLine?.toString() },\n\t\t\t])}<section class=\"block\"><h3>Lines</h3>${renderHdKeynotes({\n\t\t\t\t\tpersonality: d.personalityKeynote,\n\t\t\t\t\tpersonalityLine: d.personalityLine,\n\t\t\t\t\tdesign: d.designKeynote,\n\t\t\t\t\tdesignLine: d.designLine,\n\t\t\t\t})}</section></div>`;\n\t}\n}\n\n/** The two responses share only `profile`, so the type field is what tells them apart. */\nfunction isTypeShape(d: HdIdentity): d is CalculateTypeResponse {\n\treturn typeof (d as CalculateTypeResponse).type === 'string';\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-hd-type-card': RoxyHdTypeCard;\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';\nimport { chevron, disclosureStyles } from '../utils/disclosure.js';\nimport { interpAccordionStyles } from '../utils/interp-accordion.js';\nimport { capitalize } from '../utils/string.js';\n\ntype Variables = CalculateVariablesResponse;\ntype Arrow = Variables['arrows'][number];\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.\n *\n * @remarks\n * The quadrant grid stays the primary read: it is the arrow map as it appears on the chart, and it is what a reader scans first. The interpretation sits below it in an exclusive accordion, grouped by the two layers the arrows belong to (the body-side Primary Health System, the mind-side Rave Psychology), because the layer description is one text shared by the two arrows in it and belongs to the group rather than to each arrow. Only one arrow reading is ever open, so the card grows by one paragraph at most.\n *\n * `cognition` rides only on the determination arrow and is rendered when present. A low-confidence calculation (a birth time near a color or tone boundary) is flagged per arrow and for the chart as a whole.\n */\n@customElement('roxy-hd-variables')\nexport class RoxyHdVariables extends RoxyDataElement<Variables> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tdisclosureStyles,\n\t\tinterpAccordionStyles,\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,minmax(0,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);align-content:start;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:minmax(0,1fr)}}.group{margin-bottom:var(--roxy-space-md,1rem)}.group:last-of-type{margin-bottom:0}.group-head{font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-fg,#0a0a0a);margin:0}.group-note{margin:0 0 var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);line-height:1.6}.facets{gap:var(--roxy-space-xs,.25rem);margin:0;display:grid}.facets dt{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.05em}.facets dd{margin:0}.footnote{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);margin:0;line-height:1.6}`,\n\t];\n\n\tprotected renderData(d: Variables) {\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} ${this.renderReading(arrows, d.baseDescription)}</div>`;\n\t}\n\n\tprivate renderArrow(a: Arrow) {\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.baseName ? `, ${a.baseName}` : ''}</span>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\ta.activation?.planet\n\t\t\t\t\t? html`<span class=\"ctb\">${[a.activation.planet, capitalize(a.activation.side ?? '')].filter(Boolean).join(' \u00B7 ')}</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\t/**\n\t * The four readings, grouped by the layer each arrow belongs to. The layer\n\t * description is one text shared by both arrows of a layer, so it is lifted to\n\t * the group intro rather than repeated in each body. Group order follows the\n\t * already quadrant-sorted arrows, which puts the body layer before the mind\n\t * layer without naming either.\n\t */\n\tprivate renderReading(arrows: Arrow[], baseDescription: string | undefined) {\n\t\tconst readable = arrows.filter((a) => a.description || a.colorMeaning);\n\t\tif (readable.length === 0) return nothing;\n\n\t\tconst groups = new Map<string, Arrow[]>();\n\t\tfor (const a of readable) {\n\t\t\tconst key = a.layer ?? '';\n\t\t\tconst bucket = groups.get(key);\n\t\t\tif (bucket) bucket.push(a);\n\t\t\telse groups.set(key, [a]);\n\t\t}\n\t\tlet index = 0;\n\n\t\treturn html`<section class=\"block\"><h3>Reading</h3>${[...groups].map(\n\t\t\t\t([layer, list]) => html`<div class=\"group\">${layer ? html`<p class=\"group-head\">${layer}</p>` : nothing} ${\n\t\t\t\t\t\tlist[0]?.layerDescription\n\t\t\t\t\t\t\t? html`<p class=\"group-note\">${list[0].layerDescription}</p>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t} ${list.map((a) => this.renderArrowReading(a, index++ === 0))}</div>`,\n\t\t\t)} ${baseDescription ? html`<p class=\"footnote\">Base. ${baseDescription}</p>` : nothing}</section>`;\n\t}\n\n\tprivate renderArrowReading(a: Arrow, open: boolean) {\n\t\t// Cognition rides only on the determination arrow, so its row appears on that\n\t\t// arrow alone. Its label joins the term because, unlike color and direction,\n\t\t// the tile above carries no cognition label to read it against.\n\t\tconst cog = a.cognition;\n\t\tconst facets: Array<{ label: string; body: string | undefined }> = [\n\t\t\t{ label: 'Color', body: a.colorMeaning },\n\t\t\t{ label: 'Tone', body: a.toneMeaning },\n\t\t\t{ label: 'Direction', body: a.directionMeaning },\n\t\t\t{\n\t\t\t\tlabel: cog?.label ? `Cognition \u00B7 ${cog.label}` : 'Cognition',\n\t\t\t\tbody: cog?.description,\n\t\t\t},\n\t\t].filter((f) => Boolean(f.body));\n\n\t\treturn html`<details class=\"interp-card\" name=\"hd-variable\" ?open=\"${open}\"><summary><span class=\"interp-lead\">${a.name ?? ''}</span> ${chevron()} ${a.position ? html`<span class=\"interp-aside\"><small>${a.position}</small></span>` : nothing}</summary><div class=\"interp-body\">${a.description ? html`<p>${a.description}</p>` : nothing} ${\n\t\t\t\t\tfacets.length > 0\n\t\t\t\t\t\t? html`<dl class=\"facets\">${facets.map(\n\t\t\t\t\t\t\t\t(f) => html`<dt>${f.label}</dt><dd>${f.body}</dd>`,\n\t\t\t\t\t\t\t)}</dl>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</div></details>`;\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';\nimport { disclosureStyles } from '../utils/disclosure.js';\nimport {\n\ttype InterpSection,\n\tinterpAccordionStyles,\n\trenderInterpAccordion,\n} from '../utils/interp-accordion.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\tdisclosureStyles,\n\t\tinterpAccordionStyles,\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);align-content:start;align-self:start;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)}.line-meaning{padding-left:var(--roxy-space-sm,.5rem);border-left:2px solid var(--roxy-border,#e4e4e7);color:var(--roxy-muted,#71717a);margin:0}.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\">${\n\t\t\t\t\t\t// One text node, not two. The markup minifier collapses the space\n\t\t\t\t\t\t// between adjacent template expressions, which rendered the title as\n\t\t\t\t\t\t// \"30.The Clinging\" with the separator eaten. Join in JS instead.\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\th.number != null ? `${h.number}.` : '',\n\t\t\t\t\t\t\th.english ?? h.chinese ?? 'Hexagram',\n\t\t\t\t\t\t]\n\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t.join(' ')\n\t\t\t\t\t}</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} ${this.renderLines(h, changing)}</div></article>`;\n\t}\n\n\t/**\n\t * The line readings. Each line carries its oracle statement and, since the 2026-07 API rewrite, a written meaning; the component used to print only the changing-line NUMBERS and drop both, which left a reader with \"Changing lines: 3\" and no way to know what line 3 was telling them.\n\t *\n\t * @remarks\n\t * When lines are moving, only those lines are shown: a cast turns on the moving lines, and listing the other five buries the answer. With no lines moving (a lookup, a random draw, the daily hexagram) all six are shown, because there the hexagram is being read as a reference rather than as an answer to a question.\n\t */\n\tprivate renderLines(h: Hexagram, changing: Set<number>) {\n\t\tconst all = h.changingLines ?? [];\n\t\tif (all.length === 0) return nothing;\n\n\t\tconst isCast = changing.size > 0;\n\t\tconst shown = isCast ? all.filter((l) => changing.has(l.position)) : all;\n\t\tif (shown.length === 0) return nothing;\n\n\t\tconst sections: InterpSection[] = shown.map((l) => ({\n\t\t\tlabel: `Line ${l.position}`,\n\t\t\tbody: l.text ?? '',\n\t\t\textra: l.meaning\n\t\t\t\t? html`<p class=\"line-meaning\">${l.meaning}</p>`\n\t\t\t\t: nothing,\n\t\t}));\n\n\t\treturn renderInterpAccordion(\n\t\t\tsections,\n\t\t\t'hexagram-lines',\n\t\t\tisCast ? 'Changing lines' : 'Lines',\n\t\t);\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. 6 digits BOTTOM to top, so index 0 is line 1, the bottom line, exactly like the cast `lines` array. 1 = yang (solid, 7), 0 = yin (broken, 8). 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\t * @remarks\n\t * This used to `.reverse()`, because the API served `binary` top-to-bottom while documenting it bottom-to-top, and reversing was the only way to render the figure the right way up. The API fixed the data in 2026-07 (the same inversion was making `/cast` return the vertically MIRRORED hexagram for 56 of the 64 figures), so `binary` and `lines` now point the same way and the reverse would flip every asymmetric hexagram upside down. Do not put it back.\n\t */\n\tprivate derivedLines(h: Hexagram): number[] {\n\t\tconst binary = h.binary ?? '';\n\t\tif (/^[01]{6}$/.test(binary)) {\n\t\t\treturn Array.from(binary, (c) => (c === '1' ? 7 : 8));\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 { formatTimeRange } from '../utils/format.js';\nimport { capitalize } from '../utils/string.js';\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);grid-template-columns:minmax(0,1fr);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,minmax(0,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\">${formatTimeRange(h)}</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 { formatDate } from '../utils/format.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}.sky{gap:var(--roxy-space-sm,.5rem);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);display:grid}.moon-line{align-items:baseline;gap:.35rem var(--roxy-space-md,1rem);font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);flex-wrap:wrap;display:flex}.moon-line b{font-weight:var(--roxy-weight-bold,600)}.moon-line .lbl{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);text-transform:uppercase;letter-spacing:.06em;font-weight:var(--roxy-weight-bold,600);margin-right:.35rem}.transits{gap:.25rem;margin:0;padding:0;list-style:none;display:grid}.transits li{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);padding-left:.9rem;position:relative}.transits li:before{content:\"\";background:var(--roxy-accent,#f59e0b);border-radius:50%;width:5px;height:5px;position:absolute;top:.5em;left:0}.block-title{margin:0 0 var(--roxy-space-sm,.5rem);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}.weeks{gap:var(--roxy-space-sm,.5rem);display:grid}.week{gap:var(--roxy-space-sm,.5rem);border-top:1px solid var(--roxy-border,#e4e4e7);padding-top:var(--roxy-space-sm,.5rem);grid-template-columns:3.5rem 1fr;align-items:baseline;display:grid}.week:first-child{border-top:0;padding-top:0}.week-no{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)}.week-focus{font-weight:var(--roxy-weight-bold,600);color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem)}.week-advice{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);margin:.15rem 0 0}.dates{gap:.3rem var(--roxy-space-md,1rem);font-size:var(--roxy-text-sm,.875rem);grid-template-columns:max-content 1fr;margin:0;display:grid}.date-row{display:contents}.date-row dt{font-variant-numeric:tabular-nums;color:var(--roxy-accent-ink,#b45309);font-weight:var(--roxy-weight-bold,600);white-space:nowrap}.date-row dd{color:var(--roxy-fg,#0a0a0a);margin:0}`,\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} ${this.renderSky(d)}<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>${this.renderMonth(d)} ${(() => {\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\t/**\n\t * The sky behind the reading (daily only): where the Moon is, what phase it is in, and the transits the forecast was derived from. A daily horoscope that hides its transits is a fortune cookie; showing them is what makes this one auditable.\n\t */\n\tprivate renderSky(d: HoroscopeData) {\n\t\tconst moonSign = 'moonSign' in d ? d.moonSign : '';\n\t\tconst moonPhase = 'moonPhase' in d ? d.moonPhase : '';\n\t\tconst transits = ('activeTransits' in d ? d.activeTransits : []) ?? [];\n\t\tif (!moonSign && !moonPhase && transits.length === 0) return nothing;\n\t\tconst glyph = moonSign ? (SIGN_GLYPH[capitalize(moonSign)] ?? '') : '';\n\t\treturn html`<div class=\"sky\">${\n\t\t\t\tmoonSign || moonPhase\n\t\t\t\t\t? html`<div class=\"moon-line\">${\n\t\t\t\t\t\t\tmoonSign\n\t\t\t\t\t\t\t\t? html`<span><span class=\"lbl\">Moon</span> <span aria-hidden=\"true\">${glyph}</span> <b>${moonSign}</b></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\tmoonPhase\n\t\t\t\t\t\t\t\t? html`<span><span class=\"lbl\">Phase</span> <b>${moonPhase}</b></span>`\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\ttransits.length\n\t\t\t\t\t? html`<ul class=\"transits\" aria-label=\"Active transits\">${transits.map((t) => html`<li>${t}</li>`)}</ul>`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n\n\t/** Monthly arc: the week-by-week focus and the dated events (lunations, retrogrades, ingresses) the month turns on. */\n\tprivate renderMonth(d: HoroscopeData) {\n\t\tconst weeks = ('weekByWeek' in d ? d.weekByWeek : []) ?? [];\n\t\tconst keyDates = ('keyDates' in d ? d.keyDates : []) ?? [];\n\t\tif (weeks.length === 0 && keyDates.length === 0) return nothing;\n\t\treturn html`${\n\t\t\tweeks.length\n\t\t\t\t? html`<section><h3 class=\"block-title\">Week by week</h3><div class=\"weeks\">${weeks.map(\n\t\t\t\t\t\t\t(w) => html`<div class=\"week\"><span class=\"week-no\">Week ${w.week}</span><div><div class=\"week-focus\">${w.focus}</div>${w.advice ? html`<p class=\"week-advice\">${w.advice}</p>` : nothing}</div></div>`,\n\t\t\t\t\t\t)}</div></section>`\n\t\t\t\t: nothing\n\t\t} ${\n\t\t\tkeyDates.length\n\t\t\t\t? html`<section><h3 class=\"block-title\">Key dates</h3><dl class=\"dates\">${keyDates.map(\n\t\t\t\t\t\t\t(k) => html`<div class=\"date-row\"><dt>${formatDate(k.date) || k.date}</dt><dd>${k.event}</dd></div>`,\n\t\t\t\t\t\t)}</dl></section>`\n\t\t\t\t: nothing\n\t\t}`;\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 { formatSignPosition } from '../utils/degree.js';\nimport { formatNumber } from '../utils/format.js';\nimport {\n\trenderTablist,\n\ttype TablistItem,\n\ttablistStyles,\n} from '../utils/tablist.js';\n\ntype Tab = 'planets' | 'cusps' | 'significators';\n\nconst TABS: ReadonlyArray<TablistItem<Tab>> = [\n\t{ id: 'planets', label: 'Planets' },\n\t{ id: 'cusps', label: 'Cusps' },\n\t{ id: 'significators', label: 'Significators' },\n];\n\n/** The four KP significator strength levels, strongest (1) to weakest (4). */\nconst LEVELS = [1, 2, 3, 4] as const;\n\ntype Significators = KpChartResponse['significators'];\ntype HouseSignificator = Significators['houseWise'][number];\ntype PlanetSignificator = Significators['planetWise'][number];\n\n/** A planet or node row, normalized so planets and Rahu/Ketu share a table. */\ninterface KpBody {\n\tname: string;\n\tlongitude?: number;\n\thouse?: number;\n\tnakshatra?: string;\n\tpada?: number;\n\tstarLord?: string;\n\tsubLord?: string;\n\tsubSubLord?: string;\n\tkpNumber?: number;\n\tretrograde?: boolean;\n}\n\n/** \"Chitra 3\" when the pada is known, otherwise the bare nakshatra. */\nfunction nakshatraPada(nakshatra?: string, pada?: number): string {\n\tif (!nakshatra) return '';\n\treturn typeof pada === 'number' ? `${nakshatra} ${pada}` : nakshatra;\n}\n\n/**\n * A strength-ordered chain, \"Venus > Mars > Jupiter\". The API repeats a body in\n * `all` / `allHouses` when it signifies at more than one level (Venus as both\n * star-of-owner and owner), which reads as a stutter, so the first occurrence\n * wins and the rest are folded away. The grouped level columns still show every\n * level that body appears at.\n */\nfunction chain(values: ReadonlyArray<string | number>): string {\n\treturn [...new Set(values.map(String))].join(' > ');\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, a\n * Placidus cusps table, and the significator tables.\n *\n * @remarks\n * The cusp and planet sub lords are the primary predictive surface in KP, so\n * every row carries star lord, sub lord, sub-sub lord, and KP number (1-249).\n * The significators tab is the event-timing surface: house-wise (which planets\n * signify each house) and planet-wise (which houses each planet signifies),\n * both graded L1 to L4 with the API's own level labels shown as the legend.\n */\n@customElement('roxy-kp-chart')\nexport class RoxyKpChart extends RoxyDataElement<KpChartResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\ttablistStyles,\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)}.roxy-tablist{padding:0 var(--roxy-space-md,1rem)}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}.sig-head{padding:var(--roxy-space-md,1rem) var(--roxy-space-md,1rem) 0;gap:var(--roxy-space-xs,.25rem);display:grid}.sig-title{font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);margin:0}.sig-note{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);margin:0}.legend{gap:var(--roxy-space-xs,.25rem) var(--roxy-space-md,1rem);padding:var(--roxy-space-md,1rem) var(--roxy-space-md,1rem) 0;color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);flex-wrap:wrap;margin:0;list-style:none;display:flex}.legend b{color:var(--roxy-accent-ink,#b45309);margin-right:4px}.chain,.empty-cell{color:var(--roxy-muted,#71717a)}`,\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\tlongitude: p.longitude,\n\t\t\thouse: p.house,\n\t\t\tnakshatra: p.nakshatra,\n\t\t\tpada: p.pada,\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\tlongitude: node.longitude,\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\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>${typeof asc.longitude === 'number' ? formatSignPosition(asc.longitude) : (asc.sign ?? '')} </strong>${asc.nakshatra ? html`\u00B7 ${nakshatraPada(asc.nakshatra, asc.pada)}` : 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>${renderTablist({\n\t\t\t\titems: TABS,\n\t\t\t\tactive: this.activeTab,\n\t\t\t\tonSelect: (id) => {\n\t\t\t\t\tthis.activeTab = id;\n\t\t\t\t},\n\t\t\t\tlabel: 'KP chart views',\n\t\t\t\tidPrefix: 'kp',\n\t\t\t\tcontrols: true,\n\t\t\t})}<div id=\"kp-panel-${this.activeTab}\" role=\"tabpanel\" aria-labelledby=\"kp-tab-${this.activeTab}\">${\n\t\t\t\t\tthis.activeTab === 'planets'\n\t\t\t\t\t\t? this.renderPlanets()\n\t\t\t\t\t\t: this.activeTab === 'cusps'\n\t\t\t\t\t\t\t? this.renderCusps()\n\t\t\t\t\t\t\t: this.renderSignificators()\n\t\t\t\t}</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\"><caption class=\"roxy-sr-only\">KP planets and nodes: each body with its position, house, nakshatra and pada, star lord, sub lord, sub sub lord and KP number.</caption><thead><tr><th scope=\"col\">Body</th><th scope=\"col\">Position</th><th scope=\"col\">House</th><th scope=\"col\">Nakshatra, pada</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 class=\"num\">${typeof b.longitude === 'number' ? formatSignPosition(b.longitude) : ''}</td><td class=\"num\">${typeof b.house === 'number' ? b.house : ''}</td><td>${nakshatraPada(b.nakshatra, b.pada)}</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\"><caption class=\"roxy-sr-only\">KP Placidus cusps: each house cusp with its position, sign lord, nakshatra and pada, star lord, sub lord, sub sub lord and KP number.</caption><thead><tr><th scope=\"col\">House</th><th scope=\"col\">Position</th><th scope=\"col\">Sign lord</th><th scope=\"col\">Nakshatra, pada</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 class=\"num\">${typeof c.longitude === 'number' ? formatSignPosition(c.longitude) : (c.sign ?? '')}</td><td>${c.signLord ?? ''}</td><td>${nakshatraPada(c.nakshatra, c.pada)}</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\t/**\n\t * The KP event-timing surface. House-wise answers \"which planets can deliver\n\t * this house\", planet-wise answers \"what will this planet deliver in its\n\t * dasha\". The L1-L4 legend text is the API's own level description, so the\n\t * grading a reader sees is the grading the engine applied.\n\t */\n\tprivate renderSignificators() {\n\t\tconst sig = this.data?.significators;\n\t\tconst houseWise = sig?.houseWise ?? [];\n\t\tconst planetWise = sig?.planetWise ?? [];\n\t\tif (!houseWise.length && !planetWise.length)\n\t\t\treturn html`<p class=\"roxy-empty\" role=\"status\">No significators</p>`;\n\n\t\treturn html`${this.renderLevelLegend(houseWise)} ${\n\t\t\t\thouseWise.length\n\t\t\t\t\t? html`<div class=\"sig-head\"><h3 class=\"sig-title\">House-wise significators</h3><p class=\"sig-note\">Planets that signify each house, strongest level first.</p></div><table role=\"table\"><caption class=\"roxy-sr-only\">KP house-wise significators: each house, the planets that signify it at levels 1 to 4, and the full strength order.</caption><thead><tr><th scope=\"col\">House</th>${LEVELS.map((l) => html`<th scope=\"col\">L${l}</th>`)}<th scope=\"col\">Strength order</th></tr></thead><tbody>${houseWise.map(\n\t\t\t\t\t\t\t\t\t(h) => html`<tr><td class=\"body num\">${h.house}</td>${LEVELS.map((l) => this.renderCell(this.planetsAtLevel(h, l).join(', ')))}<td class=\"chain\">${chain(h.all ?? [])}</td></tr>`,\n\t\t\t\t\t\t\t\t)}</tbody></table>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tplanetWise.length\n\t\t\t\t\t? html`<div class=\"sig-head\"><h3 class=\"sig-title\">Planet-wise significators</h3><p class=\"sig-note\">Houses each planet signifies, strongest level first.</p></div><table role=\"table\"><caption class=\"roxy-sr-only\">KP planet-wise significators: each planet, the houses it signifies at levels 1 to 4, and the full strength order.</caption><thead><tr><th scope=\"col\">Planet</th>${LEVELS.map((l) => html`<th scope=\"col\">L${l}</th>`)}<th scope=\"col\">Strength order</th></tr></thead><tbody>${planetWise.map(\n\t\t\t\t\t\t\t\t\t(p) => html`<tr><td class=\"body\">${p.planet}</td>${LEVELS.map((l) => this.renderCell(this.housesAtLevel(p, l).join(', ')))}<td class=\"chain\">${chain(p.allHouses ?? [])}</td></tr>`,\n\t\t\t\t\t\t\t\t)}</tbody></table>`\n\t\t\t\t\t: nothing\n\t\t\t}`;\n\t}\n\n\t/** An em-dash-free placeholder keeps an empty level cell from reading as missing data. */\n\tprivate renderCell(value: string) {\n\t\treturn value\n\t\t\t? html`<td>${value}</td>`\n\t\t\t: html`<td class=\"empty-cell\">none</td>`;\n\t}\n\n\tprivate planetsAtLevel(h: HouseSignificator, level: number): string[] {\n\t\treturn (h.significators ?? [])\n\t\t\t.filter((s) => s.level === level)\n\t\t\t.flatMap((s) => s.planets ?? []);\n\t}\n\n\tprivate housesAtLevel(p: PlanetSignificator, level: number): number[] {\n\t\treturn (p.signifies ?? [])\n\t\t\t.filter((s) => s.level === level)\n\t\t\t.flatMap((s) => s.houses ?? []);\n\t}\n\n\t/** Level to the API's own label, taken from the first house that carries it. */\n\tprivate renderLevelLegend(houseWise: HouseSignificator[]) {\n\t\tconst labels = new Map<number, string>();\n\t\tfor (const h of houseWise) {\n\t\t\tfor (const s of h.significators ?? []) {\n\t\t\t\tif (s.description && !labels.has(s.level))\n\t\t\t\t\tlabels.set(s.level, s.description);\n\t\t\t}\n\t\t}\n\t\tif (labels.size === 0) return nothing;\n\t\treturn html`<ul class=\"legend\" aria-label=\"Significator levels\">${[...labels.entries()]\n\t\t\t\t.sort((a, b) => a[0] - b[0])\n\t\t\t\t.map(([level, label]) => html`<li><b>L${level}</b>${label}</li>`)}</ul>`;\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\"><caption class=\"roxy-sr-only\">KP planets: each planet with its sign, sign lord, nakshatra, star lord, sub lord, sub sub lord and KP number.</caption><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><caption class=\"roxy-sr-only\">House significators: each ruling planet and the houses it signifies.</caption><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\"><caption class=\"roxy-sr-only\">Local space directions: each body with its compass direction, azimuth, altitude and whether it sits above or below the horizon.</caption><thead><tr><th scope=\"col\">Body</th><th scope=\"col\">Direction</th><th scope=\"col\" class=\"num\">Azimuth</th><th scope=\"col\" class=\"num\">Altitude</th><th scope=\"col\">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\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 { disclosureStyles } from '../utils/disclosure.js';\nimport {\n\tASPECT_CLASS,\n\tformatNumber,\n\tnormalizeAspect,\n} from '../utils/format.js';\nimport {\n\ttype InterpSection,\n\tinterpAccordionStyles,\n\trenderInterpAccordion,\n} from '../utils/interp-accordion.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];\ntype PatternEntry = NonNullable<NatalChartResponse['patterns']>[number];\n\n/**\n * Reading order for detected configurations. A practitioner reads the rare, chart-defining figures first (a Grand Cross reframes the whole chart) and the common ones last, so the response order is re-sorted rather than dumped. Ties break on tightness, the closest to exact first.\n */\nconst PATTERN_ORDER: Record<string, number> = {\n\tGRAND_CROSS: 0,\n\tGRAND_TRINE: 1,\n\tKITE: 2,\n\tT_SQUARE: 3,\n\tYOD: 4,\n\tMYSTIC_RECTANGLE: 5,\n\tSTELLIUM: 6,\n};\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 * The chart shape the wheel actually renders.\n *\n * @remarks\n * `RelocationChartResponse` carries the same planets, houses, angles and birth details as `NatalChartResponse` (`RelocationPlanet` is field-for-field identical to the natal planet item), and differs only by having no `aspects`, `aspectsInterpretation`, `patterns`, `partOfFortune` or `summary`. The wheel already renders without them, so those five are simply optional here.\n *\n * Typing that contract is what lets {@link RoxyRelocationWheel} compose this component honestly. It used to pass its response through a `data as unknown as NatalChartResponse` double cast, which silently asserted five required fields that were not there.\n */\ntype ChartExtras =\n\t| 'aspects'\n\t| 'aspectsInterpretation'\n\t| 'patterns'\n\t| 'partOfFortune'\n\t| 'summary';\nexport type WheelChart = Omit<NatalChartResponse, ChartExtras> &\n\tPartial<Pick<NatalChartResponse, ChartExtras>>;\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<WheelChart> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\ttablistStyles,\n\t\tdisclosureStyles,\n\t\tinterpAccordionStyles,\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);grid-template-columns:minmax(0,1fr);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;min-width:0;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 caption{caption-side:top;text-align:left;color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);padding-bottom:var(--roxy-space-xs,.25rem)}.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)}.em-grid .dominant{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 10%, transparent)}.em-grid th.dominant,.em-grid td.em-total.dominant{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-tag{border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 55%, transparent);color:var(--roxy-fg,#0a0a0a);text-transform:capitalize;padding:1px 8px}.pattern-tight{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);font-variant-numeric:tabular-nums;margin-left:auto}.pattern-planets{flex-wrap:wrap;gap:.25rem;display:flex}.planet-chip{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);align-items:baseline;gap:.3rem;padding:1px 8px;display:inline-flex}.planet-chip.apex{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 20%, transparent);font-weight:var(--roxy-weight-bold,600)}.planet-chip .apex-tag{text-transform:uppercase;letter-spacing:.04em;font-size:.85em;font-weight:400}.pattern-interp{color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);margin:0;line-height:1.45}.interp-keywords{flex-wrap:wrap;gap:.25rem;display:flex}.interp-keywords .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}`,\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: WheelChart) {\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.renderPatterns()} ${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\"><caption class=\"roxy-sr-only\">Planet by planet aspect grid: the aspect each pair of planets forms, read from the planet naming the row across to the planet naming the column.</caption><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 balance. Each body is placed by its sign into one cell (Fire/Earth/Air/Water row, Cardinal/Fixed/Mutable column).\n\t *\n\t * @remarks\n\t * The cells are derived from the planet signs, not read from `summary.elementDistribution`, because a 1D distribution cannot fill a cross-tab. That makes the body set the reconciliation risk: the API counts every body it returns (nodes, Chiron, and Black Moon Lilith included), so the grid must too, or the totals here would contradict the dominant-element pill rendered right above it. Hence the totals count placed bodies rather than `planets.length` (an unrecognized sign would otherwise inflate the grand total past the sum of its rows), the caption names the body set, and the dominant row and column are tinted from `summary` so the pill and the grid land on the same cell.\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\t\tconst summary = this.data?.summary;\n\t\tconst dominantEl = capitalize(summary?.dominantElement ?? '');\n\t\tconst dominantMod = capitalize(summary?.dominantModality ?? '');\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\tlet placed = 0;\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\tplaced++;\n\t\t}\n\t\tif (placed === 0) return nothing;\n\n\t\tconst colTotal = (m: string) =>\n\t\t\tELEMENTS.reduce((s, el) => s + (cells[el]?.[m]?.length ?? 0), 0);\n\n\t\treturn html`<table class=\"em-grid\" aria-label=\"Element and modality distribution\"><caption>All ${placed} bodies in the chart, placed by sign</caption><thead><tr><th></th>${MODALITIES.map(\n\t\t\t\t\t\t(m) =>\n\t\t\t\t\t\t\thtml`<th scope=\"col\" class=\"${m === dominantMod ? 'dominant' : ''}\">${m.slice(0, 3)}</th>`,\n\t\t\t\t\t)}<th scope=\"col\">Total</th></tr></thead><tbody>${ELEMENTS.map((el) => {\n\t\t\t\t\tconst isDomRow = el === dominantEl;\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\" class=\"${isDomRow ? 'dominant' : ''}\">${el}</th>${MODALITIES.map(\n\t\t\t\t\t\t\t(m) =>\n\t\t\t\t\t\t\t\thtml`<td class=\"${isDomRow || m === dominantMod ? 'dominant' : ''}\">${(cells[el]?.[m] ?? []).join(' ')}</td>`,\n\t\t\t\t\t\t)}<td class=\"${isDomRow ? 'em-total dominant' : '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=\"${m === dominantMod ? 'em-total dominant' : 'em-total'}\">${colTotal(m)}</td>`,\n\t\t\t\t\t)}<td class=\"em-total\">${placed}</td></tr></tbody></table>`;\n\t}\n\n\t/**\n\t * Detected multi-planet configurations. Each card names the figure, tags the element or modality it pivots on, flags a dissociate (out-of-sign) figure, and puts the apex planet first with its own chip, because the apex is the point the whole configuration discharges through.\n\t */\n\tprivate renderPatterns() {\n\t\tconst patterns = this.data?.patterns ?? [];\n\t\tif (patterns.length === 0) return nothing;\n\t\tconst sorted = [...patterns].sort(\n\t\t\t(a, b) =>\n\t\t\t\t(PATTERN_ORDER[a.kind] ?? 9) - (PATTERN_ORDER[b.kind] ?? 9) ||\n\t\t\t\t(b.tightness ?? 0) - (a.tightness ?? 0),\n\t\t);\n\t\treturn html`<section class=\"block\"><h3>Chart patterns</h3>${sorted.map((p) => this.renderPattern(p))}</section>`;\n\t}\n\n\tprivate renderPattern(p: PatternEntry) {\n\t\tconst planets = p.planets ?? [];\n\t\t// Apex first: the spec already orders it first for Kite, T-Square, and Yod,\n\t\t// but sorting here keeps the chip row honest for any future pattern kind.\n\t\tconst ordered = p.apex\n\t\t\t? [...planets].sort((a, b) => Number(b === p.apex) - Number(a === p.apex))\n\t\t\t: planets;\n\t\treturn html`<div class=\"pattern\"><div class=\"pattern-head\"><span class=\"pattern-name\">${p.name}</span> ${p.element ? html`<span class=\"pattern-tag\">${p.element}</span>` : nothing} ${p.modality ? html`<span class=\"pattern-tag\">${p.modality}</span>` : nothing} ${\n\t\t\t\t\tp.dissociate\n\t\t\t\t\t\t? html`<span class=\"pattern-tag\" title=\"Out of sign: one or more planets sit outside the pattern element or modality, so the theme holds but runs weaker.\">Dissociate</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} ${\n\t\t\t\t\t// Math.round, not formatNumber(x, 0): that helper strips trailing\n\t\t\t\t\t// zeros, so a 100% tight pattern renders as \"1%\".\n\t\t\t\t\ttypeof p.tightness === 'number'\n\t\t\t\t\t\t? html`<span class=\"pattern-tight\">${Math.round(p.tightness)}% tight</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</div><div class=\"pattern-planets\">${ordered.map((name) => {\n\t\t\t\t\tconst glyph = PLANET_GLYPH[capitalize(name)];\n\t\t\t\t\tconst isApex = Boolean(p.apex) && name === p.apex;\n\t\t\t\t\treturn html`<span class=\"${isApex ? 'planet-chip apex' : 'planet-chip'}\">${glyph ? html`<span aria-hidden=\"true\">${glyph}</span>` : nothing}${name}${isApex ? html`<span class=\"apex-tag\">apex</span>` : nothing}</span>`;\n\t\t\t\t})}</div>${p.interpretation ? html`<p class=\"pattern-interp\">${p.interpretation}</p>` : nothing}</div>`;\n\t}\n\n\tprivate renderInterpretations() {\n\t\tconst sections: InterpSection[] = this.getPlanets()\n\t\t\t.filter((p) => p.interpretation)\n\t\t\t.map((p) => {\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\tconst lead = interp.summary || interp.detailed || '';\n\t\t\t\t// `detailed` only becomes a second paragraph when `summary` already\n\t\t\t\t// took the lead line, so a response carrying one or the other never\n\t\t\t\t// prints the same prose twice.\n\t\t\t\tconst detail = interp.summary ? interp.detailed : undefined;\n\t\t\t\treturn {\n\t\t\t\t\tlabel: `${glyph} ${p.name}`.trim(),\n\t\t\t\t\taside: [p.sign ?? '', deg].filter(Boolean).join(' '),\n\t\t\t\t\tbody: lead,\n\t\t\t\t\textra: html`${detail ? html`<p>${detail}</p>` : nothing} ${\n\t\t\t\t\t\tinterp.keywords?.length\n\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: nothing\n\t\t\t\t\t}`,\n\t\t\t\t};\n\t\t\t});\n\t\treturn renderInterpAccordion(\n\t\t\tsections,\n\t\t\t'natal-planet-readings',\n\t\t\t'Planet readings',\n\t\t);\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 { disclosureStyles } from '../utils/disclosure.js';\nimport {\n\ttype InterpSection,\n\tinterpAccordionStyles,\n\trenderInterpAccordion,\n} from '../utils/interp-accordion.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 * The interpretation block a numerology number carries: archetype keywords, the long reading, the strengths and challenges lists, and the three life-area readings. Every core number, the daily number, and the birth-day profile ship this same block (the profile omits spirituality), so one renderer serves them all. Partial, because the birth-day profile is the narrower shape.\n */\ntype NumerologyReading = Partial<CalculateLifePathResponse['meaning']>;\n\n/** Master numbers are never reduced, and a reader has to see immediately that they are looking at one. */\nconst MASTER_NUMBERS = new Set([11, 22, 33]);\n\n/** The three life-area readings, in the order a numerologist gives them. */\nconst GUIDANCE_FIELDS: ReadonlyArray<[keyof NumerologyReading, string]> = [\n\t['career', 'Career'],\n\t['relationships', 'Relationships'],\n\t['spirituality', 'Spirituality'],\n];\n\n/**\n * Numerology card. Renders /numerology/{life-path,expression,soul-urge,personality,birth-day,maturity,daily,personal-day,personal-month,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\tdisclosureStyles,\n\t\tinterpAccordionStyles,\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}.master{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 18%, transparent);color:var(--roxy-fg,#0a0a0a);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);margin-top:2px;padding:2px 10px;display:inline-block}.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);color:var(--roxy-fg,#0a0a0a);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{font-size:var(--roxy-text-sm,.875rem);gap:2px;display:grid}.cores .item .core-head{align-items:baseline;gap:var(--roxy-space-xs,.25rem);display:flex}.cores .item .core-key{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)}.cores .item .core-title{color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-xs,.75rem)}.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);font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em}.lists ul{gap:var(--roxy-space-xs,.25rem);font-size:var(--roxy-text-sm,.875rem);margin:0;padding-left:1.1rem;line-height:1.6;display:grid}.sub{gap:var(--roxy-space-sm,.5rem);border-top:1px solid var(--roxy-border,#e4e4e7);padding-top:var(--roxy-space-md,1rem);display:grid}.sub>h3{font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;margin:0}.sub-title{font-size:var(--roxy-text-base,1rem);font-weight:var(--roxy-weight-bold,600);margin:0}.sub p{font-size:var(--roxy-text-sm,.875rem);margin:0;line-height:1.6}.attrs{gap:var(--roxy-space-sm,.5rem);grid-template-columns:repeat(auto-fit,minmax(7rem,1fr));margin:0;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}.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) return this.renderPersonalDay(d, headerLabel);\n\t\tif ('personalMonth' in d) return this.renderPersonalMonth(d, headerLabel);\n\t\tif ('personalYear' in d) return this.renderPersonalYear(d, headerLabel);\n\t\tif ('dailyMessage' in d) return this.renderDailyNumber(d, headerLabel);\n\t\treturn this.renderNumberCard(d as NumberCardData, headerLabel);\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\treturn html`<article class=\"card\" aria-label=\"${headerLabel}\">${this.renderHero(headerLabel, d.number, d.meaning?.title, isMaster(d.number, d.type))} ${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\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} ${this.renderReading(d.meaning, 'numerology-guidance')}</article>`;\n\t}\n\n\t/** The daily number carries the same full interpretation as a core number, plus the message for the day. */\n\tprivate renderDailyNumber(d: GetDailyNumberResponse, headerLabel: string) {\n\t\treturn html`<article class=\"card\" aria-label=\"${headerLabel}\">${this.renderHero(headerLabel, d.number, d.meaning?.title, isMaster(d.number, d.type))} ${d.dailyMessage ? html`<p class=\"meaning\">${d.dailyMessage}</p>` : nothing} ${d.meaning?.description ? html`<p class=\"meaning\">${d.meaning.description}</p>` : nothing} ${this.renderReading(d.meaning, 'numerology-daily-guidance')}</article>`;\n\t}\n\n\t/** A personal day sits inside its personal month, which sits inside its personal year. Dropping that nesting strips the day of the context that gives it meaning. */\n\tprivate renderPersonalDay(\n\t\td: CalculatePersonalDayResponse,\n\t\theaderLabel: string,\n\t) {\n\t\treturn html`<article class=\"card\" aria-label=\"${headerLabel}\">${this.renderHero(headerLabel, d.personalDay, d.theme)} ${d.guidance ? html`<p class=\"meaning\">${d.guidance}</p>` : nothing}<dl class=\"attrs\">${this.attr('Date', d.targetDate)} ${this.attr(\n\t\t\t\t\t'Personal month',\n\t\t\t\t\tjoinCycle(d.personalMonth, d.personalMonthTheme),\n\t\t\t\t)} ${this.attr(\n\t\t\t\t\t'Personal year',\n\t\t\t\t\tjoinCycle(d.personalYear, d.personalYearTheme),\n\t\t\t\t)}</dl></article>`;\n\t}\n\n\tprivate renderPersonalMonth(\n\t\td: CalculatePersonalMonthResponse,\n\t\theaderLabel: string,\n\t) {\n\t\treturn html`<article class=\"card\" aria-label=\"${headerLabel}\">${this.renderHero(headerLabel, d.personalMonth, d.theme)} ${d.focus ? html`<p class=\"meaning\">${d.focus}</p>` : nothing}<dl class=\"attrs\">${this.attr('Calendar month', d.calendarMonth)} ${this.attr(\n\t\t\t\t\t'Personal year',\n\t\t\t\t\tjoinCycle(d.personalYear, d.personalYearTheme),\n\t\t\t\t)}</dl></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}\">${this.renderHero(headerLabel, d.personalYear, d.theme)} ${d.cycle ? html`<p class=\"label\">${d.cycle}</p>` : nothing} ${d.forecast ? html`<p class=\"meaning\">${d.forecast}</p>` : nothing} ${this.renderLists(\n\t\t\t\t['Opportunities', d.opportunities],\n\t\t\t\t['Challenges', d.challenges],\n\t\t\t)} ${d.advice ? html`<p class=\"meaning\">${d.advice}</p>` : nothing}</article>`;\n\t}\n\n\tprivate renderChart(d: GenerateNumerologyChartResponse, headerLabel: string) {\n\t\tconst cores = Object.entries(d.coreNumbers ?? {}).filter(([, v]) => v);\n\t\tconst ins = d.additionalInsights;\n\t\tconst lucky = d.luckyAssociations;\n\t\tconst profile = d.birthDayProfile;\n\t\tconst maturity = d.maturityStatus;\n\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} ${d.profile?.birthdate ? html`<p class=\"label\">${d.profile.birthdate}</p>` : nothing}</div>${d.summary ? html`<p class=\"meaning\">${d.summary}</p>` : nothing} ${\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\"><div class=\"core-head\"><span class=\"core-key\">${humanize(k)}</span> <strong>${v.number ?? ''}</strong></div>${v.meaning?.title ? html`<span class=\"core-title\">${v.meaning.title}</span>` : nothing} ${isMaster(v.number, v.type) ? html`<span class=\"master\">Master ${v.number}</span>` : nothing}</div>`,\n\t\t\t\t\t\t)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${renderInterpAccordion(\n\t\t\t\tcores.map(([k, v]) => ({\n\t\t\t\t\tlabel: humanize(k),\n\t\t\t\t\taside: [\n\t\t\t\t\t\tv.number != null ? `${v.number}` : '',\n\t\t\t\t\t\tisMaster(v.number, v.type) ? 'master' : '',\n\t\t\t\t\t\tv.hasKarmicDebt && v.karmicDebtNumber\n\t\t\t\t\t\t\t? `karmic debt ${v.karmicDebtNumber}`\n\t\t\t\t\t\t\t: '',\n\t\t\t\t\t]\n\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t.join(' \u00B7 '),\n\t\t\t\t\tbody: v.meaning?.description ?? '',\n\t\t\t\t\textra: this.renderReading(v.meaning, `numerology-core-${k}`),\n\t\t\t\t})),\n\t\t\t\t'numerology-cores',\n\t\t\t\t'Core numbers',\n\t\t\t)} ${\n\t\t\t\tmaturity\n\t\t\t\t\t? html`<dl class=\"attrs\">${this.attr('Maturity', maturity.isActive ? 'Active' : 'Not yet active')} ${this.attr('Current age', maturity.currentAge)} ${this.attr('Activates', maturity.activationRange)}</dl>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tprofile\n\t\t\t\t\t? html`<section class=\"sub\"><h3>Birth day profile</h3>${\n\t\t\t\t\t\t\tprofile.title\n\t\t\t\t\t\t\t\t? html`<h4 class=\"sub-title\">${[profile.day ? `Day ${profile.day}` : '', profile.title].filter(Boolean).join(' \u00B7 ')}</h4>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t} ${profile.description ? html`<p>${profile.description}</p>` : nothing} ${this.renderReading(profile, 'numerology-birth-day-profile')}</section>`\n\t\t\t\t\t: nothing\n\t\t\t} ${ins ? this.renderInsights(ins) : nothing} ${\n\t\t\t\tlucky\n\t\t\t\t\t? html`<section class=\"sub\"><h3>Lucky associations</h3><dl class=\"attrs\">${this.attr('Day', lucky.day)} ${this.attr('Element', lucky.element)} ${this.attr('Ruling planet', lucky.rulingPlanet)} ${this.attr('Colors', lucky.colors?.join(', '))} ${this.attr('Gemstones', lucky.gemstones?.join(', '))} ${this.attr('Compatible', lucky.compatibleNumbers?.join(', '))} ${this.attr('Incompatible', lucky.incompatibleNumbers?.join(', '))}</dl></section>`\n\t\t\t\t\t: nothing\n\t\t\t}</article>`;\n\t}\n\n\t/** Everything the chart carries beyond the six core numbers: the karmic analysis, the current year and month, the four pinnacles and their paired challenges, the name-derived numbers, and the letter analysis. */\n\tprivate renderInsights(\n\t\tins: NonNullable<GenerateNumerologyChartResponse['additionalInsights']>,\n\t) {\n\t\tconst lessons = ins.karmicLessons;\n\t\tconst debt = ins.karmicDebt;\n\t\tconst year = ins.personalYear;\n\t\tconst passion = ins.hiddenPassion;\n\t\tconst subconscious = ins.subconsciousSelf;\n\t\tconst letters = ins.nameLetters;\n\t\tconst present = Object.entries(lessons?.presentNumbers ?? {});\n\n\t\treturn html`${\n\t\t\tlessons\n\t\t\t\t? html`<section class=\"sub\"><h3>Karmic lessons</h3>${\n\t\t\t\t\t\tlessons.missingNumbers?.length\n\t\t\t\t\t\t\t? html`<div class=\"chips\">${lessons.missingNumbers.map((n) => html`<span>Missing ${n}</span>`)}</div>`\n\t\t\t\t\t\t\t: html`<p>No numbers are missing from the birth name.</p>`\n\t\t\t\t\t} ${\n\t\t\t\t\t\tpresent.length > 0\n\t\t\t\t\t\t\t? html`<div class=\"chips\">${present.map(([digit, count]) => html`<span>${digit} x ${count}</span>`)}</div>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t} ${renderInterpAccordion(\n\t\t\t\t\t\t(lessons.lessons ?? []).map((l) => ({\n\t\t\t\t\t\t\tlabel: l.lesson ?? `Lesson ${l.number}`,\n\t\t\t\t\t\t\taside: l.number != null ? `${l.number}` : '',\n\t\t\t\t\t\t\tbody: l.description ?? '',\n\t\t\t\t\t\t\textra: l.howToOvercome\n\t\t\t\t\t\t\t\t? html`<p><strong>How to overcome.</strong> ${l.howToOvercome}</p>`\n\t\t\t\t\t\t\t\t: nothing,\n\t\t\t\t\t\t})),\n\t\t\t\t\t\t'numerology-karmic-lessons',\n\t\t\t\t\t\t'Lessons',\n\t\t\t\t\t)}</section>`\n\t\t\t\t: nothing\n\t\t}${\n\t\t\tdebt?.hasKarmicDebt\n\t\t\t\t? html`<section class=\"sub\"><h3>Karmic debt</h3>${\n\t\t\t\t\t\tdebt.debtNumbers?.length\n\t\t\t\t\t\t\t? html`<div class=\"chips\">${debt.debtNumbers.map((n) => html`<span>Debt ${n}</span>`)}</div>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t} ${renderInterpAccordion(\n\t\t\t\t\t\t(debt.meanings ?? []).map((m) => ({\n\t\t\t\t\t\t\tlabel: `Karmic debt ${m.number}`,\n\t\t\t\t\t\t\tbody: m.description ?? '',\n\t\t\t\t\t\t\textra: html`${\n\t\t\t\t\t\t\t\tm.challenge\n\t\t\t\t\t\t\t\t\t? html`<p><strong>Challenge.</strong> ${m.challenge}</p>`\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\tm.resolution\n\t\t\t\t\t\t\t\t\t? html`<p><strong>Resolution.</strong> ${m.resolution}</p>`\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})),\n\t\t\t\t\t\t'numerology-karmic-debt',\n\t\t\t\t\t\t'Debts',\n\t\t\t\t\t)}</section>`\n\t\t\t\t: nothing\n\t\t}${\n\t\t\tyear\n\t\t\t\t? html`<section class=\"sub\"><h3>Personal year</h3><h4 class=\"sub-title\">${[\n\t\t\t\t\t\t\tyear.personalYear != null ? `${year.personalYear}` : '',\n\t\t\t\t\t\t\tyear.theme ?? '',\n\t\t\t\t\t\t\tyear.cycle ?? '',\n\t\t\t\t\t\t]\n\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t.join(' \u00B7 ')}</h4>${year.forecast ? html`<p>${year.forecast}</p>` : nothing} ${this.renderLists(\n\t\t\t\t\t\t['Opportunities', year.opportunities],\n\t\t\t\t\t\t['Challenges', year.challenges],\n\t\t\t\t\t)} ${year.advice ? html`<p>${year.advice}</p>` : nothing} ${\n\t\t\t\t\t\tyear.personalMonth\n\t\t\t\t\t\t\t? html`<p><strong>${[\n\t\t\t\t\t\t\t\t\tyear.personalMonth.personalMonth != null\n\t\t\t\t\t\t\t\t\t\t? `Personal month ${year.personalMonth.personalMonth}`\n\t\t\t\t\t\t\t\t\t\t: 'Personal month',\n\t\t\t\t\t\t\t\t\tyear.personalMonth.theme ?? '',\n\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t\t.join(' \u00B7 ')}.</strong> ${year.personalMonth.focus ?? ''}</p>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}</section>`\n\t\t\t\t: nothing\n\t\t}${\n\t\t\tins.pinnacles?.length\n\t\t\t\t? html`<section class=\"sub\"><h3>Pinnacles</h3>${renderInterpAccordion(\n\t\t\t\t\t\tins.pinnacles.map((p) => ({\n\t\t\t\t\t\t\tlabel: [\n\t\t\t\t\t\t\t\tp.position != null ? `Pinnacle ${p.position}` : 'Pinnacle',\n\t\t\t\t\t\t\t\tp.meaning?.title ?? '',\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t.join(' \u00B7 '),\n\t\t\t\t\t\t\taside: [\n\t\t\t\t\t\t\t\tp.number != null ? `${p.number}` : '',\n\t\t\t\t\t\t\t\tageRange(p.startAge, p.endAge),\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t.join(' \u00B7 '),\n\t\t\t\t\t\t\tbody: p.meaning?.description ?? '',\n\t\t\t\t\t\t\textra: this.renderLists(\n\t\t\t\t\t\t\t\t['Opportunities', p.meaning?.opportunities],\n\t\t\t\t\t\t\t\t['Challenges', p.meaning?.challenges],\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t})),\n\t\t\t\t\t\t'numerology-pinnacles',\n\t\t\t\t\t\t'Life phases',\n\t\t\t\t\t)}</section>`\n\t\t\t\t: nothing\n\t\t}${\n\t\t\tins.challenges?.length\n\t\t\t\t? html`<section class=\"sub\"><h3>Challenges</h3>${renderInterpAccordion(\n\t\t\t\t\t\tins.challenges.map((c) => ({\n\t\t\t\t\t\t\tlabel: [\n\t\t\t\t\t\t\t\tc.position != null ? `Challenge ${c.position}` : 'Challenge',\n\t\t\t\t\t\t\t\tc.meaning?.title ?? '',\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t.join(' \u00B7 '),\n\t\t\t\t\t\t\taside: [\n\t\t\t\t\t\t\t\tc.number != null ? `${c.number}` : '',\n\t\t\t\t\t\t\t\tageRange(c.startAge, c.endAge),\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t.join(' \u00B7 '),\n\t\t\t\t\t\t\tbody: c.meaning?.description ?? '',\n\t\t\t\t\t\t\textra: html`${\n\t\t\t\t\t\t\t\tc.meaning?.lesson\n\t\t\t\t\t\t\t\t\t? html`<p><strong>Lesson.</strong> ${c.meaning.lesson}</p>`\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\tc.meaning?.howToOvercome\n\t\t\t\t\t\t\t\t\t? html`<p><strong>How to overcome.</strong> ${c.meaning.howToOvercome}</p>`\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})),\n\t\t\t\t\t\t'numerology-challenges',\n\t\t\t\t\t\t'Obstacle periods',\n\t\t\t\t\t)}</section>`\n\t\t\t\t: nothing\n\t\t}${\n\t\t\tpassion || subconscious\n\t\t\t\t? html`<section class=\"sub\"><h3>Name numbers</h3>${\n\t\t\t\t\t\tpassion\n\t\t\t\t\t\t\t? html`<div><h4 class=\"sub-title\">${[\n\t\t\t\t\t\t\t\t\t\tpassion.number != null\n\t\t\t\t\t\t\t\t\t\t\t? `Hidden passion ${passion.number}`\n\t\t\t\t\t\t\t\t\t\t\t: 'Hidden passion',\n\t\t\t\t\t\t\t\t\t\tpassion.title ?? '',\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t\t\t.join(' \u00B7 ')}</h4>${passion.description ? html`<p>${passion.description}</p>` : nothing} ${\n\t\t\t\t\t\t\t\t\ttypeof passion.count === 'number'\n\t\t\t\t\t\t\t\t\t\t? html`<p class=\"label\">${`Appears ${passion.count} times in the name`}</p>`\n\t\t\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t\t\t}</div>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t} ${\n\t\t\t\t\t\tsubconscious\n\t\t\t\t\t\t\t? html`<div><h4 class=\"sub-title\">${[\n\t\t\t\t\t\t\t\t\t\tsubconscious.number != null\n\t\t\t\t\t\t\t\t\t\t\t? `Subconscious self ${subconscious.number}`\n\t\t\t\t\t\t\t\t\t\t\t: 'Subconscious self',\n\t\t\t\t\t\t\t\t\t\tsubconscious.title ?? '',\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t\t\t.join(' \u00B7 ')}</h4>${subconscious.description ? html`<p>${subconscious.description}</p>` : nothing} ${\n\t\t\t\t\t\t\t\t\tsubconscious.uniqueNumbers?.length\n\t\t\t\t\t\t\t\t\t\t? html`<p class=\"label\">${`Numbers present: ${subconscious.uniqueNumbers.join(', ')}`}</p>`\n\t\t\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t\t\t}</div>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}</section>`\n\t\t\t\t: nothing\n\t\t}${\n\t\t\tletters\n\t\t\t\t? html`<section class=\"sub\"><h3>Name letters</h3>${renderInterpAccordion(\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tlabel: 'Cornerstone',\n\t\t\t\t\t\t\t\taside: letterAside(\n\t\t\t\t\t\t\t\t\tletters.cornerstone?.letter,\n\t\t\t\t\t\t\t\t\tletters.cornerstone?.number,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tbody: letters.cornerstone?.meaning ?? '',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tlabel: 'Capstone',\n\t\t\t\t\t\t\t\taside: letterAside(\n\t\t\t\t\t\t\t\t\tletters.capstone?.letter,\n\t\t\t\t\t\t\t\t\tletters.capstone?.number,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tbody: letters.capstone?.meaning ?? '',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tlabel: 'First vowel',\n\t\t\t\t\t\t\t\taside: letterAside(letters.firstVowel?.letter),\n\t\t\t\t\t\t\t\tbody: letters.firstVowel?.meaning ?? '',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t\t'numerology-name-letters',\n\t\t\t\t\t\t'Letter analysis',\n\t\t\t\t\t)}</section>`\n\t\t\t\t: nothing\n\t\t}`;\n\t}\n\n\t/** Hero row shared by every single-number view: the numeral, the label, the archetype, and the master-number badge when the number is 11, 22, or 33. */\n\tprivate renderHero(\n\t\theaderLabel: string,\n\t\tnum: number | undefined,\n\t\ttitle: string | undefined,\n\t\tmaster = false,\n\t) {\n\t\treturn html`<div class=\"hero\">${typeof num === 'number' ? html`<div class=\"numeral\">${num}</div>` : nothing}<div><p class=\"label\">${headerLabel}</p>${title ? html`<h2 class=\"title\">${title}</h2>` : nothing} ${master ? html`<span class=\"master\">Master number</span>` : nothing}</div></div>`;\n\t}\n\n\t/** Keyword chips, the strengths and challenges lists, and the three life-area readings behind a disclosure. The whole interpretation, laid out as a reading. */\n\tprivate renderReading(r: NumerologyReading | undefined, name: string) {\n\t\tif (!r) return nothing;\n\t\tconst sections: InterpSection[] = GUIDANCE_FIELDS.map(([key, label]) => ({\n\t\t\tlabel,\n\t\t\tbody: (r[key] as string | undefined) ?? '',\n\t\t}));\n\t\treturn html`${\n\t\t\tr.keywords?.length\n\t\t\t\t? html`<div class=\"chips\">${r.keywords.map((k) => html`<span>${k}</span>`)}</div>`\n\t\t\t\t: nothing\n\t\t}${this.renderLists(['Strengths', r.strengths], ['Challenges', r.challenges])}${renderInterpAccordion(sections, name, 'Guidance')}`;\n\t}\n\n\t/**\n\t * Side-by-side prose lists. Each entry names a trait and explains it, so they are bulleted paragraphs, never chips.\n\t *\n\t * @remarks\n\t * `h3`, not `h4`. This renders at the TOP level of the single-number card, where the only heading above it is the `h2` title, so an `h4` skips a level and fails the axe `heading-order` rule. Inside a chart section or an accordion body the heading above is already an `h3`, and a repeated level is fine: the rule flags skips, not repeats.\n\t */\n\tprivate renderLists(\n\t\t...lists: Array<[string, ReadonlyArray<string> | undefined]>\n\t) {\n\t\tconst shown = lists.filter(([, items]) => items && items.length > 0);\n\t\tif (shown.length === 0) return nothing;\n\t\treturn html`<div class=\"lists\">${shown.map(\n\t\t\t\t([label, items]) => html`<div><h3>${label}</h3><ul>${(items ?? []).map((item) => html`<li>${item}</li>`)}</ul></div>`,\n\t\t\t)}</div>`;\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\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\n/** A number is master when the API says so, or when it is one of the three that are never reduced. Both checks, because the period cycles carry the number without the `type` flag. */\nfunction isMaster(num: number | undefined, type?: string): boolean {\n\treturn type === 'master' || (num !== undefined && MASTER_NUMBERS.has(num));\n}\n\n/** \"5 \u00B7 Freedom and change\", the cycle a smaller cycle sits inside. Empty when the API sent neither half. */\nfunction joinCycle(num: number | undefined, theme: string | undefined): string {\n\treturn [num != null ? `${num}` : '', theme ?? ''].filter(Boolean).join(' \u00B7 ');\n}\n\n/** \"ages 27 to 35\", or \"ages 54 onward\" for the final phase, which the API closes with a null end age. */\nfunction ageRange(start: number | undefined, end: number | undefined): string {\n\tif (start == null) return '';\n\treturn end == null ? `ages ${start} onward` : `ages ${start} to ${end}`;\n}\n\n/** \"A \u00B7 1\" for a letter that carries a Pythagorean value, \"A\" for the first vowel, which does not. */\nfunction letterAside(letter?: string, num?: number): string {\n\treturn [letter ?? '', num != null ? `${num}` : '']\n\t\t.filter(Boolean)\n\t\t.join(' \u00B7 ');\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-numerology-card': RoxyNumerologyCard;\n\t}\n}\n", "import { css, html, nothing, type TemplateResult } 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 { formatSignPosition } from '../utils/degree.js';\nimport { formatDate, formatTime, formatTimeRange } from '../utils/format.js';\n\ntype PanchangData = GetBasicPanchangResponse | GetDetailedPanchangResponse;\ntype Detailed = GetDetailedPanchangResponse;\ntype PanchangTime = Detailed['rahuKaal'];\ntype RashiPlacement = Detailed['moonSign'];\ntype SunNakshatra = Detailed['sunNakshatra'];\ntype Hora = Detailed['hora'];\ntype Panchaka = Detailed['panchaka'];\ntype Bhadra = Detailed['bhadra'];\ntype Chandrabalam = Detailed['chandrabalam'];\ntype Tarabalam = Detailed['tarabalam'];\ntype MoonSignTransition = Detailed['transitions']['moonSign'];\n\n/** One limb of the panchang: the headline value plus the muted detail line under it. */\ninterface Limb {\n\tlabel: string;\n\tvalue: string;\n\tmeta: string;\n}\n\n/** Joins the parts of a detail line, dropping anything the response omitted. */\nfunction meta(...parts: Array<string | number | undefined | null>): string {\n\treturn parts.filter(Boolean).join(' \u00B7 ');\n}\n\n/** The headline value of a limb: its name plus the one qualifier that belongs on the same line. */\nfunction name(...parts: Array<string | undefined>): string {\n\treturn parts.filter(Boolean).join(', ');\n}\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 * each with the reading that comes with it: the tithi ruling planet, deity,\n * element and how far it has elapsed; the nakshatra lord, deity and symbol; the\n * yoga and karana characteristics. Detailed mode adds the sunrise placements a\n * reader scans first (Moon rashi, Sun rashi, Sun nakshatra, current hora), the\n * exact transition times including the Moon sign change, and groups every timed\n * window into auspicious (fixed muhurtas plus each Amrit Kalam) and\n * inauspicious (Rahu Kaal, Yamaganda, Gulika, each Dur Muhurta and Varjyam,\n * plus Bhadra and Panchaka). Chandrabalam and Tarabalam close the card: which\n * birth rashis and birth nakshatras this day favors, the surface a muhurta is\n * actually chosen on.\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}td small{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);font-variant-numeric:normal;margin-top:2px;line-height:1.5;display:block}.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}.quiet{color:var(--roxy-muted,#71717a)}.chips{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;margin-top:4px;display:flex}.chip{border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 55%, transparent);padding:1px 8px}.chip.good{background:color-mix(in srgb, var(--roxy-success,#16a34a) 14%, transparent);color:var(--roxy-success-fg,#166534)}.chip.bad{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 14%, transparent);color:var(--roxy-danger-fg,#991b1b)}`,\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\t\tconst basic = 'sunLongitude' in d ? d : null;\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 showTimings = this.detail === 'detailed' && detailed !== null;\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>${this.limbs(d, detailed).map((l) => this.renderLimbRow(l))} ${\n\t\t\t\t\t\tdetailed\n\t\t\t\t\t\t\t? html`${this.renderRow('Sunrise', formatTime(detailed.sunrise))} ${this.renderRow('Sunset', formatTime(detailed.sunset))} ${this.renderRow('Moonrise', formatTime(detailed.moonrise))} ${this.renderRow('Moonset', formatTime(detailed.moonset))} ${this.renderRow('Moon sign', this.formatRashi(detailed.moonSign))} ${this.renderRow('Sun sign', this.formatRashi(detailed.sunSign))} ${this.renderRow('Sun nakshatra', this.formatSunNakshatra(detailed.sunNakshatra))} ${this.renderRow('Hora', this.formatHora(detailed.hora))}`\n\t\t\t\t\t\t\t: basic\n\t\t\t\t\t\t\t\t? html`${this.renderRow('Sun', this.formatLongitude(basic.sunLongitude))} ${this.renderRow('Moon', this.formatLongitude(basic.moonLongitude))}`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}</tbody></table>${detailed ? this.renderTransitions(detailed.transitions) : nothing} ${\n\t\t\t\tshowTimings\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])} ${this.renderBhadraRow(detailed.bhadra)} ${this.renderPanchakaRow(detailed.panchaka)}</tbody></table>${this.renderBalams(detailed.chandrabalam, detailed.tarabalam)}`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n\n\t/**\n\t * The five limbs, each with its own reading. Basic and detailed carry the\n\t * same limb shapes; only detailed carries the vara.\n\t */\n\tprivate limbs(d: PanchangData, detailed: Detailed | null): Limb[] {\n\t\tconst t = d.tithi;\n\t\tconst n = d.nakshatra;\n\t\tconst y = d.yoga;\n\t\tconst k = d.karana;\n\t\tconst rows: Limb[] = [\n\t\t\t{\n\t\t\t\tlabel: 'Tithi',\n\t\t\t\tvalue: name(t?.name, t?.paksha ? `${t.paksha} paksha` : undefined),\n\t\t\t\tmeta: meta(\n\t\t\t\t\tt?.rulingPlanet ? `Ruled by ${t.rulingPlanet}` : undefined,\n\t\t\t\t\tt?.deity ? `Deity ${t.deity}` : undefined,\n\t\t\t\t\tt?.element,\n\t\t\t\t\ttypeof t?.percent === 'number'\n\t\t\t\t\t\t? `${Math.round(t.percent)}% elapsed`\n\t\t\t\t\t\t: undefined,\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: 'Nakshatra',\n\t\t\t\tvalue: name(\n\t\t\t\t\tn?.name,\n\t\t\t\t\ttypeof n?.pada === 'number' ? `pada ${n.pada}` : undefined,\n\t\t\t\t),\n\t\t\t\tmeta: meta(\n\t\t\t\t\tn?.lord ? `Lord ${n.lord}` : undefined,\n\t\t\t\t\tn?.deity ? `Deity ${n.deity}` : undefined,\n\t\t\t\t\tn?.symbol ? `Symbol ${n.symbol}` : undefined,\n\t\t\t\t\tn?.characteristics,\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: 'Yoga',\n\t\t\t\tvalue: y?.name ?? '',\n\t\t\t\tmeta: y?.characteristics ?? '',\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: 'Karana',\n\t\t\t\tvalue: name(k?.name, k?.type),\n\t\t\t\tmeta: k?.characteristics ?? '',\n\t\t\t},\n\t\t];\n\t\tif (detailed?.vara) {\n\t\t\trows.push({\n\t\t\t\tlabel: 'Vara',\n\t\t\t\tvalue: detailed.vara.name ?? '',\n\t\t\t\tmeta: detailed.vara.lord ? `Lord ${detailed.vara.lord}` : '',\n\t\t\t});\n\t\t}\n\t\treturn rows.filter((l) => Boolean(l.value));\n\t}\n\n\tprivate renderLimbRow(l: Limb) {\n\t\treturn html`<tr><th>${l.label}</th><td>${l.value}${l.meta ? html`<small>${l.meta}</small>` : nothing}</td></tr>`;\n\t}\n\n\t/** One label/value row, skipped when the value is empty. */\n\tprivate renderRow(\n\t\tlabel: string,\n\t\tvalue: string,\n\t): TemplateResult | typeof nothing {\n\t\tif (!value) return nothing;\n\t\treturn html`<tr><th>${label}</th><td>${value}</td></tr>`;\n\t}\n\n\tprivate renderTransitions(t: Detailed['transitions'] | undefined) {\n\t\tif (!t) return nothing;\n\t\treturn html`<div class=\"section\">Next transitions</div><table><tbody>${this.renderTransitionRow('Tithi', t.tithi)} ${this.renderTransitionRow('Nakshatra', t.nakshatra)} ${this.renderTransitionRow('Yoga', t.yoga)} ${this.renderTransitionRow('Karana', t.karana)} ${this.renderMoonSignRow(t.moonSign)}</tbody></table>`;\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\t/**\n\t * Bhadra (Vishti karana) is avoided for every auspicious act, so \"none today\"\n\t * is as much of an answer as a window and is stated rather than left blank.\n\t */\n\tprivate renderBhadraRow(b: Bhadra | undefined) {\n\t\tif (!b) return nothing;\n\t\tconst span = this.formatSpan(b.startsAt, b.endsAt);\n\t\treturn html`<tr><th>Bhadra (Vishti)</th><td>${b.active && span ? span : html`<span class=\"quiet\">None today</span>`}</td></tr>`;\n\t}\n\n\t/**\n\t * Panchaka runs about five days, so the window commonly starts before or ends\n\t * after this date; the dosha type names which of the five it is.\n\t */\n\tprivate renderPanchakaRow(p: Panchaka | undefined) {\n\t\tif (!p) return nothing;\n\t\tconst span = this.formatSpan(p.startsAt, p.endsAt);\n\t\treturn html`<tr><th>Panchaka</th><td>${\n\t\t\t\t\tp.active\n\t\t\t\t\t\t? html`${p.type ? `${p.type} Panchaka` : 'Panchaka'}${\n\t\t\t\t\t\t\t\tspan ? html`<small>${span}</small>` : nothing\n\t\t\t\t\t\t\t}`\n\t\t\t\t\t\t: html`<span class=\"quiet\">None today</span>`\n\t\t\t\t}</td></tr>`;\n\t}\n\n\t/**\n\t * Chandrabalam and Tarabalam are read against the querent's own birth rashi\n\t * and birth nakshatra, so both lists are shown in full rather than summarized.\n\t */\n\tprivate renderBalams(c: Chandrabalam | undefined, t: Tarabalam | undefined) {\n\t\tif (!c && !t) return nothing;\n\t\treturn html`<div class=\"section\">Chandrabalam and Tarabalam</div><table><tbody>${\n\t\t\t\t\t\tc\n\t\t\t\t\t\t\t? html`<tr><th>Favorable Moon signs</th><td>${this.renderChips(c.favorableRashis, 'good')}</td></tr>${this.renderRow('Ashtama Chandra rashi', c.ashtamaChandraRashi ?? '')}`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t} ${\n\t\t\t\t\t\tt\n\t\t\t\t\t\t\t? html`<tr><th>Favorable birth nakshatras</th><td>${this.renderChips(t.favorableNakshatras, 'good')}</td></tr><tr><th>Unfavorable birth nakshatras</th><td>${this.renderChips(t.unfavorableNakshatras, 'bad')}</td></tr>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}</tbody></table>`;\n\t}\n\n\tprivate renderChips(items: string[] | undefined, tone: 'good' | 'bad') {\n\t\tif (!items?.length) return html`<span class=\"quiet\">None</span>`;\n\t\treturn html`<div class=\"chips\">${items.map((i) => html`<span class=\"chip ${tone}\">${i}</span>`)}</div>`;\n\t}\n\n\tprivate renderTransitionRow(\n\t\tlabel: string,\n\t\tt: { endsAt?: string; next?: string; nextPada?: number } | undefined,\n\t) {\n\t\tif (!t?.endsAt) return nothing;\n\t\tconst next = t.next\n\t\t\t? ` to ${t.next}${typeof t.nextPada === 'number' ? ` pada ${t.nextPada}` : ''}`\n\t\t\t: '';\n\t\treturn html`<tr><th>${label}</th><td>ends ${formatTime(t.endsAt)}${next}</td></tr>`;\n\t}\n\n\tprivate renderMoonSignRow(m: MoonSignTransition | undefined) {\n\t\tif (!m?.changesAt) return nothing;\n\t\treturn html`<tr><th>Moon sign</th><td>${m.current ?? ''} until ${formatTime(m.changesAt)}${m.next ? `, then ${m.next}` : ''}</td></tr>`;\n\t}\n\n\t/** A window that may end on the following day carries that date so it cannot be misread. */\n\tprivate formatSpan(\n\t\tstart: string | null | undefined,\n\t\tend: string | null | undefined,\n\t): string {\n\t\tconst range = formatTimeRange({\n\t\t\tstart: start ?? undefined,\n\t\t\tend: end ?? undefined,\n\t\t});\n\t\tif (!range || !start || !end) return range;\n\t\treturn start.slice(0, 10) === end.slice(0, 10)\n\t\t\t? range\n\t\t\t: `${range} (ends ${formatDate(end)})`;\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\treturn meta(\n\t\t\tn.name,\n\t\t\ttypeof n.pada === 'number' ? `pada ${n.pada}` : undefined,\n\t\t\tn.lord ? `lord ${n.lord}` : undefined,\n\t\t);\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\t/** Basic mode returns raw sidereal longitudes rather than named placements. */\n\tprivate formatLongitude(lon: number | undefined): string {\n\t\treturn typeof lon === 'number' ? formatSignPosition(lon) : '';\n\t}\n}\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 { disclosureStyles } from '../utils/disclosure.js';\nimport { formatNumber } from '../utils/format.js';\nimport {\n\ttype InterpSection,\n\tinterpAccordionStyles,\n\trenderInterpAccordion,\n} from '../utils/interp-accordion.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\tinterpAccordionStyles,\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);grid-template-columns:minmax(0,1fr);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;min-width:0;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}`,\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\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>${this.renderReadings(vm.rows)}</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 renderReadings(rows: Row[]) {\n\t\tconst sections: InterpSection[] = rows\n\t\t\t.filter((r) => r.interpretation)\n\t\t\t.map((r) => {\n\t\t\t\tconst glyph = PLANET_GLYPH[capitalize(r.label)] ?? '';\n\t\t\t\treturn {\n\t\t\t\t\tlabel: `${glyph} ${r.label}`.trim(),\n\t\t\t\t\taside: `${r.sign} ${formatDegreeInSign(r.degree)}`.trim(),\n\t\t\t\t\tbody: r.interpretation ?? '',\n\t\t\t\t};\n\t\t\t});\n\t\treturn renderInterpAccordion(sections, 'positions-readings', 'Readings');\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 { RelocationChartResponse } 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}\"></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}.phala{border-radius:var(--roxy-radius-full,9999px);background:var(--roxy-border,#e4e4e7);height:6px;display:flex;overflow:hidden}.phala-ishta{background:var(--roxy-success,#16a34a)}.phala-kashta{background:var(--roxy-danger,#dc2626)}.phala-label{justify-content:space-between;gap:var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);font-variant-numeric:tabular-nums;display:flex}.footnote{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);margin:0}.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><p class=\"footnote\">Ishta Phala is the capacity to give benefic results, Kashta Phala the capacity to give malefic ones. Both are in virupas and are read together, since a planet can be strong and still deliver hardship.</p></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>${this.renderPhala(p)}</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\t/**\n\t * Ishta and Kashta Phala, the fruit a planet is capable of giving in its dasha\n\t * and transits. They are derived from Uchcha and Chesta Bala, not from the\n\t * six-fold total, so a planet can rank first on strength and still carry a\n\t * heavy Kashta share. Rendering only the total hides exactly that.\n\t */\n\tprivate renderPhala(p: Planet) {\n\t\tconst ishta = typeof p.ishtaPhala === 'number' ? p.ishtaPhala : 0;\n\t\tconst kashta = typeof p.kashtaPhala === 'number' ? p.kashtaPhala : 0;\n\t\tif (ishta + kashta <= 0) return nothing;\n\t\tconst ishtaStr = formatNumber(ishta, 1) || '0';\n\t\tconst kashtaStr = formatNumber(kashta, 1) || '0';\n\t\treturn html`<div class=\"phala\" role=\"img\" aria-label=\"Ishta Phala ${ishtaStr}, Kashta Phala ${kashtaStr} virupas\"><span class=\"phala-ishta\" style=\"flex-grow:${ishta}\"></span> <span class=\"phala-kashta\" style=\"flex-grow:${kashta}\"></span></div><div class=\"phala-label\"><span>Ishta ${ishtaStr}</span> <span>Kashta ${kashtaStr}</span></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 { chevron, disclosureStyles } from '../utils/disclosure.js';\nimport {\n\tASPECT_CLASS,\n\tformatNumber,\n\tnormalizeAspect,\n} from '../utils/format.js';\nimport { interpAccordionStyles } from '../utils/interp-accordion.js';\nimport { capitalize } from '../utils/string.js';\n\ntype PlanetEntry = NatalChartResponse['planets'][number];\ntype InterAspect = CalculateSynastryResponse['interAspects'][number];\ntype SynastrySummary = CalculateSynastryResponse['summary'];\ntype SynastryPerson = CalculateSynastryResponse['person1'];\n\n/** How many inter-aspects get a full reading before the rest fall back to the catalog table. A synastry can return 90+ contacts; a practitioner works the tightest ones. */\nconst READING_COUNT = 12;\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\tdisclosureStyles,\n\t\tinterpAccordionStyles,\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);grid-template-columns:minmax(0,1fr);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}.people{gap:var(--roxy-space-sm,.5rem);grid-template-columns:repeat(auto-fit,minmax(11rem,1fr));display:grid}.person{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);gap:.3rem;display:grid}.person-name{font-weight:var(--roxy-weight-bold,600);font-size:var(--roxy-text-sm,.875rem);align-items:center;gap:.4rem;display:flex}.person-dot{border-radius:50%;flex-shrink:0;width:8px;height:8px}.person-dot.p1{background:var(--roxy-accent,#f59e0b)}.person-dot.p2{background:var(--roxy-info,#0284c7)}.big-three{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);flex-wrap:wrap;gap:.25rem .75rem;display:flex}.big-three span{align-items:baseline;gap:.25rem;display:inline-flex}.big-three .lbl{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem)}.summary-pills{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;display:flex}.pill{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) 60%, transparent);color:var(--roxy-fg,#0a0a0a);padding:2px 8px}.pill--success{background:color-mix(in srgb, var(--roxy-success,#16a34a) 12%, transparent);color:var(--roxy-success-fg,#166534)}.pill--danger{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 12%, transparent);color:var(--roxy-danger-fg,#991b1b)}.glyph{font-size:1.1em;line-height:1}.static-head{align-items:center;gap:var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-sm,.875rem);flex-wrap:wrap;font-weight:500;display:flex}.asp-name{font-weight:var(--roxy-weight-bold,600);text-transform:capitalize}.asp-name.harmonious{color:var(--roxy-success-fg,#166534)}.asp-name.challenging{color:var(--roxy-danger-fg,#991b1b)}.interp-keywords{flex-wrap:wrap;gap:.25rem;display:flex}.interp-keywords .kw{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);padding:1px 8px}.context{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);text-transform:uppercase;letter-spacing:.06em;font-weight:var(--roxy-weight-bold,600)}.catalog>summary{cursor:pointer;font-weight:var(--roxy-weight-bold,600);font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);align-items:center;gap:.5rem;display:flex}.scroll{min-width:0;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{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 returns chart highlights (Sun, Moon, Ascendant) but\n\t\t// not full planet positions, so the dual wheel cannot be drawn from a bare\n\t\t// synastry response. Say so instead of rendering a blank wheel; every other\n\t\t// block still renders, so a caller who passes the bare response gets the\n\t\t// full reading minus the drawing.\n\t\tconst hasPlanets = p1Planets.length > 0 && p2Planets.length > 0;\n\t\t// The tightest contacts carry the reading. Sort a copy: `data` is the\n\t\t// caller's object.\n\t\tconst ranked = [...interAspects].sort(\n\t\t\t(a, b) => (b.strength ?? 0) - (a.strength ?? 0),\n\t\t);\n\t\tconst lead = ranked.slice(0, READING_COUNT);\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>${this.renderPeople(person1, person2)} ${\n\t\t\t\thasPlanets\n\t\t\t\t\t? html`<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>`\n\t\t\t\t\t: html`<div class=\"missing-planets\" role=\"status\">Synastry response missing planet positions. Pass <code>data</code> with <code>person1.planets</code> and <code>person2.planets</code> arrays from the natal-chart endpoint, or use the <code>&lt;roxy-data></code> fallback.</div>`\n\t\t\t} ${this.renderSummaryPills(d.summary)} ${summaryText ? html`<p class=\"summary\">${summaryText}</p>` : nothing} ${\n\t\t\t\tlead.length > 0\n\t\t\t\t\t? html`<section class=\"block\"><h3>Inter-aspects</h3>${lead.map((a, i) => this.renderAspectCard(a, i))}</section>`\n\t\t\t\t\t: nothing\n\t\t\t} ${ranked.length > lead.length ? this.renderCatalog(ranked) : 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\t/** Chart highlights for both people: the Sun, Moon, and Ascendant a reader checks before any aspect. Colour-dotted to match each person ring on the wheel. */\n\tprivate renderPeople(\n\t\tp1: SynastryPerson | undefined,\n\t\tp2: SynastryPerson | undefined,\n\t) {\n\t\tconst card = (p: SynastryPerson | undefined, index: 1 | 2) => {\n\t\t\tif (!p) return nothing;\n\t\t\tconst big: Array<[string, string]> = [\n\t\t\t\t['Sun', p.sunSign ?? ''],\n\t\t\t\t['Moon', p.moonSign ?? ''],\n\t\t\t\t[\n\t\t\t\t\t'Asc',\n\t\t\t\t\tp.ascendant\n\t\t\t\t\t\t? `${p.ascendant.sign} ${formatNumber(p.ascendant.degree, 0)}\u00B0`\n\t\t\t\t\t\t: '',\n\t\t\t\t],\n\t\t\t];\n\t\t\tconst shown = big.filter(([, value]) => value);\n\t\t\tif (shown.length === 0) return nothing;\n\t\t\treturn html`<div class=\"person\"><span class=\"person-name\"><span class=\"person-dot p${index}\" aria-hidden=\"true\"></span> ${p.name || `Person ${index}`}</span><div class=\"big-three\">${shown.map(\n\t\t\t\t\t\t([label, value]) => html`<span><span class=\"lbl\">${label}</span> <span aria-hidden=\"true\">${SIGN_GLYPH[capitalize(value.split(' ')[0] ?? '')] ?? ''}</span> ${value}</span>`,\n\t\t\t\t\t)}</div></div>`;\n\t\t};\n\t\tconst cards = [card(p1, 1), card(p2, 2)].filter((c) => c !== nothing);\n\t\tif (cards.length === 0) return nothing;\n\t\treturn html`<div class=\"people\">${cards}</div>`;\n\t}\n\n\t/** Contact balance for the pair. `byType` is a map, so its pairs are rendered, never the object. */\n\tprivate renderSummaryPills(s: SynastrySummary | undefined) {\n\t\tif (!s || typeof s !== 'object') return nothing;\n\t\tconst byType = Object.entries(s.byType ?? {}).sort((a, b) => b[1] - a[1]);\n\t\tif (typeof s.total !== 'number' && byType.length === 0) return nothing;\n\t\treturn html`<div class=\"summary-pills\" role=\"region\" aria-label=\"Inter-aspect summary\">${typeof s.total === 'number' ? html`<span class=\"pill\">Total: ${s.total}</span>` : nothing} <span class=\"pill pill--success\">Harmonious: ${s.harmonious}</span> <span class=\"pill pill--danger\">Challenging: ${s.challenging}</span> <span class=\"pill\">Neutral: ${s.neutral}</span> ${byType.map(\n\t\t\t\t([type, count]) =>\n\t\t\t\t\thtml`<span class=\"pill\">${capitalize(type.replace(/_/g, ' '))}: ${count}</span>`,\n\t\t\t)}</div>`;\n\t}\n\n\t/**\n\t * One inter-chart contact as a reading. The header is the scannable line (both bodies, the aspect coloured by nature, orb and strength); the body leads with `meaning.relationshipContext`, which is the whole point of a synastry aspect: not what a trine means, but what THIS trine does to THESE two people.\n\t */\n\tprivate renderAspectCard(a: InterAspect, index: number) {\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 meaning = a.meaning;\n\t\tconst lead = html`<span class=\"interp-lead\"><span aria-hidden=\"true\" class=\"glyph\">${g1}</span>${a.planet1} <span class=\"asp-name ${nature}\">${normalizeAspect(a)}</span> <span aria-hidden=\"true\" class=\"glyph\">${g2}</span>${a.planet2}</span>`;\n\t\tconst aside = html`<span class=\"interp-aside\"><small>orb ${formatNumber(a.orb, 2)}\u00B0 \u00B7 str ${formatNumber(a.strength, 0)}</small></span>`;\n\t\tif (!meaning?.relationshipContext && !meaning?.description?.short) {\n\t\t\treturn html`<div class=\"interp-card\"><div class=\"static-head\">${lead}${aside}</div></div>`;\n\t\t}\n\t\treturn html`<details class=\"interp-card\" name=\"synastry-aspects\" ?open=\"${index === 0}\"><summary>${lead}${chevron()}${aside}</summary><div class=\"interp-body\">${\n\t\t\t\t\tmeaning.relationshipContext\n\t\t\t\t\t\t? html`<p><span class=\"context\">In this pairing</span> ${meaning.relationshipContext}</p>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} ${meaning.description?.short ? html`<p>${meaning.description.short}</p>` : nothing} ${\n\t\t\t\t\tmeaning.keywords?.length\n\t\t\t\t\t\t? html`<div class=\"interp-keywords\">${meaning.keywords.map((k) => html`<span class=\"kw\">${k}</span>`)}</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</div></details>`;\n\t}\n\n\t/** Every remaining contact, so nothing the endpoint returned is dropped. */\n\tprivate renderCatalog(ranked: InterAspect[]) {\n\t\treturn html`<details class=\"catalog\"><summary>${chevron()} All ${ranked.length} inter-aspects</summary><div class=\"scroll\">${this.renderAspects(ranked)}</div></details>`;\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><caption class=\"roxy-sr-only\">Inter-chart aspects: the planet from chart 1, the planet from chart 2, the aspect between them, the orb in degrees and the strength.</caption><thead><tr><th scope=\"col\">Planet 1</th><th scope=\"col\">Planet 2</th><th scope=\"col\">Aspect</th><th scope=\"col\">Orb</th><th scope=\"col\">Strength</th></tr></thead><tbody>${aspects.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>${formatNumber(a.strength, 0)}</td></tr>`,\n\t\t\t\t)}</tbody></table>`;\n\t}\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';\nimport { disclosureStyles } from '../utils/disclosure.js';\nimport {\n\ttype InterpSection,\n\tinterpAccordionStyles,\n\trenderInterpAccordion,\n} from '../utils/interp-accordion.js';\nimport { renderTablist, tablistStyles } from '../utils/tablist.js';\n\ntype TarotData = GetCardResponse | GetDailyCardResponse;\n\n/** The five life-area readings every tarot orientation carries. Both shapes the component renders supply them: the reference card carries a set per orientation, the drawn card carries one set for the orientation it landed in. */\ntype TarotGuidance = Pick<\n\tGetCardResponse['upright'],\n\t'love' | 'career' | 'finances' | 'health' | 'spirituality'\n>;\n\nconst GUIDANCE_FIELDS: ReadonlyArray<[keyof TarotGuidance, string]> = [\n\t['love', 'Love'],\n\t['career', 'Career'],\n\t['finances', 'Finances'],\n\t['health', 'Health'],\n\t['spirituality', 'Spirituality'],\n];\n\n/**\n * Tarot card. Renders /tarot/cards/{id} and /tarot/daily.\n *\n * @remarks\n * The two endpoints are NOT the same card and must not be shown the same way. The reference card ships both orientations, so the reader chooses one and the whole reading (image, keywords, description, life areas) follows that choice. The daily card is DRAWN: the API ships exactly one orientation and one set of meanings for it, so there is nothing to switch to. It used to offer the same flip, which rotated the art and relabelled the card \"reversed\" while the text below it stayed the upright reading. The draw is now fixed and stated, never toggled.\n */\n@customElement('roxy-tarot-card')\nexport class RoxyTarotCard extends RoxyDataElement<TarotData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tdisclosureStyles,\n\t\tinterpAccordionStyles,\n\t\ttablistStyles,\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{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));display:block}.image.reversed{transform:rotate(180deg)}.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)}.drawn{color:var(--roxy-fg,#0a0a0a);font-weight:var(--roxy-weight-bold,600)}.message{color:var(--roxy-fg,#0a0a0a);margin:var(--roxy-space-sm,.5rem) 0 var(--roxy-space-md,1rem)}.reading{margin:0 0 var(--roxy-space-md,1rem);white-space:pre-line}.roxy-tablist{margin:var(--roxy-space-sm,.5rem) 0}.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);color:var(--roxy-fg,#0a0a0a);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);padding:2px 8px}`,\n\t];\n\n\t/** Which orientation of the REFERENCE card is being read. The daily draw ignores this: its orientation is whatever was drawn. */\n\t@state()\n\tprivate orientation: 'upright' | 'reversed' = 'upright';\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 reversed = Boolean(card.reversed);\n\t\tconst keywords = card.keywords ?? [];\n\t\t// One text node per span: the markup minifier collapses whitespace at an\n\t\t// expression boundary, so every separator is joined in JS, never in markup.\n\t\tconst meta = [card.arcana ? `${card.arcana} arcana` : '', card.suit ?? '']\n\t\t\t.filter(Boolean)\n\t\t\t.join(' \u00B7 ');\n\n\t\treturn html`<article class=\"card\" aria-label=\"${card.name ?? 'Tarot card'}\">${this.renderImage(card.imageUrl, card.name, reversed)}<div><div class=\"meta\">${meta ? `${meta} \u00B7 ` : ''}<span class=\"drawn\">${reversed ? 'drawn reversed' : 'drawn upright'}</span></div><h2 class=\"title\">${card.name ?? 'Tarot card'}</h2>${d.dailyMessage ? html`<p class=\"message\">${d.dailyMessage}</p>` : nothing} ${card.meaning ? html`<p class=\"reading\">${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} ${this.renderGuidance(card, 'tarot-daily-guidance')}</div></article>`;\n\t}\n\n\tprivate renderFullCard(d: GetCardResponse) {\n\t\tconst reversed = this.orientation === 'reversed';\n\t\tconst oriented = reversed ? d.reversed : d.upright;\n\t\tconst keywords =\n\t\t\t(reversed ? d.keywords?.reversed : d.keywords?.upright) ??\n\t\t\toriented?.keywords ??\n\t\t\t[];\n\n\t\treturn html`<article class=\"card\" aria-label=\"${d.name ?? 'Tarot card'}\">${this.renderImage(d.imageUrl, d.name, reversed)}<div><div class=\"meta\">${[\n\t\t\t\t\t\td.arcana ? `${d.arcana} arcana` : '',\n\t\t\t\t\t\td.suit ?? '',\n\t\t\t\t\t\td.number !== undefined && d.number !== null\n\t\t\t\t\t\t\t? `no. ${d.number}`\n\t\t\t\t\t\t\t: '',\n\t\t\t\t\t]\n\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t.join(' \u00B7 ')}</div><h2 class=\"title\">${d.name ?? 'Tarot card'}</h2>${renderTablist({\n\t\t\t\t\titems: [\n\t\t\t\t\t\t{ id: 'upright', label: 'Upright' },\n\t\t\t\t\t\t{ id: 'reversed', label: 'Reversed' },\n\t\t\t\t\t],\n\t\t\t\t\tactive: this.orientation,\n\t\t\t\t\tonSelect: (id) => {\n\t\t\t\t\t\tthis.orientation = id;\n\t\t\t\t\t},\n\t\t\t\t\tlabel: 'Card orientation',\n\t\t\t\t\tidPrefix: 'tarot',\n\t\t\t\t})} ${oriented?.description ? html`<p class=\"reading\">${oriented.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} ${this.renderGuidance(oriented, `tarot-${this.orientation}-guidance`)}</div></article>`;\n\t}\n\n\t/** The artwork, rotated when the orientation being read is reversed. Decorative beyond its alt text: the orientation is stated in the meta line, so the image is never the only place it appears. */\n\tprivate renderImage(\n\t\timageUrl: string | undefined,\n\t\tname: string | undefined,\n\t\treversed: boolean,\n\t) {\n\t\tconst cls = `image ${reversed ? 'reversed' : ''}`;\n\t\tif (!imageUrl) {\n\t\t\treturn html`<div class=\"${cls}\" style=\"aspect-ratio:0.6;display:flex;align-items:center;justify-content:center;color:var(--roxy-muted)\">${name ?? '?'}</div>`;\n\t\t}\n\t\treturn html`<img class=\"${cls}\" src=\"${imageUrl}\" alt=\"${name ?? 'Tarot card'}\">`;\n\t}\n\n\t/** The five life-area readings for the orientation on screen. Grouped per orientation so switching the reference card swaps the whole accordion rather than leaving a stale section open. */\n\tprivate renderGuidance(guidance: TarotGuidance | undefined, name: string) {\n\t\tif (!guidance) return nothing;\n\t\tconst sections: InterpSection[] = GUIDANCE_FIELDS.map(([key, label]) => ({\n\t\t\tlabel,\n\t\t\tbody: guidance[key] ?? '',\n\t\t}));\n\t\treturn renderInterpAccordion(sections, name, 'Guidance');\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)}.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);color:var(--roxy-fg,#0a0a0a);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);padding:2px 8px}.verdict{gap:var(--roxy-space-md,1rem);grid-template-columns:minmax(0,8rem) 1fr;align-items:start;display:grid}@container (width<=26rem){.verdict{grid-template-columns:1fr}}.verdict .meta{gap:var(--roxy-space-sm,.5rem);justify-items:start;display:grid}.arcana{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;margin:0}.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 verdictCard = isYesNo ? (d as CastYesNoResponse).card : 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 class=\"verdict\"><div class=\"card\"><div class=\"image\">${\n\t\t\t\t\t\t\t\t\tverdictCard?.imageUrl\n\t\t\t\t\t\t\t\t\t\t? html`<img src=\"${verdictCard.imageUrl}\" alt=\"${verdictCard.name ?? 'tarot card'}\" class=\"${verdictCard.reversed ? 'reversed' : ''}\">`\n\t\t\t\t\t\t\t\t\t\t: html`${verdictCard?.name ?? '?'}`\n\t\t\t\t\t\t\t\t}</div><p class=\"name\">${verdictCard?.name ?? ''} ${verdictCard?.reversed ? html`<small>(reversed)</small>` : nothing}</p>${verdictCard?.arcana ? html`<p class=\"arcana\">${verdictCard.arcana} arcana</p>` : nothing}</div><div class=\"meta\"><div><span class=\"${`answer ${answerClass}`}\">${answer}</span> ${strength ? html`<small>\u00B7 ${strength}</small>` : nothing}</div>${\n\t\t\t\t\t\t\t\tverdictCard?.keywords && verdictCard.keywords.length > 0\n\t\t\t\t\t\t\t\t\t? html`<div class=\"chips\">${verdictCard.keywords.map((k) => html`<span>${k}</span>`)}</div>`\n\t\t\t\t\t\t\t\t\t: nothing\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\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);grid-template-columns:minmax(0,1fr);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;min-width:0;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\"><caption class=\"roxy-sr-only\">Transiting planets: each planet with its current sign, degree and daily speed.</caption><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 { formatSignPosition } from '../utils/degree.js';\nimport { formatDate, formatNumber, formatTime } 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 * @remarks\n * `datetime` is the chart time, the wall clock of the request, NOT UTC: hold the date and time fixed and vary `timezone` and every longitude in the response moves, while `datetime` does not. It is labelled \"Chart time\" for that reason. The spec description calling it UTC is wrong and is tracked upstream. The sidereal positions the aspects were derived from are shown above the table so a reader can check the drishti against the actual placements.\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);grid-template-columns:minmax(0,1fr);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}.position{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);color:var(--roxy-fg,#0a0a0a);font-variant-numeric:tabular-nums;align-items:baseline;gap:.35rem;padding:2px 10px;display:inline-flex}.position strong{color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem)}.overflow-scroll{-webkit-overflow-scrolling:touch;min-width:0;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\tconst planets = d.planets ?? [];\n\t\tif (aspects.length === 0 && mutual.length === 0) return this.renderEmpty();\n\t\tconst when = d.datetime\n\t\t\t? `${formatDate(d.datetime)}, ${formatTime(d.datetime)}`\n\t\t\t: '';\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Vedic aspects\"><div class=\"head\"><h2 class=\"title\">Vedic Aspects</h2>${when ? html`<p class=\"subtitle\">Chart time ${when}</p>` : nothing}</div>${\n\t\t\t\tplanets.length > 0\n\t\t\t\t\t? html`<div><p class=\"section-label\">Sidereal positions</p><div class=\"mutual\">${planets.map(\n\t\t\t\t\t\t\t\t(p) => html`<span class=\"position\"><strong>${p.name}</strong> ${typeof p.longitude === 'number' ? formatSignPosition(p.longitude) : (p.sign ?? '')}</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\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><caption class=\"roxy-sr-only\">Vedic planetary aspects: aspecting planet, aspect type, aspected planet, strength and orb.</caption><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{min-width:0;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);grid-template-columns:minmax(0,1fr);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\"><caption class=\"roxy-sr-only\">Vedic planetary positions: each graha with its rashi, degree, nakshatra, pada, nakshatra lord, house, avastha and retrograde state.</caption><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\"><caption class=\"roxy-sr-only\">Western planetary positions: each body with its sign, degree, house and motion.</caption><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,navamsa}',\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:\n\t\t\t'GET /vedic-astrology/yoga, POST /vedic-astrology/yoga/detect',\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 the full reading: type, strategy, authority, profile, definition, incarnation cross, and a gate and line meaning for every activation',\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, and gates, plus the type, strategy, authority, profile, and definition readings, the channels by circuit, the centers, and every activation with its gate and line meaning',\n\t\ttopic: 'Human Design',\n\t},\n\t{\n\t\tpascal: 'RoxyHdTypeCard',\n\t\ttag: 'roxy-hd-type-card',\n\t\tslug: 'hd-type-card',\n\t\theading: 'HD type',\n\t\tdescription:\n\t\t\t'Human Design type reading without the chart: type, strategy, authority, and profile, with the aura mechanic, the signature and not-self themes, and the interpretation behind each label. Also renders the profile response with its two line keynotes',\n\t\tdocsLabel: 'Human Design',\n\t\tendpointLabel: 'POST /human-design/type, /human-design/profile',\n\t\tdocsSummary:\n\t\t\t'Type, strategy, authority, and profile tiles with the aura, signature, and not-self themes, plus the reading behind each label and the profile line keynotes',\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, color, tone, and base, plus the reading for each arrow and the cognition',\n\t\tdocsLabel: 'Human Design',\n\t\tendpointLabel: 'POST /human-design/variables',\n\t\tdocsSummary:\n\t\t\t'The four transformation arrows with direction, color, tone, and base, plus a reading per arrow grouped by layer and the cognition',\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,significant-dates,transits}',\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 drawn line by line with trigram glyphs, judgment, image, and a reading for every line: the oracle statement and what it asks of the querent. A cast highlights the moving lines and shows only their readings, plus the hexagram it transforms into',\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:\n\t\t\t'Hexagram figure with trigrams, judgment, image, and a reading per line (statement plus meaning); a cast highlights the moving lines and the resulting hexagram',\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.15.0';\n", "/**\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 { RoxyHdTypeCard } from './components/hd-type-card.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"],
5
- "mappings": "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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,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,mDACf,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,cACC,+DACD,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,sNACD,UAAW,eACX,cAAe,+BACf,YACC,+OACD,MAAO,cACR,EACA,CACC,OAAQ,iBACR,IAAK,oBACL,KAAM,eACN,QAAS,UACT,YACC,yPACD,UAAW,eACX,cAAe,iDACf,YACC,+JACD,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,wMACD,UAAW,eACX,cAAe,+BACf,YACC,oIACD,MAAO,cACR,EACA,CACC,OAAQ,uBACR,IAAK,yBACL,KAAM,oBACN,QAAS,oBACT,YACC,mFACD,UAAW,WACX,cAAe,uDACf,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,uQACD,UAAW,UACX,cACC,uFACD,YACC,iKACD,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,ECvsBO,IAAMC,GAAkB,SC6FxB,IAAMC,GACZC,GAAgB,IAAKC,GAAMA,EAAE,IAAI",
4
+ "sourcesContent": ["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\tqueryKeys?: string[];\n\t\t};\n\t\tif (this.remember) this.writeRemembered(detail.values);\n\t\tvoid this.fetcher.run(\n\t\t\tbuildRequest(\n\t\t\t\tthis.endpoint,\n\t\t\t\tthis.method,\n\t\t\t\tdetail.values,\n\t\t\t\tdetail.queryKeys ?? [],\n\t\t\t),\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-sr-only{clip-path:inset(50%);white-space:nowrap;border:0;width:1px;height:1px;margin:0;padding:0;position:absolute;overflow:hidden}.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 the form mixin can attach a controller without the component wiring state by hand.\n *\n * @remarks\n * Intersected with `HTMLElement` because the controller dispatches events on the host. Lit's `ReactiveControllerHost` is the update-lifecycle contract only (`addController`, `requestUpdate`, `updateComplete`) and carries no DOM surface, even though every real host is a `LitElement` and therefore an `HTMLElement`. Declaring the DOM half is what the controller actually needs; it used to reach it through a `this.host as unknown as EventTarget` double cast instead, which asserted a capability the type never promised.\n */\ntype FetchHost<T> = ReactiveControllerHost &\n\tHTMLElement & {\n\t\tdata: T | null;\n\t\tloading: boolean;\n\t\terror: string | null;\n\t};\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\tthis.host.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 *\n * @param queryKeys - Names the spec declares as `in: query` for this operation, which `<roxy-endpoint-form>` reports on its `roxy-submit` event. A POST operation can still take query parameters (every localized endpoint takes `?lang=`), and sending one in the JSON body silently drops it, so those names are routed to the query string on POST as well as GET.\n */\nexport function buildRequest(\n\tendpoint: string,\n\tmethod: 'GET' | 'POST',\n\tvalues: Record<string, unknown>,\n\tqueryKeys: readonly string[] = [],\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 inQuery = new Set(queryKeys);\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' || inQuery.has(k)) 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';\nimport { disclosureStyles } from '../utils/disclosure.js';\nimport {\n\tinterpAccordionStyles,\n\trenderInterpAccordion,\n} from '../utils/interp-accordion.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 context note when the caller said where the number was seen, 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\tdisclosureStyles,\n\t\tinterpAccordionStyles,\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)}.badge.energy-positive{background:color-mix(in srgb, var(--roxy-success,#16a34a) 18%, transparent)}.badge.energy-cautionary{background:color-mix(in srgb, var(--roxy-warning,#ea580c) 18%, transparent)}.context{gap:var(--roxy-space-xs,.25rem);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);border-radius:0 var(--roxy-radius-sm,4px) var(--roxy-radius-sm,4px) 0;display:grid}.steps{gap:var(--roxy-space-xs,.25rem);color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);margin:0;padding-left:1.1rem;line-height:1.6;display:grid}.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}`,\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\t\tconst steps = known?.actionSteps ?? [];\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} ${known?.energy ? html`<span class=\"${`badge energy-${known.energy}`}\">${known.energy} energy</span>` : nothing}</div>${\n\t\t\t\td.contextNote\n\t\t\t\t\t? html`<div class=\"context\"><p class=\"label\">Where you saw it</p><p>${d.contextNote}</p></div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\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, 'lookup-known', known.biblical, known.shadow)} ${known.affirmation ? html`<p><em>${known.affirmation}</em></p>` : nothing} ${\n\t\t\t\t\t\t\tsteps.length > 0\n\t\t\t\t\t\t\t\t? html`<p class=\"label\">What to do next</p><ol class=\"steps\">${steps.map((s) => html`<li>${s}</li>`)}</ol>`\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\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\tname: string,\n\t\tbiblical?: string,\n\t\tshadow?: string,\n\t) {\n\t\treturn renderInterpAccordion(\n\t\t\tbuildMeaningSections(meaning, biblical, shadow),\n\t\t\tname,\n\t\t\t'Reading',\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, 'lookup-root')}${\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 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 * The interpretation accordion: the one way this library shows a label, a short value, and a body of prose behind a disclosure.\n *\n * @remarks\n * Exclusive by construction (`<details name>`), so a card grows by at most one open section and never becomes a wall of text. Callers pass their own group `name` so two accordions on one page do not fight over which section is open.\n *\n * This lives here rather than in a component because the same accordion is the right shape wherever an endpoint returns a labelled reading: the Human Design bodygraph and type card use it for strategy, authority, and aura; `roxy-hexagram` uses it for the changing lines. The CSS was copy-pasted into six components before 2026-07 and had already drifted (`.interp-body` had five distinct definitions), which is the drift this exists to stop. Migrate the remaining copies to it when they are next touched.\n */\n\nimport { css, html, nothing } from 'lit';\nimport { chevron } from './disclosure.js';\n\n/** One row: the label, the short value shown as the aside, and the interpretation body. `extra` renders under the body for a section that carries more than prose. */\nexport interface InterpSection {\n\tlabel: string;\n\taside?: string;\n\tbody: string;\n\textra?: unknown;\n}\n\nexport const interpAccordionStyles = css`.block{border-top:1px solid var(--roxy-border,#e4e4e7);padding-top:var(--roxy-space-md,1rem)}.block h3{margin:0 0 var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em}.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);align-items:center;gap:var(--roxy-space-sm,.5rem);font-weight:500;font-size:var(--roxy-text-sm,.875rem);display:flex}.interp-card summary:focus-visible{outline:2px solid var(--roxy-ring,#f59e0b66);outline-offset:2px;border-radius:var(--roxy-radius-sm,4px)}.interp-lead{flex-wrap:wrap;flex:auto;order:1;align-items:baseline;gap:.4rem;min-width:0;display:inline-flex}.interp-aside{flex-shrink:0;order:2;align-items:center;gap:.5rem;display:inline-flex}.roxy-chevron{order:3}.interp-aside small{color:var(--roxy-muted,#71717a);white-space:nowrap;font-weight:400}@container (width<=26rem){.interp-card summary{flex-wrap:wrap}.roxy-chevron{order:2}.interp-aside{flex-basis:100%;order:3;justify-content:flex-end}}.interp-body{margin-top:var(--roxy-space-sm,.5rem);gap:var(--roxy-space-sm,.5rem);color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);overflow-wrap:anywhere;line-height:1.6;display:grid}.interp-body p{margin:0}`;\n\n/**\n * Render the accordion. Sections with no body are dropped, so a caller can pass the full set and let a narrower response render only what it carries. `name` groups the `<details>` exclusively, so opening one closes the last.\n */\nexport function renderInterpAccordion(\n\tsections: InterpSection[],\n\tname: string,\n\theading = 'Reading',\n) {\n\tconst shown = sections.filter((s) => Boolean(s.body));\n\tif (shown.length === 0) return nothing;\n\n\treturn html`<section class=\"block\"><h3>${heading}</h3>${shown.map(\n\t\t\t(s, i) => html`<details class=\"interp-card\" name=\"${name}\" ?open=\"${i === 0}\"><summary><span class=\"interp-lead\">${s.label}</span> ${chevron()} ${s.aside ? html`<span class=\"interp-aside\"><small>${s.aside}</small></span>` : nothing}</summary><div class=\"interp-body\"><p>${s.body}</p>${s.extra ?? nothing}</div></details>`,\n\t\t)}</section>`;\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';\nimport {\n\trenderTablist,\n\ttype TablistItem,\n\ttablistStyles,\n} from '../utils/tablist.js';\n\ntype Tab = 'sarva' | 'bhinna' | 'reduced' | 'pinda';\n\nconst TABS: ReadonlyArray<TablistItem<Tab>> = [\n\t{ id: 'sarva', label: 'Sarvashtakavarga' },\n\t{ id: 'bhinna', label: 'Bhinnashtakavarga' },\n\t{ id: 'reduced', label: 'Reduced' },\n\t{ id: 'pinda', label: 'Shodhya Pinda' },\n];\n\ntype Signs = AshtakavargaResponse['signs'];\ntype BhinnaRow = AshtakavargaResponse['bhinnashtakavarga'][number];\ntype SarvaRow = AshtakavargaResponse['sarvashtakavarga'];\n\n/**\n * Ashtakavarga grid: Sarvashtakavarga, Bhinnashtakavarga, the Shodhana-reduced\n * grid, and Shodhya Pinda. Pass `data` from /vedic-astrology/ashtakavarga.\n *\n * @remarks\n * Bindus are benefic points, so MORE is better in every view here. The colour\n * ramp is therefore diverging, not a single hot hue: a weak count tints toward\n * --roxy-heat (which resolves to the danger token), the classical average stays\n * neutral, a strong count tints toward --roxy-success, and each tab states its\n * own scale in a legend. The previous single-hue ramp painted the best signs the\n * most alarming shade, the exact opposite of what the numbers mean.\n */\n@customElement('roxy-ashtakavarga-grid')\nexport class RoxyAshtakavargaGrid extends RoxyDataElement<AshtakavargaResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\ttablistStyles,\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);grid-template-columns:minmax(0,1fr);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}.overflow-scroll{-webkit-overflow-scrolling:touch;min-width:0;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}.bindu-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)}.tier-1{background:color-mix(in srgb, var(--roxy-heat,#ef4444) 30%, transparent)}.tier-2{background:color-mix(in srgb, var(--roxy-heat,#ef4444) 17%, transparent)}.tier-3{background:color-mix(in srgb, var(--roxy-heat,#ef4444) 7%, transparent)}.tier-4{background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 45%, transparent)}.tier-5{background:color-mix(in srgb, var(--roxy-success,#16a34a) 16%, transparent)}.tier-6{background:color-mix(in srgb, var(--roxy-success,#16a34a) 32%, transparent)}.tier-7{background:color-mix(in srgb, var(--roxy-success,#16a34a) 50%, transparent)}.legend{align-items:center;gap:var(--roxy-space-xs,.25rem) var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);flex-wrap:wrap;display:flex}.legend-scale{gap:2px;display:flex}.legend-swatch{border-radius:2px;width:16px;height:10px}.legend-note{flex:12rem}.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}.bindu-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>${renderTablist({\n\t\t\t\titems: TABS,\n\t\t\t\tactive: this.activeTab,\n\t\t\t\tonSelect: (id) => {\n\t\t\t\t\tthis.activeTab = id;\n\t\t\t\t},\n\t\t\t\tlabel: 'Ashtakavarga views',\n\t\t\t\tidPrefix: 'ashtakavarga',\n\t\t\t\tcontrols: true,\n\t\t\t})}<div id=\"ashtakavarga-panel-${this.activeTab}\" role=\"tabpanel\" aria-labelledby=\"ashtakavarga-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.activeTab === 'reduced'\n\t\t\t\t\t\t\t\t? this.renderReduced(signs)\n\t\t\t\t\t\t\t\t: this.renderPinda()\n\t\t\t\t}</div></div>`;\n\t}\n\n\t/**\n\t * Bhinna bindus per planet per sign run 0..8 (one 0/1 contribution from each\n\t * of the 8 reference points). 4 is the mid, so it holds the neutral tier and\n\t * anything above it reads as support. The reduced grid uses the same 0..8\n\t * units, so it shares this scale.\n\t */\n\tprivate bhinnaTier(count: number): string {\n\t\tif (count <= 1) return 'tier-1';\n\t\tif (count <= 2) return 'tier-2';\n\t\tif (count <= 3) return 'tier-3';\n\t\tif (count <= 4) return 'tier-4';\n\t\tif (count <= 5) return 'tier-5';\n\t\tif (count <= 6) return 'tier-6';\n\t\treturn 'tier-7';\n\t}\n\n\t/**\n\t * Sarva bindus per sign are the column total across the 7 planets. The grand\n\t * total is always 337, so the classical average is 337/12 = 28.08 and the\n\t * bands used by readers are: under 25 weak, 25 to 29 average, 30 and above\n\t * strong, with the highest signs carrying transits best. The tiers follow\n\t * those bands rather than an even split, so 28 sits on the neutral tier.\n\t */\n\tprivate sarvaTier(count: number): string {\n\t\tif (count <= 20) return 'tier-1';\n\t\tif (count <= 24) return 'tier-2';\n\t\tif (count <= 27) return 'tier-3';\n\t\tif (count <= 29) return 'tier-4';\n\t\tif (count <= 32) return 'tier-5';\n\t\tif (count <= 36) return 'tier-6';\n\t\treturn 'tier-7';\n\t}\n\n\t/**\n\t * The scale, stated. Without this a reader has to guess whether a saturated\n\t * cell is good or bad, and in a bindu grid the answer is always \"good\".\n\t */\n\tprivate renderLegend(note: string) {\n\t\treturn html`<div class=\"legend\"><span>Fewer bindus</span> <span class=\"legend-scale\" aria-hidden=\"true\">${[1, 2, 3, 4, 5, 6, 7].map(\n\t\t\t\t\t(t) => html`<span class=\"legend-swatch tier-${t}\"></span>`,\n\t\t\t\t)} </span><span>More bindus</span> <span class=\"legend-note\">${note}</span></div>`;\n\t}\n\n\tprivate renderSarva(signs: 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><caption class=\"roxy-sr-only\">Sarvashtakavarga: each of the twelve signs and the bindus all planets contribute to it, with a grand total.</caption><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\t\tconst count = sav.bindus[i] ?? 0;\n\t\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=\"${`bindu-cell ${this.sarvaTier(count)}`}\">${count}</td></tr>`;\n\t\t\t\t\t\t})}</tbody><tfoot><tr class=\"total-row\"><td>Total</td><td>${sav.total}</td></tr></tfoot></table></div>${this.renderLegend(\n\t\t\t\t'Under 25 is a weak sign, 25 to 29 average, 30 and above strong. The 12 signs always total 337.',\n\t\t\t)}`;\n\t}\n\n\tprivate renderBhinna(signs: 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`${this.renderBinduGrid(\n\t\t\tsigns,\n\t\t\tbhinna,\n\t\t\t'Bhinnashtakavarga: the bindus each planet scores in every one of the twelve signs, with a row total.',\n\t\t)} ${this.renderLegend(\n\t\t\t'Each planet scores 0 to 8 bindus per sign. 4 is the mid, 5 and above is strong support for that planet in that sign.',\n\t\t)}`;\n\t}\n\n\t/**\n\t * The Shodhana-purified grid (Trikona then Ekadipati), which is what Shodhya\n\t * Pinda is computed from. The column totals are the Reduced Sarvashtakavarga,\n\t * so they are shown as the total row rather than as a second table.\n\t */\n\tprivate renderReduced(signs: Signs) {\n\t\tconst reduced = this.data?.reducedBhinnashtakavarga;\n\t\tconst rsav = this.data?.reducedSarvashtakavarga;\n\t\tif (!reduced?.length && !rsav)\n\t\t\treturn html`<p class=\"roxy-empty\">No reduced ashtakavarga data</p>`;\n\n\t\treturn html`${this.renderBinduGrid(\n\t\t\tsigns,\n\t\t\treduced ?? [],\n\t\t\t'Reduced Bhinnashtakavarga after Shodhana: the bindus each planet keeps in every one of the twelve signs, with a row total and a Reduced Sarvashtakavarga totals row.',\n\t\t\trsav,\n\t\t)} ${this.renderLegend(\n\t\t\t'Bindus left after Trikona and Ekadipati Shodhana, the input to Shodhya Pinda. The Reduced SAV row totals the seven planets only, so it does not include the Lagna row above it.',\n\t\t)}`;\n\t}\n\n\t/**\n\t * The planet-by-sign grid both the bhinna and the reduced tabs draw. The rows\n\t * are the 7 planets plus Lagna, but a Sarva total counts the 7 planets only\n\t * (which is why the classical SAV grand total is 337), so the totals row is\n\t * named for what it is rather than left to read as a column sum.\n\t */\n\tprivate renderBinduGrid(\n\t\tsigns: Signs,\n\t\trows: BhinnaRow[],\n\t\tcaption: string,\n\t\ttotals?: SarvaRow,\n\t) {\n\t\tif (!rows.length) return html`<p class=\"roxy-empty\">No bindu data</p>`;\n\t\treturn html`<div class=\"overflow-scroll\"><table class=\"bhinna-table\"><caption class=\"roxy-sr-only\">${caption}</caption><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>${rows.map(\n\t\t\t\t\t\t(row) => html`<tr><td>${row.planet}</td>${row.bindus.map(\n\t\t\t\t\t\t\t(count) =>\n\t\t\t\t\t\t\t\thtml`<td class=\"${`bindu-cell ${this.bhinnaTier(count)}`}\">${count}</td>`,\n\t\t\t\t\t\t)}<td>${row.total}</td></tr>`,\n\t\t\t\t\t)}</tbody>${\n\t\t\t\t\ttotals\n\t\t\t\t\t\t? html`<tfoot><tr class=\"total-row\"><td>Reduced SAV</td>${signs.map((_, i) => html`<td>${totals.bindus[i] ?? 0}</td>`)}<td>${totals.total}</td></tr></tfoot>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</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><caption class=\"roxy-sr-only\">Shodhya Pinda: each planet with its Rashi Pinda, Graha Pinda and Shodhya Pinda strength scores.</caption><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 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);scrollbar-width:thin;gap:2px;min-width:0;display:flex;overflow-x:auto}.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;flex-shrink:0;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, 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, normalizeAspect } from '../utils/format.js';\nimport { interpAccordionStyles } from '../utils/interp-accordion.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, apex first.\n */\ntype AspectsData =\n\t| CalculateAspectsResponse\n\t| CalculateTransitAspectsResponse\n\t| DetectAspectPatternsResponse;\n\ntype PatternEntry = NonNullable<\n\tDetectAspectPatternsResponse['patterns']\n>[number];\n\n/**\n * Round a 0-100 score for display.\n *\n * @remarks\n * Not `formatNumber(v, 0)`: that helper strips trailing zeros from the formatted string, so a strength of 100 renders as \"1\" and 90 as \"9\". Kept local until `utils/format.ts` is fixed.\n */\nfunction score(v: unknown): string {\n\treturn typeof v === 'number' && Number.isFinite(v)\n\t\t? String(Math.round(v))\n\t\t: '';\n}\n\n/**\n * One line naming the orb budget and the body set a pattern run used, so a reader can reproduce the detection. Built as a string, not a template: interpolating the clauses in markup leaves a space before the comma.\n */\nfunction provenance(o: NonNullable<DetectAspectPatternsResponse['options']>) {\n\tconst orbs = o.strictOrbs ? 'strict' : 'industry-standard';\n\tconst bodies = o.include?.length\n\t\t? `including ${o.include.join(' and ')}`\n\t\t: 'classical bodies only';\n\treturn `Detected with ${orbs} orbs, ${bodies}.`;\n}\n\n/** Reading order for detected configurations: the rare, chart-defining figures first, then by tightness. Mirrors `roxy-natal-chart`, which renders the same `patterns` shape. */\nconst PATTERN_ORDER: Record<string, number> = {\n\tGRAND_CROSS: 0,\n\tGRAND_TRINE: 1,\n\tKITE: 2,\n\tT_SQUARE: 3,\n\tYOD: 4,\n\tMYSTIC_RECTANGLE: 5,\n\tSTELLIUM: 6,\n};\n\n@customElement('roxy-aspects-table')\nexport class RoxyAspectsTable extends RoxyDataElement<AspectsData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tdisclosureStyles,\n\t\tinterpAccordionStyles,\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}.interp-card summary{flex-wrap:wrap;gap:.5em}.interp-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}.static-head{font-size:var(--roxy-text-sm,.875rem);flex-wrap:wrap;align-items:center;gap:.5em;font-weight:500;display:flex}.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-tag{border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 55%, transparent);color:var(--roxy-fg,#0a0a0a);text-transform:capitalize;padding:1px 8px}.pattern-planets{flex-wrap:wrap;gap:.25rem;display:flex}.planet-chip{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);align-items:baseline;gap:.3rem;padding:1px 8px;display:inline-flex}.planet-chip.apex{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 20%, transparent);font-weight:var(--roxy-weight-bold,600)}.planet-chip .apex-tag{text-transform:uppercase;letter-spacing:.04em;font-size:.85em;font-weight:400}.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}.strongest{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);font-size:var(--roxy-text-sm,.875rem);flex-wrap:wrap;align-items:baseline;gap:.4rem;display:flex}.strongest .label{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);text-transform:uppercase;letter-spacing:.06em;font-weight:var(--roxy-weight-bold,600)}.strongest .meta{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);font-variant-numeric:tabular-nums;margin-left:auto}.provenance{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);margin:0}`,\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\t// Natal aspects date the chart, transits date the sky.\n\t\tconst date = 'transitDate' in d ? d.transitDate : 'date' in d ? d.date : '';\n\t\tconst options = 'options' in d ? d.options : undefined;\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Aspects\"><div class=\"head\"><h2 class=\"title\">${aspects.length === 0 ? 'Aspect patterns' : 'Aspects'}</h2>${\n\t\t\t\t\taspects.length > 0 || date\n\t\t\t\t\t\t? html`<p class=\"subtitle\">${[\n\t\t\t\t\t\t\t\taspects.length > 0\n\t\t\t\t\t\t\t\t\t? `${aspects.length} aspect${aspects.length === 1 ? '' : 's'}`\n\t\t\t\t\t\t\t\t\t: '',\n\t\t\t\t\t\t\t\tdate,\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t.join(' \u00B7 ')}</p>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</div>${summary ? this.renderSummary(summary) : nothing} ${summary && 'strongest' in summary && summary.strongest ? this.renderStrongest(summary.strongest) : 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]\n\t\t\t\t\t\t\t.sort(\n\t\t\t\t\t\t\t\t(a, b) =>\n\t\t\t\t\t\t\t\t\t(PATTERN_ORDER[a.kind] ?? 9) - (PATTERN_ORDER[b.kind] ?? 9) ||\n\t\t\t\t\t\t\t\t\t(b.tightness ?? 0) - (a.tightness ?? 0),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.map((p) => this.renderPattern(p))}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${options ? html`<p class=\"provenance\">${provenance(options)}</p>` : nothing}</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\t// byType is a map, not a list: render the pairs, never the object.\n\t\tconst byType = Object.entries(s.byType ?? {}).sort((a, b) => b[1] - a[1]);\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> ${byType.map(\n\t\t\t\t([type, count]) =>\n\t\t\t\t\thtml`<span class=\"pill pill--muted\">${capitalize(type.replace(/_/g, ' '))}: ${count}</span>`,\n\t\t\t)}</div>`;\n\t}\n\n\t/**\n\t * The tightest transit by orb: the one aspect the client is most likely to\n\t * feel today. Lifted out of the list so it is not buried among the rest.\n\t */\n\tprivate renderStrongest(\n\t\ts: NonNullable<\n\t\t\tNonNullable<CalculateTransitAspectsResponse['summary']>['strongest']\n\t\t>,\n\t) {\n\t\tconst g1 = PLANET_GLYPH[capitalize(s.planet1)] ?? '';\n\t\tconst g2 = PLANET_GLYPH[capitalize(s.planet2)] ?? '';\n\t\tconst nature = (s.interpretation ?? 'neutral').toLowerCase();\n\t\treturn html`<div class=\"strongest\"><span class=\"label\">Strongest</span> <span aria-hidden=\"true\" class=\"glyph\">${g1}</span>${s.planet1} <span class=\"nature-badge ${nature}\">${normalizeAspect(s)}</span> <span aria-hidden=\"true\" class=\"glyph\">${g2}</span>${s.planet2} <span class=\"meta\">${s.isApplying ? 'Applying' : 'Separating'} \u00B7 orb ${formatNumber(s.orb, 2)}\u00B0 \u00B7 str ${score(s.strength)}</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 ${score(a.strength)}</span>`;\n\t\tif (!hasBody) {\n\t\t\treturn html`<div class=\"interp-card\" role=\"listitem\"><div class=\"static-head\">${header}</div></div>`;\n\t\t}\n\t\treturn html`<details class=\"interp-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\t/**\n\t * One detected configuration. The apex (the focal planet a Kite, T-Square, or Yod discharges through) leads the chip row and is called out, since a T-Square read without its apex is not a reading. `element` and `modality` only appear on the kinds whose meaning pivots on them, so they are tags rather than columns.\n\t */\n\tprivate renderPattern(p: PatternEntry) {\n\t\tconst planets = p.planets ?? [];\n\t\tconst ordered = p.apex\n\t\t\t? [...planets].sort((a, b) => Number(b === p.apex) - Number(a === p.apex))\n\t\t\t: planets;\n\t\treturn html`<div class=\"pattern\"><div class=\"pattern-head\"><span class=\"pattern-name\">${p.name ?? p.kind ?? 'Pattern'}</span> ${p.element ? html`<span class=\"pattern-tag\">${p.element}</span>` : nothing} ${p.modality ? html`<span class=\"pattern-tag\">${p.modality}</span>` : nothing} ${\n\t\t\t\t\tp.dissociate\n\t\t\t\t\t\t? html`<span class=\"pattern-tag\" title=\"Out of sign: one or more planets sit outside the pattern element or modality, so the theme holds but runs weaker.\">Dissociate</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} ${typeof p.tightness === 'number' ? html`<span class=\"pattern-tight\">${Math.round(p.tightness)}% tight</span>` : nothing}</div>${\n\t\t\t\tordered.length\n\t\t\t\t\t? html`<div class=\"pattern-planets\">${ordered.map((name) => {\n\t\t\t\t\t\t\tconst glyph = PLANET_GLYPH[capitalize(name)];\n\t\t\t\t\t\t\tconst isApex = Boolean(p.apex) && name === p.apex;\n\t\t\t\t\t\t\treturn html`<span class=\"${isApex ? 'planet-chip apex' : 'planet-chip'}\">${glyph ? html`<span aria-hidden=\"true\">${glyph}</span>` : nothing}${name}${isApex ? html`<span class=\"apex-tag\">apex</span>` : nothing}</span>`;\n\t\t\t\t\t\t})}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${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", "/**\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\nconst DATE_ONLY = /^\\d{4}-\\d{2}-\\d{2}$/;\nconst BARE_TIME = /^\\d{2}:\\d{2}(:\\d{2})?$/;\n/** An ISO datetime with NO timezone designator: a wall clock, not an instant. */\nconst NAIVE_DATETIME = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(:\\d{2}(\\.\\d+)?)?$/;\n\n/**\n * Resolve an API timestamp to a Date plus the timezone it must be RENDERED in.\n *\n * @remarks\n * The API returns chart times naive (`2026-07-13T04:36:00`): that is 04:36 in the CHART's timezone, not UTC and not the viewer's. A wall clock must read the same for every viewer on earth, so hora at sunrise says 04:36 in Tokyo and in Chicago alike.\n *\n * Handing a naive string to `new Date()` makes the runtime interpret it in the VIEWER's zone, which is a silent corruption whenever that wall clock lands in the viewer's DST gap. In America/New_York `2026-03-08T02:30:00` does not exist, so the clock jumps and it renders as `3:30 AM`. Pinning the wall clock to UTC, which has no DST and therefore no gap, preserves the digits exactly while Intl still applies the viewer's locale conventions.\n *\n * An offset-bearing timestamp (`...Z`, `...+05:30`) IS a real instant, so it keeps the normal behaviour and converts to the viewer's local time.\n */\nfunction resolve(input: string): { d: Date; timeZone?: string } {\n\tconst naive = BARE_TIME.test(input)\n\t\t? `1970-01-01T${input}`\n\t\t: NAIVE_DATETIME.test(input)\n\t\t\t? input\n\t\t\t: null;\n\treturn naive\n\t\t? { d: new Date(`${naive}Z`), timeZone: 'UTC' }\n\t\t: { d: new Date(input) };\n}\n\nexport function formatTime(input: unknown): string {\n\tif (typeof input !== 'string' || input.length === 0) return '';\n\tif (DATE_ONLY.test(input)) return '';\n\tconst { d, timeZone } = resolve(input);\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\ttimeZone,\n\t});\n}\n\nexport function formatDate(input: unknown): string {\n\tif (typeof input !== 'string' || input.length === 0) return '';\n\tconst { d, timeZone } = resolve(\n\t\tDATE_ONLY.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\ttimeZone,\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\n/**\n * Format a number, dropping trailing zeros in the FRACTIONAL part only: `2.50` becomes `2.5`, `2.0` becomes `2`, and `100` stays `100`.\n *\n * @remarks\n * The old implementation ran `.replace(/\\.?0+$/, '')` against the whole string, which happily ate zeros off the INTEGER when there was no decimal point. At `dp = 0` that meant `100` rendered as `1`, `90` as `9`, `20` as `2`, and `0` as the empty string. It shipped: a 100 percent tight stellium displayed as \"1% tight\", and an aspect of strength 100 as \"str 1\". Guard on the decimal point, and never strip from the integer side.\n *\n * @example\n * ```ts\n * formatNumber(100, 0); // '100'\n * formatNumber(2.5, 1); // '2.5'\n * formatNumber(2, 1); // '2'\n * formatNumber(0, 0); // '0'\n * ```\n */\nexport function formatNumber(value: unknown, dp = 1): string {\n\tif (typeof value !== 'number' || !Number.isFinite(value)) return '';\n\tconst fixed = value.toFixed(dp);\n\treturn fixed.includes('.') ? fixed.replace(/\\.?0+$/, '') : fixed;\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 { interpAccordionStyles } from '../utils/interp-accordion.js';\nimport { planetColor } from '../utils/planet-color.js';\nimport { WORLD_LAND_PATH } from '../utils/world-map.js';\n\ntype LineSet = AstrocartographyResponse['lines'][number];\ntype GeoPoint = LineSet['ascendant']['points'][number];\n\n// Equirectangular (plate carree) projection in a 360x180 unit canvas: one unit\n// per degree. The SVG scales to the container width; the 2:1 aspect ratio holds.\nconst W = 360;\nconst H = 180;\nconst lonToX = (lon: number): number => lon + 180;\nconst latToY = (lat: number): number => 90 - lat;\n\n// Reference parallels (degrees). Tropics and polar circles use the current mean\n// obliquity; drawn as dashed guides so the curved rising/setting lines read\n// against real climate bands, not just a bare grid.\nconst TROPIC = 23.44;\nconst POLAR = 66.56;\n\nconst formatLon = (lon: number): string =>\n\tlon === 0 ? '0' : `${Math.abs(lon)}\u00B0${lon > 0 ? 'E' : 'W'}`;\nconst formatLat = (lat: number): string =>\n\tlat === 0 ? '0' : `${Math.abs(lat)}\u00B0${lat > 0 ? 'N' : 'S'}`;\n\n/**\n * Split a rising/setting line into screen polylines, breaking the path wherever\n * consecutive samples jump more than 180 degrees of longitude. Without the\n * split, a line that crosses the antimeridian draws a stray horizontal streak\n * straight across the whole map.\n */\nfunction toSegments(points: GeoPoint[]): string[] {\n\tconst segments: string[][] = [];\n\tlet current: string[] = [];\n\tlet prevLon: number | null = null;\n\tfor (const p of points) {\n\t\tif (prevLon !== null && Math.abs(p.longitude - prevLon) > 180) {\n\t\t\tif (current.length) segments.push(current);\n\t\t\tcurrent = [];\n\t\t}\n\t\tcurrent.push(`${lonToX(p.longitude)},${latToY(p.latitude)}`);\n\t\tprevLon = p.longitude;\n\t}\n\tif (current.length) segments.push(current);\n\treturn segments.filter((s) => s.length > 1).map((s) => s.join(' '));\n}\n\nconst ANGLE_LABEL: Record<string, string> = {\n\tmc: 'MC',\n\tic: 'IC',\n\tascendant: 'AC',\n\tdescendant: 'DC',\n};\n\n/**\n * Astrocartography (relocation) world map. Plots the four planetary lines for\n * every body from a /astrology/astrocartography response over a labeled\n * graticule: MC and IC as straight meridians, the Ascendant and Descendant as\n * latitude-sampled curves. Color is per body and theme-token driven; solid\n * lines are the Ascendant and Midheaven, dashed are the Descendant and IC.\n */\n@customElement('roxy-astrocartography-map')\nexport class RoxyAstrocartographyMap extends RoxyDataElement<AstrocartographyResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tdisclosureStyles,\n\t\tinterpAccordionStyles,\n\t\tcss`.wrap{background:var(--roxy-surface,#fff);width:100%;color:var(--roxy-fg,#0a0a0a);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);gap:var(--roxy-space-md,1rem);display:grid}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-primary,#0f172a);margin:0}.meta{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-sm,.875rem)}svg{border-radius:var(--roxy-radius-sm,4px);width:100%;height:auto;display:block}.map-frame{fill:color-mix(in srgb, var(--roxy-border,#e4e4e7) 12%, transparent);stroke:var(--roxy-border,#e4e4e7);stroke-width:.8px}.land{fill:var(--roxy-secondary,#475569);opacity:.13}.grat{stroke:var(--roxy-border,#e4e4e7);stroke-width:.4px;fill:none}.grat-axis{stroke:var(--roxy-muted,#71717a);stroke-width:.6px;opacity:.6}.grat-ref{stroke:var(--roxy-secondary,#475569);stroke-width:.4px;stroke-dasharray:2 2;opacity:.5;fill:none}.axis-label{fill:var(--roxy-muted,#71717a);font-size:5px;font-family:var(--roxy-font-sans)}.acg-line{fill:none;stroke-width:1px;opacity:.95}.acg-line.dashed{stroke-dasharray:4 2.5}.acg-glyph{font-size:8px;font-family:var(--roxy-font-sans);font-weight:600}.birthplace{fill:var(--roxy-fg,#0a0a0a);font-size:9px}.legend{gap:var(--roxy-space-xs,.25rem) var(--roxy-space-md,1rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);flex-wrap:wrap;display:flex}.legend-item{align-items:center;gap:.3rem;display:inline-flex}.legend-swatch{border-top-style:solid;border-top-width:2px;width:14px;height:0}.legend-note{width:100%;color:var(--roxy-muted,#71717a)}.summary{color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);margin:0}.interp-dot{border-radius:50%;flex-shrink:0;align-self:center;width:10px;height:10px}.interp-line{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);margin:0}.interp-line .code{color:var(--roxy-accent-ink,#b45309);margin-right:.4rem;font-weight:600}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No astrocartography data</div>`;\n\t}\n\n\tprotected renderData(data: AstrocartographyResponse) {\n\t\tconst lines = data.lines ?? [];\n\t\tconst bd = data.birthDetails;\n\t\treturn html`<div class=\"wrap\"><header><h2 class=\"title\">Astrocartography</h2>${\n\t\t\t\t\tbd\n\t\t\t\t\t\t? html`<div class=\"meta\">${[bd.date, bd.time].filter(Boolean).join(' \u00B7 ')} \u00B7 ${formatLat(Math.round(bd.latitude))} ${formatLon(Math.round(bd.longitude))}</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</header>${this.renderMap(lines, bd)} ${this.renderLegend(lines)} ${data.summary ? html`<p class=\"summary\">${data.summary}</p>` : nothing} ${this.renderInterpretations(lines)}</div>`;\n\t}\n\n\tprivate renderMap(\n\t\tlines: LineSet[],\n\t\tbd: AstrocartographyResponse['birthDetails'],\n\t) {\n\t\treturn html`<svg viewBox=\"0 0 ${W} ${H}\" role=\"img\" aria-label=\"World map of planetary astrocartography lines\"><title>Astrocartography world map</title><desc>Equirectangular world map. Each body has a Midheaven and Imum Coeli meridian and a curved Ascendant and Descendant line, colored per body.</desc><rect class=\"map-frame\" x=\"0\" y=\"0\" width=\"${W}\" height=\"${H}\"/><path class=\"land\" d=\"${WORLD_LAND_PATH}\" fill-rule=\"evenodd\"/>${this.renderGraticule()} ${lines.map((l, i) => this.renderBodyLines(l, i))} ${\n\t\t\t\tbd\n\t\t\t\t\t? svg`<text class=\"birthplace\" x=${lonToX(bd.longitude)} y=${latToY(bd.latitude)} text-anchor=\"middle\" dominant-baseline=\"central\"><title>Birthplace</title>\u2605</text>`\n\t\t\t\t\t: nothing\n\t\t\t}</svg>`;\n\t}\n\n\tprivate renderGraticule() {\n\t\tconst meridians = [];\n\t\tfor (let lon = -150; lon <= 150; lon += 30) {\n\t\t\tconst x = lonToX(lon);\n\t\t\tconst axis = lon === 0;\n\t\t\tmeridians.push(\n\t\t\t\tsvg`<line class=${axis ? 'grat-axis' : 'grat'} x1=${x} y1=\"0\" x2=${x} y2=${H} />`,\n\t\t\t);\n\t\t\tmeridians.push(\n\t\t\t\tsvg`<text class=\"axis-label\" x=${x} y=${H - 2} text-anchor=\"middle\">${formatLon(lon)}</text>`,\n\t\t\t);\n\t\t}\n\t\tconst parallels = [];\n\t\tfor (let lat = -60; lat <= 60; lat += 30) {\n\t\t\tconst y = latToY(lat);\n\t\t\tconst axis = lat === 0;\n\t\t\tparallels.push(\n\t\t\t\tsvg`<line class=${axis ? 'grat-axis' : 'grat'} x1=\"0\" y1=${y} x2=${W} y2=${y} />`,\n\t\t\t);\n\t\t\tparallels.push(\n\t\t\t\tsvg`<text class=\"axis-label\" x=\"2\" y=${y - 1}>${formatLat(lat)}</text>`,\n\t\t\t);\n\t\t}\n\t\t// Tropics and polar circles as dashed climate-band references.\n\t\tconst refs = [TROPIC, -TROPIC, POLAR, -POLAR].map(\n\t\t\t(lat) =>\n\t\t\t\tsvg`<line class=\"grat-ref\" x1=\"0\" y1=${latToY(lat)} x2=${W} y2=${latToY(lat)} />`,\n\t\t);\n\t\treturn svg`${meridians}${parallels}${refs}`;\n\t}\n\n\tprivate renderBodyLines(line: LineSet, index: number) {\n\t\tconst color = planetColor(line.planet, index);\n\t\tconst glyph = line.symbol || line.planet.slice(0, 2);\n\t\tconst items = [\n\t\t\tthis.renderMeridian(\n\t\t\t\tline.mc.longitude,\n\t\t\t\tcolor,\n\t\t\t\tglyph,\n\t\t\t\tline.planet,\n\t\t\t\t'mc',\n\t\t\t\tfalse,\n\t\t\t),\n\t\t\tthis.renderMeridian(\n\t\t\t\tline.ic.longitude,\n\t\t\t\tcolor,\n\t\t\t\tglyph,\n\t\t\t\tline.planet,\n\t\t\t\t'ic',\n\t\t\t\ttrue,\n\t\t\t),\n\t\t\tthis.renderCurve(\n\t\t\t\tline.ascendant.points,\n\t\t\t\tcolor,\n\t\t\t\tglyph,\n\t\t\t\tline.planet,\n\t\t\t\t'ascendant',\n\t\t\t\tfalse,\n\t\t\t),\n\t\t\tthis.renderCurve(\n\t\t\t\tline.descendant.points,\n\t\t\t\tcolor,\n\t\t\t\tglyph,\n\t\t\t\tline.planet,\n\t\t\t\t'descendant',\n\t\t\t\ttrue,\n\t\t\t),\n\t\t];\n\t\treturn svg`${items}`;\n\t}\n\n\tprivate renderMeridian(\n\t\tlon: number,\n\t\tcolor: string,\n\t\tglyph: string,\n\t\tplanet: string,\n\t\tangle: string,\n\t\tdashed: boolean,\n\t) {\n\t\tconst x = lonToX(lon);\n\t\t// MC label rides the top edge, IC the bottom, so the two meridians of one\n\t\t// body never stack their glyphs at the same point.\n\t\tconst labelY = angle === 'ic' ? H - 7 : 9;\n\t\treturn svg`<g>\n\t\t\t<line class=${`acg-line${dashed ? ' dashed' : ''}`} stroke=${color} x1=${x} y1=\"0\" x2=${x} y2=${H}><title>${planet} ${ANGLE_LABEL[angle]} line</title></line>\n\t\t\t<text class=\"acg-glyph\" fill=${color} x=${x} y=${labelY} text-anchor=\"middle\" dominant-baseline=\"central\">${glyph}</text>\n\t\t</g>`;\n\t}\n\n\tprivate renderCurve(\n\t\tpoints: GeoPoint[],\n\t\tcolor: string,\n\t\tglyph: string,\n\t\tplanet: string,\n\t\tangle: string,\n\t\tdashed: boolean,\n\t) {\n\t\tconst segments = toSegments(points ?? []);\n\t\tif (segments.length === 0) return nothing;\n\t\t// Label at the sample nearest the equator, the most visible band.\n\t\tconst anchor = (points ?? []).reduce(\n\t\t\t(best, p) => (Math.abs(p.latitude) < Math.abs(best.latitude) ? p : best),\n\t\t\tpoints[0] ?? { latitude: 0, longitude: 0 },\n\t\t);\n\t\treturn svg`<g>\n\t\t\t${segments.map(\n\t\t\t\t(pts) =>\n\t\t\t\t\tsvg`<polyline class=${`acg-line${dashed ? ' dashed' : ''}`} stroke=${color} points=${pts}><title>${planet} ${ANGLE_LABEL[angle]} line</title></polyline>`,\n\t\t\t)}\n\t\t\t<text class=\"acg-glyph\" fill=${color} x=${lonToX(anchor.longitude)} y=${latToY(anchor.latitude)} text-anchor=\"middle\" dominant-baseline=\"central\">${glyph}</text>\n\t\t</g>`;\n\t}\n\n\tprivate renderLegend(lines: LineSet[]) {\n\t\tif (lines.length === 0) return nothing;\n\t\treturn html`<div class=\"legend\">${lines.map((l, i) => {\n\t\t\t\tconst color = planetColor(l.planet, i);\n\t\t\t\treturn html`<span class=\"legend-item\"><span class=\"legend-swatch\" style=\"${`border-top-color: ${color}`}\"></span> ${l.symbol ? html`${l.symbol}` : nothing}${l.planet}</span>`;\n\t\t\t})} <span class=\"legend-note\">Solid lines are the Ascendant and Midheaven, dashed are the Descendant and IC.</span></div>`;\n\t}\n\n\tprivate renderInterpretations(lines: LineSet[]) {\n\t\tif (lines.length === 0) return nothing;\n\t\treturn html`<section class=\"block\"><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-lead\"><span class=\"interp-dot\" style=\"${`background: ${color}`}\"></span> ${l.symbol ? html`${l.symbol}` : nothing}${l.planet} </span>${chevron()}</summary><div class=\"interp-body\">${rows\n\t\t\t\t\t\t\t.filter(([, text]) => text)\n\t\t\t\t\t\t\t.map(\n\t\t\t\t\t\t\t\t([code, text]) =>\n\t\t\t\t\t\t\t\t\thtml`<p class=\"interp-line\"><span class=\"code\">${code}</span>${text}</p>`,\n\t\t\t\t\t\t\t)}</div></details>`;\n\t\t\t})}</section>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-astrocartography-map': RoxyAstrocartographyMap;\n\t}\n}\n", "import { capitalize } from './string.js';\n\n/**\n * Stable, theme-token stroke color per celestial body, for the multi-line map components (astrocartography, local space) where every body needs a distinct line that still follows the host theme.\n *\n * @remarks\n * Values are `var(--roxy-*)` references, so light and dark both resolve through the design tokens and a host override repaints every line with no rebuild. Classical bodies map to a fixed semantic token; any body the map omits (localized names, asteroids, the lunar nodes, Chiron, Lilith) falls back to a deterministic cycle keyed by its index in the response, so colors stay stable across re-renders and do not collide within the common 14-body set. Strokes and glyph fills are non-text chart marks, so the brighter base tokens are used directly rather than the WCAG-AA text variants.\n */\nconst PLANET_COLOR: Record<string, string> = {\n\tSun: 'var(--roxy-accent)',\n\tMoon: 'var(--roxy-secondary)',\n\tMercury: 'var(--roxy-info)',\n\tVenus: 'var(--roxy-success)',\n\tMars: 'var(--roxy-danger)',\n\tJupiter: 'var(--roxy-warning)',\n\tSaturn: 'var(--roxy-muted)',\n\tUranus: 'var(--roxy-info-fg)',\n\tNeptune: 'var(--roxy-success-fg)',\n\tPluto: 'var(--roxy-danger-fg)',\n};\n\n/** Deterministic fallback palette for bodies outside {@link PLANET_COLOR} (nodes, Chiron, Lilith, asteroids, or localized names). Keyed by response index so a given body keeps one color. */\nconst CYCLE = [\n\t'var(--roxy-accent)',\n\t'var(--roxy-info)',\n\t'var(--roxy-success)',\n\t'var(--roxy-danger)',\n\t'var(--roxy-warning)',\n\t'var(--roxy-secondary)',\n\t'var(--roxy-info-fg)',\n\t'var(--roxy-success-fg)',\n\t'var(--roxy-danger-fg)',\n\t'var(--roxy-accent-ink)',\n\t'var(--roxy-warning-fg)',\n\t'var(--roxy-primary)',\n];\n\n/** Theme-token color for a body, by name with an index fallback. {@link capitalize} matches the canonical TitleCase keys; unmapped or localized names cycle by `index`. */\nexport function planetColor(name: string, index = 0): string {\n\treturn (\n\t\tPLANET_COLOR[capitalize(name)] ??\n\t\tCYCLE[index % CYCLE.length] ??\n\t\t'var(--roxy-accent)'\n\t);\n}\n", "/**\n * Simplified Natural Earth 110m land outline (public domain, no attribution required) projected into the astrocartography 360x180 plate-carree space: x = lon + 180, y = 90 - lat. It therefore aligns pixel for pixel with the graticule and the planetary lines drawn in that same space, with no nested-SVG transform.\n *\n * @remarks\n * Integer-degree precision and a tiny-island cull keep it light (about 9 KB gzipped) so it ships inside the per-component bundle as a faint background fill; the colored lines stay the focus. Use `fill-rule: evenodd` so inland holes render. Regenerate from `ne_110m_land.geojson` if the projection or precision changes.\n */\nexport const WORLD_LAND_PATH =\n\t'M120 170L120 171L118 171L116 171L114 171L114 170L116 170L118 170L119 170L120 170ZM21 169L19 170L18 169L17 169L16 169L17 168L19 168L20 169L21 169ZM135 168L136 168L137 169L137 170L135 170L133 171L132 171L130 171L127 171L126 171L126 170L128 170L129 170L130 169L131 168L132 168L133 168L135 168ZM59 164L60 164L61 163L61 164L60 164L58 164L57 164L58 163L59 164ZM54 163L56 164L55 164L54 164L53 163L54 163ZM81 162L82 162L83 162L84 163L83 162L82 162L81 162L79 163L78 162L80 162L81 162ZM112 161L111 162L110 162L109 163L108 162L107 162L106 162L105 162L106 161L107 161L108 161L108 160L109 159L110 159L111 160L111 161L112 161ZM121 154L120 154L119 154L119 155L118 155L117 155L117 156L118 156L117 156L116 157L115 157L114 158L115 158L115 159L116 159L117 159L117 160L118 160L118 161L119 162L119 163L119 164L118 164L117 165L116 165L114 166L113 166L112 166L110 166L109 167L108 167L106 167L104 167L103 167L105 167L106 168L105 168L104 168L102 168L102 169L103 170L105 170L107 170L109 171L110 171L112 171L114 171L117 172L118 172L120 172L121 173L122 173L123 173L125 173L126 172L128 172L130 172L133 172L135 172L137 172L138 172L139 171L142 171L144 171L146 171L148 171L150 171L151 170L150 170L150 169L148 169L146 169L144 169L144 168L145 168L146 168L148 168L149 167L150 167L151 167L152 166L154 166L155 166L156 166L158 166L159 166L160 166L161 165L162 165L163 165L164 164L165 164L164 164L164 163L165 163L166 163L167 163L168 162L169 162L170 161L171 161L171 162L173 162L173 161L174 161L176 161L177 161L178 161L179 161L180 162L181 161L182 161L183 161L184 161L185 161L186 160L187 160L188 160L190 160L191 161L192 161L192 160L193 160L195 160L196 160L197 160L198 160L199 160L200 160L201 160L202 160L203 161L204 161L205 160L206 160L207 160L208 160L209 160L210 160L211 160L212 160L213 159L214 159L215 159L216 159L217 159L218 160L219 160L220 160L220 159L221 159L222 159L223 158L224 158L225 158L226 158L227 158L228 157L229 157L230 157L231 157L232 156L233 156L234 156L235 156L236 156L237 156L237 157L238 157L239 157L240 157L241 158L242 158L243 158L244 157L245 158L246 158L247 158L248 158L249 158L250 159L250 160L249 160L248 160L248 161L249 161L248 161L248 162L249 162L250 162L251 162L252 162L252 161L253 161L253 160L254 160L256 160L257 160L258 159L259 158L260 158L261 158L262 157L263 157L264 157L265 157L266 157L267 157L268 156L269 157L270 157L271 157L272 157L273 157L274 157L275 157L276 157L277 157L278 157L279 157L280 157L281 157L282 156L283 156L284 156L285 156L286 157L287 157L288 157L289 157L290 157L291 156L292 156L293 156L294 156L295 156L296 157L297 157L299 157L300 157L301 157L302 157L303 156L304 157L305 157L306 157L307 157L308 157L309 157L310 157L311 156L312 156L313 156L314 156L315 156L315 155L316 156L317 157L319 157L320 157L321 157L322 157L323 157L324 157L325 157L326 157L326 158L327 158L328 158L329 158L330 159L331 159L333 159L334 159L335 159L336 159L337 159L338 159L339 160L340 160L341 160L342 161L343 161L344 161L345 161L346 161L347 161L348 161L349 161L351 161L351 162L350 163L349 164L348 164L347 164L346 164L346 165L345 165L344 165L344 166L343 167L344 167L344 168L345 168L347 168L347 169L345 169L344 169L342 169L341 170L340 171L341 171L342 172L344 172L345 173L347 173L349 173L349 174L352 174L353 174L356 174L358 174L360 175L360 180L0 180L0 175L1 174L3 174L4 174L6 175L7 174L10 174L11 174L13 175L16 175L18 175L22 175L25 175L29 175L31 176L34 175L37 175L33 175L30 174L29 174L26 174L27 173L27 172L25 172L25 171L23 171L26 171L28 171L29 171L31 171L33 171L34 170L33 170L32 170L30 169L28 169L27 169L25 169L24 169L23 168L22 168L22 167L23 167L25 167L26 167L27 167L29 167L30 167L31 167L32 167L34 166L34 165L35 165L36 166L37 165L38 165L40 165L41 165L42 165L44 165L45 164L46 164L48 164L49 164L50 164L52 164L53 164L55 165L56 164L57 164L59 165L60 164L61 164L63 164L64 164L65 164L66 164L67 164L68 165L69 164L70 165L71 165L72 165L74 165L75 165L77 165L78 165L79 165L80 165L79 165L79 164L77 164L77 163L76 163L77 163L78 163L80 163L81 163L82 163L82 164L84 164L85 163L86 163L88 163L89 163L90 163L91 163L92 163L93 163L94 163L95 163L96 164L97 164L99 164L99 163L100 163L101 164L102 163L103 164L104 164L105 164L106 164L107 163L108 163L110 163L111 163L112 163L113 162L112 161L112 160L111 160L112 159L113 158L112 158L112 157L113 157L114 156L115 156L116 155L117 155L118 155L119 154L120 154L121 154L121 153L122 153L123 154L122 154L121 154ZM112 144L114 144L115 145L114 145L113 145L112 146L111 145L110 145L109 145L108 144L107 144L105 143L106 143L108 144L109 144L110 143L111 143L112 143L112 144ZM121 141L122 142L121 142L120 142L119 142L120 141L121 142L121 141ZM250 140L249 140L249 139L250 139L251 139L250 140ZM325 131L326 131L327 131L328 131L328 132L328 133L327 134L326 134L325 133L325 132L325 131ZM353 131L354 131L354 132L353 133L353 134L352 134L351 134L351 135L351 136L350 136L349 137L348 137L348 136L347 136L347 135L348 134L349 134L350 134L351 133L352 132L352 131L353 130L353 131ZM355 126L355 127L356 127L356 128L357 128L358 128L359 128L358 129L357 129L357 130L357 131L356 131L355 132L355 131L355 130L354 130L354 129L355 129L355 128L355 127L354 127L354 126L353 125L353 124L354 125L355 126ZM347 112L346 112L345 112L345 111L344 110L345 110L345 111L346 111L347 112ZM358 107L359 108L358 108L357 108L358 107L358 108L358 107ZM359 107L359 106L360 106L360 107L359 107ZM230 104L230 105L230 106L230 105L230 106L230 107L229 107L229 108L229 109L229 110L228 112L228 114L227 115L226 115L225 116L225 115L224 115L224 114L223 113L223 112L223 111L224 111L224 110L224 109L224 108L224 107L224 106L225 106L226 106L227 105L228 105L228 104L229 103L229 102L230 102L230 103L230 104ZM324 104L324 105L325 104L325 105L325 106L326 107L326 108L326 109L327 109L328 110L329 110L329 111L330 112L330 113L331 112L331 113L332 114L333 115L333 116L333 117L334 118L334 119L333 119L333 120L333 121L333 122L332 123L331 124L331 125L330 126L330 127L329 128L328 128L327 128L327 129L326 129L325 129L325 128L324 128L324 129L323 129L322 128L321 128L320 127L320 126L319 126L318 126L318 125L318 124L318 125L317 125L318 124L318 123L317 124L316 124L316 125L315 124L315 123L314 123L313 122L312 122L311 121L310 122L308 122L307 122L306 122L305 123L304 123L304 124L303 124L302 124L301 124L300 124L299 125L299 124L299 125L298 125L297 125L296 124L295 124L296 123L296 122L295 121L295 120L295 119L294 118L294 117L293 117L293 116L294 117L293 116L294 116L294 115L293 114L294 114L294 113L294 112L294 113L295 112L295 111L296 111L297 111L298 110L299 110L300 110L301 110L301 109L302 109L302 108L302 107L303 106L303 107L304 107L304 106L305 105L306 105L306 104L307 104L308 104L308 105L309 105L310 105L309 104L310 104L310 103L311 103L311 102L312 102L313 102L312 101L313 101L314 102L315 102L316 102L317 102L317 103L316 103L316 104L315 105L316 105L316 106L317 106L318 106L318 107L319 107L320 108L321 107L321 106L322 105L322 104L322 103L322 102L322 101L323 101L323 102L324 103L324 104ZM301 100L300 100L299 100L300 99L300 100L301 100ZM341 100L340 100L340 99L341 100ZM342 100L341 99L341 98L341 99L342 100ZM304 100L303 100L304 100L304 99L305 99L306 98L307 98L307 99L306 99L305 99L304 100ZM298 98L299 98L299 99L298 99L297 99L297 98L298 98ZM303 98L303 99L301 99L300 99L300 98L301 98L301 99L302 98L303 98ZM340 98L340 99L339 98L338 97L339 98L340 98ZM289 97L291 97L291 96L293 97L293 98L294 98L296 98L295 99L293 98L292 98L291 98L289 98L288 98L286 97L285 97L286 96L287 96L288 96L289 97ZM315 96L314 97L314 96L314 95L315 96ZM336 97L335 97L335 96L335 95L335 96L336 96L336 97ZM332 95L331 96L330 96L329 96L328 96L328 95L329 96L330 96L330 95L330 96L331 95L332 95L332 94L332 95ZM307 93L307 94L306 94L306 93L307 93ZM310 93L311 94L310 93L309 93L308 93L309 93L310 93ZM333 94L333 95L333 94L332 94L332 93L331 93L332 93L333 94ZM314 91L314 93L315 93L316 92L317 92L318 92L319 92L320 92L321 93L323 93L325 94L326 95L328 96L328 97L327 97L328 98L329 99L329 100L330 100L331 100L331 101L330 101L330 100L329 100L328 100L327 99L326 98L325 98L324 98L323 98L323 99L322 99L321 99L320 98L319 98L318 98L319 97L318 96L318 95L316 95L315 94L314 94L313 94L313 93L312 93L313 92L314 92L312 92L311 91L312 91L312 90L314 91ZM305 89L304 90L303 90L301 90L300 90L300 91L301 91L303 91L302 92L302 93L302 94L303 95L303 96L302 95L303 94L302 95L301 95L302 94L301 94L301 93L300 93L300 94L300 96L299 95L300 94L299 93L299 92L299 91L300 90L300 89L301 89L302 89L303 89L304 89L305 88L305 89ZM309 89L309 90L308 90L308 91L308 90L307 89L308 88L309 88L309 89ZM286 96L285 96L284 95L283 94L282 94L281 93L281 92L280 91L279 90L279 89L279 88L278 88L277 87L276 86L275 85L276 85L277 85L278 86L279 86L280 87L281 88L282 88L282 89L283 89L284 90L283 91L284 91L285 92L286 92L286 93L286 94L286 96ZM298 88L299 89L298 89L297 90L298 91L297 91L297 92L296 94L295 94L294 93L293 93L292 93L291 93L290 93L290 92L290 91L289 90L289 89L290 88L291 88L291 87L292 87L293 87L294 86L294 85L295 85L296 84L297 83L298 84L299 85L298 85L299 86L298 86L297 87L298 88ZM306 82L307 83L306 84L306 83L305 83L306 84L305 84L304 84L304 83L304 82L303 83L302 83L302 82L303 82L303 81L304 82L305 81L305 80L306 81L306 82ZM261 84L260 84L260 83L260 82L260 80L261 81L262 82L262 84L261 84ZM304 80L303 81L302 80L303 80L303 79L303 80L304 79L304 80ZM299 81L297 82L298 81L298 80L299 80L300 79L299 80L299 81ZM302 78L303 78L303 79L302 80L302 79L302 78ZM306 78L306 79L305 79L305 80L305 79L304 79L305 79L305 78L304 77L305 77L306 78ZM302 77L301 78L301 77L300 77L301 77L302 77ZM301 71L302 72L303 73L302 74L302 75L302 76L303 76L304 76L304 77L303 77L303 76L303 77L302 76L301 76L301 75L301 76L300 75L300 74L300 72L301 71ZM114 72L113 72L113 71L114 71L114 72ZM103 72L102 72L102 71L102 72L103 72L104 72L103 72ZM107 70L108 70L109 70L110 70L110 71L111 71L112 71L111 72L110 72L109 72L108 72L107 72L106 72L106 71L107 71L107 72L108 71L107 71L107 70ZM290 71L289 72L289 71L289 70L290 70L291 70L291 71L290 71ZM24 71L24 70L25 70L25 71L24 71ZM100 67L101 68L102 67L102 68L103 68L103 69L104 69L105 69L106 70L105 70L104 70L102 70L103 70L103 69L102 69L101 68L100 68L99 68L98 68L98 67L97 67L97 68L96 68L95 68L96 68L96 67L97 67L98 67L99 67L100 67ZM102 66L102 65L102 66ZM301 67L301 68L300 67L300 66L301 65L302 65L302 66L301 67ZM315 56L314 57L314 56L313 57L312 57L313 56L314 56L315 56ZM215 54L214 55L213 55L212 55L213 55L214 55L215 54ZM204 54L204 55L205 55L206 55L205 55L204 55L204 54ZM196 52L195 53L194 53L192 52L193 52L194 52L195 52L196 52ZM189 49L190 49L190 51L189 51L188 51L188 50L188 49L189 49ZM321 53L321 54L320 55L319 55L317 55L316 57L315 56L315 55L313 56L312 56L311 56L312 57L311 59L310 59L310 58L310 57L309 57L310 56L311 56L312 55L313 55L315 54L316 54L317 53L319 52L320 51L320 49L321 49L322 50L322 51L321 52L321 53ZM190 48L189 49L189 48L189 47L190 48ZM324 46L325 46L326 47L324 47L323 48L322 47L321 48L320 48L320 47L321 47L322 45L322 44L323 45L324 46ZM116 43L117 44L118 44L117 44L116 44L116 43ZM118 41L116 41L115 40L116 40L117 40L118 41ZM56 41L56 42L54 41L53 40L52 40L52 39L53 39L53 40L54 40L55 40L55 41L56 41ZM124 39L123 40L124 40L125 40L124 40L125 41L126 40L127 41L126 41L127 41L127 42L127 43L126 43L126 42L125 43L124 43L125 43L124 42L123 42L121 42L121 41L122 41L123 39L124 38L125 38L124 39ZM47 36L48 36L48 37L49 38L48 38L48 37L47 37L47 36ZM324 39L325 41L323 41L323 42L324 43L324 44L323 43L322 44L322 43L322 42L322 41L322 40L322 39L322 38L322 37L323 36L322 36L323 36L323 37L323 38L324 39ZM173 38L171 38L170 38L171 37L170 36L172 35L173 35L174 35L174 36L174 37L173 38ZM193 34L192 35L191 35L191 34L192 34L193 34ZM27 33L26 33L25 33L26 32L27 32L28 32L27 33ZM177 31L176 32L177 32L178 32L178 33L177 34L178 34L179 35L180 36L180 37L182 37L182 38L181 38L181 39L179 39L178 39L177 39L176 40L175 40L174 40L176 39L177 39L175 38L176 38L175 37L177 37L177 36L176 35L175 35L175 34L174 35L174 34L174 33L174 32L175 31L176 31L177 31ZM14 30L13 30L14 30ZM98 27L97 28L96 28L97 27L98 27ZM8 26L9 26L10 26L10 27L11 27L10 27L9 27L8 27L8 26ZM95 24L95 25L96 25L97 25L98 26L99 26L100 26L99 27L97 26L96 26L94 27L94 26L93 26L94 26L94 25L94 24L95 24ZM165 24L166 25L165 26L162 26L161 27L160 26L157 26L158 26L156 25L158 25L156 24L158 24L159 24L161 24L162 24L164 23L165 24ZM104 23L103 23L103 22L104 22L105 22L105 23L104 23ZM5 23L6 24L5 23L8 23L10 24L9 24L7 25L7 26L6 26L5 25L4 25L3 24L2 25L1 24L0 24L1 25L0 25L0 21L2 22L5 23ZM84 21L82 21L80 21L81 20L82 20L83 20L84 21ZM360 19L359 19L360 18L360 19ZM1 19L0 19L0 18L1 18L2 19L1 19ZM89 21L89 22L91 21L92 21L92 22L93 23L94 22L94 21L94 20L96 20L97 20L99 21L98 22L99 22L99 23L97 24L95 24L94 23L94 24L93 25L92 26L90 26L89 26L89 27L88 27L87 28L86 29L85 30L85 31L87 31L87 32L88 33L89 33L91 33L92 34L93 34L94 34L95 35L97 35L98 35L98 36L98 37L99 38L100 39L101 38L101 37L101 36L100 35L102 35L103 34L103 33L103 32L101 31L103 30L102 29L102 28L103 27L104 28L105 28L106 28L107 28L108 28L109 29L110 29L110 30L111 31L112 31L112 32L114 31L115 30L116 31L117 32L119 33L118 34L120 34L120 35L122 35L123 35L123 36L124 36L124 37L124 38L123 39L121 39L120 40L118 40L116 40L115 40L114 40L113 40L111 41L110 42L109 43L110 43L111 42L113 41L115 41L116 41L115 42L115 43L116 44L117 44L118 44L119 43L120 44L119 45L117 45L116 46L115 46L114 46L116 45L114 45L113 45L112 46L111 46L110 46L109 47L109 48L110 48L109 49L108 49L107 49L106 49L108 49L107 49L106 49L106 50L105 51L104 51L105 51L105 52L104 53L104 52L104 51L103 51L104 52L103 52L104 52L104 53L104 54L104 55L103 55L102 56L101 56L101 57L100 57L99 58L99 59L99 60L99 61L99 62L100 63L100 64L100 65L99 65L99 64L98 64L98 63L97 63L97 62L97 61L96 60L95 60L94 60L92 60L91 60L90 60L91 60L91 61L90 61L89 61L88 60L87 60L86 60L85 61L84 61L83 62L83 63L83 64L82 65L82 66L82 67L82 68L83 69L83 70L84 71L85 71L86 72L87 71L88 71L89 71L89 70L90 69L91 69L92 69L93 68L93 69L93 70L92 70L93 71L92 71L92 72L92 71L92 72L92 73L91 74L92 74L93 74L94 74L95 74L96 74L96 75L97 75L97 76L96 76L96 77L97 77L97 78L96 78L96 79L97 80L98 81L99 81L100 81L100 80L101 80L101 81L102 81L103 81L104 81L104 80L105 79L106 79L107 79L107 78L108 78L109 78L108 79L108 80L108 81L109 81L109 80L109 79L110 79L110 78L110 79L111 79L112 79L113 79L114 79L114 80L115 80L116 80L116 79L117 79L118 79L117 80L118 80L119 81L120 81L120 82L121 82L122 83L122 84L123 84L124 84L125 84L126 84L127 85L128 85L128 86L129 86L129 88L130 88L130 89L129 90L130 90L131 90L131 91L132 91L133 91L135 92L136 92L135 93L137 92L139 93L140 93L141 94L143 95L144 95L145 95L145 97L145 99L144 100L143 101L142 102L142 103L141 103L141 104L141 106L141 107L141 108L140 108L140 110L139 111L139 112L138 112L138 113L137 113L135 113L135 114L134 114L132 115L132 116L131 117L132 117L131 118L131 119L130 119L129 121L128 122L127 123L127 124L126 124L125 125L124 125L123 124L122 124L123 125L123 126L123 127L122 128L121 129L119 129L118 129L118 130L118 131L117 131L116 131L115 131L115 132L116 132L117 133L116 133L115 133L115 135L114 135L113 135L113 136L112 136L113 137L114 137L114 138L113 139L112 140L111 140L111 141L111 142L112 142L111 142L110 143L109 143L109 144L107 144L106 143L105 142L105 141L105 140L104 139L105 138L106 137L104 137L105 136L106 134L107 134L107 132L106 133L106 132L106 130L107 129L106 128L106 127L107 127L107 126L108 124L109 122L108 121L109 120L109 119L109 118L109 116L110 114L110 111L110 110L110 108L109 108L109 107L107 106L105 105L104 105L104 104L103 102L102 100L101 98L100 97L99 97L99 96L99 95L99 94L100 93L100 92L100 93L99 92L99 91L100 90L100 89L101 89L101 88L102 87L103 86L103 85L102 84L103 84L103 83L102 83L102 82L101 81L100 81L100 82L100 83L99 83L99 82L98 82L97 82L96 82L96 81L95 80L94 80L94 79L93 78L92 77L93 77L92 77L91 77L90 76L89 76L88 76L88 75L87 74L86 74L85 74L84 74L83 74L82 74L81 73L80 73L79 73L78 72L76 72L76 71L75 71L75 70L74 70L75 69L74 69L75 69L74 68L74 67L73 66L72 65L71 64L70 63L69 62L68 62L68 61L67 60L67 59L66 58L65 58L65 59L65 60L66 60L66 61L67 61L67 62L68 62L68 63L69 64L69 65L69 66L70 66L71 67L70 67L69 66L68 66L68 65L68 64L67 64L67 63L66 63L65 62L66 62L66 61L65 61L64 60L64 59L63 58L63 57L62 56L61 56L60 56L59 55L58 54L57 52L56 51L56 50L56 49L56 48L55 47L56 46L56 44L56 43L56 42L55 42L57 42L57 43L58 43L58 42L57 41L55 40L54 40L53 39L52 38L51 37L51 36L49 36L49 35L48 35L48 34L46 33L46 32L45 32L43 32L42 31L40 30L39 30L37 30L36 30L34 30L33 29L32 29L32 30L31 30L30 30L29 31L28 31L28 30L29 29L30 29L29 29L28 29L27 30L26 31L27 31L26 32L25 32L24 33L23 33L22 34L20 34L19 35L18 35L17 35L15 36L15 35L16 35L17 35L18 34L19 34L20 34L21 33L22 33L22 32L23 31L22 31L21 31L21 32L20 31L19 31L18 31L18 30L17 30L16 30L15 30L15 29L14 28L15 27L16 27L17 27L18 26L18 27L19 26L18 26L19 25L18 25L17 26L16 25L15 26L14 25L13 25L12 24L13 24L16 23L16 24L18 24L18 23L16 23L16 22L15 22L13 22L14 21L16 21L17 21L17 20L18 20L19 20L21 19L22 19L23 19L25 19L26 19L28 19L29 20L30 19L32 20L34 20L35 20L36 20L38 20L39 20L41 21L42 21L43 21L44 21L46 20L47 20L49 20L50 20L51 20L52 20L53 20L54 21L56 20L56 21L57 20L59 20L60 21L62 21L64 21L65 21L66 22L65 22L67 22L69 22L70 22L71 23L72 22L71 22L72 21L73 21L74 21L75 21L76 22L77 22L79 22L80 22L82 22L81 22L82 21L84 22L84 23L85 22L86 21L85 20L84 20L84 19L85 18L86 18L87 19L88 20L89 21ZM66 17L65 17L68 17L69 18L70 17L71 17L72 18L72 17L73 17L75 17L75 18L76 19L77 20L79 20L77 20L78 21L76 21L74 21L73 21L71 21L68 21L67 21L66 21L65 21L64 21L63 20L65 20L66 20L68 20L66 19L64 19L62 19L64 19L62 19L61 18L62 17L65 17L66 17ZM76 17L75 17L73 17L73 16L75 16L76 17ZM104 17L103 17L102 17L101 17L100 17L99 17L99 16L100 16L102 16L104 17ZM93 17L94 17L95 17L98 16L99 17L99 18L101 18L102 17L104 18L106 18L106 19L108 18L109 19L111 19L112 20L113 21L111 21L114 22L115 22L117 23L118 23L118 24L116 25L115 25L113 24L112 24L113 25L114 25L115 26L115 27L114 27L111 26L113 27L114 28L111 28L109 27L108 27L108 26L107 26L105 25L105 26L102 26L101 25L102 25L104 25L106 25L106 24L107 23L107 22L105 21L103 21L104 21L103 20L102 20L101 20L99 20L95 20L93 20L91 20L90 19L92 19L90 19L90 18L91 17L92 16L94 16L93 17ZM80 16L81 16L83 16L83 17L82 17L83 17L83 18L82 19L81 19L80 18L78 17L80 17L78 17L80 16ZM324 17L322 17L320 17L321 16L322 16L323 17L324 17ZM87 17L86 18L85 18L84 17L85 16L88 16L89 16L88 17L87 17ZM60 19L57 19L56 19L54 18L55 17L56 16L55 16L58 16L60 16L62 16L63 16L64 17L63 17L61 17L60 18L60 19ZM331 15L330 15L328 15L326 15L328 15L331 15ZM86 15L84 15L83 15L84 15L85 14L86 15ZM325 14L324 15L321 15L319 15L317 15L318 14L319 14L321 14L325 14ZM82 13L82 14L82 15L80 15L79 15L79 14L77 14L79 14L80 13L81 13L82 13ZM72 14L73 14L74 14L74 15L70 15L68 16L66 16L66 15L68 15L64 15L62 15L64 14L65 14L67 14L69 14L71 15L70 14L70 13L71 13L72 14ZM238 19L237 19L234 19L233 19L232 19L231 18L232 18L232 17L234 16L236 15L238 14L241 14L244 14L246 13L248 13L249 13L248 14L245 14L242 15L238 16L237 17L235 18L236 18L238 19ZM85 13L86 13L88 13L89 14L90 14L91 14L92 14L94 15L95 14L97 14L99 14L100 15L98 16L97 15L94 16L92 16L90 15L88 15L87 15L87 14L86 14L84 14L83 13L85 13ZM64 12L64 13L63 13L62 14L60 14L59 14L57 14L59 13L61 12L62 13L64 12ZM287 13L287 14L288 13L291 13L293 14L294 14L294 15L293 15L290 16L289 16L291 16L292 16L293 16L294 17L294 16L296 16L299 16L299 17L303 17L303 16L305 16L307 16L309 17L309 18L308 18L310 19L311 19L312 18L314 19L316 18L317 19L318 18L320 19L319 18L320 17L330 18L333 19L337 19L339 19L340 20L341 21L342 20L344 20L346 21L348 20L350 21L351 21L350 20L354 20L356 20L359 21L360 21L360 25L359 25L357 25L358 26L359 27L359 28L357 27L355 28L354 28L352 29L351 30L350 30L349 29L346 30L345 30L344 30L343 31L342 32L343 32L343 34L342 34L342 35L340 36L340 37L339 37L338 38L337 39L336 38L336 37L335 35L336 33L337 33L337 32L338 32L340 31L342 30L344 29L344 27L343 28L340 29L339 28L337 29L334 30L335 31L333 31L331 31L331 30L330 30L329 31L325 31L322 31L319 33L315 35L317 35L317 36L318 36L319 36L320 36L321 37L321 38L321 39L321 40L320 42L319 43L318 44L317 45L316 46L315 47L314 47L313 47L312 47L311 47L311 48L310 48L310 49L309 49L309 50L308 50L308 51L307 51L308 51L309 53L309 54L309 55L308 55L307 56L306 56L306 55L307 54L306 53L307 53L306 52L305 52L305 51L305 50L304 50L303 50L302 51L301 51L302 51L301 50L302 50L302 49L301 49L300 50L299 51L298 51L298 52L299 52L299 53L300 53L301 52L302 53L303 53L301 53L301 54L300 54L299 55L300 56L301 57L301 58L302 58L302 59L301 59L302 60L302 61L302 62L301 62L300 63L300 64L299 65L297 66L296 67L295 67L294 68L294 67L293 68L292 68L291 69L290 70L290 69L289 68L288 68L287 69L286 70L286 71L286 72L287 73L288 74L289 75L289 77L289 78L288 79L287 80L286 80L285 81L285 80L284 80L283 79L283 78L282 77L281 77L280 77L280 78L279 79L279 80L279 81L280 81L280 82L280 83L281 83L282 83L282 84L283 84L283 85L283 86L283 87L284 87L284 88L284 89L283 88L281 87L281 86L281 85L280 85L280 84L280 83L279 82L278 82L278 81L279 80L278 79L279 79L278 78L279 77L278 76L278 75L278 74L277 73L277 74L275 74L274 74L275 73L274 72L274 71L274 70L273 70L272 69L272 68L271 67L270 67L271 68L270 68L269 68L268 68L267 69L266 70L265 71L264 72L263 72L262 73L262 74L261 74L260 74L260 75L260 76L260 77L260 78L260 80L259 80L259 81L258 81L258 82L257 81L256 80L256 79L255 78L255 77L255 76L254 75L254 74L253 72L253 71L253 70L253 69L251 69L250 69L249 68L250 68L249 67L248 66L247 66L247 65L246 65L245 65L243 65L241 65L240 65L239 64L237 64L237 63L236 63L235 64L233 63L232 62L231 61L230 60L229 60L228 60L228 61L229 62L229 63L230 63L230 64L231 65L231 64L232 64L232 65L231 65L232 66L233 66L234 66L235 65L236 64L236 65L237 66L238 66L239 66L239 67L240 67L240 68L239 68L239 69L238 70L238 71L237 71L237 72L236 72L235 72L235 73L234 73L233 73L232 74L231 75L230 75L229 76L228 76L227 76L227 77L226 77L225 77L224 77L223 77L223 76L223 75L223 74L223 73L222 73L222 72L221 71L220 70L219 69L219 68L219 67L218 66L217 66L217 65L217 64L216 63L215 62L215 61L215 60L215 61L214 62L213 62L212 60L213 61L213 62L214 64L215 65L216 66L215 66L216 67L217 68L217 69L217 70L217 71L218 72L219 73L219 74L220 75L221 76L222 76L222 77L223 77L223 78L223 79L224 79L224 80L225 80L226 79L227 79L228 79L229 79L230 78L231 78L231 79L231 80L231 81L230 82L229 83L229 85L228 86L227 87L226 88L224 89L223 90L222 91L222 92L221 92L220 93L220 94L219 95L219 96L219 97L219 98L220 99L220 100L220 101L220 102L221 103L221 104L221 105L220 105L220 106L219 107L217 108L216 109L215 110L215 111L215 112L216 112L216 113L215 114L216 114L215 114L214 115L213 115L213 116L213 117L212 118L212 119L211 119L211 120L210 121L209 122L208 123L207 123L206 124L205 124L204 124L203 124L202 124L201 124L200 125L199 124L198 124L198 123L198 122L198 121L197 120L196 119L196 118L195 117L195 116L195 115L194 114L194 113L194 112L193 111L193 110L193 109L192 108L192 107L192 106L192 105L192 104L193 104L193 103L193 102L194 102L194 101L193 100L193 99L193 98L193 97L192 96L192 95L191 94L190 93L189 92L189 91L189 90L189 89L190 88L190 87L189 86L188 86L189 85L187 86L186 86L185 85L185 84L184 84L183 84L182 84L181 84L179 85L178 85L177 85L176 85L175 85L174 85L173 85L172 86L171 85L170 84L169 84L169 83L168 83L167 82L167 81L166 81L166 80L165 80L165 79L164 79L164 78L163 78L163 77L163 76L162 75L163 75L163 74L164 74L163 73L164 73L164 72L164 71L164 70L163 69L163 68L164 67L164 66L165 66L165 65L165 64L166 64L166 63L167 62L168 62L169 61L170 61L170 60L170 59L171 58L171 57L172 56L173 56L174 55L174 54L175 54L175 55L176 55L177 55L178 55L179 54L180 54L181 54L181 53L183 53L185 53L186 53L187 53L188 53L190 53L191 53L191 54L191 55L190 56L191 56L191 57L193 57L194 57L195 58L196 59L197 59L198 59L199 60L200 59L200 58L201 57L202 57L203 57L203 58L204 58L205 58L206 58L207 59L208 59L209 59L210 59L211 58L212 59L213 59L214 59L215 58L214 58L215 58L215 57L215 56L216 55L216 54L216 53L215 53L214 54L213 54L212 53L211 53L210 54L209 53L208 53L207 52L206 52L207 51L206 51L207 50L209 50L209 49L211 49L212 48L214 48L215 48L217 49L218 49L220 49L222 48L221 47L220 47L219 46L218 45L217 45L218 44L218 43L219 43L218 43L217 43L216 43L215 44L216 45L217 45L216 45L215 45L214 46L213 45L214 45L212 45L213 44L214 44L213 44L212 44L212 43L211 43L210 44L210 45L209 45L209 46L208 47L208 48L209 49L208 49L207 49L206 50L206 49L205 49L204 49L204 50L203 50L203 51L204 51L204 52L203 52L203 53L203 54L202 54L202 53L201 52L201 51L200 51L200 50L199 50L199 49L200 48L199 48L198 48L198 47L197 47L196 46L195 46L195 45L194 45L194 44L193 44L192 45L193 46L194 46L194 47L195 48L196 48L197 49L198 49L198 50L197 50L196 50L197 51L196 52L196 51L196 50L195 50L195 49L194 49L193 49L192 48L191 48L191 47L190 46L189 46L188 46L187 46L187 47L185 47L183 47L183 48L182 49L181 49L180 50L180 51L180 52L179 52L179 53L178 53L177 53L176 53L175 54L174 54L173 53L172 53L171 53L171 52L170 51L171 51L171 50L171 49L171 48L171 47L172 46L173 46L175 46L176 47L178 47L179 46L179 44L178 43L177 42L176 42L175 41L177 41L178 41L178 40L179 41L181 40L182 39L183 39L184 38L185 37L186 36L187 37L187 36L188 36L189 36L189 35L188 34L188 33L189 33L190 33L191 32L191 33L190 33L191 34L190 34L190 35L191 36L192 36L193 36L194 36L195 36L196 35L198 35L199 35L199 36L200 36L200 35L201 35L201 34L201 33L202 33L203 32L203 33L204 33L204 32L203 31L205 31L206 30L207 31L208 31L209 30L208 29L206 30L204 30L203 30L202 30L201 29L202 28L201 27L202 27L202 26L205 25L205 24L204 24L202 24L201 25L201 26L200 26L198 27L197 29L198 29L199 30L198 31L197 31L196 33L196 34L195 34L194 35L193 35L193 34L192 33L191 31L190 31L188 32L187 32L186 31L185 30L185 28L186 27L189 27L191 26L192 24L195 22L196 21L199 20L201 20L203 20L205 19L206 19L208 19L211 20L210 20L211 20L212 20L214 21L217 21L220 22L221 23L220 24L218 24L214 23L213 23L215 24L215 26L216 26L217 26L217 25L220 25L222 24L223 24L224 24L225 23L224 23L224 22L223 21L226 22L227 22L226 22L226 23L228 23L228 22L230 22L234 21L233 22L235 22L237 22L239 21L240 22L241 21L240 20L241 20L244 20L245 21L249 22L249 21L248 21L247 21L247 20L247 19L249 18L249 17L250 17L253 17L253 18L252 19L253 20L253 21L254 22L253 22L251 24L252 24L253 23L254 23L255 22L254 22L255 21L254 21L254 20L254 19L253 19L255 18L255 17L256 18L255 19L256 19L256 18L258 18L260 18L262 18L261 17L261 16L262 16L265 16L267 16L266 16L267 15L268 15L270 14L273 14L276 14L277 14L279 14L281 14L281 13L282 13L284 12L286 13L285 13L287 13ZM229 49L230 49L230 50L229 51L229 52L230 53L231 53L232 53L234 53L234 52L234 51L233 51L233 50L233 49L234 49L235 49L234 48L233 48L233 49L233 48L232 48L233 48L233 47L231 47L231 46L230 46L230 45L231 45L232 45L233 45L233 44L233 43L232 43L231 43L230 43L229 44L228 44L227 45L228 46L227 47L229 48L229 49ZM86 12L86 13L84 12L86 12ZM70 12L68 13L66 12L67 12L69 12L70 12ZM205 12L202 13L201 12L203 12L205 12ZM70 11L69 12L67 12L67 11L68 11L69 11L70 11ZM84 12L83 12L82 12L81 12L81 11L83 11L84 12ZM80 12L79 12L77 12L75 12L76 11L75 11L76 11L79 11L80 12ZM285 12L279 12L281 11L282 11L283 11L285 11L285 12ZM198 10L202 11L199 11L198 12L197 13L196 13L194 13L195 12L193 12L191 11L190 10L193 10L194 10L195 10L196 10L197 10L198 10ZM205 10L207 10L206 10L203 11L200 10L198 10L197 10L200 9L202 10L203 9L205 10ZM231 9L230 10L229 10L228 10L227 10L227 9L225 9L227 9L228 9L229 9L230 9L232 9L231 9ZM280 11L278 11L275 11L273 11L273 10L271 10L274 9L276 9L278 9L280 10L280 11ZM93 10L94 11L93 11L91 12L89 12L87 12L86 11L87 11L85 11L84 10L83 10L84 9L85 9L86 9L85 9L88 9L89 9L91 9L92 10L93 10ZM112 7L114 7L116 7L118 7L118 8L116 8L113 8L112 8L115 8L112 9L111 9L109 10L107 10L106 11L103 11L104 11L105 11L104 12L102 12L100 13L102 13L99 14L97 14L94 14L92 14L91 14L90 13L92 13L92 12L95 12L94 12L92 12L93 11L95 11L93 10L96 10L97 10L98 10L96 9L92 9L91 9L90 9L89 8L88 8L90 8L91 8L93 8L95 7L96 7L97 8L98 7L99 7L101 7L104 7L107 7L109 7L112 7ZM153 6L159 7L157 8L153 8L148 8L149 8L152 8L155 8L157 8L158 8L157 9L159 8L164 8L167 8L168 9L164 9L163 10L160 10L162 10L161 11L160 11L160 12L162 13L160 13L158 13L160 14L160 15L159 15L161 16L158 16L160 16L159 17L158 17L156 17L158 17L158 18L156 17L155 18L157 18L158 19L156 20L156 19L154 19L155 19L154 20L156 20L158 20L155 21L152 22L149 22L148 22L147 22L146 23L144 24L143 24L142 24L140 25L139 25L139 26L139 27L137 27L138 28L137 29L137 30L135 30L134 29L132 29L131 29L130 28L128 26L128 25L126 24L127 23L126 23L127 22L129 21L129 20L128 20L127 21L125 20L126 19L127 19L129 19L127 19L126 18L125 19L124 18L125 17L124 16L123 15L121 15L121 14L119 14L117 14L114 14L111 14L110 14L109 13L111 13L113 13L109 12L107 12L111 11L114 11L115 10L112 10L113 9L116 9L118 9L117 8L120 8L123 8L126 8L127 8L130 8L132 8L133 8L135 8L133 8L133 7L137 7L140 7L141 6L145 6L153 6Z';\n", "import { css, html, nothing, svg } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type {\n\tGetCriticalDaysResponse,\n\tGetDailyBiorhythmResponse,\n\tGetForecastResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { disclosureStyles } from '../utils/disclosure.js';\nimport { formatDate } from '../utils/format.js';\nimport {\n\ttype InterpSection,\n\tinterpAccordionStyles,\n\trenderInterpAccordion,\n} from '../utils/interp-accordion.js';\nimport { humanize } from '../utils/string.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/** The cycles a forecast day carries, in the order they are plotted and keyed in the legend. */\nconst FORECAST_CYCLES = [\n\t'physical',\n\t'emotional',\n\t'intellectual',\n\t'intuitive',\n] as const;\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\tdisclosureStyles,\n\t\tinterpAccordionStyles,\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}.head-meta{align-items:center;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.energy{font-variant-numeric:tabular-nums;color:var(--roxy-accent-ink,#b45309);font-weight:var(--roxy-weight-bold,600)}.phase{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);font-weight:var(--roxy-weight-bold,600);padding:2px 10px}.spotlight{gap:var(--roxy-space-xs,.25rem);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-border,#e4e4e7) 22%, transparent);border-radius:0 var(--roxy-radius-sm,4px) var(--roxy-radius-sm,4px) 0;display:grid}.spotlight .label{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;margin:0}.spotlight .lead{align-items:baseline;gap:var(--roxy-space-sm,.5rem);flex-wrap:wrap;display:flex}.spotlight strong{text-transform:capitalize}.spotlight p{font-size:var(--roxy-text-sm,.875rem);margin:0;line-height:1.6}.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);margin:0}svg{width:100%;max-width:var(--roxy-chart-max-width,600px);height:auto;display:block}.legend{gap:var(--roxy-space-md,1rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-fg,#0a0a0a);flex-wrap:wrap;display:flex}.key{text-transform:capitalize;align-items:center;gap:.35rem;display:inline-flex}.dot{border-radius:var(--roxy-radius-full,9999px);width:.6rem;height:.6rem}.dot.critical{background:var(--roxy-danger,#dc2626)}.stats{gap:var(--roxy-space-sm,.5rem);grid-template-columns:repeat(auto-fit,minmax(7rem,1fr));margin:0;display:grid}.stat{gap:2px;display:grid}.stat dt{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.05em}.stat dd{font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);font-variant-numeric:tabular-nums;margin:0}.crit-note{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);background:color-mix(in srgb, var(--roxy-danger,#dc2626) 10%, transparent);border-radius:var(--roxy-radius-sm,4px);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);margin:0}.crit-meta{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);margin:0}`,\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\tconst spot = d.spotlight;\n\n\t\treturn html`<section class=\"wrap\" aria-label=\"Daily biorhythm\"><header class=\"head\"><h2 class=\"title\">Biorhythm</h2><div class=\"head-meta\">${d.overallPhase ? html`<span class=\"phase\">${humanize(d.overallPhase)}</span>` : nothing} ${\n\t\t\t\t\t\ttypeof d.energyRating === 'number'\n\t\t\t\t\t\t\t? html`<span class=\"energy\">Energy ${d.energyRating}/10</span>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}</div></header>${\n\t\t\t\tspot\n\t\t\t\t\t? html`<div class=\"spotlight\" style=\"${`border-left-color: ${CYCLE_COLOR[spot.cycle] ?? 'var(--roxy-accent, #f59e0b)'}`}\"><p class=\"label\">Spotlight cycle</p><div class=\"lead\"><strong>${spot.cycle}</strong> ${typeof spot.value === 'number' ? html`<span class=\"energy\">${spot.value}%</span>` : nothing} ${spot.phase ? html`<span class=\"phase\">${humanize(spot.phase)}</span>` : nothing}</div>${spot.message ? html`<p>${spot.message}</p>` : nothing}</div>`\n\t\t\t\t\t: nothing\n\t\t\t}<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 s = d.summary;\n\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].filter(Boolean).join(' - ')}</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\"/>${FORECAST_CYCLES.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})} ${days.map((day, i) =>\n\t\t\t\t\t// A critical day is a zero crossing, so it sits on the midline by\n\t\t\t\t\t// definition: mark it there rather than hiding it in the curves.\n\t\t\t\t\tday.isCritical\n\t\t\t\t\t\t? svg`<circle cx=${(i * xStep).toFixed(2)} cy=${h / 2} r=\"3\" fill=\"var(--roxy-danger, #dc2626)\"><title>${[\n\t\t\t\t\t\t\t\tformatDate(day.date),\n\t\t\t\t\t\t\t\tday.criticalCycles?.length\n\t\t\t\t\t\t\t\t\t? `${day.criticalCycles.join(', ')} critical`\n\t\t\t\t\t\t\t\t\t: 'critical',\n\t\t\t\t\t\t\t\ttypeof day.energyRating === 'number'\n\t\t\t\t\t\t\t\t\t? `energy ${day.energyRating}/10`\n\t\t\t\t\t\t\t\t\t: '',\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t.join(' \u00B7 ')}</title></circle>`\n\t\t\t\t\t\t: nothing,\n\t\t\t\t)}</svg><div class=\"legend\">${FORECAST_CYCLES.map(\n\t\t\t\t\t(cycle) => html`<span class=\"key\"><span class=\"dot\" style=\"${`background: ${CYCLE_COLOR[cycle]}`}\"></span>${cycle}</span>`,\n\t\t\t\t)} <span class=\"key\"><span class=\"dot critical\"></span>critical day</span></div>${\n\t\t\t\ts\n\t\t\t\t\t? html`<dl class=\"stats\">${this.stat('Best day', formatDate(s.bestDay))} ${this.stat('Worst day', formatDate(s.worstDay))} ${this.stat(\n\t\t\t\t\t\t\t'Average energy',\n\t\t\t\t\t\t\ttypeof s.averageEnergy === 'number'\n\t\t\t\t\t\t\t\t? `${s.averageEnergy}/10`\n\t\t\t\t\t\t\t\t: '',\n\t\t\t\t\t\t)} ${this.stat(\n\t\t\t\t\t\t\t'Critical days',\n\t\t\t\t\t\t\ttypeof s.criticalDayCount === 'number'\n\t\t\t\t\t\t\t\t? `${s.criticalDayCount}`\n\t\t\t\t\t\t\t\t: '',\n\t\t\t\t\t\t)}</dl>`\n\t\t\t\t\t: nothing\n\t\t\t} ${s?.periodAdvice ? html`<p class=\"advice\">${s.periodAdvice}</p>` : nothing}</section>`;\n\t}\n\n\tprivate renderCritical(d: GetCriticalDaysResponse) {\n\t\tconst days = d.criticalDays ?? [];\n\t\tconst doubles = d.doubleCriticalDays ?? [];\n\t\tconst sections: InterpSection[] = days.map((day) => ({\n\t\t\tlabel: formatDate(day.date) || day.date,\n\t\t\taside: [day.cycle, day.severity].filter(Boolean).join(' \u00B7 '),\n\t\t\tbody: day.advisory ?? '',\n\t\t\textra: html`<p class=\"crit-meta\">${[\n\t\t\t\t\tday.direction ? `${day.direction} through zero` : '',\n\t\t\t\t\ttypeof day.period === 'number' ? `${day.period} day cycle` : '',\n\t\t\t\t]\n\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t.join(' \u00B7 ')}</p>`,\n\t\t}));\n\n\t\treturn html`<section class=\"wrap\" aria-label=\"Critical days\"><header class=\"head\"><h2 class=\"title\">Critical days</h2><span class=\"energy\">${[d.startDate, d.endDate].filter(Boolean).join(' - ')}</span></header><dl class=\"stats\">${this.stat('Events', typeof d.totalCriticalDays === 'number' ? `${d.totalCriticalDays}` : '')} ${this.stat('Double days', doubles.length ? `${doubles.length}` : '0')} ${this.stat('Triple day', d.tripleCriticalDay ? formatDate(d.tripleCriticalDay) : 'none')}</dl>${\n\t\t\t\tdoubles.length > 0\n\t\t\t\t\t? html`<p class=\"crit-note\">Two or more cycles cross zero on ${doubles.map((x) => formatDate(x) || x).join(', ')}. Take extra care on these dates.</p>`\n\t\t\t\t\t: nothing\n\t\t\t} ${renderInterpAccordion(sections, 'biorhythm-critical', 'Advisories')}</section>`;\n\t}\n\n\tprivate stat(label: string, value: string) {\n\t\tif (!value) return nothing;\n\t\treturn html`<div class=\"stat\"><dt>${label}</dt><dd>${value}</dd></div>`;\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, state } 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 { chevron, disclosureStyles } from '../utils/disclosure.js';\nimport {\n\thdReadingStyles,\n\ttype ReadingSection,\n\trenderHdFacts,\n\trenderHdKeynotes,\n\trenderHdReading,\n\trenderHdThemes,\n} from '../utils/hd-reading.js';\nimport { interpAccordionStyles } from '../utils/interp-accordion.js';\nimport { capitalize } from '../utils/string.js';\nimport { renderTablist, tablistStyles } from '../utils/tablist.js';\n\ntype Bodygraph = GenerateBodygraphResponse;\ntype GateActivation = Bodygraph['gates'][number];\ntype CenterEntry = Bodygraph['centers'][number];\ntype ChannelEntry = Bodygraph['channels'][number];\n\n/**\n * Human Design bodygraph. Pass `data` from /human-design/bodygraph. Renders the nine centers in their canonical positions and shapes, filled when defined and outlined when open, the 36 channels as wiring between gates with active channels emphasized, and the activated gate numbers.\n *\n * @remarks\n * The response carries a full interpretation, not just labels, so the card is laid out in four passes from identity down to detail. Identity sits beside the chart and is always visible: the type, strategy, authority, profile, and definition tiles, the type description as the lead paragraph, the incarnation cross, and the signature and not-self themes. Everything below is progressive disclosure through the shared exclusive-accordion pattern, so only one body of prose is ever open at a time and the card never becomes a wall of text: the reading (strategy, authority, profile, definition, aura, cross), the defined channels grouped by circuit, the nine centers, and the 26 gate activations split by chart side.\n *\n * A center returns `notSelfQuestion` whatever its state, but the question describes the conditioning of an OPEN center, so it is rendered only when the center is open. `theme` already tracks the defined or open state and is always shown.\n *\n * The chart is theme-driven through `--roxy-*` custom properties on `:host`, so it adopts the host palette in light and dark without runtime color probing.\n */\n@customElement('roxy-bodygraph')\nexport class RoxyBodygraph extends RoxyDataElement<Bodygraph> {\n\t/** Which chart side the activations panel is showing. View state, not configuration: the response always carries both sides. */\n\t@state()\n\tprivate side: 'personality' | 'design' = 'personality';\n\n\tstatic styles = [\n\t\tbaseStyles,\n\t\ttablistStyles,\n\t\tdisclosureStyles,\n\t\tinterpAccordionStyles,\n\t\thdReadingStyles,\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}.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>=40rem){.layout{grid-template-columns:minmax(0,340px) minmax(0,1fr)}}.chart{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}.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}.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}.group{margin-bottom:var(--roxy-space-md,1rem)}.group:last-child{margin-bottom:0}.group-head{font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-fg,#0a0a0a);margin:0}.group-note{margin:0 0 var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);line-height:1.6}.footnote{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);margin:0;line-height:1.6}.chip{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:1px 8px;display:inline-block}.chip--on{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 18%, transparent)}.chips{flex-wrap:wrap;gap:.25rem;display:inline-flex}.gate-id,.chan-gates{font-variant-numeric:tabular-nums;font-weight:var(--roxy-weight-bold,600);color:var(--roxy-accent-ink,#b45309)}.glyph{color:var(--roxy-accent-ink,#b45309)}.side-note{margin:0 0 var(--roxy-space-sm,.5rem);padding-top:var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);line-height:1.6}`,\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: Bodygraph) {\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\t// One text node, not two: the markup minifier collapses the leading\n\t\t\t\t\t// space of an adjacent template and the separator would lose it.\n\t\t\t\t\td.type || d.profile\n\t\t\t\t\t\t? html`<div class=\"type-line\">${[d.type, d.profile ? `Profile ${d.profile}` : ''].filter(Boolean).join(' \u00B7 ')}</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</header><div class=\"layout\"><svg class=\"chart\" 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>${this.renderReading(d)} ${this.renderChannels(d.channels ?? [])} ${this.renderCenters(d.centers ?? [])} ${this.renderActivations(d)}</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 glyph = this.planetGlyph(g.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\t/** Monochrome planet glyph for an API planet name, or the name itself when the wheel has no glyph for it. */\n\tprivate planetGlyph(planet: string | undefined): string {\n\t\tif (!planet) return '';\n\t\tconst name = capitalize(planet);\n\t\treturn PLANET_GLYPH[name] ?? planet;\n\t}\n\n\tprivate renderSummary(d: Bodygraph) {\n\t\tconst ic = d.incarnationCross;\n\t\treturn html`<div class=\"summary\">${renderHdFacts([\n\t\t\t\t{ label: 'Type', value: d.type },\n\t\t\t\t{ label: 'Strategy', value: d.strategy },\n\t\t\t\t{ label: 'Authority', value: d.authority },\n\t\t\t\t{ label: 'Profile', value: d.profile },\n\t\t\t\t{ label: 'Definition', value: d.definition },\n\t\t\t])} ${d.typeDescription ? html`<p class=\"lead\">${d.typeDescription}</p>` : nothing} ${\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} ${renderHdThemes(d.signature, d.notSelf)}<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\t/**\n\t * The mechanics of the design, in the order a reader needs them: how to engage (strategy), how to decide (authority), the role played (profile), how the definition hangs together, the aura, and the life theme of the incarnation cross. The cross name and gates already sit beside the chart, so only its description is repeated here.\n\t */\n\tprivate renderReading(d: Bodygraph) {\n\t\tconst ic = d.incarnationCross;\n\t\tconst sections: ReadingSection[] = [\n\t\t\t{ label: 'Strategy', aside: d.strategy, body: d.strategyDescription },\n\t\t\t{ label: 'Authority', aside: d.authority, body: d.authorityDescription },\n\t\t\t{\n\t\t\t\tlabel: 'Profile',\n\t\t\t\taside: d.profile,\n\t\t\t\tbody: d.profileDescription,\n\t\t\t\textra: renderHdKeynotes(d.profileKeynotes),\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: 'Definition',\n\t\t\t\taside: d.definition,\n\t\t\t\tbody: d.definitionDescription,\n\t\t\t},\n\t\t\t{ label: 'Aura', body: d.aura },\n\t\t\t{\n\t\t\t\tlabel: 'Incarnation cross',\n\t\t\t\taside: ic?.angle,\n\t\t\t\tbody: ic?.description ?? '',\n\t\t\t},\n\t\t];\n\t\treturn renderHdReading(sections, 'hd-reading');\n\t}\n\n\t/**\n\t * Defined channels, grouped by circuit. The circuit description is the same\n\t * text for every channel that belongs to it, so it is lifted to the group\n\t * intro instead of repeating inside each row. Groups keep response order, which\n\t * is gate order; no circuit ranking is invented.\n\t */\n\tprivate renderChannels(channels: ChannelEntry[]) {\n\t\tif (channels.length === 0) return nothing;\n\t\tconst groups = new Map<string, ChannelEntry[]>();\n\t\tfor (const c of channels) {\n\t\t\tconst key = c.circuit ?? '';\n\t\t\tconst bucket = groups.get(key);\n\t\t\tif (bucket) bucket.push(c);\n\t\t\telse groups.set(key, [c]);\n\t\t}\n\t\t// One accordion group spans every circuit, so the open row is the first\n\t\t// channel overall, not the first of each circuit.\n\t\tlet index = 0;\n\n\t\treturn html`<section class=\"block\"><h3>Defined channels (${channels.length})</h3>${[...groups].map(\n\t\t\t\t([circuit, list]) => html`<div class=\"group\">${circuit ? html`<p class=\"group-head\">${circuit} circuit</p>` : nothing} ${\n\t\t\t\t\t\tlist[0]?.circuitDescription\n\t\t\t\t\t\t\t? html`<p class=\"group-note\">${list[0].circuitDescription}</p>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t} ${list.map(\n\t\t\t\t\t\t(\n\t\t\t\t\t\t\tc,\n\t\t\t\t\t\t) => html`<details class=\"interp-card\" name=\"hd-channel\" ?open=\"${index++ === 0}\"><summary><span class=\"interp-lead\"><span class=\"chan-gates\">${c.gateA}-${c.gateB}</span> <span>${c.name ?? ''}</span> </span>${chevron()}</summary><div class=\"interp-body\">${c.description ? html`<p>${c.description}</p>` : nothing}</div></details>`,\n\t\t\t\t\t)}</div>`,\n\t\t\t)}</section>`;\n\t}\n\n\t/**\n\t * The nine centers. `theme` already reflects whether the center came back\n\t * defined or open, so it always shows. `notSelfQuestion` is written for the\n\t * OPEN state (\"the open Spleen clings to...\"), so showing it on a defined\n\t * center would state the opposite of the chart; it is rendered for open\n\t * centers only.\n\t */\n\tprivate renderCenters(centers: CenterEntry[]) {\n\t\tif (centers.length === 0) return nothing;\n\t\tconst definedCount = centers.filter((c) => c.defined).length;\n\t\treturn html`<section class=\"block\"><h3>Centers (${definedCount} defined, ${centers.length - definedCount} open)</h3>${centers.map(\n\t\t\t\t(\n\t\t\t\t\tc,\n\t\t\t\t\ti,\n\t\t\t\t) => html`<details class=\"interp-card\" name=\"hd-center\" ?open=\"${i === 0}\"><summary><span class=\"interp-lead\">${c.name ?? ''}</span> ${chevron()} <span class=\"interp-aside\"><span class=\"chips\"><span class=\"chip ${c.defined ? 'chip--on' : ''}\">${c.defined ? 'Defined' : 'Open'}</span> ${c.motor ? html`<span class=\"chip\">Motor</span>` : nothing} ${c.awareness ? html`<span class=\"chip\">Awareness</span>` : nothing}</span></span></summary><div class=\"interp-body\">${c.theme ? html`<p>${c.theme}</p>` : nothing} ${\n\t\t\t\t\t\t\t!c.defined && c.notSelfQuestion\n\t\t\t\t\t\t\t\t? html`<dl class=\"keynotes\"><dt>Not-self question</dt><dd>${c.notSelfQuestion}</dd></dl>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t} ${c.biology ? html`<p class=\"footnote\">Biology. ${c.biology}</p>` : nothing} ${\n\t\t\t\t\t\t\tc.gates?.length\n\t\t\t\t\t\t\t\t? html`<p class=\"footnote\">Gates ${c.gates.join(', ')}</p>`\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\t/**\n\t * The 26 activations, split by chart side. Personality is the conscious side\n\t * printed in black, design the unconscious side printed in red, and the\n\t * response describes each once at the top level, so the side description\n\t * becomes the panel intro rather than an orphan glossary entry. Splitting the\n\t * list in two also halves what a reader scans: 13 rows per side, in the\n\t * canonical planet order the response returns.\n\t */\n\tprivate renderActivations(d: Bodygraph) {\n\t\tconst gates = d.gates ?? [];\n\t\tif (gates.length === 0) return nothing;\n\n\t\tconst personality = gates.filter((g) => g.side === 'personality');\n\t\tconst design = gates.filter((g) => g.side === 'design');\n\t\t// A response with only one side (or an unrecognized side value) still\n\t\t// renders: fall back to the flat list and drop the tabs.\n\t\tconst split = personality.length > 0 && design.length > 0;\n\t\tconst side = this.side;\n\t\tconst shown = split ? (side === 'design' ? design : personality) : gates;\n\t\tconst sideNote = split ? d.sides?.[side] : undefined;\n\n\t\treturn html`<section class=\"block\"><h3>Activations (${gates.length})</h3>${\n\t\t\t\tsplit\n\t\t\t\t\t? renderTablist({\n\t\t\t\t\t\t\titems: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tid: 'personality' as const,\n\t\t\t\t\t\t\t\t\tlabel: `Personality (${personality.length})`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{ id: 'design' as const, label: `Design (${design.length})` },\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tactive: side,\n\t\t\t\t\t\t\tonSelect: (v) => {\n\t\t\t\t\t\t\t\tthis.side = v;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tlabel: 'Chart sides',\n\t\t\t\t\t\t\tidPrefix: 'hd',\n\t\t\t\t\t\t\tcontrols: true,\n\t\t\t\t\t\t})\n\t\t\t\t\t: nothing\n\t\t\t}<div id=\"${split ? `hd-panel-${side}` : nothing}\" role=\"${split ? 'tabpanel' : nothing}\" aria-labelledby=\"${split ? `hd-tab-${side}` : nothing}\">${sideNote ? html`<p class=\"side-note\">${sideNote}</p>` : nothing} ${shown.map((g, i) => this.renderGate(g, i === 0))}</div></section>`;\n\t}\n\n\tprivate renderGate(g: GateActivation, open: boolean) {\n\t\tconst glyph = this.planetGlyph(g.planet);\n\t\tconst hex = g.ichingHexagram;\n\t\treturn html`<details class=\"interp-card\" name=\"hd-gate\" ?open=\"${open}\"><summary><span class=\"interp-lead\">${glyph ? html`<span class=\"glyph\" aria-hidden=\"true\">${glyph}</span>` : nothing} <span class=\"gate-id\">${g.gate}${g.line != null ? `.${g.line}` : ''}</span> <span>${g.gateName ?? ''}</span> </span>${chevron()} ${g.planet ? html`<span class=\"interp-aside\"><small>${g.planet}</small></span>` : nothing}</summary><div class=\"interp-body\">${g.gateDescription ? html`<p>${g.gateDescription}</p>` : nothing} ${\n\t\t\t\t\tg.lineMeaning\n\t\t\t\t\t\t? html`<dl class=\"keynotes\"><dt>Line ${g.line ?? ''}</dt><dd>${g.lineMeaning}</dd></dl>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} ${\n\t\t\t\t\tg.planetDescription\n\t\t\t\t\t\t? html`<p class=\"footnote\">${g.planet}. ${g.planetDescription}</p>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} ${\n\t\t\t\t\thex?.number\n\t\t\t\t\t\t? html`<p class=\"footnote\">I Ching hexagram ${hex.number}${hex.english ? `, ${hex.english}` : ''}</p>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</div></details>`;\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", "/**\n * The Human Design reading surface: the fact tiles, the lead paragraph, the signature and not-self pills, and the profile keynotes.\n *\n * @remarks\n * `/human-design/type` returns a strict subset of the `/human-design/bodygraph` interpretation fields (type, aura, strategy, authority, their descriptions, signature, not-self, profile), so `roxy-bodygraph` and `roxy-hd-type-card` would otherwise render the same markup and carry the same CSS twice. Both import from here instead: the bodygraph wraps the chart around it, the type card is the reading on its own.\n *\n * The disclosure accordion itself is NOT here. It lives in `utils/interp-accordion.ts`, because the same accordion serves any endpoint that returns a labelled reading (`roxy-hexagram` uses it for the changing lines). Import `interpAccordionStyles` alongside `hdReadingStyles`.\n */\n\nimport { css, html, nothing } from 'lit';\nimport {\n\ttype InterpSection,\n\trenderInterpAccordion,\n} from './interp-accordion.js';\n\n/** One row of the reading accordion. Alias of the shared {@link InterpSection} so HD call sites keep reading naturally. */\nexport type ReadingSection = InterpSection;\n\n/** A labelled value tile. A fact with no value is dropped, so a narrower response renders fewer tiles rather than empty ones. */\nexport interface Fact {\n\tlabel: string;\n\tvalue?: string;\n}\n\n/** The two profile lines with the keynote of each. Normalized: the bodygraph nests these under `profileKeynotes`, `/human-design/profile` returns them flat, and both map onto this. */\nexport interface ProfileKeynotes {\n\tpersonality?: string;\n\tpersonalityLine?: number;\n\tdesign?: string;\n\tdesignLine?: number;\n}\n\nexport const hdReadingStyles = css`.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)}.lead{color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);margin:0;line-height:1.6}.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)}.keynotes{gap:var(--roxy-space-xs,.25rem);margin:0;display:grid}.keynotes dt{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.05em}.keynotes dd{margin:0}`;\n\n/** The labelled value tiles. Values the response does not carry are dropped rather than rendered empty. */\nexport function renderHdFacts(facts: Fact[]) {\n\tconst shown = facts.filter((f) => Boolean(f.value));\n\tif (shown.length === 0) return nothing;\n\treturn html`<div class=\"facts\">${shown.map(\n\t\t\t(f) => html`<div class=\"fact\"><span>${f.label}</span> <strong>${f.value}</strong></div>`,\n\t\t)}</div>`;\n}\n\n/** The signature and not-self pills: the feeling of being in alignment, and the one that signals being out of it. */\nexport function renderHdThemes(signature?: string, notSelf?: string) {\n\tif (!signature && !notSelf) return nothing;\n\treturn html`<div class=\"themes\">${signature ? html`<span class=\"pill pill--good\">Signature: ${signature}</span>` : nothing} ${notSelf ? html`<span class=\"pill pill--shadow\">Not-self: ${notSelf}</span>` : nothing}</div>`;\n}\n\n/** The reading accordion. Thin pass-through to the shared renderer so the HD components keep a domain-named call site while the markup and CSS live in one place. */\nexport function renderHdReading(\n\tsections: ReadingSection[],\n\tname: string,\n\theading = 'Reading',\n) {\n\treturn renderInterpAccordion(sections, name, heading);\n}\n\n/** The two profile lines, each with the keynote of the line. Personality first: it is the conscious line and the one the profile is read from. */\nexport function renderHdKeynotes(k: ProfileKeynotes | undefined) {\n\tif (!k?.personality && !k?.design) return nothing;\n\treturn html`<dl class=\"keynotes\">${\n\t\t\tk.personality\n\t\t\t\t? html`<dt>Line ${k.personalityLine ?? ''} \u00B7 Personality</dt><dd>${k.personality}</dd>`\n\t\t\t\t: nothing\n\t\t} ${\n\t\t\tk.design\n\t\t\t\t? html`<dt>Line ${k.designLine ?? ''} \u00B7 Design</dt><dd>${k.design}</dd>`\n\t\t\t\t: nothing\n\t\t}</dl>`;\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 { formatTimeRange } from '../utils/format.js';\nimport { capitalize } from '../utils/string.js';\n\ntype ChoghadiyaPeriod = GetChoghadiyaResponse['dayChoghadiya'][number];\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 = formatTimeRange(period);\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 { PLANET_GLYPH, SIGN_GLYPH } from '../tokens/index.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 { disclosureStyles } from '../utils/disclosure.js';\nimport { formatNumber } from '../utils/format.js';\nimport {\n\ttype InterpSection,\n\tinterpAccordionStyles,\n\trenderInterpAccordion,\n} from '../utils/interp-accordion.js';\nimport { capitalize } from '../utils/string.js';\n\ntype CompatibilityData =\n\t| CalculateCompatibilityResponse\n\t| CalculateNumCompatibilityResponse\n\t| CalculateBioCompatibilityResponse;\n\ntype AstroCompat = CalculateCompatibilityResponse;\n\n/** The four relationship planets, in the order a synastry reading works them: identity, feeling, love, desire. */\nconst RELATIONSHIP_PLANETS = ['sun', 'moon', 'venus', 'mars'] as const;\nconst ELEMENTS = ['fire', 'earth', 'air', 'water'] as const;\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\tdisclosureStyles,\n\t\tinterpAccordionStyles,\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}.lead{color:var(--roxy-fg,#0a0a0a);margin:0;font-weight:500}p.body{color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);margin:0;line-height:1.6}.pills{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;display:flex}.pill{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) 60%, transparent);color:var(--roxy-fg,#0a0a0a);padding:2px 8px}.pill--success{background:color-mix(in srgb, var(--roxy-success,#16a34a) 12%, transparent);color:var(--roxy-success-fg,#166534)}.pill--danger{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 12%, transparent);color:var(--roxy-danger-fg,#991b1b)}.elements{gap:var(--roxy-space-sm,.5rem);display:grid}.el-row{align-items:center;gap:var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-sm,.875rem);grid-template-columns:4rem 1fr 1fr;display:grid}.el-row .el-name{text-transform:capitalize;color:var(--roxy-fg,#0a0a0a)}.el-row.head span{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);text-transform:uppercase;letter-spacing:.06em;font-weight:var(--roxy-weight-bold,600)}.el-row.head span:nth-child(2){text-align:right}.el-bar{font-variant-numeric:tabular-nums;color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);align-items:center;gap:.4rem;display:flex}.el-bar.p1{flex-direction:row-reverse}.el-bar .track{background:var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-full,9999px);flex:auto;height:8px;display:flex;overflow:hidden}.el-bar.p1 .track{justify-content:flex-end}.el-bar .track>span{background:var(--roxy-accent,#f59e0b);height:100%;display:block}.el-bar.p2 .track>span{background:var(--roxy-info,#0284c7)}.el-row.shared .el-name{font-weight:var(--roxy-weight-bold,600)}.shared-note{margin:var(--roxy-space-sm,.5rem) 0 0;font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a)}.key-aspects{padding-left:var(--roxy-space-md,1rem);font-size:var(--roxy-text-sm,.875rem);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\">${Math.round(score)}</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>${Math.round(v)}</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 class=\"lead\">${summary}</p>` : nothing} ${interpretation ? html`<p class=\"body\">${interpretation}</p>` : nothing} ${advice ? html`<p class=\"body\">${advice}</p>` : nothing} ${this.renderAspectBreakdown()} ${this.renderSignCompatibility()} ${this.renderElementBalance()} ${this.renderSubScores()} ${\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 class=\"lists\"><div><h3>Key aspects</h3><ul class=\"key-aspects\">${keyAspects.slice(0, 6).map((a) => html`<li>${formatAspect(a)}</li>`)}</ul></div></div>`\n\t\t\t\t\t: nothing\n\t\t\t}</article>`;\n\t}\n\n\t/** Contact balance behind the score. Astrology only. */\n\tprivate renderAspectBreakdown() {\n\t\tconst b = this.astro()?.aspectBreakdown;\n\t\tif (!b) return nothing;\n\t\treturn html`<div class=\"pills\" role=\"region\" aria-label=\"Aspect breakdown\">${typeof b.total === 'number' ? html`<span class=\"pill\">Total: ${b.total}</span>` : nothing} <span class=\"pill pill--success\">Harmonious: ${b.harmonious}</span> <span class=\"pill pill--danger\">Challenging: ${b.challenging}</span> <span class=\"pill\">Neutral: ${b.neutral}</span></div>`;\n\t}\n\n\t/**\n\t * Sign-by-sign reading for the four relationship planets. The aside pairs the two signs (with degrees from `persons`, which would otherwise be dropped) so the header answers \"which signs\" before the body answers \"and so what\".\n\t */\n\tprivate renderSignCompatibility() {\n\t\tconst d = this.astro();\n\t\tconst sc = d?.signCompatibility;\n\t\tif (!sc) return nothing;\n\t\tconst persons = d?.persons;\n\t\tconst sections = RELATIONSHIP_PLANETS.map(\n\t\t\t(planet): InterpSection | null => {\n\t\t\t\tconst pair = sc[planet];\n\t\t\t\tif (!pair) return null;\n\t\t\t\tconst at = (p: 'person1' | 'person2'): string => {\n\t\t\t\t\tconst sign = capitalize(\n\t\t\t\t\t\t(p === 'person1' ? pair.person1Sign : pair.person2Sign) ?? '',\n\t\t\t\t\t);\n\t\t\t\t\tconst deg = persons?.[p]?.[planet]?.degree;\n\t\t\t\t\tconst glyph = SIGN_GLYPH[sign] ?? '';\n\t\t\t\t\tconst degree = typeof deg === 'number' ? ` ${Math.round(deg)}\u00B0` : '';\n\t\t\t\t\treturn `${glyph} ${sign}${degree}`.trim();\n\t\t\t\t};\n\t\t\t\treturn {\n\t\t\t\t\tlabel:\n\t\t\t\t\t\t`${PLANET_GLYPH[capitalize(planet)] ?? ''} ${capitalize(planet)}`.trim(),\n\t\t\t\t\taside: `${at('person1')} and ${at('person2')}`,\n\t\t\t\t\tbody: pair.description ?? '',\n\t\t\t\t};\n\t\t\t},\n\t\t).filter((s): s is InterpSection => s !== null);\n\t\treturn renderInterpAccordion(\n\t\t\tsections,\n\t\t\t'compat-signs',\n\t\t\t'Sign compatibility',\n\t\t);\n\t}\n\n\t/**\n\t * Elemental weight of both charts, mirrored around the element name so a shared emphasis reads as a matched pair. The shared element (or its absence) is the headline the API computes, so it is stated rather than left for the reader to spot.\n\t */\n\tprivate renderElementBalance() {\n\t\tconst eb = this.astro()?.elementBalance;\n\t\tif (!eb) return nothing;\n\t\tconst p1 = eb.person1;\n\t\tconst p2 = eb.person2;\n\t\tconst max = Math.max(\n\t\t\t1,\n\t\t\t...ELEMENTS.map((e) => Math.max(p1?.[e] ?? 0, p2?.[e] ?? 0)),\n\t\t);\n\t\tconst shared = eb.sharedElement?.toLowerCase();\n\t\treturn html`<section class=\"block\"><h3>Element balance</h3><div class=\"elements\"><div class=\"el-row head\"><span></span> <span>Person 1</span> <span>Person 2</span></div>${ELEMENTS.map((el) => {\n\t\t\t\t\tconst a = p1?.[el] ?? 0;\n\t\t\t\t\tconst b = p2?.[el] ?? 0;\n\t\t\t\t\treturn html`<div class=\"${el === shared ? 'el-row shared' : 'el-row'}\"><span class=\"el-name\">${el}</span> <span class=\"el-bar p1\"><span>${a}</span> <span class=\"track\"><span style=\"width:${(a / max) * 100}%\"></span></span> </span><span class=\"el-bar p2\"><span class=\"track\"><span style=\"width:${(b / max) * 100}%\"></span></span> <span>${b}</span></span></div>`;\n\t\t\t\t})}</div>${eb.description ? html`<p class=\"shared-note\">${eb.description}</p>` : nothing}</section>`;\n\t}\n\n\t/**\n\t * Per-cycle readings the other two domains carry instead of astrology categories: the numerology core numbers (Life Path, Expression, Soul Urge) and the biorhythm cycle alignments. Both are labelled score-plus-prose, which is exactly what the interpretation accordion is for.\n\t */\n\tprivate renderSubScores() {\n\t\tconst d = this.data;\n\t\tif (!d) return nothing;\n\t\tconst sections: InterpSection[] = [];\n\t\tif ('lifePath' in d) {\n\t\t\tconst cores: Array<[string, typeof d.lifePath]> = [\n\t\t\t\t['Life Path', d.lifePath],\n\t\t\t\t['Expression', d.expression],\n\t\t\t\t['Soul Urge', d.soulUrge],\n\t\t\t];\n\t\t\tfor (const [label, core] of cores) {\n\t\t\t\tif (!core) continue;\n\t\t\t\tsections.push({\n\t\t\t\t\tlabel,\n\t\t\t\t\taside: `${core.person1} and ${core.person2} \u00B7 ${formatNumber(core.compatibility, 0)}%`,\n\t\t\t\t\tbody: core.description ?? '',\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tif ('cycles' in d && d.cycles) {\n\t\t\tfor (const [name, cycle] of Object.entries(d.cycles)) {\n\t\t\t\tif (!cycle) continue;\n\t\t\t\tsections.push({\n\t\t\t\t\tlabel: capitalize(name),\n\t\t\t\t\taside: `${formatNumber(cycle.alignment, 0)}% in step \u00B7 ${cycle.phase?.replace(/_/g, ' ')}`,\n\t\t\t\t\tbody: cycle.description ?? '',\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn renderInterpAccordion(sections, 'compat-sub-scores', 'Breakdown');\n\t}\n\n\t/** The astrology response, or undefined when the card is showing another domain. `signCompatibility` is unique to it, so it is the discriminator. */\n\tprivate astro(): AstroCompat | undefined {\n\t\tconst d = this.data;\n\t\treturn d && 'signCompatibility' in d ? (d as AstroCompat) : undefined;\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';\nimport { cssColor } from '../utils/css-color.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:${cssColor(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", "/**\n * Resolve a crystal colour keyword to a paintable CSS colour.\n *\n * @remarks\n * Two thirds of the 92 colour values the crystals API serves are COMPOUNDS (\"blue-green\", \"pale brass-yellow\", \"deep brownish red\"), and a compound is never a valid CSS colour, so painting the raw string leaves the swatch blank. Both crystal components used to carry their own copy that merely lowercased and stripped spaces, which turns \"apple green\" into `applegreen` and blanks just the same. One resolver now serves both.\n */\n\n/**\n * Colour words the crystals API returns that CSS cannot resolve, mapped to their closest CSS value. Also collapses the `-ish` and plural forms onto their base word, so \"bluish\" and \"browns\" resolve like \"blue\" and \"brown\".\n */\nconst COLOR_WORDS: Record<string, string> = {\n\tapple: '#8db600',\n\tazure: '#007fff',\n\tblackish: 'black',\n\tbluish: 'blue',\n\tbottle: '#006a4e',\n\tbrass: '#b5a642',\n\tbrick: '#b22222',\n\tbrownish: 'brown',\n\tbrowns: 'brown',\n\tburgundy: '#800020',\n\tclear: '#eef2f6',\n\tcolorless: '#eef2f6',\n\tcolourless: '#eef2f6',\n\tcream: '#fffdd0',\n\tcreamy: '#fffdd0',\n\temerald: '#50c878',\n\tgolden: 'gold',\n\tgreenish: 'green',\n\tlilac: '#c8a2c8',\n\tmauve: '#e0b0ff',\n\tpeach: 'peachpuff',\n\tpinkish: 'pink',\n\treddish: 'red',\n\trose: '#f4a6b7',\n\troyal: 'royalblue',\n\tsilvery: 'silver',\n\tsky: 'skyblue',\n\tyellowish: 'yellow',\n};\n\n/** CSS named colours the crystals vocabulary uses verbatim. A word outside this set and {@link COLOR_WORDS} is not a colour, so it is dropped rather than passed through: one unresolvable token would otherwise invalidate the whole color-mix and blank the swatch. */\nconst CSS_COLORS = new Set([\n\t'beige',\n\t'black',\n\t'blue',\n\t'brown',\n\t'crimson',\n\t'cyan',\n\t'gold',\n\t'gray',\n\t'green',\n\t'grey',\n\t'indigo',\n\t'lavender',\n\t'magenta',\n\t'maroon',\n\t'navy',\n\t'olive',\n\t'orange',\n\t'pink',\n\t'purple',\n\t'red',\n\t'salmon',\n\t'silver',\n\t'tan',\n\t'teal',\n\t'turquoise',\n\t'violet',\n\t'white',\n\t'yellow',\n]);\n\n/** Qualifiers that shade a base colour instead of naming one: the mix partner, and how much of the base survives the mix. */\nconst COLOR_QUALIFIERS: Record<string, [partner: string, keepPct: number]> = {\n\tbright: ['white', 85],\n\tdark: ['black', 60],\n\tdeep: ['black', 70],\n\tfaintly: ['white', 30],\n\tlight: ['white', 55],\n\tpale: ['white', 45],\n\trich: ['black', 80],\n};\n\n/**\n * Resolve a crystal colour keyword to a paintable CSS colour.\n *\n * @remarks\n * Two thirds of the 92 colour values the crystals API serves are compounds (\"blue-green\", \"pale brass-yellow\", \"deep brownish red\"), and a compound is never a CSS colour, so painting the raw string leaves the swatch blank. Split on spaces and hyphens instead: qualifiers ({@link COLOR_QUALIFIERS}) shade, the first two colour words mix, and anything unrecognised is dropped. A value with no colour word at all (\"banded\") falls back to the border token rather than painting nothing.\n *\n *\n * @example\n * ```ts\n * cssColor('blue-green'); // color-mix(in srgb, blue, green)\n * cssColor('pale yellow'); // color-mix(in srgb, yellow 45%, white)\n * ```\n */\nexport function cssColor(name: string): string {\n\tconst bases: string[] = [];\n\tconst qualifiers: Array<[string, number]> = [];\n\tfor (const word of name.toLowerCase().split(/[\\s-]+/)) {\n\t\tconst qualifier = COLOR_QUALIFIERS[word];\n\t\tif (qualifier) {\n\t\t\tqualifiers.push(qualifier);\n\t\t\tcontinue;\n\t\t}\n\t\tconst base = COLOR_WORDS[word] ?? (CSS_COLORS.has(word) ? word : '');\n\t\tif (base) bases.push(base);\n\t}\n\n\tconst [first, second] = bases;\n\tif (!first) return 'var(--roxy-border, #e4e4e7)';\n\tlet color = second ? `color-mix(in srgb, ${first}, ${second})` : first;\n\tfor (const [partner, keepPct] of qualifiers) {\n\t\tcolor = `color-mix(in srgb, ${color} ${keepPct}%, ${partner})`;\n\t}\n\treturn color;\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';\nimport { cssColor } from '../utils/css-color.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\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 { disclosureStyles } from '../utils/disclosure.js';\nimport { formatDate, formatNumber } from '../utils/format.js';\nimport {\n\ttype InterpSection,\n\tinterpAccordionStyles,\n\trenderInterpAccordion,\n} from '../utils/interp-accordion.js';\n\ntype DashaData =\n\t| GetCurrentDashaResponse\n\t| GetMajorDashasResponse\n\t| GetSubDashasResponse;\n\ntype DashaPeriod = GetMajorDashasResponse['mahadashas'][number];\ntype Remaining = GetCurrentDashaResponse['remainingInMahadasha'];\n\n/** The level a period sits at, so no view ever labels an antardasha a mahadasha. */\nconst LEVEL_LABEL = {\n\tcurrent: 'Mahadasha',\n\tmajor: 'Mahadasha',\n\tsub: 'Antardasha',\n} as const;\n\n/** \"8y 11m 5d\", the form a dasha reader expects for a remaining balance. */\nfunction formatBalance(b: Remaining | undefined): string {\n\tif (!b) return '';\n\tconst parts: string[] = [];\n\tif (b.years) parts.push(`${b.years}y`);\n\tif (b.months) parts.push(`${b.months}m`);\n\tif (b.days) parts.push(`${b.days}d`);\n\treturn parts.length ? parts.join(' ') : '0d';\n}\n\n/** \"Jun 17, 2018 to Jun 17, 2035\" for the accordion aside. */\nfunction formatSpan(p: { startDate?: string; endDate?: string }): string {\n\tconst start = p.startDate ? formatDate(p.startDate) : '';\n\tconst end = p.endDate ? formatDate(p.endDate) : '';\n\tif (start && end) return `${start} to ${end}`;\n\treturn start || end;\n}\n\n/**\n * Dasha timeline. Renders /vedic-astrology/dasha/{current,major,sub/{...}}.\n *\n * @remarks\n * Default mode shows the active mahadasha, antardasha and pratyantardasha with\n * the reading each one carries. `period=\"major\"` draws the full 120-year\n * Vimshottari timeline; `period=\"sub\"` draws the antardashas inside one\n * mahadasha and states which mahadasha they sit in, since an antardasha means\n * nothing without its parent lord.\n */\n@customElement('roxy-dasha-timeline')\nexport class RoxyDashaTimeline extends RoxyDataElement<DashaData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tdisclosureStyles,\n\t\tinterpAccordionStyles,\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)}.current div small{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);display:block}.balance,.parent{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}.block{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)}`,\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\">${this.heading(d)}</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.renderParentMahadasha(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} ${renderInterpAccordion(this.readings(d, periods), 'roxy-dasha', 'Reading')}</div>`;\n\t}\n\n\tprivate heading(d: DashaData): string {\n\t\tif (this.period === 'major') return 'Vimshottari Mahadasha';\n\t\tif (this.period === 'sub') {\n\t\t\tconst lord = 'mahadashaLord' in d ? d.mahadashaLord : '';\n\t\t\treturn lord ? `Antardashas in ${lord} Mahadasha` : 'Antardashas';\n\t\t}\n\t\treturn 'Active dashas';\n\t}\n\n\tprivate renderBirthBalance(d: DashaData) {\n\t\tif (!('birthDashaBalance' in d) || !d.birthDashaBalance) return nothing;\n\t\tconst lord = 'nakshatraLord' in d && d.nakshatraLord ? d.nakshatraLord : '';\n\t\tconst remaining = formatBalance(d.birthDashaBalance);\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\t/** Sub mode lists antardashas inside one mahadasha, so name the parent and its span. */\n\tprivate renderParentMahadasha(d: DashaData) {\n\t\tif (!('mahadashaPeriod' in d) || !d.mahadashaPeriod) return nothing;\n\t\tconst p = d.mahadashaPeriod;\n\t\tconst span = formatSpan(p);\n\t\treturn html`<p class=\"parent\">Inside the <strong>${p.planet}</strong> Mahadasha${span ? `, ${span}` : ''} ${typeof p.durationYears === 'number' ? `(${formatNumber(p.durationYears, 1)} years)` : ''}.</p>`;\n\t}\n\n\t/**\n\t * Every reading the response carries, behind one exclusive accordion. Current\n\t * mode has three (mahadasha, antardasha, pratyantardasha); sub mode leads with\n\t * the parent mahadasha reading, then the antardasha running now; major mode\n\t * shows the mahadasha running now.\n\t */\n\tprivate readings(d: DashaData, periods: DashaPeriod[]): InterpSection[] {\n\t\tconst sections: InterpSection[] = [];\n\n\t\tif ('mahadashaPeriod' in d && d.mahadashaPeriod?.interpretation) {\n\t\t\tsections.push({\n\t\t\t\tlabel: `${d.mahadashaPeriod.planet} Mahadasha`,\n\t\t\t\taside: formatSpan(d.mahadashaPeriod),\n\t\t\t\tbody: d.mahadashaPeriod.interpretation,\n\t\t\t});\n\t\t}\n\n\t\tif ('mahadasha' in d) {\n\t\t\tconst levels = [\n\t\t\t\t['Mahadasha', d.mahadasha, d.remainingInMahadasha],\n\t\t\t\t['Antardasha', d.antardasha, d.remainingInAntardasha],\n\t\t\t\t['Pratyantardasha', d.pratyantardasha, d.remainingInPratyantardasha],\n\t\t\t] as const;\n\t\t\tfor (const [label, period, remaining] of levels) {\n\t\t\t\tif (!period?.interpretation) continue;\n\t\t\t\tconst left = formatBalance(remaining);\n\t\t\t\tsections.push({\n\t\t\t\t\tlabel: `${period.planet} ${label}`,\n\t\t\t\t\taside: left ? `${left} left` : formatSpan(period),\n\t\t\t\t\tbody: period.interpretation,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tconst active = periods.find((p) => this.isCurrent(p));\n\t\tif (active?.interpretation) {\n\t\t\tsections.push({\n\t\t\t\tlabel: `${active.planet} ${LEVEL_LABEL[this.period]}`,\n\t\t\t\taside: formatSpan(active),\n\t\t\t\tbody: active.interpretation,\n\t\t\t});\n\t\t}\n\n\t\treturn sections;\n\t}\n\n\tprivate renderCurrent(d: DashaData) {\n\t\tif (!('mahadasha' in d)) return nothing;\n\t\tconst levels = [\n\t\t\t['Mahadasha', d.mahadasha, d.remainingInMahadasha],\n\t\t\t['Antardasha', d.antardasha, d.remainingInAntardasha],\n\t\t\t['Pratyantardasha', d.pratyantardasha, d.remainingInPratyantardasha],\n\t\t] as const;\n\t\treturn html`<div class=\"current\">${levels.map(([label, period, remaining]) => {\n\t\t\t\tif (!period) return nothing;\n\t\t\t\tconst left = formatBalance(remaining);\n\t\t\t\treturn html`<div><span>${label}</span> <strong>${period.planet}</strong> ${left ? html`<small>${left} left</small>` : nothing}</div>`;\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 { formatDate, formatNumber, formatTime } from '../utils/format.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; object and\n * object-array values promote to full-width sections below the rows so\n * nested tables keep the whole container width.\n * 5. Otherwise -> definition list of all keys.\n *\n * Scalar display rules (shared by rows, chips, and table cells): numbers\n * round to 2 decimals, booleans read Yes/No, ISO dates and datetimes format\n * for the locale, SCREAMING_SNAKE enums humanize, http(s) strings link out.\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 };\ntype Scalar = string | number | boolean;\n\nconst TITLE_KEYS = ['title', 'name', 'label', 'heading', 'overview', 'summary'];\n/** A title is a label, not a paragraph. `overview`/`summary` are only title candidates when a response carries no real name, and a whole paragraph promoted to an <h3> is worse than no title at all. */\nconst MAX_TITLE_LEN = 80;\nconst IMAGE_KEYS = ['imageUrl', 'image', 'icon', 'symbol'];\nconst SKIP_KEYS = ['imageUrl', 'image']; // rendered separately, not in body rows\nconst QUOTE_KEYS = ['affirmation', 'mantra', 'motto', 'quote'];\n\n/**\n * Response fields that are engineer-facing noise on a reading card, and the rules for hiding them.\n *\n * @remarks\n * This mirrors `SUPPRESS_*` in the WordPress plugin's `src/Support/GenericRenderer.php`. Both render the SAME API responses for the same visitor: `roxy-data` when JavaScript runs, the PHP renderer when it does not. If the two disagree the page visibly changes content on hydration, so they must be kept in sync.\n *\n * Without this, a real `/numerology/life-path` card printed \"Calculation: Month: 6, Day: 15 -> 1+5 = 6, Year: 1990 -> ...\", \"Type: Single\", and a list endpoint printed \"Total: 78, Limit: 3, Offset: 0\". That is how the number was derived and how the API paginates: it is not the reading the visitor asked for.\n */\nconst SUPPRESS_ALWAYS = new Set(['seed']);\n/** Suppressed only when the object carries a title: an untitled record still needs its identifier. */\nconst SUPPRESS_NAMED = new Set(['id', 'slug', 'key']);\nconst SUPPRESS_NOISE = new Set([\n\t'calculation',\n\t'calculations',\n\t'type', // schema discriminator (\"single\", \"general\"): indexes a polymorphic shape, means nothing on a card\n\t'position', // pinnacle/challenge index: already carried by the row order\n\t'count',\n\t'totalcount',\n\t'total',\n\t'limit',\n\t'offset',\n\t'page',\n\t'pagesize',\n\t'perpage',\n]);\n\n/** Sections with more keys than this, and tables with more rows than this, collapse into `<details>`. */\nconst DETAILS_KEYS = 8;\n/** Depth at which a section folds shut by default rather than rendering open. */\nconst DEEP_DEPTH = 1;\nconst DETAILS_ROWS = 12;\n\nconst normKey = (k: string): string => k.toLowerCase().replace(/[_-]/g, '');\n\n/**\n * `hasKarmicDebt` / `is_master`: a true reads better as a badge than as the row \"Has karmic debt: Yes\".\n *\n * @remarks\n * Presentation only. The PHP twin also DROPS the false case as \"silence, not data\", and this deliberately does not follow it there: a generic renderer must never lose a fact the response carries, and `isRetrograde: false` (a planet in direct motion) is a real reading, not an absence. Suppression is reserved for fields that are provably not part of the reading at all, which is what {@link SUPPRESS_NOISE} enumerates.\n *\n * Matching on the camel boundary rejects `island` / `issue` / `history`, which a bare `startsWith('is')` would swallow. The PHP twin tests `strpos($key, 'has_')` against a camelCase key, so its badge branch never actually fires; it hard-suppresses the three keys it knew about instead.\n */\nconst isBadgeKey = (k: string): boolean => /^(has|is)([A-Z_]|$)/.test(k);\n\nconst ISO_DATE =\n\t/^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}(:\\d{2}(\\.\\d+)?)?(Z|[+-]\\d{2}:\\d{2})?)?$/;\nconst ENUM_STRING = /^[A-Z0-9]+(_[A-Z0-9]+)+$/;\nconst LINK_STRING = /^https?:\\/\\//;\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\nfunction isPrimitive(value: Json | undefined): value is Scalar | null {\n\treturn (\n\t\tvalue === null || ['string', 'number', 'boolean'].includes(typeof value)\n\t);\n}\n\n/** Object or object-bearing array: needs full width, never fits a dl value cell. */\nfunction isComplex(value: Json): boolean {\n\treturn (\n\t\tvalue !== null &&\n\t\ttypeof value === 'object' &&\n\t\t!(Array.isArray(value) && value.every(isPrimitive))\n\t);\n}\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-card a{color:var(--roxy-accent-ink,#b45309)}.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{grid-template-columns:minmax(8ch, min(30%, max-content)) minmax(0, 1fr);gap:var(--roxy-space-xs,.25rem) var(--roxy-space-md,1rem);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}.roxy-table-wrap{min-width:0;overflow-x:auto}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;word-break:normal;overflow-wrap:normal}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;white-space:nowrap}table.roxy-table th.col-tight,table.roxy-table td.col-tight{white-space:nowrap;width:1%}table.roxy-table th.col-wide,table.roxy-table td.col-wide{width:auto}.roxy-image{border-radius:var(--roxy-radius-md,8px);max-width:100%;height:auto;margin-bottom:var(--roxy-space-md,1rem)}.roxy-section{margin-top: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}blockquote.roxy-quote{margin:var(--roxy-space-md,1rem) 0;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);color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);font-style:italic}.roxy-badge{border-radius:var(--roxy-radius-full,9999px);background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 18%, transparent);color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);padding:1px 8px;display:inline-block}details.roxy-section,details.roxy-table-details{margin-top:var(--roxy-space-md,1rem)}details.roxy-section>summary,details.roxy-table-details>summary{cursor:pointer;font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-secondary,#475569);text-transform:capitalize}details.roxy-section>summary:focus-visible,details.roxy-table-details>summary:focus-visible{outline:2px solid var(--roxy-ring,#f59e0b66);outline-offset:2px;border-radius:4px}`,\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\">Nested data omitted</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 (isPrimitive(value)) return html`<p>${this.scalarTemplate(value)}</p>`;\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\tif (arr.every(isPrimitive)) {\n\t\t\treturn this.renderChips(arr as (Scalar | null)[]);\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 renderChips(arr: (Scalar | null)[]): TemplateResult {\n\t\treturn html`<ul class=\"roxy-chips\">${arr\n\t\t\t\t.filter((v): v is Scalar => v !== null)\n\t\t\t\t.map((v) => html`<li>${this.formatScalar(v)}</li>`)}</ul>`;\n\t}\n\n\tprivate renderTable(rows: Record<string, Json>[]): TemplateResult {\n\t\tconst clean = rows.map((r) => this.suppress(r));\n\t\tconst keys = this.collectKeys(clean);\n\n\t\t/**\n\t\t * A column holding nested data needs the width; a column holding a short scalar does not.\n\t\t *\n\t\t * @remarks\n\t\t * Browsers lay an auto table out by content, so a `date` column of ten characters and a `positions` column holding a whole nested table settle at roughly half the width each, and the nested one is the one that ends up cramped. Marking each column by what it actually CONTAINS lets the scalar columns collapse to their content (`width: 1%` is the standard way to say \"as narrow as your content allows\") and the nested column absorb everything left over. No fixed percentage: the split follows the data.\n\t\t *\n\t\t * Only worth doing when the row is mixed. If every column is scalar, or every column is nested, there is nothing to bias toward and the browser's own distribution is already right.\n\t\t */\n\t\tconst complex = new Set(\n\t\t\tkeys.filter((k) => clean.some((r) => isComplex(r[k] ?? null))),\n\t\t);\n\t\tconst mixed = complex.size > 0 && complex.size < keys.length;\n\t\tconst colClass = (k: string) =>\n\t\t\tmixed ? (complex.has(k) ? 'col-wide' : 'col-tight') : '';\n\n\t\tconst table = html`<div class=\"roxy-table-wrap\" role=\"group\" aria-label=\"Data table\" tabindex=\"0\"><table class=\"roxy-table\" role=\"table\"><thead><tr>${keys.map(\n\t\t\t\t\t\t\t(k) => html`<th class=\"${colClass(k)}\">${humanize(k)}</th>`,\n\t\t\t\t\t\t)}</tr></thead><tbody>${clean.map(\n\t\t\t\t\t\t(row) => html`<tr>${keys.map(\n\t\t\t\t\t\t\t\t(k) =>\n\t\t\t\t\t\t\t\t\thtml`<td class=\"${colClass(k)}\">${this.renderCell(row[k], k)}</td>`,\n\t\t\t\t\t\t\t)}</tr>`,\n\t\t\t\t\t)}</tbody></table></div>`;\n\t\t// A 78-row angel-number list or a 27-row nakshatra table is a scroll trap\n\t\t// inline. Past the threshold it folds away behind its own row count.\n\t\tif (clean.length > DETAILS_ROWS) {\n\t\t\treturn html`<details class=\"roxy-table-details\"><summary>${clean.length} rows</summary>${table}</details>`;\n\t\t}\n\t\treturn table;\n\t}\n\n\t/** Drop the fields that are noise on a reading card. See {@link SUPPRESS_NOISE}. */\n\tprivate suppress(obj: Record<string, Json>): Record<string, Json> {\n\t\tconst titled = TITLE_KEYS.some((k) => typeof obj[k] === 'string');\n\t\treturn Object.fromEntries(\n\t\t\tObject.entries(obj).filter(([k]) => {\n\t\t\t\tconst n = normKey(k);\n\t\t\t\tif (SUPPRESS_ALWAYS.has(n)) return false;\n\t\t\t\tif (titled && SUPPRESS_NAMED.has(n)) return false;\n\t\t\t\treturn !SUPPRESS_NOISE.has(n);\n\t\t\t}),\n\t\t);\n\t}\n\n\tprivate renderObject(input: Record<string, Json>): TemplateResult {\n\t\tconst obj = this.suppress(input);\n\t\tconst titleKey = TITLE_KEYS.find(\n\t\t\t(k) =>\n\t\t\t\ttypeof obj[k] === 'string' &&\n\t\t\t\t(obj[k] as string).length <= MAX_TITLE_LEN,\n\t\t);\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 quoteKey = QUOTE_KEYS.find((k) => typeof obj[k] === 'string');\n\t\tconst entries = 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\tk !== quoteKey &&\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\t\t// Scalars and primitive arrays fit the two-column rows; objects and\n\t\t// object arrays promote to full-width sections so nested tables are\n\t\t// not squeezed into the value column.\n\t\tconst rows = entries.filter(([, v]) => !isComplex(v));\n\t\tconst sections = entries.filter(([, v]) => isComplex(v));\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} ${quoteKey ? html`<blockquote class=\"roxy-quote\">${obj[quoteKey]}</blockquote>` : 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, k)}</dd>`,\n\t\t\t\t\t\t)}</dl>`\n\t\t\t\t\t: nothing\n\t\t\t} ${sections.map(([k, v]) => this.renderSection(k, v))}`;\n\t}\n\n\t/**\n\t * A named block of nested data. Collapses into `<details>` once it carries more than {@link DETAILS_KEYS} keys, so one fat object (a 27-nakshatra map, a 12-house table) cannot bury the rest of the card under a wall of rows.\n\t */\n\tprivate renderSection(key: string, value: Json): TemplateResult {\n\t\tconst size =\n\t\t\tvalue !== null && typeof value === 'object'\n\t\t\t\t? Array.isArray(value)\n\t\t\t\t\t? value.length\n\t\t\t\t\t: Object.keys(value).length\n\t\t\t\t: 0;\n\t\tconst body = this.renderField(value, key);\n\t\tconst heading = humanize(key);\n\t\t// Past depth 1 a section folds shut by default. A real /numerology/chart response\n\t\t// rendered every level open and grew to a 29,933px-tall element, about thirty\n\t\t// screens of correct but unusable output. The reader opens what they want.\n\t\tif (size > DETAILS_KEYS || this.depth >= DEEP_DEPTH) {\n\t\t\treturn html`<details class=\"roxy-section\" ?open=\"${this.depth < DEEP_DEPTH}\"><summary>${heading}</summary>${body}</details>`;\n\t\t}\n\t\treturn html`<div class=\"roxy-section\"><h4>${heading}</h4>${body}</div>`;\n\t}\n\n\tprivate renderField(value: Json, key?: string): TemplateResult | string {\n\t\tif (value === null || value === undefined) return '';\n\t\tif (value === true && key !== undefined && isBadgeKey(key)) {\n\t\t\treturn html`<span class=\"roxy-badge\">Yes</span>`;\n\t\t}\n\t\tif (isPrimitive(value)) return html`${this.scalarTemplate(value)}`;\n\t\tif (Array.isArray(value) && value.every(isPrimitive)) {\n\t\t\treturn this.renderChips(value as (Scalar | null)[]);\n\t\t}\n\t\t// `bare`: a nested card inside a card compounds padding and border at every\n\t\t// level, and by depth 3 the innermost object was rendering into a fraction of the\n\t\t// width with prose wrapping to two words a line.\n\t\treturn html`<roxy-data bare .data=\"${value}\" .depth=\"${this.depth + 1}\"></roxy-data>`;\n\t}\n\n\tprivate renderCell(\n\t\tvalue: Json | undefined,\n\t\tkey?: string,\n\t): TemplateResult | string {\n\t\tif (value === null || value === undefined) return '';\n\t\tif (value === true && key !== undefined && isBadgeKey(key)) {\n\t\t\treturn html`<span class=\"roxy-badge\">Yes</span>`;\n\t\t}\n\t\tif (isPrimitive(value)) return this.scalarTemplate(value);\n\t\tif (Array.isArray(value) && value.every(isPrimitive)) {\n\t\t\treturn (value as (Scalar | null)[])\n\t\t\t\t.filter((v): v is Scalar => v !== null)\n\t\t\t\t.map((v) => this.formatScalar(v))\n\t\t\t\t.join(', ');\n\t\t}\n\t\t// Nested object or object array inside a row: recurse instead of\n\t\t// stringifying to [object Object]. `bare` drops the card surface so\n\t\t// the cell does not paint a card inside a cell.\n\t\treturn html`<roxy-data bare .data=\"${value}\" .depth=\"${this.depth + 1}\"></roxy-data>`;\n\t}\n\n\tprivate scalarTemplate(value: Scalar): TemplateResult | string {\n\t\tif (typeof value === 'string' && LINK_STRING.test(value)) {\n\t\t\treturn html`<a href=\"${value}\" target=\"_blank\" rel=\"noopener noreferrer\">${value}</a>`;\n\t\t}\n\t\treturn this.formatScalar(value);\n\t}\n\n\tprivate formatScalar(value: Scalar): string {\n\t\tif (typeof value === 'number') {\n\t\t\treturn formatNumber(value, 2) || String(value);\n\t\t}\n\t\tif (typeof value === 'boolean') return value ? 'Yes' : 'No';\n\t\tif (ISO_DATE.test(value)) {\n\t\t\tconst time = formatTime(value);\n\t\t\tconst date = formatDate(value);\n\t\t\treturn time ? `${date}, ${time}` : date;\n\t\t}\n\t\tif (ENUM_STRING.test(value)) return humanize(value.toLowerCase());\n\t\treturn 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 { 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\t/** True when the spec declares the field as `in: query`, so it belongs in the query string even on a POST (`?lang=` is the one every localized endpoint carries). */\n\tinQuery?: boolean;\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\t// A path param is substituted into the URL template by name, so only\n\t\t\t\t\t\t// a true query param needs the query-string routing flag.\n\t\t\t\t\t\tinQuery: param.in === 'query',\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: {\n\t\t\t\t\tendpoint: this.endpoint,\n\t\t\t\t\tvalues: out,\n\t\t\t\t\t// The spec knows which of these belong in the query string; the\n\t\t\t\t\t// listener does not. Report them so a POST with `?lang=` reaches the\n\t\t\t\t\t// API as a query parameter instead of an ignored body key.\n\t\t\t\t\tqueryKeys: this.fields.filter((f) => f.inQuery).map((f) => f.name),\n\t\t\t\t},\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 { interpAccordionStyles } from '../utils/interp-accordion.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\tinterpAccordionStyles,\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);grid-template-columns:minmax(0,1fr);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-lead .point{color:var(--roxy-accent-ink,#b45309);font-weight:var(--roxy-weight-bold,600)}.interp-aside small{font-variant-numeric:tabular-nums}.catalog summary{cursor:pointer;color:var(--roxy-fg,#0a0a0a);align-items:center;gap:.5rem;font-weight:600;display:flex}.scroll{min-width:0;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(\n\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\tc,\n\t\t\t\t\t\t\t\ti,\n\t\t\t\t\t\t\t) => html`<details class=\"interp-card\" name=\"fixed-star-contacts\" ?open=\"${i === 0}\"><summary><span class=\"interp-lead\"><span class=\"point\">${c.point}</span> conjunct ${c.star}</span> ${chevron()} <span class=\"interp-aside\"><small>orb ${formatNumber(c.orb, 2)}\u00B0</small></span></summary>${c.interpretation ? html`<div class=\"interp-body\"><p>${c.interpretation}</p></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\n/**\n * The eight kootas and the points each carries, in the classical order the API\n * returns them. Used only as a fallback when a payload omits `maxScore`; the\n * spec marks it required. The names are the canonical ones (Vashya, Graha\n * Maitri), not the shortened forms.\n */\nconst KOOTA_MAX: Record<string, number> = {\n\tvarna: 1,\n\tvashya: 2,\n\ttara: 3,\n\tyoni: 4,\n\t'graha maitri': 5,\n\tgana: 6,\n\tbhakoot: 7,\n\tnadi: 8,\n};\n\n/**\n * 36-point Ashtakoota score card. Renders /vedic-astrology/compatibility.\n *\n * @remarks\n * Each koota row carries what it actually evaluates and how each person\n * classifies under it (Varna: Shudra against Shudra, Yoni: Sheep against Horse),\n * because the point total alone tells a couple nothing about WHY a koota scored\n * as it did.\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)}.verdict-wrap{justify-items:end;gap:var(--roxy-space-xs,.25rem);text-align:right;display:grid}.verdict{border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);padding:1px 10px}.verdict.yes{background:color-mix(in srgb, var(--roxy-success,#16a34a) 16%, transparent);color:var(--roxy-success-fg,#166534)}.verdict.no{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 16%, transparent);color:var(--roxy-danger-fg,#991b1b)}.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 small{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);margin-top:2px;line-height:1.5;display:block}td.classification{color:var(--roxy-secondary,#475569);white-space:nowrap}th.score{text-align:right}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:22%}@container (width<=32rem){.bar-col{display:none}}.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><div class=\"verdict-wrap\">${\n\t\t\t\t\t\t\t\ttypeof d.isCompatible === 'boolean'\n\t\t\t\t\t\t\t\t\t? html`<span class=\"verdict ${d.isCompatible ? 'yes' : 'no'}\">${d.isCompatible ? 'Compatible' : 'Not compatible'}</span>`\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\td.recommendation\n\t\t\t\t\t\t\t\t\t? html`<span class=\"recommendation\">${d.recommendation}</span>`\n\t\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t\t}</div></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><caption class=\"roxy-sr-only\">Guna Milan breakdown: each koota with the classification of person 1 and person 2, and the score it earned out of its maximum.</caption><thead><tr><th scope=\"col\">Koota</th><th scope=\"col\">Person 1</th><th scope=\"col\">Person 2</th><th scope=\"col\" class=\"bar-col\">Progress</th><th scope=\"col\" 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} ${b.description ? html`<small>${b.description}</small>` : nothing}</td><td class=\"classification\">${b.person1 ?? ''}</td><td class=\"classification\">${b.person2 ?? ''}</td><td class=\"bar-cell bar-col\"><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\treturn (name && KOOTA_MAX[name.toLowerCase()]) || 1;\n}\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 { disclosureStyles } from '../utils/disclosure.js';\nimport { hdReadingStyles, renderHdFacts } from '../utils/hd-reading.js';\nimport {\n\ttype InterpSection,\n\tinterpAccordionStyles,\n\trenderInterpAccordion,\n} from '../utils/interp-accordion.js';\nimport { humanize } from '../utils/string.js';\n\ntype Connection = CalculateConnectionResponse;\ntype ConnectionChannel = Connection['channels'][number];\ntype CombinedCenter = Connection['centers'][number];\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 * @remarks\n * The chart answers one question: what exists between these two that does not exist in either of them alone. So the combined centers are the lead, not the channel list. `defined` is the state of the COMBINED bodygraph, `definedBy` names who already defines that center in their own chart, and the gap between the two is the reading: a center that comes back defined with an empty `definedBy` is defined by the connection itself, present when the two are together and absent when they are apart.\n *\n * The four dynamics are the taxonomy the summary counts, and a bare count of \"Dominance: 2\" means nothing to a reader who does not already know the system, so each one carries its definition behind the shared disclosure rather than shipping as a bare label.\n */\n@customElement('roxy-hd-connection')\nexport class RoxyHdConnection extends RoxyDataElement<Connection> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tdisclosureStyles,\n\t\tinterpAccordionStyles,\n\t\thdReadingStyles,\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);grid-template-columns:minmax(0,1fr);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}.note{margin:0 0 var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);line-height:1.6}.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}.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.together{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 18%, transparent);color:var(--roxy-fg,#0a0a0a)}.who{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem)}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}.held{font-variant-numeric:tabular-nums}.scroll{min-width:0;overflow-x:auto}`,\n\t];\n\n\tprotected renderData(d: Connection) {\n\t\tconst channels = d.channels ?? [];\n\t\tconst centers = d.centers ?? [];\n\t\tconst definedCenters = centers.filter((c) => c.defined).length;\n\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>${renderHdFacts([\n\t\t\t\t{ label: 'Channels', value: d.totalChannels?.toString() },\n\t\t\t\t{\n\t\t\t\t\tlabel: 'Combined definition',\n\t\t\t\t\tvalue: d.combinedDefinition\n\t\t\t\t\t\t? humanize(String(d.combinedDefinition))\n\t\t\t\t\t\t: undefined,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: 'Centers defined',\n\t\t\t\t\tvalue:\n\t\t\t\t\t\tcenters.length > 0\n\t\t\t\t\t\t\t? `${definedCenters} of ${centers.length}`\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t},\n\t\t\t])}<p class=\"lead\">A connection chart reads the two charts as one bodygraph. Wherever the two of them together hold both gates of a channel, that channel is defined between them, and the centers it joins are defined in the connection whether or not either person defines them alone.</p>${this.renderDynamics(d.summary)} ${this.renderCenters(centers)} ${this.renderChannels(channels, centers)}</div>`;\n\t}\n\n\t/**\n\t * The four ways two charts can meet in a channel, in canonical order, each with what it means. The count is the aside, so the taxonomy and the tally read as one thing: a dynamic with no channels still shows, because its absence is as much a fact of the connection as its presence.\n\t */\n\tprivate renderDynamics(s: Connection['summary'] | undefined) {\n\t\tif (!s) return nothing;\n\t\tconst sections: InterpSection[] = [\n\t\t\t{\n\t\t\t\tlabel: 'Electromagnetic',\n\t\t\t\taside: channelCount(s.electromagnetic),\n\t\t\t\tbody: 'Each person holds one of the two gates, so the channel completes only when they are together. The classic point of attraction.',\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: 'Dominance',\n\t\t\t\taside: channelCount(s.dominance),\n\t\t\t\tbody: 'One person holds both gates and the other holds neither, so the conditioning runs one way, from the person who carries the channel to the person who does not.',\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: 'Compromise',\n\t\t\t\taside: channelCount(s.compromise),\n\t\t\t\tbody: 'One person holds both gates and the other holds a single hanging gate of the same channel, so the channel is complete for one of them and half open for the other.',\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: 'Companionship',\n\t\t\t\taside: channelCount(s.companionship),\n\t\t\t\tbody: 'Both people independently hold both gates, so neither needs the other to complete it. A shared and familiar frequency rather than an attraction.',\n\t\t\t},\n\t\t];\n\t\treturn renderInterpAccordion(sections, 'hd-connection-dynamic', 'Dynamics');\n\t}\n\n\t/**\n\t * The nine centers of the combined chart. `defined` is the combined state and `definedBy` is who carries it alone, so the two together say whether a center is brought to the connection or created by it.\n\t */\n\tprivate renderCenters(centers: CombinedCenter[]) {\n\t\tif (centers.length === 0) return nothing;\n\t\treturn html`<section class=\"block\"><h3>Centers</h3><p class=\"note\">Defined is the state of the combined chart. Beside it is who already defines that center in their own chart. A center defined only together is what the connection itself creates: it is there when the two are together and gone when they are apart. The combined definition counts how the defined centers hang together, so Single is one connected piece and a split is more than one.</p>${centers.map((c) => {\n\t\t\t\tconst by = c.definedBy ?? [];\n\t\t\t\tconst a = by.includes('A');\n\t\t\t\tconst b = by.includes('B');\n\t\t\t\t// Only the connection defines it: defined in the combined chart, and in\n\t\t\t\t// neither chart on its own.\n\t\t\t\tconst together = Boolean(c.defined) && !a && !b;\n\t\t\t\treturn html`<div class=\"row\"><span class=\"cname\">${c.name ?? humanize(String(c.id ?? ''))}</span> <span class=\"badge ${c.defined ? (together ? 'together' : 'defined') : 'open'}\">${c.defined ? (together ? 'Only together' : 'Defined') : 'Open'} </span><span class=\"who\">${centerWho(Boolean(c.defined), a, b)}</span></div>`;\n\t\t\t})}</section>`;\n\t}\n\n\t/**\n\t * Every connected channel. The centers a channel joins are named, not left as ids, because the row is what explains a defined center in the block above: this is the wiring that produced it.\n\t */\n\tprivate renderChannels(\n\t\tchannels: ConnectionChannel[],\n\t\tcenters: CombinedCenter[],\n\t) {\n\t\tif (channels.length === 0) return nothing;\n\t\tconst names = new Map(\n\t\t\tcenters.map((c) => [String(c.id ?? ''), c.name ?? ''] as const),\n\t\t);\n\t\tconst centerName = (id: string) => names.get(id) || humanize(id);\n\n\t\treturn html`<section class=\"block\"><h3>Channels</h3><div class=\"scroll\" tabindex=\"0\" role=\"region\" aria-label=\"Connection channels\"><table role=\"table\"><caption class=\"roxy-sr-only\">Connection channels: each channel with its gates, the centers it links, its circuit and dynamic, and the gates person A and person B each hold.</caption><thead><tr><th scope=\"col\">Channel</th><th scope=\"col\">Gates</th><th scope=\"col\">Centers</th><th scope=\"col\">Circuit</th><th scope=\"col\">Dynamic</th><th scope=\"col\">Person A holds</th><th scope=\"col\">Person B holds</th></tr></thead><tbody>${channels.map(\n\t\t\t\t\t\t\t(c) => html`<tr><td>${c.name ?? ''}</td><td class=\"gates\">${c.gateA}-${c.gateB}</td><td>${(c.centers ?? []).map(centerName).join(' to ')}</td><td>${c.circuit ?? ''}</td><td>${c.dynamic ? html`<span class=\"dyn\">${c.dynamic}</span>` : nothing}</td><td class=\"held\">${gateList(c.personAGates)}</td><td class=\"held\">${gateList(c.personBGates)}</td></tr>`,\n\t\t\t\t\t\t)}</tbody></table></div></section>`;\n\t}\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No connection data</div>`;\n\t}\n}\n\n/** The aside of a dynamic. A zero is stated rather than hidden: no companionship channels is a finding about the pair. */\nfunction channelCount(n: number | undefined): string | undefined {\n\tif (typeof n !== 'number') return undefined;\n\tif (n === 0) return 'None';\n\treturn n === 1 ? '1 channel' : `${n} channels`;\n}\n\n/** Which gates of the channel this person carries. Neither is possible: a dominance channel is held entirely by the other person. */\nfunction gateList(gates: number[] | undefined): string {\n\tconst list = gates ?? [];\n\treturn list.length > 0 ? list.join(', ') : 'Neither';\n}\n\n/** Who defines the center in their own chart, spelled out. `definedBy` is empty both when the center is open in both charts and when only the connection defines it, so the combined state has to disambiguate. */\nfunction centerWho(defined: boolean, a: boolean, b: boolean): string {\n\tif (a && b) return 'Defined in both charts';\n\tif (a) return 'Defined by A';\n\tif (b) return 'Defined by B';\n\treturn defined\n\t\t? 'Defined by neither alone, only by the connection'\n\t\t: 'Open in both charts';\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';\nimport { hdReadingStyles, renderHdFacts } from '../utils/hd-reading.js';\n\ntype Penta = CalculatePentaResponse;\ntype PentaChannel = Penta['channels'][number];\ntype PentaGate = Penta['gates'][number];\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 * @remarks\n * The penta is the only Human Design chart whose subject is a group rather than a person, so every row answers \"who supplies this\" as well as \"is it there\". The response reports that as zero-based indices into the member list that was sent, which is the one thing a card must not print raw: members are lettered instead, A for the first member sent, and the footnote says so.\n *\n * Read in two passes. The channels are the functions the group performs, and a channel is a defined Strength only when both of its gates are held somewhere in the group, so the attribution line under each one shows which member carries which end. The twelve gates below are the same data seen per role, and they are where a gap shows up as itself: a gate held by nobody, which the summary also counts.\n */\n@customElement('roxy-hd-penta')\nexport class RoxyHdPenta extends RoxyDataElement<Penta> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\thdReadingStyles,\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)}.section{border-top:1px solid var(--roxy-border,#e4e4e7);padding-top:var(--roxy-space-md,1rem)}.section h3{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;margin:0}.note{margin:var(--roxy-space-xs,.25rem) 0 0;font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);line-height:1.6}.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,.gate-id{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}.circuit{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);display:block}.held{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);flex-basis:100%;line-height:1.6}.who{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem)}.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)}.badge.gap{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 16%, transparent);color:var(--roxy-danger-fg,#991b1b)}.footnote{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);margin:0;line-height:1.6}`,\n\t];\n\n\tprotected renderData(d: Penta) {\n\t\tconst channels = d.channels ?? [];\n\t\tconst gates = d.gates ?? [];\n\t\tconst s = d.summary;\n\t\tconst gaps = s?.gapGates ?? [];\n\t\tconst hasCore = channels.some((c) => c.isCore);\n\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>${renderHdFacts([\n\t\t\t\t{ label: 'Members', value: d.memberCount?.toString() },\n\t\t\t\t{\n\t\t\t\t\tlabel: 'Defined channels',\n\t\t\t\t\tvalue:\n\t\t\t\t\t\ttypeof s?.definedChannels === 'number' && channels.length > 0\n\t\t\t\t\t\t\t? `${s.definedChannels} of ${channels.length}`\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: 'Filled gates',\n\t\t\t\t\tvalue:\n\t\t\t\t\t\ttypeof s?.filledGates === 'number' && gates.length > 0\n\t\t\t\t\t\t\t? `${s.filledGates} of ${gates.length}`\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: 'Core',\n\t\t\t\t\tvalue:\n\t\t\t\t\t\ttypeof s?.coreDefined === 'boolean'\n\t\t\t\t\t\t\t? s.coreDefined\n\t\t\t\t\t\t\t\t? 'Defined'\n\t\t\t\t\t\t\t\t: 'Open'\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: 'Gap gates',\n\t\t\t\t\tvalue: gaps.length > 0 ? gaps.join(', ') : undefined,\n\t\t\t\t},\n\t\t\t])}<p class=\"lead\">A penta is the field three to five people form when they work as a group. It is read from the twelve penta gates the members bring between them: a channel with both of its gates held somewhere in the group is a defined Strength, and a gate no member holds is a gap the group has to compensate for.</p>${this.renderGroup(\n\t\t\t\t'Upper (direction)',\n\t\t\t\tchannels.filter((c) => c.position === 'upper'),\n\t\t\t\t'Upper channels run from the G Center to the Throat. They carry the leadership of the group and how it presents itself.',\n\t\t\t)} ${this.renderGroup(\n\t\t\t\t'Lower (execution)',\n\t\t\t\tchannels.filter((c) => c.position === 'lower'),\n\t\t\t\t'Lower channels run from the G Center to the Sacral. They carry the managed, generative, resource work.',\n\t\t\t)} ${\n\t\t\t\t// A position the API adds later must not silently drop the channel from\n\t\t\t\t// the card: anything that is neither triangle still renders.\n\t\t\t\tthis.renderGroup(\n\t\t\t\t\t'Channels',\n\t\t\t\t\tchannels.filter(\n\t\t\t\t\t\t(c) => c.position !== 'upper' && c.position !== 'lower',\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t} ${\n\t\t\t\thasCore\n\t\t\t\t\t? html`<p class=\"footnote\">Core is the 2/14 Channel of the Beat, the material core of the penta: gate 2 sets the direction for resources, gate 14 is the resources themselves.</p>`\n\t\t\t\t\t: nothing\n\t\t\t} ${this.renderGates(gates)} ${\n\t\t\t\tchannels.length > 0 || gates.length > 0\n\t\t\t\t\t? html`<p class=\"footnote\">Members are lettered in the order they were sent, so A is the first member of the group.</p>`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n\n\t/**\n\t * One triangle of the penta. The note is what the triangle does, so it sits with the heading rather than being repeated on each of its three channels.\n\t */\n\tprivate renderGroup(label: string, channels: PentaChannel[], note?: string) {\n\t\tif (channels.length === 0) return nothing;\n\t\treturn html`<div class=\"section\"><h3>${label}</h3>${note ? html`<p class=\"note\">${note}</p>` : nothing} ${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 ?? ''} ${c.circuit ? html`<span class=\"circuit\">${c.circuit} circuit</span>` : nothing} </span><span class=\"badge ${c.defined ? 'defined' : 'open'}\">${c.defined ? 'Defined' : 'Open'}</span> ${c.isCore ? html`<span class=\"badge core\">Core</span>` : nothing} <span class=\"held\">Gate ${c.gateA} held by ${members(c.gateAHeldBy)}. Gate ${c.gateB} held by ${members(c.gateBHeldBy)}.</span></div>`,\n\t\t\t)}</div>`;\n\t}\n\n\t/**\n\t * The twelve penta gates, each with the role it brings and the members who carry it. A gate nobody holds is the gap the summary counts, so it is flagged rather than left as an empty attribution.\n\t */\n\tprivate renderGates(gates: PentaGate[]) {\n\t\tif (gates.length === 0) return nothing;\n\t\tconst filled = gates.filter((g) => g.filled).length;\n\t\treturn html`<div class=\"section\"><h3>Gates (${filled} of ${gates.length} filled)</h3><p class=\"note\">The role each gate brings to the group, and who carries it. A gap is a role no member holds, so the group compensates for it.</p>${gates.map(\n\t\t\t\t(g) => html`<div class=\"row\"><span class=\"gate-id\">${g.gate}</span> <span class=\"cname\">${g.gateName ?? ''}</span> ${\n\t\t\t\t\t\tg.filled\n\t\t\t\t\t\t\t? html`<span class=\"who\">Held by ${members(g.heldBy)}</span>`\n\t\t\t\t\t\t\t: html`<span class=\"badge gap\">Gap</span>`\n\t\t\t\t\t}</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\n/**\n * Members are lettered, not numbered. The response reports them as zero-based indices into the member list that was sent, and printing a raw \"0\" on a card reads as a bug; \"Member 1\" for index 0 would contradict the API the developer is reading beside it. A letter is unambiguous either way, and it matches how `roxy-hd-connection` names person A and person B. Five is the ceiling: the endpoint takes 3 to 5 members.\n */\nconst MEMBER_LETTERS = 'ABCDE';\n\nfunction members(indices: number[] | undefined): string {\n\tconst held = (indices ?? []).map((i) => MEMBER_LETTERS[i] ?? String(i + 1));\n\treturn held.length > 0 ? held.join(', ') : 'nobody';\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 {\n\tCalculateProfileResponse,\n\tCalculateTypeResponse,\n} from '../types/index.js';\nimport { RoxyDataElement } from '../utils/base-element.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { disclosureStyles } from '../utils/disclosure.js';\nimport {\n\thdReadingStyles,\n\trenderHdFacts,\n\trenderHdKeynotes,\n\trenderHdReading,\n\trenderHdThemes,\n} from '../utils/hd-reading.js';\nimport { interpAccordionStyles } from '../utils/interp-accordion.js';\n\ntype HdIdentity = CalculateTypeResponse | CalculateProfileResponse;\n\n/**\n * The Human Design identity read on its own, without the chart. Pass `data` from `/human-design/type` or `/human-design/profile`.\n *\n * @remarks\n * Both endpoints answer \"who is this person\" rather than \"how is the chart wired\", so one card serves both and detects which it was given: the type response leads with the type and carries the strategy, authority, and aura readings; the profile response carries the two lines and their keynotes. This is the same shape-detecting pattern `roxy-positions-table` uses across the five Western point-list endpoints.\n *\n * The interpretation surface (fact tiles, lead paragraph, signature and not-self pills, the exclusive reading accordion, the line keynotes) is shared with `roxy-bodygraph` through `utils/hd-reading.ts`, because `/human-design/type` returns a strict subset of the bodygraph interpretation fields. Reach for `roxy-bodygraph` when the chart itself is wanted; reach for this when only the reading is.\n */\n@customElement('roxy-hd-type-card')\nexport class RoxyHdTypeCard extends RoxyDataElement<HdIdentity> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tdisclosureStyles,\n\t\tinterpAccordionStyles,\n\t\thdReadingStyles,\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}.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)}`,\n\t];\n\n\tprotected renderEmpty() {\n\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No Human Design data</div>`;\n\t}\n\n\tprotected renderData(d: HdIdentity) {\n\t\treturn isTypeShape(d) ? this.renderType(d) : this.renderProfile(d);\n\t}\n\n\t/**\n\t * The type read. The tiles answer it at a glance, the lead paragraph grounds the type label in what the aura actually does, and the accordion carries the three interpretations that make the chart actionable: how to engage (strategy), how to decide (authority), and how the field is felt by others (aura).\n\t */\n\tprivate renderType(d: CalculateTypeResponse) {\n\t\treturn html`<div class=\"wrap\"><header class=\"head\"><h2 class=\"title\">Type</h2>${\n\t\t\t\t\td.type || d.profile\n\t\t\t\t\t\t? html`<div class=\"type-line\">${[d.type, d.profile ? `Profile ${d.profile}` : ''].filter(Boolean).join(' \u00B7 ')}</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</header>${renderHdFacts([\n\t\t\t\t{ label: 'Type', value: d.type },\n\t\t\t\t{ label: 'Strategy', value: d.strategy },\n\t\t\t\t{ label: 'Authority', value: d.authority },\n\t\t\t\t{ label: 'Profile', value: d.profile },\n\t\t\t])} ${d.typeDescription ? html`<p class=\"lead\">${d.typeDescription}</p>` : nothing} ${renderHdThemes(d.signature, d.notSelf)} ${renderHdReading(\n\t\t\t\t[\n\t\t\t\t\t{ label: 'Strategy', aside: d.strategy, body: d.strategyDescription },\n\t\t\t\t\t{\n\t\t\t\t\t\tlabel: 'Authority',\n\t\t\t\t\t\taside: d.authority,\n\t\t\t\t\t\tbody: d.authorityDescription,\n\t\t\t\t\t},\n\t\t\t\t\t{ label: 'Aura', body: d.aura },\n\t\t\t\t],\n\t\t\t\t'hd-type-reading',\n\t\t\t)}</div>`;\n\t}\n\n\t/**\n\t * The profile read. Two keynote sentences, so they render open as a definition list rather than behind a disclosure: putting a single sentence behind a click costs the reader more than it saves.\n\t */\n\tprivate renderProfile(d: CalculateProfileResponse) {\n\t\treturn html`<div class=\"wrap\"><header class=\"head\"><h2 class=\"title\">Profile</h2>${d.profile ? html`<div class=\"type-line\">${d.profile}</div>` : nothing}</header>${renderHdFacts([\n\t\t\t\t{ label: 'Profile', value: d.profile },\n\t\t\t\t{ label: 'Personality line', value: d.personalityLine?.toString() },\n\t\t\t\t{ label: 'Design line', value: d.designLine?.toString() },\n\t\t\t])}<section class=\"block\"><h3>Lines</h3>${renderHdKeynotes({\n\t\t\t\t\tpersonality: d.personalityKeynote,\n\t\t\t\t\tpersonalityLine: d.personalityLine,\n\t\t\t\t\tdesign: d.designKeynote,\n\t\t\t\t\tdesignLine: d.designLine,\n\t\t\t\t})}</section></div>`;\n\t}\n}\n\n/** The two responses share only `profile`, so the type field is what tells them apart. */\nfunction isTypeShape(d: HdIdentity): d is CalculateTypeResponse {\n\treturn typeof (d as CalculateTypeResponse).type === 'string';\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-hd-type-card': RoxyHdTypeCard;\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';\nimport { chevron, disclosureStyles } from '../utils/disclosure.js';\nimport { interpAccordionStyles } from '../utils/interp-accordion.js';\nimport { capitalize } from '../utils/string.js';\n\ntype Variables = CalculateVariablesResponse;\ntype Arrow = Variables['arrows'][number];\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.\n *\n * @remarks\n * The quadrant grid stays the primary read: it is the arrow map as it appears on the chart, and it is what a reader scans first. The interpretation sits below it in an exclusive accordion, grouped by the two layers the arrows belong to (the body-side Primary Health System, the mind-side Rave Psychology), because the layer description is one text shared by the two arrows in it and belongs to the group rather than to each arrow. Only one arrow reading is ever open, so the card grows by one paragraph at most.\n *\n * `cognition` rides only on the determination arrow and is rendered when present. A low-confidence calculation (a birth time near a color or tone boundary) is flagged per arrow and for the chart as a whole.\n */\n@customElement('roxy-hd-variables')\nexport class RoxyHdVariables extends RoxyDataElement<Variables> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tdisclosureStyles,\n\t\tinterpAccordionStyles,\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,minmax(0,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);align-content:start;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:minmax(0,1fr)}}.group{margin-bottom:var(--roxy-space-md,1rem)}.group:last-of-type{margin-bottom:0}.group-head{font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-fg,#0a0a0a);margin:0}.group-note{margin:0 0 var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);line-height:1.6}.facets{gap:var(--roxy-space-xs,.25rem);margin:0;display:grid}.facets dt{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.05em}.facets dd{margin:0}.footnote{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);margin:0;line-height:1.6}`,\n\t];\n\n\tprotected renderData(d: Variables) {\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} ${this.renderReading(arrows, d.baseDescription)}</div>`;\n\t}\n\n\tprivate renderArrow(a: Arrow) {\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.baseName ? `, ${a.baseName}` : ''}</span>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\ta.activation?.planet\n\t\t\t\t\t? html`<span class=\"ctb\">${[a.activation.planet, capitalize(a.activation.side ?? '')].filter(Boolean).join(' \u00B7 ')}</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\t/**\n\t * The four readings, grouped by the layer each arrow belongs to. The layer\n\t * description is one text shared by both arrows of a layer, so it is lifted to\n\t * the group intro rather than repeated in each body. Group order follows the\n\t * already quadrant-sorted arrows, which puts the body layer before the mind\n\t * layer without naming either.\n\t */\n\tprivate renderReading(arrows: Arrow[], baseDescription: string | undefined) {\n\t\tconst readable = arrows.filter((a) => a.description || a.colorMeaning);\n\t\tif (readable.length === 0) return nothing;\n\n\t\tconst groups = new Map<string, Arrow[]>();\n\t\tfor (const a of readable) {\n\t\t\tconst key = a.layer ?? '';\n\t\t\tconst bucket = groups.get(key);\n\t\t\tif (bucket) bucket.push(a);\n\t\t\telse groups.set(key, [a]);\n\t\t}\n\t\tlet index = 0;\n\n\t\treturn html`<section class=\"block\"><h3>Reading</h3>${[...groups].map(\n\t\t\t\t([layer, list]) => html`<div class=\"group\">${layer ? html`<p class=\"group-head\">${layer}</p>` : nothing} ${\n\t\t\t\t\t\tlist[0]?.layerDescription\n\t\t\t\t\t\t\t? html`<p class=\"group-note\">${list[0].layerDescription}</p>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t} ${list.map((a) => this.renderArrowReading(a, index++ === 0))}</div>`,\n\t\t\t)} ${baseDescription ? html`<p class=\"footnote\">Base. ${baseDescription}</p>` : nothing}</section>`;\n\t}\n\n\tprivate renderArrowReading(a: Arrow, open: boolean) {\n\t\t// Cognition rides only on the determination arrow, so its row appears on that\n\t\t// arrow alone. Its label joins the term because, unlike color and direction,\n\t\t// the tile above carries no cognition label to read it against.\n\t\tconst cog = a.cognition;\n\t\tconst facets: Array<{ label: string; body: string | undefined }> = [\n\t\t\t{ label: 'Color', body: a.colorMeaning },\n\t\t\t{ label: 'Tone', body: a.toneMeaning },\n\t\t\t{ label: 'Direction', body: a.directionMeaning },\n\t\t\t{\n\t\t\t\tlabel: cog?.label ? `Cognition \u00B7 ${cog.label}` : 'Cognition',\n\t\t\t\tbody: cog?.description,\n\t\t\t},\n\t\t].filter((f) => Boolean(f.body));\n\n\t\treturn html`<details class=\"interp-card\" name=\"hd-variable\" ?open=\"${open}\"><summary><span class=\"interp-lead\">${a.name ?? ''}</span> ${chevron()} ${a.position ? html`<span class=\"interp-aside\"><small>${a.position}</small></span>` : nothing}</summary><div class=\"interp-body\">${a.description ? html`<p>${a.description}</p>` : nothing} ${\n\t\t\t\t\tfacets.length > 0\n\t\t\t\t\t\t? html`<dl class=\"facets\">${facets.map(\n\t\t\t\t\t\t\t\t(f) => html`<dt>${f.label}</dt><dd>${f.body}</dd>`,\n\t\t\t\t\t\t\t)}</dl>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</div></details>`;\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';\nimport { disclosureStyles } from '../utils/disclosure.js';\nimport {\n\ttype InterpSection,\n\tinterpAccordionStyles,\n\trenderInterpAccordion,\n} from '../utils/interp-accordion.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\tdisclosureStyles,\n\t\tinterpAccordionStyles,\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);align-content:start;align-self:start;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)}.line-meaning{padding-left:var(--roxy-space-sm,.5rem);border-left:2px solid var(--roxy-border,#e4e4e7);color:var(--roxy-muted,#71717a);margin:0}.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\">${\n\t\t\t\t\t\t// One text node, not two. The markup minifier collapses the space\n\t\t\t\t\t\t// between adjacent template expressions, which rendered the title as\n\t\t\t\t\t\t// \"30.The Clinging\" with the separator eaten. Join in JS instead.\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\th.number != null ? `${h.number}.` : '',\n\t\t\t\t\t\t\th.english ?? h.chinese ?? 'Hexagram',\n\t\t\t\t\t\t]\n\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t.join(' ')\n\t\t\t\t\t}</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} ${this.renderLines(h, changing)}</div></article>`;\n\t}\n\n\t/**\n\t * The line readings. Each line carries its oracle statement and, since the 2026-07 API rewrite, a written meaning; the component used to print only the changing-line NUMBERS and drop both, which left a reader with \"Changing lines: 3\" and no way to know what line 3 was telling them.\n\t *\n\t * @remarks\n\t * When lines are moving, only those lines are shown: a cast turns on the moving lines, and listing the other five buries the answer. With no lines moving (a lookup, a random draw, the daily hexagram) all six are shown, because there the hexagram is being read as a reference rather than as an answer to a question.\n\t */\n\tprivate renderLines(h: Hexagram, changing: Set<number>) {\n\t\tconst all = h.changingLines ?? [];\n\t\tif (all.length === 0) return nothing;\n\n\t\tconst isCast = changing.size > 0;\n\t\tconst shown = isCast ? all.filter((l) => changing.has(l.position)) : all;\n\t\tif (shown.length === 0) return nothing;\n\n\t\tconst sections: InterpSection[] = shown.map((l) => ({\n\t\t\tlabel: `Line ${l.position}`,\n\t\t\tbody: l.text ?? '',\n\t\t\textra: l.meaning\n\t\t\t\t? html`<p class=\"line-meaning\">${l.meaning}</p>`\n\t\t\t\t: nothing,\n\t\t}));\n\n\t\treturn renderInterpAccordion(\n\t\t\tsections,\n\t\t\t'hexagram-lines',\n\t\t\tisCast ? 'Changing lines' : 'Lines',\n\t\t);\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. 6 digits BOTTOM to top, so index 0 is line 1, the bottom line, exactly like the cast `lines` array. 1 = yang (solid, 7), 0 = yin (broken, 8). 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\t * @remarks\n\t * This used to `.reverse()`, because the API served `binary` top-to-bottom while documenting it bottom-to-top, and reversing was the only way to render the figure the right way up. The API fixed the data in 2026-07 (the same inversion was making `/cast` return the vertically MIRRORED hexagram for 56 of the 64 figures), so `binary` and `lines` now point the same way and the reverse would flip every asymmetric hexagram upside down. Do not put it back.\n\t */\n\tprivate derivedLines(h: Hexagram): number[] {\n\t\tconst binary = h.binary ?? '';\n\t\tif (/^[01]{6}$/.test(binary)) {\n\t\t\treturn Array.from(binary, (c) => (c === '1' ? 7 : 8));\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 { formatTimeRange } from '../utils/format.js';\nimport { capitalize } from '../utils/string.js';\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);grid-template-columns:minmax(0,1fr);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,minmax(0,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\">${formatTimeRange(h)}</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 { formatDate } from '../utils/format.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}.sky{gap:var(--roxy-space-sm,.5rem);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);display:grid}.moon-line{align-items:baseline;gap:.35rem var(--roxy-space-md,1rem);font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);flex-wrap:wrap;display:flex}.moon-line b{font-weight:var(--roxy-weight-bold,600)}.moon-line .lbl{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);text-transform:uppercase;letter-spacing:.06em;font-weight:var(--roxy-weight-bold,600);margin-right:.35rem}.transits{gap:.25rem;margin:0;padding:0;list-style:none;display:grid}.transits li{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);padding-left:.9rem;position:relative}.transits li:before{content:\"\";background:var(--roxy-accent,#f59e0b);border-radius:50%;width:5px;height:5px;position:absolute;top:.5em;left:0}.block-title{margin:0 0 var(--roxy-space-sm,.5rem);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}.weeks{gap:var(--roxy-space-sm,.5rem);display:grid}.week{gap:var(--roxy-space-sm,.5rem);border-top:1px solid var(--roxy-border,#e4e4e7);padding-top:var(--roxy-space-sm,.5rem);grid-template-columns:3.5rem 1fr;align-items:baseline;display:grid}.week:first-child{border-top:0;padding-top:0}.week-no{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)}.week-focus{font-weight:var(--roxy-weight-bold,600);color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem)}.week-advice{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);margin:.15rem 0 0}.dates{gap:.3rem var(--roxy-space-md,1rem);font-size:var(--roxy-text-sm,.875rem);grid-template-columns:max-content 1fr;margin:0;display:grid}.date-row{display:contents}.date-row dt{font-variant-numeric:tabular-nums;color:var(--roxy-accent-ink,#b45309);font-weight:var(--roxy-weight-bold,600);white-space:nowrap}.date-row dd{color:var(--roxy-fg,#0a0a0a);margin:0}`,\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} ${this.renderSky(d)}<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>${this.renderMonth(d)} ${(() => {\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\t/**\n\t * The sky behind the reading (daily only): where the Moon is, what phase it is in, and the transits the forecast was derived from. A daily horoscope that hides its transits is a fortune cookie; showing them is what makes this one auditable.\n\t */\n\tprivate renderSky(d: HoroscopeData) {\n\t\tconst moonSign = 'moonSign' in d ? d.moonSign : '';\n\t\tconst moonPhase = 'moonPhase' in d ? d.moonPhase : '';\n\t\tconst transits = ('activeTransits' in d ? d.activeTransits : []) ?? [];\n\t\tif (!moonSign && !moonPhase && transits.length === 0) return nothing;\n\t\tconst glyph = moonSign ? (SIGN_GLYPH[capitalize(moonSign)] ?? '') : '';\n\t\treturn html`<div class=\"sky\">${\n\t\t\t\tmoonSign || moonPhase\n\t\t\t\t\t? html`<div class=\"moon-line\">${\n\t\t\t\t\t\t\tmoonSign\n\t\t\t\t\t\t\t\t? html`<span><span class=\"lbl\">Moon</span> <span aria-hidden=\"true\">${glyph}</span> <b>${moonSign}</b></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\tmoonPhase\n\t\t\t\t\t\t\t\t? html`<span><span class=\"lbl\">Phase</span> <b>${moonPhase}</b></span>`\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\ttransits.length\n\t\t\t\t\t? html`<ul class=\"transits\" aria-label=\"Active transits\">${transits.map((t) => html`<li>${t}</li>`)}</ul>`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n\n\t/** Monthly arc: the week-by-week focus and the dated events (lunations, retrogrades, ingresses) the month turns on. */\n\tprivate renderMonth(d: HoroscopeData) {\n\t\tconst weeks = ('weekByWeek' in d ? d.weekByWeek : []) ?? [];\n\t\tconst keyDates = ('keyDates' in d ? d.keyDates : []) ?? [];\n\t\tif (weeks.length === 0 && keyDates.length === 0) return nothing;\n\t\treturn html`${\n\t\t\tweeks.length\n\t\t\t\t? html`<section><h3 class=\"block-title\">Week by week</h3><div class=\"weeks\">${weeks.map(\n\t\t\t\t\t\t\t(w) => html`<div class=\"week\"><span class=\"week-no\">Week ${w.week}</span><div><div class=\"week-focus\">${w.focus}</div>${w.advice ? html`<p class=\"week-advice\">${w.advice}</p>` : nothing}</div></div>`,\n\t\t\t\t\t\t)}</div></section>`\n\t\t\t\t: nothing\n\t\t} ${\n\t\t\tkeyDates.length\n\t\t\t\t? html`<section><h3 class=\"block-title\">Key dates</h3><dl class=\"dates\">${keyDates.map(\n\t\t\t\t\t\t\t(k) => html`<div class=\"date-row\"><dt>${formatDate(k.date) || k.date}</dt><dd>${k.event}</dd></div>`,\n\t\t\t\t\t\t)}</dl></section>`\n\t\t\t\t: nothing\n\t\t}`;\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 { formatSignPosition } from '../utils/degree.js';\nimport { formatNumber } from '../utils/format.js';\nimport {\n\trenderTablist,\n\ttype TablistItem,\n\ttablistStyles,\n} from '../utils/tablist.js';\n\ntype Tab = 'planets' | 'cusps' | 'significators';\n\nconst TABS: ReadonlyArray<TablistItem<Tab>> = [\n\t{ id: 'planets', label: 'Planets' },\n\t{ id: 'cusps', label: 'Cusps' },\n\t{ id: 'significators', label: 'Significators' },\n];\n\n/** The four KP significator strength levels, strongest (1) to weakest (4). */\nconst LEVELS = [1, 2, 3, 4] as const;\n\ntype Significators = KpChartResponse['significators'];\ntype HouseSignificator = Significators['houseWise'][number];\ntype PlanetSignificator = Significators['planetWise'][number];\n\n/** A planet or node row, normalized so planets and Rahu/Ketu share a table. */\ninterface KpBody {\n\tname: string;\n\tlongitude?: number;\n\thouse?: number;\n\tnakshatra?: string;\n\tpada?: number;\n\tstarLord?: string;\n\tsubLord?: string;\n\tsubSubLord?: string;\n\tkpNumber?: number;\n\tretrograde?: boolean;\n}\n\n/** \"Chitra 3\" when the pada is known, otherwise the bare nakshatra. */\nfunction nakshatraPada(nakshatra?: string, pada?: number): string {\n\tif (!nakshatra) return '';\n\treturn typeof pada === 'number' ? `${nakshatra} ${pada}` : nakshatra;\n}\n\n/**\n * A strength-ordered chain, \"Venus > Mars > Jupiter\". The API repeats a body in\n * `all` / `allHouses` when it signifies at more than one level (Venus as both\n * star-of-owner and owner), which reads as a stutter, so the first occurrence\n * wins and the rest are folded away. The grouped level columns still show every\n * level that body appears at.\n */\nfunction chain(values: ReadonlyArray<string | number>): string {\n\treturn [...new Set(values.map(String))].join(' > ');\n}\n\n/**\n * KP (Krishnamurti Paddhati) chart. Renders /vedic-astrology/kp/chart: an\n * Ascendant summary, a planets-and-nodes table, a Placidus cusps table, and the\n * significator tables. The Ascendant is cusp 1, so its full four-lord chain is\n * already the first row of the cusps table and the header stays a summary.\n *\n * @remarks\n * The cusp and planet sub lords are the primary predictive surface in KP, so\n * every row carries star lord, sub lord, sub-sub lord, and KP number (1-249).\n * The significators tab is the event-timing surface: house-wise (which planets\n * signify each house) and planet-wise (which houses each planet signifies),\n * both graded L1 to L4 with the API's own level labels shown as the legend.\n */\n@customElement('roxy-kp-chart')\nexport class RoxyKpChart extends RoxyDataElement<KpChartResponse> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\ttablistStyles,\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)}.roxy-tablist{padding:0 var(--roxy-space-md,1rem)}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}.sig-head{padding:var(--roxy-space-md,1rem) var(--roxy-space-md,1rem) 0;gap:var(--roxy-space-xs,.25rem);display:grid}.sig-title{font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);margin:0}.sig-note{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);margin:0}.legend{gap:var(--roxy-space-xs,.25rem) var(--roxy-space-md,1rem);padding:var(--roxy-space-md,1rem) var(--roxy-space-md,1rem) 0;color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);flex-wrap:wrap;margin:0;list-style:none;display:flex}.legend b{color:var(--roxy-accent-ink,#b45309);margin-right:4px}.chain,.empty-cell{color:var(--roxy-muted,#71717a)}`,\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\tlongitude: p.longitude,\n\t\t\thouse: p.house,\n\t\t\tnakshatra: p.nakshatra,\n\t\t\tpada: p.pada,\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\tlongitude: node.longitude,\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\tkpNumber: node.kpNumber,\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\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>${typeof asc.longitude === 'number' ? formatSignPosition(asc.longitude) : (asc.sign ?? '')} </strong>${asc.nakshatra ? html`\u00B7 ${nakshatraPada(asc.nakshatra, asc.pada)}` : 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>${renderTablist({\n\t\t\t\titems: TABS,\n\t\t\t\tactive: this.activeTab,\n\t\t\t\tonSelect: (id) => {\n\t\t\t\t\tthis.activeTab = id;\n\t\t\t\t},\n\t\t\t\tlabel: 'KP chart views',\n\t\t\t\tidPrefix: 'kp',\n\t\t\t\tcontrols: true,\n\t\t\t})}<div id=\"kp-panel-${this.activeTab}\" role=\"tabpanel\" aria-labelledby=\"kp-tab-${this.activeTab}\">${\n\t\t\t\t\tthis.activeTab === 'planets'\n\t\t\t\t\t\t? this.renderPlanets()\n\t\t\t\t\t\t: this.activeTab === 'cusps'\n\t\t\t\t\t\t\t? this.renderCusps()\n\t\t\t\t\t\t\t: this.renderSignificators()\n\t\t\t\t}</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\"><caption class=\"roxy-sr-only\">KP planets and nodes: each body with its position, house, nakshatra and pada, star lord, sub lord, sub sub lord and KP number.</caption><thead><tr><th scope=\"col\">Body</th><th scope=\"col\">Position</th><th scope=\"col\">House</th><th scope=\"col\">Nakshatra, pada</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 class=\"num\">${typeof b.longitude === 'number' ? formatSignPosition(b.longitude) : ''}</td><td class=\"num\">${typeof b.house === 'number' ? b.house : ''}</td><td>${nakshatraPada(b.nakshatra, b.pada)}</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\"><caption class=\"roxy-sr-only\">KP Placidus cusps: each house cusp with its position, sign lord, nakshatra and pada, star lord, sub lord, sub sub lord and KP number.</caption><thead><tr><th scope=\"col\">House</th><th scope=\"col\">Position</th><th scope=\"col\">Sign lord</th><th scope=\"col\">Nakshatra, pada</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 class=\"num\">${typeof c.longitude === 'number' ? formatSignPosition(c.longitude) : (c.sign ?? '')}</td><td>${c.signLord ?? ''}</td><td>${nakshatraPada(c.nakshatra, c.pada)}</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\t/**\n\t * The KP event-timing surface. House-wise answers \"which planets can deliver\n\t * this house\", planet-wise answers \"what will this planet deliver in its\n\t * dasha\". The L1-L4 legend text is the API's own level description, so the\n\t * grading a reader sees is the grading the engine applied.\n\t */\n\tprivate renderSignificators() {\n\t\tconst sig = this.data?.significators;\n\t\tconst houseWise = sig?.houseWise ?? [];\n\t\tconst planetWise = sig?.planetWise ?? [];\n\t\tif (!houseWise.length && !planetWise.length)\n\t\t\treturn html`<p class=\"roxy-empty\" role=\"status\">No significators</p>`;\n\n\t\treturn html`${this.renderLevelLegend(houseWise)} ${\n\t\t\t\thouseWise.length\n\t\t\t\t\t? html`<div class=\"sig-head\"><h3 class=\"sig-title\">House-wise significators</h3><p class=\"sig-note\">Planets that signify each house, strongest level first.</p></div><table role=\"table\"><caption class=\"roxy-sr-only\">KP house-wise significators: each house, the planets that signify it at levels 1 to 4, and the full strength order.</caption><thead><tr><th scope=\"col\">House</th>${LEVELS.map((l) => html`<th scope=\"col\">L${l}</th>`)}<th scope=\"col\">Strength order</th></tr></thead><tbody>${houseWise.map(\n\t\t\t\t\t\t\t\t\t(h) => html`<tr><td class=\"body num\">${h.house}</td>${LEVELS.map((l) => this.renderCell(this.planetsAtLevel(h, l).join(', ')))}<td class=\"chain\">${chain(h.all ?? [])}</td></tr>`,\n\t\t\t\t\t\t\t\t)}</tbody></table>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tplanetWise.length\n\t\t\t\t\t? html`<div class=\"sig-head\"><h3 class=\"sig-title\">Planet-wise significators</h3><p class=\"sig-note\">Houses each planet signifies, strongest level first.</p></div><table role=\"table\"><caption class=\"roxy-sr-only\">KP planet-wise significators: each planet, the houses it signifies at levels 1 to 4, and the full strength order.</caption><thead><tr><th scope=\"col\">Planet</th>${LEVELS.map((l) => html`<th scope=\"col\">L${l}</th>`)}<th scope=\"col\">Strength order</th></tr></thead><tbody>${planetWise.map(\n\t\t\t\t\t\t\t\t\t(p) => html`<tr><td class=\"body\">${p.planet}</td>${LEVELS.map((l) => this.renderCell(this.housesAtLevel(p, l).join(', ')))}<td class=\"chain\">${chain(p.allHouses ?? [])}</td></tr>`,\n\t\t\t\t\t\t\t\t)}</tbody></table>`\n\t\t\t\t\t: nothing\n\t\t\t}`;\n\t}\n\n\t/** An em-dash-free placeholder keeps an empty level cell from reading as missing data. */\n\tprivate renderCell(value: string) {\n\t\treturn value\n\t\t\t? html`<td>${value}</td>`\n\t\t\t: html`<td class=\"empty-cell\">none</td>`;\n\t}\n\n\tprivate planetsAtLevel(h: HouseSignificator, level: number): string[] {\n\t\treturn (h.significators ?? [])\n\t\t\t.filter((s) => s.level === level)\n\t\t\t.flatMap((s) => s.planets ?? []);\n\t}\n\n\tprivate housesAtLevel(p: PlanetSignificator, level: number): number[] {\n\t\treturn (p.signifies ?? [])\n\t\t\t.filter((s) => s.level === level)\n\t\t\t.flatMap((s) => s.houses ?? []);\n\t}\n\n\t/** Level to the API's own label, taken from the first house that carries it. */\n\tprivate renderLevelLegend(houseWise: HouseSignificator[]) {\n\t\tconst labels = new Map<number, string>();\n\t\tfor (const h of houseWise) {\n\t\t\tfor (const s of h.significators ?? []) {\n\t\t\t\tif (s.description && !labels.has(s.level))\n\t\t\t\t\tlabels.set(s.level, s.description);\n\t\t\t}\n\t\t}\n\t\tif (labels.size === 0) return nothing;\n\t\treturn html`<ul class=\"legend\" aria-label=\"Significator levels\">${[...labels.entries()]\n\t\t\t\t.sort((a, b) => a[0] - b[0])\n\t\t\t\t.map(([level, label]) => html`<li><b>L${level}</b>${label}</li>`)}</ul>`;\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\"><caption class=\"roxy-sr-only\">KP planets: each planet with its sign, sign lord, nakshatra, star lord, sub lord, sub sub lord and KP number.</caption><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><caption class=\"roxy-sr-only\">House significators: each ruling planet and the houses it signifies.</caption><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\"><caption class=\"roxy-sr-only\">Local space directions: each body with its compass direction, azimuth, altitude and whether it sits above or below the horizon.</caption><thead><tr><th scope=\"col\">Body</th><th scope=\"col\">Direction</th><th scope=\"col\" class=\"num\">Azimuth</th><th scope=\"col\" class=\"num\">Altitude</th><th scope=\"col\">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\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 { disclosureStyles } from '../utils/disclosure.js';\nimport {\n\tASPECT_CLASS,\n\tformatNumber,\n\tnormalizeAspect,\n} from '../utils/format.js';\nimport {\n\ttype InterpSection,\n\tinterpAccordionStyles,\n\trenderInterpAccordion,\n} from '../utils/interp-accordion.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];\ntype PatternEntry = NonNullable<NatalChartResponse['patterns']>[number];\n\n/**\n * Reading order for detected configurations. A practitioner reads the rare, chart-defining figures first (a Grand Cross reframes the whole chart) and the common ones last, so the response order is re-sorted rather than dumped. Ties break on tightness, the closest to exact first.\n */\nconst PATTERN_ORDER: Record<string, number> = {\n\tGRAND_CROSS: 0,\n\tGRAND_TRINE: 1,\n\tKITE: 2,\n\tT_SQUARE: 3,\n\tYOD: 4,\n\tMYSTIC_RECTANGLE: 5,\n\tSTELLIUM: 6,\n};\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 * The chart shape the wheel actually renders.\n *\n * @remarks\n * `RelocationChartResponse` carries the same planets, houses, angles and birth details as `NatalChartResponse` (`RelocationPlanet` is field-for-field identical to the natal planet item), and differs only by having no `aspects`, `aspectsInterpretation`, `patterns`, `partOfFortune` or `summary`. The wheel already renders without them, so those five are simply optional here.\n *\n * Typing that contract is what lets {@link RoxyRelocationWheel} compose this component honestly. It used to pass its response through a `data as unknown as NatalChartResponse` double cast, which silently asserted five required fields that were not there.\n */\ntype ChartExtras =\n\t| 'aspects'\n\t| 'aspectsInterpretation'\n\t| 'patterns'\n\t| 'partOfFortune'\n\t| 'summary';\nexport type WheelChart = Omit<NatalChartResponse, ChartExtras> &\n\tPartial<Pick<NatalChartResponse, ChartExtras>>;\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<WheelChart> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\ttablistStyles,\n\t\tdisclosureStyles,\n\t\tinterpAccordionStyles,\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);grid-template-columns:minmax(0,1fr);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;min-width:0;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 caption{caption-side:top;text-align:left;color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);padding-bottom:var(--roxy-space-xs,.25rem)}.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)}.em-grid .dominant{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 10%, transparent)}.em-grid th.dominant,.em-grid td.em-total.dominant{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-tag{border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 55%, transparent);color:var(--roxy-fg,#0a0a0a);text-transform:capitalize;padding:1px 8px}.pattern-tight{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);font-variant-numeric:tabular-nums;margin-left:auto}.pattern-planets{flex-wrap:wrap;gap:.25rem;display:flex}.planet-chip{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);align-items:baseline;gap:.3rem;padding:1px 8px;display:inline-flex}.planet-chip.apex{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 20%, transparent);font-weight:var(--roxy-weight-bold,600)}.planet-chip .apex-tag{text-transform:uppercase;letter-spacing:.04em;font-size:.85em;font-weight:400}.pattern-interp{color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem);margin:0;line-height:1.45}.interp-keywords{flex-wrap:wrap;gap:.25rem;display:flex}.interp-keywords .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}`,\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: WheelChart) {\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.renderPatterns()} ${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\"><caption class=\"roxy-sr-only\">Planet by planet aspect grid: the aspect each pair of planets forms, read from the planet naming the row across to the planet naming the column.</caption><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 balance. Each body is placed by its sign into one cell (Fire/Earth/Air/Water row, Cardinal/Fixed/Mutable column).\n\t *\n\t * @remarks\n\t * The cells are derived from the planet signs, not read from `summary.elementDistribution`, because a 1D distribution cannot fill a cross-tab. That makes the body set the reconciliation risk: the API counts every body it returns (nodes, Chiron, and Black Moon Lilith included), so the grid must too, or the totals here would contradict the dominant-element pill rendered right above it. Hence the totals count placed bodies rather than `planets.length` (an unrecognized sign would otherwise inflate the grand total past the sum of its rows), the caption names the body set, and the dominant row and column are tinted from `summary` so the pill and the grid land on the same cell.\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\t\tconst summary = this.data?.summary;\n\t\tconst dominantEl = capitalize(summary?.dominantElement ?? '');\n\t\tconst dominantMod = capitalize(summary?.dominantModality ?? '');\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\tlet placed = 0;\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\tplaced++;\n\t\t}\n\t\tif (placed === 0) return nothing;\n\n\t\tconst colTotal = (m: string) =>\n\t\t\tELEMENTS.reduce((s, el) => s + (cells[el]?.[m]?.length ?? 0), 0);\n\n\t\treturn html`<table class=\"em-grid\" aria-label=\"Element and modality distribution\"><caption>All ${placed} bodies in the chart, placed by sign</caption><thead><tr><th></th>${MODALITIES.map(\n\t\t\t\t\t\t(m) =>\n\t\t\t\t\t\t\thtml`<th scope=\"col\" class=\"${m === dominantMod ? 'dominant' : ''}\">${m.slice(0, 3)}</th>`,\n\t\t\t\t\t)}<th scope=\"col\">Total</th></tr></thead><tbody>${ELEMENTS.map((el) => {\n\t\t\t\t\tconst isDomRow = el === dominantEl;\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\" class=\"${isDomRow ? 'dominant' : ''}\">${el}</th>${MODALITIES.map(\n\t\t\t\t\t\t\t(m) =>\n\t\t\t\t\t\t\t\thtml`<td class=\"${isDomRow || m === dominantMod ? 'dominant' : ''}\">${(cells[el]?.[m] ?? []).join(' ')}</td>`,\n\t\t\t\t\t\t)}<td class=\"${isDomRow ? 'em-total dominant' : '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=\"${m === dominantMod ? 'em-total dominant' : 'em-total'}\">${colTotal(m)}</td>`,\n\t\t\t\t\t)}<td class=\"em-total\">${placed}</td></tr></tbody></table>`;\n\t}\n\n\t/**\n\t * Detected multi-planet configurations. Each card names the figure, tags the element or modality it pivots on, flags a dissociate (out-of-sign) figure, and puts the apex planet first with its own chip, because the apex is the point the whole configuration discharges through.\n\t */\n\tprivate renderPatterns() {\n\t\tconst patterns = this.data?.patterns ?? [];\n\t\tif (patterns.length === 0) return nothing;\n\t\tconst sorted = [...patterns].sort(\n\t\t\t(a, b) =>\n\t\t\t\t(PATTERN_ORDER[a.kind] ?? 9) - (PATTERN_ORDER[b.kind] ?? 9) ||\n\t\t\t\t(b.tightness ?? 0) - (a.tightness ?? 0),\n\t\t);\n\t\treturn html`<section class=\"block\"><h3>Chart patterns</h3>${sorted.map((p) => this.renderPattern(p))}</section>`;\n\t}\n\n\tprivate renderPattern(p: PatternEntry) {\n\t\tconst planets = p.planets ?? [];\n\t\t// Apex first: the spec already orders it first for Kite, T-Square, and Yod,\n\t\t// but sorting here keeps the chip row honest for any future pattern kind.\n\t\tconst ordered = p.apex\n\t\t\t? [...planets].sort((a, b) => Number(b === p.apex) - Number(a === p.apex))\n\t\t\t: planets;\n\t\treturn html`<div class=\"pattern\"><div class=\"pattern-head\"><span class=\"pattern-name\">${p.name}</span> ${p.element ? html`<span class=\"pattern-tag\">${p.element}</span>` : nothing} ${p.modality ? html`<span class=\"pattern-tag\">${p.modality}</span>` : nothing} ${\n\t\t\t\t\tp.dissociate\n\t\t\t\t\t\t? html`<span class=\"pattern-tag\" title=\"Out of sign: one or more planets sit outside the pattern element or modality, so the theme holds but runs weaker.\">Dissociate</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} ${\n\t\t\t\t\t// Math.round, not formatNumber(x, 0): that helper strips trailing\n\t\t\t\t\t// zeros, so a 100% tight pattern renders as \"1%\".\n\t\t\t\t\ttypeof p.tightness === 'number'\n\t\t\t\t\t\t? html`<span class=\"pattern-tight\">${Math.round(p.tightness)}% tight</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</div><div class=\"pattern-planets\">${ordered.map((name) => {\n\t\t\t\t\tconst glyph = PLANET_GLYPH[capitalize(name)];\n\t\t\t\t\tconst isApex = Boolean(p.apex) && name === p.apex;\n\t\t\t\t\treturn html`<span class=\"${isApex ? 'planet-chip apex' : 'planet-chip'}\">${glyph ? html`<span aria-hidden=\"true\">${glyph}</span>` : nothing}${name}${isApex ? html`<span class=\"apex-tag\">apex</span>` : nothing}</span>`;\n\t\t\t\t})}</div>${p.interpretation ? html`<p class=\"pattern-interp\">${p.interpretation}</p>` : nothing}</div>`;\n\t}\n\n\tprivate renderInterpretations() {\n\t\tconst sections: InterpSection[] = this.getPlanets()\n\t\t\t.filter((p) => p.interpretation)\n\t\t\t.map((p) => {\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\tconst lead = interp.summary || interp.detailed || '';\n\t\t\t\t// `detailed` only becomes a second paragraph when `summary` already\n\t\t\t\t// took the lead line, so a response carrying one or the other never\n\t\t\t\t// prints the same prose twice.\n\t\t\t\tconst detail = interp.summary ? interp.detailed : undefined;\n\t\t\t\treturn {\n\t\t\t\t\tlabel: `${glyph} ${p.name}`.trim(),\n\t\t\t\t\taside: [p.sign ?? '', deg].filter(Boolean).join(' '),\n\t\t\t\t\tbody: lead,\n\t\t\t\t\textra: html`${detail ? html`<p>${detail}</p>` : nothing} ${\n\t\t\t\t\t\tinterp.keywords?.length\n\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: nothing\n\t\t\t\t\t}`,\n\t\t\t\t};\n\t\t\t});\n\t\treturn renderInterpAccordion(\n\t\t\tsections,\n\t\t\t'natal-planet-readings',\n\t\t\t'Planet readings',\n\t\t);\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 { disclosureStyles } from '../utils/disclosure.js';\nimport {\n\ttype InterpSection,\n\tinterpAccordionStyles,\n\trenderInterpAccordion,\n} from '../utils/interp-accordion.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 * The interpretation block a numerology number carries: archetype keywords, the long reading, the strengths and challenges lists, and the three life-area readings. Every core number, the daily number, and the birth-day profile ship this same block (the profile omits spirituality), so one renderer serves them all. Partial, because the birth-day profile is the narrower shape.\n */\ntype NumerologyReading = Partial<CalculateLifePathResponse['meaning']>;\n\n/** Master numbers are never reduced, and a reader has to see immediately that they are looking at one. */\nconst MASTER_NUMBERS = new Set([11, 22, 33]);\n\n/** The three life-area readings, in the order a numerologist gives them. */\nconst GUIDANCE_FIELDS: ReadonlyArray<[keyof NumerologyReading, string]> = [\n\t['career', 'Career'],\n\t['relationships', 'Relationships'],\n\t['spirituality', 'Spirituality'],\n];\n\n/**\n * Numerology card. Renders /numerology/{life-path,expression,soul-urge,personality,birth-day,maturity,daily,personal-day,personal-month,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\tdisclosureStyles,\n\t\tinterpAccordionStyles,\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}.master{background:color-mix(in srgb, var(--roxy-accent,#f59e0b) 18%, transparent);color:var(--roxy-fg,#0a0a0a);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);font-weight:var(--roxy-weight-bold,600);margin-top:2px;padding:2px 10px;display:inline-block}.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);color:var(--roxy-fg,#0a0a0a);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{font-size:var(--roxy-text-sm,.875rem);gap:2px;display:grid}.cores .item .core-head{align-items:baseline;gap:var(--roxy-space-xs,.25rem);display:flex}.cores .item .core-key{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)}.cores .item .core-title{color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-xs,.75rem)}.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);font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em}.lists ul{gap:var(--roxy-space-xs,.25rem);font-size:var(--roxy-text-sm,.875rem);margin:0;padding-left:1.1rem;line-height:1.6;display:grid}.sub{gap:var(--roxy-space-sm,.5rem);border-top:1px solid var(--roxy-border,#e4e4e7);padding-top:var(--roxy-space-md,1rem);display:grid}.sub>h3{font-size:var(--roxy-text-sm,.875rem);font-weight:var(--roxy-weight-bold,600);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;margin:0}.sub-title{font-size:var(--roxy-text-base,1rem);font-weight:var(--roxy-weight-bold,600);margin:0}.sub p{font-size:var(--roxy-text-sm,.875rem);margin:0;line-height:1.6}.attrs{gap:var(--roxy-space-sm,.5rem);grid-template-columns:repeat(auto-fit,minmax(7rem,1fr));margin:0;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}.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) return this.renderPersonalDay(d, headerLabel);\n\t\tif ('personalMonth' in d) return this.renderPersonalMonth(d, headerLabel);\n\t\tif ('personalYear' in d) return this.renderPersonalYear(d, headerLabel);\n\t\tif ('dailyMessage' in d) return this.renderDailyNumber(d, headerLabel);\n\t\treturn this.renderNumberCard(d as NumberCardData, headerLabel);\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\treturn html`<article class=\"card\" aria-label=\"${headerLabel}\">${this.renderHero(headerLabel, d.number, d.meaning?.title, isMaster(d.number, d.type))} ${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\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} ${this.renderReading(d.meaning, 'numerology-guidance')}</article>`;\n\t}\n\n\t/** The daily number carries the same full interpretation as a core number, plus the message for the day. */\n\tprivate renderDailyNumber(d: GetDailyNumberResponse, headerLabel: string) {\n\t\treturn html`<article class=\"card\" aria-label=\"${headerLabel}\">${this.renderHero(headerLabel, d.number, d.meaning?.title, isMaster(d.number, d.type))} ${d.dailyMessage ? html`<p class=\"meaning\">${d.dailyMessage}</p>` : nothing} ${d.meaning?.description ? html`<p class=\"meaning\">${d.meaning.description}</p>` : nothing} ${this.renderReading(d.meaning, 'numerology-daily-guidance')}</article>`;\n\t}\n\n\t/** A personal day sits inside its personal month, which sits inside its personal year. Dropping that nesting strips the day of the context that gives it meaning. */\n\tprivate renderPersonalDay(\n\t\td: CalculatePersonalDayResponse,\n\t\theaderLabel: string,\n\t) {\n\t\treturn html`<article class=\"card\" aria-label=\"${headerLabel}\">${this.renderHero(headerLabel, d.personalDay, d.theme)} ${d.guidance ? html`<p class=\"meaning\">${d.guidance}</p>` : nothing}<dl class=\"attrs\">${this.attr('Date', d.targetDate)} ${this.attr(\n\t\t\t\t\t'Personal month',\n\t\t\t\t\tjoinCycle(d.personalMonth, d.personalMonthTheme),\n\t\t\t\t)} ${this.attr(\n\t\t\t\t\t'Personal year',\n\t\t\t\t\tjoinCycle(d.personalYear, d.personalYearTheme),\n\t\t\t\t)}</dl></article>`;\n\t}\n\n\tprivate renderPersonalMonth(\n\t\td: CalculatePersonalMonthResponse,\n\t\theaderLabel: string,\n\t) {\n\t\treturn html`<article class=\"card\" aria-label=\"${headerLabel}\">${this.renderHero(headerLabel, d.personalMonth, d.theme)} ${d.focus ? html`<p class=\"meaning\">${d.focus}</p>` : nothing}<dl class=\"attrs\">${this.attr('Calendar month', d.calendarMonth)} ${this.attr(\n\t\t\t\t\t'Personal year',\n\t\t\t\t\tjoinCycle(d.personalYear, d.personalYearTheme),\n\t\t\t\t)}</dl></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}\">${this.renderHero(headerLabel, d.personalYear, d.theme)} ${d.cycle ? html`<p class=\"label\">${d.cycle}</p>` : nothing} ${d.forecast ? html`<p class=\"meaning\">${d.forecast}</p>` : nothing} ${this.renderLists(\n\t\t\t\t['Opportunities', d.opportunities],\n\t\t\t\t['Challenges', d.challenges],\n\t\t\t)} ${d.advice ? html`<p class=\"meaning\">${d.advice}</p>` : nothing}</article>`;\n\t}\n\n\tprivate renderChart(d: GenerateNumerologyChartResponse, headerLabel: string) {\n\t\tconst cores = Object.entries(d.coreNumbers ?? {}).filter(([, v]) => v);\n\t\tconst ins = d.additionalInsights;\n\t\tconst lucky = d.luckyAssociations;\n\t\tconst profile = d.birthDayProfile;\n\t\tconst maturity = d.maturityStatus;\n\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} ${d.profile?.birthdate ? html`<p class=\"label\">${d.profile.birthdate}</p>` : nothing}</div>${d.summary ? html`<p class=\"meaning\">${d.summary}</p>` : nothing} ${\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\"><div class=\"core-head\"><span class=\"core-key\">${humanize(k)}</span> <strong>${v.number ?? ''}</strong></div>${v.meaning?.title ? html`<span class=\"core-title\">${v.meaning.title}</span>` : nothing} ${isMaster(v.number, v.type) ? html`<span class=\"master\">Master ${v.number}</span>` : nothing}</div>`,\n\t\t\t\t\t\t)}</div>`\n\t\t\t\t\t: nothing\n\t\t\t} ${renderInterpAccordion(\n\t\t\t\tcores.map(([k, v]) => ({\n\t\t\t\t\tlabel: humanize(k),\n\t\t\t\t\taside: [\n\t\t\t\t\t\tv.number != null ? `${v.number}` : '',\n\t\t\t\t\t\tisMaster(v.number, v.type) ? 'master' : '',\n\t\t\t\t\t\tv.hasKarmicDebt && v.karmicDebtNumber\n\t\t\t\t\t\t\t? `karmic debt ${v.karmicDebtNumber}`\n\t\t\t\t\t\t\t: '',\n\t\t\t\t\t]\n\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t.join(' \u00B7 '),\n\t\t\t\t\tbody: v.meaning?.description ?? '',\n\t\t\t\t\textra: this.renderReading(v.meaning, `numerology-core-${k}`),\n\t\t\t\t})),\n\t\t\t\t'numerology-cores',\n\t\t\t\t'Core numbers',\n\t\t\t)} ${\n\t\t\t\tmaturity\n\t\t\t\t\t? html`<dl class=\"attrs\">${this.attr('Maturity', maturity.isActive ? 'Active' : 'Not yet active')} ${this.attr('Current age', maturity.currentAge)} ${this.attr('Activates', maturity.activationRange)}</dl>`\n\t\t\t\t\t: nothing\n\t\t\t} ${\n\t\t\t\tprofile\n\t\t\t\t\t? html`<section class=\"sub\"><h3>Birth day profile</h3>${\n\t\t\t\t\t\t\tprofile.title\n\t\t\t\t\t\t\t\t? html`<h4 class=\"sub-title\">${[profile.day ? `Day ${profile.day}` : '', profile.title].filter(Boolean).join(' \u00B7 ')}</h4>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t} ${profile.description ? html`<p>${profile.description}</p>` : nothing} ${this.renderReading(profile, 'numerology-birth-day-profile')}</section>`\n\t\t\t\t\t: nothing\n\t\t\t} ${ins ? this.renderInsights(ins) : nothing} ${\n\t\t\t\tlucky\n\t\t\t\t\t? html`<section class=\"sub\"><h3>Lucky associations</h3><dl class=\"attrs\">${this.attr('Day', lucky.day)} ${this.attr('Element', lucky.element)} ${this.attr('Ruling planet', lucky.rulingPlanet)} ${this.attr('Colors', lucky.colors?.join(', '))} ${this.attr('Gemstones', lucky.gemstones?.join(', '))} ${this.attr('Compatible', lucky.compatibleNumbers?.join(', '))} ${this.attr('Incompatible', lucky.incompatibleNumbers?.join(', '))}</dl></section>`\n\t\t\t\t\t: nothing\n\t\t\t}</article>`;\n\t}\n\n\t/** Everything the chart carries beyond the six core numbers: the karmic analysis, the current year and month, the four pinnacles and their paired challenges, the name-derived numbers, and the letter analysis. */\n\tprivate renderInsights(\n\t\tins: NonNullable<GenerateNumerologyChartResponse['additionalInsights']>,\n\t) {\n\t\tconst lessons = ins.karmicLessons;\n\t\tconst debt = ins.karmicDebt;\n\t\tconst year = ins.personalYear;\n\t\tconst passion = ins.hiddenPassion;\n\t\tconst subconscious = ins.subconsciousSelf;\n\t\tconst letters = ins.nameLetters;\n\t\tconst present = Object.entries(lessons?.presentNumbers ?? {});\n\n\t\treturn html`${\n\t\t\tlessons\n\t\t\t\t? html`<section class=\"sub\"><h3>Karmic lessons</h3>${\n\t\t\t\t\t\tlessons.missingNumbers?.length\n\t\t\t\t\t\t\t? html`<div class=\"chips\">${lessons.missingNumbers.map((n) => html`<span>Missing ${n}</span>`)}</div>`\n\t\t\t\t\t\t\t: html`<p>No numbers are missing from the birth name.</p>`\n\t\t\t\t\t} ${\n\t\t\t\t\t\tpresent.length > 0\n\t\t\t\t\t\t\t? html`<div class=\"chips\">${present.map(([digit, count]) => html`<span>${digit} x ${count}</span>`)}</div>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t} ${renderInterpAccordion(\n\t\t\t\t\t\t(lessons.lessons ?? []).map((l) => ({\n\t\t\t\t\t\t\tlabel: l.lesson ?? `Lesson ${l.number}`,\n\t\t\t\t\t\t\taside: l.number != null ? `${l.number}` : '',\n\t\t\t\t\t\t\tbody: l.description ?? '',\n\t\t\t\t\t\t\textra: l.howToOvercome\n\t\t\t\t\t\t\t\t? html`<p><strong>How to overcome.</strong> ${l.howToOvercome}</p>`\n\t\t\t\t\t\t\t\t: nothing,\n\t\t\t\t\t\t})),\n\t\t\t\t\t\t'numerology-karmic-lessons',\n\t\t\t\t\t\t'Lessons',\n\t\t\t\t\t)}</section>`\n\t\t\t\t: nothing\n\t\t}${\n\t\t\tdebt?.hasKarmicDebt\n\t\t\t\t? html`<section class=\"sub\"><h3>Karmic debt</h3>${\n\t\t\t\t\t\tdebt.debtNumbers?.length\n\t\t\t\t\t\t\t? html`<div class=\"chips\">${debt.debtNumbers.map((n) => html`<span>Debt ${n}</span>`)}</div>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t} ${renderInterpAccordion(\n\t\t\t\t\t\t(debt.meanings ?? []).map((m) => ({\n\t\t\t\t\t\t\tlabel: `Karmic debt ${m.number}`,\n\t\t\t\t\t\t\tbody: m.description ?? '',\n\t\t\t\t\t\t\textra: html`${\n\t\t\t\t\t\t\t\tm.challenge\n\t\t\t\t\t\t\t\t\t? html`<p><strong>Challenge.</strong> ${m.challenge}</p>`\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\tm.resolution\n\t\t\t\t\t\t\t\t\t? html`<p><strong>Resolution.</strong> ${m.resolution}</p>`\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})),\n\t\t\t\t\t\t'numerology-karmic-debt',\n\t\t\t\t\t\t'Debts',\n\t\t\t\t\t)}</section>`\n\t\t\t\t: nothing\n\t\t}${\n\t\t\tyear\n\t\t\t\t? html`<section class=\"sub\"><h3>Personal year</h3><h4 class=\"sub-title\">${[\n\t\t\t\t\t\t\tyear.personalYear != null ? `${year.personalYear}` : '',\n\t\t\t\t\t\t\tyear.theme ?? '',\n\t\t\t\t\t\t\tyear.cycle ?? '',\n\t\t\t\t\t\t]\n\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t.join(' \u00B7 ')}</h4>${year.forecast ? html`<p>${year.forecast}</p>` : nothing} ${this.renderLists(\n\t\t\t\t\t\t['Opportunities', year.opportunities],\n\t\t\t\t\t\t['Challenges', year.challenges],\n\t\t\t\t\t)} ${year.advice ? html`<p>${year.advice}</p>` : nothing} ${\n\t\t\t\t\t\tyear.personalMonth\n\t\t\t\t\t\t\t? html`<p><strong>${[\n\t\t\t\t\t\t\t\t\tyear.personalMonth.personalMonth != null\n\t\t\t\t\t\t\t\t\t\t? `Personal month ${year.personalMonth.personalMonth}`\n\t\t\t\t\t\t\t\t\t\t: 'Personal month',\n\t\t\t\t\t\t\t\t\tyear.personalMonth.theme ?? '',\n\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t\t.join(' \u00B7 ')}.</strong> ${year.personalMonth.focus ?? ''}</p>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}</section>`\n\t\t\t\t: nothing\n\t\t}${\n\t\t\tins.pinnacles?.length\n\t\t\t\t? html`<section class=\"sub\"><h3>Pinnacles</h3>${renderInterpAccordion(\n\t\t\t\t\t\tins.pinnacles.map((p) => ({\n\t\t\t\t\t\t\tlabel: [\n\t\t\t\t\t\t\t\tp.position != null ? `Pinnacle ${p.position}` : 'Pinnacle',\n\t\t\t\t\t\t\t\tp.meaning?.title ?? '',\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t.join(' \u00B7 '),\n\t\t\t\t\t\t\taside: [\n\t\t\t\t\t\t\t\tp.number != null ? `${p.number}` : '',\n\t\t\t\t\t\t\t\tageRange(p.startAge, p.endAge),\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t.join(' \u00B7 '),\n\t\t\t\t\t\t\tbody: p.meaning?.description ?? '',\n\t\t\t\t\t\t\textra: this.renderLists(\n\t\t\t\t\t\t\t\t['Opportunities', p.meaning?.opportunities],\n\t\t\t\t\t\t\t\t['Challenges', p.meaning?.challenges],\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t})),\n\t\t\t\t\t\t'numerology-pinnacles',\n\t\t\t\t\t\t'Life phases',\n\t\t\t\t\t)}</section>`\n\t\t\t\t: nothing\n\t\t}${\n\t\t\tins.challenges?.length\n\t\t\t\t? html`<section class=\"sub\"><h3>Challenges</h3>${renderInterpAccordion(\n\t\t\t\t\t\tins.challenges.map((c) => ({\n\t\t\t\t\t\t\tlabel: [\n\t\t\t\t\t\t\t\tc.position != null ? `Challenge ${c.position}` : 'Challenge',\n\t\t\t\t\t\t\t\tc.meaning?.title ?? '',\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t.join(' \u00B7 '),\n\t\t\t\t\t\t\taside: [\n\t\t\t\t\t\t\t\tc.number != null ? `${c.number}` : '',\n\t\t\t\t\t\t\t\tageRange(c.startAge, c.endAge),\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t.join(' \u00B7 '),\n\t\t\t\t\t\t\tbody: c.meaning?.description ?? '',\n\t\t\t\t\t\t\textra: html`${\n\t\t\t\t\t\t\t\tc.meaning?.lesson\n\t\t\t\t\t\t\t\t\t? html`<p><strong>Lesson.</strong> ${c.meaning.lesson}</p>`\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\tc.meaning?.howToOvercome\n\t\t\t\t\t\t\t\t\t? html`<p><strong>How to overcome.</strong> ${c.meaning.howToOvercome}</p>`\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})),\n\t\t\t\t\t\t'numerology-challenges',\n\t\t\t\t\t\t'Obstacle periods',\n\t\t\t\t\t)}</section>`\n\t\t\t\t: nothing\n\t\t}${\n\t\t\tpassion || subconscious\n\t\t\t\t? html`<section class=\"sub\"><h3>Name numbers</h3>${\n\t\t\t\t\t\tpassion\n\t\t\t\t\t\t\t? html`<div><h4 class=\"sub-title\">${[\n\t\t\t\t\t\t\t\t\t\tpassion.number != null\n\t\t\t\t\t\t\t\t\t\t\t? `Hidden passion ${passion.number}`\n\t\t\t\t\t\t\t\t\t\t\t: 'Hidden passion',\n\t\t\t\t\t\t\t\t\t\tpassion.title ?? '',\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t\t\t.join(' \u00B7 ')}</h4>${passion.description ? html`<p>${passion.description}</p>` : nothing} ${\n\t\t\t\t\t\t\t\t\ttypeof passion.count === 'number'\n\t\t\t\t\t\t\t\t\t\t? html`<p class=\"label\">${`Appears ${passion.count} times in the name`}</p>`\n\t\t\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t\t\t}</div>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t} ${\n\t\t\t\t\t\tsubconscious\n\t\t\t\t\t\t\t? html`<div><h4 class=\"sub-title\">${[\n\t\t\t\t\t\t\t\t\t\tsubconscious.number != null\n\t\t\t\t\t\t\t\t\t\t\t? `Subconscious self ${subconscious.number}`\n\t\t\t\t\t\t\t\t\t\t\t: 'Subconscious self',\n\t\t\t\t\t\t\t\t\t\tsubconscious.title ?? '',\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t\t\t.join(' \u00B7 ')}</h4>${subconscious.description ? html`<p>${subconscious.description}</p>` : nothing} ${\n\t\t\t\t\t\t\t\t\tsubconscious.uniqueNumbers?.length\n\t\t\t\t\t\t\t\t\t\t? html`<p class=\"label\">${`Numbers present: ${subconscious.uniqueNumbers.join(', ')}`}</p>`\n\t\t\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t\t\t}</div>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}</section>`\n\t\t\t\t: nothing\n\t\t}${\n\t\t\tletters\n\t\t\t\t? html`<section class=\"sub\"><h3>Name letters</h3>${renderInterpAccordion(\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tlabel: 'Cornerstone',\n\t\t\t\t\t\t\t\taside: letterAside(\n\t\t\t\t\t\t\t\t\tletters.cornerstone?.letter,\n\t\t\t\t\t\t\t\t\tletters.cornerstone?.number,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tbody: letters.cornerstone?.meaning ?? '',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tlabel: 'Capstone',\n\t\t\t\t\t\t\t\taside: letterAside(\n\t\t\t\t\t\t\t\t\tletters.capstone?.letter,\n\t\t\t\t\t\t\t\t\tletters.capstone?.number,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tbody: letters.capstone?.meaning ?? '',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tlabel: 'First vowel',\n\t\t\t\t\t\t\t\taside: letterAside(letters.firstVowel?.letter),\n\t\t\t\t\t\t\t\tbody: letters.firstVowel?.meaning ?? '',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t\t'numerology-name-letters',\n\t\t\t\t\t\t'Letter analysis',\n\t\t\t\t\t)}</section>`\n\t\t\t\t: nothing\n\t\t}`;\n\t}\n\n\t/** Hero row shared by every single-number view: the numeral, the label, the archetype, and the master-number badge when the number is 11, 22, or 33. */\n\tprivate renderHero(\n\t\theaderLabel: string,\n\t\tnum: number | undefined,\n\t\ttitle: string | undefined,\n\t\tmaster = false,\n\t) {\n\t\treturn html`<div class=\"hero\">${typeof num === 'number' ? html`<div class=\"numeral\">${num}</div>` : nothing}<div><p class=\"label\">${headerLabel}</p>${title ? html`<h2 class=\"title\">${title}</h2>` : nothing} ${master ? html`<span class=\"master\">Master number</span>` : nothing}</div></div>`;\n\t}\n\n\t/** Keyword chips, the strengths and challenges lists, and the three life-area readings behind a disclosure. The whole interpretation, laid out as a reading. */\n\tprivate renderReading(r: NumerologyReading | undefined, name: string) {\n\t\tif (!r) return nothing;\n\t\tconst sections: InterpSection[] = GUIDANCE_FIELDS.map(([key, label]) => ({\n\t\t\tlabel,\n\t\t\tbody: (r[key] as string | undefined) ?? '',\n\t\t}));\n\t\treturn html`${\n\t\t\tr.keywords?.length\n\t\t\t\t? html`<div class=\"chips\">${r.keywords.map((k) => html`<span>${k}</span>`)}</div>`\n\t\t\t\t: nothing\n\t\t}${this.renderLists(['Strengths', r.strengths], ['Challenges', r.challenges])}${renderInterpAccordion(sections, name, 'Guidance')}`;\n\t}\n\n\t/**\n\t * Side-by-side prose lists. Each entry names a trait and explains it, so they are bulleted paragraphs, never chips.\n\t *\n\t * @remarks\n\t * `h3`, not `h4`. This renders at the TOP level of the single-number card, where the only heading above it is the `h2` title, so an `h4` skips a level and fails the axe `heading-order` rule. Inside a chart section or an accordion body the heading above is already an `h3`, and a repeated level is fine: the rule flags skips, not repeats.\n\t */\n\tprivate renderLists(\n\t\t...lists: Array<[string, ReadonlyArray<string> | undefined]>\n\t) {\n\t\tconst shown = lists.filter(([, items]) => items && items.length > 0);\n\t\tif (shown.length === 0) return nothing;\n\t\treturn html`<div class=\"lists\">${shown.map(\n\t\t\t\t([label, items]) => html`<div><h3>${label}</h3><ul>${(items ?? []).map((item) => html`<li>${item}</li>`)}</ul></div>`,\n\t\t\t)}</div>`;\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\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\n/** A number is master when the API says so, or when it is one of the three that are never reduced. Both checks, because the period cycles carry the number without the `type` flag. */\nfunction isMaster(num: number | undefined, type?: string): boolean {\n\treturn type === 'master' || (num !== undefined && MASTER_NUMBERS.has(num));\n}\n\n/** \"5 \u00B7 Freedom and change\", the cycle a smaller cycle sits inside. Empty when the API sent neither half. */\nfunction joinCycle(num: number | undefined, theme: string | undefined): string {\n\treturn [num != null ? `${num}` : '', theme ?? ''].filter(Boolean).join(' \u00B7 ');\n}\n\n/** \"ages 27 to 35\", or \"ages 54 onward\" for the final phase, which the API closes with a null end age. */\nfunction ageRange(start: number | undefined, end: number | undefined): string {\n\tif (start == null) return '';\n\treturn end == null ? `ages ${start} onward` : `ages ${start} to ${end}`;\n}\n\n/** \"A \u00B7 1\" for a letter that carries a Pythagorean value, \"A\" for the first vowel, which does not. */\nfunction letterAside(letter?: string, num?: number): string {\n\treturn [letter ?? '', num != null ? `${num}` : '']\n\t\t.filter(Boolean)\n\t\t.join(' \u00B7 ');\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-numerology-card': RoxyNumerologyCard;\n\t}\n}\n", "import { css, html, nothing, type TemplateResult } 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 { formatSignPosition } from '../utils/degree.js';\nimport { formatDate, formatTime, formatTimeRange } from '../utils/format.js';\n\ntype PanchangData = GetBasicPanchangResponse | GetDetailedPanchangResponse;\ntype Detailed = GetDetailedPanchangResponse;\ntype PanchangTime = Detailed['rahuKaal'];\ntype RashiPlacement = Detailed['moonSign'];\ntype SunNakshatra = Detailed['sunNakshatra'];\ntype Hora = Detailed['hora'];\ntype Panchaka = Detailed['panchaka'];\ntype Bhadra = Detailed['bhadra'];\ntype Chandrabalam = Detailed['chandrabalam'];\ntype Tarabalam = Detailed['tarabalam'];\ntype MoonSignTransition = Detailed['transitions']['moonSign'];\n\n/** One limb of the panchang: the headline value plus the muted detail line under it. */\ninterface Limb {\n\tlabel: string;\n\tvalue: string;\n\tmeta: string;\n}\n\n/** Joins the parts of a detail line, dropping anything the response omitted. */\nfunction meta(...parts: Array<string | number | undefined | null>): string {\n\treturn parts.filter(Boolean).join(' \u00B7 ');\n}\n\n/** The headline value of a limb: its name plus the one qualifier that belongs on the same line. */\nfunction name(...parts: Array<string | undefined>): string {\n\treturn parts.filter(Boolean).join(', ');\n}\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 * each with the reading that comes with it: the tithi ruling planet, deity,\n * element and how far it has elapsed; the nakshatra lord, deity and symbol; the\n * yoga and karana characteristics. Detailed mode adds the sunrise placements a\n * reader scans first (Moon rashi, Sun rashi, Sun nakshatra, current hora), the\n * exact transition times including the Moon sign change, and groups every timed\n * window into auspicious (fixed muhurtas plus each Amrit Kalam) and\n * inauspicious (Rahu Kaal, Yamaganda, Gulika, each Dur Muhurta and Varjyam,\n * plus Bhadra and Panchaka). Chandrabalam and Tarabalam close the card: which\n * birth rashis and birth nakshatras this day favors, the surface a muhurta is\n * actually chosen on.\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}td small{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);font-variant-numeric:normal;margin-top:2px;line-height:1.5;display:block}.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}.quiet{color:var(--roxy-muted,#71717a)}.chips{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;margin-top:4px;display:flex}.chip{border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);background:color-mix(in srgb, var(--roxy-border,#e4e4e7) 55%, transparent);padding:1px 8px}.chip.good{background:color-mix(in srgb, var(--roxy-success,#16a34a) 14%, transparent);color:var(--roxy-success-fg,#166534)}.chip.bad{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 14%, transparent);color:var(--roxy-danger-fg,#991b1b)}`,\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\t\tconst basic = 'sunLongitude' in d ? d : null;\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 showTimings = this.detail === 'detailed' && detailed !== null;\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>${this.limbs(d, detailed).map((l) => this.renderLimbRow(l))} ${\n\t\t\t\t\t\tdetailed\n\t\t\t\t\t\t\t? html`${this.renderRow('Sunrise', formatTime(detailed.sunrise))} ${this.renderRow('Sunset', formatTime(detailed.sunset))} ${this.renderRow('Moonrise', formatTime(detailed.moonrise))} ${this.renderRow('Moonset', formatTime(detailed.moonset))} ${this.renderRow('Moon sign', this.formatRashi(detailed.moonSign))} ${this.renderRow('Sun sign', this.formatRashi(detailed.sunSign))} ${this.renderRow('Sun nakshatra', this.formatSunNakshatra(detailed.sunNakshatra))} ${this.renderRow('Hora', this.formatHora(detailed.hora))}`\n\t\t\t\t\t\t\t: basic\n\t\t\t\t\t\t\t\t? html`${this.renderRow('Sun', this.formatLongitude(basic.sunLongitude))} ${this.renderRow('Moon', this.formatLongitude(basic.moonLongitude))}`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}</tbody></table>${detailed ? this.renderTransitions(detailed.transitions) : nothing} ${\n\t\t\t\tshowTimings\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])} ${this.renderBhadraRow(detailed.bhadra)} ${this.renderPanchakaRow(detailed.panchaka)}</tbody></table>${this.renderBalams(detailed.chandrabalam, detailed.tarabalam)}`\n\t\t\t\t\t: nothing\n\t\t\t}</div>`;\n\t}\n\n\t/**\n\t * The five limbs, each with its own reading. Basic and detailed carry the\n\t * same limb shapes; only detailed carries the vara.\n\t */\n\tprivate limbs(d: PanchangData, detailed: Detailed | null): Limb[] {\n\t\tconst t = d.tithi;\n\t\tconst n = d.nakshatra;\n\t\tconst y = d.yoga;\n\t\tconst k = d.karana;\n\t\tconst rows: Limb[] = [\n\t\t\t{\n\t\t\t\tlabel: 'Tithi',\n\t\t\t\tvalue: name(t?.name, t?.paksha ? `${t.paksha} paksha` : undefined),\n\t\t\t\tmeta: meta(\n\t\t\t\t\tt?.rulingPlanet ? `Ruled by ${t.rulingPlanet}` : undefined,\n\t\t\t\t\tt?.deity ? `Deity ${t.deity}` : undefined,\n\t\t\t\t\tt?.element,\n\t\t\t\t\ttypeof t?.percent === 'number'\n\t\t\t\t\t\t? `${Math.round(t.percent)}% elapsed`\n\t\t\t\t\t\t: undefined,\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: 'Nakshatra',\n\t\t\t\tvalue: name(\n\t\t\t\t\tn?.name,\n\t\t\t\t\ttypeof n?.pada === 'number' ? `pada ${n.pada}` : undefined,\n\t\t\t\t),\n\t\t\t\tmeta: meta(\n\t\t\t\t\tn?.lord ? `Lord ${n.lord}` : undefined,\n\t\t\t\t\tn?.deity ? `Deity ${n.deity}` : undefined,\n\t\t\t\t\tn?.symbol ? `Symbol ${n.symbol}` : undefined,\n\t\t\t\t\tn?.characteristics,\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: 'Yoga',\n\t\t\t\tvalue: y?.name ?? '',\n\t\t\t\tmeta: y?.characteristics ?? '',\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: 'Karana',\n\t\t\t\tvalue: name(k?.name, k?.type),\n\t\t\t\tmeta: k?.characteristics ?? '',\n\t\t\t},\n\t\t];\n\t\tif (detailed?.vara) {\n\t\t\trows.push({\n\t\t\t\tlabel: 'Vara',\n\t\t\t\tvalue: detailed.vara.name ?? '',\n\t\t\t\tmeta: detailed.vara.lord ? `Lord ${detailed.vara.lord}` : '',\n\t\t\t});\n\t\t}\n\t\treturn rows.filter((l) => Boolean(l.value));\n\t}\n\n\tprivate renderLimbRow(l: Limb) {\n\t\treturn html`<tr><th>${l.label}</th><td>${l.value}${l.meta ? html`<small>${l.meta}</small>` : nothing}</td></tr>`;\n\t}\n\n\t/** One label/value row, skipped when the value is empty. */\n\tprivate renderRow(\n\t\tlabel: string,\n\t\tvalue: string,\n\t): TemplateResult | typeof nothing {\n\t\tif (!value) return nothing;\n\t\treturn html`<tr><th>${label}</th><td>${value}</td></tr>`;\n\t}\n\n\tprivate renderTransitions(t: Detailed['transitions'] | undefined) {\n\t\tif (!t) return nothing;\n\t\treturn html`<div class=\"section\">Next transitions</div><table><tbody>${this.renderTransitionRow('Tithi', t.tithi)} ${this.renderTransitionRow('Nakshatra', t.nakshatra)} ${this.renderTransitionRow('Yoga', t.yoga)} ${this.renderTransitionRow('Karana', t.karana)} ${this.renderMoonSignRow(t.moonSign)}</tbody></table>`;\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\t/**\n\t * Bhadra (Vishti karana) is avoided for every auspicious act, so \"none today\"\n\t * is as much of an answer as a window and is stated rather than left blank.\n\t */\n\tprivate renderBhadraRow(b: Bhadra | undefined) {\n\t\tif (!b) return nothing;\n\t\tconst span = this.formatSpan(b.startsAt, b.endsAt);\n\t\treturn html`<tr><th>Bhadra (Vishti)</th><td>${b.active && span ? span : html`<span class=\"quiet\">None today</span>`}</td></tr>`;\n\t}\n\n\t/**\n\t * Panchaka runs about five days, so the window commonly starts before or ends\n\t * after this date; the dosha type names which of the five it is.\n\t */\n\tprivate renderPanchakaRow(p: Panchaka | undefined) {\n\t\tif (!p) return nothing;\n\t\tconst span = this.formatSpan(p.startsAt, p.endsAt);\n\t\treturn html`<tr><th>Panchaka</th><td>${\n\t\t\t\t\tp.active\n\t\t\t\t\t\t? html`${p.type ? `${p.type} Panchaka` : 'Panchaka'}${\n\t\t\t\t\t\t\t\tspan ? html`<small>${span}</small>` : nothing\n\t\t\t\t\t\t\t}`\n\t\t\t\t\t\t: html`<span class=\"quiet\">None today</span>`\n\t\t\t\t}</td></tr>`;\n\t}\n\n\t/**\n\t * Chandrabalam and Tarabalam are read against the querent's own birth rashi\n\t * and birth nakshatra, so both lists are shown in full rather than summarized.\n\t */\n\tprivate renderBalams(c: Chandrabalam | undefined, t: Tarabalam | undefined) {\n\t\tif (!c && !t) return nothing;\n\t\treturn html`<div class=\"section\">Chandrabalam and Tarabalam</div><table><tbody>${\n\t\t\t\t\t\tc\n\t\t\t\t\t\t\t? html`<tr><th>Favorable Moon signs</th><td>${this.renderChips(c.favorableRashis, 'good')}</td></tr>${this.renderRow('Ashtama Chandra rashi', c.ashtamaChandraRashi ?? '')}`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t} ${\n\t\t\t\t\t\tt\n\t\t\t\t\t\t\t? html`<tr><th>Favorable birth nakshatras</th><td>${this.renderChips(t.favorableNakshatras, 'good')}</td></tr><tr><th>Unfavorable birth nakshatras</th><td>${this.renderChips(t.unfavorableNakshatras, 'bad')}</td></tr>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}</tbody></table>`;\n\t}\n\n\tprivate renderChips(items: string[] | undefined, tone: 'good' | 'bad') {\n\t\tif (!items?.length) return html`<span class=\"quiet\">None</span>`;\n\t\treturn html`<div class=\"chips\">${items.map((i) => html`<span class=\"chip ${tone}\">${i}</span>`)}</div>`;\n\t}\n\n\tprivate renderTransitionRow(\n\t\tlabel: string,\n\t\tt: { endsAt?: string; next?: string; nextPada?: number } | undefined,\n\t) {\n\t\tif (!t?.endsAt) return nothing;\n\t\tconst next = t.next\n\t\t\t? ` to ${t.next}${typeof t.nextPada === 'number' ? ` pada ${t.nextPada}` : ''}`\n\t\t\t: '';\n\t\treturn html`<tr><th>${label}</th><td>ends ${formatTime(t.endsAt)}${next}</td></tr>`;\n\t}\n\n\tprivate renderMoonSignRow(m: MoonSignTransition | undefined) {\n\t\tif (!m?.changesAt) return nothing;\n\t\treturn html`<tr><th>Moon sign</th><td>${m.current ?? ''} until ${formatTime(m.changesAt)}${m.next ? `, then ${m.next}` : ''}</td></tr>`;\n\t}\n\n\t/** A window that may end on the following day carries that date so it cannot be misread. */\n\tprivate formatSpan(\n\t\tstart: string | null | undefined,\n\t\tend: string | null | undefined,\n\t): string {\n\t\tconst range = formatTimeRange({\n\t\t\tstart: start ?? undefined,\n\t\t\tend: end ?? undefined,\n\t\t});\n\t\tif (!range || !start || !end) return range;\n\t\treturn start.slice(0, 10) === end.slice(0, 10)\n\t\t\t? range\n\t\t\t: `${range} (ends ${formatDate(end)})`;\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\treturn meta(\n\t\t\tn.name,\n\t\t\ttypeof n.pada === 'number' ? `pada ${n.pada}` : undefined,\n\t\t\tn.lord ? `lord ${n.lord}` : undefined,\n\t\t);\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\t/** Basic mode returns raw sidereal longitudes rather than named placements. */\n\tprivate formatLongitude(lon: number | undefined): string {\n\t\treturn typeof lon === 'number' ? formatSignPosition(lon) : '';\n\t}\n}\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 { disclosureStyles } from '../utils/disclosure.js';\nimport { formatNumber } from '../utils/format.js';\nimport {\n\ttype InterpSection,\n\tinterpAccordionStyles,\n\trenderInterpAccordion,\n} from '../utils/interp-accordion.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\tinterpAccordionStyles,\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);grid-template-columns:minmax(0,1fr);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;min-width:0;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}`,\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\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>${this.renderReadings(vm.rows)}</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 renderReadings(rows: Row[]) {\n\t\tconst sections: InterpSection[] = rows\n\t\t\t.filter((r) => r.interpretation)\n\t\t\t.map((r) => {\n\t\t\t\tconst glyph = PLANET_GLYPH[capitalize(r.label)] ?? '';\n\t\t\t\treturn {\n\t\t\t\t\tlabel: `${glyph} ${r.label}`.trim(),\n\t\t\t\t\taside: `${r.sign} ${formatDegreeInSign(r.degree)}`.trim(),\n\t\t\t\t\tbody: r.interpretation ?? '',\n\t\t\t\t};\n\t\t\t});\n\t\treturn renderInterpAccordion(sections, 'positions-readings', 'Readings');\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 { RelocationChartResponse } 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}\"></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}.phala{border-radius:var(--roxy-radius-full,9999px);background:var(--roxy-border,#e4e4e7);height:6px;display:flex;overflow:hidden}.phala-ishta{background:var(--roxy-success,#16a34a)}.phala-kashta{background:var(--roxy-danger,#dc2626)}.phala-label{justify-content:space-between;gap:var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);font-variant-numeric:tabular-nums;display:flex}.footnote{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);margin:0}.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><p class=\"footnote\">Ishta Phala is the capacity to give benefic results, Kashta Phala the capacity to give malefic ones. Both are in virupas and are read together, since a planet can be strong and still deliver hardship.</p></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>${this.renderPhala(p)}</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\t/**\n\t * Ishta and Kashta Phala, the fruit a planet is capable of giving in its dasha\n\t * and transits. They are derived from Uchcha and Chesta Bala, not from the\n\t * six-fold total, so a planet can rank first on strength and still carry a\n\t * heavy Kashta share. Rendering only the total hides exactly that.\n\t */\n\tprivate renderPhala(p: Planet) {\n\t\tconst ishta = typeof p.ishtaPhala === 'number' ? p.ishtaPhala : 0;\n\t\tconst kashta = typeof p.kashtaPhala === 'number' ? p.kashtaPhala : 0;\n\t\tif (ishta + kashta <= 0) return nothing;\n\t\tconst ishtaStr = formatNumber(ishta, 1) || '0';\n\t\tconst kashtaStr = formatNumber(kashta, 1) || '0';\n\t\treturn html`<div class=\"phala\" role=\"img\" aria-label=\"Ishta Phala ${ishtaStr}, Kashta Phala ${kashtaStr} virupas\"><span class=\"phala-ishta\" style=\"flex-grow:${ishta}\"></span> <span class=\"phala-kashta\" style=\"flex-grow:${kashta}\"></span></div><div class=\"phala-label\"><span>Ishta ${ishtaStr}</span> <span>Kashta ${kashtaStr}</span></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 { chevron, disclosureStyles } from '../utils/disclosure.js';\nimport {\n\tASPECT_CLASS,\n\tformatNumber,\n\tnormalizeAspect,\n} from '../utils/format.js';\nimport { interpAccordionStyles } from '../utils/interp-accordion.js';\nimport { capitalize } from '../utils/string.js';\n\ntype PlanetEntry = NatalChartResponse['planets'][number];\ntype InterAspect = CalculateSynastryResponse['interAspects'][number];\ntype SynastrySummary = CalculateSynastryResponse['summary'];\ntype SynastryPerson = CalculateSynastryResponse['person1'];\n\n/** How many inter-aspects get a full reading before the rest fall back to the catalog table. A synastry can return 90+ contacts; a practitioner works the tightest ones. */\nconst READING_COUNT = 12;\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\tdisclosureStyles,\n\t\tinterpAccordionStyles,\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);grid-template-columns:minmax(0,1fr);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}.people{gap:var(--roxy-space-sm,.5rem);grid-template-columns:repeat(auto-fit,minmax(11rem,1fr));display:grid}.person{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);gap:.3rem;display:grid}.person-name{font-weight:var(--roxy-weight-bold,600);font-size:var(--roxy-text-sm,.875rem);align-items:center;gap:.4rem;display:flex}.person-dot{border-radius:50%;flex-shrink:0;width:8px;height:8px}.person-dot.p1{background:var(--roxy-accent,#f59e0b)}.person-dot.p2{background:var(--roxy-info,#0284c7)}.big-three{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);flex-wrap:wrap;gap:.25rem .75rem;display:flex}.big-three span{align-items:baseline;gap:.25rem;display:inline-flex}.big-three .lbl{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem)}.summary-pills{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;display:flex}.pill{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) 60%, transparent);color:var(--roxy-fg,#0a0a0a);padding:2px 8px}.pill--success{background:color-mix(in srgb, var(--roxy-success,#16a34a) 12%, transparent);color:var(--roxy-success-fg,#166534)}.pill--danger{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 12%, transparent);color:var(--roxy-danger-fg,#991b1b)}.glyph{font-size:1.1em;line-height:1}.static-head{align-items:center;gap:var(--roxy-space-sm,.5rem);font-size:var(--roxy-text-sm,.875rem);flex-wrap:wrap;font-weight:500;display:flex}.asp-name{font-weight:var(--roxy-weight-bold,600);text-transform:capitalize}.asp-name.harmonious{color:var(--roxy-success-fg,#166534)}.asp-name.challenging{color:var(--roxy-danger-fg,#991b1b)}.interp-keywords{flex-wrap:wrap;gap:.25rem;display:flex}.interp-keywords .kw{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);padding:1px 8px}.context{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem);text-transform:uppercase;letter-spacing:.06em;font-weight:var(--roxy-weight-bold,600)}.catalog>summary{cursor:pointer;font-weight:var(--roxy-weight-bold,600);font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-fg,#0a0a0a);align-items:center;gap:.5rem;display:flex}.scroll{min-width:0;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{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 returns chart highlights (Sun, Moon, Ascendant) but\n\t\t// not full planet positions, so the dual wheel cannot be drawn from a bare\n\t\t// synastry response. Say so instead of rendering a blank wheel; every other\n\t\t// block still renders, so a caller who passes the bare response gets the\n\t\t// full reading minus the drawing.\n\t\tconst hasPlanets = p1Planets.length > 0 && p2Planets.length > 0;\n\t\t// The tightest contacts carry the reading. Sort a copy: `data` is the\n\t\t// caller's object.\n\t\tconst ranked = [...interAspects].sort(\n\t\t\t(a, b) => (b.strength ?? 0) - (a.strength ?? 0),\n\t\t);\n\t\tconst lead = ranked.slice(0, READING_COUNT);\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>${this.renderPeople(person1, person2)} ${\n\t\t\t\thasPlanets\n\t\t\t\t\t? html`<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>`\n\t\t\t\t\t: html`<div class=\"missing-planets\" role=\"status\">Synastry response missing planet positions. Pass <code>data</code> with <code>person1.planets</code> and <code>person2.planets</code> arrays from the natal-chart endpoint, or use the <code>&lt;roxy-data></code> fallback.</div>`\n\t\t\t} ${this.renderSummaryPills(d.summary)} ${summaryText ? html`<p class=\"summary\">${summaryText}</p>` : nothing} ${\n\t\t\t\tlead.length > 0\n\t\t\t\t\t? html`<section class=\"block\"><h3>Inter-aspects</h3>${lead.map((a, i) => this.renderAspectCard(a, i))}</section>`\n\t\t\t\t\t: nothing\n\t\t\t} ${ranked.length > lead.length ? this.renderCatalog(ranked) : 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\t/** Chart highlights for both people: the Sun, Moon, and Ascendant a reader checks before any aspect. Colour-dotted to match each person ring on the wheel. */\n\tprivate renderPeople(\n\t\tp1: SynastryPerson | undefined,\n\t\tp2: SynastryPerson | undefined,\n\t) {\n\t\tconst card = (p: SynastryPerson | undefined, index: 1 | 2) => {\n\t\t\tif (!p) return nothing;\n\t\t\tconst big: Array<[string, string]> = [\n\t\t\t\t['Sun', p.sunSign ?? ''],\n\t\t\t\t['Moon', p.moonSign ?? ''],\n\t\t\t\t[\n\t\t\t\t\t'Asc',\n\t\t\t\t\tp.ascendant\n\t\t\t\t\t\t? `${p.ascendant.sign} ${formatNumber(p.ascendant.degree, 0)}\u00B0`\n\t\t\t\t\t\t: '',\n\t\t\t\t],\n\t\t\t];\n\t\t\tconst shown = big.filter(([, value]) => value);\n\t\t\tif (shown.length === 0) return nothing;\n\t\t\treturn html`<div class=\"person\"><span class=\"person-name\"><span class=\"person-dot p${index}\" aria-hidden=\"true\"></span> ${p.name || `Person ${index}`}</span><div class=\"big-three\">${shown.map(\n\t\t\t\t\t\t([label, value]) => html`<span><span class=\"lbl\">${label}</span> <span aria-hidden=\"true\">${SIGN_GLYPH[capitalize(value.split(' ')[0] ?? '')] ?? ''}</span> ${value}</span>`,\n\t\t\t\t\t)}</div></div>`;\n\t\t};\n\t\tconst cards = [card(p1, 1), card(p2, 2)].filter((c) => c !== nothing);\n\t\tif (cards.length === 0) return nothing;\n\t\treturn html`<div class=\"people\">${cards}</div>`;\n\t}\n\n\t/** Contact balance for the pair. `byType` is a map, so its pairs are rendered, never the object. */\n\tprivate renderSummaryPills(s: SynastrySummary | undefined) {\n\t\tif (!s || typeof s !== 'object') return nothing;\n\t\tconst byType = Object.entries(s.byType ?? {}).sort((a, b) => b[1] - a[1]);\n\t\tif (typeof s.total !== 'number' && byType.length === 0) return nothing;\n\t\treturn html`<div class=\"summary-pills\" role=\"region\" aria-label=\"Inter-aspect summary\">${typeof s.total === 'number' ? html`<span class=\"pill\">Total: ${s.total}</span>` : nothing} <span class=\"pill pill--success\">Harmonious: ${s.harmonious}</span> <span class=\"pill pill--danger\">Challenging: ${s.challenging}</span> <span class=\"pill\">Neutral: ${s.neutral}</span> ${byType.map(\n\t\t\t\t([type, count]) =>\n\t\t\t\t\thtml`<span class=\"pill\">${capitalize(type.replace(/_/g, ' '))}: ${count}</span>`,\n\t\t\t)}</div>`;\n\t}\n\n\t/**\n\t * One inter-chart contact as a reading. The header is the scannable line (both bodies, the aspect coloured by nature, orb and strength); the body leads with `meaning.relationshipContext`, which is the whole point of a synastry aspect: not what a trine means, but what THIS trine does to THESE two people.\n\t */\n\tprivate renderAspectCard(a: InterAspect, index: number) {\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 meaning = a.meaning;\n\t\tconst lead = html`<span class=\"interp-lead\"><span aria-hidden=\"true\" class=\"glyph\">${g1}</span>${a.planet1} <span class=\"asp-name ${nature}\">${normalizeAspect(a)}</span> <span aria-hidden=\"true\" class=\"glyph\">${g2}</span>${a.planet2}</span>`;\n\t\tconst aside = html`<span class=\"interp-aside\"><small>orb ${formatNumber(a.orb, 2)}\u00B0 \u00B7 str ${formatNumber(a.strength, 0)}</small></span>`;\n\t\tif (!meaning?.relationshipContext && !meaning?.description?.short) {\n\t\t\treturn html`<div class=\"interp-card\"><div class=\"static-head\">${lead}${aside}</div></div>`;\n\t\t}\n\t\treturn html`<details class=\"interp-card\" name=\"synastry-aspects\" ?open=\"${index === 0}\"><summary>${lead}${chevron()}${aside}</summary><div class=\"interp-body\">${\n\t\t\t\t\tmeaning.relationshipContext\n\t\t\t\t\t\t? html`<p><span class=\"context\">In this pairing</span> ${meaning.relationshipContext}</p>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t} ${meaning.description?.short ? html`<p>${meaning.description.short}</p>` : nothing} ${\n\t\t\t\t\tmeaning.keywords?.length\n\t\t\t\t\t\t? html`<div class=\"interp-keywords\">${meaning.keywords.map((k) => html`<span class=\"kw\">${k}</span>`)}</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}</div></details>`;\n\t}\n\n\t/** Every remaining contact, so nothing the endpoint returned is dropped. */\n\tprivate renderCatalog(ranked: InterAspect[]) {\n\t\treturn html`<details class=\"catalog\"><summary>${chevron()} All ${ranked.length} inter-aspects</summary><div class=\"scroll\">${this.renderAspects(ranked)}</div></details>`;\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><caption class=\"roxy-sr-only\">Inter-chart aspects: the planet from chart 1, the planet from chart 2, the aspect between them, the orb in degrees and the strength.</caption><thead><tr><th scope=\"col\">Planet 1</th><th scope=\"col\">Planet 2</th><th scope=\"col\">Aspect</th><th scope=\"col\">Orb</th><th scope=\"col\">Strength</th></tr></thead><tbody>${aspects.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>${formatNumber(a.strength, 0)}</td></tr>`,\n\t\t\t\t)}</tbody></table>`;\n\t}\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';\nimport { disclosureStyles } from '../utils/disclosure.js';\nimport {\n\ttype InterpSection,\n\tinterpAccordionStyles,\n\trenderInterpAccordion,\n} from '../utils/interp-accordion.js';\nimport { renderTablist, tablistStyles } from '../utils/tablist.js';\n\ntype TarotData = GetCardResponse | GetDailyCardResponse;\n\n/** The five life-area readings every tarot orientation carries. Both shapes the component renders supply them: the reference card carries a set per orientation, the drawn card carries one set for the orientation it landed in. */\ntype TarotGuidance = Pick<\n\tGetCardResponse['upright'],\n\t'love' | 'career' | 'finances' | 'health' | 'spirituality'\n>;\n\nconst GUIDANCE_FIELDS: ReadonlyArray<[keyof TarotGuidance, string]> = [\n\t['love', 'Love'],\n\t['career', 'Career'],\n\t['finances', 'Finances'],\n\t['health', 'Health'],\n\t['spirituality', 'Spirituality'],\n];\n\n/**\n * Tarot card. Renders /tarot/cards/{id} and /tarot/daily.\n *\n * @remarks\n * The two endpoints are NOT the same card and must not be shown the same way. The reference card ships both orientations, so the reader chooses one and the whole reading (image, keywords, description, life areas) follows that choice. The daily card is DRAWN: the API ships exactly one orientation and one set of meanings for it, so there is nothing to switch to. It used to offer the same flip, which rotated the art and relabelled the card \"reversed\" while the text below it stayed the upright reading. The draw is now fixed and stated, never toggled.\n */\n@customElement('roxy-tarot-card')\nexport class RoxyTarotCard extends RoxyDataElement<TarotData> {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tdisclosureStyles,\n\t\tinterpAccordionStyles,\n\t\ttablistStyles,\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{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));display:block}.image.reversed{transform:rotate(180deg)}.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)}.drawn{color:var(--roxy-fg,#0a0a0a);font-weight:var(--roxy-weight-bold,600)}.message{color:var(--roxy-fg,#0a0a0a);margin:var(--roxy-space-sm,.5rem) 0 var(--roxy-space-md,1rem)}.reading{margin:0 0 var(--roxy-space-md,1rem);white-space:pre-line}.roxy-tablist{margin:var(--roxy-space-sm,.5rem) 0}.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);color:var(--roxy-fg,#0a0a0a);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);padding:2px 8px}`,\n\t];\n\n\t/** Which orientation of the REFERENCE card is being read. The daily draw ignores this: its orientation is whatever was drawn. */\n\t@state()\n\tprivate orientation: 'upright' | 'reversed' = 'upright';\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 reversed = Boolean(card.reversed);\n\t\tconst keywords = card.keywords ?? [];\n\t\t// One text node per span: the markup minifier collapses whitespace at an\n\t\t// expression boundary, so every separator is joined in JS, never in markup.\n\t\tconst meta = [card.arcana ? `${card.arcana} arcana` : '', card.suit ?? '']\n\t\t\t.filter(Boolean)\n\t\t\t.join(' \u00B7 ');\n\n\t\treturn html`<article class=\"card\" aria-label=\"${card.name ?? 'Tarot card'}\">${this.renderImage(card.imageUrl, card.name, reversed)}<div><div class=\"meta\">${meta ? `${meta} \u00B7 ` : ''}<span class=\"drawn\">${reversed ? 'drawn reversed' : 'drawn upright'}</span></div><h2 class=\"title\">${card.name ?? 'Tarot card'}</h2>${d.dailyMessage ? html`<p class=\"message\">${d.dailyMessage}</p>` : nothing} ${card.meaning ? html`<p class=\"reading\">${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} ${this.renderGuidance(card, 'tarot-daily-guidance')}</div></article>`;\n\t}\n\n\tprivate renderFullCard(d: GetCardResponse) {\n\t\tconst reversed = this.orientation === 'reversed';\n\t\tconst oriented = reversed ? d.reversed : d.upright;\n\t\tconst keywords =\n\t\t\t(reversed ? d.keywords?.reversed : d.keywords?.upright) ??\n\t\t\toriented?.keywords ??\n\t\t\t[];\n\n\t\treturn html`<article class=\"card\" aria-label=\"${d.name ?? 'Tarot card'}\">${this.renderImage(d.imageUrl, d.name, reversed)}<div><div class=\"meta\">${[\n\t\t\t\t\t\td.arcana ? `${d.arcana} arcana` : '',\n\t\t\t\t\t\td.suit ?? '',\n\t\t\t\t\t\td.number !== undefined && d.number !== null\n\t\t\t\t\t\t\t? `no. ${d.number}`\n\t\t\t\t\t\t\t: '',\n\t\t\t\t\t]\n\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t.join(' \u00B7 ')}</div><h2 class=\"title\">${d.name ?? 'Tarot card'}</h2>${renderTablist({\n\t\t\t\t\titems: [\n\t\t\t\t\t\t{ id: 'upright', label: 'Upright' },\n\t\t\t\t\t\t{ id: 'reversed', label: 'Reversed' },\n\t\t\t\t\t],\n\t\t\t\t\tactive: this.orientation,\n\t\t\t\t\tonSelect: (id) => {\n\t\t\t\t\t\tthis.orientation = id;\n\t\t\t\t\t},\n\t\t\t\t\tlabel: 'Card orientation',\n\t\t\t\t\tidPrefix: 'tarot',\n\t\t\t\t})} ${oriented?.description ? html`<p class=\"reading\">${oriented.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} ${this.renderGuidance(oriented, `tarot-${this.orientation}-guidance`)}</div></article>`;\n\t}\n\n\t/** The artwork, rotated when the orientation being read is reversed. Decorative beyond its alt text: the orientation is stated in the meta line, so the image is never the only place it appears. */\n\tprivate renderImage(\n\t\timageUrl: string | undefined,\n\t\tname: string | undefined,\n\t\treversed: boolean,\n\t) {\n\t\tconst cls = `image ${reversed ? 'reversed' : ''}`;\n\t\tif (!imageUrl) {\n\t\t\treturn html`<div class=\"${cls}\" style=\"aspect-ratio:0.6;display:flex;align-items:center;justify-content:center;color:var(--roxy-muted)\">${name ?? '?'}</div>`;\n\t\t}\n\t\treturn html`<img class=\"${cls}\" src=\"${imageUrl}\" alt=\"${name ?? 'Tarot card'}\">`;\n\t}\n\n\t/** The five life-area readings for the orientation on screen. Grouped per orientation so switching the reference card swaps the whole accordion rather than leaving a stale section open. */\n\tprivate renderGuidance(guidance: TarotGuidance | undefined, name: string) {\n\t\tif (!guidance) return nothing;\n\t\tconst sections: InterpSection[] = GUIDANCE_FIELDS.map(([key, label]) => ({\n\t\t\tlabel,\n\t\t\tbody: guidance[key] ?? '',\n\t\t}));\n\t\treturn renderInterpAccordion(sections, name, 'Guidance');\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)}.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);color:var(--roxy-fg,#0a0a0a);border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);padding:2px 8px}.verdict{gap:var(--roxy-space-md,1rem);grid-template-columns:minmax(0,8rem) 1fr;align-items:start;display:grid}@container (width<=26rem){.verdict{grid-template-columns:1fr}}.verdict .meta{gap:var(--roxy-space-sm,.5rem);justify-items:start;display:grid}.arcana{font-size:var(--roxy-text-xs,.75rem);color:var(--roxy-muted,#71717a);text-transform:uppercase;letter-spacing:.06em;margin:0}.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 verdictCard = isYesNo ? (d as CastYesNoResponse).card : 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 class=\"verdict\"><div class=\"card\"><div class=\"image\">${\n\t\t\t\t\t\t\t\t\tverdictCard?.imageUrl\n\t\t\t\t\t\t\t\t\t\t? html`<img src=\"${verdictCard.imageUrl}\" alt=\"${verdictCard.name ?? 'tarot card'}\" class=\"${verdictCard.reversed ? 'reversed' : ''}\">`\n\t\t\t\t\t\t\t\t\t\t: html`${verdictCard?.name ?? '?'}`\n\t\t\t\t\t\t\t\t}</div><p class=\"name\">${verdictCard?.name ?? ''} ${verdictCard?.reversed ? html`<small>(reversed)</small>` : nothing}</p>${verdictCard?.arcana ? html`<p class=\"arcana\">${verdictCard.arcana} arcana</p>` : nothing}</div><div class=\"meta\"><div><span class=\"${`answer ${answerClass}`}\">${answer}</span> ${strength ? html`<small>\u00B7 ${strength}</small>` : nothing}</div>${\n\t\t\t\t\t\t\t\tverdictCard?.keywords && verdictCard.keywords.length > 0\n\t\t\t\t\t\t\t\t\t? html`<div class=\"chips\">${verdictCard.keywords.map((k) => html`<span>${k}</span>`)}</div>`\n\t\t\t\t\t\t\t\t\t: nothing\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\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);grid-template-columns:minmax(0,1fr);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;min-width:0;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\"><caption class=\"roxy-sr-only\">Transiting planets: each planet with its current sign, degree and daily speed.</caption><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 { formatSignPosition } from '../utils/degree.js';\nimport { formatDate, formatNumber, formatTime } 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 * @remarks\n * `datetime` is the chart time, the wall clock of the request, NOT UTC: hold the date and time fixed and vary `timezone` and every longitude in the response moves, while `datetime` does not. It is labelled \"Chart time\" for that reason. The spec description calling it UTC is wrong and is tracked upstream. The sidereal positions the aspects were derived from are shown above the table so a reader can check the drishti against the actual placements.\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);grid-template-columns:minmax(0,1fr);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}.position{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);color:var(--roxy-fg,#0a0a0a);font-variant-numeric:tabular-nums;align-items:baseline;gap:.35rem;padding:2px 10px;display:inline-flex}.position strong{color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-sm,.875rem)}.overflow-scroll{-webkit-overflow-scrolling:touch;min-width:0;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\tconst planets = d.planets ?? [];\n\t\tif (aspects.length === 0 && mutual.length === 0) return this.renderEmpty();\n\t\tconst when = d.datetime\n\t\t\t? `${formatDate(d.datetime)}, ${formatTime(d.datetime)}`\n\t\t\t: '';\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"Vedic aspects\"><div class=\"head\"><h2 class=\"title\">Vedic Aspects</h2>${when ? html`<p class=\"subtitle\">Chart time ${when}</p>` : nothing}</div>${\n\t\t\t\tplanets.length > 0\n\t\t\t\t\t? html`<div><p class=\"section-label\">Sidereal positions</p><div class=\"mutual\">${planets.map(\n\t\t\t\t\t\t\t\t(p) => html`<span class=\"position\"><strong>${p.name}</strong> ${typeof p.longitude === 'number' ? formatSignPosition(p.longitude) : (p.sign ?? '')}</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\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><caption class=\"roxy-sr-only\">Vedic planetary aspects: aspecting planet, aspect type, aspected planet, strength and orb.</caption><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{min-width:0;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);grid-template-columns:minmax(0,1fr);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\"><caption class=\"roxy-sr-only\">Vedic planetary positions: each graha with its rashi, degree, nakshatra, pada, nakshatra lord, house, avastha and retrograde state.</caption><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\"><caption class=\"roxy-sr-only\">Western planetary positions: each body with its sign, degree, house and motion.</caption><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,navamsa}',\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 and nodes in tabbed stellar-hierarchy tables',\n\t\tdocsLabel: 'Vedic (KP)',\n\t\tendpointLabel: 'POST /vedic-astrology/kp/chart',\n\t\tdocsSummary:\n\t\t\t'Ascendant, cusps, planets and nodes 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:\n\t\t\t'GET /vedic-astrology/yoga, POST /vedic-astrology/yoga/detect',\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 the full reading: type, strategy, authority, profile, definition, incarnation cross, and a gate and line meaning for every activation',\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, and gates, plus the type, strategy, authority, profile, and definition readings, the channels by circuit, the centers, and every activation with its gate and line meaning',\n\t\ttopic: 'Human Design',\n\t},\n\t{\n\t\tpascal: 'RoxyHdTypeCard',\n\t\ttag: 'roxy-hd-type-card',\n\t\tslug: 'hd-type-card',\n\t\theading: 'HD type',\n\t\tdescription:\n\t\t\t'Human Design type reading without the chart: type, strategy, authority, and profile, with the aura mechanic, the signature and not-self themes, and the interpretation behind each label. Also renders the profile response with its two line keynotes',\n\t\tdocsLabel: 'Human Design',\n\t\tendpointLabel: 'POST /human-design/type, /human-design/profile',\n\t\tdocsSummary:\n\t\t\t'Type, strategy, authority, and profile tiles with the aura, signature, and not-self themes, plus the reading behind each label and the profile line keynotes',\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, color, tone, and base, plus the reading for each arrow and the cognition',\n\t\tdocsLabel: 'Human Design',\n\t\tendpointLabel: 'POST /human-design/variables',\n\t\tdocsSummary:\n\t\t\t'The four transformation arrows with direction, color, tone, and base, plus a reading per arrow grouped by layer and the cognition',\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,significant-dates,transits}',\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 drawn line by line with trigram glyphs, judgment, image, and a reading for every line: the oracle statement and what it asks of the querent. A cast highlights the moving lines and shows only their readings, plus the hexagram it transforms into',\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:\n\t\t\t'Hexagram figure with trigrams, judgment, image, and a reading per line (statement plus meaning); a cast highlights the moving lines and the resulting hexagram',\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.15.1';\n", "/**\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 { RoxyHdTypeCard } from './components/hd-type-card.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"],
5
+ "mappings": "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,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,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,mDACf,YACC,iEACD,MAAO,OACR,EACA,CACC,OAAQ,cACR,IAAK,gBACL,KAAM,WACN,QAAS,WACT,YACC,yGACD,UAAW,aACX,cAAe,iCACf,YACC,gEACD,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,cACC,+DACD,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,sNACD,UAAW,eACX,cAAe,+BACf,YACC,+OACD,MAAO,cACR,EACA,CACC,OAAQ,iBACR,IAAK,oBACL,KAAM,eACN,QAAS,UACT,YACC,yPACD,UAAW,eACX,cAAe,iDACf,YACC,+JACD,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,wMACD,UAAW,eACX,cAAe,+BACf,YACC,oIACD,MAAO,cACR,EACA,CACC,OAAQ,uBACR,IAAK,yBACL,KAAM,oBACN,QAAS,oBACT,YACC,mFACD,UAAW,WACX,cAAe,uDACf,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,uQACD,UAAW,UACX,cACC,uFACD,YACC,iKACD,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,ECxsBO,IAAMC,GAAkB,SC6FxB,IAAMC,GACZC,GAAgB,IAAKC,GAAMA,EAAE,IAAI",
6
6
  "names": ["css", "html", "nothing", "customElement", "LIFE_AREA_SECTIONS", "buildMeaningSections", "meaning", "biblical", "shadow", "sections", "s", "body", "html", "LitElement", "property", "state", "ifDefined", "css", "baseStyles", "DEFAULT_BASE_URL", "FetchController", "host", "req", "controller", "res", "json", "err", "signal", "url", "k", "v", "headers", "key", "body", "buildRequest", "endpoint", "method", "values", "queryKeys", "rest", "path", "_match", "name", "inQuery", "query", "ROXY_DATA_CLASS", "serializeRoxyData", "data", "roxyDataScript", "isJsonScript", "el", "MarkupDataController", "host", "parsed", "inline", "child", "text", "RoxyDataElement", "LitElement", "detail", "buildRequest", "MarkupDataController", "FetchController", "baseStyles", "changed", "html", "ifDefined", "raw", "values", "message", "banner", "__decorateClass", "property", "state", "RoxyAngelNumberCard", "RoxyDataElement", "d", "energy", "energyClass", "keywords", "steps", "html", "nothing", "k", "s", "sections", "buildMeaningSections", "i", "baseStyles", "css", "__decorateClass", "customElement", "css", "html", "nothing", "customElement", "css", "html", "chevron", "disclosureStyles", "css", "html", "nothing", "interpAccordionStyles", "css", "renderInterpAccordion", "sections", "name", "heading", "shown", "s", "nothing", "html", "i", "chevron", "RoxyAngelNumberLookup", "RoxyDataElement", "html", "d", "known", "root", "heading", "steps", "nothing", "k", "s", "meaning", "name", "biblical", "shadow", "renderInterpAccordion", "buildMeaningSections", "baseStyles", "disclosureStyles", "interpAccordionStyles", "css", "__decorateClass", "customElement", "css", "html", "nothing", "customElement", "state", "PLANET_GLYPH", "PLANET_ABBR", "SIGN_GLYPH", "SIGN_ABBR", "SIGNS_ORDER", "RASHI_KEYS", "s", "ASPECT_SYMBOL", "TRIGRAM_GLYPH", "MOON_PHASE_EMOJI", "css", "html", "nothing", "tablistStyles", "renderTablist", "opts", "items", "active", "onSelect", "label", "idPrefix", "controls", "e", "idx", "it", "delta", "next", "root", "TABS", "RoxyAshtakavargaGrid", "RoxyDataElement", "html", "d", "signs", "nothing", "renderTablist", "id", "count", "note", "t", "sav", "sign", "i", "SIGN_GLYPH", "bhinna", "reduced", "rsav", "rows", "caption", "totals", "s", "row", "_", "pinda", "baseStyles", "tablistStyles", "css", "__decorateClass", "state", "customElement", "css", "html", "nothing", "customElement", "DATE_ONLY", "BARE_TIME", "NAIVE_DATETIME", "resolve", "input", "naive", "formatTime", "d", "timeZone", "formatDate", "formatTimeRange", "t", "start", "end", "formatNumber", "value", "dp", "fixed", "formatPercent", "n", "ASPECT_CLASS", "normalizeAspect", "a", "capitalize", "s", "humanize", "c", "score", "v", "provenance", "o", "orbs", "bodies", "PATTERN_ORDER", "RoxyAspectsTable", "RoxyDataElement", "html", "d", "aspects", "patterns", "summary", "date", "options", "nothing", "a", "i", "b", "p", "s", "total", "byType", "type", "count", "capitalize", "g1", "PLANET_GLYPH", "g2", "nature", "normalizeAspect", "formatNumber", "idx", "status", "meaning", "transit", "hasBody", "header", "chevron", "m", "text", "k", "t", "planets", "ordered", "name", "glyph", "isApex", "baseStyles", "disclosureStyles", "interpAccordionStyles", "css", "__decorateClass", "customElement", "css", "html", "nothing", "svg", "customElement", "PLANET_COLOR", "CYCLE", "planetColor", "name", "index", "capitalize", "WORLD_LAND_PATH", "W", "H", "lonToX", "lon", "latToY", "lat", "TROPIC", "POLAR", "formatLon", "formatLat", "toSegments", "points", "segments", "current", "prevLon", "p", "s", "ANGLE_LABEL", "RoxyAstrocartographyMap", "RoxyDataElement", "html", "data", "lines", "bd", "nothing", "WORLD_LAND_PATH", "l", "i", "svg", "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", "interpAccordionStyles", "css", "__decorateClass", "customElement", "css", "html", "nothing", "svg", "customElement", "property", "CYCLE_COLOR", "FORECAST_CYCLES", "RoxyBiorhythmChart", "RoxyDataElement", "html", "d", "raw", "entries", "cycle", "value", "v", "normalized", "spot", "humanize", "nothing", "pct", "color", "days", "w", "h", "xStep", "s", "points", "day", "i", "x", "y", "svg", "formatDate", "doubles", "sections", "renderInterpAccordion", "label", "baseStyles", "disclosureStyles", "interpAccordionStyles", "css", "__decorateClass", "property", "customElement", "css", "html", "nothing", "customElement", "state", "nothing", "svg", "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", "css", "html", "nothing", "hdReadingStyles", "css", "renderHdFacts", "facts", "shown", "f", "nothing", "html", "renderHdThemes", "signature", "notSelf", "renderHdReading", "sections", "name", "heading", "renderInterpAccordion", "renderHdKeynotes", "k", "RoxyBodygraph", "RoxyDataElement", "html", "d", "definedCenters", "c", "activeGates", "g", "n", "activeChannels", "channelKey", "gateTitles", "nothing", "BODYGRAPH_VIEWBOX", "renderBodygraphSvg", "gates", "titles", "parts", "glyph", "planet", "name", "capitalize", "PLANET_GLYPH", "ic", "renderHdFacts", "renderHdThemes", "sections", "renderHdKeynotes", "renderHdReading", "channels", "groups", "key", "bucket", "index", "circuit", "list", "chevron", "centers", "definedCount", "i", "personality", "design", "split", "side", "shown", "sideNote", "renderTablist", "v", "open", "hex", "baseStyles", "tablistStyles", "disclosureStyles", "interpAccordionStyles", "hdReadingStyles", "css", "__decorateClass", "state", "customElement", "css", "html", "nothing", "customElement", "RoxyChoghadiyaGrid", "RoxyDataElement", "period", "now", "start", "end", "effectClass", "current", "lordGlyph", "PLANET_GLYPH", "capitalize", "timeRange", "formatTimeRange", "html", "nothing", "d", "date", "dayChoghadiya", "nightChoghadiya", "p", "baseStyles", "css", "__decorateClass", "customElement", "css", "html", "nothing", "customElement", "property", "RELATIONSHIP_PLANETS", "ELEMENTS", "RoxyCompatibilityCard", "RoxyDataElement", "d", "out", "k", "v", "html", "score", "breakdown", "rating", "archetype", "advice", "summary", "interpretation", "strengths", "challenges", "keyAspects", "nothing", "s", "a", "formatAspect", "b", "sc", "persons", "sections", "planet", "pair", "at", "p", "sign", "capitalize", "deg", "glyph", "SIGN_GLYPH", "degree", "PLANET_GLYPH", "renderInterpAccordion", "eb", "p1", "p2", "max", "e", "shared", "el", "cores", "label", "core", "formatNumber", "name", "cycle", "baseStyles", "disclosureStyles", "interpAccordionStyles", "css", "__decorateClass", "property", "customElement", "aspect", "orb", "head", "css", "html", "nothing", "customElement", "COLOR_WORDS", "CSS_COLORS", "COLOR_QUALIFIERS", "cssColor", "name", "bases", "qualifiers", "word", "qualifier", "base", "first", "second", "color", "partner", "keepPct", "MONTHS", "RoxyCrystalCard", "RoxyDataElement", "html", "d", "colors", "keywords", "pairs", "month", "nothing", "c", "cssColor", "k", "p", "label", "value", "values", "m", "present", "v", "text", "baseStyles", "css", "__decorateClass", "customElement", "css", "html", "nothing", "customElement", "property", "MONTHS", "RoxyCrystalGrid", "RoxyDataElement", "html", "d", "crystals", "title", "total", "c", "col", "cssColor", "nothing", "baseStyles", "css", "__decorateClass", "property", "customElement", "css", "html", "nothing", "customElement", "property", "LEVEL_LABEL", "formatBalance", "b", "parts", "formatSpan", "p", "start", "formatDate", "end", "RoxyDashaTimeline", "RoxyDataElement", "html", "d", "periods", "maxYears", "nothing", "renderInterpAccordion", "lord", "remaining", "span", "formatNumber", "sections", "levels", "label", "period", "left", "active", "now", "max", "years", "width", "current", "progress", "trackClass", "formatYear", "baseStyles", "disclosureStyles", "interpAccordionStyles", "css", "__decorateClass", "property", "customElement", "s", "m", "css", "html", "nothing", "customElement", "property", "TITLE_KEYS", "MAX_TITLE_LEN", "IMAGE_KEYS", "SKIP_KEYS", "QUOTE_KEYS", "SUPPRESS_ALWAYS", "SUPPRESS_NAMED", "SUPPRESS_NOISE", "DETAILS_KEYS", "DEEP_DEPTH", "DETAILS_ROWS", "normKey", "k", "isBadgeKey", "ISO_DATE", "ENUM_STRING", "LINK_STRING", "MAX_DEPTH", "isPrimitive", "value", "isComplex", "RoxyData", "RoxyDataElement", "data", "html", "nothing", "arr", "v", "rows", "clean", "r", "keys", "complex", "mixed", "colClass", "table", "humanize", "row", "obj", "titled", "n", "input", "titleKey", "imageKey", "summaryKey", "quoteKey", "entries", "sections", "key", "size", "body", "heading", "formatNumber", "time", "formatTime", "date", "formatDate", "seen", "baseStyles", "css", "__decorateClass", "property", "customElement", "css", "html", "nothing", "customElement", "property", "nothing", "svg", "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", "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", "svg", "toKundliViewModel", "meta", "divisionLabel", "lagnaOverride", "placements", "sign", "override", "lagnaSign", "name", "pos", "rashiKey", "SOUTH_CELL", "SOUTH_CELL_GRID", "southCellRect", "g", "renderSouthFrame", "b", "c", "d", "e", "nothing", "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", "css", "kundliStyles", "RoxyDivisionalChart", "RoxyDataElement", "next", "division", "label", "toKundliViewModel", "html", "d", "vm", "vargottama", "nothing", "renderKundliStyleTablist", "renderKundliSvg", "planet", "PLANET_GLYPH", "baseStyles", "kundliStyles", "tablistStyles", "css", "__decorateClass", "property", "customElement", "css", "html", "nothing", "customElement", "property", "DOSHA_LABELS", "RoxyDoshaCard", "RoxyDataElement", "html", "d", "present", "label", "sevLower", "tier", "pct", "barColor", "nothing", "r", "sections", "key", "value", "nestedKey", "nestedValue", "baseStyles", "css", "__decorateClass", "property", "customElement", "css", "html", "nothing", "customElement", "RoxyDreamCard", "RoxyDataElement", "d", "html", "nothing", "baseStyles", "css", "__decorateClass", "customElement", "css", "html", "nothing", "customElement", "RoxyDreamSearch", "RoxyDataElement", "html", "d", "symbols", "total", "s", "nothing", "baseStyles", "css", "__decorateClass", "customElement", "css", "html", "LitElement", "nothing", "customElement", "property", "state", "specCache", "loadSpec", "url", "pending", "res", "err", "RoxyEndpointForm", "LitElement", "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", "html", "renderField", "nothing", "inputId", "humanize", "opt", "groups", "locationBlock", "groupBody", "t", "baseStyles", "css", "__decorateClass", "property", "state", "customElement", "css", "html", "nothing", "customElement", "RoxyFixedStars", "RoxyDataElement", "html", "data", "conjunctions", "stars", "formatNumber", "nothing", "c", "i", "chevron", "s", "g", "SIGN_GLYPH", "capitalize", "formatDegreeInSign", "k", "baseStyles", "disclosureStyles", "interpAccordionStyles", "css", "__decorateClass", "customElement", "css", "html", "nothing", "customElement", "RoxyForecastDigest", "RoxyDataElement", "html", "d", "windows", "range", "formatDate", "nothing", "w", "days", "top", "byDomain", "domains", "dom", "n", "humanize", "e", "sig", "formatNumber", "baseStyles", "css", "__decorateClass", "customElement", "css", "html", "nothing", "customElement", "DOMAIN_LABEL", "DOMAIN_ORDER", "RoxyForecastTimeline", "RoxyDataElement", "html", "d", "events", "grouped", "present", "dom", "e", "formatDate", "nothing", "date", "dayEvents", "map", "key", "list", "sig", "width", "body", "capitalize", "target", "aspect", "aspectClass", "ASPECT_CLASS", "aspectSym", "ASPECT_SYMBOL", "orb", "formatNumber", "qualifier", "humanize", "baseStyles", "css", "__decorateClass", "customElement", "css", "html", "nothing", "customElement", "KOOTA_MAX", "RoxyGunaMilan", "RoxyDataElement", "html", "d", "breakdown", "b", "score", "max", "pct", "trackColor", "fillColor", "dashFill", "dashGap", "formatNumber", "formatPercent", "nothing", "maxScore", "defaultMax", "x", "baseStyles", "css", "__decorateClass", "customElement", "name", "css", "html", "nothing", "customElement", "RoxyHdConnection", "RoxyDataElement", "d", "channels", "centers", "definedCenters", "c", "html", "nothing", "renderHdFacts", "humanize", "s", "sections", "channelCount", "renderInterpAccordion", "by", "a", "b", "together", "centerWho", "names", "centerName", "id", "gateList", "baseStyles", "disclosureStyles", "interpAccordionStyles", "hdReadingStyles", "css", "__decorateClass", "customElement", "gates", "list", "defined", "css", "html", "nothing", "customElement", "RoxyHdPenta", "RoxyDataElement", "d", "channels", "gates", "s", "gaps", "hasCore", "c", "html", "nothing", "renderHdFacts", "label", "note", "members", "filled", "g", "baseStyles", "hdReadingStyles", "css", "__decorateClass", "customElement", "MEMBER_LETTERS", "indices", "held", "i", "css", "html", "nothing", "customElement", "RoxyHdTypeCard", "RoxyDataElement", "html", "d", "isTypeShape", "nothing", "renderHdFacts", "renderHdThemes", "renderHdReading", "renderHdKeynotes", "baseStyles", "disclosureStyles", "interpAccordionStyles", "hdReadingStyles", "css", "__decorateClass", "customElement", "css", "html", "nothing", "customElement", "RoxyHdVariables", "RoxyDataElement", "d", "arrows", "a", "b", "quadrantOrder", "html", "nothing", "glyph", "capitalize", "baseDescription", "readable", "groups", "key", "bucket", "index", "layer", "list", "open", "cog", "facets", "f", "chevron", "baseStyles", "disclosureStyles", "interpAccordionStyles", "css", "__decorateClass", "customElement", "position", "css", "html", "nothing", "svg", "customElement", "property", "RoxyHexagram", "RoxyDataElement", "d", "cast", "daily", "html", "resolved", "h", "castLines", "changingLinePositions", "dailyMessage", "resultingHexagram", "lines", "changing", "nothing", "l", "idx", "realIdx", "isChanging", "broken", "svg", "TRIGRAM_GLYPH", "a", "b", "all", "isCast", "shown", "sections", "renderInterpAccordion", "binary", "c", "baseStyles", "disclosureStyles", "interpAccordionStyles", "css", "__decorateClass", "property", "customElement", "css", "html", "nothing", "customElement", "RoxyHoraTable", "RoxyDataElement", "html", "d", "day", "night", "nothing", "label", "horas", "h", "PLANET_GLYPH", "capitalize", "formatTimeRange", "baseStyles", "css", "__decorateClass", "customElement", "css", "html", "nothing", "customElement", "property", "RoxyHoroscopeCard", "RoxyDataElement", "html", "d", "sign", "glyph", "SIGN_GLYPH", "capitalize", "energy", "dateLabel", "nothing", "luckyNumber", "luckyColor", "luckyNumbers", "luckyDays", "compatibleSigns", "s", "moonSign", "moonPhase", "transits", "t", "weeks", "keyDates", "w", "k", "formatDate", "baseStyles", "css", "__decorateClass", "property", "customElement", "css", "html", "nothing", "customElement", "state", "TABS", "LEVELS", "nakshatraPada", "nakshatra", "pada", "chain", "values", "RoxyKpChart", "RoxyDataElement", "d", "rows", "p", "nodes", "name", "node", "html", "asc", "formatSignPosition", "nothing", "formatNumber", "renderTablist", "id", "bodies", "b", "cusps", "c", "sig", "houseWise", "planetWise", "l", "h", "value", "level", "s", "labels", "a", "label", "baseStyles", "tablistStyles", "css", "__decorateClass", "state", "customElement", "css", "html", "nothing", "customElement", "RoxyKpPlanetsTable", "RoxyDataElement", "html", "d", "planets", "formatNumber", "nothing", "p", "baseStyles", "css", "__decorateClass", "customElement", "css", "html", "nothing", "customElement", "RoxyKpRulingPlanets", "RoxyDataElement", "html", "d", "significators", "nothing", "p", "i", "s", "baseStyles", "css", "__decorateClass", "customElement", "css", "html", "nothing", "svg", "customElement", "SIZE", "CENTER", "RIM", "SPOKE", "GLYPH_R", "TICK_LABEL_R", "azimuthPoint", "az", "r", "rad", "PRINCIPAL", "RoxyLocalSpaceCompass", "RoxyDataElement", "html", "data", "bodies", "bd", "nothing", "ticks", "outer", "inner", "svg", "ns1", "ns2", "ew1", "ew2", "labels", "label", "pos", "cardinal", "b", "i", "color", "planetColor", "below", "end", "glyphPos", "glyph", "altLabel", "baseStyles", "css", "__decorateClass", "customElement", "css", "html", "LitElement", "nothing", "customElement", "property", "state", "debounce", "fn", "wait", "timer", "debounced", "args", "RoxyLocationSearch", "LitElement", "debounce", "q", "value", "target", "message", "controller", "url", "headers", "key", "res", "json", "err", "city", "html", "nothing", "idx", "baseStyles", "css", "__decorateClass", "property", "state", "customElement", "css", "html", "nothing", "customElement", "property", "RoxyMoonPhase", "RoxyDataElement", "html", "d", "list", "month", "year", "phase", "nothing", "emoji", "phaseEmoji", "formatIllumination", "formatNumber", "k", "p", "baseStyles", "css", "__decorateClass", "property", "customElement", "lc", "noMoon", "alias", "MOON_PHASE_EMOJI", "v", "pct", "css", "html", "nothing", "customElement", "RoxyNakshatraCard", "RoxyDataElement", "n", "remedies", "html", "nothing", "baseStyles", "css", "__decorateClass", "customElement", "css", "html", "nothing", "svg", "customElement", "property", "state", "PATTERN_ORDER", "SIZE", "CENTER", "OUTER_R", "SIGN_R", "HOUSE_R", "PLANET_R", "ANGLE_TICK_R", "ANGLE_LABEL_R", "RoxyNatalChart", "RoxyDataElement", "m", "lon", "html", "data", "planets", "aspects", "view", "nothing", "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", "svg", "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", "dominantEl", "dominantMod", "cells", "el", "placed", "idx", "mod", "colTotal", "isDomRow", "rowTotal", "patterns", "ordered", "isApex", "sections", "interp", "lead", "detail", "renderInterpAccordion", "planetMap", "l1", "l2", "p1", "p2", "aspectName", "aspectClass", "orbLabel", "baseStyles", "tablistStyles", "disclosureStyles", "interpAccordionStyles", "css", "__decorateClass", "property", "state", "customElement", "css", "html", "nothing", "customElement", "property", "MASTER_NUMBERS", "GUIDANCE_FIELDS", "RoxyNumerologyCard", "RoxyDataElement", "d", "headerLabel", "LABELS", "html", "isMaster", "nothing", "karmicDebtText", "joinCycle", "cores", "v", "ins", "lucky", "profile", "maturity", "k", "humanize", "renderInterpAccordion", "lessons", "debt", "year", "passion", "subconscious", "letters", "present", "n", "digit", "count", "l", "m", "p", "ageRange", "c", "letterAside", "num", "title", "master", "r", "name", "sections", "key", "label", "lists", "shown", "items", "item", "value", "baseStyles", "disclosureStyles", "interpAccordionStyles", "css", "__decorateClass", "property", "customElement", "type", "theme", "start", "end", "letter", "css", "html", "nothing", "customElement", "property", "meta", "parts", "name", "RoxyPanchangTable", "RoxyDataElement", "html", "d", "detailed", "basic", "muhurtas", "auspiciousWindows", "inauspicious", "inauspiciousWindows", "showTimings", "formatDate", "l", "formatTime", "nothing", "m", "n", "y", "k", "rows", "label", "value", "t", "v", "range", "formatTimeRange", "windows", "w", "i", "b", "span", "p", "c", "items", "tone", "next", "start", "end", "r", "h", "lon", "formatSignPosition", "baseStyles", "css", "__decorateClass", "property", "customElement", "css", "html", "nothing", "customElement", "property", "RoxyPositionsTable", "RoxyDataElement", "html", "data", "vm", "cols", "b", "nothing", "r", "glyph", "PLANET_GLYPH", "capitalize", "formatNumber", "sign", "degree", "g", "SIGN_GLYPH", "formatDegreeInSign", "longitude", "p", "longitudeToSignPosition", "rows", "sections", "renderInterpAccordion", "a", "l", "d", "angleRows", "baseStyles", "disclosureStyles", "interpAccordionStyles", "css", "__decorateClass", "property", "customElement", "css", "html", "nothing", "customElement", "RoxyProfectionCard", "RoxyDataElement", "html", "data", "signGlyph", "SIGN_GLYPH", "capitalize", "lordGlyph", "PLANET_GLYPH", "lordNatalGlyph", "nothing", "baseStyles", "css", "__decorateClass", "customElement", "css", "html", "nothing", "customElement", "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", "html", "nothing", "text", "humanize", "i", "type", "number", "baseStyles", "css", "__decorateClass", "customElement", "css", "html", "nothing", "customElement", "glyphFor", "name", "PLANET_GLYPH", "capitalize", "RoxyRelocationWheel", "RoxyDataElement", "html", "data", "c", "nothing", "p", "m", "baseStyles", "css", "__decorateClass", "customElement", "css", "html", "nothing", "customElement", "BALA_COMPONENTS", "RoxyShadbalaTable", "RoxyDataElement", "html", "d", "sorted", "a", "b", "p", "glyph", "PLANET_GLYPH", "capitalize", "values", "total", "s", "v", "isAdequate", "badgeClass", "badgeLabel", "rupasStr", "formatNumber", "i", "nothing", "grow", "ishta", "kashta", "ishtaStr", "kashtaStr", "baseStyles", "css", "__decorateClass", "customElement", "css", "html", "nothing", "svg", "customElement", "READING_COUNT", "SIZE", "CENTER", "OUTER_R", "SIGN_R", "P1_R", "P2_R", "RoxySynastryChart", "RoxyDataElement", "html", "d", "person1", "person2", "compatibilityScore", "analysis", "interAspects", "p1Planets", "p2Planets", "score", "summaryText", "strengths", "challenges", "hasPlanets", "ranked", "a", "b", "lead", "nothing", "i", "s", "p1", "p2", "card", "p", "index", "shown", "formatNumber", "value", "label", "SIGN_GLYPH", "capitalize", "cards", "c", "byType", "type", "count", "g1", "PLANET_GLYPH", "g2", "nature", "meaning", "normalizeAspect", "aside", "chevron", "k", "longitude", "_", "angle", "start", "polarToCartesian", "end", "svg", "SIGNS_ORDER", "pos", "planets", "radius", "cls", "personIndex", "degPos", "glyph", "sp", "longitudeToSignPosition", "retro", "degLabel", "tooltip", "data", "items", "make", "asc", "signIdx", "innerR", "tickPos", "labelPos", "aspects", "longitudeOf", "list", "name", "target", "l1", "l2", "out", "inn", "aspectName", "ASPECT_CLASS", "orbLabel", "baseStyles", "disclosureStyles", "interpAccordionStyles", "css", "__decorateClass", "customElement", "css", "html", "nothing", "customElement", "state", "GUIDANCE_FIELDS", "RoxyTarotCard", "RoxyDataElement", "html", "d", "card", "reversed", "keywords", "meta", "nothing", "k", "oriented", "renderTablist", "id", "imageUrl", "name", "cls", "guidance", "sections", "key", "label", "renderInterpAccordion", "baseStyles", "disclosureStyles", "interpAccordionStyles", "tablistStyles", "css", "__decorateClass", "state", "customElement", "css", "html", "customElement", "property", "RoxyTarotCatalog", "RoxyDataElement", "html", "d", "cards", "title", "total", "c", "cardMeta", "baseStyles", "css", "__decorateClass", "property", "customElement", "capitalize", "css", "html", "nothing", "customElement", "property", "RoxyTarotSpread", "RoxyDataElement", "html", "d", "isYesNo", "isDrawn", "positions", "cards", "answer", "strength", "verdictCard", "spreadLabel", "question", "summary", "yesNoInterp", "answerClass", "nothing", "k", "p", "c", "baseStyles", "css", "__decorateClass", "property", "customElement", "css", "html", "nothing", "customElement", "state", "RoxyTransitsTable", "RoxyDataElement", "html", "d", "transitDate", "transitTime", "transitPlanets", "transitAspects", "summary", "dateStr", "formatDate", "formatTime", "aspectCount", "tab", "nothing", "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", "css", "__decorateClass", "state", "customElement", "css", "html", "nothing", "customElement", "RoxyVedicAspects", "RoxyDataElement", "html", "d", "aspects", "mutual", "planets", "when", "formatDate", "formatTime", "nothing", "p", "formatSignPosition", "m", "a", "formatNumber", "baseStyles", "css", "__decorateClass", "customElement", "html", "customElement", "property", "RoxyVedicKundli", "RoxyDataElement", "next", "toKundliViewModel", "html", "_d", "vm", "title", "renderKundliStyleTablist", "renderKundliSvg", "baseStyles", "kundliStyles", "tablistStyles", "__decorateClass", "property", "customElement", "css", "html", "nothing", "customElement", "GRAHA_ORDER", "RoxyVedicPlanetsTable", "RoxyDataElement", "meta", "seen", "rows", "name", "entry", "html", "d", "p", "isLagna", "glyph", "PLANET_GLYPH", "capitalize", "signGlyph", "SIGN_GLYPH", "nothing", "formatSignPosition", "combust", "chevron", "c", "dist", "formatNumber", "orb", "wars", "w", "interp", "entries", "v", "houses", "h", "yogas", "y", "baseStyles", "disclosureStyles", "css", "__decorateClass", "customElement", "css", "html", "nothing", "customElement", "RoxyWesternPlanetsTable", "RoxyDataElement", "d", "rows", "p", "name", "point", "html", "glyph", "PLANET_GLYPH", "capitalize", "signGlyph", "SIGN_GLYPH", "speed", "formatNumber", "nothing", "formatSignPosition", "baseStyles", "css", "__decorateClass", "customElement", "css", "html", "nothing", "customElement", "state", "RoxyYogaList", "RoxyDataElement", "quality", "cls", "html", "yoga", "nothing", "y", "d", "lc", "allYogas", "detected", "filtered", "ordered", "presentCount", "detailYogas", "total", "catalogYogas", "baseStyles", "css", "__decorateClass", "state", "customElement", "ROXY_COMPONENTS", "ROXY_UI_VERSION", "ROXY_UI_COMPONENTS", "ROXY_COMPONENTS", "c"]
7
7
  }