/* ============ 妈妈盒子 · H5 ============ */ :root{ --brand:#F4593C; --brand-lt:#FF7C5C; --brand-dk:#E04A2E; /* 设计稿 hero 是「越往下越浅」的暖橘(顶 #FC7A60 → 底 #FAAE9B), 之前写成了越往下越深,气泡插画一放上去边缘就发暗,这里按取样值改回来 */ --grad:linear-gradient(150deg,#E85D41 0%,#EC6A4A 45%,#EF7B55 75%,#F0906C 100%); --bg:#F8F3EF; --card:#fff; --ink:#2B2320; --ink-2:#6B615B; --muted:#72665E; --line:#EFE7E1; --green:#6E9A56; --alert:#D2402A; /* 卡片 warn 标红(胎动偏低/宫缩达阈值/产检过期) */ --purple:#8B6FE0; --blue:#4E85C7; /* ---- 「妈妈」这个身份的颜色 ---- 本批从蓝(--blue #4E85C7)换成绿。用户原话: 「妈妈回信那个背景色,现在不是浅蓝吗?可以变成偏绿色一点。」 ⚠️ 为什么另起一个变量、而不是把 --blue 的值直接改成绿: --blue 是**调色板**里的颜色名,把叫 blue 的变量填成绿色, 以后每个读到它的人都会被骗一次。--mom 是**语义**变量(谁的颜色), 换色时只动它,调色板保持诚实。 ⚠️ 内置来信屏删除后,回信气泡那套浅绿底(原来的 --mom-bg-1/2)已一并下线; 这个变量现在只剩 .sec-title.c-blue::before(绿色竖色条)一个消费者。 */ --mom:#3F7551; --r-lg:24px; --r-md:18px; --r-sm:12px; --sh:0 8px 24px rgba(188,120,96,.10); --sh-lg:0 14px 40px rgba(180,110,86,.16); /* ---- 工具区背后的「妈妈」大字水印 ---- 首页工具区(.tool-dock)的白底上躺着两个很大、很粗、很淡的「妈妈」, 压在内容底下。它不是纹理,是一枚印章:下半截整个沉在工具卡背后, 露出来的上面六成刚好够人一眼认出「哦,是妈妈两个字」。 ⚠️ **全站只有这一枚。** 上一稿三块白底各放一枚,被否了 —— 三枚同样的字顺着首页排下来,本身又成了一种重复。一枚是印章,三枚是底纹。 别再往 .today-line / .shelf 上加回去;尺寸怎么定的见 .wm 那条规则。 ⚠️ 这块地方已经推翻过两版底纹,两版都是被同一句话否掉的: 第一批「脚丫/星/云/爱心 四种图案散铺」→「太碎了,页面看着特别乱。」 第二批「等距波点,列距 36px」 →「那个小碎点看着还是太乱。」 两版的毛病是同一个:**满屏都是小东西**。小东西一多,眼睛就要挨个去认, 认的过程就是分心的过程。第三版索性反过来 —— 整块地方只放**一个**大东西, 大到不必去认,扫一眼就过去了。 **想再往这三块白底上撒任何细碎图案之前,先回头读这三行。** ⚠️ 为什么是 DOM 里一个 ,不是接着用 background-image: 前两版走的是 --pat 内联 SVG 背景(这一批已整个删掉)。换成大字之后, SVG 背景那条路要靠 渲染中文 —— 而背景图里的 SVG 拿不到页面的 字体栈,只能听系统的;万一那台机器在这个渲染上下文里没有中文字体, 结果是**静悄悄什么都不显示**,页面看着和没做过一样。 这块地方已经被否两次了,再来一次「用户什么都没看见」太贵。 DOM 里的普通文字走的是 body 那套字体栈,不会有这种失败方式。 ⚠️ 颜色别顺手调深。12px 的灰字(--muted #A79C95)在纯白上对比度是 2.68, 压到 #F9F3EE 上掉到 2.44,再深一档 #F7EFE8 就只剩 2.36。 水印和前两版底纹不是一回事 —— 它是一大片实心色,**正压在** .dock-note 那行小灰字底下,不像波点只是零星擦过去。 另一头是:大面积本来就比小图案显眼得多,所以颜色可以、也应该 比波点那版更淡。深浅只改这一个变量。 */ --wm-color:#F9F3EE; --wm-size:132px; --tabh:78px; /* 悬浮药丸 58px + 底部留白 14px + 余量 */ --ease:cubic-bezier(.32,.72,0,1); /* 宝宝写的字:挑系统自带里最「歪歪扭扭」的手写/卡通体。 翩翩体(HanziPen SC)是 iOS/macOS 自带的儿童手写体,笔画有粗细起伏、 字面故意不方正,最像小朋友写的;手札体(Hannotate)次之; Windows 退到华文彩云/幼圆;一路兜底到圆体,绝不掉进宋体。 ⚠️ 内置来信屏删除后,这个变量现在只剩首页 slogan(.hero-slogan)在用。 */ --font-kid:"HanziPen SC","翩翩体-简","HanziPen TC","Hannotate SC","手札体-简", "Yuanti SC",YouYuan,"幼圆","Hiragino Maru Gothic ProN", "PingFang SC","Microsoft YaHei",sans-serif; } *{margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:transparent} html,body{height:100%} body{ font-family:-apple-system,BlinkMacSystemFont,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","Segoe UI",Roboto,sans-serif; background:#E8DED6;color:var(--ink);-webkit-font-smoothing:antialiased; display:flex;align-items:center;justify-content:center;overflow:hidden; } button{font:inherit;color:inherit;background:none;border:0;cursor:pointer;text-align:left} svg{fill:currentColor} b{font-weight:700} em{font-style:normal} .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0} /* ---------- 无障碍 / 触控 / 动效(WK 审计补齐) ---------- */ html{scroll-behavior:smooth;-webkit-text-size-adjust:100%;text-size-adjust:100%} body,button,a,input,textarea,select{-webkit-touch-callout:none;touch-action:manipulation} button,a,input,textarea,select,summary,[tabindex]{transition:box-shadow .15s ease} :focus{outline:none} :focus-visible{outline:3px solid rgba(244,89,60,.55);outline-offset:2px;border-radius:6px} .modal,.sheet,.search-layer,.scrim{overscroll-behavior:contain} a.skip{position:absolute;left:-9999px;top:auto;z-index:2000;background:var(--brand);color:#fff;padding:10px 16px;border-radius:10px;font-weight:700} a.skip:focus{left:16px;top:16px} /* 橙渐变上的白字:加深对比 + 轻微投影提可读性 */ .page-hero,.me-top,.home-hero,.hero-main,.week-num,.hd-card,.lc-title,.lc-prev{text-shadow:0 1px 3px rgba(120,30,10,.28)} @media (prefers-reduced-motion:reduce){ *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important} } /* ---------- 手机外框 ---------- */ .phone{ position:relative;width:430px;height:932px;max-height:100vh; background:var(--bg);overflow:hidden; border-radius:46px;box-shadow:0 40px 90px rgba(120,70,50,.28),0 0 0 11px #16110f,0 0 0 13px #2e2724; } @media (max-width:520px),(max-height:940px){ .phone{width:100vw;height:100vh;height:100dvh;max-height:none;border-radius:0;box-shadow:none} } /* ---------- 屏幕容器 ---------- */ .screens{position:absolute;inset:0} .screen{ position:absolute;inset:0;overflow-y:auto;overflow-x:hidden; -webkit-overflow-scrolling:touch;background:var(--bg); padding-bottom:calc(var(--tabh) + env(safe-area-inset-bottom) + 24px); opacity:0;visibility:hidden;transform:scale(.985); transition:opacity .28s ease,transform .32s var(--ease),visibility .28s; } .screen::-webkit-scrollbar{display:none} .screen.is-active{opacity:1;visibility:visible;transform:none;z-index:2} /* ============ 通用 ============ */ .icon-btn{width:32px;height:32px;border-radius:50%;display:grid;place-items:center;position:relative;color:#fff;transition:transform .18s,background .2s} .icon-btn.glass{background:rgba(255,255,255,.2);backdrop-filter:blur(8px)} .icon-btn.plain{background:none;font-size:20px} .icon-btn:active{transform:scale(.9)} /* .icon-btn.has-dot 已删:全站唯一的使用者是首页右上角那个消息圆钮,钮没了规则也没人用 */ .chev{font-style:normal;color:#C9BFB8;font-size:19px;line-height:1} /* 模块主标题:前面加一根竖色条做修饰,并把上间距从 26 拉到 36, 让相邻模块之间有明显的呼吸感,用户一眼能看出这是几个独立模块 */ .sec-title{ font-size:17.5px;font-weight:800;letter-spacing:-.2px;margin:36px 0 14px; display:flex;align-items:center;gap:8px; } .sec-title::before{ content:"";flex:0 0 auto;width:4px;height:18px;border-radius:3px; background:var(--brand);box-shadow:0 2px 6px rgba(244,89,60,.35); } .sec-title.c-green::before{background:var(--green);box-shadow:0 2px 6px rgba(110,154,86,.35)} .sec-title.c-purple::before{background:var(--purple);box-shadow:0 2px 6px rgba(139,111,224,.35)} .sec-title.c-blue::before{background:var(--mom);box-shadow:0 2px 6px rgba(63,117,81,.35)} /* 标题后面挂的「(必填)」。目前只有「我的 → 孕期信息」一处在用。 ⚠️ 用 --brand 不用 --muted:这是一句**要求**不是附注,灰掉就没人填了。 ⚠️ letter-spacing 显式归 0 —— .sec-title 自己带 -.2px,那是给 17.5px 大字收紧用的, 12px 的小字再收会把括号和字挤在一起。 ⚠️ 不设 margin-left:靠 .sec-title 的 gap:8 拉开;.sec-more 那条 margin-left:auto 会把「编辑 ›」推到最右,中间的空档全归它。 */ .sec-req{flex:0 0 auto;font-size:12px;font-weight:600;color:var(--brand);letter-spacing:0} .sec-more{margin-left:auto;font-size:13px;color:var(--muted);font-weight:500;white-space:nowrap} .sec-more:active{opacity:.5} /* 这里原来还有一条 .sec-sub(挂在 .sec-title 底下的一句灰色说明)。 全站只有首页那四处在用,首页换骨架之后四句说明各自搬进了模块内部 (.dock-note / .tl-h-note / .ab-foot i / .sh-note),这条就成了死规则,删掉。 ⚠️ .sec-title 本身不能删 —— 「我的」页还有两处在用。 */ .ripple{position:relative;overflow:hidden;transition:transform .16s var(--ease)} .ripple:active{transform:scale(.975)} .rp{position:absolute;border-radius:50%;background:rgba(244,89,60,.16);transform:translate(-50%,-50%) scale(0);animation:rp .55s ease-out forwards;pointer-events:none} @keyframes rp{to{transform:translate(-50%,-50%) scale(1);opacity:0}} .chips-row{display:flex;gap:9px;margin-bottom:14px;overflow-x:auto;padding-bottom:2px} .chips-row.wrap{flex-wrap:wrap;overflow:visible} .chips-row::-webkit-scrollbar{display:none} .chip{ flex:0 0 auto;padding:8px 17px;border-radius:20px;background:#fff; font-size:14px;font-weight:600;color:var(--ink-2);border:1px solid var(--line); transition:background .22s var(--ease),color .22s var(--ease),border-color .22s var(--ease); } .chip.is-active{background:var(--brand);color:#fff;border-color:var(--brand);box-shadow:0 5px 14px rgba(244,89,60,.3)} .chip:active{transform:scale(.94)} /* 「收藏」不是分类,用金色星号和左边那几个分类 chip 拉开一点区别 */ .chip-fav{color:#B8912C} .chip-fav.is-active{color:#fff;background:var(--brand);border-color:var(--brand)} /* ============ 首页 · Hero ============ 全部坐标取自设计稿 ______v25(857px 宽 = 428.5pt @2x),CSS px = 设计 px ÷ 2: 品牌「妈妈盒子」 x33 y27..58 → left 16.5 top 13.5 ≈21px (设计稿右上角还有个消息圆钮 x762.7..827.3 y20.7..86,已删,见 index.html) 进度环 圆心(202,188) 外径158 描边8 → left 61.5 top 54.5 79×79 描边4 「+3天」 x293..338 y187..205 → left 146.5 top 93.5 ≈13px 天数文案 x67 y297..314 → left 33.5 top 148.5 ≈15px 气泡宝宝插画 x424..810 y46..348 → right 23 top 23 193×151 hero 橙色区底缘:中部 ≈y420(210) 两侧 ≈y340(170) → 椭圆下沿 44px ⚠️ 上面这些是**设计稿**的数,不是现在的实现值。设计稿里没有 slogan, 加进去之后品牌字以下整列都下移了,实际纵向排布以 .home-hero 里那笔账为准。 */ /* 2026-09-30 头图 = 孕 25 周(母婴作图 v7,替代 v6:用户否了 v6 的背对造型,改回 v5 姿势——侧身、闭眼睡、 小手在嘴边、正脸可见;画风稍卡通,脐带从囊壁右上方垂下、更清晰、全程不动;不规则羊水囊、暖桃底;镜头固定)。 画幅 16:9(静帧 1280×720),构图、囊位置和 v6 一致,所以摆位数全部沿用。 背景 assets/img/7f9aace360fa.jpg(1560×750 = 3 倍图 520×250)= 静帧 yun25w-still.png 缩到 .88, 截取块中心 (656,360) 摆在 (1240,375);左/上/下不够的地方按边缘色拉伸补齐并羽化。 图高钉死 = 橙区高、右对齐,屏宽 ≤520 都铺得满;再宽就露底色 #dc8569(=图左缘色)。 会动的宝宝是叠在上面的同源 GIF,见 .hero-baby。 上面叠一层很淡的暖色左深右透渐变,只为让左边白字(孕周环、天数卡)再稳一点。 形状(高度、底部椭圆弧)不变。 */ .home-hero{ position:relative;color:#fff;overflow:hidden; background: linear-gradient(90deg,rgba(150,55,35,.20) 0%,rgba(150,55,35,.07) 38%,rgba(150,55,35,0) 58%), url(assets/img/5aec5c71b009.jpg) right center/auto 100% no-repeat, #dc8569; padding:env(safe-area-inset-top) 15px 0 16px; /* 设计稿橙区 210px。但设计稿里气泡下缘是被白卡盖住的, 现在气泡补全成整圆(高 189.5),橙区必须够高才不会被 overflow:hidden 切掉。 ── 现在是 250:slogan 挪到品牌字右边之后重算的 ── 这一竖列是一笔连着的账,橙区高度是账的**结果**,不是可以随手调的数字: hero-top 10 + 32 → 42 品牌字 + slogan 并排的那一排 hero-main 28 + 79 → 149 孕周环 hero-days 17 + 52 → 218 天数玻璃卡 letter-card 橙区底 −16 → 234 「宝宝来信」卡顶 卡顶 234 − 卡底 218 = 16px 安全间隙(旧版 13,同一个量级)。 ⚠️ 橙区**没能**跟着 slogan 一起缩回 236,是被气泡拖住的: slogan 从「独占两行」变成「和品牌字同一行」,本来省出 32px。 但同一行意味着字底落到 y=34,而气泡圆顶原来就在 y=26 —— 字会直接压在气泡上。(量过 hero-art.png 的 alpha:那是实心硬边整圆, α≥8 和 α≥220 的左缘只差 1px,没有可以压上去的透明薄边。) 于是气泡整体下移 26→40,下缘跟着从 215.5 走到 229.5, 而下缘必须留在「宝宝来信」卡顶之上(旧版留 4.5px,这里同样留 4.5): 229.5 + 4.5 = 234 = 卡顶 = 橙区高 − 16 → 橙区至少 250。 省下的 32px 里只有 2px 能还给橙区(252→250), 另外 30px 退回给中间两处空隙(hero-main 10→28、hero-days 8→17), 也就是回到没有 slogan 那一版的疏密感。 ⚠️ 动 slogan 的字号/行高、动气泡的 top、动上面任一个 margin, 都要把这四行连同上面这段气泡账一起重算。 */ height:calc(250px + env(safe-area-inset-top)); border-radius:0 0 50% 50% / 0 0 44px 44px; } .petals{position:absolute;inset:0;pointer-events:none;overflow:hidden} .petals i{position:absolute;width:8px;height:8px;background:rgba(255,255,255,.5);border-radius:60% 0 60% 0;animation:petal linear infinite} @keyframes petal{0%{transform:translateY(-20px) rotate(0);opacity:0}15%{opacity:.8}100%{transform:translateY(340px) rotate(320deg);opacity:0}} .hero-top{position:relative;z-index:3;display:flex;align-items:center;justify-content:space-between;height:32px;margin-top:10px} .hero-brand{font-size:21px;font-weight:800;letter-spacing:.5px;line-height:1} /* 三个二级页的左上角标题已删除,这一排只剩右侧按钮。 .hero-top 是 space-between 且与首页共用(首页左边还有「妈妈盒子」), 所以不能改父级对齐,只能让按钮组自己靠右 */ .hero-actions{display:flex;gap:8px;margin-left:auto} /* 品牌字**右边**的 slogan(以前是它下面的两行,这一批挪上来了)。 ⚠️ margin-right:auto 是这条规则的关键,不是随手加的间距。 父级 .hero-top 是 space-between 且四页共用,不能动它的对齐; auto 边距把那一排的富余空间全吃掉,第二个孩子就不会被甩到最右边, 而是紧贴着品牌字排。删了它,slogan 会跑到屏幕右上角、压在气泡上。 (同一个路子见上面的 .hero-actions{margin-left:auto}。) ⚠️ nowrap 必须留着。CJK 可以在任意两字之间换行,一旦允许浏览器自己挑, 10 个字会折成两行 —— 而这一排是写死的 height:32,第二行会直接溢出, 并且横着压到气泡上(气泡只让开了一行的高度,见 .home-hero 那笔账)。 ⚠️ 字号 13 / 行高 16 都写死成 px,不是倍数:橙区那笔竖列账和 「字底 y=34 < 气泡顶 y=40」这条净空都是按这两个数算的。 字体走 --font-kid(翩翩体 / 手札体那套手写体)—— 用户要「不要那种规规矩矩的 字体」。这套字体栈全站共用一份(原先来信正文也用它),不新写几乎一样的第二套: 两套栈只要有一套漏了某个平台,就会出现「同一台机器上两处手写体长得不一样」, 而这种漂移没人会去对。手写体笔画细,白字压在橙色渐变上容易发虚, 所以 font-weight 提到 700、opacity 给到 .92(比旧版 .88 实一点)。 */ .hero-slogan{position:relative;z-index:3;margin:0 auto 0 9px; font-family:var(--font-kid); font-size:13px;line-height:16px;font-weight:700;letter-spacing:.3px; opacity:.92;white-space:nowrap} /* margin-top 曾被 slogan 压到 10,slogan 挪到品牌字右边后退回 28 (比原始的 24 还多 4,是气泡下移之后腾出来要填的空)。 见 .home-hero 里那笔竖列账 —— 这个数不是独立的,改它要连着改橙区高度。 */ .hero-main{position:relative;z-index:3;display:flex;align-items:flex-start;gap:6px;margin:28px 0 0 45.5px} .week-ring{position:relative;width:79px;height:79px;flex:0 0 auto;border-radius:50%;background:rgba(255,255,255,.07)} .ring-svg{width:100%;height:100%;transform:rotate(-90deg);display:block} .ring-bg{fill:none;stroke:rgba(255,255,255,.26);stroke-width:6} .ring-fg{fill:none;stroke:#fff;stroke-width:6;stroke-linecap:round;stroke-dasharray:1000;stroke-dashoffset:1000;transition:stroke-dashoffset 1.4s var(--ease)} .week-num{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center} .week-num b{font-size:38px;font-weight:800;line-height:1;letter-spacing:-1px} .week-num span{font-size:12px;opacity:.92;margin-top:3px} .week-plus{font-size:13px;font-weight:600;opacity:.95;margin-top:37px} /* 首页 hero 主插画:取自设计稿像素。设计稿里气泡下缘被白卡遮住, 已按拟合圆(设计坐标 圆心 620.1,246.3 半径 187.4)补全为整圆, 378px 图 → 189.5 CSS px。 ⚠️ top 由 26 改成 40,是被 slogan 逼的,不是调构图。 slogan 挪到品牌字右边之后,字底落在 y=34;气泡圆顶原来就在 y=26, 白字会直接盖在气泡上。解过这张 PNG 的 alpha 通道确认过: 这幅画就是**实心整圆、边缘是硬的**(α≥8 与 α≥220 的左缘只差 1px), 没有可以让字压上去的透明薄边,所以只能整幅往下让。 下移之后圆心 (屏宽−25−94.75, 134.75)、下缘 40+189.5=229.5, 必须留在「宝宝来信」卡顶(234)之上 —— 这就是橙区高必须 ≥250 的来源。 改 top 前先读 .home-hero 里那笔竖列账。 */ /* 会动的宝宝(2026-09-30,v7):GIF assets/img/91cf003e93b3.gif = 原 GIF(800×450,16fps,3 秒无缝循环) 截 x185 y0 起 450×450(整高),不缩放,1.8MB。v7 宝宝动作实测在原 GIF x310..515 y105..365, 离截块中心最远 ≈168px,遮罩 80% 实心半径 = 180px,包得住。 摆位:背景里静帧缩了 .88(静帧是 GIF 的 1.6 倍),这块 = 静帧 720 → 634 画布像素,左上角落在 (923,58), 换算成橙区高 H:宽高 634/750 = .8453H,顶 58/750 = .0773H,右 (1560−1557)/750 ≈ .004H。 背景就是同一画面的静帧、镜头固定,所以只需一圈宽羽化遮罩(80%→100%)把方块边化掉, 囊里光点在羽化圈冻结成静帧也看不出来。加载完之前 opacity:0,JS 收到 load 再淡入, 没加载出来就一直是背景那一帧。用户要求:囊不动,只让宝宝自己动 —— 所以这一层没有任何 transform 动画。 */ .hero-baby{position:absolute;z-index:2; top:calc((250px + env(safe-area-inset-top)) * .0773); right:calc((250px + env(safe-area-inset-top)) * .004); width:calc((250px + env(safe-area-inset-top)) * .8453); height:calc((250px + env(safe-area-inset-top)) * .8453); pointer-events:none;user-select:none} .hero-kid{position:absolute;inset:0;width:100%;height:100%; object-fit:cover;background:transparent;opacity:0;transition:opacity .8s ease; -webkit-mask-image:radial-gradient(closest-side,#000 80%,transparent 100%); mask-image:radial-gradient(closest-side,#000 80%,transparent 100%)} .hero-kid.is-on{opacity:1} /* 系统开了「减少动态效果」就全部停下:这类装饰性循环动画是前庭不适的常见诱因 */ @media (prefers-reduced-motion:reduce){ .hero-kid{display:none} } /* 天数文案:一张毛玻璃小卡,不再是裸字浮在橙底上。 ⚠️ 这块的高度是有硬预算的,改字号前先算一遍: 橙区固定 250px,而「宝宝来信」卡 margin-top:-16 → 卡顶落在 y=234, 且它横跨 x 75..324,和这张小卡(x 17.5..~158)左半边是重叠的。 往上推:hero-top 42 + hero-main(28+79) = 149,本块 margin-top 17 → 顶在 166。 所以卡身高度必须 ≤ 68px 才留得出安全间隙。 行高全部写死成 px 而不是倍数,就是为了让这笔账可算、不随字体变。 当前:padding 7+8 + who 16 + gap 1 + tail 20 = 52 → 底边 218,离 234 还有 16px。 (margin-top 曾为 slogan 压到 8,slogan 挪走后退回 17,见 .home-hero 里的竖列账) */ .hero-days{position:relative;z-index:3;margin:17px 0 0;padding-left:17.5px;max-width:196px} .hd-card{display:inline-flex;flex-direction:column;gap:1px;padding:7px 13px 8px;border-radius:16px; background:rgba(255,255,255,.17);border:1px solid rgba(255,255,255,.3); box-shadow:0 6px 18px rgba(163,60,38,.13); -webkit-backdrop-filter:blur(12px) saturate(1.25);backdrop-filter:blur(12px) saturate(1.25)} /* 不支持 backdrop-filter 的机器上,半透明白会发灰、字浮不起来, 把底色调实一点把对比度补回来 */ @supports not ((backdrop-filter:blur(2px)) or (-webkit-backdrop-filter:blur(2px))){ .hd-card{background:rgba(255,255,255,.26)} } /* gap 从 5px 改成 0,那 5px 挪到 .hd-heart 的 margin-right 上: 现在这一行是「♥ 小名 + 在妈妈肚子里」,小名和后半句必须**贴着**, 留着 gap:5px 会在中间豁开一道缝,读起来像两个词。 */ .hd-who{display:flex;align-items:center;gap:0;font-size:13px;font-weight:700;opacity:.95;line-height:16px;min-width:0} /* ⚠️ 小名那格是 maxlength="12"。12 字 ×14px = 168px,加上 ♥ 和「在妈妈肚子里」 远超 .hero-days 的 max-width:196px。这一行是 flex(默认不换行), 不给截断就会直接溢出到旁边的插画上。 截断的优先级放在**小名**上而不是后半句:小名被截成「小汤圆宝宝…」还认得出, 后半句被截掉则整句话不成话。 */ .hd-who b{font-size:14px;font-weight:800;letter-spacing:.2px; min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} /* 后半句不参与压缩,永远完整 */ .hd-where{flex:0 0 auto} .hd-heart{flex:0 0 auto;display:block;margin-right:5px} /* 整体 nowrap:这张卡就是按这一行的宽度定的,断行会把数字甩下去 */ .hd-tail{white-space:nowrap;font-size:12.5px;opacity:.88;line-height:20px} .hd-tail b{font-size:17px;font-weight:800;letter-spacing:-.3px;opacity:1;margin:0 1px} /* 「宝宝来信」卡:设计稿 x150..648 → left 75 · 宽 249 · 高 80。 气泡补全成整圆后下缘到 215.5,卡顶必须 ≥215.5 才不会再压住宝宝, 故上移量由 34.5 改为 16(橙区 252 − 16 = 卡顶 236)。 橙区因 slogan 从 236 加到 252 之后,卡顶跟着从 220 落到 236, 离气泡下缘 215.5 更远了,这一条只会更安全,不用动。 */ .letter-card{ position:relative;z-index:6;display:flex;align-items:center;gap:9px; width:249px;height:80px;margin:-16px 0 0 75px; background:rgba(255,255,255,.92);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px); border-radius:20px;padding:0 12px 0 13.5px;box-shadow:0 10px 26px rgba(150,60,40,.16); } /* 没有未读时整张收起来(hideLetterCard() 挂的类)。 这个库里没有全局 .hide,都是逐个元素声明的(.moment.hide / .rl-gift.hide 同一个路子)。 */ .letter-card.hide{display:none} /* 信封外面包一层,只为了给「有新回信」的小红点一个定位参照 */ .lc-envwrap{position:relative;flex:0 0 auto;line-height:0} .lc-env{width:64px;height:auto;display:block;filter:drop-shadow(0 4px 8px rgba(200,90,70,.22))} .letter-card.has-new .lc-envwrap::after{ content:"";position:absolute;top:2px;right:-1px;width:10px;height:10px;border-radius:50%; background:var(--brand);box-shadow:0 0 0 2.5px #fff;animation:newPulse 1.6s var(--ease) infinite; } @keyframes newPulse{0%,100%{transform:scale(1)}50%{transform:scale(1.28)}} /* 卡内正文固定三行:标题 / 摘要 / 去看看。overflow:hidden 兜底, 哪行文案再长也不会挤出第四行 */ .lc-body{min-width:0;flex:1;overflow:hidden} .lc-title{font-size:16px;font-weight:800;color:var(--ink);line-height:1.2;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} .lc-desc{font-size:11.5px;color:var(--ink-2);margin:4px 0 5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} /* 尖括号必须跟文字同行:宝宝回信后这行会变长,之前它会被挤到下一行单独站着 */ .lc-link{display:flex;align-items:center;gap:3px;font-size:12.5px;font-weight:700;color:var(--brand);white-space:nowrap} .lc-link span{min-width:0;overflow:hidden;text-overflow:ellipsis} .lc-link i{flex:0 0 auto;font-style:normal} /* ============ 首页 · body ============ */ .home-body{padding:0 26px} /* ⚠️ 这两条原来挂在 .sec-title 上。首页不再有 .sec-title 了,选择器必须跟着换到 新的第一块 .tool-dock —— 忘了换不会报错,只会静默失效(来信卡收起来时 头图底下那 64px 的洞补不回来),所以 smoke 里专门钉了一条。 */ /* 2026-09-30:第一块换成了 .daily-check(孕期每日小打卡),这两条改成「谁是第一块就给谁」, .tool-dock 退成第二块,间距并进下面 .today-line,.shelf 那条 16px。 */ .home-body>:first-child{margin-top:21px} /* 来信卡收起来时,它原本占的 64px 流高(margin-top:-16 + height:80)没了, 只剩这 21px 顶着一大片橙色头图,太挤。补到 30px。 走类名而不是 :has(),老一点的移动端浏览器上 :has() 不一定有。 */ .home-body.no-letter>:first-child{margin-top:30px} .page-body{padding:0 18px;margin-top:-46px;position:relative;z-index:5} .page-body.no-top{margin-top:8px} /* ============ 首页三大块的公共外壳 ============ */ /* 上一稿这三块各造了一种底:米色托盘 / 没有容器 / 白气泡 + 糖果卡, 四种表面语言堆在一屏里,结果就是「不规矩」。 这一稿收敛成一条规矩:**结构可以各不相同,表面必须一模一样**。 三块统一是「白色通栏色块」—— 左右各吃掉 .home-body 的 26px 内边距顶到屏幕边缘, 块与块之间露出米色页底当缝。结构上的差别(宫格 / 时间线 / 横向卡带)一点没动, 变化留在骨架里,表面不掺和,这样才是既不单调又不乱。 颜色只允许出现在小构件上:工具图标块、书封、时间线圆点、AI 气泡、各种胶囊。 ⚠️ padding 左右必须正好等于 26,抵回负外边距,里面的内容才和页面其余部分对齐 —— 对齐的是内容,出血的是底色,这两件事要分开。 ⚠️ 三块的圆角、底色、左右内边距改成在这里一处定义。以后要调,改这一条, 别再回到各自的规则里单独写,那正是上一稿乱掉的原因。 */ .daily-check,.tool-dock,.game-promo,.preg-tips,.today-line,.tree-hole,.shelf{ margin:0 -26px;padding:16px 26px 18px;border-radius:26px; background-color:#fff; /* ⚠️ 这两条是一对,缺一不可,而且必须一起看: 它们让每一块自己成为一个**层叠上下文**,好让块里那枚 .wm(大字水印) 用 z-index:-1 停在「白底之上、内容之下」这一层。 position:relative 单写不够 —— z-index 是 auto 时不建层叠上下文, -1 就会一路掉到这块白底的**后面**去,水印整个消失。 所以这里的 z-index:0 看着像句废话,其实是水印能不能显示的开关。 */ position:relative;z-index:0; } /* 块间距。给后两块,第一块的上间距另有规则(来信卡收放要用)。 ⚠️ 这是**块与块之间**的缝。某一块自己内部觉得挤,要调的是那块的 padding, 不是这里 —— 改这里会把三块的关系一起改掉。 */ .tool-dock,.game-promo,.preg-tips,.today-line,.tree-hole,.shelf{margin-top:16px} /* ===== 后两块的暖色渐变底(本批新增)===== 用户原话:「在那个宝宝的今日脚印那块,稍微给背景它加一点渐变」 「本周孕育指南的也是……但不用加那么重」 —— 所以两块同一套形状、不同强度;.tool-dock **保持纯白**,用户没提, 而且它背后压着那枚「妈妈」大字水印,底色一动水印的浓淡就得重调。 ⚠️⚠️ 角度必须是 90deg,而且左边 32% 必须保持**纯白**。这不是审美选择, 是被「今日脚印」那条时间线的实现方式逼出来的硬约束: 时间线是一条 1.5px 的竖线(.today-line::before),线上那些圆点靠 **一圈不透明的外壳底色**把线「咬断」,一共四处,全部写死 #fff: .tl-h-dot box-shadow 0 0 0 3.5px #fff … 0 0 0 8px #fff(还负责盖住线头) .st-dot box-shadow 0 0 0 3px #fff .ab-dot box-shadow 0 0 0 3px #fff .ai-bubble::after background:#fff(把最后一个点以下那截线擦掉) 这四处全都钉在竖线那一列(--tl-x ≈ 63.5px,算上光晕最远到 x≈76px)。 底色一旦在那一列变成暖色,这四处就成了四块**白斑**压在暖底上 —— 而且是「看着像渲染没刷新」的那种,不是「颜色不好看」。 90deg 的渐变颜色**只跟 x 有关、与 y 和卡高无关**,才给得出一句 可验证的保证:x < 32% 之内恒为 #fff。斜着走(比如 150deg)就不行 —— 同一列的顶部和底部会落在渐变的不同位置,卡一变高约束就悄悄破了。 余量账(最窄的 320 屏,外壳出血后宽 336px): 白区 = 336 × 32% = 107.5px,光晕最远 76px,余 31.5px。 屏越宽白区越宽(390 屏 130px),320 是最紧的一档,够。 ⚠️ 要改角度或起止位置,先把上面四处 #fff 一起解决掉,否则一定出白斑。 ⚠️ .shelf 那块**没有**这个约束(它的书卡各自带不透明底色,叠压头像描的边 走 --sb-bg,都不依赖外壳)。这里仍写成同样的 32% 白区,纯粹是为了让上下 相邻的两块「渐变从同一个位置开始」—— 起点不齐会看着像没对齐的意外。 别把它当成 .shelf 自己的技术要求。 ⚠️ 用 background-image 而不是 background 简写:简写会把上面那条公共规则里的 background-color:#fff 一起清掉,渐变要是哪天被覆盖或不支持,就直接透出 页面的米色底了。分开写,白底始终在最下面兜着。 */ .today-line{ background-image: /* 右上角一点柔光,让它不只是「从左到右变暖」。放在 x=96%, 离竖线那一列(x≈63.5px)远得很,不参与上面那笔账。 */ radial-gradient(130px 90px at 96% 3%, rgba(255,206,178,.30), rgba(255,206,178,0) 72%), linear-gradient(90deg,#fff 0%,#fff 32%,#FFF9F4 64%,#FFF2E7 100%); } /* 「不用加那么重」:同样的 90deg、同样的 32% 白区,终点浅一半 (#FFF8F3 之于 #FFF2E7),也不加那道柔光。 */ .shelf{ background-image:linear-gradient(90deg,#fff 0%,#fff 32%,#FFFCFA 64%,#FFF8F3 100%); } /* 大字水印「妈妈」。**全站只有一枚,在工具区(.tool-dock)。** ⚠️ 上一稿是三块各放一枚,被否了:「今日成长脚印和本周孕育指南那两个去掉, 只保留工具那个。」三枚同样的字顺着首页排下来,本身又成了一种重复 —— 一枚是印章,三枚是底纹,而底纹这个方向已经翻过两次车了。 **别再往 .today-line / .shelf 上加回去。** ⚠️ 它和标题是一对:标题写着「小汤圆的孕育工具」(跟着小名走), 水印压在后面写着「妈妈」。工具是给宝宝用的,动手的是妈妈。 所以水印这两个字**不跟小名变**,它本来就不是在说宝宝。 尺寸和位置是按「露出多少」倒推的,不是随手填的: · 工具区从块顶到宫格之间只有约 75px 是透空的(16 内边距 + 抬头行 + 说明行), 往下整片都被不透明的工具卡铺满(.mini-card 是实心渐变底)。 · 132px 的字,字面高约 113px,于是**露出上面六成,下面四成沉到卡片背后** —— 「可以被数胎动、孕期体重那些卡挡住,只保留露出部分就行」,说的就是这个。 · 再往大调会好看,但露出的比例会跟着掉;掉到一半以下时,「妈妈」两个字 只剩上半截,就认不出来了。调 --wm-size 之前先想清楚这笔交换。 ⚠️ letter-spacing 用 em 不用 px:跟着字号缩放,改 --wm-size 时不用再回来改这行。 负值是要的 —— 两个字挨紧才像一枚印章,松开就散成两个字了。 ⚠️ pointer-events:none:工具卡整张都是可点区域,水印绝不能吃掉点击。 z-index:-1 本来也轮不到它接事件,但这行是白纸黑字的保险。 */ .wm{ position:absolute;top:0;right:16px;z-index:-1; font-size:var(--wm-size);font-weight:900;line-height:1;letter-spacing:-.04em; color:var(--wm-color); pointer-events:none;user-select:none;-webkit-user-select:none; } /* 水印比抬头那条透空带高,得有人把它裁在圆角里,否则字面顶部会从块的 上边缘冒出去,糊在头图底下。裁在这块自己身上就够 —— 只有它有水印。 (宫格四周有 26px 内边距,工具卡的投影够不到边缘,裁掉不了任何东西。) */ .tool-dock{overflow:hidden} /* 三块的抬头用同一套字号和间距。上一稿我给三个「更多」入口做了三种样子 (白胶囊 / 灰字 / 灰字),毫无理由地不一致 —— 同一层级的东西就该长一样。 ⚠️ .dock-all 原来是白底胶囊,托盘变白之后白底压白底会直接消失, 顺手一起并进这条统一规则里了。 */ .dock-title,.tl-h-title,.sh-title{font-size:16.5px;font-weight:800;letter-spacing:-.2px} .dock-all,.tl-h-all,.sh-all{ margin-left:auto;flex:0 0 auto;white-space:nowrap; font-size:12px;font-weight:600;color:var(--muted); } .dock-all:active,.tl-h-all:active,.sh-all:active{opacity:.5} /* 三块的说明也用同一套。上一稿 .dock-note 是半透明白 chip、另两条是灰字, 同样是没道理的三选一 —— chip 那个样子是为了在深色托盘上读得清, 底一变白,chip 的白底就没意义了,统一回灰字最干净。 */ .dock-note,.sh-note,.tl-h-note{font-size:12px;color:var(--muted);line-height:1.5} /* ============ 模块零 · 孕期每日小打卡(2026-09-30)============ 外壳走上面那条公共白色通栏(.daily-check 已并进去)。内部是三行「图标 · 名称 · 状态标签 · ›」, 整行是按钮。标签三种状态:默认(浅橙,动作提示/未完成)、.is-done(绿,已打卡带 ✓)、 .is-warn(红,待补记 / 今天就是产检日)。 ⚠️ 行高按手指靶子给到 46px;最窄 320 屏下标签最长是「距糖耐还有 12 天」≈ 100px, 名称列固定不收缩、标签可省略,挤不爆。 */ .daily-check{padding-top:14px;padding-bottom:8px} .dc-head{display:flex;align-items:center;gap:8px;margin-bottom:4px} .dc-title{font-size:16.5px;font-weight:800;letter-spacing:-.2px} .dc-done{margin-left:auto;flex:0 0 auto;font-size:12px;font-weight:600;color:var(--muted)} .dc-done.is-all{color:var(--green)} .dc-done.hide{display:none} .dc-row{display:flex;align-items:center;gap:10px;width:100%;height:46px;padding:0; background:none;border:0;text-align:left;color:inherit;font:inherit} .dc-row+.dc-row{border-top:1px solid var(--line)} .dc-row:active{opacity:.6} .dc-ico{flex:0 0 auto;width:30px;height:30px;object-fit:contain} .dc-name{flex:0 0 auto;font-size:14.5px;font-weight:700} .dc-tag{margin-left:auto;min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis; padding:3px 9px;border-radius:999px;font-size:12px;font-weight:600; color:var(--brand-dk);background:#FFF0EA} .dc-tag.is-done{color:var(--green);background:#EEF5EA} .dc-tag.is-done::before{content:"✓ "} .dc-tag.is-warn{color:var(--alert);background:#FDECE8} .dc-row .chev{flex:0 0 auto;font-size:16px;margin-left:-4px} /* ============ 宝宝消消乐 · 推广入口(2026-09-30)============ 糖果色渐变大卡:左边名字 + 一句玩法 + 「开始玩」胶囊,右边 3×3 小棋盘循环演示「三连消除」, 角上三颗星星闪烁。整张卡是一个按钮。动效在 prefers-reduced-motion 下关掉。 */ .game-promo.hide{display:none} .gp-card{position:relative;display:flex;align-items:center;gap:10px;width:100%;overflow:hidden; border:0;border-radius:22px;padding:16px 14px 16px 18px;text-align:left;font:inherit;color:#fff; background:linear-gradient(125deg,#FF8FA3 0%,#FFB07C 55%,#FFD36E 100%); box-shadow:0 10px 24px rgba(255,130,120,.28)} .gp-card::before{content:"";position:absolute;left:-40px;bottom:-60px;width:160px;height:160px;border-radius:50%; background:rgba(255,255,255,.16)} .gp-card:active{transform:scale(.98)} .gp-new{position:absolute;left:0;top:0;font-size:10.5px;font-weight:800;color:#E4476A;background:#FFF3C4; border-radius:0 0 12px 0;padding:3px 10px 3px 12px;letter-spacing:.5px} .gp-text{position:relative;flex:1;min-width:0;display:flex;flex-direction:column;align-items:flex-start;padding-top:8px} .gp-name{font-size:21px;font-weight:900;letter-spacing:.5px;text-shadow:0 2px 0 rgba(214,86,86,.35)} .gp-sub{margin-top:5px;font-size:12px;line-height:1.55;color:rgba(255,255,255,.95)} .gp-cta{margin-top:10px;display:inline-flex;align-items:center;gap:3px;border-radius:999px;padding:6px 14px; font-size:13px;font-weight:800;color:#E4476A;background:#fff;box-shadow:0 4px 10px rgba(200,70,70,.2); animation:gpBeat 2.2s ease-in-out infinite} @keyframes gpBeat{0%,70%,100%{transform:scale(1)}80%{transform:scale(1.08)}90%{transform:scale(.97)}} .gp-board{position:relative;flex:0 0 auto;display:grid;grid-template-columns:repeat(3,30px);gap:4px;padding:6px; border-radius:14px;background:rgba(255,255,255,.35);transform:rotate(4deg)} .gp-board i{display:grid;place-items:center;width:30px;height:30px;border-radius:9px;background:#fff; font-style:normal;font-size:18px;line-height:1;box-shadow:0 2px 0 rgba(220,120,100,.25); transition:transform .35s cubic-bezier(.3,1.6,.5,1),opacity .3s} .gp-board i.is-pop{transform:scale(1.3);opacity:0} .gp-board i.is-in{animation:gpDrop .45s cubic-bezier(.3,1.5,.5,1)} @keyframes gpDrop{from{transform:translateY(-16px);opacity:0}to{transform:none;opacity:1}} .gp-board i.is-hint{background:#FFF6D6;box-shadow:0 0 0 2px #FFD36E} .gp-spark{position:absolute;color:#fff;font-size:12px;animation:gpTw 1.8s ease-in-out infinite;opacity:0} .gp-spark.s1{right:12px;top:8px}.gp-spark.s2{right:120px;top:14px;animation-delay:.6s;font-size:9px} .gp-spark.s3{right:16px;bottom:10px;animation-delay:1.2s;font-size:10px} @keyframes gpTw{0%,100%{opacity:0;transform:scale(.6)}50%{opacity:1;transform:scale(1)}} @media (prefers-reduced-motion:reduce){.gp-cta,.gp-spark{animation:none}.gp-spark{opacity:.8}} /* ============ 孕期小知识(2026-09-30)============ 外壳是公共白色通栏。里面三层: ① .pt-today 今日小知识大卡:暖粉渐变 + 右上角一颗慢慢浮动的「宝宝大小」emoji(本周水果); 底部 7 个圆点是本周第 1–7 天,今天实心、以前可回看、以后锁着。 ② .pt-grid 四张马卡龙色小卡:宝宝 / 妈妈 / 饮食 / 注意,进入视口时依次浮上来。 ③ .pt-foot 一行免责小字。 动效全部在 prefers-reduced-motion 下关掉。 */ .preg-tips.hide{display:none} .pt-head{display:flex;align-items:baseline;gap:8px;margin-bottom:10px} .pt-title{font-size:16.5px;font-weight:800;letter-spacing:-.2px} .pt-when{margin-left:auto;font-size:12px;font-weight:700;color:var(--brand); background:#FFF0EA;border-radius:999px;padding:3px 10px} .pt-today{position:relative;overflow:hidden;border-radius:20px;padding:14px 16px 12px; background:linear-gradient(135deg,#FFE9E1 0%,#FFF1E6 55%,#FFF7EE 100%)} .pt-today::after{content:"";position:absolute;right:-30px;top:-40px;width:130px;height:130px;border-radius:50%; background:radial-gradient(circle,rgba(255,255,255,.75),rgba(255,255,255,0) 70%);pointer-events:none} .pt-float{position:absolute;right:14px;top:10px;font-size:34px;line-height:1;z-index:1; animation:ptFloat 3.6s ease-in-out infinite;filter:drop-shadow(0 4px 6px rgba(200,110,80,.18))} @keyframes ptFloat{0%,100%{transform:translateY(0) rotate(-4deg)}50%{transform:translateY(-6px) rotate(4deg)}} .pt-badge{display:inline-block;font-size:11px;font-weight:700;color:#fff;border-radius:999px;padding:2px 9px; background:linear-gradient(90deg,#F4593C,#FF8A66)} .pt-body{min-height:88px;padding-right:44px} .pt-body.is-in{animation:ptIn .42s var(--ease)} @keyframes ptIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}} .pt-t{margin-top:8px;font-size:16px;font-weight:800;color:#5A2E22;letter-spacing:-.2px} .pt-d{margin-top:5px;font-size:13px;line-height:1.65;color:#6B4B40} .pt-days{display:flex;justify-content:space-between;margin-top:10px;padding-top:10px;border-top:1px dashed rgba(224,74,46,.18)} .pt-day{flex:0 0 auto;display:flex;flex-direction:column;align-items:center;gap:3px; background:none;border:0;padding:0;font:inherit;color:#B08A7C} .pt-day i{display:block;width:26px;height:26px;border-radius:50%;line-height:26px;text-align:center; font-style:normal;font-size:11.5px;font-weight:700;background:rgba(255,255,255,.75);color:#C07A64; transition:transform .2s var(--ease),background .2s} .pt-day span{font-size:10px} .pt-day.is-past i{background:#fff;color:#E0725A} .pt-day.is-today i{background:linear-gradient(135deg,#F4593C,#FF8A66);color:#fff; box-shadow:0 0 0 3px rgba(244,89,60,.18);animation:ptPulse 2.4s ease-in-out infinite} .pt-day.is-today span{color:var(--brand);font-weight:700} @keyframes ptPulse{0%,100%{box-shadow:0 0 0 3px rgba(244,89,60,.18)}50%{box-shadow:0 0 0 6px rgba(244,89,60,.06)}} .pt-day.is-sel i{transform:scale(1.14)} .pt-day.is-sel:not(.is-today) i{background:#FFD9CC;color:#C24A30} .pt-day.is-lock i{background:rgba(255,255,255,.45);color:#D9BDB2} .pt-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px} .pt-card{position:relative;border-radius:16px;padding:11px 12px 12px;min-width:0} .pt-card b{display:block;font-size:13px;font-weight:800;margin-top:4px} .pt-card p{margin:4px 0 0;font-size:12px;line-height:1.55;color:var(--ink-2)} .pt-ico{display:inline-grid;place-items:center;width:30px;height:30px;border-radius:10px;background:rgba(255,255,255,.8);font-size:17px} .pc-baby{background:linear-gradient(160deg,#FFF1E8,#FFE6DA)} .pc-baby b{color:#C4583C} .pc-mom{background:linear-gradient(160deg,#FCEFF5,#F8E1EC)} .pc-mom b{color:#B3547E} .pc-eat{background:linear-gradient(160deg,#EFF7EA,#E3F0DB)} .pc-eat b{color:#4F7F3E} .pc-care{background:linear-gradient(160deg,#EEF3FB,#E1EAF7)} .pc-care b{color:#4A6FA6} /* 进入视口依次浮上来(JS 给 .pt-grid 加 .is-shown;不支持 IntersectionObserver 时直接加) */ .pt-grid .pt-card{opacity:0;transform:translateY(12px);transition:opacity .5s ease,transform .6s var(--ease)} .pt-grid.is-shown .pt-card{opacity:1;transform:none} .pt-grid.is-shown .pt-card:nth-child(2){transition-delay:.08s} .pt-grid.is-shown .pt-card:nth-child(3){transition-delay:.16s} .pt-grid.is-shown .pt-card:nth-child(4){transition-delay:.24s} .pt-foot{margin-top:9px;font-size:11px;color:var(--muted);text-align:center} /* ============ 妈妈的树洞(2026-09-30)============ 浅薄荷→奶白的底,和上下暖色块拉开,读起来「安静」。右侧一棵 SVG 小树, 树干上的洞(#thHole)是纸团飞进去的落点。扔进去后:纸团飞入 → 洞口亮一下、树冠晃一下 → 卡内出现「已收好」。不做任何回应文字(用户选定)。 */ .tree-hole{background-image:linear-gradient(160deg,#F1F8EE 0%,#FAFCF6 55%,#FFFDF9 100%)} .th-head{display:flex;align-items:center;gap:8px} .th-title{font-size:16.5px;font-weight:800;letter-spacing:-.2px} .th-lock{margin-left:auto;display:inline-flex;align-items:center;gap:4px;font-size:11.5px;font-weight:600; color:#5E8A55;background:#E4F1DF;border-radius:999px;padding:3px 9px} .th-stage{display:flex;align-items:flex-end;gap:6px;margin-top:6px} .th-lead{flex:1;min-width:0;font-size:13px;line-height:1.7;color:#5C6B58;padding-bottom:10px} .th-tree{flex:0 0 auto;width:104px;height:108px;overflow:visible} .th-crown{transform-origin:60px 70px;animation:thSway 5s ease-in-out infinite} @keyframes thSway{0%,100%{transform:rotate(-1.2deg)}50%{transform:rotate(1.2deg)}} .th-tree.is-eat .th-crown{animation:thShake .7s ease-in-out} @keyframes thShake{0%,100%{transform:rotate(0)}25%{transform:rotate(-4deg)}60%{transform:rotate(3deg)}} .th-tree.is-eat .th-hole{animation:thGlow .9s ease-out} @keyframes thGlow{0%{fill:#7A5238}35%{fill:#F4C38F}100%{fill:#7A5238}} .th-form{margin-top:4px;background:#fff;border:1px solid #E3EEDD;border-radius:16px;padding:10px 12px} .th-form textarea{display:block;width:100%;border:0;outline:0;resize:none;background:transparent; font:inherit;font-size:14px;line-height:1.6;color:var(--ink)} .th-form textarea::placeholder{color:#A9B5A4} .th-row{display:flex;align-items:center;gap:8px;margin-top:6px} .th-mine{border:0;background:none;padding:0;font:inherit;font-size:12px;font-weight:600;color:#6F8A68} .th-mine b{font-weight:800} .th-send{margin-left:auto;border:0;border-radius:999px;padding:8px 18px;font:inherit;font-size:13.5px;font-weight:700; color:#fff;background:linear-gradient(90deg,#7FB573,#98C98A);box-shadow:0 6px 14px rgba(110,160,95,.25)} .th-send:disabled{opacity:.45;box-shadow:none} .th-send:active{transform:scale(.96)} .th-done{height:0;overflow:hidden;text-align:center;font-size:13px;font-weight:700;color:#5E8A55; transition:height .3s var(--ease),margin .3s var(--ease)} .th-done.is-on{height:22px;margin-top:10px;animation:ptIn .4s var(--ease)} .th-done .th-sos{font-weight:500;color:var(--ink-2)} .th-done.is-sos{height:auto} .th-note{position:fixed;z-index:60;left:0;top:0;pointer-events:none;border-radius:10px; background:#FFFDF6;box-shadow:0 6px 18px rgba(90,110,80,.25);padding:6px 9px;font-size:12px;color:var(--ink-2); max-width:180px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} .th-list{list-style:none;margin:10px 0 0;padding:0} .th-list.hide{display:none} .th-list li{position:relative;background:#fff;border-radius:14px;padding:9px 34px 9px 12px;margin-top:8px; border:1px solid #EAF2E6} .th-list time{display:block;font-size:11px;color:#8FA088} .th-list p{margin:3px 0 0;font-size:13px;line-height:1.6;color:var(--ink-2);white-space:pre-wrap;word-break:break-all} .th-list .th-del{position:absolute;right:8px;top:8px;border:0;background:none;padding:2px 4px;font-size:15px;color:#B9C4B4} .th-list .th-empty{text-align:center;color:var(--muted);font-size:12px;background:none;border:0} .th-help{margin-top:10px;font-size:11px;line-height:1.6;color:var(--muted)} .th-help a{color:#5E8A55;font-weight:700} @media (prefers-reduced-motion:reduce){ .pt-float,.pt-day.is-today i,.th-crown{animation:none} .pt-grid .pt-card{opacity:1;transform:none;transition:none} } /* ============ 模块一 · 工具 ============ */ .dock-head{display:flex;align-items:center;gap:8px;margin-bottom:7px} /* 说明行仍是 inline-flex:前面那枚小图标要和文字同行居中, 但不能撑满整行(撑满的话图标会被推到左边很远)。 */ .dock-note{display:inline-flex;align-items:center;gap:5px;margin-bottom:11px} .dock-note svg{flex:0 0 auto;color:var(--brand);opacity:.8} /* Bento */ /* 卡进了白底容器,各自那圈阴影就没用了 —— 白底上叠浅阴影只会显脏, 五份糊在一起反而看不出是五张卡。圆角同步收一档,配小一号的画幅。 */ .tool-dock .mini-card{box-shadow:none;border-radius:18px} /* 第三列从 .96fr 提到 1fr(第一列 1.3 补回来):这一列底下新添了「更多工具」, 四个字加一个 ›,按老比例在 320px 视口下这列只有 71px,减掉内边距剩 55px, 正好差一点点会顶出去。 */ .bento{display:grid;grid-template-columns:1.3fr 1fr 1fr;gap:10px} .bento-col{display:flex;flex-direction:column;gap:10px} .mini-card{position:relative;border-radius:20px;padding:14px;overflow:hidden;box-shadow:var(--sh)} .mc-title{font-size:19px;font-weight:800;letter-spacing:-.3px} .mc-title.sm{font-size:15px} .mc-sub{font-size:12px;color:var(--ink-2);margin-top:3px} .mc-btn{display:inline-block;margin-top:12px;background:var(--brand);color:#fff;font-size:13px;font-weight:700;padding:6px 15px;border-radius:14px;box-shadow:0 4px 10px rgba(244,89,60,.3)} .mc-art{position:absolute;width:52px;height:auto;right:6px;bottom:2px;filter:drop-shadow(0 5px 10px rgba(160,90,70,.18))} .mc-art.big{position:static;width:74px;display:block;margin:2px auto 6px} .mc-big{font-size:22px;font-weight:800;margin-top:2px} .mc-big small{font-size:13px;font-weight:700} /* 卡片第二行(上游 sub 的落点):只有 kick / weight 两张卡有富余空间 —— 其余三张是 固定高度(fweight 64 / cal 88 / curve 80)且列很窄(≈73px 文本宽),放不下第二行; 要显示它们的 sub,得先重排 .bento 那笔高度账(158+10+64=232),别硬塞。 :empty 时整行不占位,所以没数据时卡面与改动前完全一致。 */ /* 工具卡的状态行:固定高度 bento 只留了**一个**状态位,而上游的 text 可能比卡宽 (数宫缩卡那列文本宽只有 ≈73px,上游给「最近间隔 4分12秒」)→ 一律单行省略,别撑破卡面。 ⚠️ 只作用于 .bento 里的卡,别外溢到页面其它 .mc-sub。 */ .bento .mc-sub{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:1.35} /* 孕检日历卡略高(88px,扣掉内边距与标题还剩 ≈36px),允许两行 —— 上游过期未记时给「待补记 · 9月26日」,一行放不下会把日期省略掉,那就丢了关键信息。 */ .mini-card.cal .mc-sub{white-space:normal;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical} .mc-extra{font-size:11px;color:var(--muted);margin-top:3px;line-height:1.35; display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden} .mc-extra:empty{display:none} /* 上游 warn(胎动偏低 / 宫缩达到临产阈值 / 产检已过期未记):数字与文案一起标红。 颜色另起 --alert,不复用 --brand-dk:品牌深橘在这套暖底上读起来只是"强调",不像告警。 */ .mini-card.is-warn .mc-sub,.mini-card.is-warn .mc-sub b, .mini-card.is-warn .mc-big,.mini-card.is-warn .mc-big small, .mini-card.is-warn .mc-extra{color:var(--alert)} /* 四张工具卡的渐变跨度收窄到原来的一半左右: 渐变落差太大时整块颜色被拉花,模块边界反而看不清 */ .mini-card.kick{background:linear-gradient(150deg,#FFE2D6,#FFD7CA);height:158px} .mini-card.kick .mc-art{width:74px;right:2px;bottom:0} /* 胎儿估重(这张卡原来是「胎心记录」,本批换了内容;类名 .heart → .fweight, 下面那条 .mc-art 跟着改。除类名外,这里的数值一个都没动)。 版式是「名字 + 状态两行叠着,插画退到右下角」,和 .cal / .curve 同一套 —— 这一列窄,横排(图标 + 名字 + 右边状态)塞不下,标题会被挤成竖排。 底色浅蓝不是随手挑的:正上方「数胎动」是粉的,两块粉挨着分不出是两张卡; 插画又是珊瑚红的(原来是心,现在是表盘指针),压在粉底上糊成一片,浅蓝才托得住。 内边距上下收到 12(别处是 14):这一格只有 64px 高, 14 + 名字 20 + 间距 3 + 状态 16 + 14 = 67,会超三个像素。 */ .mini-card.fweight{background:linear-gradient(150deg,#E7EFFA,#DDE8F8);height:64px;padding:12px 14px} .mini-card.weight{background:linear-gradient(160deg,#FFE9E1,#FFDDD3);display:flex;flex-direction:column;justify-content:center;text-align:center} .mini-card.weight .mc-title{font-size:16px} .mini-card.cal{background:linear-gradient(150deg,#ECF3DE,#E4F0D4);height:88px} /* 生长曲线原来是 flex:1,把第三列剩下的高度全吃了(约 134px), 可它的内容和上面的孕检日历一样多,白撑着。压到 80px, 省下的 54px 给下面的「更多工具」。 ⚠️ 这三张卡的高度是硬凑的:88 + 10 + 80 + 10 + 44 = 232, 左边那一列是 158 + 10 + 64 = 232,两列必须一样高,中间那张「孕期体重」 才不会比别人矮一截。动其中任何一个数,另一列要跟着补回来。 80 是这套竖排的下限:内边距 28 + 名字 20 + 间距 3 + 状态 16 = 67,再矮就贴边了。 */ .mini-card.curve{background:linear-gradient(150deg,#ECE5FA,#E5DCF9);height:80px} .mini-card.cal .mc-art,.mini-card.curve .mc-art{width:42px;right:6px;bottom:4px} /* 这张卡的插画得单独摆一份,不能跟着上面 .cal / .curve 那条走。 ① 尺寸 38 而不是 42:日历、曲线那两张 png 画面里自带内部留白, 这里的表盘是满幅的圆,同样宽度看着会比它俩大一圈。 ② 位置 right:11 / bottom:10:圆的最宽处顶在画布边缘,.mini-card 又是 overflow:hidden,按别处的 6 / 4 摆会被圆角啃掉一小块。这两个数当初是 为那颗同样满幅的心量出来的,换成圆表盘照样成立,所以原样留着。 ③ 滤镜只留 drop-shadow:原来前面还挂着 saturate(.82) brightness(1.04), 那是专为 q-heart.png 那颗高饱和珊瑚红压色的 —— 它比 app-* 那几张低饱和的 奶油粉 / 淡紫 / 浅绿都要「喊」。现在这枚表盘是自己画的 SVG,配色一开始 就落在同一档里,不需要再压;继续挂着反而会把指针洗淡。 投影值照抄 .mc-art 的原值不动:打光要跟邻居一致。 */ .mini-card.fweight .mc-art{width:38px;right:11px;bottom:10px; filter:drop-shadow(0 5px 10px rgba(160,90,70,.18))} /* 「更多工具」:通往「记一下」弹层里那十几个工具。 故意不给糖果色 —— 它不是第六个工具,是个出口。素底 + 一行小字, 扫过去不会被当成工具卡数进去。 高度 44 是按手指来的(再矮一点更好看,但这是这一屏唯一通往其余工具的门, 点不准的代价太大),不是按内容 —— 一行 11.5px 的字只要 16px。 */ /* ⚠️ 底色必须跟着容器走:容器是白的就用灰米(现在这样),容器要是改成米色底, 这里得反过来提亮,否则浅底压浅底整张卡会直接消失。 */ .mini-card.more{background:#EFE7DA;height:44px;display:flex;align-items:center;justify-content:center;gap:3px;padding:0 6px} .mc-more-t{font-size:11.5px;font-weight:700;color:#8A7A66;white-space:nowrap} .mini-card.more .chev{font-style:normal;font-size:13px;font-weight:700;color:#A3937F;line-height:1} /* 模块二 · 今天的动线 */ /* 上一版这里是两个独立模块:AI 小结一张渐变卡(左边 4px 色条 + 40px 大引号), 下面「今日成长脚印」一张白卡装的时间轴。两块都是「米色页面上摆一张卡」, 和上面的工具、下面的指南是同一种容器语言,四段叠起来才显得那么直筒。 这一版合成一条线,容器语言换成「没有容器,只有一条线」: .tl-head 起点节点(今天 · 大圆点 · 今日成长脚印 · 查看全部) .steps 四条记录(白卡撤了,只剩内容本身) .ai-bubble 收尾节点(AI 徽标代替时间 · 圆点 · 一只气泡) AI 那句话总结的就是它正上方那四条记录,本来就该挨着,不该隔着一整套抬头分开摆。 竖线的画法也换了。原来是每个 .step::before 各画一小段, 靠 :first-child{top:50%} / :last-child{bottom:50%} 拼出来 —— 那样只能在 .steps 内部拼,跨不到 .tl-head 和 .ai-bubble 上。 三条规则全删,改成这里一条从头贯到尾。 ⚠️ 底色、圆角、左右内边距在上面的「公共外壳」里统一定义,这里只管线和节点。 ——「咬线」的那几圈外圈颜色必须等于这块的底色(现在是 #fff), 跟着外壳走,外壳改底色这里就得一起改,见下面几处标注。 */ /* 这一块的几何全部由下面几个变量推出来,别再往下面的规则里写死像素。 三行(.tl-head / .step / .ai-bubble)必须是同构的三列: [ 时间列 --tl-time ][ --tl-gap ][ 圆点 9px ][ --tl-gap ][ 正文 ] 只要有一列的宽度或间距在某一行上写得不一样,那一行的圆点就会离开竖线。 ⚠️ 之前就是这么错的:.st-time 写的是 width:42px(可被 flex 压缩), 而 .tl-h-when / .ab-badge 写的是 flex:0 0 42px(不可压缩)。 320px 视口下 .step 一行内容总宽约 311 > 可用 264,flex 就去压唯一压得动的时间列, 把它压到约 36px,圆点跟着左移,看上去就是「时间贴到竖线上」。 现在三处统一 flex:0 0 var(--tl-time),谁都不许缩。 */ /* 引导占位(今天没有任何足迹时):**沿用 AI 气泡那套语言** —— 左列 + 圆点 + 带尖角的气泡, 与时间轴共用同一条竖线,不再是一张横跨整块的白卡(用户反馈那样突兀)。 ⚠️ 底色用白(用户指定):所以要**加一圈描边**才看得出气泡边界 —— AI 气泡靠暖渐变区分,白气泡压白底只剩阴影会糊成一片。 ⚠️ 尖角用「旋转 45° 的小方块 + 同色描边」,这样描边能跟着拐过去;纯 border 三角做不出描边。 */ .tl-guide{position:relative;display:flex;align-items:flex-start;gap:var(--tl-gap); width:100%;padding:10px var(--tl-pad) 0} .tl-guide-bubble{display:block;position:relative;background:#fff;border:1px solid var(--line); border-radius:4px 16px 16px 16px;padding:11px 14px 12px} .tl-guide-bubble::before{content:"";position:absolute;left:-5px;top:11px;width:9px;height:9px; background:#fff;border-left:1px solid var(--line);border-bottom:1px solid var(--line); transform:rotate(45deg);border-radius:0 0 0 2px} .tl-guide-t{display:block;font-size:15px;font-weight:600;line-height:1.55;color:#403430} .tl-guide-s{display:block;font-size:12.5px;color:var(--ink-2);margin-top:4px;line-height:1.6} /* 引导里可点的应用芯片(名字来自接口 unused[];identifier 是 box_app 按 App 表 url 路径解析的) */ .tl-guide-apps{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px} .tl-guide-apps:empty{display:none} .tl-chip{font:inherit;font-size:12.5px;font-weight:700;color:var(--brand-dk); background:#FFF1EC;border:1px solid #FFDFD5;border-radius:999px;padding:7px 13px;line-height:1} .tl-chip.is-plain{color:var(--muted);background:#F6F1ED;border-color:var(--line)} /* 接口说这句"需要标红"时(digest.warn)整句变告警色 */ .today-line.ai-warn .ab-say{color:var(--alert)} /* 没有真实事件的当天不显示 AI 气泡:那句话里的次数是**写死的**(见 index.html 的注释), 今天没记 / 未关联时显示它等于编数据。拿到真实事件(fpApply('rows'))时才摘掉这个类。 */ .today-line.no-ai .ai-bubble{display:none} .today-line{ position:relative; --tl-time:44px; /* 时间列宽:够放 "13:00" 还余一点 */ --tl-gap:13px; /* 三列之间的间距。从 10 提到 13,给时间和竖线之间让出空气 */ --tl-pad:2px; /* 每行自身的左右内边距 */ --tl-top:22px; /* 这一块的上留白 */ --tl-bot:24px; /* 这一块的下留白 */ /* 竖线中心 = 左内边距 + 时间列 + 间距 + 圆点半径(4.5) */ --tl-x:calc(var(--tl-pad) + var(--tl-time) + var(--tl-gap) + 4.5px); /* 正文左缘 = 竖线中心 + 圆点半径 + 间距 */ --tl-text:calc(var(--tl-x) + 4.5px + var(--tl-gap)); padding-top:var(--tl-top);padding-bottom:var(--tl-bot); } /* 一整条,不掐头也不去尾:上端由 .tl-h-dot 的不透明外圈盖掉, 下端由 .ai-bubble::after 那块底色橡皮擦掉。 这两处都只依赖各自圆点的位置(我自己定死的),不依赖气泡里文字排了几行 —— 要是改成算 bottom 的像素值,文案一变或字体一换线就会拖长一截或者短一截。 ⚠️ top/bottom 必须正好等于这一块的上下留白,**不能写 0**。 绝对定位是相对 padding box 算的,写 0 会让线从留白最顶端画起, 而 .tl-h-dot 的外圈只盖得住自己周围 12.5px —— 上下各会露出一截悬空的线头。 用同一组变量绑死,以后调留白线会跟着走。 */ .today-line::before{content:"";position:absolute;left:calc(var(--tl-x) - .75px); top:var(--tl-top);bottom:var(--tl-bot);width:1.5px;background:#F0E2D9} /* 起点节点。三列宽度全部走变量,圆点才落得进竖线。 */ .tl-head{display:flex;align-items:center;gap:var(--tl-gap);padding:0 var(--tl-pad);position:relative} .tl-h-when{flex:0 0 var(--tl-time);font-size:13px;font-weight:700;color:var(--brand)} /* 起点点得比途中的记录点更醒目,但**盒子仍然是 9px** —— 大小全靠 box-shadow 往外扩, 一改 width 就会把圆心推离 --tl-x,线和点就错位了。 三层 shadow 由外到内:底色 → 品牌色细圈 → 底色。⚠️ 最外层必须是不透明的容器底色(#fff), 它同时负责把 .tl-head 上方那截线头盖掉;写成半透明或写错色,线头就会露出来。 */ .tl-h-dot{flex:0 0 auto;width:9px;height:9px;border-radius:50%;background:var(--brand); box-shadow:0 0 0 3.5px #fff,0 0 0 5.5px rgba(244,89,60,.30),0 0 0 8px #fff} /* ⚠️ 两个标题现在都含用户填的小名,而小名输入框是 maxlength="12"。 12 个全角字 + 「的孕育工具」= 17 字 ≈ 277px,工具区那行留给标题的位置只有约 310px —— 塞得下,但只剩 30px 余量,字体或按钮文案一动就会把「所有工具 ›」挤出去。 与其赌那 30px,不如让标题自己先省略号收尾。.tl-h-title 本来就有这套, .dock-title 是这次跟着一起挂上来的。 */ .tl-h-title,.dock-title{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} /* 说明缩进到 73px,和下面 .st-txt 的左边缘对齐(2+42+10+9+10), 看着像是挂在这条线右侧的一句注脚,不是又一行贴边灰字。 */ .tl-h-note{margin:5px 0 2px var(--tl-text)} /* 它自己不再是一张卡了(背景/阴影/圆角/左右内边距都归外壳管), .step 的左边缘因此和 .tl-head / .ai-bubble 对齐,三块共用同一条线。 */ .steps{padding:2px 0;cursor:pointer} .step{display:flex;align-items:center;gap:var(--tl-gap);padding:11px var(--tl-pad);position:relative;font-size:14.5px} /* ⚠️ 必须是 flex:0 0(不可压缩),只写 width 会被 flex 压缩 —— 见本块开头那段说明。 */ .st-time{flex:0 0 var(--tl-time);font-size:13px;color:var(--muted);font-variant-numeric:tabular-nums} /* ⚠️ 外圈用来「咬断」竖线,所以它必须是**圆点背后那块底**的颜色 = 外壳的 #fff。 */ .st-dot{width:9px;height:9px;border-radius:50%;background:var(--brand);z-index:2;box-shadow:0 0 0 3px #fff} .st-txt{font-weight:600;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} /* 数据来源标签:做成浅色小胶囊,一眼看出这条记录是哪个孕期工具同步过来的。 ⚠️ 底色要和它贴着的那块底拉开差距 —— 而这一版**外壳底真的变了**, 上一版注释里假设的那件事发生了,所以这条跟着压深了一档: 胶囊 #F1E8E1 → #EADDD3,字 #9A8A7E → #8D7C6F 账(胶囊底 vs 它背后的外壳底,比值越大边界越清楚): 旧:#F1E8E1 压在纯白上 = 1.209 本批不改的话:#F1E8E1 压在 #FFF2E7 上 = 1.077 ← 几乎看不见,只剩一行浮着的字 改完:#EADDD3 压在 #FFF2E7 上 = 1.211 ← 回到旧版的清晰度 ⚠️ 它 margin-left:auto 贴在行的最右端,正好落在渐变**最深的那一头**, 所以必须按终点色 #FFF2E7 算,按平均色算会算松。 ⚠️ 字色一起压深是为了补回胶囊变深吃掉的那点对比(2.50 → 3.01)。 这两个值是一对,别只动一个。 */ .st-from{margin-left:auto;flex:0 0 auto;white-space:nowrap;font-size:11.5px;color:#8D7C6F; background:#EADDD3;border-radius:9px;padding:3px 8px;line-height:1.35} /* 收尾节点。三个直接子元素和 .step 同构(42 的左格 + 9 的点 + 剩下的), 圆点才落在同一条线上。align-items 用 flex-start 而不是 center —— 气泡是多行的,居中的话点会飘到气泡中腰,看着不像是从这个点说出来的。 徽标和点的 margin-top 是配着气泡第一行(标签行)算的: 气泡上内边距 11 + 标签行半高 7 = 18,加上 .ai-bubble 自己的 10 上内边距 = 28。 */ .ai-bubble{position:relative;display:flex;align-items:flex-start;gap:var(--tl-gap); width:100%;text-align:left;padding:10px var(--tl-pad) 0;cursor:pointer} .ab-badge{flex:0 0 var(--tl-time);margin-top:12.5px; font-size:10.5px;font-weight:800;letter-spacing:.4px;color:var(--brand);line-height:1} .ab-dot{flex:0 0 auto;width:9px;height:9px;margin-top:13.5px;border-radius:50%; background:var(--brand);z-index:2;box-shadow:0 0 0 3px #fff} .ab-body{flex:1;min-width:0} /* 一只气泡,不是「又一张卡」:左上角削平 + 一个指回竖线的小尖角, 语气是「有人在说话」。原来那套左色条 + 40px 大引号不要了 —— 引号是在给一张卡补语气,有了尖角就不需要了。 ⚠️ 底色沿用上一版 AI 小结卡那道暖渐变,不能用白:外壳已经是白的, 白气泡压白底就只剩一圈阴影,看不出是「在说话」。 这也是整块里唯一允许上色的地方 —— 时间线上其余部分都是白底黑字, 颜色留给「谁在说话」这一件事。 */ .ab-bubble{display:block;position:relative;background:linear-gradient(135deg,#FDF2E9,#FBE9DE); border-radius:4px 16px 16px 16px;padding:11px 14px 12px} /* ⚠️ 尖角的颜色要对上气泡渐变在**左上角**的那一端(#FDF2E9),不是取平均色 */ .ab-bubble::before{content:"";position:absolute;left:-7px;top:12px;width:0;height:0; border:6px solid transparent;border-right:7px solid #FDF2E9;border-left:0} /* 模块名降级成气泡里的一枚小标签。它和说明、「往期小结 ›」挤在同一行是塞不下的 (320px 下可用 197,三段要 212),所以标签进气泡、另两段留在落款行。 */ .ab-tag{display:block;font-size:11px;font-weight:800;letter-spacing:.2px; color:var(--brand);opacity:.85;margin-bottom:5px} .ab-say{display:block;font-size:15px;font-weight:600;line-height:1.6;color:#403430} .ab-say b{color:var(--brand)} .ab-foot{display:flex;align-items:center;gap:8px;margin-top:8px;padding-left:2px} /* 这里原来还有一条 .ab-foot i(左边那句「AI自动汇总你每日记录」的样式)。 那句按用户要求删掉了,规则跟着删 —— 不留只被注释引用的死样式。 下面 em 的 margin-left:auto 是它现在还贴右的原因,别当成冗余清掉。 */ .ab-foot em{margin-left:auto;flex:0 0 auto;font-style:normal;white-space:nowrap; font-size:11.5px;font-weight:700;color:var(--brand)} /* 底色橡皮:把圆点以下那截线擦掉,线就停在这个点上,不会从气泡旁边一直拖到模块底。 top 只跟圆点走(圆心 28 + 半径 4.5 ≈ 32),和气泡有多高无关。 left/width 刚好盖住 58 那条线,够不着 x≥73 的气泡。 ⚠️ 颜色 = 外壳底色 #fff,跟着外壳走。 */ .ai-bubble::after{content:"";position:absolute;left:calc(var(--tl-x) - 2.75px); top:32px;bottom:0;width:5.5px;background:#fff} /* ⚠️ 这两块的圆点是「长在」竖线上的,.ripple 默认的按下缩放会把点从线上拽下来 (线不跟着缩)。改成压透明度做反馈,涟漪照旧。 */ .steps,.ai-bubble{transition:opacity .16s var(--ease)} .steps:active,.ai-bubble:active{transform:none;opacity:.6} /* 模块三 · 书架卡带 */ /* 上一版这里是「1 张大卡 + 底下两张小卡」的九宫格式排布,卡都是竖着堆的, 和上面的工具区在视觉上是同一种东西 —— 一屏里第二次看到「大块 + 两个小块」。 这一版改成**横向卡带**:三张等宽的卡横着排,滑动查看,右边故意露出下一张的一角。 竖着滚的页面里插一段横着滑的内容,是打破直筒感最直接的办法, 而且资源本来就是「一排书」,横着摆比竖着堆更贴合它自己的样子。 */ /* 抬头和另两块一样:标题 + 右侧灰字入口 + 底下一句说明,字号间距全走公共规则。 上一稿这里额外加了一条 2px 的「书架横杆」压在标题底下 —— 另两块都没有, 纯粹是我给这一块单造的花样,正是「乱」的来源之一,去掉。 */ .shelf-bar{display:flex;align-items:center;gap:8px;margin-bottom:7px} .sh-title{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} .sh-note{margin-bottom:12px} /* 卡带出血到屏幕边缘,和上面的工具托盘用同一招,理由不一样: 托盘是为了让底色成为一个「区」,这里是为了让卡能滑出屏幕、露出下一张。 要是卡带停在 26px 栏内,右边缘会硬生生切一刀,看着像没排版好而不是「可以滑」。 ⚠️ padding 左右 = 26 抵回负外边距,第一张卡才和页面其余内容左对齐; scroll-padding-left 必须跟着写,否则吸附会把卡吸到屏幕边缘(x=0)而不是 26。 */ .shelf-rail{ display:flex;gap:11px;margin:0 -26px;padding:2px 26px 6px; overflow-x:auto;scroll-snap-type:x mandatory;scroll-padding-left:26px; -webkit-overflow-scrolling:touch; } .shelf-rail::-webkit-scrollbar{display:none} /* 78%:375 宽下卡是 292,右边正好剩 45px 露出下一张的边 —— 够让人知道还能滑, 又不至于露出半张让人以为是排版错位。用百分比而不是定宽,窄屏上会自己收。 等高不用写 min-height:flex 容器默认 align-items:stretch,三张自动拉齐到最高的那张, 再靠 .sb-row{margin-top:auto} 把底行压到卡底。 */ .shelf-book{ flex:0 0 78%;scroll-snap-align:start; display:flex;flex-direction:column;text-align:left; border-radius:20px;padding:14px; } /* 三张各自的糖果色沿用上一版那三张卡的配色,认得出是同一批东西。 ⚠️ 不带阴影 —— 和 .tool-dock .mini-card 同一个道理:糖果色卡摆在白外壳上, 本身已经和底分得很开,再加阴影只会显脏。这一屏的规矩是 「白外壳负责分区,色块负责分内容,阴影一个都不要」。 */ /* --sb-bg 是这张卡**底部**的颜色(渐变的收尾色)。底行的叠压头像要用它描白边, 描的必须是所处位置的实际底色,写死 #fff 会在糖果色上留一圈亮边。 */ .shelf-book.sb-book{background:linear-gradient(150deg,#FFEEE2,#FCE3D3);--sb-bg:#FCE3D3} .shelf-book.sb-food{background:linear-gradient(150deg,#EEF5E5,#E2EFD5);--sb-bg:#E2EFD5} .shelf-book.sb-music{background:linear-gradient(150deg,#F0EAFB,#E5DBF8);--sb-bg:#E5DBF8} /* 封面从「左边一张小图」改成「上面一张大图」,卡才像一本立在架上的书。 统一按高度 76 缩放:三张原图宽高比不一样(书是竖的,另两个是方图标), 锁高不锁宽,它们的视觉重量才差不多。margin 左右 auto 是在列向 flex 里做水平居中。 */ /* ⚠️ 封面必须占一个**固定的框**,而不是按图自身尺寸摆。 三张原图比例差很远(书是竖的窄长条,另两个是方图标), 上一稿只锁高度 76、宽度随意,于是三张卡的封面宽窄不一、视觉重量也不一样。 现在给统一的 width:100% + height:80px + object-fit:contain: 框一样大,图在框里等比缩放并居中,谁也不变形。 */ .sb-cover{width:100%;height:80px;display:block;object-fit:contain;margin:0 0 11px; filter:drop-shadow(0 8px 15px rgba(180,120,80,.26))} /* 标题一行封顶。三张的标题长短不一,放任换行会把下面的简介顶到不同高度。 */ .sb-title{font-size:15px;font-weight:800;line-height:1.4;letter-spacing:-.2px; overflow:hidden;text-overflow:ellipsis;white-space:nowrap} /* 简介最多两行。现有三条文案在 320px 下都是一行,这里是防以后换了长文案 把某一张卡撑高、连累另外两张一起变高(卡带是等高的)。 */ .sb-desc{font-size:12px;color:var(--ink-2);line-height:1.5;margin-top:5px; display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden} /* margin-top:auto 把底行压到卡底,三张卡的底行因此始终在同一条水平线上, 哪怕上面的简介行数不一样。 gap:7px 是「头像 ↔ 人数」的距离,它俩是同一件事的两半,贴紧念着才连贯; 「免费」靠自己的 margin-left:auto 甩到最右,不吃这个 gap。 */ .sb-row{display:flex;align-items:center;gap:7px;margin-top:auto;padding-top:12px} /* ⚠️ min-width:0 —— flex 子项默认 min-width:auto,光有 overflow/ellipsis 是不生效的, 窄屏(320)下这行会顶着「免费」把它挤出卡外。缩要缩在这儿,别缩头像。 */ .sb-got{font-style:normal;font-size:11px;color:var(--muted);white-space:nowrap; overflow:hidden;text-overflow:ellipsis;min-width:0} /* ---- 领取用户的叠压头像 ---- 纯 CSS:assets/ 里没有人像图,为这点装饰新增 6 张图片不划算, 也会把单文件产物撑大。每个 是一个圆底,::before 画头、::after 画肩。 ⚠️ 这一行的宽度非常紧,加大任何一个数之前先把账算一遍: .shelf-book 是 flex-basis:78%,78% 算的是 .shelf-rail 的**内容盒** (= 屏宽 - 52),不是屏宽。卡内可用宽度 = 0.78*(W-52) - 28: W=320 → 181px W=375 → 224px W=390 → 236px 这一行要装:头像叠 + 7 + 人数 + 7 + 「免费」≈41。 ⚠️ 人数那截这一版变长了:旧文案 6 个字 ≈69 → 「12.8 万妈妈已领取」≈88(+19)。 (这里不照抄旧文案原文:test/smoke.js 有一条「旧写法一处都不剩」的全文 grep, 跑在**构建产物**上,而 CSS 注释是会被 build.js 原样内联进去的 —— 在注释里写一遍旧文案,就会把那条 grep 打红。) (11px 字号下,汉字按 11px、数字按 5.5px、点和空格按 2.75px 估。) 于是 = 头像叠 + 143: → 375 给头像的预算 224-143 = 81px,6 个(17px 叠 5px,含 padding-left:5)共 77px,仍放得下; → 320 预算只剩 181-143 = 38px。4 个要 53px、3 个要 46px,都装不下,只有 2 个(34px)行。 人数才是这行的主角,不能让它吃省略号 —— 按「要砍先砍装饰」, 窄屏这一版从收成 4 个改成收成 2 个,见文件下方那条媒体查询。 */ .sb-faces{display:flex;flex:0 0 auto;padding-left:5px} .sb-faces i{ width:17px;height:17px;border-radius:50%; margin-left:-5px; /* 一个压一个 */ position:relative;overflow:hidden; /* 用 box-shadow 而不是 border 描白边:border 会吃掉 17px 里的内径, 把本来就只有 17px 的圆挤小;box-shadow 画在盒子外面,不影响布局。 白边的作用是把叠在一起的两颗头分开,颜色必须跟卡片底色一致。 */ box-shadow:0 0 0 1.5px var(--sb-bg,#fff); } /* 后面的盖住前面的,视觉上像一叠卡片从左往右码过来 */ .sb-faces i:nth-child(1){background:#F0A18C} .sb-faces i:nth-child(2){background:#E9BE7C} .sb-faces i:nth-child(3){background:#A9C79C} .sb-faces i:nth-child(4){background:#8FB4D8} .sb-faces i:nth-child(5){background:#BFA0D8} .sb-faces i:nth-child(6){background:#EE9A9A} /* 头 + 肩,最简剪影。半透明白而不是纯白:压在糖果色底上太扎眼。 */ .sb-faces i::before,.sb-faces i::after{ content:'';position:absolute;left:50%;transform:translateX(-50%); background:rgba(255,255,255,.9); } .sb-faces i::before{top:3px;width:6px;height:6px;border-radius:50%} .sb-faces i::after{bottom:-1px;width:11px;height:7px;border-radius:6px 6px 0 0} /* 窄屏收成 2 个头像。见上面那笔账:320 宽下卡内只有 181px, 人数文案改长(+19px)之后,留给头像的预算从 57px 掉到 38px —— 原来收成 4 个(要 53px)已经不够了,只有 2 个(34px)塞得进去。 头像是装饰,人数是信息,要砍先砍装饰:宁可少两颗球, 也不能让「12.8 万妈妈已领取」吃省略号变成「12.8 万妈妈已…」。 360 是这一叠 6 个能完整放下的最小屏宽,所以断点还是 359。 */ @media (max-width:359px){ .sb-faces i:nth-child(n+3){display:none} } /* 「免费」甩到最右。文件末尾还有一条全局 .pill-free{margin-left:auto}, 这里显式再写一次:靠一条几百行外的规则来决定这里的排版太脆, 而且上一版为了不让它靠右,正是在这个位置写了 margin-left:0。 ⚠️ 底色必须写死成不透明白:文件末尾那条 .pill-free 用的是 rgba(110,154,86,.14)(半透明绿,为详情页的白底列表调的), 它在本文件里排在下面、同样是单类名,会盖掉上面那条 #E3F0D8。 半透明绿铺在三张糖果色卡上会各自被染成三种脏色 —— 挪到右边孤零零一颗之后 尤其明显。白底 + 绿字在粉/绿/紫三张卡上都干净,且三张长一个样。 */ .sb-row .pill-free{margin-left:auto;flex:0 0 auto; background:#fff;color:var(--green);padding:3px 9px;border-radius:8px} .pill-free{background:#E3F0D8;color:#5E8646;font-size:11.5px;font-weight:700;padding:3px 10px;border-radius:9px} /* .pill-get(橙色「立即领取」胶囊)已删:它只在首页书架第一张卡上用过一次, 那颗假按钮连同这条规则一起去掉了。领取动作在资源详情页底部的 #rdGet。 */ .unlock{text-align:center;font-size:12.5px;color:var(--muted);margin:16px 0 4px} .unlock a{color:var(--brand);font-weight:600} /* ============ 通用页头(档案) ============ */ .page-hero{padding:calc(env(safe-area-inset-top) + 16px) 20px 62px;color:#fff;background:var(--grad);position:relative;overflow:hidden} .page-hero::after{content:"";position:absolute;width:230px;height:230px;border-radius:50%;background:rgba(255,255,255,.09);top:-70px;right:-60px} .hero-info{display:flex;align-items:center;gap:14px;margin-top:20px;position:relative;z-index:2} .hero-info>div:first-child{flex:1;min-width:0} .hero-h1{font-size:27px;font-weight:800;letter-spacing:-.5px;margin-bottom:9px} .hero-p{font-size:13.5px;opacity:.93;line-height:1.6} /* 第二行是「查得到就行」的信息,压一档字号和透明度, 让标题和第一行先被读到,橙区不再是三行齐平的一堵字 */ .hero-p.sub{font-size:12px;opacity:.72;margin-top:1px} /* 档案页那两行左边站着一个「这周宝宝多大了」的 emoji。 垫一层半透明白底圆盘,emoji 才不会直接糊在橘色上; 两行文字整体让开一个图标的位置 —— 就是「往右一点点」那个意思。 min-width:0 是给里面那个文字 div 的,不然长小名会把圆盘挤扁 */ .ar-lines{display:flex;align-items:center;gap:11px;margin-top:2px} .ar-lines>div{min-width:0} .ar-size{flex:0 0 auto;width:44px;height:44px;border-radius:50%; background:rgba(255,255,255,.2);display:grid;place-items:center;font-size:25px;line-height:1} /* ---------- 档案页 hero(重排过一次) ---------- .hero-info 是共用的(.page-hero 现在只有档案页在用); 档案页是自上而下四层,所以只在这里把 flex 关掉,不动共用那条。 */ .ar-hero{display:block} /* 页面名。上一版是 .ar-eyebrow —— 13px、opacity .78 的一行小字, 为了把字号让给孕周。方向没错,但让过头了:这行是整页唯一出现宝宝小名的地方, 13px 的半透明白压在橙色渐变上,扫过去根本注意不到。 这一版不用字号抢(25px 还是归 .ar-week),改用「材质」抢: 半透明白底 + 一圈亮描边 + 毛玻璃,从橙色里浮起来一层 —— 字还是小的,但边界一有就跳出来了。 inline-flex 而不是 block:牌子宽度得跟着小名长短走, 撑满整行就成了色块,不像牌子。max-width 兜住超长小名。 gap 用 0 + 图标自己挂 margin:三个 flex item 统一 gap 会把 「小汤圆」和「的成长档案」也撑开 6px,读起来断成两截。 h1 默认的加粗和外边距在这里全部自己接管。 */ .ar-title{ display:inline-flex;align-items:center;gap:0;max-width:100%; margin:0 0 12px;padding:5px 12px 5px 10px; border-radius:99px;background:rgba(255,255,255,.18); border:1px solid rgba(255,255,255,.3); -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px); font-weight:600;letter-spacing:.2px; } .ar-t-ico{flex:0 0 auto;margin-right:6px;opacity:.9} /* 小名是这枚牌子的重点,比后半句大两档半。省略号是给超长小名兜底的 —— 它是 flex item,不给 min-width:0 就不肯缩,会把牌子顶出屏幕。 */ .ar-t-name{font-size:15px;font-weight:800;letter-spacing:-.2px;line-height:1.3; min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} .ar-t-rest{flex:0 0 auto;font-size:12.5px;opacity:.8;white-space:nowrap} /* 孕周接手了原来 .hero-h1 的位置。27px 太挤(右边不再有环,但左边多了 44px 圆盘), 收到 25px,正好和 .ar-size 的高度配平。 */ .ar-week{font-size:25px;font-weight:800;letter-spacing:-.5px;line-height:1.2} /* 孕程细条。i 的宽度由 JS 现写(syncPregnancy), 过渡时间和进度环那条对齐,两页切过去动感是一样的。 */ .ar-prog{margin-top:18px;height:5px;border-radius:99px;background:rgba(255,255,255,.28);overflow:hidden} .ar-prog>i{display:block;height:100%;width:0;border-radius:99px;background:#fff; transition:width 1.4s var(--ease)} .ar-foot{display:flex;justify-content:space-between;margin-top:8px;font-size:11.5px;opacity:.86} .ar-foot b{font-weight:800;font-size:12.5px} /* 四层竖排比原来「两行文字 + 右边一个环」高了约 34px。 橙区本来就不小,再长一截就压得下面没地方了,所以把底部留白从 62 收到 44。 .page-body 的负外边距要跟着改同样的数(-46 → -28), 这两个数的差值才是「白卡顶边离橙区内容的距离」,一直是 16px, 只改一边白卡就会爬上去盖住「已陪伴 N 天」那行。 */ #screen-archive .page-hero{padding-bottom:44px} #screen-archive .page-body{margin-top:-28px} /* 自动归档卡 */ .auto-card{background:#fff;border-radius:22px;padding:18px;box-shadow:var(--sh-lg)} /* 标题行左边是「● 正在自动归档」,右边顶着当前周次角标 */ .ac-head{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:17px;font-weight:800} .ac-h-l{display:flex;align-items:center;gap:9px;min-width:0} .live-dot{flex:0 0 auto;width:9px;height:9px;border-radius:50%;background:#5EBE6B;position:relative} .live-dot::after{content:"";position:absolute;inset:-4px;border-radius:50%;border:2px solid rgba(94,190,107,.5);animation:pulse 1.8s ease-out infinite} @keyframes pulse{0%{transform:scale(.7);opacity:1}100%{transform:scale(1.5);opacity:0}} /* 统计胶囊现在排在生成入口下面,所以间距从这儿给 */ .ac-chips{display:flex;gap:7px;flex-wrap:wrap;margin-top:14px} .chip-stat{background:#F6F1EC;border-radius:10px;padding:6px 11px;font-size:12px;color:var(--ink-2)} .chip-stat b{color:var(--brand)} /* ---- 生成档案入口(周档案 / 完整档案):并入自动归档卡内 ---- */ .gen-badge{flex:0 0 auto;font-size:11.5px;font-weight:700;color:var(--brand);background:rgba(244,89,60,.1);padding:5px 10px;border-radius:9px} /* 上面那句说明段落删掉了,这里自己把上间距补回来 */ .gen-btns{display:flex;gap:10px;margin-top:15px} .gen-btn{ flex:1;min-width:0;display:flex;align-items:center;gap:10px;text-align:left; background:#F7F1EB;border-radius:16px;padding:12px;color:var(--ink); } .gen-btn svg{flex:0 0 auto;color:var(--brand)} .gen-btn span{display:flex;flex-direction:column;gap:3px;min-width:0} .gen-btn b{font-size:14px;font-weight:800;line-height:1.35} /* 副标题:原先卡片上那句笼统的说明拆到了这里,每个入口自己解释自己 */ .gen-btn em{font-size:10.5px;color:var(--muted);font-style:normal;font-weight:600;line-height:1.3;white-space:nowrap} /* ---- 档案图片预览 ---- */ /* 抬头卡:暖色底 + 白底方形图标,先告诉你手里这张是什么 */ .pst-hero{display:flex;align-items:flex-start;gap:14px;border-radius:22px;padding:18px;margin-bottom:12px; background:linear-gradient(140deg,#FFF3EA,#FAE3D6)} .pst-ico{flex:0 0 auto;width:46px;height:46px;border-radius:15px;background:#fff;color:var(--brand); display:grid;place-items:center;box-shadow:0 6px 14px rgba(196,110,80,.18)} .pst-h-txt{min-width:0} .pst-h-title{font-size:18px;font-weight:800;color:#3A2C24} .pst-lead{font-size:13px;color:#8B6E5E;line-height:1.7;margin:6px 0 0} /* 这张图里装了什么:条数、天数、成图尺寸 */ .pst-chips{display:flex;gap:7px;flex-wrap:wrap;margin-bottom:14px} .pst-chip{background:#fff;border-radius:11px;padding:7px 11px;font-size:11.5px;color:var(--ink-2);box-shadow:var(--sh)} .pst-chip b{color:var(--brand);font-weight:800;margin-left:3px} /* 分享卡的三颗样式胶囊。用站内通用的 .chip,只在这儿管排版。 320 屏上 .detail-body 内宽 276:三颗 chip 各是 padding 34 + 文字 (信纸 28 / 成长足迹 56 / 比大小 42)= 62 + 90 + 76 = 228, 加两道 8px 间距共 244,比 276 富余 32px,不用横滚也不会折行。 ⚠️ 加第四套样式前先按这个算式量一遍,超了就要给这行补 overflow-x:auto。 */ .pst-tpl{display:flex;gap:8px;margin-bottom:13px} /* 完整档案是一页一张 A4,屏幕上就一张张纸往下摞,纸和纸之间留条缝 */ .pst-pages{display:flex;flex-direction:column;gap:14px} /* 白色卡纸把图裱起来,再压一道虚线裁切位,像张待印的样张 */ .pst-frame{position:relative;padding:10px;border-radius:20px;overflow:hidden;box-shadow:var(--sh-lg);background:#fff;line-height:0} .pst-frame::after{content:"";position:absolute;inset:5px;border:1.5px dashed rgba(150,110,88,.2);border-radius:16px;pointer-events:none} /* canvas 用 2 倍像素画,这里按容器宽显示 */ .pst-frame canvas{width:100%;height:auto;display:block;border-radius:12px} .pst-tip{font-size:11.5px;color:var(--muted);line-height:1.7;margin:13px 0 0} /* 打印时只留这几张档案图,其它一概不出现在纸上 */ @media print{ /* 页边距已经画进画布里了(左边还留了装订边),浏览器不要再套一圈 */ @page{size:A4;margin:0} body *{visibility:hidden} #detailPoster,#detailPoster .detail-body,#detailPoster .pst-pages,#detailPoster .pst-frame,#detailPoster canvas{visibility:visible} #detailPoster{position:absolute;inset:0;transform:none;overflow:visible;background:#fff} #detailPoster .detail-bar,#detailPoster .pst-hero,#detailPoster .pst-chips,#detailPoster .pst-tip,#pstCta{display:none} #detailPoster .detail-body{overflow:visible;padding:0} /* 卡纸、裁切虚线、纸间缝隙都只是屏幕上的装饰,纸上不要 */ .pst-pages{display:block;gap:0} .pst-frame{box-shadow:none;border-radius:0;padding:0;margin:0} .pst-frame::after{display:none} .pst-frame canvas{border-radius:0} /* 一张画布 = 一张纸。最后一张后面不再断页,否则会多吐一张白纸 */ #detailPoster .pst-frame{page-break-after:always;break-after:page} #detailPoster .pst-frame:last-child{page-break-after:auto;break-after:auto} } /* 分段控件 */ /* 三个分栏各自那行 sec-title 已删(和标签文字重复), 它原本提供的下间距改由这里给,否则内容会贴着分段控件 */ .segmented{position:relative;display:flex;background:#EFE7E0;border-radius:20px;padding:5px;margin:22px 0 16px} .seg-thumb{position:absolute;top:5px;bottom:5px;left:5px;background:#fff;border-radius:16px;box-shadow:0 3px 10px rgba(150,100,80,.14);transition:transform .38s var(--ease),width .38s var(--ease);z-index:1} .seg-btn{position:relative;z-index:2;flex:1;text-align:center;padding:11px 4px;font-size:15px;font-weight:600;color:var(--ink-2);transition:color .25s,font-weight .2s;white-space:nowrap} .seg-btn.is-active{color:var(--ink);font-weight:800} .seg-btn i{font-style:normal;font-size:12px;color:var(--brand)} .seg-panel{display:none} .seg-panel.is-active{display:block;animation:fadeUp .38s var(--ease)} @keyframes fadeUp{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}} /* 成长数据空态(未建档):.is-empty 由 syncPregnancy 的 pregEmpty 分支挂上。 演示数字(体重 58.2kg / 日均胎动 31 次 / 双顶径 6.1cm / 体重曲线…)全部无接口数据源, 对未建档用户是纯假数据,整块隐藏改显示引导;健康态下这层完全不参与,原型观感不变。 */ .data-empty{display:none;font-size:13px;color:var(--ink-2);line-height:1.9;text-align:center;padding:26px 18px;background:#fff;border-radius:22px;box-shadow:var(--sh)} .seg-panel[data-panel="data"].is-empty .data-demo{display:none} .seg-panel[data-panel="data"].is-empty .data-empty{display:block} /* 时光轴 */ .tl-card{background:#fff;border-radius:22px;padding:20px 18px 6px;box-shadow:var(--sh)} .tl-item{position:relative;padding:0 0 24px 22px} .tl-item::before{content:"";position:absolute;left:0;top:5px;width:11px;height:11px;border-radius:50%;background:var(--brand);z-index:2} .tl-item::after{content:"";position:absolute;left:5px;top:14px;bottom:-2px;width:1.6px;background:#F6E1D8} .tl-item:last-child::after{display:none} .tl-date{font-size:12.5px;font-weight:700;color:var(--muted);margin-bottom:7px} .tl-item:first-child .tl-date{color:var(--brand)} .tl-text{font-size:15.5px;line-height:1.78;color:#39302C} .tl-text b{color:var(--brand)} .tl-from{display:inline-block;margin-top:9px;background:#F6F1EC;border-radius:8px;padding:5px 10px;font-size:11.5px;color:var(--muted)} .tl-item.hide{display:none} /* 成长数据 */ .stat-row{display:grid;grid-template-columns:repeat(3,1fr);gap:9px} .stat-card{background:#fff;border-radius:16px;padding:13px 12px 8px;box-shadow:var(--sh)} .sc-label{font-size:12px;color:var(--ink-2)} .sc-value{font-size:24px;font-weight:800;letter-spacing:-.6px;margin:5px 0 3px} .sc-value small{font-size:12px;font-weight:700} .sc-trend{font-size:12px;font-weight:700;color:var(--brand)} .sc-trend.ok{color:var(--green)} .sc-trend.purple{color:var(--purple)} .spark{width:100%;height:auto;margin-top:8px;display:block} .spark polyline{stroke-dasharray:300;stroke-dashoffset:300;animation:draw 1.1s .2s var(--ease) forwards} @keyframes draw{to{stroke-dashoffset:0}} .chart-card{background:#fff;border-radius:22px;padding:18px;margin-top:12px;box-shadow:var(--sh)} .cc-title{font-size:16px;font-weight:800;margin-bottom:14px} .chart{width:100%;height:auto;display:block;overflow:visible} .chart .grid{stroke:#F2ECE7;stroke-width:1} .chart .band{fill:rgba(160,196,130,.24)} .chart .area{fill:rgba(244,89,60,.08)} .chart .line{fill:none;stroke:var(--brand);stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:400;stroke-dashoffset:400;animation:draw 1.3s .15s var(--ease) forwards} .chart .pt{fill:#fff;stroke:var(--brand);stroke-width:3} .chart .pt.fill{fill:var(--brand);stroke:#fff} .cc-x{display:flex;justify-content:space-between;font-size:11.5px;color:var(--muted);margin-top:9px;padding:0 2px} .cc-legend{display:flex;gap:18px;margin-top:12px;padding-top:12px;border-top:1px solid var(--line)} .lg{font-size:12.5px;color:var(--ink-2);display:flex;align-items:center;gap:6px} .lg::before{content:"";width:16px;height:4px;border-radius:2px} .lg-line::before{background:var(--brand)} .lg-band::before{background:rgba(160,196,130,.5)} .meas-card{background:#fff;border-radius:22px;padding:6px 18px;margin-top:12px;box-shadow:var(--sh)} .meas{display:flex;align-items:center;gap:14px;padding:17px 0;border-bottom:1px solid var(--line)} .meas:last-child{border:0} .m-name{font-size:16px;font-weight:800;flex:0 0 62px} .m-bar{flex:1;height:9px;border-radius:5px;background:#E9EFE1;position:relative} .m-bar i{position:absolute;left:0;top:0;bottom:0;width:var(--p);background:linear-gradient(90deg,#DCE8CE,#C6DCB0);border-radius:5px} .m-bar::after{content:"";position:absolute;left:var(--p,50%);top:50%;width:17px;height:17px;border-radius:50%;background:#fff;border:3px solid var(--brand);transform:translate(-50%,-50%);box-shadow:0 2px 6px rgba(0,0,0,.12)} .m-val{text-align:right;flex:0 0 58px} .m-val small{font-size:12px} .m-val em{display:block;font-size:11.5px;color:var(--muted);font-weight:600;margin-top:2px} .m-val{font-size:19px;font-weight:800} /* 珍贵时刻 */ .moment-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px} .moment{background:#fff;border-radius:18px;overflow:hidden;box-shadow:var(--sh);padding-bottom:12px} .mo-art{height:104px;display:grid;place-items:center;position:relative} /* 扁平图标统一规格:46px、线宽 2.4、圆角端点; .f = 半透明白底(让图形从渐变里浮出来),.s = 描边,.d = 实心点 */ .mo-art svg{width:46px;height:46px;display:block;color:currentColor} .mo-art svg .f{fill:#fff;opacity:.66} .mo-art svg .s{fill:none;stroke:currentColor;stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round} .mo-art svg .d{fill:currentColor} .mo-art.a1{background:linear-gradient(140deg,#EDE7F8,#E3D9F5);color:#6B54BE} .mo-art.a2{background:linear-gradient(140deg,#FCE9E4,#FADCD3);color:#D0563F} .mo-art.a3{background:linear-gradient(140deg,#E9F2E0,#DDEBD0);color:#5A8A41} .mo-art.a4{background:linear-gradient(140deg,#FBEDE4,#F7E0D2);color:#CE6F35} .mo-art.a5{background:linear-gradient(140deg,#E2EDF7,#D4E4F4);color:#3C6DA8} .mo-art.a6{background:linear-gradient(140deg,#FDEAE0,#FADCCC);color:#C4632F} .star{position:absolute;top:8px;right:9px;font-size:17px;color:rgba(255,255,255,.85);text-shadow:0 1px 3px rgba(0,0,0,.15);transition:transform .25s var(--ease),color .2s} .star.is-on{color:#FFC93C} .star:active{transform:scale(1.35)} .mo-title{font-size:14.5px;font-weight:800;margin:11px 12px 5px} .mo-meta{font-size:11.5px;color:var(--muted);margin:0 12px 7px} .mo-from{display:inline-block;margin:0 12px;background:#F6F1EC;border-radius:7px;padding:4px 8px;font-size:11px;color:var(--muted)} .moment.hide{display:none} /* 纪念册 */ .album-card{display:flex;gap:15px;width:100%;background:linear-gradient(120deg,#FCEDE1,#F9E0D0);border-radius:22px;padding:18px;margin-top:22px;box-shadow:var(--sh)} .al-book{flex:0 0 82px;height:110px;border-radius:5px 10px 10px 5px;background:linear-gradient(150deg,#F2795A,#E04E2E);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;color:#fff;box-shadow:0 10px 20px rgba(190,80,50,.32),inset 4px 0 0 rgba(255,255,255,.22)} .al-leaf{font-size:28px} .al-tag{font-size:11.5px;font-weight:800;text-align:center;line-height:1.35} .al-title{font-size:17px;font-weight:800} .al-title em{font-size:12.5px;color:var(--brand);margin-left:6px} .al-desc{font-size:12.5px;color:var(--ink-2);line-height:1.7;margin:7px 0 11px} .al-bar{height:8px;border-radius:4px;background:rgba(255,255,255,.75);overflow:hidden} .al-bar i{display:block;height:100%;width:var(--p);background:linear-gradient(90deg,#FF8A68,#F0563A);border-radius:4px} .al-meta{font-size:11.5px;color:var(--ink-2);margin-top:8px} /* ============ 我的 ============ */ .me-top{padding:calc(env(safe-area-inset-top) + 18px) 18px 26px;background:var(--grad);border-radius:0 0 32px 32px;color:#fff;position:relative;overflow:hidden} .me-top::after{content:"";position:absolute;width:220px;height:220px;border-radius:50%;background:rgba(255,255,255,.08);top:-80px;right:-60px} /* 齿轮按钮直接挂在 .hero-top 上,没有 .hero-actions 包着, 够不到那条 margin-left:auto,所以这里单独把这一排改成靠右 */ .me-top .hero-top{margin-bottom:18px;justify-content:flex-end} /* 半透明玻璃压在橘色渐变上永远发灰、发脏,文字也只能跟着用白的,读起来累。 改成一张实心暖白卡:橘色只做底衬,卡内回到正常的深色文字层级, 和页面下方的 .preg-card / .list-card 是同一种白卡语言。 ── 底纹改成横向,这是第三版,前两版都被同一句话打回来 ── ⚠️ 用户为这张卡提过**两次**同样的意见(「加一点渐变,不要纯白色」 「现在纯白色不好看」)。两次我都只是把色标往深里调 —— #FFF7F3 → 加个 52% 中间标 → #FFE9DB,两次都没解决。 **问题从来不在颜色深浅,在暖色铺到的面积。** 150deg 是斜的:暖色只落在右下那个角,而卡是 ~300×100 的扁盒子, 对角线方向上「右下角」小得可怜,正中间和左上恒定是白的。 色标再往深调,只会把那个小角调脏,卡整体照样读作白。 → 所以这一版换成 90deg 横向,让暖色从右边**整片**压过来, 白区收在左边 20%(正好留给头像)。终点 #FFE4D4 其实只比上一版 #FFE9DB 深一点点,但观感差别很大 —— 差在面积,不在那点色差。 → 下次若还嫌白,**别再动色标**,先想面积和方向。 ⚠️ 横向渐变顺带解开了上一版那条「不能再往深里调」的限制: 当时的顾虑是终点会和 .me-avatar 的底(linear-gradient(140deg,#FFE6DA,#FBCFBF)) 糊在一起。那是 150deg 才有的问题 —— 斜渐变把暖色送到了头像所在的左侧中部。 现在头像坐在左边 20% 的纯白区里,暖色在它右边,两者根本不相邻。 ⚠️ 白区 20% 是给头像留的,别收窄:.me-avatar 是 66px 宽、左边距 18px, 在 ~300px 的卡上占到约 28%。白区若缩到 20% 以下,头像右半边会开始 压在暖色上,那圈 box-shadow 的白边就废了(它就是靠白底才划得出边界的)。 对比度复核(这次是实算的,见下面那笔更正):底色取渐变终点 #FFE4D4, 再叠上右上角那团柔光(rgba(255,196,160,.34))算最坏情况: --ink #2B2320 11.70:1 ✓ 远超 AA --ink-2 #6B615B 4.58:1 ✓ 刚过 AA 4.5(余量很薄,见下) --brand #F4593C 2.52:1 ✗ 不过 AA ⚠️ 上一版这段注释写着「.me-info p b 用 --brand 约 3.3:1」—— **那个数是错的**, 3.31:1 是 --brand 压在**纯白**上的值,不是压在 #FFE9DB 上的。 实算:压 #FFE9DB 是 2.83:1,压现在的 #FFE4D4+柔光是 2.52:1。 也就是说「已连续记录 **42** 天」那个品牌色数字,**在这一版之前就已经不过 AA**, 不是这次改坏的,但这次又薄了 0.3。没有一并修,是因为改它要动全站品牌色的 用法(--brand 压浅底到处都是这个量级),不该夹在一次底纹调整里顺手做。 要修的话:给 .me-info p b 单独配一个压深版品牌色(约 #C9401F 起步才够 4.5)。 ⚠️ --ink-2 那 4.58 只比 4.5 高 0.08,**别再加深终点或加大柔光**: 终点走到 #FFE0CC、或柔光提到 .42,它就掉到 4.5 以下了(实算 4.44 / 4.45)。 */ .me-card{display:flex;align-items:center;gap:14px;border-radius:26px;padding:17px 18px; background-color:#fff; /* 两层:底下一条横向暖色渐变(白区留给左边的头像), 上面右上角一团柔光,免得整块暖色看着像一条平铺的色带。 和首页 .today-line 是同一套手法(那边也是 radial 柔光 + 90deg 渐变)。 */ background-image: radial-gradient(128px 92px at 94% 6%, rgba(255,196,160,.34), rgba(255,196,160,0) 72%), linear-gradient(90deg,#fff 0%,#fff 20%,#FFF1E6 58%,#FFE4D4 100%); color:var(--ink); box-shadow:0 14px 32px rgba(140,56,34,.22),0 2px 6px rgba(140,56,34,.10); position:relative;z-index:2;overflow:hidden;cursor:pointer;transition:transform .18s var(--ease)} .me-card:active{transform:scale(.985)} /* 尖括号跟全站 .chev 一个灰度,别再用白色 */ .me-chev{margin-left:auto;flex:0 0 auto;font-style:normal;font-size:24px;line-height:1;color:#C9BFB8} /* 头像底从「白蒙版 + 白描边」换成暖橘底 + 品牌色剪影(与 .pc-ico 同一套配色)。 ⚠️ 外圈本批从 #FFF3EC 改回了纯 #fff。那圈浅橘白光晕本来是照着 「卡是白的」调的 —— 卡一变暖(终点 #FFE9DB),#FFF3EC 就夹在 卡色和头像底色中间,三层暖色叠在一起,那道圈等于消失了。 用纯白才重新和两边都拉开,头像才有一条清楚的边界。 别跟着卡的渐变把它也调暖,那就白改了。 */ .me-avatar{width:66px;height:66px;border-radius:50%; background:linear-gradient(140deg,#FFE6DA,#FBCFBF); display:grid;place-items:center;color:#EE7C5F;border:0; box-shadow:0 0 0 3px #fff,0 6px 14px rgba(196,110,80,.20); flex:0 0 auto;position:relative} /* 上传头像后用 盖掉默认剪影;没图时 img 不占位 */ .me-avatar img{display:none;position:absolute;inset:0;width:100%;height:100%;object-fit:cover;border-radius:50%} .me-avatar.has-img img{display:block} .me-avatar.has-img>svg{visibility:hidden} /* 白卡上再放白角标会糊掉,所以反过来:品牌色实心 + 白图标, 外面镶一圈白边,压在头像和卡面的交界处也读得出来 */ .av-edit{position:absolute;right:-2px;bottom:-2px;width:21px;height:21px;border-radius:50%; background:var(--brand);color:#fff;display:grid;place-items:center; box-shadow:0 0 0 2px #fff,0 3px 8px rgba(196,80,52,.38)} .me-info{flex:1;min-width:0} .me-name{font-size:21px;font-weight:800;color:var(--ink);letter-spacing:-.3px} /* 原来靠 opacity 压层级,在白底上只会发灰,换成正经的次级文字色 */ .me-info p{font-size:13px;color:var(--ink-2);line-height:1.5;margin-top:5px} .me-info p b{color:var(--brand);font-weight:800} /* ⚠️ 这里原来有一条 .me-bio(一句话签名的单行截断)。签名整块已按用户要求删掉, 这条规则跟着删了 —— DOM 里再没有 .me-bio 这个元素。 留一条永远选不中东西的规则,下一个人读 CSS 会以为页面上还有这行内容, 然后跑去 JS 里找是谁把它藏起来了。 要加回签名,四处一起加:#pfBio 输入框 / #meBio 展示行 / syncBio() / 这条规则。 */ .sec-title.dark{color:var(--ink)} /* ---- 孕期信息卡 ---- 原来是纯白卡,夹在橘色 .me-top 和下面那张暖橘福利卡中间,自己反倒最没存在感。 ⚠️ 这里**不能**也换成暖橘:一页上两张暖卡挨着,等于谁都没被突出, 而且福利卡(讲「白送你一件东西」)本就该是全页最跳的那张。 所以这张必须靠色系和邻居错开,两张卡才各自站得住。 配色改到第五版了,把前四版为什么被打回来写清楚,别再走一遍: v1 纯白 —— 没存在感 v2 雾蓝 #F2F7FD→#E6EEF9 —— 打回,原话「颜色不是很好」 v3 薰衣草紫→藕荷粉 #E7DDFA→#F7E4F0 —— 又打回,原话「需要有设计感一些」 v4 深靛→紫→玫 #4E3FA8→#7C4FCB→#B0417F —— 打回,原话「那个紫太扎眼了」 ⚠️ 复盘的关键在这里:v2 和 v3 是**同一个错**,我第二次才看出来。 v2 我归因成「两端色相拉得太近」,于是 v3 把色相从 2° 拉到 61°, 结果还是被打回 —— 说明色相差不是真正的病根。 **v2 和 v3 都是「浅色水洗」**:三通道全在 220 以上, 不管两端离多远,整张卡在手机上都只是一小片淡色, 而它上面就压着一整条饱和橘色的 .me-top。淡色卡贴在浓色条下面, 再怎么调色相也只会显得虚。所以 v4 不再在浅色里挑颜色, 直接换成**深色卡 + 白字**:靠明度对比站住,而不是靠色相。 v4 深靛→紫→玫 #4E3FA8→#7C4FCB→#B0417F —— 打回,原话「那个紫太扎眼了」 v4 的深色思路**是对的**(打回的是色相,不是明度),所以 v5 原样保留 「深色卡 + 白字」,只把紫换成绿: v5:墨绿 #1E5A46 → 绿 #2C6B4C → 草绿 #3E6B30,白字。 · 色相 160.0° / 149.6° / 105.8°,仍全在暖橘带(10°–60°)之外, 和福利卡错开的原始目的没丢; · 首尾跨 54.2°,比 v4 的 77.9° 窄,但**远远大于 v2 死掉时的 2°**, 渐变看得见就够了; · 明度上和上下两张浅色卡彻底分开 —— v4 挣来的那一半没退。 ⚠️ 换色时白字对比度**变好了,不是凑合过**(实测,白 #FFF 压在三个色标上): v4 紫 8.08 / 5.47 / 5.37 → 最低 5.37 v5 绿 8.06 / 6.34 / 6.27 → 最低 6.27 .pc-sub / .pc-stage 那种 78% 白的副文同理:v4 最低 3.90 → v5 最低 4.54。 末档特意从更漂亮的 #4A7C3C(白字只有 4.95,**比紫还差**)压深到 #3E6B30, 就是为了不拿可读性换颜色。改这三个值之前先把这两组数重量一遍。 ⚠️ 别把它调浅回去凑「温柔」。真要调,先想清楚怎么解决 「淡色卡压在饱和橘条下面显虚」这件事,那是 v2/v3 死掉的地方。 ⚠️ 也别顺手把它调成 --mom 那支绿(#3F7551)。那支是「妈妈这个人」的语义色, 挪来当一张信息卡的底,等于宣布这张卡属于妈妈 —— 它讲的是宝宝的孕周。 ⚠️ 换底色必须连带把卡里**所有**彩色件一起换掉,这张卡的坑比别的卡多, 因为它的零件散在三个地方: · 这里(图标底、进度槽、进度条、三段文字、标题、副文) · index.html 的 SVG presentation attribute(进度环 + 宝宝,共 4 处) · 全局规则里两个**会被继承进来**的颜色 —— 见下面 .chev / .rp 两条 只改背景会得到「深紫底配浅紫环」,比原来的纯白更难看。 */ .preg-card{display:block;width:100%; /* 两层背景:上层是右上角那点高光,下层才是主渐变。 ⚠️ 用多重背景而不是 ::before 画高光,是为了躲开一个真实的层序坑: 这张卡带 .ripple(position:relative 但 z-index:auto,**不产生层叠上下文**), 绝对定位的 ::before 会画在普通流子元素**上面**,高光正好糊住标题; 改用 z-index:-1 又会穿到祖先背景后面去,还得再补 isolation。 高光本来就只是背景的一部分,写成背景层这些问题一个都不存在。 */ background: radial-gradient(110px 80px at 86% 6%, rgba(255,255,255,.20), rgba(255,255,255,0) 72%), linear-gradient(140deg,#1E5A46 0%,#2C6B4C 46%,#3E6B30 100%); border-radius:22px;padding:18px; /* 阴影跟着卡片自己的色相走,不用全局那个中性灰 var(--sh): 深色卡投一片灰影会显脏,投同色系的影才像这张卡「浮」起来。 ⚠️ 这就是「跟着色相走」的代价:换底色时它**必须一起换**。 本批之前是 rgba(78,63,168,.30)(v4 紫的 rgb),底换成绿而影还是紫的话, 卡下面会渗出一圈淡紫 —— 在浅色页面上看得见,但很容易当成「本来就有的氛围」。 下面这个是 v5 首档 #1E5A46 的 rgb。 */ box-shadow:0 10px 24px rgba(30,90,70,.30)} .pc-row{display:flex;align-items:center;gap:13px} .pc-ico{width:52px;height:52px;border-radius:15px;background:rgba(255,255,255,.16);display:grid;place-items:center;flex:0 0 auto} /* ⚠️ 标题这行原来不写 color,靠继承拿到深墨色。底一换成深色, 不显式写白就是「深紫底上的深墨字」—— 等于没有字。 */ .pc-title{font-size:21px;font-weight:800;letter-spacing:-.4px;color:#fff} .pc-sub{font-size:12.5px;color:rgba(255,255,255,.78);margin-top:4px} .pc-main{flex:1;min-width:0} /* ⚠️ 这两条挡的是**继承进来的**全局颜色,是这次换色最容易漏的一处 —— 它们不在这个模块的代码里,grep「preg」「pc-」一个都搜不到: · .chev 全局是 #C9BFB8(浅灰),画在深紫底上基本看不见; · .rp(涟漪)全局是 rgba(244,89,60,.16),橘色 16% 铺在深紫上是一团脏影。 两条都只在这张卡里覆盖,不动全局 —— 别的卡还是浅底,全局值在那儿是对的。 */ .preg-card .chev{color:rgba(255,255,255,.75)} .preg-card .rp{background:rgba(255,255,255,.22)} /* 底槽和进度条都改成白的透明度分级:深色卡上再挑一个「更深的紫」当底槽, 在 9px 高的条子上根本分不出层次 */ .pc-bar{height:9px;border-radius:5px;background:rgba(255,255,255,.22);margin:16px 0 10px;overflow:hidden} .pc-bar i{display:block;height:100%;width:var(--p);background:linear-gradient(90deg,rgba(255,255,255,.85),#fff);border-radius:5px} .pc-stage{display:flex;justify-content:space-between;font-size:11.5px;color:rgba(255,255,255,.85)} /* 当前段从「换个字色」升级成一颗白药丸:深色卡上只靠白色深浅分主次, 11.5px 的小字拉不开差距;反白一块才一眼看得出走到哪一段了。 ⚠️ margin 上下各 -3px 抵掉 padding,保证这一行的高度和没药丸时一样 —— 不然这张卡会因为「当前段」比兄弟高 6px 而整体长高。 ⚠️ .cur 是 syncPregnancy() 按孕周在三段之间**搬来搬去**的, 药丸可能落在第一段或第三段(贴着卡的左右内边)。space-between 三段都放得下:早/晚期 3 字≈34.5px、中期「孕中期 · 当前」7 字≈80px, 加内边距最宽 98px,三段合计 167px < 可用 248px。 */ /* ⚠️ 药丸里的字色是**卡底渐变的首档**,不是随便一个深色 —— 白药丸是从卡上「挖」出来的,字色取卡自己的深色才像同一张卡上的东西。 本批底色换绿,这里跟着从 #4E3FA8 换成 #1E5A46(白底上 8.06:1)。 漏改的话:绿卡上一颗白药丸、里面躺着一个紫字,这是全卡最后一处紫。 */ .pc-stage .cur{color:#1E5A46;background:#fff;font-weight:700; padding:3px 9px;margin:-3px 0;border-radius:99px} /* ---- 试用装福利卡(企业微信入口)---- 和 .preg-card 同样的大圆角,是「我的」页上第二张真正的卡; 刻意不长得像下面 .list-card 里那些行 —— 它不是一条设置项。 底色从纯白换成暖渐变:这张卡现在讲的是「白送你一件东西」, 跟周围一水儿的白底卡拉开,福利感才立得住。 */ /* ⚠️ 这一版是**竖向三段**(不是四段,别照旧记忆数): .wx-top 角标行(右对齐)/ .wx-body 图文行 / .wx-cta 通栏按钮。 标题行 .wx-head **不是**卡的直接子元素,它在 .wx-body 的右列 .wx-main 里, 和价格共用同一条左缘 —— 那是用户要的「放到到手价上边、跟到手价对齐」。 演化:左右两列 → 三段(标题独占一行)→ 四段(角标再提一行) → 又回到三段(标题行搬进右列)。每一步都是被账或被用户原话逼的。 ⚠️ 两笔账的**分母不一样**,别混用: 角标行量的是**卡内净宽 248**(320 − 36 − 36); 标题行量的是**右列 160**(248 − 图 76 − gap 12)。 拿 248 去算标题行会得出「宽得很,都塞得下」的反结论。 角标为什么必须自己占一行(按现在的 160 算): 商品名「可心柔婴儿纸巾」7 × 16 = 112, 再塞 gap 6 + 「限量福利」角标 60 = 178 > 160 ✗ 差 18px。 而且这还是 1.0 倍;微信字体滑块最大档 1.35 倍下商品名自己就占 151.2, 160 里只剩 8.8px,角标连一个字都进不去。 所以角标只能自己占一行、右对齐 —— 那也正是用户要的「放到右上角」。 ⚠️ .wx-card 的 flex-direction 是 column,**不是** row。 谁改回 row(或删掉 direction 退回默认),三段会并排挤成一条, 而且**不报错**,只是难看。smoke 钉了一条。 ⚠️ 也别加 flex-wrap:竖排容器里 wrap 只在高度溢出时生效,在这儿是纯噪声, 还会让下一个人以为有换行逻辑。 */ .wx-card{display:flex;flex-direction:column;width:100%; background:linear-gradient(135deg,#FFF4EC,#FFE6D9); border-radius:22px;padding:16px 18px;box-shadow:var(--sh)} /* ---- 第一段:角标行 ---- ⚠️ 用 justify-content:flex-end 把角标推到右上角,**不是** position:absolute。 这是硬约束不是风格选择:.wx-card 挂着 .ripple,.ripple 带 overflow:hidden (style.css:135),任何骑边(绝对定位 / top 负值)的角标都会被裁掉半截 —— 用户上一轮说的「限量福利被切了」正是这么来的。 修法也**不是**给卡加 overflow:visible:那会把涟漪放出圆角卡外。 走正常流 + 右对齐,物理上就不存在被裁的可能。 ⚠️ 这一行只装角标一件,看着「浪费」了一行高度。别为了省它把角标并进别处: 角标 4×10.5 + 内边 18 = 60px,塞进现在只有 160px 的右列必然溢出, 而溢出的表现是商品名被省略号啃掉、且不报错。 18px 行高换商品名完整可见,这笔划算。 */ .wx-top{display:flex;justify-content:flex-end;margin-bottom:8px} /* ---- 第二段:图文行(图 + 右列) ---- ⚠️ align-items 必须是 **stretch**,不能是 center。这是用户「左边整个的位置 都是留给图片」那句话的**全部实现**:只有父容器 stretch,下面 .wx-fig 的 align-self:stretch 才有效,图片才会长满左列整个高度。 改回 center 的话图片缩回自己的内容高,左边空出一块, 而且**不报错、不溢出** —— 只有真机上看得出来。smoke 里有断言钉着这条。 gap 13 → 12:右列从 147px 加宽到 160px,这 1px 也是凑出来的(见 .wx-main)。 */ .wx-body{display:flex;align-items:stretch;gap:12px;margin-top:12px} /* 商品占位图(现在是内联 SVG 抽纸,待换真图)。 ⚠️ 宽度写死在容器上而不是交给里面的 svg/img 自己撑:换成真实商品图那天, 图的原始比例不会把这一格顶大、把右边标题挤没。 ⚠️ 但**高度故意不写死**,用 align-self:stretch + min-height:92px: stretch 让图跟着右列一起长 —— 这是用户「左边整个的位置都是留给图片」 那句要求的**实现本身**。父级 .wx-body 必须同时是 align-items:stretch, 缺一条图就缩回自己的内容高,而且不报错、只在真机上看得出来 (smoke 里两条都钉着)。 ⚠️ min-height:92 本批起**已经不再起作用**,留着只是个地板。 标题行改竖排之后右列变高了: .wx-head = 20.8(标题 16×1.3) + gap 3 + 14.95(限领 11.5×1.3) = 38.75 + gap 5 + 26(价格) + gap 5 + 18.1(副文一行) ≈ **92.9** (副文折两行时 ≈ 111) 92.9 恒大于 92,撑高度的活已经全归 stretch 了。别看到这个数就以为 它还在管事,也别为了「对齐」把它调成 93 —— 调了没有任何效果。 88 → 76:这是上一版**横排**标题行留下的数(那时右列要塞 152px 的商品名 + 限领)。 ⚠️ 竖排之后这条约束没了:现在右列最宽的是副文 138px,图理论上能回到 88 (右列剩 148,仍 ≥ 138)。本批**没有改回去** —— 余量会从 22px 掉到 10px, 而用户这次并没有说图小了。真要动先把下面 .wx-main 那笔账重算一遍。 ⚠️ background 不能省。里面是**内联 svg**,object-fit 对它**不生效** —— 生效的是 preserveAspectRatio(默认 xMidYMid meet = contain)。 64×64 的方图进 76×92 的框会上下各留 8px 空条,露出卡的橙色渐变。 #FFF1E6 取的是 svg 自己那张 的颜色,接缝就看不见了。 别改成 slice(cover)—— 那会把抽纸盒裁掉头尾。 */ .wx-fig{flex:0 0 76px;width:76px;align-self:stretch;min-height:92px; background:#FFF1E6;line-height:0;border-radius:16px;overflow:hidden} .wx-fig>svg,.wx-fig>img{display:block;width:100%;height:100%;object-fit:cover} /* 角标本体。⚠️ 它现在住在 .wx-top 里(卡的右上角),**不再**是 .wx-main 的 第一件。别再给它 align-self:flex-start —— 那是它待在右列时用来「缩成胶囊」的, 现在父容器是 justify-content:flex-end 的单件行,那条已经没有意义。 ⚠️ 这里**永远**不要出现 position:absolute / top 负值,理由见 .wx-top 上面那段。 「电商化」这一版给它换成了品牌色斜向渐变 + 稍重的投影:促销角标本来就该比 正文更跳,但仍克制在一枚小胶囊里,不做成撕裂丝带那种廉价样式。 */ .wx-badge{font-size:10.5px;font-weight:800; color:#fff;background:linear-gradient(135deg,#E86A3E,#D8452F); border-radius:9px;padding:3px 9px; letter-spacing:.3px;box-shadow:0 2px 6px rgba(216,95,56,.32)} /* 图文行的右列:竖排 标题行 / 价格 / 副文。 ⚠️ 本批把 .wx-head(商品名 + 限领)**搬进了这一列**,排在 .wx-price 之前。 用户的原话是「商品名放到到手价上边,跟到手价那个对齐」—— 同属这一列 = 共用同一条左缘 = 「对齐」。别再把它提回卡的直接子元素。 ⚠️ CTA 和角标仍然**不在**这一列(在卡的直接子元素 / .wx-top),别在这儿找。 ⚠️ 320 屏上这一列是 **160px**: 320 − 页边距 36 − 卡内边距 36 − 图 76 − 一道 gap 12 = 160 标题行本批起**竖排**,两件各占一整行、互不抢宽度: 商品名「可心柔婴儿纸巾」7×16 = 112 ✓ 余 48px 「限领一份」 4×11.5 = 46 ✓ 余 114px 价格行「到手价」3×11.5 = 34.5 + gap 5 + 「¥0」≈ 26 ≈ 66 ✓ 余 94px 副文「加小汤圆的孕育顾问领取」11×12.5 ≈ 138 ✓ 余 22px(允许折两行) ⚠️ 全列最紧的一行现在是**副文**(138/160,余 22px),不再是标题行。 上一版标题行横排、只余 8px,微信那个全局字体滑块一调大就把商品名啃成 「可心柔婴儿纸…」—— 那正是用户本批报的 bug,别把它装回来。 justify-content:center 保留:右列自己现在就有 92.9px 高、和图基本齐平, 正常情况下居中不产生位移;它兜的是「以后图被调高」那种情形。 */ .wx-main{flex:1;min-width:0;display:flex;flex-direction:column;justify-content:center;gap:5px} /* ---- 标题行(住在 .wx-main 里,右列的第一件) ---- ⚠️ 对齐用的是 flex-end(底对齐),**不是** baseline,虽然 baseline 才是 两段不同字号文字并排的正解。原因是 .wx-title 带 overflow:hidden (ellipsis 必须的)—— 按 CSS Inline / Flexbox 的规定,overflow 非 visible 的块容器**没有可用基线**,浏览器会拿它的 border box 底边合成一条, 结果就是「限领一份」被顶到标题上方去,看着像上标。 这个坑不会报错、只在真机上看得出来。 底对齐的残留误差(字号降了之后重算过):标题 15px/1.3 = 19.5 高, 基线离底边 (19.5−15)/2 + 0.12×15 ≈ 4.05px;限领 10.5px/1.3 = 13.65 高, 基线离底边 (13.65−10.5)/2 + 0.12×10.5 ≈ 2.84px。 两条基线差 ≈ 1.2px —— 肉眼看不出来,比 baseline 塌掉那种错法小一个量级。 gap 6 → 5:右列 160px 里要塞 105 + 42 = 147,gap 只能给 5 才留得下 8px 余量。 ==== 本批改成竖排,上面这整段横排的账作废(留着是为了说明为什么不能改回去)==== 用户报「商品名被切成『可心柔婴儿纸…』」。真因不是写错了,是那 8px 余量本身: 它是按 15px 字号**死算**出来的,而微信有一个全局字体大小滑块,用户一旦调大, 105px 的商品名当场涨到 130+,8px 余量瞬间蒸发,ellipsis 就啃掉了商品名。 横排方案的根子问题是「两件抢同一条 160px」,再怎么调字号都只是把临界点往后推。 竖排之后标题独占整行,商品名可用宽度从 113(160−5−42) 变成 160, 放大 1.5 倍都还装得下 —— 宽度争抢从根上消失了。 ⚠️ 别改回 flex-direction:row 去「省一行高度」,那等于把这个 bug 装回来。 ⚠️ align-items:flex-start 不能省:默认 stretch 会把两个 span 拉成满列宽, 「限领一份」的灰底/间距一旦以后加上去就会横贯整列。 */ .wx-head{display:flex;flex-direction:column;align-items:flex-start;gap:3px;min-width:0} /* ---- 标题行的两件 ---- ⚠️ 上一版这两件横排、抢同一条 160px,所以配过一组「伸缩性相反」的规则 (.wx-title flex:1 1 auto 可压缩,.wx-lim flex:0 0 auto 不可压缩, 意思是「真溢出时宁可啃商品名,也不让那句话消失」)。 **本批改竖排之后那组 flex 规则已经全部删掉**:两件各占一整行, 「谁先被压缩」这个问题根本不存在了。 ⚠️ 别再照着那套旧描述往回加 flex:1 1 auto / flex:0 0 auto —— 在 column 容器里它们管的是**高度**,加上去只会让这两行开始互相挤压。 ⚠️ min-width:0 保留,配合 max-width:100%。.wx-head 现在是 column flex, 这两个 span 在交叉轴上仍会被长内容撑出去;两条一起才能保证超长商品名 在本列内触发 ellipsis,而不是把整张卡顶宽。 ⚠️ 字号 15 → 16。上一版压到 15 是横排时被 160px 挤的(16.5 会当场溢出); 竖排之后标题独占整行,7 字 × 16 = 112 ≤ 160,还剩 48px —— 够微信字体滑块放大到 1.42 倍仍不触发省略号。 没直接回到 16.5 是留一档安全余量:16.5 时只剩 1.38 倍。 ⚠️ ellipsis 三件套(overflow/text-overflow/white-space)保留当兜底。 现在它基本不该再触发 —— 真触发了说明字号又被谁调大了,去看上面那笔账。 */ .wx-title{max-width:100%;min-width:0;font-size:16px;font-weight:700;color:var(--ink); line-height:1.3;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} /* 「限领一份」。本批按用户要求移到商品名**下面独占一行**(原来并排在右侧)。 它是商品名的附注,不该和商品名一样重,所以仍是小字。 ⚠️ 字号 10.5 → 11.5,和资源库 banner 的 .rlg-lim 对齐。 这是补一个真实的不一致:用户早先要求两张卡「一模一样」,但上一版 这边被 160px 逼到 10.5、那边是 11.5 —— 文案逐字相同、**字号却差一档**, 并排看得出来。竖排腾出宽度后没有理由再小一档了。 (smoke 那条断言只比对文案字符串,比不出字号差,所以它一直是绿的。) ⚠️ 文案和 .rlg-lim **必须逐字相同**,smoke 里有断言钉着。改这句就得同时改那句。 ⚠️ 现在这行有整整 160px,「(每人限领一份)」8 字 × 11.5 = 92 也放得下 —— 但本批**不擅自改回长文案**:用户这次只要求挪位置,没说要改字。 ⚠️ 别把这句合回 .wx-title 凑成一个字符串:合成一个字符串就只剩一个字号, 「限领」不再是商品名底下那行灰色小字,用户要的那个视觉层级整个没了。 颜色比 --ink-2(#6B615B) 再淡一档。这里写死不用变量:全站没有 --ink-3, var(--ink-3,#…) 那种写法会让人误以为存在这么个变量。 */ /* ⚠️ 这里**没有** align-self:flex-start,是特意删掉的,别再加回来: 父级 .wx-head 已经写着 align-items:flex-start,子项上再写一遍是句空话。 变异测试把它删掉时一条断言都不红 —— 不是断言漏了,是它本来就不产生效果。 (.rlg-lim 那处一模一样,也一并删了。) */ .wx-lim{white-space:nowrap;font-size:11.5px;color:#8E827C;line-height:1.3} /* ---- 价格行 ---- 这一版「电商化」唯一新增的语义件:一个小号「到手价」+ 一个大号「¥0」。 ⚠️ 只有到手价,**没有划掉的原价**。原价得编一个数字,而这是真实品牌的 真实商品,划线价属于价格宣称,编一个就是虚假标价。 「¥0」不是新承诺 —— 它就是这张卡从第一版起写着的「立即免费领取」 换成电商的排版语言再说一遍。 ⚠️ 必须显式 font-style:normal:浏览器默认样式会把它斜过来, 中文没有真正的斜体,浏览器只能几何倾斜,糊得厉害。 这里用 / 而不是两个 ,是为了在 HTML 里一眼能分出主次。 */ /* ⚠️ margin-top 去掉了:.wx-main 现在是 justify-content:center 的竖列, 价格和副文靠 gap:5px 拉开。留着 margin-top 会和 gap 叠加,把这一列顶偏。 这里 align-items:baseline 是**安全**的(和 .wx-head 那处相反): 这两件都是普通行盒,没有 overflow:hidden,基线是真实存在的。 */ .wx-price{display:flex;align-items:baseline;gap:5px} .wx-price>i{font-style:normal;font-size:11.5px;color:var(--ink-2)} .wx-price>b{font-size:26px;font-weight:800;color:var(--brand);letter-spacing:-.5px;line-height:1} /* ⚠️ 这一行装的是「加<小名>的孕育顾问领取」,而小名那格是 maxlength="12", 整句能到 20 字上下。 所以必须是两行截断,不能沿用原来的单行省略 —— 单行会把后半截(含小名)整个吃掉,而 textContent 不受 CSS 截断影响, 测试里那条 /小汤圆/ 照样绿,屏幕上却什么都看不见。这是个静默失败。 */ /* ⚠️ margin-top 同样去掉了,理由和 .wx-price 一样:父列已经有 gap:5px。 */ .wx-sub{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2; font-size:12.5px;color:var(--ink-2);line-height:1.45;overflow:hidden} /* ---- 第四段:通栏 CTA ---- 用实心按钮而不是一个 › :这张卡要的是「点我」,不是「还有下一层」。 现在它是 .wx-card 的**直接子元素**,靠 column 容器的 stretch 铺满整卡 248px (上一版只占右列 159px)。整卡宽的实心按钮是电商卡的标准收尾。 ⚠️ 别再给它 flex:0 0 100%。那是更早一版配合 .wx-card 的 flex-wrap 用的; 在 column 容器里 flex-basis 作用于**高度**,会把这条按钮拉成整卡高。 ⚠️ text-align:center 不能省:全局 button{text-align:left}(style.css:80) 会一路继承下来,不写死的话文字贴在左边,看着像一条被拉长的标签。 */ .wx-cta{margin-top:13px;text-align:center;font-size:15.5px;font-weight:800;color:#fff; background:linear-gradient(135deg,#E86A3E,#D8452F); border-radius:14px;padding:12px;letter-spacing:.3px; box-shadow:0 4px 12px rgba(216,95,56,.3)} .list-card{background:#fff;border-radius:22px;padding:0 16px;box-shadow:var(--sh)} .li{display:flex;align-items:center;gap:13px;width:100%;padding:16px 0;border-bottom:1px solid var(--line)} .li:last-child{border:0} /* 列表图标已全部换成扁平描边矢量,各自给一个与底色同系的描边色 */ .li-ico{width:38px;height:38px;border-radius:11px;display:grid;place-items:center;flex:0 0 auto} .li-ico.y{background:#F4F0D8;color:#9A8A2E} .li-ico.p{background:#EFE9FA;color:#7B5FD4} .li-ico.o{background:#FBEDE3;color:#DE7443} .li-ico.b{background:#E6EFF8;color:#4478BC} .li-ico.r{background:#FBE9E7;color:#C33A2E} .li-t{font-size:16.5px;font-weight:700} .li-v{margin-left:auto;font-size:13px;color:var(--brand);font-weight:600} .li .chev{margin-left:auto} .li-v + .chev{margin-left:6px} /* ============ 详情页 ============ */ .detail{ position:absolute;inset:0;z-index:80;background:var(--bg); transform:translateX(100%);transition:transform .38s var(--ease); display:flex;flex-direction:column; } .detail.show{transform:none;box-shadow:-10px 0 30px rgba(0,0,0,.1)} .detail-bar{display:flex;align-items:center;gap:10px;padding:calc(env(safe-area-inset-top) + 14px) 18px 12px;background:rgba(248,243,239,.9);backdrop-filter:blur(14px);border-bottom:1px solid var(--line)} .dt-back{font-size:32px;line-height:.7;color:var(--ink);width:34px} .dt-title{font-size:17px;font-weight:800} .dt-star{margin-left:auto;font-size:23px;color:var(--muted);transition:transform .25s var(--ease)} .dt-star.on{color:#FFC93C} .dt-star:active{transform:scale(1.3)} .detail-body{flex:1;overflow-y:auto;padding:22px 22px 40px} .detail-body::-webkit-scrollbar{display:none} .dl-btn{flex:1;text-align:center;padding:15px;border-radius:22px;font-size:15.5px;font-weight:700;transition:transform .16s} .dl-btn:active{transform:scale(.96)} .dl-btn.ghost{background:#fff;color:var(--ink-2);box-shadow:var(--sh)} .dl-btn.main{background:var(--brand);color:#fff;box-shadow:0 10px 22px rgba(244,89,60,.34)} .dt-plain{margin-left:auto;line-height:1;color:var(--ink-2);width:30px;height:30px;display:grid;place-items:center} .dt-plain:active{opacity:.5} .d-sec{display:flex;align-items:center;font-size:16.5px;font-weight:800;color:var(--ink);margin:26px 0 13px} .d-sec .sec-more{font-size:12.5px} /* ============ 设置与服务 二级页 ============ */ .st-lead{font-size:13.5px;line-height:1.75;color:var(--ink-2);margin-bottom:4px} .st-card{background:#fff;border-radius:22px;padding:0 16px;box-shadow:var(--sh)} .st-card:first-child{margin-top:16px} .st-row{display:flex;align-items:center;gap:12px;width:100%;padding:15px 0;border-bottom:1px solid var(--line);position:relative;overflow:hidden} .st-row:last-child{border-bottom:0} .st-rt{font-size:15.5px;font-weight:700;min-width:0} /* 副标题挂在标题下面,em 撑成块级,行内不会把开关挤走 */ .st-rt em{display:block;font-size:12px;font-weight:500;font-style:normal;color:var(--muted);margin-top:3px;line-height:1.5} .st-rv{margin-left:auto;font-size:12.5px;color:var(--muted);flex:0 0 auto;max-width:52%;text-align:right} .st-row .chev{margin-left:auto;color:var(--muted)} .st-rv + .chev{margin-left:6px} /* 注意:不能叫 .st-txt —— 首页「今日成长脚印」的文字已经占了这个名字, 同名会把 padding 和分隔线漏到首页去,所以这里用 .st-para */ .st-para{font-size:14px;line-height:1.85;color:var(--ink-2);padding:15px 0;border-bottom:1px solid var(--line)} .st-para:last-child{border-bottom:0} /* 开关:轨道 40×24,圆点 18,开时右移 16px(40-18-2×3) */ .st-row.sw{cursor:pointer} .sw-track{margin-left:auto;flex:0 0 auto;width:40px;height:24px;border-radius:12px;background:#E2DAD3;position:relative;transition:background .24s var(--ease)} .sw-track b{position:absolute;left:3px;top:3px;width:18px;height:18px;border-radius:50%;background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.2);transition:transform .24s var(--ease)} .st-row.sw.on .sw-track{background:var(--brand)} .st-row.sw.on .sw-track b{transform:translateX(16px)} /* 关于页的品牌头 */ .st-about{text-align:center;padding:14px 0 22px} .st-logo{width:78px;height:78px;margin:0 auto 14px;border-radius:22px;background:linear-gradient(140deg,#FDE3D6,#F9C9B4);display:grid;place-items:center;box-shadow:var(--sh)} .st-logo svg{width:46px;height:46px} .st-appname{font-size:20px;font-weight:800;letter-spacing:-.3px} .st-ver{font-size:12.5px;color:var(--muted);margin-top:6px} /* ============ AI 小结详情 ============ 页面节奏:深 → 浅 → 线。 ① 今日卡是全页唯一的深色块,一进来眼睛就落在它上面; ② 三条建议是白卡,靠左侧分类色条区分主题; ③ 往期是一条时间轴,弱化成背景信息。 原来三段都是同一种白卡罗列,谁也不比谁重要,所以看着散。 */ .ai-body{background:linear-gradient(180deg,#FFF6F1 0%,var(--bg) 240px)} /* ---- ① 今日卡 ---- */ .ai-today{position:relative;overflow:hidden;border-radius:26px;padding:20px 20px 6px; background:linear-gradient(145deg,#4A3A34 0%,#6B4A3C 55%,#8A5340 100%); box-shadow:0 18px 34px rgba(90,58,44,.3)} /* 两团柔光,让深色底不至于死板;纯 CSS,不额外加图 */ .ai-glow{position:absolute;width:190px;height:190px;border-radius:50%;pointer-events:none; background:radial-gradient(circle,rgba(255,166,120,.5),transparent 70%);top:-96px;right:-54px} .ai-glow.b{width:150px;height:150px;background:radial-gradient(circle,rgba(255,255,255,.16),transparent 70%); top:auto;right:auto;bottom:-72px;left:-40px} .ai-t-top{position:relative;display:flex;align-items:center;gap:8px} .ai-week{font-size:12.5px;font-weight:800;color:#FFD9C4;background:rgba(255,255,255,.14); padding:5px 10px;border-radius:8px} .ai-date{margin-left:auto;font-size:12px;color:rgba(255,255,255,.62)} /* 今日状态:一枚小圆点 + 两个字,替掉原来那个撑场面的大引号 */ .ai-mood{position:relative;display:inline-flex;align-items:center;gap:6px;margin-top:16px; font-size:12.5px;font-weight:800;color:#FFC9A8;letter-spacing:1px} .ai-mood::before{content:"";width:7px;height:7px;border-radius:50%;background:#7BD3A0; box-shadow:0 0 0 4px rgba(123,211,160,.22)} .ai-hero-txt{position:relative;font-size:19px;font-weight:700;line-height:1.75;color:#fff; margin:9px 0 0;letter-spacing:.2px} .ai-stats{position:relative;display:flex;margin-top:18px} .ai-st{flex:1;text-align:center;padding:14px 4px 16px;position:relative} /* 竖分隔线用伪元素,比 border 好控制:首列不画,避免左边多一道 */ .ai-st+.ai-st::before{content:"";position:absolute;left:0;top:16px;bottom:18px;width:1px; background:rgba(255,255,255,.16)} .ai-st b{display:block;font-size:20px;font-weight:800;color:#fff;letter-spacing:-.3px} .ai-st span{display:block;font-size:11.5px;color:rgba(255,255,255,.6);margin-top:5px} /* 和昨天比的涨跌,只是补充信息,做得很轻 */ .ai-st em{display:inline-block;font-style:normal;font-size:10.5px;font-weight:700;margin-left:4px; color:#8FDCB0;vertical-align:2px} .ai-st em.dn{color:#FFB59B} .ai-st em.eq{color:rgba(255,255,255,.45)} /* ---- 段落小标题:序号 + 标题 + 一条延伸到底的细线 ---- */ .ai-sec{display:flex;align-items:center;gap:9px;margin:26px 0 13px} .ai-sec-n{font-size:11px;font-weight:800;color:var(--brand);background:rgba(244,89,60,.1); padding:3px 7px;border-radius:6px;letter-spacing:.5px} .ai-sec h3{font-size:16px;font-weight:800;color:var(--ink);letter-spacing:.2px} .ai-sec-line{flex:1;height:1px;background:linear-gradient(90deg,rgba(0,0,0,.09),transparent)} /* ---- ② 三条建议:每张卡一个主题色 ---- */ .ai-tips{display:flex;flex-direction:column;gap:11px} .ai-tip{position:relative;overflow:hidden;background:#fff;border-radius:18px; padding:15px 17px 16px 19px;box-shadow:var(--sh)} /* 左边一道竖色条,四张卡换四种颜色,扫一眼就知道在讲哪方面 */ .ai-tip::before{content:"";position:absolute;left:0;top:0;bottom:0;width:4px;background:var(--c)} /* 右上角一个巨大的浅色序号,纯装饰,撑住卡片右侧的空 */ .at-n{position:absolute;top:-8px;right:10px;font-size:52px;font-weight:800;line-height:1; color:var(--c);opacity:.09;pointer-events:none;user-select:none} .ai-tip.c-p{--c:#F2795A} .ai-tip.c-g{--c:#5AB98C} .ai-tip.c-b{--c:#5E93D8} .ai-tip.c-y{--c:#E0A63C} .ai-tip.c-r{--c:#D9739B} .at-cat{display:inline-block;font-size:11px;font-weight:800;color:var(--c); background:color-mix(in srgb,var(--c) 12%,#fff);padding:4px 9px;border-radius:7px;letter-spacing:.5px} /* color-mix 不支持的老浏览器上,上一行整条声明会被丢弃、底色变透明, 所以先垫一层带透明度的同色底作为兜底 */ @supports not (background:color-mix(in srgb,red 10%,#fff)){ .at-cat{background:rgba(0,0,0,.05)} } .at-head{font-size:15.5px;font-weight:800;line-height:1.6;color:var(--ink);margin:10px 0 5px; padding-right:24px} .at-txt{font-size:13.5px;line-height:1.75;color:var(--ink-2)} /* ---- ③ 往期:一条竖线串起来的时间轴 ---- */ .ai-logs{position:relative;display:flex;flex-direction:column;gap:8px;padding-left:22px} .ai-logs::before{content:"";position:absolute;left:5px;top:16px;bottom:16px;width:2px; border-radius:2px;background:linear-gradient(180deg,#F6D8C8,rgba(246,216,200,0))} .ai-log{position:relative;display:block;width:100%;text-align:left;background:#fff; border-radius:16px;padding:13px 15px;box-shadow:var(--sh)} .al-dot{position:absolute;left:-21px;top:19px;width:9px;height:9px;border-radius:50%; background:#fff;border:2px solid #EFC7B4;transition:.2s} /* 原来点一条会把它标成 .is-on(当前正在看的那天)。现在点了是弹窗, 看完就关,不存在「停留在某一天」,高亮改成按下去的一瞬间 */ .ai-log:active{background:#FFF6F1;box-shadow:0 8px 18px rgba(214,120,86,.16)} .ai-log:active .al-dot{border-color:var(--brand);background:var(--brand); box-shadow:0 0 0 4px rgba(244,89,60,.15)} .al-date{font-size:13.5px;font-weight:700;color:var(--ink)} .al-week{font-size:11.5px;color:var(--brand);margin-left:8px;font-weight:600} .al-txt{display:block;font-size:12.5px;color:var(--muted);margin-top:5px;line-height:1.5;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} /* ============ 资源列表 / 资源内容 ============ */ /* ---- 试用装福利 banner ---- 和「我的」页那张 .wx-card 同一件事、同一套暖色、结构也一样 (标题行 / 图文行 / 通栏 CTA 三段竖排),但仍然**不复用**它的类: 两边的尺寸账不同(图 68×60 vs 88×88、字号各小一档、页边距也不一样), 共用一个类只会逼出一堆 .detail-body .wx-card{...} 的覆盖规则。 ⚠️ 两套类名各自独立,所以**改一边要记得改另一边** —— 角标裁切这个 bug 当初就是只在这边被发现、那边照抄了同样的写法又犯一次。 ⚠️ 布局同 .wx-card:**竖向三段** —— .rlg-head 标题行 / .rlg-body 图文行 / .rlg-cta 通栏按钮。所以 flex-direction 是 column,不是 row。 ⚠️ 320 屏上的宽度账(**这一版重算过**): 卡内净宽 = 320 − 页边距 44(.detail-body 左右各 22)− 卡内边距 28 = 248, 和「我的」页那张卡一样宽(那边是 320 − 36 − 36)。两边数字撞在一起是巧合, 别当成一个可以共享的常量。 标题行(本批起**竖排**,跟 .wx-card 同步,两件各占一整行): 「可心柔婴儿纸巾」7 × 16 = 112 ≤ 248 ✓ 余 136px 「限领一份」 4 × 11.5 = 46 ≤ 248 ✓ 余 202px 图文行右列 = 248 − 图 68 − gap 10 = 170px: 角标「福利」2 × 10 + 内边 16 = 36 ✓ 价格行「到手价」3 × 11 = 33 + gap 5 + 「¥0」19px 两个半角 ≈ 21 → 59 ✓ 副文「加小汤圆的孕育顾问领取」11 × 12 = 132 ✓(且允许折两行) CTA 通栏 248px(上一版只有 170px)。 ⚠️ 为什么当初要拆成「标题行升到卡的直接子元素」这个结构:更早那一版是 左右两列、标题挤在 170px 的右列里,横排的商品名 + 限领要 218px,放不下。 标题行升上来拿到通栏 248px 才排得开。 ⚠️ 本批标题行又从横排改成了竖排(跟 .wx-card 同步,理由见那边), 于是 218px 那笔账作废了 —— 但**结构不要退回去**:退回右列之后 商品名只剩 170px,和「我的」页那张的 160px 一样会被字体滑块顶爆。 ⚠️ 尺度刻意比 .wx-card 小一号(图不放大到 88、字号各降一档): 那边四周是空的,这条 banner 下面紧跟着 128 条资源列表, 照搬那边的尺寸会把资源列表整个顶出首屏。 */ .rl-gift{display:flex;flex-direction:column;width:100%;text-align:left; background:linear-gradient(135deg,#FFF4EC,#FFE2D2); border-radius:20px;padding:12px 14px;margin:0 0 14px;box-shadow:var(--sh)} /* ⚠️ 用逐元素的 .rl-gift.hide,不引入全局 .hide,更不用 hidden 属性: 全项目零处使用 hidden,而 .letter-card.hide / .moment.hide 这套 逐元素写法是既有惯例,跟着走。 (测试里两条都断言:既查 .hide 类,也查算出来的 display —— jsdom 自带 [hidden]{display:none},光量 display 的话用 hidden 属性 也能蒙混过关。) */ .rl-gift.hide{display:none} /* ⚠️ 和 .wx-badge 同一个故事:上一版是 position:absolute;top:-7px 骑在卡上边缘, 被 .rl-gift 身上 .ripple 的 overflow:hidden(style.css:135)裁掉一半, 「福利」两个字只露出下半截。这是**比 .wx-badge 更早**就存在的老问题。 改成流内标签之后不可能再被裁。别改回绝对定位。 */ .rlg-badge{align-self:flex-start;font-size:10px;font-weight:700; color:#fff;background:var(--brand);border-radius:8px;padding:2px 8px; letter-spacing:.5px;box-shadow:0 2px 6px rgba(216,95,56,.28)} /* ---- 第一段:标题行 ---- ⚠️ align-items 用 flex-end 不用 baseline,理由和 .wx-head 一模一样: .rlg-title 带 overflow:hidden,按规范它没有可用基线,浏览器会拿 border box 底边合成一条,「(每人限领一份)」会被顶成上标。 改这条之前先读 .wx-head 上面那段注释。 ==== 本批同样改成竖排,上面那段 flex-end 的理由随横排一起作废 ==== 这一张其实排得下(248px 通栏,横排余 30px),改它纯粹是为了和「我的」页那张 保持一致 —— 用户早先要求两张卡「一模一样」,一张横排一张竖排并排看就是两个东西。 竖排之后也不再有「没有可用基线」那个坑:两件不在同一行,压根不需要对基线。 ⚠️ 别只改一边。这两张卡的标题行是**成对**的,动一张就得动另一张。 */ .rlg-head{display:flex;flex-direction:column;align-items:flex-start;gap:3px;min-width:0} /* ---- 第二段:图文行 ---- */ .rlg-body{display:flex;align-items:center;gap:10px;margin-top:9px} /* 同时管占位的 和以后换上的 ,换真图时这段不用动 */ .rlg-fig{flex:0 0 auto;width:68px;height:60px;display:block;border-radius:12px; object-fit:cover;background:#FFF9F5} /* 图文行的右列:竖向,默认 stretch,所以价格行/副文自动满列宽; 只有角标 align-self:flex-start 缩成胶囊。 ⚠️ 标题和 CTA 已经不在这一列里了(升到 .rlg-head 和卡的直接子元素)。 */ .rlg-main{flex:1;min-width:0;display:flex;flex-direction:column} /* ⚠️ 竖排之后两件不再抢同一条宽度,「谁先被压缩」这个问题整个消失了。 ellipsis 三件套留着当兜底,正常不该触发。字号 15 → 16,和 .wx-title 同步。 */ .rlg-title{max-width:100%;min-width:0;font-size:16px;font-weight:700;color:var(--ink); line-height:1.3;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} /* 「限领一份」,和「我的」页 .wx-lim 同一句、同样是小字、 本批起同样排在商品名**下面独占一行**(原来在标题右侧)。 ⚠️ 这两条规则现在字号也一致了(都 11.5)。上一版这边 11.5、那边被挤到 10.5, 文案逐字相同但字号差一档 —— 那种「几乎一样」比明显不同更难发现。 */ /* 同 .wx-lim:不写 align-self,父级 .rlg-head 的 align-items:flex-start 已经管了。 */ .rlg-lim{white-space:nowrap;font-size:11.5px;color:#8E827C;line-height:1.3} /* 价格行,和 .wx-price 同构、字号各降一档。同样只有到手价、没有编出来的划线价。 ⚠️ 得显式 font-style:normal,否则浏览器默认样式把中文几何倾斜,糊得厉害。 */ .rlg-price{display:flex;align-items:baseline;gap:5px;margin-top:6px} .rlg-price>i{font-style:normal;font-size:11px;color:var(--ink-2)} .rlg-price>b{font-size:19px;font-weight:800;color:var(--brand);letter-spacing:-.5px;line-height:1} /* 副标题只讲「怎么领」,**不再兼当 CTA** —— 下面有真按钮了。 ⚠️ 从单行省略改成了两行截断。这行现在由 syncBabyWords() 写入 「加<小名>的孕育顾问领取」,小名 maxlength="12",整句能到 20 字 ≈ 240px, 而右列只有 170px —— 再用 nowrap+ellipsis 会把「领取」连同小名一起吃掉, 偏偏 textContent 查得到,测试还是绿的。和 .wx-sub 栽的是同一个坑。 */ .rlg-sub{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2; font-size:12px;color:var(--ink-2);margin-top:5px;line-height:1.45;overflow:hidden} /* ---- 第三段:通栏 CTA ---- ⚠️ 和 .wx-cta 同款但字号小一号(这条 banner 整体比「我的」页那张卡矮)。 ⚠️ 现在是 .rl-gift 的直接子元素,靠 column 容器的 stretch 铺满 248px。 别给它 flex:0 0 100% —— 在 column 容器里 flex-basis 作用于**高度**。 ⚠️ 必须 text-align:center:全局 button{text-align:left} 会继承下来, 而且 .rl-gift 自己还写了一遍 text-align:left,不覆盖就贴左边。 */ .rlg-cta{margin-top:11px;text-align:center;font-size:14px;font-weight:700;color:#fff; background:var(--brand);border-radius:12px;padding:9px 10px; box-shadow:0 4px 10px rgba(216,95,56,.24)} .rl-lead{font-size:13px;color:var(--ink-2);margin:0 0 14px} .rl-lead b{color:var(--brand);font-size:15px} .res-list{display:flex;flex-direction:column;gap:11px} .res-item{display:flex;align-items:center;gap:12px;width:100%;text-align:left;background:#fff;border-radius:18px;padding:11px;box-shadow:var(--sh)} .ri-thumb{flex:0 0 auto;width:62px;height:62px;border-radius:14px;display:grid;place-items:center;overflow:hidden} .ri-thumb img{width:74%;height:74%;object-fit:contain;display:block} .ri-thumb.o{background:#FDEBE2}.ri-thumb.g{background:#E8F1E2} .ri-thumb.p{background:#EFE8F6}.ri-thumb.b{background:#E4EDF9} .ri-body{min-width:0;flex:1} .ri-title{display:block;font-size:15px;font-weight:800;color:var(--ink);line-height:1.3;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} .ri-desc{display:block;font-size:12px;color:var(--ink-2);margin:4px 0 7px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} .ri-row{display:flex;align-items:center;gap:6px} .ri-row em{font-style:normal;font-size:11px;line-height:1} /* 状态标顶到最右(原来 margin-left:auto 挂在「8 分钟读完」上)。 ⚠️ 2026-09-19:这一格原来还有「已领 ✓」这个状态(.pill-got), 9.19 需求取消「已领」概念后只剩「免费」,相关样式一并删除。 */ .pill-free{margin-left:auto} .pill-free{background:rgba(110,154,86,.14);color:var(--green);font-weight:700;padding:3.5px 7px;border-radius:6px} .ri-cat{background:rgba(244,89,60,.1);color:var(--brand);font-weight:700;padding:3.5px 7px;border-radius:6px} /* 适用孕周,顶掉了原来的「几分钟读完」。不给底色 —— 左边已经有一个实心分类标, 再来一个就成了两个胶囊抢注意力,而它只是补充说明。 nowrap:「孕24-28周」这种断在中间比溢出还难看 */ .ri-ga{color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis} /* ---- 已领的资源:整块已删除(2026-09-19) ---- .pill-got / .ri-got-tick / .res-item.is-got / .chip-got 都随「已领」概念一起删了 (9.19 需求:资料由顾问在微信里直接发,H5 不再有「立即领取即到手」这个动作)。 ⚠️ .ri-thumb 的 position:relative 曾经挂在这一块里给角标定位用 —— 现在没有角标了, 也就不需要;若以后要往里放绝对定位元素,记得自己加回来。 */ .res-list.slim .ri-thumb{width:50px;height:50px;border-radius:12px} .res-list.slim .ri-title{font-size:14px} .rd-cover{height:168px;border-radius:22px;display:grid;place-items:center;background:#FDEBE2;margin-bottom:16px;overflow:hidden} .rd-cover.o{background:linear-gradient(135deg,#FDEEE5,#F9DCCC)} .rd-cover.g{background:linear-gradient(135deg,#ECF4E6,#DBE9D0)} .rd-cover.p{background:linear-gradient(135deg,#F2EBF8,#E4D9F1)} .rd-cover.b{background:linear-gradient(135deg,#E8F0FA,#D6E4F5)} .rd-cover img{width:132px;height:132px;object-fit:contain;display:block;filter:drop-shadow(0 8px 18px rgba(140,90,70,.2))} .rd-cat{display:inline-block;font-size:11.5px;font-weight:700;color:var(--brand);background:rgba(244,89,60,.1);padding:5px 11px;border-radius:8px} .rd-title{font-size:24px;font-weight:800;letter-spacing:-.5px;margin:11px 0 7px;line-height:1.3} .rd-desc{font-size:13.5px;color:var(--ink-2);margin:0} .rd-meta{display:flex;flex-wrap:wrap;gap:7px;margin:14px 0 6px;padding-bottom:18px;border-bottom:1px solid var(--line)} .rd-meta span{font-size:11.5px;color:var(--muted);background:#fff;border:1px solid var(--line);padding:5px 10px;border-radius:8px} .rd-body h4{font-size:16px;font-weight:800;color:var(--ink);margin:22px 0 9px} .rd-body p{font-size:15px;line-height:1.95;color:#4A403A;margin:0} /* 「收藏 / 立即领取」吸底浮动:它是 .detail 的直接子元素(不在滚动区里), 所以正文怎么滑,这条都停在底部。不用 position:fixed —— .detail 自身带 transform,fixed 会以它为包含块,反而错位。 */ .rd-cta{ flex:0 0 auto;display:flex;gap:11px;position:relative; padding:12px 22px calc(env(safe-area-inset-bottom) + 14px); background:rgba(248,243,239,.94);backdrop-filter:blur(14px); border-top:1px solid var(--line); } /* 上沿渐隐,正文滑到底时不会被硬生生切断 */ .rd-cta::before{ content:"";position:absolute;left:0;right:0;bottom:100%;height:22px;pointer-events:none; background:linear-gradient(rgba(248,243,239,0),rgba(248,243,239,.94)); } /* ⚠️ 这里原来有一条 .rd-cta .dl-btn.main.got(领过之后按钮变绿)—— 9.19 需求取消「已领」概念后按钮只有一种状态,该条删除。 */ /* 吸底条已占掉底部空间,滚动区不用再留 40px */ #detailRes .detail-body,#detailPoster .detail-body{padding-bottom:18px} /* 档案预览有三个按钮,挤一点、字小一号 */ .pst-cta .dl-btn{padding-left:0;padding-right:0;font-size:14px} /* ---- 百度网盘领取弹窗:整块已删除(2026-09-19) ---- .pan-box / .pan-row / .pan-k / .pan-v / .pan-note 随 #modalPan 一起删 (9.19 需求:资料由顾问在微信里直接发,H5 不再发网盘链接与提取码)。 要恢复「H5 自己发链接」,等于把「解锁」概念加回来 —— 先回问需求方。 */ /* ---- 加企业微信顾问弹窗 ---- 紧挨着上面的网盘弹窗放:这两个弹窗是同一条领取动线的前后两步 (先扫码换码,再拿链接)。隔开几百行的话,改动线文案时几乎必然只改到一头。 */ .wx-qr-box{margin-top:16px;text-align:center} /* 这条挂在元素本身(原占位的 、现在这张真图 都吃):换图时一个字都不用动。 ⚠️ 别改成 .wx-qr img 或 svg.wx-qr —— 那样一换成 尺寸就全丢。 */ .wx-qr{display:block;width:168px;height:168px;margin:0 auto;border-radius:14px;background:#fff} .wx-qr-cap{font-size:12px;color:var(--muted);margin-top:10px} /* ⚠️ 这里原来有 .wx-code(兑换码输入框)与 .wx-code.is-err(码错标红)—— 9.19 需求删掉输入框后一并删除。 */ /* ⚠️ 2026-09-19(9.19 需求 1.2):这里原来是 .wx-err(兑换码红字)以及 is-done / is-gift / is-gate 三模式的收起规则(把 .wx-form 与 #wxOk 藏起来)。 兑换码输入框和两颗按钮整个删掉之后,这些规则没有对应元素了,一并删除。 弹窗现在是单态(只剩标题 + 引导语 + 二维码),唯一出口是右上角 .modal-x。 */ /* ============ 记一下 弹层 ============ */ .scrim{position:absolute;inset:0;background:rgba(50,30,22,.42);backdrop-filter:blur(2px);opacity:0;visibility:hidden;transition:opacity .32s,visibility .32s;z-index:90} .scrim.show{opacity:1;visibility:visible} .sheet{ position:absolute;left:0;right:0;bottom:0;z-index:95;max-height:92%; background:#FAF5F1;border-radius:28px 28px 0 0; display:flex;flex-direction:column; transform:translateY(100%);transition:transform .42s var(--ease); box-shadow:0 -10px 40px rgba(90,50,35,.2); } .sheet.show{transform:none} .sheet.dragging{transition:none} .sheet-grip{padding:10px 0 4px;display:grid;place-items:center;cursor:grab;touch-action:none} .sheet-grip span{width:42px;height:5px;border-radius:3px;background:#DCD2CA} .sheet-head{display:flex;align-items:flex-start;justify-content:space-between;padding:8px 22px 14px} .sheet-head h2{font-size:26px;font-weight:800;letter-spacing:-.5px} .sheet-head p{font-size:13px;color:var(--ink-2);margin-top:8px} .sheet-close{width:38px;height:38px;border-radius:50%;background:#EEE7E1;display:grid;place-items:center;font-size:15px;color:var(--ink-2);flex:0 0 auto} .sheet-close:active{transform:scale(.9)} .sheet-scroll{flex:1;overflow-y:auto;padding:0 18px 8px} .sheet-scroll::-webkit-scrollbar{display:none} /* ⚠️ 临时隐藏开关(2026-09-22):「记一下」弹层里的「今天已使用」快捷区 + 日期/今天已记 那行 **功能尚未实现**(数据是写死的演示值),产品要求先整体隐藏、代码保留。 用法:在 index.html 对应元素上挂 .tbd-hide。 恢复:去掉 index.html 里那三处 .tbd-hide 即可(js/app.js 的 dedupeApps 会自动重新生效)。 */ .tbd-hide{display:none!important} /* 「今日心情」已删除,只剩 3 个工具,所以是 3 列 */ .quick-row{display:grid;grid-template-columns:repeat(3,1fr);gap:9px} .quick{border-radius:17px;padding:13px 8px;text-align:center;transition:transform .16s} .quick:active{transform:scale(.95)} .quick.q1{background:#FCE4DA}.quick.q2{background:#FBDDD2}.quick.q3{background:#FCE2DE} .q-ico{display:block;width:34px;height:auto;margin:0 auto 7px;object-fit:contain} .q-t{display:block;font-size:14px;font-weight:800} .q-v{display:block;font-size:12.5px;font-weight:700;color:var(--brand);margin-top:4px} .apps-head{display:flex;align-items:center;font-size:15.5px;font-weight:700;color:var(--ink-2);margin:22px 4px 14px} .apps-head.first{margin-top:2px} .apps-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:16px 8px} .app{display:flex;flex-direction:column;align-items:center;gap:8px;font-size:12.5px;font-weight:600;color:var(--ink-2);transition:transform .16s} .app:active{transform:scale(.9)} /* 16 宫格磁贴:整块(含圆角底色 + 3D 图标)直接取自设计稿 */ .a-ico{width:54px;height:54px;display:block;object-fit:contain} /* ============ 搜索层 ============ */ .search-layer{position:absolute;inset:0;z-index:85;background:var(--bg);opacity:0;visibility:hidden;transform:translateY(-8px);transition:opacity .28s var(--ease),visibility .28s var(--ease),transform .28s var(--ease)} .search-layer.show{opacity:1;visibility:visible;transform:none} .sl-bar{display:flex;align-items:center;gap:12px;padding:calc(env(safe-area-inset-top) + 16px) 18px 14px} .sl-input{flex:1;display:flex;align-items:center;gap:9px;background:#fff;border-radius:20px;padding:11px 15px;box-shadow:var(--sh)} .sl-input input{flex:1;border:0;outline:0;font:inherit;font-size:15px;background:none} .sl-cancel{font-size:15px;color:var(--brand);font-weight:600} .sl-body{padding:8px 18px} .sl-sec{font-size:14px;font-weight:700;color:var(--ink-2);margin:18px 2px 12px} .sl-hot .hot{display:flex;align-items:center;gap:12px;width:100%;padding:13px 2px;font-size:15px;border-bottom:1px solid var(--line)} .sl-hot .hot i{width:20px;height:20px;border-radius:6px;background:#F0E8E2;color:var(--muted);font-style:normal;font-size:12px;font-weight:700;display:grid;place-items:center} .sl-hot .hot:nth-child(1) i{background:var(--brand);color:#fff} .sl-hot .hot:nth-child(2) i{background:#F79274;color:#fff} .sl-hot .hot:nth-child(3) i{background:#F9B9A5;color:#fff} /* ============ 底部导航 ============ */ /* 设计稿的导航是一枚「悬浮药丸」(x60..791 / y1902..1988 of 857 → 左30 右32 高43.5)。 药丸形态与位置保持设计稿,但图标与文字按可读性放大: 图标 24px · 文字 12.5px · 中心圆钮 44px,药丸高度相应提到 58px。 */ .tabbar{ position:absolute;left:26px;right:26px;bottom:calc(14px + env(safe-area-inset-bottom));z-index:60; height:58px;border-radius:29px; display:flex;align-items:center;padding:0 4px; background:rgba(252,249,247,.95);backdrop-filter:blur(18px);-webkit-backdrop-filter:blur(18px); box-shadow:0 10px 30px rgba(150,90,70,.16),0 2px 8px rgba(150,90,70,.08); } .tab{position:relative;flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;height:100%;color:#A99D95;transition:color .22s} .tab.is-active{color:var(--brand)} /* 底部导航图标:设计稿原图转成蒙版,用 currentColor 染色, 未选中 #B3A79F / 选中 var(--brand),形状与设计稿逐像素一致 */ .t-ico{width:24px;height:24px;display:block;position:relative;transition:transform .28s var(--ease); background-color:currentColor; -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat; -webkit-mask-position:center;mask-position:center; -webkit-mask-size:contain;mask-size:contain} .t-ico.ic-home{-webkit-mask-image:url(assets/img/1afd85e578dd.png);mask-image:url(assets/img/1afd85e578dd.png)} .t-ico.ic-archive{-webkit-mask-image:url(assets/img/fa7b793b47e8.png);mask-image:url(assets/img/fa7b793b47e8.png)} .t-ico.ic-letter{-webkit-mask-image:url(assets/img/949338312a1f.png);mask-image:url(assets/img/949338312a1f.png)} /* ⚠️ 2026-09-19(9.19 需求第 2 条):底 tab 从「兜爸心选」改回「宝宝来信」, 用的是上面 .ic-letter(图标资源一直在,没删过)。原来这条 .ic-shop(购物袋图标) 已随改名删除 —— 商城入口仍在「我的」页服务卡与首页商城主卡上。 图标源文件 assets/img/b3253e3c7a83.png 保留在仓库里(不引用的二进制无害), 哪天要再挂一枚商城 tab,把这条规则抄回来即可。 */ .t-ico.ic-me{-webkit-mask-image:url(assets/img/0ebc7631fea4.png);mask-image:url(assets/img/0ebc7631fea4.png)} .tab.is-active .t-ico{transform:translateY(-2px) scale(1.06)} /* nowrap:最长的那条是「兜爸心选」(原「宝宝来信」,同为四个汉字),12.5px ≈ 50px, 320px 视口下每格 tab ≈ 64px,塞得下。但字号一旦被系统放大就会折行, 而 tab 是固定高度的,折了会把图标顶出去,所以宁可让它溢出也不折。 */ .t-txt{font-size:12.5px;font-weight:600;line-height:1.1;letter-spacing:.2px;white-space:nowrap} /* 角标移到 .tab 上定位——.t-ico 现在是 mask 元素,子元素会被一并遮罩 */ .t-badge{display:none;position:absolute;top:9px;left:calc(50% + 8px);width:9px;height:9px;background:#FF3B30;border-radius:50%;border:1.5px solid #FCF9F7} .t-badge.show{display:block} .tab-fab{position:relative} /* 「记一下」中心按钮:整枚圆钮直接取自设计稿像素。 设计稿中它并不「凸出」药丸,而是与其它图标同处一行、只是更大。 */ .fab{ flex:0 0 auto;width:38px;height:38px;border-radius:50%; display:grid;place-items:center; box-shadow:0 6px 16px rgba(244,89,60,.42); transition:transform .3s var(--ease); } .fab img{width:100%;height:100%;display:block;border-radius:50%;object-fit:cover} .tab-fab .t-txt{color:var(--brand)} .tab-fab:active .fab{transform:scale(.9) rotate(90deg)} /* ⚠️ 这条以前写作 `.sheet.show ~ .tabbar .fab`。本批把