@openephemeris/mcp-server 4.5.0 → 4.7.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.
@@ -2,10 +2,18 @@ import { registerTool, validateRequired, validateCoordinates } from "../index.js
2
2
  import { getActiveClient } from "../../backend/client.js";
3
3
  import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
4
4
  import { DATETIME_DESC, TIMEZONE_PROPERTY, assertZonedDatetime, toDateTimeInputBody } from "../datetime.js";
5
- function buildSubject(name, datetime, lat, lon) {
5
+ // `field`/`timezoneField` name the caller's own argument path (e.g.
6
+ // "subjects[2].datetime") so a zone-less value is rejected with a message
7
+ // that points at the offending subject rather than the batch as a whole.
8
+ //
9
+ // birth_datetime MUST go through toDateTimeInputBody: a naive clock time plus
10
+ // a sibling `timezone` is a valid input shape, and dropping the zone here
11
+ // turns it into an ambiguous datetime the Go contract rejects per-subject —
12
+ // which is what this tool used to do to every subject in the batch.
13
+ function buildSubject(name, datetime, lat, lon, timezone, field = "datetime", timezoneField = "timezone") {
6
14
  return {
7
15
  name,
8
- birth_datetime: { iso: datetime },
16
+ birth_datetime: toDateTimeInputBody(field, datetime, timezone, timezoneField),
9
17
  birth_location: {
10
18
  latitude: { decimal: lat },
11
19
  longitude: { decimal: lon },
@@ -52,8 +60,8 @@ registerTool({
52
60
  handler: async (args) => {
53
61
  validateRequired(args, ["subjects"]);
54
62
  args.subjects.forEach((s, i) => assertZonedDatetime(`subjects[${i}].datetime`, s?.datetime, s?.timezone, `subjects[${i}].timezone`));
55
- const items = args.subjects.map((s) => ({
56
- subject: buildSubject(s.name, s.datetime, s.latitude, s.longitude),
63
+ const items = args.subjects.map((s, i) => ({
64
+ subject: buildSubject(s.name, s.datetime, s.latitude, s.longitude, s?.timezone, `subjects[${i}].datetime`, `subjects[${i}].timezone`),
57
65
  }));
58
66
  return await getActiveClient().post("/ephemeris/natal/batch", { items });
59
67
  },
@@ -1,7 +1,8 @@
1
1
  import { registerTool, validateRequired, pickEnum } from "../index.js";
2
2
  import { getActiveClient } from "../../backend/client.js";
3
3
  import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
4
- import { DATETIME_DESC, TIMEZONE_PROPERTY, localToUtcIso } from "../datetime.js";
4
+ import { DATETIME_DESC, TIMEZONE_PROPERTY } from "../datetime.js";
5
+ import { localToUtcIsoHistorical } from "../datetime-historical.js";
5
6
  registerTool({
6
7
  name: "human_design_bodygraph",
7
8
  description: "Generate a Human Design Bodygraph image (SVG) from a birth datetime (UTC). " +
@@ -12,7 +13,7 @@ registerTool({
12
13
  "For a user-facing interactive bodygraph explorer, use explore_human_design instead.\n\n" +
13
14
  "CREDIT COST: 2 credits per call.\n\n" +
14
15
  "EXAMPLE (local birth time + zone): born 15 April 1990 at 14:30 in Chicago:\n" +
15
- " datetime='1990-04-15T14:30:00', timezone='America/Chicago'\n" +
16
+ " datetime='1990-04-15T14:30:00', timezone='America/Chicago', latitude=41.8781, longitude=-87.6298\n" +
16
17
  "EXAMPLE (already in UTC):\n" +
17
18
  " datetime='1990-04-15T19:30:00Z'",
18
19
  inputSchema: {
@@ -24,6 +25,14 @@ registerTool({
24
25
  " Human Design is time-sensitive — accuracy to the minute matters.",
25
26
  },
26
27
  timezone: TIMEZONE_PROPERTY,
28
+ latitude: {
29
+ type: "number",
30
+ description: "Optional birth latitude in decimal degrees. Only used to apply the historical timezone correction for pre-1970 local birth times (e.g. state-level DST deviations); has no effect on the bodygraph itself.",
31
+ },
32
+ longitude: {
33
+ type: "number",
34
+ description: "Optional birth longitude in decimal degrees. See latitude.",
35
+ },
27
36
  style: {
28
37
  type: "string",
29
38
  enum: ["light", "dark", "mono"],
@@ -44,7 +53,7 @@ registerTool({
44
53
  handler: async (args) => {
45
54
  validateRequired(args, ["datetime"]);
46
55
  const body = {
47
- birth_datetime_utc: localToUtcIso("datetime", args.datetime, args.timezone),
56
+ birth_datetime_utc: await localToUtcIsoHistorical("datetime", args.datetime, args.timezone, { latitude: args.latitude, longitude: args.longitude }),
48
57
  };
49
58
  const format = pickEnum(args.format, ["svg", "png"]) || "svg";
50
59
  const style = pickEnum(args.style, ["light", "dark", "mono"]);
@@ -1,7 +1,21 @@
1
1
  import { registerTool, validateRequired } from "../index.js";
2
2
  import { getActiveClient } from "../../backend/client.js";
3
3
  import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
4
- import { DATETIME_DESC, TIMEZONE_PROPERTY, localToUtcIso } from "../datetime.js";
4
+ import { DATETIME_DESC, TIMEZONE_PROPERTY } from "../datetime.js";
5
+ import { localToUtcIsoHistorical } from "../datetime-historical.js";
6
+ /** Optional birth coordinates, present only to feed the historical timezone
7
+ * correction for pre-1970 naive local birth times — not sent to the Go
8
+ * endpoint, which is non-relocational. */
9
+ const OPTIONAL_BIRTH_COORDS = {
10
+ latitude: {
11
+ type: "number",
12
+ description: "Optional birth latitude in decimal degrees. Only used to apply the historical timezone correction for pre-1970 local birth times; has no other effect.",
13
+ },
14
+ longitude: {
15
+ type: "number",
16
+ description: "Optional birth longitude in decimal degrees. See latitude.",
17
+ },
18
+ };
5
19
  registerTool({
6
20
  name: "hd_planetary_return",
7
21
  description: "Calculate a Human Design planetary return chart — full HD chart " +
@@ -29,6 +43,7 @@ registerTool({
29
43
  description: DATETIME_DESC,
30
44
  },
31
45
  timezone: TIMEZONE_PROPERTY,
46
+ ...OPTIONAL_BIRTH_COORDS,
32
47
  return_year: {
33
48
  type: "integer",
34
49
  description: "Year to find the return near (e.g. 2020 for a Saturn return at ~age 29).",
@@ -49,7 +64,7 @@ registerTool({
49
64
  return await getActiveClient().request("POST", "/human-design/cycles/return", {
50
65
  data: {
51
66
  planet: args.planet,
52
- birth_datetime_utc: localToUtcIso("datetime", args.datetime, args.timezone),
67
+ birth_datetime_utc: await localToUtcIsoHistorical("datetime", args.datetime, args.timezone, { latitude: args.latitude, longitude: args.longitude }),
53
68
  return_year: args.return_year,
54
69
  format: args.format,
55
70
  include_chiron: args.include_chiron,
@@ -82,6 +97,7 @@ registerTool({
82
97
  description: DATETIME_DESC,
83
98
  },
84
99
  timezone: TIMEZONE_PROPERTY,
100
+ ...OPTIONAL_BIRTH_COORDS,
85
101
  target_year: {
86
102
  type: "integer",
87
103
  description: "Year to search for the opposition near.",
@@ -102,7 +118,7 @@ registerTool({
102
118
  return await getActiveClient().request("POST", "/human-design/cycles/opposition", {
103
119
  data: {
104
120
  planet: args.planet,
105
- birth_datetime_utc: localToUtcIso("datetime", args.datetime, args.timezone),
121
+ birth_datetime_utc: await localToUtcIsoHistorical("datetime", args.datetime, args.timezone, { latitude: args.latitude, longitude: args.longitude }),
106
122
  target_year: args.target_year,
107
123
  format: args.format,
108
124
  include_chiron: args.include_chiron,
@@ -1,7 +1,8 @@
1
1
  import { registerTool, validateRequired } from "../index.js";
2
2
  import { getActiveClient } from "../../backend/client.js";
3
3
  import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
4
- import { DATETIME_DESC, localToUtcIso, timezoneProperty } from "../datetime.js";
4
+ import { DATETIME_DESC, timezoneProperty } from "../datetime.js";
5
+ import { localToUtcIsoHistorical } from "../datetime-historical.js";
5
6
  // POST /human-design/composite — OE-027
6
7
  registerTool({
7
8
  name: "human_design_composite",
@@ -21,11 +22,27 @@ registerTool({
21
22
  description: DATETIME_DESC,
22
23
  },
23
24
  person_a_timezone: timezoneProperty("Person A's birth location"),
25
+ person_a_latitude: {
26
+ type: "number",
27
+ description: "Optional Person A birth latitude in decimal degrees. Only used to apply the historical timezone correction for pre-1970 local birth times; has no other effect.",
28
+ },
29
+ person_a_longitude: {
30
+ type: "number",
31
+ description: "Optional Person A birth longitude in decimal degrees. See person_a_latitude.",
32
+ },
24
33
  person_b_datetime: {
25
34
  type: "string",
26
35
  description: DATETIME_DESC,
27
36
  },
28
37
  person_b_timezone: timezoneProperty("Person B's birth location", "America/Los_Angeles"),
38
+ person_b_latitude: {
39
+ type: "number",
40
+ description: "Optional Person B birth latitude in decimal degrees. See person_a_latitude.",
41
+ },
42
+ person_b_longitude: {
43
+ type: "number",
44
+ description: "Optional Person B birth longitude in decimal degrees.",
45
+ },
29
46
  format: {
30
47
  type: "string",
31
48
  enum: ["json", "llm"],
@@ -41,10 +58,10 @@ registerTool({
41
58
  validateRequired(args, ["person_a_datetime", "person_b_datetime"]);
42
59
  const body = {
43
60
  subject_1: {
44
- birth_datetime_utc: localToUtcIso("person_a_datetime", args.person_a_datetime, args.person_a_timezone, "person_a_timezone"),
61
+ birth_datetime_utc: await localToUtcIsoHistorical("person_a_datetime", args.person_a_datetime, args.person_a_timezone, { latitude: args.person_a_latitude, longitude: args.person_a_longitude }, "person_a_timezone"),
45
62
  },
46
63
  subject_2: {
47
- birth_datetime_utc: localToUtcIso("person_b_datetime", args.person_b_datetime, args.person_b_timezone, "person_b_timezone"),
64
+ birth_datetime_utc: await localToUtcIsoHistorical("person_b_datetime", args.person_b_datetime, args.person_b_timezone, { latitude: args.person_b_latitude, longitude: args.person_b_longitude }, "person_b_timezone"),
48
65
  },
49
66
  };
50
67
  if (args.format)
@@ -81,6 +98,14 @@ registerTool({
81
98
  name: { type: "string", description: "Member's name." },
82
99
  datetime: { type: "string", description: DATETIME_DESC },
83
100
  timezone: timezoneProperty("this member's birth location"),
101
+ latitude: {
102
+ type: "number",
103
+ description: "Optional birth latitude in decimal degrees. Only used to apply the historical timezone correction for pre-1970 local birth times; has no other effect.",
104
+ },
105
+ longitude: {
106
+ type: "number",
107
+ description: "Optional birth longitude in decimal degrees. See latitude.",
108
+ },
84
109
  },
85
110
  required: ["id", "name", "datetime"],
86
111
  },
@@ -101,13 +126,13 @@ registerTool({
101
126
  annotations: { title: "HD Penta Group Chart", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
102
127
  handler: async (args) => {
103
128
  validateRequired(args, ["group_name", "members"]);
104
- const members = args.members.map((m, i) => ({
129
+ const members = await Promise.all(args.members.map(async (m, i) => ({
105
130
  id: m.id,
106
131
  name: m.name,
107
132
  birth_data: {
108
- birth_datetime_utc: localToUtcIso(`members[${i}].datetime`, m.datetime, m.timezone, `members[${i}].timezone`),
133
+ birth_datetime_utc: await localToUtcIsoHistorical(`members[${i}].datetime`, m.datetime, m.timezone, { latitude: m.latitude, longitude: m.longitude }, `members[${i}].timezone`),
109
134
  },
110
- }));
135
+ })));
111
136
  const body = {
112
137
  group_name: args.group_name,
113
138
  members,
@@ -1,7 +1,8 @@
1
1
  import { registerTool, validateRequired } from "../index.js";
2
2
  import { getActiveClient } from "../../backend/client.js";
3
3
  import { OUTPUT_SCHEMA_IMAGE_AND_JSON } from "../output-schemas.js";
4
- import { DATETIME_DESC, TIMEZONE_PROPERTY, localToUtcIso } from "../datetime.js";
4
+ import { DATETIME_DESC, TIMEZONE_PROPERTY } from "../datetime.js";
5
+ import { localToUtcIsoHistorical } from "../datetime-historical.js";
5
6
  registerTool({
6
7
  name: "human_design_chart",
7
8
  description: "Calculate a full Human Design I Ching hexagram chart from birth data. Returns the person's Type " +
@@ -65,7 +66,7 @@ registerTool({
65
66
  handler: async (args) => {
66
67
  validateRequired(args, ["datetime"]);
67
68
  const body = {
68
- birth_datetime_utc: localToUtcIso("datetime", args.datetime, args.timezone),
69
+ birth_datetime_utc: await localToUtcIsoHistorical("datetime", args.datetime, args.timezone, { latitude: args.latitude, longitude: args.longitude }),
69
70
  };
70
71
  if (args.latitude != null)
71
72
  body.latitude = args.latitude;
@@ -1,7 +1,8 @@
1
1
  import { registerTool, validateCoordinates } from "../index.js";
2
2
  import { getActiveClient } from "../../backend/client.js";
3
3
  import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
4
- import { TIMEZONE_PROPERTY, localToUtcIso } from "../datetime.js";
4
+ import { TIMEZONE_PROPERTY } from "../datetime.js";
5
+ import { localToUtcIsoHistorical } from "../datetime-historical.js";
5
6
  registerTool({
6
7
  name: "ephemeris_moon_phase",
7
8
  description: "Get the Moon's current phase angle, illumination, sign and void-of-course status AT a " +
@@ -49,7 +50,7 @@ registerTool({
49
50
  // Backend requires datetime even though the schema marks it optional.
50
51
  // Default to current UTC time when caller omits it.
51
52
  params.datetime = args.datetime
52
- ? localToUtcIso("datetime", args.datetime, args.timezone)
53
+ ? await localToUtcIsoHistorical("datetime", args.datetime, args.timezone, { latitude: args.latitude, longitude: args.longitude })
53
54
  : new Date().toISOString();
54
55
  if (args.latitude != null)
55
56
  params.latitude = args.latitude;
@@ -1,7 +1,8 @@
1
1
  import { registerTool, validateRequired, validateCoordinates } from "../index.js";
2
2
  import { getActiveClient } from "../../backend/client.js";
3
3
  import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
4
- import { DATETIME_DESC, TIMEZONE_PROPERTY, localToUtcIso } from "../datetime.js";
4
+ import { DATETIME_DESC, TIMEZONE_PROPERTY } from "../datetime.js";
5
+ import { localToUtcIsoHistorical } from "../datetime-historical.js";
5
6
  registerTool({
6
7
  name: "vedic_chart",
7
8
  description: "Calculate a Vedic (Jyotish) natal chart with sidereal positions. Returns planet placements " +
@@ -42,7 +43,7 @@ registerTool({
42
43
  validateRequired(args, ["datetime", "latitude", "longitude"]);
43
44
  validateCoordinates(args, "latitude", "longitude");
44
45
  const body = {
45
- datetime_utc: localToUtcIso("datetime", args.datetime, args.timezone),
46
+ datetime_utc: await localToUtcIsoHistorical("datetime", args.datetime, args.timezone, { latitude: args.latitude, longitude: args.longitude }),
46
47
  latitude: args.latitude,
47
48
  longitude: args.longitude,
48
49
  };
package/dist/ui/bazi.html CHANGED
@@ -1,35 +1,35 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
3
  <head>
4
- <meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; img-src data:; font-src data:; connect-src 'none'" />
5
- <meta charset="UTF-8" />
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <meta name="color-scheme" content="dark light" />
8
- <!-- CSP is injected at build time by shared/singlefile-plugin.ts (the dev
9
- server needs external src/ references that a strict CSP would block). -->
10
- <title>BaZi Four Pillars Explorer</title>
4
+ <meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; img-src data:; font-src data:; connect-src 'none'" />
5
+ <meta charset="UTF-8" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <meta name="color-scheme" content="dark light" />
8
+ <!-- CSP is injected at build time by shared/singlefile-plugin.ts (the dev
9
+ server needs external src/ references that a strict CSP would block). -->
10
+ <title>BaZi Four Pillars Explorer</title>
11
11
 
12
12
 
13
- <style>:root{--bg:#010102;--surface:#030408;--surface-2:#080b11;--border:#13161d;--border-strong:#242933;--text:#e2e4e9;--text-secondary:#a1a5ab;--muted:#84868b;--gold:#cc9c42;--gold-dim:#7b6540;--gold-glow:rgba(204,156,66,.2);--gold-subtle:rgba(204,156,66,.1);--success:#1da871;--error:#c53443;--radius:10px;--radius-sm:6px;--radius-pill:99px;--shadow-md:0 8px 40px rgba(0,0,0,.65), 0 0 0 1px var(--border-strong);--shadow-gold:0 0 28px rgba(204,156,66,.15), 0 0 0 1px rgba(204,156,66,.2)}@supports (color:color(display-p3 0 0 0)){:root{--bg:color(display-p3 .00306656 .00431968 .00888397);--surface:color(display-p3 .013072 .016989 .0298495);--surface-2:color(display-p3 .0345774 .0431759 .0653236);--border:color(display-p3 .0763929 .0859556 .109705);--border-strong:color(display-p3 .144788 .159634 .196542);--text:color(display-p3 .889546 .895785 .910689);--text-secondary:color(display-p3 .635245 .644982 .668335);--muted:color(display-p3 .518127 .525635 .543633);--gold:color(display-p3 .76996 .617341 .321369);--gold-dim:color(display-p3 .469305 .400291 .270966);--gold-glow:color(display-p3 .76996 .617341 .321369/.2);--gold-subtle:color(display-p3 .76996 .617341 .321369/.1);--success:color(display-p3 .313719 .651039 .459895);--error:color(display-p3 .710345 .252818 .279408);--shadow-md:0 8px 40px color(display-p3 0 0 0/.65), 0 0 0 1px var(--border-strong);--shadow-gold:0 0 28px color(display-p3 .76996 .617341 .321369/.15), 0 0 0 1px color(display-p3 .76996 .617341 .321369/.2)}}@supports (color:lab(0% 0 0)){:root{--bg:lab(.302122% .0219196 -.522962);--surface:lab(1.18159% .0276566 -1.4848);--surface-2:lab(3.00584% .0228807 -3.15676);--border:lab(7.15581% -.0557452 -5.11242);--border-strong:lab(16.3713% -.0768304 -7.37782);--text:lab(90.6942% -.142396 -2.26941);--text-secondary:lab(67.4758% -.215352 -3.76978);--muted:lab(55.8848% -.174642 -3.01716);--gold:lab(67.5798% 11.9379 52.333);--gold-dim:lab(44.394% 5.21129 24.4453);--gold-glow:lab(67.5798% 11.9379 52.333/.2);--gold-subtle:lab(67.5798% 11.9379 52.333/.1);--success:lab(61.2436% -46.7762 18.3644);--error:lab(45.8893% 57.7361 27.393);--shadow-md:0 8px 40px lab(0% 0 0/.65), 0 0 0 1px var(--border-strong);--shadow-gold:0 0 28px lab(67.5798% 11.9379 52.333/.15), 0 0 0 1px lab(67.5798% 11.9379 52.333/.2)}}*,:before,:after{box-sizing:border-box;margin:0;padding:0}[hidden]{display:none!important}html,body{--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark;background:var(--bg);height:100%;color:var(--text);font-family:Geist,Space Grotesk,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Noto Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:13px;line-height:1.5;overflow-x:hidden}#app{flex-direction:column;gap:8px;min-height:0;padding:8px 12px;display:flex}#loading-state{min-height:300px;color:var(--muted);flex-direction:column;justify-content:center;align-items:center;gap:14px;display:flex}#loading-state p{letter-spacing:.06em;text-transform:uppercase;font-size:11px}.oe-loader{width:64px;height:64px;stroke:var(--gold);stroke-width:2px;fill:none;stroke-dasharray:200;stroke-dashoffset:200px;filter:drop-shadow(0 0 4px var(--gold-glow));animation:2.5s cubic-bezier(.16,1,.3,1) infinite oe-draw}@keyframes oe-draw{0%{stroke-dashoffset:200px;stroke-opacity:.1}50%{stroke-dashoffset:0;stroke-opacity:1;filter:drop-shadow(0 0 8px var(--gold))}to{stroke-dashoffset:-200px;stroke-opacity:.1}}#bazi-container{border-radius:var(--radius);border:1px solid var(--border-strong);width:100%;max-width:720px;box-shadow:var(--shadow-gold);background:#010102;background:color(display-p3 .00306656 .00431968 .00888397);background:lab(.302122% .0219196 -.522962);margin:0 auto;transition:box-shadow .3s;position:relative;overflow:visible}#bazi-container:hover{box-shadow:0 0 40px rgba(204,156,66,.22),0 0 0 1px rgba(204,156,66,.3);box-shadow:0 0 40px color(display-p3 .76996 .617341 .321369/.22),0 0 0 1px color(display-p3 .76996 .617341 .321369/.3);box-shadow:0 0 40px lab(67.5798% 11.9379 52.333/.22),0 0 0 1px lab(67.5798% 11.9379 52.333/.3)}#bazi-container svg{width:100%;height:auto;max-height:min(62vh,560px);display:block}.pillar-hit{cursor:pointer;transition:opacity .16s}.pillar-hit:hover{outline:2px solid var(--gold);outline-offset:-2px;fill:rgba(204,156,66,.08)!important;fill:color(display-p3 .76996 .617341 .321369/.08)!important;fill:lab(67.5798% 11.9379 52.333/.08)!important}.pillar-hit:focus-visible{outline:2px solid var(--gold);outline-offset:-2px;fill:rgba(204,156,66,.08)!important;fill:color(display-p3 .76996 .617341 .321369/.08)!important;fill:lab(67.5798% 11.9379 52.333/.08)!important}#info-panel{background:var(--surface);border:1px solid var(--border-strong);border-radius:var(--radius);flex-direction:column;gap:4px;width:100%;max-width:720px;margin:0 auto;padding:10px 14px;display:flex}.info-row{align-items:baseline;gap:8px;display:flex}.info-label{letter-spacing:.08em;text-transform:uppercase;color:var(--muted);font-size:9px;font-weight:700}.info-value{color:var(--gold);font-size:13px;font-weight:600}.info-hint{color:var(--text-secondary);font-size:10px}.error-state{min-height:200px;color:var(--text-secondary);text-align:center;flex-direction:column;justify-content:center;align-items:center;gap:8px;padding:24px;display:flex}.error-icon{opacity:.7;font-size:24px}.error-retry-btn{border:1px solid var(--border-strong);color:var(--text);font:inherit;letter-spacing:.02em;cursor:pointer;background:0 0;border-radius:999px;margin-top:4px;padding:7px 20px;font-size:11px;font-weight:600;transition:background .18s,border-color .18s}.error-retry-btn:hover{background:rgba(204,156,66,.1);background:color(display-p3 .76996 .617341 .321369/.1);background:lab(67.5798% 11.9379 52.333/.1)}.chart-status{-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);border-radius:var(--radius-pill);color:var(--gold);letter-spacing:.04em;z-index:900;opacity:0;pointer-events:none;background:rgba(5,7,13,.92);background:color(display-p3 .0216592 .0280553 .0483601/.92);background:lab(1.95095% .0425801 -2.41514/.92);border:1px solid rgba(204,156,66,.35);border:1px solid color(display-p3 .76996 .617341 .321369/.35);border:1px solid lab(67.5798% 11.9379 52.333/.35);max-height:0;padding:5px 18px;font-size:11px;font-weight:600;transition:max-height .24s cubic-bezier(.16,1,.3,1),opacity .24s,transform .24s cubic-bezier(.16,1,.3,1);position:fixed;top:10px;left:50%;overflow:hidden;transform:translate(-50%)translateY(-10px);box-shadow:0 4px 20px rgba(0,0,0,.5),0 0 0 1px rgba(204,156,66,.08);box-shadow:0 4px 20px color(display-p3 0 0 0/.5),0 0 0 1px color(display-p3 .76996 .617341 .321369/.08);box-shadow:0 4px 20px lab(0% 0 0/.5),0 0 0 1px lab(67.5798% 11.9379 52.333/.08)}.chart-status.visible{opacity:1;max-height:44px;transform:translate(-50%)translateY(0)}.bazi-action-bar{flex-wrap:wrap;gap:8px;width:100%;max-width:720px;margin:0 auto;padding:10px 0 0;display:flex}.action-btn{color:var(--gold);letter-spacing:.02em;cursor:pointer;white-space:nowrap;background:rgba(212,175,55,.08);border:1px solid rgba(212,175,55,.3);border-radius:8px;align-items:center;gap:6px;padding:7px 16px;font-size:12px;font-weight:600;transition:background .2s,border-color .2s,transform .1s;display:inline-flex}.action-btn:hover{background:rgba(212,175,55,.15);border-color:rgba(212,175,55,.5);transform:translateY(-1px)}.action-btn--primary{background:linear-gradient(135deg,rgba(212,175,55,.2),rgba(180,140,30,.25));border-color:rgba(212,175,55,.5)}.pan-zoom-controls{z-index:800;flex-direction:column;gap:6px;display:flex;position:absolute;bottom:12px;right:12px}.pan-zoom-controls[hidden]{display:none!important}.pan-btn{background:var(--surface-2);border:1px solid var(--border-strong);color:var(--text);border-radius:var(--radius-sm);cursor:pointer;width:36px;height:36px;box-shadow:var(--shadow-md);justify-content:center;align-items:center;font-family:inherit;font-size:18px;transition:all .15s;display:flex}.pan-btn.reset{width:auto;padding:0 10px;font-size:11px;font-weight:500}.pan-btn:hover{background:var(--surface);border-color:var(--gold-dim);color:var(--gold)}.pan-btn:active{transform:scale(.95)}.pan-btn--fullscreen{width:36px;height:36px}@media (max-width:480px){.pan-zoom-controls{gap:5px}.pan-btn,.pan-btn--fullscreen{background:color-mix(in oklab, var(--surface-2) 72%, transparent);-webkit-backdrop-filter:blur(6px);width:32px;height:32px;font-size:15px}.pan-btn.reset{width:32px;padding:0;font-size:0}.pan-btn.reset:before{content:"⟲";font-size:15px}}body.is-fullscreen{height:100vh;overflow:hidden}body.is-fullscreen #app{flex-direction:column;gap:0;width:100vw;max-width:100%;height:100vh;padding:0;display:flex;overflow:hidden}body.is-fullscreen #bazi-container{min-height:0;max-width:unset;width:100%;height:auto;box-shadow:none;background:0 0;border:none;flex:1;justify-content:center;align-items:center;margin:0;padding:16px 24px 0;display:flex}body.is-fullscreen #loading-state{flex:1;height:auto;min-height:0}body.is-fullscreen #bazi-container svg{width:auto;max-width:100%;height:100%;max-height:100%}body.is-fullscreen .pan-zoom-controls{top:16px;right:16px}#fs-bottom-bar{border-top:1px solid var(--border);background:#020306;background:color(display-p3 .0100648 .0127997 .0215356);background:lab(.889429% .0122339 -1.01076);flex-shrink:0;grid-template-rows:1fr;grid-template-columns:220px 1fr 220px;height:240px;min-height:180px;max-height:280px;display:grid}#fs-bottom-bar [data-column=left],#fs-bottom-bar [data-column=right]{scrollbar-width:thin;scrollbar-color:var(--border-strong) transparent;flex-direction:column;gap:4px;padding:10px 14px 12px;display:flex;overflow-x:hidden;overflow-y:auto}#fs-bottom-bar [data-column=left]{border-right:1px solid var(--border)}#fs-bottom-bar [data-column=center]{pointer-events:none}#fs-bottom-bar [data-column=right]{border-left:1px solid var(--border);overflow-y:auto}#fs-bottom-bar [data-column]>*+*{border-top:1px solid var(--border);margin-top:4px;padding-top:8px}#fs-bottom-bar .bazi-action-bar{flex-direction:column;padding:8px 0 0}#fs-bottom-bar .action-btn{justify-content:center;width:100%}.cancel-toast{background:var(--surface-2,#1e1e2e);border:1px solid var(--border-strong,#444);color:var(--text-secondary,#aaa);border-radius:var(--radius-sm,6px);opacity:0;z-index:9999;pointer-events:none;box-shadow:var(--shadow-md,0 4px 12px rgba(0,0,0,.3));padding:8px 16px;font-family:inherit;font-size:12px;transition:opacity .3s,transform .3s;position:fixed;bottom:20px;left:50%;transform:translate(-50%)translateY(20px)}.cancel-toast.visible{opacity:1;transform:translate(-50%)translateY(0)}@media (max-width:420px){#app{gap:8px;padding:8px}}:root[data-theme=light]{--bg:#f4f5f8;--surface:#fbfcfe;--surface-2:#eceef3;--border:#d5d7dd;--border-strong:#babec6;--text:#181b1f;--text-secondary:#4a4d54;--muted:#606369;--gold:#8a6000;--gold-dim:#967c4f;--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}@supports (color:color(display-p3 0 0 0)){:root[data-theme=light]{--bg:color(display-p3 .956515 .960735 .970805);--surface:color(display-p3 .98376 .986943 .994535);--surface-2:color(display-p3 .928401 .934691 .949715);--border:color(display-p3 .836244 .844458 .864107);--border-strong:color(display-p3 .731542 .743532 .772301);--text:color(display-p3 .096883 .103987 .12134);--text-secondary:color(display-p3 .291758 .301882 .326359);--muted:color(display-p3 .379924 .388781 .410092);--gold:color(display-p3 .524671 .380491 .0387678);--gold-dim:color(display-p3 .572756 .489268 .332751)}}@supports (color:lab(0% 0 0)){:root[data-theme=light]{--bg:lab(96.503% -.0977516 -1.51461);--surface:lab(98.8273% -.0742972 -1.13657);--surface-2:lab(94.1743% -.142723 -2.26961);--border:lab(86.0453% -.183761 -3.02231);--border-strong:lab(76.7468% -.254452 -4.52154);--text:lab(9.4703% -.11944 -3.722);--text-secondary:lab(32.6639% -.205338 -4.49569);--muted:lab(41.9548% -.197008 -3.7598);--gold:lab(44.2758% 13.6718 62.9124);--gold-dim:lab(53.685% 6.10271 28.558)}}:root[data-theme=light] body{--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light;background-image:none}:root[data-theme=light] #bazi-container{border-color:var(--border-strong);background:#fff;background:color(display-p3 1 1 1);background:lab(100% 0 0)}:root[data-theme=light] .chart-status{background:rgba(247,245,241,.92);background:color(display-p3 .967616 .959866 .945308/.92);background:lab(96.5376% .34076 2.2589/.92);border-color:rgba(141,95,0,.35);border-color:color(display-p3 .542549 .371783 -.107551/.35);border-color:lab(44.1995% 17.0662 84.3373/.35)}:root[data-theme=light] #info-panel{background:var(--surface);border-color:var(--border)}:root[data-theme=light] #fs-bottom-bar{background:#f7f5f1;background:color(display-p3 .967616 .959866 .945308);background:lab(96.5376% .34076 2.2589);border-top-color:#caced4;border-top-color:color(display-p3 .796183 .806346 .830691);border-top-color:lab(82.5562% -.22167 -3.77336)}:root[data-theme=light] #fs-bottom-bar [data-column=left],:root[data-theme=light] #fs-bottom-bar [data-column=right]{background:#f1eeea;background:color(display-p3 .941472 .933762 .919279);background:lab(94.2176% .341028 2.25905)}
13
+ <style>:root{--bg:#010102;--surface:#030408;--surface-2:#080b11;--border:#13161d;--border-strong:#242933;--text:#e2e4e9;--text-secondary:#a1a5ab;--muted:#84868b;--gold:#cc9c42;--gold-dim:#7b6540;--gold-glow:rgba(204,156,66,.2);--gold-subtle:rgba(204,156,66,.1);--success:#1da871;--error:#c53443;--radius:10px;--radius-sm:6px;--radius-pill:99px;--shadow-md:0 8px 40px rgba(0,0,0,.65), 0 0 0 1px var(--border-strong);--shadow-gold:0 0 28px rgba(204,156,66,.15), 0 0 0 1px rgba(204,156,66,.2)}@supports (color:color(display-p3 0 0 0)){:root{--bg:color(display-p3 .00306656 .00431968 .00888397);--surface:color(display-p3 .013072 .016989 .0298495);--surface-2:color(display-p3 .0345774 .0431759 .0653236);--border:color(display-p3 .0763929 .0859556 .109705);--border-strong:color(display-p3 .144788 .159634 .196542);--text:color(display-p3 .889546 .895785 .910689);--text-secondary:color(display-p3 .635245 .644982 .668335);--muted:color(display-p3 .518127 .525635 .543633);--gold:color(display-p3 .76996 .617341 .321369);--gold-dim:color(display-p3 .469305 .400291 .270966);--gold-glow:color(display-p3 .76996 .617341 .321369/.2);--gold-subtle:color(display-p3 .76996 .617341 .321369/.1);--success:color(display-p3 .313719 .651039 .459895);--error:color(display-p3 .710345 .252818 .279408);--shadow-md:0 8px 40px color(display-p3 0 0 0/.65), 0 0 0 1px var(--border-strong);--shadow-gold:0 0 28px color(display-p3 .76996 .617341 .321369/.15), 0 0 0 1px color(display-p3 .76996 .617341 .321369/.2)}}@supports (color:lab(0% 0 0)){:root{--bg:lab(.302122% .0219196 -.522962);--surface:lab(1.18159% .0276566 -1.4848);--surface-2:lab(3.00584% .0228807 -3.15676);--border:lab(7.15581% -.0557452 -5.11242);--border-strong:lab(16.3712% -.0768155 -7.37782);--text:lab(90.6942% -.142366 -2.26941);--text-secondary:lab(67.4758% -.215352 -3.76978);--muted:lab(55.8848% -.174642 -3.01716);--gold:lab(67.5798% 11.9379 52.333);--gold-dim:lab(44.394% 5.21132 24.4453);--gold-glow:lab(67.5798% 11.9379 52.333/.2);--gold-subtle:lab(67.5798% 11.9379 52.333/.1);--success:lab(61.2436% -46.7762 18.3644);--error:lab(45.8893% 57.7361 27.393);--shadow-md:0 8px 40px lab(0% 0 0/.65), 0 0 0 1px var(--border-strong);--shadow-gold:0 0 28px lab(67.5798% 11.9379 52.333/.15), 0 0 0 1px lab(67.5798% 11.9379 52.333/.2)}}*,:before,:after{box-sizing:border-box;margin:0;padding:0}[hidden]{display:none!important}html,body{--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark;background:var(--bg);height:100%;color:var(--text);font-family:Geist,Space Grotesk,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Noto Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:13px;line-height:1.5;overflow-x:hidden}#app{flex-direction:column;gap:8px;min-height:0;padding:8px 12px;display:flex}#loading-state{min-height:300px;color:var(--muted);flex-direction:column;justify-content:center;align-items:center;gap:14px;display:flex}#loading-state p{letter-spacing:.06em;text-transform:uppercase;font-size:11px}.oe-loader{width:64px;height:64px;stroke:var(--gold);stroke-width:2px;fill:none;stroke-dasharray:200;stroke-dashoffset:200px;filter:drop-shadow(0 0 4px var(--gold-glow));animation:2.5s cubic-bezier(.16,1,.3,1) infinite oe-draw}@keyframes oe-draw{0%{stroke-dashoffset:200px;stroke-opacity:.1}50%{stroke-dashoffset:0;stroke-opacity:1;filter:drop-shadow(0 0 8px var(--gold))}to{stroke-dashoffset:-200px;stroke-opacity:.1}}#bazi-container{border-radius:var(--radius);border:1px solid var(--border-strong);width:100%;max-width:720px;box-shadow:var(--shadow-gold);background:#010102;background:color(display-p3 .00306656 .00431968 .00888397);background:lab(.302122% .0219196 -.522962);margin:0 auto;transition:box-shadow .3s;position:relative;overflow:visible}#bazi-container:hover{box-shadow:0 0 40px rgba(204,156,66,.22),0 0 0 1px rgba(204,156,66,.3);box-shadow:0 0 40px color(display-p3 .76996 .617341 .321369/.22),0 0 0 1px color(display-p3 .76996 .617341 .321369/.3);box-shadow:0 0 40px lab(67.5798% 11.9379 52.333/.22),0 0 0 1px lab(67.5798% 11.9379 52.333/.3)}#bazi-container svg{width:100%;height:auto;max-height:min(62vh,560px);display:block}.pillar-hit{cursor:pointer;transition:opacity .16s}.pillar-hit:hover{outline:2px solid var(--gold);outline-offset:-2px;fill:rgba(204,156,66,.08)!important;fill:color(display-p3 .76996 .617341 .321369/.08)!important;fill:lab(67.5798% 11.9379 52.333/.08)!important}.pillar-hit:focus-visible{outline:2px solid var(--gold);outline-offset:-2px;fill:rgba(204,156,66,.08)!important;fill:color(display-p3 .76996 .617341 .321369/.08)!important;fill:lab(67.5798% 11.9379 52.333/.08)!important}#info-panel{background:var(--surface);border:1px solid var(--border-strong);border-radius:var(--radius);flex-direction:column;gap:4px;width:100%;max-width:720px;margin:0 auto;padding:10px 14px;display:flex}.info-row{align-items:baseline;gap:8px;display:flex}.info-label{letter-spacing:.08em;text-transform:uppercase;color:var(--muted);font-size:9px;font-weight:700}.info-value{color:var(--gold);font-size:13px;font-weight:600}.info-hint{color:var(--text-secondary);font-size:10px}.error-state{min-height:200px;color:var(--text-secondary);text-align:center;flex-direction:column;justify-content:center;align-items:center;gap:8px;padding:24px;display:flex}.error-icon{opacity:.7;font-size:24px}.error-retry-btn{border:1px solid var(--border-strong);color:var(--text);font:inherit;letter-spacing:.02em;cursor:pointer;background:0 0;border-radius:999px;margin-top:4px;padding:7px 20px;font-size:11px;font-weight:600;transition:background .18s,border-color .18s}.error-retry-btn:hover{background:rgba(204,156,66,.1);background:color(display-p3 .76996 .617341 .321369/.1);background:lab(67.5798% 11.9379 52.333/.1)}.chart-status{-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);border-radius:var(--radius-pill);color:var(--gold);letter-spacing:.04em;z-index:900;opacity:0;pointer-events:none;background:rgba(5,7,13,.92);background:color(display-p3 .0216592 .0280553 .0483601/.92);background:lab(1.95095% .0425801 -2.41514/.92);border:1px solid rgba(204,156,66,.35);border:1px solid color(display-p3 .76996 .617341 .321369/.35);border:1px solid lab(67.5798% 11.9379 52.333/.35);max-height:0;padding:5px 18px;font-size:11px;font-weight:600;transition:max-height .24s cubic-bezier(.16,1,.3,1),opacity .24s,transform .24s cubic-bezier(.16,1,.3,1);position:fixed;top:10px;left:50%;overflow:hidden;transform:translate(-50%)translateY(-10px);box-shadow:0 4px 20px rgba(0,0,0,.5),0 0 0 1px rgba(204,156,66,.08);box-shadow:0 4px 20px color(display-p3 0 0 0/.5),0 0 0 1px color(display-p3 .76996 .617341 .321369/.08);box-shadow:0 4px 20px lab(0% 0 0/.5),0 0 0 1px lab(67.5798% 11.9379 52.333/.08)}.chart-status.visible{opacity:1;max-height:44px;transform:translate(-50%)translateY(0)}.bazi-action-bar{flex-wrap:wrap;gap:8px;width:100%;max-width:720px;margin:0 auto;padding:10px 0 0;display:flex}.action-btn{color:var(--gold);letter-spacing:.02em;cursor:pointer;white-space:nowrap;background:rgba(212,175,55,.08);border:1px solid rgba(212,175,55,.3);border-radius:8px;align-items:center;gap:6px;padding:7px 16px;font-size:12px;font-weight:600;transition:background .2s,border-color .2s,transform .1s;display:inline-flex}.action-btn:hover{background:rgba(212,175,55,.15);border-color:rgba(212,175,55,.5);transform:translateY(-1px)}.action-btn--primary{background:linear-gradient(135deg,rgba(212,175,55,.2),rgba(180,140,30,.25));border-color:rgba(212,175,55,.5)}.pan-zoom-controls{z-index:800;flex-direction:column;gap:6px;display:flex;position:absolute;bottom:12px;right:12px}.pan-zoom-controls[hidden]{display:none!important}.pan-btn{background:var(--surface-2);border:1px solid var(--border-strong);color:var(--text);border-radius:var(--radius-sm);cursor:pointer;width:36px;height:36px;box-shadow:var(--shadow-md);justify-content:center;align-items:center;font-family:inherit;font-size:18px;transition:all .15s;display:flex}.pan-btn.reset{width:auto;padding:0 10px;font-size:11px;font-weight:500}.pan-btn:hover{background:var(--surface);border-color:var(--gold-dim);color:var(--gold)}.pan-btn:active{transform:scale(.95)}.pan-btn--fullscreen{width:36px;height:36px}@media (max-width:480px){.pan-zoom-controls{gap:5px}.pan-btn,.pan-btn--fullscreen{background:color-mix(in oklab, var(--surface-2) 72%, transparent);-webkit-backdrop-filter:blur(6px);width:32px;height:32px;font-size:15px}.pan-btn.reset{width:32px;padding:0;font-size:0}.pan-btn.reset:before{content:"⟲";font-size:15px}}body.is-fullscreen{height:100vh;overflow:hidden}body.is-fullscreen #app{flex-direction:column;gap:0;width:100vw;max-width:100%;height:100vh;padding:0;display:flex;overflow:hidden}body.is-fullscreen #bazi-container{min-height:0;max-width:unset;width:100%;height:auto;box-shadow:none;background:0 0;border:none;flex:1;justify-content:center;align-items:center;margin:0;padding:16px 24px 0;display:flex}body.is-fullscreen #loading-state{flex:1;height:auto;min-height:0}body.is-fullscreen #bazi-container svg{width:auto;max-width:100%;height:100%;max-height:100%}body.is-fullscreen .pan-zoom-controls{top:16px;right:16px}#fs-bottom-bar{border-top:1px solid var(--border);background:#020306;background:color(display-p3 .0100648 .0127997 .0215356);background:lab(.889429% .0122339 -1.01076);flex-shrink:0;grid-template-rows:1fr;grid-template-columns:220px 1fr 220px;height:240px;min-height:180px;max-height:280px;display:grid}#fs-bottom-bar [data-column=left],#fs-bottom-bar [data-column=right]{scrollbar-width:thin;scrollbar-color:var(--border-strong) transparent;flex-direction:column;gap:4px;padding:10px 14px 12px;display:flex;overflow-x:hidden;overflow-y:auto}#fs-bottom-bar [data-column=left]{border-right:1px solid var(--border)}#fs-bottom-bar [data-column=center]{pointer-events:none}#fs-bottom-bar [data-column=right]{border-left:1px solid var(--border);overflow-y:auto}#fs-bottom-bar [data-column]>*+*{border-top:1px solid var(--border);margin-top:4px;padding-top:8px}#fs-bottom-bar .bazi-action-bar{flex-direction:column;padding:8px 0 0}#fs-bottom-bar .action-btn{justify-content:center;width:100%}.cancel-toast{background:var(--surface-2,#1e1e2e);border:1px solid var(--border-strong,#444);color:var(--text-secondary,#aaa);border-radius:var(--radius-sm,6px);opacity:0;z-index:9999;pointer-events:none;box-shadow:var(--shadow-md,0 4px 12px rgba(0,0,0,.3));padding:8px 16px;font-family:inherit;font-size:12px;transition:opacity .3s,transform .3s;position:fixed;bottom:20px;left:50%;transform:translate(-50%)translateY(20px)}.cancel-toast.visible{opacity:1;transform:translate(-50%)translateY(0)}@media (max-width:420px){#app{gap:8px;padding:8px}}:root[data-theme=light]{--bg:#f4f5f8;--surface:#fbfcfe;--surface-2:#eceef3;--border:#d5d7dd;--border-strong:#babec6;--text:#181b1f;--text-secondary:#4a4d54;--muted:#606369;--gold:#8a6000;--gold-dim:#967c4f;--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}@supports (color:color(display-p3 0 0 0)){:root[data-theme=light]{--bg:color(display-p3 .956515 .960735 .970805);--surface:color(display-p3 .98376 .986943 .994535);--surface-2:color(display-p3 .928401 .934691 .949715);--border:color(display-p3 .836244 .844458 .864107);--border-strong:color(display-p3 .731542 .743532 .772301);--text:color(display-p3 .096883 .103987 .12134);--text-secondary:color(display-p3 .291758 .301882 .326359);--muted:color(display-p3 .379924 .388781 .410092);--gold:color(display-p3 .524671 .380491 .0387678);--gold-dim:color(display-p3 .572756 .489268 .332751)}}@supports (color:lab(0% 0 0)){:root[data-theme=light]{--bg:lab(96.503% -.0977516 -1.51461);--surface:lab(98.8273% -.0742674 -1.13657);--surface-2:lab(94.1743% -.142753 -2.26963);--border:lab(86.0453% -.183702 -3.02233);--border-strong:lab(76.7468% -.254452 -4.52154);--text:lab(9.4703% -.119448 -3.722);--text-secondary:lab(32.6639% -.205323 -4.4957);--muted:lab(41.9548% -.197023 -3.7598);--gold:lab(44.2758% 13.6718 62.9124);--gold-dim:lab(53.685% 6.10271 28.558)}}:root[data-theme=light] body{--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light;background-image:none}:root[data-theme=light] #bazi-container{border-color:var(--border-strong);background:#fff;background:color(display-p3 1 1 1);background:lab(100% 0 0)}:root[data-theme=light] .chart-status{background:rgba(247,245,241,.92);background:color(display-p3 .967616 .959866 .945308/.92);background:lab(96.5376% .34079 2.2589/.92);border-color:rgba(141,95,0,.35);border-color:color(display-p3 .542549 .371783 -.107551/.35);border-color:lab(44.1995% 17.0662 84.3373/.35)}:root[data-theme=light] #info-panel{background:var(--surface);border-color:var(--border)}:root[data-theme=light] #fs-bottom-bar{background:#f7f5f1;background:color(display-p3 .967616 .959866 .945308);background:lab(96.5376% .34079 2.2589);border-top-color:#caced4;border-top-color:color(display-p3 .796183 .806346 .830691);border-top-color:lab(82.5562% -.22167 -3.77336)}:root[data-theme=light] #fs-bottom-bar [data-column=left],:root[data-theme=light] #fs-bottom-bar [data-column=right]{background:#f1eeea;background:color(display-p3 .941472 .933762 .919279);background:lab(94.2176% .341028 2.25905)}
14
14
  /*$vite$:1*/</style>
15
- </head>
16
- <body>
17
- <div id="app">
18
- <div id="loading-state">
19
- <svg class="oe-loader" viewBox="0 0 100 100"><circle cx="50" cy="50" r="45"/></svg>
20
- <p>Casting your Four Pillars…</p>
21
- </div>
22
- <div id="chart-status" class="chart-status" aria-live="polite"></div>
23
- <div id="bazi-container" hidden>
24
- <div id="pan-zoom-controls" class="pan-zoom-controls" hidden>
25
- <button id="btn-zoom-in" class="pan-btn" aria-label="Zoom in">+</button>
26
- <button id="btn-zoom-out" class="pan-btn" aria-label="Zoom out">-</button>
27
- <button id="btn-reset-view" class="pan-btn reset" aria-label="Reset view">⟲ Reset</button>
28
- </div>
29
- </div>
30
- <div id="info-panel" hidden></div>
31
- </div>
32
-
15
+ </head>
16
+ <body>
17
+ <div id="app">
18
+ <div id="loading-state">
19
+ <svg class="oe-loader" viewBox="0 0 100 100"><circle cx="50" cy="50" r="45"/></svg>
20
+ <p>Casting your Four Pillars…</p>
21
+ </div>
22
+ <div id="chart-status" class="chart-status" aria-live="polite"></div>
23
+ <div id="bazi-container" hidden>
24
+ <div id="pan-zoom-controls" class="pan-zoom-controls" hidden>
25
+ <button id="btn-zoom-in" class="pan-btn" aria-label="Zoom in">+</button>
26
+ <button id="btn-zoom-out" class="pan-btn" aria-label="Zoom out">-</button>
27
+ <button id="btn-reset-view" class="pan-btn reset" aria-label="Reset view">⟲ Reset</button>
28
+ </div>
29
+ </div>
30
+ <div id="info-panel" hidden></div>
31
+ </div>
32
+
33
33
  <script type="module">var e = Object.defineProperty, t = (t2, n2) => {
34
34
  let r2 = {};
35
35
  for (var i2 in t2) e(r2, i2, { get: t2[i2], enumerable: true });
@@ -6938,5 +6938,5 @@ P_.ontoolresult = (e4) => {
6938
6938
  }
6939
6939
  })();
6940
6940
  </script>
6941
- </body>
6942
- </html>
6941
+ </body>
6942
+ </html>