Browse Source

feat: 组件升级(claymorphism适配+PlayfulCard重构)

Ultraworked with Sisyphus
User 5 months ago
parent
commit
9d440e10d6

+ 18 - 16
cfc-frontend/components/FunTaskItem.vue

@@ -70,26 +70,28 @@ export default {
 .fun-task-item {
 .fun-task-item {
   display: flex;
   display: flex;
   align-items: center;
   align-items: center;
-  background: #fff;
-  border-radius: 20rpx;
+  background: var(--surface, #ffffff);
+  border-radius: var(--radius-md, 20rpx);
   padding: 24rpx;
   padding: 24rpx;
   margin-bottom: 20rpx;
   margin-bottom: 20rpx;
-  box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.05);
-  transition: transform 0.2s;
+  border: 2rpx solid var(--border, #FED7AA);
+  box-shadow: var(--shadow-sm);
+  transition: transform 0.15s ease;
 }
 }
 .fun-task-item:active { transform: scale(0.98); }
 .fun-task-item:active { transform: scale(0.98); }
-.fun-task-item.completed { opacity: 0.7; background: #F0FDF4; }
-.fun-task-item.urgent { border: 2rpx solid #FF6B6B; animation: pulse-urgent 1s infinite; }
-@keyframes pulse-urgent { 0%, 100% { box-shadow: 0 0 0 0 rgba(255,107,107,0.4); } 50% { box-shadow: 0 0 0 10rpx rgba(255,107,107,0); } }
-.task-icon { font-size: 48rpx; width: 80rpx; height: 80rpx; background: #F0F9FF; border-radius: 16rpx; display: flex; align-items: center; justify-content: center; margin-right: 20rpx; }
+.fun-task-item.completed { opacity: 0.65; background: #FEF2F2; border-color: #FECACA; }
+.fun-task-item.urgent { border: 2rpx solid var(--color-error, #EF4444); animation: pulse-urgent 1.5s infinite; }
+@keyframes pulse-urgent { 0%, 100% { box-shadow: 0 0 0 0 rgba(239,68,68,0.3); } 50% { box-shadow: 0 0 0 12rpx rgba(239,68,68,0); } }
+.task-icon { font-size: 44rpx; width: 72rpx; height: 72rpx; background: rgba(249,115,22,0.1); border-radius: 16rpx; display: flex; align-items: center; justify-content: center; margin-right: 20rpx; }
 .task-content { flex: 1; }
 .task-content { flex: 1; }
-.task-title { font-size: 30rpx; font-weight: 600; color: #1F2937; margin-bottom: 8rpx; }
+.task-title { font-size: 28rpx; font-weight: 600; color: var(--text, #3D2E1E); margin-bottom: 8rpx; }
 .task-meta { display: flex; align-items: center; gap: 16rpx; }
 .task-meta { display: flex; align-items: center; gap: 16rpx; }
-.points-badge { background: linear-gradient(135deg, #FEF3C7, #FDE68A); color: #92400E; font-size: 22rpx; padding: 4rpx 12rpx; border-radius: 20rpx; font-weight: 600; }
-.deadline { font-size: 22rpx; color: #6B7280; }
-.task-action { margin-left: 20rpx; }
-.complete-btn { display: flex; align-items: center; background: linear-gradient(135deg, #0EA5E9, #06B6D4); color: #fff; border: none; border-radius: 30rpx; padding: 12rpx 24rpx; font-size: 24rpx; font-weight: 600; }
-.btn-icon { margin-right: 8rpx; }
-.completed-badge { display: flex; align-items: center; background: #ECFDF5; color: #059669; padding: 12rpx 20rpx; border-radius: 30rpx; font-size: 24rpx; }
-.check-icon { margin-right: 8rpx; }
+.points-badge { background: linear-gradient(135deg, #FEF3C7, #FDE68A); color: #92400E; font-size: 22rpx; padding: 4rpx 14rpx; border-radius: 20rpx; font-weight: 700; }
+.deadline { font-size: 22rpx; color: var(--muted, #94A3B8); }
+.task-action { margin-left: 16rpx; }
+.complete-btn { display: flex; align-items: center; background: linear-gradient(135deg, var(--color-primary, #F97316), #FB923C); color: #fff; border: none; border-radius: 30rpx; padding: 14rpx 28rpx; font-size: 24rpx; font-weight: 600; box-shadow: 0 4rpx 8rpx rgba(249,115,22,0.3); }
+.complete-btn:active { transform: scale(0.95); opacity: 0.9; }
+.btn-icon { margin-right: 6rpx; }
+.completed-badge { display: flex; align-items: center; background: rgba(34,197,94,0.1); color: var(--color-success, #22C55E); padding: 12rpx 20rpx; border-radius: 30rpx; font-size: 24rpx; font-weight: 600; }
+.check-icon { margin-right: 6rpx; }
 </style>
 </style>

+ 1 - 1
cfc-frontend/components/MediaRecorder.vue

@@ -246,7 +246,7 @@ export default {
 
 
 .btn-add-text {
 .btn-add-text {
 	margin-top: 20rpx;
 	margin-top: 20rpx;
-	background: #FF6B6B;
+	background: #F97316;
 	color: #fff;
 	color: #fff;
 }
 }
 
 

+ 93 - 18
cfc-frontend/components/PlayfulButton.vue

@@ -1,7 +1,10 @@
 <template>
 <template>
   <button
   <button
     class="playful-btn"
     class="playful-btn"
-    :class="['playful-btn--' + variant, 'playful-btn--' + size]"
+    :class="['playful-btn--' + variant, 'playful-btn--' + size, {
+      'playful-btn--disabled': disabled,
+      'playful-btn--clay': variant === 'clay'
+    }]"
     :disabled="disabled"
     :disabled="disabled"
     @click="emitClick"
     @click="emitClick"
     :aria-label="ariaLabel"
     :aria-label="ariaLabel"
@@ -14,14 +17,17 @@
 export default {
 export default {
   name: 'PlayfulButton',
   name: 'PlayfulButton',
   props: {
   props: {
-    variant: { type: String, default: 'primary' }, // 'primary' | 'secondary'
-    size: { type: String, default: 'md' }, // 'sm' | 'md' | 'lg'
+    variant: { type: String, default: 'primary' },
+    // 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'clay' | 'outline'
+    size: { type: String, default: 'md' },
+    // 'xs' | 'sm' | 'md' | 'lg'
     disabled: { type: Boolean, default: false },
     disabled: { type: Boolean, default: false },
-    ariaLabel: { type: String, default: '' }
+    ariaLabel: { type: String, default: '' },
+    block: { type: Boolean, default: false }
   },
   },
   methods: {
   methods: {
     emitClick(e) {
     emitClick(e) {
-      if (!this.disabled) this.$emit('click', e);
+      if (!this.disabled) this.$emit('click', e)
     }
     }
   }
   }
 }
 }
@@ -29,27 +35,96 @@ export default {
 
 
 <style scoped>
 <style scoped>
 .playful-btn {
 .playful-btn {
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
   border: none;
   border: none;
   border-radius: 999px;
   border-radius: 999px;
-  padding: 0.6rem 1rem;
   font-weight: 700;
   font-weight: 700;
-  cursor: pointer;
-  transition: transform .15s ease, box-shadow .15s ease;
+  transition: transform .15s ease, box-shadow .15s ease, opacity .2s ease;
+  line-height: 1.4;
 }
 }
+.playful-btn--block {
+  display: flex;
+  width: 100%;
+}
+
+/* ---- Primary ---- */
 .playful-btn--primary {
 .playful-btn--primary {
-  background: var(--color-primary, #0EA5E9);
+  background: var(--color-primary, #F97316);
   color: #fff;
   color: #fff;
-  box-shadow: 0 2px 6px rgba(14,165,233,.3);
+  box-shadow: 0 2px 8px rgba(249, 115, 22, 0.3);
 }
 }
+
+/* ---- Secondary ---- */
 .playful-btn--secondary {
 .playful-btn--secondary {
-  background: #f8fafc;
-  color: var(--text, #1f2937);
-  border: 1px solid var(--border, #e5e7eb);
+  background: var(--surface, #ffffff);
+  color: var(--text, #3D2E1E);
+  border: 2rpx solid var(--border, #FED7AA);
+  box-shadow: 0 2px 6px rgba(249, 115, 22, 0.06);
+}
+
+/* ---- Success ---- */
+.playful-btn--success {
+  background: var(--color-success, #22C55E);
+  color: #fff;
+  box-shadow: 0 2px 8px rgba(34, 197, 94, 0.3);
+}
+
+/* ---- Warning ---- */
+.playful-btn--warning {
+  background: var(--color-warning, #F59E0B);
+  color: #fff;
+  box-shadow: 0 2px 8px rgba(245, 158, 11, 0.3);
+}
+
+/* ---- Error ---- */
+.playful-btn--error {
+  background: var(--color-error, #EF4444);
+  color: #fff;
+  box-shadow: 0 2px 8px rgba(239, 68, 68, 0.3);
+}
+
+/* ---- Clay (孩子端玩具风) ---- */
+.playful-btn--clay {
+  background: linear-gradient(145deg, #FFB347, var(--color-primary, #F97316));
+  color: #fff;
+  border: 3rpx solid #FED7AA;
+  box-shadow:
+    inset -2px -2px 6px rgba(255, 255, 255, 0.3),
+    4px 4px 12px rgba(249, 115, 22, 0.25);
+}
+
+/* ---- Outline ---- */
+.playful-btn--outline {
+  background: transparent;
+  color: var(--color-primary, #F97316);
+  border: 2rpx solid var(--color-primary, #F97316);
 }
 }
-.playful-btn--sm { font-size: 0.875rem; padding: 0.5rem 0.75rem; }
-.playful-btn--md { font-size: 1rem; padding: 0.6rem 1rem; }
-.playful-btn--lg { font-size: 1.125rem; padding: 0.75rem 1.25rem; }
 
 
-.playful-btn:active { transform: translateY(1px) scale(0.98); }
-.playful-btn:focus { outline: 2px solid rgba(14,165,233,.6); outline-offset: 2px; }
+/* ---- Sizes ---- */
+.playful-btn--xs { font-size: 22rpx; padding: 8rpx 20rpx; }
+.playful-btn--sm { font-size: 24rpx; padding: 12rpx 28rpx; }
+.playful-btn--md { font-size: 28rpx; padding: 16rpx 36rpx; }
+.playful-btn--lg { font-size: 32rpx; padding: 20rpx 48rpx; min-height: 88rpx; }
+
+/* ---- States ---- */
+.playful-btn:active:not(:disabled) {
+  transform: scale(0.97);
+}
+.playful-btn--clay:active:not(:disabled) {
+  transform: scale(0.95);
+  box-shadow:
+    inset 0 0 8px rgba(0,0,0,0.1),
+    2px 2px 6px rgba(249, 115, 22, 0.15);
+}
+.playful-btn--disabled,
+.playful-btn:disabled {
+  opacity: 0.5;
+  cursor: not-allowed;
+}
+.playful-btn:focus {
+  outline: 2px solid rgba(249, 115, 22, 0.4);
+  outline-offset: 2px;
+}
 </style>
 </style>

+ 105 - 56
cfc-frontend/components/PlayfulCard.vue

@@ -1,56 +1,105 @@
-<template>
-  <view class="playful-card" :style="cardStyle">
-    <view class="playful-card__header" v-if="$slots.header">
-      <slot name="header"></slot>
-    </view>
-    <view class="playful-card__content">
-      <slot></slot>
-    </view>
-    <view class="playful-card__actions" v-if="$slots.actions">
-      <slot name="actions"></slot>
-    </view>
-  </view>
-</template>
-
-<script>
-export default {
-  name: 'PlayfulCard',
-  props: {
-    // simple elevation control (not strictly required with CSS vars)
-    elevation: { type: Number, default: 1 }
-  },
-  computed: {
-    cardStyle() {
-      // Optional per-card styling hook; kept simple here
-      return {};
-    }
-  }
-}
-</script>
-
-<style scoped>
-.playful-card {
-  background: var(--surface, #ffffff);
-  border: 1px solid var(--border, #e5e7eb);
-  border-radius: 20px;
-  padding: 16px;
-  box-shadow: 0 4px 14px rgba(14, 165, 233, 0.12);
-}
-.playful-card__header {
-  font-weight: 700;
-  font-family: var(--font-display, system-ui, -apple-system, "Noto Sans SC", sans-serif);
-  font-size: 1.05rem;
-  margin-bottom: 8px;
-}
-.playful-card__content {
-  color: var(--text, #1f2937);
-  line-height: 1.6;
-  font-family: var(--font-body, system-ui, -apple-system, "Inter", sans-serif);
-}
-.playful-card__actions {
-  margin-top: 12px;
-  display: flex;
-  justify-content: flex-end;
-  gap: 8px;
-}
-</style>
+<template>
+  <view class="playful-card" :class="cardClasses" :style="computedStyle" @click="handleClick">
+    <view class="playful-card__header" v-if="hasHeader">
+      <slot name="header"></slot>
+    </view>
+    <view class="playful-card__content">
+      <slot></slot>
+    </view>
+    <view class="playful-card__actions" v-if="hasActions">
+      <slot name="actions"></slot>
+    </view>
+  </view>
+</template>
+
+<script>
+export default {
+  name: 'PlayfulCard',
+  props: {
+    variant: { type: String, default: 'flat' },
+    shadow: { type: String, default: 'md' },
+    clickable: { type: Boolean, default: false },
+    padding: { type: String, default: '' }
+  },
+  data() {
+    return {
+      hasHeader: false,
+      hasActions: false
+    }
+  },
+  mounted() {
+    this.hasHeader = !!this.$slots.header
+    this.hasActions = !!this.$slots.actions
+  },
+  computed: {
+    cardClasses() {
+      return [
+        'playful-card--' + this.variant,
+        'playful-card--shadow-' + this.shadow,
+        this.clickable ? 'playful-card--clickable' : ''
+      ].filter(Boolean)
+    },
+    computedStyle() {
+      const style = {}
+      if (this.padding) style.padding = this.padding
+      return style
+    }
+  },
+  methods: {
+    handleClick(e) {
+      if (this.clickable) this.$emit('click', e)
+    }
+  }
+}
+</script>
+
+<style scoped>
+.playful-card {
+  background: var(--surface, #ffffff);
+  border-radius: 20rpx;
+  padding: 24rpx;
+  transition: transform .15s ease, box-shadow .2s ease;
+}
+.playful-card--flat {
+  border: 1px solid var(--border, #FED7AA);
+  box-shadow: var(--shadow-md);
+}
+.playful-card--clay {
+  border: 4rpx solid var(--border, #FED7AA);
+  background: linear-gradient(145deg, #FFFFFF, var(--bg, #FFF7ED));
+  box-shadow: var(--shadow-clay);
+}
+.playful-card--bordered {
+  border: 1px solid var(--border-light, #FFEDD5);
+}
+.playful-card--teacher {
+  border: 1px solid #DBEAFE;
+  box-shadow: 0 4rpx 14rpx rgba(59, 130, 246, 0.08);
+  background: var(--surface, #ffffff);
+}
+.playful-card--shadow-none { box-shadow: none; }
+.playful-card--shadow-sm { box-shadow: var(--shadow-sm); }
+.playful-card--shadow-md { box-shadow: var(--shadow-md); }
+.playful-card--shadow-lg { box-shadow: var(--shadow-lg); }
+.playful-card--clickable:active {
+  transform: scale(0.98);
+}
+.playful-card__header {
+  font-weight: 700;
+  font-size: 32rpx;
+  margin-bottom: 16rpx;
+  color: var(--text, #3D2E1E);
+}
+.playful-card__content {
+  color: var(--text, #3D2E1E);
+  line-height: 1.6;
+  font-size: 28rpx;
+}
+.playful-card__actions {
+  margin-top: 16rpx;
+  display: flex;
+  justify-content: flex-end;
+  gap: 16rpx;
+  flex-wrap: wrap;
+}
+</style>

+ 4 - 4
cfc-frontend/components/PointsProgressRing.vue

@@ -57,9 +57,9 @@ export default {
       return this.circumference * (1 - this.progress)
       return this.circumference * (1 - this.progress)
     },
     },
     progressColor() {
     progressColor() {
-      if (this.progress >= 0.75) return '#10B981' // green
-      if (this.progress >= 0.5) return '#F59E0B'  // yellow
-      return '#0EA5E9' // blue
+      if (this.progress >= 0.75) return '#22C55E' // green (success)
+      if (this.progress >= 0.5) return '#F97316'  // orange (primary)
+      return '#FB923C' // light orange
     },
     },
     milestone() {
     milestone() {
       if (this.nextMilestone > this.points) {
       if (this.nextMilestone > this.points) {
@@ -104,7 +104,7 @@ export default {
   display: block;
   display: block;
   font-size: 28px;
   font-size: 28px;
   font-weight: 800;
   font-weight: 800;
-  color: #0EA5E9;
+  color: var(--color-accent, #0EA5E9);
 }
 }
 .points-label {
 .points-label {
   display: block;
   display: block;

+ 344 - 51
cfc-frontend/components/wuxing-sandbox.vue

@@ -1,53 +1,103 @@
 <template>
 <template>
   <view class="wuxing-sandbox">
   <view class="wuxing-sandbox">
     <view class="sandbox-header">
     <view class="sandbox-header">
-      <text class="sandbox-title">五行能量沙盘</text>
+      <text class="sandbox-title">🌟 五行能量沙盘</text>
       <text class="sandbox-badge">{{ badgeText }}</text>
       <text class="sandbox-badge">{{ badgeText }}</text>
     </view>
     </view>
+
     <view class="sandbox-star">
     <view class="sandbox-star">
-      <view class="star-point star-point-top" @click="onPointClick('mind')">
-        <text class="point-icon">🔥</text>
+      <!-- ===== 背景光晕 ===== -->
+      <view class="star-glow-bg"></view>
+
+      <!-- ===== 五角星轮廓(clip-path) ===== -->
+      <view class="star-shape">
+        <view class="star-shape__fill"></view>
+        <view class="star-shape__outline"></view>
+      </view>
+
+      <!-- ===== 五角星连线(内五边形) ===== -->
+      <view class="pentagram-lines">
+        <view class="p-line p-line--1"></view>
+        <view class="p-line p-line--2"></view>
+        <view class="p-line p-line--3"></view>
+        <view class="p-line p-line--4"></view>
+        <view class="p-line p-line--5"></view>
+      </view>
+
+      <!-- ===== 顶点 1:心·火(上) ===== -->
+      <view class="star-point star-point--top" @click="onPointClick('mind')" hover-class="point-hover">
+        <view class="point-glow point-glow--fire"></view>
+        <view class="point-dot point-dot--fire">
+          <text class="point-icon">🔥</text>
+        </view>
         <text class="point-label">心·火</text>
         <text class="point-label">心·火</text>
         <text class="point-status" v-if="mode === 'preview'">点此登录</text>
         <text class="point-status" v-if="mode === 'preview'">点此登录</text>
       </view>
       </view>
-      <view class="star-point star-point-left" @click="onPointClick('action')">
-        <text class="point-icon">🌿</text>
-        <text class="point-label">行·木</text>
+
+      <!-- ===== 顶点 2:富·水(右上) ===== -->
+      <view class="star-point star-point--ur" @click="onPointClick('wealth')" hover-class="point-hover">
+        <view class="point-glow point-glow--water"></view>
+        <view class="point-dot point-dot--water">
+          <text class="point-icon">💧</text>
+        </view>
+        <text class="point-label">富·水</text>
         <text class="point-status" v-if="mode === 'preview'">点此登录</text>
         <text class="point-status" v-if="mode === 'preview'">点此登录</text>
       </view>
       </view>
-      <view class="star-point star-point-right" @click="onPointClick('wealth')">
-        <text class="point-icon">💧</text>
-        <text class="point-label">富·水</text>
+
+      <!-- ===== 顶点 3:身·土(右下) ===== -->
+      <view class="star-point star-point--lr" @click="onPointClick('body')" hover-class="point-hover">
+        <view class="point-glow point-glow--earth"></view>
+        <view class="point-dot point-dot--earth">
+          <text class="point-icon">🌏</text>
+        </view>
+        <text class="point-label">身·土</text>
         <text class="point-status" v-if="mode === 'preview'">点此登录</text>
         <text class="point-status" v-if="mode === 'preview'">点此登录</text>
       </view>
       </view>
-      <view class="star-point star-point-bl" @click="onPointClick('wisdom')">
-        <text class="point-icon">⚔️</text>
+
+      <!-- ===== 顶点 4:智·金(左下) ===== -->
+      <view class="star-point star-point--ll" @click="onPointClick('wisdom')" hover-class="point-hover">
+        <view class="point-glow point-glow--metal"></view>
+        <view class="point-dot point-dot--metal">
+          <text class="point-icon">⚔️</text>
+        </view>
         <text class="point-label">智·金</text>
         <text class="point-label">智·金</text>
         <text class="point-status" v-if="mode === 'preview'">点此登录</text>
         <text class="point-status" v-if="mode === 'preview'">点此登录</text>
       </view>
       </view>
-      <view class="star-point star-point-br" @click="onPointClick('body')">
-        <text class="point-icon">🌏</text>
-        <text class="point-label">身·土</text>
+
+      <!-- ===== 顶点 5:行·木(左上) ===== -->
+      <view class="star-point star-point--ul" @click="onPointClick('action')" hover-class="point-hover">
+        <view class="point-glow point-glow--wood"></view>
+        <view class="point-dot point-dot--wood">
+          <text class="point-icon">🌿</text>
+        </view>
+        <text class="point-label">行·木</text>
         <text class="point-status" v-if="mode === 'preview'">点此登录</text>
         <text class="point-status" v-if="mode === 'preview'">点此登录</text>
       </view>
       </view>
+
+      <!-- ===== 中心 ===== -->
       <view class="star-center">
       <view class="star-center">
+        <view class="center-icon-wrap">
+          <text class="center-icon">☯</text>
+        </view>
         <text class="center-text">五行平衡</text>
         <text class="center-text">五行平衡</text>
         <text class="center-sub">共同成长</text>
         <text class="center-sub">共同成长</text>
       </view>
       </view>
     </view>
     </view>
+
     <view class="shenke-hint" v-if="mode === 'preview'">
     <view class="shenke-hint" v-if="mode === 'preview'">
       <text class="hint-text">🌱 完成测评,点亮「身·土」</text>
       <text class="hint-text">🌱 完成测评,点亮「身·土」</text>
     </view>
     </view>
+
     <view class="dimension-bar" v-if="mode !== 'preview'">
     <view class="dimension-bar" v-if="mode !== 'preview'">
-      <view class="dim-item inactive">🌿行</view>
+      <view class="dim-item dim-item--wood">🌿行</view>
       <text class="dim-arrow">→</text>
       <text class="dim-arrow">→</text>
-      <view class="dim-item inactive">🔥心</view>
+      <view class="dim-item dim-item--fire">🔥心</view>
       <text class="dim-arrow">→</text>
       <text class="dim-arrow">→</text>
-      <view class="dim-item inactive">🌏身</view>
+      <view class="dim-item dim-item--earth">🌏身</view>
       <text class="dim-arrow">→</text>
       <text class="dim-arrow">→</text>
-      <view class="dim-item inactive">⚔️智</view>
+      <view class="dim-item dim-item--metal">⚔️智</view>
       <text class="dim-arrow">→</text>
       <text class="dim-arrow">→</text>
-      <view class="dim-item inactive">💧富</view>
+      <view class="dim-item dim-item--water">💧富</view>
     </view>
     </view>
   </view>
   </view>
 </template>
 </template>
@@ -67,19 +117,39 @@ export default {
 </script>
 </script>
 
 
 <style scoped>
 <style scoped>
+/* ============================================================
+   容器 — 暗色渐变背景
+   ============================================================ */
 .wuxing-sandbox {
 .wuxing-sandbox {
   margin: 20rpx 30rpx;
   margin: 20rpx 30rpx;
-  padding: 30rpx;
-  background: linear-gradient(135deg, #1a1a2e, #16213e);
-  border-radius: 24rpx;
+  padding: 24rpx 24rpx 20rpx;
+  background: linear-gradient(135deg, #0f0f23, #1a1a3e, #16213e);
+  border-radius: 28rpx;
   position: relative;
   position: relative;
   overflow: hidden;
   overflow: hidden;
 }
 }
+.wuxing-sandbox::before {
+  content: '';
+  position: absolute;
+  top: -50%;
+  left: -50%;
+  width: 200%;
+  height: 200%;
+  background: radial-gradient(ellipse at 30% 20%, rgba(255, 215, 0, 0.03), transparent 60%),
+              radial-gradient(ellipse at 70% 80%, rgba(66, 165, 245, 0.03), transparent 60%);
+  pointer-events: none;
+}
+
+/* ============================================================
+   标题栏
+   ============================================================ */
 .sandbox-header {
 .sandbox-header {
   display: flex;
   display: flex;
   justify-content: space-between;
   justify-content: space-between;
   align-items: center;
   align-items: center;
-  margin-bottom: 30rpx;
+  margin-bottom: 20rpx;
+  position: relative;
+  z-index: 2;
 }
 }
 .sandbox-title {
 .sandbox-title {
   font-size: 28rpx;
   font-size: 28rpx;
@@ -87,56 +157,279 @@ export default {
   color: #FFD700;
   color: #FFD700;
 }
 }
 .sandbox-badge {
 .sandbox-badge {
-  font-size: 22rpx;
-  color: #aaa;
-  background: rgba(255,255,255,0.1);
-  padding: 6rpx 16rpx;
+  font-size: 20rpx;
+  color: rgba(255, 215, 0, 0.7);
+  background: rgba(255, 215, 0, 0.1);
+  padding: 4rpx 14rpx;
   border-radius: 20rpx;
   border-radius: 20rpx;
 }
 }
+
+/* ============================================================
+   五角星区域
+   ============================================================ */
 .sandbox-star {
 .sandbox-star {
   position: relative;
   position: relative;
-  height: 400rpx;
+  height: 460rpx;
   display: flex;
   display: flex;
   justify-content: center;
   justify-content: center;
   align-items: center;
   align-items: center;
 }
 }
+
+/* ---- 背景光晕 ---- */
+.star-glow-bg {
+  position: absolute;
+  width: 360rpx;
+  height: 360rpx;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+  background: radial-gradient(circle, rgba(255, 215, 0, 0.08), transparent 70%);
+  border-radius: 50%;
+  pointer-events: none;
+}
+
+/* ---- 五角星形状(clip-path) ---- */
+.star-shape {
+  position: absolute;
+  width: 320rpx;
+  height: 304rpx;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+  pointer-events: none;
+}
+.star-shape__fill {
+  position: absolute;
+  inset: 0;
+  clip-path: polygon(
+    50% 0%, 61% 35%, 98% 35%, 68% 57%,
+    79% 91%, 50% 70%, 21% 91%, 32% 57%,
+    2% 35%, 39% 35%
+  );
+  background: linear-gradient(135deg, rgba(255, 215, 0, 0.12), rgba(255, 180, 50, 0.04));
+  animation: starPulse 4s ease-in-out infinite;
+}
+.star-shape__outline {
+  position: absolute;
+  inset: -2rpx;
+  clip-path: polygon(
+    50% 0%, 61% 35%, 98% 35%, 68% 57%,
+    79% 91%, 50% 70%, 21% 91%, 32% 57%,
+    2% 35%, 39% 35%
+  );
+  background: transparent;
+  border: 1rpx solid rgba(255, 215, 0, 0.15);
+  /* fake border via slightly larger duplicate */
+}
+/* Real outline using pseudo element trick */
+.star-shape__outline::before {
+  content: '';
+  position: absolute;
+  inset: 0;
+  clip-path: polygon(
+    50% 0%, 61% 35%, 98% 35%, 68% 57%,
+    79% 91%, 50% 70%, 21% 91%, 32% 57%,
+    2% 35%, 39% 35%
+  );
+  background: transparent;
+  box-shadow: 0 0 20rpx rgba(255, 215, 0, 0.06);
+}
+
+@keyframes starPulse {
+  0%, 100% { opacity: 1; }
+  50% { opacity: 0.6; }
+}
+
+/* ---- 五角星连线(五条边) ---- */
+.pentagram-lines {
+  position: absolute;
+  inset: 0;
+  pointer-events: none;
+}
+.p-line {
+  position: absolute;
+  height: 2rpx;
+  background: linear-gradient(90deg, rgba(255, 215, 0, 0.2), rgba(255, 215, 0, 0.05));
+  transform-origin: left center;
+  top: 0;
+  left: 0;
+}
+
+/* Line 1: Fire → Earth (top → lower-right) */
+.p-line--1 { top: 46rpx; left: 250rpx; width: 290rpx; transform: rotate(68deg); }
+/* Line 2: Earth → Wood (lower-right → upper-left) */
+.p-line--2 { top: 340rpx; left: 340rpx; width: 290rpx; transform: rotate(-106deg); }
+/* Line 3: Wood → Water (upper-left → upper-right) */
+.p-line--3 { top: 156rpx; left: 72rpx; width: 364rpx; transform: rotate(0deg); }
+/* Line 4: Water → Metal (upper-right → lower-left) */
+.p-line--4 { top: 156rpx; left: 400rpx; width: 290rpx; transform: rotate(106deg); }
+/* Line 5: Metal → Fire (lower-left → top) */
+.p-line--5 { top: 340rpx; left: 100rpx; width: 290rpx; transform: rotate(-68deg); }
+
+/* ============================================================
+   顶点
+   ============================================================ */
 .star-point {
 .star-point {
   position: absolute;
   position: absolute;
   display: flex;
   display: flex;
   flex-direction: column;
   flex-direction: column;
   align-items: center;
   align-items: center;
-  width: 120rpx;
-}
-.star-point-top { top: 0; left: 50%; transform: translateX(-50%); }
-.star-point-left { top: 120rpx; left: 20rpx; }
-.star-point-right { top: 120rpx; right: 20rpx; }
-.star-point-bl { bottom: 40rpx; left: 60rpx; }
-.star-point-br { bottom: 40rpx; right: 60rpx; }
-.point-icon { font-size: 50rpx; margin-bottom: 6rpx; }
-.point-label { font-size: 22rpx; color: #fff; font-weight: bold; }
-.point-status { font-size: 18rpx; color: #FF6B6B; margin-top: 4rpx; }
+  transform: translate(-50%, -50%);
+  z-index: 3;
+  cursor: pointer;
+}
+.point-hover {
+  opacity: 0.8;
+}
+
+/* 顶点定位 */
+.star-point--top  { top: 8%;   left: 50%; }
+.star-point--ur   { top: 32%;  left: 84%; }
+.star-point--lr   { top: 76%;  left: 72%; }
+.star-point--ll   { top: 76%;  left: 28%; }
+.star-point--ul   { top: 32%;  left: 16%; }
+
+/* ---- 顶点光晕 ---- */
+.point-glow {
+  position: absolute;
+  width: 90rpx;
+  height: 90rpx;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+  border-radius: 50%;
+  opacity: 0.25;
+  pointer-events: none;
+}
+.point-glow--fire  { background: radial-gradient(circle, #FF6B35, transparent 70%); }
+.point-glow--water { background: radial-gradient(circle, #42A5F5, transparent 70%); }
+.point-glow--earth { background: radial-gradient(circle, #8D6E63, transparent 70%); }
+.point-glow--metal { background: radial-gradient(circle, #FFD700, transparent 70%); }
+.point-glow--wood  { background: radial-gradient(circle, #4CAF50, transparent 70%); }
+
+/* ---- 顶点圆点 ---- */
+.point-dot {
+  width: 56rpx;
+  height: 56rpx;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  position: relative;
+  z-index: 1;
+}
+.point-dot--fire  { background: linear-gradient(135deg, #FF6B35, #E65100); box-shadow: 0 0 16rpx rgba(255, 107, 53, 0.4); }
+.point-dot--water { background: linear-gradient(135deg, #42A5F5, #1565C0); box-shadow: 0 0 16rpx rgba(66, 165, 245, 0.4); }
+.point-dot--earth { background: linear-gradient(135deg, #8D6E63, #5D4037); box-shadow: 0 0 16rpx rgba(141, 110, 99, 0.4); }
+.point-dot--metal { background: linear-gradient(135deg, #FFD700, #FF8F00); box-shadow: 0 0 16rpx rgba(255, 215, 0, 0.4); }
+.point-dot--wood  { background: linear-gradient(135deg, #4CAF50, #2E7D32); box-shadow: 0 0 16rpx rgba(76, 175, 80, 0.4); }
+
+.point-icon {
+  font-size: 28rpx;
+  line-height: 1;
+}
+
+/* ---- 顶点标签 ---- */
+.point-label {
+  font-size: 20rpx;
+  color: rgba(255, 255, 255, 0.9);
+  font-weight: bold;
+  margin-top: 8rpx;
+  white-space: nowrap;
+}
+.point-status {
+  font-size: 16rpx;
+  color: #F97316;
+  margin-top: 2rpx;
+  white-space: nowrap;
+}
+
+/* ============================================================
+   中心圆
+   ============================================================ */
 .star-center {
 .star-center {
-  width: 120rpx; height: 120rpx;
-  background: radial-gradient(circle, rgba(255,215,0,0.2), rgba(255,215,0,0.05));
-  border: 2rpx solid rgba(255,215,0,0.3);
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+  width: 110rpx;
+  height: 110rpx;
   border-radius: 50%;
   border-radius: 50%;
   display: flex;
   display: flex;
   flex-direction: column;
   flex-direction: column;
   justify-content: center;
   justify-content: center;
   align-items: center;
   align-items: center;
+  z-index: 4;
+  background: radial-gradient(circle at 40% 35%, rgba(255, 215, 0, 0.15), rgba(255, 215, 0, 0.03));
+  border: 1rpx solid rgba(255, 215, 0, 0.2);
+  box-shadow: 0 0 30rpx rgba(255, 215, 0, 0.08), inset 0 0 20rpx rgba(255, 215, 0, 0.04);
+  animation: centerPulse 3s ease-in-out infinite;
+}
+
+@keyframes centerPulse {
+  0%, 100% { box-shadow: 0 0 30rpx rgba(255, 215, 0, 0.08), inset 0 0 20rpx rgba(255, 215, 0, 0.04); }
+  50% { box-shadow: 0 0 40rpx rgba(255, 215, 0, 0.15), inset 0 0 30rpx rgba(255, 215, 0, 0.08); }
 }
 }
-.center-text { font-size: 22rpx; color: #FFD700; font-weight: bold; }
-.center-sub { font-size: 18rpx; color: #aaa; }
-.shenke-hint { text-align: center; margin-top: 10rpx; }
-.hint-text { font-size: 22rpx; color: rgba(255,215,0,0.7); }
+
+.center-icon-wrap {
+  width: 36rpx;
+  height: 36rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-bottom: 2rpx;
+}
+.center-icon {
+  font-size: 28rpx;
+  color: #FFD700;
+}
+.center-text {
+  font-size: 20rpx;
+  color: #FFD700;
+  font-weight: bold;
+  line-height: 1.3;
+}
+.center-sub {
+  font-size: 16rpx;
+  color: rgba(255, 215, 0, 0.5);
+  line-height: 1.2;
+}
+
+/* ============================================================
+   提示 & 维度条
+   ============================================================ */
+.shenke-hint {
+  text-align: center;
+  margin-top: 8rpx;
+  position: relative;
+  z-index: 2;
+}
+.hint-text {
+  font-size: 22rpx;
+  color: rgba(255, 215, 0, 0.7);
+}
+
 .dimension-bar {
 .dimension-bar {
-  display: flex; align-items: center; justify-content: center;
-  margin-top: 20rpx; gap: 8rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-top: 16rpx;
+  gap: 6rpx;
+  position: relative;
+  z-index: 2;
 }
 }
 .dim-item {
 .dim-item {
-  font-size: 22rpx; color: #FFD700;
-  background: rgba(255,215,0,0.1);
-  padding: 6rpx 14rpx; border-radius: 12rpx;
+  font-size: 20rpx;
+  padding: 4rpx 12rpx;
+  border-radius: 10rpx;
+}
+.dim-item--wood  { color: #4CAF50;  background: rgba(76, 175, 80, 0.1); }
+.dim-item--fire  { color: #FF6B35;  background: rgba(255, 107, 53, 0.1); }
+.dim-item--earth { color: #8D6E63;  background: rgba(141, 110, 99, 0.1); }
+.dim-item--metal { color: #FFD700;  background: rgba(255, 215, 0, 0.1); }
+.dim-item--water { color: #42A5F5;  background: rgba(66, 165, 245, 0.1); }
+.dim-arrow {
+  font-size: 18rpx;
+  color: rgba(255, 255, 255, 0.2);
 }
 }
-.dim-arrow { font-size: 20rpx; color: rgba(255,215,0,0.3); }
 </style>
 </style>