@roxyapi/ui 0.3.1 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/AGENTS.md +34 -7
  2. package/README.md +145 -26
  3. package/dist/cdn/components/ashtakavarga-grid.js +74 -19
  4. package/dist/cdn/components/ashtakavarga-grid.js.map +2 -2
  5. package/dist/cdn/components/biorhythm-chart.js +18 -4
  6. package/dist/cdn/components/biorhythm-chart.js.map +2 -2
  7. package/dist/cdn/components/choghadiya-grid.js +47 -12
  8. package/dist/cdn/components/choghadiya-grid.js.map +3 -3
  9. package/dist/cdn/components/compatibility-card.js +21 -7
  10. package/dist/cdn/components/compatibility-card.js.map +2 -2
  11. package/dist/cdn/components/dasha-timeline.js +113 -28
  12. package/dist/cdn/components/dasha-timeline.js.map +3 -3
  13. package/dist/cdn/components/data.js +27 -13
  14. package/dist/cdn/components/data.js.map +2 -2
  15. package/dist/cdn/components/divisional-chart.js +225 -118
  16. package/dist/cdn/components/divisional-chart.js.map +4 -4
  17. package/dist/cdn/components/dosha-card.js +18 -4
  18. package/dist/cdn/components/dosha-card.js.map +2 -2
  19. package/dist/cdn/components/endpoint-form.js +25 -11
  20. package/dist/cdn/components/endpoint-form.js.map +2 -2
  21. package/dist/cdn/components/guna-milan.js +20 -6
  22. package/dist/cdn/components/guna-milan.js.map +2 -2
  23. package/dist/cdn/components/hexagram.js +22 -8
  24. package/dist/cdn/components/hexagram.js.map +2 -2
  25. package/dist/cdn/components/horoscope-card.js +20 -6
  26. package/dist/cdn/components/horoscope-card.js.map +2 -2
  27. package/dist/cdn/components/kp-chart.js +19 -5
  28. package/dist/cdn/components/kp-chart.js.map +2 -2
  29. package/dist/cdn/components/kp-planets-table.js +17 -3
  30. package/dist/cdn/components/kp-planets-table.js.map +2 -2
  31. package/dist/cdn/components/kp-ruling-planets.js +17 -3
  32. package/dist/cdn/components/kp-ruling-planets.js.map +2 -2
  33. package/dist/cdn/components/location-search.js +18 -4
  34. package/dist/cdn/components/location-search.js.map +2 -2
  35. package/dist/cdn/components/moon-phase.js +27 -13
  36. package/dist/cdn/components/moon-phase.js.map +2 -2
  37. package/dist/cdn/components/nakshatra-card.js +16 -2
  38. package/dist/cdn/components/nakshatra-card.js.map +2 -2
  39. package/dist/cdn/components/natal-chart.js +79 -40
  40. package/dist/cdn/components/natal-chart.js.map +3 -3
  41. package/dist/cdn/components/numerology-card.js +18 -4
  42. package/dist/cdn/components/numerology-card.js.map +2 -2
  43. package/dist/cdn/components/panchang-table.js +53 -25
  44. package/dist/cdn/components/panchang-table.js.map +3 -3
  45. package/dist/cdn/components/shadbala-table.js +24 -10
  46. package/dist/cdn/components/shadbala-table.js.map +2 -2
  47. package/dist/cdn/components/synastry-chart.js +96 -48
  48. package/dist/cdn/components/synastry-chart.js.map +3 -3
  49. package/dist/cdn/components/tarot-card.js +17 -3
  50. package/dist/cdn/components/tarot-card.js.map +2 -2
  51. package/dist/cdn/components/tarot-spread.js +39 -25
  52. package/dist/cdn/components/tarot-spread.js.map +2 -2
  53. package/dist/cdn/components/transits-table.js +18 -4
  54. package/dist/cdn/components/transits-table.js.map +2 -2
  55. package/dist/cdn/components/vedic-kundli.js +215 -105
  56. package/dist/cdn/components/vedic-kundli.js.map +4 -4
  57. package/dist/cdn/components/vedic-planets-table.js +22 -8
  58. package/dist/cdn/components/vedic-planets-table.js.map +2 -2
  59. package/dist/cdn/components/western-planets-table.js +18 -4
  60. package/dist/cdn/components/western-planets-table.js.map +2 -2
  61. package/dist/cdn/components/yoga-list.js +17 -3
  62. package/dist/cdn/components/yoga-list.js.map +2 -2
  63. package/dist/cdn/roxy-ui.js +1082 -816
  64. package/dist/cdn/roxy-ui.js.map +4 -4
  65. package/dist/components/ashtakavarga-grid.d.ts +13 -1
  66. package/dist/components/ashtakavarga-grid.d.ts.map +1 -1
  67. package/dist/components/ashtakavarga-grid.js +86 -11
  68. package/dist/components/ashtakavarga-grid.js.map +2 -2
  69. package/dist/components/biorhythm-chart.js +14 -0
  70. package/dist/components/biorhythm-chart.js.map +2 -2
  71. package/dist/components/choghadiya-grid.d.ts +6 -0
  72. package/dist/components/choghadiya-grid.d.ts.map +1 -1
  73. package/dist/components/choghadiya-grid.js +50 -2
  74. package/dist/components/choghadiya-grid.js.map +2 -2
  75. package/dist/components/compatibility-card.js +14 -0
  76. package/dist/components/compatibility-card.js.map +2 -2
  77. package/dist/components/dasha-timeline.d.ts +10 -0
  78. package/dist/components/dasha-timeline.d.ts.map +1 -1
  79. package/dist/components/dasha-timeline.js +135 -4
  80. package/dist/components/dasha-timeline.js.map +2 -2
  81. package/dist/components/data.js +14 -0
  82. package/dist/components/data.js.map +2 -2
  83. package/dist/components/divisional-chart.d.ts +9 -6
  84. package/dist/components/divisional-chart.d.ts.map +1 -1
  85. package/dist/components/divisional-chart.js +546 -251
  86. package/dist/components/divisional-chart.js.map +4 -4
  87. package/dist/components/dosha-card.js +14 -0
  88. package/dist/components/dosha-card.js.map +2 -2
  89. package/dist/components/endpoint-form.js +14 -0
  90. package/dist/components/endpoint-form.js.map +2 -2
  91. package/dist/components/guna-milan.js +14 -0
  92. package/dist/components/guna-milan.js.map +2 -2
  93. package/dist/components/hexagram.js +14 -0
  94. package/dist/components/hexagram.js.map +2 -2
  95. package/dist/components/horoscope-card.js +14 -0
  96. package/dist/components/horoscope-card.js.map +2 -2
  97. package/dist/components/kp-chart.js +14 -0
  98. package/dist/components/kp-chart.js.map +2 -2
  99. package/dist/components/kp-planets-table.js +14 -0
  100. package/dist/components/kp-planets-table.js.map +2 -2
  101. package/dist/components/kp-ruling-planets.js +14 -0
  102. package/dist/components/kp-ruling-planets.js.map +2 -2
  103. package/dist/components/location-search.js +14 -0
  104. package/dist/components/location-search.js.map +2 -2
  105. package/dist/components/moon-phase.js +14 -0
  106. package/dist/components/moon-phase.js.map +2 -2
  107. package/dist/components/nakshatra-card.js +14 -0
  108. package/dist/components/nakshatra-card.js.map +2 -2
  109. package/dist/components/natal-chart.d.ts.map +1 -1
  110. package/dist/components/natal-chart.js +76 -6
  111. package/dist/components/natal-chart.js.map +2 -2
  112. package/dist/components/numerology-card.js +14 -0
  113. package/dist/components/numerology-card.js.map +2 -2
  114. package/dist/components/panchang-table.d.ts +1 -0
  115. package/dist/components/panchang-table.d.ts.map +1 -1
  116. package/dist/components/panchang-table.js +37 -1
  117. package/dist/components/panchang-table.js.map +2 -2
  118. package/dist/components/shadbala-table.js +14 -0
  119. package/dist/components/shadbala-table.js.map +2 -2
  120. package/dist/components/synastry-chart.d.ts +6 -0
  121. package/dist/components/synastry-chart.d.ts.map +1 -1
  122. package/dist/components/synastry-chart.js +106 -7
  123. package/dist/components/synastry-chart.js.map +2 -2
  124. package/dist/components/tarot-card.js +14 -0
  125. package/dist/components/tarot-card.js.map +2 -2
  126. package/dist/components/tarot-spread.js +14 -0
  127. package/dist/components/tarot-spread.js.map +2 -2
  128. package/dist/components/transits-table.js +14 -0
  129. package/dist/components/transits-table.js.map +2 -2
  130. package/dist/components/vedic-kundli.d.ts +14 -9
  131. package/dist/components/vedic-kundli.d.ts.map +1 -1
  132. package/dist/components/vedic-kundli.js +537 -245
  133. package/dist/components/vedic-kundli.js.map +4 -4
  134. package/dist/components/vedic-planets-table.js +14 -0
  135. package/dist/components/vedic-planets-table.js.map +2 -2
  136. package/dist/components/western-planets-table.js +14 -0
  137. package/dist/components/western-planets-table.js.map +2 -2
  138. package/dist/components/yoga-list.js +14 -0
  139. package/dist/components/yoga-list.js.map +2 -2
  140. package/dist/index.cjs +1397 -797
  141. package/dist/index.cjs.map +4 -4
  142. package/dist/index.js +1278 -678
  143. package/dist/index.js.map +4 -4
  144. package/dist/manifest.json +23 -23
  145. package/dist/styles/tokens.css +8 -23
  146. package/dist/utils/base-styles.d.ts.map +1 -1
  147. package/dist/utils/kundli-render.d.ts +43 -104
  148. package/dist/utils/kundli-render.d.ts.map +1 -1
  149. package/dist/utils/kundli-styles.d.ts +13 -0
  150. package/dist/utils/kundli-styles.d.ts.map +1 -0
  151. package/dist/version.d.ts +1 -1
  152. package/package.json +1 -1
  153. package/src/components/ashtakavarga-grid.ts +73 -11
  154. package/src/components/choghadiya-grid.ts +37 -2
  155. package/src/components/dasha-timeline.ts +135 -4
  156. package/src/components/divisional-chart.ts +40 -97
  157. package/src/components/natal-chart.ts +89 -6
  158. package/src/components/panchang-table.ts +34 -1
  159. package/src/components/synastry-chart.ts +84 -8
  160. package/src/components/vedic-kundli.ts +35 -95
  161. package/src/styles/tokens.css +8 -23
  162. package/src/utils/base-styles.ts +14 -0
  163. package/src/utils/kundli-render.ts +609 -270
  164. package/src/utils/kundli-styles.ts +124 -0
  165. package/src/version.ts +1 -1
@@ -6,7 +6,7 @@ import type {
6
6
  NatalChartResponse,
7
7
  } from '../types/index.js';
8
8
  import { baseStyles } from '../utils/base-styles.js';
9
- import { polarToCartesian } from '../utils/degree.js';
9
+ import { longitudeToSignPosition, polarToCartesian } from '../utils/degree.js';
10
10
  import {
11
11
  ASPECT_CLASS,
12
12
  formatNumber,
@@ -72,7 +72,9 @@ export class RoxySynastryChart extends LitElement {
72
72
  svg {
73
73
  display: block;
74
74
  width: 100%;
75
- max-width: 400px;
75
+ max-width: 560px;
76
+ aspect-ratio: 1 / 1;
77
+ height: auto;
76
78
  margin: 0 auto;
77
79
  }
78
80
 
@@ -94,6 +96,31 @@ export class RoxySynastryChart extends LitElement {
94
96
  font-weight: 600;
95
97
  font-size: 13px;
96
98
  }
99
+ .person-tag {
100
+ font-size: 7px;
101
+ font-weight: 700;
102
+ opacity: 0.85;
103
+ }
104
+ .planet-deg {
105
+ fill: var(--roxy-muted, #71717a);
106
+ font-size: 7px;
107
+ font-family: var(--roxy-font-sans);
108
+ }
109
+ .planet-deg .retro {
110
+ fill: var(--roxy-danger, #dc2626);
111
+ }
112
+ .asc-tick {
113
+ stroke: var(--roxy-accent-fg, #b45309);
114
+ stroke-width: 1;
115
+ opacity: 0.75;
116
+ }
117
+ .asc-label {
118
+ fill: var(--roxy-accent-fg, #b45309);
119
+ font-size: 9px;
120
+ font-weight: 700;
121
+ font-family: var(--roxy-font-sans);
122
+ letter-spacing: 0.04em;
123
+ }
97
124
  .aspect {
98
125
  stroke-width: 0.8;
99
126
  fill: none;
@@ -316,7 +343,8 @@ export class RoxySynastryChart extends LitElement {
316
343
  />
317
344
  ${this.renderSpokes()} ${this.renderSigns()}
318
345
  ${this.renderInterAspectLines(p1Planets, p2Planets, interAspects)}
319
- ${this.renderRing(p1Planets, P1_R, 'p1')} ${this.renderRing(p2Planets, P2_R, 'p2')}
346
+ ${this.renderRing(p1Planets, P1_R, 'p1', 1)} ${this.renderRing(p2Planets, P2_R, 'p2', 2)}
347
+ ${this.renderAscendants(this.data)}
320
348
  </svg>
321
349
  <div class="legend-row">
322
350
  <span><span class="swatch" style="background: var(--roxy-accent)"></span>Person 1</span>
@@ -376,20 +404,68 @@ export class RoxySynastryChart extends LitElement {
376
404
  });
377
405
  }
378
406
 
379
- private renderRing(planets: PlanetEntry[], radius: number, cls: string) {
407
+ private renderRing(
408
+ planets: PlanetEntry[],
409
+ radius: number,
410
+ cls: string,
411
+ personIndex: 1 | 2,
412
+ ) {
380
413
  return planets.map((p) => {
381
414
  if (!Number.isFinite(p.longitude)) return nothing;
382
- const pos = polarToCartesian(
415
+ const angle = this.toAngle(p.longitude);
416
+ const pos = polarToCartesian(CENTER, CENTER, radius, angle);
417
+ // Degree label sits one tier inward from the glyph so the two
418
+ // concentric rings never blur their numbers into the aspect lines.
419
+ const degOffset = personIndex === 1 ? -12 : -10;
420
+ const degPos = polarToCartesian(
383
421
  CENTER,
384
422
  CENTER,
385
- radius,
386
- this.toAngle(p.longitude),
423
+ radius + degOffset,
424
+ angle,
387
425
  );
388
426
  const glyph = PLANET_GLYPH[capitalize(p.name)] ?? p.name.slice(0, 2);
389
- return svg`<text class=${cls} x=${pos.x} y=${pos.y} text-anchor="middle" dominant-baseline="central"><title>${p.name}</title>${glyph}</text>`;
427
+ const sp = longitudeToSignPosition(p.longitude);
428
+ const retro = p.isRetrograde === true;
429
+ const degLabel = `${sp.degree}°${String(sp.minute).padStart(2, '0')}'`;
430
+ const tooltip = `${p.name}${retro ? ' retrograde' : ''} - ${degLabel} ${sp.sign}`;
431
+ return svg`<g>
432
+ <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>
433
+ <text class="planet-deg" x=${degPos.x} y=${degPos.y} text-anchor="middle" dominant-baseline="central">${sp.degree}°${retro ? svg`<tspan class="retro"> ℞</tspan>` : nothing}</text>
434
+ </g>`;
390
435
  });
391
436
  }
392
437
 
438
+ /**
439
+ * Ascendant markers for both people. Drawn as small spokes at the inner
440
+ * rim with the label outside, so the two rising signs are immediately
441
+ * scannable on the wheel without depending on tooltips.
442
+ */
443
+ private renderAscendants(data: SynastryWithPlanets) {
444
+ const items: ReturnType<typeof svg>[] = [];
445
+ const make = (
446
+ asc: { sign: string; degree: number } | undefined,
447
+ personIndex: 1 | 2,
448
+ ) => {
449
+ if (!asc) return;
450
+ const signIdx = SIGNS_ORDER.findIndex(
451
+ (s) => s.toLowerCase() === asc.sign.toLowerCase(),
452
+ );
453
+ if (signIdx === -1) return;
454
+ const longitude = signIdx * 30 + asc.degree;
455
+ const angle = this.toAngle(longitude);
456
+ const innerR = personIndex === 1 ? P1_R + 14 : P2_R + 14;
457
+ const tickPos = polarToCartesian(CENTER, CENTER, innerR, angle);
458
+ const labelPos = polarToCartesian(CENTER, CENTER, OUTER_R + 14, angle);
459
+ items.push(svg`<g>
460
+ <line class="asc-tick" x1=${tickPos.x} y1=${tickPos.y} x2=${labelPos.x} y2=${labelPos.y} />
461
+ <text class="asc-label" x=${labelPos.x} y=${labelPos.y} text-anchor="middle" dominant-baseline="central">Asc${personIndex}</text>
462
+ </g>`);
463
+ };
464
+ make(data.person1?.ascendant, 1);
465
+ make(data.person2?.ascendant, 2);
466
+ return items;
467
+ }
468
+
393
469
  private renderInterAspectLines(
394
470
  p1: PlanetEntry[],
395
471
  p2: PlanetEntry[],
@@ -1,126 +1,66 @@
1
- import { css, html, LitElement } from 'lit';
1
+ import { html, LitElement } from 'lit';
2
2
  import { customElement, property } from 'lit/decorators.js';
3
3
  import type { BirthChartResponse } from '../types/index.js';
4
4
  import { baseStyles } from '../utils/base-styles.js';
5
5
  import {
6
- buildHousesFromMeta,
7
- type HouseDef,
8
- renderEastFrame,
9
- renderEastHouseGroup,
10
- renderNorthFrame,
11
- renderNorthHouseGroup,
12
- renderSouthFrame,
13
- renderSouthHouseGroup,
6
+ type ChartStyle,
7
+ type KundliViewModel,
8
+ renderKundliStyleTablist,
9
+ renderKundliSvg,
10
+ toKundliViewModel,
14
11
  } from '../utils/kundli-render.js';
12
+ import { kundliStyles } from '../utils/kundli-styles.js';
15
13
 
16
14
  /**
17
15
  * Vedic kundli (D1 Rashi chart). Pass `data` from /vedic-astrology/birth-chart.
18
- * Three render styles via the `chart-style` attribute: south (default),
19
- * north, and east. All three draw the identical planet-in-sign data, so the
20
- * style is purely a layout choice. Each planet shows its abbreviation and
21
- * whole-degree, with an SVG tooltip carrying exact position, nakshatra, pada,
22
- * and avastha.
16
+ * Three regional render styles are available; the visible tablist lets the
17
+ * end user switch between South / North / East at any time. The same planet-
18
+ * in-sign data feeds every style, so the toggle is purely a layout choice.
23
19
  *
24
- * Theming flows through CSS custom properties on :host, so the chart adopts
25
- * the host page palette without runtime color probing.
20
+ * Each planet shows its abbreviation and whole-degree-within-sign, with an
21
+ * SVG tooltip carrying exact position, nakshatra, pada, and avastha. The host
22
+ * page sets the initial style via `chart-style` attribute; from there the
23
+ * user takes over.
24
+ *
25
+ * Theming flows through CSS custom properties on `:host`, so the chart
26
+ * adopts the host page palette without runtime color probing.
26
27
  */
27
28
  @customElement('roxy-vedic-kundli')
28
29
  export class RoxyVedicKundli extends LitElement {
29
- static styles = [
30
- baseStyles,
31
- css`
32
- .wrap {
33
- display: grid;
34
- gap: var(--roxy-space-md, 1rem);
35
- }
36
- .title {
37
- font-size: var(--roxy-text-lg, 1.125rem);
38
- font-weight: var(--roxy-weight-bold, 600);
39
- margin: 0;
40
- }
41
- svg {
42
- display: block;
43
- width: 100%;
44
- max-width: 360px;
45
- margin: 0 auto;
46
- }
47
- .line {
48
- fill: transparent;
49
- stroke: var(--roxy-border, #e4e4e7);
50
- }
51
- .sign-text {
52
- fill: var(--roxy-muted, #71717a);
53
- font-size: 9px;
54
- font-weight: 500;
55
- font-family: var(--roxy-font-sans);
56
- }
57
- .planet-text {
58
- fill: var(--roxy-fg, #0a0a0a);
59
- font-size: 10px;
60
- font-weight: 600;
61
- font-family: var(--roxy-font-sans);
62
- }
63
- .house-num {
64
- fill: var(--roxy-muted, #71717a);
65
- font-size: 9px;
66
- font-weight: 400;
67
- font-family: var(--roxy-font-sans);
68
- }
69
- .lagna-marker {
70
- fill: var(--roxy-accent-fg, #b45309);
71
- font-size: 8px;
72
- font-weight: 700;
73
- font-family: var(--roxy-font-sans);
74
- letter-spacing: 0.05em;
75
- }
76
- .lagna-bg {
77
- fill: color-mix(in srgb, var(--roxy-accent, #f59e0b) 12%, transparent);
78
- stroke: color-mix(in srgb, var(--roxy-accent, #f59e0b) 45%, transparent);
79
- stroke-width: 0.8;
80
- }
81
- `,
82
- ];
30
+ static styles = [baseStyles, kundliStyles];
83
31
 
84
32
  @property({ attribute: false })
85
33
  data: BirthChartResponse | null = null;
86
34
 
87
35
  @property({ type: String, reflect: true, attribute: 'chart-style' })
88
- chartStyle: 'south' | 'north' | 'east' = 'south';
36
+ chartStyle: ChartStyle = 'north';
89
37
 
90
- private buildHouses(): HouseDef[] {
91
- if (!this.data?.meta) return [];
92
- return buildHousesFromMeta(this.data.meta);
38
+ private viewModel(): KundliViewModel | null {
39
+ if (!this.data?.meta) return null;
40
+ return toKundliViewModel(this.data.meta, 'D1 Rashi');
93
41
  }
94
42
 
43
+ private setStyle = (next: ChartStyle) => {
44
+ this.chartStyle = next;
45
+ };
46
+
95
47
  render() {
96
- if (!this.data)
48
+ const vm = this.viewModel();
49
+ if (!vm)
97
50
  return html`<div class="roxy-empty" role="status">No kundli data</div>`;
98
- const houses = this.buildHouses();
99
- const style = this.chartStyle;
100
-
101
- const frame =
102
- style === 'north'
103
- ? renderNorthFrame()
104
- : style === 'east'
105
- ? renderEastFrame()
106
- : renderSouthFrame();
107
- const houseGroup =
108
- style === 'north'
109
- ? renderNorthHouseGroup
110
- : style === 'east'
111
- ? renderEastHouseGroup
112
- : renderSouthHouseGroup;
113
-
114
51
  return html`<div class="wrap">
115
- <h2 class="title">Vedic kundli</h2>
52
+ <div class="header">
53
+ <h2 class="title">Vedic kundli</h2>
54
+ ${renderKundliStyleTablist(this.chartStyle, this.setStyle)}
55
+ </div>
116
56
  <svg
117
- viewBox="0 0 300 300"
57
+ viewBox="0 0 400 400"
58
+ preserveAspectRatio="xMidYMid meet"
118
59
  role="img"
119
60
  aria-label="Vedic birth chart with twelve sign houses"
120
61
  >
121
62
  <title>Vedic kundli</title>
122
- ${frame}
123
- ${houses.map((h) => houseGroup(h))}
63
+ ${renderKundliSvg(vm, this.chartStyle)}
124
64
  </svg>
125
65
  </div>`;
126
66
  }
@@ -90,15 +90,12 @@
90
90
  --roxy-motion-duration: 200ms;
91
91
  --roxy-motion-easing: cubic-bezier(0.4, 0, 0.2, 1);
92
92
 
93
- /* Heat scale: 7-step gradient used by ashtakavarga bindu cells.
94
- * Low bindus (1) are cool green; high bindus (7+) are hot red. */
95
- --roxy-heat-1: #f0fdf4;
96
- --roxy-heat-2: #d1fae5;
97
- --roxy-heat-3: #a7f3d0;
98
- --roxy-heat-4: #fde68a;
99
- --roxy-heat-5: #fdba74;
100
- --roxy-heat-6: #fb923c;
101
- --roxy-heat-7: #ef4444;
93
+ /* Heat scale: a single base hue. Consumers mix it with `transparent` at
94
+ * increasing percentages to paint cooler-to-hotter tiers. The mix-with-
95
+ * transparent approach lets the page bg show through and keeps text
96
+ * colour stable (always --roxy-fg), so the cells read in both themes
97
+ * without per-tier text colours. */
98
+ --roxy-heat: var(--roxy-danger, #ef4444);
102
99
  }
103
100
 
104
101
  /* Dark theme via system preference */
@@ -134,13 +131,7 @@
134
131
  0 4px 6px -1px rgba(0, 0, 0, 0.6), 0 2px 4px -2px rgba(0, 0, 0, 0.5);
135
132
  --roxy-shadow-lg: 0 12px 24px -8px rgba(0, 0, 0, 0.7);
136
133
 
137
- --roxy-heat-1: #052e16;
138
- --roxy-heat-2: #14532d;
139
- --roxy-heat-3: #166534;
140
- --roxy-heat-4: #92400e;
141
- --roxy-heat-5: #b45309;
142
- --roxy-heat-6: #c2410c;
143
- --roxy-heat-7: #b91c1c;
134
+ --roxy-heat: var(--roxy-danger, #ef4444);
144
135
  }
145
136
  }
146
137
 
@@ -205,13 +196,7 @@
205
196
  0 4px 6px -1px rgba(0, 0, 0, 0.6), 0 2px 4px -2px rgba(0, 0, 0, 0.5);
206
197
  --roxy-shadow-lg: 0 12px 24px -8px rgba(0, 0, 0, 0.7);
207
198
 
208
- --roxy-heat-1: #052e16;
209
- --roxy-heat-2: #14532d;
210
- --roxy-heat-3: #166534;
211
- --roxy-heat-4: #92400e;
212
- --roxy-heat-5: #b45309;
213
- --roxy-heat-6: #c2410c;
214
- --roxy-heat-7: #b91c1c;
199
+ --roxy-heat: var(--roxy-danger, #ef4444);
215
200
  }
216
201
 
217
202
  /* Reduced motion override */
@@ -86,4 +86,18 @@ export const baseStyles = css`
86
86
  outline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));
87
87
  outline-offset: 2px;
88
88
  }
89
+
90
+ /* Force the text-style variant on every Unicode glyph in the component.
91
+ * macOS and iOS substitute coloured emoji glyphs for the planetary and
92
+ * gender Unicode code points (Mars, Venus, Mercury, etc.) when the
93
+ * system colour-emoji font wins font selection. The text-style variant
94
+ * keeps glyphs monochrome so they inherit the surrounding fill colour
95
+ * and match the brand palette consistently across platforms.
96
+ *
97
+ * font-variant-emoji is part of CSS Fonts 4 (Safari 17+, Chrome 134+,
98
+ * Firefox 139+). On older browsers the rule is silently ignored.
99
+ */
100
+ :host {
101
+ font-variant-emoji: text;
102
+ }
89
103
  `;