@openephemeris/mcp-server 3.13.10 → 3.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +3 -3
  3. package/dist/index.js +5 -43
  4. package/dist/oauth/discovery.d.ts +1 -0
  5. package/dist/oauth/discovery.js +8 -3
  6. package/dist/oauth/store.d.ts +20 -0
  7. package/dist/oauth/store.js +117 -3
  8. package/dist/oauth/token.js +4 -2
  9. package/dist/prompts.js +9 -0
  10. package/dist/server-sse.js +71 -64
  11. package/dist/tools/apps/bazi-app.js +2 -0
  12. package/dist/tools/apps/bi-wheel-app.js +55 -6
  13. package/dist/tools/apps/bodygraph-app.js +68 -10
  14. package/dist/tools/apps/chart-wheel-app.js +53 -4
  15. package/dist/tools/apps/location-tools.js +3 -0
  16. package/dist/tools/apps/moon-phase-app.js +75 -21
  17. package/dist/tools/apps/transit-timeline-app.js +75 -23
  18. package/dist/tools/apps/vedic-chart-app.js +2 -0
  19. package/dist/tools/auth.js +4 -0
  20. package/dist/tools/dev.js +3 -0
  21. package/dist/tools/index.d.ts +6 -0
  22. package/dist/tools/index.js +8 -7
  23. package/dist/tools/output-schemas.d.ts +37 -0
  24. package/dist/tools/output-schemas.js +130 -0
  25. package/dist/tools/specialized/acg.js +3 -0
  26. package/dist/tools/specialized/bazi.js +8 -0
  27. package/dist/tools/specialized/bi_wheel.js +2 -0
  28. package/dist/tools/specialized/chart_wheel.js +2 -0
  29. package/dist/tools/specialized/comparative.js +5 -0
  30. package/dist/tools/specialized/eclipse.js +2 -0
  31. package/dist/tools/specialized/electional.js +5 -0
  32. package/dist/tools/specialized/ephemeris_core.js +3 -0
  33. package/dist/tools/specialized/ephemeris_extended.js +9 -0
  34. package/dist/tools/specialized/hd_bodygraph.js +2 -0
  35. package/dist/tools/specialized/hd_cycles.js +3 -0
  36. package/dist/tools/specialized/hd_group.js +3 -0
  37. package/dist/tools/specialized/human_design.js +2 -0
  38. package/dist/tools/specialized/moon.js +3 -0
  39. package/dist/tools/specialized/natal.js +2 -0
  40. package/dist/tools/specialized/progressed.js +2 -0
  41. package/dist/tools/specialized/relocation.js +2 -0
  42. package/dist/tools/specialized/returns.js +4 -0
  43. package/dist/tools/specialized/synastry.js +2 -0
  44. package/dist/tools/specialized/transits.js +52 -43
  45. package/dist/tools/specialized/vedic.js +2 -0
  46. package/dist/tools/specialized/venus_star_points.js +7 -0
  47. package/dist/ui/bazi.html +1 -1
  48. package/dist/ui/bi-wheel.html +3514 -3121
  49. package/dist/ui/bodygraph.html +1308 -1261
  50. package/dist/ui/chart-wheel.html +3404 -3116
  51. package/dist/ui/moon-phase.html +2622 -2616
  52. package/dist/ui/transit-timeline.html +2695 -2656
  53. package/dist/ui/vedic-chart.html +1 -1
  54. package/package.json +14 -11
  55. package/smithery.yaml +16 -1
@@ -1,27 +1,22 @@
1
1
  import { registerTool, validateRequired } from "../index.js";
2
2
  import { getActiveClient } from "../../backend/client.js";
3
+ import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
3
4
  registerTool({
4
5
  name: "ephemeris_transits",
5
6
  description: "Search for astrological transit events affecting a natal chart over a date range. " +
6
- "Returns a list of exact transit moments — when transiting planets form specified aspects " +
7
- "to natal planet positions. Ideal for generating horoscope timelines, event forecasting, or " +
8
- "finding optimal timing windows.\n\n" +
9
- "HOW IT WORKS: This tool first calculates the natal chart to extract your actual planetary " +
10
- "ecliptic longitudes, then searches for transiting planets crossing those exact degrees.\n\n" +
11
- "ASPECT ANGLES: Use aspect_angle to search for specific aspects to natal positions:\n" +
7
+ "Returns exact transit moments — when transiting planets form specified aspects " +
8
+ "to natal planet positions.\n\n" +
9
+ "EFFICIENCY TIP: Always specify both transiting_planets and natal_points to keep " +
10
+ "compute fast. Omitting both sends all outer planets against all core natal positions " +
11
+ " a much heavier computation.\n\n" +
12
+ "ASPECT ANGLES: Use aspect_angle to search for specific aspects:\n" +
12
13
  " 0 = conjunction/return (default), 180 = opposition, 90 = square, 120 = trine.\n" +
13
14
  " Example: Saturn Return → transiting_planets=['saturn'], natal_points=['saturn'], aspect_angle=0\n" +
14
15
  " Example: Uranus Opposition → transiting_planets=['uranus'], natal_points=['uranus'], aspect_angle=180\n" +
15
- " Example: Chiron Return → transiting_planets=['chiron'], natal_points=['chiron'], aspect_angle=0\n\n" +
16
- "SUPPORTED BODIES: Sun, Moon, Mercury, Venus, Mars, Jupiter, Saturn, Uranus, Neptune, " +
17
- "Pluto, Chiron, Pholus, Ceres, Pallas, Juno, Vesta, MeanNode.\n\n" +
18
- "CREDIT COST: 6 credits per call (1 for natal + 5 for transit search). " +
19
- "Requests exceeding 30 seconds incur 1 additional credit per 30s of compute time.\n\n" +
20
- "SEARCH RANGE LIMITS: Explorer tier is limited to 1-year windows; Developer to 5 years. " +
21
- "Ranges exceeding the limit are silently clamped.\n\n" +
22
- "EXAMPLE: Find all Saturn transits to the natal Sun/Moon for the next 6 months:\n" +
23
- " natal_datetime='1990-04-15T14:30:00', natal_latitude=41.8781, natal_longitude=-87.6298,\n" +
24
- " start_date='2026-01-01', end_date='2026-06-30', transiting_planets=['saturn']",
16
+ " Example: Outer planets to natal Sun/Moon → transiting_planets=['saturn','uranus','neptune','pluto'], natal_points=['sun','moon']\n\n" +
17
+ "DEFAULT natal_points (when omitted): sun, moon, mercury, venus, mars, jupiter, saturn.\n" +
18
+ "SEARCH RANGE LIMITS: Explorer/PayG tier 1 year max; Developer → 5 years; Startup → 10 years.\n" +
19
+ "CREDIT COST: 6 credits per call.",
25
20
  inputSchema: {
26
21
  type: "object",
27
22
  properties: {
@@ -66,6 +61,7 @@ registerTool({
66
61
  required: ["natal_datetime", "natal_latitude", "natal_longitude", "start_date", "end_date"],
67
62
  additionalProperties: false,
68
63
  },
64
+ outputSchema: OUTPUT_SCHEMA_JSON,
69
65
  annotations: { title: "Transit Search", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
70
66
  handler: async (args) => {
71
67
  validateRequired(args, ["natal_datetime", "natal_latitude", "natal_longitude", "start_date", "end_date"]);
@@ -87,35 +83,49 @@ registerTool({
87
83
  // The natal response typically has a `planets` array or object
88
84
  const planets = natalResult?.planets || natalResult?.data?.planets || [];
89
85
  const planetArray = Array.isArray(planets) ? planets : Object.values(planets);
90
- // Filter to requested natal points if specified
86
+ // ── Core bodies used when no natal_points filter is given ────────────
87
+ // Defaulting to all planets creates 40+ serial SearchTransit calls on the
88
+ // backend (10+ targets × 4+ outer planets). Cap to the 7 classical bodies.
89
+ const CORE_BODIES_DEFAULT = new Set([
90
+ "sun", "moon", "mercury", "venus", "mars", "jupiter", "saturn",
91
+ ]);
91
92
  const wantedPoints = args.natal_points
92
93
  ? new Set(args.natal_points.map((p) => p.toLowerCase()))
93
- : null;
94
+ : CORE_BODIES_DEFAULT;
94
95
  for (const planet of planetArray) {
95
96
  const name = (planet.name || planet.id || "").toLowerCase();
96
97
  const lon = planet.longitude ?? planet.ecliptic_longitude ?? planet.lon;
97
98
  if (typeof lon !== "number" || !isFinite(lon))
98
99
  continue;
99
- if (wantedPoints && !wantedPoints.has(name))
100
+ if (!wantedPoints.has(name))
100
101
  continue;
101
- targetDegrees.push(Math.round(lon * 100) / 100); // 2 decimal places
102
+ targetDegrees.push(Math.round(lon * 100) / 100);
102
103
  natalPositionMap[name] = lon;
103
104
  }
104
- // Also extract angles (ASC, MC, DSC, IC) if present
105
- const angles = natalResult?.angles || natalResult?.data?.angles;
106
- if (angles) {
107
- const angleEntries = Array.isArray(angles) ? angles : Object.entries(angles).map(([k, v]) => ({ name: k, ...(typeof v === 'object' ? v : { longitude: v }) }));
108
- for (const angle of angleEntries) {
109
- const name = (angle.name || angle.id || "").toLowerCase();
110
- const lon = angle.longitude ?? angle.ecliptic_longitude ?? angle.lon;
111
- if (typeof lon !== "number" || !isFinite(lon))
112
- continue;
113
- if (wantedPoints && !wantedPoints.has(name))
114
- continue;
115
- targetDegrees.push(Math.round(lon * 100) / 100);
116
- natalPositionMap[name] = lon;
105
+ // Extract angles (ASC, MC) only when explicitly requested
106
+ if (args.natal_points) {
107
+ const angles = natalResult?.angles || natalResult?.data?.angles;
108
+ if (angles) {
109
+ const angleEntries = Array.isArray(angles)
110
+ ? angles
111
+ : Object.entries(angles).map(([k, v]) => ({ name: k, ...(typeof v === "object" ? v : { longitude: v }) }));
112
+ for (const angle of angleEntries) {
113
+ const name = (angle.name || angle.id || "").toLowerCase();
114
+ const lon = angle.longitude ?? angle.ecliptic_longitude ?? angle.lon;
115
+ if (typeof lon !== "number" || !isFinite(lon))
116
+ continue;
117
+ if (!wantedPoints.has(name))
118
+ continue;
119
+ targetDegrees.push(Math.round(lon * 100) / 100);
120
+ natalPositionMap[name] = lon;
121
+ }
117
122
  }
118
123
  }
124
+ // Hard cap: never send more than 12 target degrees
125
+ const MAX_TARGETS = 12;
126
+ if (targetDegrees.length > MAX_TARGETS) {
127
+ targetDegrees.splice(MAX_TARGETS);
128
+ }
119
129
  if (targetDegrees.length === 0) {
120
130
  throw new Error("Could not extract natal planet longitudes from the natal chart calculation. " +
121
131
  "Please verify your natal_datetime, natal_latitude, and natal_longitude are correct.");
@@ -129,23 +139,22 @@ registerTool({
129
139
  if (/^\d{4}-\d{2}-\d{2}$/.test(endStr)) {
130
140
  endStr += "T23:59:59Z";
131
141
  }
142
+ const aspectAngle = typeof args.aspect_angle === "number" ? args.aspect_angle : 0;
143
+ let effectiveTargets = targetDegrees;
144
+ if (aspectAngle !== 0) {
145
+ effectiveTargets = targetDegrees.map((deg) => ((deg + aspectAngle) % 360 + 360) % 360);
146
+ }
132
147
  const transitBody = {
133
148
  start_date: startStr,
134
149
  end_date: endStr,
135
- target_degrees: targetDegrees,
150
+ target_degrees: effectiveTargets,
136
151
  };
137
152
  if (args.transiting_planets)
138
153
  transitBody.planet_names = args.transiting_planets;
139
- // When aspect_angle is provided, apply offset to compute effective target degrees
140
- // (natal_lon + aspect_angle) mod 360 for each natal point
141
- let effectiveTargets = targetDegrees;
142
- if (typeof args.aspect_angle === "number" && args.aspect_angle !== 0) {
143
- effectiveTargets = targetDegrees.map((deg) => ((deg + args.aspect_angle) % 360 + 360) % 360);
144
- transitBody.target_degrees = effectiveTargets;
145
- // Also include aspect metadata for labeling in results
146
- transitBody.search_criteria = { aspect_angle: args.aspect_angle };
154
+ if (aspectAngle !== 0) {
155
+ transitBody.search_criteria = { aspect_angle: aspectAngle };
147
156
  }
148
- const transitResult = await getActiveClient().request("POST", "/predictive/transits/search", { data: transitBody });
157
+ const transitResult = await getActiveClient().request("POST", "/predictive/transits/search", { data: transitBody, timeoutMs: 90_000 });
149
158
  // Return combined context so the LLM knows what natal positions were targeted
150
159
  return {
151
160
  natal_positions: natalPositionMap,
@@ -1,5 +1,6 @@
1
1
  import { registerTool, validateRequired, validateCoordinates } from "../index.js";
2
2
  import { getActiveClient } from "../../backend/client.js";
3
+ import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
3
4
  registerTool({
4
5
  name: "vedic_chart",
5
6
  description: "Calculate a Vedic (Jyotish) natal chart with sidereal positions. Returns planet placements " +
@@ -33,6 +34,7 @@ registerTool({
33
34
  required: ["datetime", "latitude", "longitude"],
34
35
  additionalProperties: false,
35
36
  },
37
+ outputSchema: OUTPUT_SCHEMA_JSON,
36
38
  annotations: { title: "Vedic Natal Chart", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
37
39
  handler: async (args) => {
38
40
  validateRequired(args, ["datetime", "latitude", "longitude"]);
@@ -1,5 +1,6 @@
1
1
  import { registerTool, validateRequired } from "../index.js";
2
2
  import { getActiveClient } from "../../backend/client.js";
3
+ import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
3
4
  function buildSubject(datetime, lat, lon) {
4
5
  return {
5
6
  name: "Subject",
@@ -29,6 +30,7 @@ registerTool({
29
30
  required: ["datetime", "latitude", "longitude"],
30
31
  additionalProperties: false,
31
32
  },
33
+ outputSchema: OUTPUT_SCHEMA_JSON,
32
34
  annotations: { title: "Venus Star Points", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
33
35
  handler: async (args) => {
34
36
  validateRequired(args, ["datetime", "latitude", "longitude"]);
@@ -59,6 +61,7 @@ registerTool({
59
61
  required: ["start_date", "end_date"],
60
62
  additionalProperties: false,
61
63
  },
64
+ outputSchema: OUTPUT_SCHEMA_JSON,
62
65
  annotations: { title: "Venus Conjunctions", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
63
66
  handler: async (args) => {
64
67
  validateRequired(args, ["start_date", "end_date"]);
@@ -89,6 +92,7 @@ registerTool({
89
92
  required: ["date"],
90
93
  additionalProperties: false,
91
94
  },
95
+ outputSchema: OUTPUT_SCHEMA_JSON,
92
96
  annotations: { title: "Venus 8-Year Star", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
93
97
  handler: async (args) => {
94
98
  validateRequired(args, ["date"]);
@@ -120,6 +124,7 @@ registerTool({
120
124
  required: [],
121
125
  additionalProperties: false,
122
126
  },
127
+ outputSchema: OUTPUT_SCHEMA_JSON,
123
128
  annotations: { title: "Venus Phase", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
124
129
  handler: async (args) => {
125
130
  const query = {};
@@ -147,6 +152,7 @@ registerTool({
147
152
  required: ["start_date", "end_date"],
148
153
  additionalProperties: false,
149
154
  },
155
+ outputSchema: OUTPUT_SCHEMA_JSON,
150
156
  annotations: { title: "Venus Elongations", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
151
157
  handler: async (args) => {
152
158
  validateRequired(args, ["start_date", "end_date"]);
@@ -177,6 +183,7 @@ registerTool({
177
183
  required: ["start_date"],
178
184
  additionalProperties: false,
179
185
  },
186
+ outputSchema: OUTPUT_SCHEMA_JSON,
180
187
  annotations: { title: "Venus Stations", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
181
188
  handler: async (args) => {
182
189
  validateRequired(args, ["start_date"]);
package/dist/ui/bazi.html CHANGED
@@ -7,7 +7,7 @@
7
7
  <title>BaZi Four Pillars Explorer</title>
8
8
 
9
9
 
10
- <style>*,:before,:after{box-sizing:border-box;margin:0;padding:0}:root{--bg-primary:#090b0f;--bg-secondary:#12161d;--bg-tertiary:#1c222b;--bg-hover:#272e3b;--border:#282e38;--border-subtle:#1d2229;--text-primary:#e1e5eb;--text-secondary:#9da5b1;--text-muted:#6c727b;--accent:#62b3ff;--accent-warm:#e6ac3d;--radius:8px;--radius-sm:4px;--radius-lg:12px;--wuxing-wood:#31aa40;--wuxing-fire:#f14d4c;--wuxing-earth:#ca8a10;--wuxing-metal:#9fafc8;--wuxing-water:#0099e0;--wuxing-wood-bg:#1b451e;--wuxing-fire-bg:#65201e;--wuxing-earth-bg:#583c10;--wuxing-metal-bg:#3c434d;--wuxing-water-bg:#003f60;--dm-border:#d29922;--dm-bg:#201a10;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}@supports (color:color(display-p3 0 0 0)){:root{--bg-primary:color(display-p3 .036047 .0438664 .059078);--bg-secondary:color(display-p3 .0739679 .0866504 .111186);--bg-tertiary:color(display-p3 .114361 .13221 .166818);--bg-hover:color(display-p3 .15679 .180114 .225406);--border:color(display-p3 .161376 .180145 .216325);--border-subtle:color(display-p3 .118728 .13221 .158123);--text-primary:color(display-p3 .883958 .896627 .920543);--text-secondary:color(display-p3 .622745 .646433 .6914);--text-muted:color(display-p3 .429297 .445909 .477439);--accent:color(display-p3 .446063 .694439 1.01077);--accent-warm:color(display-p3 .866978 .684443 .324483);--wuxing-wood:color(display-p3 .343741 .657851 .307102);--wuxing-fire:color(display-p3 .872583 .352089 .325751);--wuxing-earth:color(display-p3 .754604 .550516 .200367);--wuxing-metal:color(display-p3 .636614 .68404 .77495);--wuxing-water:color(display-p3 .226818 .589506 .875825);--wuxing-wood-bg:color(display-p3 .150499 .267148 .135899);--wuxing-fire-bg:color(display-p3 .36387 .143128 .129405);--wuxing-earth-bg:color(display-p3 .328547 .240912 .0972974);--wuxing-metal-bg:color(display-p3 .240898 .260909 .299258);--wuxing-water-bg:color(display-p3 .0921333 .242221 .364185);--dm-border:color(display-p3 .789908 .60997 .245434);--dm-bg:color(display-p3 .119765 .101379 .0671137)}}@supports (color:lab(0% 0 0)){:root{--bg-primary:lab(3.02674% -.179462 -2.15476);--bg-secondary:lab(7.16596% -.441141 -5.41423);--bg-tertiary:lab(12.9118% -.60384 -7.27841);--bg-hover:lab(18.6882% -.727877 -9.08878);--border:lab(18.7165% -.689313 -7.30941);--border-subtle:lab(12.9391% -.548743 -5.49436);--text-primary:lab(90.6878% -.517368 -3.73452);--text-secondary:lab(67.45% -.932217 -7.41489);--text-muted:lab(47.7476% -.701487 -5.56231);--accent:lab(70.4043% -7.21234 -50.7672);--accent-warm:lab(74.5248% 14.3487 62.5064);--wuxing-wood:lab(61.5358% -50.6384 43.17);--wuxing-fire:lab(57.3944% 63.124 38.0626);--wuxing-earth:lab(62.7263% 19.0613 64.9727);--wuxing-metal:lab(70.8424% -1.5474 -14.6858);--wuxing-water:lab(59.1191% -14.8305 -49.6808);--wuxing-wood-bg:lab(25.5679% -22.4482 18.6532);--wuxing-fire-bg:lab(23.6033% 31.5073 18.7032);--wuxing-earth-bg:lab(28.0231% 9.19801 30.8603);--wuxing-metal-bg:lab(28.0014% -.778109 -7.34471);--wuxing-water-bg:lab(24.4811% -7.8918 -24.9024);--dm-border:lab(67.5362% 14.8294 64.5914);--dm-bg:lab(9.55197% 1.60985 7.31485)}}@media (prefers-color-scheme:light){:root{--bg-primary:#f3f5f9;--bg-secondary:#e7ebf2;--bg-tertiary:#d8dee8;--bg-hover:#d0d8e5;--border:#bdc5d1;--border-subtle:#d2d8e2;--text-primary:#0f1216;--text-secondary:#414853;--text-muted:#6c727b;--accent:#0065b2;--accent-warm:#966800;--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light;--wuxing-wood:#005f0e;--wuxing-fire:#a20519;--wuxing-earth:#805300;--wuxing-metal:#48566c;--wuxing-water:#005380;--wuxing-wood-bg:#c0e3c0;--wuxing-fire-bg:#fdc9c4;--wuxing-earth-bg:#f2daba;--wuxing-metal-bg:#d6dfec;--wuxing-water-bg:#b4defc;--dm-border:#966800;--dm-bg:#f6ede0}@supports (color:color(display-p3 0 0 0)){:root{--bg-primary:color(display-p3 .95471 .961142 .973263);--bg-secondary:color(display-p3 .909797 .922535 .946581);--bg-tertiary:color(display-p3 .852455 .871315 .906983);--bg-hover:color(display-p3 .821139 .84609 .893374);--border:color(display-p3 .745559 .770059 .816515);--border-subtle:color(display-p3 .826933 .845684 .881152);--text-primary:color(display-p3 .0608605 .0691527 .0850621);--text-secondary:color(display-p3 .261513 .281801 .32064);--text-muted:color(display-p3 .429297 .445909 .477439);--accent:color(display-p3 .143802 .388951 .683672);--accent-warm:color(display-p3 .596632 .396992 -.158844);--wuxing-wood:color(display-p3 .0968244 .374385 .0683277);--wuxing-fire:color(display-p3 .580784 .119608 .128804);--wuxing-earth:color(display-p3 .489279 .326588 -.0287041);--wuxing-metal:color(display-p3 .294019 .335238 .415486);--wuxing-water:color(display-p3 -.0775243 .316124 .547443);--wuxing-wood-bg:color(display-p3 .778394 .884493 .76257);--wuxing-fire-bg:color(display-p3 .959986 .795906 .773571);--wuxing-earth-bg:color(display-p3 .93331 .858308 .743829);--wuxing-metal-bg:color(display-p3 .84663 .871726 .919277);--wuxing-water-bg:color(display-p3 .739548 .864306 .975015);--dm-border:color(display-p3 .596632 .396992 -.158844);--dm-bg:color(display-p3 .957692 .931855 .88349)}}@supports (color:lab(0% 0 0)){:root{--bg-primary:lab(96.5044% -.267148 -1.87216);--bg-secondary:lab(93.0079% -.518024 -3.73493);--bg-tertiary:lab(88.3503% -.749856 -5.58736);--bg-hover:lab(86.0117% -.963002 -7.43048);--border:lab(79.0511% -.952899 -7.42528);--border-subtle:lab(86.0302% -.748128 -5.58645);--text-primary:lab(5.23796% -.285208 -3.0582);--text-secondary:lab(30.3224% -.794604 -7.35167);--text-muted:lab(47.7476% -.701487 -5.56231);--accent:lab(41.1205% -1.70796 -50.1423);--accent-warm:lab(47.6194% 20.1868 104.51);--wuxing-wood:lab(34.5429% -45.3762 42.1829);--wuxing-fire:lab(34.3495% 57.1812 37.8813);--wuxing-earth:lab(39.4811% 17.4358 64.8795);--wuxing-metal:lab(36.0172% -1.09252 -14.5181);--wuxing-water:lab(32.2784% -8.65509 -43.065);--wuxing-wood-bg:lab(86.8562% -16.7675 13.1583);--wuxing-fire-bg:lab(85.5193% 18.485 10.0423);--wuxing-earth-bg:lab(88.4503% 4.9783 19.0112);--wuxing-metal-bg:lab(88.3319% -.966102 -7.43206);--wuxing-water-bg:lab(86.1283% -8.87641 -19.3614);--dm-border:lab(47.6194% 20.1868 104.51);--dm-bg:lab(94.2538% 1.22291 7.5882)}}}html,body{background:var(--bg-primary);width:100%;height:100%;color:var(--text-primary);font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Noto Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:13px;line-height:1.5;overflow:hidden}body{flex-direction:column;display:flex}#app{flex-direction:column;flex:1;display:flex;overflow:hidden}#loading-state{color:var(--text-secondary);flex-direction:column;flex:1;justify-content:center;align-items:center;gap:12px;display:flex}#loading-state[hidden]{display:none}.oe-loader{width:48px;height:48px;animation:1.2s linear infinite spin}.oe-loader circle{fill:none;stroke:var(--accent);stroke-width:3px;stroke-dasharray:200;stroke-dashoffset:80px;stroke-linecap:round}@keyframes spin{to{transform:rotate(360deg)}}.chart-status{background:var(--bg-secondary);border-top:1px solid var(--border-subtle);color:var(--text-muted);opacity:0;z-index:50;padding:6px 14px;font-size:11px;transition:opacity .2s,transform .2s;position:fixed;bottom:0;left:0;right:0;transform:translateY(100%)}.chart-status.visible{opacity:1;transform:translateY(0)}#bazi-container{flex-direction:column;flex:1;gap:16px;padding:16px;display:flex;overflow-y:auto}#bazi-container[hidden]{display:none}.bazi-pillars{grid-template-columns:repeat(4,1fr);gap:8px;animation:.6s ease-out bazi-fade-in;display:grid}@keyframes bazi-fade-in{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.bazi-pillar{border:1px solid var(--border-subtle);border-radius:var(--radius);background:var(--bg-secondary);cursor:pointer;flex-direction:column;transition:border-color .15s,box-shadow .15s,transform .15s;display:flex;overflow:hidden}.bazi-pillar:hover{border-color:var(--border);transform:translateY(-1px);box-shadow:0 2px 12px rgba(0,0,0,.1);box-shadow:0 2px 12px color(display-p3 0 0 0/.1);box-shadow:0 2px 12px lab(0% 0 0/.1)}.bazi-pillar--dm{border-color:var(--dm-border);background:var(--dm-bg);box-shadow:inset 3px 0 0 var(--dm-border), inset -3px 0 0 var(--dm-border)}.bazi-pillar--dm:hover{border-color:var(--dm-border);box-shadow:inset 3px 0 0 var(--dm-border), inset -3px 0 0 var(--dm-border), 0 4px 16px rgba(210,153,34,.15)}@supports (color:color(display-p3 0 0 0)){.bazi-pillar--dm:hover{box-shadow:inset 3px 0 0 var(--dm-border), inset -3px 0 0 var(--dm-border), 0 4px 16px color(display-p3 .789908 .60997 .245434/.15)}}@supports (color:lab(0% 0 0)){.bazi-pillar--dm:hover{box-shadow:inset 3px 0 0 var(--dm-border), inset -3px 0 0 var(--dm-border), 0 4px 16px lab(67.5362% 14.8294 64.5914/.15)}}.bazi-pillar-header{text-transform:uppercase;letter-spacing:.08em;color:var(--text-muted);background:var(--bg-tertiary);border-bottom:1px solid var(--border-subtle);justify-content:center;align-items:center;gap:4px;padding:6px 8px;font-size:10px;font-weight:700;display:flex}.bazi-pillar--dm .bazi-pillar-header{color:var(--dm-border)}.dm-badge{background:var(--dm-border);color:#090b0f;color:color(display-p3 .036047 .0438664 .059078);color:lab(3.02674% -.179462 -2.15476);letter-spacing:.04em;border-radius:10px;padding:1px 5px;font-size:9px;font-weight:700}@media (prefers-color-scheme:light){.dm-badge{color:#fcf8f1;color:color(display-p3 .985424 .972455 .948118);color:lab(97.7087% .579864 3.77247)}}.bazi-stem-zone{border-bottom:1px solid var(--border-subtle);flex-direction:column;align-items:center;gap:2px;padding:10px 8px;display:flex}.bazi-stem-chinese{font-size:28px;font-weight:700;line-height:1.1}.bazi-stem-name{color:var(--text-secondary);font-size:11px;font-weight:600}.bazi-stem-element{color:var(--bg-primary);border-radius:10px;padding:1px 6px;font-size:10px;font-weight:500}@media (prefers-color-scheme:light){.bazi-stem-element{color:#fff6f8;color:color(display-p3 .992746 .964982 .972458);color:lab(97.5544% 3.37881 .0330448)}}.bazi-branch-zone{border-bottom:1px solid var(--border-subtle);flex-direction:column;align-items:center;gap:2px;padding:10px 8px;display:flex}.bazi-branch-animal-emoji{font-size:22px;line-height:1.1}.bazi-branch-name{color:var(--text-secondary);font-size:11px;font-weight:600}.bazi-branch-animal{color:var(--text-muted);font-size:10px}.bazi-hidden-zone{flex-direction:column;align-items:center;gap:3px;min-height:48px;padding:6px 8px;display:flex}.bazi-hidden-label{text-transform:uppercase;letter-spacing:.06em;color:var(--text-muted);margin-bottom:1px;font-size:9px;font-weight:600}.bazi-hidden-stems{flex-wrap:wrap;justify-content:center;gap:6px;display:flex}.bazi-hidden-stem{flex-direction:column;align-items:center;gap:1px;display:flex}.bazi-hidden-char{font-size:16px;font-weight:600;line-height:1.1}.bazi-hidden-strength{opacity:.7;border-radius:50%;width:6px;height:6px}.bazi-hidden-strength--main{opacity:1}.bazi-hidden-strength--secondary{opacity:.65}.bazi-hidden-strength--residual{opacity:.35}.bazi-ten-god-tag{background:var(--bg-hover);color:var(--text-secondary);border-radius:10px;padding:1px 5px;font-size:9px;font-weight:600}.bazi-balance{background:var(--bg-secondary);border:1px solid var(--border-subtle);border-radius:var(--radius);flex-direction:column;gap:8px;padding:12px 14px;animation:.8s ease-out .2s both bazi-fade-in;display:flex}.bazi-balance-header{justify-content:space-between;align-items:center;display:flex}.bazi-balance-title{text-transform:uppercase;letter-spacing:.06em;color:var(--text-muted);font-size:11px;font-weight:700}.bazi-balance-strength{background:var(--bg-hover);color:var(--text-secondary);border-radius:10px;padding:2px 8px;font-size:11px;font-weight:600}.bazi-balance-strength--strong{color:var(--wuxing-wood)}.bazi-balance-strength--weak{color:var(--wuxing-fire)}.bazi-bar-container{border-radius:var(--radius-sm);border:1px solid var(--border-subtle);height:28px;display:flex;overflow:hidden}.bazi-bar-segment{min-width:24px;color:var(--text-primary);justify-content:center;align-items:center;font-size:10px;font-weight:700;transition:flex .4s ease-out;display:flex;position:relative;overflow:hidden}.bazi-bar-segment-label{opacity:.8;white-space:nowrap;font-size:9px}.bazi-bar-legend{flex-wrap:wrap;justify-content:center;gap:12px;display:flex}.bazi-legend-item{color:var(--text-secondary);cursor:pointer;align-items:center;gap:4px;font-size:11px;transition:color .15s;display:flex}.bazi-legend-item:hover{color:var(--text-primary)}.bazi-legend-dot{border-radius:50%;flex-shrink:0;width:8px;height:8px}.bazi-legend-pct{font-variant-numeric:tabular-nums;font-weight:700}.bazi-legend-score{color:var(--text-muted);font-size:10px}.bazi-yongshen{border-radius:var(--radius-sm);background:var(--bg-tertiary);border:1px solid var(--border-subtle);color:var(--text-secondary);justify-content:center;align-items:center;gap:6px;padding:6px 12px;font-size:12px;display:flex}.bazi-yongshen-label{color:var(--text-muted);font-weight:500}.bazi-yongshen-value{font-weight:700}.bazi-drawer-overlay{z-index:60;opacity:0;background:rgba(0,0,0,.4);background:color(display-p3 0 0 0/.4);background:lab(0% 0 0/.4);transition:opacity .2s;position:fixed;top:0;bottom:0;left:0;right:0}.bazi-drawer-overlay.visible{opacity:1}.bazi-drawer{background:var(--bg-secondary);border-top:1px solid var(--border);border-radius:var(--radius-lg) var(--radius-lg) 0 0;z-index:61;max-height:60vh;padding:16px;transition:transform .25s ease-out;position:fixed;bottom:0;left:0;right:0;overflow-y:auto;transform:translateY(100%)}.bazi-drawer.visible{transform:translateY(0)}.bazi-drawer-handle{background:var(--border);border-radius:2px;width:36px;height:4px;margin:0 auto 12px}.bazi-drawer-title{align-items:center;gap:8px;margin-bottom:12px;font-size:15px;font-weight:700;display:flex}.bazi-drawer-section{margin-bottom:12px}.bazi-drawer-section-title{text-transform:uppercase;letter-spacing:.06em;color:var(--text-muted);margin-bottom:6px;font-size:10px;font-weight:700}.bazi-drawer-ten-god{background:var(--bg-tertiary);border-radius:var(--radius-sm);align-items:center;gap:10px;margin-bottom:6px;padding:8px 10px;display:flex}.bazi-drawer-tg-chinese{font-size:22px;font-weight:700}.bazi-drawer-tg-info{flex-direction:column;gap:1px;display:flex}.bazi-drawer-tg-name{font-size:13px;font-weight:600}.bazi-drawer-tg-category{color:var(--text-muted);text-transform:capitalize;font-size:11px}.bazi-drawer-hidden-table{border-collapse:collapse;width:100%;font-size:12px}.bazi-drawer-hidden-table th{text-transform:uppercase;letter-spacing:.04em;color:var(--text-muted);text-align:left;border-bottom:1px solid var(--border-subtle);padding:4px 8px;font-size:10px;font-weight:700}.bazi-drawer-hidden-table td{border-bottom:1px solid var(--border-subtle);color:var(--text-secondary);padding:5px 8px}.bazi-drawer-hidden-table tr:last-child td{border-bottom:none}.bazi-actions{flex-wrap:wrap;gap:8px;animation:.8s ease-out .4s both bazi-fade-in;display:flex}.action-btn{border-radius:var(--radius);border:1px solid var(--border);background:var(--bg-secondary);color:var(--text-secondary);cursor:pointer;align-items:center;gap:4px;padding:8px 14px;font-size:12px;font-weight:600;transition:background .15s,color .15s,box-shadow .15s;display:inline-flex}.action-btn:hover{background:var(--bg-hover);color:var(--text-primary)}.action-btn--primary{color:#cbdfff;color:color(display-p3 .811259 .873257 .992208);color:lab(88.2011% -1.89927 -18.3428);background:linear-gradient(135deg,#1d4587,#32326d);background:linear-gradient(135deg,color(display-p3 .153533 .2659 .511983),color(display-p3 .195291 .194916 .412031));background:linear-gradient(135deg,lab(29.3399% 5.63866 -42.0206),lab(23.3003% 14.2058 -35.0966));border-color:#33548c;border-color:color(display-p3 .229049 .327581 .533696);border-color:lab(35.4848% 1.84765 -35.3079)}.action-btn--primary:hover{background:linear-gradient(135deg,#2151a1,#3d3c86);background:linear-gradient(135deg,color(display-p3 .180134 .31482 .611657),color(display-p3 .239239 .236673 .50744));background:linear-gradient(135deg,lab(34.9279% 7.15981 -48.9835),lab(28.8006% 17.5515 -42.0715));box-shadow:0 2px 12px rgba(29,69,135,.3);box-shadow:0 2px 12px color(display-p3 .153533 .2659 .511983/.3);box-shadow:0 2px 12px lab(29.3399% 5.63866 -42.0206/.3)}.error-state,.empty-state{text-align:center;flex-direction:column;flex:1;justify-content:center;align-items:center;gap:8px;padding:32px;display:flex}.error-icon,.empty-icon{font-size:32px}.tooltip{z-index:100;border-radius:var(--radius-sm);background:var(--bg-tertiary);border:1px solid var(--border);color:var(--text-primary);pointer-events:none;opacity:0;max-width:200px;padding:6px 10px;font-size:11px;transition:opacity .15s;position:fixed}.tooltip.visible{opacity:1}@media (max-width:360px){.bazi-stem-chinese{font-size:22px}.bazi-branch-animal-emoji{font-size:18px}.bazi-hidden-char{font-size:13px}.bazi-pillar-header{padding:4px 6px;font-size:9px}#bazi-container{gap:10px;padding:10px}.bazi-pillars{gap:4px}}.chart-layer{opacity:0;transform-origin:310px 310px;will-change:opacity, transform;transform:scale(.98)translateZ(0)}#chart-container.chart-visible .chart-layer{animation:.6s cubic-bezier(.16,1,.3,1) forwards svgLayerAssemble;animation-delay:calc(var(--layer-index,1) * .1s + .1s)}@keyframes svgLayerAssemble{0%{opacity:0;transform:scale(.97)}to{opacity:1;transform:scale(1)}}.floating-action-btn:after{content:"";background:linear-gradient(90deg,transparent,rgba(255,255,255,.2),transparent);width:50%;height:100%;animation:3s 2s infinite shimmer;position:absolute;top:0;left:-100%;transform:skew(-20deg)}@keyframes shimmer{0%{left:-100%}20%{left:200%}to{left:200%}}@keyframes slideUpFadeIn{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}@keyframes slideUpFadeInPanel{0%{opacity:0;transform:translateY(12px)scale(.98)}to{opacity:1;transform:translateY(0)scale(1)}}
10
+ <style>*,:before,:after{box-sizing:border-box;margin:0;padding:0}:root{--bg-primary:#090b0f;--bg-secondary:#12161d;--bg-tertiary:#1c222b;--bg-hover:#272e3b;--border:#282e38;--border-subtle:#1d2229;--text-primary:#e1e5eb;--text-secondary:#9da5b1;--text-muted:#6c727b;--accent:#62b3ff;--accent-warm:#e6ac3d;--radius:8px;--radius-sm:4px;--radius-lg:12px;--wuxing-wood:#31aa40;--wuxing-fire:#f14d4c;--wuxing-earth:#ca8a10;--wuxing-metal:#9fafc8;--wuxing-water:#0099e0;--wuxing-wood-bg:#1b451e;--wuxing-fire-bg:#65201e;--wuxing-earth-bg:#583c10;--wuxing-metal-bg:#3c434d;--wuxing-water-bg:#003f60;--dm-border:#d29922;--dm-bg:#201a10;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}@supports (color:color(display-p3 0 0 0)){:root{--bg-primary:color(display-p3 .036047 .0438664 .059078);--bg-secondary:color(display-p3 .0739679 .0866504 .111186);--bg-tertiary:color(display-p3 .114361 .13221 .166818);--bg-hover:color(display-p3 .15679 .180114 .225406);--border:color(display-p3 .161376 .180145 .216325);--border-subtle:color(display-p3 .118728 .13221 .158123);--text-primary:color(display-p3 .883958 .896627 .920543);--text-secondary:color(display-p3 .622745 .646433 .6914);--text-muted:color(display-p3 .429297 .445909 .477439);--accent:color(display-p3 .446063 .694439 1.01077);--accent-warm:color(display-p3 .866978 .684443 .324483);--wuxing-wood:color(display-p3 .343741 .657851 .307102);--wuxing-fire:color(display-p3 .872583 .352089 .325751);--wuxing-earth:color(display-p3 .754604 .550516 .200367);--wuxing-metal:color(display-p3 .636614 .68404 .77495);--wuxing-water:color(display-p3 .226818 .589506 .875825);--wuxing-wood-bg:color(display-p3 .150499 .267148 .135899);--wuxing-fire-bg:color(display-p3 .36387 .143128 .129405);--wuxing-earth-bg:color(display-p3 .328547 .240912 .0972974);--wuxing-metal-bg:color(display-p3 .240898 .260909 .299258);--wuxing-water-bg:color(display-p3 .0921333 .242221 .364185);--dm-border:color(display-p3 .789908 .60997 .245434);--dm-bg:color(display-p3 .119765 .101379 .0671137)}}@supports (color:lab(0% 0 0)){:root{--bg-primary:lab(3.02674% -.179462 -2.15476);--bg-secondary:lab(7.16596% -.441141 -5.41423);--bg-tertiary:lab(12.9118% -.60384 -7.27841);--bg-hover:lab(18.6882% -.727877 -9.08878);--border:lab(18.7165% -.689313 -7.30941);--border-subtle:lab(12.9391% -.548743 -5.49436);--text-primary:lab(90.6878% -.517368 -3.73452);--text-secondary:lab(67.45% -.932217 -7.41489);--text-muted:lab(47.7476% -.701487 -5.56231);--accent:lab(70.4043% -7.21234 -50.7672);--accent-warm:lab(74.5248% 14.3487 62.5064);--wuxing-wood:lab(61.5358% -50.6384 43.17);--wuxing-fire:lab(57.3944% 63.124 38.0626);--wuxing-earth:lab(62.7263% 19.0613 64.9727);--wuxing-metal:lab(70.8424% -1.5474 -14.6858);--wuxing-water:lab(59.1191% -14.8305 -49.6808);--wuxing-wood-bg:lab(25.5679% -22.4482 18.6532);--wuxing-fire-bg:lab(23.6033% 31.5073 18.7032);--wuxing-earth-bg:lab(28.0231% 9.19801 30.8603);--wuxing-metal-bg:lab(28.0014% -.778109 -7.34471);--wuxing-water-bg:lab(24.4811% -7.8918 -24.9024);--dm-border:lab(67.5362% 14.8294 64.5914);--dm-bg:lab(9.55197% 1.60985 7.31485)}}@media (prefers-color-scheme:light){:root{--bg-primary:#f3f5f9;--bg-secondary:#e7ebf2;--bg-tertiary:#d8dee8;--bg-hover:#d0d8e5;--border:#bdc5d1;--border-subtle:#d2d8e2;--text-primary:#0f1216;--text-secondary:#414853;--text-muted:#6c727b;--accent:#0065b2;--accent-warm:#966800;--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light;--wuxing-wood:#005f0e;--wuxing-fire:#a20519;--wuxing-earth:#805300;--wuxing-metal:#48566c;--wuxing-water:#005380;--wuxing-wood-bg:#c0e3c0;--wuxing-fire-bg:#fdc9c4;--wuxing-earth-bg:#f2daba;--wuxing-metal-bg:#d6dfec;--wuxing-water-bg:#b4defc;--dm-border:#966800;--dm-bg:#f6ede0}@supports (color:color(display-p3 0 0 0)){:root{--bg-primary:color(display-p3 .95471 .961142 .973263);--bg-secondary:color(display-p3 .909797 .922535 .946581);--bg-tertiary:color(display-p3 .852455 .871315 .906983);--bg-hover:color(display-p3 .821139 .84609 .893374);--border:color(display-p3 .745559 .770059 .816515);--border-subtle:color(display-p3 .826933 .845684 .881152);--text-primary:color(display-p3 .0608605 .0691527 .0850621);--text-secondary:color(display-p3 .261513 .281801 .32064);--text-muted:color(display-p3 .429297 .445909 .477439);--accent:color(display-p3 .143802 .388951 .683672);--accent-warm:color(display-p3 .596632 .396992 -.158844);--wuxing-wood:color(display-p3 .0968244 .374385 .0683277);--wuxing-fire:color(display-p3 .580784 .119608 .128804);--wuxing-earth:color(display-p3 .489279 .326588 -.0287041);--wuxing-metal:color(display-p3 .294019 .335238 .415486);--wuxing-water:color(display-p3 -.0775243 .316124 .547443);--wuxing-wood-bg:color(display-p3 .778394 .884493 .76257);--wuxing-fire-bg:color(display-p3 .959986 .795906 .773571);--wuxing-earth-bg:color(display-p3 .93331 .858308 .743829);--wuxing-metal-bg:color(display-p3 .84663 .871726 .919277);--wuxing-water-bg:color(display-p3 .739548 .864306 .975015);--dm-border:color(display-p3 .596632 .396992 -.158844);--dm-bg:color(display-p3 .957692 .931855 .88349)}}@supports (color:lab(0% 0 0)){:root{--bg-primary:lab(96.5044% -.267148 -1.87216);--bg-secondary:lab(93.0079% -.518024 -3.73493);--bg-tertiary:lab(88.3503% -.749856 -5.58736);--bg-hover:lab(86.0117% -.963002 -7.43048);--border:lab(79.0511% -.952899 -7.42528);--border-subtle:lab(86.0302% -.748128 -5.58645);--text-primary:lab(5.23796% -.285208 -3.0582);--text-secondary:lab(30.3224% -.794604 -7.35167);--text-muted:lab(47.7476% -.701487 -5.56231);--accent:lab(41.1205% -1.70796 -50.1423);--accent-warm:lab(47.6194% 20.1868 104.51);--wuxing-wood:lab(34.5429% -45.3762 42.1829);--wuxing-fire:lab(34.3495% 57.1812 37.8813);--wuxing-earth:lab(39.4811% 17.4358 64.8795);--wuxing-metal:lab(36.0172% -1.09252 -14.5181);--wuxing-water:lab(32.2784% -8.65509 -43.065);--wuxing-wood-bg:lab(86.8562% -16.7675 13.1583);--wuxing-fire-bg:lab(85.5193% 18.485 10.0423);--wuxing-earth-bg:lab(88.4503% 4.9783 19.0112);--wuxing-metal-bg:lab(88.3319% -.966102 -7.43206);--wuxing-water-bg:lab(86.1283% -8.87641 -19.3614);--dm-border:lab(47.6194% 20.1868 104.51);--dm-bg:lab(94.2538% 1.22291 7.5882)}}}html,body{background:var(--bg-primary);width:100%;height:100%;color:var(--text-primary);font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Noto Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:13px;line-height:1.5;overflow:hidden}body{flex-direction:column;display:flex}#app{flex-direction:column;flex:1;display:flex;overflow:hidden}#loading-state{color:var(--text-secondary);flex-direction:column;flex:1;justify-content:center;align-items:center;gap:12px;display:flex}#loading-state[hidden]{display:none}.oe-loader{width:48px;height:48px;animation:1.2s linear infinite spin}.oe-loader circle{fill:none;stroke:var(--accent);stroke-width:3px;stroke-dasharray:200;stroke-dashoffset:80px;stroke-linecap:round}@keyframes spin{to{transform:rotate(360deg)}}.chart-status{background:var(--bg-secondary);border-top:1px solid var(--border-subtle);color:var(--text-muted);opacity:0;z-index:50;padding:6px 14px;font-size:11px;transition:opacity .2s,transform .2s;position:fixed;bottom:0;left:0;right:0;transform:translateY(100%)}.chart-status.visible{opacity:1;transform:translateY(0)}#bazi-container{flex-direction:column;flex:1;gap:16px;padding:16px;display:flex;overflow-y:auto}#bazi-container[hidden]{display:none}.bazi-pillars{grid-template-columns:repeat(4,1fr);gap:8px;animation:.6s ease-out bazi-fade-in;display:grid}@keyframes bazi-fade-in{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.bazi-pillar{border:1px solid var(--border-subtle);border-radius:var(--radius);background:var(--bg-secondary);cursor:pointer;flex-direction:column;transition:border-color .15s,box-shadow .15s,transform .15s;display:flex;overflow:hidden}.bazi-pillar:hover{border-color:var(--border);transform:translateY(-1px);box-shadow:0 2px 12px rgba(0,0,0,.1);box-shadow:0 2px 12px color(display-p3 0 0 0/.1);box-shadow:0 2px 12px lab(0% 0 0/.1)}.bazi-pillar--dm{border-color:var(--dm-border);background:var(--dm-bg);box-shadow:inset 3px 0 0 var(--dm-border), inset -3px 0 0 var(--dm-border)}.bazi-pillar--dm:hover{border-color:var(--dm-border);box-shadow:inset 3px 0 0 var(--dm-border), inset -3px 0 0 var(--dm-border), 0 4px 16px rgba(210,153,34,.15)}@supports (color:color(display-p3 0 0 0)){.bazi-pillar--dm:hover{box-shadow:inset 3px 0 0 var(--dm-border), inset -3px 0 0 var(--dm-border), 0 4px 16px color(display-p3 .789908 .60997 .245434/.15)}}@supports (color:lab(0% 0 0)){.bazi-pillar--dm:hover{box-shadow:inset 3px 0 0 var(--dm-border), inset -3px 0 0 var(--dm-border), 0 4px 16px lab(67.5362% 14.8294 64.5914/.15)}}.bazi-pillar-header{text-transform:uppercase;letter-spacing:.08em;color:var(--text-muted);background:var(--bg-tertiary);border-bottom:1px solid var(--border-subtle);justify-content:center;align-items:center;gap:4px;padding:6px 8px;font-size:10px;font-weight:700;display:flex}.bazi-pillar--dm .bazi-pillar-header{color:var(--dm-border)}.dm-badge{background:var(--dm-border);color:#090b0f;color:color(display-p3 .036047 .0438664 .059078);color:lab(3.02674% -.179462 -2.15476);letter-spacing:.04em;border-radius:10px;padding:1px 5px;font-size:9px;font-weight:700}@media (prefers-color-scheme:light){.dm-badge{color:#fcf8f1;color:color(display-p3 .985424 .972455 .948118);color:lab(97.7087% .579864 3.77247)}}.bazi-stem-zone{border-bottom:1px solid var(--border-subtle);flex-direction:column;align-items:center;gap:2px;padding:10px 8px;display:flex}.bazi-stem-chinese{font-size:28px;font-weight:700;line-height:1.1}.bazi-stem-name{color:var(--text-secondary);font-size:11px;font-weight:600}.bazi-stem-element{color:var(--bg-primary);border-radius:10px;padding:1px 6px;font-size:10px;font-weight:500}@media (prefers-color-scheme:light){.bazi-stem-element{color:#fff6f8;color:color(display-p3 .992746 .964982 .972458);color:lab(97.5544% 3.37881 .0330448)}}.bazi-branch-zone{border-bottom:1px solid var(--border-subtle);flex-direction:column;align-items:center;gap:2px;padding:10px 8px;display:flex}.bazi-branch-animal-emoji{font-size:22px;line-height:1.1}.bazi-branch-name{color:var(--text-secondary);font-size:11px;font-weight:600}.bazi-branch-animal{color:var(--text-muted);font-size:10px}.bazi-hidden-zone{flex-direction:column;align-items:center;gap:3px;min-height:48px;padding:6px 8px;display:flex}.bazi-hidden-label{text-transform:uppercase;letter-spacing:.06em;color:var(--text-muted);margin-bottom:1px;font-size:9px;font-weight:600}.bazi-hidden-stems{flex-wrap:wrap;justify-content:center;gap:6px;display:flex}.bazi-hidden-stem{flex-direction:column;align-items:center;gap:1px;display:flex}.bazi-hidden-char{font-size:16px;font-weight:600;line-height:1.1}.bazi-hidden-strength{opacity:.7;border-radius:50%;width:6px;height:6px}.bazi-hidden-strength--main{opacity:1}.bazi-hidden-strength--secondary{opacity:.65}.bazi-hidden-strength--residual{opacity:.35}.bazi-ten-god-tag{background:var(--bg-hover);color:var(--text-secondary);border-radius:10px;padding:1px 5px;font-size:9px;font-weight:600}.bazi-balance{background:var(--bg-secondary);border:1px solid var(--border-subtle);border-radius:var(--radius);flex-direction:column;gap:8px;padding:12px 14px;animation:.8s ease-out .2s both bazi-fade-in;display:flex}.bazi-balance-header{justify-content:space-between;align-items:center;display:flex}.bazi-balance-title{text-transform:uppercase;letter-spacing:.06em;color:var(--text-muted);font-size:11px;font-weight:700}.bazi-balance-strength{background:var(--bg-hover);color:var(--text-secondary);border-radius:10px;padding:2px 8px;font-size:11px;font-weight:600}.bazi-balance-strength--strong{color:var(--wuxing-wood)}.bazi-balance-strength--weak{color:var(--wuxing-fire)}.bazi-bar-container{border-radius:var(--radius-sm);border:1px solid var(--border-subtle);height:28px;display:flex;overflow:hidden}.bazi-bar-segment{min-width:24px;color:var(--text-primary);justify-content:center;align-items:center;font-size:10px;font-weight:700;transition:flex .4s ease-out;display:flex;position:relative;overflow:hidden}.bazi-bar-segment-label{opacity:.8;white-space:nowrap;font-size:9px}.bazi-bar-legend{flex-wrap:wrap;justify-content:center;gap:12px;display:flex}.bazi-legend-item{color:var(--text-secondary);cursor:pointer;align-items:center;gap:4px;font-size:11px;transition:color .15s;display:flex}.bazi-legend-item:hover{color:var(--text-primary)}.bazi-legend-dot{border-radius:50%;flex-shrink:0;width:8px;height:8px}.bazi-legend-pct{font-variant-numeric:tabular-nums;font-weight:700}.bazi-legend-score{color:var(--text-muted);font-size:10px}.bazi-yongshen{border-radius:var(--radius-sm);background:var(--bg-tertiary);border:1px solid var(--border-subtle);color:var(--text-secondary);justify-content:center;align-items:center;gap:6px;padding:6px 12px;font-size:12px;display:flex}.bazi-yongshen-label{color:var(--text-muted);font-weight:500}.bazi-yongshen-value{font-weight:700}.bazi-drawer-overlay{z-index:60;opacity:0;background:rgba(0,0,0,.4);background:color(display-p3 0 0 0/.4);background:lab(0% 0 0/.4);transition:opacity .2s;position:fixed;top:0;bottom:0;left:0;right:0}.bazi-drawer-overlay.visible{opacity:1}.bazi-drawer{background:var(--bg-secondary);border-top:1px solid var(--border);border-radius:var(--radius-lg) var(--radius-lg) 0 0;z-index:61;max-height:60vh;padding:16px;transition:transform .25s ease-out;position:fixed;bottom:0;left:0;right:0;overflow-y:auto;transform:translateY(100%)}.bazi-drawer.visible{transform:translateY(0)}.bazi-drawer-handle{background:var(--border);border-radius:2px;width:36px;height:4px;margin:0 auto 12px}.bazi-drawer-title{align-items:center;gap:8px;margin-bottom:12px;font-size:15px;font-weight:700;display:flex}.bazi-drawer-section{margin-bottom:12px}.bazi-drawer-section-title{text-transform:uppercase;letter-spacing:.06em;color:var(--text-muted);margin-bottom:6px;font-size:10px;font-weight:700}.bazi-drawer-ten-god{background:var(--bg-tertiary);border-radius:var(--radius-sm);align-items:center;gap:10px;margin-bottom:6px;padding:8px 10px;display:flex}.bazi-drawer-tg-chinese{font-size:22px;font-weight:700}.bazi-drawer-tg-info{flex-direction:column;gap:1px;display:flex}.bazi-drawer-tg-name{font-size:13px;font-weight:600}.bazi-drawer-tg-category{color:var(--text-muted);text-transform:capitalize;font-size:11px}.bazi-drawer-hidden-table{border-collapse:collapse;width:100%;font-size:12px}.bazi-drawer-hidden-table th{text-transform:uppercase;letter-spacing:.04em;color:var(--text-muted);text-align:left;border-bottom:1px solid var(--border-subtle);padding:4px 8px;font-size:10px;font-weight:700}.bazi-drawer-hidden-table td{border-bottom:1px solid var(--border-subtle);color:var(--text-secondary);padding:5px 8px}.bazi-drawer-hidden-table tr:last-child td{border-bottom:none}.bazi-actions{flex-wrap:wrap;gap:8px;animation:.8s ease-out .4s both bazi-fade-in;display:flex}.action-btn{border-radius:var(--radius);border:1px solid var(--border);background:var(--bg-secondary);color:var(--text-secondary);cursor:pointer;align-items:center;gap:4px;padding:8px 14px;font-size:12px;font-weight:600;transition:background .15s,color .15s,box-shadow .15s;display:inline-flex}.action-btn:hover{background:var(--bg-hover);color:var(--text-primary)}.action-btn--primary{color:#cbdfff;color:color(display-p3 .811259 .873257 .992208);color:lab(88.2011% -1.89927 -18.3428);background:linear-gradient(135deg,#1d4587,#32326d);background:linear-gradient(135deg,color(display-p3 .153533 .2659 .511983),color(display-p3 .195291 .194916 .412031));background:linear-gradient(135deg,lab(29.3399% 5.63866 -42.0206),lab(23.3003% 14.2058 -35.0966));border-color:#33548c;border-color:color(display-p3 .229049 .327581 .533696);border-color:lab(35.4848% 1.84765 -35.3079)}.action-btn--primary:hover{background:linear-gradient(135deg,#2151a1,#3d3c86);background:linear-gradient(135deg,color(display-p3 .180134 .31482 .611657),color(display-p3 .239239 .236673 .50744));background:linear-gradient(135deg,lab(34.9279% 7.15981 -48.9835),lab(28.8006% 17.5515 -42.0715));box-shadow:0 2px 12px rgba(29,69,135,.3);box-shadow:0 2px 12px color(display-p3 .153533 .2659 .511983/.3);box-shadow:0 2px 12px lab(29.3399% 5.63866 -42.0206/.3)}.error-state,.empty-state{text-align:center;flex-direction:column;flex:1;justify-content:center;align-items:center;gap:8px;padding:32px;display:flex}.error-icon,.empty-icon{font-size:32px}.tooltip{z-index:100;border-radius:var(--radius-sm);background:var(--bg-tertiary);border:1px solid var(--border);color:var(--text-primary);pointer-events:none;opacity:0;max-width:200px;padding:6px 10px;font-size:11px;transition:opacity .15s;position:fixed}.tooltip.visible{opacity:1}@media (max-width:360px){.bazi-stem-chinese{font-size:22px}.bazi-branch-animal-emoji{font-size:18px}.bazi-hidden-char{font-size:13px}.bazi-pillar-header{padding:4px 6px;font-size:9px}#bazi-container{gap:10px;padding:10px}.bazi-pillars{gap:4px}}.chart-layer{opacity:1;transform-origin:310px 310px;animation:.5s cubic-bezier(.16,1,.3,1) both svgLayerAssemble;animation-delay:calc(var(--layer-index,0) * 80ms);transform:scale(1)}@keyframes svgLayerAssemble{0%{opacity:0;transform:scale(.97)}to{opacity:1;transform:scale(1)}}.floating-action-btn:after{content:"";background:linear-gradient(90deg,transparent,rgba(255,255,255,.2),transparent);width:50%;height:100%;animation:3s 2s infinite shimmer;position:absolute;top:0;left:-100%;transform:skew(-20deg)}@keyframes shimmer{0%{left:-100%}20%{left:200%}to{left:200%}}@keyframes slideUpFadeIn{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}@keyframes slideUpFadeInPanel{0%{opacity:0;transform:translateY(12px)scale(.98)}to{opacity:1;transform:translateY(0)scale(1)}}
11
11
  /*$vite$:1*/</style>
12
12
  </head>
13
13
  <body>