人手改的那一手真正落得下去;界面不撒谎那几处补齐

手改是**兜 AI 的错**的那一手 —— 这一轮把它从「摆在那儿但落不了地」做成真的:

件上就地改
· 保存**按地址收**,不看当下那张卡:载荷从前借道工单的 `blocks[i]` 取列名,
  于是熔断卡(没有 blocks)在屏上时,人补的那一格一个字都送不出去 ——
  而他要补的恰恰是把这一单卡住的那个必填格。授权面改由活动清单的台账声明把关。
· **能增删行**:错不止「这一格填错了」,还有「这一行不该在」与「漏了一行」。
  删挂记号不当场抹掉(看得见、可后悔),且**删要说出来**(`drops`)——
  「没回传就是删了」会把一次不完整的回传变成一次删表。
· **必填没填按不下提交**:与放行门 L1 同一个数同一套算法;闸上摆出差在哪一行哪一格。
· 只写真改了的那几行 —— 改一格却留「修订 4 行」的痕,那句话是假的。

判据与门
· 裁量判据带谓词时**谓词说了算**:「选填缺口已补齐」基座数得出来,
  人填好的目标价它照样判「客户未提供」的毛病由此消掉。
· 验收卡判据**读时现算** —— 人在成果件上补一格,判据跟着变。
· 放行门认「**办完了没有**」不认「有人写过」:从前写个 `false` 就把门推开,
  于是一单没打标就进了放行门。三个数全由基座现数。
· 拒回把「活没干完」说成「数或行对不上」的毛病:判据点名的表一行都没写时直说那一步没办。
  **指向两扇打不开的门,比不指还糟。**

界面不撒谎
· 日志只有三色:负责人绿 · 智能体蓝 · 系统灰(归侧五种是度量的分法,不是给人看的)。
· 验收收口答两件事:落了什么(按**交付物**点名,一份成果的几张表并成一行)、
  往哪儿去(转出哪一口、带过去哪些字段);一个口都没发就直说到此为止。
· 签完到收尾之间那一段有自己的话「字已签下,正在落地」—— 中间态本来就该说出来,只是要说对。
· 消息不再被内部事件刷屏:只有从通道进来的件才谈得上「无人认领」。
· 建客户公司与联系人**一次确认落两行**;联系人编码自增不问人;卡面摆表的人读名。

A1 三案例端到端全 released:全 A 类直通 12 拍 / 客户点名跳一条 10 拍 / 新客户缺必填 14 拍。
五道门禁全绿(971 passed)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JsTDjoHovERXyy6Wmw1ALp
This commit is contained in:
2026-08-02 13:41:44 +08:00
co-authored by Claude Opus 5
parent 94f1c7a4ef
commit 259192f736
228 changed files with 27850 additions and 2847 deletions
+292 -10
View File
@@ -116,7 +116,7 @@
/* ===== 三栏衔接:列表区 / 视图区 / 对话区统一为三张等距同规格卡片 =====
覆盖 vendor 的「左中融合 + 右侧浮卡」旧结构:等间距 gutter、同圆角、同描边、同投影 */
/* 对话区宽度 = var(--jc-chat-w)(用户拖拽分隔柄写入 workspace inline style),未拖时走各断点默认 */
.proto-root .workspace { position: relative; gap: 12px; padding: 12px 14px; --jc-ws-pr: 14px; --jcai-ai-chat-width: var(--jc-chat-w, 440px); grid-template-columns: 310px minmax(var(--jc-work-min), 1fr) minmax(0, var(--jcai-ai-chat-width)); }
.proto-root .workspace { position: relative; gap: 12px; padding: 12px 14px; --jc-ws-pr: 14px; --jcai-ai-chat-width: var(--jc-chat-w, 440px); grid-template-columns: minmax(var(--jc-side-min), 310px) minmax(var(--jc-work-min), 1fr) minmax(var(--jc-chat-min), var(--jcai-ai-chat-width)); }
/* 收起态 grid:无媒体查询、全断点生效,覆盖 vendor 各断点的三栏定义(修列错位 bug)。
清单收起→[视图区 1fr | 会话区];会话收起→[清单 | 视图区 1fr];都收起→[视图区 1fr]。 */
.proto-root .workspace.jc-side-collapsed:not(.jc-chat-collapsed) { grid-template-columns: minmax(0, 1fr) var(--jcai-ai-chat-width, 440px); }
@@ -146,10 +146,25 @@
background: #fff;
overflow: hidden;
}
/*
空态要在这张卡里**上下居中**,不是贴着顶。
`.jc-empty` 早就写了 `margin: auto`,可它一直只把自己横向居中 ——
`margin-top/bottom: auto` 只有在 flex/grid 容器里才吃得开,在块级容器里算 0。
而这张卡(`.jc-panel-card`)恰恰没设 display:flex(设了 flex 的是它的反面
`:not(.jc-panel-card)`),于是五个模块的空态全贴在卡的顶边上。
只挑「直接儿子是空态」的那些卡改 —— `DocPanel`(纪要正文)用的是同一个类名,
它里头是一整块要滚的文档,居中了就成了上下留白、内容夹在中间。
`:has()` 在这儿正好:按内容挑,不必给六处组件各加一个修饰类。 */
.proto-root .workspace .execution-panel.jc-panel-card:has(> .jc-empty) {
display: flex;
flex-direction: column;
}
.proto-root .session-chat { border-radius: 12px; }
/* 窄屏(≤1380 视口):收窄三栏配比,保证对话区不被裁切(拖拽值 --jc-chat-w 仍优先) */
@media (max-width: 1380px) {
.proto-root .workspace { --jc-ws-pr: 12px; --jcai-ai-chat-width: var(--jc-chat-w, clamp(430px, 34vw, 560px)); grid-template-columns: 256px minmax(var(--jc-work-min), 1fr) minmax(0, var(--jcai-ai-chat-width)); gap: 10px; padding: 10px 12px; }
.proto-root .workspace { --jc-ws-pr: 12px; --jcai-ai-chat-width: var(--jc-chat-w, clamp(430px, 34vw, 560px)); grid-template-columns: minmax(var(--jc-side-min), 256px) minmax(var(--jc-work-min), 1fr) minmax(var(--jc-chat-min), var(--jcai-ai-chat-width)); gap: 10px; padding: 10px 12px; }
}
/* 对话区/视图区可调比例:workspace 直属分隔柄,锚在「视图区↔对话区」的 12px gutter 上
@@ -1638,6 +1653,12 @@
.proto-root .jc-tbl th { background: var(--soft); text-align: left; padding: 8px 10px; font-weight: 600; color: var(--ink-2); white-space: nowrap; }
.proto-root .jc-tbl td { padding: 7px 10px; border-top: 1px solid var(--line-soft); color: var(--ink); }
.proto-root .jc-tbl input { width: 100%; border: 1px solid var(--brand); border-radius: 5px; padding: 3px 6px; font: inherit; font-size: 12px; }
/* 空格子喊「待填写」—— 红边红占位字,填上即恢复常态(一片文字里的两个空格,不喊没人看得见) */
.proto-root .jc-tbl input.jc-tbl-todo { border-color: var(--danger); background: var(--danger-soft); }
.proto-root .jc-tbl input.jc-tbl-todo::placeholder { color: var(--danger); font-weight: 700; opacity: 1; }
.proto-root .jc-tbl input.jc-tbl-todo:focus { outline: 2px solid var(--danger); outline-offset: -1px; }
/* 只读态的空格子:如实说没填,不留一片让人以为「本来就没这项」的空白 */
.proto-root .jc-tbl .jc-tbl-empty { font-style: normal; font-size: 11px; color: var(--ink-4); }
.proto-root .jc-tbl-bar { display: flex; gap: 7px; align-items: center; justify-content: flex-end; }
.proto-root .jc-bars { display: flex; flex-direction: column; gap: 7px; }
@@ -2115,6 +2136,20 @@
.proto-root .jc-dv-h { display: flex; align-items: flex-start; gap: 10px; }
.proto-root .jc-dv-ico { flex: none; width: 30px; height: 30px; border-radius: 8px; display: grid; place-items: center; color: var(--ink-4); background: var(--soft); }
.proto-root .jc-dv.s-ok .jc-dv-ico { color: var(--ok); background: var(--ok-soft); }
/*
* **执行与验收两种颜色**(2026-08-02 用户定):一摞成果里「我办过的那张单」与
* 「我签过字的那一关」是两类东西 —— 同色排下来,人得逐行读标题才分得出。
* 执行走品牌蓝(在办的调子),验收走绿(过了关的调子);退回压过两者走警示色。
*/
.proto-root .jc-dv.m-exe .jc-dv-ico { color: var(--brand); background: var(--brand-wash); }
.proto-root .jc-dv.m-exe .jc-dv-st { color: var(--brand-deep); background: var(--brand-wash); }
.proto-root .jc-dv.m-exe { border-left: 3px solid var(--brand-soft); }
.proto-root .jc-dv.m-acc .jc-dv-ico { color: var(--ok); background: var(--ok-soft); }
.proto-root .jc-dv.m-acc .jc-dv-st { color: var(--ok); background: var(--ok-soft); }
.proto-root .jc-dv.m-acc { border-left: 3px solid var(--ok); }
.proto-root .jc-dv.s-bad.m-exe, .proto-root .jc-dv.s-bad.m-acc { border-left-color: var(--danger); }
.proto-root .jc-dv.s-bad.m-exe .jc-dv-ico, .proto-root .jc-dv.s-bad.m-acc .jc-dv-ico { color: var(--danger); background: var(--danger-soft); }
.proto-root .jc-dv.s-bad.m-exe .jc-dv-st, .proto-root .jc-dv.s-bad.m-acc .jc-dv-st { color: var(--danger); background: var(--danger-soft); }
.proto-root .jc-dv.s-live .jc-dv-ico { color: #fff; background: var(--ai-grad); }
.proto-root .jc-dv-t { flex: 1; min-width: 0; }
.proto-root .jc-dv-t em { display: block; font-style: normal; font-size: 10px; font-weight: 700; letter-spacing: .04em; color: var(--ink-4); font-family: var(--mono); }
@@ -2267,6 +2302,15 @@
/* 卡体与动作栏 */
.proto-root .jc-fc-b { padding: 11px 13px; display: flex; flex-direction: column; gap: 10px; }
.proto-root .jc-fc-ft { display: flex; align-items: center; gap: 8px; padding: 9px 13px; border-top: 1px solid var(--line-soft); background: #fbfcfe; }
/*
* **交不了的时候,说清差在哪** —— 只摆一个灰按钮等于让人猜自己哪儿做错了。
* 底色用警示色而不是错误红:这不是出错,是活还没干完。
*/
.proto-root .jc-fc-gate { padding: 9px 13px; border-top: 1px solid #f2dfc2; background: #fffaf2; }
.proto-root .jc-fc-gate p { display: flex; align-items: center; gap: 6px; margin: 0; color: #9a5b02; font-size: 12.5px; }
.proto-root .jc-fc-gate p svg { flex: 0 0 auto; }
.proto-root .jc-fc-gate ul { margin: 6px 0 0; padding: 0 0 0 19px; list-style: disc; color: var(--ink-2); font-size: 12px; line-height: 1.75; }
.proto-root .jc-fc-gate li.more { list-style: none; margin-left: -19px; color: var(--ink-3); }
.proto-root .jc-fc-sp { flex: 1; }
.proto-root .jc-fc-open { width: 100%; justify-content: center; }
/* 说明 / 建议 */
@@ -2286,12 +2330,48 @@
.proto-root .jc-fc-doc:hover { border-color: var(--fc); background: #fff; box-shadow: var(--shadow-1); }
.proto-root .jc-fc-doc-ico { flex: none; width: 30px; height: 30px; border-radius: 8px; display: grid; place-items: center; color: #fff; background: var(--fc); }
.proto-root .jc-fc-doc-bd { flex: 1; min-width: 0; }
.proto-root .jc-fc-doc-bd em { display: block; font-style: normal; font-size: 9.5px; font-weight: 800; letter-spacing: .05em; color: var(--ink-4); }
.proto-root .jc-fc-doc-bd b { display: block; margin-top: 1px; font-size: 12.5px; font-weight: 700; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/*
* **四字粗体在上、小字说明在下**(2026-08-02 用户:执行卡与验收卡「格式不统一」)。
* 从前是反的(小字在上),而两张卡里只有一张这么排 —— 人扫过去落点对不齐。
*/
.proto-root .jc-fc-doc-bd b { display: block; font-size: 12.5px; font-weight: 800; color: var(--ink); }
.proto-root .jc-fc-doc-bd em { display: block; margin-top: 2px; font-style: normal; font-size: 10.5px; font-weight: 500; line-height: 1.5; color: var(--ink-3); }
.proto-root .jc-fc-doc > svg { flex: none; color: var(--ink-4); transition: transform var(--t-fast); }
.proto-root .jc-fc-doc:hover > svg { transform: translateX(2px); color: var(--fc); }
/* 判据表(卡内紧凑版) */
.proto-root .jc-fc .jc-rp-crit.sm li { padding: 6px 11px; font-size: 11.5px; }
/*
* **作业指导书与验收判据同一套版面**(2026-08-02 用户定)。
* 从前指导书是一串松散的圆点(`.jc-steps`),判据是一摞带章的行 ——
* 同一张卡上两套版面语言,人得在两种读法之间来回切。
* 差别只留一处:指导书**没有达标/未达标** —— 它是要办的事,不是已办成的事;
* 不给步骤画对勾:系统并不知道人做没做,画上去就是撒谎。
*/
.proto-root .jc-guide li { align-items: flex-start; }
.proto-root .jc-guide .jc-lv { flex: none; margin-top: 1px; }
.proto-root .jc-guide .jc-lv-step { background: var(--brand-wash); color: var(--brand); border: 1px solid var(--brand-soft); }
.proto-root .jc-guide .jc-lv-done { display: inline-grid; place-items: center; background: #fff4e5; color: #de7802; border: 1px solid #f2dfc2; padding: 1px 4px; }
.proto-root .jc-guide .t { line-height: 1.65; }
/* 末行是这几步的收口 —— 底色分开,读到那儿就知道「做到这样算数」 */
.proto-root .jc-guide li.done { background: #fffaf2; }
.proto-root .jc-guide li.done .t b { display: block; margin-bottom: 1px; color: #9a5b02; font-weight: 800; }
/*
* **办结之后那一屏:落地结果**(2026-08-02 用户定)。
* 判据说的是「签之前要核什么」;签完之后人问的是「世界上发生了什么」。
*/
.proto-root .jc-landing { display: flex; flex-direction: column; gap: 8px; }
.proto-root .jc-landing-h { display: flex; align-items: center; gap: 6px; margin: 0; font-size: 12.5px; color: var(--ok); }
.proto-root .jc-landing-h b { font-weight: 800; }
.proto-root .jc-landing-h span { color: var(--ink-2); font-weight: 700; }
.proto-root .jc-landing .jc-rp-crit .r { color: var(--ink-3); font-weight: 700; }
.proto-root .jc-landing-p { display: flex; align-items: flex-start; gap: 6px; margin: 0; font-size: 11.5px; color: var(--ink-2); line-height: 1.6; }
.proto-root .jc-landing-p svg { flex: 0 0 auto; margin-top: 2px; color: var(--brand); }
.proto-root .jc-landing-p b { margin-right: 6px; font-weight: 800; color: var(--ink); }
.proto-root .jc-landing-p.warn { color: #9a5b02; }
.proto-root .jc-landing-p.warn svg { color: #de7802; }
/* 带过去了哪些字段 —— 摆名字不摆值:值在成果件里,这一行答的是「带了哪些东西」 */
.proto-root .jc-landing-carry { display: block; margin-top: 3px; font-style: normal; font-size: 11px; color: var(--ink-3); line-height: 1.6; }
/* 决策选项(卡内) */
.proto-root .jc-tch .jc-branches { margin: 0; display: flex; flex-direction: column; gap: 7px; }
@@ -2685,7 +2765,15 @@
.proto-root .jc-mdonut .jc-donut-lg span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* ══ 空占位(待处理 / 已完成):层叠光环 + 图标 + 主副文 + 提示囊 ══ */
.proto-root .jc-empty { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 58px 24px 64px; text-align: center; animation: rise var(--t-med) both; }
/*
* 空态 —— **在它那一栏里居中**,不是吊在顶上。
*
* 从前是固定的上下内边距(58/64),于是在一栏一人高的工作区里,那幅图与那两行字
* 挤在顶部三分之一处,底下留着一大片白。空态是常态不是缺页:它该像一张摆正的卡片,
* 而不是页面还没加载完的残影。
* `margin: auto` 让它在 flex 容器里上下左右都居中;容器不给高度时退回原来的内边距。
*/
.proto-root .jc-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; margin: auto; gap: 8px; padding: 40px 24px; text-align: center; animation: rise var(--t-med) both; }
.proto-root .jc-empty-art { position: relative; width: 108px; height: 108px; margin-bottom: 6px; }
.proto-root .jc-empty-art i { position: absolute; border-radius: 999px; }
.proto-root .jc-empty-art .r1 { inset: 0; opacity: .55; }
@@ -2864,12 +2952,29 @@
*/
.proto-root .workspace {
--jc-work-min: 690px;
/*
* 对话区也要有地板(2026-07-31 补)。
*
* 上面那段只给了中栏地板,对话区写的是 `minmax(0, …)` —— 意思是「让到多少算多少」。
* 三种 MacBook Air 都还剩 384px 以上,于是当时认为够。**1280 宽不在那张表里**:
* 1280 − 内边距 28 − 间距 24 = 1228,减去 310(清单)+ 690(中栏)只剩 228 ——
* 比它自己写的下限 340px 还窄。实测后果:决策卡的两个选项被压成一列竖排的单字,
* 「我按缺口起草一封询问函」一个字一行,人根本没法读,更谈不上点。
*
* 三个都到地板要 180 + 690 + 340 = 1210 ≤ 1228,装得下 ——
* 所以让**清单**先窄(它是一列任务卡,窄一点照样读),而不是压对话区。
*/
--jc-chat-min: 340px;
--jc-side-min: 180px;
}
/* 收起清单 / 收起对话时中栏本就宽,地板不必再管 —— 免得收起态反被地板顶出横向溢出 */
.proto-root .workspace.jc-side-collapsed,
.proto-root .workspace.jc-chat-collapsed {
--jc-work-min: 0px;
/* 收起态那一栏根本不在网格里,地板留着只会把剩下的栏顶出横向溢出 */
--jc-chat-min: 0px;
--jc-side-min: 0px;
}
/* 列表区空态 —— 紧凑版:软色圆 + 主副文,与主面板的整屏光环同一语气 */
@@ -2924,16 +3029,112 @@
}
/* ── 工作日志(补充,非原型)—— 一行一步,标明谁的产出 ────────────────── */
/* ── 沟通记录:一单往来的**原件** —— 一封一张纸,收/发两向分色 ── */
/* 系统开场白上的那一下 —— 灰调不抢戏:它是个去处,不是要人拍板的动作 */
.proto-root .jc-sys-act { display: inline-flex; align-items: center; gap: 5px; margin-top: 8px; padding: 4px 11px; border: 1px solid var(--line); border-radius: 999px; background: #fff; font: inherit; font-size: 11.5px; font-weight: 600; color: var(--ink-2); cursor: pointer; transition: border-color var(--t-fast), color var(--t-fast); }
.proto-root .jc-sys-act:hover { border-color: var(--brand); color: var(--brand); }
.proto-root .jc-sys-act:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
/* ── 数据录入卡(第五类人类工具,2026-07-31)──────────────────────────
壳、头、表单、按钮**一律用卡族公用的那套**(`jc-fc` / `jc-fc-h` / `jc-cfill`)。
上一版自造了一整套 `jc-entry-*` 骨架:圆角、描边、头部配色全跟兄弟卡对不上,
连类型章(图标 + 类型名)都没有 —— 五张卡摆在一条对话流里,唯独它像外来的。
卡族要长得像一家人,身份写在头上,不靠各造一套框来区分。
只留三样这张卡独有的语义:落表提示、必填星、「待填写」小签。 */
.proto-root .jc-fc.t-entry { --fc: var(--ok); --fc-soft: var(--ok-soft); }
/* 落到哪张表、哪一行 —— 按下确认写的是什么,得先说清楚 */
/*
* **卡面摆的是表的人读名,不是 `customer.profile`**(2026-08-02 用户定)——
* 界面不摆系统内的英文名。所以这一格不再用等宽字体:它现在是一句人话。
*/
.proto-root .jc-entry-tbl { display: block; margin-top: 1px; font-size: 11.5px; font-weight: 700; color: var(--ink-2); }
.proto-root .jc-entry-key { display: block; margin-top: 2px; font-style: normal; font-size: 10.5px; color: var(--ink-4); }
/* 自增的那几列不摆进表单,但要说一声 —— 一声不吭地拿掉,人会以为这张档少了一格 */
.proto-root .jc-entry-auto { display: flex; align-items: center; gap: 5px; margin: 6px 0 0; font-size: 11px; color: var(--ink-3); }
.proto-root .jc-entry-auto svg { flex: 0 0 auto; color: var(--brand); }
/* 两段以上才出的小标题 —— 一段的卡上摆它,是把上面那句又说了一遍 */
.proto-root .jc-entry-sec { margin: 10px 0 0; font-size: 11px; font-weight: 800; letter-spacing: .04em; color: var(--ink-3); }
.proto-root .jc-fc-b > .jc-cfill { margin-top: 0; }
.proto-root .jc-cfill-f .req { font-style: normal; color: var(--danger); margin-left: 2px; }
/* 待填写用**警示色的小签**,不染整格:染整格会把已填好的那几格也搅乱 */
.proto-root .jc-entry-todo { font-style: normal; margin-left: 6px; padding: 0 6px; border-radius: 999px; background: var(--danger); color: #fff; font-size: 10px; font-weight: 700; }
.proto-root .jc-cfill-f.todo input { border-color: var(--danger-soft, #f6c6c6); }
.proto-root .jc-entry-warn { margin-right: auto; font-size: 11px; color: var(--danger); }
.proto-root .jc-comms { display: flex; flex-direction: column; gap: 10px; padding: 2px 0; }
.proto-root .jc-comm { border: 1px solid var(--line-soft); border-radius: 10px; background: #fff; overflow: hidden; }
.proto-root .jc-comm.t-in { border-left: 3px solid var(--brand); }
.proto-root .jc-comm.t-out { border-left: 3px solid #8b93a7; }
.proto-root .jc-comm-h { display: flex; align-items: center; gap: 10px; padding: 10px 14px 8px; }
/* ── 沟通记录的未读(2026-07-31 用户定)──────────────────────────────
一封客户来件落进来之后,「看没看过」从前没人记 —— 新到的信和三天前的信
长得一模一样,人只能靠时间戳自己比。未读要**一眼扫得出**:左缘一道红边 +
标题旁一枚「未读」小签,不靠底色染整块(整块变色会把正文的可读性也搭进去)。
计数只跟着按钮走:打开页签不自动清 —— 那是替人宣布他看过了。 */
.proto-root .jc-comm.unread { border-color: var(--danger-soft, #f6c6c6); box-shadow: inset 3px 0 0 var(--danger); }
.proto-root .jc-comm-new { flex: none; padding: 1px 7px; border-radius: 999px; background: var(--danger); color: #fff; font-size: 10px; font-weight: 800; letter-spacing: .04em; }
/* 时间戳把按钮顶到最右 —— 标记是这一行的收尾动作,不跟标题抢位置 */
.proto-root .jc-comm-h .jc-comm-at { margin-left: auto; }
.proto-root .jc-comm-mark { flex: none; display: inline-flex; align-items: center; gap: 4px; padding: 3px 9px; border: 1px solid var(--line-soft); border-radius: 999px; background: #fff; font: inherit; font-size: 11px; font-weight: 600; color: var(--ink-3); cursor: pointer; transition: border-color var(--t-fast), color var(--t-fast), background var(--t-fast); }
.proto-root .jc-comm-mark:hover:not(:disabled) { border-color: var(--brand); color: var(--brand); }
.proto-root .jc-comm-mark:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
.proto-root .jc-comm-mark:disabled { opacity: .55; cursor: default; }
/* 已读那一枚淡下去 —— 它是「想改回未读」的入口,不该跟未读的按钮抢注意力 */
.proto-root .jc-comm-mark.done { color: var(--ink-4); border-style: dashed; }
.proto-root .jc-comm-dir { display: inline-flex; align-items: center; gap: 4px; flex: none; padding: 2px 7px; border-radius: 5px; background: #eef2fb; color: var(--brand); font-size: 11px; font-weight: 600; }
.proto-root .jc-comm-dir.t-out { background: #f1f2f5; color: #5d6577; }
.proto-root .jc-comm-sub { min-width: 0; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13.5px; font-weight: 600; color: var(--ink); }
.proto-root .jc-comm-at { flex: none; font-size: 11px; color: var(--ink-4); }
.proto-root .jc-comm-meta { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px; padding: 0 14px 10px; font-size: 11.5px; color: var(--ink-3); }
.proto-root .jc-comm-meta b { font-weight: 600; color: var(--ink-2); }
.proto-root .jc-comm-meta em { font-style: normal; color: var(--ink-4); }
/* ── 邮件正文:让它读起来像**一封信**,不像第二张卡 ────────────────────
从前是「整块灰底 + 一条硬分割线」:白色信头下面接一块灰,两者拼成两个盒子,
人第一眼看到的是两张摞着的卡,而不是一封有抬头有正文的信。
改成**引文那一路**:同底色、左缘一道浅竖线、往里缩一格 —— 竖线说的是
「下面这段是对方写的原话」,这比一块灰底说得清楚。
三处取自 ui-ux-pro-max 的排版规则:
· 行长限 65–75 字符(`max-width: 68ch`)—— 正文原来横铺整栏,一行三四十个汉字,
眼睛回扫时容易串行;
· 行高落到 1.75(原来 1.85 偏散,那是给大段散文的);
· 正文是这一屏的主内容,字号提到 13px —— 它不该比元信息还小。
`overflow-wrap` 从 `anywhere` 收成 `break-word`:`anywhere` 会把词从中间劈开,
而料号(LM358DR)被劈成两行是**读错的开始**,只有超长且无处可断时才允许断。
字体写 `inherit` 不写 `var(--sans)`:**`--sans` 这个变量全仓库没有定义过**
(只有 `--mono` 有)。从前这里是 `font: 400 12.5px/1.85 var(--sans)` 简写 ——
带未定义 var 的简写会**整条作废**,字号行高一起丢,实测算出来是 16px/normal。
`<pre>` 的 UA 默认字体是等宽,所以这一句必须显式写,不能省。 */
.proto-root .jc-comm-body { margin: 0 14px 12px; padding: 2px 0 2px 12px; border-left: 2px solid var(--line); max-width: 68ch; font-family: inherit; font-size: 13px; font-weight: 400; line-height: 1.75; color: var(--ink-2); white-space: pre-wrap; overflow-wrap: break-word; }
/* 来件与发件各给一点色相 —— 与信头左缘那道边同源,一眼分得出方向 */
.proto-root .jc-comm.t-in .jc-comm-body { border-left-color: var(--brand-wash, #dbe6fb); }
.proto-root .jc-comm.t-out .jc-comm-body { border-left-color: #e3e5ea; }
.proto-root .jc-comm-att { display: flex; flex-wrap: wrap; gap: 6px; padding: 10px 14px; border-top: 1px solid var(--line-soft); }
.proto-root .jc-att { display: inline-flex; align-items: center; gap: 6px; max-width: 100%; padding: 4px 8px; border: 1px solid var(--line-soft); border-radius: 6px; background: #fff; font-size: 11.5px; color: var(--ink-2); }
.proto-root .jc-att svg { flex: none; color: #4f8a52; }
/* 读不出内容的件:警示色 + 那句说明照抄 —— 摆一个「已上传 ✓」是撒谎 */
.proto-root .jc-att.blind { border-color: #e4c9a5; background: #fdf8f0; }
.proto-root .jc-att.blind svg { color: #b5803c; }
.proto-root .jc-att b { flex: none; font-weight: 600; }
.proto-root .jc-att i { flex: none; font-style: normal; font-size: 10.5px; color: var(--ink-4); }
.proto-root .jc-att em { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-style: normal; font-size: 10.5px; color: var(--ink-4); }
.proto-root .jc-log { display: flex; flex-direction: column; }
.proto-root .jc-log-row { display: flex; gap: 10px; align-items: baseline; padding: 8px 2px; }
.proto-root .jc-log-row + .jc-log-row { border-top: 1px solid var(--line-soft); }
.proto-root .jc-log-at { flex: none; font-size: 10.5px; color: var(--ink-4); }
.proto-root .jc-log-side { flex: none; font-size: 10.5px; font-weight: 700; padding: 1px 7px; border-radius: 999px; background: var(--soft); color: var(--ink-2); }
/* 归侧四类各一色:机器 / 人 / 人裁 / 世界等待 —— 一眼看出这一步是谁推的 */
.proto-root .jc-log-row.t-machine .jc-log-side { background: var(--brand-wash); color: var(--brand-deep); }
.proto-root .jc-log-row.t-human .jc-log-side { background: #e6f7f4; color: #0a6a64; }
.proto-root .jc-log-row.t-human-verdict .jc-log-side { background: #fff4e5; color: #de7802; }
.proto-root .jc-log-row.t-world-wait .jc-log-side { background: var(--soft); color: var(--ink-3); }
/* 归侧四类各一色:机器 / 人 / 人裁 / 系统等待 —— 一眼看出这一步是谁推的 */
/*
* **日志只有三色**(2026-08-02 用户定):负责人绿 · 智能体蓝 · 系统灰。
* 从前按归侧(machine / human / human-verdict / world-wait / trigger)上五色 ——
* 那是度量的分法,对读日志的人不构成区别:他只问「这一步是我办的、AI 办的,
* 还是流程自己走到的」。三档一档一意,一眼扫得动。
*/
.proto-root .jc-log-row.t-agent .jc-log-side { background: var(--brand-wash); color: var(--brand-deep); }
.proto-root .jc-log-row.t-owner .jc-log-side { background: #e6f7f4; color: #0a6a64; }
.proto-root .jc-log-row.t-system .jc-log-side { background: var(--soft); color: var(--ink-3); }
.proto-root .jc-log-t { flex: 1; min-width: 0; }
.proto-root .jc-log-t b { display: block; font-size: 12.5px; font-weight: 600; }
.proto-root .jc-log-t em { display: block; margin-top: 2px; font-style: normal; font-size: 11px; line-height: 1.6; color: var(--ink-3); }
@@ -2992,3 +3193,84 @@
.proto-root .jc-port.on .jc-port-dot { border-color: var(--brand); background: var(--brand); box-shadow: inset 0 0 0 2.5px #fff; }
.proto-root .jc-port b { font-weight: 700; }
.proto-root .jc-port em { margin-left: auto; font-style: normal; font-size: 10px; color: var(--ink-4); }
/* ═════════ AI 正在工作 —— 两处状态动画(2026-07-30) ═════════
语义:「在持续办事」,不是「在打字」。三点打字气泡(jc-typing)只在
AI 正回你的话时出现;这里的均衡条与涟漪表达的是**环在自己转**。
动效纪律:纯 CSS、幅度克制、只动 transform/opacity(不回流);
prefers-reduced-motion 下全部静止但状态仍可读。 */
/* ── ① 对话区 · AI 办事条(消息流末尾的常驻在场) ── */
.proto-root .jc-aiwork { display: inline-flex; align-items: center; gap: 9px; padding: 9px 13px; background: linear-gradient(135deg, rgba(51, 112, 255, 0.06), rgba(51, 112, 255, 0.02)); border: 1px solid rgba(51, 112, 255, 0.18); border-radius: 4px 14px 14px 14px; }
.proto-root .jc-aiwork-eq { display: inline-flex; align-items: flex-end; gap: 2.5px; height: 14px; }
.proto-root .jc-aiwork-eq i { width: 3px; height: 5px; border-radius: 2px; background: var(--brand); transform-origin: bottom; animation: jcEq 1.15s ease-in-out infinite; }
.proto-root .jc-aiwork-eq i:nth-child(2) { animation-delay: 0.14s; }
.proto-root .jc-aiwork-eq i:nth-child(3) { animation-delay: 0.28s; }
.proto-root .jc-aiwork-eq i:nth-child(4) { animation-delay: 0.42s; }
.proto-root .jc-aiwork-txt { font-size: 12px; font-weight: 600; color: var(--brand); letter-spacing: 0.01em; }
.proto-root .jc-aiwork-sub { font-size: 11px; color: var(--ink-3); }
@keyframes jcEq { 0%, 100% { transform: scaleY(0.45); opacity: 0.55; } 40% { transform: scaleY(1.9); opacity: 1; } }
/* 头像呼吸环:AI 在场的第二信号 —— 很轻,只有留意的人看得见 */
.proto-root .jc-ava-live { animation: jcBreathe 2.4s ease-in-out infinite; }
@keyframes jcBreathe { 0%, 100% { box-shadow: 0 0 0 0 rgba(51, 112, 255, 0.28); } 50% { box-shadow: 0 0 0 6px rgba(51, 112, 255, 0); } }
/* ── ② 空工作区 · AI 推进中场景(涟漪 + 工作线) ── */
.proto-root .jc-working { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 52px 24px 58px; text-align: center; animation: rise var(--t-med) both; }
.proto-root .jc-working-art { position: relative; width: 116px; height: 116px; margin-bottom: 4px; display: grid; place-items: center; }
/* 涟漪两环:从中心缓慢扩散消隐 —— 「环在转」的空间隐喻 */
.proto-root .jc-working-art .rp { position: absolute; inset: 22px; border-radius: 999px; border: 1.5px solid rgba(51, 112, 255, 0.35); animation: jcRipple 2.6s cubic-bezier(0.2, 0.6, 0.36, 1) infinite; }
.proto-root .jc-working-art .rp2 { animation-delay: 1.3s; }
.proto-root .jc-working-ico { position: relative; z-index: 1; width: 52px; height: 52px; border-radius: 16px; display: grid; place-items: center; color: #fff; background: linear-gradient(140deg, var(--brand), #244ecf); box-shadow: 0 6px 18px rgba(51, 112, 255, 0.32); animation: jcBreathe 2.4s ease-in-out infinite; }
@keyframes jcRipple { 0% { transform: scale(0.72); opacity: 0; } 18% { opacity: 0.9; } 100% { transform: scale(1.55); opacity: 0; } }
/* 工作线:三行微光骨架 —— AI 正在把报告一行行写出来的意象 */
.proto-root .jc-working-lines { display: flex; flex-direction: column; gap: 7px; width: 190px; margin: 8px 0 2px; }
.proto-root .jc-working-lines i { height: 7px; border-radius: 4px; background: linear-gradient(90deg, var(--soft) 25%, rgba(51, 112, 255, 0.16) 50%, var(--soft) 75%); background-size: 220% 100%; animation: jcShimmer 1.7s ease-in-out infinite; }
.proto-root .jc-working-lines i:nth-child(2) { width: 78%; animation-delay: 0.18s; }
.proto-root .jc-working-lines i:nth-child(3) { width: 56%; animation-delay: 0.36s; }
@keyframes jcShimmer { 0% { background-position: 120% 0; } 100% { background-position: -100% 0; } }
.proto-root .jc-working > b { font-size: 15px; font-weight: 800; color: var(--ink); }
.proto-root .jc-working > p { margin: 0; max-width: 30em; font-size: 12px; color: var(--ink-3); line-height: 1.8; }
.proto-root .jc-working-hint { display: inline-flex; align-items: center; gap: 6px; margin-top: 6px; padding: 5px 13px; background: rgba(51, 112, 255, 0.07); border: 1px solid rgba(51, 112, 255, 0.2); border-radius: 999px; font-size: 11px; font-weight: 600; color: var(--brand); }
/* 动效偏好:全部静止 —— 状态仍在(条不动、环常亮、线为素底),信息一分不少 */
@media (prefers-reduced-motion: reduce) {
.proto-root .jc-aiwork-eq i,
.proto-root .jc-ava-live,
.proto-root .jc-working-art .rp,
.proto-root .jc-working-ico,
.proto-root .jc-working-lines i { animation: none; }
.proto-root .jc-working-art .rp { opacity: 0.35; transform: scale(1.1); }
}
/* ═══ 算出来的去向 ═══════════════════════════════════════════════════════
* 与「选口」那一组同一副面孔,但**不是按钮**:去向是分类表算出来的事实,
* 不该长得像一道可点的选择题。判据原文摆在下面 —— 人要能回核「凭什么走这条」。
*/
.proto-root .jc-ports.routed .jc-port { cursor: default; }
.proto-root .jc-ports.routed .jc-port:hover { transform: none; }
.proto-root .jc-ports-why { margin: 6px 0 0; font-size: 11px; color: var(--ink-4); }
.proto-root .jc-ports-why code { font-size: 10.5px; color: var(--ink-3); background: var(--soft); border-radius: 5px; padding: 1px 6px; }
/* ── 验收判据的第三态 —— 放在末尾,压得过后面那条 `li:hover` ───────────────
*
* 裁过、裁成不满足:那不是「活没干完」,是 AI 办过、办不到,把判断交给人
* (提交门本来就允许这样提交:裁过即可)。从前它与「压根没裁」同挤成一个红叉,
* 人看到一条永远不绿的项,既不知道 AI 有没有办过、也不知道为什么,只能凭感觉签。
* 用琥珀不用红:**红是缺口,琥珀是「等你拿个主意」**。
*
* 位置有讲究:`.jc-rp-crit li:hover` 与它同特异性(0,3,1),写在前面就会被悬停盖掉 ——
* 鼠标一扫过,那一条就变回普通底色,人以为自己看错了。
*/
/*
* 标法用**左侧色条**而不是整行底色:底色那一层在这条链上压不过既有的
* `li` / `li:hover`(同特异性、位置更后),追下去只会变成一串 !important;
* 而色条是 inset 阴影,谁也不跟它抢 —— 本仓标「命中行」本来就用这一招
* (`jc-dmn-r.hit::before` 那条左边的竖线)。视觉语言一致,还更醒目。
*/
.proto-root .jc-rp-crit li.judged { box-shadow: inset 3px 0 0 #de7802; }
.proto-root .jc-rp-crit li.judged .r { color: #de7802; }
/* 理由那一句:裁成不满足时它才是签字的人真正要读的东西 */
.proto-root .jc-rp-crit .jc-crit-why {
display: block; margin-top: 3px; font-style: normal; font-size: 11px;
line-height: 1.6; color: var(--ink-3);
}