/* ---- greeting ---- */ .greeting-row { display: flex; align-items: center; gap: 20rpx; padding: 16rpx 8rpx 24rpx; animation: cardIn 0.4s ease both; } /* 圆形头像:外层 overflow:hidden + 内层 image border-radius:50% 双保险, 避免远程(cloud://)头像裁不出圆角而露直角。无头像时显示人形图标占位, 加浅色底让占位更有质感;有头像时去掉底,避免深色头像边缘露白缝。 */ .greeting-avatar { width: 88rpx; height: 88rpx; flex-shrink: 0; border-radius: 50%; overflow: hidden; background: var(--bg-soft); display: flex; align-items: center; justify-content: center; } .greeting-avatar-img { width: 100%; height: 100%; border-radius: 50%; display: block; } .greeting-avatar.has-avatar { background: transparent; } .greeting-main { flex: 1; min-width: 0; } .greeting-title { display: block; font-size: 40rpx; font-weight: 700; color: var(--text); line-height: 1.3; } .greeting-sub { display: block; font-size: 26rpx; color: var(--text-secondary); margin-top: 4rpx; line-height: 1.2; } /* ---- header card ---- */ .header-card { display: flex; flex-direction: column; gap: 28rpx; padding: 4rpx 0; } /* 上区:左连胜视觉重心,右计划徽章 */ .streak-row { display: flex; align-items: center; justify-content: space-between; } .streak-section { display: flex; align-items: center; } /* 火焰图标 + 光晕:光晕脉动让火焰"活"起来 */ .streak-icon-wrap { position: relative; width: 80rpx; height: 80rpx; display: flex; align-items: center; justify-content: center; margin-right: 16rpx; flex-shrink: 0; } .streak-halo { position: absolute; top: 0; left: 0; right: 0; bottom: 0; border-radius: 50%; background: radial-gradient(circle at center, rgba(var(--primary-rgb), 0.45) 0%, rgba(var(--primary-rgb), 0.18) 50%, rgba(var(--primary-rgb), 0) 75%); animation: streakHalo 2s ease-in-out infinite; } .streak-icon { position: relative; width: 64rpx; height: 64rpx; z-index: 1; animation: float 2.5s ease-in-out infinite; } .streak-text { display: flex; flex-direction: column; } .streak-num { font-size: 72rpx; font-weight: 800; line-height: 1; /* On the gradient hero card --text cascades to white; on any plain card it stays dark, so var(--text) reads correctly in both contexts. We must NOT use var(--primary) here — that would be orange-on-orange and invisible. */ color: var(--text); text-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.15); font-variant-numeric: tabular-nums; } .streak-label { font-size: 22rpx; color: var(--text-secondary); margin-top: 4rpx; line-height: 1; } @keyframes streakHalo { 0%, 100% { transform: scale(0.85); opacity: 0.7; } 50% { transform: scale(1.1); opacity: 1; } } /* 计划徽章:移到上区右侧,半透明白底药丸,与火焰渐变卡片区分 */ .plan-badge { display: flex; align-items: center; background: rgba(255, 255, 255, 0.18); padding: 8rpx 18rpx; border-radius: 999rpx; flex-shrink: 0; } .plan-badge-icon { width: 28rpx; height: 28rpx; margin-right: 8rpx; } .plan-badge-text { font-size: 26rpx; font-weight: 600; color: var(--text); line-height: 1; } /* 下区:分段进度 */ .segment-progress { display: flex; flex-direction: column; gap: 10rpx; } /* planTotal <= 10:按天分段格子 */ .segment-track { display: flex; gap: 8rpx; } .segment-cell { flex: 1; height: 12rpx; border-radius: 6rpx; background: transparent; border: 2rpx solid rgba(255, 255, 255, 0.30); box-sizing: border-box; transition: background 0.3s ease, border-color 0.3s ease; } .segment-cell.done { background: var(--on-primary, #FFFFFF); border-color: var(--on-primary, #FFFFFF); } .segment-cell.current { background: var(--on-primary, #FFFFFF); border-color: var(--on-primary, #FFFFFF); animation: segmentPulse 1.2s ease-in-out infinite; } /* planTotal > 10:连续条 + 里程碑节点,避免格子过密 */ .milestone-track { width: 100%; } .milestone-bar { position: relative; width: 100%; height: 12rpx; background: rgba(0, 0, 0, 0.12); border-radius: 6rpx; overflow: visible; } .milestone-fill { height: 100%; background: var(--on-primary, linear-gradient(90deg, var(--primary), var(--primary-light))); border-radius: 6rpx; transition: width 0.6s cubic-bezier(0.4, 0, 0.2, 1); } .milestone-node { position: absolute; top: 50%; width: 10rpx; height: 10rpx; border-radius: 50%; background: var(--card-bg); transform: translate(-50%, -50%); border: 2rpx solid var(--border); } .progress-label { font-size: 22rpx; color: var(--text-secondary); line-height: 1; } @keyframes segmentPulse { 0%, 100% { box-shadow: 0 0 4rpx rgba(var(--primary-rgb), 0.4); } 50% { box-shadow: 0 0 14rpx rgba(var(--primary-rgb), 0.9); } } /* ---- target card ---- */ .target-section { text-align: center; } .target-header { display: flex; align-items: center; justify-content: center; margin-bottom: 8rpx; } .target-header .section-title { margin-bottom: 0; } .section-icon { width: 32rpx; height: 32rpx; margin-right: 8rpx; } .target-display { margin: 20rpx 0; } .target-ring { display: inline-flex; align-items: center; justify-content: center; width: 280rpx; height: 280rpx; border-radius: 50%; background: linear-gradient(135deg, rgba(var(--primary-rgb), 0.10), rgba(var(--primary-rgb), 0.03)); border: 6rpx solid rgba(var(--primary-rgb), 0.18); box-shadow: 0 0 0 14rpx rgba(var(--primary-rgb), 0.05); overflow: hidden; } .target-time { font-size: 84rpx; font-weight: 800; color: var(--primary); font-variant-numeric: tabular-nums; letter-spacing: -1rpx; line-height: 1; max-width: 240rpx; text-align: center; white-space: nowrap; overflow: hidden; } .today-status { margin-top: 16rpx; display: flex; align-items: center; justify-content: center; gap: 8rpx; } .done-badge { display: inline-flex; align-items: center; background: rgba(var(--success-rgb), 0.08); padding: 10rpx 24rpx; border-radius: 24rpx; } .done-icon { width: 28rpx; height: 28rpx; margin-right: 6rpx; } .done-text { font-size: 26rpx; color: var(--success); line-height: 1; } .pending-icon { width: 28rpx; height: 28rpx; margin-right: 6rpx; } .pending-text { font-size: 26rpx; color: var(--text-secondary); line-height: 1; } /* ---- action buttons ---- */ .action-buttons { display: flex; flex-direction: column; gap: 24rpx; margin: 8rpx 0 8rpx; } /* 自由训练 / 循环训练 并排一行 */ .action-row { display: flex; gap: 16rpx; } .action-row .action-cell { flex: 1; min-width: 0; /* 防止图标+文字在窄屏撑破 flex 项 */ } /* ---- picker ---- */ .picker-title { font-size: 34rpx; font-weight: 600; color: var(--text); display: block; text-align: center; margin-bottom: 32rpx; } .preset-grid { display: flex; flex-wrap: wrap; gap: 16rpx; margin-bottom: 28rpx; } .preset-item { flex: 0 0 calc(33.33% - 12rpx); box-sizing: border-box; background: var(--bg-soft); border: 2rpx solid transparent; border-radius: 16rpx; padding: 20rpx 0; text-align: center; display: flex; flex-direction: column; transition: all 0.2s ease; } .preset-item:active { transform: scale(0.94); } .preset-item.selected { background: var(--primary-bg); border: 2rpx solid var(--primary); } .preset-num { font-size: 36rpx; font-weight: 700; color: var(--text); line-height: 1.1; } .preset-item.selected .preset-num { color: var(--primary); } .preset-unit { font-size: 20rpx; color: var(--text-secondary); margin-top: 2rpx; line-height: 1; } .custom-input-row { display: flex; align-items: center; justify-content: center; margin-bottom: 28rpx; } .custom-label { font-size: 28rpx; color: var(--text-secondary); line-height: 1; } .custom-input { width: 160rpx; height: 64rpx; background: var(--bg-soft); border-radius: 12rpx; text-align: center; font-size: 32rpx; font-weight: 600; color: var(--primary); margin: 0 16rpx; } .picker-cancel { display: block; text-align: center; font-size: 28rpx; color: var(--text-secondary); padding: 12rpx 0; margin-top: 8rpx; } /* ---- circuit (循环训练) config panel ---- */ .picker-sub { display: block; text-align: center; font-size: 24rpx; color: var(--text-secondary); margin: -18rpx 0 24rpx; } .circuit-row { display: flex; align-items: center; justify-content: space-between; padding: 20rpx 8rpx; border-bottom: 1rpx solid var(--border); } .circuit-row-label { font-size: 30rpx; color: var(--text); font-weight: 500; } .stepper { display: flex; align-items: center; gap: 20rpx; } .stepper-btn { width: 64rpx; height: 64rpx; border-radius: 50%; background: var(--bg-soft); color: var(--primary); font-size: 40rpx; font-weight: 700; display: flex; align-items: center; justify-content: center; line-height: 1; transition: transform 0.12s ease, opacity 0.12s ease; } .stepper-btn:active { transform: scale(0.9); opacity: 0.8; } .stepper-val { min-width: 124rpx; text-align: center; font-size: 32rpx; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; } /* ---- 训练完成高亮 (3 秒后淡出) ---- */ /* 这个 class 落在 宿主节点上(ui-card.wxss 已把宿主设为 display:block, 否则 border/box-shadow 只会碎成两根竖条、transform 完全不生效)。 描边用 box-shadow 的 spread 而非 border:border 会撑大宿主 8rpx,高亮出现/消失 时整页布局跳动;box-shadow 不占布局空间。宿主自身无圆角,必须补上与内部卡片 一致的 24rpx,否则描边会是直角框套在圆角卡片外面。 */ .just-completed { animation: justCompletedPulse 1s ease-in-out 2; border-radius: 24rpx; box-shadow: 0 0 0 4rpx var(--primary), 0 4rpx 24rpx rgba(var(--primary-rgb), 0.3); } @keyframes justCompletedPulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.02); } }