.stats { display: flex; justify-content: space-around; text-align: center; padding: 8rpx 0; } .stat-item { display: flex; flex-direction: column; align-items: center; flex: 1; } .stat-icon { width: 40rpx; height: 40rpx; margin-bottom: 8rpx; } .stat-num { font-size: 36rpx; font-weight: 700; color: var(--primary); animation: popIn 0.5s ease; text-align: center; } .stat-label { font-size: 22rpx; color: var(--text-secondary); margin-top: 4rpx; text-align: center; } /* ---- badges ---- */ .badge-section { padding: 0; } .badge-header { display: flex; justify-content: space-between; align-items: center; } .badge-header .section-title { margin-bottom: 0; } .badge-title-wrap { display: flex; align-items: center; gap: 8rpx; } .badge-title-icon { width: 36rpx; height: 36rpx; align-self: center; margin-top: -2rpx; } .badge-status { display: flex; align-items: baseline; justify-content: center; flex-wrap: wrap; gap: 10rpx; margin: 12rpx 0 44rpx; text-align: center; } .badge-status-days { font-size: 24rpx; color: var(--text-secondary); } .badge-status-dot { font-size: 24rpx; color: var(--text-secondary); opacity: 0.5; } .badge-status-next { font-size: 24rpx; color: var(--text-secondary); } .badge-days-num { font-size: 44rpx; font-weight: 800; color: var(--primary); } .badge-track { position: relative; height: 4rpx; margin: 48rpx 0 20rpx; background: rgba(var(--primary-rgb), 0.12); border-radius: 2rpx; } .badge-segment { position: absolute; top: 0; height: 100%; } .badge-segment-fill { height: 100%; background: var(--primary); border-radius: 2rpx; transition: width 0.6s ease; } .badge-node { position: absolute; top: 50%; transform: translate(-50%, -50%); width: 56rpx; height: 56rpx; border-radius: 50%; background: var(--card-bg, #fff); border: 2rpx solid rgba(var(--primary-rgb), 0.2); display: flex; align-items: center; justify-content: center; transition: background 0.4s ease, border-color 0.4s ease, transform 0.4s ease; } .badge-node.unlocked { background: var(--primary); border-color: var(--primary); } .badge-node.celebrate { animation: badgePop 0.6s ease; box-shadow: 0 0 0 8rpx rgba(var(--primary-rgb), 0.22); } @keyframes badgePop { 0% { transform: translate(-50%, -50%) scale(1); } 35% { transform: translate(-50%, -50%) scale(1.35); } 65% { transform: translate(-50%, -50%) scale(0.9); } 100% { transform: translate(-50%, -50%) scale(1); } } .badge-node-icon { width: 32rpx; height: 32rpx; } /* 已解锁节点的 ✓ 角标:纯 CSS 画勾(图标 SVG 颜色烤死,无法用变量改色) */ .badge-check { position: absolute; right: -3rpx; bottom: -3rpx; width: 24rpx; height: 24rpx; border-radius: 50%; background: var(--primary); border: 2rpx solid var(--card-bg, #fff); box-sizing: border-box; } .badge-check::after { content: ''; position: absolute; left: 7rpx; top: 3rpx; width: 6rpx; height: 11rpx; border: solid var(--card-bg, #fff); border-width: 0 3rpx 3rpx 0; transform: rotate(45deg); } .badge-labels { position: relative; height: 30rpx; margin-top: 32rpx; } .badge-label { position: absolute; top: 0; transform: translateX(-50%); font-size: 20rpx; color: var(--text-secondary); white-space: nowrap; opacity: 0.8; } .badge-label.unlocked { color: var(--primary); font-size: 22rpx; font-weight: 700; opacity: 1; } /* ---- calendar ---- */ .calendar-section { padding: 0; } .month-picker { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20rpx; } .month-title-wrap { display: flex; align-items: center; gap: 10rpx; } .month-icon { width: 32rpx; height: 32rpx; } .month-title { font-size: 28rpx; font-weight: 600; color: var(--text); } .month-arrow { padding: 16rpx 20rpx; display: flex; align-items: center; justify-content: center; } .month-arrow:active { opacity: 0.5; } .month-arrow-img { width: 32rpx; height: 32rpx; color: var(--primary); } /* ---- trend ---- */ .trend-section { padding: 0; } .trend-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8rpx; } .trend-title-wrap { display: flex; align-items: center; gap: 8rpx; } .trend-header .section-title { margin-bottom: 0; } /* ---- history ---- */ .history-section { padding: 0; } .history-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8rpx; } .history-title-wrap { display: flex; align-items: center; gap: 8rpx; } .history-title-icon { width: 28rpx; height: 28rpx; } .history-header .section-title { margin-bottom: 0; } .history-hint { font-size: 22rpx; color: var(--text-secondary); margin-bottom: 8rpx; } /* segmented control: [本月 | 最近] in the records history header. Mirrors the .period-seg language used on the leaderboard/settings pages. */ .rec-seg { display: flex; background: var(--bg-soft); border-radius: 999rpx; padding: 4rpx; flex-shrink: 0; } .rec-seg-item { padding: 8rpx 24rpx; font-size: 24rpx; color: var(--text-secondary); border-radius: 999rpx; transition: background 0.25s ease, color 0.25s ease, box-shadow 0.25s ease; } .rec-seg-item.active { background: var(--card-bg); color: var(--primary); font-weight: 600; box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.10); } .empty-state { display: flex; flex-direction: column; align-items: center; padding: 60rpx 0; } .empty-icon { width: 80rpx; height: 80rpx; margin-bottom: 16rpx; animation: float 3s ease-in-out infinite; } .empty-text { color: var(--text-secondary); font-size: 28rpx; margin-bottom: 8rpx; } .empty-sub { font-size: 24rpx; color: var(--text-secondary); } .history-list { margin-top: 8rpx; } .history-item { display: flex; align-items: center; padding: 20rpx 0; border-bottom: 1rpx solid var(--border); animation: cardIn 0.35s ease both; } .history-item:last-child { border-bottom: none; } .history-item-icon { width: 36rpx; height: 36rpx; margin-right: 16rpx; flex-shrink: 0; } .history-left { display: flex; flex-direction: column; flex: 1; } .history-date { font-size: 28rpx; color: var(--text); } .history-plan { font-size: 22rpx; color: var(--text-secondary); margin-top: 4rpx; } .history-right { display: flex; align-items: center; gap: 12rpx; flex-shrink: 0; } .history-duration { font-size: 32rpx; font-weight: 600; color: var(--primary); margin-right: 4rpx; } .history-delete-btn { display: flex; align-items: center; justify-content: center; gap: 6rpx; padding: 0 18rpx; height: 56rpx; background: rgba(var(--danger-rgb), 0.1); border: 2rpx solid rgba(var(--danger-rgb), 0.2); border-radius: 28rpx; flex-shrink: 0; transition: transform 0.15s ease, background 0.15s ease, border-color 0.15s ease; } .history-delete-btn:active { transform: scale(0.92); background: rgba(var(--danger-rgb), 0.2); border-color: rgba(var(--danger-rgb), 0.4); } .history-delete-icon { width: 28rpx; height: 28rpx; flex-shrink: 0; } .history-delete-text { font-size: 24rpx; color: var(--danger); font-weight: 600; line-height: 1; } /* ---- day detail popup ---- 普通 view 实现,不用 ui-modal:自定义组件根元素的 position: fixed 会被小程序运行时吞掉(见 settings.wxss plan-editor 注释),叠加 .page-enter 的 transform 会让 fixed 降级相对 .container,导致弹窗 落到容器末尾而非视口居中。普通 view 的 fixed 100% 生效。 */ .day-detail-mask { position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: 1000; display: flex; align-items: center; justify-content: center; } .day-detail-mask__bg { position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.45); animation: dayDetailFade 0.25s ease; } .day-detail-body { position: relative; width: 560rpx; border-radius: 28rpx; padding: 48rpx 40rpx 36rpx; background: var(--card-bg); box-sizing: border-box; text-align: center; box-shadow: 0 16rpx 48rpx rgba(0, 0, 0, 0.25); animation: dayDetailPop 0.35s cubic-bezier(0.34, 1.56, 0.64, 1); } @media (prefers-color-scheme: dark) { .day-detail-body { /* 暗黑下 body(#26262B)与页面(#131316)都偏深,加深阴影 + 微亮描边拉开层次 */ box-shadow: 0 16rpx 48rpx rgba(0, 0, 0, 0.6), 0 0 0 1rpx rgba(255, 255, 255, 0.06); } } @keyframes dayDetailFade { from { opacity: 0; } to { opacity: 1; } } @keyframes dayDetailPop { from { transform: scale(0); opacity: 0; } 60% { transform: scale(1.05); } to { transform: scale(1); opacity: 1; } } .detail-date-row { display: flex; align-items: center; justify-content: center; margin-bottom: 36rpx; gap: 10rpx; } .detail-icon { width: 36rpx; height: 36rpx; } .detail-date { font-size: 34rpx; font-weight: 700; color: var(--text); } .detail-grid { display: flex; justify-content: space-around; margin-bottom: 36rpx; } .detail-item { display: flex; flex-direction: column; align-items: center; } .detail-item-icon { width: 36rpx; height: 36rpx; margin-bottom: 8rpx; } .detail-num { font-size: 36rpx; font-weight: 700; color: var(--primary); margin-bottom: 6rpx; } .detail-label { font-size: 22rpx; color: var(--text-secondary); } .detail-close { padding: 16rpx 0; font-size: 28rpx; color: var(--text-secondary); border-top: 1rpx solid var(--border); } /* ---- empty state illustration ---- */ .empty-state { display: flex; flex-direction: column; align-items: center; padding: 60rpx 32rpx; } .empty-illus { position: relative; width: 200rpx; height: 200rpx; margin-bottom: 40rpx; } .empty-illus-body { position: absolute; bottom: 30rpx; left: 50%; transform: translateX(-50%); width: 160rpx; height: 30rpx; background: linear-gradient(90deg, var(--primary), var(--primary-light)); border-radius: 16rpx; } .empty-illus-arm { position: absolute; bottom: 36rpx; width: 20rpx; height: 60rpx; background: var(--primary); border-radius: 10rpx; } .empty-illus-arm--l { left: 30rpx; transform: rotate(30deg); } .empty-illus-arm--r { right: 30rpx; transform: rotate(-30deg); } .empty-illus-bubble { position: absolute; top: 0; right: 0; background: var(--primary-bg); color: var(--primary); font-size: 22rpx; font-weight: 600; padding: 8rpx 16rpx; border-radius: 16rpx; line-height: 1; } .empty-text { font-size: 30rpx; color: var(--text); margin-bottom: 12rpx; } .empty-sub { font-size: 26rpx; color: var(--text-secondary); } /* ---- 首次训练空状态引导 ---- */ .first-train-prompt { display: flex; flex-direction: column; align-items: center; padding: 60rpx 32rpx 80rpx; background: var(--card-bg); border-radius: 24rpx; box-shadow: 0 2rpx 16rpx rgba(0, 0, 0, 0.06); margin-bottom: 24rpx; } .first-train-illus { width: 240rpx; height: 240rpx; margin-bottom: 32rpx; } .first-train-title { font-size: 36rpx; font-weight: 700; color: var(--text); margin-bottom: 12rpx; } .first-train-sub { font-size: 26rpx; color: var(--text-secondary); margin-bottom: 36rpx; } .first-train-cta { display: flex; align-items: center; justify-content: center; height: 88rpx; padding: 0 80rpx; background: linear-gradient(135deg, var(--primary), var(--primary-light)); color: #FFFFFF; font-size: 30rpx; font-weight: 600; border-radius: 44rpx; box-shadow: 0 8rpx 20rpx rgba(var(--primary-rgb), 0.3); transition: transform 0.15s ease, box-shadow 0.15s ease; } .first-train-cta:active { transform: scale(0.96); box-shadow: 0 4rpx 10rpx rgba(var(--primary-rgb), 0.2); }