feat: 小程序超级个体/个人资料/CKB获客;VIP列表展示过滤;管理端与API联调

- 超级个体:去掉首位特例;列表仅展示有头像且非微信默认昵称(vip.go)
- 个人资料:居中头像、低调联系方式、点头像优先走存客宝 lead(ckbLeadToken)
- 阅读页分享朋友圈复制与 toast 去重
- soul-api: miniprogram users 带 ckbLeadToken;其它 handler 与路由调整
- 脚本:content_upload、miniprogram 上传辅助等

Made-with: Cursor
This commit is contained in:
卡若
2026-03-22 08:34:28 +08:00
parent 17ce20c8ee
commit 5724fba877
119 changed files with 8198 additions and 4369 deletions

View File

@@ -1,135 +1,175 @@
<!-- 个人资料展示页 - enhanced_professional_profile 1:1 重构 -->
<!-- 卡若创业派对 - 个人资料展示页(与 member-detail 同一视觉) -->
<view class="page">
<view class="nav-bar" style="padding-top: {{statusBarHeight}}px;">
<view class="nav-back" bindtap="goBack"><icon name="chevron-left" size="44" color="#5EEAD4" customClass="back-icon"></icon></view>
<view class="nav-back" bindtap="goBack">
<icon name="chevron-left" size="44" color="#5EEAD4" customClass="nav-icon"></icon>
</view>
<text class="nav-title">个人资料</text>
<view class="nav-right" bindtap="goToEdit"><text class="nav-more">⋯</text></view>
<view class="nav-edit" bindtap="goToEdit">
<icon name="edit" size="32" color="#5EEAD4"></icon>
</view>
</view>
<view class="nav-placeholder" style="height: {{statusBarHeight + 44}}px;"></view>
<view style="height: {{statusBarHeight + 44}}px;"></view>
<view class="loading" wx:if="{{loading}}">加载中...</view>
<scroll-view wx:else class="scroll-main" scroll-y>
<!-- 头像区卡片 -->
<view class="hero-card" wx:if="{{profile}}">
<view class="hero-gradient"></view>
<view class="hero-content">
<view class="hero-avatar">
<image wx:if="{{profile.avatar}}" class="avatar-img" src="{{profile.avatar}}" mode="aspectFill"/>
<view wx:else class="avatar-placeholder">{{profile.nickname ? profile.nickname[0] : '?'}}</view>
</view>
<text class="hero-name">{{profile.nickname || '未设置昵称'}}</text>
<view class="hero-tags">
<text class="tag tag-mbti" wx:if="{{profile.mbti}}">{{profile.mbti}}</text>
<view class="tag tag-region" wx:if="{{profile.region}}"><icon name="map-pin" size="24" color="currentColor" customClass="tag-icon"></icon><text>{{profile.region}}</text></view>
</view>
</view>
</view>
<view class="state-wrap" wx:if="{{loading}}">
<view class="loading-dot"></view>
<text class="state-txt">加载中...</text>
</view>
<!-- 基本信息 -->
<view class="section">
<view class="section-head">
<icon name="user" size="40" color="#00CED1" customClass="section-icon"></icon>
<text class="section-title">基本信息</text>
</view>
<view class="section-body">
<view class="field" wx:if="{{profile.industry}}">
<text class="field-label">行业</text>
<text class="field-value">{{profile.industry}}</text>
</view>
<view class="field" wx:if="{{profile.position}}">
<text class="field-label">职位</text>
<text class="field-value">{{profile.position}}</text>
</view>
<view class="field" wx:if="{{profile.businessScale}}">
<text class="field-label">业务体量</text>
<text class="field-value">{{profile.businessScale}}</text>
</view>
<view class="field-divider" wx:if="{{profile.industry || profile.position || profile.businessScale}}"></view>
<view class="field" wx:if="{{profile.skills}}">
<text class="field-label">我擅长</text>
<text class="field-value">{{profile.skills}}</text>
</view>
<view class="field" wx:if="{{profile.phoneMask || profile.phone}}">
<text class="field-label">联系方式</text>
<view class="field-value-row" bindtap="copyPhone">
<text class="field-value mono">{{profile.phoneMask || profile.phone || '未填写'}}</text>
<text class="field-hint" wx:if="{{profile.phone}}">复制</text>
<scroll-view scroll-y class="scroll-wrap" style="height: calc(100vh - {{statusBarHeight + 44}}px - 120rpx);" wx:if="{{!loading && profile}}">
<!-- 首屏壳:头像 + 联系方式 -->
<view class="shell">
<view class="shell-glow"></view>
<view class="hero-row">
<view class="avatar-outer">
<view class="avatar-wrap">
<image class="avatar-img" wx:if="{{profile.avatar}}" src="{{profile.avatar}}" mode="aspectFill"/>
<view class="avatar-ph" wx:else><text>{{profile.nickname ? profile.nickname[0] : '?'}}</text></view>
</view>
</view>
<view class="field" wx:if="{{profile.wechatMask || profile.wechat}}">
<text class="field-label">微信号</text>
<view class="field-value-row" bindtap="copyWechat">
<text class="field-value mono">{{profile.wechatMask || profile.wechat || '未填写'}}</text>
<text class="field-hint" wx:if="{{profile.wechat}}">复制</text>
<view class="link-column">
<text class="link-column-title">我的联系方式</text>
<view class="link-chip" wx:if="{{profile.phone}}" bindtap="copyPhone">
<view class="link-chip-icon link-chip-icon-phone">
<icon name="smartphone" size="34" color="#5EEAD4" customClass="lc-ic"></icon>
</view>
<view class="link-chip-main">
<text class="link-chip-label">手机号</text>
<text class="link-chip-val mono">{{profile.phone}}</text>
</view>
<view class="link-chip-action"><text>复制</text></view>
</view>
<view class="link-chip" wx:if="{{profile.wechat}}" bindtap="copyWechat">
<view class="link-chip-icon link-chip-icon-wx">
<icon name="message-circle" size="34" color="#34D399" customClass="lc-ic"></icon>
</view>
<view class="link-chip-main">
<text class="link-chip-label">微信号</text>
<text class="link-chip-val mono">{{profile.wechat}}</text>
</view>
<view class="link-chip-action"><text>复制</text></view>
</view>
<view class="link-empty" wx:if="{{!profile.phone && !profile.wechat}}">
<text class="link-empty-txt">未填写联系方式</text>
</view>
</view>
<view class="field-empty" wx:if="{{!profile.industry && !profile.position && !profile.businessScale && !profile.skills && !profile.phone && !profile.wechat}}">
点击右上角 ⋯ 编辑完善资料
</view>
<text class="profile-name">{{profile.nickname || '未设置昵称'}}</text>
<view class="profile-tags" wx:if="{{profile.mbti || profile.region}}">
<text class="tag tag-mbti" wx:if="{{profile.mbti}}">{{profile.mbti}}</text>
<view class="tag tag-region" wx:if="{{profile.region}}">
<icon name="map-pin" size="24" color="currentColor" customClass="pin-icon"></icon>
<text>{{profile.region}}</text>
</view>
</view>
</view>
<!-- 个人故事 -->
<view class="section" wx:if="{{profile.storyBestMonth || profile.storyAchievement || profile.storyTurning}}">
<view class="section-head">
<icon name="lightbulb" size="40" color="#FFD700" customClass="section-icon section-icon-yellow"></icon>
<text class="section-title">个人故事</text>
<!-- 一体化信息卡 -->
<view class="mono-card" wx:if="{{profile.industry || profile.position || profile.businessScale || profile.skills || profile.storyBestMonth || profile.storyAchievement || profile.storyTurning || profile.helpOffer || profile.helpNeed || profile.projectIntro}}">
<!-- 职业画像 -->
<view class="mono-sec" wx:if="{{profile.industry || profile.position || profile.businessScale}}">
<view class="mono-sec-head">
<text class="mono-sec-title">职业画像</text>
</view>
<view class="kv" wx:if="{{profile.industry}}">
<text class="kv-k">行业</text>
<text class="kv-v">{{profile.industry}}</text>
</view>
<view class="kv" wx:if="{{profile.position}}">
<text class="kv-k">职位</text>
<text class="kv-v">{{profile.position}}</text>
</view>
<view class="kv" wx:if="{{profile.businessScale}}">
<text class="kv-k">业务体量</text>
<text class="kv-v">{{profile.businessScale}}</text>
</view>
</view>
<view class="section-body">
<view class="story-block" wx:if="{{profile.storyBestMonth}}">
<view class="story-head"><icon name="trophy" size="28" color="#FFD700" customClass="story-emoji"></icon><text class="story-label">最赚钱的一个月做的是什么</text></view>
<text class="story-text">{{profile.storyBestMonth}}</text>
<view class="mono-divider" wx:if="{{(profile.industry || profile.position || profile.businessScale) && profile.skills}}"></view>
<!-- 我擅长 -->
<view class="mono-sec skills-showcase" wx:if="{{profile.skills}}">
<view class="mono-sec-head">
<text class="mono-sec-title">我擅长</text>
</view>
<view class="field-divider" wx:if="{{profile.storyBestMonth && (profile.storyAchievement || profile.storyTurning)}}"></view>
<view class="story-block" wx:if="{{profile.storyAchievement}}">
<view class="story-head"><icon name="star" size="28" color="#FFD700" customClass="story-emoji"></icon><text class="story-label">最有成就感的一件事</text></view>
<text class="story-text">{{profile.storyAchievement}}</text>
<view class="skills-quote">
<text class="skills-quote-text">{{profile.skills}}</text>
</view>
<view class="field-divider" wx:if="{{profile.storyAchievement && profile.storyTurning}}"></view>
<view class="story-block" wx:if="{{profile.storyTurning}}">
<view class="story-head"><icon name="refresh-cw" size="28" color="#FFD700" customClass="story-emoji"></icon><text class="story-label">人生的转折点</text></view>
<text class="story-text">{{profile.storyTurning}}</text>
</view>
<view class="mono-divider" wx:if="{{profile.skills && (profile.storyBestMonth || profile.storyAchievement || profile.storyTurning)}}"></view>
<!-- 个人故事 -->
<view class="mono-sec" wx:if="{{profile.storyBestMonth || profile.storyAchievement || profile.storyTurning}}">
<view class="mono-sec-head">
<text class="mono-sec-title">个人故事</text>
</view>
<view class="story" wx:if="{{profile.storyBestMonth}}">
<view class="story-head"><icon name="trophy" size="28" color="#FBBF24" customClass="story-icon"></icon><text class="story-q">最赚钱的一个月</text></view>
<text class="story-a">{{profile.storyBestMonth}}</text>
</view>
<view class="story-gap" wx:if="{{profile.storyBestMonth && (profile.storyAchievement || profile.storyTurning)}}"></view>
<view class="story" wx:if="{{profile.storyAchievement}}">
<view class="story-head"><icon name="star" size="28" color="#FBBF24" customClass="story-icon"></icon><text class="story-q">最有成就感的事</text></view>
<text class="story-a">{{profile.storyAchievement}}</text>
</view>
<view class="story-gap" wx:if="{{profile.storyAchievement && profile.storyTurning}}"></view>
<view class="story" wx:if="{{profile.storyTurning}}">
<view class="story-head"><icon name="refresh-cw" size="28" color="#FBBF24" customClass="story-icon"></icon><text class="story-q">人生的转折点</text></view>
<text class="story-a">{{profile.storyTurning}}</text>
</view>
</view>
<view class="mono-divider" wx:if="{{(profile.storyBestMonth || profile.storyAchievement || profile.storyTurning) && (profile.helpOffer || profile.helpNeed)}}"></view>
<!-- 互助需求 -->
<view class="mono-sec" wx:if="{{profile.helpOffer || profile.helpNeed}}">
<view class="mono-sec-head">
<text class="mono-sec-title">互助需求</text>
</view>
<view class="help-grid">
<view class="help-tile help-give" wx:if="{{profile.helpOffer}}">
<text class="help-tile-tag">我能帮你</text>
<text class="help-tile-txt">{{profile.helpOffer}}</text>
</view>
<view class="help-tile help-need" wx:if="{{profile.helpNeed}}">
<text class="help-tile-tag need">我需要</text>
<text class="help-tile-txt">{{profile.helpNeed}}</text>
</view>
</view>
</view>
<view class="mono-divider" wx:if="{{(profile.helpOffer || profile.helpNeed) && profile.projectIntro}}"></view>
<!-- 项目介绍 -->
<view class="mono-sec" wx:if="{{profile.projectIntro}}">
<view class="mono-sec-head">
<text class="mono-sec-title">项目介绍</text>
</view>
<text class="proj-body">{{profile.projectIntro}}</text>
</view>
</view>
<!-- 互助需求 -->
<view class="section" wx:if="{{profile.helpOffer || profile.helpNeed}}">
<view class="section-head">
<icon name="handshake" size="40" color="#00CED1" customClass="section-icon"></icon>
<text class="section-title">互助需求</text>
</view>
<view class="section-body">
<view class="help-block" wx:if="{{profile.helpOffer}}">
<text class="help-tag help-tag-accent">我能帮你</text>
<text class="help-text">{{profile.helpOffer}}</text>
</view>
<view class="help-block" wx:if="{{profile.helpNeed}}">
<text class="help-tag help-tag-orange">我需要帮助</text>
<text class="help-text">{{profile.helpNeed}}</text>
</view>
</view>
<!-- 空态 -->
<view class="empty-hint" wx:if="{{!profile.industry && !profile.position && !profile.businessScale && !profile.skills && !profile.storyBestMonth && !profile.storyAchievement && !profile.storyTurning && !profile.helpOffer && !profile.helpNeed && !profile.projectIntro}}">
<icon name="edit" size="48" color="#334155"></icon>
<text class="empty-hint-txt">资料尚未完善,点击右上角编辑</text>
</view>
<!-- 项目介绍 -->
<view class="section" wx:if="{{profile.projectIntro}}">
<view class="section-head">
<icon name="rocket" size="40" color="#00CED1" customClass="section-icon"></icon>
<text class="section-title">项目介绍</text>
</view>
<view class="section-body">
<text class="project-text">{{profile.projectIntro}}</text>
</view>
</view>
<view class="bottom-spacer"></view>
<view class="scroll-pad"></view>
</scroll-view>
<!-- 底部按钮 - 设计稿为描边橙色 -->
<view class="bottom-bar">
<view class="vip-btn-outline" bindtap="goToVip">
<!-- 底部按钮 -->
<view class="bottom-bar" wx:if="{{!loading}}">
<view class="vip-btn" bindtap="goToVip">
<text>成为超级个体</text>
<icon name="chevron-right" size="36" color="#00CED1" customClass="vip-btn-arrow"></icon>
<icon name="chevron-right" size="32" color="#0f172a"></icon>
</view>
</view>
</view>

View File

@@ -1,115 +1,183 @@
/* 个人资料展示页 - enhanced_professional_profile 1:1 重构 */
.page { background: #050B14; min-height: 100vh; color: #fff; }
/* 卡若创业派对 - 个人资料展示(与 member-detail 同一视觉语言) */
.page {
background: radial-gradient(120% 80% at 50% -20%, rgba(20, 80, 90, 0.35) 0%, #050B14 45%);
min-height: 100vh;
color: #fff;
}
/* —— 导航 —— */
.nav-bar {
position: fixed; top: 0; left: 0; right: 0; z-index: 100;
position: fixed; top: 0; left: 0; right: 0; z-index: 999;
display: flex; align-items: center; justify-content: space-between;
height: 44px; padding: 0 32rpx;
background: rgba(5,11,20,0.9); backdrop-filter: blur(8rpx);
border-bottom: 1rpx solid rgba(255,255,255,0.05);
padding: 0 28rpx; height: 44px;
background: rgba(5, 11, 20, 0.72);
backdrop-filter: blur(20rpx); -webkit-backdrop-filter: blur(20rpx);
border-bottom: 1rpx solid rgba(255, 255, 255, 0.06);
}
.nav-back { padding: 16rpx; margin-left: -8rpx; }
.back-icon { font-size: 40rpx; color: #5EEAD4; }
.nav-title { font-size: 34rpx; font-weight: bold; }
.nav-right { padding: 16rpx; }
.nav-more { font-size: 48rpx; color: #fff; line-height: 1; }
.nav-placeholder { width: 100%; }
.nav-back { width: 72rpx; height: 72rpx; display: flex; align-items: center; justify-content: flex-start; }
.nav-icon { font-size: 44rpx; color: #5eead4; font-weight: 300; }
.nav-title { font-size: 32rpx; font-weight: 600; color: #f8fafc; letter-spacing: 4rpx; }
.nav-edit { width: 72rpx; height: 72rpx; display: flex; align-items: center; justify-content: flex-end; }
.loading { padding: 96rpx; text-align: center; color: #94A3B8; }
.scroll-wrap { box-sizing: border-box; }
.scroll-main { height: calc(100vh - 120rpx); padding: 0 32rpx 32rpx; }
/* 头像区卡片 */
.hero-card {
position: relative; overflow: hidden;
background: #0F1720; border: 1rpx solid rgba(255,255,255,0.08);
border-radius: 32rpx; margin-bottom: 32rpx;
padding: 64rpx 32rpx; display: flex; flex-direction: column; align-items: center;
/* —— 首屏外壳 —— */
.shell {
position: relative; margin: 28rpx 24rpx 0; padding: 40rpx 32rpx 36rpx;
border-radius: 32rpx;
background: linear-gradient(145deg, rgba(22, 36, 48, 0.95) 0%, rgba(12, 20, 32, 0.98) 100%);
border: 1rpx solid rgba(94, 234, 212, 0.12);
box-shadow: 0 24rpx 80rpx rgba(0, 0, 0, 0.45), inset 0 1rpx 0 rgba(255, 255, 255, 0.06);
overflow: hidden;
}
.hero-gradient {
position: absolute; top: 0; left: 0; right: 0; height: 128rpx;
background: linear-gradient(to bottom, rgba(30,58,69,0.3) 0%, transparent 100%);
.shell-glow {
position: absolute; top: -40%; right: -20%; width: 70%; height: 80%;
background: radial-gradient(circle, rgba(45, 212, 191, 0.12) 0%, transparent 70%);
pointer-events: none;
}
.hero-content { position: relative; z-index: 1; display: flex; flex-direction: column; align-items: center; }
.hero-avatar {
width: 176rpx; height: 176rpx; border-radius: 50%;
overflow: hidden; border: 2rpx solid rgba(255,255,255,0.1);
margin-bottom: 32rpx;
.hero-row { position: relative; z-index: 1; display: flex; align-items: flex-start; gap: 28rpx; }
.avatar-outer { position: relative; width: 168rpx; height: 168rpx; flex-shrink: 0; }
.avatar-wrap {
width: 100%; height: 100%; border-radius: 50%; overflow: hidden;
border: 2rpx solid rgba(255, 255, 255, 0.12);
box-shadow: 0 12rpx 40rpx rgba(0, 0, 0, 0.35);
}
.avatar-img { width: 100%; height: 100%; display: block; }
.avatar-placeholder {
width: 100%; height: 100%; display: flex; align-items: center; justify-content: center;
font-size: 72rpx; font-weight: bold; color: #5EEAD4;
background: rgba(94,234,212,0.2);
.avatar-img { width: 100%; height: 100%; object-fit: cover; }
.avatar-ph {
width: 100%; height: 100%; background: #1a2332;
display: flex; align-items: center; justify-content: center;
font-size: 52rpx; color: #5eead4; font-weight: 700;
}
.hero-name { font-size: 40rpx; font-weight: bold; margin-bottom: 24rpx; }
.hero-tags { display: flex; align-items: center; justify-content: center; gap: 24rpx; }
.tag { padding: 8rpx 24rpx; border-radius: 999rpx; font-size: 24rpx; font-weight: 500; }
.tag-mbti { background: #134E4A; color: #5EEAD4; border: 1rpx solid rgba(94,234,212,0.2); }
.tag-region { display: flex; align-items: center; gap: 8rpx; background: #1F2937; color: #d1d5db; border: 1rpx solid rgba(255,255,255,0.1); }
.tag-region .tag-icon { flex-shrink: 0; }
/* 通用区块 */
.section {
background: #0F1720; border: 1rpx solid rgba(255,255,255,0.08);
border-radius: 32rpx; margin-bottom: 32rpx;
padding: 40rpx; box-shadow: 0 16rpx 32rpx rgba(0,0,0,0.2);
/* 右侧联系方式列 */
.link-column { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 16rpx; }
.link-column-title { font-size: 26rpx; font-weight: 700; color: #f1f5f9; letter-spacing: 2rpx; }
.link-chip {
display: flex; align-items: center; gap: 20rpx;
padding: 22rpx; border-radius: 20rpx;
background: rgba(15, 23, 42, 0.65);
border: 1rpx solid rgba(94, 234, 212, 0.25);
}
.section-head { display: flex; align-items: center; gap: 20rpx; margin-bottom: 40rpx; }
.section-icon { font-size: 40rpx; }
.section-icon-yellow { filter: brightness(1.2); }
.section-title { font-size: 30rpx; font-weight: bold; }
.section-body { }
.field { margin-bottom: 48rpx; }
.field:last-child { margin-bottom: 0; }
.field-label { display: block; font-size: 26rpx; color: #94A3B8; margin-bottom: 16rpx; }
.field-value { font-size: 30rpx; font-weight: 500; color: #fff; line-height: 1.5; }
.field-value.mono { font-family: monospace; letter-spacing: 0.02em; }
.field-value-row { display: flex; align-items: center; gap: 16rpx; }
.field-hint { font-size: 24rpx; color: #5EEAD4; }
.field-divider { height: 1rpx; background: rgba(255,255,255,0.05); margin: 32rpx 0; }
.field-empty { font-size: 26rpx; color: #64748b; }
/* 个人故事 */
.story-block { margin-bottom: 48rpx; }
.story-block:last-child { margin-bottom: 0; }
.story-head { display: flex; align-items: center; gap: 16rpx; margin-bottom: 16rpx; }
.story-emoji { font-size: 32rpx; }
.story-label { font-size: 26rpx; font-weight: 500; color: #94A3B8; }
.story-text { font-size: 28rpx; color: #e5e7eb; line-height: 1.6; display: block; }
/* 互助需求 */
.help-block {
background: #17212F; border: 1rpx solid rgba(255,255,255,0.05);
border-radius: 20rpx; padding: 32rpx; margin-bottom: 24rpx;
.link-chip:active { background: rgba(15, 30, 40, 0.75); }
.link-chip-icon {
width: 64rpx; height: 64rpx; border-radius: 16rpx;
display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.help-block:last-child { margin-bottom: 0; }
.help-tag {
display: inline-block; font-size: 22rpx; font-weight: 500;
padding: 8rpx 16rpx; border-radius: 8rpx; margin-bottom: 16rpx;
.link-chip-icon-phone { background: rgba(45, 212, 191, 0.12); }
.link-chip-icon-wx { background: rgba(52, 211, 153, 0.12); }
.lc-ic { display: block; }
.link-chip-main { flex: 1; min-width: 0; }
.link-chip-label { display: block; font-size: 20rpx; color: #94a3b8; margin-bottom: 6rpx; }
.link-chip-val { display: block; font-size: 26rpx; font-weight: 600; color: #f8fafc; line-height: 1.35; word-break: break-all; }
.link-chip-val.mono { font-family: ui-monospace, monospace; letter-spacing: 1rpx; }
.link-chip-action { flex-shrink: 0; font-size: 22rpx; font-weight: 600; color: #5eead4; }
.link-empty { padding: 24rpx; border-radius: 20rpx; background: rgba(15, 23, 42, 0.4); border: 1rpx dashed rgba(148, 163, 184, 0.2); }
.link-empty-txt { font-size: 24rpx; color: #64748b; }
.profile-name {
position: relative; z-index: 1; display: block; text-align: center;
margin-top: 36rpx; font-size: 40rpx; font-weight: 700; color: #fff; letter-spacing: 4rpx;
}
.help-tag-accent { background: #112D2A; color: #5EEAD4; }
.help-tag-orange { background: #2D1F0D; color: #F59E0B; }
.help-text { font-size: 26rpx; color: #fff; line-height: 1.6; display: block; }
.profile-tags {
position: relative; z-index: 1;
display: flex; align-items: center; justify-content: center; gap: 20rpx; flex-wrap: wrap;
margin-top: 24rpx;
}
.tag { font-size: 24rpx; font-weight: 500; padding: 10rpx 26rpx; border-radius: 999rpx; }
.tag-mbti { background: rgba(19, 78, 74, 0.6); color: #5eead4; border: 1rpx solid rgba(94, 234, 212, 0.25); }
.tag-region {
background: rgba(30, 41, 59, 0.8); color: #cbd5e1; border: 1rpx solid rgba(255, 255, 255, 0.08);
display: flex; align-items: center; gap: 8rpx;
}
.pin-icon { color: #f87171; font-size: 22rpx; }
.project-text { font-size: 28rpx; color: #e5e7eb; line-height: 1.6; }
/* —— 一体化信息卡 —— */
.mono-card {
margin: 24rpx 24rpx 0; padding: 8rpx 0 32rpx; border-radius: 32rpx;
background: rgba(15, 23, 34, 0.88);
border: 1rpx solid rgba(255, 255, 255, 0.07);
box-shadow: 0 16rpx 48rpx rgba(0, 0, 0, 0.25);
}
.mono-sec { padding: 28rpx 32rpx 8rpx; }
.mono-sec-head { margin-bottom: 24rpx; }
.mono-sec-title { font-size: 32rpx; font-weight: 700; color: #f8fafc; }
.mono-divider { height: 1rpx; margin: 8rpx 32rpx; background: linear-gradient(90deg, transparent, rgba(148, 163, 184, 0.15), transparent); }
.bottom-spacer { height: 180rpx; }
.kv { margin-bottom: 28rpx; }
.kv:last-child { margin-bottom: 8rpx; }
.kv-k { display: block; font-size: 22rpx; color: #64748b; margin-bottom: 10rpx; }
.kv-v { font-size: 28rpx; color: #e2e8f0; line-height: 1.65; font-weight: 500; }
/* 底部按钮 - 设计稿:透明背景 + 橙色描边 */
.skills-showcase .skills-quote {
padding: 28rpx 28rpx 28rpx 24rpx; border-radius: 20rpx;
background: linear-gradient(105deg, rgba(45, 212, 191, 0.08) 0%, rgba(15, 23, 42, 0.5) 100%);
border-left: 6rpx solid #2dd4bf;
box-shadow: inset 0 0 0 1rpx rgba(45, 212, 191, 0.12);
}
.skills-quote-text { font-size: 30rpx; color: #f1f5f9; line-height: 1.75; font-weight: 500; }
.story { margin-bottom: 8rpx; }
.story-gap { height: 28rpx; }
.story-head { display: flex; align-items: center; gap: 12rpx; margin-bottom: 12rpx; }
.story-icon { flex-shrink: 0; }
.story-q { font-size: 24rpx; font-weight: 600; color: #94a3b8; }
.story-a { display: block; font-size: 28rpx; color: #e2e8f0; line-height: 1.7; padding-left: 4rpx; }
.help-grid { display: flex; flex-direction: column; gap: 20rpx; }
.help-tile {
padding: 28rpx; border-radius: 22rpx;
background: rgba(23, 33, 47, 0.9); border: 1rpx solid rgba(255, 255, 255, 0.06);
}
.help-tile-tag {
display: inline-block; font-size: 20rpx; font-weight: 700;
padding: 8rpx 18rpx; border-radius: 12rpx; margin-bottom: 16rpx;
}
.help-give .help-tile-tag { color: #5eead4; background: rgba(6, 78, 59, 0.45); border: 1rpx solid rgba(45, 212, 191, 0.2); }
.help-need .help-tile-tag.need { color: #fbbf24; background: rgba(69, 47, 8, 0.45); border: 1rpx solid rgba(251, 191, 36, 0.2); }
.help-tile-txt { font-size: 28rpx; color: #f1f5f9; line-height: 1.65; }
.proj-body { font-size: 28rpx; color: #cbd5e1; line-height: 1.75; padding-bottom: 8rpx; }
/* —— 空态 —— */
.empty-hint {
margin: 48rpx 24rpx; padding: 64rpx 32rpx;
display: flex; flex-direction: column; align-items: center; gap: 24rpx;
border-radius: 28rpx; background: rgba(15, 23, 34, 0.5);
border: 1rpx dashed rgba(148, 163, 184, 0.15);
}
.empty-hint-txt { font-size: 26rpx; color: #64748b; }
.scroll-pad { height: calc(80rpx + env(safe-area-inset-bottom)); }
/* —— 底部 —— */
.bottom-bar {
position: fixed; bottom: 0; left: 0; right: 0; z-index: 50;
padding: 32rpx; padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
background: rgba(5,11,20,0.95); backdrop-filter: blur(8rpx);
border-top: 1rpx solid rgba(255,255,255,0.05);
padding: 20rpx 24rpx; padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
background: rgba(5, 11, 20, 0.92); backdrop-filter: blur(20rpx);
border-top: 1rpx solid rgba(255, 255, 255, 0.06);
}
.vip-btn-outline {
display: flex; align-items: center; justify-content: center; gap: 16rpx;
width: 100%; height: 96rpx;
background: transparent; color: #F59E0B;
border: 2rpx solid rgba(245,158,11,0.3);
border-radius: 999rpx; font-size: 30rpx; font-weight: 500;
.vip-btn {
display: flex; align-items: center; justify-content: center; gap: 12rpx;
width: 100%; height: 88rpx; border-radius: 999rpx; border: none;
background: linear-gradient(135deg, #5eead4 0%, #2dd4bf 50%, #14b8a6 100%);
color: #0f172a; font-size: 28rpx; font-weight: 700;
box-shadow: 0 8rpx 28rpx rgba(45, 212, 191, 0.35);
}
.vip-btn-arrow { font-size: 36rpx; }
.vip-btn:active { opacity: 0.85; }
/* —— 加载态 —— */
.state-wrap {
display: flex; flex-direction: column; align-items: center; justify-content: center;
min-height: 60vh; gap: 24rpx;
}
.state-txt { font-size: 28rpx; color: #64748b; }
.loading-dot {
width: 56rpx; height: 56rpx; border-radius: 50%;
border: 4rpx solid rgba(94, 234, 212, 0.2); border-top-color: #5eead4;
animation: spin 1s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }