Explorar o código

feat(v15): 中性灰白底 + 实底按钮/侧栏/顶栏 + A 卡填满 8 列 + 移动端 393 适配

- 页底改中性灰白(去彩色光斑),侧栏/顶栏/按钮/chip/徽标/输入框全部实底
- A 卡:阶段格加阶段名,下半拆「卡池进度 | 待评分」;B 卡续接阶段行
- F 卡按内容收缩(一行 .feed li 的 54px 行高改为 grid,37px)
- 移动端:五阶段两行三列、说明 14、统计数字 20 档、F 两行式、无横向溢出
- verify-v15:修堆叠判定(B 在 A 正下方+左对齐)
FmodeCode hai 4 días
pai
achega
3cb09509bf

+ 6 - 1
scripts/verify-v15.mjs

@@ -356,6 +356,7 @@ const main = async () => {
     const vr = (document.getElementById('v15-det') || appR().querySelector('main#view').firstElementChild).shadowRoot;
     const R = (el) => { const b = el.getBoundingClientRect(); return { x: +b.x.toFixed(1), y: +b.y.toFixed(1), w: +b.width.toFixed(1), h: +b.height.toFixed(1) }; };
     const a = vr.querySelector('kf-glass-card[data-role="a"]'), b = vr.querySelector('kf-glass-card[data-role="b"]');
+    const rowInfo = (() => { const out = []; for (let q = a.parentElement; q && q !== vr; q = q.parentElement) out.push(q.localName + '.' + q.className + '@' + Math.round(q.getBoundingClientRect().top) + '-' + Math.round(q.getBoundingClientRect().bottom)); return out; })();
     const fsCount = {};
     walk(vr, (el) => {
       if (![...el.childNodes].some((n) => n.nodeType === 3 && n.textContent.trim())) return;
@@ -367,7 +368,11 @@ const main = async () => {
     let over = [];
     walk(vr, (el) => { const r = el.getBoundingClientRect(); if (r.width > 0 && r.right > document.documentElement.clientWidth + 1) over.push(elLabel(el) + '@' + Math.round(r.right)); });
     return { scrollWidth: document.documentElement.scrollWidth, clientWidth: document.documentElement.clientWidth,
-      A: a ? R(a) : null, B: b ? R(b) : null, stacked: a && b ? b.y >= a.y + a.h - 2 : null,
+      A: a ? R(a) : null, B: b ? R(b) : null,
+      /* 堆叠 = B 在垂直方向完全位于 A 下方且与 A 左边缘对齐(同一列里上下排)。
+         不能拿「一行」的 bottom 比 —— 行的 bottom 跟着最高的卡走,B 自己就是行内最高时恒为 false。 */
+      stacked: a && b ? Math.abs(a.getBoundingClientRect().left - b.getBoundingClientRect().left) < 2
+        && b.getBoundingClientRect().top >= a.getBoundingClientRect().bottom - 1 : null,
       CDE: ['c', 'd', 'e'].map((r) => { const k = vr.querySelector('kf-glass-card[data-role="' + r + '"]'); return k ? R(k) : null; }),
       fonts: Object.keys(fsCount).sort((p, q) => parseFloat(p) - parseFloat(q)), fontSizeCount: fsCount,
       overflowing: [...new Set(over)].slice(0, 10) };

+ 3 - 3
src/components/kf-badge.js

@@ -43,7 +43,7 @@ export class KfBadge extends LitElement {
       display: inline-flex; align-items: center; gap: 4px; height: 22px; padding: 0 8px;
       text-box-trim: trim-both; text-box-edge: cap alphabetic;
       border-radius: var(--r-sm); font: 600 11px/1 var(--kf-font); letter-spacing: -0.01em;
-      border: 1px solid var(--kf-line-strong); color: var(--kf-ink-2); background: rgba(255,255,255,0.55);
+      border: 1px solid var(--kf-line-strong); color: var(--kf-ink-2); background: var(--kf-surface-btn);
       white-space: nowrap; font-variant-numeric: tabular-nums;
     }
     .b::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; opacity: 0.9; flex: none; }
@@ -62,8 +62,8 @@ export class KfBadge extends LitElement {
     :host([kind="stage"][value="S3"]) .b { background: var(--kf-s3); } :host([kind="stage"][value="S4"]) .b { background: var(--kf-s4); }
     :host([kind="stage"][value="S5"]) .b { background: var(--kf-s5); }
     /* v10 强调色收敛:品类徽标不再染蓝 —— 中性灰描边;蓝只留给「主数值 / 趋势线 / CTA / 链接」 */
-    :host([kind="method"]) .b { color: var(--kf-ink-2); border-color: var(--kf-line-strong); background: rgba(255,255,255,0.55); }
-    :host([kind="sample"]) .b { color: var(--kf-ink-3); border-color: var(--kf-line-strong); background: rgba(255,255,255,0.35); }
+    :host([kind="method"]) .b { color: var(--kf-ink-2); border-color: var(--kf-line-strong); background: var(--kf-surface-btn); }
+    :host([kind="sample"]) .b { color: var(--kf-ink-3); border-color: var(--kf-line-strong); background: transparent; }
     :host([kind="sample"]) .b::before { border-radius: 2px; }
   `;
 

+ 3 - 3
src/components/kf-opportunity-card.js

@@ -88,9 +88,9 @@ export class KfOpportunityCard extends LitElement {
     .acts .sp { flex: 1; }
     a.report { font-size: 11px; color: var(--kf-accent); text-decoration: none; border-bottom: 1px dashed rgba(91, 91, 214, 0.40); }
     a.report:hover { border-bottom-style: solid; }
-    .st { display: inline-flex; border: 1px solid var(--kf-line-strong); border-radius: var(--r-sm); overflow: hidden; background: rgba(255,255,255,0.5); }
+    .st { display: inline-flex; border: 1px solid var(--kf-line-strong); border-radius: var(--r-sm); overflow: hidden; background: var(--kf-surface); }
     .st button { border: 0; background: transparent; font: 500 11px/1 var(--kf-font); color: var(--kf-ink-2); padding: 0 10px; height: 26px; cursor: pointer; transition: background var(--kf-dur) var(--kf-ease); }
-    .st button:hover { background: rgba(255,255,255,0.6); }
+    .st button:hover { background: var(--kf-surface-btn); }
     .st button[aria-pressed="true"]:hover { background: var(--kf-ink); }
     .st button[aria-pressed="true"] { background: var(--kf-ink); color: #fff; }
     .st button[aria-pressed="true"].ok { background: #0f5232; }
@@ -117,7 +117,7 @@ export class KfOpportunityCard extends LitElement {
       .acts { gap: 8px; }
       .st { height: 44px; }
       .st button { height: 44px; padding: 0 14px; font-size: 13px; }
-      .st button:active { background: rgba(255,255,255,0.7); }
+      .st button:active { background: var(--kf-surface-btn); }
       .acts .kf-btn { min-height: 44px; padding: 0 14px; font-size: 13px; }
       a.report { min-height: 44px; display: inline-flex; align-items: center; font-size: 13px; }
       .sample { font-size: 11px; padding: 3px 8px; }

+ 1 - 1
src/components/kf-pipeline.js

@@ -30,7 +30,7 @@ export class KfPipeline extends LitElement {
     .v { font-size: 20px; font-weight: 600; line-height: 1.1; color: var(--kf-ink); font-variant-numeric: tabular-nums; font-family: var(--kf-font-num); }
     .l { font-size: 11px; color: var(--kf-ink-3); }
     .arr { display: inline-flex; color: var(--kf-ink-3); }
-    .rate { margin-left: auto; font-size: 11px; line-height: 1; color: var(--kf-ink-3); border: 1px solid var(--kf-line-strong); border-radius: var(--r-sm); padding: 4px 12px; background: rgba(255,255,255,0.5); }
+    .rate { margin-left: auto; font-size: 11px; line-height: 1; color: var(--kf-ink-3); border: 1px solid var(--kf-line-strong); border-radius: var(--r-sm); padding: 4px 12px; background: var(--kf-surface-btn); }
     .rate b { color: var(--kf-accent-ink); font-variant-numeric: tabular-nums; font-family: var(--kf-font-num); }
   `;
 

+ 3 - 3
src/components/kf-score-panel.js

@@ -48,9 +48,9 @@ export class KfScorePanel extends LitElement {
     .meta b { color: var(--kf-ink); font-weight: 600; font-variant-numeric: tabular-nums; }
     .none { color: var(--kf-ink-3); font-size: 14px; font-weight: 600; }
     ul { list-style: none; margin: 14px 0 0; padding: 0; display: grid; gap: 6px; }
-    li { display: grid; grid-template-columns: 88px 48px 1fr; gap: 8px; align-items: baseline; padding: 8px 12px; border-radius: var(--r-sm); background: rgba(255,255,255,0.4); border: 1px solid var(--kf-line); }
+    li { display: grid; grid-template-columns: 88px 48px 1fr; gap: 8px; align-items: baseline; padding: 8px 12px; border-radius: var(--r-sm); background: var(--kf-surface-btn); border: 1px solid var(--kf-line); }
     /* Agent 评分:6% 染色 + 1px 同色半透明描边(不是整块紫底) */
-    li.agent { background: color-mix(in srgb, var(--kf-accent) 6%, rgba(255,255,255,0.4)); border-color: color-mix(in srgb, var(--kf-accent) 18%, transparent); }
+    li.agent { background: color-mix(in srgb, var(--kf-accent) 6%, var(--kf-surface)); border-color: color-mix(in srgb, var(--kf-accent) 18%, transparent); }
     .who { color: var(--kf-ink); font-weight: 600; font-size: 13px; }
     .s { font-variant-numeric: tabular-nums; font-weight: 600; color: var(--kf-accent-ink); font-size: 14px; }
     /* 行内只用 kf-stat 的数字槽(数字滚动 + 单位分层都复用它),不渲染标签 / 注脚 */
@@ -58,7 +58,7 @@ export class KfScorePanel extends LitElement {
     .c .t { color: var(--kf-ink-3); font-size: 11px; margin-left: 6px; }
     form { margin-top: 16px; padding: 12px; border-radius: var(--r-sm); border: 1px dashed var(--kf-line-strong); display: grid; gap: 8px; }
     .row { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
-    input[type="number"], input[type="text"] { height: 32px; border-radius: var(--r-sm); border: 1px solid var(--kf-line-strong); background: rgba(255,255,255,0.6); transition: var(--kf-t); }
+    input[type="number"], input[type="text"] { height: 32px; border-radius: var(--r-sm); border: 1px solid var(--kf-line-strong); background: var(--kf-surface); transition: var(--kf-t); }
     input:focus { outline: none; border-color: var(--kf-focus); box-shadow: 0 0 0 2px rgba(91, 91, 214, 0.22); background: #fff; }
     input[type="number"] { width: 88px; padding: 0 8px; font: 600 14px var(--kf-font-num); font-variant-numeric: tabular-nums; }
     input[type="text"] { flex: 1; min-width: 160px; padding: 0 12px; font: 13px var(--kf-font); }

+ 1 - 1
src/components/kf-table.js

@@ -63,7 +63,7 @@ export class KfTable extends LitElement {
     :host([dense]) td { padding: 8px 10px; }
     tr:last-child td { border-bottom: 0; }
     tbody tr { transition: background var(--kf-dur) var(--kf-ease); }
-    tbody tr:hover td { background: rgba(255,255,255,0.45); }
+    tbody tr:hover td { background: var(--kf-surface-btn); }
     tbody tr:focus-visible { outline: 2px solid var(--kf-focus); outline-offset: -2px; }
     tr.hl td { background: rgba(255, 214, 102, 0.26); }
     .r { text-align: right; font-variant-numeric: tabular-nums; }

+ 1 - 2
src/components/kf-toast.js

@@ -47,8 +47,7 @@ export class KfToast extends LitElement {
       transition: transform 200ms cubic-bezier(0.2, 0, 0, 1), opacity 200ms cubic-bezier(0.2, 0, 0, 1); }
     :host([open]) { opacity: 1; transform: translate(-50%, 0); pointer-events: auto; }
     .t { display: flex; align-items: center; gap: 10px; padding: 10px 16px; border-radius: var(--r-md);
-      background: rgba(20, 32, 60, 0.92); color: #fff; font-size: 13px; box-shadow: var(--shadow-3);
-      -webkit-backdrop-filter: blur(18px); backdrop-filter: blur(18px); }
+      background: var(--kf-ink); color: #fff; font-size: 14px; box-shadow: var(--elev-3); }
     .dot { width: 8px; height: 8px; border-radius: 50%; background: #5ee0a0; }
     :host([kind="warn"]) .dot { background: #ffd166; }
     :host([kind="err"]) .dot { background: #ff7b72; }

+ 4 - 21
src/layout/kf-app.js

@@ -430,31 +430,14 @@ export class KfApp extends SignalWatcher(LitElement) {
     /* 宿主背景必须透明:子元素的 backdrop-filter 只看得见宿主「自己的盒子背景/边框」,
        看不见宿主的 ::before。宿主一旦有不透明底,玻璃背后就永远是纯色(v7 的坑)。 */
     :host { display: block; min-height: 100vh; position: relative; isolation: isolate; background: transparent; }
-    /* 背景光场:fixed 画布(滚动时光场不动,像窗外真实的光)+ 四团色斑。
-       色斑本身就用大半径径向渐变「软」出来,不再套 filter: blur —— 一层带模糊的 fixed 图层
-       会让整页贴满 backdrop 的玻璃重新采样,又贵又糊。光场够软,模糊留给玻璃自己做。 */
+    /* 背景(v15):中性灰白的平底,左上角一缕极淡的白光。
+       不再用彩色光斑 —— 卡片改成实底后,玻璃背后的色斑只剩「页面上乱飘的色块」,而且没东西可糊了。 */
     :host::before { content: ""; position: fixed; inset: 0; z-index: 0; pointer-events: none;
       background:
-        radial-gradient(30% 26% at 6% 2%, rgba(44, 92, 230, 0.62), transparent 70%),
-        radial-gradient(28% 24% at 76% 4%, rgba(118, 64, 236, 0.62), transparent 70%),
-        radial-gradient(36% 30% at 34% 104%, rgba(16, 170, 146, 0.5), transparent 72%),
-        radial-gradient(20% 18% at 84% 66%, rgba(232, 118, 36, 0.3), transparent 66%),
-        radial-gradient(24% 20% at 100% 82%, rgba(226, 92, 150, 0.26), transparent 66%),
+        radial-gradient(52% 42% at 18% -6%, rgba(255, 255, 255, 0.85), transparent 70%),
         var(--kf-paper);
-      animation: kf-drift-a 64s ease-in-out infinite alternate;
     }
-    /* 右上角一团柔光和一条顶部斜光带:让顶栏 / 导航的玻璃有明暗变化可糊 */
-    :host::after { content: ""; position: fixed; inset: 0; z-index: 0; pointer-events: none;
-      background:
-        radial-gradient(20% 22% at 62% 44%, rgba(255, 255, 255, 0.25), transparent 72%),
-        linear-gradient(196deg, rgba(255, 255, 255, 0.22), rgba(255, 255, 255, 0) 22%);
-      animation: kf-drift-b 96s ease-in-out infinite alternate;
-    }
-    @keyframes kf-drift-a { from { transform: translate3d(-2%, -1%, 0); } to { transform: translate3d(2%, 3%, 0); } }
-    @keyframes kf-drift-b { from { transform: translate3d(1%, 2%, 0); } to { transform: translate3d(-2%, -2%, 0); } }
-    /* 关闭动效:动画本身(不只 0.01ms 的时长)一起关掉 —— prefers-reduced-motion 与 data-motion="off" 都走这条 */
-    @media (prefers-reduced-motion: reduce) { :host::before, :host::after { animation: none; } }
-    :host-context([data-motion="off"])::before, :host-context([data-motion="off"])::after { animation: none; }
+    :host::after { content: none; }
     .shell { position: relative; z-index: 1; display: grid; grid-template-columns: 232px minmax(0, 1fr); min-height: 100vh; }
     .nav { position: sticky; top: 0; height: 100vh; z-index: 5; min-width: 0; }
     .main { min-width: 0; display: flex; flex-direction: column; }

+ 4 - 5
src/layout/kf-nav.js

@@ -44,11 +44,10 @@ export class KfNav extends LitElement {
 
   static styles = css`
     :host { display: block; height: 100%; }
-    /* 大面板玻璃:和 chip 同档(.55 + blur 12),背后光场在动;背景 / 模糊 / 发丝边来自共享表 .kf-glass.is-panel */
-    /* 浮层(侧栏)保留玻璃:.58 白面 + blur(28px) saturate(180%) —— 板块六「浮层保留、内容卡减薄」 */
+    /* 侧栏(v15):实底白 + 右侧 1px 发丝线。不做玻璃 —— 它常驻首屏,稳定比「透」重要。 */
     .side { height: 100%; box-sizing: border-box; display: flex; flex-direction: column; padding: 20px 12px 16px;
-      --kf-glass-alpha: rgba(255, 255, 255, 0.58); --kf-glass-blur: 28px; --kf-glass-sat: 180%;
-      border-radius: 0 var(--kf-radius-lg) var(--kf-radius-lg) 0; border-left: 0; }
+      background: var(--kf-surface); border: 1px solid var(--kf-line-soft); border-left: 0; border-top: 0; border-bottom: 0;
+      border-radius: 0 var(--r-md) 0 0; }
     .brand { display: flex; gap: 12px; align-items: center; padding: 4px 8px 18px; }
     /* 品牌块:v10 收成一块实色强调色(过去是四色 conic 渐变 + 彩色投影,过饱和) */
     .mark { width: 40px; height: 40px; border-radius: var(--r-md); display: grid; place-items: center; color: #fff; font-weight: 600; font-size: 20px;
@@ -126,7 +125,7 @@ export class KfNav extends LitElement {
       return n ? html`<span class="badge ${cls} ${it.badge === 'stuck' ? 'danger' : ''}" title=${it.badge === 'stuck' ? '卡住的人' : '池中卡片'} data-count=${it.badge}>${n}</span>` : '';
     };
     return html`
-      <aside class="side kf-glass is-panel" aria-label="主导航">
+      <aside class="side" aria-label="主导航">
         <div class="brand">
           <span class="mark" aria-hidden="true">康</span>
           <div><div class="name">产品创新看板</div><div class="sub">${t('研发中心 · AI 实战营')}</div></div>

+ 5 - 5
src/layout/kf-topbar.js

@@ -37,8 +37,8 @@ export class KfTopbar extends LitElement {
 
   static styles = css`
     :host { display: block; position: sticky; top: 0; z-index: 4; }
-    /* 顶栏 = 上层玻璃:.72 + blur(32px),比内容卡实一档 */
-    .bar { display: flex; align-items: center; gap: 14px; padding: 12px 28px; --kf-glass-alpha: rgba(255, 255, 255, 0.66); --kf-glass-blur: 24px; --kf-glass-sat: 180%; border-radius: 0 0 var(--kf-radius-lg) var(--kf-radius-lg); border-top: 0; }
+    /* 顶栏(v15):实底白 + 下缘 1px 发丝线。sticky 浮在内容之上,给与卡片一致的实底,不用玻璃。 */
+    .bar { display: flex; align-items: center; gap: 14px; padding: 12px 28px; background: var(--kf-surface); border: 1px solid var(--kf-line-soft); border-top: 0; border-radius: 0 0 var(--r-md) var(--r-md); }
     .t { min-width: 0; flex: 1; }
     h1 { margin: 0; font-size: 20px; font-weight: 600; color: var(--kf-ink); letter-spacing: -0.01em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-box-trim: trim-both; text-box-edge: cap alphabetic; }
     .s { font-size: 11px; color: var(--kf-ink-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@@ -49,7 +49,7 @@ export class KfTopbar extends LitElement {
     .sync .dot { width: 7px; height: 7px; border-radius: 50%; background: #2e7d5b; }
     .sync.warn .dot { background: #b27a00; }
     .sync.err .dot { background: var(--kf-s); }
-    .me { display: flex; align-items: center; gap: 8px; padding: 2px 2px 2px 12px; border-radius: var(--r-sm); border: 1px solid transparent; background: linear-gradient(var(--kf-glass-chip), var(--kf-glass-chip)) padding-box, var(--kf-edge-chip) border-box; box-shadow: var(--kf-shadow-chip); }
+    .me { display: flex; align-items: center; gap: 8px; padding: 2px 2px 2px 12px; border-radius: var(--r-sm); border: 1px solid var(--kf-line-soft); background: var(--kf-surface-btn); }
     .me label { font-size: 11px; color: var(--kf-ink-3); }
     select { height: 28px; border-radius: var(--r-sm); border: 0; background: transparent; font: 600 13px var(--kf-font); color: var(--kf-ink); padding: 0 8px 0 2px; cursor: pointer; }
     .who { width: 28px; height: 28px; border-radius: 50%; display: grid; place-items: center; font-size: 11px; font-weight: 600; color: #fff;
@@ -67,7 +67,7 @@ export class KfTopbar extends LitElement {
       .me label { display: none; }
       .who { width: 32px; height: 32px; font-size: 13px; margin-left: -8px; }
       select { height: 44px; min-width: 44px; font-size: 14px; font-weight: 600; max-width: 128px; }
-      .me:active { background: linear-gradient(var(--kf-glass-chip-hover), var(--kf-glass-chip-hover)) padding-box, var(--kf-edge-chip) border-box; }
+      .me:active { background: var(--kf-surface-btn); }
       button.refresh { height: 44px; min-width: 44px; padding: 0 14px; font-size: 14px; border-radius: var(--r-sm); }
     }
   `;
@@ -85,7 +85,7 @@ export class KfTopbar extends LitElement {
   render() {
     const initials = this.me ? Array.from(this.me).slice(-1).join('') : '?';
     return html`
-      <header class="bar kf-glass is-overlay">
+      <header class="bar">
         <div class="t"><h1>${this.title}</h1>${this.sub ? html`<div class="s">${this.sub}</div>` : ''}</div>
         <div class="acts"><slot name="actions"></slot></div>
         <div class="sync ${this.status === 'error' ? 'err' : this.status === 'loading' ? 'warn' : ''}" role="status">

+ 4 - 4
src/pages/card-toolbar.js

@@ -24,7 +24,7 @@ export const TOOLBAR_CSS = css`
   .tb .kf-chip.on .n { opacity: 0.9; }
   .dd { position: relative; }
   .dd > summary { list-style: none; cursor: pointer; display: inline-flex; align-items: center; gap: 4px; box-sizing: border-box; height: 28px; padding: 0 10px;
-    border-radius: var(--r-sm); border: 1px solid rgba(255, 255, 255, 0.14); background: transparent; font: 500 12px/1 var(--kf-font); color: var(--kf-ink-2);
+    border-radius: var(--r-sm); border: 1px solid var(--kf-line-soft); background: var(--kf-surface); font: 500 12px/1 var(--kf-font); color: var(--kf-ink-2);
     transition: background var(--kf-dur) var(--kf-ease), border-color var(--kf-dur) var(--kf-ease), color var(--kf-dur) var(--kf-ease); }
   .dd > summary:hover { background: rgba(255, 255, 255, 0.55); border-color: rgba(255, 255, 255, 0.55); color: var(--kf-ink); }
   /* 手机「排序:最新」折叠行的悬停(之前只有 active 态,真实鼠标悬停时没有任何反馈) */
@@ -34,7 +34,7 @@ export const TOOLBAR_CSS = css`
   /* 下拉面板 = 上层玻璃(.72 + blur 32),和卡片拉开层次 */
   .dd .panel { position: absolute; z-index: 20; top: calc(100% + 4px); left: 0; min-width: 176px; padding: 4px; display: grid; gap: 2px;
     border-radius: var(--kf-radius-sm); border: 1px solid transparent;
-    background: linear-gradient(var(--kf-glass-top), var(--kf-glass-top)) padding-box, var(--kf-edge) border-box;
+    background: var(--kf-surface);
     -webkit-backdrop-filter: blur(var(--kf-blur-top)) saturate(var(--kf-sat-top)); backdrop-filter: blur(var(--kf-blur-top)) saturate(var(--kf-sat-top));
     box-shadow: var(--kf-shadow-pop); }
   .dd .opt { all: unset; box-sizing: border-box; display: flex; align-items: center; gap: 8px; padding: 6px 8px; border-radius: var(--r-sm);
@@ -67,9 +67,9 @@ export const TOOLBAR_CSS = css`
     .mbar .cnt b { font-weight: 600; }
     .fbtn { all: revert; box-sizing: border-box; display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 14px; border-radius: var(--r-md); cursor: pointer;
       font: 600 14px var(--kf-font); color: var(--kf-ink); border: 1px solid transparent; flex: none;
-      background: linear-gradient(var(--kf-glass-chip), var(--kf-glass-chip)) padding-box, var(--kf-edge-chip) border-box; box-shadow: var(--kf-shadow-chip);
+      background: var(--kf-surface); box-shadow: var(--kf-shadow-chip);
       -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px); transition: transform 90ms var(--kf-ease); }
-    .fbtn:active { transform: scale(0.985); background: linear-gradient(rgba(255,255,255,0.75), rgba(255,255,255,0.75)) padding-box, var(--kf-edge-chip) border-box; }
+    .fbtn:active { transform: scale(0.985); background: var(--kf-surface-btn); }
     .fbtn.on { border-color: var(--kf-accent); box-shadow: inset 0 0 0 1px var(--kf-accent); }
     .fbtn .nb { min-width: 20px; height: 20px; padding: 0 6px; border-radius: 999px; display: grid; place-items: center; font: 500 11px var(--kf-font-num); color: #fff; background: var(--kf-accent); font-variant-numeric: tabular-nums; }
     .seg2.m { display: inline-flex; margin-left: auto; height: 44px; border-radius: var(--r-md); flex: none; }

+ 2 - 3
src/pages/filter-sheet.js

@@ -135,8 +135,7 @@ export class KfFilterSheet extends LitElement {
     .sheet { position: absolute; left: 0; right: 0; bottom: 0; max-height: 88vh; display: flex; flex-direction: column;
       transform: translateY(var(--sheet-dy, 0px)); box-sizing: border-box;
       border-radius: var(--r-md) var(--r-md) 0 0; border: 1px solid transparent; border-bottom: 0;
-      background: linear-gradient(rgba(255, 255, 255, 0.78), rgba(255, 255, 255, 0.78)) padding-box,
-        linear-gradient(135deg, rgba(255,255,255,0.95), rgba(255,255,255,0.2) 40%, rgba(10,20,40,0.08)) border-box;
+      background: var(--kf-surface); box-shadow: var(--elev-3);
       -webkit-backdrop-filter: blur(32px) saturate(190%); backdrop-filter: blur(32px) saturate(190%);
       box-shadow: var(--kf-shadow-tabbar);   /* = elev-3 的上下镜像(贴着视口底边才看见的那一档) */
       animation: rise 240ms var(--kf-ease); transition: transform 120ms var(--kf-ease); outline: none;
@@ -174,7 +173,7 @@ export class KfFilterSheet extends LitElement {
     .sw { width: 10px; height: 10px; border-radius: 3px; flex: none; }
     .sw.t-blue { background: var(--kf-s1); } .sw.t-violet { background: var(--kf-s2); } .sw.t-teal { background: var(--kf-s3); }
     .sw.t-amber { background: var(--kf-s4); } .sw.t-rose { background: var(--kf-s5); }
-    .ft { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: 8px; padding: 12px 16px; border-top: 1px solid var(--kf-line); background: rgba(255, 255, 255, 0.4); }
+    .ft { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: 8px; padding: 12px 16px; border-top: 1px solid var(--kf-line); background: var(--kf-surface); }
     .ft .kf-btn { height: 48px; font-size: 14px; font-weight: 600; border-radius: var(--r-md); }
     .ft .kf-btn[disabled] { opacity: 0.45; }
     .ft .go { font-variant-numeric: tabular-nums; }

+ 1 - 1
src/pages/shared.js

@@ -42,7 +42,7 @@ export const VIEW_CSS = css`
      区块标题(.p-sec)与它下面内容之间 12;区块与区块之间 48。 */
   .p-head { display: flex; align-items: flex-end; gap: var(--kf-space-card); padding: var(--kf-space-card) 0; }
   .p-head h2 { margin: 0; font-size: 20px; line-height: var(--lh-title); font-weight: 600; color: var(--kf-ink); letter-spacing: var(--ls-cn-display); }
-  .p-head p { margin: 4px 0 0; font-size: 13px; line-height: 1.6; color: var(--kf-ink-3); max-width: 48em; }
+  .p-head p { margin: 4px 0 0; font-size: 14px; line-height: 1.6; color: var(--kf-ink-3); max-width: 48em; }
   .p-actions { margin-left: auto; display: flex; gap: var(--kf-space-in); flex-wrap: wrap; align-items: center; }
   .p-sec { display: flex; align-items: baseline; gap: var(--kf-space-in); margin: var(--kf-space-section) 0 var(--kf-space-in); min-height: 28px; }
   .p-sec h3 { font-size: 16px; line-height: var(--lh-title); font-weight: 600; color: var(--kf-ink); letter-spacing: var(--ls-cn-display); }

+ 1 - 1
src/pages/view-ledger.js

@@ -120,7 +120,7 @@ export class ViewLedger extends LitElement {
       .mledger { display: grid; gap: 8px; }
       .mledger li { display: grid; gap: 6px; padding: 12px 14px; min-height: 64px; border-radius: var(--r-md); cursor: pointer;
         border: 1px solid transparent;
-        background: linear-gradient(rgba(255, 255, 255, 0.62), rgba(255, 255, 255, 0.62)) padding-box, var(--kf-edge) border-box;
+        background: var(--kf-surface); border: 1px solid var(--kf-line-soft);
         -webkit-backdrop-filter: blur(24px) saturate(180%); backdrop-filter: blur(24px) saturate(180%); box-shadow: var(--kf-shadow); }
       .mledger li:active { transform: scale(0.985); transition: transform 80ms cubic-bezier(0.4, 0, 0.2, 1); }
       .mledger .t { font-size: 14px; font-weight: 600; line-height: 1.4; color: var(--kf-ink); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }

+ 1 - 1
src/pages/view-members.js

@@ -40,7 +40,7 @@ export class ViewMembers extends LitElement {
       padding: 8px 12px; border-radius: var(--r-sm); font-size: 13px; line-height: 1.5; color: var(--kf-ink-2);
       font-variant-numeric: tabular-nums; transition: background var(--kf-dur) var(--kf-ease); }
     .list li + li { border-top: 1px solid var(--kf-line); }
-    .list li:not(.head):hover { background: rgba(255,255,255,0.45); }
+    .list li:not(.head):hover { background: var(--kf-surface-btn); }
     .list li.head { box-shadow: none; color: var(--kf-ink-3); font-size: 11px; letter-spacing: var(--ls-cn-small); font-weight: 600; padding: 0 12px 8px; border-bottom: 1px solid var(--kf-line); border-radius: 0; }
     .av { width: 28px; height: 28px; border-radius: 50%; display: grid; place-items: center; font-weight: 600; font-size: 11px; color: #fff; background: linear-gradient(135deg, var(--kf-s1), var(--kf-s2)); }
     .nm { font-weight: 600; color: var(--kf-ink); }

+ 7 - 7
src/pages/view-pool.js

@@ -88,9 +88,9 @@ export class ViewPool extends LitElement {
     }
     /* 搜索框:与排序段同高(28px)、同圆角;聚焦时 2px 焦点环由共享表给 */
     .frow.toolbar input[type="search"] { appearance: none; -webkit-appearance: none; height: 28px; box-sizing: border-box; padding: 0 10px;
-      border-radius: var(--r-sm); border: 1px solid rgba(255, 255, 255, 0.14); background: rgba(255, 255, 255, 0.5); color: var(--kf-ink);
+      border-radius: var(--r-sm); border: 1px solid var(--kf-line-soft); background: var(--kf-surface); color: var(--kf-ink);
       font: 400 12px/1 var(--kf-font); min-width: 240px; margin-left: auto; transition: background var(--kf-dur) var(--kf-ease), border-color var(--kf-dur) var(--kf-ease); }
-    .frow.toolbar input[type="search"]:hover { background: rgba(255, 255, 255, 0.66); }
+    .frow.toolbar input[type="search"]:hover { background: var(--kf-surface-btn); }
     .frow.toolbar input[type="search"]:focus { outline: none; border-color: var(--kf-focus); box-shadow: 0 0 0 2px rgba(91, 91, 214, 0.22); background: rgba(255,255,255,0.85); }
     .sfield { margin-left: auto; display: flex; }
     /* 排序行末尾的收尾(v13 三):形态(display / gap / 内衬 / 上边线 / 字体 / 字色)直接由 CARD_CSS 的 .cfoot 给,
@@ -109,14 +109,14 @@ export class ViewPool extends LitElement {
     .pbar { display: none; }
     @media (max-width: 767px) {
       .pbar { display: grid; grid-template-columns: 96px minmax(0, 1fr); grid-template-areas: "f m" "s s"; gap: 8px; padding: 8px; margin-bottom: 12px; border-radius: var(--r-md); align-items: center; }
-      .pbar-btn { grid-area: f; appearance: none; -webkit-appearance: none; box-sizing: border-box; width: 100%; height: 44px; padding: 0; margin: 0; border: 1px solid rgba(255, 255, 255, 0.14); border-radius: var(--r-sm); cursor: pointer;
-        background: rgba(255, 255, 255, 0.72); color: var(--kf-ink);
+      .pbar-btn { grid-area: f; appearance: none; -webkit-appearance: none; box-sizing: border-box; width: 100%; height: 44px; padding: 0; margin: 0; border: 1px solid var(--kf-line-soft); border-radius: var(--r-sm); cursor: pointer;
+        background: var(--kf-surface); color: var(--kf-ink);
         display: grid; grid-auto-flow: column; justify-content: center; align-items: center; gap: 4px; font: 600 16px/1 var(--kf-font); letter-spacing: var(--ls-cn-small); }
-      .pbar input[type="search"] { grid-area: m; appearance: none; -webkit-appearance: none; min-width: 0; width: 100%; height: 44px; padding: 0 12px; border-radius: var(--r-sm); border: 1px solid rgba(255, 255, 255, 0.14); font: 400 14px var(--kf-font); background: rgba(255, 255, 255, 0.5); }
-      .pbar-more { grid-area: s; border-radius: var(--r-sm); background: rgba(255, 255, 255, 0.32); }
+      .pbar input[type="search"] { grid-area: m; appearance: none; -webkit-appearance: none; min-width: 0; width: 100%; height: 44px; padding: 0 12px; border-radius: var(--r-sm); border: 1px solid var(--kf-line-soft); font: 400 14px var(--kf-font); background: var(--kf-surface); }
+      .pbar-more { grid-area: s; border-radius: var(--r-sm); background: var(--kf-surface-btn); }
       .pbar-more > summary { display: flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 12px; font: 600 14px var(--kf-font); color: var(--kf-ink-2); cursor: pointer; }
       .pbar-sorts { display: flex; gap: 0; padding: 0 8px 8px; }
-      .pbar-sorts button { appearance: none; -webkit-appearance: none; border: 1px solid rgba(255, 255, 255, 0.14); border-left-width: 0; margin: 0; box-sizing: border-box; flex: 1; height: 44px; display: grid; place-items: center; border-radius: 0; font: 500 13px var(--kf-font); color: var(--kf-ink-2); background: rgba(255, 255, 255, 0.45); cursor: pointer; }
+      .pbar-sorts button { appearance: none; -webkit-appearance: none; border: 1px solid var(--kf-line-soft); border-left-width: 0; margin: 0; box-sizing: border-box; flex: 1; height: 44px; display: grid; place-items: center; border-radius: 0; font: 500 13px var(--kf-font); color: var(--kf-ink-2); background: var(--kf-surface); cursor: pointer; }
       .pbar-sorts button:first-child { border-left-width: 1px; border-top-left-radius: var(--r-sm); border-bottom-left-radius: var(--r-sm); }
       .pbar-sorts button:last-child { border-top-right-radius: var(--r-sm); border-bottom-right-radius: var(--r-sm); }
       .pbar-sorts button[aria-pressed="true"] { background: rgba(0, 0, 0, 0.06); color: var(--kf-ink); border-color: rgba(0, 0, 0, 0.10); }

+ 6 - 7
src/pages/view-report-type.js

@@ -50,9 +50,9 @@ export class ViewReportType extends LitElement {
     /* 类型切换 = 点缀层 chip(.55 + blur 12);当前项反白实底 */
     .tabs a { display: inline-flex; align-items: center; gap: 8px; height: 32px; padding: 0 12px; border-radius: var(--r-sm); text-decoration: none;
       font-size: 13px; line-height: 1; font-weight: 500; color: var(--kf-ink-2); border: 1px solid transparent;
-      background: linear-gradient(var(--kf-glass-chip), var(--kf-glass-chip)) padding-box, var(--kf-edge-chip) border-box;
+      background: var(--kf-surface);
       box-shadow: var(--kf-shadow-chip); transition: var(--kf-t); }
-    .tabs a:hover { background: linear-gradient(var(--kf-glass-chip-hover), var(--kf-glass-chip-hover)) padding-box, var(--kf-edge-chip-hover) border-box; }
+    .tabs a:hover { background: var(--kf-surface-btn); }
     .tabs a.back { width: 32px; padding: 0; justify-content: center; }
     .tabs a[aria-current="page"] { background: var(--gray-12); color: #fff; border-color: var(--gray-12); box-shadow: var(--shadow-1); }
     .tabs a .n { font: 500 11px/1 var(--kf-font-num); color: var(--kf-ink-3); font-variant-numeric: tabular-nums; }
@@ -65,8 +65,7 @@ export class ViewReportType extends LitElement {
     .kpis { margin-left: auto; display: flex; gap: 8px; }
     /* 数据卡 = 内容卡同一层玻璃(v11 板块六:.72 + 1px 描边走阴影 + blur(8px)) */
     .kpi { min-width: 112px; padding: 8px 12px; border-radius: var(--kf-radius-sm); display: grid; grid-template-columns: auto 1fr; grid-template-rows: auto auto; gap: 6px 10px; align-items: end;
-      background: var(--kf-glass-card); -webkit-backdrop-filter: blur(var(--kf-glass-card-blur)); backdrop-filter: blur(var(--kf-glass-card-blur));
-      box-shadow: var(--kf-glass-card-shadow); }
+      background: var(--kf-surface); border: 1px solid var(--kf-line-soft); }
     .kpi .ic { grid-row: span 2; width: 28px; height: 28px; border-radius: var(--r-sm); display: grid; place-items: center; color: var(--kf-accent-ink); background: rgba(91, 91, 214, 0.10); }
     .kpi b { font-size: 32px; font-weight: 600; line-height: 1; letter-spacing: var(--ls-cn-display); color: var(--gray-12); font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1;
       display: block; height: max-content; text-box-trim: trim-both; text-box-edge: cap alphabetic; }   /* v11b:flex 容器不修剪,见工作台同处注释 */
@@ -97,9 +96,9 @@ export class ViewReportType extends LitElement {
     .pager { display: flex; align-items: center; justify-content: center; gap: 4px; margin: 24px 0 8px; flex-wrap: wrap; }
     .pager button { all: unset; cursor: pointer; min-width: 32px; height: 32px; padding: 0 8px; display: grid; place-items: center; border-radius: var(--r-sm);
       border: 1px solid transparent;
-      background: linear-gradient(var(--kf-glass-chip), var(--kf-glass-chip)) padding-box, var(--kf-edge-chip) border-box;
+      background: var(--kf-surface);
       font: 600 13px var(--kf-font-num); color: var(--kf-ink-2); font-variant-numeric: tabular-nums; transition: var(--kf-t); }
-    .pager button:hover { background: linear-gradient(var(--kf-glass-chip-hover), var(--kf-glass-chip-hover)) padding-box, var(--kf-edge-chip-hover) border-box; }
+    .pager button:hover { background: var(--kf-surface-btn); }
     .pager button[aria-current="page"] { background: var(--kf-ink); color: #fff; border-color: var(--kf-ink); }
     .pager button[disabled] { opacity: 0.35; cursor: default; }
     .pager .sz { margin-left: 8px; font: 500 11px var(--kf-font-num); color: var(--kf-ink-3); font-variant-numeric: tabular-nums; }
@@ -119,7 +118,7 @@ export class ViewReportType extends LitElement {
       .head .ico { width: 36px; height: 36px; border-radius: var(--r-md); }
       .head h2 { font-size: 16px; font-weight: 600; }
       .kpis { margin-left: 0; width: 100%; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0; padding: 8px 0;
-        border-radius: var(--r-md); background: linear-gradient(var(--kf-glass-mid), var(--kf-glass-mid)) padding-box, var(--kf-edge) border-box; border: 1px solid transparent;
+        border-radius: var(--r-md); background: var(--kf-surface); border: 1px solid transparent;
         -webkit-backdrop-filter: blur(24px) saturate(180%); backdrop-filter: blur(24px) saturate(180%); box-shadow: none; }
       .kpi { min-width: 0; padding: 0 4px 0 12px; display: grid; grid-template-columns: 1fr; gap: 0; border-left: 1px solid var(--kf-line); border-radius: 0; background: none; border: 0; box-shadow: none; backdrop-filter: none; -webkit-backdrop-filter: none; }
       .kpi:first-child { border-left: 0; }

+ 1 - 1
src/pages/view-report.js

@@ -78,7 +78,7 @@ export class ViewReport extends LitElement {
     .exec li::before { counter-increment: e; content: counter(e, decimal-leading-zero); font-family: var(--kf-font-num); font-size: 11px; color: var(--kf-accent-ink); padding-top: 4px; }
     /* 章节目录 = 上层玻璃(.72 + blur 32),和正文卡片拉开层次 */
     .toc { position: sticky; top: 72px; z-index: 6; display: flex; gap: 4px; overflow-x: auto; padding: 6px; margin: 0 0 16px;
-      border-radius: var(--kf-radius); }
+      border-radius: var(--kf-radius); background: var(--kf-surface); border: 1px solid var(--kf-line-soft); }
     .dgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 8px; margin-top: 8px; }
     a.d { display: grid; grid-template-columns: 32px minmax(0,1fr); gap: 2px 8px; padding: 12px; border-radius: var(--r-sm); text-decoration: none;
       background: rgba(255,255,255,0.4); border: 1px solid var(--kf-line); color: inherit; transition: var(--kf-t); }

+ 2 - 2
src/pages/view-reports.js

@@ -97,9 +97,9 @@ export class ViewReports extends LitElement {
     .pager { display: flex; align-items: center; justify-content: center; gap: 4px; margin: 24px 0 8px; }
     .pager button { all: unset; cursor: pointer; min-width: 32px; height: 32px; padding: 0 8px; display: grid; place-items: center; border-radius: var(--r-md);
       border: 1px solid transparent;
-      background: linear-gradient(var(--kf-glass-chip), var(--kf-glass-chip)) padding-box, var(--kf-edge-chip) border-box;
+      background: var(--kf-surface);
       font-size: 13px; font-weight: 500; color: var(--kf-ink-2); font-variant-numeric: tabular-nums; transition: var(--kf-t); }
-    .pager button:hover { background: linear-gradient(var(--kf-glass-chip-hover), var(--kf-glass-chip-hover)) padding-box, var(--kf-edge-chip-hover) border-box; }
+    .pager button:hover { background: var(--kf-surface-btn); }
     .pager button[aria-current="page"] { background: var(--kf-accent); color: #fff; border-color: var(--kf-accent); }
     .pager button[disabled] { opacity: 0.35; cursor: default; }
     .pager .sz { margin-left: 8px; font-size: 11px; font-weight: 500; letter-spacing: var(--ls-cn-small); color: var(--kf-ink-3); font-variant-numeric: tabular-nums; }

+ 89 - 34
src/pages/view-workbench.js

@@ -98,17 +98,28 @@ export class ViewWorkbench extends LitElement {
     .stg .b.blue { background: var(--kf-s1); } .stg .b.violet { background: var(--kf-s2); } .stg .b.teal { background: var(--kf-s3); }
     .stg .b.amber { background: var(--kf-s4); } .stg .b.rose { background: var(--kf-s5); }
     .stg .n { justify-self: end; font-size: 20px; font-weight: 600; line-height: 1; letter-spacing: var(--ls-cn-display); color: var(--gray-12); font-variant-numeric: tabular-nums; }
+    .stg .sf { grid-column: 1 / -1; font-size: 12px; line-height: 1.3; color: var(--kf-ink-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
     .stg .f { grid-column: 1 / -1; height: 4px; border-radius: 2px; background: rgba(16, 24, 40, 0.07); overflow: hidden; margin-top: 4px; }
     .stg .f i { display: block; height: 100%; border-radius: 2px; background: currentColor; width: calc(var(--v) * 100%); }
     .stg.blue { color: var(--kf-s1); } .stg.violet { color: var(--kf-s2); } .stg.teal { color: var(--kf-s3); } .stg.amber { color: var(--kf-s4); } .stg.rose { color: var(--kf-s5); }
     .stg.todo { color: var(--kf-ink-3); background: transparent; border-style: dashed; border-color: color-mix(in srgb, var(--kf-ink-3) 22%, transparent); }
     .stg.todo .n { color: var(--kf-ink-3); font-weight: 500; }
-    /* 待评分:只有这几行时 A 卡会矮一截,min-height 让 A 在有卡住的人时仍撑得起来 */
-    .pending { display: grid; gap: 0; }
+    /* A 卡下半:待评分(左)| 卡池进度(右)。两个分区头共用 .lbl,行底对齐 12 */
+    .me-split { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); gap: 32px; }
+    .me-split > div { min-width: 0; }
+    .me-split .lbl { min-height: 22px; }
+    .pending { display: grid; gap: 0; margin-top: 4px; }
     .pending li { display: flex; align-items: baseline; gap: 8px; min-height: 32px; font-size: 14px; }
     .pending li a { color: var(--kf-ink); text-decoration: none; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
     .pending li a:hover { color: var(--kf-accent-ink); }
     .pending li .s { margin-left: auto; font-weight: 600; color: var(--kf-accent-ink); font-variant-numeric: tabular-nums; }
+    .me-none { font-size: 14px; color: var(--kf-ink-3); padding-top: 10px; }
+    .prog { display: grid; gap: 0; margin-top: 4px; }
+    .prog li { display: grid; grid-template-columns: 6px auto 1fr auto; align-items: baseline; gap: 10px; min-height: 32px; font-size: 14px; }
+    .prog .pk { color: var(--kf-ink-2); }
+    .prog .pv { color: var(--kf-ink); font-variant-numeric: tabular-nums; }
+    .prog .pv b { font-weight: 600; }
+    .prog .pp { color: var(--kf-ink-3); font-size: 12px; font-variant-numeric: tabular-nums; }
 
     /* ---------- B 卡:现场(深色) ---------- */
     .live { display: grid; gap: var(--kf-space-in); height: 100%; align-content: start;
@@ -142,16 +153,21 @@ export class ViewWorkbench extends LitElement {
       white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-height: 18px; }
 
     /* ---------- F:最近动过(通栏) ---------- */
-    .feed { display: grid; gap: 0; }
-    .feed li { display: flex; align-items: baseline; gap: 12px; min-height: 44px; padding: 10px 0; border-top: 1px solid var(--kf-line); font-size: 14px; }
-    .feed li:first-child { border-top: 0; padding-top: 0; }
-    .feed li a { color: var(--kf-ink); font-weight: 500; text-decoration: none; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
-    .feed li a:hover { color: var(--kf-accent-ink); }
-    .feed .st { font-size: 12px; color: var(--kf-ink-3); flex: none; }
-    .feed .tm { margin-left: auto; font-size: 12px; color: var(--kf-ink-3); font-variant-numeric: tabular-nums; flex: none; }
-    .feed-head { display: flex; align-items: center; gap: 8px; }
+    /* 分区标签:三个区块共用同一种「12px 灰小标 + 右侧箭头」,整页只有一种小标题样式 */
+    .feed-head { display: flex; align-items: center; gap: 8px; min-height: 22px; }
     .feed-head .go { margin-left: auto; }
-    .feed-empty { font-size: 14px; color: var(--kf-ink-3); padding: 8px 0; }
+    /* 行:左标题 / 中阶段 / 右时间。网格而不是 flex —— 中间那列 auto 宽,右边永远贴右 */
+    .feed { display: grid; margin-top: 8px; }
+    .feed li { display: grid; grid-template-columns: minmax(0, 1fr) auto 64px; align-items: baseline; gap: 16px; padding: 11px 0; border-top: 1px solid var(--kf-line); font-size: 14px; }
+    .feed li:first-child { border-top: 0; padding-top: 4px; }
+    .feed li:last-child { padding-bottom: 4px; border-bottom: 0; }
+    .feed li:last-child a { font-weight: 500; }
+    .feed-more { display: inline-flex; align-items: center; gap: 4px; margin-top: 6px; font-size: 14px; }
+    .feed li a { color: var(--kf-ink); font-weight: 500; text-decoration: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
+    .feed li a:hover { color: var(--kf-accent-ink); }
+    .feed .st { font-size: 12px; color: var(--kf-ink-3); white-space: nowrap; }
+    .feed .tm { font-size: 12px; color: var(--kf-ink-3); font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }
+    .feed-empty { font-size: 14px; color: var(--kf-ink-3); padding: 8px 0 0; }
     .foot-links { display: none; }
 
     /* 平板:A/B 变 7/5 太挤,直接上下堆;C/D/E 保持一行 */
@@ -161,24 +177,39 @@ export class ViewWorkbench extends LitElement {
     }
     /* 手机 393:A/B 竖排,C/D/E 三卡一行(每卡 3 行文字仍放得下),可点区域 44px */
     @media (max-width: 767px) {
-      .bento { gap: var(--kf-space-card); margin-top: var(--kf-space-card); }
+      .bento { gap: var(--kf-space-card); margin-top: 24px; }
+      .p-head + .bento { margin-top: 24px; }
       .bento > .row { gap: var(--kf-space-card); }
-      .bento > .row.cde { grid-template-columns: repeat(3, minmax(0, 1fr)); }
-      .stagebar { grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 6px; }
-      .stg { padding: 8px 6px; grid-template-columns: auto; gap: 4px; justify-items: start; }
-      .stg .n { justify-self: start; font-size: 16px; }
-      .me-nums { margin-left: 0; width: 100%; justify-content: space-between; gap: 12px; }
-      .me-nums div { text-align: left; }
-      .stat b { font-size: 24px; }
+      .bento > .row.cde { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
+      .me { gap: 12px; }
+      .me-id h3, .me-id .sub { display: inline; }
+      .me-id > div { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
+      .me-nums { margin-left: 0; width: 100%; justify-content: flex-start; gap: 24px; }
+      .me-nums div { text-align: left; display: flex; align-items: baseline; gap: 4px; }
+      /* 五阶段一行放不下英文名:两行三列(第五格占满第二行左半),英文名折行两行后省略 */
+      .stagebar { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
+      .stg { padding: 10px; }
+      .stg .sf { white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; line-height: 1.35; }
+      .me-split { grid-template-columns: minmax(0, 1fr); gap: 12px; }
+      .prog li { min-height: 32px; }
+      .stat { gap: 6px; }
+      .stat b { font-size: 20px; }
+      .stat b .u { font-size: 12px; }
+      .stat .top { min-height: 18px; }
       .stat .top .go { display: none; }
+      /* 手机上一律 14:说明文字在 393 宽下 12px 读不清;只是「文字」不换档,数字仍按档位 */
+      .me-none, .empty { font-size: 14px; }
       .btn-key { display: none; }
-      .feed li { flex-wrap: wrap; }
-      .feed li a { white-space: normal; flex: 1 1 100%; }
+      /* F:两行 —— 标题占满第一行,作者 / 时间在第二行两端 */
+      .feed li { grid-template-columns: minmax(0, 1fr) auto; row-gap: 2px; }
+      .feed li a { grid-column: 1 / -1; white-space: normal; }
       .go, .hd .go, .me-id .go { min-height: 44px; min-width: 44px; justify-content: center; }
+      .feed-more { min-height: 44px; align-items: center; }
       .pending li { min-height: 44px; }
+      .empty { font-size: 14px; }
       .foot-links { display: flex; gap: 8px; margin-top: var(--kf-space-card); }
       .foot-links a { display: inline-flex; align-items: center; gap: 6px; min-height: 44px; padding: 0 14px; border-radius: var(--r-md); font-size: 14px; font-weight: 600;
-        color: var(--kf-accent-ink); text-decoration: none; background: #fff; border: 1px solid rgba(0, 0, 0, 0.06); }
+        color: var(--kf-accent-ink); text-decoration: none; background: var(--kf-surface); border: 1px solid var(--kf-line-soft); }
     }
   `];
 
@@ -192,7 +223,7 @@ export class ViewWorkbench extends LitElement {
     return html`
       ${head('我的推进', '五阶段进度与现场状态', html`<a class="go" href=${href('/pool')} data-link>机会卡池 →</a>`)}
       <div class="bento">
-        <div class="row ab kf-enter" style="--i:0">
+        <div class="row ab grid2 kf-enter" style="--i:0">
           <kf-glass-card data-role="a">${this.#mine(me, pool, live)}</kf-glass-card>
           <kf-glass-card data-role="b" dark>${this.#live(live, pool)}</kf-glass-card>
         </div>
@@ -203,7 +234,7 @@ export class ViewWorkbench extends LitElement {
           <kf-glass-card data-role="e">${this.#stat('decided', pool)}</kf-glass-card>
         </div>
 
-        <kf-glass-card data-role="f" class="kf-enter" style="--i:2">${this.#feed(latest)}</kf-glass-card>
+        <kf-glass-card data-role="f" class="kf-enter" style="--i:2">${this.#feed(latest, pool)}</kf-glass-card>
       </div>
       ${cardFooter({ shown: latest.length, all: pool.total, filtered: false, label: '张机会卡,最近 3 张列在上方', onTop: () => window.scrollTo({ top: 0, behavior: 'smooth' }) })}
       <!-- 只有手机显示:证据台账从底部 Tab 移到工作台页脚(真实链接,部署前缀同源) -->
@@ -220,11 +251,16 @@ export class ViewWorkbench extends LitElement {
       return html`<div class="me" data-empty="no-me">
         <div class="me-id"><div class="avatar q">?</div>
           <div><h3>还没选「我是」</h3><span class="sub">先看全员:${live.memberCount} 人</span></div>
-          <a class="go" href=${href('/members')} data-link>${icon('user', 14)} 选我</a></div>
+          <a class="go" href=${href('/members')} data-link>${icon('user', 14)} ${t('选我')}</a></div>
+        <div class="me-nums">
+          <div><b>${live.memberCount}</b><span>人</span></div>
+          <div><b>${live.submittedPeople}</b><span>已交</span></div>
+        </div>
         <div class="stagebar" data-allstages>
           ${live.stages.map((r, i) => html`<div class="stg ${TONE[r.stage.code]}" style=${`--i:${i + 1}`} data-stage=${r.stage.code}>
             <span class="b ${TONE[r.stage.code]}">${r.stage.code}</span>
             <span class="n">${r.submitted || '—'}</span>
+            <span class="sf">${r.stage.name}</span>
             <span class="f" aria-hidden="true"><i style=${`--v:${(r.submitted / maxSub).toFixed(2)}`}></i></span></div>`)}
         </div>
         <div class="empty"><span>已交 ${live.submittedPeople} 人 · 选了自己,这里换成你的阶段进度与待办</span></div>
@@ -250,19 +286,37 @@ export class ViewWorkbench extends LitElement {
           return html`<div class="stg kf-enter ${TONE[s.code]} ${ok ? '' : 'todo'}" style=${`--i:${i + 1}`} data-stage=${s.code}>
             <span class="b ${TONE[s.code]}">${s.code}</span>
             <span class="n">${n || '—'}</span>
+            <span class="sf">${s.name}</span>
             <span class="f" aria-hidden="true"><i style=${`--v:${(n / max).toFixed(2)}`}></i></span></div>`;
         })}
       </div>
       ${me.count === 0 ? html`<div class="empty"><span>本月还没有你的成果</span>
         <a class="go" href=${href('/stages')} data-link>看五阶段产出 →</a></div>` : ''}
-      ${pending.length ? html`<div>
-        <div class="lbl">待评分 ${pending.length}</div>
-        <ul class="pending">${pending.slice(0, 3).map((o) => html`<li>
-          <a href=${href(`/pool/${o.id}`)} data-link>${o.title}</a><span class="s">${o.stats.avg != null ? Math.round(o.stats.avg) : '—'}</span></li>`)}</ul>
-      </div>` : ''}
+      <div class="me-split">
+        <div>
+          <div class="lbl">卡池进度</div>
+          ${this.#progress(pool)}
+        </div>
+        <div>
+          <div class="lbl">待评分${pending.length ? ` ${pending.length}` : ''}</div>
+          ${pending.length ? html`<ul class="pending">${pending.slice(0, 3).map((o) => html`<li>
+            <a href=${href(`/pool/${o.id}`)} data-link>${o.title}</a><span class="s">${o.stats.avg != null ? Math.round(o.stats.avg) : '—'}</span></li>`)}</ul>`
+            : html`<p class="me-none">没有等你评分的卡</p>`}
+        </div>
+      </div>
     </div>`;
   }
 
+  /** 卡池进度:候选 / 立项 / 否决 三段 + 百分比(状态用色点,不用整块色底) */
+  #progress(pool) {
+    const s = pool.byStatus;
+    const total = Math.max(1, pool.total);
+    const rows = [['候选', s.candidate, '#8A8A93'], ['已立项', s.approved, '#2F7D5B'], ['已否决', s.rejected, '#A1A1AA']];
+    return html`<ul class="prog">${rows.map(([k, v, c]) => html`<li>
+      <i class="dot" style=${`background:${c}`}></i><span class="pk">${k}</span>
+      <span class="pv"><b>${v}</b> 张</span><span class="pp">${Math.round((v / total) * 100)}%</span></li>`)}</ul>`;
+  }
+
   /** B 卡:现场。深色底 + 反白字;有卡住的人 → 橙点 + 人数 + 名单;没人卡住 → 绿点 + 正向文案。 */
   #live(live, pool) {
     const stalled = live.stalled;
@@ -307,14 +361,15 @@ export class ViewWorkbench extends LitElement {
   }
 
   /** F:最近动过(最多 3 条,右对齐时间) */
-  #feed(latest) {
+  #feed(latest, pool) {
     return html`<div data-feed>
       <div class="feed-head"><span class="lbl">最近动过</span>
         <a class="go" href=${href('/pool')} data-link aria-label="全部机会卡">全部 →</a></div>
-      ${latest.length ? html`<ul class="feed" style="margin-top:8px">${latest.map((o) => html`<li>
+      ${latest.length ? html`<ul class="feed">${latest.map((o) => html`<li>
         <a href=${href(`/pool/${o.id}`)} data-link>${o.title}</a>
-        <span class="st">${o.stageObj ? o.stageObj.code + ' ' + o.stageObj.name : ''}</span>
-        <span class="tm">${ago(o.upload?.uploadedAt || o.createdAt)}</span></li>`)}</ul>`
+        <span class="st">${(o.upload?.uploadedBy || '') + (o.stageObj ? ' · ' + o.stageObj.name : '')}</span>
+        <span class="tm">${ago(o.upload?.uploadedAt || o.createdAt)}</span></li>`)}</ul>
+        <a class="feed-more go" href=${href('/pool')} data-link>看全部 ${pool.total} 张机会卡 →</a>`
       : html`<p class="feed-empty">还没有机会卡</p>`}
     </div>`;
   }

+ 20 - 30
src/styles/tokens.js

@@ -20,7 +20,7 @@ export const TOKENS_CSS = `:root, :host {
   /* 光场最深处:蓝团 rgba(44,92,230,.62) 叠在纸色上 = rgb(118,149,237);玻璃合成色按它算最坏情况 */
   --kf-scene-deep: #7695ed;
   /* 页面底色(光场下面是它) */
-  --kf-paper: #eef1f9;
+  --kf-paper: #EFF0F3;   /* v15:中性灰白页底(原来的蓝调 + 彩色光斑会让实底卡「浮在色块上」) */
 
   /* 文字:三级 + 反白。全部按「玻璃后是 --kf-scene-deep」的最坏合成色验过 ≥ 4.5:1(verify-ui-v8)
      v10:正文 / 辅助改用 6 档灰阶的 gray-12 / gray-11 / gray-9(任务书 2.4)。
@@ -46,6 +46,7 @@ export const TOKENS_CSS = `:root, :host {
   --kf-line: #EAEAEA;                 /* gray-5 分隔线 */
   --kf-line-soft: rgba(0, 0, 0, 0.06); /* v15 卡片 / 面板的 1px 极浅描边 */
   --kf-surface: #FFFFFF;              /* v15 普通卡片实底 */
+  --kf-surface-btn: #F6F6F7;          /* 次要按钮实底(原来是半透明白玻璃) */
   --kf-surface-raised: #FCFCFD;       /* 卡片 hover 底色(比实底略亮一档,不加阴影) */
   --kf-line-strong: rgba(24, 24, 27, 0.22);
   --kf-fill: rgba(24, 24, 27, 0.05);
@@ -245,7 +246,7 @@ b, strong { font-weight: 600; }
 html, body {
   margin: 0;
   min-height: 100%;
-  background: #dfe5f3;
+  background: var(--kf-paper);
   color: var(--kf-ink-2);
   font-family: var(--kf-font);
   font-size: 14px;
@@ -289,7 +290,7 @@ summary::-webkit-details-marker { display: none; }
   backdrop-filter: blur(var(--kf-blur-top)) saturate(var(--kf-sat-top));
   box-shadow: var(--elev-2);
 }
-.kf-card {
+.kf-card:not(.is-overlay) {
   /* v15 定稿:内容卡 = 实底 #fff + 1px 极浅描边(rgba(0,0,0,.06))/ 无阴影。
      之前的半透明白面 + 轻微模糊在灰底上只剩「脏」,用户看到的是色块乱。 */
   position: relative; isolation: isolate;
@@ -359,51 +360,40 @@ summary:focus:not(:focus-visible), [tabindex]:focus:not(:focus-visible) { outlin
 /* 双环:内环与底色同色制造空隙,外环可见(浮层 / 抽屉里的主要操作) */
 .kf-focus-dual:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--kf-paper), 0 0 0 4px var(--kf-accent); }
 
-/* ============ 按钮 / chip:点缀层 .55 / blur(12px),hover .75 ============ */
+/* ============ 按钮 / chip(v15):实底,不再叠一层半透明玻璃骑在页面上 ============
+   secondary = #F6F6F7 实底 + 1px 描边(hover 变白 + 描边加深);primary = 强调色实底(整页唯一的强调色按钮) */
 .kf-btn {
   display: inline-flex; align-items: center; justify-content: center; gap: 6px;
   box-sizing: border-box; height: 32px; padding: 0 14px; border-radius: var(--kf-radius-btn);
-  border: 1px solid transparent;
-  background:
-    linear-gradient(var(--kf-glass-chip), var(--kf-glass-chip)) padding-box,
-    var(--kf-edge-chip) border-box;
-  -webkit-backdrop-filter: blur(var(--kf-blur-chip)) saturate(180%);
-  backdrop-filter: blur(var(--kf-blur-chip)) saturate(180%);
-  box-shadow: var(--kf-shadow-chip);
+  border: 1px solid var(--kf-line-soft);
+  background: var(--kf-surface-btn);
   color: var(--kf-ink); font: 500 13px/1 var(--kf-font); cursor: pointer;
   text-box-trim: trim-both; text-box-edge: cap alphabetic;
   transition: var(--kf-t);
 }
-.kf-btn:hover {
-  background:
-    linear-gradient(var(--kf-glass-chip-hover), var(--kf-glass-chip-hover)) padding-box,
-    var(--kf-edge-chip-hover) border-box;
-}
+.kf-btn:hover { background: #fff; border-color: rgba(0, 0, 0, 0.14); }
 .kf-btn:active { transform: scale(0.985); transition: transform 80ms cubic-bezier(0.4, 0, 0.2, 1); }
 .kf-btn[disabled] { opacity: 0.5; cursor: not-allowed; }
-/* 按钮三形态(v12 P0):
-   primary   实底、无边框、白字
-   secondary 透明底 + 1px 描边(.14 白)+ 次级字色(= .kf-btn 的默认形态,筛选 chip 也用它)
+/* 按钮三形态(v12 P0,v15 去玻璃):
+   primary   实底强调色、无边框、白字(一页只给一个主操作)
+   secondary 浅灰实底 + 1px 描边(= .kf-btn 的默认形态,筛选 chip 也用它)
    ghost     无底无框,只在 hover / active 给背景 */
-.kf-btn.primary { background: var(--kf-accent); border-color: var(--kf-accent); color: #fff; box-shadow: var(--shadow-1); }
-.kf-btn.primary:hover { background: var(--kf-accent-strong); }
-.kf-btn.secondary, .kf-btn { background: transparent; border-color: rgba(255, 255, 255, 0.14); box-shadow: none; color: var(--kf-ink-2);
-  -webkit-backdrop-filter: none; backdrop-filter: none; }
-.kf-btn.secondary:hover { background: rgba(255, 255, 255, 0.55); border-color: rgba(255, 255, 255, 0.55); color: var(--kf-ink); }
-.kf-btn.primary { box-shadow: var(--shadow-1); }
-.kf-btn.ghost { background: transparent; border-color: transparent; box-shadow: none; backdrop-filter: none; -webkit-backdrop-filter: none; color: var(--kf-ink-2); }
-.kf-btn.ghost:hover { background: rgba(24, 24, 27, 0.06); color: var(--kf-ink); }
+.kf-btn.primary { background: var(--kf-accent); border-color: var(--kf-accent); color: #fff; }
+.kf-btn.primary:hover { background: var(--kf-accent-strong); border-color: var(--kf-accent-strong); }
+.kf-btn.secondary { border-color: rgba(0, 0, 0, 0.10); color: var(--kf-ink-2); }
+.kf-btn.ghost { background: transparent; border-color: transparent; color: var(--kf-ink-2); }
+.kf-btn.ghost:hover { background: rgba(24, 24, 27, 0.06); border-color: transparent; color: var(--kf-ink); }
 .kf-btn.danger { color: var(--kf-danger); border-color: rgba(154,31,24,0.3); }
 
 .kf-chip {
   display: inline-flex; align-items: center; gap: 4px; box-sizing: border-box; height: 28px; padding: 0 10px;
-  border-radius: var(--r-sm); border: 1px solid rgba(255, 255, 255, 0.14);
-  background: transparent;
+  border-radius: var(--r-sm); border: 1px solid var(--kf-line-soft);
+  background: var(--kf-surface);
   font: 500 13px/1 var(--kf-font); color: var(--kf-ink-2); cursor: pointer;
   text-box-trim: trim-both; text-box-edge: cap alphabetic;
   transition: var(--kf-t);
 }
-.kf-chip:hover { background: rgba(255, 255, 255, 0.55); border-color: rgba(255, 255, 255, 0.55); color: var(--kf-ink); }
+.kf-chip:hover { background: var(--kf-surface-btn); border-color: rgba(0, 0, 0, 0.14); color: var(--kf-ink); }
 .kf-chip[aria-pressed="true"], .kf-chip[aria-pressed="true"]:hover { background: var(--kf-ink); color: #fff; border-color: var(--kf-ink); }
 .kf-chip .n { font-variant-numeric: tabular-nums; }   /* 数字不降透明度:v8 实测 .8 时部分 11.5px 数字压到 4.5 以下 */
 .kf-chip:active { transform: scale(0.985); transition: transform 80ms cubic-bezier(0.4, 0, 0.2, 1); }