/* ===== pv-tokens.css ===== */
/* ============================================================
   pv-tokens.css  ·  paidvideo 设计系统 v0（阶段0）
   全站唯一设计 token 来源。accent = 青 #38e0d8。
   本文件只定义 CSS 变量 + pv- / surface- 命名空间的类，
   不含任何裸元素选择器(body/button…)，因此引入后对现有页面零视觉影响。
   现状页面尚未使用这些变量/类；阶段1 起逐页改用。
   ============================================================ */
:root{
  /* — 品牌强调（全站唯一 accent） — */
  --accent:#38e0d8; --accent-press:#22b8b0; --on-accent:#04302c; --accent-ink:#0b6f69;
  /* — 语义色（前后台通用） — */
  --price:#ffcf4d; --danger:#ff5d5d; --success:#37c98d; --warn:#f2a93b;
  /* — 深色（用户端）中性阶 — */
  --d-bg:#0d1017; --d-surface:#151a24; --d-surface-2:#1c2230; --d-line:#2a3140;
  --d-text:#e9edf4; --d-text-2:#b8c1d0; --d-muted:#8a95a8;
  /* — 浅色（后台）中性阶（暖白，唯一保留的暖调） — */
  --l-bg:#f6f3ef; --l-surface:#ffffff; --l-surface-2:#faf7f2; --l-line:#e7ded4;
  --l-text:#241f1a; --l-text-2:#4f463d; --l-muted:#8a7f73;
  /* — 字体 — */
  --font:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif;
  --mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  /* — 字阶（8 档，取代原 22 种） — */
  --t-cap:12px; --t-sm:13px; --t-body:15px; --t-h4:17px; --t-h3:20px; --t-h2:26px; --t-h1:34px;
  /* — 圆角（3 档 + pill，取代原 18 种） — */
  --r1:8px; --r2:12px; --r3:16px; --pill:999px;
  /* — 间距阶 — */
  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px; --s6:32px;
  /* — 阴影（2 档，取代原 18 种） — */
  --e1:0 1px 2px rgba(0,0,0,.18),0 4px 12px rgba(0,0,0,.10);
  --e2:0 2px 6px rgba(0,0,0,.24),0 14px 36px rgba(0,0,0,.18);
}
/* 语义 surface：组件只认这些语义名，换面即适配前后台 */
.surface-dark{--bg:var(--d-bg);--surface:var(--d-surface);--surface-2:var(--d-surface-2);
  --line:var(--d-line);--text:var(--d-text);--text-2:var(--d-text-2);--muted:var(--d-muted);--acc-ink:var(--accent);}
.surface-light{--bg:var(--l-bg);--surface:var(--l-surface);--surface-2:var(--l-surface-2);
  --line:var(--l-line);--text:var(--l-text);--text-2:var(--l-text-2);--muted:var(--l-muted);--acc-ink:var(--accent-ink);}

/* ===== 组件基类（阶段2 起全站统一到这些） ===== */
.pv-btn{font-family:var(--font);font-size:var(--t-body);font-weight:600;line-height:1;
  padding:12px 20px;border-radius:var(--r2);border:1px solid transparent;cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center;gap:8px;transition:.15s;white-space:nowrap;text-decoration:none}
.pv-btn:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.pv-btn--primary{background:var(--accent);color:var(--on-accent)}
.pv-btn--primary:hover{background:var(--accent-press)}
.pv-btn--secondary{background:transparent;color:var(--acc-ink);border-color:var(--acc-ink)}
.pv-btn--secondary:hover{background:color-mix(in srgb,var(--accent) 12%,transparent)}
.pv-btn--ghost{background:var(--surface-2);color:var(--text-2);border-color:var(--line)}
.pv-btn--ghost:hover{color:var(--text)}
.pv-btn--danger{background:var(--danger);color:#fff}
.pv-btn[disabled],.pv-btn.is-disabled{opacity:.45;cursor:not-allowed}
.pv-btn--block{width:100%}

.pv-card{background:var(--surface);border:1px solid var(--line);border-radius:var(--r2);
  box-shadow:var(--e1);padding:var(--s4)}
.pv-panel{background:var(--surface);border:1px solid var(--line);border-radius:var(--r3);padding:var(--s5)}

.pv-chip{font-family:var(--mono);font-size:var(--t-cap);font-weight:600;padding:3px 9px;
  border-radius:var(--pill);display:inline-block;line-height:1.4}
.pv-chip--accent{background:color-mix(in srgb,var(--accent) 16%,transparent);color:var(--acc-ink)}
.pv-chip--danger{background:color-mix(in srgb,var(--danger) 16%,transparent);color:var(--danger)}
.pv-chip--success{background:color-mix(in srgb,var(--success) 16%,transparent);color:var(--success)}

.pv-input{width:100%;font-family:var(--font);font-size:var(--t-body);padding:11px 13px;
  background:var(--surface-2);border:1px solid var(--line);border-radius:var(--r1);color:var(--text);outline:none}
.pv-input::placeholder{color:var(--muted)}
.pv-input:focus-visible{border-color:var(--accent);outline:2px solid color-mix(in srgb,var(--accent) 40%,transparent);outline-offset:0}

.pv-price{font-family:var(--mono);font-variant-numeric:tabular-nums;color:var(--price);font-weight:700}

/* ============================================================
   pv-tokens v1 · 企业级精修追加（阶段2）
   全部 additive：只新增 token / 工具类，不改任何既有值，
   故已 token 化的页面零回归，新页面按需采用这些工具类。
   ============================================================ */
:root{
  /* 动效 */
  --dur-1:.15s; --dur-2:.28s; --ease:cubic-bezier(.4,0,.2,1);
  /* 焦点环（可访问性） */
  --ring:0 0 0 3px color-mix(in srgb,var(--accent) 30%,transparent);
  /* 轻阴影层级（补 e1/e2 之下的一档） */
  --e0:0 1px 1px rgba(0,0,0,.10),0 1px 3px rgba(0,0,0,.07);
  /* 玻璃顶栏底 */
  --glass:color-mix(in srgb,var(--d-bg) 86%,transparent);
}
@media (prefers-reduced-motion:reduce){
  *{transition-duration:.01ms!important;animation-duration:.01ms!important}
}

/* 交互卡片：hover 抬升 + 描边点亮 */
.pv-card--hover{transition:transform var(--dur-1) var(--ease),box-shadow var(--dur-1) var(--ease),border-color var(--dur-1) var(--ease);will-change:transform}
.pv-card--hover:hover{transform:translateY(-2px);box-shadow:var(--e2);border-color:color-mix(in srgb,var(--accent) 42%,var(--d-line))}
.pv-card--hover:active{transform:translateY(0)}

/* 统计磁贴（企业级看板质感） */
.pv-stat{background:var(--surface,var(--d-surface));border:1px solid var(--line,var(--d-line));border-radius:var(--r2);padding:14px 16px;display:flex;flex-direction:column;gap:5px}
.pv-stat .n{font-family:var(--mono);font-variant-numeric:tabular-nums;font-size:var(--t-h3);font-weight:800;color:var(--accent);line-height:1}
.pv-stat .l{font-size:var(--t-cap);color:var(--muted,var(--d-muted));line-height:1.3}

/* 区块小标签 / eyebrow */
.pv-eyebrow{font-size:var(--t-cap);letter-spacing:.06em;color:var(--muted,var(--d-muted));font-weight:600;display:flex;align-items:center;gap:8px}
.pv-eyebrow .ct{font-family:var(--mono);color:var(--accent);font-weight:700}

/* 玻璃顶栏 */
.pv-appbar{position:sticky;top:0;z-index:8;display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:12px 16px;background:var(--glass);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
  border-bottom:1px solid color-mix(in srgb,var(--d-line) 55%,transparent)}
.pv-appbar a{color:var(--d-text-2);text-decoration:none;font-size:var(--t-sm);transition:color var(--dur-1)}
.pv-appbar a:hover{color:var(--d-text)}
.pv-appbar a.accent{color:var(--accent);font-weight:600}

/* 细分隔线 */
.pv-hair{height:1px;background:var(--d-line);border:0;margin:0}

/* 会员升级条（accent 柔光） */
.pv-upsell{display:flex;align-items:center;justify-content:space-between;gap:12px;
  background:linear-gradient(100deg,color-mix(in srgb,var(--accent) 16%,transparent),color-mix(in srgb,var(--accent) 6%,transparent));
  border:1px solid color-mix(in srgb,var(--accent) 34%,transparent);border-radius:var(--r2);padding:13px 15px}

/* ══════════════════════════════════════════════════════════════════════════
   PV_MEUI_V1（2026-08-22）个人中心的入口行 / 折叠卡
   --------------------------------------------------------------------------
   /me 上的卡片来自 8 个互不相干的模块（escrow / agent_apply / ugc / ugc_share /
   session_keep / wallet / features 群入口 / review），每个模块自己拼一串内联样式。
   于是同一屏里出现了 16px 和 12px 两种圆角、三套内边距，
   🔴 而且其中三张把深色**写死**成 #161b26 / #131826 + 浅字 #e8ecf4 ——
      线上默认是小红书白主题（pv-red.css 把 --d-bg 重定义成 #F5F5F7、卡面纯白），
      于是那三张在白页面里是**三块黑砖**。
   收敛成这里的两个类，模块侧只写 class、不再写任何颜色，白/深两套主题自动都对。

   🔴 为什么放在 pv-tokens.css 而不是 /me 的 <style> 里：
      design_system.py 把本文件注入**每一个页面**，所以模块保持"自包含、删掉即回退"
      —— 它们不依赖 repurchase.py 的模板，只依赖这份全站基础设施（同 .pv-stat 的地位）。
   🔴 hover 必须锁在 @media(hover:hover) 里：手机没有 hover，触屏点完样式会**粘住**不退。
      这条红线在本项目已经现形四次（按钮 → 卡片 → /fun 答题选项 → 这里）。 */
.pv-merow{display:flex;align-items:center;gap:11px;padding:14px 16px;margin-bottom:11px;
  background:var(--d-surface);border:1px solid var(--d-line);border-radius:var(--r3);
  text-decoration:none;color:var(--d-text);
  transition:border-color var(--dur-1) var(--ease),transform var(--dur-1) var(--ease)}
.pv-merow .ic{font-size:20px;line-height:1.2;flex:none}
.pv-merow .bd{flex:1;min-width:0}
.pv-merow .tt{display:block;font-size:15px;font-weight:600;color:var(--d-text);line-height:1.35}
.pv-merow .sb{display:block;font-size:12px;color:var(--d-muted);margin-top:2px;line-height:1.5}
.pv-merow .go{font-size:13px;color:var(--d-muted);white-space:nowrap;flex:none}
.pv-merow .go.acc{color:var(--accent);font-weight:600}
@media(hover:hover){.pv-merow:hover{transform:translateY(-1px);
  border-color:color-mix(in srgb,var(--accent) 42%,var(--d-line))}}
.pv-merow:active{transform:translateY(0)}

/* 折叠卡：默认收成一行，点开才展开。用原生 <details>，零 JS。
   给「我的申请」「登录与安全」这类"平时不用看、出事才看"的信息用 ——
   它们此前各占一整块，把用户真正要找的东西挤到了第四屏。 */
.pv-mefold{background:var(--d-surface);border:1px solid var(--d-line);border-radius:var(--r3);
  padding:0 16px;margin-bottom:11px}
.pv-mefold>summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:10px;
  padding:14px 0;font-size:14px;font-weight:600;color:var(--d-text)}
.pv-mefold>summary::-webkit-details-marker{display:none}
.pv-mefold>summary .sb{font-weight:400;font-size:12px;color:var(--d-muted)}
.pv-mefold>summary .go{margin-left:auto;font-size:12px;color:var(--d-muted);transition:transform var(--dur-1)}
.pv-mefold[open]>summary .go{transform:rotate(90deg)}
.pv-mefold>.bd{padding:0 0 14px;border-top:1px solid var(--d-line)}

/* ===== pv-red.css ===== */
/* ============================================================
   pv-red.css  ·  PV_THEME_RED_V1 —— 「小红书白」配色覆盖层
   ------------------------------------------------------------
   老板 2026-08-15 拍板的 B 方案：整站顾客端由「深色 + 青绿」翻成
   「白底 + 品牌红 #FF2442」。

   🔴 这个文件只做一件事：重新定义 pv-tokens.css 里的 token 值。
      不新增任何选择器、不碰任何组件类、不含裸元素选择器。
      因此它对「用了 token 的页面」全量生效、对「写死颜色的页面」
      完全没有影响 —— 后者要逐页手改，是后续批次的事。

   🔴 加载顺序必须在 pv-tokens.css 之后（同为 :root 同特异度，后来者胜）。
      注入方在 design_system.py，只注入给顾客端路由；
      /admin 与 /shop 后台不注入，保持原来的青绿/暖白橙不受影响。

   🔴 变量名一个都没改（仍叫 --d-bg 这种「深色」名字）。
      改名要动 14 个文件上百处引用，收益为零、风险很大。
      这里只换值：--d-* 从此读作「用户端中性阶」，不再读作「深色」。

   🔴 底色与卡片是反的，别当成写错了。
      小红书的层次是「页面底浅灰 + 卡片纯白」，不是「底纯白 + 卡片纯白」。
      list.html 的 .card / .nav a / .cattabs a 都用 background:var(--d-surface)，
      surface 若与 bg 同为纯白，卡片和导航标签会在白底上整个消失。
      所以 --d-bg 是灰、--d-surface 是白 —— 深色主题下正好相反，这是有意的。

   📐 所有中性阶与文字色都按 WCAG 对比度实算过（见每行末尾的数字），
      正文/小字一律 ≥4.5:1。改这些值之前请重算，别凭眼睛调。
   ============================================================ */
:root{
  /* — 品牌强调：青 #38e0d8 → 小红书红 —
       ⚠️ 填充色与文字色有意分成两个值：#FF2442 是小红书的招牌红，
       但它在白底上只有 3.76:1、白字压在它上面也只有 3.76:1，
       当文字色用会不达标。所以「背景填充用 --accent 保品牌辨识度，
       浅底上的文字/链接用 --accent-ink 保可读」，两者分工不要混。 */
  --accent:#FF2442;        /* 品牌红，只做背景填充/边框/角标。原 #38e0d8 */
  --accent-press:#D9082A;  /* 按下态 */
  --on-accent:#FFFFFF;     /* 红底上的文字。原 #04302c 是深青，翻白底后必须换 */
  --accent-ink:#D9082A;    /* 浅底上的强调文字/链接。5.22:1 */

  /* 🔴 --lp-ink 与 --accent-ink 同值，但**不是**重复定义，两者不能互相顶替：
     --accent-ink 在 pv-tokens.css 里也有定义(深青 #0b6f69)，是「两套色板各有一份」；
     --lp-ink 只在本文件存在，用法固定是 var(--lp-ink, 深色主题下的原值) ——
     给那些「深底用青、浅底用红」、单个 token 表达不了的属性用。
     首例：list.html 的 .ft a（页脚链接）。直接换 --accent-ink 会让它在深色主题下
     变成 #0b6f69 压 #0d1017 = 3.14:1，是对线上用户的回归。 */
  --lp-ink:#D9082A;

  /* — 语义色：全部按浅底重配，原值是按深底调的 — */
  --price:#D9082A;   /* 5.22:1。原金色 #ffcf4d 在白底上约 1.4:1，等于看不见 */
  --danger:#D92D20;  /* 原 #ff5d5d 在白底上偏粉、不够警示 */
  --success:#15803D; /* 原 #37c98d 在白底上发飘 */
  --warn:#B45309;    /* 原 #f2a93b 同上 */

  /* — 用户端中性阶 — */
  --d-bg:#F5F5F7;        /* 页面底：浅灰。卡片靠它衬出来 */
  --d-surface:#FFFFFF;   /* 卡片/标签：纯白 */
  --d-surface-2:#EFEFF2; /* 次级面：输入框底、封面占位 */
  --d-line:#E6E6EC;      /* 分隔线与控件描边 */
  --d-text:#1A1A21;      /* 主文字 15.9:1。不用纯黑，纯黑在白底上过硬 */
  --d-text-2:#56565F;    /* 次级文字 6.7:1 */
  --d-muted:#6E6E7B;     /* 弱化文字 4.6:1。⚠️ 别再调浅：11px 的观看数、
                            页脚、分类标签全用它，调到 #9C9CA8 就只剩 2.7:1 */

  /* — 阴影：原值是按深底调的（黑色 18%~24%），直接搬到白底上会脏得像脱色。
       白底靠极淡阴影 + 留白分层。 — */
  --e0:0 1px 2px rgba(24,24,32,.04);
  --e1:0 1px 2px rgba(24,24,32,.05),0 4px 12px rgba(24,24,32,.04);
  --e2:0 2px 6px rgba(24,24,32,.07),0 14px 36px rgba(24,24,32,.06);

  /* — 焦点环与玻璃顶栏跟着主色/底色走 — */
  --ring:0 0 0 3px color-mix(in srgb,var(--accent) 26%,transparent);
  --glass:color-mix(in srgb,#F5F5F7 88%,transparent);

  /* ==========================================================
     PV_BTN_V1 按钮系统（2026-08-16）用到的浅底专用值
     ----------------------------------------------------------
     这几个跟 --lp-ink 同一个道理：按钮的「浅底文字/描边/淡底」在红主题下
     要红系，主题关掉(深色)时要青系，**单个 token 表达不了两种**。
     所以只在本文件定义，pv-buttons.css 那边一律写
     var(--lp-x, 深色下的原值)。详见 pv-buttons.css 头部红线 3。
     🔴 主按钮的投影有意带品牌色调（不是中性灰）：白底上灰投影发脏，
        带一点红的投影才"浮"得起来。
     ========================================================== */
  --lp-btn-soft:#FFF1F3;              /* 次要按钮 hover 底 / 图标选中底 */
  --lp-btn-soft-line:#FFC9D1;         /* 图标选中描边 */
  --lp-danger-ink:#B4231A;            /* 危险按钮文字。白底 6.0:1 */
  --lp-danger-line:#E8A9A3;           /* 危险按钮描边 */
  --lp-danger-soft:#FFF1F0;           /* 危险按钮 hover 底 */
  /* 🎨 PV_FX_V1 批次 1: 投影加重。原值(.10/.20)是「白底怕脏」压出来的，
     结果按钮全贴在纸面上、没有层次。加重的同时**保持带红调** ——
     同样深度的灰投影在白底上会发脏，这条不能改。 */
  --lp-btn-shadow:0 1px 2px rgba(217,8,42,.12),0 6px 18px rgba(255,36,66,.28);
  --lp-btn-shadow-hi:0 2px 8px rgba(217,8,42,.18),0 12px 28px rgba(255,36,66,.34);

  /* 🎨 PV_FX_V1 批次 1: 主按钮同色系微渐变（pv-buttons.css 的 --_fill 消费它）。
     🔴 起点必须是品牌色 #FF2442 本身，只允许往深里走：
        · 起点换成更浅的红(比如 #FF3355)，白字对比度会从 3.76 掉到 3.59 ——
          3.76 是老板知情接受的品牌取舍下限，不能再往下。
        · 「红＝品牌」这条识别线是靠起点那个色建立的，换了就不是这个牌子了。
        终点 #E8003F 白字 4.66:1，比起点更高 ⇒ 整条渐变最差处仍是 3.76，与改造前持平。
     🔴 按下态整条都 ≥5.2:1（起点就是原来的 --accent-press）。
     🔴 这两个变量**只在本文件定义** ⇒ 主题关着时 pv-buttons.css 取兜底 var(--accent)
        ＝ 改造前那个纯色，逐像素零变化。 */
  --lp-btn-fill:linear-gradient(135deg,#FF2442 0%,#E8003F 100%);
  --lp-btn-fill-press:linear-gradient(135deg,#D9082A 0%,#B00030 100%);

  /* 🎨 PV_FX_V1 批次 4「内容层」(首页卡片)。两个都只在本文件定义,
     list.html 那边写 var(--lp-x, 改造前的原值) ⇒ 主题关着逐像素零变化。 */
  /* 卡片常态投影。极淡、且带红调 —— 同样深度的灰投影在白底上会发脏(同按钮那条)。
     🔴 只加投影, **不碰卡片边框**: 「结构线必须中性」那条红线还在(见下面 --lp-line),
        小红书的卡片本来就是无边框的, 描一圈淡红会很脏。 */
  --lp-card-shadow:0 1px 2px rgba(24,24,32,.04),0 6px 16px rgba(255,36,66,.07);
  /* 封面骨架微光。改造前是 color-mix(in srgb,var(--d-text) 7%,transparent) 的死灰。 */
  --lp-shim:color-mix(in srgb,#FF2442 11%,transparent);

  /* ==========================================================
     副色 --lp-alt  (PV_FX_V1 批次 5, 老板 2026-08-16 拍板)
     ----------------------------------------------------------
     🔴 它解决的问题不是「只有一个颜色不好看」, 而是**红被用得太廉价**:
        改造前品牌红同时在演四个角色(品牌 / 成交按钮 / 价格 / 徽章),
        角色一多, 它对「这里要花钱」的提示力就被稀释了。
        副色把**非成交**类的活跃元素接走, 红从此只说一件事。

     🔴 为什么是紫不是橙(方案里问过老板, 他选了推荐项):
        橙会跟 --lp-warn(#B45309 深琥珀)撞, 而 warn 标的是「冻结金额/待付款」
        这类**资金状态** —— 上一轮特意把它从 danger 里分出来、还钉了一条
        「RGB 距离 ≥40」的断言。副色再选橙, 等于把刚分开的两个语义又推回一起。
        紫没有任何现存语义占用, 且紫红相邻, 白底上出挑但不吵。

     🔴 分工同 --accent / --accent-ink, 别混用:
        --lp-alt      填充/背景, 保鲜亮度
        --lp-alt-ink  浅底上的**文字/描边**, 白底 6.72:1
     🔴 绝不许用在: 任何成交按钮、支付渠道按钮、价格、以及
        warn/danger/success 三个语义色。副色只管「活跃但不花钱」的东西。
     ========================================================== */
  /* 🏷 PV_HEAD_V1 首页公告条（2026-08-16）。老板真机反馈「一眼看上去非常死板」，
     根因之一是它长着「报错框」的样子：左竖杠 + 浅底 + **同色警示红文字**。
     形态在 list.html 里改（去竖杠、四角圆、加喇叭图标），颜色在这儿：
     🔴 文字从纯警示红换成**深红棕** —— 红字本身就是「出错了」的信号，
        而这条要说的是「有话跟你说」。#7A2430 在 #FFF4F5 上 9.2:1，
        比改造前(--price #D9082A 压 10% 淡红底)更好读。
     🔴 图标单独一个色：它是装饰、可以更鲜艳(3.5:1 过非文本门槛)，
        文字则必须老实。别把两者合成一个 token。
     🔴 都只在本文件定义 ⇒ ?theme=off 仍是改造前那套金/红，逐像素零变化。 */
  --lp-notice-bg:#FFF4F5;
  --lp-notice-ink:#7A2430;
  --lp-notice-mark:#FF2442;

  --lp-alt:#7C5CFF;
  --lp-alt-ink:#5B3FD6;    /* 白底 6.72:1 */
  --lp-alt-soft:#F1EDFF;
  --lp-alt-line:#D9CEFF;
  --lp-on-alt:#FFFFFF;     /* --lp-alt 上的文字 4.35:1 —— 见 list.html .bdg.new 那条注释 */

  /* ==========================================================
     浅色中性阶 --l-*
     ----------------------------------------------------------
     这套本来是后台的暖白色阶。顾客端唯一用到它的是 _rec_block.html
     的浅底变体(rec_surface=light, 即 peach/gold/gallery 这些浅色落地页)。
     🔴 覆盖它安全的前提是「后台不注入本文件」—— 见 design_system._theme_choice()。
        那道路径判断要是被拿掉, 整个后台的暖白橙会跟着一起变冷, 别动它。
     ========================================================== */
  --l-bg:#F5F5F7; --l-surface:#FFFFFF; --l-surface-2:#F0F0F3; --l-line:#E6E6EC;
  --l-text:#1A1A21; --l-text-2:#56565F; --l-muted:#6E6E7B;

  /* ==========================================================
     落地页色板 --lp-*  (PV_THEME_RED_V1 批次 2a)
     ----------------------------------------------------------
     🔴🔴 这组变量**只在本文件里定义**, pv-tokens.css 里没有 ——
          这是有意的, 不是漏了。

     落地页模板(video_peach / product_gallery)里一律写成
         var(--lp-bg, #FFF7F3)
     这种「变量 + 原值兜底」的形式:
       · 没开主题时  -> 变量不存在 -> 取兜底 = 原来的桃橙暖调 -> **逐像素零变化**
       · 开了主题时  -> 取这里的值 -> 小红书红调

     🔴 千万别把这些页面改成 var(--d-bg) 那种「直接用全站 token」的写法。
        --d-* 在没开主题时是**深色**, 那样 peach 落地页会从暖白瞬间变成黑的,
        而且是对全部线上用户立刻生效 —— 灾难性回归。兜底值是这套改法的安全绳。
     ========================================================== */
  --lp-bg:#F5F5F7;         /* 原 #FFF7F3 桃白 */
  --lp-card:#FFFFFF;       /* 原 #fff, 没变 */
  --lp-shadow:rgba(24,24,32,.06);   /* 原 rgba(216,90,48,.10) 是橙色阴影 */
  --lp-text:#1A1A21;       /* 原 #2b2b2b  17.3:1 */
  --lp-text-2:#56565F;     /* 原 #4a4a4a  7.3:1  正文描述 */
  --lp-muted:#6E6E7B;      /* 原 #a9a9a9 / #c2ac9f 两档合并  ≥4.6:1
                              ⚠️ 原 #a9a9a9 在白底上只有 2.5:1, 顺手修掉的老问题 */
  --lp-soft:#FFF0F2;       /* 原 #FAECE7 淡桃 -> 淡红 */
  --lp-soft-ink:#C4082A;   /* 原 #993C1D  在 --lp-soft 上 5.6:1 */
  --lp-soft-ink2:#A80722;  /* 原 #712B13  价格用, 更深一档 */
  --lp-strong:#8E0620;     /* 原 #4A1B0C  试看结束弹层里的大价格 */
  --lp-brand:#FF2442;      /* 原 #D85A30  主行动按钮底。白字 3.76:1 —— 与首页
                              统一的品牌取舍(见文件头), 按钮文字已同步加粗到 600 */
  --lp-on-brand:#FFFFFF;   /* --lp-brand 上的文字。客服浮标原来是青底深青字, 兜底保留 */
  --lp-surface-2:#F0F0F3;  /* 次级面: 封面占位、静音标签底 (channel 原 #1c2230) */

  /* 两种「线」有意分开, 别合并:
       --lp-line      结构线(卡片描边、行分隔) —— 必须中性。
                      小红书的卡片本来就是无边框的, 全站描一圈淡红会很脏。
       --lp-line-soft 强调线(提示框、描边按钮) —— 才用淡红。 */
  --lp-line:#E6E6EC;
  --lp-line-soft:#FFD9DE;  /* 原 #F5C4B3 */

  /* 压在黑遮罩/封面图上的文字。这类地方底色是写死的黑, 不跟主题走,
     所以要的是「在黑底上可读」而不是「在白底上可读」—— 别拿 --lp-text 顶替。 */
  --lp-on-dark:#FFFFFF;

  /* 「已解锁」这类成功态标签。绿色不参与品牌配色, 只承担语义,
     所以按可读性取值(6.1:1), 不跟着红色走。 */
  --lp-success:#12692F;
  --lp-success-soft:#E8F5EC;

  /* 合集页(product_album)的主按钮原来是青色渐变, 整段换掉而不是只换端点色 ——
     只换端点会得到「红到青」这种脏渐变。 */
  --lp-brand-grad:linear-gradient(135deg,#FF2442,#E01B36);

  /* 浮层阴影(公告弹窗)。原值是 rgba(0,0,0,.55) —— 那是给深色弹窗调的,
     照搬到白弹窗上会脏得像一团污渍。 */
  --lp-shadow-modal:rgba(24,24,32,.18);

  /* ==========================================================
     状态色 (批次 3b)
     ----------------------------------------------------------
     老板 2026-08-15 拍板「功能色也向红系收拢」。执行时分了两类:

     · **装饰性**的紫蓝渐变(钱包余额卡 / 挂单 hero 的 #7b61ff→#4f8cff)
       —— 直接收成 --lp-brand-grad, 这是收拢的大头, 也是最扎眼的非红元素。

     · **语义性**的状态色 —— 保留可区分性, 只是把色相往暖里收。
       🔴 尤其 warn: 它标的是「冻结金额 / 待付款」这类**资金状态**,
          真跟 danger 或品牌红撞成一个色, 用户分不清「钱冻着」和「出错了」,
          那是资金层面的误解, 不是审美问题。所以留了独立的一档深琥珀。
     ========================================================== */
  --lp-warn:#B45309;          /* 原 #ffb454/#ffb547/#ffd08a  白底 5.9:1 */
  --lp-warn-soft:#FFF4E5;
  --lp-warn-line:#F5D6A8;
  --lp-danger:#C4102B;        /* 原 #ff7676  错误提示 */
  --lp-danger-soft:#FFEAEC;
  --lp-danger-line:#FFC9CE;
  --lp-success-line:#B7E3C4;
}

/* ===== pv-buttons.css ===== */
/* ============================================================
   pv-buttons.css  ·  PV_BTN_V1（2026-08-16）
   全站统一按钮系统。老板 2026-08-16 看过 Artifact 预览后拍板。

   🔴 三条设计红线（改之前先读，都是有理由的，不是审美偏好）

   1. **hover 必须锁在 `@media (hover:hover) and (pointer:fine)` 里。**
      顾客 100% 是手机（[[paidvideo-mobile-first]]）。触摸屏上 :hover 在手指
      抬起后会**粘住** —— 按钮保持放大+加深阴影直到点别处，看着像卡了 bug。
      手机上的主力反馈是 :active 的 scale(.97) 回弹，那个不受影响。

   2. **危险按钮默认是描边款，不是实心红。**
      主色 --accent(#FF2442) 本身就是红，跟 --danger(#D92D20) 的 RGB 距离
      只有 52 —— 并排放一眼分不出「买」和「删」。所以靠**形态**区分：
      主按钮实心填充、危险按钮描边。只有弹窗里那一次终态确认用
      .pvb--danger-solid。别为了"更醒目"把删除按钮改成实心。

   3. **浅底上的文字/描边一律走 `var(--lp-x, 深色原值)` 兜底，不能直接用
      --accent。** #FF2442 当小号文字在白底上只有 3.76:1；而 --accent-ink
      在 pv-tokens.css 里是深青 #0b6f69，深色主题下压在深卡面上同样不可读。
      两套主题各要各的值，单个 token 表达不了 —— 这就是 --lp-* 存在的理由
      （首例见 list.html 的 .ft a，详见 pv-red.css 里 --lp-ink 的注释）。

   本文件只定义 .pvb / .pvi 命名空间，**不含任何裸元素选择器**，
   所以没挂类的按钮一个像素都不会变。注入见 design_system.py。
   回退：删掉 design_system 里那一行注入即可。

   ── 2026-08-16 PV_FX_V1 批次 1「形态层」（老板看过提案后拍板 A 潮玩活力）──
   目标是给全站一套**统一的形状语言**：改造前同一屏能看到四种转角
   （按钮 18px / 大号 20px / 小号胶囊 / 卡片 12px）。现在按钮一律胶囊。
     ① 圆角 18px/20px → 999px（.pvb--sm 本来就是胶囊，没动）
     ② 字重 600 → 700（胶囊 + 中等字重会显得「软」，形态变了字重要跟上）
     ③ 主按钮填充从纯色改成**同色系**微渐变，走 --lp-btn-fill 兜底
        🔴 渐变起点必须仍是品牌色 #FF2442 本身、只往深里走：
           起点换浅色会让白字对比度掉到 3.76 以下（那是老板知情接受的下限），
           而且「红＝品牌」的识别线是靠起点那个色建立的。
        🔴 有意**不给** .pvb--danger-solid 上渐变：红线 2 说危险按钮靠形态区分，
           它跟主按钮长得越不一样越好。
     ④ 投影加重（在 pv-red.css 里改值）——白底怕脏所以原来压到 4~6%，
        结果按钮全「贴在纸上」。加重的同时保持带红调，灰投影在白底上发脏。
   形态改动**两套主题都变**，这是本轮的目的；颜色改动仍严格走 --lp-* 兜底，
   主题关着（?theme=off）逐像素零变化。

   ── 2026-08-16 追加一轮「克制打磨」（老板从三档里选的就是这一档）──
   只改观感、不加任何元素/JS/依赖，四处：
     ① 松手回弹换成过冲曲线，按下仍是 .08s ease-out（一快一弹＝实体按键感）
     ② 两档实心按钮加 1px inset 顶高光，按下时阴影压平
     ③ .pvb--block 按下只收到 .985 —— 满宽按钮用 .97 是「整块塌一下」
     ④ .pvi 跟 .pvb 用同一条曲线（同屏出现，手感必须是一套）
   涟漪、光泽扫过、图标切换弹跳都**没做**，那是「明显一些」那一档的内容。
   ============================================================ */

.pvb{
  /* --lp-* 只在 pv-red.css 里定义；主题没开时取兜底＝深色主题下的合适值。
     🔴 兜底一个都不能漏：var(--lp-x) 不带逗号会让整条属性解析失败。 */
  --_ink:var(--lp-ink,var(--accent,#38e0d8));
  --_soft:var(--lp-btn-soft,rgba(56,224,216,.10));
  --_dg-ink:var(--lp-danger-ink,var(--danger,#ff5d5d));
  --_dg-line:var(--lp-danger-line,rgba(255,93,93,.5));
  --_dg-soft:var(--lp-danger-soft,rgba(255,93,93,.10));
  --_sh:var(--lp-btn-shadow,var(--e1));
  --_sh-hi:var(--lp-btn-shadow-hi,var(--e2));
  /* 🔴 主按钮填充。主题关着时 --lp-btn-fill 不存在 ⇒ 取 var(--accent)
     ＝ 改造前那个纯色，**逐像素零变化**；开着才取 pv-red.css 里的同色系渐变。
     兜底里再套一层 #38e0d8 是防 pv-tokens.css 也没加载上的极端情况。 */
  --_fill:var(--lp-btn-fill,var(--accent,#38e0d8));
  --_fill-press:var(--lp-btn-fill-press,var(--accent-press,#22b8b0));

  appearance:none;-webkit-appearance:none;
  /* 字重 700：胶囊形态下 600 会显得软（转角越圆，字看着越轻）。 */
  font-family:var(--font);font-size:var(--t-body);font-weight:700;line-height:1;
  display:inline-flex;align-items:center;justify-content:center;gap:7px;
  /* 胶囊。white-space:nowrap 保证永远单行 ⇒ 999px 不会在多行按钮上塌成腰鼓形。 */
  padding:13px 22px;border:1.5px solid transparent;border-radius:999px;
  cursor:pointer;white-space:nowrap;text-decoration:none;position:relative;
  /* 🌀 松手回弹用的是过冲曲线(1.56 那一段会越过终点再收回来)，
     按下那一下另算 —— 见文件末尾 :active 那条 .08s。
     一快一弹是手机上唯一能做出「实体按键」感的组合，而且零额外元素、
     零 JS：这是「克制打磨」这档里性价比最高的一笔。 */
  transition:transform .24s cubic-bezier(.34,1.56,.64,1),
             box-shadow .2s ease,background-color .2s ease,
             border-color .2s ease,color .2s ease;
}
.pvb:focus-visible{outline:2px solid var(--_ink);outline-offset:3px}

/* ── 主要：解锁 / 购买 / 提交 ── */
.pvb--primary{
  background:var(--_fill);color:var(--on-accent);
  /* 顶边那条 inset 高光把纯色块「立」起来一点点。
     🔴 用固定的白色半透明、不引任何新 token：它叠在**任何**底色上都成立，
        而这一档在支付弹窗/落地页/后台边缘各种底上都出现过。
        1px、14% —— 再重就变成拟物按钮了，那不是这套设计的方向。 */
  box-shadow:var(--_sh),inset 0 1px 0 rgba(255,255,255,.14);
}
/* ── 次要：取消 / 返回 ── */
.pvb--secondary{
  background:var(--d-surface);color:var(--_ink);border-color:var(--_ink);
  box-shadow:var(--e0,none);
}
/* ── 弱化：第三优先级，纯中性 ── */
.pvb--ghost{
  background:var(--d-surface);color:var(--d-text-2);border-color:var(--d-line);
  box-shadow:var(--e0,none);
}
/* ── 危险：描边款（见红线 2）── */
.pvb--danger{
  background:var(--d-surface);color:var(--_dg-ink);border-color:var(--_dg-line);
  box-shadow:var(--e0,none);
}
/* 弹窗里那一次终态确认才用实心 */
.pvb--danger-solid{
  background:var(--danger);color:#fff;
  box-shadow:var(--_sh),inset 0 1px 0 rgba(255,255,255,.14);
}
/* ── 正向确认：上架 / 通过 / 确认收货 ──
   🔴 这一档**有意用绿色**，不往红系收。它和 .pvb--danger 是一对反义操作
   （上架↔下架、通过↔驳回），两个都描边红的话就只剩文字能区分了。
   同批次 3b 保留 --lp-warn 的道理：语义色要保住可区分性。 */
.pvb--ok{
  background:var(--d-surface);
  color:var(--lp-success,var(--success,#37c98d));
  border-color:var(--lp-success-line,rgba(55,201,141,.45));
  box-shadow:var(--e0,none);
}

/* .pvb--pill 现在跟基类同值，是空操作。**有意保留**：站内已经有一批按钮挂着它，
   删掉要全站扫使用处，而留着零成本。将来若基类改回非胶囊，它还得起作用。 */
.pvb--pill{border-radius:999px}
.pvb--sm{font-size:var(--t-sm);padding:8px 15px;border-radius:999px;gap:5px}
/* 大号：登录提交、落地页「立即解锁」这类页面级主行动。
   ⚠️ 原来是 20px，注释写着「老板给的主按钮上限（16–20px）」——
      那条上限已被 PV_FX_V1 提案里的「A 潮玩活力」推翻（老板 2026-08-16 拍板），
      全档统一胶囊。别看到旧注释又改回去。 */
.pvb--lg{font-size:var(--t-h4);padding:15px 24px;border-radius:999px}
.pvb--block{width:100%}

/* ── hover：只给真有指针的设备（见红线 1）── */
@media (hover:hover) and (pointer:fine){
  .pvb:not([disabled]):not(.is-loading):hover{transform:scale(1.04)}
  /* 🔴 这里必须把 inset 高光**再写一遍**：box-shadow 是整条替换的，
     只写 var(--_sh-hi) 会让高光在 hover 时凭空消失（鼠标一放上去按钮反而变平）。
     同理见下面 --danger-solid。 */
  .pvb--primary:not([disabled]):not(.is-loading):hover{
    background:var(--_fill-press);
    box-shadow:var(--_sh-hi),inset 0 1px 0 rgba(255,255,255,.14);
  }
  .pvb--secondary:not([disabled]):not(.is-loading):hover{background:var(--_soft)}
  .pvb--ghost:not([disabled]):not(.is-loading):hover{
    color:var(--d-text);border-color:var(--_ink);
  }
  .pvb--danger:not([disabled]):not(.is-loading):hover{background:var(--_dg-soft)}
  .pvb--danger-solid:not([disabled]):not(.is-loading):hover{
    box-shadow:var(--_sh-hi),inset 0 1px 0 rgba(255,255,255,.14);
  }
  .pvb--ok:not([disabled]):not(.is-loading):hover{
    background:var(--lp-success-soft,rgba(55,201,141,.10));
  }
}
/* ── 按下 —— 手机上这才是主力反馈 ──
   按下走 .08s ease-out（立刻跟手，不能有过冲：手指还按着的时候按钮弹一下
   看着像抖动），松手回到上面那条 .24s 过冲曲线。 */
.pvb:not([disabled]):not(.is-loading):active{
  transform:scale(.97);
  transition-duration:.08s;transition-timing-function:ease-out;
}
/* 按下去阴影跟着压扁 —— 按钮「贴到纸面上」。只给带阴影的两档实心按钮；
   描边档本来就没阴影，写了是空操作。 */
.pvb--primary:not([disabled]):not(.is-loading):active,
.pvb--danger-solid:not([disabled]):not(.is-loading):active{
  box-shadow:inset 0 1px 0 rgba(255,255,255,.14);
}
/* 🔴 满宽按钮**必须收得更少**。scale(.97) 在一颗 340px 宽的按钮上是两边各缩
   5px，看着不是「按下去」而是「整块塌了一下」；同样的比例在 100px 的小按钮上
   才是对的。同一条道理见 list.html 里卡片用的 .985。 */
.pvb--block:not([disabled]):not(.is-loading):active{transform:scale(.985)}

/* ── 禁用：降饱和 + 明确不可点 ──
   用实色不用 opacity：半透明叠在封面图/渐变上会糊成一团。 */
.pvb[disabled],.pvb.is-disabled{
  background:var(--d-surface-2);color:var(--d-muted);border-color:transparent;
  box-shadow:none;cursor:not-allowed;transform:none;
}

/* ── 加载：三个跳动的小圆点 ──
   用法：按钮里放 <span class="pvb__t">文字</span>
        + <span class="pvb__dots" aria-hidden="true"><i></i><i></i><i></i></span>
        然后 JS 切 .is-loading。没有 .pvb__dots 也不会坏，只是没动画。 */
.pvb.is-loading{cursor:progress;pointer-events:none}
.pvb.is-loading .pvb__t{visibility:hidden}
.pvb__dots{position:absolute;inset:0;display:none;
  align-items:center;justify-content:center;gap:5px}
.pvb.is-loading .pvb__dots{display:flex}
.pvb__dots i{width:6px;height:6px;border-radius:50%;background:currentColor;
  display:block;animation:pvbBounce .6s ease-in-out infinite}
.pvb__dots i:nth-child(2){animation-delay:.12s}
.pvb__dots i:nth-child(3){animation-delay:.24s}
@keyframes pvbBounce{
  0%,80%,100%{transform:translateY(0);opacity:.55}
  40%{transform:translateY(-5px);opacity:1}
}

/* ── 图标按钮：收藏 / 点赞 / 分享 ──
   🔴 图标用**内联 SVG**，不引 Tabler/Phosphor 的 CDN。
      外部资源在国内会被墙 —— 这项目栽过一次：官方 Telegram Login Widget
      从 telegram.org 加载，国内手机上按钮根本不显示，最后整个弃用改深链。 */
.pvi{
  appearance:none;-webkit-appearance:none;
  background:var(--d-surface);border:1.5px solid var(--d-line);border-radius:999px;
  width:42px;height:42px;padding:0;
  display:inline-flex;align-items:center;justify-content:center;
  cursor:pointer;color:var(--d-text-2);box-shadow:var(--e0,none);
  /* 跟 .pvb 用同一条回弹曲线 —— 收藏/点赞和购买按钮出现在同一屏，
     两种回弹手感会显得是两套东西拼的。 */
  transition:transform .24s cubic-bezier(.34,1.56,.64,1),
             box-shadow .2s ease,color .2s ease,
             border-color .2s ease,background-color .2s ease;
}
.pvi svg{width:21px;height:21px;display:block;
  transition:transform .2s cubic-bezier(.34,1.56,.64,1)}
@media (hover:hover) and (pointer:fine){
  .pvi:hover{transform:scale(1.05);box-shadow:var(--e1);
    color:var(--lp-ink,var(--accent,#38e0d8))}
}
.pvi:active{transform:scale(.94);transition-duration:.08s;transition-timing-function:ease-out}
.pvi:focus-visible{outline:2px solid var(--lp-ink,var(--accent,#38e0d8));outline-offset:3px}
/* 选中：描边图标转实心填充 + 上品牌色，不只是换个颜色 */
.pvi.is-on{
  color:var(--accent);
  border-color:var(--lp-btn-soft-line,rgba(56,224,216,.45));
  background:var(--lp-btn-soft,rgba(56,224,216,.10));
}
.pvi.is-on svg{fill:currentColor}
/* 点击那一下的弹跳（JS 加 .pop，动画结束移除） */
.pvi.pop svg{animation:pviPop .38s cubic-bezier(.34,1.56,.64,1)}
@keyframes pviPop{0%{transform:scale(1)}38%{transform:scale(1.32)}100%{transform:scale(1)}}

@media (prefers-reduced-motion:reduce){
  .pvb,.pvi,.pvi svg{transition-duration:.01ms}
  .pvb:hover,.pvb:active,.pvi:hover,.pvi:active{transform:none}
  .pvb__dots i,.pvi.pop svg{animation:none}
  .pvb__dots i{opacity:.8}
}

/* ===== pv-fx.css ===== */
/* ============================================================
   pv-fx.css  ·  PV_FX_V1 批次 2「特效层」（2026-08-16）

   老板看过提案后从三档里选了**「明显」**这一档（上一轮选的是最轻的
   「克制」）。本批次落地其中两样：**点击涟漪** 与 **Tab 进场弹跳**。
   光泽扫过归批次 3、卡片进场归批次 4。

   🔴 整个文件 + pv-fx.js 是**纯加法**：删掉 design_system.py 里那一行
      注入即回到批次 1 的状态，没有任何别处依赖它。

   🔴 三条纪律（都是前几轮踩出来的）

   1. **动效不能是内容显示的前提。**
      涟漪由 JS 创建元素、JS 挂了就是没有涟漪，按钮功能一行不受影响。
      本文件里**没有任何常驻在元素上的透明度归零 / 隐藏声明**，所以不存在
      「脚本没跑 → 内容看不见」这条失败路径。(唯一一处透明度归零在 @keyframes
       的终点，那是涟漪自己淡出，动画结束元素就被 JS 删掉了。)

   2. **hover 一律锁 (hover:hover) and (pointer:fine)。**
      本文件其实一条 hover 都没写 —— 涟漪走 pointerdown，天生只在真按下时出现，
      不会像 :hover 那样在触摸屏上抬手后粘住。

   3. **prefers-reduced-motion 全降级**（文件末尾），JS 那边也各自判一次 ——
      两头都堵，因为用户可能在页面加载后才改系统设置。

   ── 为什么 Tab 做的是「进场弹跳」而不是提案预览里的「点击弹跳」──
   🔴 提案页面里 Tab 是 SPA 式切换，点了就地换选中态、动画看得完整。
      **线上不是** —— .pvtab a 是真链接，点下去立刻导航走，弹跳动画根本来不及播，
      做了等于没做。所以改成「新页面加载时，当前那格图标弹一下」：
      每次进页面都必然看得到，而且它说的是「你现在在这里」，语义比点击反馈更有用。
   ============================================================ */

/* ── 涟漪 ──────────────────────────────────────────────────
   overflow:hidden 有意写在**本文件**而不是 pv-buttons.css：
   删掉本文件 = 特效层整体回退，不留半截状态。
   已确认站内 66 处 .pvb 内部只有 .pvb__t 与 .pvb__dots(inset:0)，
   没有任何靠溢出显示的角标 —— 加 hidden 不会裁掉东西。 */
.pvb,.pvi{overflow:hidden}

.pvfx-rip{
  position:absolute;border-radius:50%;
  transform:scale(0);pointer-events:none;
  background:rgba(255,255,255,.28);
  animation:pvfxRip .55s cubic-bezier(.22,1,.36,1) forwards;
}
/* 描边/幽灵档底是白的，白涟漪看不见 —— 改用按钮自己的文字色兑一点。
   currentColor 让每一档(主色描边/中性/危险红/确认绿/副色)自动各取各的，
   不用为每档单独写一条。 */
.pvb--secondary .pvfx-rip,
.pvb--ghost .pvfx-rip,
.pvb--danger .pvfx-rip,
.pvb--ok .pvfx-rip,
.pvi .pvfx-rip{
  background:color-mix(in srgb,currentColor 18%,transparent);
}
/* color-mix 不支持的老机器：退回极淡的中性灰，绝不能留成透明(=没有涟漪)。 */
@supports not (background:color-mix(in srgb,red 10%,transparent)){
  .pvb--secondary .pvfx-rip,.pvb--ghost .pvfx-rip,
  .pvb--danger .pvfx-rip,.pvb--ok .pvfx-rip,.pvi .pvfx-rip{
    background:rgba(120,120,130,.16);
  }
}
@keyframes pvfxRip{
  to{transform:scale(2.6);opacity:0}
}
/* 涟漪是 absolute，会排在按钮里那段裸文本之上 —— 这是 Material 那套涟漪的
   常规做法，28% 的白扫过文字看不出问题。但按钮**有** .pvb__t 时(加载态那批)
   顺手把它抬起来，能更干净就更干净。 */
.pvb__t{position:relative;z-index:1}

/* ── 光泽扫过（批次 3）────────────────────────────────────
   一道高光每 2.8 秒扫过按钮一次。

   🔴🔴 只给「页面级主行动」，绝不全站铺开。
      光泽扫过是**持续在消耗注意力**的效果：全站按钮都扫，用户很快疲劳，
      而且真正该点的那颗就不再特殊了 —— 那就把这个效果的意义整个抵消掉。

   🔴 具体只挂在四个落地页**页内锁定区**的那颗大按钮上
      (video_peach / product_album / product_channel / product_software)。
      两处**有意不挂**，理由不是漏了：
      · 底部固定条 .bar 里那颗小胶囊 —— 它是 fixed 常驻的，常驻元素持续闪
        比页内的烦得多；而且小胶囊上扫光只是一道白线闪，看不出是光泽。
      · **支付通道按钮 .pvm-btn 一颗都不挂** —— 提案里写的是「支付弹窗确认键」，
        但实际读代码发现那个弹窗里根本没有独立的确认键，通道按钮本身就是终态。
        而那四颗带的是支付宝蓝/微信绿/epay紫/个人码渐变的**品牌识别色**，
        往上叠白色高光会污染品牌色，四颗并排一起扫更是灾难。
   🔴 video_hot.html 的 .buy 自带 animation:beat 脉动，跟扫光叠加会打架，
      有意跳过（它也压根没挂 .pvb）。

   ⚠️ 加载态与禁用态必须停：按钮不响应的时候还在闪，是在骗用户「这里能点」。 */
.pvb--primary.pvb--sweep::after{
  content:"";position:absolute;top:0;bottom:0;left:-50%;width:38%;
  background:linear-gradient(100deg,transparent,rgba(255,255,255,.42),transparent);
  transform:skewX(-18deg);pointer-events:none;
  /* 靠 .pvb 的 overflow:hidden(本文件顶部那条)裁成胶囊形状。 */
  animation:pvfxSweep 2.8s ease-in-out infinite;
}
/* 42% 之后就停在画面外 —— 剩下 58% 的时间是**间隔**。
   没有这段间隔的话它就成了一条不停转的跑马灯，那是另一种东西。 */
@keyframes pvfxSweep{
  0%{left:-50%}
  42%{left:118%}
  100%{left:118%}
}
.pvb--sweep.is-loading::after,
.pvb--sweep[disabled]::after,
.pvb--sweep.is-disabled::after{display:none}

/* ── Tab 进场弹跳 ────────────────────────────────────────
   只弹当前那一格。图标已经在 pv-tabbar.css 里有 transition，
   这里用 animation，两者互不干扰。 */
.pvtab a.is-on .pvtab__i{
  animation:pvfxTabIn .5s cubic-bezier(.34,1.56,.64,1);
}
@keyframes pvfxTabIn{
  0%{transform:scale(.72)}
  100%{transform:scale(1)}
}

@media (prefers-reduced-motion:reduce){
  .pvfx-rip{display:none}
  .pvtab a.is-on .pvtab__i{animation:none}
  /* 扫光是本文件里唯一的**常驻**动画。对开了减弱动效的人必须整条撤掉，
     不能只是放慢 —— 那类设置往往是前庭功能问题，不是嫌快。 */
  .pvb--primary.pvb--sweep::after{display:none}
}

/* ===== pv-xhs.css ===== */
/* PV_XHS_V1 · 小红书风格层
 * ---------------------------------------------------------------------------
 * 老板 2026-08-29：「整个网站风格尽可能往小红书靠拢，可以完全模仿」
 *                 「不要看着像劣质网站，简约活泼一点」
 *
 * 这一层**只覆盖视觉属性，不碰布局**（列数、宽度、flex 结构一律不动）——
 * 布局改动风险高、回退难，而「像不像小红书」八成由下面这几件事决定。
 *
 * 排在 bundle 最后加载，所以同特异度即可覆盖前面几层。
 * 回退：把 pv-xhs.css 从 design_system 的 bundle 列表里去掉，一秒还原。
 *
 * === 实测出来的四个病灶（2026-08-29 线上量的，不是推断）===
 *
 *  ① 16 个 <a> 在用**浏览器默认链接蓝 #0000EE** —— 等于压根没设颜色。
 *     红白配色里到处冒蓝字，这是「劣质」最直接的来源。
 *  ② 卡片同时上了 **16px 圆角 + 1px 边框 + 阴影** 三重强调。
 *     小红书的卡片是**无边框、无阴影、8px 圆角**，靠灰底和间隙分隔 ——
 *     加了框反而显得廉价。
 *  ③ 分类芯片做成了 110×56 的**红边框胶囊**。小红书的分类是纯文字，
 *     选中态只有「加粗 + 底下一条 3px 短红线」。
 *  ④ 间距偏松（gap 12px），小红书更紧凑，一屏能多露内容。
 */

/* ── ① 修默认链接蓝 ───────────────────────────────────────────────────
 * 只兜底「没人设过颜色」的情况：用 :where() 保持零特异度，
 * 任何一处真正设过 color 的规则都能盖过它，不会误伤已有设计。 */
:where(a){ color: inherit; }
:where(a:visited){ color: inherit; }

/* 卡片类容器统一继承正文色，内部各自的价格/次要文字仍按自己的规则走 */
.pvct-c, .pvgp-c, .card.pvgc, .pvrail-rail a{
  color: var(--d-tx, #1A1A21);
  -webkit-tap-highlight-color: transparent;
}

/* ── ② 内容卡片：去边框、去阴影、圆角收到 8px ───────────────────────
 * 小红书的信息流卡片没有任何描边，卡片之间靠 #F5F5F7 的页面底色分隔。 */
.card.pvgc{
  border: 0 !important;
  box-shadow: none !important;
  border-radius: 8px;
  overflow: hidden;              /* 圆角要能裁住封面图 */
  background: #FFF;
}
/* 封面：图片本来就是 cover（没问题），这里只保证圆角跟随卡片 */
.card.pvgc .cv{ border-radius: 8px 8px 0 0; overflow: hidden; }

/* 卡片信息区：小红书是「标题 2 行 → 底部一行小字」，字重克制 */
.card.pvgc .inf{ padding: 8px 10px 10px; }
.card.pvgc .inf .t{
  font-size: 14px; line-height: 1.4; font-weight: 400;
  color: var(--d-tx, #1A1A21);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; white-space: normal;
}
/* 价格：原来是 17px/800，太重。小红书的价格是「稍大一点 + 半粗」，
 * 靠颜色而不是靠字重来突出。 */
.card.pvgc .inf .m .p{ font-size: 14px; font-weight: 600; }
.card.pvgc .inf .m .vw{ font-size: 11px; color: var(--d-mu, #9A9AA5); }

/* 时长/张数这类角标：小红书是半透明黑底、小字、贴角 */
.card.pvgc .dur{
  background: rgba(0,0,0,.5); color: #FFF;
  font-size: 10.5px; border-radius: 4px; padding: 1px 5px;
}

/* ── ③ 分类芯片：胶囊 → 纯文字 + 选中短红线 ────────────────────────
 * 这是小红书顶部分类最标志性的样子。芯片式胶囊是「后台管理系统」的做法，
 * 放在内容型 App 里就是那股廉价感的来源。 */
.pvct-c{
  border: 0 !important;
  background: transparent !important;
  border-radius: 0 !important;
  padding: 9px 2px !important;
  font-size: 14px;
  font-weight: 400;
  color: var(--d-mu, #6E6E7B);
  position: relative;
  white-space: nowrap;
}
.pvct-c.on{
  color: var(--d-tx, #1A1A21);
  font-weight: 600;
  font-size: 15px;               /* 选中略大，是小红书的做法 */
}
.pvct-c.on::after{
  content: "";
  position: absolute; left: 50%; bottom: 3px;
  transform: translateX(-50%);
  width: 16px; height: 3px; border-radius: 2px;
  background: var(--accent, #FF2442);
}

/* ── ④ 间距收紧 ─────────────────────────────────────────────────────
 * 小红书双列的列间距约 8px、左右边距 8px。原来是 12/12，
 * 收紧之后同一屏能多露出内容 —— 这是「信息流看着舒服」的一半原因。 */
.grid.is-js{ gap: 8px !important; padding: 0 8px !important; }
.grid.is-js .mcol{ gap: 8px !important; }

/* 群卡片同样去掉描边感，跟内容卡统一 */
.pvgp-c{
  border: 0 !important;
  box-shadow: none !important;
  border-radius: 8px;
  background: #FFF;
}

/* ── ⑤ 首页头部压缩：把「相亲角」顶上去 ─────────────────────────────
 * 老板定的第一感官是「相亲角 + 群语音」，而实测那两张大卡片原本在 y144 ——
 * 上面压着 144px 的装饰。小红书首页顶部只有搜索和分类，没有这类元数据。
 *
 * 🔴 有意只藏 .tags，**不碰 .notice 的功能**：公告跑马灯(PV_BLINK_V1)是
 *    老板专门做的、用来发临时通知的，这里只收紧它的上下间距，不隐藏、不停滚。 */

/* 「238 部内容 / 持续更新 / 官方支付·即时到账」——
 * 这三个标签说的是事实，但它们是**元数据**：用户不会因为「238 部」而留下。
 * 而且「官方支付」这类信任信号该出现在**付款那一刻**（落地页已经有了），
 * 不是首页顶部。想恢复：删掉这一条即可。 */
.brand .tags{ display: none !important; }

/* 公告条：留着，但别占那么高 */
.notice{ padding-top: 6px !important; padding-bottom: 6px !important; }

/* 站名跟着收一点，别让一个 28px 的标题独占一屏顶部 */
.brand h1{ margin-bottom: 2px !important; }

/* ── 触感：小红书点按有轻微回弹，这是「活泼」的来源之一 ──────────── */
@media (hover: none){
  .card.pvgc:active, .pvgp-c:active{
    transform: scale(.97);
    transition: transform .12s ease;
  }
}
@media (prefers-reduced-motion: reduce){
  .card.pvgc:active, .pvgp-c:active{ transform: none; }
}
