guanwei 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.en.md +202 -0
- package/README.md +247 -0
- package/dist/assets/index-CsOD5rSo.js +102 -0
- package/dist/assets/index-CsOD5rSo.js.map +1 -0
- package/dist/assets/index-DQx62TUr.css +1 -0
- package/dist/favicon.svg +12 -0
- package/dist/index.html +15 -0
- package/eslint.config.js +28 -0
- package/index.html +25 -0
- package/package.json +96 -0
- package/postcss.config.js +10 -0
- package/public/favicon.svg +12 -0
- package/scripts/guanwei +245 -0
- package/scripts/install.sh +79 -0
- package/scripts/release.sh +42 -0
- package/scripts/setup.bat +36 -0
- package/scripts/setup.sh +123 -0
- package/server/src/data/db.json +12059 -0
- package/server/src/data/guanwei.db +0 -0
- package/server/src/data/lifeContext.ts +423 -0
- package/server/src/data/spreads.ts +255 -0
- package/server/src/data/tarotCards.ts +2353 -0
- package/server/src/index.ts +71 -0
- package/server/src/routes/ai.ts +376 -0
- package/server/src/routes/divine.ts +140 -0
- package/server/src/routes/hour.ts +40 -0
- package/server/src/routes/tarot.ts +129 -0
- package/server/src/routes/users.ts +140 -0
- package/server/src/services/chartBrief.ts +131 -0
- package/server/src/services/divineStore.ts +188 -0
- package/server/src/services/hourInference.ts +150 -0
- package/server/src/services/llmProvider.ts +181 -0
- package/server/src/services/promptBuilder.ts +327 -0
- package/server/src/services/relativesCheck.ts +139 -0
- package/server/src/services/sixRelatives.ts +70 -0
- package/server/src/services/skills.ts +116 -0
- package/server/src/types/index.ts +104 -0
- package/server/src/utils/semanticAnalyzer.ts +555 -0
- package/server/src/utils/tarotEngine.ts +849 -0
- package/server/tsconfig.json +18 -0
- package/shared/core/data/classics.ts +276 -0
- package/shared/core/data/courses.ts +211 -0
- package/shared/core/data/duanyu.ts +148 -0
- package/shared/core/data/ganzhi.ts +53 -0
- package/shared/core/data/gua64.ts +93 -0
- package/shared/core/data/liuren.ts +18 -0
- package/shared/core/data/liuyao.ts +73 -0
- package/shared/core/data/qimen.ts +27 -0
- package/shared/core/data/region-full.ts +3 -0
- package/shared/core/data/region.ts +310 -0
- package/shared/core/data/tarotSpreads.ts +78 -0
- package/shared/core/data/xiaoliuren.ts +18 -0
- package/shared/core/data/ziwei.ts +97 -0
- package/shared/core/data/zodiac.ts +20 -0
- package/shared/core/engine/astrology.ts +169 -0
- package/shared/core/engine/bazi.ts +306 -0
- package/shared/core/engine/calendar.ts +127 -0
- package/shared/core/engine/daily.ts +133 -0
- package/shared/core/engine/liuren.ts +86 -0
- package/shared/core/engine/liuyao.ts +93 -0
- package/shared/core/engine/meihua.ts +87 -0
- package/shared/core/engine/qimen.ts +78 -0
- package/shared/core/engine/questionFit.ts +94 -0
- package/shared/core/engine/tarot.ts +69 -0
- package/shared/core/engine/trueSolarTime.ts +86 -0
- package/shared/core/engine/xiaoliuren.ts +19 -0
- package/shared/core/engine/ziwei.ts +217 -0
- package/shared/core/engine/ziweiInterpret.ts +161 -0
- package/shared/core/types.ts +206 -0
- package/src/App.tsx +69 -0
- package/src/arts/registry.ts +31 -0
- package/src/assets/react.svg +1 -0
- package/src/components/Backdrop.tsx +27 -0
- package/src/components/BambooArt.tsx +41 -0
- package/src/components/CalendarInput.tsx +131 -0
- package/src/components/DateInput.tsx +103 -0
- package/src/components/Disclaimer.tsx +12 -0
- package/src/components/Empty.tsx +8 -0
- package/src/components/ErrorBoundary.tsx +38 -0
- package/src/components/HomeSideAnchor.tsx +62 -0
- package/src/components/InkVein.tsx +10 -0
- package/src/components/LifeEventsInput.tsx +47 -0
- package/src/components/LocationPicker.tsx +117 -0
- package/src/components/Motes.tsx +65 -0
- package/src/components/Navigation.tsx +80 -0
- package/src/components/ProfileForm.tsx +40 -0
- package/src/components/ProfilePicker.tsx +40 -0
- package/src/components/QuestionFields.tsx +47 -0
- package/src/components/ReportView.tsx +211 -0
- package/src/components/ResultCard.tsx +40 -0
- package/src/components/SealButton.tsx +18 -0
- package/src/components/SiteFooter.tsx +17 -0
- package/src/components/SiteNav.tsx +103 -0
- package/src/components/SongDialog.tsx +64 -0
- package/src/components/SongSearchSelect.tsx +81 -0
- package/src/components/SongSelect.tsx +61 -0
- package/src/components/StarField.tsx +119 -0
- package/src/components/TarotCard.tsx +129 -0
- package/src/components/TimeShichenInput.tsx +29 -0
- package/src/components/arts/AstrologyArt.tsx +141 -0
- package/src/components/arts/BaziArt.tsx +269 -0
- package/src/components/arts/LiurenArt.tsx +87 -0
- package/src/components/arts/LiuyaoArt.tsx +111 -0
- package/src/components/arts/MeihuaArt.tsx +105 -0
- package/src/components/arts/QimenArt.tsx +86 -0
- package/src/components/arts/TarotArt.tsx +110 -0
- package/src/components/arts/XiaoliurenArt.tsx +93 -0
- package/src/components/arts/ZiweiArt.tsx +296 -0
- package/src/data/arts.ts +84 -0
- package/src/data/lifeContext.ts +423 -0
- package/src/data/sample-report.json +146 -0
- package/src/data/shichen.ts +21 -0
- package/src/data/spreads.ts +255 -0
- package/src/data/tarotCards.ts +2353 -0
- package/src/hooks/useAIInterpret.ts +76 -0
- package/src/hooks/useDivine.ts +39 -0
- package/src/hooks/useTheme.ts +29 -0
- package/src/index.css +190 -0
- package/src/lib/utils.ts +6 -0
- package/src/main.tsx +12 -0
- package/src/pages/AboutPage.tsx +25 -0
- package/src/pages/AcademyPage.tsx +128 -0
- package/src/pages/AstrologyPage.tsx +33 -0
- package/src/pages/AuthPage.tsx +263 -0
- package/src/pages/BaZiPage.tsx +33 -0
- package/src/pages/ClassicsPage.tsx +120 -0
- package/src/pages/DemoPage.tsx +161 -0
- package/src/pages/HistoryPage.tsx +133 -0
- package/src/pages/Home.tsx +179 -0
- package/src/pages/HomePage.tsx +174 -0
- package/src/pages/ModulePage.tsx +320 -0
- package/src/pages/SpreadEditor.tsx +230 -0
- package/src/pages/SpreadEditorPage.tsx +105 -0
- package/src/pages/SpreadLibrary.tsx +199 -0
- package/src/pages/SpreadLibraryPage.tsx +17 -0
- package/src/pages/TarotPage.tsx +738 -0
- package/src/pages/ZiWeiPage.tsx +33 -0
- package/src/services/api.ts +342 -0
- package/src/stores/useDivinationStore.ts +22 -0
- package/src/styles/song.css +1066 -0
- package/src/styles/tokens.css +60 -0
- package/src/types/index.ts +104 -0
- package/src/utils/astrologyCalc.ts +61 -0
- package/src/utils/comboEngine.ts +134 -0
- package/src/utils/dst.ts +24 -0
- package/src/utils/panTone.ts +206 -0
- package/src/utils/recordStore.ts +60 -0
- package/src/utils/semanticAnalyzer.ts +555 -0
- package/src/utils/spreadStorage.ts +32 -0
- package/src/utils/storage.ts +27 -0
- package/src/utils/tarotEngine.ts +849 -0
- package/src/utils/userStore.ts +234 -0
- package/src/vite-env.d.ts +1 -0
- package/tailwind.config.js +52 -0
- package/tsconfig.json +40 -0
- package/vite.config.ts +34 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import"https://fonts.googleapis.com/css2?family=Cinzel:wght@400;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap";@import"https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@300;400;500;600;700&family=Ma+Shan+Zheng&family=Zhi+Mang+Xing&display=swap";*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}html{scroll-behavior:smooth;overflow-x:hidden}body{--tw-bg-opacity: 1;background-color:rgb(10 10 15 / var(--tw-bg-opacity, 1));font-family:Noto Sans SC,sans-serif;--tw-text-opacity: 1;color:rgb(224 224 224 / var(--tw-text-opacity, 1));overflow-x:hidden}::-moz-selection{background-color:#c9a2274d;--tw-text-opacity: 1;color:rgb(224 224 224 / var(--tw-text-opacity, 1))}::selection{background-color:#c9a2274d;--tw-text-opacity: 1;color:rgb(224 224 224 / var(--tw-text-opacity, 1))}::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{--tw-bg-opacity: 1;background-color:rgb(10 10 15 / var(--tw-bg-opacity, 1))}::-webkit-scrollbar-thumb{border-radius:9999px;background-color:#c9a2274d}::-webkit-scrollbar-thumb:hover{background-color:#c9a22780}.glass-panel{border-radius:.5rem;border-width:1px;border-color:#c9a22733;background-color:#1a1a2e99;--tw-backdrop-blur: blur(12px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.shimmer-text{background:linear-gradient(90deg,#c9a227,gold,#c9a227);background-size:200% auto;-webkit-background-clip:text;-webkit-text-fill-color:transparent;animation:shimmer 3s linear infinite}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{top:0;right:0;bottom:0;left:0}.inset-1{top:.25rem;right:.25rem;bottom:.25rem;left:.25rem}.-bottom-1{bottom:-.25rem}.-top-3{top:-.75rem}.bottom-0{bottom:0}.bottom-1{bottom:.25rem}.bottom-8{bottom:2rem}.left-0{left:0}.left-1{left:.25rem}.left-1\.5{left:.375rem}.left-1\/2{left:50%}.left-3{left:.75rem}.right-0{right:0}.right-1{right:.25rem}.right-1\.5{right:.375rem}.right-3{right:.75rem}.top-0{top:0}.top-1{top:.25rem}.top-1\.5{top:.375rem}.top-1\/2{top:50%}.z-50{z-index:50}.mx-auto{margin-left:auto;margin-right:auto}.mb-1{margin-bottom:.25rem}.mb-12{margin-bottom:3rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.ml-11{margin-left:2.75rem}.ml-auto{margin-left:auto}.mt-0{margin-top:0}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-3\.5{margin-top:.875rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-8{margin-top:2rem}.mt-auto{margin-top:auto}.line-clamp-1{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1}.line-clamp-3{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.h-1\.5{height:.375rem}.h-12{height:3rem}.h-16{height:4rem}.h-20{height:5rem}.h-24{height:6rem}.h-3{height:.75rem}.h-32{height:8rem}.h-4{height:1rem}.h-48{height:12rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-72{height:18rem}.h-8{height:2rem}.h-full{height:100%}.h-px{height:1px}.max-h-96{max-height:24rem}.min-h-screen{min-height:100vh}.w-12{width:3rem}.w-16{width:4rem}.w-20{width:5rem}.w-24{width:6rem}.w-3{width:.75rem}.w-32{width:8rem}.w-4{width:1rem}.w-44{width:11rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-8{width:2rem}.w-full{width:100%}.w-px{width:1px}.max-w-24{max-width:6rem}.max-w-2xl{max-width:42rem}.max-w-4xl{max-width:56rem}.max-w-5xl{max-width:64rem}.max-w-6xl{max-width:72rem}.max-w-7xl{max-width:80rem}.max-w-xl{max-width:36rem}.flex-1{flex:1 1 0%}.-translate-x-1\/2{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-0{--tw-translate-y: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-4{--tw-translate-y: 1rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-45{--tw-rotate: 45deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes bounce{0%,to{transform:translateY(-25%);animation-timing-function:cubic-bezier(.8,0,1,1)}50%{transform:none;animation-timing-function:cubic-bezier(0,0,.2,1)}}.animate-bounce{animation:bounce 1s infinite}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.animate-pulse-glow{animation:pulseGlow 2s ease-in-out infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-move{cursor:move}.cursor-pointer{cursor:pointer}.resize-none{resize:none}.resize{resize:both}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-sm{border-radius:.125rem}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-ancient{--tw-border-opacity: 1;border-color:rgb(201 162 39 / var(--tw-border-opacity, 1))}.border-ancient\/10{border-color:#c9a2271a}.border-ancient\/20{border-color:#c9a22733}.border-ancient\/30{border-color:#c9a2274d}.border-ancient\/40{border-color:#c9a22766}.border-ancient\/50{border-color:#c9a22780}.border-ancient\/60{border-color:#c9a22799}.border-crimson\/40{border-color:#8b000066}.border-crimson\/60{border-color:#8b000099}.border-green-500\/20{border-color:#22c55e33}.border-mystic\/20{border-color:#7b68ee33}.border-mystic\/30{border-color:#7b68ee4d}.border-mystic\/50{border-color:#7b68ee80}.border-red-500\/20{border-color:#ef444433}.border-stardust\/10{border-color:#e0e0e01a}.border-stardust\/15{border-color:#e0e0e026}.border-stardust\/20{border-color:#e0e0e033}.border-yellow-500\/20{border-color:#eab30833}.bg-abyss{--tw-bg-opacity: 1;background-color:rgb(26 26 46 / var(--tw-bg-opacity, 1))}.bg-abyss\/20{background-color:#1a1a2e33}.bg-abyss\/30{background-color:#1a1a2e4d}.bg-abyss\/40{background-color:#1a1a2e66}.bg-abyss\/60{background-color:#1a1a2e99}.bg-ancient{--tw-bg-opacity: 1;background-color:rgb(201 162 39 / var(--tw-bg-opacity, 1))}.bg-ancient\/10{background-color:#c9a2271a}.bg-ancient\/20{background-color:#c9a22733}.bg-ancient\/40{background-color:#c9a22766}.bg-ancient\/5{background-color:#c9a2270d}.bg-mystic\/10{background-color:#7b68ee1a}.bg-mystic\/20{background-color:#7b68ee33}.bg-mystic\/5{background-color:#7b68ee0d}.bg-void{--tw-bg-opacity: 1;background-color:rgb(10 10 15 / var(--tw-bg-opacity, 1))}.bg-void\/40{background-color:#0a0a0f66}.bg-void\/50{background-color:#0a0a0f80}.bg-void\/80{background-color:#0a0a0fcc}.bg-void\/95{background-color:#0a0a0ff2}.bg-gradient-to-b{background-image:linear-gradient(to bottom,var(--tw-gradient-stops))}.bg-gradient-to-br{background-image:linear-gradient(to bottom right,var(--tw-gradient-stops))}.from-ancient\/20{--tw-gradient-from: rgb(201 162 39 / .2) var(--tw-gradient-from-position);--tw-gradient-to: rgb(201 162 39 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-ancient\/50{--tw-gradient-from: rgb(201 162 39 / .5) var(--tw-gradient-from-position);--tw-gradient-to: rgb(201 162 39 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-crimson\/20{--tw-gradient-from: rgb(139 0 0 / .2) var(--tw-gradient-from-position);--tw-gradient-to: rgb(139 0 0 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-mystic\/20{--tw-gradient-from: rgb(123 104 238 / .2) var(--tw-gradient-from-position);--tw-gradient-to: rgb(123 104 238 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.to-ancient\/20{--tw-gradient-to: rgb(201 162 39 / .2) var(--tw-gradient-to-position)}.to-crimson\/20{--tw-gradient-to: rgb(139 0 0 / .2) var(--tw-gradient-to-position)}.to-mystic\/20{--tw-gradient-to: rgb(123 104 238 / .2) var(--tw-gradient-to-position)}.to-transparent{--tw-gradient-to: transparent var(--tw-gradient-to-position)}.p-1{padding:.25rem}.p-12{padding:3rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-10{padding-left:2.5rem;padding-right:2.5rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-16{padding-top:4rem;padding-bottom:4rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.pb-16{padding-bottom:4rem}.pl-10{padding-left:2.5rem}.pr-10{padding-right:2.5rem}.pr-3{padding-right:.75rem}.pt-2{padding-top:.5rem}.pt-20{padding-top:5rem}.pt-6{padding-top:1.5rem}.text-left{text-align:left}.text-center{text-align:center}.font-display{font-family:Cinzel,serif}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-5xl{font-size:3rem;line-height:1}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[9px\]{font-size:9px}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.tabular-nums{--tw-numeric-spacing: tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.leading-tight{line-height:1.25}.tracking-wide{letter-spacing:.025em}.tracking-wider{letter-spacing:.05em}.tracking-widest{letter-spacing:.1em}.text-ancient{--tw-text-opacity: 1;color:rgb(201 162 39 / var(--tw-text-opacity, 1))}.text-ancient\/30{color:#c9a2274d}.text-ancient\/40{color:#c9a22766}.text-ancient\/60{color:#c9a22799}.text-ancient\/70{color:#c9a227b3}.text-ancient\/80{color:#c9a227cc}.text-blue-400{--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity, 1))}.text-crimson{--tw-text-opacity: 1;color:rgb(139 0 0 / var(--tw-text-opacity, 1))}.text-crimson\/60{color:#8b000099}.text-crimson\/70{color:#8b0000b3}.text-crimson\/80{color:#8b0000cc}.text-gray-300{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity, 1))}.text-green-400{--tw-text-opacity: 1;color:rgb(74 222 128 / var(--tw-text-opacity, 1))}.text-green-400\/60{color:#4ade8099}.text-mystic{--tw-text-opacity: 1;color:rgb(123 104 238 / var(--tw-text-opacity, 1))}.text-mystic\/60{color:#7b68ee99}.text-mystic\/70{color:#7b68eeb3}.text-mystic\/80{color:#7b68eecc}.text-orange-400{--tw-text-opacity: 1;color:rgb(251 146 60 / var(--tw-text-opacity, 1))}.text-red-400\/60{color:#f8717199}.text-stardust{--tw-text-opacity: 1;color:rgb(224 224 224 / var(--tw-text-opacity, 1))}.text-stardust\/30{color:#e0e0e04d}.text-stardust\/40{color:#e0e0e066}.text-stardust\/50{color:#e0e0e080}.text-stardust\/60{color:#e0e0e099}.text-stardust\/70{color:#e0e0e0b3}.text-void{--tw-text-opacity: 1;color:rgb(10 10 15 / var(--tw-text-opacity, 1))}.text-yellow-400\/60{color:#facc1599}.underline{text-decoration-line:underline}.placeholder-stardust\/30::-moz-placeholder{color:#e0e0e04d}.placeholder-stardust\/30::placeholder{color:#e0e0e04d}.accent-ancient{accent-color:#c9a227}.opacity-0{opacity:0}.opacity-100{opacity:1}.shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[0_0_12px_rgba\(201\,162\,39\,0\.25\)\]{--tw-shadow: 0 0 12px rgba(201,162,39,.25);--tw-shadow-colored: 0 0 12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.blur-3xl{--tw-blur: blur(64px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-md{--tw-backdrop-blur: blur(12px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.duration-500{transition-duration:.5s}.duration-700{transition-duration:.7s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.perspective-1000{perspective:1000px}.preserve-3d{transform-style:preserve-3d}.backface-hidden{backface-visibility:hidden}.rotate-y-180{transform:rotateY(180deg)}.animate-fade-in{animation:fade-in .5s ease-out forwards}.animate-pulse-glow{animation:pulse-glow 2s ease-in-out infinite}@keyframes shimmer{0%{background-position:200% center}to{background-position:-200% center}}@keyframes fade-in{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes float{0%,to{transform:translateY(0)}50%{transform:translateY(-10px)}}@keyframes pulse-glow{0%,to{box-shadow:0 0 5px #c9a2274d}50%{box-shadow:0 0 20px #c9a22799}}@keyframes typing-cursor{0%,to{opacity:1}50%{opacity:0}}@media print{body{background:#fff!important}header,footer,nav,aside,.site-head,.site-nav,.back-link,.module-hero,.mh-intro,.mh-row,.altar-panel,.fit-card,.fit-note,.btn-row,.ai-streaming,.ai-error,.result-placeholder,.disclaimer,.d-title,.motes,.ink-vein,.bamboo,.cal-grid,.profile-card,.no-print{display:none!important}main{display:block!important;padding:0!important}.wrap{max-width:none!important;padding:0!important}.altar{display:block!important}.altar-result{width:100%!important;max-width:none!important}.report-view{color:#000!important;background:#fff!important}.report-view .result-card{-moz-column-break-inside:auto;break-inside:auto;border:1px solid #ddd!important;background:#fff!important;box-shadow:none!important;color:#000!important;margin-bottom:6mm}.report-view .result-card h3{-moz-column-break-after:avoid;break-after:avoid}.report-view .domain-cell,.report-view li,.report-view .traits-grid .trait{-moz-column-break-inside:avoid;break-inside:avoid}.report-view .result-title{-moz-column-break-after:avoid;break-after:avoid}.report-view .result-text,.report-view p,.report-view li,.report-view h3{color:#000!important}.report-view .domain-name{color:#555!important}@page{margin:12mm}}@keyframes pulse-soft{0%,to{opacity:.55}50%{opacity:1}}.hover\:border-ancient:hover{--tw-border-opacity: 1;border-color:rgb(201 162 39 / var(--tw-border-opacity, 1))}.hover\:border-ancient\/30:hover{border-color:#c9a2274d}.hover\:border-ancient\/40:hover{border-color:#c9a22766}.hover\:border-ancient\/50:hover{border-color:#c9a22780}.hover\:border-ancient\/60:hover{border-color:#c9a22799}.hover\:border-crimson:hover{--tw-border-opacity: 1;border-color:rgb(139 0 0 / var(--tw-border-opacity, 1))}.hover\:border-mystic\/60:hover{border-color:#7b68ee99}.hover\:border-stardust\/40:hover{border-color:#e0e0e066}.hover\:border-stardust\/50:hover{border-color:#e0e0e080}.hover\:bg-ancient\/10:hover{background-color:#c9a2271a}.hover\:bg-ancient\/30:hover{background-color:#c9a2274d}.hover\:bg-ancient\/5:hover{background-color:#c9a2270d}.hover\:bg-mystic\/30:hover{background-color:#7b68ee4d}.hover\:bg-mystic\/5:hover{background-color:#7b68ee0d}.hover\:text-ancient:hover{--tw-text-opacity: 1;color:rgb(201 162 39 / var(--tw-text-opacity, 1))}.hover\:text-ancient\/80:hover{color:#c9a227cc}.hover\:text-crimson:hover{--tw-text-opacity: 1;color:rgb(139 0 0 / var(--tw-text-opacity, 1))}.hover\:text-stardust:hover{--tw-text-opacity: 1;color:rgb(224 224 224 / var(--tw-text-opacity, 1))}.focus\:border-ancient\/60:focus{border-color:#c9a22799}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-ancient:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(201 162 39 / var(--tw-ring-opacity, 1))}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-30:disabled{opacity:.3}@keyframes pulseGlow{0%,to{box-shadow:0 0 5px #c9a2274d}50%{box-shadow:0 0 20px #c9a22799}}.group:hover .group-hover\:animate-pulse-glow{animation:pulseGlow 2s ease-in-out infinite}.group:hover .group-hover\:border-ancient{--tw-border-opacity: 1;border-color:rgb(201 162 39 / var(--tw-border-opacity, 1))}.group:hover .group-hover\:text-ancient{--tw-text-opacity: 1;color:rgb(201 162 39 / var(--tw-text-opacity, 1))}.group:hover .group-hover\:text-ancient\/60{color:#c9a22799}.group:hover .group-hover\:opacity-100{opacity:1}.group:hover .group-hover\:animate-pulse-glow{animation:pulse-glow 2s ease-in-out infinite}@media(min-width:640px){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}}@media(min-width:768px){.md\:flex{display:flex}.md\:hidden{display:none}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:grid-cols-8{grid-template-columns:repeat(8,minmax(0,1fr))}.md\:gap-6{gap:1.5rem}.md\:p-8{padding:2rem}.md\:text-4xl{font-size:2.25rem;line-height:2.5rem}.md\:text-7xl{font-size:4.5rem;line-height:1}.md\:text-base{font-size:1rem;line-height:1.5rem}.md\:text-xl{font-size:1.25rem;line-height:1.75rem}}@media(min-width:1024px){.lg\:grid-cols-10{grid-template-columns:repeat(10,minmax(0,1fr))}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.lg\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.lg\:px-8{padding-left:2rem;padding-right:2rem}.lg\:text-8xl{font-size:6rem;line-height:1}}:root{--paper: #F5F1E7;--paper-deep: #EDE8D9;--paper-dim: #E4DECC;--ink: #37342C;--ink-soft: #6B675C;--ink-faint: #97917F;--line: rgba(55,52,44,.16);--line-soft: rgba(55,52,44,.1);--celadon: #96A88F;--celadon-deep: #5F7660;--celadon-tint: #E3E8DC;--crab: #7C9792;--crab-tint: #DCE4E0;--rice: #D9CDAC;--rice-tint: #EDE5CE;--cinnabar: #A5402D;--cinnabar-deep:#8C3526;--cinnabar-tint:#F3E3DC;--white-paper: #FBF9F3;--font-song: "Noto Serif SC","Songti SC","Source Han Serif SC","SimSun","STSong",serif;--font-kai: "Ma Shan Zheng","Kaiti SC","KaiTi","STKaiti","Noto Serif SC",serif;--font-zm: "Zhi Mang Xing","Ma Shan Zheng","Kaiti SC",serif;--fs-xs: .75rem;--fs-sm: .875rem;--fs-base:1.05rem;--fs-lg: 1.35rem;--fs-xl: clamp(1.6rem, 3.2vw, 2.2rem);--fs-2xl: clamp(2.2rem, 5.5vw, 3.6rem);--fs-3xl: clamp(3rem, 9vw, 6rem);--fs-display: clamp(4.2rem, 14vw, 10rem);--sp-1:.5rem;--sp-2:1rem;--sp-3:1.5rem;--sp-4:2rem;--sp-5:3rem;--sp-6:4.5rem;--sp-7:6.5rem;--sp-8:9rem;--r-sm:2px;--r-md:4px;--r-lg:8px;--shadow-paper: 0 1px 2px rgba(55,52,44,.06), 0 10px 30px -18px rgba(55,52,44,.18);--ease-out: cubic-bezier(.22,1,.36,1);--ease-ink: cubic-bezier(.5,0,.1,1);--dur-fast: .22s;--dur-mid: .6s;--dur-slow: 1.2s}*{margin:0;padding:0;box-sizing:border-box}html{scroll-behavior:smooth}body{font-family:var(--font-song);color:var(--ink);background:var(--paper);font-size:var(--fs-base);line-height:1.85;-webkit-font-smoothing:antialiased;overflow-x:hidden}::-moz-selection{background:var(--cinnabar);color:var(--paper)}::selection{background:var(--cinnabar);color:var(--paper)}img,svg{display:block;max-width:100%}a{color:inherit;text-decoration:none}button{font-family:inherit;cursor:pointer;background:none;border:none;color:inherit}input,select,textarea{font-family:inherit;color:inherit}#paper-grain{position:fixed;top:0;right:0;bottom:0;left:0;z-index:-2;pointer-events:none;background:radial-gradient(120% 90% at 12% 0%,rgba(255,255,255,.55),transparent 55%),radial-gradient(100% 80% at 100% 100%,rgba(198,188,160,.22),transparent 60%)}#paper-grain:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;background-image:repeating-linear-gradient(0deg,rgba(55,52,44,.016) 0 1px,transparent 1px 3px),repeating-linear-gradient(90deg,rgba(55,52,44,.012) 0 1px,transparent 1px 5px);opacity:.5}#mountains{position:fixed;left:0;right:0;bottom:0;height:38vh;z-index:-1;pointer-events:none;opacity:.5}.wrap{max-width:1200px;margin:0 auto;padding:0 clamp(1.25rem,4vw,3rem)}.site-head{position:sticky;top:0;z-index:50;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);background:linear-gradient(180deg,#f5f1e7eb,#f5f1e7b8);border-bottom:1px solid var(--line-soft)}.head-inner{display:flex;align-items:center;justify-content:space-between;padding-block:.8rem;gap:1rem}.brand{display:flex;align-items:baseline;gap:.6rem;flex-shrink:0}.brand .seal{align-self:center;font-family:var(--font-kai);font-size:.72rem;letter-spacing:.12em;color:var(--cinnabar);border:1.5px solid var(--cinnabar);padding:.28rem .34rem;line-height:1;border-radius:2px}.brand .name{font-family:var(--font-kai);font-size:1.45rem;letter-spacing:.32em;color:var(--ink)}.brand .sub{font-size:var(--fs-xs);color:var(--ink-faint);letter-spacing:.3em;white-space:nowrap}.nav-links{display:flex;align-items:center;gap:clamp(.6rem,2vw,1.6rem);flex-wrap:wrap;justify-content:flex-end}.nav-links a{font-size:var(--fs-sm);letter-spacing:.18em;color:var(--ink-soft);padding:.3rem 0;position:relative;transition:color var(--dur-fast) var(--ease-out)}.nav-links a:after{content:"";position:absolute;left:0;right:0;bottom:0;height:1px;background:var(--cinnabar);transform:scaleX(0);transform-origin:right;transition:transform var(--dur-mid) var(--ease-out)}.nav-links a:hover{color:var(--ink)}.nav-links a:hover:after{transform:scaleX(1);transform-origin:left}.nav-links a.active{color:var(--cinnabar)}.view{display:none;animation:viewIn .9s var(--ease-out) both}.view.active{display:block}@keyframes viewIn{0%{opacity:0;transform:translateY(18px)}to{opacity:1;transform:none}}.hero{position:relative;min-height:calc(100vh - 76px);display:flex;flex-direction:column;justify-content:center;padding-block:var(--sp-6)}.hero-kicker{display:flex;align-items:center;gap:1rem;font-size:var(--fs-sm);letter-spacing:.5em;color:var(--ink-faint);margin-bottom:var(--sp-3)}.hero-kicker:before{content:"";width:3.5rem;height:1px;background:var(--ink-faint)}.hero-title{font-family:var(--font-kai);font-size:var(--fs-display);letter-spacing:.12em;line-height:1.05;color:var(--ink);text-shadow:0 2px 30px rgba(255,255,255,.6)}.hero-title .accent{color:var(--celadon-deep);font-family:var(--font-zm)}.hero-line{margin-top:var(--sp-4);font-size:var(--fs-lg);color:var(--ink-soft);max-width:34ch;line-height:2;letter-spacing:.08em}.hero-line em{font-style:normal;color:var(--cinnabar)}.hero-desc{margin-top:var(--sp-3);max-width:52ch;color:var(--ink-faint);font-size:var(--fs-sm);letter-spacing:.14em;line-height:2.1}.hero-actions{margin-top:var(--sp-5);display:flex;gap:1rem;flex-wrap:wrap}.btn-seal{position:relative;padding:.85rem 2.2rem;font-family:var(--font-kai);font-size:1.05rem;letter-spacing:.35em;color:var(--cinnabar);border:1.5px solid var(--cinnabar);border-radius:2px;transition:all var(--dur-mid) var(--ease-out);overflow:hidden;display:inline-block;cursor:pointer}.btn-seal:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;background:var(--cinnabar);transform:scaleY(0);transform-origin:top;transition:transform var(--dur-mid) var(--ease-out)}.btn-seal:hover:before{transform:scaleY(1)}.btn-seal.btn-ghost{color:var(--ink-soft);border-color:var(--ink-soft)}.btn-seal.btn-ghost:before{background:var(--ink-soft)}.btn-seal.btn-ghost:hover{color:var(--paper)}.hero-vert{position:absolute;right:clamp(1rem,4vw,3rem);top:50%;transform:translateY(-50%);writing-mode:vertical-rl;font-family:var(--font-kai);font-size:var(--fs-sm);letter-spacing:.6em;color:var(--ink-faint);opacity:.75;display:flex;gap:2.2rem}.hero-vert span{white-space:nowrap}.scroll-hint{position:absolute;bottom:2.4rem;left:50%;transform:translate(-50%);writing-mode:vertical-rl;font-size:var(--fs-xs);letter-spacing:.5em;color:var(--ink-faint);display:flex;align-items:center;gap:.6rem;animation:floatHint 3.2s var(--ease-ink) infinite}.scroll-hint:after{content:"";width:1px;height:3rem;background:linear-gradient(180deg,var(--ink-faint),transparent)}.section-head{margin-bottom:var(--sp-5)}.section-eyebrow{display:flex;align-items:center;gap:1rem;font-size:var(--fs-sm);letter-spacing:.5em;color:var(--ink-faint)}.section-eyebrow:before{content:"";width:2.5rem;height:1px;background:var(--ink-faint)}.section-title{font-family:var(--font-kai);font-size:var(--fs-2xl);letter-spacing:.2em;margin-top:.8rem;color:var(--ink)}.section-note{margin-top:.6rem;color:var(--ink-faint);font-size:var(--fs-sm);letter-spacing:.12em}.arts-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(1.2rem,2.5vw,2rem)}@media(max-width:900px){.arts-grid{grid-template-columns:repeat(2,1fr)}}@media(max-width:560px){.arts-grid{grid-template-columns:1fr}}.art-card{position:relative;background:linear-gradient(175deg,var(--white-paper),var(--paper) 70%,var(--paper-deep));border:1px solid var(--line);border-radius:var(--r-md);padding:var(--sp-4) var(--sp-3);cursor:pointer;transition:transform var(--dur-mid) var(--ease-out),box-shadow var(--dur-mid) var(--ease-out),border-color var(--dur-mid);overflow:hidden;min-height:240px;display:flex;flex-direction:column;text-decoration:none;color:inherit}.art-card:before{content:"";position:absolute;top:0;left:1.5rem;right:1.5rem;height:1px;background:linear-gradient(90deg,transparent,var(--celadon),transparent)}.art-card:after{content:"";position:absolute;inset:auto -30% -55% -30%;height:90%;background:radial-gradient(ellipse at center,rgba(150,168,143,.16),transparent 65%);opacity:0;transition:opacity var(--dur-slow) var(--ease-ink)}.art-card:hover{transform:translateY(-4px);box-shadow:var(--shadow-paper);border-color:var(--celadon)}.art-card:hover:after{opacity:1}.art-card:focus-visible{outline:2px solid var(--celadon-deep);outline-offset:2px}.art-num{font-family:var(--font-kai);font-size:var(--fs-sm);color:var(--ink-faint);letter-spacing:.3em;display:flex;align-items:center;gap:.5rem}.art-num:after{content:"";flex:1;height:1px;background:var(--line-soft)}.art-symbol{margin:var(--sp-2) 0 var(--sp-2);font-family:var(--font-zm);font-size:var(--fs-2xl);color:var(--celadon-deep);line-height:1;text-align:center;width:3.4rem;height:3.4rem;margin-left:auto;margin-right:auto;display:flex;align-items:center;justify-content:center;border:1px solid var(--line-soft);border-radius:50%;background:radial-gradient(circle at 35% 30%,var(--celadon-tint),transparent 70%)}.art-name{font-family:var(--font-kai);font-size:var(--fs-xl);letter-spacing:.24em;text-align:center;color:var(--ink)}.art-poem{text-align:center;color:var(--ink-faint);font-size:var(--fs-sm);letter-spacing:.18em;margin-top:.6rem}.art-enter{margin-top:auto;padding-top:var(--sp-2);text-align:center;font-size:var(--fs-xs);letter-spacing:.4em;color:var(--ink-faint);transition:color var(--dur-fast)}.art-card:hover .art-enter{color:var(--cinnabar)}.about{background:var(--paper-deep);border-block:1px solid var(--line-soft)}.about-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--sp-4)}@media(max-width:860px){.about-grid{grid-template-columns:1fr}}.about-item{padding-right:var(--sp-3)}.about-item h3{font-family:var(--font-kai);font-size:1.1rem;letter-spacing:.2em;display:flex;align-items:center;gap:.7rem;color:var(--ink)}.about-item h3:before{content:"·";color:var(--cinnabar);font-size:1.4rem}.about-item p{margin-top:.7rem;font-size:var(--fs-sm);color:var(--ink-soft);line-height:2.1;letter-spacing:.06em}.module-hero{padding:var(--sp-7) 0 var(--sp-5);position:relative}.module-kicker{display:flex;align-items:center;gap:1rem;font-size:var(--fs-sm);letter-spacing:.4em;color:var(--ink-faint)}.module-kicker:before{content:"";width:2.5rem;height:1px;background:var(--ink-faint)}.module-title-row{display:flex;align-items:flex-end;gap:var(--sp-3);flex-wrap:wrap;margin-top:1rem}.module-title{font-family:var(--font-kai);font-size:var(--fs-2xl);letter-spacing:.18em;color:var(--ink)}.module-title .cn{display:block;font-family:var(--font-zm);font-size:var(--fs-3xl);color:var(--celadon-deep);letter-spacing:.1em}.module-poem{font-family:var(--font-kai);color:var(--ink-soft);font-size:var(--fs-lg);letter-spacing:.3em;padding-bottom:.5rem}.module-intro{margin-top:var(--sp-2);max-width:62ch;color:var(--ink-soft);font-size:var(--fs-sm);letter-spacing:.08em;line-height:2.2}.module-intro .source{color:var(--ink-faint);font-size:var(--fs-xs)}.altar{display:grid;grid-template-columns:340px 1fr;gap:var(--sp-5);align-items:start}@media(max-width:960px){.altar{grid-template-columns:1fr}}.altar-panel{background:linear-gradient(175deg,var(--white-paper),var(--paper-deep));border:1px solid var(--line);border-radius:var(--r-lg);padding:var(--sp-4);position:sticky;top:88px}@media(max-width:960px){.altar-panel{position:static}}.panel-title{font-family:var(--font-kai);font-size:1.1rem;letter-spacing:.25em;display:flex;align-items:center;gap:.6rem;color:var(--ink);padding-bottom:var(--sp-2);border-bottom:1px solid var(--line-soft)}.panel-title:before{content:"◇";color:var(--celadon-deep);font-size:.8rem}.field{margin-top:var(--sp-3)}.field label{display:block;font-size:var(--fs-sm);letter-spacing:.2em;color:var(--ink-soft);margin-bottom:.4rem}.field .hint{font-size:var(--fs-xs);color:var(--ink-faint);letter-spacing:.08em;margin-top:.3rem}.field-row{display:grid;grid-template-columns:1fr 1fr;gap:.8rem}.input-line{width:100%;padding:.6rem .8rem;background:#fbf9f399;border:1px solid var(--line);border-radius:var(--r-sm);font-size:var(--fs-base);transition:border-color var(--dur-fast),box-shadow var(--dur-fast)}.input-line:focus{outline:none;border-color:var(--celadon-deep);box-shadow:0 0 0 3px #5f76601f}select.input-line{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-image:linear-gradient(45deg,transparent 50%,var(--ink-soft) 50%),linear-gradient(135deg,var(--ink-soft) 50%,transparent 50%);background-position:calc(100% - 18px) 50%,calc(100% - 13px) 50%;background-size:5px 5px;background-repeat:no-repeat}.btn-divine{margin-top:var(--sp-4);width:100%;padding:1rem;background:var(--celadon-deep);color:var(--paper);font-family:var(--font-kai);font-size:1.15rem;letter-spacing:.5em;text-indent:.5em;border-radius:var(--r-sm);transition:background var(--dur-mid) var(--ease-out),transform var(--dur-mid);cursor:pointer}.btn-divine:hover{background:var(--cinnabar);transform:translateY(-1px)}.btn-divine:disabled{opacity:.5;cursor:wait}.btn-divine .small{display:block;font-size:var(--fs-xs);letter-spacing:.3em;font-family:var(--font-song);color:#fbf9f3bf;margin-top:.15rem}.altar-result{min-height:320px}.result-placeholder{display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:320px;gap:.8rem;color:var(--ink-faint);border:1px dashed var(--line);border-radius:var(--r-lg);padding:var(--sp-4);text-align:center}.result-placeholder .glyph{font-family:var(--font-zm);font-size:3.4rem;color:var(--rice)}.result-placeholder p{letter-spacing:.3em;font-size:var(--fs-sm)}.result-card{background:linear-gradient(175deg,var(--white-paper),var(--paper-deep));border:1px solid var(--line);border-radius:var(--r-lg);padding:var(--sp-4);margin-bottom:var(--sp-3);animation:viewIn .8s var(--ease-out) both}.result-card h3{font-family:var(--font-kai);font-size:1.1rem;letter-spacing:.2em;color:var(--celadon-deep);display:flex;align-items:center;gap:.6rem;padding-bottom:.8rem;margin-bottom:var(--sp-2);border-bottom:1px solid var(--line-soft)}.result-card h3:before{content:"◆";font-size:.8rem}.result-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:var(--sp-2)}.result-cell{padding:.9rem;background:#fbf9f38c;border:1px solid var(--line-soft);border-radius:var(--r-sm)}.result-cell .k{font-size:var(--fs-xs);color:var(--ink-faint);letter-spacing:.25em}.result-cell .v{font-size:1.15rem;color:var(--ink);margin-top:.2rem;letter-spacing:.08em;font-weight:500}.result-cell .v.big{font-size:1.5rem;font-family:var(--font-kai)}.result-cell .v.hot{color:var(--cinnabar)}.result-cell .v.cool{color:var(--celadon-deep)}.result-text{color:var(--ink-soft);font-size:var(--fs-sm);line-height:2.2;letter-spacing:.04em;margin-top:.5rem}.report-view,.report-view p,.report-view li,.report-view h3,.result-text,.result-text p,.result-text li{font-family:system-ui,-apple-system,PingFang SC,Hiragino Sans GB,Microsoft YaHei,sans-serif}.result-text strong{color:var(--ink);font-weight:600}.result-text .tag-hot{color:var(--cinnabar);font-weight:500}.result-text .tag-cool{color:var(--celadon-deep);font-weight:500}.result-text p+p{margin-top:.6rem}.wx-fire{color:var(--cinnabar)}.wx-wood{color:#5e7a4e}.wx-water{color:#3e5f7a}.wx-metal{color:#8c7a4e}.wx-earth{color:#7a6a4a}.disclaimer{margin-top:var(--sp-5);display:flex;gap:1rem;align-items:flex-start;padding:var(--sp-3);background:var(--cinnabar-tint);border:1px solid rgba(165,64,45,.25);border-radius:var(--r-md);font-size:var(--fs-sm);color:#7a3b2c;line-height:2}.disclaimer .seal-mini{flex-shrink:0;font-family:var(--font-kai);color:var(--cinnabar);border:1px solid var(--cinnabar);padding:.3rem .4rem;font-size:.7rem;letter-spacing:.2em;border-radius:2px;margin-top:.15rem}.disclaimer strong{color:var(--cinnabar-deep)}.site-foot{border-top:1px solid var(--line-soft);padding:var(--sp-5) 0 var(--sp-4);margin-top:var(--sp-6)}.foot-inner{display:flex;justify-content:space-between;align-items:center;gap:var(--sp-3);flex-wrap:wrap}.foot-brand{display:flex;align-items:center;gap:.8rem;font-family:var(--font-kai);letter-spacing:.3em;color:var(--ink-soft)}.foot-brand .seal{color:var(--cinnabar);border:1.5px solid var(--cinnabar);padding:.24rem .3rem;font-size:.66rem;border-radius:2px}.foot-meta{font-size:var(--fs-xs);color:var(--ink-faint);letter-spacing:.1em;line-height:2}.pill{display:inline-block;padding:.15rem .7rem;border:1px solid var(--line);border-radius:99px;font-size:var(--fs-xs);color:var(--ink-soft);letter-spacing:.15em;margin:.15rem .3rem .15rem 0;background:#fbf9f380}.pill.hot{color:var(--cinnabar);border-color:#a5402d59}.pill.cool{color:var(--celadon-deep);border-color:#5f766059}.center{text-align:center}.mt-1{margin-top:var(--sp-1)}.mt-2{margin-top:var(--sp-2)}.mt-3{margin-top:var(--sp-3)}.mt-4{margin-top:var(--sp-4)}.mt-5{margin-top:var(--sp-5)}.small{font-size:var(--fs-sm)}.tiny{font-size:var(--fs-xs)}.cinnabar{color:var(--cinnabar)}.celadon{color:var(--celadon-deep)}.muted{color:var(--ink-faint)}.fade-up{animation:fadeUp 1s var(--ease-out) both}@keyframes fadeUp{0%{opacity:0;transform:translateY(16px)}to{opacity:1;transform:none}}.delay-1{animation-delay:.12s}.delay-2{animation-delay:.24s}.delay-3{animation-delay:.36s}.separator{display:flex;align-items:center;gap:1rem;color:var(--ink-faint);font-size:var(--fs-xs);letter-spacing:.5em;margin:var(--sp-4) 0}.separator:before,.separator:after{content:"";flex:1;height:1px;background:var(--line-soft)}.back-link{display:inline-flex;align-items:center;gap:.5rem;font-size:var(--fs-sm);letter-spacing:.2em;color:var(--ink-faint);transition:color var(--dur-fast);margin-bottom:var(--sp-3)}.back-link:hover{color:var(--cinnabar)}@media(max-width:760px){.hero-vert{display:none}.art-card{min-height:200px}.brand .sub{display:none}.module-title-row{flex-direction:column;align-items:flex-start;gap:.6rem}.nav-links{gap:.6rem}}@media(prefers-reduced-motion:reduce){*{animation-duration:.01ms!important;transition-duration:.01ms!important;scroll-behavior:auto!important}}.coins{display:flex;gap:1rem;justify-content:center;flex-wrap:wrap}.coin{width:74px;height:74px;border-radius:50%;background:radial-gradient(circle at 32% 28%,#d8c9a0,#a8905e 60%,#8a7448);border:3px solid #6E5B38;box-shadow:inset 0 -6px 12px #3c2d1466,inset 0 4px 8px #fffadc80,0 6px 14px #37342c40;display:flex;align-items:center;justify-content:center;font-family:var(--font-kai);font-size:1.2rem;color:#5c4a26;position:relative}.coin:before{content:"〒";position:absolute;font-size:2rem;color:#5c4a26d9}.coin .face{position:relative;z-index:1;text-align:center;line-height:1.15;font-size:.68rem;letter-spacing:.05em}.yao-row{display:flex;align-items:center;gap:1rem;justify-content:center;padding:.55rem 0;border-bottom:1px dotted var(--line-soft)}.yao-label{width:3.2rem;font-size:var(--fs-xs);color:var(--ink-faint);letter-spacing:.2em;text-align:right;font-variant-numeric:tabular-nums}.yao-glyph{font-size:2rem;line-height:1;letter-spacing:.2em}.yao-move{color:var(--cinnabar);font-size:var(--fs-xs);letter-spacing:.2em}.yao-move .dot{width:.5rem;height:.5rem;border-radius:50%;background:var(--cinnabar);display:inline-block;margin-left:.3rem}.qimen-grid{display:grid;grid-template-columns:repeat(3,1fr);border:1px solid var(--line);border-radius:var(--r-md);overflow:hidden;max-width:560px;margin:0 auto;background:var(--paper-deep)}.qm-cell{aspect-ratio:1;border:1px solid var(--line-soft);padding:.7rem;position:relative;background:linear-gradient(160deg,#fbf9f3b3,#ede8d980)}.qm-cell .qm-name{font-family:var(--font-kai);font-size:1.05rem;color:var(--celadon-deep);letter-spacing:.15em}.qm-cell .qm-items{font-size:.72rem;color:var(--ink-soft);line-height:1.7;letter-spacing:.05em;margin-top:.3rem}.qm-cell .qm-star{font-size:.68rem;color:var(--ink-faint)}.ziwei-grid{display:grid;grid-template-columns:repeat(4,1fr);border:1px solid var(--line);border-radius:var(--r-md);overflow:hidden;max-width:640px;margin:0 auto}.zw-cell{border:1px solid var(--line-soft);padding:.55rem;min-height:96px;background:#fbf9f38c}.zw-cell.center{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.2rem;background:var(--paper-deep)}.zw-cell .zw-name{font-family:var(--font-kai);font-size:.8rem;color:var(--celadon-deep);letter-spacing:.1em;display:flex;justify-content:space-between}.zw-cell .zw-stars{font-size:.62rem;color:var(--ink-soft);line-height:1.8;letter-spacing:.04em}.liuren-stage{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:var(--sp-2)}.liuren-item{padding:1rem;background:#fbf9f38c;border:1px solid var(--line-soft);border-radius:var(--r-sm)}.liuren-item .k{font-size:var(--fs-xs);color:var(--ink-faint);letter-spacing:.3em}.liuren-item .v{font-size:1.2rem;margin-top:.3rem;letter-spacing:.2em;font-family:var(--font-kai)}.motes{position:fixed;top:0;right:0;bottom:0;left:0;pointer-events:none;overflow:hidden;z-index:0}.mote{position:absolute;font-family:var(--font-zm);color:var(--ink-faint);opacity:.2;letter-spacing:.1em;animation:moteFloat var(--mote-duration,10s) ease-in-out infinite;animation-delay:var(--mote-delay,0s);-webkit-user-select:none;-moz-user-select:none;user-select:none;text-shadow:0 1px 6px rgba(255,255,255,.5)}@keyframes moteFloat{0%,to{transform:translateY(0) translate(0);opacity:.16}50%{transform:translateY(-52px) translate(var(--mote-drift,-12px));opacity:.34}}#mountains{animation:inkDrift 90s ease-in-out infinite alternate}@keyframes inkDrift{0%{transform:translate(0) scale(1)}to{transform:translate(-22px) scale(1.03)}}.mist{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none;overflow:hidden;z-index:0}.mist:before,.mist:after{content:"";position:absolute;top:12%;width:60vw;height:34vh;background:radial-gradient(ellipse at center,rgba(150,168,143,.13),transparent 65%);filter:blur(10px);animation:mistDrift 34s ease-in-out infinite alternate}.mist:before{left:-20vw;animation-delay:-8s}.mist:after{right:-22vw;top:26%;width:52vw;animation-delay:-20s}@keyframes mistDrift{0%{transform:translate(0)}to{transform:translate(9vw)}}.hero-glow{position:absolute;width:34vw;height:34vw;border-radius:50%;pointer-events:none;filter:blur(60px);opacity:.5;animation:glowBreath 8s ease-in-out infinite}.hero-glow--left{left:-8vw;top:-6vw;background:radial-gradient(circle,rgba(150,168,143,.22),transparent 70%)}.hero-glow--right{right:-10vw;bottom:-8vw;background:radial-gradient(circle,rgba(124,151,146,.18),transparent 70%);animation-delay:-4s}@keyframes glowBreath{0%,to{opacity:.35;transform:scale(1)}50%{opacity:.6;transform:scale(1.06)}}@media(prefers-reduced-motion:reduce){.mote,#mountains,.mist:before,.mist:after,.hero-glow{animation:none!important}}.tarot-stage{display:flex;justify-content:center;padding:var(--sp-4) 0;position:relative}.tarot-fan{display:flex;justify-content:center;gap:2px;transform:rotate(-4deg)}.tarot-card{width:96px;height:156px;flex-shrink:0;background:linear-gradient(160deg,#f7f2e4,#e6dcbe 70%,#d6c9a4);border:1px solid #C9B98F;border-radius:6px;box-shadow:0 8px 20px -10px #37342c66,inset 0 0 0 4px #c9b98f59;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:transform var(--dur-mid) var(--ease-out);position:relative}.tarot-card:before{content:"✦";font-size:1.4rem;color:#a58d5e}.tarot-card:hover{transform:translateY(-10px) rotate(0)}.tarot-card.picked{transform:translateY(-14px) rotate(0)}.tarot-card .card-inner{position:absolute;top:0;right:0;bottom:0;left:0;padding:.5rem;display:flex;flex-direction:column;align-items:center;justify-content:space-between;background:linear-gradient(170deg,#fdfaf1,#efe6cc);border-radius:5px;opacity:0;transition:opacity var(--dur-mid)}.tarot-card.revealed .card-inner{opacity:1}.card-inner .cn{font-family:var(--font-kai);font-size:1.05rem;color:var(--ink);letter-spacing:.1em}.card-inner .en{font-size:.52rem;color:var(--ink-faint);letter-spacing:.14em}.card-inner .sigil{font-size:1.6rem;color:var(--cinnabar)}.btn-seal:before{z-index:0}.btn-seal>*{position:relative;z-index:1}.btn-seal:hover>*{color:var(--paper)}.btn-seal.btn-ghost:hover>*{color:var(--paper)}#ink-vein{position:fixed;top:0;right:0;bottom:0;left:0;pointer-events:none;z-index:-1;overflow:hidden}#ink-vein .vein-lines{position:absolute;top:0;right:0;bottom:0;left:0;opacity:.05;background-image:repeating-linear-gradient(115deg,transparent 0 38px,rgba(55,52,44,.5) 38px 39px),repeating-linear-gradient(25deg,transparent 0 58px,rgba(55,52,44,.35) 58px 59px);animation:veinFlow 140s linear infinite}@keyframes veinFlow{0%{background-position:0 0,0 0}to{background-position:120px 60px,-80px 40px}}#ink-vein .vein-poem{position:absolute;right:1.6rem;top:50%;transform:translateY(-50%);writing-mode:vertical-rl;font-family:var(--font-kai);font-size:var(--fs-sm);letter-spacing:.9em;color:var(--ink-faint);opacity:.34;-webkit-user-select:none;-moz-user-select:none;user-select:none;animation:poemBreath 9s ease-in-out infinite;white-space:nowrap}@keyframes poemBreath{0%,to{opacity:.22}50%{opacity:.42}}#ink-vein .vein-seal{position:absolute;right:2.2rem;bottom:6.5rem;font-family:var(--font-kai);font-size:.6rem;letter-spacing:.2em;color:var(--cinnabar);opacity:.4;border:1px solid rgba(165,64,45,.5);padding:.3rem .34rem;border-radius:2px;animation:poemBreath 7s ease-in-out infinite;animation-delay:-3s}@media(max-width:860px){#ink-vein .vein-poem,#ink-vein .vein-seal{display:none}}.has-sub{position:relative}.sub-menu{position:absolute;top:calc(100% + .4rem);left:50%;transform:translate(-50%) translateY(-6px);min-width:9.5rem;padding:.5rem 0;background:var(--white-paper);border:1px solid var(--line);border-radius:var(--r-md);box-shadow:var(--shadow-paper);opacity:0;visibility:hidden;transition:all var(--dur-mid) var(--ease-out);z-index:60}.has-sub:hover .sub-menu,.has-sub:focus-within .sub-menu{opacity:1;visibility:visible;transform:translate(-50%) translateY(0)}.sub-menu a{display:block;padding:.42rem 1.2rem;font-size:var(--fs-sm);letter-spacing:.2em;color:var(--ink-soft);text-align:left;white-space:nowrap}.sub-menu a:hover{color:var(--cinnabar);background:var(--cinnabar-tint)}.song-select{position:relative;width:100%}.song-select .trigger{width:100%;padding:.6rem .8rem;display:flex;align-items:center;justify-content:space-between;gap:.6rem;background:#fbf9f399;border:1px solid var(--line);border-radius:var(--r-sm);font-size:var(--fs-base);color:var(--ink);cursor:pointer;text-align:left;transition:border-color var(--dur-fast),box-shadow var(--dur-fast)}.song-select .trigger:hover{border-color:var(--celadon)}.song-select.open .trigger{border-color:var(--celadon-deep);box-shadow:0 0 0 3px #5f76601f}.song-select .trigger:after{content:"";width:7px;height:7px;flex-shrink:0;border-right:1.5px solid var(--ink-soft);border-bottom:1.5px solid var(--ink-soft);transform:rotate(45deg) translateY(-2px);transition:transform var(--dur-fast)}.song-select.open .trigger:after{transform:rotate(225deg) translateY(1px)}.song-select .panel{position:absolute;top:calc(100% + .35rem);left:0;right:0;max-height:240px;overflow-y:auto;background:var(--white-paper);border:1px solid var(--line);border-radius:var(--r-md);box-shadow:var(--shadow-paper);z-index:70;padding:.35rem 0;animation:viewIn .25s var(--ease-out) both}.song-select .panel button{display:block;width:100%;padding:.5rem .9rem;text-align:left;font-size:var(--fs-sm);letter-spacing:.1em;color:var(--ink-soft);transition:background var(--dur-fast),color var(--dur-fast)}.song-select .panel button:hover{background:var(--celadon-tint);color:var(--ink)}.song-select .panel button.sel{color:var(--celadon-deep);font-weight:600}.song-select .panel button.sel:before{content:"◆ ";font-size:.62rem}.song-dialog-mask{position:fixed;top:0;right:0;bottom:0;left:0;background:#37342c59;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);display:flex;align-items:center;justify-content:center;z-index:200;animation:fadeUp .3s var(--ease-out) both}.song-dialog{width:min(420px,90vw);padding:var(--sp-4);background:linear-gradient(175deg,var(--white-paper),var(--paper-deep));border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow-paper);animation:viewIn .35s var(--ease-out) both}.song-dialog .dlg-title{font-family:var(--font-kai);font-size:1.15rem;letter-spacing:.25em;color:var(--ink);display:flex;align-items:center;gap:.6rem;padding-bottom:var(--sp-2);border-bottom:1px solid var(--line-soft);margin-bottom:var(--sp-3)}.song-dialog .dlg-title:before{content:"❖";color:var(--cinnabar);font-size:.9rem}.song-dialog .dlg-body{color:var(--ink-soft);font-size:var(--fs-sm);line-height:2.1;letter-spacing:.05em}.song-dialog .dlg-actions{display:flex;gap:.8rem;justify-content:flex-end;margin-top:var(--sp-4)}.casting-glyph{animation:castSpin 2.4s var(--ease-ink) infinite}@keyframes castSpin{0%{transform:rotate(0) scale(1);opacity:.7}50%{transform:rotate(180deg) scale(1.08);opacity:1}to{transform:rotate(360deg) scale(1);opacity:.7}}.casting-ring{position:relative;width:4.4rem;height:4.4rem;border-radius:50%;margin:0 auto .8rem;border:1px dashed var(--celadon);animation:ringExpand 2.4s var(--ease-ink) infinite}@keyframes ringExpand{0%{transform:scale(.75);opacity:.5}50%{transform:scale(1);opacity:1}to{transform:scale(.75);opacity:.5}}.stagger>*{animation:fadeUp .7s var(--ease-out) both}.stagger>*:nth-child(1){animation-delay:.05s}.stagger>*:nth-child(2){animation-delay:.16s}.stagger>*:nth-child(3){animation-delay:.27s}.stagger>*:nth-child(4){animation-delay:.38s}.stagger>*:nth-child(5){animation-delay:.49s}.bazi-pan{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--sp-2);max-width:640px;margin:0 auto}.bz-pillar{background:#fbf9f38c;border:1px solid var(--line-soft);border-radius:var(--r-sm);padding:.9rem .5rem;text-align:center;position:relative;overflow:hidden;transition:border-color var(--dur-mid),transform var(--dur-mid)}.bz-pillar:hover{border-color:var(--celadon);transform:translateY(-2px)}.bz-pillar .p-name{font-size:var(--fs-xs);color:var(--ink-faint);letter-spacing:.3em;margin-bottom:.5rem}.bz-pillar .p-gan{font-family:var(--font-kai);font-size:2rem;line-height:1.15;display:block}.bz-pillar .p-zhi{font-family:var(--font-kai);font-size:2rem;line-height:1.15;display:block;margin-top:.15rem}.bz-pillar .p-wx{font-size:var(--fs-xs);margin-top:.4rem;letter-spacing:.2em}.bz-pillar .p-shishen{font-size:var(--fs-xs);color:var(--celadon-deep);margin-top:.2rem;letter-spacing:.1em}.bz-pillar .p-nayin{font-size:.62rem;color:var(--ink-faint);margin-top:.3rem;letter-spacing:.08em;border-top:1px dotted var(--line-soft);padding-top:.35rem}.bz-pillar.day-pillar{border-color:var(--cinnabar);background:linear-gradient(175deg,#f3e3dc80,#fbf9f399);box-shadow:0 0 0 1px #a5402d26}.bz-pillar.day-pillar .p-name{color:var(--cinnabar)}.bz-pillar .p-zhu{position:absolute;top:.35rem;right:.5rem;font-size:.6rem;color:var(--ink-faint);letter-spacing:.15em}.zw-cell{transition:background var(--dur-mid),box-shadow var(--dur-mid)}.zw-cell.ming-cell{background:linear-gradient(175deg,#f3e3dc8c,#fbf9f380);box-shadow:inset 0 0 0 1px #a5402d40}.zw-cell .zw-stars .star-name{display:inline-block;padding:.06rem .22rem;border-radius:2px;margin-right:.14rem}.zw-cell .zw-stars .star-name.star-hot{color:var(--cinnabar);background:#a5402d14}.zw-cell .zw-stars .star-name.star-cool{color:var(--celadon-deep);background:#5f766014}.tarot-slot{display:flex;flex-direction:column;align-items:center;gap:.5rem}.tarot-slot .slot-label{font-size:var(--fs-xs);color:var(--ink-faint);letter-spacing:.25em;text-align:center;max-width:110px;line-height:1.6}.tarot-fan .tarot-card.face-down:after{content:"";position:absolute;top:6px;right:6px;bottom:6px;left:6px;border:1px solid rgba(165,92,62,.35);border-radius:3px}@media(prefers-reduced-motion:reduce){#ink-vein .vein-lines,#ink-vein .vein-poem,.casting-glyph,.casting-ring{animation:none!important}}.btn-seal{isolation:isolate}.btn-seal:before{z-index:-1;transform-origin:top}.btn-seal:hover{color:var(--paper)}.btn-seal .sb-label{position:relative;z-index:1}.btn-seal:hover .sb-label{color:var(--paper)}.arts-sub{padding:.6rem .4rem .8rem}.sub-group{margin-bottom:.3rem}.sub-group-name{font-size:.62rem;letter-spacing:.35em;color:var(--ink-faint);padding:.35rem .9rem .2rem;border-bottom:1px dotted var(--line-soft);margin-bottom:.2rem}.sub-group a{display:flex;align-items:baseline;gap:.55rem;font-size:var(--fs-sm);letter-spacing:.18em;color:var(--ink-soft);padding:.4rem .9rem;border-radius:var(--r-sm)}.sub-group a:hover{color:var(--cinnabar);background:var(--cinnabar-tint)}.sub-group .sub-glyph{font-family:var(--font-zm);color:var(--celadon-deep);font-size:.95rem}.sub-group .sub-poem{margin-left:auto;font-size:.6rem;color:var(--ink-faint);letter-spacing:.1em;white-space:nowrap}.user-menu .user-chip{display:flex;align-items:center;gap:.45rem;padding:.28rem .7rem .28rem .32rem;border:1px solid var(--line);border-radius:99px;background:#fbf9f3b3;cursor:pointer;transition:border-color var(--dur-fast),box-shadow var(--dur-fast)}.user-menu .user-chip:hover{border-color:var(--celadon);box-shadow:0 0 0 3px #5f76601a}.user-menu .user-seal{width:1.7rem;height:1.7rem;border-radius:50%;display:flex;align-items:center;justify-content:center;background:var(--celadon-deep);color:var(--paper);font-family:var(--font-kai);font-size:.85rem;flex-shrink:0}.user-menu .user-name{font-size:var(--fs-sm);letter-spacing:.12em;color:var(--ink);max-width:5rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.user-menu .user-caret{font-size:.62rem;color:var(--ink-faint)}.user-menu .sub-menu a{padding:.5rem 1.2rem}.side-anchor{position:fixed;left:1.4rem;top:50%;transform:translateY(-50%);display:flex;flex-direction:column;gap:.9rem;z-index:30}.side-anchor button{display:flex;align-items:center;gap:.5rem;font-size:var(--fs-xs);letter-spacing:.25em;color:var(--ink-faint);writing-mode:vertical-rl;transition:color var(--dur-fast);cursor:pointer;padding:.15rem 0}.side-anchor .dot{width:5px;height:5px;border-radius:50%;background:currentColor;opacity:.5;flex-shrink:0}.side-anchor button:hover{color:var(--ink)}.side-anchor button.active{color:var(--cinnabar)}.side-anchor button.active .dot{opacity:1;box-shadow:0 0 0 3px #a5402d26}@media(max-width:1100px){.side-anchor{display:none}}.song-search .panel{width:100%}.song-search .ss-search{padding:.5rem .7rem .35rem}.song-search .ss-input{width:100%;padding:.42rem .6rem;background:#fbf9f3cc;border:1px solid var(--line);border-radius:var(--r-sm);font-size:var(--fs-sm)}.song-search .ss-input:focus{outline:none;border-color:var(--celadon-deep)}.song-search .ss-list{max-height:220px;overflow-y:auto;padding:.2rem 0}.song-search .ss-empty{padding:.8rem;text-align:center;color:var(--ink-faint);font-size:var(--fs-xs);letter-spacing:.2em}.song-select .trigger:after{display:none}.song-select .trigger .chev{flex-shrink:0;color:var(--ink-faint);transition:transform var(--dur-fast)}.song-select.open .trigger .chev{transform:rotate(180deg);color:var(--celadon-deep)}.song-select .trigger{line-height:1.6}.song-select .panel{left:0;right:0}.user-menu .sub-menu{right:0;left:auto;transform:none;min-width:8.5rem}.user-menu:hover .sub-menu{transform:none}.cal-input{position:relative}.cal-field{display:flex;gap:.4rem;align-items:center}.cal-field .input-line{flex:1}.cal-field input.cal-error{border-color:var(--cinnabar)}.cal-toggle{display:flex;align-items:center;justify-content:center;width:2.3rem;height:2.3rem;flex-shrink:0;border:1px solid var(--line);border-radius:var(--r-sm);background:#fbf9f399;color:var(--ink-soft);cursor:pointer;transition:border-color var(--dur-fast),color var(--dur-fast)}.cal-toggle:hover{border-color:var(--celadon);color:var(--celadon-deep)}.cal-panel{position:absolute;top:calc(100% + .35rem);left:0;z-index:70;width:min(290px,90vw);padding:.7rem;background:var(--white-paper);border:1px solid var(--line);border-radius:var(--r-md);box-shadow:var(--shadow-paper);animation:viewIn .25s var(--ease-out) both}.cal-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:.5rem}.cal-title{font-family:var(--font-kai);font-size:.95rem;letter-spacing:.15em;color:var(--ink)}.cal-nav{display:flex;padding:.25rem;color:var(--ink-faint);cursor:pointer;border-radius:var(--r-sm)}.cal-nav:hover{color:var(--cinnabar);background:var(--cinnabar-tint)}.cal-week{display:grid;grid-template-columns:repeat(7,1fr);text-align:center;font-size:.62rem;color:var(--ink-faint);letter-spacing:.1em;margin-bottom:.2rem}.cal-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:2px}.cal-grid button{aspect-ratio:1;display:flex;align-items:center;justify-content:center;font-size:var(--fs-sm);color:var(--ink-soft);border-radius:var(--r-sm);cursor:pointer;transition:background var(--dur-fast),color var(--dur-fast)}.cal-grid button:hover{background:var(--celadon-tint);color:var(--ink)}.cal-grid button.sel{background:var(--celadon-deep);color:var(--paper);font-weight:600}.song-search .ss-custom{width:100%;padding:.6rem .9rem;text-align:center;font-size:var(--fs-sm);color:var(--celadon-deep);letter-spacing:.1em;cursor:pointer}.song-search .ss-custom:hover{background:var(--celadon-tint)}.song-select .trigger .chev,.song-search .trigger .chev{width:16px;height:16px;stroke-width:2.4}.nav-links .has-sub>a .chev-mini{width:14px;height:14px;stroke-width:2.2;vertical-align:-2px}.user-menu .user-caret{display:inline-flex;width:14px;height:14px}.user-menu .user-caret svg{width:14px;height:14px;stroke-width:2.2}.song-select .panel button,.song-select .trigger span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.song-select{min-width:0}.song-select .trigger{min-height:2.55rem}.song-select .panel{min-width:100%;width:-moz-max-content;width:max-content;max-width:16rem}.song-select .panel button{font-size:var(--fs-sm)}.altar-panel{position:sticky;top:84px;max-height:calc(100vh - 108px);overflow-y:auto;scrollbar-width:thin}.altar-panel::-webkit-scrollbar{width:4px}.altar-panel::-webkit-scrollbar-thumb{background:var(--celadon);border-radius:2px}@media(max-width:960px){.altar-panel{position:static;max-height:none;overflow:visible}}.altar-result{padding-bottom:var(--sp-2)}.bamboo-art{position:absolute;right:1rem;top:50%;transform:translateY(-50%);width:min(300px,30vw);pointer-events:none;opacity:.85}.bamboo-art svg{width:100%;height:auto;filter:drop-shadow(0 6px 18px rgba(95,118,96,.12))}.page-decor{position:relative}.page-decor .wrap{position:relative;z-index:1}@media(max-width:900px){.bamboo-art{display:none}}.nav-links a{white-space:nowrap}.nav-links .has-sub>a{display:inline-flex;align-items:center;gap:.28rem}.nav-links .has-sub>a .chev-mini{flex-shrink:0}.tarot-fan{transform:none;align-items:flex-start;gap:.9rem}.tarot-slot{width:104px}.tarot-slot .tarot-card{margin:0 auto}.tarot-slot .slot-label{min-height:2.6em;display:flex;align-items:flex-start;justify-content:center}.tarot-stage .tarot-fan.wrap-fan{max-width:640px}.center-actions{display:flex;gap:.8rem;justify-content:center;align-items:center;flex-wrap:wrap}.today-grid{display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-4);align-items:stretch}.today-grid .result-card{display:flex;flex-direction:column;margin-bottom:0;min-height:220px}.today-grid .result-card .result-text{flex:1}@media(max-width:860px){.today-grid{grid-template-columns:1fr}}.scroll-hint{transition:opacity .6s var(--ease-out),visibility .6s}.zw-palace-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:var(--sp-2);margin-top:var(--sp-3)}.zw-palace-cell{padding:.7rem .8rem;background:#fbf9f38c;border:1px solid var(--line-soft);border-radius:var(--r-sm);transition:border-color var(--dur-mid),background var(--dur-mid)}.zw-palace-cell:hover{border-color:var(--celadon)}.zw-palace-cell.is-ming{background:linear-gradient(175deg,#f3e3dc8c,#fbf9f380);border-color:#a5402d59}.zw-palace-cell.empty{opacity:.55}.zp-head{display:flex;align-items:baseline;gap:.4rem;border-bottom:1px dotted var(--line-soft);padding-bottom:.3rem;margin-bottom:.35rem}.zp-name{font-family:var(--font-kai);font-size:.92rem;color:var(--celadon-deep);letter-spacing:.12em}.zp-zhi{font-size:.66rem;color:var(--ink-faint)}.zp-ming{margin-left:auto;font-size:.6rem;color:var(--cinnabar);border:1px solid rgba(165,64,45,.4);padding:0 .3rem;border-radius:2px}.zp-stars{font-size:.72rem;color:var(--ink-soft);line-height:1.7;letter-spacing:.06em;min-height:1.7em}.zp-theme{font-size:.62rem;color:var(--ink-faint);letter-spacing:.15em;margin-top:.2rem}.hero{padding-bottom:calc(var(--sp-6) + 2.2rem)}.scroll-hint{position:absolute;bottom:1.1rem;left:50%;transform:translate(-50%);display:flex;align-items:center;gap:.55rem;font-size:var(--fs-xs);letter-spacing:.35em;color:var(--ink-faint);writing-mode:horizontal-tb;animation:floatHintX 3s var(--ease-ink) infinite;z-index:2}.scroll-hint svg{width:14px;height:14px;animation:hintBounce 1.6s ease-in-out infinite}@keyframes floatHintX{0%,to{transform:translate(-50%) translateY(0)}50%{transform:translate(-50%) translateY(7px)}}@keyframes hintBounce{0%,to{transform:translateY(0)}50%{transform:translateY(3px)}}.scroll-hint.hidden{opacity:0;visibility:hidden}.btn-row{display:flex;gap:.8rem;align-items:center;flex-wrap:wrap}.btn-row .btn-seal,.btn-row a.btn-seal{display:inline-flex;align-items:center;justify-content:center}.dlg-actions,.center-actions{align-items:center}.report-list{margin:0;padding-left:1.2rem;color:var(--ink-soft);font-size:var(--fs-sm);line-height:2.1;letter-spacing:.04em}.report-list li::marker{color:var(--celadon-deep)}.trait-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:var(--sp-2)}.trait-cell{padding:.9rem;background:#fbf9f38c;border:1px solid var(--line-soft);border-radius:var(--r-sm);border-top:2px solid var(--celadon)}.trait-name{font-family:var(--font-kai);font-size:.98rem;color:var(--celadon-deep);letter-spacing:.15em;margin-bottom:.3rem}.trait-desc{font-size:var(--fs-sm);color:var(--ink-soft);line-height:1.9}.timeline{position:relative;padding-left:1.4rem}.timeline:before{content:"";position:absolute;left:.32rem;top:.3rem;bottom:.3rem;width:1px;background:var(--line)}.tl-item{position:relative;padding-bottom:var(--sp-3)}.tl-marker{position:absolute;left:-1.4rem;top:.25rem;width:.66rem;height:.66rem;border-radius:50%;background:var(--paper);border:2px solid var(--celadon-deep);display:flex;align-items:center;justify-content:center}.tl-item:first-child .tl-marker{background:var(--celadon-deep)}.tl-head{display:flex;align-items:baseline;gap:.6rem}.tl-head strong{font-family:var(--font-kai);font-size:.95rem;color:var(--ink);letter-spacing:.12em}.tl-age{font-size:var(--fs-xs);color:var(--ink-faint);letter-spacing:.15em}.tl-summary{font-size:var(--fs-sm);color:var(--ink-soft);line-height:2;margin-top:.2rem}.domain-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:var(--sp-2)}.domain-cell{padding:.9rem;background:#fbf9f38c;border:1px solid var(--line-soft);border-radius:var(--r-sm)}.domain-name{font-family:var(--font-kai);font-size:.9rem;color:var(--cinnabar);letter-spacing:.25em;margin-bottom:.4rem;border-bottom:1px dotted var(--line-soft);padding-bottom:.3rem}.domain-cell p{font-size:var(--fs-sm);color:var(--ink-soft);line-height:1.95;margin-top:.2rem}.fit-note{padding:var(--sp-2) var(--sp-3);margin-bottom:var(--sp-3);background:var(--rice-tint);border:1px solid rgba(217,205,172,.6);border-left:3px solid var(--rice);border-radius:var(--r-md);font-size:var(--fs-sm);color:var(--ink-soft);line-height:2}.fit-note strong{color:var(--ink);letter-spacing:.15em}.fit-note .fit-suggest{color:var(--cinnabar);margin-top:.3rem}.fit-card.fit-partial{border-left-color:var(--rice)}.fit-card.fit-bad{border-left-color:var(--cinnabar)}.fit-card.fit-ok{border-left-color:var(--celadon)}.scroll-hint.inline-hint{position:static;transform:none;margin-top:2.2rem;writing-mode:horizontal-tb;animation:none}.scroll-hint.inline-hint svg{width:15px;height:15px;animation:hintBounce 1.6s ease-in-out infinite}.hero{padding-bottom:var(--sp-6)}.ai-streaming{border:1px dashed var(--celadon);border-radius:var(--r-md);padding:var(--sp-3);background:#e3e8dc40}.ai-stream-head{display:flex;align-items:center;gap:.6rem}.ai-spinner{width:15px;height:15px;border-radius:50%;flex-shrink:0;border:2px solid var(--celadon);border-top-color:transparent;animation:castSpin 1s linear infinite}.ai-stream-body{margin-top:.7rem;max-height:260px;overflow-y:auto;padding:.6rem .8rem;background:#fbf9f3b3;border-radius:var(--r-sm);scrollbar-width:thin}.ai-error{border:1px solid rgba(165,64,45,.3);border-radius:var(--r-md);padding:var(--sp-3);background:#f3e3dc4d}.shichen-chip{display:inline-flex;align-items:center;justify-content:center;padding:.4rem .9rem;flex-shrink:0;white-space:nowrap;background:var(--celadon-tint);border:1px solid var(--celadon);border-radius:var(--r-sm);font-size:var(--fs-xs);color:var(--celadon-deep);letter-spacing:.15em}.profile-card{display:flex;align-items:center;gap:1rem;cursor:pointer;padding:1rem 1.2rem;background:linear-gradient(175deg,var(--white-paper),var(--paper-deep));border:1px solid var(--line);border-radius:var(--r-md);transition:border-color var(--dur-mid),box-shadow var(--dur-mid),transform var(--dur-mid)}.profile-card:hover{border-color:var(--celadon);box-shadow:var(--shadow-paper);transform:translateY(-2px)}.profile-card.primary{border-left:3px solid var(--cinnabar)}.pc-badge{flex-shrink:0;width:2rem;height:2rem;border-radius:50%;display:flex;align-items:center;justify-content:center;background:var(--cinnabar);color:var(--paper);font-family:var(--font-kai);font-size:.85rem}.pc-badge.sample{background:var(--celadon-deep)}.pc-body{flex:1;min-width:0}.pc-title{font-family:var(--font-kai);font-size:.98rem;color:var(--ink);letter-spacing:.12em;margin-bottom:.2rem}.pc-info{font-size:var(--fs-xs);color:var(--ink-faint);letter-spacing:.06em;line-height:1.8;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pc-action{flex-shrink:0;font-size:var(--fs-xs);color:var(--celadon-deep);letter-spacing:.2em}.module-hero.compact{padding:var(--sp-3) 0 var(--sp-2)}.mh-row{display:flex;align-items:baseline;gap:1.2rem;flex-wrap:wrap}.mh-row .back-link{margin-bottom:0;flex-shrink:0}.mh-row .module-title{margin-top:0;font-size:var(--fs-xl);display:flex;align-items:baseline;gap:.9rem;letter-spacing:.14em}.mh-row .module-title .cn{font-size:clamp(1.5rem,3vw,2.2rem);display:inline}.mh-row .mh-sub{font-family:var(--font-kai);font-size:var(--fs-sm);color:var(--ink-faint);letter-spacing:.25em;white-space:nowrap}.mh-row .mh-kicker{margin-left:auto;font-size:var(--fs-xs);letter-spacing:.3em;color:var(--ink-faint);white-space:nowrap}@media(max-width:640px){.mh-row .mh-kicker{white-space:normal;letter-spacing:.15em;line-height:1.6;max-width:16em;text-align:right}}.mh-intro{margin-top:.4rem;max-width:72ch}.mh-intro summary{cursor:pointer;font-size:var(--fs-xs);letter-spacing:.25em;color:var(--celadon-deep);list-style:none;display:inline-flex;align-items:center;gap:.4rem;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mh-intro summary:before{content:"▸";font-size:.7rem;transition:transform var(--dur-fast)}.mh-intro[open] summary:before{transform:rotate(90deg)}.mh-intro p{font-size:var(--fs-sm);color:var(--ink-soft);line-height:2;margin-top:.5rem}
|
package/dist/favicon.svg
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<!-- 墨绿圆底 -->
|
|
3
|
+
<circle cx="16" cy="16" r="16" fill="#2C3A33"/>
|
|
4
|
+
<!-- 纸色外圆 -->
|
|
5
|
+
<circle cx="16" cy="16" r="10" fill="#F5EFE0"/>
|
|
6
|
+
<!-- 太极黑鱼(S 形分割) -->
|
|
7
|
+
<path d="M16 6 A10 10 0 0 1 16 26 A5 5 0 0 1 16 16 A5 5 0 0 0 16 6 Z" fill="#2C3A33"/>
|
|
8
|
+
<!-- 黑鱼之眼(纸色) -->
|
|
9
|
+
<circle cx="16" cy="21" r="1.7" fill="#F5EFE0"/>
|
|
10
|
+
<!-- 白鱼之眼(墨色) -->
|
|
11
|
+
<circle cx="16" cy="11" r="1.7" fill="#2C3A33"/>
|
|
12
|
+
</svg>
|
package/dist/index.html
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>观微 · 玄学问道 —— 九术参详,观微知著</title>
|
|
8
|
+
<meta name="description" content="以纸墨留白为骨,融四柱八字、紫微斗数、奇门遁甲、梅花易数、六爻、大六壬、小六壬、星盘、塔罗九术于一体。观微知著,以术问道。" />
|
|
9
|
+
<script type="module" crossorigin src="/assets/index-CsOD5rSo.js"></script>
|
|
10
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DQx62TUr.css">
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<div id="root"></div>
|
|
14
|
+
</body>
|
|
15
|
+
</html>
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import js from '@eslint/js'
|
|
2
|
+
import globals from 'globals'
|
|
3
|
+
import reactHooks from 'eslint-plugin-react-hooks'
|
|
4
|
+
import reactRefresh from 'eslint-plugin-react-refresh'
|
|
5
|
+
import tseslint from 'typescript-eslint'
|
|
6
|
+
|
|
7
|
+
export default tseslint.config(
|
|
8
|
+
{ ignores: ['dist'] },
|
|
9
|
+
{
|
|
10
|
+
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
|
11
|
+
files: ['**/*.{ts,tsx}'],
|
|
12
|
+
languageOptions: {
|
|
13
|
+
ecmaVersion: 2020,
|
|
14
|
+
globals: globals.browser,
|
|
15
|
+
},
|
|
16
|
+
plugins: {
|
|
17
|
+
'react-hooks': reactHooks,
|
|
18
|
+
'react-refresh': reactRefresh,
|
|
19
|
+
},
|
|
20
|
+
rules: {
|
|
21
|
+
...reactHooks.configs.recommended.rules,
|
|
22
|
+
'react-refresh/only-export-components': [
|
|
23
|
+
'warn',
|
|
24
|
+
{ allowConstantExport: true },
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
)
|
package/index.html
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>观微 · 玄学问道 —— 九术参详,观微知著</title>
|
|
8
|
+
<meta name="description" content="以纸墨留白为骨,融四柱八字、紫微斗数、奇门遁甲、梅花易数、六爻、大六壬、小六壬、星盘、塔罗九术于一体。观微知著,以术问道。" />
|
|
9
|
+
<script type="module">
|
|
10
|
+
if (import.meta.hot?.on) {
|
|
11
|
+
import.meta.hot.on('vite:error', (error) => {
|
|
12
|
+
if (error.err) {
|
|
13
|
+
console.error(
|
|
14
|
+
[error.err.message, error.err.frame].filter(Boolean).join('\n'),
|
|
15
|
+
)
|
|
16
|
+
}
|
|
17
|
+
})
|
|
18
|
+
}
|
|
19
|
+
</script>
|
|
20
|
+
</head>
|
|
21
|
+
<body>
|
|
22
|
+
<div id="root"></div>
|
|
23
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
24
|
+
</body>
|
|
25
|
+
</html>
|
package/package.json
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "guanwei",
|
|
3
|
+
"private": false,
|
|
4
|
+
"version": "1.1.1",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"test": "vitest run",
|
|
9
|
+
"build": "tsc -b && vite build",
|
|
10
|
+
"lint": "eslint .",
|
|
11
|
+
"preview": "vite preview",
|
|
12
|
+
"check": "tsc -b --noEmit",
|
|
13
|
+
"cli": "./scripts/guanwei",
|
|
14
|
+
"prepublishOnly": "npm run build"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"express": "^4.18.2",
|
|
18
|
+
"cors": "^2.8.5",
|
|
19
|
+
"tsx": "^4.7.0",
|
|
20
|
+
"astronomy-engine": "^2.1.19",
|
|
21
|
+
"lunar-typescript": "^1.8.6",
|
|
22
|
+
"iztro": "2.6.0",
|
|
23
|
+
"vite": "^6.3.5",
|
|
24
|
+
"@vitejs/plugin-react": "^4.4.1",
|
|
25
|
+
"vite-tsconfig-paths": "^5.1.4"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@eslint/js": "^9.25.0",
|
|
29
|
+
"@testing-library/dom": "^10.4.1",
|
|
30
|
+
"@testing-library/react": "^16.3.2",
|
|
31
|
+
"@types/express": "^4.17.21",
|
|
32
|
+
"@types/node": "^22.15.30",
|
|
33
|
+
"@types/react": "^18.3.12",
|
|
34
|
+
"@types/react-dom": "^18.3.1",
|
|
35
|
+
"@vitejs/plugin-react": "^4.4.1",
|
|
36
|
+
"autoprefixer": "^10.4.21",
|
|
37
|
+
"clsx": "^2.1.1",
|
|
38
|
+
"eslint": "^9.25.0",
|
|
39
|
+
"eslint-plugin-react-hooks": "^5.2.0",
|
|
40
|
+
"eslint-plugin-react-refresh": "^0.4.19",
|
|
41
|
+
"globals": "^16.0.0",
|
|
42
|
+
"jsdom": "^30.0.1",
|
|
43
|
+
"lucide-react": "^0.511.0",
|
|
44
|
+
"playwright": "^1.62.1",
|
|
45
|
+
"postcss": "^8.5.3",
|
|
46
|
+
"react": "^18.3.1",
|
|
47
|
+
"react-dom": "^18.3.1",
|
|
48
|
+
"react-router-dom": "^7.3.0",
|
|
49
|
+
"tailwind-merge": "^3.0.2",
|
|
50
|
+
"tailwindcss": "^3.4.17",
|
|
51
|
+
"typescript": "~5.8.3",
|
|
52
|
+
"typescript-eslint": "^8.30.1",
|
|
53
|
+
"vite-tsconfig-paths": "^5.1.4",
|
|
54
|
+
"vitest": "^4.1.10",
|
|
55
|
+
"zustand": "^5.0.3"
|
|
56
|
+
},
|
|
57
|
+
"description": "观微 Guanwei · 九术排盘与 AI 深度解读(八字/紫微/星盘/奇门/六爻/六壬/梅花/小六壬/塔罗)",
|
|
58
|
+
"bin": {
|
|
59
|
+
"guanwei": "scripts/guanwei"
|
|
60
|
+
},
|
|
61
|
+
"files": [
|
|
62
|
+
"dist",
|
|
63
|
+
"src",
|
|
64
|
+
"server/src",
|
|
65
|
+
"shared",
|
|
66
|
+
"scripts",
|
|
67
|
+
"public",
|
|
68
|
+
"index.html",
|
|
69
|
+
"vite.config.ts",
|
|
70
|
+
"tsconfig.json",
|
|
71
|
+
"tailwind.config.js",
|
|
72
|
+
"postcss.config.js",
|
|
73
|
+
"eslint.config.js",
|
|
74
|
+
"README.md"
|
|
75
|
+
],
|
|
76
|
+
"keywords": [
|
|
77
|
+
"chinese-astrology",
|
|
78
|
+
"bazi",
|
|
79
|
+
"ziwei",
|
|
80
|
+
"qimen",
|
|
81
|
+
"tarot",
|
|
82
|
+
"divination",
|
|
83
|
+
"metaphysics",
|
|
84
|
+
"llm",
|
|
85
|
+
"ai",
|
|
86
|
+
"typescript"
|
|
87
|
+
],
|
|
88
|
+
"license": "MIT",
|
|
89
|
+
"repository": {
|
|
90
|
+
"type": "git",
|
|
91
|
+
"url": "git+https://github.com/RubyCcll/guanwei.git"
|
|
92
|
+
},
|
|
93
|
+
"engines": {
|
|
94
|
+
"node": ">=18"
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<!-- 墨绿圆底 -->
|
|
3
|
+
<circle cx="16" cy="16" r="16" fill="#2C3A33"/>
|
|
4
|
+
<!-- 纸色外圆 -->
|
|
5
|
+
<circle cx="16" cy="16" r="10" fill="#F5EFE0"/>
|
|
6
|
+
<!-- 太极黑鱼(S 形分割) -->
|
|
7
|
+
<path d="M16 6 A10 10 0 0 1 16 26 A5 5 0 0 1 16 16 A5 5 0 0 0 16 6 Z" fill="#2C3A33"/>
|
|
8
|
+
<!-- 黑鱼之眼(纸色) -->
|
|
9
|
+
<circle cx="16" cy="21" r="1.7" fill="#F5EFE0"/>
|
|
10
|
+
<!-- 白鱼之眼(墨色) -->
|
|
11
|
+
<circle cx="16" cy="11" r="1.7" fill="#2C3A33"/>
|
|
12
|
+
</svg>
|
package/scripts/guanwei
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ============================================================
|
|
3
|
+
# 观微 Guanwei CLI(支持:npm 全局安装 / npm link / 本地源码)
|
|
4
|
+
#
|
|
5
|
+
# 用法:
|
|
6
|
+
# guanwei setup [--key xxx] [--provider xxx] 配置 API Key(存 ~/.guanwei/.env,更新不丢)
|
|
7
|
+
# guanwei start [--dev] [--port 5173] 启动并自动打开浏览器
|
|
8
|
+
# guanwei update 更新到最新版(全局:npm 升级;本地:git 增量合并)
|
|
9
|
+
# guanwei check / status 版本检查 / 状态
|
|
10
|
+
# guanwei doctor 环境自检
|
|
11
|
+
# guanwei stop 停止服务
|
|
12
|
+
# guanwei web 仅打开浏览器
|
|
13
|
+
# guanwei --help 帮助
|
|
14
|
+
# ============================================================
|
|
15
|
+
set -uo pipefail
|
|
16
|
+
|
|
17
|
+
# ── 定位项目根(支持 npm link / npm 全局安装的符号链接)──
|
|
18
|
+
SCRIPT_PATH=$(node -e "process.stdout.write(require('fs').realpathSync(process.argv[1]))" "$0" 2>/dev/null || echo "$0")
|
|
19
|
+
ROOT=$(cd "$(dirname "${SCRIPT_PATH}")/.." && pwd)
|
|
20
|
+
GUANWEI_HOME="${GUANWEI_HOME:-${HOME}/.guanwei}"
|
|
21
|
+
ENV_FILE="${GUANWEI_HOME}/.env"
|
|
22
|
+
VERSION=$(node -e "console.log(require('${ROOT}/package.json').version)" 2>/dev/null || echo "?")
|
|
23
|
+
HEAD=$(git -C "${ROOT}" rev-parse --short HEAD 2>/dev/null || echo "pkg")
|
|
24
|
+
if [[ -d "${ROOT}/.git" ]]; then MODE="local"; else MODE="global"; fi
|
|
25
|
+
|
|
26
|
+
remote_head() { git ls-remote origin -h refs/heads/main 2>/dev/null | cut -f1; }
|
|
27
|
+
latest_tag() { git ls-remote --tags origin 'refs/tags/v*' 2>/dev/null | sed 's|.*refs/tags/||' | sort -V | tail -1; }
|
|
28
|
+
|
|
29
|
+
cmd_help() {
|
|
30
|
+
sed -n '3,19p' "$0" | sed 's/^# \{0,1\}//'
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
cmd_check() {
|
|
34
|
+
if [[ "${MODE}" == "global" ]]; then
|
|
35
|
+
local latest
|
|
36
|
+
latest=$(npm view guanwei version 2>/dev/null || echo "?")
|
|
37
|
+
if [[ "${latest}" == "${VERSION}" || "${latest}" == "?" ]]; then
|
|
38
|
+
echo "✅ 已是最新版本(${VERSION})"
|
|
39
|
+
else
|
|
40
|
+
echo "📦 有新版本:本地 ${VERSION} → npm ${latest};运行:guanwei update"
|
|
41
|
+
fi
|
|
42
|
+
else
|
|
43
|
+
local remote remoteTag
|
|
44
|
+
remote=$(remote_head)
|
|
45
|
+
remoteTag=$(latest_tag)
|
|
46
|
+
if [[ -z "${remote}" ]]; then echo "⚠️ 无法连接 GitHub"; return 0; fi
|
|
47
|
+
if [[ "${HEAD}" == "${remote:0:7}" ]]; then
|
|
48
|
+
echo "✅ 已是最新版本(${VERSION} · ${HEAD})"
|
|
49
|
+
else
|
|
50
|
+
echo "📦 有新版本:本地 ${VERSION} · ${HEAD} → 远端 ${remoteTag} · ${remote:0:7};运行:guanwei update"
|
|
51
|
+
fi
|
|
52
|
+
fi
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
cmd_status() {
|
|
56
|
+
echo "观微 Guanwei"
|
|
57
|
+
echo " 版本 : ${VERSION}(${MODE} 模式)"
|
|
58
|
+
[[ "${MODE}" == "local" ]] && echo " 提交 : ${HEAD}"
|
|
59
|
+
echo " 项目目录 : ${ROOT}"
|
|
60
|
+
echo " 配置 : $([ -f "${ENV_FILE}" ] && echo "已配置(${ENV_FILE})" || echo "未配置(运行 guanwei setup)")"
|
|
61
|
+
local be_pid fe_pid
|
|
62
|
+
be_pid=$(lsof -nP -iTCP:3018 -sTCP:LISTEN -t 2>/dev/null | head -1)
|
|
63
|
+
fe_pid=$(lsof -nP -iTCP:${WEB_PORT:-5173} -sTCP:LISTEN -t 2>/dev/null | head -1)
|
|
64
|
+
echo " 服务状态 : 后端 $([ -n "${be_pid}" ] && echo '运行中' || echo '未运行') · 前端 $([ -n "${fe_pid}" ] && echo '运行中' || echo '未运行')"
|
|
65
|
+
cmd_check
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
cmd_setup() {
|
|
69
|
+
local PROVIDER="" KEY="" CHOICE
|
|
70
|
+
while [[ $# -gt 0 ]]; do
|
|
71
|
+
case "$1" in
|
|
72
|
+
--provider) PROVIDER="$2"; shift 2 ;;
|
|
73
|
+
--key) KEY="$2"; shift 2 ;;
|
|
74
|
+
*) echo "未知参数: $1"; exit 1 ;;
|
|
75
|
+
esac
|
|
76
|
+
done
|
|
77
|
+
mkdir -p "${GUANWEI_HOME}"
|
|
78
|
+
if [[ -z "${PROVIDER}" ]]; then
|
|
79
|
+
if [[ -n "${KEY}" ]]; then PROVIDER=deepseek; else
|
|
80
|
+
echo "选择 AI 服务商:"
|
|
81
|
+
echo " 1) DeepSeek(推荐) 2) Gemini 3) Groq 4) 通义千问 5) 自定义端点"
|
|
82
|
+
read -rp "编号 [1]: " CHOICE
|
|
83
|
+
case "${CHOICE:-1}" in
|
|
84
|
+
1) PROVIDER=deepseek;; 2) PROVIDER=gemini;; 3) PROVIDER=groq;;
|
|
85
|
+
4) PROVIDER=qwen;; 5) PROVIDER=custom;; *) echo "无效"; exit 1;;
|
|
86
|
+
esac
|
|
87
|
+
fi
|
|
88
|
+
fi
|
|
89
|
+
if [[ -z "${KEY}" ]]; then
|
|
90
|
+
read -rsp "请输入 ${PROVIDER} API Key(不回显): " KEY; echo
|
|
91
|
+
fi
|
|
92
|
+
[[ -z "${KEY}" ]] && { echo "错误:Key 不能为空"; exit 1; }
|
|
93
|
+
{
|
|
94
|
+
echo "# 由 guanwei setup 生成($(date '+%Y-%m-%d %H:%M'))"
|
|
95
|
+
echo "LLM_PROVIDER=${PROVIDER}"
|
|
96
|
+
case "${PROVIDER}" in
|
|
97
|
+
deepseek) echo "LLM_DEEPSEEK_KEY=${KEY}"; echo "LLM_DEEPSEEK_MODEL=deepseek-chat";;
|
|
98
|
+
gemini) echo "LLM_GEMINI_KEY=${KEY}";;
|
|
99
|
+
groq) echo "LLM_GROQ_KEY=${KEY}";;
|
|
100
|
+
qwen) echo "LLM_QWEN_KEY=${KEY}";;
|
|
101
|
+
custom)
|
|
102
|
+
echo "LLM_CUSTOM_KEY=${KEY}"
|
|
103
|
+
read -rp "端点 URL [https://your-endpoint/v1/chat/completions]: " EP
|
|
104
|
+
echo "LLM_CUSTOM_ENDPOINT=${EP:-https://your-endpoint/v1/chat/completions}";;
|
|
105
|
+
esac
|
|
106
|
+
} > "${ENV_FILE}"
|
|
107
|
+
chmod 600 "${ENV_FILE}"
|
|
108
|
+
echo "✅ 配置已保存:${ENV_FILE}(仅本机可读)"
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
cmd_start() {
|
|
112
|
+
local DEV="" web_port="${WEB_PORT:-5173}" api_port="${API_PORT:-3018}"
|
|
113
|
+
while [[ $# -gt 0 ]]; do
|
|
114
|
+
case "$1" in
|
|
115
|
+
--dev) DEV="1"; shift ;;
|
|
116
|
+
--port) web_port="$2"; shift 2 ;;
|
|
117
|
+
--api) api_port="$2"; shift 2 ;;
|
|
118
|
+
*) echo "未知参数: $1"; exit 1 ;;
|
|
119
|
+
esac
|
|
120
|
+
done
|
|
121
|
+
if [[ ! -f "${ENV_FILE}" ]]; then
|
|
122
|
+
echo "⚠️ 尚未配置,先运行:guanwei setup --key 你的APIKey"; exit 1
|
|
123
|
+
fi
|
|
124
|
+
set -a; source "${ENV_FILE}"; set +a
|
|
125
|
+
export PORT="${api_port}" # 后端实际监听端口
|
|
126
|
+
|
|
127
|
+
local mode_label="生产"
|
|
128
|
+
[[ -n "${DEV}" ]] && mode_label="开发"
|
|
129
|
+
echo "🚀 启动观微(${mode_label}模式)"
|
|
130
|
+
echo " 前端 : http://localhost:${web_port} 后端 : http://localhost:${api_port}"
|
|
131
|
+
|
|
132
|
+
if [[ -n "${DEV}" ]]; then
|
|
133
|
+
(cd "${ROOT}/server" && "${ROOT}/node_modules/.bin/tsx" watch src/index.ts >/dev/null 2>&1) &
|
|
134
|
+
(cd "${ROOT}" && "${ROOT}/node_modules/.bin/vite" --port "${web_port}" >/dev/null 2>&1) &
|
|
135
|
+
else
|
|
136
|
+
(cd "${ROOT}/server" && "${ROOT}/node_modules/.bin/tsx" src/index.ts >/dev/null 2>&1) &
|
|
137
|
+
(cd "${ROOT}" && "${ROOT}/node_modules/.bin/vite" preview --port "${web_port}" --strictPort --host 127.0.0.1 >/dev/null 2>&1) &
|
|
138
|
+
fi
|
|
139
|
+
|
|
140
|
+
for i in $(seq 1 30); do
|
|
141
|
+
curl -sf "http://127.0.0.1:${api_port}/api/health" >/dev/null 2>&1 && break
|
|
142
|
+
sleep 1
|
|
143
|
+
done
|
|
144
|
+
sleep 2
|
|
145
|
+
if curl -sf -o /dev/null "http://127.0.0.1:${web_port}/" 2>/dev/null; then
|
|
146
|
+
echo "✅ 已就绪,正在打开浏览器..."
|
|
147
|
+
cmd_web "${web_port}" || true
|
|
148
|
+
else
|
|
149
|
+
echo "⚠️ 前端暂未就绪,稍后访问 http://localhost:${web_port}"
|
|
150
|
+
fi
|
|
151
|
+
echo " Ctrl+C 停止"
|
|
152
|
+
wait
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
cmd_web() {
|
|
156
|
+
local port="${1:-${WEB_PORT:-5173}}"
|
|
157
|
+
local url="http://localhost:${port}"
|
|
158
|
+
case "$(uname -s)" in
|
|
159
|
+
Darwin) open "${url}" ;;
|
|
160
|
+
Linux) xdg-open "${url}" 2>/dev/null || echo "请打开浏览器访问: ${url}" ;;
|
|
161
|
+
MINGW*|MSYS*|CYGWIN*) start "${url}" ;;
|
|
162
|
+
*) echo "请打开浏览器访问: ${url}" ;;
|
|
163
|
+
esac
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
cmd_update() {
|
|
167
|
+
if [[ "${MODE}" == "global" ]]; then
|
|
168
|
+
echo "📦 全局安装模式——通过 npm 升级..."
|
|
169
|
+
npm i -g guanwei@latest 2>&1 | tail -2
|
|
170
|
+
echo "✅ 升级完成,重启生效:guanwei start"
|
|
171
|
+
else
|
|
172
|
+
echo "🔍 检查远端更新..."
|
|
173
|
+
git -C "${ROOT}" fetch origin 2>&1 | tail -1
|
|
174
|
+
local remote; remote=$(remote_head)
|
|
175
|
+
if [[ -z "${remote}" ]]; then echo "⚠️ 无法连接 GitHub"; exit 1; fi
|
|
176
|
+
if [[ "${HEAD}" == "${remote:0:7}" ]]; then echo "✅ 已是最新"; return 0; fi
|
|
177
|
+
local dirty
|
|
178
|
+
dirty=$(git -C "${ROOT}" status --porcelain --untracked-files=no 2>/dev/null | grep -v '^??' | head -5)
|
|
179
|
+
if [[ -n "${dirty}" ]]; then
|
|
180
|
+
echo "⚠️ 本地未提交修改(不会覆盖):"; echo "${dirty}" | sed 's/^/ /'
|
|
181
|
+
read -rp " 继续?[y/N] " ans
|
|
182
|
+
[[ "${ans,,}" == "y" ]] || { echo "已取消"; exit 1; }
|
|
183
|
+
git -C "${ROOT}" stash push -m "guanwei-update-auto" >/dev/null 2>&1 && STASHED=1
|
|
184
|
+
fi
|
|
185
|
+
echo "📦 增量更新..."
|
|
186
|
+
git -C "${ROOT}" merge --ff-only origin/main 2>&1 | tail -2 || git -C "${ROOT}" pull --rebase origin main 2>&1 | tail -2
|
|
187
|
+
echo "📦 安装依赖..."
|
|
188
|
+
(cd "${ROOT}" && npm install --no-fund --no-audit 2>&1 | tail -1)
|
|
189
|
+
(cd "${ROOT}/server" && npm install --no-fund --no-audit 2>&1 | tail -1)
|
|
190
|
+
[[ -n "${STASHED:-}" ]] && git -C "${ROOT}" stash pop >/dev/null 2>&1 && echo "✅ 本地修改已恢复"
|
|
191
|
+
echo "✅ 更新完成:$(node -e "console.log(require('${ROOT}/package.json').version)") · $(git -C "${ROOT}" rev-parse --short HEAD)"
|
|
192
|
+
fi
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
cmd_doctor() {
|
|
196
|
+
local ok=1
|
|
197
|
+
echo "🩺 观微环境自检(${MODE} 模式)"
|
|
198
|
+
echo "──────────────────────────────"
|
|
199
|
+
if command -v node >/dev/null 2>&1; then
|
|
200
|
+
echo "✅ Node.js $(node -v | sed 's/v//')"
|
|
201
|
+
else
|
|
202
|
+
echo "❌ 未检测到 Node.js"; ok=0
|
|
203
|
+
fi
|
|
204
|
+
if [[ -s "${ENV_FILE}" ]]; then
|
|
205
|
+
if grep -qE "sk-你的|sk-test|your-" "${ENV_FILE}" 2>/dev/null; then
|
|
206
|
+
echo "❌ 配置含占位/测试密钥——重新运行 guanwei setup"; ok=0
|
|
207
|
+
else
|
|
208
|
+
echo "✅ 已配置(LLM_PROVIDER=$(grep '^LLM_PROVIDER=' "${ENV_FILE}" | cut -d= -f2))"
|
|
209
|
+
fi
|
|
210
|
+
else
|
|
211
|
+
echo "❌ 未配置——运行 guanwei setup --key 你的APIKey"; ok=0
|
|
212
|
+
fi
|
|
213
|
+
echo "✅ 项目目录: ${ROOT}"
|
|
214
|
+
local be fe
|
|
215
|
+
be=$(curl -s -o /dev/null -w '%{http_code}' --max-time 2 http://localhost:3018/api/health 2>/dev/null || echo 0)
|
|
216
|
+
fe=$(curl -s -o /dev/null -w '%{http_code}' --max-time 2 "http://localhost:${WEB_PORT:-5173}/" 2>/dev/null || echo 0)
|
|
217
|
+
[[ "${be}" == "200" ]] && echo "✅ 后端 3018 运行中" || echo "ℹ️ 后端 3018 未运行"
|
|
218
|
+
[[ "${fe}" == "200" ]] && echo "✅ 前端 ${WEB_PORT:-5173} 运行中" || echo "ℹ️ 前端 ${WEB_PORT:-5173} 未运行"
|
|
219
|
+
cmd_check
|
|
220
|
+
echo "──────────────────────────────"
|
|
221
|
+
[[ ${ok} -eq 1 ]] && echo "🎉 自检通过" || echo "🛠️ 按提示修复后重试:guanwei doctor"
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
cmd_stop() {
|
|
225
|
+
for port in 3018 ${WEB_PORT:-5173}; do
|
|
226
|
+
local pid
|
|
227
|
+
pid=$(lsof -nP -iTCP:${port} -sTCP:LISTEN -t 2>/dev/null | head -1)
|
|
228
|
+
[[ -n "${pid}" ]] && kill "${pid}" 2>/dev/null && echo "已停止端口 ${port}(pid ${pid})"
|
|
229
|
+
done
|
|
230
|
+
echo "✅ 停止命令已执行"
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
CMD="${1:-help}"
|
|
234
|
+
case "${CMD}" in
|
|
235
|
+
setup) shift; cmd_setup "$@" ;;
|
|
236
|
+
start) shift; cmd_start "$@" ;;
|
|
237
|
+
web) shift; cmd_web "$@" ;;
|
|
238
|
+
update) cmd_update ;;
|
|
239
|
+
check) cmd_check ;;
|
|
240
|
+
status) cmd_status ;;
|
|
241
|
+
doctor) cmd_doctor ;;
|
|
242
|
+
stop) cmd_stop ;;
|
|
243
|
+
help|-h|--help) cmd_help ;;
|
|
244
|
+
*) echo "未知命令: ${CMD}"; cmd_help; exit 1 ;;
|
|
245
|
+
esac
|