Files
mama-box/guangchang/index.html

2287 lines
198 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<!-- 11-04 UGC 总开关关着时本页不展示,直接回首页(js/ugc.js) -->
<script src="../js/ugc.js?v=26110438" data-guard></script>
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
<meta name="format-detection" content="telephone=no">
<title>孕妈广场</title>
<!-- 孕妈广场(2026-11-01 第一版,占位内容,纯前端;mama-box 首页「孕妈广场」横滑卡点进来)
用户原话:「点进去之后变成小红书那种瀑布流,每一个话题都是那样的。先整理出来 15 个话题,先做占位放上。点击详情页的时候可以点赞和评论。」
· 话题表 topics.js(与首页共用);笔记 / 评论池 data.js(每话题 7 条笔记 + 10 条评论池,评论按笔记 id 确定性抽 3~8 条)。
· URL:?t=话题id 进对应话题,&n=笔记id 直接打开详情;切 tab 只用 replaceState 改 query,**hash 原样保留**(身份 #openid 在里面)。
· 点赞 / 收藏 / 评论 / 评论点赞只存本机 localStorage「mmbox.gc.v1」,按 openid 分开;正式版接后端时整块替换 store。
· 返回:详情层 → history.back() 关层;列表 → 有站内历史就 history.back(),没有就回 ../(保留身份,去掉 t/n)。
· 禁止下拉回弹:固定外壳 + 容器滚动 + touchmove 拦截(同首页那段:往上找能朝该方向滚的容器,找不到才拦)。 -->
<style>
:root{
--brand:#F4593C;--ink:#2B2320;--ink-2:#6B615B;--muted:#9A8380;--line:#F1E7E1;
--bg:#F8F3EF;--peach:#FFEDE6;--btn:linear-gradient(135deg,#F77B55,#EE5A3E);
--safe-b:env(safe-area-inset-bottom);
}
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html,body{margin:0;padding:0;height:100%;overflow:hidden;overscroll-behavior:none}
body{background:var(--bg);font-family:-apple-system,BlinkMacSystemFont,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","Segoe UI",Roboto,sans-serif;
color:var(--ink);-webkit-font-smoothing:antialiased;font-size:14px;line-height:1.5;-webkit-text-size-adjust:100%}
button{font:inherit;color:inherit;border:0;background:none;padding:0;cursor:pointer}
.ic{width:16px;height:16px;flex:none;display:inline-block;vertical-align:middle}
.hide{display:none!important}
/* ---------- 外壳:唯一的滚动容器 ---------- */
#sc{position:fixed;inset:0;overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch;overscroll-behavior:none;
background:radial-gradient(220px 180px at 100% 0,rgba(255,196,214,.45),rgba(255,196,214,0) 70%),radial-gradient(240px 200px at 0 40px,rgba(255,206,170,.45),rgba(255,206,170,0) 70%),var(--bg)}
#sc::-webkit-scrollbar{display:none}
.top{position:sticky;top:0;z-index:20;padding-top:env(safe-area-inset-top);background:rgba(248,243,239,.9);-webkit-backdrop-filter:blur(14px) saturate(160%);backdrop-filter:blur(14px) saturate(160%);transition:box-shadow .2s}
.top.on{box-shadow:0 4px 14px rgba(160,110,90,.10)}
.nav{display:flex;align-items:center;gap:6px;height:46px;padding:0 10px}
.nav .bk{width:36px;height:36px;display:grid;place-items:center;border-radius:50%;color:var(--ink)}
.nav .bk:active{background:rgba(0,0,0,.05)}
.nav .bk .ic{width:22px;height:22px}
.nav h1{flex:1;margin:0;text-align:center;font-size:17px;font-weight:900;letter-spacing:.5px}
.nav h1 span{background:linear-gradient(transparent 60%,#FFD0DC 60%,#FFD0DC 92%,transparent 92%);padding:0 3px}
.nav .sp{width:36px}
/* ---------- 一级分类(11-02 第四版:用户「去掉图标、滑块缺设计感」→ 小红书式文字标签:选中字放大加粗 + 底下一条会滑动的分类色胶囊;左右滑页面也能切) ---------- */
.cats{position:relative;display:flex;gap:8px;margin:0 6px;padding:2px 0 10px}
.cats button{position:relative;z-index:1;flex:none;padding:6px 12px 4px;font-size:15.5px;font-weight:700;color:#A08B85;letter-spacing:.3px;line-height:24px;transition:color .25s}
.cats button .ic{display:none}
.cats button.on{font-size:18px;font-weight:900;color:#2A1E1E}
.cats button i{position:absolute;left:calc(100% - 12px);top:2px;font-style:normal;font-size:10px;font-weight:800;line-height:12px;color:var(--cf);opacity:0;transition:opacity .25s}
.cats button.on i{opacity:1}
.cats .bar{display:block;padding:0;border:0;gap:0;/* 11-03:别吃到详情底栏通用 .bar 的内边距(色块被撑到 17px) */position:absolute;z-index:0;left:0;bottom:12px;height:7px;width:28px;border-radius:7px;background:var(--cbar,#F4593C);opacity:.32;
transition:transform .32s cubic-bezier(.3,1.3,.5,1),width .32s cubic-bezier(.3,1.3,.5,1),background .25s;pointer-events:none}
.cats::after{content:"";position:absolute;left:6px;right:6px;bottom:0;height:1px;background:linear-gradient(90deg,transparent,#EADAD3 20%,#EADAD3 80%,transparent)}
.cats button:active{transform:scale(.96)}
.cats .c-all{--cf:#F4593C}
/* 四块分类色(11-01 第四版:按用户选题清单分 家庭 / 婚姻 / 职场 / 母婴):kf 实色 · kt 深字 · kl/kl2 浅底两色 */
.k-family,.c-family{--kf:#E0566F;--kt:#C23A55;--kl:#FFF0F3;--kl2:#FFD9E0}
.k-marriage,.c-marriage{--kf:#7B5CC4;--kt:#6346B0;--kl:#F4F0FF;--kl2:#E0D5FA}
.k-work,.c-work{--kf:#3A72B8;--kt:#2C5E9E;--kl:#EEF4FC;--kl2:#D2E2F6}
.k-baby,.c-baby{--kf:#2E8A7C;--kt:#21705F;--kl:#EBF7F3;--kl2:#CDEBE3}
.cats .c-family,.cats .c-marriage,.cats .c-work,.cats .c-baby{--cf:var(--kf)}
/* ---------- 祈福树 banner(11-02):夜空 + 摇摆的树 + 飘福牌 ---------- */
.qf{position:relative;display:block;width:calc(100% - 24px);height:148px;margin:2px 12px 0;border-radius:20px;overflow:hidden;text-align:left;
background:radial-gradient(120% 140% at 82% 100%,#3B3A86 0%,#252A63 38%,#161B3F 75%);box-shadow:0 12px 26px -14px rgba(30,30,90,.7)}
.qf:active{transform:scale(.985)}
.qf-st{position:absolute;inset:0;pointer-events:none;opacity:.9;
background-image:radial-gradient(1.4px 1.4px at 12% 20%,#fff,transparent),radial-gradient(1px 1px at 28% 70%,#fff,transparent),radial-gradient(1.2px 1.2px at 46% 14%,#FFE9B0,transparent),
radial-gradient(1px 1px at 54% 82%,#fff,transparent),radial-gradient(1.5px 1.5px at 62% 30%,#fff,transparent),radial-gradient(1px 1px at 8% 88%,#FFE9B0,transparent),radial-gradient(1.2px 1.2px at 40% 46%,#fff,transparent);
animation:qfTw 3.2s ease-in-out infinite alternate}
.qf-st::after{content:"";position:absolute;inset:0;background-image:radial-gradient(1.3px 1.3px at 20% 40%,#fff,transparent),radial-gradient(1px 1px at 35% 26%,#FFE9B0,transparent),radial-gradient(1.4px 1.4px at 50% 60%,#fff,transparent),radial-gradient(1px 1px at 16% 62%,#fff,transparent);
animation:qfTw 2.4s ease-in-out infinite alternate-reverse}
@keyframes qfTw{from{opacity:.35}to{opacity:1}}
.qf-glow{position:absolute;right:-6px;bottom:-30px;width:190px;height:190px;border-radius:50%;pointer-events:none;
background:radial-gradient(circle,rgba(255,206,110,.55) 0%,rgba(255,170,80,.22) 40%,transparent 70%);animation:qfGl 3.6s ease-in-out infinite}
@keyframes qfGl{0%,100%{opacity:.7;transform:scale(.94)}50%{opacity:1;transform:scale(1.06)}}
.qf-tree{position:absolute;right:-4px;bottom:-4px;height:150px;width:auto;transform-origin:52% 100%;animation:qfSw 5.5s ease-in-out infinite;filter:drop-shadow(0 6px 12px rgba(0,0,0,.35))}
@keyframes qfSw{0%,100%{transform:rotate(-1.6deg)}50%{transform:rotate(1.6deg)}}
.qf-fly{position:absolute;right:22px;bottom:60px;width:110px;height:100px;pointer-events:none}
.qf-fly i{position:absolute;bottom:0;width:15px;height:20px;border-radius:3px;background:linear-gradient(#E8343F,#B8141F);color:#FFD98A;font-style:normal;font-size:10px;font-weight:900;line-height:20px;text-align:center;
font-family:"STKaiti","KaiTi","Kaiti SC",serif;box-shadow:0 0 8px rgba(255,190,90,.6);opacity:0;animation:qfUp 4.8s ease-in infinite}
.qf-fly i::before{content:"";position:absolute;left:50%;top:-5px;width:1px;height:5px;background:#FFD98A}
.qf-fly i:nth-child(1){left:6px;animation-delay:0s}.qf-fly i:nth-child(2){left:44px;animation-delay:1.2s}
.qf-fly i:nth-child(3){left:82px;animation-delay:2.4s}.qf-fly i:nth-child(4){left:26px;animation-delay:3.6s}
@keyframes qfUp{0%{opacity:0;transform:translateY(10px) rotate(-8deg) scale(.7)}15%{opacity:1}70%{opacity:.9}100%{opacity:0;transform:translateY(-88px) rotate(10deg) scale(1)}}
.qf-tx{position:relative;z-index:2;display:flex;flex-direction:column;align-items:flex-start;height:100%;padding:16px 0 14px 16px;color:#fff}
.qf-tx small{display:inline-flex;align-items:center;gap:5px;height:20px;padding:0 9px 0 7px;border-radius:99px;background:rgba(255,255,255,.12);font-size:11px;font-weight:700;color:#FFE3A6;letter-spacing:.5px}
.qf-tx small i{width:6px;height:6px;border-radius:50%;background:#FFC85C;box-shadow:0 0 6px #FFC85C;animation:qfGl 1.8s ease-in-out infinite}
.qf-tx b{margin-top:9px;font-size:19px;font-weight:900;letter-spacing:.5px;line-height:1.2;font-family:"STKaiti","KaiTi","Kaiti SC","STSong",serif;
background:linear-gradient(180deg,#FFF3D2,#FFC86A);-webkit-background-clip:text;background-clip:text;color:transparent;text-shadow:0 0 18px rgba(255,200,110,.25)}
.qf-tx b i{font-style:normal;margin:0 1px;font-family:-apple-system,"PingFang SC",sans-serif;font-weight:900}
.qf-tx em{margin-top:5px;font-style:normal;font-size:11px;color:rgba(255,236,200,.75);letter-spacing:.5px}
.qf-go{position:relative;overflow:hidden;margin-top:auto;display:inline-flex;align-items:center;gap:2px;height:30px;padding:0 10px 0 14px;border-radius:99px;
background:linear-gradient(135deg,#FFE29A,#F6B544);color:#7A3A0C;font-size:13px;font-weight:900;box-shadow:0 6px 14px -6px rgba(255,190,80,.9)}
.qf-go .ic{width:13px;height:13px}
.qf-go::after{content:"";position:absolute;top:0;bottom:0;left:-60%;width:40%;background:linear-gradient(100deg,transparent,rgba(255,255,255,.7),transparent);transform:skewX(-18deg);animation:qfSh 2.8s ease-in-out infinite}
@keyframes qfSh{0%,55%{left:-60%}100%{left:130%}}
@media (prefers-reduced-motion:reduce){.qf *,.qf *::before,.qf *::after{animation:none!important}.qf-fly{display:none}}
/* 投稿奖励:热门话题列表头一行 */
.htl .rwl{display:flex;align-items:center;gap:6px;width:100%;margin:6px 0 2px;padding:8px 10px;border-radius:12px;background:linear-gradient(100deg,#FFF1E8,#FFE6E6);text-align:left;font-size:12px;font-weight:700;color:#8A4B36}
.htl .rwl .ic{flex:none;width:16px;height:16px;color:#F2553A}
.htl .rwl span{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.htl .rwl em{font-style:normal;color:#F2394A;font-weight:900}
.htl .rwl b{flex:none;font-size:11.5px;color:#F2553A}
/* ---------- 投稿有奖横幅 ---------- */
.rw{position:relative;display:flex;align-items:center;gap:12px;margin:2px 12px 0;padding:13px 14px;border-radius:18px;overflow:hidden;width:calc(100% - 24px);text-align:left;
background:radial-gradient(120px 90px at 100% 0,rgba(255,255,255,.35),transparent 70%),linear-gradient(120deg,#FF8A5B,#F4593C 60%,#E8473A);color:#fff;box-shadow:0 10px 22px -12px #E8473A}
.rw .gf{width:42px;height:42px;flex:none;display:grid;place-items:center;border-radius:14px;background:rgba(255,255,255,.22)}
.rw .gf .ic{width:24px;height:24px}
.rw .rt{flex:1;min-width:0}
.rw .rt small{display:block;font-size:12px;font-weight:700;opacity:.9;letter-spacing:.5px}
.rw .rt b{display:block;margin-top:1px;font-size:17px;font-weight:900;letter-spacing:.3px;white-space:nowrap}
.rw .rt b em{font-style:normal;font-size:20px;color:#FFF3B8}
.rw .go{flex:none;height:30px;padding:0 11px;border-radius:99px;background:#fff;color:#E8473A;font-size:12.5px;font-weight:800;display:inline-flex;align-items:center}
.rw.sm{margin-top:12px;padding:10px 12px}
.rw.sm .gf{width:34px;height:34px;border-radius:11px}
.rw.sm .gf .ic{width:19px;height:19px}
.rw.sm .rt b{font-size:14.5px}
.rw.sm .rt b em{font-size:16px}
/* ---------- 区块标题 ---------- */
.sh{display:flex;align-items:center;gap:6px;margin:18px 14px 8px}
.sh h2{margin:0;font-size:17px;font-weight:900;letter-spacing:.3px}
.sh .fire{width:18px;height:18px;color:#FF5A3C}
.sh small{font-size:12px;font-weight:600;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
.sh .more{margin-left:auto;font-size:12.5px;font-weight:700;color:var(--muted);display:inline-flex;align-items:center}
/* ---------- 热门话题:横滑卡 ---------- */
.hot{display:flex;gap:10px;padding:0 12px 2px;overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain;scroll-snap-type:x mandatory}
.hot::-webkit-scrollbar{display:none}
.hot::after{content:"";flex:none;width:2px}
/* 11-02 v2 测一测:广场第 5 个分类「测一测」(经验后面)+「大家在聊」信息流里穿插测试卡。卡片插画 ceshi/img/<id>_s.webp */
.cats .c-ceshi{--cf:#7C5CFC;align-self:center;display:inline-flex;align-items:center;gap:3px;margin-left:9px;height:30px;padding:0 12px 0 9px;border-radius:99px;font-size:14px;font-weight:800;color:#7C5CFC;
background:linear-gradient(120deg,#F1ECFF,#FFE8F1);box-shadow:inset 0 0 0 1px rgba(124,92,252,.18);line-height:30px}
.cats .c-ceshi::before{content:"";position:absolute;left:-9px;top:7px;bottom:7px;width:1px;background:#E6D7D0}
.cats .c-ceshi .ic{display:block;width:13px;height:13px;flex:none}
.cats .c-ceshi i{display:none}
.cats .c-ceshi.on{font-size:14px;font-weight:900;color:#fff;background:linear-gradient(120deg,#8E6BFF,#EE6A9C);box-shadow:0 6px 14px -6px rgba(200,90,180,.7)}
/* 测一测列表(11-02 v3 用户:「列表别跟帖子一个样,换个形式」)→ 分组专栏:组头 + 推荐横卡 + 条目行 */
.csl{padding:0 14px}
/* 11-03 测试列表 · 参考图排版(分组标题 + 宫格卡) */
.cst{display:grid;grid-template-columns:repeat(5,1fr);gap:7px;padding:12px 14px 0}
.cst button{height:34px;border-radius:10px;background:#fff;border:1px solid #F0E6EE;box-shadow:0 2px 6px rgba(150,110,140,.06);font-size:13px;font-weight:700;color:#5A4C58;white-space:nowrap}
.cst button.on{background:linear-gradient(135deg,#EFEAFF,#E6F0FF);border-color:#D9D0FA;color:#4F45B5;font-weight:900}
.csg{margin-top:22px}
/* 11-04 测试列表「热闹」:实时在测 + 战报 + 手气测 + 卡片在测 / TOP / 弹入 / 扫光 */
.luck-fl{position:fixed;left:50%;top:64px;z-index:60;display:flex;align-items:center;gap:8px;height:44px;padding:0 6px 0 8px;border-radius:99px;color:#fff;
background:linear-gradient(120deg,#7B5CF5,#A17BFF 60%,#FF8FB1);box-shadow:0 10px 22px -8px rgba(123,92,245,.75);transform:translate(-50%,-14px) scale(.9);opacity:0;pointer-events:none;transition:transform .3s cubic-bezier(.3,1.4,.5,1),opacity .2s;white-space:nowrap}
.luck-fl.on{transform:translate(-50%,0);opacity:1;pointer-events:auto}
.luck-fl-d{width:30px;height:30px;animation:lkIdle 3.2s ease-in-out infinite}.luck-fl-d svg{width:100%;height:100%;display:block}
.luck-fl b{font-size:14px;font-weight:800}
.luck-fl em{height:32px;padding:0 14px;border-radius:99px;background:#fff;color:#6A4BE0;font-size:13.5px;font-style:normal;font-weight:900;line-height:32px;animation:lkPulse 1.8s ease-in-out infinite}
.luck{position:relative;display:flex;align-items:center;gap:10px;width:calc(100% - 24px);margin:12px 12px 0;padding:14px 12px 14px 14px;border-radius:20px;text-align:left;color:#fff;
background:radial-gradient(circle at 88% 0,rgba(255,255,255,.28) 0 38px,transparent 39px),radial-gradient(circle at 6% 120%,rgba(255,201,77,.45) 0 46px,transparent 47px),linear-gradient(120deg,#7B5CF5,#A17BFF 55%,#FF8FB1);box-shadow:0 10px 22px -10px rgba(123,92,245,.7);overflow:visible}
.luck-dc{flex:none;width:46px;height:46px;filter:drop-shadow(0 4px 6px rgba(60,30,140,.35));animation:lkIdle 3.2s ease-in-out infinite;transform-origin:50% 60%}
.luck-dc svg{width:100%;height:100%;display:block}
.luck-dc.d2{position:absolute;left:44px;top:6px;width:24px;height:24px;animation-delay:.4s}
@keyframes lkIdle{0%,72%,100%{transform:rotate(0)}78%{transform:rotate(-14deg) translateY(-3px)}86%{transform:rotate(10deg) translateY(-1px)}93%{transform:rotate(-4deg)}}
.luck.roll .luck-dc{animation:lkTumble .35s linear infinite}
.luck.roll .luck-dc.d2{animation-duration:.28s}
@keyframes lkTumble{0%{transform:rotate(0) translateY(0)}25%{transform:rotate(90deg) translateY(-6px)}50%{transform:rotate(180deg) translateY(0)}75%{transform:rotate(270deg) translateY(-4px)}100%{transform:rotate(360deg)}}
.luck.hit .luck-dc{animation:lkLand .5s cubic-bezier(.3,1.6,.5,1)}
@keyframes lkLand{from{transform:scale(1.3) rotate(-20deg)}to{transform:none}}
.luck-t{flex:1;min-width:0;display:flex;flex-direction:column;gap:5px;padding-left:4px}
.luck-t>b{font-size:16.5px;font-weight:900;letter-spacing:.3px;text-shadow:0 1px 2px rgba(60,30,140,.25)}
.luck-w{display:block;height:22px;line-height:22px;padding:0 9px;border-radius:8px;background:rgba(255,255,255,.22);font-size:12px;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.luck-w .sp{display:inline-block;animation:lkSp .09s linear}
@keyframes lkSp{from{transform:translateY(-70%);opacity:.3}}
.luck-w .hit{display:inline-block;color:#FFE27A;font-weight:900;animation:lkLand .45s cubic-bezier(.3,1.6,.5,1)}
.luck-b{flex:none;height:34px;padding:0 14px;border-radius:99px;background:#fff;color:#6A4BE0;font-size:14px;font-style:normal;font-weight:900;line-height:34px;box-shadow:0 4px 10px -4px rgba(60,30,140,.5);animation:lkPulse 1.8s ease-in-out infinite}
@keyframes lkPulse{50%{transform:scale(1.07)}}
.luck.roll .luck-b,.luck.hit .luck-b{animation:none;opacity:.6}
.luck:active{transform:scale(.985)}
.luck-fx{position:absolute;left:50%;top:50%;pointer-events:none}
.luck-fx i{position:absolute;width:7px;height:7px;border-radius:2px;animation:lkBoom .9s ease-out forwards}
@keyframes lkBoom{from{transform:translate(0,0) scale(1);opacity:1}to{transform:translate(var(--x),var(--y)) rotate(200deg) scale(.4);opacity:0}}
.csv{display:grid;grid-template-columns:1fr;gap:6px;margin:10px 12px 0;padding:10px 12px;border-radius:16px;background:linear-gradient(135deg,#FFF1EA,#FFF7F0 60%,#F6F0FF);box-shadow:0 4px 14px -8px rgba(240,112,79,.35)}
.csv-n{font-size:13px;font-weight:700;color:#6E5A55;display:flex;align-items:center;gap:6px}
.csv-n b{font-size:17px;font-weight:900;color:#F0453A;display:inline-block}
.csv-n b.bp{animation:csvBp .5s ease}
@keyframes csvBp{40%{transform:translateY(-2px) scale(1.08)}}
.csv-dot{width:8px;height:8px;border-radius:50%;background:#F0453A;box-shadow:0 0 0 0 rgba(240,69,58,.5);animation:csvDot 1.4s ease-out infinite}
@keyframes csvDot{70%{box-shadow:0 0 0 7px rgba(240,69,58,0)}100%{box-shadow:0 0 0 0 rgba(240,69,58,0)}}
.csv-r{grid-column:1/-1;position:relative;height:24px;overflow:hidden}
.csv-i{position:absolute;inset:0;display:flex;align-items:center;gap:6px;width:100%;font-size:12.5px;color:#7A6863;text-align:left;opacity:0;transform:translateY(100%);transition:transform .45s ease,opacity .45s ease}
.csv-i.on{opacity:1;transform:none}.csv-i.up{opacity:0;transform:translateY(-100%)}
.csv-i img{flex:none;width:20px;height:20px;border-radius:50%;object-fit:cover;border:1.5px solid #fff;background:#FFE3D3}
.csv-i span{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.csv-i em{font-style:normal;font-weight:800;color:#3A2A26;margin-right:4px}
.csv-i b{font-weight:800;color:#8D6BFF}
.csv-i small{flex:none;font-size:11px;color:#B5A39C}
.ck .cv .ck-top{position:absolute;right:0;top:0;z-index:1;height:20px;padding:0 8px 0 9px;border-radius:0 0 0 12px;color:#fff;font-size:10.5px;font-style:italic;font-weight:900;line-height:20px;letter-spacing:.3px}
.ck-top.t1{background:linear-gradient(135deg,#F0453A,#FF8A3D)}.ck-top.t2{background:linear-gradient(135deg,#FF8A2E,#FFC06E)}.ck-top.t3{background:linear-gradient(135deg,#8D6BFF,#B9A3FF)}
.ck .cv em{position:relative;overflow:hidden}
.ck .cv em::after{content:"";position:absolute;top:0;bottom:0;left:-60%;width:40%;background:linear-gradient(100deg,transparent,rgba(255,255,255,.55),transparent);transform:skewX(-18deg);animation:ckShine 3.6s ease-in-out infinite}
@keyframes ckShine{0%,62%{left:-60%}88%,100%{left:130%}}
.pre{opacity:0}
.pre.pop-in{animation:ckPop .5s cubic-bezier(.3,1.35,.5,1) both}
@keyframes ckPop{from{opacity:0;transform:translateY(14px) scale(.96)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){.luck-dc,.luck-b{animation:none}.pre{opacity:1}.pre.pop-in,.ck .cv em::after,.csv-dot{animation:none}}
.csg-h{display:flex;flex-direction:column;gap:5px;padding:0 2px}
.csg-h b{display:flex;align-items:center;gap:6px;padding-left:10px;border-left:3px solid #B9B3D6;font-size:19px;font-weight:900;line-height:1.1;color:#2B2433}
.csg-h b i{font-style:normal;font-size:18px}
.csg-h b{border-left:0;padding-left:0}
.csg-h small{padding-left:32px}
.csg-ic{display:grid;place-items:center;width:26px;height:26px;border-radius:8px;background:var(--gi)}
.csg-ic svg{width:16px;height:16px}
.csg.g-quiz{--gi:#FF8A65}.csg.g-psy{--gi:#9A7FE0}.csg.g-game{--gi:#3FAE7A}.csg.g-shop{--gi:#4E8DE6}
.csr.gq,.ck.gq{--c1:#FFF4EA;--c2:#FFE3D3;--c3:#FFC9AE;--c4:#FFB08F;--cb:#FF8A65}
.csr.gp,.ck.gp{--c1:#F6F1FF;--c2:#EAE2FB;--c3:#CDBEF5;--c4:#DCCFF7;--cb:#9A7FE0}
.csr.gg,.ck.gg{--c1:#F0FAF4;--c2:#DDF3E7;--c3:#B5E5CB;--c4:#C6EBD6;--cb:#3FAE7A}
.csr.gs,.ck.gs{--c1:#F0F6FF;--c2:#DFEBFD;--c3:#BCD5FA;--c4:#CCDFFB;--cb:#4E8DE6}
.csg-h b{border-left:0}
.csrl{display:flex;flex-direction:column;gap:9px;margin-top:12px}
.csr{display:flex;align-items:center;gap:11px;width:100%;padding:11px 12px;border-radius:14px;background:#fff;box-shadow:0 3px 10px -4px rgba(120,90,130,.14);text-align:left}
.csr:active{transform:scale(.98)}
.csr-i{flex:none;display:grid;place-items:center;width:40px;height:40px;border-radius:11px;background:var(--cb)}
.csr-i svg{width:20px;height:20px}
.csr-m{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}
.csr-m b{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;font-size:14px;font-weight:800;line-height:1.4;color:#2B2433}
.csr-m small{font-size:11px;color:#8D8091}
.csr-m small i{margin-left:8px;font-style:normal;font-weight:800;color:#F0704F}
.csr em{flex:none;height:26px;padding:0 12px;border-radius:99px;background:var(--cb);color:#fff;font-size:12px;font-style:normal;font-weight:800;line-height:26px}
.csg-h small{padding-left:13px;font-size:13px;color:#8F8494}
.ckg{display:grid;gap:12px 10px;margin-top:12px}
.ckg.c3{grid-template-columns:repeat(3,1fr)}
.ckg.c2{grid-template-columns:repeat(2,1fr)}
.ck{display:flex;flex-direction:column;min-width:0;border-radius:16px;background:#fff;box-shadow:0 4px 14px -4px rgba(120,90,130,.16);overflow:hidden;text-align:center}
.ck:active{transform:scale(.97)}
.ck .cv{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:5px;height:128px;padding:0 6px;background:linear-gradient(160deg,var(--c1),var(--c2));overflow:hidden}
.c2 .ck .cv{height:150px;gap:7px}
.ck .cbl{position:absolute;inset:0;width:100%;height:100%}
.ck .cbl .b1{fill:var(--c3);opacity:.75}.ck .cbl .b2{fill:var(--c4);opacity:.6}.ck .cbl .b3{fill:#fff;opacity:.35}
.ck .cv b,.ck .cv small,.ck .cv em{position:relative}
.ck .cv b{font-size:16.5px;font-weight:900;line-height:1.2;color:#2B2433;letter-spacing:.5px}
.c2 .ck .cv b{font-size:20px;padding:0 8px}
.ck .cv b{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;padding:0 2px;font-size:13.5px;line-height:1.35;letter-spacing:0}
.c2 .ck .cv b{font-size:15.5px;padding:0 6px}
.ck .cv{height:146px}
.c2 .ck .cv{height:160px}
#more .ck .cv{padding-top:14px;height:160px}#more .c2 .ck .cv{height:172px}
#more .ck .cv b{font-size:15.5px;line-height:1.32}
#more .c2 .ck .cv{height:206px}
/* 11-04 二改(用户:「下面的呈现太大了,跟首页孕期百宝箱下面往外滚的一样:一个头像、一个人名和一小行字」)→ 两行白条改成一行 20px 小滚动条 */
#more .c2 .ck .cv:has(.ck-hl){padding-bottom:22px}
.ck .cv .ck-hl{position:absolute;left:7px;right:7px;bottom:7px;height:22px;padding:0 8px 0 3px;border-radius:99px;background:rgba(255,255,255,.78);overflow:hidden;text-align:left}
.ck-hl .hl-i{left:3px!important;right:8px!important;top:1px!important}
.ck-hl .hl-i{position:absolute;left:0;right:0;top:0;display:flex;align-items:center;gap:4px;height:20px;font-size:11px;color:var(--cb);white-space:nowrap;opacity:0;transform:translateY(100%);transition:transform .45s ease,opacity .45s ease}
.ck-hl .hl-i.on{opacity:1;transform:none}.ck-hl .hl-i.up{opacity:0;transform:translateY(-100%)}
.ck-hl .hl-i img{flex:none;width:16px;height:16px;border-radius:50%;object-fit:cover;background:#fff}
.ck-hl .hl-i u{flex:none;text-decoration:none;font-weight:800;color:#4A3E50}
.ck-hl .hl-i span{min-width:0;overflow:hidden;text-overflow:ellipsis}
@media (prefers-reduced-motion:reduce){.ck-hl .hl-i{transition:none}}
#more .c2 .ck .cv b{font-size:17px;padding:0 4px}
.ck .cnn{margin-top:8px}
.ck .cv small{font-size:10.5px;color:#8D8091;white-space:nowrap}
.ck .cv em{margin-top:2px;height:22px;padding:0 10px;border-radius:6px;background:var(--cb);color:#fff;font-size:11px;font-style:normal;font-weight:800;line-height:22px;box-shadow:0 3px 8px -3px var(--cb)}
.c2 .ck .cv em{height:25px;line-height:25px;padding:0 13px;font-size:12px}
.ck .cv .dn{position:absolute;right:6px;top:6px;height:17px;padding:0 6px;border-radius:99px;background:rgba(255,255,255,.88);color:var(--cb);font-size:10px;font-style:normal;font-weight:800;line-height:17px}
.ck .ct{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;margin:8px 8px 0;min-height:2.8em;font-size:12.5px;font-weight:700;line-height:1.4;color:#3A3040}
.c2 .ck .ct{font-size:13.5px}
.ck .cnn{display:inline-flex;align-items:center;justify-content:center;gap:2px;margin:4px 0 9px;font-size:11px;font-weight:800;color:#F0704F}
/* 11-04 用户:「背景太单一、行图标都一样、加头像、整体 UI 太单一」→ 每组一块分组色底板(带淡图案 + 大号分组水印),行图标按测试各不相同、底色三档深浅,卡片 / 行 / 组标题都挂头像堆 */
.csg{position:relative;margin:22px -4px 0;padding:16px 10px 14px;border-radius:22px;background:var(--gb);overflow:hidden}
.csg::before{content:"";position:absolute;inset:0;background-image:radial-gradient(var(--gd) 1.2px,transparent 1.4px);background-size:16px 16px;opacity:.55;pointer-events:none}
.csg>*{position:relative}
.csg.g-quiz{--gb:linear-gradient(170deg,#FFEDE2,#FFF6F0 40%,#FFF1E8);--gd:#FFD2BC}
.csg.g-psy{--gb:linear-gradient(170deg,#EFE8FF,#F8F5FF 40%,#F1EBFF);--gd:#DCCFF7}
.csg.g-game{--gb:linear-gradient(170deg,#E2F6EA,#F3FBF6 40%,#E6F7EE);--gd:#BFE7D0}
.csg.g-shop{--gb:linear-gradient(170deg,#E3EEFF,#F4F8FF 40%,#E8F1FF);--gd:#C7DBFA}
.csg>.csg-deco{position:absolute;right:-14px;top:-18px;width:96px;height:96px;border-radius:30px;background:var(--gi);opacity:.13;transform:rotate(14deg);display:grid;place-items:center}
.csg>.csg-deco svg{width:64px;height:64px}
.csg-h b{flex-wrap:wrap}
.csg-n{display:inline-flex;align-items:center;gap:4px;margin-left:auto;height:24px;padding:0 9px 0 4px;border-radius:99px;background:rgba(255,255,255,.75);font-size:11px;font-weight:800;color:var(--gi)}
.csg-n .cav img{width:18px;height:18px}
.cav{display:inline-flex;align-items:center;vertical-align:middle}
.cav img{width:16px;height:16px;border-radius:50%;object-fit:cover;border:1.5px solid #fff;background:#FFE3D3;margin-left:-5px}
.cav img:first-child{margin-left:0}
.ck .cnn .cav{margin-right:5px}
.csr-m small .cav{margin-left:8px}.csr-m small .cav+i{margin-left:4px}
.csr-i.s1{background:linear-gradient(135deg,var(--cb),var(--c4))}
.csr-i.s2{background:var(--c1);box-shadow:inset 0 0 0 1.5px var(--c3)}
.csr-i.s2 svg{fill:var(--cb)}.csr-i.s2 svg [fill="#fff"]{fill:var(--cb)}.csr-i.s2 svg [stroke="#fff"]{stroke:var(--cb)}
.csr-i svg{width:22px;height:22px}
.csr-i{border-radius:13px;transform:rotate(-4deg)}
.csr:nth-child(even) .csr-i{transform:rotate(4deg)}
.ck.has-bg .cv>.cbl,.ck.has-bg .cv>.ck-wm{display:none}
.ck .cv .ck-wash{position:absolute;inset:0;pointer-events:none}
.ck.gq .ck-wash{background:linear-gradient(180deg,rgba(255,244,234,.86),rgba(255,236,222,.74) 62%,rgba(255,228,211,.35))}
.ck.gp .ck-wash{background:linear-gradient(180deg,rgba(246,241,255,.86),rgba(238,230,252,.74) 62%,rgba(234,226,251,.35))}
.ck.gg .ck-wash{background:linear-gradient(180deg,rgba(240,250,244,.86),rgba(228,246,236,.74) 62%,rgba(221,243,231,.35))}
.ck.gs .ck-wash{background:linear-gradient(180deg,rgba(240,246,255,.86),rgba(230,240,254,.74) 62%,rgba(223,235,253,.35))}
.ck .cv .ck-bg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:50% 50%}
.csr-i.has-bg{background-size:cover!important;background-position:70% 85%!important;box-shadow:inset 0 0 0 1.5px rgba(255,255,255,.7)}
/* 11-04 二改(用户:照片压在字后面抢字)→ 图文分开:照片只占卡片上方一条、往下渐隐成本组纯色,标题/题数/按钮全在纯色区,不再叠在照片上 */
.ck.has-bg .cv{justify-content:flex-start;background:linear-gradient(180deg,var(--c1),var(--c2))}
.ck.has-bg .cv .ck-wash{display:none}
.ck.has-bg .cv .ck-bg{inset:0 0 auto 0;height:var(--ph,62px);-webkit-mask-image:linear-gradient(180deg,#000 55%,transparent);mask-image:linear-gradient(180deg,#000 55%,transparent)}
.ck.has-bg .cv>b{margin-top:calc(var(--ph,62px) - 8px)}
#more .ck.has-bg .cv{--ph:64px;height:auto;min-height:168px;padding:0 6px 12px}
#more .c2 .ck.has-bg .cv{--ph:84px;min-height:212px}
#more .c2 .ck.has-bg .cv:has(.ck-hl){padding-bottom:36px}
.ck.has-bg .cv .ck-top,.ck.has-bg .cv .dn{z-index:2}
/* 11-04 三改(用户:风景照还是太抢镜,视觉都被抢走、标题不突出)→ 照片退成淡淡的氛围:降饱和 + 半透明 + 高度缩小、更早渐隐;标题加大加粗加深,题数 / 按钮弱一点 */
.ck.has-bg .cv .ck-bg{opacity:.5;filter:saturate(.55) brightness(1.06);-webkit-mask-image:linear-gradient(180deg,#000 30%,transparent);mask-image:linear-gradient(180deg,#000 30%,transparent)}
#more .ck.has-bg .cv{--ph:48px;min-height:150px}
#more .c2 .ck.has-bg .cv{--ph:60px;min-height:190px}
#more .ck.has-bg .cv>b{margin-top:calc(var(--ph) - 12px);font-weight:900;color:#1F1717}
#more .ck .cv b{font-size:16px;line-height:1.36}
#more .c2 .ck .cv b{font-size:18px}
.ck.has-bg .cv small{color:#A89A96}
.ck.has-bg .cv em{box-shadow:none;opacity:.92}
.csr-i.has-bg{filter:saturate(.6) brightness(1.05)}
.ck .cv .ck-wm{position:absolute;right:-8px;bottom:-6px;width:62px;height:62px;opacity:.22;transform:rotate(-12deg);pointer-events:none}
.ck .cv .ck-wm svg{width:100%;height:100%}
.ck .cv .ck-wm svg,.ck .cv .ck-wm svg [fill="#fff"]{fill:var(--cb)}.ck .cv .ck-wm svg [stroke="#fff"]{stroke:var(--cb)}
.csv-n{flex-wrap:nowrap}
.csv-av{margin-left:auto}
.csv-av .cav img{width:22px;height:22px;margin-left:-7px;transition:transform .22s,opacity .22s}
.csv-av .cav img:first-child{margin-left:0}
.csv-av .cav img.sw{transform:scale(.3);opacity:0}
.csv-r{height:90px !important}
.csv-i{opacity:0;transform:translateY(90px);transition:transform .5s cubic-bezier(.3,1.2,.5,1),opacity .45s ease !important;height:30px}
.csv-i img{width:22px !important;height:22px !important}
.csv-i:nth-child(odd) b{color:#F0704F}
/* 摇一摇全屏浮层 */
.lko{position:fixed;inset:0;z-index:9999;display:grid;place-items:center;pointer-events:auto}
.lko-bg{position:absolute;inset:0;background:radial-gradient(circle at 50% 42%,rgba(141,107,255,.55),rgba(40,20,80,.78));opacity:0;transition:opacity .25s;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}
.lko.on .lko-bg{opacity:1}
.lko-in{position:relative;display:flex;flex-direction:column;align-items:center;gap:14px;width:300px;transform:scale(.6);opacity:0;transition:transform .35s cubic-bezier(.3,1.5,.5,1),opacity .25s}
.lko.on .lko-in{transform:none;opacity:1}
.lko-dc{position:relative;width:170px;height:110px}
.lko-dc span{position:absolute;width:84px;height:84px;filter:drop-shadow(0 10px 14px rgba(20,0,60,.45));animation:lkoT .42s linear infinite}
.lko-dc span svg{width:100%;height:100%;display:block}
.lko-dc .a{left:6px;top:14px}.lko-dc .b{right:6px;top:0;width:66px;height:66px;animation-duration:.34s;animation-direction:reverse}
@keyframes lkoT{0%{transform:rotate(0) translateY(0)}25%{transform:rotate(90deg) translateY(-16px)}50%{transform:rotate(180deg)}75%{transform:rotate(270deg) translateY(-10px)}100%{transform:rotate(360deg)}}
.lko.hit .lko-dc span{animation:lkoLand .5s cubic-bezier(.3,1.7,.5,1)}
@keyframes lkoLand{from{transform:scale(1.35) rotate(-25deg)}to{transform:none}}
.lko-tip{margin:0;color:#fff;font-size:15px;font-weight:800;letter-spacing:2px;opacity:.9}
.lko.hit .lko-tip{font-size:24px;letter-spacing:3px;color:#FFE27A;opacity:1;animation:lkoLand .5s cubic-bezier(.3,1.7,.5,1)}
.lko-reel{width:100%;height:58px;border-radius:18px;background:rgba(255,255,255,.16);box-shadow:inset 0 0 0 2px rgba(255,255,255,.35);overflow:hidden;display:grid;place-items:center}
.lko-reel span{display:block;color:#fff;font-size:24px;font-weight:900;letter-spacing:1px;white-space:nowrap}
.lko-reel span.sp{animation:lkoSp .1s linear}
@keyframes lkoSp{from{transform:translateY(-90%);opacity:.2;filter:blur(2px)}}
.lko.hit .lko-reel{display:none}
.lko-card{width:100%}
.lko-card .ck{transform:scale(.5) rotate(-8deg);opacity:0;animation:lkoCard .55s .05s cubic-bezier(.3,1.5,.5,1) forwards;box-shadow:0 18px 40px -10px rgba(20,0,60,.6)}
@keyframes lkoCard{to{transform:none;opacity:1}}
.lko-card .ck .cv{height:auto;padding:26px 16px 20px;gap:8px}
.lko-card .ck .cv b{font-size:20px;-webkit-line-clamp:3}
.lko-card .ck .cv small{font-size:12.5px}
.lko-card .ck .cv em{height:32px;line-height:32px;padding:0 20px;font-size:14px}
.lko-card .lko-ic{display:grid;place-items:center;width:52px;height:52px;border-radius:16px;background:var(--cb);box-shadow:0 6px 14px -6px var(--cb);position:relative}
.lko-card .lko-ic svg{width:30px;height:30px}
.lko-fx{position:absolute;left:50%;top:50%;pointer-events:none}
.lko-act{display:flex;flex-direction:column;align-items:stretch;gap:10px;width:100%;opacity:0;transform:translateY(10px);pointer-events:none;transition:opacity .25s,transform .3s cubic-bezier(.3,1.4,.5,1)}
.lko.done .lko-act{opacity:1;transform:none;pointer-events:auto}
.lko:not(.hit) .lko-act{display:none}
.lko-go{height:50px;border-radius:99px;background:linear-gradient(120deg,#FFD25A,#FF9A4D);color:#5A2A00;font-size:17px;font-weight:900;letter-spacing:1px;box-shadow:0 10px 22px -10px rgba(255,150,60,.9);animation:lkPulse 1.8s ease-in-out infinite}
.lko-re{display:flex;align-items:center;justify-content:center;gap:6px;height:44px;border-radius:99px;background:rgba(255,255,255,.16);box-shadow:inset 0 0 0 1.5px rgba(255,255,255,.55);color:#fff;font-size:15px;font-weight:800}
.lko-re svg{width:22px;height:22px}
.lko-x,.lko-snd{position:absolute;top:calc(14px + env(safe-area-inset-top));z-index:2;width:36px;height:36px;border-radius:50%;background:rgba(255,255,255,.16);color:#fff;font-size:24px;line-height:36px;text-align:center}
.lko-x{right:14px}.lko-snd{left:14px}
.lko-snd::before{content:"";position:absolute;inset:0;background:center/20px no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 9.5h3.5L12 5.5v13l-4.5-4H4z' fill='white'/%3E%3Cpath d='M15.5 9a4.2 4.2 0 010 6M18 6.5a7.8 7.8 0 010 11'/%3E%3C/svg%3E")}
.lko-snd.off::before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 9.5h3.5L12 5.5v13l-4.5-4H4z' fill='white'/%3E%3Cpath d='M16 9.5l5 5M21 9.5l-5 5'/%3E%3C/svg%3E")}
.lko-fx i{position:absolute;width:9px;height:12px;border-radius:2px;animation:lkoBoom 1.3s cubic-bezier(.2,.7,.4,1) forwards}
@keyframes lkoBoom{from{transform:translate(0,0) rotate(0) scale(1);opacity:1}to{transform:translate(var(--x),calc(var(--y) + 180px)) rotate(var(--r)) scale(.6);opacity:0}}
@media (prefers-reduced-motion:reduce){.lko-dc span{animation:none}}
.ck .cnn svg{width:11px;height:11px}
.csr.pa,.ck.pa{--c1:#FFF4EA;--c2:#FFE4D6;--c3:#FFC9AE;--c4:#FFB08F;--cb:#FF8A65}
.csr.pb,.ck.pb{--c1:#F4F0FA;--c2:#E9E4F4;--c3:#B9AEDB;--c4:#E8D9EE;--cb:#8D84BE}
.csr.pc,.ck.pc{--c1:#FFF9EC;--c2:#F0F2F6;--c3:#C9DCF0;--c4:#DDE6D2;--cb:#7F8EC9}
.csr.pd,.ck.pd{--c1:#F6EEFA;--c2:#FBEFE6;--c3:#D9C6EE;--c4:#FBD9BF;--cb:#9A86C4}
.csr.pe,.ck.pe{--c1:#F1FAEF;--c2:#EEF6F5;--c3:#CDE9D5;--c4:#BFDDEB;--cb:#7C8FCB}
.csr.pf,.ck.pf{--c1:#FFF1E6;--c2:#FDE6DD;--c3:#FFC5A6;--c4:#F8D7C4;--cb:#E58A64}
.csd{display:flex;align-items:center;gap:10px;margin:20px 0 -4px;color:#A69CA8;font-size:12.5px}
.csd::before,.csd::after{content:"";flex:1;height:1px;background:#E6DEE6}
.k-ceshi{--kf:#7C5CFC;--kt:#6346B0;--kl:#F1EDFF;--kl2:#E4DDFD}
.g-quiz{--tg:#F0714F;--tl:#FFEFE9}.g-psy{--tg:#7C5CFC;--tl:#F1EDFF}.g-game{--tg:#13A08A;--tl:#E4F6F1}.g-shop{--tg:#E9557F;--tl:#FFEEF3}
.nc.tst .cvw{background:var(--tl)}
.nc.tst .cvw img{display:block;width:100%;height:calc(var(--cw) * 1.08);object-fit:cover;object-position:center 30%}
.nc.tst .tb{position:absolute;left:7px;top:7px;display:inline-flex;align-items:center;gap:3px;height:21px;padding:0 8px 0 6px;border-radius:7px;background:var(--tg);color:#fff;font-size:11px;font-weight:800;letter-spacing:.5px;box-shadow:0 3px 8px -3px var(--tg)}
.nc.tst .tb .ic{width:12px;height:12px;stroke-width:2.2}
.nc.tst .tq{position:absolute;left:0;right:0;bottom:0;padding:22px 9px 7px;background:linear-gradient(transparent,rgba(30,20,40,.42));color:#fff;font-size:11.5px;font-weight:700;text-shadow:0 1px 2px rgba(0,0,0,.25)}
.nc.tst .nf{justify-content:space-between}
.nc.tst .gs{font-size:11px;font-weight:700;color:var(--tg)}
.nc.tst .gs.dn{max-width:96px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.nc.tst .gt{flex:none;height:22px;padding:0 9px;border-radius:99px;background:var(--tl);color:var(--tg);font-size:11.5px;font-weight:800;line-height:22px}
.csh{display:flex;align-items:center;gap:6px;margin:2px 12px 0;padding:11px 14px;border-radius:16px;background:linear-gradient(120deg,#F1EDFF,#FFEFF4 70%,#FFF3EA)}
.csh .ic{width:16px;height:16px;color:#8E6BFF;stroke-width:2.2}
.csh b{font-size:15px;font-weight:900;color:#2A1E1E}
.csh span{margin-left:auto;font-size:12px;font-weight:700;color:#C0507A}
.htl{margin:0 12px;padding:4px 12px 2px;border-radius:18px;background:#fff;box-shadow:0 6px 18px -12px rgba(120,60,40,.25)}
.htl .hr{display:flex;align-items:center;gap:10px;padding:11px 0;border-bottom:1px dashed #F0E2DC;--hk:var(--kf)}
.htl .hr:last-of-type{border-bottom:0}
.htl .no{flex:none;width:20px;text-align:center;font-style:italic;font-size:16px;font-weight:900;color:#C9B3AC}
.htl .no.t0{color:#F2465A}.htl .no.t1{color:#FF6A3D}.htl .no.t2{color:#FF9A2E}
.htl .hm{flex:1;min-width:0}
.htl .hm b{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;font-size:14.5px;font-weight:900;line-height:1.4;color:#2A1E1E}
.htl .hm em{font-style:normal;color:var(--hk);margin:0 1px}
.htl .hm small{display:block;margin-top:2px;font-size:11.5px;color:#A8918B;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.htl .hm u{text-decoration:none;color:var(--hk);font-weight:700;margin-right:6px}
.htl .rk{flex:none;height:17px;padding:0 5px;border-radius:5px;background:#FF5A3C;color:#fff;font-size:10.5px;font-weight:800;line-height:17px}
.htl .jn{flex:none;height:26px;padding:0 11px;border-radius:99px;border:1px solid var(--hk);color:var(--hk);background:#fff;font-size:12px;font-weight:800}
.htl .hall{display:block;width:100%;padding:10px 0 9px;border-top:1px solid #F5EAE6;font-size:12.5px;font-weight:700;color:#9A817C}
.hc{flex:none;width:168px;scroll-snap-align:start;display:flex;flex-direction:column;padding:12px 12px 11px;border-radius:18px;text-align:left;background:var(--hb);position:relative;overflow:hidden}
.hc{--hb:linear-gradient(160deg,var(--kl),var(--kl2));--hk:var(--kf);--ht:var(--kt)}
.hc .wm{position:absolute;right:-4px;bottom:-14px;font-size:72px;font-weight:900;line-height:1;color:#fff;opacity:.7;font-family:"STKaiti","KaiTi","Kaiti SC",serif;pointer-events:none}
.hc .kb{align-self:flex-start;position:relative}
.hc .rk{position:absolute;right:10px;top:10px;height:18px;padding:0 6px;border-radius:6px;background:#FF5A3C;color:#fff;font-size:10.5px;font-weight:800;line-height:18px}
.hc h3{position:relative;margin:8px 0 0;font-size:15px;font-weight:900;line-height:1.35;color:#2A1E1E}
.hc p{position:relative;margin:4px 0 0;font-size:11.5px;line-height:1.5;color:#7A6663;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;min-height:34px}
.hc .jn{position:relative;align-self:flex-start;margin-top:10px;height:28px;padding:0 12px;border-radius:99px;background:var(--hk);color:#fff;font-size:12.5px;font-weight:800;display:inline-flex;align-items:center;gap:3px}
.hc .jn .ic{width:13px;height:13px}
/* 分类小徽标:家庭 / 经验(封面、热门卡、话题头、详情共用) */
.kb{display:inline-flex;align-items:center;gap:3px;height:20px;padding:0 7px 0 5px;border-radius:7px;font-size:11px;font-weight:800;letter-spacing:.5px;color:#fff;white-space:nowrap}
.kb .ic{width:12px;height:12px}
.kb{background:var(--kf)}
/* ---------- 话题头卡(选了具体话题时) ---------- */
.th{position:relative;margin:2px 12px 0;padding:14px 16px 14px;border-radius:20px;overflow:hidden;background:var(--hb);box-shadow:0 10px 24px -18px var(--hk)}
.th{--hb:linear-gradient(150deg,var(--kl),var(--kl2));--hk:var(--kf);--ht:var(--kt)}
.th .wm{position:absolute;right:-4px;top:-8px;font-size:104px;font-weight:900;line-height:1;color:#fff;opacity:.6;font-family:"STKaiti","KaiTi","Kaiti SC",serif;pointer-events:none}
.th .x{position:absolute;right:8px;top:8px;width:30px;height:30px;display:grid;place-items:center;border-radius:50%;background:rgba(255,255,255,.7);color:#7A6663}
.th .x .ic{width:14px;height:14px}
.th h2{position:relative;margin:8px 0 4px;font-size:21px;font-weight:900;line-height:1.3;color:#2A1E1E;letter-spacing:.3px}
.th h2 em{font-style:normal;color:var(--ht);margin-right:2px}
.th p{position:relative;margin:0;max-width:280px;font-size:12.5px;line-height:1.6;color:#5E4E4A}
.th .tf{position:relative;display:flex;gap:8px;margin-top:12px}
.th .join{height:34px;padding:0 16px;border-radius:99px;background:var(--hk);color:#fff;font-size:13.5px;font-weight:800;display:inline-flex;align-items:center;gap:4px;box-shadow:0 6px 12px -6px var(--hk)}
.th .join .ic{width:14px;height:14px}
.th .sw{height:34px;padding:0 14px;border-radius:99px;background:rgba(255,255,255,.8);color:var(--ht);font-size:13px;font-weight:800}
/* ---------- 层级:分类 · 话题胶囊(11-02) ---------- */
.lvw{margin:16px 0 0}
.lvw .lv{display:flex;align-items:baseline;gap:8px;padding:0 14px}
.lvw .lv h2{margin:0;font-size:17px;font-weight:900;letter-spacing:.3px;color:var(--kt)}
.lvw .lv small{font-size:12px;font-weight:600;color:var(--muted);white-space:nowrap}
.lvw .lv .ba{margin-left:auto;font-size:12.5px;font-weight:800;color:var(--kt)}
.tcs{display:flex;gap:7px;padding:9px 12px 2px;overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain;scrollbar-width:none}
.tcs::-webkit-scrollbar{display:none}
.tcs::after{content:"";flex:none;width:4px}
.tcs button{flex:none;height:30px;padding:0 11px;border-radius:99px;background:#fff;border:1px solid #EFE1DB;font-size:12.5px;font-weight:700;color:#5E4E4A;white-space:nowrap;display:inline-flex;align-items:center;gap:5px}
.tcs button i{font-style:normal;font-size:11px;font-weight:800;color:#B59A93;font-variant-numeric:tabular-nums}
.tcs button.on{background:var(--kf);border-color:var(--kf);color:#fff;box-shadow:0 5px 12px -6px var(--kf)}
.tcs button.on i{color:rgba(255,255,255,.85)}
.th .bc{position:relative;display:flex;align-items:center;gap:6px}
.th .bc button{display:inline-flex}
.th .bc span:last-child{font-size:12px;font-weight:700;color:var(--ht)}
.th .bc .kb{height:auto;padding:0;border-radius:0;background:none;box-shadow:none;color:var(--ht);font-size:12.5px;letter-spacing:.3px} /* 11-03 用户:话题卡左上角分类不要底色块 */
.mo{display:block;width:calc(100% - 24px);margin:14px 12px 0;padding:13px 14px;border-radius:16px;text-align:center;background:linear-gradient(150deg,var(--kl),var(--kl2))}
.mo small{display:block;font-size:11.5px;font-weight:600;color:#9A817C}
.mo b{display:block;margin-top:3px;font-size:14.5px;font-weight:900;color:var(--kt)}
/* ---------- 瀑布流 ---------- */
.wf{display:flex;align-items:flex-start;gap:8px;padding:10px 12px 0}
.wf .col{flex:1;min-width:0;display:flex;flex-direction:column;gap:8px}
.nc{display:block;width:100%;text-align:left;border-radius:14px;overflow:hidden;background:#fff;box-shadow:0 3px 12px rgba(170,110,90,.08);animation:ncIn .35s ease both}
.nc:active{transform:scale(.985)}
/* 我的投稿入口卡(11-02 从右上角挪到「全部」瀑布流第一位,点进 mine/ 独立页) */
.nc.fvc{display:flex;align-items:center;gap:8px;padding:11px 12px;border-radius:14px;background:#fff;color:var(--ink);font-size:13.5px;font-weight:900;text-align:left;box-shadow:0 4px 14px rgba(170,110,90,.08)}
.fvc .fi{width:30px;height:30px;flex:none;border-radius:10px;display:grid;place-items:center;background:#FFF4D6;color:#F2A20C}
.fvc .fi .ic{width:17px;height:17px;fill:currentColor;stroke:none}
.fvc span{flex:1;min-width:0}.fvc small{display:block;font-size:11px;font-weight:600;color:var(--muted)}
.fvc>.ic{width:14px;height:14px;color:#C9B6B0}
/* 我的收藏(11-02 用户:收藏了要有地方找 → 首页「我的」页入口 → ?fav=1 打开这一层;广场「全部」里我的投稿卡下面也有入口) */
#fvp{position:fixed;inset:0;z-index:35;background:var(--bg);transform:translateX(100%);transition:transform .32s cubic-bezier(.2,.8,.2,1);display:flex;flex-direction:column}
#fvp.show{transform:none}
#fvp .nav{flex:none;padding-top:env(safe-area-inset-top);height:calc(46px + env(safe-area-inset-top))}
#fvs{flex:1;overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:none;padding-bottom:calc(30px + env(safe-area-inset-bottom))}
#fvs .fvh{margin:4px 14px 0;font-size:12.5px;color:var(--muted)}
#fvs .fve{margin:40px 24px;text-align:center;color:var(--muted);font-size:13px;line-height:1.7}
#fvs .fve b{display:block;margin-bottom:4px;font-size:16px;color:var(--ink)}
.nc.myc{position:relative;padding:14px 12px 12px;color:#fff;background:linear-gradient(150deg,#FF8A65,#F0607E 70%,#D8609E);box-shadow:0 10px 20px -14px #E8506E}
.nc.myc::after{content:"";position:absolute;right:-26px;top:-30px;width:96px;height:96px;border-radius:50%;background:rgba(255,255,255,.15)}
.myc .mi{position:relative;width:38px;height:38px;border-radius:12px;display:grid;place-items:center;background:rgba(255,255,255,.22)}
.myc .mi .ic{width:20px;height:20px}
.myc b{position:relative;display:block;margin-top:10px;font-size:16px;font-weight:900}
.myc p{position:relative;margin:2px 0 0;font-size:11.5px;line-height:1.5;opacity:.92}
.myc p em{font-style:normal;font-weight:900;color:#FFF1B8}
.myc .ms{position:relative;display:flex;gap:4px;flex-wrap:wrap;margin-top:9px}
.myc .ms span{height:20px;padding:0 7px;border-radius:6px;background:rgba(255,255,255,.95);color:#C0504E;font-size:11px;font-weight:800;line-height:20px}
.myc .go{position:relative;display:flex;align-items:center;justify-content:space-between;margin-top:10px;padding-top:9px;border-top:1px dashed rgba(255,255,255,.4);font-size:12px;font-weight:800}
.myc .go .ic{width:14px;height:14px}
.myc .dot{position:absolute;right:10px;top:10px;z-index:1;height:18px;padding:0 6px;border-radius:99px;background:#fff;color:#E8473A;font-size:10.5px;font-style:normal;font-weight:900;line-height:18px}
@keyframes ncIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
.nc .cvw{position:relative}
.nc .nb{padding:8px 9px 9px}
.nc h3{margin:0;font-size:13.5px;font-weight:700;line-height:1.45;color:#2A2220;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.nc .nf{display:flex;align-items:center;gap:5px;margin-top:7px}
.nc .nf img{width:18px;height:18px;border-radius:50%;object-fit:cover;flex:none;background:#FFE3D3}
.nc .nf .nm{flex:0 1 auto;min-width:0;font-size:11px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.nc .nf{gap:4px}
.nc .nf .stg{flex:none;font-style:normal;font-size:10px;line-height:16px;padding:0 4px;border-radius:99px;background:#F5EFEC;color:#A08C86;white-space:nowrap}
.nc .nf .lk{margin-left:auto;min-width:0;gap:1px}
.nc .nf .lk .ic{width:13px;height:13px}
.lk{flex:none;display:inline-flex;align-items:center;gap:2px;min-width:44px;justify-content:flex-end;height:22px;font-size:11.5px;color:var(--muted);font-variant-numeric:tabular-nums}
.lk .ic{width:15px;height:15px}
.lk.on{color:#F0453A}
.lk.pop .ic{animation:pop .35s ease}
@keyframes pop{40%{transform:scale(1.35)}}
.nc .tp{display:block;margin-top:4px;font-size:11.5px;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.nc .tp{color:var(--kt)}
.end{padding:22px 0 calc(116px + var(--safe-b));text-align:center}
.end b{display:block;font-size:12px;font-weight:600;color:#C2ABA4;letter-spacing:2px}
.end small{display:block;margin-top:8px;font-size:10.5px;color:#CDBBB5;opacity:.85}
.mb-brand{text-align:center;color:#C29A8F;font-size:11.5px;line-height:1.7}.mb-brand img{display:block;width:86px;height:auto;margin:0 auto 6px;opacity:.6}.mb-brand p{display:flex;align-items:center;justify-content:center;gap:8px;margin:0;letter-spacing:.06em}.mb-brand p::before,.mb-brand p::after{content:'';width:28px;height:1px;background:#EAD3CC}
.end{padding-top:28px}
/* ---------- 封面(em 计:卡片 1em≈13px,详情放大)
11-01 第三版:用户说列表「太乱」→ 原来 6 种花样(方格纸/横线本/波点胶带/深色引号…)全部去掉,只留一种版式;
颜色只按分类走:家庭 = 粉、经验 = 青绿,各 3 个深浅轮换。左上角实底「家庭 / 经验」徽标,一眼分清。 ---------- */
.cv{position:relative;width:100%;overflow:hidden;font-size:13px;isolation:isolate;display:flex;flex-direction:column;padding:.95em 1.05em 1.1em;background:linear-gradient(160deg,var(--c1),var(--c2))}
.cv .kb{align-self:flex-start;font-size:.85em;height:1.55em;padding:0 .55em 0 .4em;border-radius:.5em;gap:.2em}
.cv .kb .ic{width:1em;height:1em}
.cv .ct{flex:1;display:flex;flex-direction:column;justify-content:center;position:relative;z-index:1}
.cv .t1{font-size:1.65em;font-weight:900;line-height:1.25;letter-spacing:.04em;color:#2A1E1E;word-break:break-all}
.cv .t2{margin-top:.5em;font-size:.92em;font-weight:700;line-height:1.4;color:var(--tk)}
/* 照片封面(11-01 用户:广场图片要有一些像真实上传的照片,不要全是文字封面):约三分之一笔记用照片,满铺裁切,左上角仍挂分类徽标 */
.cv.ph{padding:0;background:#EFE6E1}
.cv.ph img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
.cv.ph .kb{position:absolute;left:.95em;top:.95em;z-index:1;box-shadow:0 2px 6px rgba(0,0,0,.12)}
.cv .wm{position:absolute;right:-.1em;bottom:-.25em;font-size:5.6em;font-weight:900;line-height:1;color:#fff;opacity:.55;font-family:"STKaiti","KaiTi","Kaiti SC",serif;pointer-events:none;z-index:0}
/* 图上压字(11-02 用户:文字放到图片上穿插来,小红书式):ov 底部渐变大字 / tg 贴纸字 */
.nc .ovt{position:absolute;left:0;right:0;bottom:0;padding:56px 11px 11px;background:linear-gradient(transparent,rgba(30,18,14,.35) 30%,rgba(30,18,14,.72));color:#fff;pointer-events:none}
.nc .ovt b{display:-webkit-box;-webkit-line-clamp:4;-webkit-box-orient:vertical;overflow:hidden;font-size:17px;font-weight:900;line-height:1.38;letter-spacing:.3px;text-shadow:0 1px 4px rgba(0,0,0,.3)}
.nc .ovt small{display:inline-block;margin-bottom:5px;padding:0 6px;border-radius:5px;background:rgba(255,255,255,.22);font-size:10.5px;font-weight:700;line-height:18px}
.nc .tgt{position:absolute;left:9px;right:9px;bottom:12px;pointer-events:none}
.nc .tgt b{display:-webkit-box;-webkit-line-clamp:4;-webkit-box-orient:vertical;overflow:hidden;font-size:15.5px;font-weight:900;line-height:1.62;color:#2A1E1E}
.nc .tgt span{background:#FFF2A6;padding:1px 5px;-webkit-box-decoration-break:clone;box-decoration-break:clone;border-radius:3px}
.nc:nth-child(odd) .tgt span{background:#fff}
.nc .ovt~*,.nc .tgt~*{display:none}
.nc .ovt.at-top{bottom:auto;top:0;padding:11px 11px 56px;background:linear-gradient(rgba(30,18,14,.72),rgba(30,18,14,.35) 70%,transparent)}
.nc .ovt.at-mid{bottom:auto;top:50%;transform:translateY(-50%);padding:16px 11px;background:rgba(30,18,14,.42)}
.nc .tgt.at-top{bottom:auto;top:12px}
.nc .tgt.at-mid{bottom:auto;top:50%;transform:translateY(-50%)}
.cm-ld{padding:22px 0;text-align:center;font-size:12.5px;color:#B8A39D}
.nc.s-ov .nb .tp,.nc.s-tg .nb .tp{display:none} /* 11-02 用户:图上带字的卡,下方放一行标题、不放话题 */
.nc.s-ov .nb h3,.nc.s-tg .nb h3{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;-webkit-line-clamp:unset}
/* ---------- 详情层 ---------- */
#dt{position:fixed;inset:0;z-index:40;background:#fff;transform:translateX(100%);transition:transform .32s cubic-bezier(.2,.8,.2,1);display:flex;flex-direction:column}
#dt.show{transform:none}
#dt .dnav{flex:none;display:flex;align-items:center;gap:8px;height:calc(50px + env(safe-area-inset-top));padding:env(safe-area-inset-top) 12px 0 6px;background:#fff;border-bottom:1px solid transparent;transition:border-color .2s}
#dt .dnav.on{border-color:var(--line)}
#dt .dnav .bk{width:36px;height:36px;display:grid;place-items:center;border-radius:50%}
#dt .dnav .bk .ic{width:22px;height:22px}
#dt .dnav img{width:30px;height:30px;border-radius:50%;object-fit:cover;background:#FFE3D3}
#dt .dnav .who{flex:1;min-width:0;display:flex;flex-direction:column;line-height:1.25}
#dt .dnav .who b{font-size:14px;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
#dt .dnav .who small{font-size:11px;color:var(--muted)}
#dt .dnav .fo{flex:none;height:28px;padding:0 13px;border-radius:99px;border:1.5px solid #F4593C;color:#F4593C;font-size:12.5px;font-weight:800}
#dt .dnav .fo.on{border-color:#E5DAD5;color:var(--muted)}
#dsc{flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch;overscroll-behavior:none}
#dsc::-webkit-scrollbar{display:none}
.dcv .cv{font-size:24px}
.dcv .cv .kb{display:none}
.dbody{padding:16px 18px 6px}
.dbody h2{margin:0;font-size:19px;font-weight:900;line-height:1.45;letter-spacing:.2px}
.dbody .tx{margin-top:10px;font-size:15px;line-height:1.85;color:#3A302C;letter-spacing:.2px}
.dbody .tx p{margin:0 0 14px}
.dbody .tx p.li{margin:-6px 0 14px;padding-left:1.3em;text-indent:-1.3em}
.dbody .tx p.li+p.li{margin-top:-10px}
.dbody .dk{display:flex;align-items:center;gap:6px;margin-bottom:8px}
.dbody .dk button{height:22px;padding:0 8px;border-radius:7px;font-size:12px;font-weight:800}
.dbody .dk button{background:var(--kl);color:var(--kt)}
.dbody .tgs{display:flex;flex-wrap:wrap;gap:6px;margin-top:4px}
.dbody .tgs button{height:24px;padding:0 9px;border-radius:99px;background:var(--peach);color:#D9583C;font-size:12.5px;font-weight:700}
/* 详情正文后:参与本话题 */
.pj{display:flex;align-items:center;gap:12px;margin:14px 18px 4px;padding:13px 14px;border-radius:16px;background:var(--hb)}
.pj{--hb:linear-gradient(140deg,var(--kl),var(--kl2));--hk:var(--kf);--ht:var(--kt)}
.pj .pt{flex:1;min-width:0}
.pj .pt b{display:block;font-size:14.5px;font-weight:900;color:#2A1E1E}
.pj .pt small{display:block;margin-top:2px;font-size:12px;color:#6E5C57}
.pj .pt small em{font-style:normal;font-weight:800;color:#E8473A}
.pj button{flex:none;height:32px;padding:0 13px;border-radius:99px;background:var(--hk);color:#fff;font-size:13px;font-weight:800}
/* ---------- 底部弹层:投稿规则 / 全部话题 ---------- */
#mask{position:fixed;inset:0;z-index:60;background:rgba(30,20,18,.45);opacity:0;pointer-events:none;transition:opacity .22s}
#mask.show{opacity:1;pointer-events:auto}
#sheet{position:fixed;left:0;right:0;bottom:0;z-index:61;max-height:82vh;display:flex;flex-direction:column;border-radius:22px 22px 0 0;background:#FFFBF8;transform:translateY(105%);transition:transform .28s cubic-bezier(.2,.8,.2,1)}
#sheet.show{transform:none}
#sheet .sg{width:36px;height:4px;margin:8px auto 0;border-radius:4px;background:#E6D8D2;flex:none}
#sheet .sbd{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:none;padding:6px 18px calc(18px + var(--safe-b))}
#sheet h3{margin:8px 0 0;font-size:18px;font-weight:900;text-align:center}
.rb{margin:14px 0 0;padding:16px 14px;border-radius:18px;text-align:center;color:#fff;background:radial-gradient(140px 90px at 100% 0,rgba(255,255,255,.3),transparent 70%),linear-gradient(120deg,#FF8A5B,#F4593C 60%,#E8473A)}
.rb small{display:block;font-size:12.5px;font-weight:700;opacity:.9}
.rb b{display:block;margin-top:4px;font-size:24px;font-weight:900;letter-spacing:.5px}
.rb b em{font-style:normal;color:#FFF3B8}
.rb i{display:block;margin-top:2px;font-style:normal;font-size:12px;opacity:.9}
.stp{margin:16px 0 0;padding:0;list-style:none;counter-reset:s}
.stp li{position:relative;padding:0 0 14px 38px;font-size:14px;line-height:1.6;color:#3A302C;counter-increment:s}
.stp li::before{content:counter(s);position:absolute;left:0;top:0;width:26px;height:26px;border-radius:50%;background:#FFEDE6;color:#F4593C;font-size:13px;font-weight:900;display:grid;place-items:center}
.stp li b{display:block;font-size:14.5px;font-weight:800;color:#2A1E1E}
.stp li small{display:block;font-size:12.5px;color:var(--muted)}
.cur-t{margin-top:12px;padding:10px 12px;border-radius:12px;background:#F6EEEA;font-size:13px;color:#6E5C57}
.cur-t b{color:#2A1E1E}
.sbtn{display:block;width:100%;height:46px;margin-top:6px;border-radius:99px;background:var(--btn);color:#fff;font-size:16px;font-weight:900;box-shadow:0 8px 16px -8px #EE5A3E}
.snote{margin-top:10px;text-align:center;font-size:11.5px;color:#B8A49E}
.tl-h{display:flex;align-items:center;gap:6px;margin:16px 0 8px;font-size:14px;font-weight:900}
.tl{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.tl button{display:flex;align-items:center;gap:4px;min-height:42px;padding:6px 10px;border-radius:12px;text-align:left;font-size:13.5px;font-weight:700;line-height:1.35;background:var(--hb);color:#3A2C28}
.tl button.on{box-shadow:inset 0 0 0 2px var(--hk)}
.tl button{--hb:var(--kl);--hk:var(--kf)}
.tl button span{flex:1}
.tl button em{font-style:normal;color:var(--hk);font-weight:900;margin:0 1px}
.tl button small{display:block;margin-top:2px;font-size:11px;font-weight:600;color:#A8918B}
.tl-h small{margin-left:6px;font-size:12px;font-weight:600;color:#A8918B}
.tl button i{flex:none;font-style:normal;padding:0 4px;border-radius:5px;background:#FF5A3C;color:#fff;font-size:9.5px;font-weight:800;line-height:15px}
.tl-all{display:block;width:100%;height:40px;margin-top:14px;border-radius:12px;background:#F6EEEA;font-size:14px;font-weight:800;color:#6E5C57}
.dbody .tm{margin-top:12px;font-size:12px;color:#B8A49E}
.cm{margin-top:8px;padding:14px 18px 20px;border-top:8px solid #F8F3EF}
.cm-h{display:flex;align-items:baseline;gap:6px;font-size:15px;font-weight:900}
.cm-h small{font-size:12.5px;font-weight:500;color:var(--muted)}
.cm-in{display:flex;align-items:center;gap:8px;margin-top:12px}
.cm-in .me{width:30px;height:30px;border-radius:50%;flex:none;display:grid;place-items:center;background:linear-gradient(140deg,#FFC9B5,#F59A7F);color:#fff;font-size:12px;font-weight:800}
.cm-in button{flex:1;height:34px;padding:0 14px;border-radius:99px;background:#F5EEEA;text-align:left;font-size:13px;color:#B3A19B}
.ci{display:flex;gap:10px;padding:14px 0 12px;border-bottom:1px solid #F5EDE8}
.ci:last-child{border-bottom:0}
.ci>img,.ci>.me{width:32px;height:32px;border-radius:50%;object-fit:cover;flex:none;background:#FFE3D3}
.ci>.me{display:grid;place-items:center;background:linear-gradient(140deg,#FFC9B5,#F59A7F);color:#fff;font-size:12px;font-weight:800}
.ci.mine{animation:ncIn .35s ease both}
.ci-b{flex:1;min-width:0}
.ci-n{display:flex;align-items:center;gap:6px;font-size:12.5px;color:var(--muted)}
.ci-n b{color:#7A6A64;font-weight:700}
.ci-n .au{height:16px;margin-left:3px;padding:0 5px;border-radius:4px;background:#F4593C;color:#fff;font-size:10px;font-weight:800;line-height:16px}
.ci-n .mt{height:16px;padding:0 5px;border-radius:4px;background:#FFE7E0;color:#EC4D33;font-size:10px;font-weight:800;line-height:16px}
.ci-n .lk{margin-left:auto}
.ci-t{margin:3px 0 0;font-size:14.5px;line-height:1.65;color:#2F2624;word-break:break-word}
.ci-s{margin-top:3px;font-size:11.5px;color:#B8A49E}
/* 11-03 用户评论要后台审核:自己的评论挂状态 */
.ci-st{display:inline-block;margin-top:5px;padding:0 7px;border-radius:4px;font-size:11px;line-height:18px;font-weight:600}
.ci-st.pending{background:#FFF4E5;color:#E08A00}.ci-st.rejected{background:#F2F3F5;color:#86909C}.ci-st.local{background:#F2F3F5;color:#A0A6AE}
.ci.mine.rejected .ci-t{color:#A0A6AE}
.ci-b[data-rk] .ci-t,.rp p[data-rk]{cursor:pointer}.ci-b[data-rk] .ci-t:active,.rp p[data-rk]:active{opacity:.6}
.rp .au.me{background:#FFE7E0;color:#EC4D33}.rp p.rej{color:#A0A6AE}.rp .ci-st{margin-top:3px}
/* 11-03 用户:孕周挪到名字右边,样式同专题页的小胶囊 */
.ci-n .stg{font-style:normal;font-size:11px;line-height:17px;padding:0 6px;border-radius:99px;background:#F5EFEC;color:#A08C86;white-space:nowrap}
.ci-s .rpy{margin-left:0;color:#8C7B75;font-weight:600;cursor:pointer}
.rp{margin-top:8px;padding:8px 10px;border-radius:10px;background:#F8F3EF;font-size:13px;line-height:1.65;color:#3A302C}
.rp p{margin:0 0 4px}
.rp p:last-child{margin-bottom:0}
.rp b{font-weight:700;color:#7A6A64}
.rp .au{display:inline-block;height:15px;margin:0 4px 0 7px;padding:0 4px;border-radius:4px;background:#F4593C;color:#fff;font-size:9.5px;font-weight:800;line-height:15px;vertical-align:1px}
.cm-end{padding:18px 0 6px;text-align:center;font-size:12px;color:#C9B7B1}
.bar{flex:none;display:flex;align-items:center;gap:6px;padding:8px 10px calc(8px + var(--safe-b)) 14px;background:#fff;border-top:1px solid var(--line)}
.bar .ip{flex:1;min-width:0;display:flex;align-items:center;gap:6px;height:38px;padding:0 6px 0 14px;border-radius:99px;background:#F5EEEA}
.bar .ip .ic{width:15px;height:15px;color:#B3A19B}
.bar input{flex:1;min-width:0;height:100%;border:0;background:none;outline:none;font:inherit;font-size:14px;color:var(--ink)}
.bar input::placeholder{color:#B3A19B}
.bar .send{flex:none;height:28px;padding:0 12px;border-radius:99px;background:var(--btn);color:#fff;font-size:13px;font-weight:800}
.bar .send:disabled{opacity:.4}
.bar .ib{flex:none;display:flex;align-items:center;gap:3px;height:38px;padding:0 6px;font-size:13px;color:#5E504C;font-variant-numeric:tabular-nums}
.bar .ib .ic{width:23px;height:23px}
.bar .ib.on.lv{color:#F0453A}
.bar .ib.on.fv{color:#F2A516}
.bar .ib.pop .ic{animation:pop .35s ease}
.bar.typing .ib{display:none}
.bar:not(.typing) .send{display:none}
/* ---------- 投稿(11-01:用户可投稿 → 审核中 → 后台通过/不通过 → 下次打开提醒) ---------- */
.nav .nsp{flex:none;width:36px}
#cp{position:fixed;inset:0;z-index:50;background:#FFFBF8;display:flex;flex-direction:column;transform:translateY(100%);transition:transform .3s cubic-bezier(.2,.8,.2,1)}
#cp.show{transform:none}
#cp .cph{flex:none;display:flex;align-items:center;gap:8px;height:calc(50px + env(safe-area-inset-top));padding:env(safe-area-inset-top) 12px 0 6px;border-bottom:1px solid var(--line);background:#fff}
#cp .cph .x{width:36px;height:36px;display:grid;place-items:center;border-radius:50%;color:var(--ink)}
#cp .cph .x .ic{width:18px;height:18px}
#cp .cph h2{flex:1;margin:0;font-size:16px;font-weight:900;text-align:center}
#cp .cph .ok{flex:none;height:32px;padding:0 16px;border-radius:99px;background:var(--btn);color:#fff;font-size:14px;font-weight:900}
#cp .cph .ok:disabled{opacity:.45}
#cp .cpb{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:none;padding:14px 16px calc(24px + var(--safe-b))}
.cp-t{display:flex;align-items:center;gap:8px;width:100%;min-height:46px;padding:8px 12px;border-radius:14px;background:var(--kl,#F6EEEA);text-align:left}
.cp-t .ct2{flex:1;min-width:0;font-size:14px;font-weight:800;color:var(--kt,#6E5C57);line-height:1.4}
.cp-t .ch{flex:none;font-size:12px;font-weight:700;color:var(--muted);display:inline-flex;align-items:center}
.cp-rw{margin-top:10px;padding:9px 12px;border-radius:12px;background:#FFF1EB;font-size:12.5px;color:#9A5A44}
.cp-rw em{font-style:normal;font-weight:900;color:#E8473A}
.cp-in{display:block;width:100%;margin-top:14px;padding:4px 2px 10px;border:0;border-bottom:1px solid var(--line);background:none;outline:none;font:inherit;font-size:19px;font-weight:900;color:var(--ink)}
.cp-in::placeholder,.cp-ta::placeholder{color:#C2B0AA;font-weight:600}
.cp-ta{display:block;width:100%;min-height:260px;margin-top:12px;padding:2px;border:0;background:none;outline:none;resize:none;font:inherit;font-size:15.5px;line-height:1.8;color:#3A302C}
.cp-cnt{margin-top:4px;font-size:12px;color:var(--muted);text-align:right}
.cp-cnt b{color:#E8473A}
.cp-cnt.ok b{color:#2E8A7C}
.cp-pics{display:flex;flex-wrap:wrap;gap:8px;margin-top:14px}
.cp-pics .pt,.cp-pics .add{position:relative;width:calc((100% - 16px) / 3);aspect-ratio:1;border-radius:12px;overflow:hidden;background:#F3EAE5}
.cp-pics .pt img{width:100%;height:100%;object-fit:cover}
.cp-pics .pt.up::after{content:"上传中…";position:absolute;inset:0;display:grid;place-items:center;background:rgba(255,255,255,.6);font-size:12px;color:#6E5C57}
.cp-pics .pt.bad::after{content:"上传失败";position:absolute;inset:0;display:grid;place-items:center;background:rgba(255,255,255,.75);font-size:12px;color:#E8473A}
.cp-pics .pt button{position:absolute;right:4px;top:4px;width:22px;height:22px;border-radius:50%;background:rgba(0,0,0,.5);color:#fff;font-size:15px;line-height:22px}
.cp-pics .add{display:grid;place-items:center;border:1.5px dashed #E2CFC7;background:#FFF8F4;color:#B8A49E;font-size:12px}
.cp-pics .add .ic{display:block;margin:0 auto 4px;width:22px;height:22px}
.cp-tip{margin-top:16px;font-size:12px;line-height:1.7;color:#B8A49E}
/* 审核结果 / 提交成功弹窗 */
#rs{position:fixed;inset:0;z-index:70;display:grid;place-items:center;padding:24px;background:rgba(30,20,18,.5);opacity:0;pointer-events:none;transition:opacity .2s}
#rs.show{opacity:1;pointer-events:auto}
#rs .rsb{width:100%;max-width:320px;padding:22px 20px 18px;border-radius:22px;background:#FFFBF8;text-align:center;transform:scale(.94);transition:transform .2s}
#rs.show .rsb{transform:none}
#rs .rsi{width:58px;height:58px;margin:0 auto;border-radius:50%;display:grid;place-items:center;background:#FFEDE6;color:#F4593C}
#rs .rsi .ic{width:30px;height:30px}
#rs .rsi.ok{background:#DDF2EE;color:#2E8A7C}
#rs .rsi.no{background:#F2ECEA;color:#8A7570}
#rs h3{margin:12px 0 0;font-size:18px;font-weight:900}
#rs .rst{margin:6px 0 0;font-size:13.5px;line-height:1.7;color:#6E5C57}
#rs .rst b{color:#2A1E1E}
#rs .rst em{font-style:normal;font-weight:900;color:#E8473A}
#rs .rsw{margin-top:10px;padding:8px 10px;border-radius:10px;background:#F6F0EE;font-size:12.5px;line-height:1.6;color:#7A6663;text-align:left}
#rs .rsk{display:block;width:100%;height:42px;margin-top:16px;border-radius:99px;background:var(--btn);color:#fff;font-size:15px;font-weight:900}
/* 真实投稿:封面「精选」角标、详情配图 */
.cv .jx{position:absolute;right:.7em;top:.8em;z-index:2;height:1.55em;padding:0 .55em;border-radius:.5em;background:linear-gradient(135deg,#FFB547,#F4803C);color:#fff;font-size:.85em;font-weight:800;line-height:1.55em}
.dbody .pics{display:grid;grid-template-columns:1fr 1fr;gap:6px;margin:0 0 14px}
.dbody .pics img{width:100%;aspect-ratio:1;object-fit:cover;border-radius:10px;background:#F3EAE5}
.dbody .pics img:only-child{grid-column:1/-1;aspect-ratio:auto}
.toast{position:fixed;left:50%;top:44%;z-index:80;max-width:280px;padding:10px 16px;border-radius:12px;background:rgba(40,30,28,.86);color:#fff;font-size:13.5px;line-height:1.6;text-align:center;transform:translate(-50%,8px);opacity:0;pointer-events:none;transition:opacity .2s,transform .2s}
.toast.show{opacity:1;transform:translate(-50%,0)}
/* ---------- 底部胶囊 Tab(11-03 用户:「主页面里加上返回兜爸和记一下那个 tab,就跟数胎动一样」)
照数胎动 /taidong/ 的最终样式:悬浮药丸 + 中间「记一下」橙色圆钮(玻璃顶部挖缺口坐进去)+ 右边「返回兜爸」(有真头像就显示头像 + 小房子角标)。
z-index 30:详情 / 收藏 / 投稿 / 弹层都在 35 以上,打开时自然盖住它。 ---------- */
.tab-fade{position:fixed;left:0;right:0;bottom:0;z-index:29;pointer-events:none;height:calc(96px + var(--safe-b));background:linear-gradient(180deg,rgba(255,246,241,0),rgba(255,246,241,.75))}
.tabbar{position:fixed;left:16px;right:16px;bottom:calc(22px + var(--safe-b));height:62px;z-index:30;border-radius:31px;padding:0 6px;display:grid;grid-template-columns:repeat(3,1fr)}
.tabbar::before{content:"";position:absolute;inset:0;z-index:-1;border-radius:inherit;pointer-events:none;background:#FFF9F5;
box-shadow:inset 0 0 0 1px rgba(255,255,255,.85),inset 0 1px 0 #fff;
-webkit-mask:radial-gradient(circle 31px at 50% 6px,transparent 30.5px,#000 31.5px);mask:radial-gradient(circle 31px at 50% 6px,transparent 30.5px,#000 31.5px)}
.tabbar::after{content:"";position:absolute;inset:0;z-index:-2;border-radius:inherit;pointer-events:none;box-shadow:0 14px 34px rgba(200,100,70,.2),0 2px 6px rgba(200,100,70,.06)}
.tab{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;padding:0 0 6px;border:0;background:none;font-family:inherit;color:#A3958D;cursor:pointer;transition:color .22s;-webkit-tap-highlight-color:transparent}
.tab.on{color:#F4593C}
.t-ico{width:25px;height:25px;display:block;position:relative}
.t-svg{display:block;width:100%;height:100%;overflow:visible}
.t-svg .tf,.t-svg .tl{fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.t-svg .td{fill:currentColor;stroke:none}
.tab.on .t-svg .tf{fill:currentColor}
.tab.on .t-svg .tl{stroke:#fff}
.tab.on .t-svg .td{fill:#fff}
.tab .t-txt{font-size:12.5px;font-weight:600;line-height:1.1;letter-spacing:.2px;white-space:nowrap}
.tab.on .t-txt{font-weight:800}
.tab::after{content:"";position:absolute;left:50%;bottom:6px;width:4px;height:4px;margin-left:-2px;border-radius:50%;background:#F4593C;opacity:0}
.tab.on::after{opacity:1}
.tab-fab::after{display:none}
.tab-fab .fab{position:absolute;left:50%;top:-20px;width:52px;height:52px;margin-left:-26px;border-radius:50%;display:grid;place-items:center;overflow:visible;
background:linear-gradient(150deg,#FF8A6E,#F4593C);box-shadow:0 6px 14px rgba(244,89,60,.32),inset 0 1px 0 rgba(255,255,255,.3);transition:transform .3s cubic-bezier(.3,1.6,.5,1)}
.tab-fab .fab::before{content:"";display:block;width:20px;height:20px;opacity:.28;border-radius:2px;
background:linear-gradient(#fff,#fff) center/100% 3px no-repeat,linear-gradient(#fff,#fff) center/3px 100% no-repeat}
.tab-fab:active .fab{transform:scale(.9)}
.fab-w{position:absolute;left:50%;top:50%;transform:translate(calc(-50% - 5px),-54%) rotate(-8deg);display:flex;align-items:center;white-space:nowrap;font-weight:900;font-style:normal;color:#4A1E14;line-height:1;pointer-events:none;
text-shadow:1.6px 0 #fff,-1.6px 0 #fff,0 1.6px #fff,0 -1.6px #fff,1.2px 1.2px #fff,-1.2px 1.2px #fff,1.2px -1.2px #fff,-1.2px -1.2px #fff,0 3px 4px rgba(120,30,10,.25)}
.fab-w i{font-style:normal;font-size:31px}
.fab-w em{font-style:normal;font-size:12.5px;line-height:1;margin:9px 0 0;letter-spacing:-.5px}
.fab-w s{text-decoration:none;font-size:20px;display:inline-block;transform:skewX(-8deg)}
.tab-fab .t-txt{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
#tabHome .t-ico{margin-bottom:6px}
#tabHome .t-txt{font-size:11.5px;font-weight:600}
.tab-avimg{position:absolute;inset:-3px;width:calc(100% + 6px);height:calc(100% + 6px);border-radius:50%;object-fit:cover;display:none;background:#fff;box-shadow:0 0 0 1.5px #fff,0 3px 10px rgba(226,105,74,.3)}
.tab-hm{position:absolute;right:-8px;bottom:-5px;width:15px;height:15px;z-index:1;border-radius:50%;display:none;background:linear-gradient(150deg,#E2694A,#C24E31);box-shadow:0 0 0 1.5px #FFF6F1}
.tab-hm svg{display:block;width:10px;height:10px;margin:2.5px}
.t-ico.has-av .tab-avimg,.t-ico.has-av .tab-hm{display:block}
.t-ico.has-av .t-svg{visibility:hidden}
.t-ico.has-av::before{content:"";position:absolute;inset:-7px;border-radius:50%;z-index:-1;pointer-events:none; /* 渐变圈:整圈 粉→橙→深橙,比数胎动那条半圈更明显(11-03 用户要「渐变圈的效果」) */
background:conic-gradient(from 200deg,#FFB38A,#F4593C,#E2694A,#FF8FA3,#FFB38A);
-webkit-mask:radial-gradient(circle closest-side,transparent 82%,#000 85%);mask:radial-gradient(circle closest-side,transparent 82%,#000 85%)}
/* 「记一下」弹层:标题一行 + 4 列工具宫格(同数胎动 / 首页) */
.rec-h{display:flex;align-items:baseline;gap:10px;padding:10px 2px 14px}
.rec-h b{font-size:19px;font-weight:800;color:#2A1E1E;flex:none}
.rec-h span{font-size:12px;color:#9C8F88;flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rec-x{flex:none;align-self:center;width:30px;height:30px;border:0;border-radius:50%;display:grid;place-items:center;background:rgba(120,70,50,.08);color:#9C8F88;cursor:pointer}
.rec-x .ic{width:12px;height:12px}
.rec-apps{display:grid;grid-template-columns:repeat(4,1fr);gap:20px 6px;padding:4px 0 8px}
.rec-app{position:relative;display:flex;flex-direction:column;align-items:center;gap:6px;min-width:0;border:0;background:none;font-family:inherit;color:#2A1E1E;cursor:pointer;transition:transform .16s}
.rec-app:active{transform:scale(.92)}
.rec-app img,.rec-app .rl{width:48px;height:48px;display:block;object-fit:contain;border-radius:14px}
.rec-app .rl{display:grid;place-items:center;background:#F6D9CB;color:#C2553A;font-size:19px;font-weight:800}
.rec-app span{display:block;max-width:100%;font-size:11.5px;font-weight:600;letter-spacing:-.2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rec-app.off img,.rec-app.off .rl{opacity:.45;filter:grayscale(.4)}
.rec-app.off i{position:absolute;top:-8px;left:calc(50% + 4px);font-style:normal;font-size:9px;font-weight:700;line-height:1;padding:3px 5px;border-radius:99px;background:#B9A9A2;color:#fff;white-space:nowrap}
.rec-empty{padding:30px 0;text-align:center;font-size:13px;color:#9C8F88}
/* ---------- 分类小 banner(11-03 用户:家庭婚姻 / 职场 / 经验 / 测一测各做一张小 banner 替换祈福树,祈福树只留在「全部」)
图 guangchang/bn/*.webp(AI 生成 3D 黏土风,纯色底),卡片底色取图的底色,图贴右边、左侧文字 ---------- */
.cbn{position:relative;display:flex;align-items:stretch;width:calc(100% - 24px);height:112px;margin:2px 12px 0;border:0;padding:0;border-radius:18px;overflow:hidden;text-align:left;font-family:inherit;cursor:pointer;background:var(--bb);box-shadow:0 6px 16px rgba(160,90,70,.1);transition:transform .16s;-webkit-tap-highlight-color:transparent}
.cbn:active{transform:scale(.985)}
.cbn img{position:absolute;right:-6px;top:50%;height:132px;width:auto;transform:translateY(-50%);pointer-events:none;animation:cbnF 5s ease-in-out infinite}
@keyframes cbnF{0%,100%{transform:translateY(-50%)}50%{transform:translateY(calc(-50% - 3px))}}
.cbn::after{content:"";position:absolute;inset:0;pointer-events:none;background:linear-gradient(90deg,var(--bb) 38%,transparent 66%)}
.cbn-tx{position:relative;z-index:1;display:flex;flex-direction:column;align-items:flex-start;padding:14px 0 12px 16px;max-width:64%}
.cbn-tx small{font-size:11px;font-weight:700;color:var(--bc);opacity:.85;letter-spacing:.3px}
.cbn-tx b{margin-top:4px;font-size:17.5px;font-weight:900;color:#2A1E1E;line-height:1.25;white-space:nowrap}
.cbn-tx em{margin-top:3px;font-style:normal;font-size:11.5px;color:#7C6E68;white-space:nowrap}
.cbn-go{margin-top:auto;display:inline-flex;align-items:center;gap:1px;height:26px;padding:0 9px 0 12px;border-radius:99px;background:var(--bc);color:#fff;font-size:12px;font-weight:800;box-shadow:0 3px 8px rgba(0,0,0,.12)}
.cbn-go .ic{width:12px;height:12px}
.cbn.b-family{--bb:#FCDEE3;--bc:#E25C7A}
.cbn.b-work{--bb:#D2E0F7;--bc:#4A7BD0}
.cbn.b-baby{--bb:#D6EFE7;--bc:#2E9B78}
.cbn.b-ceshi{--bb:#E8E0FC;--bc:#7A5BD6}
/* 11-03 卡片话题标签:标题下一行「#职场」「#经验分享」「#家庭婚姻」,像发布时带的话题 */
.nb .ntg{display:inline-block;margin:4px 0 0;padding:1px 7px;border-radius:6px;font-size:11px;font-weight:700;line-height:18px;background:#FFF0EC;color:#E2694A}
.nb .ntg.k-work{background:#EDF3FD;color:#4A7BD0}
.nb .ntg.k-baby{background:#E9F6F1;color:#2E9B78}
.nb .ntg.k-family{background:#FFEEF2;color:#E25C7A}
</style>
</head>
<body>
<svg width="0" height="0" style="position:absolute" aria-hidden="true">
<symbol id="i-back" viewBox="0 0 24 24"><path d="M15 5l-7 7 7 7" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></symbol>
<symbol id="i-heart" viewBox="0 0 24 24"><path d="M12 20.3s-7.6-4.6-9.2-9.4C1.7 7.6 3.9 4.5 7.2 4.5c2 0 3.6 1.1 4.8 2.8 1.2-1.7 2.8-2.8 4.8-2.8 3.3 0 5.5 3.1 4.4 6.4-1.6 4.8-9.2 9.4-9.2 9.4z" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/></symbol>
<symbol id="i-heart-f" viewBox="0 0 24 24"><path d="M12 20.3s-7.6-4.6-9.2-9.4C1.7 7.6 3.9 4.5 7.2 4.5c2 0 3.6 1.1 4.8 2.8 1.2-1.7 2.8-2.8 4.8-2.8 3.3 0 5.5 3.1 4.4 6.4-1.6 4.8-9.2 9.4-9.2 9.4z" fill="currentColor"/></symbol>
<symbol id="i-star" viewBox="0 0 24 24"><path d="M12 3.6l2.6 5.3 5.8.8-4.2 4.1 1 5.8L12 16.9l-5.2 2.7 1-5.8-4.2-4.1 5.8-.8z" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/></symbol>
<symbol id="i-star-f" viewBox="0 0 24 24"><path d="M12 3.6l2.6 5.3 5.8.8-4.2 4.1 1 5.8L12 16.9l-5.2 2.7 1-5.8-4.2-4.1 5.8-.8z" fill="currentColor"/></symbol>
<symbol id="i-chat" viewBox="0 0 24 24"><path d="M4.5 18.8V7.6A3 3 0 017.5 4.6h9a3 3 0 013 3v6a3 3 0 01-3 3H8.8z" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/></symbol>
<symbol id="i-pen" viewBox="0 0 24 24"><path d="M4 20h4L19 9l-4-4L4 16z" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/></symbol>
<symbol id="i-grid" viewBox="0 0 24 24"><path d="M4.5 4.5h6v6h-6zM13.5 4.5h6v6h-6zM4.5 13.5h6v6h-6zM13.5 13.5h6v6h-6z" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/></symbol>
<symbol id="i-home" viewBox="0 0 24 24"><path d="M3.8 11.2L12 4.3l8.2 6.9M6.2 9.4v10h11.6v-10" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M12 17.6s-2.9-1.7-2.9-3.6c0-1 .8-1.7 1.6-1.7.6 0 1 .3 1.3.8.3-.5.7-.8 1.3-.8.8 0 1.6.7 1.6 1.7 0 1.9-2.9 3.6-2.9 3.6z" fill="currentColor"/></symbol>
<symbol id="i-bulb" viewBox="0 0 24 24"><path d="M9 17.5h6M9.8 20.5h4.4M12 3.5a6 6 0 00-3.6 10.8c.5.4.8 1 .8 1.6v1.6h5.6v-1.6c0-.6.3-1.2.8-1.6A6 6 0 0012 3.5z" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></symbol>
<symbol id="i-gift" viewBox="0 0 24 24"><path d="M4 10.5h16v3H4zM5.5 13.5h13v6.5h-13zM12 10.5V20M12 10.5c-1.2-2.6-4.8-4.4-6-2.6-1 1.6 1.6 2.6 6 2.6zm0 0c1.2-2.6 4.8-4.4 6-2.6 1 1.6-1.6 2.6-6 2.6z" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linejoin="round"/></symbol>
<symbol id="i-fire" viewBox="0 0 24 24"><path d="M12 21c-4 0-6.5-2.7-6.5-6.2 0-3.6 2.9-5.6 3.6-9.3 2.6 1.4 3.6 3.6 3.6 5.4 1-.6 1.6-1.8 1.7-3 2.4 1.9 4.1 4.3 4.1 7 0 3.5-2.5 6.1-6.5 6.1z" fill="currentColor"/></symbol>
<symbol id="i-spark" viewBox="0 0 24 24"><path d="M12 3l2 6.2L20 12l-6 2.8L12 21l-2-6.2L4 12l6-2.8z" fill="currentColor"/></symbol>
<symbol id="i-x" viewBox="0 0 24 24"><path d="M6 6l12 12M18 6L6 18" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></symbol>
<symbol id="i-right" viewBox="0 0 24 24"><path d="M9 5l7 7-7 7" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></symbol>
<symbol id="i-ring" viewBox="0 0 24 24"><path d="M12 20.3s-7.6-4.6-9.2-9.4C1.7 7.6 3.9 4.5 7.2 4.5c2 0 3.6 1.1 4.8 2.8 1.2-1.7 2.8-2.8 4.8-2.8 3.3 0 5.5 3.1 4.4 6.4-1.6 4.8-9.2 9.4-9.2 9.4z" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/></symbol>
<symbol id="i-bag" viewBox="0 0 24 24"><path d="M4 8.5h16v10.5H4zM9 8.5V6.2c0-.9.7-1.7 1.7-1.7h2.6c.9 0 1.7.8 1.7 1.7v2.3M4 13h16" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/></symbol>
<symbol id="i-baby" viewBox="0 0 24 24"><circle cx="12" cy="12" r="8" fill="none" stroke="currentColor" stroke-width="2"/><path d="M9.2 14.6c1.6 1.4 4 1.4 5.6 0" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><circle cx="9.3" cy="10.6" r="1.1" fill="currentColor"/><circle cx="14.7" cy="10.6" r="1.1" fill="currentColor"/></symbol>
<symbol id="i-check" viewBox="0 0 24 24"><path d="M5 12.5l4.5 4.5L19 7.5" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"/></symbol>
<symbol id="i-clock" viewBox="0 0 24 24"><circle cx="12" cy="12" r="8.5" fill="none" stroke="currentColor" stroke-width="2"/><path d="M12 7.5V12l3 2" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></symbol>
<symbol id="i-plus" viewBox="0 0 24 24"><path d="M12 5v14M5 12h14" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></symbol>
</svg>
<div id="sc">
<div class="top" id="top">
<div class="nav">
<button class="bk" id="back" type="button" aria-label="返回"><svg class="ic"><use href="#i-back"/></svg></button>
<h1><span>孕妈广场</span></h1>
<i class="nsp"></i>
</div>
<div class="cats" id="cats" role="tablist" aria-label="分类"></div>
</div>
<div id="pane">
<div id="head"></div>
<div class="sh" id="fh"></div>
<div class="wf" id="wf"><div class="col"></div><div class="col"></div></div>
<div id="more"></div>
<div class="end"><div class="mb-brand"><img src="../assets/img/brand-logo-c.png" alt="兜爸心选"><p>陪你从孕期到育儿的每一天</p></div></div> <!-- 11-04 用户:底部「到底啦 / 示例占位」文字去掉,换品牌 logo + slogan -->
</div>
</div>
<div class="tab-fade" aria-hidden="true"></div>
<nav class="tabbar" id="tabbar">
<button class="tab on" id="tabPlaza" type="button"><span class="t-ico"><svg class="t-svg" viewBox="0 0 24 24" aria-hidden="true"><path class="tf" d="M4 6.6A2.6 2.6 0 0 1 6.6 4h10.8A2.6 2.6 0 0 1 20 6.6v7.8a2.6 2.6 0 0 1-2.6 2.6H11l-4.2 3.2c-.4.3-.9 0-.9-.4V17h0A2.6 2.6 0 0 1 4 14.4z"/><path class="tl" d="M8.5 9.4h7M8.5 12.6h4.4"/></svg></span><span class="t-txt">孕妈广场</span></button>
<button class="tab tab-fab" id="tabRec" type="button"><span class="fab"><b class="fab-w" aria-hidden="true"><i>记</i><em>一下</em><s>!</s></b></span><span class="t-txt">记一下</span></button>
<button class="tab" id="tabHome" type="button"><span class="t-ico" id="tabAv"><svg class="t-svg" viewBox="0 0 24 24" aria-hidden="true"><path class="tf" d="M4 10.4 12 4l8 6.4V18a2.4 2.4 0 0 1-2.4 2.4H6.4A2.4 2.4 0 0 1 4 18z"/><path class="tl" d="M9.8 20.2v-4.4a2.2 2.2 0 0 1 4.4 0v4.4"/></svg></span><span class="t-txt">返回首页</span></button>
</nav>
<div id="fvp" aria-hidden="true">
<div class="nav"><button class="bk" id="fvBack" type="button" aria-label="返回"><svg class="ic"><use href="#i-back"/></svg></button><h1><span>我的收藏</span></h1><i class="nsp"></i></div>
<div id="fvs"><div class="fvh" id="fvh"></div><div class="wf" id="fvw"><div class="col"></div><div class="col"></div></div></div>
</div>
<div id="dt" aria-hidden="true">
<div class="dnav" id="dnav">
<button class="bk" id="dback" type="button" aria-label="返回"><svg class="ic"><use href="#i-back"/></svg></button>
<img id="dav" alt="">
<span class="who"><b id="dnm"></b><small id="dst"></small></span>
<button class="fo" id="dfo" type="button">关注</button>
</div>
<div id="dsc"></div>
<div class="bar" id="bar">
<label class="ip"><svg class="ic"><use href="#i-pen"/></svg><input id="cin" type="text" maxlength="200" placeholder="说点什么…" enterkeyhint="send"><button class="send" id="csend" type="button" disabled>发送</button></label>
<button class="ib lv" id="blk" type="button" aria-label="点赞"><svg class="ic"><use href="#i-heart"/></svg><span></span></button>
<button class="ib fv" id="bfv" type="button" aria-label="收藏"><svg class="ic"><use href="#i-star"/></svg><span></span></button>
<button class="ib" id="bcm" type="button" aria-label="评论"><svg class="ic"><use href="#i-chat"/></svg><span></span></button>
</div>
</div>
<div id="cp" aria-hidden="true">
<div class="cph"><button class="x" id="cpX" type="button" aria-label="关闭"><svg class="ic"><use href="#i-x"/></svg></button><h2>写我的故事</h2><button class="ok" id="cpOk" type="button">提交</button></div>
<div class="cpb">
<button type="button" class="cp-t" id="cpT"></button>
<div class="cp-rw">投稿被选中,奖励 <em>¥30</em> 现金 + <em>500</em> 兜豆</div>
<input class="cp-in" id="cpTitle" type="text" maxlength="30" placeholder="起个标题(4~30 字)">
<textarea class="cp-ta" id="cpBody" maxlength="3000" placeholder="写下你的真实经历:发生了什么、当时怎么想、后来怎么做的……写得越具体,越容易被选中。"></textarea>
<div class="cp-cnt" id="cpCnt"></div>
<div class="cp-pics" id="cpPics"><label class="add" id="cpAdd"><span><svg class="ic"><use href="#i-plus"/></svg>配图(选填)</span><input id="cpFile" type="file" accept="image/*" hidden></label></div>
<div class="cp-tip">· 提交后进入审核,审核结果会在这里提醒你;通过的故事会展示在孕妈广场。<br>· 请写自己的真实经历,不要发广告、联系方式或别人的隐私。<br>· 草稿会自动保存在这台手机上。</div>
</div>
</div>
<div id="rs" role="dialog" aria-modal="true"><div class="rsb" id="rsb"></div></div>
<div id="mask"></div>
<div id="sheet" role="dialog" aria-modal="true"><i class="sg"></i><div class="sbd" id="sbd"></div></div>
<div class="toast" id="toast"></div>
<script src="topics.js?v=26110438"></script>
<script src="data.js?v=26110438"></script>
<script src="feed.js?v=26110438"></script>
<script src="ceshi/meta.js?v=26110438"></script>
<script src="../js/share-card.js?v=26110438"></script>
<script>
(function () {
'use strict';
var $ = function (s, c) { return (c || document).querySelector(s); };
var T = window.GC_TOPICS || [], D = window.GC_DATA || {};
var TBY = {}; T.forEach(function (t) { TBY[t.id] = t; });
var esc = function (s) { return String(s == null ? '' : s).replace(/[&<>"]/g, function (c) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' }[c]; }); };
var seed = function (t) { var x = 7; t = String(t); for (var i = 0; i < t.length; i++) x = (x * 31 + t.charCodeAt(i)) | 0; return Math.abs(x); };
var kfmt = function (n) { return n >= 10000 ? (n / 10000).toFixed(1).replace(/\.0$/, '') + '万' : n >= 1000 ? (n / 1000).toFixed(1).replace(/\.0$/, '') + 'k' : String(n); };
/* 点赞 / 收藏 / 评论数:一万以内写实数,点一下能看见 +1 */
var cfmt = function (n) { return n >= 10000 ? (n / 10000).toFixed(1).replace(/\.0$/, '') + '万' : String(n); };
function rng(s) { var x = seed(s) || 1; return function () { x = (x * 1103515245 + 12345) & 0x7fffffff; return x / 0x7fffffff; }; }
/* ---------- 身份:同首页 hashParam,hash 优先、query 兜底 ---------- */
function param(name) {
try {
var h = (location.hash.slice(1) || '') + '&' + (location.search.slice(1) || '');
var m = h.match(new RegExp('(?:^|[&#])' + name + '=([^&#]*)'));
return m ? decodeURIComponent(m[1]).split('?')[0] : '';
} catch (e) { return ''; }
}
var OPENID = param('openid');
var MYNAME = param('nickname') || '孕妈'; /* 授权回填的昵称在 hash 里;没有就叫「孕妈」,后面另挂「我」标 */
/* ---------- 头像:沿用首页 assets/img/mom/ 写实头像 ---------- */
var AV = ['m01','m02','m03','m04','m05','m06','m07','m08','m09','m10','m11','m12','m13','m14','m15','m16','m17','m18','m19','m20','m21','m22',
'p01','p02','p03','p04','p05','p06','p07','p08','p09','p10','p11','p12','p13','p14','s01','s02','s03','s04','s05','s06','s07','s08','s09','s10',
'k01','k02','k03','k04','k05','k06','k07','k08','k09','k10','k11','k12','k13'];
var avSrc = function (key) { return '../assets/img/mom/' + AV[seed(key) % AV.length] + '.jpg'; };
var avOf = function (n) { return n.avatar || avSrc(n.author); }; /* 真实投稿用本人头像,占位笔记用头像池 */
/* ---------- 笔记:data.js 的原始内容 + 确定性补字段(id / 封面样式 / 比例 / 评论) ---------- */
var NOTES = [], NBY = {}; /* 真实投稿到达后会往前插(loadApproved),所以 NOTES / MIXED 用 var 可重赋值 */
var RATIO = [1.12, 0.94, 1.04, 0.88, 1.18, 0.98, 0.9];
/* 11-02 用户:「要参差不齐的小红书瀑布流,现在都横向对齐」→ 照片封面高度按 id 哈希在 0.95~1.45 之间取,不再统一 1.3 */
var PR = [1.33, 1.05, 1.25, 1.45, 1.15, 0.95, 1.38, 1.2];
T.forEach(function (t, ti) {
var d = D[t.id]; if (!d) return;
(d.notes || []).forEach(function (n, i) {
var o = {
id: t.id + '-' + (i + 1), t: t.id, i: i, title: n.title, cover: n.cover || n.title, coverSub: n.coverSub || '',
author: n.author, stage: n.stage, likes: +n.likes || 0, body: n.body || '',
ratio: n.photo ? PR[seed(t.id + '-' + (i + 1) + 'r') % PR.length] : RATIO[(ti + i * 3) % RATIO.length], tone: (ti + i) % 3, photo: n.photo || ''
};
NOTES.push(o); NBY[o.id] = o;
});
});
/* 「全部」的混排:各话题轮流取一条(同一话题不扎堆),每轮按 id 哈希打散 */
var MIXED = (function () {
var out = [], byT = T.map(function (t) { return NOTES.filter(function (n) { return n.t === t.id; }); });
for (var r = 0; r < 30; r++) {
var round = [];
byT.forEach(function (l) { if (l[r]) round.push(l[r]); });
round.sort(function (a, b) { return seed(a.id + 'm') % 97 - seed(b.id + 'm') % 97; });
out = out.concat(round);
}
return out;
})();
var AGO = ['3 分钟前', '18 分钟前', '1 小时前', '2 小时前', '5 小时前', '昨天 21:40', '昨天 08:12', '10-29', '10-27', '10-25'];
/* 评论(11-02 用户:每篇 ≥20 条、紧贴正文、有作者回复;评论人从 1000 个人设里取,一人会在多篇下留言)
cm.json = { p: [[昵称, 头像(数字=av/NNNN.webp,字符串=assets/img/mom/xxx.jpg), 阶段]], c: { 帖子id: [[人设, 内容, 赞, [[人设|-1=作者, 内容]]]] } }
模拟内容,见 AGENTS.md 12c;文件较大,进页面后后台拉,详情页先显示「评论加载中」 */
var CMD = null, CMERR = false;
/* 头像编码:数字 = av/NNNN.webp(旧代码头像);'av:c012' = av/c012.webp(卡通/可爱卡通);'/…' = 站内绝对路径(内置头像库 /_bridge/avatars/);其余 = assets/img/mom/xxx.jpg */
var avP = function (a) { return typeof a === 'number' ? 'av/' + ('000' + a).slice(-4) + '.webp' : a.indexOf('av:') === 0 ? 'av/' + a.slice(3) + '.webp' : a.charAt(0) === '/' ? a : '../assets/img/mom/' + a + '.jpg'; };
fetch('cm.json?v=26110438').then(function (r) { return r.json(); }).then(function (j) {
CMD = j; if (openId && NBY[openId]) { renderComments(NBY[openId]); syncBar(NBY[openId]); }
}).catch(function () { CMERR = true; if (openId && NBY[openId]) renderComments(NBY[openId]); });
function commentsOf(n) {
if (n.real || !CMD) return []; /* 真实投稿不配模拟评论 */
var L = CMD.c[n.id] || [], P = CMD.p;
return L.map(function (c, k) {
var p = P[c[0]];
return { key: n.id + '#' + k, n: p[0], av: avP(p[1]), s: p[2], t: c[1], likes: c[2],
r: c[3].map(function (x) { var q = x[0] < 0 ? null : P[x[0]]; return { n: q ? q[0] : n.author, t: x[1], au: !q }; }) };
});
}
/* ---------- 本机存储 mmbox.gc.v1:{ <openid|_guest>: { like:{}, fav:{}, cl:{}, cm:{id:[{t,ts}]} } } ---------- */
var SK = 'mmbox.gc.v1', UK = OPENID || '_guest';
function loadAll() { try { return JSON.parse(localStorage.getItem(SK) || '{}') || {}; } catch (e) { return {}; } }
var ALL = loadAll();
var ME = ALL[UK] || (ALL[UK] = {});
['like', 'fav', 'cl', 'cm', 'fo'].forEach(function (k) { if (!ME[k] || typeof ME[k] !== 'object') ME[k] = {}; });
function save() { try { ALL[UK] = ME; localStorage.setItem(SK, JSON.stringify(ALL)); } catch (e) {} }
var liked = function (id) { return !!ME.like[id]; };
var likeN = function (n) { return n.likes + (liked(n.id) ? 1 : 0); };
var favN = function (n) { return Math.round(n.likes * .38) + 3 + (ME.fav[n.id] ? 1 : 0); };
/* 11-03 用户:评论要后台审核通过才对外公开。服务器 /plaza/comments:list = 别人已通过的;mine = 我在这篇下发的(含审核中 / 未通过)。
ME.cm 里没有 id 的是 11-03 以前只存本机的旧评论,从没公开过,照旧只给自己看(标「仅自己可见」)。 */
var RC = {};
var myCm = function (id) {
var old = (ME.cm[id] || []).filter(function (c) { return !c.id; }).map(function (c) { return { t: c.t, ts: c.ts, s: c.s, st: 'local' }; });
var srv = RC[id] ? RC[id].mine.map(function (c) { return { id: c.id, t: c.text, ts: c.at, s: c.stage, st: c.status, why: c.reason, parent: c.parent, to: c.parentName }; }) : [];
return old.concat(srv.reverse());
};
var realCm = function (id) { return RC[id] ? RC[id].list : []; };
/* 11-03 用户:可以回复别人的评论。回复也先审核;楼里只有一层,回复回复也挂在同一楼,写「回复 XX」 */
var REPLY = null;
function extraReplies(id, k) {
var o = realCm(id).filter(function (c) { return c.parent === k; }).map(function (c) { return { n: c.nickname || '孕妈', t: c.text, to: c.parentName, ts: c.at }; });
var m = myCm(id).filter(function (c) { return c.parent === k; }).map(function (c) { return { n: MYNAME, me: 1, t: c.t, to: c.to, st: c.st, why: c.why, ts: c.ts }; });
return o.concat(m).sort(function (x, y) { return x.ts - y.ts; }); /* 楼里按时间先后 */
}
function stTag(c) { return c.st === 'pending' ? '<span class="ci-st pending">审核中 · 通过后大家才能看到</span>' : c.st === 'rejected' ? '<span class="ci-st rejected">未通过' + (c.why ? ':' + esc(c.why) : '') + '</span>' : c.st === 'local' ? '<span class="ci-st local">仅自己可见</span>' : ''; }
function rpHTML(list, k, owner) {
return list.length ? '<div class="rp">' + list.map(function (x) {
return '<p' + (x.me ? ' class="rme' + (x.st === 'rejected' ? ' rej' : '') + '"' : ' data-rk="' + esc(k) + '" data-rn="' + esc(x.n) + '"') + '><b>' + esc(x.n) + '</b>' + (x.au ? '<span class="au">作者</span>' : '') + (x.me ? '<span class="au me">我</span>' : '') +
(x.to && x.to !== owner ? ' 回复 <b>' + esc(x.to) + '</b>' : '') + ':' + esc(x.t) + (x.me && x.st && x.st !== 'approved' ? '<br>' + stTag(x) : '') + '</p>';
}).join('') + '</div>' : '';
}
var cmN = function (n) { return commentsOf(n).length + realCm(n.id).length + myCm(n.id).filter(function (c) { return c.st !== 'rejected'; }).length; }; /* 含回复 */
function loadRC(n) {
var u = '/api/mp/public/mama-box/plaza/comments?kind=post&target=' + encodeURIComponent(n.id) + (OPENID ? '&openid=' + encodeURIComponent(OPENID) : '');
fetch(u).then(function (r) { return r.json(); }).then(function (j) {
if (!j || j.code !== 200) return;
RC[n.id] = j.result;
if (openId === n.id) { renderComments(n); syncBar(n); }
}).catch(function () {});
}
function toast(msg) {
var t = $('#toast'); t.textContent = msg; t.classList.add('show');
clearTimeout(toast._t); toast._t = setTimeout(function () { t.classList.remove('show'); }, 1800);
}
function haptic() { if (navigator.vibrate) navigator.vibrate(8); }
/* ---------- 封面:一种版式,颜色只按分类(家庭粉 / 经验青绿)× 3 个深浅 ---------- */
var PAL = {
family: { ink: '#C23A55', c: [['#FFE6EB', '#FFC6D2'], ['#FFEAE2', '#FFCBB8'], ['#FCE8F2', '#F5C4DC']] },
marriage: { ink: '#6346B0', c: [['#EFE9FF', '#D6C8F6'], ['#F5E8FA', '#E2C6EF'], ['#E9EBFF', '#C9CEF5']] },
work: { ink: '#2C5E9E', c: [['#E4EFFB', '#BED5F1'], ['#E5F2F8', '#BFDDEB'], ['#ECEFF6', '#CBD3E6']] },
baby: { ink: '#21705F', c: [['#E0F3EE', '#B8E3D8'], ['#E6F3E3', '#C2E2BE'], ['#E1EFF5', '#B9D9E7']] }
};
var CAT_IC = { family: 'i-home', marriage: 'i-ring', work: 'i-bag', baby: 'i-baby' };
var CAT_SHORT = { family: '家庭婚姻', marriage: '家庭婚姻', work: '职场', baby: '经验' };
var CAT_SUB = { family: '婆家、长辈、夫妻相处、分工、日常拉扯', marriage: '夫妻相处、落差、分工、情绪、细碎磨合',
work: '在岗孕妈、产检、边界、顾虑、复工', baby: '身体变化、囤货、预算、生产经历、过来人经验' };
var kbHTML = function (cat) { return '<span class="kb k-' + cat + '"><svg class="ic"><use href="#' + CAT_IC[cat] + '"/></svg>' + CAT_SHORT[cat] + '</span>'; };
function coverHTML(n, h) {
var t = TBY[n.t], pl = PAL[t.cat], c = pl.c[n.tone];
if (n.photo) return '<div class="cv ph" style="' + (h ? 'height:' + h : '') + '"><img src="' + esc(n.photo) + '" alt="" loading="lazy"></div>'; /* 11-03 用户:信息流卡片左上角「职场 / 家庭婚姻」标签删掉 */
return '<div class="cv" style="--c1:' + c[0] + ';--c2:' + c[1] + ';--tk:' + pl.ink + ';' + (h ? 'height:' + h : '') + '">' + (n.real ? '<span class="jx">精选投稿</span>' : '') +
'<div class="ct"><div class="t1">' + esc(n.cover) + '</div><div class="t2">' + esc(n.coverSub) + '</div></div><i class="wm" aria-hidden="true">' + esc(t.g) + '</i></div>';
}
function likeHTML(n) {
var on = liked(n.id);
return '<span class="lk' + (on ? ' on' : '') + '" data-like="' + n.id + '" role="button" aria-label="点赞"><svg class="ic"><use href="#i-heart' + (on ? '-f' : '') + '"/></svg>' + cfmt(likeN(n)) + '</span>';
}
/* 卡片样式 sty(只对照片封面):'' 普通图 / 'ov' 图上压大字(底部渐变)/ 'tg' 图上贴纸字 —— 11-02 用户:「把一些文字放到图片上,穿插着来,类似小红书」 */
function cardHTML(n, showTopic, sty) {
var t = TBY[n.t], r = n.ratio, ov = '';
if (!n.photo) sty = '';
/* 11-02 用户:图上放的短语「不知所云」→ 图上直接放完整标题;卡片下方再放一行标题(单行省略)、不放话题。
11-02 二改:普通卡(图上没字)也不放话题;图上文字 70% 在底部,30% 放顶部/中间(按帖子 id 哈希固定,刷新不跳) */
var ph = 0; for (var q = 0; q < n.id.length; q++) ph = (ph * 31 + n.id.charCodeAt(q)) >>> 0;
var pos = ph % 10 < 7 ? '' : ph % 10 < 9 ? ' at-mid' : ' at-top';
if (sty === 'ov') { r = Math.max(r, 1.33); ov = '<div class="ovt' + pos + '"><b>' + esc(n.title) + '</b></div>'; }
else if (sty === 'tg') { r = Math.max(r, 1.2); ov = '<div class="tgt' + pos + '"><b><span>' + esc(n.title) + '</span></b></div>'; }
/* 11-04 用户:卡片底部昵称旁边带上孕周,样式同评论区 .stg;图上压字卡原来顶部那行孕周去掉,免得一张卡出现两次 */
return '<button type="button" class="nc' + (sty ? ' s-' + sty : '') + '" data-id="' + n.id + '"><div class="cvw">' +
coverHTML(n, 'calc(var(--cw) * ' + r + ')') + ov + '</div>' +
'<div class="nb"><h3>' + esc(n.title) + '</h3>' + (t && TAG_NAME[t.cat] ? '<span class="ntg k-' + t.cat + '">#' + TAG_NAME[t.cat] + '</span>' : '') +
'<div class="nf"><img src="' + esc(avOf(n)) + '" alt="" loading="lazy"><span class="nm">' + esc(n.author) + '</span>' + (n.stage ? '<i class="stg">' + esc(n.stage.replace(/\s+/g, '')) + '</i>' : '') + likeHTML(n) + '</div></div></button>';
}
/* ---------- 列表 ---------- */
/* cur 当前话题('' = 不限话题);catF 一级分类('' 全部 / family 家庭 / marriage 婚姻 / work 职场 / baby 母婴)。选了话题时 catF 恒等于该话题的 cat */
var cur = '', catF = '';
var UBAND = (function () { try { var g = JSON.parse(localStorage.getItem('mmbox.gcwk.v1') || 'null'); return !g ? -1 : g.pp ? 'pp' : g.w && window.GC_BAND ? window.GC_BAND('孕' + g.w + '周') : -1; } catch (e) { return -1; } })();
/* 11-01 用户:家庭+婚姻合成「家庭婚姻」,母婴改「经验」→ 三块(marriage 话题在 topics.js 里已并进 family) */
/* 11-03 用户:「家庭婚姻 / 职场 / 经验标签全部删除,只展示全部,所有内容放到全部里;每篇带一个话题标签(职场 / 经验分享…)」
→ 顶部只留「全部」+「测一测」(首页孕期百宝箱「趣味小测试」进的就是测一测);话题标签见 cardHTML 的 .ntg */
/* 11-03 三改:顶部「测一测」也删了,只剩「全部」;测试列表只从首页孕期百宝箱「趣味小测试」进(?c=ceshi),这时顶部换成「趣味小测试」标题、不出分类条 */
var CATS = [['', '全部', 'i-grid']];
var TAG_NAME = { family: '家庭婚姻', work: '职场', baby: '经验分享' };
var CAT_ORDER = ['family', 'work', 'baby'];
var CAT_NAME = { family: '家庭婚姻', work: '职场方向', baby: '孕育经验' };
var inCat = function (t) { return !catF || t.cat === catF; };
/* 投稿奖励(11-01 用户定):话题投稿被选中 → 30 元现金 + 500 兜豆 */
var REWARD = '<em>¥30</em> 现金 + <em>500</em> 兜豆';
function renderCats() {
var cs = catF === 'ceshi';
/* 11-04 用户:「列表页把『全部』去掉,只留顶上的头和『孕妈广场』」→ 分类条一律不出 */
$('#cats').style.display = 'none';
$('#top .nav h1 span').textContent = cs ? '趣味小测试' : '孕妈广场';
var bs = $('#cats').querySelectorAll('button[data-c]');
if (bs.length) { /* 已画过:只换选中态,胶囊才能滑过去 */
[].forEach.call(bs, function (b) { var on = b.dataset.c === catF; b.classList.toggle('on', on); b.setAttribute('aria-selected', on); });
moveBar(); return;
}
$('#cats').innerHTML = CATS.map(function (x) {
return '<button type="button" role="tab" data-c="' + x[0] + '" class="c-' + (x[0] || 'all') + (catF === x[0] ? ' on' : '') + '" aria-selected="' + (catF === x[0]) + '">' +
(x[0] === 'ceshi' ? '<svg class="ic"><use href="#i-spark"/></svg>' : '') + x[1] + '<i>' + catCnt(x[0]) + '</i></button>';
}).join('') + '<span class="bar"></span>';
moveBar();
}
function catCnt(c) { if (c === 'ceshi') return TM.length; return NOTES.filter(function (n) { return !c || TBY[n.t].cat === c; }).length; }
/* 胶囊挪到选中标签文字下方,宽度跟文字走(取文字宽的一半,偏小红书) */
function moveBar() {
var on = $('#cats .on'), bar = $('#cats .bar'); if (!on || !bar) return;
var w = on.offsetWidth - 20, x = on.offsetLeft + (on.offsetWidth - w) / 2;
bar.style.width = w + 'px'; bar.style.transform = 'translateX(' + x + 'px)';
bar.style.background = getComputedStyle(on).getPropertyValue('--cf');
bar.style.opacity = on.dataset.c === 'ceshi' ? '0' : '';
}
window.addEventListener('resize', moveBar);
/* 11-02 用户:「孕妈广场做一张为宝宝祈福的 banner,点了直接进祈福树;要把祈福树调上来、有动效,像首页 3D 婴儿房,吸引点击;替换掉 30 现金 + 500 兜豆」
→ 夜空卡 + 右侧祈福树(透明图 assets/img/d71826d10457.png,AI 生成)轻轻摇 + 树后金光呼吸 + 福牌往上飘 + 星星闪;整卡可点 */
function qifuHTML() {
return '<button type="button" class="qf" id="qfBanner" aria-label="去宝宝祈福树,为宝宝挂一张福牌">' +
'<i class="qf-st" aria-hidden="true"></i><i class="qf-glow" aria-hidden="true"></i>' +
'<img class="qf-tree" src="../assets/img/d71826d10457.png" alt="" decoding="async">' +
'<span class="qf-fly" aria-hidden="true"><i>福</i><i>安</i><i>福</i><i>康</i></span>' +
'<span class="qf-tx"><small><i></i>宝宝祈福树</small><b><i>#</i>为宝宝挂一张福牌<i>#</i></b><em>集齐五福,愿宝宝平平安安</em>' +
'<span class="qf-go">去祈福<svg class="ic"><use href="#i-right"/></svg></span></span></button>';
}
/* 分类小 banner:家庭婚姻 / 职场 / 经验 点了 = 参与本类最热话题(投稿规则弹层);测一测 点了 = 进最热的那个测试 */
var CBN = {
family: ['家庭婚姻', '孕期的家,也需要用心经营', '和老公、婆婆、爸妈的那些事', '我也来聊聊'],
work: ['职场', '怀孕了,工作也要安心', '产检请假、孕期上班、休产假', '我也来聊聊'],
baby: ['经验', '过来人的孕育笔记', '踩过的坑、买对的好物都在这', '分享我的经验'],
ceshi: ['孕育测一测', '', '', '测最热的一个']
};
function cbnHTML(c) {
var x = CBN[c]; if (!x) return '';
var tgt;
if (c === 'ceshi') {
var top = byHot(TM)[0];
x = x.slice(); x[1] = '测测你是哪种孕妈'; x[2] = '累计 ' + Math.round(TM.reduce(function (a, y) { return a + gcTested(y.id); }, 0) / 1e4) + ' 万人次参与 · ' + TM.length + ' 个测试';
tgt = top ? ' data-test="' + top.id + '"' : '';
} else { var h = hotList()[0]; tgt = ' data-join="' + (h ? h.id : '') + '"'; }
return '<button type="button" class="cbn b-' + c + '"' + tgt + '><img src="bn/' + c + '.webp" alt="" decoding="async">' +
'<span class="cbn-tx"><small>' + x[0] + '</small><b>' + x[1] + '</b><em>' + x[2] + '</em><span class="cbn-go">' + x[3] + '<svg class="ic"><use href="#i-right"/></svg></span></span></button>';
}
/* 跳祈福树:同首页 jumpApp(QIFU_URL) —— 相对路径、身份走 query、上报 last_app 与分享位置(AGENTS 硬约定 3/6/7/13) */
function goQifu() { goApp('/qifu-shu/'); }
/* 跳站内其他 H5(祈福树 / 记一下宫格共用):只走相对路径(AGENTS 13),后台给的完整地址也剥成 /slug/… */
function goApp(url) {
try { var u = new URL(url, location.href); if (u.origin === location.origin || /(^|\.)yizhezhe\.com$/.test(u.hostname)) url = u.pathname + u.search; } catch (e) {}
var q = [], oid = param('openid'), uid = param('unionid');
if (oid) q.push('openid=' + encodeURIComponent(oid));
if (uid) q.push('unionid=' + encodeURIComponent(uid));
if (!oid && !uid) q.push('__no_identity=1');
var target = url + (url.indexOf('?') >= 0 ? '&' : '?') + q.join('&');
try {
if (oid) {
var api = '/api/mp/public/last-app?openid=' + encodeURIComponent(oid) + '&url=' + encodeURIComponent(location.origin + url);
if (!(navigator.sendBeacon && navigator.sendBeacon(api)) && window.fetch) fetch(api, { method: 'POST', keepalive: true }).catch(function () {});
}
if (window.wxAuth && wxAuth.reportLocation) wxAuth.reportLocation({ href: target });
} catch (e) {}
haptic(); location.href = target;
}
/* 11-02 v2 用户:「测一测放到『经验』后边;孕妈广场上现在那个测一测删掉;『大家在聊』里穿插几个测一测,点了进对应的测试」
→ CATS 加第 5 个分类 ceshi;选中时 #head 放说明卡、#fh 放分组胶囊、#wf 瀑布流放 25 张测试卡;「全部」信息流每 8 张帖子穿插 1 张测试卡(先 CS_MIX 再按热度)。
测试目录只引轻量 ceshi/meta.js;题库在 ceshi/tests.js,只在测试页加载。 */
var TM = window.GC_TESTS_META || [], TMBY = {};
TM.forEach(function (x) { TMBY[x.id] = x; });
var TG = { quiz: '常识小测', psy: '趣味心理', game: '趣味闯关', shop: '好物配置' }, tGrp = '';
var CS_MIX = ['t11', 't29', 't01', 't24', 't26', 't16', 't03', 't27', 't14', 't21', 't30', 't18'];
function csDone() { try { return (JSON.parse(localStorage.getItem('mmbox.gcts.v1') || '{}')[param('openid') || '_guest']) || {}; } catch (e) { return {}; } }
function ceshiURL(id, fromTab) {
var q = new URLSearchParams(location.search); ['t', 'n', 'c', 'id', 'mine', 'write', 'fav'].forEach(function (k) { q.delete(k); });
if (fromTab) q.set('c', 'ceshi');
q.set('id', id);
return 'ceshi/?' + q.toString() + location.hash;
}
function testCardHTML(x, done) {
var d = done && done[x.id];
return '<button type="button" class="nc tst g-' + x.group + '" data-test="' + x.id + '"><div class="cvw"><img src="ceshi/img/' + x.id + '_s.webp" alt="" loading="lazy">' +
'<span class="tb"><svg class="ic"><use href="#i-spark"/></svg>测一测</span><span class="tq">' + gcTestedText(x.id) + ' · ' + x.n + ' 题</span></div>' +
'<div class="nb"><h3>' + esc(x.title) + '</h3><div class="nf">' + (d ? '<span class="gs dn">已测 · ' + esc(d.title) + '</span>' : '<span class="gs">' + TG[x.group] + '</span>') +
'<span class="gt">' + (d ? '再测' : '去测') + ' ›</span></div></div></button>';
}
/* 热度排序:按「N人测过」(ceshi/meta.js gcTested,模拟数,见 AGENTS.md 12b)从高到低 */
var byHot = function (l) { return l.slice().sort(function (a, b) { return gcTested(b.id) - gcTested(a.id); }); };
var TGD = { quiz: '有标准答案,答完看解析', psy: '没有对错,测测你是哪一型', game: '挑战一下,看能拿什么称号', shop: '测测你给娃买东西、挑东西是哪种风格' };
/* 11-03 用户发参考图:「测试列表按图里的排版」→ 分组标题(色条 + 图标 + 名称 + 一句话)+ 宫格卡:
彩色渐变封面(两团柔和色块)上写大字短名 + 小字「谁来测 · N 题」+「开始测试」胶囊,封面下一行完整标题 + 人数;
常识小测 / 趣味闯关 3 列,趣味心理 / 好物配置 2 列(大卡)。原热度榜不再单列,组内仍按人数从高到低排。 */
var CS_SHORT = window.GC_SHORT || {}; /* 短名表在 ceshi/meta.js(测试开始页顶部小胶囊也用) */
/* 11-04 用户:「列表页小图标都用扁平化」→ 分组 emoji 换成纯色圆角块 + 白色实心图标(CS_ICO);
「一排 3 个字看不清」→ 每组统一一排 2 个,最多 3 排(6 张),多出来的改一行一条的列表(csRowHTML);5 个的组出 4 张卡 + 1 行,不留单张。 */
var CS_ICO = {
quiz: '<svg viewBox="0 0 24 24"><path d="M3.5 5.6c2.6-.9 5.4-.6 7.6 1V19c-2.2-1.4-5-1.7-7.6-.9zM20.5 5.6c-2.6-.9-5.4-.6-7.6 1V19c2.2-1.4 5-1.7 7.6-.9z" fill="#fff"/></svg>',
psy: '<svg viewBox="0 0 24 24"><path d="M12 20s-7.5-4.5-8.8-9.2C2.3 7.6 4.4 4.8 7.4 4.8c1.9 0 3.5 1 4.6 2.6 1.1-1.6 2.7-2.6 4.6-2.6 3 0 5.1 2.8 4.2 6C19.5 15.5 12 20 12 20z" fill="#fff"/></svg>',
game: '<svg viewBox="0 0 24 24"><path d="M7 4h10v5a5 5 0 01-10 0zM7 6H4v1.5A3.5 3.5 0 007.3 11M17 6h3v1.5a3.5 3.5 0 01-3.3 3.5" fill="#fff"/><path d="M7 6H4v1.5A3.5 3.5 0 007.3 11M17 6h3v1.5a3.5 3.5 0 01-3.3 3.5" fill="none" stroke="#fff" stroke-width="1.6"/><path d="M10.5 14h3v3h-3zM8 17.5h8V20H8z" fill="#fff"/></svg>',
shop: '<svg viewBox="0 0 24 24"><path d="M5 8.5h14l-1 11.5H6z" fill="#fff"/><path d="M9 10V7a3 3 0 016 0v3" fill="none" stroke="#fff" stroke-width="1.8" stroke-linecap="round"/></svg>'
};
/* 11-04 用户:「一行一条前面的图标都是一样的小书」→ 每个测试一枚自己的扁平图标(白色实心,底色按分组再分深浅三档),宫格卡封面右下角也放一枚大号淡水印 */
var CS_TI = {
t01: '<path d="M12 6.2c-1.6-2.3-6.6-2.2-7.4 2.2-.8 4.5 2.6 10.6 5.2 11 1 .2 1.4-.4 2.2-.4s1.2.6 2.2.4c2.6-.4 6-6.5 5.2-11-.8-4.4-5.8-4.5-7.4-2.2z"/><path d="M12 6c0-1.6.8-2.8 2.4-3.4" fill="none" stroke="#fff" stroke-width="1.7" stroke-linecap="round"/>',
t02: '<circle cx="12" cy="6.5" r="3.6"/><path d="M4.5 21c0-4.6 3.4-7.6 7.5-7.6s7.5 3 7.5 7.6z"/><path d="M12 13.6l-1.4 2.2L12 21l1.4-5.2z" fill="rgba(0,0,0,.18)"/>',
t03: '<circle cx="12" cy="12.5" r="7.6"/><circle cx="9.3" cy="12" r="1.1" fill="rgba(0,0,0,.28)"/><circle cx="14.7" cy="12" r="1.1" fill="rgba(0,0,0,.28)"/><path d="M10 15.2c1.2 1 2.8 1 4 0" fill="none" stroke="rgba(0,0,0,.28)" stroke-width="1.3" stroke-linecap="round"/><path d="M12 4.9c-.4-1.4.6-2.5 2-2.2" fill="none" stroke="#fff" stroke-width="1.6" stroke-linecap="round"/>',
t04: '<path d="M8 3h8l-1 3.5H9z"/><rect x="7.5" y="7.5" width="9" height="13.5" rx="3.2"/><path d="M9.5 12h5M9.5 15.5h5" stroke="rgba(0,0,0,.2)" stroke-width="1.3"/>',
t05: '<rect x="3.5" y="7" width="17" height="13" rx="3"/><path d="M9 7V5.2C9 4.5 9.5 4 10.2 4h3.6c.7 0 1.2.5 1.2 1.2V7" fill="none" stroke="#fff" stroke-width="1.8"/><path d="M3.5 12.5h17" stroke="rgba(0,0,0,.18)" stroke-width="1.4"/><rect x="10.5" y="11.2" width="3" height="2.6" rx=".8" fill="rgba(0,0,0,.2)"/>',
t06: '<ellipse cx="12" cy="15.5" rx="8.5" ry="4.5"/><circle cx="16.8" cy="9.2" r="3.4"/><path d="M19.8 9.4l2 .6-2 .8z"/><circle cx="17.5" cy="8.6" r=".7" fill="rgba(0,0,0,.35)"/>',
t07: '<path d="M3 11h18c0 4.7-3.6 8.5-9 8.5S3 15.7 3 11z"/><path d="M8.5 8.5c-.8-1 .6-2-.2-3.2M12 8.5c-.8-1 .6-2-.2-3.2M15.5 8.5c-.8-1 .6-2-.2-3.2" fill="none" stroke="#fff" stroke-width="1.5" stroke-linecap="round"/>',
t08: '<ellipse cx="9" cy="7.8" rx="4" ry="5"/><path d="M8.2 12.5h1.6l.7 8.2a1.5 1.5 0 01-3 0z"/><path d="M16 3v6.5M14 3v4.8a2 2 0 004 0V3M16 9.5V21" fill="none" stroke="#fff" stroke-width="1.6" stroke-linecap="round"/>',
t09: '<path d="M14.5 3.2A8.8 8.8 0 1020.8 15 7 7 0 0114.5 3.2z"/><path d="M17 5.5h3l-3 3.2h3" fill="none" stroke="#fff" stroke-width="1.4" stroke-linejoin="round"/>',
t10: '<path d="M12 2.8s-6.5 7.2-6.5 11.6a6.5 6.5 0 0013 0C18.5 10 12 2.8 12 2.8z"/><path d="M9 14.5a3 3 0 002.6 3" fill="none" stroke="rgba(0,0,0,.2)" stroke-width="1.5" stroke-linecap="round"/>',
t11: '<rect x="3.5" y="5" width="17" height="15.5" rx="3"/><path d="M3.5 9.5h17" stroke="rgba(0,0,0,.2)" stroke-width="1.4"/><path d="M8 3v4M16 3v4" stroke="#fff" stroke-width="2" stroke-linecap="round"/><path d="M8 14.6l2.4 2.2 4.6-4.4" fill="none" stroke="rgba(0,0,0,.28)" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"/>',
t12: '<path d="M12 2.8l2.8 5.8 6.3.9-4.6 4.4 1.1 6.3L12 17.2l-5.6 3 1.1-6.3L2.9 9.5l6.3-.9z"/>',
t13: '<path d="M12 21v-8.5" stroke="#fff" stroke-width="2" stroke-linecap="round"/><path d="M12 13C12 8 8.5 5.5 4 6c0 4.5 3.2 7.2 8 7zM12 11.5c0-4 3-6.8 7.5-6.5 0 4.2-3 6.8-7.5 6.5z"/>',
t14: '<circle cx="9" cy="9" r="4"/><path d="M9 2v1.4M3.4 9H2M4.1 4.1l1 1M13.9 4.1l-1 1" stroke="#fff" stroke-width="1.6" stroke-linecap="round"/><path d="M7.5 20.5a4.5 4.5 0 01.6-9 6 6 0 0111.4 2.2 3.4 3.4 0 01-.5 6.8z"/>',
t15: '<path d="M4 5.5c2.6-.9 5.4-.5 7.3 1v13c-1.9-1.4-4.7-1.8-7.3-.9zM20 5.5c-2.6-.9-5.4-.5-7.3 1v13c1.9-1.4 4.7-1.8 7.3-.9z"/><path d="M15 9.2l1.2.8 1.6-2" fill="none" stroke="rgba(0,0,0,.25)" stroke-width="1.3" stroke-linecap="round"/>',
t16: '<circle cx="8" cy="7" r="3"/><circle cx="16" cy="7" r="3"/><path d="M2.5 19c0-3.6 2.4-6 5.5-6s5.5 2.4 5.5 6zM10.5 19c0-3.6 2.4-6 5.5-6s5.5 2.4 5.5 6z"/><path d="M12 16.6s-2-1.2-2-2.6c0-.8.6-1.3 1.2-1.3.4 0 .7.2.8.5.1-.3.4-.5.8-.5.6 0 1.2.5 1.2 1.3 0 1.4-2 2.6-2 2.6z" fill="#FFD3DE"/>',
t17: '<path d="M7 19.5a4.5 4.5 0 01-.7-9 6.2 6.2 0 0111.8 1.3A3.9 3.9 0 0117.5 19.5z"/><path d="M8 22l1-2M12 22l1-2M16 22l1-2" stroke="#fff" stroke-width="1.6" stroke-linecap="round"/>',
t18: '<path d="M12 3.5v16.5M6.5 20h11" stroke="#fff" stroke-width="1.8" stroke-linecap="round"/><path d="M4 7.5h16" stroke="#fff" stroke-width="1.6" stroke-linecap="round"/><path d="M2.5 13.5L5 7.5l2.5 6zM16.5 13.5L19 7.5l2.5 6z"/><path d="M2.5 13.5a2.5 2 0 005 0zM16.5 13.5a2.5 2 0 005 0z"/>',
t19: '<circle cx="8" cy="8" r="3.2"/><circle cx="16.5" cy="10.5" r="2.5"/><path d="M2.5 20c0-4 2.4-6.6 5.5-6.6s5.5 2.6 5.5 6.6zM12.5 20c.2-3 1.8-5 4-5s3.8 2 4 5z"/>',
t20: '<circle cx="12" cy="8" r="4.2"/><path d="M4.5 21c0-4.5 3.4-7.4 7.5-7.4s7.5 2.9 7.5 7.4z"/><circle cx="10.2" cy="8.3" r="1.3" fill="none" stroke="rgba(0,0,0,.3)" stroke-width=".9"/><circle cx="13.8" cy="8.3" r="1.3" fill="none" stroke="rgba(0,0,0,.3)" stroke-width=".9"/><path d="M8.4 4.6c1.2-1.4 6-1.4 7.2 0" fill="none" stroke="#fff" stroke-width="1.6" stroke-linecap="round"/>',
t21: '<path d="M4 13a8 8 0 0116 0" fill="none" stroke="#fff" stroke-width="2"/><rect x="2.5" y="12.5" width="5" height="7.5" rx="2"/><rect x="16.5" y="12.5" width="5" height="7.5" rx="2"/><path d="M12 9.5v4.2a1.6 1.6 0 11-1-1.5V9.5h3.2" fill="none" stroke="#fff" stroke-width="1.4"/>',
t22: '<path d="M12 2.8a6.5 6.5 0 00-3.8 11.8V17h7.6v-2.4A6.5 6.5 0 0012 2.8z"/><rect x="8.6" y="18.2" width="6.8" height="2.6" rx="1.2"/><path d="M10.4 8.4l3.2 3.2M13.6 8.4l-3.2 3.2" stroke="rgba(0,0,0,.25)" stroke-width="1.5" stroke-linecap="round"/>',
t23: '<circle cx="12" cy="12" r="2.6" fill="rgba(0,0,0,.18)"/><path d="M12 9.4c-1.4-4 1.4-6.4 0-6.4s1.4 2.4 0 6.4z"/><ellipse cx="12" cy="5.8" rx="2.6" ry="3.6"/><ellipse cx="12" cy="18.2" rx="2.6" ry="3.6"/><ellipse cx="5.8" cy="12" rx="3.6" ry="2.6"/><ellipse cx="18.2" cy="12" rx="3.6" ry="2.6"/><circle cx="12" cy="12" r="2.4" fill="#FFE07A"/>',
t24: '<path d="M4 4h6v2.2a2 2 0 103.6 0V4H20v6h-2.2a2 2 0 100 3.6H20V20h-6v-2.2a2 2 0 10-3.6 0V20H4v-6.4h2.2a2 2 0 100-3.6H4z"/>',
t25: '<circle cx="12" cy="12" r="8.6"/><circle cx="9" cy="10" r="1.2" fill="rgba(0,0,0,.3)"/><circle cx="15" cy="10" r="1.2" fill="rgba(0,0,0,.3)"/><path d="M8 13.6c1.8 2.8 6.2 2.8 8 0" fill="none" stroke="rgba(0,0,0,.3)" stroke-width="1.6" stroke-linecap="round"/>',
t26: '<path d="M3 5h2.4l2.3 10.2h10.4L20.5 8H6.6"/><path d="M3 5h2.4l2.3 10.2h10.4L20.5 8H6.6" fill="none" stroke="#fff" stroke-width="1.8" stroke-linejoin="round"/><circle cx="9" cy="19" r="1.7"/><circle cx="16.5" cy="19" r="1.7"/>',
t27: '<rect x="3.5" y="9" width="17" height="11.5" rx="2"/><rect x="2.5" y="6" width="19" height="4" rx="1.5"/><path d="M12 6v14.5" stroke="rgba(0,0,0,.2)" stroke-width="1.6"/><path d="M12 6c-1.5-3.5-5.5-3-4 0M12 6c1.5-3.5 5.5-3 4 0" fill="none" stroke="#fff" stroke-width="1.6"/>',
t28: '<path d="M3 9.5l9-5.5 9 5.5V20H3z"/><rect x="7" y="13" width="4" height="4" rx=".8" fill="rgba(0,0,0,.18)"/><rect x="13" y="13" width="4" height="7" rx=".8" fill="rgba(0,0,0,.18)"/>',
t29: '<rect x="2.5" y="7.5" width="19" height="10" rx="5"/><path d="M7 10.5v4M5 12.5h4" stroke="rgba(0,0,0,.3)" stroke-width="1.5" stroke-linecap="round"/><circle cx="15.5" cy="11.3" r="1.1" fill="rgba(0,0,0,.3)"/><circle cx="17.8" cy="13.6" r="1.1" fill="rgba(0,0,0,.3)"/>',
t30: '<rect x="5" y="3.5" width="14" height="17.5" rx="2.5"/><rect x="9" y="2" width="6" height="3.4" rx="1.2" fill="rgba(0,0,0,.2)"/><path d="M8 9.5l1 1 2-2M8 14.5l1 1 2-2M13 9.8h3.5M13 14.8h3.5" fill="none" stroke="rgba(0,0,0,.28)" stroke-width="1.4" stroke-linecap="round"/>'
};
function csTI(x) { return CS_TI[x.id] ? '<svg viewBox="0 0 24 24" fill="#fff" aria-hidden="true">' + CS_TI[x.id] + '</svg>' : CS_ICO[x.group]; }
/* 头像:59 张人设照轮着取,同一张卡/行 3 个不重复,相邻两处也不撞(模拟,AGENTS.md 12b,12-31 复核) */
var CS_AVP = (function () { var a = [], i; for (i = 1; i <= 13; i++) a.push('k' + (i < 10 ? '0' : '') + i); for (i = 1; i <= 22; i++) a.push('m' + (i < 10 ? '0' : '') + i); for (i = 1; i <= 14; i++) a.push('p' + (i < 10 ? '0' : '') + i); for (i = 1; i <= 10; i++) a.push('s' + (i < 10 ? '0' : '') + i);
for (i = a.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)), t = a[i]; a[i] = a[j]; a[j] = t; } return a; })();
var csAvK = 0;
function csAvs(n) { var h = '<span class="cav">'; for (var i = 0; i < n; i++) h += '<img src="../assets/img/mom/' + CS_AVP[csAvK++ % CS_AVP.length] + '.jpg" alt="" loading="lazy">'; return h + '</span>'; }
var CS_SEC = { quiz: ['', '查漏补缺,温和掌握孕产育儿知识', 2], psy: ['', '看见情绪,也看见关系', 2], game: ['', '挑战一下,看能拿什么称号', 2], shop: ['', '测测你给娃买东西、挑东西是哪种风格', 2] };
/* 11-04 用户:「每个测试的背景图要做匹配的图片,不要同样的背景色;按组区分色块、组内统一」→ 每个测试一张插画(ceshi/cv/tNN.webp),
色调跟组走:常识小测暖桃 / 趣味心理薰衣草紫 / 趣味闯关薄荷绿 / 好物配置天蓝;画面上半留白放标题。列表行的小方块也换成同一张图。 */
var CS_CV_V = 3; /* 同日二改:用户嫌插画乱 → 换真实风景照(按组选色调)+ 同色柔光遮罩 */
function csRowHTML(x, done, i) {
var d = done[x.id], who = (x.sub || '').split('·')[0].trim();
return '<button type="button" class="csr ' + CS_GPAL[x.group] + '" data-test="' + x.id + '"><span class="csr-i s' + (i % 3) + ' has-bg" style="background-image:url(ceshi/cv/' + x.id + '.webp?v=' + CS_CV_V + ')"></span>' +
'<span class="csr-m"><b>' + esc(x.title.replace(/^测一测|/, '')) + '</b><small>' + esc(who) + ' · ' + x.n + ' 题' + csAvs(3) + '<i>' + gcTestedText(x.id) + '</i></small></span>' +
'<em>' + (d ? '再测' : '去测') + '</em></button>';
}
var CS_PAL = ['pa', 'pb', 'pc', 'pd', 'pe', 'pf']; /* 6 套封面配色轮流:蜜桃 / 薰衣草 / 奶油蓝 / 浅紫 / 薄荷 / 杏橙 */
var CS_BLOB = '<svg class="cbl" viewBox="0 0 100 100" preserveAspectRatio="none" aria-hidden="true"><path class="b1" d="M58 0C66 14 80 18 100 14V0z"/><path class="b2" d="M0 72C18 60 30 78 46 86S80 84 100 70V100H0z"/><path class="b3" d="M0 0H28C20 12 8 16 0 30z"/></svg>';
/* 11-04 用户:「封面下面那行完整标题放到图片上」→ 封面大字由短名改成完整标题,封面下只留人数 */
/* 11-04 用户:「几个模块颜色都一样,分不出来;图片样式可以一样,UI 按模块变一下」→ 配色 / 封面色块形状按分组走,不再全局轮换:
常识小测 蜜桃橙、趣味心理 薰衣草紫、趣味闯关 薄荷绿、好物配置 天空蓝;四组各一种色块形状(CS_BLOBS),列表行同色。 */
var CS_GPAL = { quiz: 'gq', psy: 'gp', game: 'gg', shop: 'gs' };
var CS_BLOBS = {
quiz: CS_BLOB,
psy: '<svg class="cbl" viewBox="0 0 100 100" preserveAspectRatio="none" aria-hidden="true"><circle class="b1" cx="86" cy="10" r="22"/><path class="b2" d="M0 78C22 70 40 92 62 88S90 74 100 80V100H0z"/><circle class="b3" cx="10" cy="24" r="12"/></svg>',
game: '<svg class="cbl" viewBox="0 0 100 100" preserveAspectRatio="none" aria-hidden="true"><path class="b1" d="M70 0L100 0 100 34z"/><path class="b2" d="M0 100L0 70 34 100z M60 100L100 62 100 100z"/><path class="b3" d="M0 0H22L0 22z"/></svg>',
shop: '<svg class="cbl" viewBox="0 0 100 100" preserveAspectRatio="none" aria-hidden="true"><rect class="b1" x="64" y="-8" width="44" height="30" rx="14"/><rect class="b2" x="-10" y="76" width="120" height="34" rx="16"/><rect class="b3" x="-6" y="6" width="26" height="14" rx="7"/></svg>'
};
/* 11-04 用户:「宫格卡随机几张,在『开始测试』下面、白边上面加一行『谁测出了什么结果』;有这行的卡底下不要头像,只留 N 人测过」
每组宫格(最多 6 张)随机挑 2~3 张(11-04 二改:1~2 张);昵称 / 头像同战报那批(模拟,AGENTS.md 12b),结果名取 meta.js GC_RES 真实结果名;同一屏昵称不重复 */
var ckHlUsed = [];
function ckHlLine(x) {
var rs = (window.GC_RES || {})[x.id]; if (!rs || !rs.length) return '';
var c = [], k; for (k = 0; k < CL_NM.length; k++) if (ckHlUsed.indexOf(k) < 0) c.push(k);
if (!c.length) { ckHlUsed = []; c = CL_NM.map(function (_, j) { return j; }); }
/* 一条备 3 句(3 个不同的人 + 不同结果),定时往上滚,同首页百宝箱 lv-i */
var it = [], n = Math.min(3, c.length), rr = rs.slice().sort(function () { return Math.random() - .5; });
while (it.length < n) {
k = c.splice(Math.floor(Math.random() * c.length), 1)[0]; ckHlUsed.push(k);
it.push('<span class="hl-i' + (it.length ? '' : ' on') + '"><img src="../assets/img/mom/' + CL_AV[k % CL_AV.length] + '.jpg" alt="" loading="lazy"><u>' + esc(CL_NM[k]) + '</u><span>测出「' + esc(rr[it.length % rr.length]) + '」</span></span>');
}
return '<span class="ck-hl">' + it.join('') + '</span>';
}
var ckHlT = 0;
function ckHlRun() {
clearInterval(ckHlT);
ckHlT = setInterval(function () {
[].forEach.call(document.querySelectorAll('.ck-hl'), function (h, j) {
var l = h.children, i, cur = 0; if (l.length < 2) return;
for (i = 0; i < l.length; i++) if (l[i].classList.contains('on')) cur = i;
setTimeout(function () {
l[cur].classList.remove('on'); l[cur].classList.add('up');
var nx = l[(cur + 1) % l.length]; nx.classList.remove('up'); nx.classList.add('on');
setTimeout(function () { l[cur].classList.remove('up'); }, 500);
}, j * 600);
});
}, 3600);
}
function csCardHTML(x, done, i, hl) {
var d = done[x.id], who = (x.sub || '').split('·')[0].trim(), hs = hl ? ckHlLine(x) : '';
var top = byHot(TM).slice(0, 3).map(function (y) { return y.id; }).indexOf(x.id);
return '<button type="button" class="ck ' + CS_GPAL[x.group] + ' has-bg" data-test="' + x.id + '"><span class="cv"><img class="ck-bg" src="ceshi/cv/' + x.id + '.webp?v=' + CS_CV_V + '" alt="" loading="lazy" decoding="async"><i class="ck-wash"></i>' +
(top >= 0 ? '<i class="ck-top t' + (top + 1) + '">TOP' + (top + 1) + '</i>' : '') +
'<i class="ck-wm">' + csTI(x) + '</i><b>' + esc(x.title.replace(/^测一测|/, '')) + '</b><small>' + esc(who) + ' · ' + x.n + ' 题</small><em>' + (d ? '再测一次' : '开始测试') + '</em>' + (d ? '<i class="dn">已测</i>' : '') + hs + '</span>' +
'<span class="cnn">' + (hs ? '' : csAvs(3)) + '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12.6 2.5c.4 3-1.6 4.6-3 6.2C8 10.4 7 12 7 14.3A5 5 0 0012 19.5a5 5 0 005-5.2c0-2-1-3.6-1.9-4.6-.2 1.3-.9 2.2-1.9 2.6.6-3.4-.2-7-.6-9.8z" fill="currentColor"/></svg>' + gcTestedText(x.id) + '</span></button>';
}
/* ---------- 11-04 用户:「测试列表页太安静,要热闹、有创意」 ----------
① banner 下一条「此刻 N 人正在测」(红点呼吸、数字隔 2 秒小跳)+ 战报滚动「谁 刚测出「结果」· 哪个测试」(点了进那个测试);
② 右边「手气测」骰子:随机挑一个还没测过的测试,骰子转一下就进;
③ 卡片封面左上「● N 人在测」,隔几秒随机两张卡数字跳;全站最热 3 个封面右上 TOP1~3 角标;卡片进屏错落弹入、「开始测试」按钮定时扫光。
人数 / 昵称 / 头像都是模拟(同「N 人测过」口径,AGENTS.md 12b,12-31 复核);战报只写「测出了哪个结果」,结果名取 meta.js GC_RES(真实结果名)。 */
var CL_NM = ['小满妈妈', '糯米团子', '橙子不酸', '鹿鹿呀', '安安的妈', '豆包本包', '一只小葵', '阿圆', '栗子酱', '桃桃乌龙', '芝麻汤圆', '晴天娃娃',
'果冻布丁', '岁岁平安', '叮当妈', '饭团子', '奶糖不甜', '小鱼干', '朵朵妈咪', '暖暖', '布丁要长大', '花卷儿', '柚子茶', '星星的妈',
'甜甜圈', '小熊软糖', '一颗青梅', '冬冬妈', '可乐加冰', '麦穗儿', '云朵朵', '橘子汽水', '乐乐的妈', '荔枝', '蜜桃乌龙', '小葡萄'];
var CL_AV = ['p02', 'm05', 'p05', 'm12', 'k04', 'p09', 'm16', 'p11', 'm07', 'k10', 'p03', 'm19', 'p13', 'm02', 'k06', 'p06', 'm10', 'p12', 'm21', 'p07', 'm04', 'k12', 'p14', 'm15',
'p01', 'm01', 'k01', 'm03', 'p04', 'm06', 'k02', 'm08', 'p08', 'm09', 'k03', 'm11'];
/* 11-04 用户:「手气测挺好玩,要明显、让用户玩起来」→ 独立一块「摇一摇」:骰子闲时晃一晃;点了骰子翻滚、标题像老虎机一样转、越转越慢停在一个没测过的测试上,撒彩点后进入 */
var DICE_P = { 1: [[12, 12]], 2: [[8, 8], [16, 16]], 3: [[7, 7], [12, 12], [17, 17]], 4: [[8, 8], [16, 8], [8, 16], [16, 16]], 5: [[7, 7], [17, 7], [12, 12], [7, 17], [17, 17]], 6: [[8, 6.5], [16, 6.5], [8, 12], [16, 12], [8, 17.5], [16, 17.5]] };
function diceSVG(n) {
return '<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="2" y="2" width="20" height="20" rx="5.5" fill="#fff"/><rect x="2" y="17" width="20" height="5" rx="2.5" fill="#EDE6FF" opacity=".9"/>' +
DICE_P[n].map(function (c) { return '<circle cx="' + c[0] + '" cy="' + c[1] + '" r="2" fill="' + (n === 1 ? '#F0453A' : '#6A4BE0') + '"/>'; }).join('') + '</svg>';
}
function csNowBase() { return Math.round(TM.reduce(function (a, x) { return a + gcTested(x.id); }, 0) / 1150); }
function csLiveHTML() {
var left = TM.length - Object.keys(csDone()).filter(function (k) { return TM.some(function (x) { return x.id === k; }); }).length;
return '<button type="button" class="luck" id="csvGo"><span class="luck-dc" id="csdDc">' + diceSVG(5) + '</span><span class="luck-dc d2">' + diceSVG(3) + '</span>' +
'<span class="luck-t"><b>不知道测哪个?摇一下</b><span class="luck-w"><span id="csdW">' + (left > 0 ? '还有 ' + left + ' 个没测过,交给手气' : '全部测完啦,再摇一个重温') + '</span></span></span>' +
'<em class="luck-b">摇一摇</em><i class="luck-fx" id="csdFx"></i></button>' +
'<div class="csv"><div class="csv-n"><i class="csv-dot"></i>此刻 <b id="csvN" class="num">' + csNowBase().toLocaleString() + '</b> 人正在测<span class="csv-av" id="csvAv">' + csAvs(5) + '</span></div>' +
'<div class="csv-r" id="csvR"></div></div>';
}
/* 11-04 用户:「往下滑时『摇一摇』浮在最上面,让用户随时能用」→ 大卡滑出屏幕后,顶栏下面浮一条小的摇一摇(点了同样全屏摇号) */
var luckIO = null;
function luckFloat() {
var fl = document.getElementById('luckFl');
if (!fl) {
fl = document.createElement('button'); fl.type = 'button'; fl.id = 'luckFl'; fl.className = 'luck-fl';
fl.innerHTML = '<span class="luck-fl-d">' + diceSVG(5) + '</span><b>不知道测哪个?</b><em>摇一摇</em>';
fl.addEventListener('click', function () { var g = document.getElementById('csvGo'); if (g) csdRoll(g); });
document.body.appendChild(fl);
}
var tg = document.getElementById('csvGo'); if (!tg || !('IntersectionObserver' in window)) return;
if (luckIO) luckIO.disconnect();
luckIO = new IntersectionObserver(function (es) {
var e = es[0], nav = document.querySelector('#top .nav'), b = nav ? nav.getBoundingClientRect().bottom : 56;
fl.style.top = (Math.max(0, b) + 8) + 'px';
fl.classList.toggle('on', catF === 'ceshi' && !e.isIntersecting && e.boundingClientRect.top < b + 10);
}, { threshold: 0, rootMargin: '-60px 0px 0px 0px' });
luckIO.observe(tg);
}
var csdBusy = false;
/* 11-04 用户:「点摇一摇,整个页面上浮出一个动态效果,结束后再跳到那个测试」→ 全屏浮层:两颗大骰子翻滚 + 老虎机转测试名(越转越慢)→ 落定弹出那个测试的卡(分组配色 + 专属图标)+ 全屏撒彩纸 → 进入 */
/* 11-04 用户:「摇一摇的动效要有音效」→ Web Audio 现合成(不加音频文件):开摇骰子哗啦声、转名字每格一下「嗒」、落定「叮咚」+ 彩纸「啵」;
右上角喇叭可关,记在 mmbox.gc.snd。用户点按钮时才建 AudioContext(微信 / iOS 要求用户手势后才能出声)。 */
var SND = { ctx: null, on: true };
try { SND.on = localStorage.getItem('mmbox.gc.snd') !== '0'; } catch (e) {}
function sndCtx() {
if (!SND.on) return null;
try { if (!SND.ctx) SND.ctx = new (window.AudioContext || window.webkitAudioContext)(); if (SND.ctx.state === 'suspended') SND.ctx.resume(); } catch (e) { return null; }
return SND.ctx;
}
function tone(f, t0, d, type, vol, f2) {
var c = sndCtx(); if (!c) return;
var o = c.createOscillator(), g = c.createGain(), t = c.currentTime + (t0 || 0);
o.type = type || 'sine'; o.frequency.setValueAtTime(f, t); if (f2) o.frequency.exponentialRampToValueAtTime(f2, t + d);
g.gain.setValueAtTime(0, t); g.gain.linearRampToValueAtTime(vol || .2, t + .008); g.gain.exponentialRampToValueAtTime(.0008, t + d);
o.connect(g); g.connect(c.destination); o.start(t); o.stop(t + d + .02);
}
function noise(t0, d, vol, hp) {
var c = sndCtx(); if (!c) return;
var n = Math.floor(c.sampleRate * d), buf = c.createBuffer(1, n, c.sampleRate), ch = buf.getChannelData(0);
for (var i = 0; i < n; i++) ch[i] = (Math.random() * 2 - 1) * Math.pow(1 - i / n, 3);
var s = c.createBufferSource(), f = c.createBiquadFilter(), g = c.createGain(), t = c.currentTime + (t0 || 0);
s.buffer = buf; f.type = 'bandpass'; f.frequency.value = hp || 2400; f.Q.value = 1.2; g.gain.value = vol || .3;
s.connect(f); f.connect(g); g.connect(c.destination); s.start(t);
}
var SFX = {
rattle: function () { for (var i = 0; i < 9; i++) noise(i * .045 + Math.random() * .02, .05, .35, 1800 + Math.random() * 1600); }, /* 骰子在杯里哗啦 */
tick: function (k) { tone(1250 + (k % 2) * 180, 0, .05, 'square', .05); noise(0, .025, .12, 3500); }, /* 转名字「嗒」 */
land: function () { tone(784, 0, .5, 'triangle', .22); tone(1175, .1, .7, 'triangle', .2); tone(1568, .2, .9, 'sine', .12); noise(.02, .18, .25, 900); }, /* 叮咚 + 啵 */
tap: function () { tone(660, 0, .08, 'sine', .12, 990); }
};
/* 11-04 用户:「摇出来以后两个选择:『就它了』或者重新摇」→ 落定后不再自动跳,给两个按钮;重新摇避开刚摇出的那个 */
function csdRoll(btn) {
if (csdBusy) return; csdBusy = true; haptic(); if (btn) btn.classList.add('roll');
var dn = csDone(), last = null, pk = null;
var ov = document.createElement('div'); ov.className = 'lko';
ov.innerHTML = '<div class="lko-bg"></div><button type="button" class="lko-x" aria-label="关闭">×</button><button type="button" class="lko-snd' + (SND.on ? '' : ' off') + '" aria-label="音效开关"></button>' +
'<div class="lko-in"><div class="lko-dc"><span class="a">' + diceSVG(6) + '</span><span class="b">' + diceSVG(3) + '</span></div>' +
'<p class="lko-tip">手气摇号中…</p><div class="lko-reel"><span id="lkoR">?</span></div><div class="lko-card" id="lkoC"></div>' +
'<div class="lko-act"><button type="button" class="lko-go">就它了,去测 ›</button><button type="button" class="lko-re">' + diceSVG(5) + '重新摇</button></div></div><div class="lko-fx" id="lkoFx"></div>';
document.body.appendChild(ov); void ov.offsetWidth; ov.classList.add('on');
var R = ov.querySelector('#lkoR'), dcs = ov.querySelectorAll('.lko-dc span');
function close() { ov.classList.remove('on'); setTimeout(function () { if (ov.parentNode) ov.parentNode.removeChild(ov); }, 260); csdBusy = false; if (btn) btn.classList.remove('roll', 'hit'); }
function roll() {
var pool = TM.filter(function (x) { return !dn[x.id] && x !== last; }); if (!pool.length) pool = TM.filter(function (x) { return x !== last; });
pk = pool[Math.floor(Math.random() * pool.length)];
var i = 0, steps = 18;
ov.classList.remove('hit', 'done'); ov.querySelector('.lko-tip').textContent = '手气摇号中…'; ov.querySelector('#lkoC').innerHTML = ''; ov.querySelector('#lkoFx').innerHTML = '';
SFX.rattle();
setTimeout(function spin() {
var end = i >= steps, t = end ? pk : TM[Math.floor(Math.random() * TM.length)];
R.className = ''; void R.offsetWidth; R.className = end ? 'hit' : 'sp'; R.textContent = CS_SHORT[t.id] || t.title;
[].forEach.call(dcs, function (d) { d.innerHTML = diceSVG(1 + Math.floor(Math.random() * 6)); });
if (!end) { SFX.tick(i); if (i % 3 === 0 && navigator.vibrate) try { navigator.vibrate(8); } catch (e) {} i++; setTimeout(spin, 45 + i * i * 1.15); return; }
ov.classList.add('hit'); haptic(); SFX.land();
ov.querySelector('.lko-tip').textContent = '摇到了!';
ov.querySelector('#lkoC').innerHTML = '<div class="ck ' + CS_GPAL[pk.group] + '"><span class="cv">' + (CS_BLOBS[pk.group] || CS_BLOB) + '<i class="ck-wm">' + csTI(pk) + '</i><i class="lko-ic">' + csTI(pk) + '</i>' +
'<b>' + esc(pk.title.replace(/^测一测|/, '')) + '</b><small>' + TG[pk.group] + ' · ' + pk.n + ' 题</small></span></div>';
var fx = ov.querySelector('#lkoFx'), cols = ['#FF8A65', '#9A7FE0', '#3FAE7A', '#4E8DE6', '#FFC94D', '#F0453A', '#FF8FB1'], h = '';
for (var k = 0; k < 46; k++) {
var ag = Math.random() * 6.283, r = 120 + Math.random() * 200;
h += '<i style="--x:' + Math.round(Math.cos(ag) * r) + 'px;--y:' + Math.round(Math.sin(ag) * r - 60) + 'px;--r:' + Math.round(Math.random() * 720) + 'deg;background:' + cols[k % 7] + ';animation-delay:' + Math.round(Math.random() * 120) + 'ms;' + (k % 3 ? '' : 'border-radius:50%;') + '"></i>';
}
fx.innerHTML = h;
setTimeout(function () { ov.classList.add('done'); }, 380); /* 卡片弹完再出按钮 */
last = pk;
}, 260);
}
ov.addEventListener('click', function (e) {
if (e.target.closest('.lko-go')) { SFX.tap(); location.href = ceshiURL(pk.id, true); return; }
if (e.target.closest('.lko-re')) { if (!ov.classList.contains('done')) return; haptic(); roll(); return; }
if (e.target.closest('.lko-x')) { close(); return; }
var sb = e.target.closest('.lko-snd');
if (sb) { SND.on = !SND.on; sb.classList.toggle('off', !SND.on); try { localStorage.setItem('mmbox.gc.snd', SND.on ? '1' : '0'); } catch (x) {} if (SND.on) SFX.tap(); }
});
roll();
}
window.addEventListener('pageshow', function () { csdBusy = false; [].forEach.call(document.querySelectorAll('.lko'), function (o) { o.parentNode.removeChild(o); }); var b = document.getElementById('csvGo'); if (b) { b.classList.remove('roll', 'hit'); var bb = b.querySelector('.luck-b'); if (bb) bb.textContent = '摇一摇'; } });
var csvT = 0, csvI = 0, csvRec = [], csvRecT = [];
function csvOne() {
var R = window.GC_RES || {}, ids = TM.filter(function (x) { return R[x.id] && R[x.id].length; });
if (!ids.length) return '';
var tp = ids.filter(function (x) { return csvRecT.indexOf(x.id) < 0; }); if (tp.length) ids = tp;
var t = ids[Math.floor(Math.random() * ids.length)], rs = R[t.id], r = rs[Math.floor(Math.random() * rs.length)], k, c = [];
csvRecT.push(t.id); if (csvRecT.length > 6) csvRecT.shift(); /* 最近 6 条不出同一个测试 */
for (k = 0; k < CL_NM.length; k++) if (csvRec.indexOf(k) < 0) c.push(k);
k = c[Math.floor(Math.random() * c.length)]; csvRec.push(k); if (csvRec.length > 14) csvRec.shift(); /* 同屏 3 行 + 最近 14 个人不重复 */
return '<button type="button" class="csv-i" data-test="' + t.id + '"><img src="../assets/img/mom/' + CL_AV[k] + '.jpg" alt="" width="22" height="22">' +
'<span><em>' + esc(CL_NM[k]) + '</em>刚测出<b>「' + esc(r) + '」</b></span><small>' + esc(CS_SHORT[t.id] || '') + '</small></button>';
}
/* 11-04 用户:「此刻正在测下面一行太少,最多三行滚动」→ 同屏 3 行,新的一条从底下推上来,最上面那条淡出 */
var CSV_H = 30;
function csvLay(b) { [].forEach.call(b.querySelectorAll('.csv-i:not(.gone)'), function (el, i) { el.style.transform = 'translateY(' + i * CSV_H + 'px)'; el.style.opacity = i > 2 ? 0 : 1; }); }
function csLiveRun() {
clearInterval(csvT);
var box = $('#csvR'); if (!box) return;
box.innerHTML = csvOne() + csvOne() + csvOne(); csvLay(box);
var base = csNowBase(), n = base, tick = 0;
csvT = setInterval(function () {
if (document.hidden || !document.getElementById('csvR')) return;
tick++;
if (tick % 2 === 0) { /* 每 2.6 秒推上来一条 */
var b = document.getElementById('csvR'), first = b.querySelector('.csv-i:not(.gone)');
b.insertAdjacentHTML('beforeend', csvOne());
var nw = b.lastElementChild; nw.style.transform = 'translateY(' + 3 * CSV_H + 'px)'; nw.style.opacity = 0; void nw.offsetWidth;
if (first) { first.classList.add('gone'); first.style.transform = 'translateY(' + -CSV_H + 'px)'; first.style.opacity = 0; setTimeout(function () { if (first.parentNode) first.parentNode.removeChild(first); }, 500); }
csvLay(b);
}
if (tick % 3 === 0) { /* 头像堆换一个人 */
var av = document.querySelectorAll('#csvAv img'); if (av.length) { var im = av[Math.floor(Math.random() * av.length)]; im.classList.add('sw'); setTimeout(function () { im.src = '../assets/img/mom/' + CS_AVP[csAvK++ % CS_AVP.length] + '.jpg'; im.classList.remove('sw'); }, 220); }
}
n = Math.max(Math.round(base * .93), Math.min(Math.round(base * 1.07), n + Math.round((Math.random() - .45) * 14)));
var e = document.getElementById('csvN'); if (e) { e.textContent = n.toLocaleString(); e.classList.remove('bp'); void e.offsetWidth; e.classList.add('bp'); }
}, 1300);
}
function csFx() { /* 卡片进屏错落弹入 */
var els = document.querySelectorAll('#more .ck, #more .csr');
if (!('IntersectionObserver' in window)) return;
var io = new IntersectionObserver(function (es) {
var k = 0;
es.forEach(function (e) { if (!e.isIntersecting) return; e.target.style.animationDelay = (k++ * 70) + 'ms'; e.target.classList.add('pop-in'); io.unobserve(e.target); });
}, { threshold: .15 });
[].forEach.call(els, function (el) { el.classList.add('pre'); io.observe(el); });
}
function ceshiListHTML() {
var done = csDone(), gs = ['quiz', 'psy', 'game', 'shop'].filter(function (g) { return !tGrp || tGrp === g; }), k = 0; csAvK = 0; ckHlUsed = [];
return '<div class="csl">' + gs.map(function (g, gi) {
var l = byHot(TM.filter(function (x) { return x.group === g; })); if (!l.length) return '';
var c = CS_SEC[g], nc = Math.min(6, l.length - l.length % 2);
return (gi ? '<div class="csd"><span>' + (gi === 1 && !tGrp ? '点上方标签,可以只看某一类' : '继续往下看') + '</span></div>' : '') +
'<section class="csg g-' + g + '"><i class="csg-deco" aria-hidden="true">' + CS_ICO[g] + '</i><div class="csg-h"><b><i class="csg-ic">' + CS_ICO[g] + '</i>' + TG[g] + '<span class="csg-n">' + csAvs(4) + Math.round(l.reduce(function (a, x) { return a + gcTested(x.id); }, 0) / 1e4) + ' 万人测过</span></b><small>' + c[1] + '</small></div>' +
'<div class="ckg c2">' + (function () {
var ix = l.slice(0, nc).map(function (_, j) { return j; }).sort(function () { return Math.random() - .5; }).slice(0, nc >= 4 ? 1 + Math.floor(Math.random() * 2) : 1); /* 11-04 二改:每组 1~2 张,最多 2 */
return l.slice(0, nc).map(function (x, j) { return csCardHTML(x, done, k++, ix.indexOf(j) >= 0); }).join('');
})() + '</div>' +
(l.length > nc ? '<div class="csrl">' + l.slice(nc).map(function (x) { return csRowHTML(x, done, k++); }).join('') + '</div>' : '') + '</section>';
}).join('') + '</div>';
}
function ceshiHead() { /* 11-02 用户同意:介绍卡压成一行,让热度榜进第一屏 */
return '<div class="csh"><svg class="ic"><use href="#i-spark"/></svg><b>孕育测一测</b><span>累计 ' + Math.round(TM.reduce(function (a, x) { return a + gcTested(x.id); }, 0) / 1e4) + ' 万人次参与</span></div>';
}
function ceshiFh(fh) {
fh.className = 'lvw k-ceshi';
var all = [['', '全部', TM.length]].concat(['quiz', 'psy', 'game', 'shop'].map(function (g) { return [g, TG[g], TM.filter(function (x) { return x.group === g; }).length]; }));
/* 11-03 参考图:顶部一排分类小方签(不写数量),选中的高亮 */
fh.innerHTML = '<div class="cst">' + all.map(function (x) { return '<button type="button" data-tg="' + x[0] + '"' + (tGrp === x[0] ? ' class="on"' : '') + '>' + x[1] + '</button>'; }).join('') + '</div>';
}
function rewardHTML(sm) {
return '<button type="button" class="rw' + (sm ? ' sm' : '') + '" data-rule="1"><span class="gf"><svg class="ic"><use href="#i-gift"/></svg></span>' +
'<span class="rt"><small>参与话题投稿 · 被选中奖励</small><b>' + REWARD + '</b></span><span class="go">怎么参与<svg class="ic" style="width:12px;height:12px"><use href="#i-right"/></svg></span></button>';
}
/* 热门话题:带 hot 的排前面,其余按原顺序;跟着一级分类过滤 */
function hotList() {
var l = T.filter(inCat), hot = l.filter(function (t) { return t.hot; });
if (!catF) { /* 「全部」下四块轮流排,避免前几张全是同一块 */
var by = CAT_ORDER.map(function (c) { return hot.filter(function (t) { return t.cat === c; }); }), rr = [];
for (var r = 0; r < 10; r++) by.forEach(function (x) { if (x[r]) rr.push(x[r]); });
hot = rr;
}
return hot.concat(l.filter(function (t) { return !t.hot; }));
}
function renderHead() {
var t = TBY[cur], el = $('#head'), fh = $('#fh');
var fl0 = document.getElementById('luckFl'); if (fl0) fl0.classList.remove('on');
if (catF === 'ceshi') { el.innerHTML = cbnHTML('ceshi') + csLiveHTML(); ceshiFh(fh); csLiveRun(); luckFloat(); return; } /* 原一行介绍 ceshiHead 并进 banner */
if (!t) {
var hl = hotList();
el.innerHTML = (catF ? cbnHTML(catF) : qifuHTML()) + /* 祈福树只在「全部」 */
'<div class="sh"><svg class="fire"><use href="#i-fire"/></svg><h2>热门话题</h2><button type="button" class="more" data-all="1">全部<svg class="ic" style="width:13px;height:13px"><use href="#i-right"/></svg></button></div>' +
/* 11-02 用户:「热门话题不要一块一块的,改成井号、偏列表的形式」→ 排行列表:名次 + #话题# + 一行简介 + 篇数/热,右侧「参与」
投稿奖励从顶部大横幅挪到这里当列表头一行(用户:「30 现金 + 500 兜豆看放哪」→ 跟「参与」放一起,点了看规则) */
'<div class="htl"><button type="button" class="rwl" data-rule="1"><svg class="ic"><use href="#i-gift"/></svg><span>投稿被选中得 ' + REWARD + '</span><b>怎么参与 ›</b></button>' + hl.slice(0, 4).map(function (x, i) { /* 11-02 用户:热门话题 6 → 4 个,去掉下面浅色小字 */
return '<div class="hr k-' + x.cat + '" data-t="' + x.id + '" role="button"><i class="no' + (i < 3 ? ' t' + i : '') + '">' + (i + 1) + '</i>' +
'<span class="hm"><b><em>#</em>' + esc(x.name) + '<em>#</em></b></span>' +
'<button type="button" class="jn" data-join="' + x.id + '">参与</button></div>';
}).join('') + '<button type="button" class="hall" data-all="1">查看全部话题 ›</button></div>';
if (catF) { fhLevels(fh); return; }
fh.className = 'sh';
/* 11-03 用户:广场里不显示具体有多少篇、多少个话题 → 篇数 / 话题数一律不露 */
fh.innerHTML = '<h2>大家在聊</h2><small>孕妈们的真实分享</small>';
return;
}
var d = D[t.id] || {};
el.innerHTML = '<div class="th k-' + t.cat + '"><i class="wm" aria-hidden="true">' + esc(t.g) + '</i><button type="button" class="x" data-t="" aria-label="看全部"><svg class="ic"><use href="#i-x"/></svg></button>' +
'<div class="bc"><button type="button" data-t="">' + kbHTML(t.cat).replace('</span>', ' ›</span>') + '</button><span>话题</span></div>' +
'<h2><em>#</em>' + esc(t.name) + '<em>#</em></h2><p>' + esc(d.desc || '') + '</p>' +
'<div class="tf"><button type="button" class="join" data-join="' + t.id + '"><svg class="ic"><use href="#i-plus"/></svg>参与话题</button><button type="button" class="sw" data-all="1">换个话题</button></div></div>';
/* 11-02 用户:「话题页比较乱」→ 去掉投稿奖励横幅和同分类话题胶囊,只留一行标题 */
fh.className = 'sh';
fh.innerHTML = '<h2>这个话题下的分享</h2>';
}
/* 11-02 用户:「选了家庭婚姻下一个话题,看着像这块就这几篇,层次感没出来」→ 选了分类 / 话题时,列表上方固定一行「分类 · N 个话题 · 共 M 篇」+ 该分类全部话题胶囊(带篇数),当前话题高亮,「全部」回分类 */
var cntT = function (id) { return NOTES.filter(function (n) { return n.t === id; }).length; };
function fhLevels(fh) {
var tl = hotList().filter(function (x) { return cntT(x.id); }), all = 0;
tl.forEach(function (x) { all += cntT(x.id); });
fh.className = 'lvw k-' + catF;
fh.innerHTML = '<div class="lv"><h2>' + CATS.filter(function (c) { return c[0] === catF; })[0][1] + '</h2>' +
(cur ? '<button type="button" class="ba" data-t="">看这块全部 ›</button>' : '') + '</div>' +
'<div class="tcs"><button type="button" data-t=""' + (cur ? '' : ' class="on"') + '>全部</button>' +
tl.map(function (x) { return '<button type="button" data-t="' + x.id + '"' + (cur === x.id ? ' class="on"' : '') + '>#' + esc(x.name) + '#</button>'; }).join('') + '</div>';
var on = fh.querySelector('.tcs .on'); if (on && cur) fh.querySelector('.tcs').scrollLeft = Math.max(0, on.offsetLeft - 60);
}
function renderFeed() {
var list = cur ? NOTES.filter(function (n) { return n.t === cur; }) : MIXED.filter(function (n) { return inCat(TBY[n.t]); });
/* 11-02 按孕周段排:同阶段孕妈的帖子为主、穿插过来人(GC_ORDER 在 feed.js);真实投稿仍排最前;孕周由首页写进 mmbox.gcwk.v1 */
if (window.GC_ORDER) list = list.filter(function (n) { return n.real; }).concat(window.GC_ORDER(list.filter(function (n) { return !n.real; }), UBAND));
var wf = $('#wf'), cols = wf.children;
cols[0].innerHTML = ''; cols[1].innerHTML = '';
var cw = cols[0].clientWidth || 175;
wf.style.setProperty('--cw', cw + 'px');
/* 真瀑布流:每张卡放进当前更矮的那一列(逐张量高,标题一行/两行也算进去) */
var hs = [0, 0], tmp = document.createElement('div'), lastTx = [false, true], txN = [0, 1]; /* 11-02 用户:图上带字的卡至少占 40% → 每列「带字 / 不带字」交替(测试卡算不带字),两列错开一格,带字的在压大字 ov / 贴纸字 tg 间轮换;整体约 45% */
/* 11-04 用户:「从孕期百宝箱点进来的孕期百问 / 计算器 / 趣味小测试,最上边都要是孕期百宝箱」→ 小程序顶栏取 document.title */
document.title = catF === 'ceshi' ? '孕期百宝箱' : '孕妈广场';
if (catF === 'ceshi') {
$('#more').innerHTML = ceshiListHTML(); csFx(); ckHlRun(); return;
}
/* 「全部」信息流:穿插测试卡 */
if (!cur && !catF && TM.length) {
var dn = csDone(), mixed = [], ci = 0;
/* 测试卡:先出 CS_MIX 精选,再按热度轮完其余测试。
11-03 用户:「笔记里测一测减少一些,已经有测一测模块了」→ 原来第 3 位起每 8 张插 1 张(约 20 张),改成第 6 位起每 30 张插 1 张、最多 3 张 */
var csq = CS_MIX.concat(byHot(TM).map(function (x) { return x.id; }).filter(function (id) { return CS_MIX.indexOf(id) < 0; }));
list.forEach(function (n, k) { if (k >= 6 && (k - 6) % 30 === 0 && ci < 3) { var tid = csq[ci++ % csq.length]; if (TMBY[tid]) mixed.push({ test: TMBY[tid] }); } mixed.push(n); });
list = [{ mine: 1 }].concat(mixed);
}
/* 11-03 用户:切分类有点卡。原来每张卡塞进列里再 offsetHeight 量高,每量一次整页重排;85 张卡在中端机上卡 0.5 秒以上,正好卡在滑入动画中间。
现在:帖子卡高度直接算(封面 = 列宽 × 比例,底部 = 标题 1/2 行 + 作者行,和 .nc 样式对应),只有「我的投稿 / 收藏 / 测试卡」这几种
一次性批量量高;整列拼成字符串一次挂上,每列先出前 14 张,其余等滑入动画走完再补;入场动画只给前 12 张。 */
var tw = cw - 18;
function txtW(t) { var w = 0; for (var i = 0; i < t.length; i++) w += t.charCodeAt(i) > 255 ? 13.6 : 7.4; return w; }
function estH(n, r) { return cw * r + 8 + 9 + (txtW(n.title) > tw ? 2 : 1) * 19.6 + 7 + 18; }
var specials = [];
list.forEach(function (n) {
if (n.mine) specials.push(myCardHTML(), favCardHTML());
else if (n.test) specials.push(testCardHTML(n.test, dn));
});
var spH = [];
if (specials.length) {
var meas = document.createElement('div');
meas.className = 'col'; meas.style.cssText = 'position:absolute;left:0;top:0;width:' + cw + 'px;visibility:hidden;pointer-events:none';
meas.innerHTML = specials.join(''); wf.appendChild(meas);
[].forEach.call(meas.children, function (el) { spH.push(el.offsetHeight); }); /* 一次重排量完 */
wf.removeChild(meas);
}
var out = [[], []], si = 0, nk = 0, k2 = 0;
function anim(h, k) { return k >= 12 ? h.replace('class="nc', 'style="animation:none" class="nc') : h.replace('class="nc', 'style="animation-delay:' + Math.min(k, 10) * 30 + 'ms" class="nc'); }
function add(html, c, h) { out[c].push(anim(html, k2++)); hs[c] += h + 8; }
list.forEach(function (n) {
if (n.mine) { add(specials[si], 0, spH[si++]); add(specials[si], 0, spH[si++]); return; }
if (n.test) { var tc0 = hs[0] <= hs[1] ? 0 : 1; add(specials[si], tc0, spH[si++]); lastTx[tc0] = false; return; }
nk++;
var c = hs[0] <= hs[1] ? 0 : 1, sty = !lastTx[c] && n.photo ? (txN[c]++ % 2 ? 'tg' : 'ov') : '';
lastTx[c] = !!sty;
var r = n.ratio; if (n.photo && sty === 'ov') r = Math.max(r, 1.33); else if (n.photo && sty === 'tg') r = Math.max(r, 1.2);
add(cardHTML(n, !cur, sty), c, estH(n, r));
});
var FIRST = 14, gen = renderFeed.gen = (renderFeed.gen || 0) + 1;
cols[0].innerHTML = out[0].slice(0, FIRST).join(''); cols[1].innerHTML = out[1].slice(0, FIRST).join('');
if (out[0].length > FIRST || out[1].length > FIRST) setTimeout(function () {
if (gen !== renderFeed.gen) return; /* 期间又切了分类,作废 */
cols[0].insertAdjacentHTML('beforeend', out[0].slice(FIRST).join('')); cols[1].insertAdjacentHTML('beforeend', out[1].slice(FIRST).join(''));
}, 450);
/* 话题下帖子看完,接着引到同分类其他话题,避免以为这块只有这几篇 */
var mo = $('#more'), tc = cur && TBY[cur];
if (tc) {
mo.innerHTML = '<button type="button" class="mo k-' + tc.cat + '" data-t=""><small>这个话题就这些啦</small><b>广场里还有更多分享,去看看 ›</b></button>';
} else mo.innerHTML = '';
}
function setQuery(t, n) {
var q = new URLSearchParams(location.search);
if (t) q.set('t', t); else q.delete('t');
if (!t && catF) q.set('c', catF); else q.delete('c'); /* 只选了分类没选话题时记在 ?c=,刷新 / 详情返回还在原分类 */
if (n) q.set('n', n); else q.delete('n');
q.delete('mine'); q.delete('write'); q.delete('fav');
var s = q.toString();
return location.pathname + (s ? '?' + s : '') + location.hash; /* hash(身份)原样保留 */
}
function selectTopic(t, smooth) {
if (!TBY[t]) t = '';
cur = t;
if (t) catF = ''; /* 11-03 分类标签取消:进话题时顶部停在「全部」 */
renderCats(); renderHead(); renderFeed();
history.replaceState(history.state, '', setQuery(cur, ''));
var sc = $('#sc'); if (smooth !== false) sc.scrollTop = 0;
}
$('#cats').addEventListener('click', function (e) {
var b = e.target.closest('button[data-c]');
if (!b || (b.dataset.c === catF && !cur)) return;
if (paneBusy) return;
var o = catOrder(), d = o.indexOf(b.dataset.c) - o.indexOf(catF);
if (!d) { catF = b.dataset.c; haptic(); selectTopic(''); return; }
slideTo(b.dataset.c, d > 0 ? 1 : -1); /* 点标签也滑入,和手势一致 */
});
/* 11-02 用户:「广场首页左右滑动,可以切到家庭婚姻、职场、经验」+「突然就滑过去了,要有动效、让人感觉是被划过去的」
→ 手指横拖时整块内容(#pane)跟手走、顶部胶囊同步往目标分类挪;松手过 22% 屏宽(或甩得快)就整块滑出、换内容、从另一侧滑入;
不够就弹回。第一个 / 最后一个分类往外拖有阻尼。点分类标签也走同一套滑入。横滑列表、弹层里不触发。 */
var paneBusy = false;
function catOrder() { return catF === 'ceshi' ? ['ceshi'] : CATS.map(function (c) { return c[0]; }); } /* 测试列表里左右滑不切走 */
function barBetween(a, b, p) { /* 胶囊在 a、b 两个标签间按进度 p 插值 */
var bar = $('#cats .bar'); if (!bar || !a) return;
var wa = a.offsetWidth - 20, xa = a.offsetLeft + 10, wb = b ? b.offsetWidth - 20 : wa, xb = b ? b.offsetLeft + 10 : xa;
bar.style.transition = 'none';
bar.style.width = (wa + (wb - wa) * p) + 'px'; bar.style.transform = 'translateX(' + (xa + (xb - xa) * p) + 'px)';
}
function slideTo(c, dir) { /* dir 1 = 往左滑(去下一个),-1 = 往右滑 */
var pane = $('#pane'), W = $('#sc').clientWidth;
paneBusy = true; haptic();
pane.style.transition = 'transform .2s cubic-bezier(.4,0,1,1),opacity .2s';
pane.style.transform = 'translateX(' + (-dir * W * .6) + 'px)'; pane.style.opacity = '.15';
var bar = $('#cats .bar'); if (bar) bar.style.transition = '';
catF = c; renderCats();
setTimeout(function () {
selectTopic('');
pane.style.transition = 'none'; pane.style.transform = 'translateX(' + (dir * W * .35) + 'px)';
void pane.offsetWidth;
pane.style.transition = 'transform .38s cubic-bezier(.2,1.25,.4,1),opacity .25s ease-out';
pane.style.transform = 'translateX(0)'; pane.style.opacity = '1';
setTimeout(function () { pane.style.transition = ''; pane.style.transform = ''; pane.style.opacity = ''; paneBusy = false; }, 400);
}, 200);
}
(function () {
var sx = 0, sy = 0, t0 = 0, mode = '', ok = false, dx = 0, sc = $('#sc'), pane = $('#pane');
sc.addEventListener('touchstart', function (e) {
var t = e.touches[0]; sx = t.clientX; sy = t.clientY; t0 = Date.now(); mode = ''; dx = 0;
ok = !paneBusy && e.touches.length === 1 && !e.target.closest('.tcs,.hot,.cats,.cs-l,#sheet,#note,.nd') && !document.body.classList.contains('lock');
}, { passive: true });
sc.addEventListener('touchmove', function (e) {
if (!ok) return;
var t = e.touches[0], mx = t.clientX - sx, my = t.clientY - sy;
if (!mode) {
if (Math.abs(mx) < 8 && Math.abs(my) < 8) return;
mode = Math.abs(mx) > Math.abs(my) * 1.2 ? 'h' : 'v';
if (mode === 'h') pane.style.transition = 'none';
}
if (mode !== 'h') return;
if (e.cancelable) e.preventDefault();
var order = catOrder(), i = order.indexOf(catF), j = i + (mx < 0 ? 1 : -1), W = sc.clientWidth;
var has = j >= 0 && j < order.length;
dx = has ? mx : mx * .28; /* 两头没有下一页:阻尼 */
pane.style.transform = 'translateX(' + dx + 'px)';
pane.style.opacity = String(1 - Math.min(.45, Math.abs(dx) / W * .6));
var bs = $('#cats').querySelectorAll('button[data-c]');
barBetween(bs[i], has ? bs[j] : null, Math.min(1, Math.abs(dx) / W));
}, { passive: false });
sc.addEventListener('touchend', function () {
if (!ok || mode !== 'h') { ok = false; return; }
ok = false;
var order = catOrder(), i = order.indexOf(catF), dir = dx < 0 ? 1 : -1, j = i + dir, W = sc.clientWidth;
var v = Math.abs(dx) / Math.max(1, Date.now() - t0);
if (j >= 0 && j < order.length && (Math.abs(dx) > W * .22 || (v > .5 && Math.abs(dx) > 30))) { slideTo(order[j], dir); return; }
/* 不够:弹回 */
pane.style.transition = 'transform .35s cubic-bezier(.2,1.3,.4,1),opacity .25s';
pane.style.transform = 'translateX(0)'; pane.style.opacity = '1';
var bar = $('#cats .bar'); if (bar) bar.style.transition = ''; moveBar();
setTimeout(function () { if (!paneBusy) { pane.style.transition = ''; pane.style.transform = ''; pane.style.opacity = ''; } }, 360);
}, { passive: true });
sc.addEventListener('touchcancel', function () { if (mode === 'h') { pane.style.transform = ''; pane.style.opacity = ''; moveBar(); } ok = false; }, { passive: true });
})();
$('#fh').addEventListener('click', function (e) {
var tg = e.target.closest('[data-tg]');
if (tg) { tGrp = tg.dataset.tg; haptic(); ceshiFh($('#fh')); renderFeed(); return; }
var b = e.target.closest('[data-t]'); if (!b || b.dataset.t === cur) return;
haptic(); var sl = $('#fh .tcs') ? $('#fh .tcs').scrollLeft : 0;
selectTopic(b.dataset.t, false);
var tc = $('#fh .tcs'); if (tc && !b.dataset.t) tc.scrollLeft = sl;
});
$('#more').addEventListener('click', function (e) { if (e.target.closest('[data-t]')) { haptic(); selectTopic(''); } });
$('#head').addEventListener('click', function (e) {
if (e.target.closest('#qfBanner')) { goQifu(); return; }
var cb = e.target.closest('.cbn[data-test], .csv-i[data-test]'); if (cb) { haptic(); location.href = ceshiURL(cb.dataset.test, true); return; }
var dc = e.target.closest('#csvGo'); if (dc) { csdRoll(dc); return; }
var j = e.target.closest('[data-join]'); if (j) { haptic(); openRule(j.dataset.join); return; }
if (e.target.closest('[data-rule]')) { openRule(''); return; }
if (e.target.closest('[data-all]')) { openTopics(); return; }
var b = e.target.closest('[data-t]'); if (b) { haptic(); selectTopic(b.dataset.t); }
});
/* ---------- 底部弹层:投稿规则 / 全部话题 ---------- */
var sheetOn = '';
function openSheet(kind, html) {
sheetOn = kind; $('#sbd').innerHTML = html; $('#sbd').scrollTop = 0;
$('#mask').classList.add('show'); $('#sheet').classList.add('show');
}
var pickFor = '';
function closeSheet() { sheetOn = ''; $('#mask').classList.remove('show'); $('#sheet').classList.remove('show'); }
function openRule(tid) {
var t = TBY[tid];
openSheet('rule', '<h3>话题投稿有奖</h3>' +
'<div class="rb"><small>投稿被选中,每篇奖励</small><b>' + REWARD + '</b></div>' +
(t ? '<div class="cur-t">你要参与的话题:<b>#' + esc(t.name) + '#</b></div>' : '') +
'<ol class="stp">' +
'<li><b>选一个话题</b><small>在「热门话题」或「全部话题」里挑你有话说的那个</small></li>' +
'<li><b>写下你的真实经历</b><small>家里的暖事、踩过的坑、过来人的经验都可以</small></li>' +
'<li><b>编辑挑选,被选中就发奖励</b><small>选中的故事会展示在孕妈广场,奖励发给作者</small></li></ol>' +
'<button type="button" class="sbtn" data-write="' + (t ? t.id : '') + '">写我的故事</button>' +
'<div class="snote">提交后进入审核,审核结果会在孕妈广场提醒你</div>');
}
function openTopics() {
var grp = function (cat) {
var tl = T.filter(function (t) { return t.cat === cat; });
return '<div class="tl-h">' + kbHTML(cat) + '</div><div class="tl k-' + cat + '">' + tl.map(function (t) {
return '<button type="button" data-pick="' + t.id + '" class="' + (cur === t.id ? 'on' : '') + '"><span><em>#</em>' + esc(t.name) + '<em>#</em></span>' + (t.hot ? '<i>热</i>' : '') + '</button>';
}).join('') + '</div>';
};
openSheet('topics', '<h3>全部话题</h3>' + (catF ? [catF] : []).concat(CAT_ORDER.filter(function (c) { return c !== catF; })).map(grp).join('') +
'<button type="button" class="tl-all" data-pick="">看全部分享</button>');
}
$('#mask').addEventListener('click', closeSheet);
$('#sheet').addEventListener('click', function (e) {
var p = e.target.closest('[data-pick]');
if (p && pickFor === 'compose') { closeSheet(); pickFor = ''; if (p.dataset.pick) setCpTopic(p.dataset.pick); return; }
if (p) { closeSheet(); haptic(); if (!p.dataset.pick) catF = ''; selectTopic(p.dataset.pick); return; }
var w = e.target.closest('[data-write]');
if (w) { closeSheet(); openCompose(w.dataset.write || cur); return; }
if (e.target.closest('[data-mywrite]')) { closeSheet(); openCompose(cur); }
});
/* 卡片:点心形就地点赞,点别处进详情 */
function toggleLike(id) {
if (ME.like[id]) delete ME.like[id]; else ME.like[id] = 1;
save(); haptic();
}
function syncCardLike(id) {
var n = NBY[id];
document.querySelectorAll('.lk[data-like="' + id + '"]').forEach(function (el) {
var on = liked(id);
el.classList.toggle('on', on);
el.innerHTML = '<svg class="ic"><use href="#i-heart' + (on ? '-f' : '') + '"/></svg>' + cfmt(likeN(n));
if (on) { el.classList.remove('pop'); void el.offsetWidth; el.classList.add('pop'); }
});
}
$('#more').addEventListener('click', function (e) {
var ts = e.target.closest('[data-test]');
if (ts) { e.stopPropagation(); haptic(); location.href = ceshiURL(ts.dataset.test, true); }
}, true);
$('#wf').addEventListener('click', function (e) {
if (e.target.closest('[data-mine]')) { haptic(); location.href = mineURL(); return; }
if (e.target.closest('[data-fav]')) { haptic(); openFav(false); return; }
var ts = e.target.closest('[data-test]');
if (ts) { haptic(); location.href = ceshiURL(ts.dataset.test, catF === 'ceshi'); return; }
var lk = e.target.closest('[data-like]');
if (lk) { e.stopPropagation(); toggleLike(lk.dataset.like); syncCardLike(lk.dataset.like); return; }
var c = e.target.closest('.nc');
if (c) openNote(c.dataset.id, true);
});
/* ---------- 详情 ---------- */
var openId = '', pushed = false;
/* 正文按 \n 分段;「1. 」「2、」开头的行当清单项:悬挂缩进、条间距更紧 */
function bodyHTML(s) {
return String(s).split(/\n+/).map(function (p) { return p.trim(); }).filter(Boolean).map(function (p) {
return /^\d{1,2}[.、.]\s*/.test(p) ? '<p class="li">' + esc(p) + '</p>' : '<p>' + esc(p) + '</p>';
}).join('');
}
/* 11-02 用户:自己发的评论也带上孕周(首页写进 mmbox.gcwk.v1;产后显示「宝妈」) */
function myStage() {
try { var g = JSON.parse(localStorage.getItem('mmbox.gcwk.v1') || 'null'); return !g ? '' : g.pp ? '宝妈' : g.w ? '孕 ' + g.w + ' 周' : ''; } catch (e) { return ''; }
}
function commentHTML(c, mine) {
if (mine) {
var st = c.s || myStage();
var mk = c.id && c.st === 'approved' ? 'r:' + c.id : ''; /* 通过了的自己的评论,别人能回复,回复挂在这里 */
return '<div class="ci mine' + (c.st === 'rejected' ? ' rejected' : '') + '"><span class="me">我</span><div class="ci-b"' + (mk ? ' data-rk="' + mk + '" data-rn="' + esc(MYNAME) + '"' : '') + '><div class="ci-n"><b>' + esc(MYNAME) + '</b><span class="mt">我</span>' + (st ? '<i class="stg">' + esc(st) + '</i>' : '') + '</div>' +
'<p class="ci-t">' + esc(c.t) + '</p>' + (mk ? '<div class="ci-s"><span class="rpy">回复</span></div>' : '') + stTag(c) + (mk ? rpHTML(extraReplies(openId, mk), mk, MYNAME) : '') + '</div></div>'; /* 11-02 自己的评论也不显示时间 */
}
var on = !!ME.cl[c.key], n = c.likes + (on ? 1 : 0);
var rp = rpHTML(c.r.concat(extraReplies(openId, c.key)), c.key, c.n);
return '<div class="ci"><img src="' + (c.av || avSrc(c.n)) + '" alt="" loading="lazy"><div class="ci-b" data-rk="' + esc(c.key) + '" data-rn="' + esc(c.n) + '"><div class="ci-n"><b>' + esc(c.n) + '</b>' + (c.s ? '<i class="stg">' + esc(c.s) + '</i>' : '') +
'<span class="lk' + (on ? ' on' : '') + '" data-cl="' + esc(c.key) + '" data-base="' + c.likes + '" role="button"><svg class="ic"><use href="#i-heart' + (on ? '-f' : '') + '"/></svg>' + n + '</span></div>' +
'<p class="ci-t">' + esc(c.t) + '</p><div class="ci-s"><span class="rpy">回复</span></div>' /* 11-02 用户:评论时间先不显示 */ + rp + '</div></div>';
}
function agoOf(ts) {
var s = Math.max(0, (Date.now() - ts) / 1000);
if (s < 60) return '刚刚';
if (s < 3600) return Math.floor(s / 60) + ' 分钟前';
if (s < 86400) return Math.floor(s / 3600) + ' 小时前';
var d = new Date(ts); return (d.getMonth() + 1) + '-' + d.getDate();
}
function renderComments(n) {
var mine = myCm(n.id).filter(function (c) { return !c.parent; }).reverse(), cs = commentsOf(n);
$('#cmh').innerHTML = '评论 <small>共 ' + cmN(n) + ' 条</small>';
if (!CMD && !n.real && !CMERR) { $('#cml').innerHTML = mine.map(function (c) { return commentHTML(c, true); }).join('') + '<div class="cm-ld">评论加载中…</div>'; return; }
/* 别人发的、已审核通过的真实评论排在模拟评论前面 */
var rl = realCm(n.id).filter(function (c) { return !c.parent; }).map(function (c) { return { key: 'r:' + c.id, n: c.nickname || '孕妈', av: c.avatar || '', s: c.stage, t: c.text, likes: 0, r: [] }; });
$('#cml').innerHTML = mine.map(function (c) { return commentHTML(c, true); }).join('') + rl.concat(cs).map(function (c) { return commentHTML(c); }).join('');
}
function syncBar(n, popK) {
var lv = $('#blk'), fv = $('#bfv'), on = liked(n.id), fo = !!ME.fav[n.id];
lv.classList.toggle('on', on); lv.querySelector('use').setAttribute('href', on ? '#i-heart-f' : '#i-heart'); lv.querySelector('span').textContent = cfmt(likeN(n));
fv.classList.toggle('on', fo); fv.querySelector('use').setAttribute('href', fo ? '#i-star-f' : '#i-star'); fv.querySelector('span').textContent = cfmt(favN(n));
$('#bcm span').textContent = cfmt(cmN(n));
if (popK) { var b = popK === 'lv' ? lv : fv; b.classList.remove('pop'); void b.offsetWidth; b.classList.add('pop'); }
}
function openNote(id, push) {
var n = NBY[id]; if (!n) return;
var t = TBY[n.t];
openId = id;
$('#dav').src = avOf(n);
$('#dnm').textContent = n.author;
$('#dst').textContent = n.stage || '';
var fo = $('#dfo'); fo.classList.toggle('on', !!ME.fo[n.author]); fo.textContent = ME.fo[n.author] ? '已关注' : '关注';
var h = Math.round(window.innerWidth * (n.photo ? 1.1 : .72)); /* 详情封面统一矮一点,正文早点露出来 */
var day = 26 + (seed(n.id) % 6), mon = day > 31 ? 11 : 10;
var when = n.real ? (function (d) { return (d.getMonth() + 1) + '-' + d.getDate(); })(new Date(n.at)) : mon + '-' + (day > 31 ? day - 31 : day);
$('#dsc').innerHTML = '<div class="dcv">' + coverHTML(n, h + 'px') + '</div>' +
'<div class="dbody"><div class="dk">' + '<button type="button" class="k-' + t.cat + '" data-go="' + t.id + '">#' + esc(t.name) + '#</button></div>' +
'<h2>' + esc(n.title) + '</h2><div class="tx">' + bodyHTML(n.body) + '</div>' +
((n.images || []).length ? '<div class="pics">' + n.images.map(function (u) { return '<img src="' + esc(u) + '" alt="" loading="lazy">'; }).join('') + '</div>' : '') +
'<div class="tm">' + [n.stage ? esc(n.stage) : '', n.real ? '妈妈投稿' : ''].filter(Boolean).join(' · ') + '</div></div>' /* 11-02 用户:帖子发布日期先隐藏(when 留着,以后恢复直接拼回去) */ +
'<div class="pj k-' + t.cat + '"><span class="pt"><b>你也有类似的经历?</b><small>投稿被选中得 ' + REWARD + '</small></span><button type="button" data-join="' + t.id + '">参与话题</button></div>' +
'<div class="cm" id="cmw"><div class="cm-h" id="cmh"></div>' +
'<div class="cm-in"><span class="me">我</span><button type="button" id="cmgo">留下你的温柔一句…</button></div>' +
'<div id="cml"></div><div class="cm-end">— 没有更多评论了 —</div></div>';
renderComments(n); syncBar(n); loadRC(n);
$('#cin').value = ''; $('#bar').classList.remove('typing'); $('#csend').disabled = true;
$('#dsc').scrollTop = 0; $('#dnav').classList.remove('on');
var dt = $('#dt'); dt.classList.add('show'); dt.setAttribute('aria-hidden', 'false');
if (push) { history.pushState({ gcNote: id }, '', setQuery(cur, id)); pushed = true; }
else history.replaceState(history.state, '', setQuery(cur, id));
}
function hideNote() {
var dt = $('#dt'); dt.classList.remove('show'); dt.setAttribute('aria-hidden', 'true');
$('#cin').blur();
var id = openId; openId = '';
if (id) syncCardLike(id);
if (fvOn) renderFav(); /* 详情里取消了收藏,回到收藏页要立刻消失 */
}
function closeNote() {
if (!openId) return;
if (pushed) { history.back(); return; } /* popstate 里 hideNote */
hideNote(); history.replaceState(history.state, '', setQuery(cur, ''));
}
window.addEventListener('popstate', function () {
if (sheetOn) closeSheet();
pushed = false;
if (openId) hideNote();
});
$('#dback').addEventListener('click', closeNote);
$('#dfo').addEventListener('click', function () {
var n = NBY[openId]; if (!n) return;
if (ME.fo[n.author]) delete ME.fo[n.author]; else ME.fo[n.author] = 1;
save(); haptic();
this.classList.toggle('on', !!ME.fo[n.author]); this.textContent = ME.fo[n.author] ? '已关注' : '关注';
});
$('#dsc').addEventListener('scroll', function () { $('#dnav').classList.toggle('on', this.scrollTop > 8); }, { passive: true });
$('#dsc').addEventListener('click', function (e) {
var jn = e.target.closest('[data-join]'); if (jn) { haptic(); openRule(jn.dataset.join); return; }
var g = e.target.closest('[data-go]');
if (g) { var to = g.dataset.go; closeNote(); setTimeout(function () { if (!to) catF = ''; selectTopic(to); }, 60); return; }
var cl = e.target.closest('[data-cl]');
if (cl) {
var k = cl.dataset.cl, on;
if (ME.cl[k]) delete ME.cl[k]; else ME.cl[k] = 1;
save(); haptic(); on = !!ME.cl[k];
cl.classList.toggle('on', on);
cl.innerHTML = '<svg class="ic"><use href="#i-heart' + (on ? '-f' : '') + '"/></svg>' + (+cl.dataset.base + (on ? 1 : 0));
if (on) { cl.classList.remove('pop'); void cl.offsetWidth; cl.classList.add('pop'); }
return;
}
var rr = e.target.closest('[data-rk]');
if (rr) { REPLY = { k: rr.dataset.rk, n: rr.dataset.rn }; cin.placeholder = '回复 ' + REPLY.n + ':'; cin.focus(); return; }
if (e.target.closest('#cmgo')) { REPLY = null; cin.placeholder = '说点什么…'; $('#cin').focus(); }
});
$('#blk').addEventListener('click', function () {
var n = NBY[openId]; if (!n) return;
toggleLike(n.id); syncBar(n, liked(n.id) ? 'lv' : '');
});
$('#bfv').addEventListener('click', function () {
var n = NBY[openId]; if (!n) return;
if (ME.fav[n.id]) delete ME.fav[n.id]; else ME.fav[n.id] = Date.now(); /* 存收藏时间,「我的收藏」按它倒序 */
save(); haptic(); syncBar(n, ME.fav[n.id] ? 'fv' : '');
toast(ME.fav[n.id] ? '已收藏,在这台手机上随时能找到' : '已取消收藏');
});
$('#bcm').addEventListener('click', function () {
var w = $('#cmw'); if (w) $('#dsc').scrollTo({ top: w.offsetTop - 50, behavior: 'smooth' });
});
var cin = $('#cin');
cin.addEventListener('focus', function () { $('#bar').classList.add('typing'); });
cin.addEventListener('blur', function () { setTimeout(function () { if (!cin.value.trim()) { $('#bar').classList.remove('typing'); REPLY = null; cin.placeholder = '说点什么…'; } }, 120); });
cin.addEventListener('input', function () { $('#csend').disabled = !cin.value.trim(); });
cin.addEventListener('keydown', function (e) { if (e.key === 'Enter') { e.preventDefault(); send(); } });
$('#csend').addEventListener('click', send);
function send() {
var n = NBY[openId], v = cin.value.trim();
if (!n || !v || send.busy) return;
if (!OPENID) { toast('请在小程序里打开后再评论'); return; }
/* 11-03:评论先交后台审核,通过后才公开;审核中只有自己看得到 */
send.busy = true; $('#csend').disabled = true;
fetch(API + '/comment?' + idq(), { method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ kind: 'post', target: n.id, title: n.title, text: v.slice(0, 200), stage: myStage(), parent: REPLY ? REPLY.k : '', parentName: REPLY ? REPLY.n : '' }) })
.then(function (r) { return r.json(); }).then(function (j) {
send.busy = false;
if (!j || j.code !== 200) { $('#csend').disabled = !cin.value.trim(); toast((j && j.message) || '没发出去,稍后再试'); return; }
var rc = RC[n.id] || (RC[n.id] = { list: [], mine: [] }); rc.mine.unshift(j.result);
var wasReply = !!REPLY; REPLY = null; cin.placeholder = '说点什么…';
haptic();
cin.value = ''; $('#csend').disabled = true; cin.blur(); $('#bar').classList.remove('typing');
if (openId === n.id) { renderComments(n); syncBar(n); }
if (!wasReply) { var w = $('#cmw'); if (w) $('#dsc').scrollTo({ top: w.offsetTop - 50, behavior: 'smooth' }); }
toast(wasReply ? '回复已提交,审核通过后大家就能看到' : '已提交,审核通过后大家就能看到');
}).catch(function () { send.busy = false; $('#csend').disabled = !cin.value.trim(); toast('网络不太好,稍后再试'); });
}
/* ================= 投稿(2026-11-01) =================
用户原话:「用户的账号可以去投稿……提交之后会显示『正在被审核』。如果用户的稿件被通过,后台会给他一个提醒」。
接口 box_app /api/mp/public/mama-box/plaza/*(只认 openid):
POST post {topic,title,body,images[]} → 稿件(pending)· GET mine → {list, unread} · POST mine/seen {ids}
GET posts?limit= → 已通过的稿件(不含 openid),混进广场展示,封面标「精选投稿」。
审核在管理后台「孕妈广场投稿」页;通过 = 被选中,奖励 ¥30 现金 + 500 兜豆由运营线下发放、后台标记。
· 提醒:每次打开广场拉 mine,unread(审核有结果且没提醒过)逐条弹窗,关掉后 seen。首页广场模块也会挂一条提示(app.js initPlaza)。
· 草稿存本机 mmbox.gc.draft.v1(按 openid),关掉写稿页不丢。 */
var API = '/api/mp/public/mama-box/plaza', UNION = param('unionid');
var idq = function () { return 'openid=' + encodeURIComponent(OPENID) + (UNION ? '&unionid=' + encodeURIComponent(UNION) : ''); };
var getJ = function (u, opt) { return fetch(u, opt).then(function (r) { return r.json(); }); };
var MINE = [];
/* 已通过的稿件 → 混进笔记流(话题流和「全部」都排最前) */
function loadApproved() {
getJ(API + '/posts?limit=100').then(function (j) {
var l = (j && j.result && (j.result.list || j.result)) || [];
if (!Array.isArray(l) || !l.length) return;
var add = [];
l.forEach(function (p, k) {
if (!TBY[p.topic] || NBY['u-' + p.id]) return;
var o = { id: 'u-' + p.id, t: p.topic, real: true, title: p.title, cover: p.title.length > 9 ? p.title.slice(0, 8) + '…' : p.title, coverSub: '来自妈妈的真实投稿',
author: p.nickname || '孕妈', avatar: p.avatar || '', stage: p.stage || '', likes: 0, body: p.body || '', images: p.images || [],
at: p.approvedAt || p.at || Date.now(), ratio: RATIO[k % RATIO.length], tone: k % 3 };
NBY[o.id] = o; add.push(o);
});
if (!add.length) return;
NOTES = add.concat(NOTES); MIXED = add.concat(MIXED);
renderFeed();
if (deep && NBY[deep] && !openId) openNote(deep, false); /* 分享出去的真实投稿链接:稿件到了再开 */
}).catch(function () {});
}
/* 我的投稿:入口卡在「全部」瀑布流第一位,详情是独立页 mine/ */
var UNREAD = 0;
var mineURL = function () { return 'mine/' + location.hash; };
function myCardHTML() {
var n = { pending: 0, approved: 0 };
MINE.forEach(function (p) { if (n[p.status] != null) n[p.status]++; });
return '<button type="button" class="nc myc" id="myc" data-mine="1">' + (UNREAD ? '<i class="dot">' + UNREAD + ' 条新结果</i>' : '') +
'<span class="mi"><svg class="ic" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9M16.5 3.5a2.1 2.1 0 013 3L7 19l-4 1 1-4z"/></svg></span>' +
'<b>我的投稿</b>' + (MINE.length ? '<p>已投 ' + MINE.length + ' 篇,看看审核进度</p><div class="ms">' + (n.pending ? '<span>审核中 ' + n.pending + '</span>' : '') + (n.approved ? '<span>已通过 ' + n.approved + '</span>' : '') + '</div>'
: '<p>写下你的故事,被选中得 <em>¥30</em> + <em>500</em> 兜豆</p>') +
'<span class="go">' + (MINE.length ? '查看全部' : '去看看') + '<svg class="ic"><use href="#i-right"/></svg></span></button>';
}
function favIds() {
return Object.keys(ME.fav).filter(function (id) { return NBY[id]; }).sort(function (a, b) { return (+ME.fav[b] || 0) - (+ME.fav[a] || 0); });
}
function favCardHTML() {
var k = favIds().length;
return '<button type="button" class="nc fvc" id="fvc" data-fav="1"><i class="fi"><svg class="ic"><use href="#i-star-f"/></svg></i><span>我的收藏<small>' + (k ? '已收藏 ' + k + ' 篇' : '看到喜欢的点 ☆ 收藏') + '</small></span><svg class="ic"><use href="#i-right"/></svg></button>';
}
var fvOn = false, fvDeep = false;
function renderFav() {
var ids = favIds(), cols = $('#fvw').children, hs = [0, 0], tmp = document.createElement('div');
cols[0].innerHTML = ''; cols[1].innerHTML = '';
$('#fvh').textContent = ids.length ? '共 ' + ids.length + ' 篇 · 只保存在这台手机上' : '';
var em = $('#fvs .fve'); if (em) em.remove();
if (!ids.length) { $('#fvw').insertAdjacentHTML('beforebegin', '<div class="fve"><b>还没有收藏</b>看到有用的帖子,点底部的 ☆ 就能收藏到这里</div>'); return; }
$('#fvw').style.setProperty('--cw', (cols[0].clientWidth || 175) + 'px');
ids.forEach(function (id, k) {
tmp.innerHTML = cardHTML(NBY[id], false, ''); var el = tmp.firstChild; el.style.animationDelay = Math.min(k, 10) * 30 + 'ms';
var c = hs[0] <= hs[1] ? 0 : 1; cols[c].appendChild(el); hs[c] += el.offsetHeight + 8;
});
}
function openFav(deep) {
fvOn = true; fvDeep = !!deep;
var p = $('#fvp'); p.classList.add('show'); p.setAttribute('aria-hidden', 'false'); $('#fvs').scrollTop = 0;
renderFav();
}
function closeFav() {
/* 从首页「我的 → 我的收藏」直接进来的,返回就回首页 */
if (fvDeep && history.length > 1 && document.referrer && document.referrer.indexOf('/guangchang/') < 0) { history.back(); return; }
fvOn = false; var p = $('#fvp'); p.classList.remove('show'); p.setAttribute('aria-hidden', 'true');
var c = $('#fvc'); if (c) c.outerHTML = favCardHTML();
history.replaceState(history.state, '', setQuery(cur, ''));
}
$('#fvBack').addEventListener('click', closeFav);
$('#fvw').addEventListener('click', function (e) {
var lk = e.target.closest('[data-like]'); if (lk) { toggleLike(lk.dataset.like); syncCardLike(lk.dataset.like); return; }
var c = e.target.closest('[data-id]'); if (c) { haptic(); openNote(c.dataset.id, true); }
});
function syncMyCard() { var c = $('#myc'); if (c) { c.outerHTML = myCardHTML(); } }
function loadMine(cb) {
if (!OPENID) return;
getJ(API + '/mine?' + idq()).then(function (j) {
var r = j && j.result; if (!r) return;
MINE = r.list || [];
var un = r.unread || [];
UNREAD = un.length; syncMyCard();
if (cb) cb(); else if (un.length) showResults(un);
}).catch(function () {});
}
/* 审核结果弹窗:逐条弹,全部看完一次性 seen */
function showResults(list) {
var q = list.slice(), ids = list.map(function (p) { return p.id; });
(function next() {
var p = q.shift();
if (!p) {
fetch(API + '/mine/seen?' + idq(), { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ids: ids }) }).catch(function () {});
UNREAD = 0; syncMyCard();
return;
}
var ok = p.status === 'approved';
showRs(ok ? 'ok' : 'no', ok ? '你的投稿通过啦' : '这篇投稿没有通过',
'《<b>' + esc(p.title) + '</b>》' + (ok ? '已被选中,将展示在孕妈广场。<br>奖励 <em>¥30</em> 现金 + <em>500</em> 兜豆,工作人员会尽快发放。' : '暂时没有通过审核,可以修改后重新投稿。'),
ok ? '' : '原因:' + esc(p.reason || '暂不符合展示要求'), q.length ? '下一条' : '知道了', next);
})();
}
function showRs(kind, title, text, why, btn, cb) {
$('#rsb').innerHTML = '<div class="rsi ' + kind + '"><svg class="ic"><use href="#' + (kind === 'ok' ? 'i-check' : kind === 'no' ? 'i-x' : 'i-clock') + '"/></svg></div>' +
'<h3>' + title + '</h3><p class="rst">' + text + '</p>' + (why ? '<div class="rsw">' + why + '</div>' : '') + '<button type="button" class="rsk" id="rsk">' + btn + '</button>';
$('#rs').classList.add('show');
$('#rsk').onclick = function () { $('#rs').classList.remove('show'); if (cb) setTimeout(cb, 220); };
}
/* 写稿页 */
var DK = 'mmbox.gc.draft.v1', cpTopic = '', pics = [], ups = 0;
function draft(v) {
try {
var all = JSON.parse(localStorage.getItem(DK) || '{}') || {};
if (v === undefined) return all[UK] || {};
if (v) all[UK] = v; else delete all[UK];
localStorage.setItem(DK, JSON.stringify(all));
} catch (e) { return {}; }
}
function setCpTopic(id) {
cpTopic = TBY[id] ? id : '';
var t = TBY[cpTopic], b = $('#cpT');
b.className = 'cp-t' + (t ? ' k-' + t.cat : '');
b.innerHTML = (t ? kbHTML(t.cat) + '<span class="ct2">#' + esc(t.name) + '#</span>' : '<span class="ct2">选择要参与的话题</span>') +
'<span class="ch">' + (t ? '换话题' : '去选') + '<svg class="ic" style="width:13px;height:13px"><use href="#i-right"/></svg></span>';
saveDraft();
}
function cnt() {
var n = $('#cpBody').value.trim().length, c = $('#cpCnt');
c.className = 'cp-cnt' + (n >= 300 ? ' ok' : '');
c.innerHTML = '已写 <b>' + n + '</b> 字 · ' + (n < 50 ? '至少 50 字' : n < 300 ? '写到 300 字以上更容易被选中' : '很棒,继续写也可以');
}
function saveDraft() { draft({ t: cpTopic, a: $('#cpTitle').value, b: $('#cpBody').value }); }
function openCompose(tid) {
if (!OPENID) { toast('请从小程序里打开孕妈广场再投稿'); return; }
if (openId) closeNote();
var d = draft();
$('#cpTitle').value = d.a || ''; $('#cpBody').value = d.b || '';
setCpTopic(tid || d.t || '');
cnt();
$('#cp').classList.add('show'); $('#cp').setAttribute('aria-hidden', 'false');
}
function closeCompose() { saveDraft(); $('#cp').classList.remove('show'); $('#cp').setAttribute('aria-hidden', 'true'); document.activeElement && document.activeElement.blur(); }
$('#cpX').addEventListener('click', closeCompose);
$('#cpT').addEventListener('click', function () { pickFor = 'compose'; openTopics(); });
$('#cpTitle').addEventListener('input', saveDraft);
$('#cpBody').addEventListener('input', function () { cnt(); saveDraft(); });
function shrink(f) {
return new Promise(function (res) {
var u = URL.createObjectURL(f), im = new Image();
im.onload = function () {
var k = Math.min(1, 1600 / Math.max(im.width, im.height)), c = document.createElement('canvas');
c.width = Math.round(im.width * k); c.height = Math.round(im.height * k);
c.getContext('2d').drawImage(im, 0, 0, c.width, c.height); URL.revokeObjectURL(u);
c.toBlob(function (b) { res(b || f); }, 'image/jpeg', .85);
};
im.onerror = function () { URL.revokeObjectURL(u); res(f); };
im.src = u;
});
}
var syncAdd = function () { $('#cpAdd').classList.toggle('hide', pics.length >= 6); };
$('#cpFile').addEventListener('change', function () {
var f = this.files && this.files[0]; this.value = '';
if (!f || pics.length >= 6) return;
var it = { url: null, el: document.createElement('span') };
it.el.className = 'pt up';
it.el.innerHTML = '<img alt=""><button type="button" aria-label="删除这张">×</button>';
it.el.querySelector('img').src = URL.createObjectURL(f);
it.el.querySelector('button').onclick = function () { pics = pics.filter(function (x) { return x !== it; }); it.el.remove(); syncAdd(); };
$('#cpPics').insertBefore(it.el, $('#cpAdd')); pics.push(it); syncAdd(); ups++;
shrink(f).then(function (b) { var fd = new FormData(); fd.append('file', b, 'plaza.jpg'); return fetch('/api/upload', { method: 'POST', body: fd }); })
.then(function (r) { return r.json(); }).then(function (j) { it.url = j && j.result && j.result.url || null; if (!it.url) throw 0; it.el.classList.remove('up'); })
.catch(function () { toast('图片上传失败,可以删掉重新选'); it.el.classList.remove('up'); it.el.classList.add('bad'); })
.then(function () { ups--; });
});
$('#cpOk').addEventListener('click', function () {
var btn = this, title = $('#cpTitle').value.trim(), body = $('#cpBody').value.trim();
if (!cpTopic) { toast('先选一个要参与的话题'); return; }
if (title.length < 4) { toast('标题至少 4 个字'); return; }
if (body.length < 50) { toast('正文至少 50 个字,再多写一点吧'); return; }
if (ups > 0) { toast('图片还在上传,稍等一下'); return; }
btn.disabled = true; btn.textContent = '提交中';
getJ(API + '/post?' + idq(), { method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ topic: cpTopic, title: title, body: body, images: pics.map(function (x) { return x.url; }).filter(Boolean) }) })
.then(function (j) {
if (!j || j.code !== 200 || !j.result) { toast((j && j.message) || '提交失败,请稍后再试'); return; }
MINE.unshift(j.result);
draft(null); pics.forEach(function (x) { x.el.remove(); }); pics = []; syncAdd();
$('#cpTitle').value = ''; $('#cpBody').value = '';
closeCompose(); haptic();
showRs('wait', '已提交,正在审核中', '《<b>' + esc(title) + '</b>》已经交给编辑审核,<br>有结果会在这里提醒你。', '', '好的');
})
.catch(function () { toast('网络不太好,请稍后再试(草稿已保存)'); })
.then(function () { btn.disabled = false; btn.textContent = '提交'; });
});
/* ---------- 返回 ---------- */
function homeURL() {
var q = new URLSearchParams(location.search); q.delete('t'); q.delete('n'); q.delete('c');
var s = q.toString();
return '../' + (s ? '?' + s : '') + location.hash;
}
$('#back').addEventListener('click', function () {
/* 11-02 用户:「从首页点热门话题进来,左上角返回要回孕妈广场,不是首页」→ 在话题里先退回广场「全部」,再按一次才回首页 */
if (cur) { haptic(); catF = ''; selectTopic(''); return; }
var fromHome = false;
try { fromHome = !!document.referrer && new URL(document.referrer).origin === location.origin; } catch (e) {}
if (fromHome && history.length > 1) {
history.back();
/* 后退没生效(宿主新开的 web-view 没有站内历史)→ 直接回首页 */
setTimeout(function () { location.href = homeURL(); }, 500);
} else location.href = homeURL();
});
/* ---------- 底部 Tab:孕妈广场 / 记一下 / 返回兜爸(11-03 用户:「就跟数胎动一样」) ---------- */
$('#tabPlaza').addEventListener('click', function () { /* 再点一次:回到顶部;在话题里就退回「全部」 */
haptic();
if (cur || catF) { catF = ''; selectTopic(''); }
$('#sc').scrollTo({ top: 0, behavior: 'smooth' });
});
$('#tabHome').addEventListener('click', function () { haptic(); location.href = homeURL(); }); /* 广场就在首页仓里,直接回 ../ 带身份,不走 goHome */
/* 记一下:和首页「记一下」同一份数据 —— 后台 App 表已上架、category=孕期工具(首页 loadPublishedApps 同规则);
数胎动 16 / 数宫缩 20 / 胎儿估重 15 周前灰掉、点了提示(同首页 STAGE_GATE,孕周取首页写的 mmbox.gcwk.v1,拿不准不拦) */
var REC_GATE = { taidong: [16, '数胎动'], gongsuopinlv: [20, '数宫缩'], taierguzhong: [15, '胎儿估重'] }, recApps = null;
var myWeek = (function () { try { var g = JSON.parse(localStorage.getItem('mmbox.gcwk.v1') || 'null'); return g && !g.pp && g.w ? +g.w : 0; } catch (e) { return 0; } })();
function recLocked(a) { var g = REC_GATE[a.identifier]; return g && myWeek && myWeek < g[0] ? g : null; }
function recHTML() {
if (!recApps) return '<div class="rec-empty">加载中…</div>';
if (!recApps.length) return '<div class="rec-empty">暂时没取到工具,稍后再试</div>';
var ok = recApps.filter(function (a) { return !recLocked(a); }), lk = recApps.filter(recLocked); /* 没开放的排到后面(同首页) */
return ok.concat(lk).map(function (a) {
var g = recLocked(a), nm = a.name || a.identifier || '工具', ic = a.logo || a.icon;
return '<button type="button" class="rec-app' + (g ? ' off' : '') + '" data-rid="' + esc(a.identifier || '') + '">' +
(ic ? '<img src="' + esc(ic) + '" alt="">' : '<b class="rl">' + esc(nm.slice(0, 1)) + '</b>') +
'<span>' + esc(nm) + '</span>' + (g ? '<i>孕' + g[0] + '周开放</i>' : '') + '</button>';
}).join('');
}
function loadRec() {
if (recApps || loadRec.busy) return; loadRec.busy = true;
fetch('/api/mp/apps?isPublished=1&pageSize=200').then(function (r) { return r.ok ? r.json() : null; }).then(function (d) {
recApps = ((d && d.result && d.result.items) || []).filter(function (a) { return a.url && a.category === '孕期工具'; })
.sort(function (x, y) { return (y.seq || 0) - (x.seq || 0) || (y.no || 0) - (x.no || 0); });
}).catch(function () { recApps = []; }).then(function () {
loadRec.busy = false;
var g = $('#recApps'); if (g && sheetOn === 'rec') g.innerHTML = recHTML();
});
}
$('#tabRec').addEventListener('click', function () {
haptic(); loadRec();
openSheet('rec', '<div class="rec-h"><b>记一下</b><span>兜爸心选的孕期工具</span><button type="button" class="rec-x" data-recx aria-label="关闭"><svg class="ic"><use href="#i-x"/></svg></button></div>' +
'<div class="rec-apps" id="recApps">' + recHTML() + '</div>');
});
$('#sbd').addEventListener('click', function (e) {
if (sheetOn !== 'rec') return;
if (e.target.closest('[data-recx]')) { closeSheet(); return; }
var b = e.target.closest('[data-rid]'); if (!b || !recApps) return;
var a = recApps.filter(function (x) { return (x.identifier || '') === b.dataset.rid; })[0]; if (!a) return;
var g = recLocked(a);
if (g) { haptic(); toast(g[1] + '孕 ' + g[0] + ' 周以后开放,你现在孕 ' + myWeek + ' 周,还用不到哦'); return; }
goApp(a.url);
});
/* 返回兜爸的头像(11-03 用户:「图标换成用户的头像,上面加渐变圈」)—— 同数胎动的取值顺序:
① 跨应用 user-center/info 的真头像(权威);② 授权回传在 hash 里的 avatar;③ 都没有 → 按 openid 固定给一个默认妈妈头像
(同 /_bridge/avatar-picker.js 的 defaultFor,同一人在每个应用看到的一样)。商城默认头像 /uploads/system/ 当没有。
小房子 SVG 不删:头像加载失败就露回来,这是回首页的入口,不能变空位。 */
var realAv = function (u) { return !!u && !/\/uploads\/system\//.test(u); };
function defAv(oid) { var h = 0, s = String(oid || ''); for (var i = 0; i < s.length; i++) h = (h * 31 + s.charCodeAt(i)) >>> 0; return 'https://mp.yizhezhe.com/_bridge/avatars/mom-' + ((h % 20) + 1 < 10 ? '0' : '') + ((h % 20) + 1) + '.png'; }
function paintTabAv(url) {
var ico = $('#tabAv'), im = ico.querySelector('.tab-avimg');
if (!url) return;
if (!im) {
im = document.createElement('img'); im.className = 'tab-avimg'; im.alt = ''; ico.appendChild(im);
ico.insertAdjacentHTML('beforeend', '<i class="tab-hm" aria-hidden="true"><svg viewBox="0 0 24 24" fill="#fff"><path d="M12 4 3.5 11H6v8.5h4.5v-5h3v5H18V11h2.5z"/></svg></i>');
}
im.onload = function () { ico.classList.add('has-av'); };
im.onerror = function () { if (im.getAttribute('src') !== defAv(OPENID)) im.src = defAv(OPENID); else ico.classList.remove('has-av'); };
if (im.getAttribute('src') !== url) im.src = url;
}
function loadTabAv() {
if (!OPENID || !window.fetch) return;
fetch('/api/mp/public/user-center/info?openid=' + encodeURIComponent(OPENID) + (param('unionid') ? '&unionid=' + encodeURIComponent(param('unionid')) : ''))
.then(function (r) { return r.ok ? r.json() : null; }).then(function (d) {
var av = d && d.result && d.result.found && d.result.data && d.result.data.avatar;
if (realAv(av)) paintTabAv(av);
}).catch(function () {});
}
if (OPENID) { paintTabAv(realAv(param('avatar')) ? param('avatar') : defAv(OPENID)); loadTabAv(); }
window.addEventListener('pageshow', function (e) { if (e.persisted) loadTabAv(); }); /* 从别的应用改完头像退回来,跟着换 */
/* ---------- 吸顶阴影 ---------- */
var sc = $('#sc');
sc.addEventListener('scroll', function () { $('#top').classList.toggle('on', sc.scrollTop > 4); }, { passive: true });
/* ---------- 禁止下拉回弹(同首页那段):竖向拖动时从手指下往上找还能朝该方向滚的容器,找不到才拦 ---------- */
var sx = 0, sy = 0;
document.addEventListener('touchstart', function (e) {
if (e.touches.length !== 1) return;
sx = e.touches[0].clientX; sy = e.touches[0].clientY;
}, { passive: true });
document.addEventListener('touchmove', function (e) {
if (e.touches.length !== 1) { if (e.cancelable) e.preventDefault(); return; }
var dx = e.touches[0].clientX - sx, dy = e.touches[0].clientY - sy;
if (Math.abs(dy) <= Math.abs(dx)) return;
var el = e.target;
while (el && el !== document.body && el !== document.documentElement) {
if (el.nodeType === 1) {
var oy = getComputedStyle(el).overflowY;
if ((oy === 'auto' || oy === 'scroll') && el.scrollHeight > el.clientHeight + 1) {
if (dy > 0 && el.scrollTop > 0) return;
if (dy < 0 && el.scrollTop + el.clientHeight < el.scrollHeight - 1) return;
}
}
el = el.parentNode;
}
if (e.cancelable) e.preventDefault();
}, { passive: false });
/* ---------- 启动 ---------- */
var deep = new URLSearchParams(location.search).get('n'), q0 = new URLSearchParams(location.search); /* 先读:selectTopic 会 replaceState 把 n 去掉 */
var c0 = new URLSearchParams(location.search).get('c');
if (c0 === 'ceshi') catF = c0; /* 11-03 分类取消:旧链接 ?c=family / work / baby 一律落「全部」 */
selectTopic(param('t') && TBY[param('t')] ? param('t') : '', false);
if (deep && NBY[deep]) openNote(deep, false);
loadApproved();
if (q0.get('fav') === '1') openFav(true); /* 首页「我的 → 我的收藏」 */
if (q0.get('mine') === '1') location.href = mineURL(); /* 首页审核提醒 ?mine=1 → 我的投稿页(selectTopic 已把 mine 从地址里去掉,返回不会再跳) */
else if (q0.get('write') === '1') { loadMine(function () {}); openCompose(q0.get('t') || ''); } /* 我的投稿页「写新的故事 / 修改后重投」:结果在那页已看过,不再弹 */
else loadMine(); /* 我的投稿页「写新的故事 / 修改后重投」 */
var rt; window.addEventListener('resize', function () { clearTimeout(rt); rt = setTimeout(renderFeed, 150); });
/* 11-04 微信转发图:跟着地址走 —— ?n= 笔记(g/<id>.jpg,真实投稿用广场图)、?t= 话题(g/t-<id>.jpg)、?c=ceshi 测试列表、其余广场首页;见 js/share-card.js */
if (window.mbShareWatch) window.mbShareWatch(function () {
var q = new URLSearchParams(location.search), n = NBY[q.get('n')], t = TBY[q.get('t')];
if (n) return n.real ? ['../assets/share/g/home.jpg', n.title] : ['../assets/share/g/' + n.id + '.jpg', n.title];
if (t) return ['../assets/share/g/t-' + t.id + '.jpg', '#' + t.name + '#'];
if (q.get('c') === 'ceshi') return ['../assets/share/g/ceshi.jpg', '趣味小测试|30 个孕育小测试,1 分钟测出你是哪种孕妈'];
return ['../assets/share/g/home.jpg', '孕妈广场|孕期的那些事,听听过来人怎么说'];
});
})();
</script>
</body>
</html>