/* ==========================================================================
   Flaxl Claw · 页面级样式（依赖 tokens.css / app.css）
   ========================================================================== */

/* ---------- 品牌标记的尺寸体系 ----------
   所有 data-logo 容器统一为 inline-flex 居中，内部 svg 由容器选择器决定大小 */
[data-logo] { display: inline-flex; align-items: center; justify-content: center; }
.brand-mark { width: 19px; height: 28px; display: block; }
.brand > [data-logo] { flex: 0 0 auto; }
.state-mark .brand-mark { width: 26px; height: 38px; }
.state-mark--sm { width: 34px; height: 34px; }
.state-mark--sm .brand-mark { width: 13px; height: 19px; }
.lic-ico .brand-mark { width: 12px; height: 18px; }
.about-mark .brand-mark { width: 46px; height: 66px; }
.login-brand-mark { position: relative; z-index: 1; }
.login-brand-mark .brand-mark { width: 52px; height: 76px; }

/* ---------- 页面滚动容器（让每个页面自己撑满高度） ---------- */
.scroller { display: flex; flex-direction: column; }
.page.is-active { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
.page > .wrap { flex: 0 0 auto; width: 100%; }

/* ---------- 对话首页 ---------- */
.chat-page {
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  padding: var(--sp-10) var(--sp-8) var(--sp-12);
  gap: var(--sp-8);
}
.chat-hero { text-align: center; display: grid; gap: var(--sp-3); }
.chat-hi { font-size: var(--fs-display); line-height: var(--lh-display); font-weight: 600; color: var(--ink-900); letter-spacing: -.02em; }
.chat-sub { font-size: var(--fs-h3); line-height: var(--lh-h3); color: var(--ink-500); font-weight: 400; }
.chat-sub b { color: var(--ink-700); font-weight: 500; }

.composer {
  width: 100%; max-width: 780px;
  background: var(--white);
  border: 1px solid var(--ink-200);
  border-radius: var(--r-xl);
  box-shadow: 0 1px 2px rgba(16, 24, 40, .04), 0 12px 32px -18px rgba(16, 24, 40, .18);
  transition: border-color var(--t-base), box-shadow var(--t-base);
  position: relative;
}
.composer:focus-within {
  border-color: var(--brand-200);
  box-shadow: 0 0 0 3px rgba(230, 0, 18, .08), 0 16px 40px -20px rgba(16, 24, 40, .22);
}
.composer-input {
  width: 100%; border: 0; outline: none; resize: none;
  padding: var(--sp-5) var(--sp-6) var(--sp-2);
  font-size: var(--fs-h3); line-height: 26px; color: var(--ink-900);
  background: transparent; min-height: 92px; font-family: inherit;
}
.composer-input::placeholder { color: var(--ink-300); }
.composer-tools { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-2) var(--sp-3) var(--sp-3); }
.tool-btn {
  width: 32px; height: 32px; border-radius: var(--r-sm);
  display: grid; place-items: center; color: var(--ink-400);
  transition: all var(--t-fast);
}
.tool-btn svg { width: 17px; height: 17px; }
.tool-btn:hover { background: var(--ink-100); color: var(--ink-700); }

.model-select {
  margin-left: auto;
  height: 32px; padding: 0 10px 0 var(--sp-3);
  display: inline-flex; align-items: center; gap: 6px;
  border-radius: var(--r-sm); background: var(--ink-100);
  font-size: var(--fs-xs); font-weight: 500; color: var(--ink-700);
  transition: all var(--t-fast);
}
.model-select:hover { background: var(--ink-150); color: var(--ink-900); }
.model-select svg { width: 13px; height: 13px; color: var(--ink-400); }
.model-select .m-name { font-family: var(--font-num); letter-spacing: .01em; }

.send-btn {
  width: 32px; height: 32px; border-radius: var(--r-sm);
  background: var(--brand-500); color: var(--white);
  display: grid; place-items: center; transition: all var(--t-fast);
}
.send-btn svg { width: 16px; height: 16px; }
.send-btn:hover { background: var(--brand-600); }
.send-btn.is-disabled { background: var(--ink-150); color: var(--ink-300); }

/* 语音输入（第十二轮）：和发送箭头并排。
   默认与 tool-btn 同款（透明底 + ink-400 图标）；
   一旦开始听就换成品牌红底白图标 —— 与发送键共用同一套
   「品牌色＝正在进行的动作」语义。
   向外扩散的涟漪只挂在 ::after 上，按钮本体保持稳定不缩放
   （给本体套 scale 动画会让它自己忽大忽小，观感像坏了）。 */
.voice-btn {
  width: 32px; height: 32px; border-radius: var(--r-sm);
  display: grid; place-items: center; color: var(--ink-400);
  transition: all var(--t-fast); position: relative;
}
.voice-btn svg { width: 16px; height: 16px; }
.voice-btn:hover { background: var(--ink-100); color: var(--ink-700); }
.voice-btn.is-on,
.voice-btn.is-on:hover { background: var(--brand-500); color: var(--white); }
.voice-btn.is-on::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit;
  border: 2px solid var(--brand-400);
  animation: voice-ring 1.5s ease-out infinite;
  pointer-events: none;
}
@keyframes voice-ring {
  0%   { transform: scale(1);    opacity: .75; }
  100% { transform: scale(1.55); opacity: 0; }
}
/* 正在听的时候，输入框跟着亮一圈，让人知道"声音进去的是这里" */
.composer.is-voice { border-color: var(--brand-200); }
.composer.is-voice .composer-input::placeholder { color: var(--brand-400); }
.chat-foot { font-size: var(--fs-xs); color: var(--ink-300); }

/* ==========================================================================
   第三十轮：「看广告赚积分」横幅（样式参考 ChatGPT 输入框上方的广告位）
   白底细边圆角卡：左侧圆形灰底喇叭，中间标题 + 副文案，右侧黑色胶囊主按钮，
   最右一个低调的 ×。层级刻意压在输入框之下 —— 横幅无阴影、圆角小一档，
   输入框始终是这一屏的主角。
   负 margin 的原因：.chat-page 是 gap: sp-6 的纵向 flex，横幅作为直接子元素
   天生和输入框差 24px；参考图里横幅是贴着输入框的，收回 12px（sp-6 - sp-3）。
   若改了 .chat-page 的 gap，这里要跟着改 —— 两处是故意耦合的。
   ========================================================================== */
.ad-banner {
  width: 100%; max-width: 780px;
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  background: var(--white);
  border: 1px solid var(--ink-150);
  border-radius: var(--r-lg);
  margin-bottom: calc(-1 * (var(--sp-6) - var(--sp-3)));
}
.ad-banner__ico {
  display: grid; place-items: center; width: 36px; height: 36px; flex: 0 0 auto;
  border-radius: var(--r-full); background: var(--ink-100); color: var(--ink-800);
}
.ad-banner__main { flex: 1 1 auto; min-width: 0; }
.ad-banner__t { font-size: var(--fs-h3); line-height: var(--lh-h3); font-weight: 600; color: var(--ink-900); }
.ad-banner__s { margin: 2px 0 0; font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--ink-500); }
/* 主按钮用最深的墨色而不是品牌红：参考图的 CTA 是黑的；且红色在本项目
   留给「正在进行的动作」，一个可点可不点的推广位不该抢那个语义。 */
.ad-banner__go {
  flex: 0 0 auto; height: 34px; padding: 0 var(--sp-5);
  display: inline-flex; align-items: center;
  border: none; border-radius: var(--r-full);
  background: var(--ink-900); color: var(--white);
  font-family: var(--font-sans); font-size: var(--fs-sm); font-weight: 500;
  cursor: pointer; white-space: nowrap;
  transition: background var(--t-fast), transform var(--t-fast);
}
.ad-banner__go:hover { background: var(--ink-800); }
.ad-banner__go:active { transform: scale(.97); }
.ad-banner__go:focus-visible { outline: none; box-shadow: var(--sh-focus); }
.ad-banner__x {
  flex: 0 0 auto; display: grid; place-items: center; width: 28px; height: 28px;
  border: none; border-radius: var(--r-full); background: transparent;
  color: var(--ink-400); cursor: pointer;
  transition: color var(--t-fast), background var(--t-fast);
}
.ad-banner__x:hover { color: var(--ink-700); background: var(--ink-100); }
.ad-banner__x:focus-visible { outline: none; box-shadow: var(--sh-focus); }

/* 挂在输入框上的浮层 */
.pop--skill { position: absolute; left: 0; bottom: calc(100% + 10px); width: 300px; max-height: 320px; overflow-y: auto; }
.pop--model { position: absolute; right: 0; bottom: calc(100% + 10px); width: 268px; max-height: 320px; overflow-y: auto; }
.pop--user { position: absolute; top: calc(100% + 6px); right: 0; width: 252px; }
.pop--points { position: absolute; top: calc(100% + 8px); right: 0; }

.pop-item .pi-ico {
  width: 26px; height: 26px; border-radius: var(--r-xs);
  display: grid; place-items: center; flex: 0 0 auto;
  background: var(--ink-100); color: var(--ink-500);
}
.pop-item .pi-ico svg { width: 14px; height: 14px; }
.pop-item.is-active .pi-ico { background: var(--brand-100); color: var(--brand-500); }

/* 顶栏「浮层 · 积分」的样式已随入口一起移除；积分块挪到头像弹层，样式见 app.css 的 .pop-points / .ppts-* */
.anchor { position: relative; }

/* ---------- 登录 ---------- */
.login-stage {
  flex: 1 1 auto; min-height: 0;
  display: grid; place-items: center;
  padding: var(--sp-10);
  background: linear-gradient(180deg, var(--ink-50), var(--ink-100));
}
.login-card {
  width: min(840px, calc(100vw - 48px));
  display: grid; grid-template-columns: 1fr 1fr;
  background: var(--white); border-radius: var(--r-xl);
  overflow: hidden; box-shadow: var(--sh-lg);
  animation: modal-in var(--t-slow) both;
}
@media (max-width: 820px) { .login-card { grid-template-columns: 1fr; } .login-brand { display: none !important; } }
.login-brand {
  /* 对齐原稿「登录.png」：左侧是纯黑，不带任何红晕 */
  background: var(--ink-1000); color: var(--white);
  display: grid; place-items: center; gap: var(--sp-5);
  padding: var(--sp-12) var(--sp-9); min-height: 420px;
  position: relative; overflow: hidden;
}
.login-brand-lockup { display: flex; align-items: center; gap: 10px; position: relative; z-index: 1; }
.login-brand-word { font-size: 24px; font-weight: 700; letter-spacing: -.02em; }
.login-brand-badge {
  font-family: var(--font-num); font-size: 13px; font-weight: 700;
  background: var(--brand-500); color: var(--white); padding: 4px 6px; border-radius: 4px;
}
.login-form { padding: var(--sp-8); display: flex; flex-direction: column; }
.qr-box {
  position: relative;
  width: 172px; height: 172px; margin: var(--sp-6) auto var(--sp-4);
  border-radius: var(--r-md); background: var(--ink-100);
  display: grid; place-items: center; color: var(--ink-700);
}
.qr-code { display: grid; place-items: center; transition: opacity var(--t-base); }
.qr-code svg { width: 140px; height: 140px; }
.qr-box.is-expired .qr-code { opacity: .12; }
/* 超时后才出现：浮在二维码正中的「自动刷新」小图标按钮 */
.qr-refresh {
  position: absolute; inset: 0; margin: auto;
  width: 46px; height: 46px; border-radius: 50%;
  display: grid; place-items: center; cursor: pointer; z-index: 1;
  background: var(--white); border: 1px solid var(--ink-200);
  color: var(--ink-900); box-shadow: var(--sh-md);
  transition: all var(--t-fast);
}
.qr-refresh svg { width: 18px; height: 18px; }
.qr-refresh:hover { background: var(--ink-950); border-color: var(--ink-950); color: var(--white); }
.login-legal { margin-top: auto; padding-top: var(--sp-5); font-size: var(--fs-xs); color: var(--ink-400); text-align: center; line-height: 1.7; }
.login-legal a { color: var(--ink-600); }

/* ---------- 技能商店 ---------- */
.store-head { display: flex; align-items: center; gap: var(--sp-6); margin-bottom: var(--sp-6); }
.store-head-main { flex: 1 1 auto; min-width: 0; }
.store-head-actions { display: flex; align-items: center; gap: var(--sp-3); flex: 0 0 auto; }
.store-search { width: 240px; }
.skill-corner { position: absolute; top: 10px; right: 10px; }

/* ---------- 外呼技能 · 认证 ---------- */
.cert-note {
  background: var(--ink-50); border-radius: var(--r-md);
  padding: var(--sp-4) var(--sp-5); margin-bottom: var(--sp-7);
  font-size: var(--fs-sm); color: var(--ink-600); line-height: 1.8;
}
.cert-note b { color: var(--ink-900); font-weight: 600; }
.form-foot { display: flex; justify-content: flex-end; gap: var(--sp-3); margin-top: var(--sp-8); padding-top: var(--sp-5); border-top: 1px solid var(--ink-100); }
.template-link { display: inline-flex; align-items: center; gap: 5px; font-size: var(--fs-xs); color: var(--brand-500); white-space: nowrap; padding-top: 12px; text-decoration: none; }
.template-link svg { width: 13px; height: 13px; }
.template-link:hover { text-decoration: underline; }

/* ---------- 我的认证 ---------- */
.cert-detail { display: grid; }
.cert-detail .form-row { margin-bottom: var(--sp-7); align-items: center; }
.cert-detail .form-row:last-child { margin-bottom: 0; }

/* ---------- 订阅 ---------- */
.subscribe-hero { text-align: center; margin-bottom: var(--sp-9, 36px); }
.subscribe-hero .page-title { font-size: 26px; }
.subscribe-switch { margin-top: var(--sp-5); display: inline-flex; }

/* ---------- 付款 ---------- */
.pay-card { max-width: 620px; margin: 0 auto; }
.pay-head { position: relative; display: flex; align-items: center; justify-content: center; margin-bottom: var(--sp-6); }
.pay-head .page-title { font-size: var(--fs-h2); }
.pay-back { position: absolute; left: 0; top: 50%; transform: translateY(-50%); }
.pay-methods { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); max-width: 420px; margin: 0 auto; }
.pay-method {
  height: 46px; border: 1px solid var(--ink-200); border-radius: var(--r-sm);
  display: flex; align-items: center; justify-content: center; gap: var(--sp-2);
  font-size: var(--fs-sm); color: var(--ink-700); transition: all var(--t-fast);
}
.pay-method:hover { border-color: var(--ink-300); }
.pay-method.is-active { border-color: var(--brand-500); background: var(--brand-50); color: var(--brand-500); font-weight: 600; }
.pay-method svg { width: 18px; height: 18px; }
.pay-amount { text-align: center; margin: var(--sp-7) 0 var(--sp-5); display: flex; align-items: baseline; justify-content: center; gap: 4px; }
.pay-amount .amt { font-size: 30px; font-weight: 700; font-family: var(--font-num); color: var(--brand-500); letter-spacing: -.02em; }
.pay-qr {
  width: 200px; height: 200px; margin: 0 auto;
  background: var(--ink-50); border-radius: var(--r-md);
  display: grid; place-items: center; color: var(--ink-700);
}
.pay-qr svg { width: 160px; height: 160px; }
.pay-legal {
  margin-top: var(--sp-8); padding-top: var(--sp-5);
  border-top: 1px solid var(--ink-100);
  display: flex; align-items: center; justify-content: center; gap: 7px;
  font-size: var(--fs-sm); color: var(--ink-500);
}
.checkbox {
  width: 16px; height: 16px; border-radius: 4px; flex: 0 0 auto;
  border: 1px solid var(--ink-300); display: grid; place-items: center;
  transition: all var(--t-fast); cursor: pointer; color: transparent;
}
.checkbox.is-on { background: var(--brand-500); border-color: var(--brand-500); color: var(--white); }
.checkbox svg { width: 11px; height: 11px; }

/* ---------- 设置中心 ---------- */
.settings-wrap { max-width: 720px; margin: 0 auto; }
.settings-wrap .page-head { text-align: center; }
.settings-wrap .page-head .page-title { font-size: var(--fs-h2); }

/* ---------- 通讯任务 ---------- */
.comm-head { display: flex; align-items: center; gap: var(--sp-4); margin-bottom: var(--sp-6); }
.comm-filters { display: flex; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-5); }
.date-select {
  height: 32px; padding: 0 10px; display: inline-flex; align-items: center; gap: 6px;
  background: var(--ink-100); border-radius: var(--r-xs);
  font-size: var(--fs-xs); color: var(--ink-500);
}
.date-select svg { width: 13px; height: 13px; }

/* ---------- 通讯任务 · token 费 ---------- */
/* 时间段从原来的"一行说明文字"换成了真能筛的分段控件 —— 页面有真实流水了，
   筛选不生效的筛选器就是死的。右侧那句说明跟按钮并排，靠 margin-left:auto
   推到最右；窄屏折行时它自己会掉到第二行，不会把按钮挤出去。 */
.comm-filters--tk { flex-wrap: wrap; }
.comm-filters--tk .lic-note { margin-left: auto; }
/* 第一列是这一行的主标识（这笔钱花在哪件事上），比其它列重一档：
   整张表要能一眼扫出"哪一行是什么"，而不是六列一样重 */
table.data .tk-name { font-weight: 500; color: var(--ink-900); }

/* ---------- 通讯任务 · 充值（重做：通栏余额 + 左选右摘要） ---------- */
.rc-balance {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-8);
  flex-wrap: wrap;
  padding: var(--sp-7) var(--sp-8);
  background: var(--white); border: 1px solid var(--ink-150);
  border-radius: var(--r-lg); box-shadow: var(--sh-xs);
  margin-bottom: var(--sp-5);
}
.rcb-label { display: block; font-size: var(--fs-xs); color: var(--ink-400); letter-spacing: .04em; }
.rcb-value {
  display: block; margin-top: var(--sp-2);
  font-family: var(--font-num); font-size: 40px; line-height: 1; font-weight: 700;
  color: var(--ink-900); letter-spacing: -.03em;
}
.rcb-stats { display: flex; gap: var(--sp-8); }
.rcb-stats b { display: block; font-family: var(--font-num); font-size: var(--fs-h3); font-weight: 600; color: var(--ink-800); }
.rcb-stats small { display: block; margin-top: 3px; font-size: var(--fs-xs); color: var(--ink-400); }

.rc-block {
  background: var(--white); border: 1px solid var(--ink-150);
  border-radius: var(--r-lg); padding: var(--sp-6);
}
.rc-block-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--sp-4); margin-bottom: var(--sp-5);
}
.rc-block-title { font-size: var(--fs-h3); font-weight: 600; color: var(--ink-900); }
.rc-block-note { font-size: var(--fs-xs); color: var(--ink-400); }

/* ---------- 我的交易 ---------- */
/* 竖向时间轴已移除，横向步骤条独占一行，放宽到与内容区同宽更好排 7 个节点 */
.trade-layout { max-width: 100%; }
.trade-layout .steps { flex-wrap: wrap; row-gap: var(--sp-4); }
.trade-status {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 5px 12px; border-radius: var(--r-full);
  background: var(--brand-100); color: var(--brand-500);
  font-size: var(--fs-xs); font-weight: 600;
}

/* ---------- 评审用的设计标注 ---------- */
.anno-note { display: block; }

/* ==========================================================================
   助手首页（第四轮做减法：快捷入口四宫格与保障条已撤掉，只剩 hero + 输入区）
   宽度与输入框对齐（780）

   纵向居中：padding 上下必须对称。之前写的是「上 32 / 下 48」，
   flex 居中只对「去掉 padding 后的内容盒」生效，padding 不对称就会把整块
   内容再往上推 8px —— 看着就是「差一点点没居中」。
   ========================================================================== */
.chat-page {
  gap: var(--sp-6);
  padding: var(--sp-10) var(--sp-8);
}
.chat-foot { margin: 0; }

/* 内容高到装不下时才退化成顶部对齐（safe 关键字：溢出时自动放弃居中，
   避免顶部被裁掉且滚不到）。不支持 safe 的浏览器会忽略这一行，退回 center。 */
.chat-page { justify-content: safe center; }

/* ==========================================================================
   充值页 · 订阅套餐（第十四轮）
   --------------------------------------------------------------------------
   一级「个人版 / 企业版」+ 二级付费周期。卡片的信息顺序与 WorkBuddy 定价页
   一致：版本名 → 一句话 → 价格（含划线原价 / 折合月价）→ 按钮 → 权益清单。
   强调色只出现两处：推荐卡的描边、折扣角标。其余全靠排版拉层次 ——
   四张卡并排时如果每张都在喊，就没人看得清。
   ========================================================================== */
.rc-block--sub { margin-bottom: var(--sp-5); }

/* 一级：买积分的三条路（个人版 / 企业版 / 加量包）—— 实心分段控件，主选择 */
.pkg-bar { margin-bottom: var(--sp-4); }

/* 二级：付费周期。它跟一级**必须长得不一样** ——
   一级是实心分段控件（灰轨道 + 白色胶囊），这里是轻量描边圆片 + 前置小标签。
   两行控件长得一模一样，用户就分不出"先选哪个" —— 这正是"主次不分"的成因。
   选中态沿用全站那套「品牌红描边 + 极浅品牌底」，但只染字和边框，不做实心块。 */
.pkg-terms-row {
  display: flex; align-items: center; gap: var(--sp-3);
  margin-bottom: var(--sp-5);
}
.pkg-terms-row[hidden] { display: none; }
.pkg-terms-label { flex: 0 0 auto; font-size: var(--fs-xs); color: var(--ink-400); }
.segmented.pkg-terms { background: transparent; padding: 0; gap: var(--sp-2); }
.segmented.pkg-terms button {
  height: 30px; padding: 0 var(--sp-4);
  border: 1px solid var(--ink-200); border-radius: var(--r-full);
  background: var(--white); color: var(--ink-600);
  font-size: var(--fs-xs); font-weight: 500;
}
.segmented.pkg-terms button:hover {
  border-color: var(--ink-300); color: var(--ink-900); background: var(--white);
}
.segmented.pkg-terms button.is-active {
  background: var(--brand-50); border-color: var(--brand-200);
  color: var(--brand-600); font-weight: 600; box-shadow: none;
}

/* 订阅 / 加量包两个面板就地切换，没轮到的那块整个收掉 */
#pkgPanelPack[hidden] { display: none; }

.pkg-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--sp-4); }
.pkg-grid.is-ent { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 1280px) {
  .pkg-grid, .pkg-grid.is-ent { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.pkg-card {
  position: relative; display: flex; flex-direction: column;
  padding: var(--sp-5); padding-top: var(--sp-6);
  background: var(--white); border: 1px solid var(--ink-150);
  border-radius: var(--r-lg); transition: all var(--t-base);
  cursor: pointer;
}
.pkg-card:hover { border-color: var(--ink-300); box-shadow: var(--sh-md); transform: translateY(-2px); }

/* 选中态：收编回全站那套「品牌红描边 + 极浅品牌底」。
   默认四张卡长得一模一样，没有任何一张在喊"买我" —— 红只在你点过之后出现。 */
.pkg-card.is-picked {
  border: 1.5px solid var(--brand-500);
  background: var(--brand-50);
  box-shadow: 0 12px 30px -14px rgba(230, 0, 18, .22);
}
.pkg-card.is-picked .pkg-card__ico { background: var(--white); color: var(--brand-500); }

/* 当前在用的那一档：卡片置灰 + 右上角「当前使用」。绿点 + 绿字 + 淡绿底 ——
   沿用全站「小绿点＝正在运行」的那套语言，一眼就知道是"在用"而不是"在卖"。
   卡片本身仍然只走灰阶，绿的只有这一枚角标。 */
.pkg-card.is-current { background: var(--ink-50); border-color: var(--ink-150); }
.pkg-card.is-current:hover { transform: none; box-shadow: none; border-color: var(--ink-200); }
.pkg-card__cur {
  position: absolute; top: var(--sp-3); right: var(--sp-3);
  height: 19px; padding: 0 8px; border-radius: var(--r-full);
  background: var(--success-bg); color: var(--success-ink);
  font-size: var(--fs-2xs); font-weight: 600;
  display: inline-flex; align-items: center; gap: 4px; white-space: nowrap;
}
.pkg-card__cur::before {
  content: ""; flex: 0 0 auto; width: 5px; height: 5px;
  border-radius: 50%; background: var(--success);
}

/* 折扣角标：比主按钮安静一档 —— 浅红底红字，不抢眼 */
.pkg-card__off {
  position: absolute; top: var(--sp-3); right: var(--sp-3);
  height: 19px; padding: 0 8px; border-radius: var(--r-full);
  background: var(--brand-50); color: var(--brand-600); border: 1px solid var(--brand-100);
  font-size: var(--fs-2xs); font-weight: 600;
  display: inline-grid; place-items: center; white-space: nowrap;
}

.pkg-card__hd { display: flex; align-items: center; gap: var(--sp-3); }
.pkg-card__ico {
  flex: 0 0 auto; width: 34px; height: 34px; border-radius: var(--r-md);
  display: inline-grid; place-items: center;
  background: var(--ink-100); color: var(--ink-700);
}
.pkg-card.is-picked .pkg-card__ico { background: var(--white); color: var(--brand-500); }
.pkg-card__name { display: block; font-size: var(--fs-body); font-weight: 600; color: var(--ink-900); }
.pkg-card__sub { display: block; margin-top: 1px; font-size: var(--fs-2xs); color: var(--ink-500); }

.pkg-card__price { display: flex; align-items: baseline; gap: 2px; margin-top: var(--sp-5); }
.pkg-card__price .cur { font-size: var(--fs-h3); font-weight: 600; color: var(--ink-900); }
.pkg-card__price .num {
  font-family: var(--font-num); font-size: 32px; line-height: 1; font-weight: 700;
  color: var(--ink-900); letter-spacing: -.03em;
}
.pkg-card__price .num.is-word { font-size: 22px; letter-spacing: 0; }
.pkg-card__price .per { margin-left: 3px; font-size: var(--fs-xs); color: var(--ink-400); }

/* 划线原价 + 折合月价：一行里左原价右折算，没折扣时左侧留空 */
.pkg-card__meta {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-2);
  min-height: 18px; margin-top: 6px;
}
.pkg-card__was { font-size: var(--fs-2xs); color: var(--ink-400); text-decoration: line-through; }
.pkg-card__avg { font-size: var(--fs-2xs); color: var(--ink-500); }

.pkg-card__cta { margin: var(--sp-4) 0 var(--sp-5); }

.pkg-card__rlabel { font-size: var(--fs-2xs); color: var(--ink-400); margin-bottom: var(--sp-3); }
.pkg-card__rights { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.pkg-card__rights li { display: flex; gap: var(--sp-2); font-size: var(--fs-xs); color: var(--ink-600); line-height: 1.5; }
.pkg-card__rights svg { flex: 0 0 auto; margin-top: 2px; color: var(--ink-300); }
.pkg-card__rights b { font-weight: 600; color: var(--ink-900); }
.pkg-card.is-picked .pkg-card__rights svg { color: var(--brand-400); }

/* 续费口径：这一条比价格更需要说清，所以给它一条独立的底纹 */
.pkg-note {
  margin: var(--sp-5) 0 0; padding: var(--sp-3) var(--sp-4);
  background: var(--ink-50); border-radius: var(--r-md);
  font-size: var(--fs-2xs); color: var(--ink-500); line-height: 1.75;
}

/* ==========================================================================
   积分加量包（第十五轮）
   --------------------------------------------------------------------------
   参考 WorkBuddy 的加量包口径：订阅之外的一次性购买、独立有效期、可重复购买。
   卡片四张，全部由 PACKS 一份数据算出来（价格 / 折合单价 / 省多少）。
   彩色只用两处：有折扣时的「省 ¥x」角标、选中后的红描边。
   ========================================================================== */
/* 从"整页的提示条"变成了"卡片里的一行说明"，所以收掉橙色警示底：
   ① tokens 里 --warning 的适用范围写的是「待处理 / 审核中」，用在购买说明上是越界；
   ② 它现在住在白卡里，旁边就是订阅卡，一块橙色会把整页唯一的红色抢掉。
   关键信息（一次性 / 不自动续费 / 不退款）本身已经用 <b> 加重，不靠颜色喊。 */
.pk-notice {
  display: flex; align-items: flex-start; gap: var(--sp-3);
  margin: calc(var(--sp-2) * -1) 0 var(--sp-5); padding: var(--sp-3) var(--sp-4);
  background: var(--ink-50); border: 1px solid var(--ink-150);
  border-radius: var(--r-md);
  font-size: var(--fs-xs); color: var(--ink-600); line-height: 1.7;
}
.pk-notice svg { flex: 0 0 auto; margin-top: 2px; color: var(--ink-400); }
.pk-notice b { font-weight: 600; color: var(--ink-900); }

.pk-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--sp-4); }
@media (max-width: 1180px) { .pk-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.pack {
  position: relative; display: flex; flex-direction: column;
  padding: var(--sp-5); padding-top: var(--sp-6);
  background: var(--white); border: 1px solid var(--ink-150);
  border-radius: var(--r-lg); transition: all var(--t-base);
  cursor: pointer;
}
.pack:hover { border-color: var(--ink-300); box-shadow: var(--sh-md); transform: translateY(-2px); }
/* 和套餐卡同一套选中语言：品牌红描边 + 极浅品牌底 */
.pack.is-picked {
  border: 1.5px solid var(--brand-500);
  background: var(--brand-50);
  box-shadow: 0 12px 30px -14px rgba(230, 0, 18, .22);
}
/* 只有真便宜了才挂这一枚 —— 第一档不便宜，就不挂 */
.pack__off {
  position: absolute; top: var(--sp-3); right: var(--sp-3);
  height: 19px; padding: 0 8px; border-radius: var(--r-full);
  background: var(--brand-50); color: var(--brand-600); border: 1px solid var(--brand-100);
  font-size: var(--fs-2xs); font-weight: 600;
  display: inline-grid; place-items: center; white-space: nowrap;
}
.pack.is-picked .pack__off { background: var(--white); }

.pack__hd { display: flex; align-items: baseline; gap: 4px; }
.pack__pts {
  font-family: var(--font-num); font-size: 30px; line-height: 1.1; font-weight: 700;
  color: var(--ink-900); letter-spacing: -.03em;
}
.pack__unit { font-size: var(--fs-xs); color: var(--ink-500); }

.pack__price { display: flex; align-items: baseline; gap: 2px; margin-top: var(--sp-4); }
.pack__price .cur { font-size: var(--fs-body); font-weight: 600; color: var(--ink-900); }
.pack__price .num {
  font-family: var(--font-num); font-size: 22px; line-height: 1; font-weight: 700;
  color: var(--ink-900); letter-spacing: -.02em;
}
.pack__rate { margin-top: 6px; font-size: var(--fs-2xs); color: var(--ink-500); }
.pack__rate b { color: var(--ink-800); font-weight: 600; }

.pack__meta { list-style: none; margin: var(--sp-4) 0 0; padding: 0; display: grid; gap: 6px; }
.pack__meta li { display: flex; align-items: center; gap: 6px; font-size: var(--fs-2xs); color: var(--ink-600); }
.pack__meta svg { flex: 0 0 auto; color: var(--ink-300); }

.pack .btn { margin-top: var(--sp-5); }

.pk-note {
  margin: var(--sp-5) 0 0; padding: var(--sp-3) var(--sp-4);
  background: var(--ink-50); border-radius: var(--r-md);
  font-size: var(--fs-2xs); color: var(--ink-500); line-height: 1.75;
}

/* ==========================================================================
   购买记录（第十四轮）
   ========================================================================== */
.ord-no { font-family: var(--font-num); font-size: var(--fs-2xs); color: var(--ink-500); letter-spacing: .02em; }
.ord-item b { display: block; font-size: var(--fs-sm); font-weight: 600; color: var(--ink-900); }
.ord-item small { display: block; margin-top: 1px; font-size: var(--fs-2xs); color: var(--ink-500); }
.ord-amt { font-family: var(--font-num); font-weight: 600; color: var(--ink-900); }
.ord-amt small { font-family: var(--font-sans); font-weight: 400; color: var(--ink-400); }

.ord-st {
  display: inline-flex; align-items: center; gap: 5px;
  height: 22px; padding: 0 9px; border-radius: var(--r-full);
  font-size: var(--fs-2xs); font-weight: 500; white-space: nowrap;
  background: var(--ink-100); color: var(--ink-600);
}
.ord-st::before { content: ''; width: 5px; height: 5px; border-radius: 50%; background: currentColor; }
.ord-st.is-paid { background: var(--success-bg); color: var(--success-ink); }
.ord-st.is-pending { background: var(--warning-bg); color: var(--warning-ink); }
/* 开票的两种状态必须分开：正在开（进行中 → 黄）和已经开好（有结果 → 红）。
   同一行里同一种颜色，用户分不出"等"和"好了"。 */
.ord-st.is-invoicing { background: var(--warning-bg); color: var(--warning-ink); }
.ord-st.is-invoiced { background: var(--brand-50); color: var(--brand-600); }
.ord-sts { display: flex; flex-wrap: wrap; gap: 5px; }

/* ==========================================================================
   小伙伴 · 咯排（第二十六轮 → 第二十七轮改黑底语音版）
   --------------------------------------------------------------------------
   顶栏那根电话图标原来跳「实时通话台」—— 那是业务外呼工作台，
   用户想点的其实是"跟这个小东西说句话"，两者不是一回事。现在落到本页。

   第二十七轮按用户原话改了三处：
     ① "整个页面都要是黑色的背景" —— 纯黑（--ink-1000）；
     ② "不需要输入文字" —— 删掉输入框，只留一枚话筒；
     ③ "直接就能语音对话" —— 进页面就是 listen 态，点话筒就是说一句。
   原稿自带纯黑底，页面也纯黑：**不给形象加圆角、阴影、背光**，
   抹掉边界它才是"长在这一页里"，而不是"被贴上来"。
   （白底那版恰恰相反，必须靠圆角+阴影+一团雾让它"站"在页面上。）

   版面策略：对话流放在形象**上面**（flex: 0 1 auto，可被压缩），
   舞台吃剩余空间并居中。于是——
     · 空态：对话流 0 高，形象正好在屏幕正中央；
     · 开口后：对话流向上长，形象始终贴在话筒正上方，"它就靠在你嘴边说话"。
   顺序反了会把形象一路顶出屏幕。

   动效纪律（沿用全站）：形象本体只做上下位移，绝不套 scale ——
   缩放会让它自己忽大忽小，观感像坏了。"正在说话"的声波另挂三个 <i>，
   与本体解耦，也只在 data-pal="speak" 时才跑。
   ========================================================================== */
.pal-page {
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column;
  background: var(--ink-1000);
  /* 顶栏与话筒都改成浮动层（见下），需要一个定位上下文 */
  position: relative;
  overflow: hidden;
}

/* ---- 沉浸：整个屏都是黑的 ----
   用户原话："整个屏都是黑色的；左侧的导航栏也遮着；突出我的卡通人"。
   侧栏和全局顶栏在这一页整个收掉（display:none，不是染黑 ——
   染黑会留下一条 240px 的空白边，形象还是被挤在中间一小块）。
   .workarea 是 flex:1 1 auto，侧栏一走它自动占满，形象于是真的在整屏中央。
   类名挂在 body 上：那两个容器不在 pal 页内部，写在 .pal-page 底下管不到。
   特异性给到 (0,2,1)，压过 .sidebar / .topbar 的 (0,1,0)，
   所以不依赖这两张表的加载顺序。 */
body.is-pal { background: var(--ink-1000); }
body.is-pal .frame { background: var(--ink-1000); }
body.is-pal .sidebar { display: none; }
body.is-pal .topbar { display: none; }

/* 这一页**铺满视口**，不是"占满 scroller 的可见高度"。
   理由：.page 平时躺在 .scroller（overflow-y:auto）里，高度由内容决定 ——
   那样形象只会落在"内容块"中央，而内容块比视口矮一截，形象就跟着偏。
   fixed + inset:0 让它直接盖住整屏，侧栏和顶栏又已经收掉，
   于是"整个屏都是黑的"是字面意义上的黑。
   z-index 取 30：高过 scroller 里的普通内容，低过 overlay(100)/modal(200)/toast(300)，
   这一页自己不弹任何浮层，不需要更高。 */
.page.is-active[data-page="pal"] {
  position: fixed; inset: 0; z-index: 30;
  display: flex; flex-direction: column;
  min-height: 0;
}

/* 这一页上，浮动的东西一律不出现。它们的 z-index 都在 pal 页之上
   （toast 300 / 推送卡同级的 protonav），靠层级压不过，只能显式收：
     · 原型导航 —— 那是给我们自己跳页面用的，用户在该沉浸的时候不需要；
     · 推送卡   —— "要你读完但不该打断手上的活"，而这一页整页就是那个"活"；
     · 设备坞   —— 顶栏已经收掉，没有入口能再开它，但万一用户在别的页开着
                   切过来，它会孤零零挂在黑页右边。
   只收显示，不动数据：推送的未读数、已读状态都不碰，离开这一页照旧。 */
body.is-pal .protonav,
body.is-pal .push-card,
body.is-pal .dock { display: none; }

/* 顶栏没了，页内那根条也不再需要分隔线 —— 黑底上一条灰线反而把画面切成两半。
   名字留小一号：这一页的主角是形象，不是标题。 */
body.is-pal .pal-bar { border-bottom: 0; }

/* ---- 顶栏：返回 / 名字+状态 / 重新开始 ----
   **浮动层**，不占文档流：侧栏和全局顶栏都收掉了，这一页要"整个屏都是黑的"，
   顶部再压一条实心栏会把画面切成两半，形象也挤不到视口正中。
   透明底 + 绝对定位，它浮在形象上方，只在需要时（ hover / 点击 ）才显形。 */
.pal-bar {
  position: absolute; top: 0; left: 0; right: 0; z-index: 5;
  display: flex; align-items: center; gap: var(--sp-3);
  height: 52px; padding: 0 var(--sp-4);
}
.pal-bar__btn {
  flex: 0 0 auto; width: 32px; height: 32px; border-radius: var(--r-sm);
  display: grid; place-items: center; color: rgba(255, 255, 255, .52);
  transition: background var(--t-fast), color var(--t-fast);
}
.pal-bar__btn:hover { background: rgba(255, 255, 255, .09); color: rgba(255, 255, 255, .92); }
.pal-bar__btn svg { width: 16px; height: 16px; }
/* 两侧按钮等宽（32px），中间这块才能真正居中 */
.pal-bar__id {
  flex: 1 1 auto; min-width: 0;
  display: flex; align-items: baseline; justify-content: center; gap: var(--sp-2);
}
.pal-bar__name { font-size: var(--fs-h3); font-weight: var(--fw-semibold); color: #fff; }

/* ---- 舞台：形象 ----
   占满整屏并居中。侧栏 / 全局顶栏 / 对话流 / 提示文字全部收掉之后，
   它是这一页唯一的主角 —— 用户原话："突出我的卡通人"。
   上下各留 132px：上面让开浮动顶栏（52px + 呼吸），
   下面让开浮动话筒（约 100px + 呼吸）。两边等宽 ⇒ 形象精确落在视口中线上。 */
.pal-stage {
  flex: 1 1 auto; min-height: 0;
  display: grid; place-items: center; align-content: center;
  padding: 132px var(--sp-6);
}
.pal-char { position: relative; --pal-h: clamp(280px, 46vh, 520px); }
/* 形象**不要**背光、不要圆角、不要阴影：原图自带纯黑底，页面也是纯黑，
   加任何一层都会在原稿边缘切出一道界线，反而露出"这是贴上来的一张图"。
   抹掉边界，它才是长在这一页里的。
   也**不随对话缩小** —— 没有字幕要腾地方，它就应当一直是全大的那个。 */
.pal-char__img {
  position: relative; z-index: 1;
  display: block; width: auto;
  height: var(--pal-h);
  background: var(--ink-1000);
  /* 不写默认 animation：这一页永远处在 listen 或 speak，
     两套动作各自声明（见下面），默认那条只会和它们打架。
     （曾经默认挂 pal-float，后来 idle 态没了，它就成了没人用的第三条。） */
  user-select: none; -webkit-user-drag: none;
}

/* 没有"聊上了就缩小"那一套了：这一页不显示任何字幕，形象不需要给谁腾地方，
   它从头到尾都是全大的那个。is-chatting 也随之不再存在 ——
   （曾经有过一版：对话流会把形象压成一枚标识，那是为字幕让路的版式。） */

/* ---- 声波：说话时从头部荡开三圈 ---- */
.pal-char__wave {
  position: absolute; left: 50%; top: 19%;
  width: calc(var(--pal-h) * .41); height: calc(var(--pal-h) * .41);
  margin: calc(var(--pal-h) * -.205) 0 0 calc(var(--pal-h) * -.205);
  z-index: 2; pointer-events: none;
}
.pal-char__wave i {
  position: absolute; inset: 0;
  border-radius: var(--r-full);
  border: 2px solid var(--brand-400);
  opacity: 0;
}
.page[data-page="pal"][data-pal="speak"] .pal-char__wave i { animation: pal-wave 1.35s ease-out infinite; }
.page[data-page="pal"][data-pal="speak"] .pal-char__wave i:nth-child(2) { animation-delay: .27s; }
.page[data-page="pal"][data-pal="speak"] .pal-char__wave i:nth-child(3) { animation-delay: .54s; }

/* ---- 两套动作 ----
   （曾经还有第三套 pal-float「待机慢浮」—— 那是还有 idle 态时的版式。
    现在这一页一进来就是在听，永远没有"待机"，那套 keyframe 也就没有了主人，
    删掉，不留死代码。） */
/* 倾听：小幅度快浮 —— 它在凑过来听 */
.page[data-page="pal"][data-pal="listen"] .pal-char__img { animation: pal-listen 1.1s var(--ease) infinite; }
@keyframes pal-listen {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-5px); }
}
/* 说话：落点错开的弹跳，节奏比人说话稍快一点 */
.page[data-page="pal"][data-pal="speak"] .pal-char__img { animation: pal-talk .66s var(--ease) infinite; }
@keyframes pal-talk {
  0%, 100% { transform: translateY(0); }
  32%      { transform: translateY(-18px); }
  64%      { transform: translateY(-4px); }
}
@keyframes pal-wave {
  0%   { transform: scale(.82); opacity: .6; }
  100% { transform: scale(1.18); opacity: 0; }
}

/* ---- 话筒：这一页唯一的输入 ----
   没有输入框、没有文字。想跟它说话就点一下，剩下的它用动作回你。
   尺寸给到 64px（比一般图标按钮大一倍）：它是整页唯一的交互目标，
   也是"我正在跟你说话"的那个动作本身。
   **浮动在底部**，不占文档流 —— 占流的话舞台就被顶矮一截，
   形象再也落不到视口中线上。 */
.pal-mic {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 5;
  display: grid; place-items: center;
  padding: var(--sp-5) var(--sp-6) var(--sp-6);
}
.pal-mic__btn {
  position: relative;
  flex: 0 0 auto; width: 64px; height: 64px; border-radius: var(--r-full);
  display: grid; place-items: center;
  background: var(--brand-500); color: #fff;
  transition: background var(--t-fast), transform var(--t-fast);
}
.pal-mic__btn svg { width: 24px; height: 24px; position: relative; z-index: 1; }
.pal-mic__btn:hover { background: var(--brand-600); }
.pal-mic__btn:active { transform: scale(.94); }
/* 待机时一圈缓慢的呼吸光圈：告诉用户"它一直在听，你随时可以点"。
   挂在 ::after 上，本体不套 scale（全站动效纪律）。 */
.pal-mic__btn::after {
  content: ''; position: absolute; inset: 0;
  border-radius: var(--r-full);
  border: 2px solid var(--brand-400);
  animation: pal-mic-pulse 2.4s var(--ease) infinite;
}
/* 它正在说的时候话筒暗下去 —— 该它讲，别抢。 */
.page[data-page="pal"][data-pal="speak"] .pal-mic__btn { background: var(--ink-700); }
.page[data-page="pal"][data-pal="speak"] .pal-mic__btn::after { animation: none; opacity: 0; }
@keyframes pal-mic-pulse {
  0%   { transform: scale(1);    opacity: .55; }
  70%  { transform: scale(1.5);  opacity: 0; }
  100% { transform: scale(1.5);  opacity: 0; }
}
