Files
digital-psychology/shuzi.html
T

643 lines
48 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-LVVXH3TL04"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-LVVXH3TL04');
</script>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>愈心谷数字解构</title>
<style>
@font-face { font-family:'TriangleDigits'; src:url(data:font/woff2;base64,d09GMgABAAAAAAUAAA4AAAAACHwAAASsAAIZmQAAAAAAAAAAAAAAAAAAAAAAAAAAGhYbbBxIBmAANBEQCocshhEBNgIkAxoLGAAEIAWDIgcgG9QGKC4G7Ib6hm2MRajDYhGiDhrol2EQYF1VSXrYswJPkJb83g+eA7l2QeKDmZzBKY+S2Y6GNNvdREZSoL/sv5IIQxUu06If+FX4/z+X49/WsztrTAw5kRt099ubOm5NXEAFHuBcGvAGSjDAgLDn2bZk6fIVBBISV5n1GLNAADYApcVbCydXozYtkTdtbu8OvEOS0PEgPgIdEQfiY0OwiSCOBmAPsl4AYswwdCJQA1FoSBQqZkProGuMIFPAPhuoa8oSVYX8YAQSAZpDCmDZcIkm/ZAjI0LR3A1KzY56XmlDxUYMYNhtcBARzR51kKE7KkxKozJobFeXdNJlKY3czMCYMrUMa/83F2mmEHEHkFJnDXn9YBwBCSjAHYUA3NEIBjQ0BFDLHki2t3+KqVZYkbggAFQ26ho8RWcQ3tl/htql/UbHN70BAoXUbXpAnK4F+eoWL5vNxzpnKT0L1CrUld9zyZWVebLzdRVOGASMYohloBiiuziLHrm5uQI5VmbV7EqrcnVlszArq2tWV6c5C0+s7O5L1+3WqS7Q2737TCeTufqRH9o1O3uOtCpHMUc36sxupMOcNaesYEbpnGdwwlHmrs8VKBTmstgNaLvfBrx5PQ/wj1yzJd01+3LOm+/CzOY4zhHWtXYr5PbIyREYwJnHeFm4pXu2IcxByHzZVWJ3Er3bMQkX9snibM6Y1aTyc3rkXNUJPXpz8SR3SFeH84FFWYV9bzibJvHlL0bRde6KYc9cmiIKk5+FN+NThqtvc8aBGfnF6WzIqLk1ON06sNXy3bLFuIJ8DQT/QGhPY9JrsRk3RddPID33rzz9cLGnXZjvNNQR4659v7m7f0qW1qex/MqwciHDfdsqBnOLCispr6nWU0/DmAXZBdjkTA0M/4LXawb7VDhbjduWNPaWsM25jxyH1ENRUmejPPOk33dOKZ+v4BRLNZQeriawC/Nzxb0nr7/lPdzfGvGf3kgW0N6/tXYq1Si9RA/v58kV3DTY5DgaxwV1Uw5++lzxouLrgNYX82rdHtlWXSn61Di0UAxfhc2HeamcDnfrnVra3xecFNc61xtZhSxqUlFZFQ62rTQ+w3YS4S9Z4bNHHUB7y/fxoxt9pVAyqdOZ66cPKs7Oz8sYj5f2lIpvQPQfX3t4++1V80/rnFtRkIspHBjC5WXnpReTvuTiMVkJsZFp5SVhxARkdDKQhx19XV78vjqr1UAXlvCfnhUiz41CK/6P8dI6eIab2nlH17ap48+X3P/67iJUpWdlq6vNFAQABCB9dmU3fPxwgFPdb2YhMwAvzT++ByhOmZz+3/9vizVMBYAZOVthCvnfDK9OI6rfpSMQ1O8ljbVAg/Zm6S2UNDN4K6A9UySALjrjrgTjPKoUNdG7bdIswFkQgyCYswaJI28NikwKujXQYMBXOC8yEihiaSpGlAKsZbII4YSJENhVwgyBgJQEXSDaUphohpCxTCWZFJKhBY+AiHgRfBMjhobUGOI+OYREilhp4gmpjs63SFuCvHUricIo0nYoVERiSqyLCF+MnFdHwYlnbI0JjLBYonBsPGESCHYCTx5NXJ+7DhJpNTCDOrOPjGrLzlAAAAA) format('woff2'); }
* { box-sizing: border-box; margin: 0; padding: 0; }
body { background:linear-gradient(160deg,#FFD1C7,#FFC8B5); font-family:-apple-system,BlinkMacSystemFont,"PingFang SC","Microsoft YaHei",sans-serif; display:flex; flex-direction:column; justify-content:center; align-items:center; min-height:100vh; color:#333; padding:10px 10px 20px; -webkit-user-select:none; user-select:none; -webkit-touch-callout:none; }
.container { position:relative; width:600px; max-width:95%; padding:12px 40px 40px; display:flex; flex-direction:column; align-items:center; background:#fff; border-radius:18px; box-shadow:0 8px 30px rgba(0,0,0,.08); margin-bottom:30px; }
.input-row { display:flex; gap:5px; align-items:center; margin-bottom:24px; font-family:sans-serif; }
.input-row input { width:56px; padding:6px 4px; border:1px solid #d9ccb6; border-radius:3px; font-size:14px; text-align:center; color:#6b5b4e; background:#fff; outline:none; }
.input-row input:focus { border-color:#a89580; }
.input-row .lbl { font-size:0.75em; color:#9b8a78; }
.btn-gen { padding:6px 12px; background:#8b7a68; color:#fff; border:none; border-radius:3px; font-size:0.75em; cursor:pointer; margin-left:2px; }
.btn-gen:active { opacity:0.8; }
.top-numbers { display:flex; flex-direction:column; align-items:center; margin-bottom:-20px; z-index:2; font-family:'TriangleDigits','Georgia','Times New Roman',serif; }
.top-numbers .num-top { font-size:2.2rem; font-weight:normal; }
.top-numbers .num-mid-row { display:flex; gap:60px; font-size:2.2rem; font-weight:normal; }
.triangle-wrapper { position:relative; width:300px; height:260px; margin:20px 0; display:flex; justify-content:center; align-items:center; overflow:visible; }
.triangle-svg { position:absolute; top:0; left:0; width:100%; height:100%; z-index:0; }
.triangle-path { fill:#f2ebdd; stroke:#d9ccb6; stroke-width:2; }
.divider-line { stroke:#d9ccb6; stroke-width:2; }
.inner-number { position:absolute; z-index:1; font-size:2.2rem; font-weight:bold; cursor:pointer; font-family:'TriangleDigits','Georgia','Times New Roman',serif; color:#5a4636; }
.red-num { color:#c47a78; top:25%; }
.mid-left { top:55%; left:30%; } .mid-right { top:55%; right:30%; }
.bot-1 { bottom:10%; left:18%; } .bot-2 { bottom:10%; left:38%; }
.bot-3 { bottom:10%; right:38%; } .bot-4 { bottom:10%; right:18%; }
.side-decorations { position:absolute; width:100%; height:100%; top:0; left:0; font-family:'TriangleDigits','Georgia','Times New Roman',serif; }
.side-num { position:absolute; font-size:2.2rem; opacity:0.65; cursor:pointer; font-family:'TriangleDigits','Georgia','Times New Roman',serif; font-weight:normal; color:#8b7e6e; }
.left-group { top:30%; left:-40px; text-align:right; line-height:1.5; }
.right-group { top:30%; right:-40px; text-align:left; line-height:1.5; }
.footer-date { margin-top:0; display:flex; gap:40px; font-size:1.8rem; letter-spacing:2px; color:#5a4636; font-family:'TriangleDigits','Georgia','Times New Roman',serif; }
.sections { width:100%; max-width:360px; margin-top:24px; font-family:sans-serif; font-size:1em; color:#6b5b4e; }
.divider { border:none; border-top:1px solid #e0d5c4; margin:12px 0; opacity:0.6; }
.codes .r { display:flex; justify-content:space-between; border-bottom:1px dotted rgba(168,144,112,0.15); padding:2px 4px; }
.codes .k { color:#9b8a78; } .codes .v { color:#6b5b4e; }
.joint-age { font-size:0.9em; color:#a89070; font-weight:600; text-align:center; margin:8px 0 2px; border-bottom:1px solid rgba(168,144,112,0.2); padding-bottom:2px; }
.joint-grid { display:grid; grid-template-columns:repeat(2,1fr); gap:2px 10px; }
.joint-grid .jc { font-weight:700; color:#5a4636; } .joint-grid .jm { color:#9b8a78; }
.tooltip { position:fixed; padding:5px 10px; background:#6b5b4e; color:#fff; border-radius:4px; font-size:0.7em; pointer-events:none; opacity:0; transition:opacity 0.12s; z-index:999; max-width:200px; line-height:1.5; font-family:sans-serif; }
.tooltip.on { opacity:1; }
.footer { text-align:center; font-size:0.6em; color:#9b8a78; margin-top:10px; }
/* 付费墙 */
.shuzi-lock { position:relative; border-radius:10px; overflow:hidden; border:1px solid #f2e6d0; }
.shuzi-lock > .blur { filter:blur(5px); pointer-events:none; user-select:none; }
.shuzi-lock .cover { position:absolute; inset:0; z-index:2; background:linear-gradient(180deg, rgba(250,247,242,.5), rgba(250,247,242,.95)); display:flex; flex-direction:column; align-items:center; justify-content:center; text-align:center; padding:20px; }
.shuzi-lock .cover .lk-t { font-size:1.05em; font-weight:700; color:#c47a78; }
.shuzi-lock .cover .lk-d { font-size:0.75em; color:#9b8a78; margin:8px 0 14px; }
.shuzi-lock .cover .lk-btn { background:#c47a78; color:#fff; border:none; padding:10px 28px; border-radius:20px; font-size:0.85em; font-weight:600; cursor:pointer; }
.shuzi-lock.unlocked .cover { display:none; }
.shuzi-lock.unlocked .blur { filter:none; pointer-events:auto; user-select:auto; }
.scene-3d { position:relative; display:flex; justify-content:center; margin:8px 0; cursor:grab; }
.scene-3d:active { cursor:grabbing; }
.scene-3d canvas { display:block; touch-action:none; }
.scene-hint { position:absolute; bottom:2px; left:50%; transform:translateX(-50%); font-size:0.55em; color:#b8a898; pointer-events:none; opacity:0.7; }
.freq-label { text-align:center; font-size:0.7em; color:#6b5b4e; margin-top:2px; line-height:1.8; }
.tabs-nav { display:flex; flex-wrap:wrap; gap:4px; margin-bottom:18px; justify-content:center; padding:0 4px; }
.tab-btn { padding:5px 10px; border:1px solid #d9ccb6; border-radius:3px; background:#fff; color:#9b8a78; font-size:0.7em; cursor:pointer; font-family:sans-serif; transition:all 0.15s; white-space:nowrap; }
.tab-btn:hover { border-color:#c47a78; color:#c47a78; }
.tab-btn.active { background:#c47a78; color:#fff; border-color:#c47a78; }
.tab-panel { display:none; }
.tab-panel.active { display:block; }
.tab-panel .module-title { font-size:0.82em; font-weight:600; color:#5a4636; text-align:center; margin-bottom:8px; }
.tab-panel .module-desc { font-size:0.68em; color:#9b8a78; text-align:center; margin-bottom:10px; line-height:1.6; }
.tab-panel .module-section { font-size:0.72em; color:#6b5b4e; line-height:1.75; padding:0 4px; margin-bottom:10px; }
.tab-panel .module-section b { color:#5a4636; }
.bagua-grid { display:grid; grid-template-columns:repeat(4,1fr); gap:6px; text-align:center; margin:8px 0; }
.bagua-cell { padding:6px 4px; border-radius:4px; font-size:0.68em; line-height:1.5; }
@media (max-width:600px) {
.triangle-wrapper { width:220px; height:190px; margin:10px auto 0; }
.triangle-wrapper svg { width:220px; height:190px; }
.inner-number { font-size:1.6rem; }
.red-num { top:22%; }
.mid-left { top:52%; left:28%; } .mid-right { top:52%; right:28%; }
.bot-1 { bottom:10%; left:14%; } .bot-2 { bottom:10%; left:35%; }
.bot-3 { bottom:10%; right:35%; } .bot-4 { bottom:10%; right:14%; }
.side-num { font-size:1.6rem; }
.left-group { left:-32px; top:26%; } .right-group { right:-32px; top:26%; }
.top-numbers .num-top { font-size:1.6rem; }
.top-numbers .num-mid-row { font-size:1.6rem; gap:40px; }
.footer-date { gap:14px; font-size:1.2rem; letter-spacing:0; }
}
</style>
</head>
<body>
<div style="text-align:center;padding:20px 0 4px;">
<img src="logo.png" alt="愈心谷" style="height:36px">
</div>
<div style="max-width:600px;margin:0 auto;padding:4px 14px;">
<a href="jiema.html" style="color:rgba(255,255,255,0.8);text-decoration:none;font-size:13px;">← 返回愈心解码</a>
</div>
<div class="container">
<div style="text-align:center;margin-bottom:10px;">
<h1 style="font-size:1.4em;font-weight:800;letter-spacing:0.15em;color:#C8923A;margin:0 0 6px;">愈心谷数字解构</h1>
<div style="font-size:0.65em;color:#999;letter-spacing:0.12em;margin-top:2px;">✦ 输入公历出生年月日 ✦</div>
</div>
<div class="input-row">
<input type="number" id="inY" value="1986"><span class="lbl"></span>
<input type="number" id="inM" value="2"><span class="lbl"></span>
<input type="number" id="inD" value="17"><span class="lbl"></span>
<button class="btn-gen" id="goBtn">生成</button>
</div>
<div class="top-numbers">
<div class="num-top" id="valR">3</div>
<div class="num-mid-row"><span id="valQ">4</span><span id="valP">8</span></div>
</div>
<div class="triangle-wrapper">
<svg class="triangle-svg" viewBox="0 0 300 260">
<polygon points="150,10 290,250 10,250" class="triangle-path"/>
<line x1="85" y1="130" x2="215" y2="130" class="divider-line"/>
<line x1="55" y1="190" x2="245" y2="190" class="divider-line"/>
<line x1="150" y1="130" x2="150" y2="250" class="divider-line"/>
</svg>
<div class="inner-number red-num" id="valO" style="left:50%;transform:translateX(-50%)">7</div>
<div class="inner-number mid-left" id="valM">1</div>
<div class="inner-number mid-right" id="valN">6</div>
<div class="inner-number bot-1" id="valI">8</div>
<div class="inner-number bot-2" id="valJ">2</div>
<div class="inner-number bot-3" id="valK">1</div>
<div class="inner-number bot-4" id="valL">5</div>
<div class="side-decorations">
<div class="side-num left-group" style="display:flex;flex-direction:column;align-items:center;">
<div id="valU">3</div>
<div style="display:flex;gap:8px"><span id="valT">9</span><span id="valS">3</span></div>
</div>
<div class="side-num right-group" style="display:flex;flex-direction:column;align-items:center;">
<div id="valX">9</div>
<div style="display:flex;gap:8px"><span id="valV">7</span><span id="valW">2</span></div>
</div>
</div>
</div>
<div class="footer-date">
<span id="dateD">17</span><span id="dateM">02</span><span id="dateY">1986</span>
</div>
<div class="sections">
<div class="tabs-nav">
<button class="tab-btn active" data-tab="shuzi">✨ 数字报告</button>
<button class="tab-btn" data-tab="meihua">🪷 梅花易数</button>
<button class="tab-btn" data-tab="xiaoliuren">🔮 小六壬</button>
<button class="tab-btn" data-tab="daliuren">🌌 大六壬</button>
<button class="tab-btn" data-tab="qimen">🏯 奇门遁甲</button>
<button class="tab-btn" data-tab="xingzuo">⭐ 星座</button>
<button class="tab-btn" data-tab="wuxing">☯️ 五行八卦</button>
</div>
<div class="tab-panel active" id="shuzi-panel">
<div class="missing" id="missingBlock"></div>
<div class="missing-short" id="missingMsg"></div>
<hr class="divider">
<div class="codes" id="codesBlock"></div>
<div class="joint" id="jointBlock"></div>
</div>
<div class="tab-panel" id="meihua-panel"></div>
<div class="tab-panel" id="xiaoliuren-panel"></div>
<div class="tab-panel" id="daliuren-panel"></div>
<div class="tab-panel" id="qimen-panel"></div>
<div class="tab-panel" id="xingzuo-panel"></div>
<div class="tab-panel" id="wuxing-panel"></div>
<div class="footer">内在探索 · 心灵成长</div>
</div>
</div>
<div class="tooltip" id="tip"></div>
<script src="common.js"></script>
<script>
const NUM_CLR={
1:{top:[232,160,160],front:[196,122,120],right:[168,96,96]},
2:{top:[240,200,160],front:[232,168,124],right:[208,144,96]},
3:{top:[238,208,128],front:[224,184,88],right:[200,152,64]},
4:{top:[160,216,112],front:[112,173,71],right:[88,136,48]},
5:{top:[144,200,240],front:[91,155,213],right:[64,120,176]},
6:{top:[240,168,176],front:[212,135,142],right:[176,104,112]},
7:{top:[184,168,216],front:[139,122,181],right:[104,88,152]},
8:{top:[160,144,128],front:[107,91,78],right:[80,64,48]},
9:{top:[244,236,224],front:[232,220,200],right:[208,192,168]},
};
// ===== Dimetric 投影 + Z 轴旋转 —— 底座天然水平 =====
let rotZ = -0.55; // Z 轴旋转角(弧度)
let dragActive=false, dragPX=0;
let currentFreq={};
function proj(x,y,z,rz) {
// Z 轴旋转 + 45° dimetric 投影
const cr=Math.cos(rz), sr=Math.sin(rz);
const xr=x*cr-y*sr, yr=x*sr+y*cr;
return { sx:yr-xr, sy:-(xr+yr)+z*0.7, depth:-(xr+yr)+z };
}
function faceVis(face, rz) {
const cr=Math.cos(rz), sr=Math.sin(rz);
switch(face) {
case 'right': return cr+sr>0;
case 'left': return cr+sr<0;
case 'front': return cr-sr>0;
case 'back': return cr-sr<0;
case 'top': return true;
case 'bottom':return false;
}
}
function faceCorns(cx,cy,cz,hs,face) {
const h=hs;
switch(face) {
case 'top': return [[cx-h,cy-h,cz+h],[cx+h,cy-h,cz+h],[cx+h,cy+h,cz+h],[cx-h,cy+h,cz+h]];
case 'bottom': return [[cx-h,cy-h,cz-h],[cx+h,cy-h,cz-h],[cx+h,cy+h,cz-h],[cx-h,cy+h,cz-h]];
case 'front': return [[cx-h,cy+h,cz-h],[cx+h,cy+h,cz-h],[cx+h,cy+h,cz+h],[cx-h,cy+h,cz+h]];
case 'back': return [[cx-h,cy-h,cz-h],[cx+h,cy-h,cz-h],[cx+h,cy-h,cz+h],[cx-h,cy-h,cz+h]];
case 'right': return [[cx+h,cy-h,cz-h],[cx+h,cy+h,cz-h],[cx+h,cy+h,cz+h],[cx+h,cy-h,cz+h]];
case 'left': return [[cx-h,cy-h,cz-h],[cx-h,cy+h,cz-h],[cx-h,cy+h,cz+h],[cx-h,cy-h,cz+h]];
}
}
function renderScene(canvas, freq, rz) {
const dpr=window.devicePixelRatio||1;
const mob=window.innerWidth<=600;
const CS=mob?20:26;
const STEP=CS*2+(mob?2:4);
const DH=CS*2+(mob?1:2);
const PAD=mob?30:40;
const cols={};
for(let n=1;n<=9;n++){
const row=2-Math.floor((n-1)/3), col=(n-1)%3;
cols[n]={wx:(col-1)*STEP,wy:(row-1)*STEP};
}
// 计算包围盒
let mnX=Infinity,mxX=-Infinity,mnY=Infinity,mxY=-Infinity;
for(let n=1;n<=9;n++){
const {wx,wy}=cols[n];
const layers=Math.max(1,freq[n]||1);
for(let l=0;l<layers;l++){
const wz=l*DH;
const cs=[[wx-CS,wy-CS,wz],[wx+CS,wy-CS,wz],[wx+CS,wy+CS,wz],[wx-CS,wy+CS,wz],
[wx-CS,wy-CS,wz+CS*2],[wx+CS,wy-CS,wz+CS*2],[wx+CS,wy+CS,wz+CS*2],[wx-CS,wy+CS,wz+CS*2]];
cs.forEach(c=>{const p=proj(c[0],c[1],c[2],rz);mnX=Math.min(mnX,p.sx);mxX=Math.max(mxX,p.sx);mnY=Math.min(mnY,p.sy);mxY=Math.max(mxY,p.sy);});
}
}
// 底座平台包围盒
const bw=STEP*2+CS*2+16, bz=-CS-3;
[[-bw,-bw,bz],[bw,-bw,bz],[bw,bw,bz],[-bw,bw,bz]].forEach(c=>{
const p=proj(c[0],c[1],c[2],rz);mnX=Math.min(mnX,p.sx);mxX=Math.max(mxX,p.sx);mnY=Math.min(mnY,p.sy);mxY=Math.max(mxY,p.sy);
});
const viewW=Math.max(mxX-mnX+PAD*2,mob?300:400);
const viewH=Math.max(mxY-mnY+PAD*2,mob?320:420);
canvas.width=Math.ceil(viewW*dpr);canvas.height=Math.ceil(viewH*dpr);
canvas.style.width=Math.ceil(viewW)+'px';canvas.style.height=Math.ceil(viewH)+'px';
const ctx=canvas.getContext('2d');ctx.scale(dpr,dpr);ctx.clearRect(0,0,viewW,viewH);
const centerX=(mxX+mnX)/2, ox=viewW/2-centerX, oy=viewH-PAD-mxY;
const faces=[];
const AF=['top','bottom','front','back','right','left'];
// 底座平台(厚块)
(()=>{
const bt=mob?4:5, bzTop=-CS-2, bzBot=bzTop-bt;
const bclr=[170,155,135];
[
{t:'top', c:[[-bw,-bw,bzTop],[bw,-bw,bzTop],[bw,bw,bzTop],[-bw,bw,bzTop]],clr:bclr},
{t:'front', c:[[-bw,bw,bzBot],[bw,bw,bzBot],[bw,bw,bzTop],[-bw,bw,bzTop]],clr:bclr.map(v=>Math.floor(v*0.85))},
{t:'right', c:[[bw,-bw,bzBot],[bw,bw,bzBot],[bw,bw,bzTop],[bw,-bw,bzTop]],clr:bclr.map(v=>Math.floor(v*0.7))},
].forEach(fb=>{
const pts=fb.c.map(c=>proj(c[0],c[1],c[2],rz));
const avgZ=pts.reduce((s,p)=>s+p.depth,0)/4;
const projPts=pts.map(p=>[ox+p.sx,oy-p.sy]);
faces.push({z:avgZ,proj:projPts,color:fb.clr,isTop:fb.t==='top',num:0});
});
})();
// 方块面
for(let n=1;n<=9;n++){
const {wx,wy}=cols[n];
const layers=Math.max(1,freq[n]||1);
const clr=NUM_CLR[n];
const fc={top:clr.top,bottom:clr.top,front:clr.front,back:clr.front,right:clr.right,left:clr.right};
for(let l=0;l<layers;l++){
const wz=l*DH;
for(const face of AF){
if(!faceVis(face,rz))continue;
const crns=faceCorns(wx,wy,wz,CS,face);
const pts=crns.map(c=>proj(c[0],c[1],c[2],rz));
const avgZ=pts.reduce((s,p)=>s+p.depth,0)/4;
const projPts=pts.map(p=>[ox+p.sx,oy-p.sy]);
const cnt=proj(wx,wy,wz+CS,rz);
faces.push({z:avgZ,proj:projPts,color:fc[face],isTop:face==='top',num:n,cx:ox+cnt.sx,cy:oy-cnt.sy});
}
}
}
faces.sort((a,b)=>a.z-b.z);
const alpha=0.82;
for(const f of faces){
const [r,g,b]=f.color;
ctx.fillStyle=`rgba(${r},${g},${b},${alpha})`;
ctx.beginPath();ctx.moveTo(f.proj[0][0],f.proj[0][1]);
for(let i=1;i<4;i++)ctx.lineTo(f.proj[i][0],f.proj[i][1]);
ctx.closePath();ctx.fill();
if(f.isTop&&f.num){
ctx.fillStyle='rgba(255,255,255,0.92)';
const fs=mob?11:14;ctx.font=`bold ${fs}px Georgia,"Noto Serif SC",serif`;
ctx.textAlign='center';ctx.textBaseline='middle';
ctx.shadowColor='rgba(0,0,0,0.25)';ctx.shadowBlur=2;
ctx.fillText(f.num,f.cx,f.cy);
ctx.shadowColor='transparent';ctx.shadowBlur=0;
}
}
// 底部 2D 横条
(()=>{
const bh=mob?18:22,by=viewH-bh;
const grad=ctx.createLinearGradient(0,by,0,viewH);
grad.addColorStop(0,'rgba(180,165,145,0.5)');
grad.addColorStop(0.3,'rgba(160,145,125,0.35)');
grad.addColorStop(1,'rgba(140,125,105,0.1)');
ctx.fillStyle=grad;ctx.fillRect(0,by,viewW,bh);
ctx.strokeStyle='rgba(140,125,105,0.45)';ctx.lineWidth=1;
ctx.beginPath();ctx.moveTo(0,by);ctx.lineTo(viewW,by);ctx.stroke();
})();
}
function drawScene(){
const canvas=document.querySelector('#scene3d canvas');
if(!canvas)return;
renderScene(canvas,currentFreq,rotZ);
}
function setupRotation(){
const el=document.querySelector('#scene3d');if(!el)return;
function getX(e){return e.touches&&e.touches.length?e.touches[0].clientX:e.clientX}
function onStart(e){dragActive=true;dragPX=getX(e);e.preventDefault()}
function onMove(e){
if(!dragActive)return;
const cx=getX(e),dx=cx-dragPX;dragPX=cx;
rotZ+=dx*0.008;drawScene();e.preventDefault();
}
function onEnd(){dragActive=false}
el.addEventListener('mousedown',onStart);
el.addEventListener('touchstart',onStart,{passive:false});
window.addEventListener('mousemove',onMove);
window.addEventListener('touchmove',onMove,{passive:false});
window.addEventListener('mouseup',onEnd);
window.addEventListener('touchend',onEnd);
}
// ===== 解读模块生成器 =====
const GUA64=['','乾为天','天泽履','天火同人','天雷无妄','天风姤','天水讼','天山遁','天地否','泽天夬','兑为泽','泽火革','泽雷随','泽风大过','泽水困','泽山咸','泽地萃','火天大有','火泽睽','离为火','火雷噬嗑','火风鼎','火水未济','火山旅','火地晋','雷天大壮','雷泽归妹','雷火丰','震为雷','雷风恒','雷水解','雷山小过','雷地豫','风天小畜','风泽中孚','风火家人','风雷益','巽为风','风水涣','风山渐','风地观','水天需','水泽节','水火既济','水雷屯','水风井','坎为水','水山蹇','水地比','山天大畜','山泽损','山火贲','山雷颐','山风蛊','山水蒙','艮为山','山地剥','地天泰','地泽临','地火明夷','地雷复','地风升','地水师','地山谦','坤为地'];
const GUA64_DESC={'乾为天':'刚健中正,纯阳之卦。运势旺盛,宜主动进取。','坤为地':'柔顺包容,厚德载物。耐心守成,终得善果。','水雷屯':'万事起头难。创业维艰,宜稳扎稳打。','山水蒙':'蒙昧初开。宜虚心求教,不可自作聪明。','水天需':'等待时机。耐心守候,时机未到不可强求。','天水讼':'争执诉讼之象。退一步海阔天空。','地水师':'统兵出征。纪律严明,以正制邪。','水地比':'亲附和合。广结善缘,必得助力。','地天泰':'天地交泰。万事亨通,上下和合。','天地否':'闭塞不通。宜隐忍守正,静待时机。','天火同人':'志同道合。同心协力可成大事。','火天大有':'丰收大有。顺天应时,财源广进。','雷天大壮':'强盛壮大。力量充沛但切忌恃强凌弱。','火地晋':'旭日东升。逐步晋升,光明在前。','地火明夷':'光明受损。韬光养晦,等待天明。','风火家人':'家庭和乐。修身齐家,家和万事兴。','火泽睽':'乖离不合。求同存异,小事可成。','水山蹇':'艰难险阻。退守求稳,不可强闯。','雷水解':'困难解除。柳暗花明,危机化解。','山泽损':'损下益上。有舍有得,吃亏是福。','风雷益':'增益有利。抓住机遇,积极作为。','泽天夬':'决断果断。当断则断,不受其乱。','天风姤':'不期而遇。随缘而处,不可强求。','泽地萃':'聚集荟萃。人气旺盛,利于合作。','地风升':'步步高升。循序渐进,终达目标。','泽水困':'困顿之象。坚守正道,终可脱困。','水风井':'修德养民。滋养根本,源远流长。','泽火革':'变革之时。顺势而变,除旧布新。','火风鼎':'鼎新革故。稳固根基,创新求变。','震为雷':'震动警醒。临危不乱,化险为夷。','艮为山':'知止不殆。适可而止,安守本分。','风山渐':'循序渐进。按部就班,水到渠成。','雷泽归妹':'婚嫁之象。以诚相待,终成眷属。','雷火丰':'丰盛之时。月满则亏,知足常乐。','火山旅':'行旅之象。随遇而安,莫问归期。','巽为风':'柔顺渗透。以柔克刚,润物无声。','兑为泽':'喜悦沟通。以和为贵,广结善缘。','风水涣':'涣散离散。聚拢人心,凝聚力量。','水泽节':'节制有度。合理规划,量力而行。','风泽中孚':'诚信感召。以诚待人,金石为开。','雷山小过':'小有过失。宜下不宜上,宜小不宜大。','水火既济':'事已成就。居安思危,防微杜渐。','火水未济':'未竟之业。持之以恒,终将成功。','地山谦':'谦逊受益。虚怀若谷,众望所归。','雷地豫':'安乐愉悦。居安思危,不可懈怠。','泽雷随':'随顺时势。灵活应变,顺势而为。','山风蛊':'蛊坏整治。拨乱反正,振弊起衰。','地泽临':'居高临下。亲近下属,恩威并施。','风地观':'观览体察。审时度势,明察秋毫。','火雷噬嗑':'咬合刑罚。明断是非,刚正不阿。','山火贲':'文饰美化。返璞归真,内在为重。','山地剥':'剥落凋零。守正待时,顺势而为。','地雷复':'一阳来复。否极泰来,新生在望。','天雷无妄':'真实无妄。顺其自然,不妄作为。','山天大畜':'蓄积力量。厚积薄发,大器晚成。','山雷颐':'颐养之道。养生养德,自求口实。','泽风大过':'过度之象。刚柔相济,中庸为贵。','坎为水':'重重险难。坚守诚信,终可出险。','离为火':'光明依附。柔顺中正,照亮四方。'};
function meihuaHTML(y,m,d){
const dz=['子','丑','寅','卯','辰','巳','午','未','申','酉','戌','亥'];
const dzNum={:1,:2,:3,:4,:5,:6,:7,:8,:9,:10,:11,:12};
const tg=['甲','乙','丙','丁','戊','己','庚','辛','壬','癸'];
const guaName=['','乾 ☰','兑 ☱','离 ☲','震 ☳','巽 ☴','坎 ☵','艮 ☶','坤 ☷'];
const guaEle=['','金','金','火','木','木','水','土','土'];
const ndz=dz[(y-4)%12],ntg=tg[(y-4)%10],nDZ=dzNum[ndz];
const upNum=nDZ%8||8,downNum=(m+d)%8||8,dongY=(nDZ+m+d)%6||6;
const benGuaIdx=(upNum-1)*8+downNum;
const benName=GUA64[benGuaIdx]||(guaName[upNum]+'+'+guaName[downNum]);
const varUp=dongY<=3?upNum:((upNum^5)||8),varDown=dongY<=3?((downNum^5)||8):downNum;
const varIdx=(varUp-1)*8+varDown;
const varName=GUA64[varIdx]||(guaName[varUp]+'+'+guaName[varDown]);
const desc=GUA64_DESC[benName]||'卦象已显,静心体悟其中玄机。';
const dongYaoNames=['初爻','二爻','三爻','四爻','五爻','上爻'];
const ue=guaEle[upNum],de=guaEle[downNum];
const shengKe={'金':'木','木':'土','土':'水','水':'火','火':'金'};
let tiYong;
if(upNum===downNum)tiYong='体用比和,万事顺遂';
else if(shengKe[ue]===de)tiYong='体克用,事可成但需费心力';
else if(shengKe[de]===ue)tiYong='用克体,宜守不宜攻,等待时机';
else tiYong='体用相生,遇贵人之象,万事可成';
return `<div class="module-title">✦ ${benName} ✦</div>
<div class="module-desc">${ntg}${ndz}年 · 上卦${guaName[upNum]} 下卦${guaName[downNum]} · 动在${dongYaoNames[dongY-1]}</div>
<div class="module-section"><b>▸ 本卦:${benName}</b><br><span style="color:#9b8a78">${desc}</span><br><br><b>▸ 变卦:${varName}</b><br><span style="color:#9b8a78">${GUA64_DESC[varName]||'变动已生,观其变化而知吉凶。'}</span><br><br><b>▸ 体用生克</b><br>上卦属${ue}·下卦属${de}${tiYong}</div>`;
}
const XLR_NAMES=['','大安','留连','速喜','赤口','小吉','空亡'];
const XLR_DESC={'大安':'大吉。光明正大,平安顺遂。求财向东南,凡事安稳。','留连':'凶。事难成就,去者未归。宜静不宜动,急则生变。','速喜':'大吉。喜事将至,向南吉利,行人有信至。','赤口':'凶。口舌是非,宜守不宜攻,失物难寻。','小吉':'大吉。好事将近,路遇贵人,向西南吉利。','空亡':'大凶。谋事落空,宜静待时机,强求反遭祸。'};
function xiaoLiuRenHTML(y,m,d){
const mo=m>12?m-12:m,shi=7;let pos=1;
for(let i=1;i<mo;i++)pos=pos%6+1;
for(let i=1;i<d;i++)pos=pos%6+1;
for(let i=1;i<shi;i++)pos=pos%6+1;
const name=XLR_NAMES[pos],isGood=name==='大安'||name==='速喜'||name==='小吉';
return `<div class="module-title">✦ 小六壬 掌诀:${name} ✦</div>
<div class="module-desc">月上起日,日上起时(午时)→ 最终落位</div>
<div class="module-section"><span style="font-size:1.6em;font-weight:700;color:${isGood?'#70ad47':'#c47a78'}">${name}</span><br><span style="color:#9b8a78">${XLR_DESC[name]}</span><br><br><b>▸ 六掌速查</b><br><span style="color:#70ad47">大安</span> · <span style="color:#c47a78">留连</span> · <span style="color:#70ad47">速喜</span> · <span style="color:#c47a78">赤口</span> · <span style="color:#70ad47">小吉</span> · <span style="color:#c47a78">空亡</span></div>`;
}
function daLiuRenHTML(y,m,d){
const dz=['子','丑','寅','卯','辰','巳','午','未','申','酉','戌','亥'];
const ydz=dz[(y-4)%12],yueJiangMap={1:'子',2:'亥',3:'戌',4:'酉',5:'申',6:'未',7:'午',8:'巳',9:'辰',10:'卯',11:'寅',12:'丑'};
return `<div class="module-title">✦ 大六壬 课式概要 ✦</div>
<div class="module-desc">${y}年(${ydz}年)· ${m}月 月将${yueJiangMap[m]||'午'} · 占时午</div>
<div class="module-section"><b>▸ 简介</b><br><span style="color:#9b8a78">六壬为三式之首,以月将加占时起天地盘,排四课发三传断吉凶。演算极精(12天将+12神煞+遁干),此处展示基础课式。</span><br><br><b>▸ 天地盘</b><br><span style="color:#9b8a78">地盘:子丑寅卯辰巳午未申酉戌亥(固定)<br>天盘:月将加临占时之上,顺布十二辰</span><br><br><b>▸ 四课</b><br><span style="color:#9b8a78">第一课日干阳神 · 第二课日干阴神 · 第三课日支阳神 · 第四课日支阴神</span><br><br><b>▸ 三传</b><br><span style="color:#9b8a78">初传(发用·起始)→ 中传(移易·过程)→ 末传(归计·结局)</span><br><br><b>▸ 九宗门</b><br><span style="color:#9b8a78">贼克·比用·涉害·遥克·昴星·别责·八专·伏吟·反吟</span><br><br><span style="color:#b8a898;font-size:0.95em">※ 完整排盘需配合具体时辰与日干支,建议请六壬师详断。</span></div>`;
}
function qiMenHTML(y,m,d){
const dz=['子','丑','寅','卯','辰','巳','午','未','申','酉','戌','亥'];
const tg=['甲','乙','丙','丁','戊','己','庚','辛','壬','癸'];
const mingGongMap={1:'丑',2:'寅',3:'卯',4:'辰',5:'巳',6:'午',7:'未',8:'申',9:'酉',10:'戌',11:'亥',12:'子'};
return `<div class="module-title">✦ 奇门遁甲 命盘概要 ✦</div>
<div class="module-desc">${tg[(y-4)%10]}${dz[(y-4)%12]}年 · 命宫:${mingGongMap[m]||'午'}</div>
<div class="module-section"><b>▸ 简介</b><br><span style="color:#9b8a78">奇门合天(九星)、地(九宫)、人(八门)、神(八神)四层于一体。排盘需节气+时辰+用局,极为精密。</span><br><br><b>▸ 地盘九宫</b><br><span style="color:#9b8a78">戴九履一·左三右七·二四为肩·六八为足·五居中央<br>坎一水·坤二土·震三木·巽四木·中五土·乾六金·兑七金·艮八土·离九火</span><br><br><b>▸ 八门(人事)</b><br><span style="color:#9b8a78">开门(吉)·休门(吉)·生门(吉)·伤门(凶)·杜门(平)·景门(平)·死门(凶)·惊门(凶)</span><br><br><b>▸ 九星(天时)</b><br><span style="color:#9b8a78">天蓬·天任·天冲·天辅·天英·天芮·天柱·天心·天禽</span><br><br><span style="color:#b8a898;font-size:0.95em">※ 全面排盘需根据具体时辰和节气确定阳遁/阴遁几局,建议请奇门师详断。</span></div>`;
}
const ZODIAC=[
{name:'摩羯座',emoji:'♑',elem:'土',from:[12,22],to:[1,19],trait:'坚韧务实,目标明确,大器晚成',lucky:'深绿·黑'},
{name:'水瓶座',emoji:'♒',elem:'风',from:[1,20],to:[2,18],trait:'独立创新,思维超前,人道主义',lucky:'蓝·银'},
{name:'双鱼座',emoji:'♓',elem:'水',from:[2,19],to:[3,20],trait:'浪漫敏感,富有同情心,艺术天赋',lucky:'紫·海蓝'},
{name:'白羊座',emoji:'♈',elem:'火',from:[3,21],to:[4,19],trait:'热情勇敢,行动力强,开拓先锋',lucky:'红·金'},
{name:'金牛座',emoji:'♉',elem:'土',from:[4,20],to:[5,20],trait:'稳健可靠,审美出众,坚定执着',lucky:'粉·绿'},
{name:'双子座',emoji:'♊',elem:'风',from:[5,21],to:[6,21],trait:'机智灵活,善于沟通,双面魅力',lucky:'黄·银'},
{name:'巨蟹座',emoji:'♋',elem:'水',from:[6,22],to:[7,22],trait:'温柔顾家,情感丰富,保护欲强',lucky:'白·银'},
{name:'狮子座',emoji:'♌',elem:'火',from:[7,23],to:[8,22],trait:'自信大方,领导力强,光芒四射',lucky:'金·橙'},
{name:'处女座',emoji:'♍',elem:'土',from:[8,23],to:[9,22],trait:'细致严谨,追求完美,服务精神',lucky:'灰·米'},
{name:'天秤座',emoji:'♎',elem:'风',from:[9,23],to:[10,23],trait:'优雅公正,善于平衡,社交达人',lucky:'粉·蓝'},
{name:'天蝎座',emoji:'♏',elem:'水',from:[10,24],to:[11,22],trait:'深沉敏锐,意志坚定,极致深情',lucky:'深红·黑'},
{name:'射手座',emoji:'♐',elem:'火',from:[11,23],to:[12,21],trait:'乐观自由,探索精神,哲学思维',lucky:'紫·深蓝'},
];
function xingZuoHTML(y,m,d){
let z=ZODIAC.find(x=>(m===x.from[0]&&d>=x.from[1])||(m===x.to[0]&&d<=x.to[1]));
if(!z){if((m===12&&d>=22)||(m===1&&d<=19))z=ZODIAC[0];else if(m===1)z=ZODIAC[1];else z=ZODIAC.find(x=>m===x.from[0]&&d<x.from[1])||ZODIAC[0];}
const et={:'热情主动,充满生命力,敢于冒险',:'踏实稳重,注重现实,可靠可信',:'思维敏捷,善于交流,适应力强',:'情感深邃,直觉敏锐,富有创造力'};
const ec={:'#c47a78',:'#8b7a68',:'#91a3b0',:'#6b9eb3'};
return `<div class="module-title">✦ ${z.emoji} ${z.name} ✦</div>
<div class="module-desc">${z.elem}象星座 · 幸运色:${z.lucky}</div>
<div class="module-section"><span style="font-size:2em">${z.emoji}</span><br><b>▸ 性格特质</b><br><span style="color:#9b8a78">${z.trait}</span><br><br><b>▸ 元素能量</b><br><span style="color:#9b8a78">${et[z.elem]}</span><br><br><b>▸ 十二星座</b><br>${ZODIAC.map(x=>`<span style="color:${ec[x.elem]}">${x.emoji}</span>`).join(' ')}</div>`;
}
const BAGUA=[
{name:'乾 ☰',xiang:'天',elem:'金',clr:'#d4c5a0',txt:'#8b7355',desc:'刚健·创造'},
{name:'兑 ☱',xiang:'泽',elem:'金',clr:'#e8d5c8',txt:'#a08070',desc:'喜悦·沟通'},
{name:'离 ☲',xiang:'火',elem:'火',clr:'#e8c8c0',txt:'#b06050',desc:'光明·智慧'},
{name:'震 ☳',xiang:'雷',elem:'木',clr:'#c8d8b0',txt:'#5a7a3a',desc:'行动·震动'},
{name:'巽 ☴',xiang:'风',elem:'木',clr:'#b8d0b8',txt:'#4a7a4a',desc:'渗透·柔顺'},
{name:'坎 ☵',xiang:'水',elem:'水',clr:'#a8c8d8',txt:'#3a6a8a',desc:'险陷·智慧'},
{name:'艮 ☶',xiang:'山',elem:'土',clr:'#d0c8b0',txt:'#7a6a4a',desc:'静止·坚守'},
{name:'坤 ☷',xiang:'地',elem:'土',clr:'#e0d8c0',txt:'#8a7a5a',desc:'柔顺·包容'},
];
function wuXingHTML(y,m,d){
const yElem=['金','水','木','火','土'][Math.floor(((y-4)%10)/2)];
const mElem=['木','木','土','火','火','土','金','金','土','水','水','土'][m-1];
const dElem=['木','火','土','金','水'][d%5];
const ec={:'#d4c5a0',:'#a8c8d8',:'#b8d0b8',:'#e8c8c0',:'#e0d8c0'};
return `<div class="module-title">✦ 五行八卦 能量图谱 ✦</div>
<div class="module-desc">年柱${yElem} · 月柱${mElem} · 日柱${dElem}</div>
<div class="module-section"><b>▸ 五行</b><br>
<div style="display:flex;gap:4px;margin:6px 0">${['金','水','木','火','土'].map(e=>`<span style="flex:1;text-align:center;padding:4px;background:${ec[e]};color:#5a4636;border-radius:3px;font-size:0.95em"><b>${e}</b></span>`).join('')}</div>
<span style="color:#9b8a78">金(义)·水(智)·木(仁)·火(礼)·土(信)<br>相生:金→水→木→火→土→金<br>相克:金→木→土→水→火→金</span><br><br><b>▸ 八卦</b><br>
<div class="bagua-grid">${BAGUA.map(b=>`<div class="bagua-cell" style="background:${b.clr};color:${b.txt}"><b>${b.name}</b><br><span style="font-size:0.92em">${b.elem}·${b.xiang}<br>${b.desc}</span></div>`).join('')}</div>
<span style="color:#9b8a78">八卦歌诀:乾三连·坤六断·震仰盂·艮覆碗·离中虚·坎中满·兑上缺·巽下断</span></div>`;
}
// ===== Tab 切换 =====
function initTabs(){
const nav=document.querySelector('.tabs-nav');
if(!nav)return;
nav.addEventListener('click',e=>{
const btn=e.target.closest('.tab-btn');
if(!btn)return;
const tab=btn.dataset.tab;
nav.querySelectorAll('.tab-btn').forEach(b=>b.classList.remove('active'));
btn.classList.add('active');
document.querySelectorAll('.tab-panel').forEach(p=>p.classList.remove('active'));
const panel=document.getElementById(tab+'-panel');
if(panel)panel.classList.add('active');
});
}
function update(v,y,m,d){
document.getElementById('valR').textContent=v.R;
document.getElementById('valQ').textContent=v.Q;
document.getElementById('valP').textContent=v.P;
document.getElementById('valO').textContent=v.O;
document.getElementById('valM').textContent=v.M;
document.getElementById('valN').textContent=v.N;
document.getElementById('valI').textContent=v.I;
document.getElementById('valJ').textContent=v.J;
document.getElementById('valK').textContent=v.K;
document.getElementById('valL').textContent=v.L;
document.getElementById('valU').textContent=v.U;
document.getElementById('valT').textContent=v.T;
document.getElementById('valS').textContent=v.S;
document.getElementById('valX').textContent=v.X;
document.getElementById('valV').textContent=v.V;
document.getElementById('valW').textContent=v.W;
document.getElementById('dateD').textContent=String(d).padStart(2,'0');
document.getElementById('dateM').textContent=String(m).padStart(2,'0');
document.getElementById('dateY').textContent=y;
const allNums=[0,1,2,3,4,5,6,7,8,9];
const inner=new Set([v.O,v.M,v.N,v.I,v.J,v.K,v.L]);
const present=new Set([...inner,v.Q,v.P,v.R,v.T,v.S,v.U,v.V,v.W,v.X,v.AB[0],v.AB[1],v.CD[0],v.CD[1],v.EF[0],v.EF[1],v.GH[0],v.GH[1]]);
const miss={inner:allNums.filter(n=>!inner.has(n)),outer:allNums.filter(n=>![v.Q,v.P,v.R,v.T,v.S,v.U,v.V,v.W,v.X].includes(n)),both:allNums.filter(n=>!present.has(n))};
const n=NUM[v.O]||{};
const freq={};
for(let i=1;i<=9;i++)freq[i]=0;
const allVals=[v.O,v.M,v.N,v.I,v.J,v.K,v.L,v.Q,v.P,v.R,v.T,v.S,v.U,v.V,v.W,v.X,
v.AB[0],v.AB[1],v.CD[0],v.CD[1],v.EF[0],v.EF[1],v.GH[0],v.GH[1]];
allVals.forEach(x=>{if(x>=1&&x<=9)freq[x]++;});
currentFreq=freq;
const freqArr=Object.entries(freq).sort((a,b)=>b[1]-a[1]);
const most=freqArr[0],least=freqArr.filter(([,c])=>c===freqArr[freqArr.length-1][1]);
let freeHtml=`<div style="text-align:center;margin-bottom:18px;">`;
freeHtml+=`<div style="font-size:2.4em;font-weight:700;color:#c47a78;line-height:1;margin-bottom:4px;">${v.O}号人</div>`;
freeHtml+=`<div style="font-size:0.85em;font-weight:600;color:#5a4636;margin-bottom:6px;">${n.title||''}</div>`;
freeHtml+=`<div style="font-size:0.75em;color:#6b5b4e;line-height:1.7;max-width:340px;margin:0 auto;text-align:left;">${n.desc||''}</div>`;
freeHtml+=`</div>`;
let premiumHtml=``;
premiumHtml+=`<div style="font-size:0.7em;color:#9b8a78;margin-top:8px;line-height:1.7;text-align:left;max-width:340px;margin-left:auto;margin-right:auto;">`;
premiumHtml+=`<b>✦ 天赋优势</b>${n.pos||''}<br><b>✦ 人生课题</b>${n.neg||''}<br><b>✦ 五行属性</b>${n.elem||''}<br><b>✦ 适合职业</b>${n.job||''}</div></div>`;
premiumHtml+=`<hr class="divider">`;
premiumHtml+=`<div style="font-size:0.82em;font-weight:600;color:#5a4636;text-align:center;margin-bottom:8px;">✦ 数字能量图谱 ✦</div>`;
premiumHtml+=`<div style="font-size:0.7em;color:#6b5b4e;text-align:center;margin-bottom:0;">你的生命三角共汇聚了 <b>${allVals.filter(x=>x>=1).length}</b> 个能量数字</div>`;
premiumHtml+=`<div class="scene-3d" id="scene3d"><canvas></canvas><div class="scene-hint">↻ 左右旋转</div></div>`;
premiumHtml+=`<div class="freq-label">🔥 能量最强:<b>${most[0]}</b>(出现 ${most[1]} 次),是你生命中最闪耀的特质</div>`;
if(least.length>0)premiumHtml+=`<div class="freq-label" style="margin-top:0;">💧 能量最弱:${least.map(([n])=>`<b>${n}</b>`).join('、')}(仅 ${least[0][1]} 次),值得你用心浇灌</div>`;
premiumHtml+=`<hr class="divider">`;
premiumHtml+=`<div style="font-size:0.82em;font-weight:600;color:#5a4636;text-align:center;margin-bottom:6px;">✦ 三角内外——真实自我与外界眼光 ✦</div>`;
premiumHtml+=`<div style="font-size:0.7em;line-height:1.7;color:#6b5b4e;padding:0 4px;">`;
premiumHtml+=`<div><b>▸ 三角内部</b>:代表你内在真实的自我——潜意识的驱动、与生俱来的性格特质、不为人知的内心世界。</div>`;
premiumHtml+=`<div style="margin-top:3px;"><b>▸ 三角外部</b>:代表外界对你的认知——你在工作、家庭、社交中呈现出的样子,以及他人眼中的你。</div>`;
premiumHtml+=`<div style="margin-top:3px;"><b>▸ 下方基因</b>(父母遗传):代表来自父亲和母亲的先天遗传基因,是你性格的底层土壤。</div></div>`;
premiumHtml+=`<hr class="divider">`;
premiumHtml+=`<div style="font-size:0.82em;font-weight:600;color:#5a4636;text-align:center;margin-bottom:6px;">✦ 性格密码深度解读 ✦</div>`;
premiumHtml+=`<div style="font-size:0.7em;line-height:1.8;color:#6b5b4e;padding:0 4px;">`;
premiumHtml+=`<div style="margin-bottom:4px;"><b>潜意识码:${v.I}${v.J}${v.K}${v.L}</b></div>`;
premiumHtml+=`<div style="color:#9b8a78;margin-bottom:8px;">你内心深处的真实驱动力,最本能的反应模式。四个数字分别主宰:思维、情感、行动、人际。</div>`;
premiumHtml+=`<div style="margin-bottom:4px;"><b>内心码:${v.M}${v.N}</b></div>`;
premiumHtml+=`<div style="color:#9b8a78;margin-bottom:8px;">深层情感模式与核心价值观。理性行动 vs 感性人际——两者的平衡就是你面对压力时的姿态。</div>`;
premiumHtml+=`<div style="margin-bottom:4px;"><b>坐镇码:${v.I}${v.M}${v.O}</b></div>`;
premiumHtml+=`<div style="color:#9b8a78;margin-bottom:8px;">性格核心轴线:潜意识→内心→主性格。三环相扣,是你从内驱力到外在呈现的完整链条,也是你最稳定的底色。</div>`;
premiumHtml+=`<div style="margin-bottom:4px;"><b>父亲基因:${v.EF.join('')} ${v.GH.join('')}</b> · <b>母亲基因:${v.AB.join('')} ${v.CD.join('')}</b></div>`;
premiumHtml+=`<div style="color:#9b8a78;">父亲基因 ← 年份 ${v.EF.join('')}${v.GH.join('')})承载家族传承与事业基因<br>母亲基因 ← 月${v.CD.join('')}${v.AB.join('')})影响情感模式与人际底色</div></div>`;
premiumHtml+=`<hr class="divider">`;
premiumHtml+=`<div style="font-size:0.82em;font-weight:600;color:#5a4636;text-align:center;margin-bottom:6px;">✦ 数字缺失与能量过剩 ✦</div>`;
premiumHtml+=`<div style="font-size:0.7em;line-height:1.7;color:#6b5b4e;padding:0 4px;">`;
if(miss.both.length>0){premiumHtml+=`<div style="margin-bottom:4px;"><b>⚠ 缺失数字</b></div>`;miss.both.forEach(n=>{premiumHtml+=`<div style="margin-bottom:3px;">· <b>缺${n}</b>${MISS_MSG[n]||''}</div>`;});}
else premiumHtml+=`<div style="margin-bottom:4px;color:#9b8a78;">✦ 你的数字分布完整,能量均衡。</div>`;
const over=[];for(let i=1;i<=9;i++){if(freq[i]>=4&&!miss.both.includes(i))over.push(i);}
if(over.length>0){premiumHtml+=`<div style="margin-top:6px;margin-bottom:4px;"><b>⚡ 能量过剩</b></div>`;over.forEach(n=>{premiumHtml+=`<div style="margin-bottom:3px;">· <b>多${n}</b>(×${freq[n]}):${MISS_STRONG[n]||''}</div>`;});}
premiumHtml+=`</div>`;
const joints=[['I','J'],['J','M'],['M','I'],['K','L'],['L','N'],['N','K'],['M','O'],['O','N'],['M','N'],['Q','P'],['Q','O'],['P','O']].map(([a,b])=>{const k=''+v[a]+v[b];const jk=Object.keys(JOINT).find(x=>x.startsWith(k));return {code:k,label:jk?JOINT[jk]:'—'};});
premiumHtml+=`<hr class="divider">`;
premiumHtml+=`<div style="font-size:0.82em;font-weight:600;color:#5a4636;text-align:center;margin-bottom:6px;">✦ 12组人生联合码 ✦</div>`;
premiumHtml+=`<div style="font-size:0.68em;color:#9b8a78;text-align:center;margin-bottom:8px;">相邻数字组合,解密你不同人生阶段的内在剧本</div>`;
const ages=[
{label:'21—40岁 · 工作和朋友',codes:joints.slice(0,4),desc:'由潜意识码主导,反映你在职场上升期和社交圈中的表现模式。'+(v.I+v.J+v.M>=10?'能量较强,事业心旺盛,社交活跃。':'能量内敛,更注重深度而非广度。')},
{label:'41—60岁 · 儿女和下属',codes:joints.slice(4,8),desc:'由内心码和主性格主导,体现你对下一代和下级的培养方式及中年价值观。'+(v.K+v.L+v.N>=10?'有较强的责任感和支配欲。':'倾向于给予空间,放手让他人成长。')},
{label:'61岁至晚年 · 晚年和家庭',codes:joints.slice(8,12),desc:'由外心码主导,展现你晚年的生活智慧和家庭关系的最终呈现。'+(v.M+v.N+v.O>=10?'晚年活跃,持续发挥影响力。':'晚年宁静,享受内在平和。')},
];
ages.forEach(ag=>{
premiumHtml+=`<div class="joint-age">${ag.label}</div>`;
premiumHtml+=`<div style="font-size:0.65em;color:#9b8a78;text-align:center;margin:-2px 0 6px;line-height:1.5;">${ag.desc}</div>`;
premiumHtml+=`<div class="joint-grid">`;
ag.codes.forEach(jc=>{premiumHtml+=`<div><span class="jc">${jc.code}</span> <span class="jm">${jc.label}</span></div>`;});
premiumHtml+=`</div>`;
});
const paid=localStorage.getItem('jiema_paid');
const lockEl=document.getElementById('missingBlock');
if(paid){
lockEl.innerHTML=freeHtml+premiumHtml;
}else{
lockEl.innerHTML=freeHtml+'<div class="shuzi-lock" id="shuziLock">'+premiumHtml+'</div>';
const lock=document.getElementById('shuziLock');
Array.from(lock.children).forEach(c=>c.classList.add('blur'));
const cover=document.createElement('div');cover.className='cover';
cover.innerHTML='<div class="lk-t">🔒 解锁你的完整数字报告</div><div class="lk-d">天赋优势 · 能量分布 · 性格编码 · 12组联合码</div>';
const btn=document.createElement('button');btn.className='lk-btn';btn.textContent='¥39.9 立即解锁 →';
btn.addEventListener('click',unlockShuzi);cover.appendChild(btn);lock.appendChild(cover);
}
setTimeout(()=>{
const canvas=document.querySelector('#scene3d canvas');
if(canvas){renderScene(canvas,freq,rotZ);setupRotation();}
},30);
document.getElementById('missingMsg').textContent='';
document.getElementById('codesBlock').innerHTML='';
document.getElementById('jointBlock').innerHTML='';
const tipEl=document.getElementById('tip');
['valR','valQ','valP','valO','valM','valN','valI','valJ','valK','valL','valU','valT','valS','valX','valV','valW'].forEach(id=>{
const el=document.getElementById(id);if(!el)return;el.style.cursor='pointer';
const k=id.replace('val','');
el.onpointerenter=()=>{const f=tips[k]?tips[k](v):'';tipEl.innerHTML=f||k;tipEl.classList.add('on')};
el.onpointermove=e=>{tipEl.style.left=(e.clientX+14)+'px';tipEl.style.top=(e.clientY-10)+'px'};
});
// 填充其他解读面板
document.getElementById('meihua-panel').innerHTML=meihuaHTML(y,m,d);
document.getElementById('xiaoliuren-panel').innerHTML=xiaoLiuRenHTML(y,m,d);
document.getElementById('daliuren-panel').innerHTML=daLiuRenHTML(y,m,d);
document.getElementById('qimen-panel').innerHTML=qiMenHTML(y,m,d);
document.getElementById('xingzuo-panel').innerHTML=xingZuoHTML(y,m,d);
document.getElementById('wuxing-panel').innerHTML=wuXingHTML(y,m,d);
}
function unlockShuzi(){localStorage.setItem("jiema_paid","1");const l=document.getElementById("shuziLock");l.querySelectorAll(".blur").forEach(c=>c.classList.remove("blur"));l.classList.add("unlocked");}
function go(){const y=+document.getElementById('inY').value,m=+document.getElementById('inM').value,d=+document.getElementById('inD').value;if(!y||!m||!d)return;update(calc(y,m,d),y,m,d)}
document.getElementById('goBtn').addEventListener('click',go);
document.querySelectorAll('.input-row input').forEach(i=>i.addEventListener('keydown',e=>{if(e.key==='Enter')go()}));
setTimeout(go,150);
initTabs();
// URL 参数预填(从 jiema.html 跳转过来)
(function(){
const p=new URLSearchParams(location.search);
const y=p.get('y'),m=p.get('m'),d=p.get('d');
if(y&&m&&d){
document.getElementById('inY').value=y;
document.getElementById('inM').value=m;
document.getElementById('inD').value=d;
setTimeout(go,200);
}
})();
</script>
</body>
</html>