Files
mama-box/guangchang/index.html

1517 lines
119 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">
<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{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 12px}
.csg{margin-top:18px}
.csg-h{display:flex;align-items:baseline;gap:8px;padding:0 4px}
.csg-h b{position:relative;font-size:17px;font-weight:900;color:#2A1E1E}
.csg-h b::after{content:"";position:absolute;left:-2px;right:-2px;bottom:1px;height:7px;border-radius:4px;background:var(--tg);opacity:.22;z-index:-1}
.csg-h b{z-index:0}
.csg-h small{font-size:12px;color:#A08B85}
.csg-h em{margin-left:auto;font-style:normal;font-size:12px;font-weight:800;color:var(--tg)}
/* 11-02 v4 用户:「测一测页面太乱,整洁一些,多少人测过要明显」→ 所有分组统一一种列表行:缩略图 + 标题/说明 + 右侧大号人数 */
.cpl{margin-top:8px;border-radius:20px;background:#fff;box-shadow:0 3px 12px rgba(170,110,90,.07);overflow:hidden}
.cr{display:flex;align-items:center;gap:12px;width:100%;padding:12px;text-align:left;border-top:1px solid #F7EFEB}
.cr:first-child{border-top:0}
.cr:active{background:#FCF8F6}
.cr .cth{position:relative;flex:none;width:58px;height:58px}
.cr .cth img{display:block;width:100%;height:100%;border-radius:14px;object-fit:cover;object-position:center 28%;background:var(--tl)}
.cr .crk{position:absolute;left:-5px;top:-5px;min-width:20px;height:20px;padding:0 5px;border-radius:7px;background:#B9A7A1;color:#fff;font-size:11.5px;font-weight:900;line-height:20px;text-align:center;border:2px solid #fff;font-style:normal}
.cr .crk.r1{background:#F0453A}.cr .crk.r2{background:#F28A1E}.cr .crk.r3{background:#F2B21E}
.cr .tx{flex:1;min-width:0}
.cr b{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;font-size:14.5px;font-weight:800;line-height:1.4;color:#2A1E1E}
.cr small{display:block;margin-top:3px;font-size:12px;color:#A99590;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
.cr small em{font-style:normal;font-weight:800;color:var(--tg)}
.cr .cn{flex:none;min-width:66px;padding:7px 8px 6px;border-radius:14px;background:linear-gradient(160deg,#FFF3EE,#FFE4DA);text-align:center} /* 11-02 用户:「N万人测过」要更明显 */
.cr .cn b{display:flex;align-items:baseline;justify-content:center;font-size:22px;font-weight:900;line-height:1.05;color:#EE4B2B;font-family:-apple-system,"DIN Alternate","Helvetica Neue",sans-serif;letter-spacing:-.5px}
.cr .cn b i{font-size:12.5px;font-style:normal;font-weight:900;margin-left:1px}
.cr .cn small{display:flex;align-items:center;justify-content:center;gap:2px;margin-top:3px;font-size:11px;font-weight:800;color:#F0704F}
.cr .cn small svg{width:11px;height:11px}
.cr .cn.dn b{font-size:13px;color:var(--tg)}
.ckm{display:block;width:100%;height:42px;border-top:1px solid #F7EFEB;color:#8A7470;font-size:12.5px;font-weight:800;background:#fff}
.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)}
.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:1;min-width:0;font-size:11px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.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(26px + 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}
/* ---------- 封面(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}
.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)}
</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"><b>— 到底啦 —</b><small>内容为示例占位,正式版将替换为妈妈们的真实分享</small></div>
</div>
</div>
<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=26110237"></script>
<script src="data.js?v=26110237"></script>
<script src="feed.js?v=26110237"></script>
<script src="ceshi/meta.js?v=26110237"></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=26110237').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); };
var myCm = function (id) { return ME.cm[id] || []; };
var cmN = function (n) { return commentsOf(n).length + myCm(n.id).length; };
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">' + kbHTML(t.cat) + '</div>';
return '<div class="cv" style="--c1:' + c[0] + ';--c2:' + c[1] + ';--tk:' + pl.ink + ';' + (h ? 'height:' + h : '') + '">' + kbHTML(t.cat) + (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 + '">' + (n.stage ? '<small>' + esc(n.stage) + '</small>' : '') + '<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>'; }
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><div class="nf"><img src="' + esc(avOf(n)) + '" alt="" loading="lazy"><span class="nm">' + esc(n.author) + '</span>' + 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) */
var CATS = [['', '全部', 'i-grid'], ['family', '家庭婚姻', 'i-home'], ['work', '职场', 'i-bag'], ['baby', '经验', 'i-baby'], ['ceshi', '测一测', 'i-spark']];
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 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>';
}
/* 跳祈福树:同首页 jumpApp(QIFU_URL) —— 相对路径、身份走 query、上报 last_app 与分享位置(AGENTS 硬约定 3/6/7/13) */
function goQifu() {
var url = '/qifu-shu/', 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 + '?' + 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); }); }, hotOpen = false;
var TGD = { quiz: '有标准答案,答完看解析', psy: '没有对错,测测你是哪一型', game: '挑战一下,看能拿什么称号', shop: '看看你是哪一类育儿采购玩家' };
/* 统一列表行:缩略图(热度榜带名次)+ 标题 / 说明 + 右侧大号人数;测过的右侧换成「已测」 */
function rowHTML(x, done, rank) {
var d = done[x.id], num = gcTestedText(x.id).replace('人测过', '').replace('万', '<i>万</i>');
return '<button type="button" class="cr g-' + x.group + '" data-test="' + x.id + '"><span class="cth"><img src="ceshi/img/' + x.id + '_s.webp" alt="" loading="lazy">' +
(rank ? '<i class="crk' + (rank <= 3 ? ' r' + rank : '') + '">' + rank + '</i>' : '') + '</span>' +
'<span class="tx"><b>' + esc(x.title) + '</b><small>' + (d ? '<em>' + (x.group === 'quiz' || x.group === 'game' ? '已拿「' : '我是「') + esc(d.title) + '」</em>' : (rank ? '<em>' + TG[x.group] + '</em> · ' : '') + esc(x.sub)) + '</small></span>' +
'<span class="cn"><b>' + num + '</b><small><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>人测过</small></span></button>';
}
function hotHTML(done) {
var l = byHot(TM);
return '<section class="csg csk"><div class="csg-h"><b>热度榜</b><small>按测过的人数排名</small></div><div class="cpl">' +
l.slice(0, hotOpen ? l.length : 5).map(function (x, i) { return rowHTML(x, done, i + 1); }).join('') +
'<button type="button" class="ckm" data-hot="1">' + (hotOpen ? '收起' : '查看完整榜单(' + l.length + ' 个)') + '</button></div></section>';
}
function ceshiListHTML() {
var done = csDone();
return '<div class="csl">' + (tGrp ? '' : hotHTML(done)) + ['quiz', 'psy', 'game', 'shop'].filter(function (g) { return !tGrp || tGrp === g; }).map(function (g) {
var l = byHot(TM.filter(function (x) { return x.group === g; })); if (!l.length) return '';
var nd = l.filter(function (x) { return done[x.id]; }).length;
return '<section class="csg g-' + g + '"><div class="csg-h"><b>' + TG[g] + '</b><small>' + l.length + ' 套 · ' + TGD[g] + '</small>' + (nd ? '<em>已测 ' + nd + '</em>' : '') + '</div>' +
'<div class="cpl">' + l.map(function (x) { return rowHTML(x, done); }).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]; }));
fh.innerHTML = '<div class="lv"><h2>测一测</h2><small>' + TM.length + ' 个测试 · 每个 12 题以上</small></div>' +
'<div class="tcs">' + all.map(function (x) { return '<button type="button" data-tg="' + x[0] + '"' + (tGrp === x[0] ? ' class="on"' : '') + '>' + x[1] + '<i>' + x[2] + '</i></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');
if (catF === 'ceshi') { el.innerHTML = ceshiHead(); ceshiFh(fh); return; }
if (!t) {
var hl = hotList();
el.innerHTML = qifuHTML() +
'<div class="sh"><svg class="fire"><use href="#i-fire"/></svg><h2>热门话题</h2><button type="button" class="more" data-all="1">全部 ' + hl.length + ' 个<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">查看全部 ' + hl.length + ' 个话题 ›</button></div>';
if (catF) { fhLevels(fh); return; }
fh.className = 'sh';
fh.innerHTML = '<h2>大家在聊</h2><small>' + T.filter(function (x) { return cntT(x.id); }).length + ' 个话题 · 共 ' + NOTES.length + ' 篇</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>话题 · ' + cntT(t.id) + ' 篇</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><small>共 ' + cntT(t.id) + ' 篇</small>';
}
/* 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><small>' + tl.length + ' 个话题 · 共 ' + all + ' 篇</small>' +
(cur ? '<button type="button" class="ba" data-t="">看这块全部 ›</button>' : '') + '</div>' +
'<div class="tcs"><button type="button" data-t=""' + (cur ? '' : ' class="on"') + '>全部<i>' + all + '</i></button>' +
tl.map(function (x) { return '<button type="button" data-t="' + x.id + '"' + (cur === x.id ? ' class="on"' : '') + '>#' + esc(x.name) + '#<i>' + cntT(x.id) + '</i></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% */
if (catF === 'ceshi') {
$('#more').innerHTML = ceshiListHTML(); return;
}
/* 「全部」信息流:穿插测试卡 */
if (!cur && !catF && TM.length) {
var dn = csDone(), mixed = [], ci = 0;
/* 测试卡:第 3 位起每 8 张帖子插 1 张(约占 1/9),先出 CS_MIX 精选,再按热度轮完其余测试 */
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 >= 3 && (k - 3) % 8 === 0) { var tid = csq[ci++ % csq.length]; if (TMBY[tid]) mixed.push({ test: TMBY[tid] }); } mixed.push(n); });
list = [{ mine: 1 }].concat(mixed);
}
var nk = 0;
list.forEach(function (n, k) {
if (n.mine) {
tmp.innerHTML = myCardHTML(); var me = tmp.firstChild;
cols[0].appendChild(me); hs[0] += me.offsetHeight + 8;
tmp.innerHTML = favCardHTML(); var fe = tmp.firstChild;
cols[0].appendChild(fe); hs[0] += fe.offsetHeight + 8;
return;
}
if (n.test) {
tmp.innerHTML = testCardHTML(n.test, dn);
var te = tmp.firstChild; te.style.animationDelay = Math.min(k, 10) * 30 + 'ms';
var tc0 = hs[0] <= hs[1] ? 0 : 1; cols[tc0].appendChild(te); hs[tc0] += te.offsetHeight + 8; lastTx[tc0] = false;
return;
}
k = nk++;
var c = hs[0] <= hs[1] ? 0 : 1, sty = !lastTx[c] && n.photo ? (txN[c]++ % 2 ? 'tg' : 'ov') : '';
lastTx[c] = !!sty;
tmp.innerHTML = cardHTML(n, !cur, sty);
var el = tmp.firstChild; el.style.animationDelay = Math.min(k, 10) * 30 + 'ms';
cols[c].appendChild(el);
hs[c] += el.offsetHeight + 8;
});
/* 话题下帖子看完,接着引到同分类其他话题,避免以为这块只有这几篇 */
var mo = $('#more'), tc = cur && TBY[cur];
if (tc) {
var rest = NOTES.filter(function (n) { return n.t !== cur && TBY[n.t].cat === tc.cat; }).length;
mo.innerHTML = '<button type="button" class="mo k-' + tc.cat + '" data-t=""><small>这个话题就这些啦</small><b>「' + CATS.filter(function (c) { return c[0] === tc.cat; })[0][1] + '」还有 ' + rest + ' 篇,去看看 ›</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 = TBY[t].cat; /* 首页带 ?t= 进来 / 点详情里的话题标签:分类跟着切到该话题所属类 */
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 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 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) + '<small>' + tl.length + ' 个话题</small></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><small>' + cntT(t.id) + ' 篇分享</small></span>' + (t.hot ? '<i>热</i>' : '') + '</button>';
}).join('') + '</div>';
};
openSheet('topics', '<h3>全部 ' + T.length + ' 个话题</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) {
if (e.target.closest('[data-hot]')) { e.stopPropagation(); haptic(); hotOpen = !hotOpen; var k = $('#more .csk'); if (k) k.outerHTML = hotHTML(csDone()); return; }
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();
return '<div class="ci mine"><span class="me">我</span><div class="ci-b"><div class="ci-n"><b>' + esc(MYNAME) + '</b><span class="mt">我</span></div>' +
'<p class="ci-t">' + esc(c.t) + '</p>' + (st ? '<div class="ci-s">' + esc(st) + '</div>' : '') + '</div></div>'; /* 11-02 自己的评论也不显示时间 */
}
var on = !!ME.cl[c.key], n = c.likes + (on ? 1 : 0);
var rp = c.r.length ? '<div class="rp">' + c.r.map(function (x) { return '<p><b>' + esc(x.n) + '</b>' + (x.au ? '<span class="au">作者</span>' : '') + ':' + esc(x.t) + '</p>'; }).join('') + '</div>' : '';
return '<div class="ci"><img src="' + (c.av || avSrc(c.n)) + '" alt="" loading="lazy"><div class="ci-b"><div class="ci-n"><b>' + esc(c.n) + '</b>' +
'<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>' + (c.s ? '<div class="ci-s">' + esc(c.s) + '</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).slice().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; }
$('#cml').innerHTML = mine.map(function (c) { return commentHTML(c, true); }).join('') + 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">' + kbHTML(t.cat) + '<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);
$('#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;
}
if (e.target.closest('#cmgo')) $('#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'); }, 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) return;
(ME.cm[n.id] = myCm(n.id)).push({ t: v.slice(0, 200), ts: Date.now(), s: myStage() });
save(); haptic();
cin.value = ''; $('#csend').disabled = true; cin.blur(); $('#bar').classList.remove('typing');
renderComments(n); syncBar(n);
var w = $('#cmw'); if (w) $('#dsc').scrollTo({ top: w.offsetTop - 50, behavior: 'smooth' });
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();
});
/* ---------- 吸顶阴影 ---------- */
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 (CAT_ORDER.indexOf(c0) >= 0 || c0 === 'ceshi') catF = c0;
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); });
})();
</script>
</body>
</html>