dsh-recency-guard 0.16.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -13
- package/bin/rescue.mjs +97 -10
- package/dist/client.js +551 -77
- package/dist/index.js +839 -225
- package/dsh-plugin.json +1 -1
- package/locale/en.json +46 -0
- package/locale/zh.json +46 -0
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -61,6 +61,8 @@ var zh_default = {
|
|
|
61
61
|
emptyHint: "\u5B88\u62A4\u63D2\u4EF6\u5C1A\u672A\u8BB0\u5F55\u4EFB\u4F55\u542F\u52A8\u4E8B\u5B9E\u3002",
|
|
62
62
|
snapshotAt: "\u5FEB\u7167\u65F6\u523B {time}",
|
|
63
63
|
pollingOn: "\u6BCF {seconds} \u79D2\u8F6E\u8BE2",
|
|
64
|
+
pollingBackoff: "\u6570\u636E\u7A33\u5B9A\uFF0C\u5DF2\u653E\u6162\u5237\u65B0",
|
|
65
|
+
pollingHint: "\u95F4\u9694\u6309\u5185\u5BB9\u7A33\u5B9A\u6027\u81EA\u9002\u5E94\uFF083\u201330 \u79D2\uFF09\uFF1B\u6570\u636E\u7A33\u5B9A\u65F6\u653E\u6162\uFF0C\u53D8\u5316\u65F6\u7ACB\u523B\u56DE\u5230 5 \u79D2\u3002",
|
|
64
66
|
pollingPaused: "\u8F6E\u8BE2\u5DF2\u6682\u505C\uFF08\u753B\u9762\u505C\u5728\u6682\u505C\u65F6\u523B\uFF09",
|
|
65
67
|
restore: "\u6062\u590D\u975E\u5ACC\u7591\u63D2\u4EF6",
|
|
66
68
|
stale: "\u6570\u636E\u5DF2\u505C\u7559 {minutes} \u5206\u949F\uFF08\u8F6E\u8BE2\u5DF2\u6682\u505C\uFF09",
|
|
@@ -98,6 +100,7 @@ var zh_default = {
|
|
|
98
100
|
markov: "\u8F6C\u79FB\u77E9\u9635",
|
|
99
101
|
dataflow: "\u6570\u636E\u6D41",
|
|
100
102
|
diagnostics: "\u7CFB\u7EDF\u8BCA\u65AD",
|
|
103
|
+
preventive: "\u9884\u8B66\uFF08\u53EA\u89C2\u6D4B\uFF09",
|
|
101
104
|
cooccurrence: "\u5171\u73B0\u9A8C\u8BC1",
|
|
102
105
|
calibration: "\u8BEF\u4F24\u6821\u51C6",
|
|
103
106
|
bayes: "\u8D1D\u53F6\u65AF\u8BFB\u6570"
|
|
@@ -133,6 +136,15 @@ var zh_default = {
|
|
|
133
136
|
intervals: "\u5D29\u6E83\u95F4\u9694\uFF08\u4E2D\u4F4D / CV\uFF09",
|
|
134
137
|
changePoint: "CUSUM \u53D8\u70B9",
|
|
135
138
|
controlBand: "\u63A7\u5236\u5E26\uFF08\u4F11\u54C8\u7279\uFF09",
|
|
139
|
+
survival: "\u751F\u5B58\u5206\u6790\uFF08\u6307\u6570 / Weibull \u5747\u503C\uFF09",
|
|
140
|
+
intervalTrend: "\u95F4\u9694\u8D8B\u52BF\uFF08\u8FD1\u6BB5 / \u57FA\u51C6\uFF09",
|
|
141
|
+
shapeAtBound: "\u649E\u754C\u4F2A\u503C",
|
|
142
|
+
directionDenser: "\u5D29\u6E83\u53D8\u5BC6",
|
|
143
|
+
directionSparser: "\u5D29\u6E83\u53D8\u7A00",
|
|
144
|
+
directionSteady: "\u5E73\u7A33",
|
|
145
|
+
mismatchAtBound: "Weibull \u5F62\u72B6\u649E\u641C\u7D22\u4E0A\u754C\uFF1Ak \u662F\u8FB9\u754C\u4F2A\u503C\uFF0C\u5747\u503C\u4E0D\u53EF\u4FE1\uFF08\u95F4\u9694\u8FD1\u4E4E\u5B8C\u5168\u89C4\u5219\uFF09",
|
|
146
|
+
mismatchCv: "\u89C2\u6D4B CV={cv} \u504F\u79BB\u6307\u6570\u5047\u8BBE\u7684 1\uFF1A\u6307\u6570\u6A21\u578B\u5931\u914D\uFF0C\u03BB\u0302/\u5747\u503C\u4EC5\u4F9B\u53C2\u8003",
|
|
147
|
+
mismatchDirection: "\u65B9\u5411\u5224\u5B9A\u6837\u672C\u4E0D\u8DB3\uFF08<9\uFF09\uFF1A\u5371\u9669\u7387\u65B9\u5411\u53EA\u662F\u63D0\u793A\u4E0D\u662F\u7ED3\u8BBA",
|
|
136
148
|
undefined: "\u4E0D\u53EF\u5224\u5B9A",
|
|
137
149
|
valueUndefined: "\u6307\u6807\u58F0\u660E\u4E3A\u53EF\u5224\u5B9A\u4F46\u503C\u4E3A\u7A7A\uFF08\u7ED3\u6784\u4E0D\u5B8C\u6574\uFF09",
|
|
138
150
|
unavailableReason: "\u8DE8\u5206\u533A\u53EA\u8BFB\u89C6\u56FE\u4E0D\u63D0\u4F9B\u8FD0\u884C\u65F6\u6307\u6807\uFF08\u8BFB\u4E0D\u5230 \u2260 \u4E00\u5207\u4E3A\u96F6\uFF09"
|
|
@@ -202,6 +214,9 @@ var zh_default = {
|
|
|
202
214
|
watch: "\u89C2\u5BDF\u4E2D",
|
|
203
215
|
rounds: "\u7B2C {rounds}/{required} \u8F6E"
|
|
204
216
|
},
|
|
217
|
+
unresolved: {
|
|
218
|
+
title: "\u4E0A\u6B21\u9694\u79BB\u540E\u4ECD\u6709 {count} \u6761\u65E0\u6CD5\u81EA\u52A8\u89E3\u51B3\u7684\u51B2\u7A81\u6B8B\u4F59\uFF08\u53D7\u4FDD\u62A4\u7EC4\u4EF6\u5BFC\u81F4\uFF09"
|
|
219
|
+
},
|
|
205
220
|
card: {
|
|
206
221
|
enlarge: "\u6269\u5927\u9762\u677F",
|
|
207
222
|
shrink: "\u6062\u590D\u9762\u677F"
|
|
@@ -224,6 +239,32 @@ var zh_default = {
|
|
|
224
239
|
note: "\u5907\u6CE8"
|
|
225
240
|
}
|
|
226
241
|
},
|
|
242
|
+
preventive: {
|
|
243
|
+
title: "\u9884\u9632\u6027\u9884\u8B66",
|
|
244
|
+
hint: "\u53EA\u9884\u8B66\uFF0C\u4E0D\u884C\u52A8",
|
|
245
|
+
alertOnly: "\u53EA\u9884\u8B66\uFF0C\u4E0D\u5173\u95ED\u4EFB\u4F55\u63D2\u4EF6 \u2014\u2014 \u52A8\u4F5C\u4ECD\u8D70\u53D6\u8BC1\u6D41\u7A0B\uFF08RQ1/RQ2\uFF09\u3002",
|
|
246
|
+
unavailable: "\u8BE5\u89C6\u56FE\u4E0D\u63D0\u4F9B\u9884\u9632\u6027\u8BFB\u6570\uFF08\u4E0D\u53EF\u5F97 \u2260 \u4E00\u5207\u6B63\u5E38\uFF09\u3002",
|
|
247
|
+
loadTime: "\u542F\u52A8\u9891\u7387\uFF08\u52A0\u8F7D\u8017\u65F6\u4EE3\u7406\uFF09",
|
|
248
|
+
configChanges: "\u914D\u7F6E\u53D8\u66F4\u9891\u7387\uFF08CUSUM\uFF09",
|
|
249
|
+
current: "\u5F53\u524D\u6C34\u5E73",
|
|
250
|
+
baseline: "\u4E2D\u5FC3\u7EBF",
|
|
251
|
+
upper: "\u4E0A\u63A7\u5236\u9650\uFF08\u8D8A\u754C\u9884\u8B66\uFF09",
|
|
252
|
+
lower: "\u4E0B\u63A7\u5236\u9650\uFF08\u5BF9\u7167\uFF09",
|
|
253
|
+
sigma: "\u7A33\u5065 \u03C3\u0302",
|
|
254
|
+
samples: "\u6837\u672C\u6570",
|
|
255
|
+
perMinute: "\u6B21/\u5206\u949F",
|
|
256
|
+
statistic: "\u7EDF\u8BA1\u91CF S",
|
|
257
|
+
threshold: "\u5224\u5B9A\u9608\u503C h",
|
|
258
|
+
reference: "\u53C2\u8003\u503C k",
|
|
259
|
+
baselineGap: "\u57FA\u7EBF\u95F4\u9694",
|
|
260
|
+
intervals: "\u95F4\u9694\u6570",
|
|
261
|
+
breach: "\u6F02\u79FB\u5224\u5B9A",
|
|
262
|
+
noBreach: "\u672A\u8D8A\u754C",
|
|
263
|
+
breachAt: "\u7B2C {index} \u4E2A\u95F4\u9694\u9996\u6B21\u8D8A\u754C",
|
|
264
|
+
alertYes: "\u9884\u8B66\uFF1A\u8D8A\u754C",
|
|
265
|
+
alertNo: "\u672A\u8D8A\u754C",
|
|
266
|
+
source: "\u6765\u6E90\uFF1A{boots} \u6B21\u542F\u52A8 / {changes} \u6B21\u53D8\u66F4 \xB7 \u5355\u4F4D {units}"
|
|
267
|
+
},
|
|
227
268
|
graphStruct: {
|
|
228
269
|
title: "\u7ED3\u6784\u6D1E\u5BDF",
|
|
229
270
|
hubs: "\u67A2\u7EBD",
|
|
@@ -235,6 +276,11 @@ var zh_default = {
|
|
|
235
276
|
less: "\u6536\u8D77",
|
|
236
277
|
nodeTitle: "{label} \xB7 \u5165 {in} / \u51FA {out}"
|
|
237
278
|
},
|
|
279
|
+
graphImpact: {
|
|
280
|
+
label: "\u5F71\u54CD\u9762",
|
|
281
|
+
hint: "\u52A8\u5B83\u4F1A\u6CE2\u53CA\u8C01\uFF1A\u4E0A\u6E38 = \u53CD\u5411\u53EF\u8FBE\uFF08\u5931\u53BB\u8F93\u5165\u65B9\uFF09\uFF0C\u4E0B\u6E38 = \u6B63\u5411\u53EF\u8FBE\uFF08\u8F93\u51FA\u6D41\u5411\uFF09\u3002\u4E0E\u76F8\u90BB\u5217\u8868\u7684 1 \u8DF3\u4E0D\u540C\uFF0C\u8FD9\u91CC\u662F\u5168\u5B50\u56FE",
|
|
282
|
+
value: "\u4E0A\u6E38 {up} \xB7 \u4E0B\u6E38 {down}"
|
|
283
|
+
},
|
|
238
284
|
decisionEvidence: {
|
|
239
285
|
empty: "\u5C1A\u65E0\u5ACC\u7591\u540D\u5355\uFF08\u672A\u53D1\u751F\u8FC7\u5D29\u6E83\u6062\u590D\u51B3\u7B56\uFF09",
|
|
240
286
|
legacy: "\u8BE5\u51B3\u7B56\u6765\u81EA\u65E7\u7248\u672C\uFF0C\u672A\u8BB0\u5F55\u56E0\u5B50\u5206\u89E3 \u2014\u2014 \u4E0D\u663E\u793A\u5047\u7684\u96F6\u503C",
|
|
@@ -479,6 +525,8 @@ var en_default = {
|
|
|
479
525
|
emptyHint: "The guard has not recorded any startup facts yet.",
|
|
480
526
|
snapshotAt: "Snapshot at {time}",
|
|
481
527
|
pollingOn: "polling every {seconds}s",
|
|
528
|
+
pollingBackoff: "data is stable, refresh slowed down",
|
|
529
|
+
pollingHint: "The interval adapts to content stability (3\u201330s); slower when stable, back to 5s on change.",
|
|
482
530
|
pollingPaused: "polling paused (the view is frozen at the pause moment)",
|
|
483
531
|
restore: "Restore non-suspects",
|
|
484
532
|
stale: "Data is {minutes} min old (polling paused)",
|
|
@@ -516,6 +564,7 @@ var en_default = {
|
|
|
516
564
|
markov: "Transition matrix",
|
|
517
565
|
dataflow: "Data flow",
|
|
518
566
|
diagnostics: "Diagnostics",
|
|
567
|
+
preventive: "Warnings (observe only)",
|
|
519
568
|
cooccurrence: "Co-occurrence",
|
|
520
569
|
calibration: "False-positive calibration",
|
|
521
570
|
bayes: "Bayesian reading"
|
|
@@ -551,6 +600,15 @@ var en_default = {
|
|
|
551
600
|
intervals: "Crash intervals (median / CV)",
|
|
552
601
|
changePoint: "CUSUM change point",
|
|
553
602
|
controlBand: "Control band (Shewhart)",
|
|
603
|
+
survival: "Survival (exponential / Weibull mean)",
|
|
604
|
+
intervalTrend: "Interval trend (recent / baseline)",
|
|
605
|
+
shapeAtBound: "boundary artifact",
|
|
606
|
+
directionDenser: "crashes densifying",
|
|
607
|
+
directionSparser: "crashes spacing out",
|
|
608
|
+
directionSteady: "steady",
|
|
609
|
+
mismatchAtBound: "Weibull shape hit the search bound: k is a boundary artifact, the mean is untrustworthy (near-regular intervals)",
|
|
610
|
+
mismatchCv: "Observed CV={cv} deviates from the exponential assumption of 1: exponential model mismatched, \u03BB\u0302/mean are indicative only",
|
|
611
|
+
mismatchDirection: "Direction under-sampled (<9): hazard direction is a hint, not a conclusion",
|
|
554
612
|
undefined: "not determinable",
|
|
555
613
|
valueUndefined: "Metric is marked defined but its value is empty (incomplete shape)",
|
|
556
614
|
unavailableReason: "A cross-partition read-only view has no runtime metrics (unavailable \u2260 all zero)"
|
|
@@ -620,6 +678,9 @@ var en_default = {
|
|
|
620
678
|
watch: "Watching",
|
|
621
679
|
rounds: "round {rounds}/{required}"
|
|
622
680
|
},
|
|
681
|
+
unresolved: {
|
|
682
|
+
title: "{count} conflict finding(s) remained unresolved after the last quarantine (protected components involved)"
|
|
683
|
+
},
|
|
623
684
|
card: {
|
|
624
685
|
enlarge: "Enlarge panel",
|
|
625
686
|
shrink: "Restore panel"
|
|
@@ -642,6 +703,32 @@ var en_default = {
|
|
|
642
703
|
note: "note"
|
|
643
704
|
}
|
|
644
705
|
},
|
|
706
|
+
preventive: {
|
|
707
|
+
title: "Preventive warnings",
|
|
708
|
+
hint: "warn only, never act",
|
|
709
|
+
alertOnly: "Warnings only \u2014 no plugin is ever disabled here; actions still go through evidence (RQ1/RQ2).",
|
|
710
|
+
unavailable: "This view does not provide preventive readings (unavailable \u2260 all clear).",
|
|
711
|
+
loadTime: "Startup frequency (load-time proxy)",
|
|
712
|
+
configChanges: "Config change frequency (CUSUM)",
|
|
713
|
+
current: "Current level",
|
|
714
|
+
baseline: "Centre line",
|
|
715
|
+
upper: "Upper control limit (alert)",
|
|
716
|
+
lower: "Lower control limit (reference)",
|
|
717
|
+
sigma: "Robust \u03C3\u0302",
|
|
718
|
+
samples: "Samples",
|
|
719
|
+
perMinute: "per minute",
|
|
720
|
+
statistic: "Statistic S",
|
|
721
|
+
threshold: "Threshold h",
|
|
722
|
+
reference: "Reference k",
|
|
723
|
+
baselineGap: "Baseline gap",
|
|
724
|
+
intervals: "Intervals",
|
|
725
|
+
breach: "Drift verdict",
|
|
726
|
+
noBreach: "not breached",
|
|
727
|
+
breachAt: "first breached at interval {index}",
|
|
728
|
+
alertYes: "Alert: breached",
|
|
729
|
+
alertNo: "not breached",
|
|
730
|
+
source: "Source: {boots} startups / {changes} changes \xB7 units {units}"
|
|
731
|
+
},
|
|
645
732
|
graphStruct: {
|
|
646
733
|
title: "Structure",
|
|
647
734
|
hubs: "Hubs",
|
|
@@ -653,6 +740,11 @@ var en_default = {
|
|
|
653
740
|
less: "Show less",
|
|
654
741
|
nodeTitle: "{label} \xB7 in {in} / out {out}"
|
|
655
742
|
},
|
|
743
|
+
graphImpact: {
|
|
744
|
+
label: "Impact",
|
|
745
|
+
hint: "What breaks if this node changes: upstream = reverse-reachable (who loses input), downstream = forward-reachable (where output flows). Whole subgraph, unlike the 1-hop neighbor list",
|
|
746
|
+
value: "upstream {up} \xB7 downstream {down}"
|
|
747
|
+
},
|
|
656
748
|
decisionEvidence: {
|
|
657
749
|
empty: "No suspect list yet (no crash-recovery decision has been made)",
|
|
658
750
|
legacy: "This decision predates factor recording \u2014 showing no fake zero values",
|
|
@@ -2118,7 +2210,11 @@ function GraphDetails(props) {
|
|
|
2118
2210
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", { children: t("graph.refLabel") }),
|
|
2119
2211
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("dd", { className: "rg-mono", children: node.ref ?? "\u2014" }),
|
|
2120
2212
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", { children: t("graph.degreeLabel") }),
|
|
2121
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("dd", { children: t("graph.degreeValue", { in: props.degree.in, out: props.degree.out }) })
|
|
2213
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("dd", { children: t("graph.degreeValue", { in: props.degree.in, out: props.degree.out }) }),
|
|
2214
|
+
props.impact !== void 0 && props.impact !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
2215
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", { title: t("graphImpact.hint"), children: t("graphImpact.label") }),
|
|
2216
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("dd", { children: t("graphImpact.value", { up: props.impact.upstreamCount, down: props.impact.downstreamCount }) })
|
|
2217
|
+
] })
|
|
2122
2218
|
] }),
|
|
2123
2219
|
labelText.truncated || (detailText?.truncated ?? false) ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", { className: "rg-graph-longtext", children: [
|
|
2124
2220
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("summary", { children: t("graph.omittedChars", { count: labelText.omitted + (detailText?.omitted ?? 0) }) }),
|
|
@@ -2288,6 +2384,103 @@ function GraphTooltip({ node, degree, x, y, containerWidth }) {
|
|
|
2288
2384
|
] });
|
|
2289
2385
|
}
|
|
2290
2386
|
|
|
2387
|
+
// src/client/graph/graph-analysis.ts
|
|
2388
|
+
function analyzeStructure(nodes, edges, hubThreshold = 3) {
|
|
2389
|
+
const inCount = /* @__PURE__ */ new Map();
|
|
2390
|
+
const outCount = /* @__PURE__ */ new Map();
|
|
2391
|
+
const known = new Set(nodes.map((n) => n.id));
|
|
2392
|
+
let edgeCount = 0;
|
|
2393
|
+
for (const edge of edges) {
|
|
2394
|
+
if (edge.from === edge.to) continue;
|
|
2395
|
+
if (!known.has(edge.from) || !known.has(edge.to)) continue;
|
|
2396
|
+
edgeCount += 1;
|
|
2397
|
+
outCount.set(edge.from, (outCount.get(edge.from) ?? 0) + 1);
|
|
2398
|
+
inCount.set(edge.to, (inCount.get(edge.to) ?? 0) + 1);
|
|
2399
|
+
}
|
|
2400
|
+
const degrees = nodes.map((node) => {
|
|
2401
|
+
const inDegree = inCount.get(node.id) ?? 0;
|
|
2402
|
+
const outDegree = outCount.get(node.id) ?? 0;
|
|
2403
|
+
const total = inDegree + outDegree;
|
|
2404
|
+
const role = total === 0 ? "isolated" : inDegree > 0 && outDegree > 0 ? total >= hubThreshold ? "hub" : "middle" : outDegree > 0 ? "source" : "sink";
|
|
2405
|
+
return { id: node.id, label: node.label, inDegree, outDegree, total, role };
|
|
2406
|
+
});
|
|
2407
|
+
degrees.sort((a, b) => b.total - a.total || a.id.localeCompare(b.id));
|
|
2408
|
+
return {
|
|
2409
|
+
degrees,
|
|
2410
|
+
hubs: degrees.filter((d) => d.role === "hub"),
|
|
2411
|
+
sources: degrees.filter((d) => d.role === "source"),
|
|
2412
|
+
sinks: degrees.filter((d) => d.role === "sink"),
|
|
2413
|
+
isolated: degrees.filter((d) => d.role === "isolated"),
|
|
2414
|
+
edgeCount,
|
|
2415
|
+
empty: nodes.length === 0
|
|
2416
|
+
};
|
|
2417
|
+
}
|
|
2418
|
+
function reachableFrom(from, nodes, edges) {
|
|
2419
|
+
if (!nodes.some((n) => n.id === from)) return null;
|
|
2420
|
+
const known = new Set(nodes.map((n) => n.id));
|
|
2421
|
+
const outgoing = /* @__PURE__ */ new Map();
|
|
2422
|
+
for (const edge of edges) {
|
|
2423
|
+
if (edge.from === edge.to) continue;
|
|
2424
|
+
if (!known.has(edge.from) || !known.has(edge.to)) continue;
|
|
2425
|
+
const list = outgoing.get(edge.from) ?? [];
|
|
2426
|
+
list.push(edge.to);
|
|
2427
|
+
outgoing.set(edge.from, list);
|
|
2428
|
+
}
|
|
2429
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2430
|
+
const queue = [from];
|
|
2431
|
+
while (queue.length > 0) {
|
|
2432
|
+
const cur = queue.shift();
|
|
2433
|
+
for (const next of outgoing.get(cur) ?? []) {
|
|
2434
|
+
if (seen.has(next) || next === from) continue;
|
|
2435
|
+
seen.add(next);
|
|
2436
|
+
queue.push(next);
|
|
2437
|
+
}
|
|
2438
|
+
}
|
|
2439
|
+
return seen;
|
|
2440
|
+
}
|
|
2441
|
+
function impactedBy(target, nodes, edges) {
|
|
2442
|
+
if (!nodes.some((n) => n.id === target)) return null;
|
|
2443
|
+
const known = new Set(nodes.map((n) => n.id));
|
|
2444
|
+
const incoming = /* @__PURE__ */ new Map();
|
|
2445
|
+
for (const edge of edges) {
|
|
2446
|
+
if (edge.from === edge.to) continue;
|
|
2447
|
+
if (!known.has(edge.from) || !known.has(edge.to)) continue;
|
|
2448
|
+
const list = incoming.get(edge.to) ?? [];
|
|
2449
|
+
list.push(edge.from);
|
|
2450
|
+
incoming.set(edge.to, list);
|
|
2451
|
+
}
|
|
2452
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2453
|
+
const queue = [target];
|
|
2454
|
+
while (queue.length > 0) {
|
|
2455
|
+
const cur = queue.shift();
|
|
2456
|
+
for (const prev of incoming.get(cur) ?? []) {
|
|
2457
|
+
if (seen.has(prev) || prev === target) continue;
|
|
2458
|
+
seen.add(prev);
|
|
2459
|
+
queue.push(prev);
|
|
2460
|
+
}
|
|
2461
|
+
}
|
|
2462
|
+
return seen;
|
|
2463
|
+
}
|
|
2464
|
+
function structureInsights(structure) {
|
|
2465
|
+
if (structure.empty) return [];
|
|
2466
|
+
const out = [];
|
|
2467
|
+
if (structure.hubs.length > 0) {
|
|
2468
|
+
const top = structure.hubs[0];
|
|
2469
|
+
out.push(`\u67A2\u7EBD ${structure.hubs.length} \u4E2A\uFF0C\u6700\u9AD8\u4E3A ${top.label}\uFF08\u8FDB ${top.inDegree} / \u51FA ${top.outDegree}\uFF09`);
|
|
2470
|
+
}
|
|
2471
|
+
if (structure.sources.length > 0) {
|
|
2472
|
+
out.push(`\u53EA\u751F\u4EA7\u4E0D\u6D88\u8D39 ${structure.sources.length} \u4E2A\uFF1A${structure.sources.slice(0, 3).map((d) => d.label).join("\u3001")}`);
|
|
2473
|
+
}
|
|
2474
|
+
if (structure.sinks.length > 0) {
|
|
2475
|
+
out.push(`\u53EA\u6D88\u8D39\u4E0D\u751F\u4EA7 ${structure.sinks.length} \u4E2A\uFF1A${structure.sinks.slice(0, 3).map((d) => d.label).join("\u3001")}`);
|
|
2476
|
+
}
|
|
2477
|
+
if (structure.isolated.length > 0) {
|
|
2478
|
+
out.push(`\u5B64\u7ACB\u8282\u70B9 ${structure.isolated.length} \u4E2A\uFF1A${structure.isolated.slice(0, 3).map((d) => d.label).join("\u3001")}`);
|
|
2479
|
+
}
|
|
2480
|
+
out.push(`\u5171 ${structure.edgeCount} \u6761\u8FB9`);
|
|
2481
|
+
return out;
|
|
2482
|
+
}
|
|
2483
|
+
|
|
2291
2484
|
// src/client/graph/GuardGraph.tsx
|
|
2292
2485
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
2293
2486
|
var MINIMAP_CANVAS = { width: 152, height: 96 };
|
|
@@ -2714,6 +2907,15 @@ function GuardGraph({ graph, height = VIEWPORT_HEIGHT_WIDE, focusId, onFocusChan
|
|
|
2714
2907
|
() => focusId === null ? { upstream: [], downstream: [] } : neighborsOf(focusId, visibleEdges, nodeById),
|
|
2715
2908
|
[focusId, visibleEdges, nodeById]
|
|
2716
2909
|
);
|
|
2910
|
+
const focusImpact = (0, import_react2.useMemo)(() => {
|
|
2911
|
+
if (focusId === null) return null;
|
|
2912
|
+
const upstream = impactedBy(focusId, graph.nodes, visibleEdges);
|
|
2913
|
+
const downstream = reachableFrom(focusId, graph.nodes, visibleEdges);
|
|
2914
|
+
if (upstream === null || downstream === null) return null;
|
|
2915
|
+
upstream.delete(focusId);
|
|
2916
|
+
downstream.delete(focusId);
|
|
2917
|
+
return { upstreamCount: upstream.size, downstreamCount: downstream.size };
|
|
2918
|
+
}, [focusId, graph.nodes, visibleEdges]);
|
|
2717
2919
|
const labelOf = (0, import_react2.useCallback)(
|
|
2718
2920
|
(id) => {
|
|
2719
2921
|
const node = nodeById.get(id);
|
|
@@ -3013,7 +3215,8 @@ function GuardGraph({ graph, height = VIEWPORT_HEIGHT_WIDE, focusId, onFocusChan
|
|
|
3013
3215
|
downstream: focusNeighbors.downstream,
|
|
3014
3216
|
labelOf,
|
|
3015
3217
|
onLocate: locateNode,
|
|
3016
|
-
onClose: () => onFocusChange(null)
|
|
3218
|
+
onClose: () => onFocusChange(null),
|
|
3219
|
+
impact: focusImpact
|
|
3017
3220
|
}
|
|
3018
3221
|
),
|
|
3019
3222
|
!focusNode && selectedEdgeDetail !== null && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(EdgeDetails, { detail: selectedEdgeDetail, onClose: () => setSelectedEdgeId(null) })
|
|
@@ -3044,6 +3247,96 @@ function GuardGraph({ graph, height = VIEWPORT_HEIGHT_WIDE, focusId, onFocusChan
|
|
|
3044
3247
|
// src/client/panel/PanelCards.tsx
|
|
3045
3248
|
var import_react3 = require("react");
|
|
3046
3249
|
|
|
3250
|
+
// src/client/panel/preventive-model.ts
|
|
3251
|
+
function finite2(value) {
|
|
3252
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
3253
|
+
}
|
|
3254
|
+
function percentOrValue(value, digits = 2) {
|
|
3255
|
+
return finite2(value) ? value.toFixed(digits) : t("metrics.undefined");
|
|
3256
|
+
}
|
|
3257
|
+
function preMinute(value) {
|
|
3258
|
+
return finite2(value) ? `${value.toFixed(2)} ${t("preventive.perMinute")}` : t("metrics.undefined");
|
|
3259
|
+
}
|
|
3260
|
+
function secondsOfMs(value, digits = 1) {
|
|
3261
|
+
return finite2(value) ? `${(value / 1e3).toFixed(digits)} s` : t("metrics.undefined");
|
|
3262
|
+
}
|
|
3263
|
+
function usable(metric, required) {
|
|
3264
|
+
return metric.defined === true && metric.value !== null && required(metric.value);
|
|
3265
|
+
}
|
|
3266
|
+
function preventiveSummary(snapshot) {
|
|
3267
|
+
const note = t("preventive.alertOnly");
|
|
3268
|
+
const preventive = snapshot.preventive;
|
|
3269
|
+
if (preventive === null || preventive === void 0) {
|
|
3270
|
+
return { available: false, reads: [], source: null, note, anyAlert: false };
|
|
3271
|
+
}
|
|
3272
|
+
const load = preventive.loadTime;
|
|
3273
|
+
const loadDefined = usable(
|
|
3274
|
+
load,
|
|
3275
|
+
(value) => finite2(value.current) && finite2(value.baseline) && finite2(value.upper) && finite2(value.lower) && finite2(value.sigma) && finite2(value.ratio)
|
|
3276
|
+
);
|
|
3277
|
+
const loadRead = {
|
|
3278
|
+
key: "loadTime",
|
|
3279
|
+
title: t("preventive.loadTime"),
|
|
3280
|
+
defined: loadDefined,
|
|
3281
|
+
reason: loadDefined ? null : load.reason ?? t("metrics.valueUndefined"),
|
|
3282
|
+
label: load.label,
|
|
3283
|
+
samples: finite2(load.samples) ? load.samples : 0,
|
|
3284
|
+
alert: loadDefined ? load.value.alert === true : false,
|
|
3285
|
+
rows: loadDefined ? [
|
|
3286
|
+
{ key: "current", label: t("preventive.current"), value: preMinute(load.value.current) },
|
|
3287
|
+
{ key: "baseline", label: t("preventive.baseline"), value: preMinute(load.value.baseline) },
|
|
3288
|
+
{ key: "upper", label: t("preventive.upper"), value: preMinute(load.value.upper) },
|
|
3289
|
+
{ key: "lower", label: t("preventive.lower"), value: preMinute(load.value.lower) },
|
|
3290
|
+
{
|
|
3291
|
+
key: "sigma",
|
|
3292
|
+
label: t("preventive.sigma"),
|
|
3293
|
+
value: `${percentOrValue(load.value.sigma)} (${load.value.sigmaEstimator})`
|
|
3294
|
+
},
|
|
3295
|
+
{ key: "samples", label: t("preventive.samples"), value: String(load.samples) }
|
|
3296
|
+
] : []
|
|
3297
|
+
};
|
|
3298
|
+
const config = preventive.configChanges;
|
|
3299
|
+
const configDefined = usable(
|
|
3300
|
+
config,
|
|
3301
|
+
(value) => finite2(value.statistic) && finite2(value.threshold) && finite2(value.reference) && finite2(value.intervals) && finite2(value.baselineMs)
|
|
3302
|
+
);
|
|
3303
|
+
const configRead = {
|
|
3304
|
+
key: "configChanges",
|
|
3305
|
+
title: t("preventive.configChanges"),
|
|
3306
|
+
defined: configDefined,
|
|
3307
|
+
reason: configDefined ? null : config.reason ?? t("metrics.valueUndefined"),
|
|
3308
|
+
label: config.label,
|
|
3309
|
+
samples: finite2(config.samples) ? config.samples : 0,
|
|
3310
|
+
alert: configDefined ? config.value.alert === true : false,
|
|
3311
|
+
rows: configDefined ? [
|
|
3312
|
+
{ key: "statistic", label: t("preventive.statistic"), value: percentOrValue(config.value.statistic, 2) },
|
|
3313
|
+
{ key: "threshold", label: t("preventive.threshold"), value: percentOrValue(config.value.threshold, 2) },
|
|
3314
|
+
{ key: "reference", label: t("preventive.reference"), value: percentOrValue(config.value.reference, 2) },
|
|
3315
|
+
{ key: "baseline", label: t("preventive.baselineGap"), value: secondsOfMs(config.value.baselineMs) },
|
|
3316
|
+
{ key: "sigma", label: t("preventive.sigma"), value: secondsOfMs(config.value.sigmaMs) },
|
|
3317
|
+
{ key: "intervals", label: t("preventive.intervals"), value: String(config.value.intervals) },
|
|
3318
|
+
{
|
|
3319
|
+
key: "breach",
|
|
3320
|
+
label: t("preventive.breach"),
|
|
3321
|
+
value: config.value.breachIndex === null ? t("preventive.noBreach") : t("preventive.breachAt", { index: config.value.breachIndex })
|
|
3322
|
+
}
|
|
3323
|
+
] : []
|
|
3324
|
+
};
|
|
3325
|
+
const source = preventive.source;
|
|
3326
|
+
return {
|
|
3327
|
+
available: true,
|
|
3328
|
+
reads: [loadRead, configRead],
|
|
3329
|
+
source: source === void 0 || source === null ? null : {
|
|
3330
|
+
bootSamples: finite2(source.bootSamples) ? source.bootSamples : 0,
|
|
3331
|
+
changeSamples: finite2(source.changeSamples) ? source.changeSamples : 0,
|
|
3332
|
+
units: source.units,
|
|
3333
|
+
note: source.note
|
|
3334
|
+
},
|
|
3335
|
+
note,
|
|
3336
|
+
anyAlert: loadRead.alert || configRead.alert
|
|
3337
|
+
};
|
|
3338
|
+
}
|
|
3339
|
+
|
|
3047
3340
|
// src/client/panel/panel-model.ts
|
|
3048
3341
|
var STAGE_ORDER = ["idle", "monitoring", "crashed", "deciding", "stabilizing", "recovered"];
|
|
3049
3342
|
function stageLabelOf(stage, fallback) {
|
|
@@ -3172,14 +3465,14 @@ function metricRows(snapshot) {
|
|
|
3172
3465
|
const rows = [];
|
|
3173
3466
|
const push = (key, label, metric, format, bar) => {
|
|
3174
3467
|
const raw = metric.value;
|
|
3175
|
-
const
|
|
3468
|
+
const usable2 = metric.defined && raw !== null;
|
|
3176
3469
|
rows.push({
|
|
3177
3470
|
key,
|
|
3178
3471
|
label,
|
|
3179
|
-
value:
|
|
3180
|
-
defined:
|
|
3181
|
-
reason:
|
|
3182
|
-
bar:
|
|
3472
|
+
value: usable2 ? format(raw) : t("metrics.undefined"),
|
|
3473
|
+
defined: usable2,
|
|
3474
|
+
reason: usable2 ? null : metric.reason ?? (metric.defined ? t("metrics.valueUndefined") : null),
|
|
3475
|
+
bar: usable2 ? bar : null
|
|
3183
3476
|
});
|
|
3184
3477
|
};
|
|
3185
3478
|
push("crashRate", t("metrics.crashRate"), metrics.crashRate, (value) => pctText(value), metrics.crashRate.value ?? null);
|
|
@@ -3235,8 +3528,39 @@ function metricRows(snapshot) {
|
|
|
3235
3528
|
(value) => typeof value.label === "string" && value.label !== "" ? value.label : t("metrics.undefined"),
|
|
3236
3529
|
null
|
|
3237
3530
|
);
|
|
3531
|
+
const mismatch = survivalMismatchReason(metrics.survival);
|
|
3532
|
+
push(
|
|
3533
|
+
"survival",
|
|
3534
|
+
t("metrics.survival"),
|
|
3535
|
+
metrics.survival,
|
|
3536
|
+
(value) => {
|
|
3537
|
+
const shape = value.weibullShapeAtBound ? `k ${t("metrics.shapeAtBound")}` : `k ${isFiniteNumber(value.weibullShape) ? value.weibullShape.toFixed(2) : t("metrics.undefined")}`;
|
|
3538
|
+
const base = `${secondsText(value.exponentialMeanMs, 1)} / ${secondsText(value.weibullMeanMs, 1)} \xB7 ${shape}`;
|
|
3539
|
+
return mismatch === null ? base : `${base} \u26A0`;
|
|
3540
|
+
},
|
|
3541
|
+
null
|
|
3542
|
+
);
|
|
3543
|
+
push(
|
|
3544
|
+
"intervalTrend",
|
|
3545
|
+
t("metrics.intervalTrend"),
|
|
3546
|
+
metrics.intervalTrend,
|
|
3547
|
+
(value) => {
|
|
3548
|
+
const ratio = isFiniteNumber(value.ratio) ? value.ratio.toFixed(2) : t("metrics.undefined");
|
|
3549
|
+
const directionKey = value.direction === "denser" ? "metrics.directionDenser" : value.direction === "sparser" ? "metrics.directionSparser" : "metrics.directionSteady";
|
|
3550
|
+
return `\xD7${ratio} \xB7 ${t(directionKey)}`;
|
|
3551
|
+
},
|
|
3552
|
+
null
|
|
3553
|
+
);
|
|
3238
3554
|
return rows;
|
|
3239
3555
|
}
|
|
3556
|
+
function survivalMismatchReason(survival) {
|
|
3557
|
+
if (!survival.defined || survival.value === null) return survival.reason ?? null;
|
|
3558
|
+
const v = survival.value;
|
|
3559
|
+
if (v.weibullShapeAtBound) return t("metrics.mismatchAtBound");
|
|
3560
|
+
if (isFiniteNumber(v.cvObserved) && Math.abs(v.cvObserved - 1) > 0.5) return t("metrics.mismatchCv", { cv: v.cvObserved.toFixed(2) });
|
|
3561
|
+
if (!v.hazardDirectionReliable) return t("metrics.mismatchDirection");
|
|
3562
|
+
return null;
|
|
3563
|
+
}
|
|
3240
3564
|
var MARKOV_EXITS_LIMIT = 2;
|
|
3241
3565
|
function markovView(snapshot) {
|
|
3242
3566
|
const markov = snapshot.markov;
|
|
@@ -3564,6 +3888,14 @@ function LifecycleBody({ snapshot }) {
|
|
|
3564
3888
|
]
|
|
3565
3889
|
}
|
|
3566
3890
|
),
|
|
3891
|
+
(snapshot.unresolved?.length ?? 0) > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "rg-unresolved", role: "alert", children: [
|
|
3892
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "rg-unresolved-title", children: t("unresolved.title", { count: snapshot.unresolved?.length ?? 0 }) }),
|
|
3893
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ul", { children: snapshot.unresolved?.map((finding, index) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("li", { children: [
|
|
3894
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "rg-badge rg-badge-warn", children: finding.kind }),
|
|
3895
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "rg-unresolved-bundle", children: finding.plugins.join(" \u2194 ") }),
|
|
3896
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "rg-unresolved-detail", children: finding.message })
|
|
3897
|
+
] }, `${finding.kind}-${index}`)) })
|
|
3898
|
+
] }),
|
|
3567
3899
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ol", { className: "rg-stage-rail", "aria-label": t("state.stages"), children: rail.map((cell) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("li", { className: `rg-stage-cell rg-stage-${cell.state}`, "aria-current": cell.state === "current" ? "step" : void 0, children: [
|
|
3568
3900
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "rg-stage-dot", "aria-hidden": true }),
|
|
3569
3901
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "rg-stage-name", children: cell.label })
|
|
@@ -3864,6 +4196,34 @@ function CooccurrenceBody({ snapshot }) {
|
|
|
3864
4196
|
] })
|
|
3865
4197
|
] });
|
|
3866
4198
|
}
|
|
4199
|
+
function PreventiveBody({ snapshot }) {
|
|
4200
|
+
const summary = preventiveSummary(snapshot);
|
|
4201
|
+
if (!summary.available) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "rg-empty", children: t("preventive.unavailable") });
|
|
4202
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
4203
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "rg-notice rg-preventive-alertonly", children: summary.note }),
|
|
4204
|
+
summary.reads.map((read) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("section", { className: "rg-preventive-read", children: [
|
|
4205
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("h4", { className: "rg-card-subtitle", children: [
|
|
4206
|
+
read.title,
|
|
4207
|
+
read.defined && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: `rg-badge ${read.alert ? "rg-badge-warn" : "rg-badge-neutral"}`, children: read.alert ? t("preventive.alertYes") : t("preventive.alertNo") })
|
|
4208
|
+
] }),
|
|
4209
|
+
read.defined ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
4210
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "rg-card-note", title: read.label, children: read.label }),
|
|
4211
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("dl", { className: "rg-dl rg-dl-compact", children: read.rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "rg-dl-pair", children: [
|
|
4212
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("dt", { children: row.label }),
|
|
4213
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("dd", { children: row.value })
|
|
4214
|
+
] }, row.key)) })
|
|
4215
|
+
] }) : (
|
|
4216
|
+
// 不可判定 ⇒ 只说原因;绝不渲染 0 值(也绝不显示「一切正常」)。
|
|
4217
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "rg-empty", children: read.reason ?? t("metrics.undefined") })
|
|
4218
|
+
)
|
|
4219
|
+
] }, read.key)),
|
|
4220
|
+
summary.source !== null && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "rg-card-note", title: summary.source.note, children: t("preventive.source", {
|
|
4221
|
+
boots: summary.source.bootSamples,
|
|
4222
|
+
changes: summary.source.changeSamples,
|
|
4223
|
+
units: summary.source.units
|
|
4224
|
+
}) })
|
|
4225
|
+
] });
|
|
4226
|
+
}
|
|
3867
4227
|
function PartitionsBody({
|
|
3868
4228
|
snapshot,
|
|
3869
4229
|
selectedKey,
|
|
@@ -4073,59 +4433,6 @@ function BayesBody({ snapshot }) {
|
|
|
4073
4433
|
|
|
4074
4434
|
// src/client/panel/InsightCards.tsx
|
|
4075
4435
|
var import_react4 = require("react");
|
|
4076
|
-
|
|
4077
|
-
// src/client/graph/graph-analysis.ts
|
|
4078
|
-
function analyzeStructure(nodes, edges, hubThreshold = 3) {
|
|
4079
|
-
const inCount = /* @__PURE__ */ new Map();
|
|
4080
|
-
const outCount = /* @__PURE__ */ new Map();
|
|
4081
|
-
const known = new Set(nodes.map((n) => n.id));
|
|
4082
|
-
let edgeCount = 0;
|
|
4083
|
-
for (const edge of edges) {
|
|
4084
|
-
if (edge.from === edge.to) continue;
|
|
4085
|
-
if (!known.has(edge.from) || !known.has(edge.to)) continue;
|
|
4086
|
-
edgeCount += 1;
|
|
4087
|
-
outCount.set(edge.from, (outCount.get(edge.from) ?? 0) + 1);
|
|
4088
|
-
inCount.set(edge.to, (inCount.get(edge.to) ?? 0) + 1);
|
|
4089
|
-
}
|
|
4090
|
-
const degrees = nodes.map((node) => {
|
|
4091
|
-
const inDegree = inCount.get(node.id) ?? 0;
|
|
4092
|
-
const outDegree = outCount.get(node.id) ?? 0;
|
|
4093
|
-
const total = inDegree + outDegree;
|
|
4094
|
-
const role = total === 0 ? "isolated" : inDegree > 0 && outDegree > 0 ? total >= hubThreshold ? "hub" : "middle" : outDegree > 0 ? "source" : "sink";
|
|
4095
|
-
return { id: node.id, label: node.label, inDegree, outDegree, total, role };
|
|
4096
|
-
});
|
|
4097
|
-
degrees.sort((a, b) => b.total - a.total || a.id.localeCompare(b.id));
|
|
4098
|
-
return {
|
|
4099
|
-
degrees,
|
|
4100
|
-
hubs: degrees.filter((d) => d.role === "hub"),
|
|
4101
|
-
sources: degrees.filter((d) => d.role === "source"),
|
|
4102
|
-
sinks: degrees.filter((d) => d.role === "sink"),
|
|
4103
|
-
isolated: degrees.filter((d) => d.role === "isolated"),
|
|
4104
|
-
edgeCount,
|
|
4105
|
-
empty: nodes.length === 0
|
|
4106
|
-
};
|
|
4107
|
-
}
|
|
4108
|
-
function structureInsights(structure) {
|
|
4109
|
-
if (structure.empty) return [];
|
|
4110
|
-
const out = [];
|
|
4111
|
-
if (structure.hubs.length > 0) {
|
|
4112
|
-
const top = structure.hubs[0];
|
|
4113
|
-
out.push(`\u67A2\u7EBD ${structure.hubs.length} \u4E2A\uFF0C\u6700\u9AD8\u4E3A ${top.label}\uFF08\u8FDB ${top.inDegree} / \u51FA ${top.outDegree}\uFF09`);
|
|
4114
|
-
}
|
|
4115
|
-
if (structure.sources.length > 0) {
|
|
4116
|
-
out.push(`\u53EA\u751F\u4EA7\u4E0D\u6D88\u8D39 ${structure.sources.length} \u4E2A\uFF1A${structure.sources.slice(0, 3).map((d) => d.label).join("\u3001")}`);
|
|
4117
|
-
}
|
|
4118
|
-
if (structure.sinks.length > 0) {
|
|
4119
|
-
out.push(`\u53EA\u6D88\u8D39\u4E0D\u751F\u4EA7 ${structure.sinks.length} \u4E2A\uFF1A${structure.sinks.slice(0, 3).map((d) => d.label).join("\u3001")}`);
|
|
4120
|
-
}
|
|
4121
|
-
if (structure.isolated.length > 0) {
|
|
4122
|
-
out.push(`\u5B64\u7ACB\u8282\u70B9 ${structure.isolated.length} \u4E2A\uFF1A${structure.isolated.slice(0, 3).map((d) => d.label).join("\u3001")}`);
|
|
4123
|
-
}
|
|
4124
|
-
out.push(`\u5171 ${structure.edgeCount} \u6761\u8FB9`);
|
|
4125
|
-
return out;
|
|
4126
|
-
}
|
|
4127
|
-
|
|
4128
|
-
// src/client/panel/InsightCards.tsx
|
|
4129
4436
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
4130
4437
|
function GraphStructureBar({ graph, onLocate }) {
|
|
4131
4438
|
const [expanded, setExpanded] = (0, import_react4.useState)(false);
|
|
@@ -4287,9 +4594,105 @@ var PanelErrorBoundary = class extends import_react5.Component {
|
|
|
4287
4594
|
}
|
|
4288
4595
|
};
|
|
4289
4596
|
|
|
4597
|
+
// src/client/panel/poll-adaptive.ts
|
|
4598
|
+
var POLL_BASE_MS = 5e3;
|
|
4599
|
+
var POLL_MIN_MS = 3e3;
|
|
4600
|
+
var POLL_MAX_MS = 3e4;
|
|
4601
|
+
var POLL_BACKOFF_MULTIPLIER = 3;
|
|
4602
|
+
function positive(value, fallback) {
|
|
4603
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
|
|
4604
|
+
}
|
|
4605
|
+
function nextPollDelay(input) {
|
|
4606
|
+
const base = positive(input.baseMs, POLL_BASE_MS);
|
|
4607
|
+
let min = positive(input.minMs, POLL_MIN_MS);
|
|
4608
|
+
let max = positive(input.maxMs, POLL_MAX_MS);
|
|
4609
|
+
if (min > max) {
|
|
4610
|
+
const swapped = min;
|
|
4611
|
+
min = max;
|
|
4612
|
+
max = swapped;
|
|
4613
|
+
}
|
|
4614
|
+
const clamp = (value) => Math.round(Math.min(max, Math.max(min, value)));
|
|
4615
|
+
if (input.changed === true) return clamp(base);
|
|
4616
|
+
const rounds = typeof input.sameRounds === "number" && Number.isFinite(input.sameRounds) && input.sameRounds > 0 ? Math.floor(input.sameRounds) : 0;
|
|
4617
|
+
const cap = Math.min(max, base * POLL_BACKOFF_MULTIPLIER);
|
|
4618
|
+
const raw = base * (1 + rounds);
|
|
4619
|
+
return clamp(Number.isFinite(raw) ? Math.min(cap, raw) : cap);
|
|
4620
|
+
}
|
|
4621
|
+
function stableStringify(value) {
|
|
4622
|
+
return canonicalize(value, /* @__PURE__ */ new Set());
|
|
4623
|
+
}
|
|
4624
|
+
function canonicalize(value, stack) {
|
|
4625
|
+
if (value === null) return "null";
|
|
4626
|
+
switch (typeof value) {
|
|
4627
|
+
case "number":
|
|
4628
|
+
return Number.isFinite(value) ? JSON.stringify(value) : "null";
|
|
4629
|
+
case "string":
|
|
4630
|
+
return JSON.stringify(value);
|
|
4631
|
+
case "boolean":
|
|
4632
|
+
return value ? "true" : "false";
|
|
4633
|
+
case "bigint":
|
|
4634
|
+
return JSON.stringify(`${value.toString()}n`);
|
|
4635
|
+
case "undefined":
|
|
4636
|
+
case "function":
|
|
4637
|
+
case "symbol":
|
|
4638
|
+
return "null";
|
|
4639
|
+
default:
|
|
4640
|
+
break;
|
|
4641
|
+
}
|
|
4642
|
+
if (Array.isArray(value)) {
|
|
4643
|
+
if (stack.has(value)) return JSON.stringify("[Circular]");
|
|
4644
|
+
stack.add(value);
|
|
4645
|
+
const out = `[${value.map((entry) => canonicalize(entry, stack)).join(",")}]`;
|
|
4646
|
+
stack.delete(value);
|
|
4647
|
+
return out;
|
|
4648
|
+
}
|
|
4649
|
+
const object = value;
|
|
4650
|
+
if (stack.has(object)) return JSON.stringify("[Circular]");
|
|
4651
|
+
stack.add(object);
|
|
4652
|
+
const parts = [];
|
|
4653
|
+
for (const key of Object.keys(object).sort()) {
|
|
4654
|
+
const entry = object[key];
|
|
4655
|
+
if (entry === void 0 || typeof entry === "function" || typeof entry === "symbol") continue;
|
|
4656
|
+
parts.push(`${JSON.stringify(key)}:${canonicalize(entry, stack)}`);
|
|
4657
|
+
}
|
|
4658
|
+
stack.delete(object);
|
|
4659
|
+
return `{${parts.join(",")}}`;
|
|
4660
|
+
}
|
|
4661
|
+
function fnv1a32(text) {
|
|
4662
|
+
let hash = 2166136261;
|
|
4663
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
4664
|
+
hash ^= text.charCodeAt(index);
|
|
4665
|
+
hash = Math.imul(hash, 16777619);
|
|
4666
|
+
}
|
|
4667
|
+
return hash >>> 0;
|
|
4668
|
+
}
|
|
4669
|
+
var OMIT_TOP_LEVEL = /* @__PURE__ */ new Set(["at"]);
|
|
4670
|
+
var OMIT_DIAGNOSTIC_KEYS = /* @__PURE__ */ new Set(["snapshotMs"]);
|
|
4671
|
+
function stripVolatile(snapshot) {
|
|
4672
|
+
if (snapshot === null || typeof snapshot !== "object" || Array.isArray(snapshot)) return snapshot;
|
|
4673
|
+
const copy = { ...snapshot };
|
|
4674
|
+
for (const key of OMIT_TOP_LEVEL) delete copy[key];
|
|
4675
|
+
const diagnostics = copy.diagnostics;
|
|
4676
|
+
if (diagnostics !== null && typeof diagnostics === "object" && !Array.isArray(diagnostics)) {
|
|
4677
|
+
const cleaned = { ...diagnostics };
|
|
4678
|
+
for (const key of OMIT_DIAGNOSTIC_KEYS) delete cleaned[key];
|
|
4679
|
+
copy.diagnostics = cleaned;
|
|
4680
|
+
}
|
|
4681
|
+
return copy;
|
|
4682
|
+
}
|
|
4683
|
+
function snapshotFingerprint(snapshot) {
|
|
4684
|
+
return fnv1a32(stableStringify(stripVolatile(snapshot))).toString(16).padStart(8, "0");
|
|
4685
|
+
}
|
|
4686
|
+
function graphFingerprint(graph) {
|
|
4687
|
+
return fnv1a32(stableStringify(graph ?? null)).toString(16).padStart(8, "0");
|
|
4688
|
+
}
|
|
4689
|
+
function pollContentFingerprint(snapshot, graph) {
|
|
4690
|
+
return `${snapshotFingerprint(snapshot)}|${graphFingerprint(graph)}`;
|
|
4691
|
+
}
|
|
4692
|
+
|
|
4290
4693
|
// src/client/panel/GuardPanel.tsx
|
|
4291
4694
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
4292
|
-
var
|
|
4695
|
+
var POLL_BASE = POLL_BASE_MS;
|
|
4293
4696
|
var COLLAPSE_KEY = "recency-guard-collapsed";
|
|
4294
4697
|
function loadCollapsed() {
|
|
4295
4698
|
try {
|
|
@@ -4313,6 +4716,8 @@ function GuardPanel(props) {
|
|
|
4313
4716
|
const [failure, setFailure] = (0, import_react6.useState)(null);
|
|
4314
4717
|
const [busy, setBusy] = (0, import_react6.useState)(false);
|
|
4315
4718
|
const [polling, setPolling] = (0, import_react6.useState)(true);
|
|
4719
|
+
const [pollDelay, setPollDelay] = (0, import_react6.useState)(POLL_BASE);
|
|
4720
|
+
const [stableRounds, setStableRounds] = (0, import_react6.useState)(0);
|
|
4316
4721
|
const [collapsed, setCollapsed] = (0, import_react6.useState)(() => loadCollapsed());
|
|
4317
4722
|
const [form, setForm] = (0, import_react6.useState)("wide");
|
|
4318
4723
|
const [selectedNodeId, setSelectedNodeId] = (0, import_react6.useState)(null);
|
|
@@ -4323,6 +4728,8 @@ function GuardPanel(props) {
|
|
|
4323
4728
|
const [conflictNotice, setConflictNotice] = (0, import_react6.useState)(false);
|
|
4324
4729
|
const rootRef = (0, import_react6.useRef)(null);
|
|
4325
4730
|
const mounted = (0, import_react6.useRef)(true);
|
|
4731
|
+
const fingerprintRef = (0, import_react6.useRef)(null);
|
|
4732
|
+
const sameRoundsRef = (0, import_react6.useRef)(0);
|
|
4326
4733
|
const load = (0, import_react6.useCallback)(
|
|
4327
4734
|
async (partitionKey) => {
|
|
4328
4735
|
const [snapshotResult, graphResult, archivesResult] = await Promise.all([
|
|
@@ -4332,7 +4739,7 @@ function GuardPanel(props) {
|
|
|
4332
4739
|
// 面板据此隐藏归档卡片 —— 不假装「归档为空」。
|
|
4333
4740
|
props.fetchArchives ? props.fetchArchives(partitionKey ?? void 0) : Promise.resolve({ ok: false, reason: "archives-absent" })
|
|
4334
4741
|
]);
|
|
4335
|
-
if (!mounted.current) return;
|
|
4742
|
+
if (!mounted.current) return { changed: true, sameRounds: 0 };
|
|
4336
4743
|
if (snapshotResult.ok) {
|
|
4337
4744
|
setSnapshot(snapshotResult.data);
|
|
4338
4745
|
setFailure(null);
|
|
@@ -4351,21 +4758,50 @@ function GuardPanel(props) {
|
|
|
4351
4758
|
archivesInjected: props.fetchArchives !== void 0
|
|
4352
4759
|
})
|
|
4353
4760
|
);
|
|
4761
|
+
if (!snapshotResult.ok) {
|
|
4762
|
+
sameRoundsRef.current = 0;
|
|
4763
|
+
return { changed: true, sameRounds: 0 };
|
|
4764
|
+
}
|
|
4765
|
+
const fingerprint = pollContentFingerprint(
|
|
4766
|
+
snapshotResult.data,
|
|
4767
|
+
graphResult.ok ? graphResult.data : null
|
|
4768
|
+
);
|
|
4769
|
+
const previous = fingerprintRef.current;
|
|
4770
|
+
const changed = previous === null || previous !== fingerprint;
|
|
4771
|
+
const sameRounds = changed ? 0 : Math.min(sameRoundsRef.current + 1, 999);
|
|
4772
|
+
fingerprintRef.current = fingerprint;
|
|
4773
|
+
sameRoundsRef.current = sameRounds;
|
|
4774
|
+
return { changed, sameRounds };
|
|
4354
4775
|
},
|
|
4355
4776
|
[props.fetchSnapshot, props.fetchGraph, props.fetchArchives]
|
|
4356
4777
|
);
|
|
4357
4778
|
(0, import_react6.useEffect)(() => {
|
|
4358
4779
|
mounted.current = true;
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4780
|
+
let cancelled = false;
|
|
4781
|
+
let timer = null;
|
|
4782
|
+
const afterLoad = (outcome) => {
|
|
4783
|
+
if (cancelled) return;
|
|
4784
|
+
const delay = nextPollDelay({
|
|
4785
|
+
sameRounds: outcome.sameRounds,
|
|
4786
|
+
changed: outcome.changed,
|
|
4787
|
+
baseMs: POLL_BASE
|
|
4788
|
+
});
|
|
4789
|
+
setPollDelay(delay);
|
|
4790
|
+
setStableRounds(outcome.sameRounds);
|
|
4791
|
+
if (!polling) return;
|
|
4792
|
+
timer = setTimeout(() => {
|
|
4793
|
+
void run();
|
|
4794
|
+
}, delay);
|
|
4795
|
+
};
|
|
4796
|
+
const run = async () => {
|
|
4797
|
+
const outcome = await load(requestedKey);
|
|
4798
|
+
afterLoad(outcome);
|
|
4799
|
+
};
|
|
4800
|
+
void run();
|
|
4366
4801
|
return () => {
|
|
4802
|
+
cancelled = true;
|
|
4803
|
+
if (timer !== null) clearTimeout(timer);
|
|
4367
4804
|
mounted.current = false;
|
|
4368
|
-
clearInterval(timer);
|
|
4369
4805
|
};
|
|
4370
4806
|
}, [load, polling, requestedKey]);
|
|
4371
4807
|
(0, import_react6.useEffect)(() => {
|
|
@@ -4455,6 +4891,13 @@ function GuardPanel(props) {
|
|
|
4455
4891
|
currentPartition && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "rg-subtitle rg-partition-workspace-full", title: currentPartition.workspace, children: shortenPath(currentPartition.workspace, 72) })
|
|
4456
4892
|
] }),
|
|
4457
4893
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rg-actions", children: [
|
|
4894
|
+
polling && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "rg-poll-chip", role: "status", title: t("panel.pollingHint"), children: [
|
|
4895
|
+
t("panel.pollingOn", { seconds: Math.max(1, Math.round(pollDelay / 1e3)) }),
|
|
4896
|
+
stableRounds > 0 && pollDelay > POLL_BASE && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
4897
|
+
" \xB7 ",
|
|
4898
|
+
t("panel.pollingBackoff")
|
|
4899
|
+
] })
|
|
4900
|
+
] }),
|
|
4458
4901
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
4459
4902
|
"button",
|
|
4460
4903
|
{
|
|
@@ -4623,6 +5066,17 @@ function GuardPanel(props) {
|
|
|
4623
5066
|
}
|
|
4624
5067
|
),
|
|
4625
5068
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { className: "rg-group-title", children: t("groups.observation") }),
|
|
5069
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
5070
|
+
Card,
|
|
5071
|
+
{
|
|
5072
|
+
id: "preventive",
|
|
5073
|
+
title: t("sections.preventive"),
|
|
5074
|
+
hint: t("preventive.hint"),
|
|
5075
|
+
collapsed: collapsed.has("preventive"),
|
|
5076
|
+
onToggle: () => toggleCollapse("preventive"),
|
|
5077
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PreventiveBody, { snapshot })
|
|
5078
|
+
}
|
|
5079
|
+
),
|
|
4626
5080
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
4627
5081
|
Card,
|
|
4628
5082
|
{
|
|
@@ -4734,7 +5188,13 @@ function GuardPanel(props) {
|
|
|
4734
5188
|
failure !== null && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "rg-error", role: "alert", children: failure }),
|
|
4735
5189
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("footer", { className: "rg-foot", children: [
|
|
4736
5190
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: t("panel.snapshotAt", { time: snapshot.at.replace("T", " ").slice(0, 19) }) }),
|
|
4737
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.
|
|
5191
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { children: [
|
|
5192
|
+
polling ? t("panel.pollingOn", { seconds: Math.max(1, Math.round(pollDelay / 1e3)) }) : t("panel.stale", { minutes: staleMinutes }),
|
|
5193
|
+
polling && stableRounds > 0 && pollDelay > POLL_BASE && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5194
|
+
" \xB7 ",
|
|
5195
|
+
t("panel.pollingBackoff")
|
|
5196
|
+
] })
|
|
5197
|
+
] })
|
|
4738
5198
|
] })
|
|
4739
5199
|
] }) })
|
|
4740
5200
|
] });
|
|
@@ -4990,7 +5450,7 @@ function openPanel(ctx) {
|
|
|
4990
5450
|
}
|
|
4991
5451
|
|
|
4992
5452
|
// src/client/styles.css
|
|
4993
|
-
var styles_default = "/**\n * \u7BA1\u7406\u9762\u677F\u7684\u6837\u5F0F\u3002\n *\n * ## \u7EAA\u5F8B\n *\n * 1. **\u53EA\u7528\u4E3B\u9898\u53D8\u91CF**\uFF1A\u989C\u8272\u3001\u5706\u89D2\u3001\u5B57\u4F53\u5168\u90E8\u5F15\u7528 `--dsw-alias-*` / `--dsw-radius-*`\n * / `--dsw-shadow-*` \u5BB6\u65CF\u3002\u5BBF\u4E3B\u91CD\u547D\u540D\u4E00\u4E2A\u53D8\u91CF\u65F6\u9762\u677F\u53EA\u662F\u53D8\u4E11\uFF0C\u4E0D\u4F1A\u5D29 \u2014\u2014\n * \u56E0\u6B64\u6BCF\u4E2A var() \u90FD\u5E26\u4E00\u4E2A\u4FDD\u5B88\u7684\u515C\u5E95\u503C\u3002\n * 2. **\u4E24\u79CD\u5F62\u6001\u6309\u5BB9\u5668\u5BBD\u5EA6**\uFF1A`.rg-panel[data-form=\"narrow\"]` \u7531 JS \u6D4B\u51FA\u7684\n * \u9762\u677F\u5BBD\u5EA6\u9A71\u52A8\uFF08\u9762\u677F\u53EF\u80FD\u6302\u5728\u88AB\u62D6\u7A84\u7684\u4FA7\u680F\u91CC\uFF0C\u5A92\u4F53\u67E5\u8BE2\u91CF\u7684\u662F\u7A97\u53E3\uFF0C\u4F1A\u7B54\u9519\uFF09\u3002\n * 3. **\u5C40\u90E8\u52A8\u6548\u4EE4\u724C**\uFF1A\u8FC7\u6E21\u65F6\u957F\u4E0E\u7F13\u52A8\u5B9A\u4E49\u5728 `.rg-panel` \u4E0A\u7684 `--rg-*`\uFF0C\n * \u4E0D\u4F9D\u8D56\u672A\u7ECF\u9A8C\u8BC1\u7684\u5168\u5C40 `--ds-*`\uFF08\u751F\u6001\u63D2\u4EF6\u540C\u6837\u81EA\u6301\u8FD9\u5957\u4EE4\u724C\uFF09\u3002\n * 4. **\u4E0D\u5199\u6B7B\u5BB9\u5668\u5BBD\u5EA6**\uFF1A\u9762\u677F\u5360\u6EE1\u5BBF\u4E3B\u7ED9\u7684\u4E2D\u592E\u9762\u677F\u533A\u57DF\u3002\n * 5. **\u5BF9\u6BD4\u5EA6**\uFF1A\u6B63\u6587 `--dsw-alias-label-primary`\uFF0C\u6B21\u8981 `--dsw-alias-label-secondary`\uFF0C\n * \u63D0\u793A `--dsw-alias-label-tertiary`\uFF08\u4EAE/\u6697\u4E3B\u9898\u90FD\u7531\u5BBF\u4E3B\u4FDD\u8BC1\u53EF\u8BFB\uFF09\u3002\n */\n\n.rg-panel {\n /* \u5C40\u90E8\u4EE4\u724C\uFF1A\u63A7\u4EF6\u9AD8\u5EA6\u3001\u52A8\u6548\u3001\u95F4\u8DDD\u3002\u6539\u4E00\u5904\uFF0C\u6574\u5757\u9762\u677F\u8DDF\u7740\u4E00\u81F4\u3002 */\n --rg-control-h: 28px;\n --rg-motion-fast: 120ms;\n --rg-motion-medium: 200ms;\n --rg-ease: cubic-bezier(0.2, 0, 0, 1);\n --rg-gap: 16px;\n\n display: flex;\n flex-direction: column;\n gap: var(--rg-gap);\n padding: 20px 24px 32px;\n min-width: 0;\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-bg-base);\n font-family: var(--dsw-font-family);\n font-size: var(--dsw-font-s-14, 14px);\n line-height: var(--dsw-font-s-14-line-height, 22px);\n\n /**\n * \u9762\u677F\u5FC5\u987B**\u81EA\u5DF1**\u662F\u6EDA\u52A8\u5BB9\u5668\u3002\n *\n * \u4E3A\u4EC0\u4E48\u4E0D\u80FD\u6307\u671B\u5BBF\u4E3B\uFF1A\u5B9E\u6D4B\uFF08\u6C99\u7BB1 sb-rg-c5\uFF09\u5BBF\u4E3B\u69FD\u4F4D\u662F\u8FD9\u6837\u4E00\u4E32\n * .centerCol { overflow-y: hidden } \u2190 \u7956\u5148\u628A\u6EA2\u51FA\u88C1\u6389\n * .mainPanel { height: 714px; overflow: visible }\n * .rg-panel { height: 3965px } \u2190 \u5185\u5BB9\u81EA\u7136\u9AD8\u5EA6\uFF0C\u8D85\u51FA\u540E\u76F4\u63A5\u88AB\u88C1\n * \u6587\u6863\u672C\u8EAB\u4E0D\u6EDA\uFF08docScrollH == clientH == 714\uFF09\uFF0C\u56E0\u6B64**\u4E0B\u65B9\u6570\u636E\u9875\u6C38\u8FDC\u770B\u4E0D\u5230**\u3002\n *\n * \u4E09\u4E2A\u5C5E\u6027\u7F3A\u4E00\u4E0D\u53EF\uFF1A\n * - `height: 100%` + `min-height: 0`\uFF1A\u6491\u6EE1\u5BBF\u4E3B\u7ED9\u7684\u786E\u5B9A\u9AD8\u5EA6\uFF0C\u4E14\u5141\u8BB8\u6536\u7F29\u5230\u53EF\u6EDA\u52A8\uFF1B\n * \u53EA\u5199 overflow \u800C\u4E0D\u9650\u5236\u9AD8\u5EA6\uFF0Cflex \u5B50\u9879\u4ECD\u4F1A\u6309\u5185\u5BB9\u6491\u5F00\uFF0C\u6EDA\u4E0D\u8D77\u6765\u3002\n * - `overflow-y: auto`\uFF1A\u9762\u677F\u81EA\u5DF1\u6EDA\u3002\n * - `overscroll-behavior: contain`\uFF1A\u6EDA\u5230\u5C3D\u5934\u4E0D\u628A\u6EDA\u52A8\u4F20\u7ED9\u5BBF\u4E3B\uFF0C\u5426\u5219\u4F1A\u628A\u6574\u9875/\u4FA7\u680F\n * \u5E26\u7740\u4E00\u8D77\u6EDA\uFF0C\u89C6\u89C9\u4E0A\u50CF\"\u9762\u677F\u5728\u4E71\u8DF3\"\u3002\n */\n height: 100%;\n max-height: 100%;\n min-height: 0;\n overflow-y: auto;\n overflow-x: hidden;\n overscroll-behavior: contain;\n}\n\n/* \u7A84\u5F62\u6001\uFF08\u4FA7\u680F / \u5206\u5C4F\uFF09\uFF1A\u6536\u7D27\u8FB9\u8DDD\u4E0E\u95F4\u8DDD\uFF0C\u628A\u7EB5\u5411\u7A7A\u95F4\u8BA9\u7ED9\u5185\u5BB9\u3002 */\n.rg-panel[data-form='narrow'] {\n --rg-gap: 12px;\n padding: 14px 14px 24px;\n font-size: var(--dsw-font-xs-13, 13px);\n}\n\n/* ---------- \u5934\u90E8 ---------- */\n\n.rg-header {\n display: flex;\n flex-wrap: wrap;\n align-items: flex-start;\n justify-content: space-between;\n gap: 12px;\n}\n\n.rg-header-main {\n min-width: 0;\n flex: 1 1 260px;\n}\n\n.rg-title {\n margin: 0;\n font-size: var(--dsw-font-l-20, 20px);\n font-weight: var(--dsw-font-l-20-font-weight, 600);\n color: var(--dsw-alias-label-primary);\n}\n\n.rg-panel[data-form='narrow'] .rg-title {\n font-size: var(--dsw-font-m-18, 18px);\n}\n\n.rg-subtitle {\n margin: 4px 0 0;\n font-size: var(--dsw-font-xs-13, 13px);\n color: var(--dsw-alias-label-secondary);\n overflow-wrap: anywhere;\n}\n\n.rg-project-name {\n font-weight: var(--dsw-font-xs-strong-13, 600);\n color: var(--dsw-alias-label-primary);\n}\n\n.rg-partition-workspace-full {\n font-size: var(--dsw-font-xxs-12, 12px);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n max-width: 100%;\n direction: ltr;\n}\n\n.rg-actions {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n/* ---------- \u63A7\u4EF6 ---------- */\n\n.rg-button {\n appearance: none;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n min-height: var(--rg-control-h);\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n border-radius: var(--dsw-radius-sm, 8px);\n padding: 4px 12px;\n font: inherit;\n font-size: var(--dsw-font-xs-13, 13px);\n cursor: pointer;\n transition:\n background var(--rg-motion-fast) var(--rg-ease),\n border-color var(--rg-motion-fast) var(--rg-ease);\n}\n\n.rg-button:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover, var(--dsw-alias-bg-layer-2));\n}\n\n.rg-button:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-alias-brand-primary);\n outline-offset: 2px;\n}\n\n.rg-button:disabled {\n opacity: 0.45;\n cursor: not-allowed;\n}\n\n.rg-button-small {\n min-height: 24px;\n padding: 2px 9px;\n font-size: var(--dsw-font-xxs-12, 12px);\n}\n\n.rg-button-icon {\n min-width: 28px;\n padding: 2px 6px;\n justify-content: center;\n font-size: var(--dsw-font-s-14, 14px);\n line-height: 1;\n}\n\n.rg-button-danger {\n border-color: var(--dsw-alias-state-error-primary);\n color: var(--dsw-alias-state-error-primary);\n}\n\n.rg-button-active {\n border-color: var(--dsw-alias-brand-primary);\n color: var(--dsw-alias-brand-primary);\n}\n\n/* \u8F6E\u8BE2\u6682\u505C\u6001\u6309\u94AE\uFF08\u6682\u505C = \u9700\u8981\u88AB\u770B\u89C1\u7684\u72B6\u6001\uFF0C\u4E0D\u80FD\u53EA\u9760 aria-pressed\uFF09\u3002 */\n.rg-button-paused {\n border-color: var(--dsw-alias-state-warn-primary);\n color: var(--dsw-alias-state-warn-primary);\n}\n\n.rg-link {\n appearance: none;\n border: none;\n background: none;\n padding: 0 2px;\n font: inherit;\n font-size: inherit;\n color: var(--dsw-alias-brand-primary);\n cursor: pointer;\n text-decoration: underline;\n}\n\n/* \u5206\u6BB5\u63A7\u4EF6\uFF08\u5E03\u5C40 / \u7740\u8272\u53E3\u5F84\uFF09\u3002 */\n.rg-segmented {\n display: inline-flex;\n align-items: stretch;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-sm, 8px);\n overflow: hidden;\n background: var(--dsw-alias-bg-layer-1);\n}\n\n.rg-segment {\n appearance: none;\n border: none;\n border-right: 1px solid var(--dsw-alias-border-l1);\n background: none;\n color: var(--dsw-alias-label-secondary);\n padding: 3px 9px;\n font: inherit;\n font-size: var(--dsw-font-xxs-12, 12px);\n cursor: pointer;\n transition: background var(--rg-motion-fast) var(--rg-ease);\n}\n\n.rg-segment:last-child {\n border-right: none;\n}\n\n.rg-segment:hover {\n background: var(--dsw-alias-interactive-bg-hover, var(--dsw-alias-bg-layer-2));\n}\n\n.rg-segment[aria-pressed='true'] {\n background: var(--dsw-alias-interactive-bg-active, var(--dsw-alias-bg-layer-2));\n color: var(--dsw-alias-label-primary);\n font-weight: var(--dsw-font-xxs-strong-12, 600);\n}\n\n.rg-segment:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n\n.rg-field {\n display: flex;\n flex-direction: column;\n gap: 3px;\n min-width: 0;\n}\n\n.rg-field-grow {\n flex: 1 1 160px;\n}\n\n.rg-field-label {\n font-size: var(--dsw-font-xxs-12, 12px);\n color: var(--dsw-alias-label-secondary);\n}\n\n.rg-input,\n.rg-select {\n min-height: var(--rg-control-h);\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-sm, 8px);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n padding: 2px 8px;\n font: inherit;\n font-size: var(--dsw-font-xs-13, 13px);\n max-width: 100%;\n}\n\n.rg-input:focus-visible,\n.rg-select:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* ---------- \u63D0\u793A\u6761 ---------- */\n\n.rg-notice {\n margin: 0;\n padding: 8px 10px;\n border: 1px solid var(--dsw-alias-state-warn-primary);\n border-radius: var(--dsw-radius-sm, 8px);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n font-size: var(--dsw-font-xxs-12, 12px);\n}\n\n.rg-error {\n margin: 0;\n padding: 10px 12px;\n border-radius: var(--dsw-radius-sm, 8px);\n border: 1px solid var(--dsw-alias-state-error-primary);\n color: var(--dsw-alias-state-error-primary);\n font-size: var(--dsw-font-xs-13, 13px);\n}\n\n.rg-empty {\n margin: 0;\n padding: 8px 0;\n font-size: var(--dsw-font-xs-13, 13px);\n color: var(--dsw-alias-label-secondary);\n}\n\n.rg-muted {\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n}\n\n.rg-strong {\n font-weight: var(--dsw-font-xs-strong-13, 600);\n}\n\n.rg-block {\n display: block;\n}\n\n.rg-ellipsis {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.rg-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 16px;\n margin-left: 6px;\n padding: 0 4px;\n border-radius: 999px;\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-secondary);\n font-size: var(--dsw-font-xxxs-11, 11px);\n}\n\n/* \u52A0\u8F7D / \u4E0D\u53EF\u7528\u72B6\u6001\u5757\uFF1A\u5360\u4F4D\u9AD8\u5EA6\u7A33\u5B9A\uFF0C\u907F\u514D\u8F6E\u8BE2\u65F6\u9875\u9762\u8DF3\u52A8\u3002 */\n.rg-state-block {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 24px 0;\n}\n\n.rg-state-title {\n margin: 0;\n font-size: var(--dsw-font-m-18, 18px);\n font-weight: var(--dsw-font-m-18-font-weight, 600);\n}\n\n/* ---------- \u5361\u7247\u7F51\u683C ---------- */\n\n.rg-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));\n gap: 12px;\n}\n\n.rg-panel[data-form='narrow'] .rg-grid {\n grid-template-columns: 1fr;\n}\n\n.rg-card {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 14px 16px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: var(--dsw-radius-md, 12px);\n background: var(--dsw-alias-bg-layer-1);\n min-width: 0;\n min-height: 0;\n}\n\n/**\n * \u5361\u7247\u5185\u5BB9\u533A\u56FA\u5B9A\u9AD8\u5EA6 + \u5185\u90E8\u6EDA\u52A8\uFF08v0.9.1 \u7528\u6237\u9700\u6C42\uFF09\u3002\n *\n * \u4E3A\u4EC0\u4E48\u9650\u9AD8\u800C\u4E0D\u662F\u8BA9\u5185\u5BB9\u81EA\u7136\u4F38\u5C55\uFF1A\u5C55\u5F00\u7684\u5361\u7247\u591A\u4E86\u4E4B\u540E\uFF0C\u9762\u677F\u88AB\u5355\u4E2A\n * \u5361\u7247\u6491\u5230\u51E0\u5343\u50CF\u7D20\uFF0C\u4E0B\u9762\u7684\u5361\u7247\u8981\u6EDA\u5F88\u4E45\u624D\u770B\u5F97\u5230 \u2014\u2014 \u5747\u5300\u7684\u89C6\u53E3\u5BC6\u5EA6\n * \u6BD4\u5355\u5361\u7684\u5B8C\u6574\u6027\u66F4\u91CD\u8981\uFF08\u8FD9\u6B63\u662F\u7528\u6237\u539F\u59CB\u8BC9\u6C42\uFF09\u3002\n *\n * - \u9ED8\u8BA4 `--rg-card-body-h: 240px`\uFF1A\u8DB3\u591F\u770B\u7EA6 10 \u884C\u5185\u5BB9\uFF0C\u8D85\u51FA\u5185\u90E8\u6EDA\u52A8\uFF1B\n * - `overscroll-behavior: contain`\uFF1A\u6EDA\u5230\u5C3D\u5934\u4E0D\u628A\u5916\u5C42\u9762\u677F\u5E26\u7740\u6EDA\uFF1B\n * - `.rg-card-enlarged` \u89E3\u9664\u9650\u9AD8\uFF08\u2922 \u6309\u94AE\uFF09\uFF0C\u644A\u5F00\u9605\u8BFB\u957F\u6E05\u5355\uFF1B\n * - \u7A84\u5F62\u6001\u628A\u9650\u9AD8\u964D\u5230 180px\uFF08\u4FA7\u680F\u7A7A\u95F4\u5C11\uFF0C\u5BC6\u5EA6\u4F18\u5148\uFF09\u3002\n */\n.rg-card-body {\n display: flex;\n flex-direction: column;\n gap: 10px;\n height: var(--rg-card-body-h, 240px);\n overflow-y: auto;\n overscroll-behavior: contain;\n min-height: 0;\n}\n\n/* \u6269\u5927\u6001\uFF1A\u89E3\u9664\u9650\u9AD8\uFF0C\u5361\u7247\u6309\u5185\u5BB9\u81EA\u7136\u4F38\u5C55\uFF08\u9762\u677F\u81EA\u8EAB\u4ECD\u662F\u6EDA\u52A8\u5BB9\u5668\uFF09\u3002 */\n.rg-card-enlarged .rg-card-body {\n height: auto;\n max-height: none;\n overflow-y: visible;\n}\n\n/* \u6269\u5927\u6309\u94AE\uFF1A\u5934\u90E8\u5185\u7684\u7B2C\u4E8C\u4E2A\u52A8\u4F5C\uFF0C\u5C0F\u5C3A\u5BF8\u3001\u4F4E\u5BF9\u6BD4\uFF0C\u4E0D\u4E0E\u6298\u53E0\u7BAD\u5934\u7ADE\u4E89\u3002 */\n.rg-card-expand {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 22px;\n height: 22px;\n margin-left: auto;\n border-radius: var(--dsw-radius-sm, 8px);\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n user-select: none;\n transition: background var(--rg-motion-fast, 120ms) var(--rg-ease, ease);\n}\n.rg-card-expand:hover,\n.rg-card-expand:focus-visible {\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n}\n.rg-card-enlarged .rg-card-expand {\n color: var(--dsw-alias-label-primary);\n}\n\n.rg-card-title {\n margin: 0;\n font-size: var(--dsw-font-s-14, 14px);\n font-weight: var(--dsw-font-s-strong-14, 600);\n}\n\n/* \u7A84\u5F62\u6001\uFF1A\u4FA7\u680F\u7A7A\u95F4\u5C11\uFF0C\u5BC6\u5EA6\u4F18\u5148 \u2014\u2014 \u5185\u5BB9\u533A\u9650\u9AD8\u964D\u4E3A 180px\u3002 */\n.rg-panel[data-form='narrow'] .rg-card-body {\n --rg-card-body-h: 180px;\n}\n\n.rg-card-title {\n margin: 0;\n font-size: var(--dsw-font-s-14, 14px);\n font-weight: var(--dsw-font-s-strong-14, 600);\n}\n\n.rg-card-subtitle {\n margin: 4px 0 0;\n font-size: var(--dsw-font-xxs-12, 12px);\n font-weight: var(--dsw-font-xxs-strong-12, 600);\n color: var(--dsw-alias-label-secondary);\n}\n\n.rg-card-note {\n margin: 0;\n font-size: var(--dsw-font-xxs-12, 12px);\n color: var(--dsw-alias-label-secondary);\n}\n\n/* \u53EF\u6298\u53E0\u5361\u7247\uFF1A\u6807\u9898\u884C\u662F\u6309\u94AE\uFF0C\u6574\u4E2A\u5934\u90E8\u53EF\u70B9\u3002 */\n.rg-card-head {\n appearance: none;\n border: none;\n background: none;\n padding: 0;\n margin: 0;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n width: 100%;\n cursor: pointer;\n font: inherit;\n color: inherit;\n text-align: left;\n}\n\n.rg-card-head:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-alias-brand-primary);\n outline-offset: 2px;\n border-radius: var(--dsw-radius-xs, 4px);\n}\n\n.rg-card-head-hint {\n margin-left: auto;\n font-size: var(--dsw-font-xxxs-11, 11px);\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.rg-card-chevron {\n color: var(--dsw-alias-label-secondary);\n font-size: var(--dsw-font-xxs-12, 12px);\n}\n\n.rg-card-collapsed {\n padding-bottom: 10px;\n}\n\n.rg-card-body {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n/* ---------- \u5FBD\u6807 / \u5706\u70B9 / \u8BA1\u6570\u7247 ---------- */\n\n.rg-badge {\n display: inline-flex;\n align-items: center;\n padding: 1px 8px;\n border-radius: var(--dsw-radius-sm, 8px);\n border: 1px solid var(--dsw-alias-border-l2);\n font-size: var(--dsw-font-xxs-12, 12px);\n white-space: nowrap;\n}\n\n.rg-badge-idle,\n.rg-badge-monitoring {\n border-color: var(--dsw-alias-brand-primary);\n color: var(--dsw-alias-brand-primary);\n}\n\n.rg-badge-crashed,\n.rg-badge-error {\n border-color: var(--dsw-alias-state-error-primary);\n color: var(--dsw-alias-state-error-primary);\n}\n\n.rg-badge-deciding,\n.rg-badge-worsening,\n.rg-badge-warn {\n border-color: var(--dsw-alias-state-warn-primary);\n color: var(--dsw-alias-state-warn-primary);\n}\n\n.rg-badge-stabilizing,\n.rg-badge-recovered,\n.rg-badge-improving,\n.rg-badge-success {\n border-color: var(--dsw-alias-state-success-primary);\n color: var(--dsw-alias-state-success-primary);\n}\n\n.rg-badge-stable,\n.rg-badge-neutral {\n border-color: var(--dsw-alias-border-l2);\n color: var(--dsw-alias-label-secondary);\n}\n\n.rg-chip {\n display: inline-flex;\n align-items: center;\n padding: 0 6px;\n border-radius: var(--dsw-radius-xs, 4px);\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-secondary);\n font-size: var(--dsw-font-xxxs-11, 11px);\n white-space: nowrap;\n}\n\n.rg-chip-warn {\n border: 1px solid var(--dsw-alias-state-warn-primary);\n color: var(--dsw-alias-state-warn-primary);\n background: none;\n}\n\n.rg-chip-more {\n font-variant-numeric: tabular-nums;\n}\n\n.rg-names {\n display: inline-flex;\n flex-wrap: wrap;\n gap: 3px;\n min-width: 0;\n}\n\n.rg-dot {\n display: inline-block;\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: var(--dsw-alias-label-secondary);\n flex: none;\n}\n\n.rg-dot-info {\n background: var(--dsw-alias-brand-primary);\n}\n\n.rg-dot-success {\n background: var(--dsw-alias-state-success-primary);\n}\n\n.rg-dot-warn {\n background: var(--dsw-alias-state-warn-primary);\n}\n\n.rg-dot-error {\n background: var(--dsw-alias-state-error-primary);\n}\n\n/* ---------- \u8FDB\u5EA6\u6761 ---------- */\n\n.rg-bar {\n display: inline-block;\n width: 72px;\n height: 4px;\n border-radius: 2px;\n background: var(--dsw-alias-bg-layer-2);\n overflow: hidden;\n flex: none;\n}\n\n.rg-bar-wide {\n width: 100%;\n}\n\n.rg-bar-fill {\n display: block;\n height: 100%;\n background: var(--dsw-alias-brand-primary);\n transition: width var(--rg-motion-medium) var(--rg-ease);\n}\n\n/* ---------- KPI \u6458\u8981\u6761 ---------- */\n\n.rg-kpis {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));\n gap: 10px;\n}\n\n.rg-kpi {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n padding: 12px 14px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: var(--dsw-radius-md, 12px);\n background: var(--dsw-alias-bg-layer-1);\n min-width: 0;\n}\n\n.rg-kpi-label {\n font-size: var(--dsw-font-xxs-12, 12px);\n color: var(--dsw-alias-label-secondary);\n}\n\n.rg-kpi-value {\n font-size: var(--dsw-font-s-14, 14px);\n font-weight: var(--dsw-font-s-strong-14, 600);\n font-variant-numeric: tabular-nums;\n}\n\n.rg-kpi-big {\n font-size: var(--dsw-font-m-18, 18px);\n font-weight: var(--dsw-font-m-18-font-weight, 600);\n}\n\n.rg-kpi-detail {\n font-size: var(--dsw-font-xxxs-11, 11px);\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n max-width: 100%;\n}\n\n.rg-kpi-meta {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.rg-ring {\n flex: none;\n}\n\n.rg-ring-text {\n fill: var(--dsw-alias-label-primary);\n font-size: 11px;\n font-weight: 600;\n font-variant-numeric: tabular-nums;\n}\n\n/* ---------- \u63CF\u8FF0\u5217\u8868 / \u9636\u6BB5\u8F68\u9053 ---------- */\n\n.rg-dl {\n display: grid;\n grid-template-columns: auto 1fr;\n gap: 4px 12px;\n margin: 0;\n font-size: var(--dsw-font-xs-13, 13px);\n}\n\n.rg-dl dt {\n color: var(--dsw-alias-label-secondary);\n}\n\n.rg-dl dd {\n margin: 0;\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n flex-wrap: wrap;\n}\n\n.rg-dl-compact {\n font-size: var(--dsw-font-xxs-12, 12px);\n}\n\n.rg-mono {\n font-family: var(--dsw-font-mono, var(--dsw-font-family-mono, ui-monospace, monospace));\n font-size: var(--dsw-font-xxs-12, 12px);\n overflow-wrap: anywhere;\n}\n\n/* \u9636\u6BB5\u8F68\u9053\uFF1A\u72B6\u6001\u673A\u4E0D\u662F\u8FDB\u5EA6\u6761\uFF0Cvisited \u4E0E current \u7528\u4E0D\u540C\u901A\u9053\u8868\u8FBE\u3002 */\n.rg-stage-rail {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-wrap: wrap;\n gap: 4px 10px;\n}\n\n.rg-stage-cell {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n font-size: var(--dsw-font-xxxs-11, 11px);\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n}\n\n.rg-stage-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n border: 1px solid var(--dsw-alias-border-l2);\n background: none;\n flex: none;\n}\n\n.rg-stage-visited {\n color: var(--dsw-alias-label-secondary);\n}\n\n.rg-stage-visited .rg-stage-dot {\n background: var(--dsw-alias-border-l3, var(--dsw-alias-border-l2));\n border-color: var(--dsw-alias-border-l3, var(--dsw-alias-border-l2));\n}\n\n.rg-stage-current {\n color: var(--dsw-alias-label-primary);\n font-weight: var(--dsw-font-xxxs-strong-11, 600);\n}\n\n.rg-stage-current .rg-stage-dot {\n background: var(--dsw-alias-brand-primary);\n border-color: var(--dsw-alias-brand-primary);\n box-shadow: 0 0 0 2px var(--dsw-alias-bg-layer-2);\n}\n\n/* ---------- \u6307\u6807 ---------- */\n\n.rg-metrics {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.rg-metric {\n display: flex;\n flex-direction: column;\n gap: 3px;\n}\n\n.rg-metric-label {\n font-size: var(--dsw-font-xxs-12, 12px);\n color: var(--dsw-alias-label-secondary);\n}\n\n.rg-metric-value {\n font-size: var(--dsw-font-xs-13, 13px);\n font-variant-numeric: tabular-nums;\n}\n\n.rg-metric-undefined {\n color: var(--dsw-alias-label-secondary);\n font-style: italic;\n}\n\n.rg-metric-reason {\n font-size: var(--dsw-font-xxxs-11, 11px);\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n}\n\n.rg-metric-detail {\n font-size: var(--dsw-font-xxxs-11, 11px);\n color: var(--dsw-alias-label-secondary);\n}\n\n.rg-trend {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n}\n\n/* ---------- \u8FC1\u79FB / \u51B3\u7B56 / \u4E8B\u4EF6\u65F6\u95F4\u7EBF ---------- */\n\n.rg-transitions,\n.rg-decisions,\n.rg-events {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 5px;\n}\n\n.rg-transition,\n.rg-decision,\n.rg-event {\n display: flex;\n align-items: baseline;\n gap: 8px;\n min-width: 0;\n font-size: var(--dsw-font-xxs-12, 12px);\n}\n\n.rg-transition-reason,\n.rg-decision-detail,\n.rg-event-detail {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--dsw-alias-label-secondary);\n}\n\n.rg-decision-bundle {\n color: var(--dsw-alias-label-primary);\n}\n\n.rg-transition-time,\n.rg-decision-time,\n.rg-event-time {\n flex: none;\n font-variant-numeric: tabular-nums;\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n font-size: var(--dsw-font-xxxs-11, 11px);\n}\n\n.rg-event-ago {\n flex: none;\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n font-size: var(--dsw-font-xxxs-11, 11px);\n}\n\n/* ---------- \u5ACC\u7591\u6392\u540D ---------- */\n\n.rg-risks {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n/* \u300C\u5C55\u5F00\u5176\u4F59 N \u4E2A\u300D\u6309\u94AE\uFF1A\u5DE6\u5BF9\u9F50\u7684\u94FE\u63A5\u5F62\u6001\uFF0C\u4E0E\u5361\u7247\u5185\u7684\u5176\u5B83\u64CD\u4F5C\u533A\u5206\u3002 */\n.rg-risks-expand {\n align-self: flex-start;\n margin-top: 2px;\n}\n\n.rg-risk {\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding-bottom: 8px;\n border-bottom: 1px solid var(--dsw-alias-border-l1);\n}\n\n.rg-risk:last-child {\n border-bottom: none;\n padding-bottom: 0;\n}\n\n.rg-risk-main {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n.rg-risk-name {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: var(--dsw-font-xs-13, 13px);\n}\n\n.rg-risk-score {\n font-variant-numeric: tabular-nums;\n font-size: var(--dsw-font-xs-13, 13px);\n}\n\n.rg-risk-detail {\n font-size: var(--dsw-font-xxxs-11, 11px);\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n}\n\n.rg-risk-actions {\n display: flex;\n gap: 6px;\n}\n\n/* ---------- \u80FD\u529B\u6E05\u5355\u8868 ---------- */\n\n.rg-table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--dsw-font-xxs-12, 12px);\n table-layout: fixed;\n}\n\n.rg-table th,\n.rg-table td {\n text-align: left;\n vertical-align: top;\n padding: 5px 6px;\n border-bottom: 1px solid var(--dsw-alias-hairline, var(--dsw-alias-border-l1));\n overflow-wrap: anywhere;\n}\n\n.rg-table thead th {\n color: var(--dsw-alias-label-secondary);\n font-weight: var(--dsw-font-xxs-strong-12, 600);\n white-space: nowrap;\n border-bottom-color: var(--dsw-alias-border-l2);\n}\n\n.rg-table tbody tr {\n cursor: pointer;\n}\n\n.rg-table tbody tr:hover {\n background: var(--dsw-alias-interactive-bg-hover, var(--dsw-alias-bg-layer-2));\n}\n\n/* \u9009\u4E2D\u884C\uFF1A\u5DE6\u4FA7 2px \u7AD6\u6761 + \u5E95\u8272\uFF08\u53EA\u9760\u5E95\u8272\u5728\u6697\u8272\u4E3B\u9898\u4E0B\u4E0D\u591F\u663E\u773C\uFF09\u3002 */\n.rg-row-selected {\n background: var(--dsw-alias-interactive-bg-active, var(--dsw-alias-bg-layer-2));\n box-shadow: inset 2px 0 0 0 var(--dsw-alias-brand-primary);\n}\n\n/* \u7A84\u5F62\u6001\u4E0B\u8868\u683C\u4F1A\u6324\u6210\u4E00\u56E2 \u2014\u2014 \u5217\u5BBD\u6309\u300C\u80FD\u529B\u540D / \u5173\u7CFB\u300D\u4E24\u680F\u91CD\u6392\u3002 */\n.rg-panel[data-form='narrow'] .rg-table {\n table-layout: auto;\n}\n\n.rg-panel[data-form='narrow'] .rg-table th:nth-child(2),\n.rg-panel[data-form='narrow'] .rg-table td:nth-child(2),\n.rg-panel[data-form='narrow'] .rg-table th:nth-child(3),\n.rg-panel[data-form='narrow'] .rg-table td:nth-child(3) {\n display: none;\n}\n\n.rg-gaps {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.rg-gap {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: var(--dsw-font-xxs-12, 12px);\n}\n\n.rg-gap-detail {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* ---------- \u9879\u76EE\u5206\u533A ---------- */\n\n.rg-partitions {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.rg-partition {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n font-size: var(--dsw-font-xxs-12, 12px);\n padding: 3px 4px;\n border-radius: var(--dsw-radius-xs, 4px);\n}\n\n.rg-partition-selected {\n background: var(--dsw-alias-interactive-bg-active, var(--dsw-alias-bg-layer-2));\n box-shadow: inset 2px 0 0 0 var(--dsw-alias-brand-primary);\n}\n\n.rg-partition-label {\n font-weight: var(--dsw-font-xs-strong-13, 600);\n max-width: 40%;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.rg-partition-workspace {\n flex: 1 1 140px;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n direction: rtl;\n text-align: left;\n font-size: var(--dsw-font-xxxs-11, 11px);\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n}\n\n.rg-partition-time {\n flex: none;\n font-variant-numeric: tabular-nums;\n font-size: var(--dsw-font-xxxs-11, 11px);\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n}\n\n/* ---------- \u5F52\u6863 ---------- */\n\n.rg-archive-run {\n display: flex;\n align-items: flex-end;\n gap: 8px;\n flex-wrap: wrap;\n}\n\n.rg-archives {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.rg-archive {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 6px 8px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: var(--dsw-radius-sm, 8px);\n}\n\n.rg-archive-dir {\n font-family: var(--dsw-font-mono, var(--dsw-font-family-mono, ui-monospace, monospace));\n font-size: var(--dsw-font-xxs-12, 12px);\n overflow-wrap: anywhere;\n}\n\n.rg-archive-meta,\n.rg-archive-summary {\n font-size: var(--dsw-font-xxxs-11, 11px);\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n}\n\n/* ---------- \u533A\u5757 / \u9875\u811A ---------- */\n\n.rg-section {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.rg-section-head {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-wrap: wrap;\n}\n\n.rg-section-title {\n margin: 0;\n font-size: var(--dsw-font-m-18, 18px);\n font-weight: var(--dsw-font-m-18-font-weight, 600);\n}\n\n.rg-selection-chip {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-size: var(--dsw-font-xxs-12, 12px);\n color: var(--dsw-alias-label-secondary);\n padding: 2px 8px;\n border: 1px solid var(--dsw-alias-brand-primary);\n border-radius: 999px;\n}\n\n.rg-foot {\n display: flex;\n flex-wrap: wrap;\n gap: 4px 16px;\n border-top: 1px solid var(--dsw-alias-hairline, var(--dsw-alias-border-l1));\n padding-top: 8px;\n font-size: var(--dsw-font-xxxs-11, 11px);\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n}\n\n/* ---------- \u56FE\u8C31 ---------- */\n\n.rg-graph {\n display: flex;\n flex-direction: column;\n gap: 8px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: var(--dsw-radius-md, 12px);\n background: var(--dsw-alias-bg-layer-1);\n padding: 10px;\n min-width: 0;\n}\n\n.rg-graph-toolbar {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.rg-graph-zoom {\n display: inline-flex;\n gap: 4px;\n}\n\n.rg-graph-hint {\n font-size: var(--dsw-font-xxxs-11, 11px);\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n}\n\n.rg-graph-viewport {\n position: relative;\n overflow: hidden;\n border-radius: var(--dsw-radius-sm, 8px);\n background: var(--dsw-alias-bg-layer-2);\n cursor: grab;\n touch-action: none;\n}\n\n.rg-graph-viewport:active {\n cursor: grabbing;\n}\n\n.rg-graph-viewport:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-alias-brand-primary);\n outline-offset: 2px;\n}\n\n.rg-graph-node:focus-visible {\n outline: none;\n}\n\n/* \u952E\u76D8\u805A\u7126\u7684\u8282\u70B9\u5FC5\u987B\u80FD\u770B\u89C1\u7126\u70B9\uFF08\u5426\u5219 Tab \u8D70\u4E00\u5708\u4E0D\u77E5\u9053\u505C\u5728\u54EA\uFF09\u3002 */\n.rg-graph-node:focus-visible .rg-graph-node-bg {\n stroke: var(--dsw-alias-brand-primary);\n stroke-width: 3px;\n}\n\n.rg-graph-node-label {\n fill: var(--dsw-alias-label-primary);\n font-size: 13px;\n font-weight: 600;\n}\n\n.rg-graph-node-detail {\n fill: var(--dsw-alias-label-secondary);\n font-size: 11px;\n}\n\n.rg-graph-column-title {\n fill: var(--dsw-alias-label-secondary);\n font-size: 12px;\n font-weight: 600;\n}\n\n/* \u66F2\u7EBF\u8FB9\u7684\u8BED\u4E49\u6807\u7B7E\uFF08\u4EC5\u9AD8\u4EAE\u8FB9\u663E\u793A\uFF0C\u907F\u514D\u566A\u58F0\uFF09\u3002 */\n.rg-graph-edge-label {\n fill: var(--dsw-alias-brand-primary);\n font-size: 10px;\n font-weight: 600;\n pointer-events: none;\n}\n\n/* \u8282\u70B9\u5E03\u5C40\u8FC7\u6E21\uFF08v0.11.3\uFF09\uFF1A\u5207\u6362\u5E03\u5C40/\u62D6\u62FD\u56DE\u5F39\u65F6\u4E0D\u518D\u786C\u8DF3\u53D8\u3002\n transform \u7531 style \u63D0\u4F9B\uFF1B\u62D6\u52A8\u4E2D\u7684\u8282\u70B9\u5728\u7EC4\u4EF6\u91CC\u628A transition \u7F6E none\u3002 */\n.rg-graph-node {\n transition: transform var(--rg-motion-medium) var(--rg-ease, ease);\n}\n\n/* \u8FB9\u7684\u547D\u4E2D\u70ED\u533A\uFF1A\u900F\u660E\u5BBD\u63CF\u8FB9\u53EA\u505A\u70B9\u51FB\u76EE\u6807\uFF0C\u89C6\u89C9\u4E0D\u53C2\u4E0E\u3002 */\n.rg-edge-hit {\n fill: none;\n stroke: transparent;\n stroke-width: 14;\n pointer-events: stroke;\n cursor: pointer;\n}\n\n/* \u56FE\u4F8B\uFF08\u7C7B\u578B\u8FC7\u6EE4 chips\uFF0C\u5E26\u8BA1\u6570\uFF09\u3002 */\n.rg-graph-legend {\n display: inline-flex;\n flex-wrap: wrap;\n gap: 6px;\n margin-left: 4px;\n}\n\n.rg-legend-chip {\n appearance: none;\n display: inline-flex;\n align-items: center;\n gap: 5px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n border-radius: 999px;\n padding: 2px 10px;\n font: inherit;\n font-size: var(--dsw-font-xxs-12, 12px);\n cursor: pointer;\n transition: background var(--rg-motion-fast) var(--rg-ease);\n}\n\n.rg-legend-chip:hover {\n background: var(--dsw-alias-interactive-bg-hover, var(--dsw-alias-bg-layer-2));\n}\n\n.rg-legend-chip-off {\n opacity: 0.45;\n text-decoration: line-through;\n}\n\n.rg-legend-chip:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.rg-legend-count {\n font-variant-numeric: tabular-nums;\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n}\n\n/* \u5F62\u72B6\u56FE\u4F8B\uFF08v0.11\uFF09\uFF1A\u56FE\u4F8B\u91CC\u76F4\u63A5\u753B\u8282\u70B9\u5F62\u72B6 \u2014\u2014 \u5F62\u72B6\u662F\u989C\u8272\u4E4B\u5916\u7684\u7B2C\u4E8C\u7F16\u7801\u901A\u9053\uFF0C\n \u56FE\u4F8B\u4E0D\u5C55\u793A\u5B83\uFF0C\u8272\u76F2/\u7070\u5EA6\u6253\u5370\u7528\u6237\u5C31\u6C38\u8FDC\u4E0D\u77E5\u9053\u65B9\u6846=\u5448\u73B0\u3001\u4E09\u89D2=\u7F3A\u53E3\u3002 */\n.rg-legend-shape {\n width: 14px;\n height: 14px;\n flex: none;\n}\n\n/* \u641C\u7D22\u904D\u5386\u6307\u793A\uFF08v0.11\uFF09\uFF1A\u7B2C n/m \u4E2A\u5339\u914D\uFF0C\u56DE\u8F66\u5FAA\u73AF\u8DF3\u8F6C\u65F6\u544A\u8BC9\u7528\u6237\u4F4D\u7F6E\u3002 */\n.rg-search-index {\n font-size: var(--dsw-font-xxs-12, 12px);\n font-variant-numeric: tabular-nums;\n color: var(--dsw-alias-label-secondary);\n white-space: nowrap;\n}\n\n/* \u9A6C\u5C14\u53EF\u592B\u8DE8\u9636\u6BB5\u53BB\u5411\u5FBD\u6807\uFF08v0.11\uFF09\uFF1A`\u2192 \u5D29\u6E83 40%` \u9AD8\u5371\u8FC1\u79FB\u5FC5\u987B\u4E00\u773C\u53EF\u89C1\u3002 */\n.rg-markov-exits {\n display: inline-flex;\n gap: 4px;\n margin-left: 6px;\n flex-wrap: wrap;\n}\n\n.rg-chip-exit {\n font-size: var(--dsw-font-xxs-12, 12px);\n color: var(--dsw-alias-label-secondary);\n border: 1px dashed var(--dsw-alias-border-l2);\n background: transparent;\n white-space: nowrap;\n}\n\n/* \u56FE\u8C31\u4E3B\u4F53\uFF1A\u89C6\u53E3 + \u8BE6\u60C5\u4FA7\u680F\u4E24\u680F\uFF08\u7A84\u5BB9\u5668\u7EB5\u5411\u5806\u53E0\uFF09\u3002 */\n.rg-graph-body {\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n gap: 10px;\n}\n\n@media (min-width: 960px) {\n .rg-graph-body:has(.rg-graph-aside) {\n grid-template-columns: minmax(0, 1fr) 260px;\n }\n}\n\n.rg-graph-status {\n display: flex;\n align-items: center;\n gap: 6px 14px;\n flex-wrap: wrap;\n font-size: var(--dsw-font-xxxs-11, 11px);\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n}\n\n.rg-graph-zoom-label {\n font-variant-numeric: tabular-nums;\n}\n\n.rg-graph-status-selected {\n color: var(--dsw-alias-label-primary);\n}\n\n/* \u60AC\u505C\u6D6E\u5C42\uFF1A\u6D6E\u52A8\u5361\u7247\uFF08\u552F\u4E00\u5E26\u9634\u5F71\u7684\u8868\u9762\uFF09\u3002 */\n.rg-graph-tooltip {\n position: absolute;\n z-index: 5;\n transform: translate(-50%, -100%);\n display: flex;\n flex-direction: column;\n gap: 2px;\n max-width: 260px;\n padding: 6px 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-sm, 8px);\n background: var(--dsw-alias-bg-layer-1);\n box-shadow: var(--dsw-shadow-lv3, var(--dsw-shadow-lv1, none));\n pointer-events: none;\n}\n\n.rg-tooltip-title {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n font-size: var(--dsw-font-xxs-12, 12px);\n font-weight: var(--dsw-font-xxs-strong-12, 600);\n color: var(--dsw-alias-label-primary);\n}\n\n.rg-tooltip-meta,\n.rg-tooltip-detail {\n font-size: var(--dsw-font-xxxs-11, 11px);\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n overflow-wrap: anywhere;\n}\n\n/* \u56FE\u8C31\u641C\u7D22\u6846\u4E0E\u7ED3\u679C\u4E0B\u62C9\u3002 */\n.rg-graph-search {\n position: relative;\n display: inline-flex;\n}\n\n.rg-search-input {\n min-height: var(--rg-control-h);\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n border-radius: var(--dsw-radius-sm, 8px);\n padding: 2px 9px;\n font: inherit;\n font-size: var(--dsw-font-xxs-12, 12px);\n min-width: 150px;\n}\n\n.rg-search-input:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.rg-search-input::placeholder {\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n}\n\n.rg-search-results {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n z-index: 10;\n margin: 0;\n padding: 4px;\n list-style: none;\n min-width: 200px;\n max-height: 220px;\n overflow: auto;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-sm, 8px);\n background: var(--dsw-alias-bg-layer-1);\n box-shadow: var(--dsw-shadow-lv3, var(--dsw-shadow-lv1, none));\n}\n\n.rg-search-results button {\n appearance: none;\n border: none;\n background: none;\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n padding: 5px 8px;\n font: inherit;\n font-size: var(--dsw-font-xxs-12, 12px);\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n text-align: left;\n border-radius: var(--dsw-radius-xs, 4px);\n}\n\n.rg-search-results button:hover {\n background: var(--dsw-alias-interactive-bg-hover, var(--dsw-alias-bg-layer-2));\n}\n\n.rg-search-noresult {\n padding: 5px 8px;\n font-size: var(--dsw-font-xxs-12, 12px);\n color: var(--dsw-alias-label-secondary);\n}\n\n/* \u8BE6\u60C5\u4FA7\u680F\u3002 */\n.rg-graph-aside {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 12px 14px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: var(--dsw-radius-md, 12px);\n background: var(--dsw-alias-bg-layer-1);\n min-width: 0;\n align-self: start;\n}\n\n.rg-graph-aside-header {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n.rg-graph-aside-title {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: var(--dsw-font-s-14, 14px);\n}\n\n.rg-graph-aside-detail {\n margin: 0;\n font-size: var(--dsw-font-xxs-12, 12px);\n color: var(--dsw-alias-label-secondary);\n}\n\n.rg-graph-aside-actions {\n display: flex;\n gap: 6px;\n}\n\n/* \u90BB\u5C45\u5BFC\u822A\uFF08\u8BE6\u60C5\u4FA7\u680F\uFF09\uFF1A\u4E0A\u6E38/\u4E0B\u6E38\u5206\u7EC4\u5217\u8868\uFF0C\u70B9\u51FB\u5373\u8DF3\u8F6C\u5B9A\u4F4D\u3002 */\n.rg-graph-neighbors {\n display: flex;\n flex-direction: column;\n gap: 6px;\n border-top: 1px solid var(--dsw-alias-border-l1);\n padding-top: 8px;\n}\n\n.rg-graph-neighbor-title {\n margin: 0;\n display: flex;\n align-items: center;\n font-size: var(--dsw-font-xxs-12, 12px);\n font-weight: var(--dsw-font-xxs-strong-12, 600);\n color: var(--dsw-alias-label-secondary);\n}\n\n.rg-graph-neighbor-list {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.rg-graph-neighbor-link {\n appearance: none;\n border: none;\n background: none;\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n padding: 3px 6px;\n font: inherit;\n font-size: var(--dsw-font-xxs-12, 12px);\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n text-align: left;\n border-radius: var(--dsw-radius-xs, 4px);\n}\n\n.rg-graph-neighbor-link:hover {\n background: var(--dsw-alias-interactive-bg-hover, var(--dsw-alias-bg-layer-2));\n}\n\n.rg-graph-neighbor-link:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* \u52A8\u6548\u4E0E\u504F\u597D\uFF1A\u5C0A\u91CD\u300C\u51CF\u5C11\u52A8\u6001\u6548\u679C\u300D\uFF08\u524D\u5EAD\u5931\u8C03\u7528\u6237\u4F1A\u56E0\u8FC7\u6E21\u4E0D\u9002\uFF09\u3002 */\n@media (prefers-reduced-motion: reduce) {\n .rg-panel *,\n .rg-panel *::before,\n .rg-panel *::after {\n transition-duration: 0.01ms !important;\n animation-duration: 0.01ms !important;\n }\n}\n\n/* ---------- \u6062\u590D\u5224\u5B9A\u6761\uFF08v0.9.1\uFF09 ---------- */\n\n.rg-verdict {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n margin: 0;\n padding: 8px 12px;\n border-radius: var(--dsw-radius-sm, 8px);\n font-size: var(--dsw-font-xs-13, 13px);\n}\n/* act\uFF08\u5173\u95ED\u4E86\u63D2\u4EF6\uFF09\u4E0E watch\uFF08\u89C2\u5BDF\u8F6E\uFF09\u7528**\u8FB9\u6846+\u6807\u7B7E**\u533A\u5206\u800C\u4E0D\u662F\u53EA\u9760\u989C\u8272\uFF1A\n \u7070\u5EA6\u6253\u5370/\u8272\u5F31\u7528\u6237\u4E5F\u80FD\u5206\u8FA8\u3002 */\n.rg-verdict-act {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n}\n.rg-verdict-watch {\n border: 1px dashed var(--dsw-alias-border-l1);\n background: transparent;\n}\n.rg-verdict-tag {\n padding: 1px 8px;\n border-radius: var(--dsw-radius-sm, 8px);\n font-weight: var(--dsw-font-s-strong-14, 600);\n background: var(--dsw-alias-bg-layer-2);\n}\n.rg-verdict-meta {\n margin-left: auto;\n color: var(--dsw-alias-label-tertiary);\n}\n\n/* ---------- v0.10 \u6D1E\u5BDF\u5361\uFF1A\u9A6C\u5C14\u53EF\u592B / \u6570\u636E\u6D41 / \u7CFB\u7EDF\u8BCA\u65AD ---------- */\n\n/* \u5361\u7247\u9876\u90E8\u7684\u4E00\u884C\u6458\u8981\uFF08\u6837\u672C\u6570\u3001\u6536\u655B\u6027\u7B49\u767D\u76D2\u5143\u4FE1\u606F\uFF09\u3002 */\n.rg-card-note {\n margin: 0 0 8px;\n font-size: 12px;\n color: var(--dsw-alias-label-tertiary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* \u9A6C\u5C14\u53EF\u592B\u884C\uFF1A\u9636\u6BB5\u540D | \u81EA\u73AF\u6982\u7387\u6761 | \u767E\u5206\u6BD4\u3002 */\n.rg-markov {\n list-style: none;\n margin: 0;\n padding: 0;\n display: grid;\n gap: 6px;\n}\n.rg-markov-row {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n.rg-markov-stage {\n width: 84px;\n flex: none;\n color: var(--dsw-alias-label-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.rg-markov-row .rg-bar {\n flex: 1 1 auto;\n width: auto;\n}\n.rg-markov-value {\n width: 44px;\n flex: none;\n text-align: right;\n font-variant-numeric: tabular-nums;\n color: var(--dsw-alias-label-primary);\n}\n.rg-markov-nodata {\n flex: 1 1 auto;\n color: var(--dsw-alias-label-tertiary);\n font-size: 12px;\n}\n.rg-markov-stationary {\n margin-top: 10px;\n}\n.rg-subhead {\n margin: 0 0 6px;\n font-size: 12px;\n font-weight: var(--dsw-font-s-strong-14, 600);\n color: var(--dsw-alias-label-secondary);\n}\n.rg-chip-row {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n}\n\n/* \u6570\u636E\u6D41\u94FE\u8DEF\uFF1A\u5E8F\u53F7 | \u540D\u79F0+\u8BF4\u660E | \u8BA1\u6570\u3002 */\n.rg-dataflow {\n list-style: none;\n margin: 0;\n padding: 0;\n display: grid;\n gap: 8px;\n counter-reset: rg-flow;\n}\n.rg-dataflow-step {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n min-width: 0;\n}\n.rg-dataflow-index {\n flex: none;\n width: 20px;\n height: 20px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: var(--dsw-radius-full, 999px);\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-secondary);\n font-size: 11px;\n font-weight: var(--dsw-font-s-strong-14, 600);\n}\n\n/* \u6D41\u52A8\u8109\u51B2\uFF08v0.11\u300C\u53EF\u89C6\u5316\u6D41\u52A8\u300D\uFF09\uFF1A\u56DB\u73AF\u94FE\u8DEF\u7684\u5E8F\u53F7\u70B9\u6309\u94FE\u8DEF\u987A\u5E8F\u547C\u5438 \u2014\u2014\n \u6570\u636E\u4ECE journal \u6D41\u5411\u753B\u9762\u7684\u65B9\u5411\u611F\u7528\u5EF6\u8FDF\u9519\u76F8\u8868\u8FBE\uFF08\u6BCF\u73AF\u5EF6\u8FDF 0.3s\uFF09\u3002\n \u52A8\u753B\u53EA\u52A8 opacity\uFF08\u5408\u6210\u5C42\u5C5E\u6027\uFF0C\u4E0D\u89E6\u53D1\u91CD\u6392\uFF09\uFF1B\u7CFB\u7EDF\u300C\u51CF\u5C11\u52A8\u6001\u300D\u65F6\u505C\u7528\uFF0C\n \u9759\u6001\u5E8F\u53F7\u4ECD\u7136\u5B8C\u6574\u627F\u8F7D\u4FE1\u606F\uFF08\u52A8\u753B\u662F\u589E\u5F3A\uFF0C\u4E0D\u662F\u4FE1\u606F\u8F7D\u4F53\uFF09\u3002 */\n.rg-dataflow-step .rg-dataflow-index {\n animation: rg-flow-pulse 1.8s var(--rg-ease, ease) infinite;\n}\n.rg-dataflow-step:nth-child(2) .rg-dataflow-index {\n animation-delay: 0.3s;\n}\n.rg-dataflow-step:nth-child(3) .rg-dataflow-index {\n animation-delay: 0.6s;\n}\n.rg-dataflow-step:nth-child(4) .rg-dataflow-index {\n animation-delay: 0.9s;\n}\n@keyframes rg-flow-pulse {\n 0%,\n 100% {\n opacity: 1;\n box-shadow: 0 0 0 0 color-mix(in srgb, var(--dsw-alias-brand-primary) 0%, transparent);\n }\n 50% {\n opacity: 0.55;\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--dsw-alias-brand-primary) 18%, transparent);\n }\n}\n.rg-dataflow-main {\n min-width: 0;\n display: grid;\n gap: 2px;\n}\n.rg-dataflow-label {\n color: var(--dsw-alias-label-primary);\n font-weight: var(--dsw-font-s-strong-14, 600);\n font-size: 13px;\n}\n.rg-dataflow-detail {\n color: var(--dsw-alias-label-tertiary);\n font-size: 12px;\n overflow: hidden;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n}\n.rg-dataflow-count {\n flex: none;\n margin-left: auto;\n font-variant-numeric: tabular-nums;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* \u7CFB\u7EDF\u8BCA\u65AD\u5361\uFF1A\u7D27\u51D1\u952E\u503C\u5BF9 + \u53CD\u9988\u6309\u94AE\u3002 */\n.rg-issues-button {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n margin-top: 10px;\n text-decoration: none;\n color: var(--dsw-alias-brand-primary);\n border: 1px solid var(--dsw-alias-border-l1);\n}\n.rg-issues-button:hover {\n border-color: var(--dsw-alias-brand-primary);\n}\n\n/* ---------- \u51B3\u7B56\u56E0\u5B50\u5361\uFF08v0.13 \u65B9\u5411\u2462\uFF09 ---------- */\n/* \u4E09\u56E0\u5B50\u52A0\u6743\u8D21\u732E\u7684\u53EF\u89C6\u5316\u5206\u89E3\uFF1A\u6761\u5F62\u957F\u5EA6 = \u8BE5\u56E0\u5B50\u8D21\u732E\uFF080~1\uFF09\uFF0C\n \u8BA9\u300C\u4E3A\u4EC0\u4E48\u662F\u5B83\u300D\u4ECE\u603B\u5206\u53D8\u6210\u4E00\u4E2A\u53EF\u8BFB\u7684\u6210\u56E0\u7ED3\u6784\u3002 */\n.rg-evidence-list {\n display: flex;\n flex-direction: column;\n gap: 10px;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n.rg-evidence {\n padding: 8px 10px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: var(--dsw-radius-m, 8px);\n background: var(--dsw-alias-bg-layer-1, transparent);\n}\n/* \u5934\u53F7\u5ACC\u7591\u52A0\u5DE6\u4FA7\u5F3A\u8C03\u8FB9\uFF1A\u5B83\u662F\u300C\u8FD9\u4E00\u8F6E\u771F\u6B63\u4F1A\u88AB\u5173\u6389\u7684\u90A3\u4E2A\u300D\u3002 */\n.rg-evidence-head {\n border-left: 3px solid var(--dsw-alias-state-error-primary);\n}\n.rg-evidence-head-row {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n}\n.rg-evidence-bundle {\n font-weight: 600;\n word-break: break-all;\n}\n.rg-evidence-risk {\n margin-left: auto;\n font-variant-numeric: tabular-nums;\n color: var(--dsw-alias-label-secondary);\n}\n.rg-evidence-bars {\n display: flex;\n flex-direction: column;\n gap: 3px;\n margin-top: 6px;\n}\n.rg-evidence-bar-row {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 11px;\n}\n.rg-evidence-bar-label {\n flex: none;\n width: 4.5em;\n color: var(--dsw-alias-label-tertiary);\n}\n.rg-evidence-bar-track {\n flex: 1 1 auto;\n height: 5px;\n border-radius: 3px;\n background: var(--dsw-alias-hairline);\n overflow: hidden;\n}\n.rg-evidence-bar {\n display: block;\n height: 100%;\n border-radius: 3px;\n transition: width 200ms ease;\n}\n.rg-evidence-bar-value {\n flex: none;\n width: 3.2em;\n text-align: right;\n font-variant-numeric: tabular-nums;\n color: var(--dsw-alias-label-secondary);\n}\n.rg-evidence-meta {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-wrap: wrap;\n margin-top: 6px;\n font-size: 11px;\n color: var(--dsw-alias-label-tertiary);\n}\n/* \u4E09\u56E0\u5B50\u5404\u81EA\u7684\u8BED\u4E49\u8272\uFF1A\u65B0\u8FD1\u6027=\u4FE1\u606F\u3001\u5B9E\u9A8C\u6027=\u8B66\u544A\u3001\u5386\u53F2=\u9519\u8BEF\u3002 */\n.rg-tone-info {\n background: var(--dsw-alias-brand-primary);\n}\n.rg-tone-warn {\n background: var(--dsw-alias-state-warning-primary, var(--dsw-alias-brand-primary));\n}\n.rg-tone-error {\n background: var(--dsw-alias-state-error-primary);\n}\n@media (prefers-reduced-motion: reduce) {\n .rg-evidence-bar {\n transition: none;\n }\n}\n\n/* ---------- \u56FE\u8C31\u7ED3\u6784\u6D1E\u5BDF\u6761\uFF08v0.13\uFF09 ---------- */\n/* \u628A\u300C\u80FD\u753B\u300D\u5347\u7EA7\u4E3A\u300C\u80FD\u8BFB\u7ED3\u6784\u300D\uFF1A\u4E00\u6761\u6A2A\u5411\u4E8B\u5B9E\u6761\uFF0C\u6BCF\u4E2A chip \u53EF\u70B9\u5373\u5B9A\u4F4D\u3002\n \u8272\u5757\u4E4B\u5916\u8FD8\u6709\u4E00\u6BB5\u53EF\u8BFB\u53E5\u5B50\uFF08rg-struct-detail\uFF09\uFF0C\u4FDD\u8BC1\u7070\u5EA6/\u8272\u76F2\u4E0B\u4FE1\u606F\u4E0D\u4E22\u3002 */\n.rg-graph-structure {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n margin-bottom: 8px;\n padding: 6px 10px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: var(--dsw-radius-m, 8px);\n background: var(--dsw-alias-bg-layer-1, transparent);\n font-size: 11px;\n}\n.rg-struct-heading {\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n.rg-struct-chip {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 2px 8px;\n border-radius: 999px;\n border: 1px solid var(--dsw-alias-border-l1);\n background: var(--dsw-alias-bg-base);\n}\n.rg-struct-label {\n color: var(--dsw-alias-label-secondary);\n}\n.rg-struct-count {\n font-variant-numeric: tabular-nums;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n.rg-struct-node {\n max-width: 12em;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.rg-struct-more,\n.rg-struct-summary,\n.rg-struct-detail {\n color: var(--dsw-alias-label-tertiary);\n}\n.rg-struct-detail {\n flex-basis: 100%;\n font-size: 10px;\n line-height: 1.5;\n}\n/* chip \u7684\u8BED\u4E49\u5E95\u8272\uFF08\u7528\u6781\u4F4E\u4E0D\u900F\u660E\u5EA6\uFF0C\u907F\u514D\u62A2\u8D70\u8282\u70B9\u4E3B\u8272\uFF09\u3002 */\n.rg-tone-bg-info {\n border-color: var(--dsw-alias-brand-primary);\n}\n.rg-tone-bg-warn {\n border-color: var(--dsw-alias-state-warning-primary, var(--dsw-alias-brand-primary));\n}\n.rg-tone-bg-error {\n border-color: var(--dsw-alias-state-error-primary);\n}\n.rg-tone-bg-neutral {\n opacity: 0.75;\n}\n\n/* ---------- \u5171\u73B0\u9A8C\u8BC1\u5361\uFF08v0.13 \u65B9\u5411\u2463\uFF09 ---------- */\n/* \u53EA\u62A5\u300C\u80FD\u5426\u52A0\u6743\u300D\uFF0C\u4E0D\u62A5\u52A0\u6743\u503C\uFF1A\u52A0\u6743\u9700\u8981\u989D\u5916\u7684\u4E25\u683C\u5316\u8BBA\u8BC1\u3002\n \u4E0D\u53EF\u5224\u5B9A\u663E\u793A\u6587\u5B57\u800C\u4E0D\u662F 0%\uFF0C\u907F\u514D\u88AB\u8BFB\u6210\u300C\u8FD9\u7C7B\u5D29\u6E83\u4ECE\u4E0D\u5173\u63D2\u4EF6\u300D\u3002 */\n.rg-note {\n margin: 6px 0 0;\n font-size: 11px;\n line-height: 1.5;\n color: var(--dsw-alias-label-secondary);\n}\n.rg-note-ok {\n color: var(--dsw-alias-brand-primary);\n}\n.rg-note-muted {\n color: var(--dsw-alias-label-tertiary);\n}\n";
|
|
5453
|
+
var styles_default = "/**\n * \u7BA1\u7406\u9762\u677F\u7684\u6837\u5F0F\u3002\n *\n * ## \u7EAA\u5F8B\n *\n * 1. **\u53EA\u7528\u4E3B\u9898\u53D8\u91CF**\uFF1A\u989C\u8272\u3001\u5706\u89D2\u3001\u5B57\u4F53\u5168\u90E8\u5F15\u7528 `--dsw-alias-*` / `--dsw-radius-*`\n * / `--dsw-shadow-*` \u5BB6\u65CF\u3002\u5BBF\u4E3B\u91CD\u547D\u540D\u4E00\u4E2A\u53D8\u91CF\u65F6\u9762\u677F\u53EA\u662F\u53D8\u4E11\uFF0C\u4E0D\u4F1A\u5D29 \u2014\u2014\n * \u56E0\u6B64\u6BCF\u4E2A var() \u90FD\u5E26\u4E00\u4E2A\u4FDD\u5B88\u7684\u515C\u5E95\u503C\u3002\n * 2. **\u4E24\u79CD\u5F62\u6001\u6309\u5BB9\u5668\u5BBD\u5EA6**\uFF1A`.rg-panel[data-form=\"narrow\"]` \u7531 JS \u6D4B\u51FA\u7684\n * \u9762\u677F\u5BBD\u5EA6\u9A71\u52A8\uFF08\u9762\u677F\u53EF\u80FD\u6302\u5728\u88AB\u62D6\u7A84\u7684\u4FA7\u680F\u91CC\uFF0C\u5A92\u4F53\u67E5\u8BE2\u91CF\u7684\u662F\u7A97\u53E3\uFF0C\u4F1A\u7B54\u9519\uFF09\u3002\n * 3. **\u5C40\u90E8\u52A8\u6548\u4EE4\u724C**\uFF1A\u8FC7\u6E21\u65F6\u957F\u4E0E\u7F13\u52A8\u5B9A\u4E49\u5728 `.rg-panel` \u4E0A\u7684 `--rg-*`\uFF0C\n * \u4E0D\u4F9D\u8D56\u672A\u7ECF\u9A8C\u8BC1\u7684\u5168\u5C40 `--ds-*`\uFF08\u751F\u6001\u63D2\u4EF6\u540C\u6837\u81EA\u6301\u8FD9\u5957\u4EE4\u724C\uFF09\u3002\n * 4. **\u4E0D\u5199\u6B7B\u5BB9\u5668\u5BBD\u5EA6**\uFF1A\u9762\u677F\u5360\u6EE1\u5BBF\u4E3B\u7ED9\u7684\u4E2D\u592E\u9762\u677F\u533A\u57DF\u3002\n * 5. **\u5BF9\u6BD4\u5EA6**\uFF1A\u6B63\u6587 `--dsw-alias-label-primary`\uFF0C\u6B21\u8981 `--dsw-alias-label-secondary`\uFF0C\n * \u63D0\u793A `--dsw-alias-label-tertiary`\uFF08\u4EAE/\u6697\u4E3B\u9898\u90FD\u7531\u5BBF\u4E3B\u4FDD\u8BC1\u53EF\u8BFB\uFF09\u3002\n */\n\n.rg-panel {\n /* \u5C40\u90E8\u4EE4\u724C\uFF1A\u63A7\u4EF6\u9AD8\u5EA6\u3001\u52A8\u6548\u3001\u95F4\u8DDD\u3002\u6539\u4E00\u5904\uFF0C\u6574\u5757\u9762\u677F\u8DDF\u7740\u4E00\u81F4\u3002 */\n --rg-control-h: 28px;\n --rg-motion-fast: 120ms;\n --rg-motion-medium: 200ms;\n --rg-ease: cubic-bezier(0.2, 0, 0, 1);\n --rg-gap: 16px;\n\n display: flex;\n flex-direction: column;\n gap: var(--rg-gap);\n padding: 20px 24px 32px;\n min-width: 0;\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-bg-base);\n font-family: var(--dsw-font-family);\n font-size: var(--dsw-font-s-14, 14px);\n line-height: var(--dsw-font-s-14-line-height, 22px);\n\n /**\n * \u9762\u677F\u5FC5\u987B**\u81EA\u5DF1**\u662F\u6EDA\u52A8\u5BB9\u5668\u3002\n *\n * \u4E3A\u4EC0\u4E48\u4E0D\u80FD\u6307\u671B\u5BBF\u4E3B\uFF1A\u5B9E\u6D4B\uFF08\u6C99\u7BB1 sb-rg-c5\uFF09\u5BBF\u4E3B\u69FD\u4F4D\u662F\u8FD9\u6837\u4E00\u4E32\n * .centerCol { overflow-y: hidden } \u2190 \u7956\u5148\u628A\u6EA2\u51FA\u88C1\u6389\n * .mainPanel { height: 714px; overflow: visible }\n * .rg-panel { height: 3965px } \u2190 \u5185\u5BB9\u81EA\u7136\u9AD8\u5EA6\uFF0C\u8D85\u51FA\u540E\u76F4\u63A5\u88AB\u88C1\n * \u6587\u6863\u672C\u8EAB\u4E0D\u6EDA\uFF08docScrollH == clientH == 714\uFF09\uFF0C\u56E0\u6B64**\u4E0B\u65B9\u6570\u636E\u9875\u6C38\u8FDC\u770B\u4E0D\u5230**\u3002\n *\n * \u4E09\u4E2A\u5C5E\u6027\u7F3A\u4E00\u4E0D\u53EF\uFF1A\n * - `height: 100%` + `min-height: 0`\uFF1A\u6491\u6EE1\u5BBF\u4E3B\u7ED9\u7684\u786E\u5B9A\u9AD8\u5EA6\uFF0C\u4E14\u5141\u8BB8\u6536\u7F29\u5230\u53EF\u6EDA\u52A8\uFF1B\n * \u53EA\u5199 overflow \u800C\u4E0D\u9650\u5236\u9AD8\u5EA6\uFF0Cflex \u5B50\u9879\u4ECD\u4F1A\u6309\u5185\u5BB9\u6491\u5F00\uFF0C\u6EDA\u4E0D\u8D77\u6765\u3002\n * - `overflow-y: auto`\uFF1A\u9762\u677F\u81EA\u5DF1\u6EDA\u3002\n * - `overscroll-behavior: contain`\uFF1A\u6EDA\u5230\u5C3D\u5934\u4E0D\u628A\u6EDA\u52A8\u4F20\u7ED9\u5BBF\u4E3B\uFF0C\u5426\u5219\u4F1A\u628A\u6574\u9875/\u4FA7\u680F\n * \u5E26\u7740\u4E00\u8D77\u6EDA\uFF0C\u89C6\u89C9\u4E0A\u50CF\"\u9762\u677F\u5728\u4E71\u8DF3\"\u3002\n */\n height: 100%;\n max-height: 100%;\n min-height: 0;\n overflow-y: auto;\n overflow-x: hidden;\n overscroll-behavior: contain;\n}\n\n/* \u7A84\u5F62\u6001\uFF08\u4FA7\u680F / \u5206\u5C4F\uFF09\uFF1A\u6536\u7D27\u8FB9\u8DDD\u4E0E\u95F4\u8DDD\uFF0C\u628A\u7EB5\u5411\u7A7A\u95F4\u8BA9\u7ED9\u5185\u5BB9\u3002 */\n.rg-panel[data-form='narrow'] {\n --rg-gap: 12px;\n padding: 14px 14px 24px;\n font-size: var(--dsw-font-xs-13, 13px);\n}\n\n/* ---------- \u5934\u90E8 ---------- */\n\n.rg-header {\n display: flex;\n flex-wrap: wrap;\n align-items: flex-start;\n justify-content: space-between;\n gap: 12px;\n}\n\n.rg-header-main {\n min-width: 0;\n flex: 1 1 260px;\n}\n\n.rg-title {\n margin: 0;\n font-size: var(--dsw-font-l-20, 20px);\n font-weight: var(--dsw-font-l-20-font-weight, 600);\n color: var(--dsw-alias-label-primary);\n}\n\n.rg-panel[data-form='narrow'] .rg-title {\n font-size: var(--dsw-font-m-18, 18px);\n}\n\n.rg-subtitle {\n margin: 4px 0 0;\n font-size: var(--dsw-font-xs-13, 13px);\n color: var(--dsw-alias-label-secondary);\n overflow-wrap: anywhere;\n}\n\n.rg-project-name {\n font-weight: var(--dsw-font-xs-strong-13, 600);\n color: var(--dsw-alias-label-primary);\n}\n\n.rg-partition-workspace-full {\n font-size: var(--dsw-font-xxs-12, 12px);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n max-width: 100%;\n direction: ltr;\n}\n\n.rg-actions {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n/* ---------- \u63A7\u4EF6 ---------- */\n\n.rg-button {\n appearance: none;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n min-height: var(--rg-control-h);\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n border-radius: var(--dsw-radius-sm, 8px);\n padding: 4px 12px;\n font: inherit;\n font-size: var(--dsw-font-xs-13, 13px);\n cursor: pointer;\n transition:\n background var(--rg-motion-fast) var(--rg-ease),\n border-color var(--rg-motion-fast) var(--rg-ease);\n}\n\n.rg-button:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover, var(--dsw-alias-bg-layer-2));\n}\n\n.rg-button:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-alias-brand-primary);\n outline-offset: 2px;\n}\n\n.rg-button:disabled {\n opacity: 0.45;\n cursor: not-allowed;\n}\n\n.rg-button-small {\n min-height: 24px;\n padding: 2px 9px;\n font-size: var(--dsw-font-xxs-12, 12px);\n}\n\n.rg-button-icon {\n min-width: 28px;\n padding: 2px 6px;\n justify-content: center;\n font-size: var(--dsw-font-s-14, 14px);\n line-height: 1;\n}\n\n.rg-button-danger {\n border-color: var(--dsw-alias-state-error-primary);\n color: var(--dsw-alias-state-error-primary);\n}\n\n.rg-button-active {\n border-color: var(--dsw-alias-brand-primary);\n color: var(--dsw-alias-brand-primary);\n}\n\n/* \u8F6E\u8BE2\u6682\u505C\u6001\u6309\u94AE\uFF08\u6682\u505C = \u9700\u8981\u88AB\u770B\u89C1\u7684\u72B6\u6001\uFF0C\u4E0D\u80FD\u53EA\u9760 aria-pressed\uFF09\u3002 */\n.rg-button-paused {\n border-color: var(--dsw-alias-state-warn-primary);\n color: var(--dsw-alias-state-warn-primary);\n}\n\n.rg-link {\n appearance: none;\n border: none;\n background: none;\n padding: 0 2px;\n font: inherit;\n font-size: inherit;\n color: var(--dsw-alias-brand-primary);\n cursor: pointer;\n text-decoration: underline;\n}\n\n/* \u5206\u6BB5\u63A7\u4EF6\uFF08\u5E03\u5C40 / \u7740\u8272\u53E3\u5F84\uFF09\u3002 */\n.rg-segmented {\n display: inline-flex;\n align-items: stretch;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-sm, 8px);\n overflow: hidden;\n background: var(--dsw-alias-bg-layer-1);\n}\n\n.rg-segment {\n appearance: none;\n border: none;\n border-right: 1px solid var(--dsw-alias-border-l1);\n background: none;\n color: var(--dsw-alias-label-secondary);\n padding: 3px 9px;\n font: inherit;\n font-size: var(--dsw-font-xxs-12, 12px);\n cursor: pointer;\n transition: background var(--rg-motion-fast) var(--rg-ease);\n}\n\n.rg-segment:last-child {\n border-right: none;\n}\n\n.rg-segment:hover {\n background: var(--dsw-alias-interactive-bg-hover, var(--dsw-alias-bg-layer-2));\n}\n\n.rg-segment[aria-pressed='true'] {\n background: var(--dsw-alias-interactive-bg-active, var(--dsw-alias-bg-layer-2));\n color: var(--dsw-alias-label-primary);\n font-weight: var(--dsw-font-xxs-strong-12, 600);\n}\n\n.rg-segment:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n\n.rg-field {\n display: flex;\n flex-direction: column;\n gap: 3px;\n min-width: 0;\n}\n\n.rg-field-grow {\n flex: 1 1 160px;\n}\n\n.rg-field-label {\n font-size: var(--dsw-font-xxs-12, 12px);\n color: var(--dsw-alias-label-secondary);\n}\n\n.rg-input,\n.rg-select {\n min-height: var(--rg-control-h);\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-sm, 8px);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n padding: 2px 8px;\n font: inherit;\n font-size: var(--dsw-font-xs-13, 13px);\n max-width: 100%;\n}\n\n.rg-input:focus-visible,\n.rg-select:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* ---------- \u63D0\u793A\u6761 ---------- */\n\n.rg-notice {\n margin: 0;\n padding: 8px 10px;\n border: 1px solid var(--dsw-alias-state-warn-primary);\n border-radius: var(--dsw-radius-sm, 8px);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n font-size: var(--dsw-font-xxs-12, 12px);\n}\n\n.rg-error {\n margin: 0;\n padding: 10px 12px;\n border-radius: var(--dsw-radius-sm, 8px);\n border: 1px solid var(--dsw-alias-state-error-primary);\n color: var(--dsw-alias-state-error-primary);\n font-size: var(--dsw-font-xs-13, 13px);\n}\n\n.rg-empty {\n margin: 0;\n padding: 8px 0;\n font-size: var(--dsw-font-xs-13, 13px);\n color: var(--dsw-alias-label-secondary);\n}\n\n.rg-muted {\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n}\n\n.rg-strong {\n font-weight: var(--dsw-font-xs-strong-13, 600);\n}\n\n.rg-block {\n display: block;\n}\n\n.rg-ellipsis {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.rg-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 16px;\n margin-left: 6px;\n padding: 0 4px;\n border-radius: 999px;\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-secondary);\n font-size: var(--dsw-font-xxxs-11, 11px);\n}\n\n/* \u52A0\u8F7D / \u4E0D\u53EF\u7528\u72B6\u6001\u5757\uFF1A\u5360\u4F4D\u9AD8\u5EA6\u7A33\u5B9A\uFF0C\u907F\u514D\u8F6E\u8BE2\u65F6\u9875\u9762\u8DF3\u52A8\u3002 */\n.rg-state-block {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 24px 0;\n}\n\n.rg-state-title {\n margin: 0;\n font-size: var(--dsw-font-m-18, 18px);\n font-weight: var(--dsw-font-m-18-font-weight, 600);\n}\n\n/* ---------- \u5361\u7247\u7F51\u683C ---------- */\n\n.rg-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));\n gap: 12px;\n}\n\n.rg-panel[data-form='narrow'] .rg-grid {\n grid-template-columns: 1fr;\n}\n\n.rg-card {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 14px 16px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: var(--dsw-radius-md, 12px);\n background: var(--dsw-alias-bg-layer-1);\n min-width: 0;\n min-height: 0;\n}\n\n/**\n * \u5361\u7247\u5185\u5BB9\u533A\u56FA\u5B9A\u9AD8\u5EA6 + \u5185\u90E8\u6EDA\u52A8\uFF08v0.9.1 \u7528\u6237\u9700\u6C42\uFF09\u3002\n *\n * \u4E3A\u4EC0\u4E48\u9650\u9AD8\u800C\u4E0D\u662F\u8BA9\u5185\u5BB9\u81EA\u7136\u4F38\u5C55\uFF1A\u5C55\u5F00\u7684\u5361\u7247\u591A\u4E86\u4E4B\u540E\uFF0C\u9762\u677F\u88AB\u5355\u4E2A\n * \u5361\u7247\u6491\u5230\u51E0\u5343\u50CF\u7D20\uFF0C\u4E0B\u9762\u7684\u5361\u7247\u8981\u6EDA\u5F88\u4E45\u624D\u770B\u5F97\u5230 \u2014\u2014 \u5747\u5300\u7684\u89C6\u53E3\u5BC6\u5EA6\n * \u6BD4\u5355\u5361\u7684\u5B8C\u6574\u6027\u66F4\u91CD\u8981\uFF08\u8FD9\u6B63\u662F\u7528\u6237\u539F\u59CB\u8BC9\u6C42\uFF09\u3002\n *\n * - \u9ED8\u8BA4 `--rg-card-body-h: 240px`\uFF1A\u8DB3\u591F\u770B\u7EA6 10 \u884C\u5185\u5BB9\uFF0C\u8D85\u51FA\u5185\u90E8\u6EDA\u52A8\uFF1B\n * - `overscroll-behavior: contain`\uFF1A\u6EDA\u5230\u5C3D\u5934\u4E0D\u628A\u5916\u5C42\u9762\u677F\u5E26\u7740\u6EDA\uFF1B\n * - `.rg-card-enlarged` \u89E3\u9664\u9650\u9AD8\uFF08\u2922 \u6309\u94AE\uFF09\uFF0C\u644A\u5F00\u9605\u8BFB\u957F\u6E05\u5355\uFF1B\n * - \u7A84\u5F62\u6001\u628A\u9650\u9AD8\u964D\u5230 180px\uFF08\u4FA7\u680F\u7A7A\u95F4\u5C11\uFF0C\u5BC6\u5EA6\u4F18\u5148\uFF09\u3002\n */\n.rg-card-body {\n display: flex;\n flex-direction: column;\n gap: 10px;\n height: var(--rg-card-body-h, 240px);\n overflow-y: auto;\n overscroll-behavior: contain;\n min-height: 0;\n}\n\n/* \u6269\u5927\u6001\uFF1A\u89E3\u9664\u9650\u9AD8\uFF0C\u5361\u7247\u6309\u5185\u5BB9\u81EA\u7136\u4F38\u5C55\uFF08\u9762\u677F\u81EA\u8EAB\u4ECD\u662F\u6EDA\u52A8\u5BB9\u5668\uFF09\u3002 */\n.rg-card-enlarged .rg-card-body {\n height: auto;\n max-height: none;\n overflow-y: visible;\n}\n\n/* \u6269\u5927\u6309\u94AE\uFF1A\u5934\u90E8\u5185\u7684\u7B2C\u4E8C\u4E2A\u52A8\u4F5C\uFF0C\u5C0F\u5C3A\u5BF8\u3001\u4F4E\u5BF9\u6BD4\uFF0C\u4E0D\u4E0E\u6298\u53E0\u7BAD\u5934\u7ADE\u4E89\u3002 */\n.rg-card-expand {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 22px;\n height: 22px;\n margin-left: auto;\n border-radius: var(--dsw-radius-sm, 8px);\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n user-select: none;\n transition: background var(--rg-motion-fast, 120ms) var(--rg-ease, ease);\n}\n.rg-card-expand:hover,\n.rg-card-expand:focus-visible {\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n}\n.rg-card-enlarged .rg-card-expand {\n color: var(--dsw-alias-label-primary);\n}\n\n.rg-card-title {\n margin: 0;\n font-size: var(--dsw-font-s-14, 14px);\n font-weight: var(--dsw-font-s-strong-14, 600);\n}\n\n/* \u7A84\u5F62\u6001\uFF1A\u4FA7\u680F\u7A7A\u95F4\u5C11\uFF0C\u5BC6\u5EA6\u4F18\u5148 \u2014\u2014 \u5185\u5BB9\u533A\u9650\u9AD8\u964D\u4E3A 180px\u3002 */\n.rg-panel[data-form='narrow'] .rg-card-body {\n --rg-card-body-h: 180px;\n}\n\n.rg-card-title {\n margin: 0;\n font-size: var(--dsw-font-s-14, 14px);\n font-weight: var(--dsw-font-s-strong-14, 600);\n}\n\n.rg-card-subtitle {\n margin: 4px 0 0;\n font-size: var(--dsw-font-xxs-12, 12px);\n font-weight: var(--dsw-font-xxs-strong-12, 600);\n color: var(--dsw-alias-label-secondary);\n}\n\n.rg-card-note {\n margin: 0;\n font-size: var(--dsw-font-xxs-12, 12px);\n color: var(--dsw-alias-label-secondary);\n}\n\n/* \u53EF\u6298\u53E0\u5361\u7247\uFF1A\u6807\u9898\u884C\u662F\u6309\u94AE\uFF0C\u6574\u4E2A\u5934\u90E8\u53EF\u70B9\u3002 */\n.rg-card-head {\n appearance: none;\n border: none;\n background: none;\n padding: 0;\n margin: 0;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n width: 100%;\n cursor: pointer;\n font: inherit;\n color: inherit;\n text-align: left;\n}\n\n.rg-card-head:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-alias-brand-primary);\n outline-offset: 2px;\n border-radius: var(--dsw-radius-xs, 4px);\n}\n\n.rg-card-head-hint {\n margin-left: auto;\n font-size: var(--dsw-font-xxxs-11, 11px);\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.rg-card-chevron {\n color: var(--dsw-alias-label-secondary);\n font-size: var(--dsw-font-xxs-12, 12px);\n}\n\n.rg-card-collapsed {\n padding-bottom: 10px;\n}\n\n.rg-card-body {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n/* ---------- \u5FBD\u6807 / \u5706\u70B9 / \u8BA1\u6570\u7247 ---------- */\n\n.rg-badge {\n display: inline-flex;\n align-items: center;\n padding: 1px 8px;\n border-radius: var(--dsw-radius-sm, 8px);\n border: 1px solid var(--dsw-alias-border-l2);\n font-size: var(--dsw-font-xxs-12, 12px);\n white-space: nowrap;\n}\n\n.rg-badge-idle,\n.rg-badge-monitoring {\n border-color: var(--dsw-alias-brand-primary);\n color: var(--dsw-alias-brand-primary);\n}\n\n.rg-badge-crashed,\n.rg-badge-error {\n border-color: var(--dsw-alias-state-error-primary);\n color: var(--dsw-alias-state-error-primary);\n}\n\n.rg-badge-deciding,\n.rg-badge-worsening,\n.rg-badge-warn {\n border-color: var(--dsw-alias-state-warn-primary);\n color: var(--dsw-alias-state-warn-primary);\n}\n\n.rg-badge-stabilizing,\n.rg-badge-recovered,\n.rg-badge-improving,\n.rg-badge-success {\n border-color: var(--dsw-alias-state-success-primary);\n color: var(--dsw-alias-state-success-primary);\n}\n\n.rg-badge-stable,\n.rg-badge-neutral {\n border-color: var(--dsw-alias-border-l2);\n color: var(--dsw-alias-label-secondary);\n}\n\n.rg-chip {\n display: inline-flex;\n align-items: center;\n padding: 0 6px;\n border-radius: var(--dsw-radius-xs, 4px);\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-secondary);\n font-size: var(--dsw-font-xxxs-11, 11px);\n white-space: nowrap;\n}\n\n.rg-chip-warn {\n border: 1px solid var(--dsw-alias-state-warn-primary);\n color: var(--dsw-alias-state-warn-primary);\n background: none;\n}\n\n.rg-chip-more {\n font-variant-numeric: tabular-nums;\n}\n\n.rg-names {\n display: inline-flex;\n flex-wrap: wrap;\n gap: 3px;\n min-width: 0;\n}\n\n.rg-dot {\n display: inline-block;\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: var(--dsw-alias-label-secondary);\n flex: none;\n}\n\n.rg-dot-info {\n background: var(--dsw-alias-brand-primary);\n}\n\n.rg-dot-success {\n background: var(--dsw-alias-state-success-primary);\n}\n\n.rg-dot-warn {\n background: var(--dsw-alias-state-warn-primary);\n}\n\n.rg-dot-error {\n background: var(--dsw-alias-state-error-primary);\n}\n\n/* ---------- \u8FDB\u5EA6\u6761 ---------- */\n\n.rg-bar {\n display: inline-block;\n width: 72px;\n height: 4px;\n border-radius: 2px;\n background: var(--dsw-alias-bg-layer-2);\n overflow: hidden;\n flex: none;\n}\n\n.rg-bar-wide {\n width: 100%;\n}\n\n.rg-bar-fill {\n display: block;\n height: 100%;\n background: var(--dsw-alias-brand-primary);\n transition: width var(--rg-motion-medium) var(--rg-ease);\n}\n\n/* ---------- KPI \u6458\u8981\u6761 ---------- */\n\n.rg-kpis {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));\n gap: 10px;\n}\n\n.rg-kpi {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n padding: 12px 14px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: var(--dsw-radius-md, 12px);\n background: var(--dsw-alias-bg-layer-1);\n min-width: 0;\n}\n\n.rg-kpi-label {\n font-size: var(--dsw-font-xxs-12, 12px);\n color: var(--dsw-alias-label-secondary);\n}\n\n.rg-kpi-value {\n font-size: var(--dsw-font-s-14, 14px);\n font-weight: var(--dsw-font-s-strong-14, 600);\n font-variant-numeric: tabular-nums;\n}\n\n.rg-kpi-big {\n font-size: var(--dsw-font-m-18, 18px);\n font-weight: var(--dsw-font-m-18-font-weight, 600);\n}\n\n.rg-kpi-detail {\n font-size: var(--dsw-font-xxxs-11, 11px);\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n max-width: 100%;\n}\n\n.rg-kpi-meta {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.rg-ring {\n flex: none;\n}\n\n.rg-ring-text {\n fill: var(--dsw-alias-label-primary);\n font-size: 11px;\n font-weight: 600;\n font-variant-numeric: tabular-nums;\n}\n\n/* ---------- \u63CF\u8FF0\u5217\u8868 / \u9636\u6BB5\u8F68\u9053 ---------- */\n\n.rg-dl {\n display: grid;\n grid-template-columns: auto 1fr;\n gap: 4px 12px;\n margin: 0;\n font-size: var(--dsw-font-xs-13, 13px);\n}\n\n.rg-dl dt {\n color: var(--dsw-alias-label-secondary);\n}\n\n.rg-dl dd {\n margin: 0;\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n flex-wrap: wrap;\n}\n\n.rg-dl-compact {\n font-size: var(--dsw-font-xxs-12, 12px);\n}\n\n.rg-mono {\n font-family: var(--dsw-font-mono, var(--dsw-font-family-mono, ui-monospace, monospace));\n font-size: var(--dsw-font-xxs-12, 12px);\n overflow-wrap: anywhere;\n}\n\n/* \u9636\u6BB5\u8F68\u9053\uFF1A\u72B6\u6001\u673A\u4E0D\u662F\u8FDB\u5EA6\u6761\uFF0Cvisited \u4E0E current \u7528\u4E0D\u540C\u901A\u9053\u8868\u8FBE\u3002 */\n.rg-stage-rail {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-wrap: wrap;\n gap: 4px 10px;\n}\n\n.rg-stage-cell {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n font-size: var(--dsw-font-xxxs-11, 11px);\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n}\n\n.rg-stage-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n border: 1px solid var(--dsw-alias-border-l2);\n background: none;\n flex: none;\n}\n\n.rg-stage-visited {\n color: var(--dsw-alias-label-secondary);\n}\n\n.rg-stage-visited .rg-stage-dot {\n background: var(--dsw-alias-border-l3, var(--dsw-alias-border-l2));\n border-color: var(--dsw-alias-border-l3, var(--dsw-alias-border-l2));\n}\n\n.rg-stage-current {\n color: var(--dsw-alias-label-primary);\n font-weight: var(--dsw-font-xxxs-strong-11, 600);\n}\n\n.rg-stage-current .rg-stage-dot {\n background: var(--dsw-alias-brand-primary);\n border-color: var(--dsw-alias-brand-primary);\n box-shadow: 0 0 0 2px var(--dsw-alias-bg-layer-2);\n}\n\n/* ---------- \u6307\u6807 ---------- */\n\n.rg-metrics {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.rg-metric {\n display: flex;\n flex-direction: column;\n gap: 3px;\n}\n\n.rg-metric-label {\n font-size: var(--dsw-font-xxs-12, 12px);\n color: var(--dsw-alias-label-secondary);\n}\n\n.rg-metric-value {\n font-size: var(--dsw-font-xs-13, 13px);\n font-variant-numeric: tabular-nums;\n}\n\n.rg-metric-undefined {\n color: var(--dsw-alias-label-secondary);\n font-style: italic;\n}\n\n.rg-metric-reason {\n font-size: var(--dsw-font-xxxs-11, 11px);\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n}\n\n.rg-metric-detail {\n font-size: var(--dsw-font-xxxs-11, 11px);\n color: var(--dsw-alias-label-secondary);\n}\n\n.rg-trend {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n}\n\n/* ---------- \u8FC1\u79FB / \u51B3\u7B56 / \u4E8B\u4EF6\u65F6\u95F4\u7EBF ---------- */\n\n.rg-transitions,\n.rg-decisions,\n.rg-events {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 5px;\n}\n\n.rg-transition,\n.rg-decision,\n.rg-event {\n display: flex;\n align-items: baseline;\n gap: 8px;\n min-width: 0;\n font-size: var(--dsw-font-xxs-12, 12px);\n}\n\n.rg-transition-reason,\n.rg-decision-detail,\n.rg-event-detail {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--dsw-alias-label-secondary);\n}\n\n.rg-decision-bundle {\n color: var(--dsw-alias-label-primary);\n}\n\n.rg-transition-time,\n.rg-decision-time,\n.rg-event-time {\n flex: none;\n font-variant-numeric: tabular-nums;\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n font-size: var(--dsw-font-xxxs-11, 11px);\n}\n\n.rg-event-ago {\n flex: none;\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n font-size: var(--dsw-font-xxxs-11, 11px);\n}\n\n/* ---------- \u5ACC\u7591\u6392\u540D ---------- */\n\n.rg-risks {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n/* \u300C\u5C55\u5F00\u5176\u4F59 N \u4E2A\u300D\u6309\u94AE\uFF1A\u5DE6\u5BF9\u9F50\u7684\u94FE\u63A5\u5F62\u6001\uFF0C\u4E0E\u5361\u7247\u5185\u7684\u5176\u5B83\u64CD\u4F5C\u533A\u5206\u3002 */\n.rg-risks-expand {\n align-self: flex-start;\n margin-top: 2px;\n}\n\n.rg-risk {\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding-bottom: 8px;\n border-bottom: 1px solid var(--dsw-alias-border-l1);\n}\n\n.rg-risk:last-child {\n border-bottom: none;\n padding-bottom: 0;\n}\n\n.rg-risk-main {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n.rg-risk-name {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: var(--dsw-font-xs-13, 13px);\n}\n\n.rg-risk-score {\n font-variant-numeric: tabular-nums;\n font-size: var(--dsw-font-xs-13, 13px);\n}\n\n.rg-risk-detail {\n font-size: var(--dsw-font-xxxs-11, 11px);\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n}\n\n.rg-risk-actions {\n display: flex;\n gap: 6px;\n}\n\n/* ---------- \u80FD\u529B\u6E05\u5355\u8868 ---------- */\n\n.rg-table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--dsw-font-xxs-12, 12px);\n table-layout: fixed;\n}\n\n.rg-table th,\n.rg-table td {\n text-align: left;\n vertical-align: top;\n padding: 5px 6px;\n border-bottom: 1px solid var(--dsw-alias-hairline, var(--dsw-alias-border-l1));\n overflow-wrap: anywhere;\n}\n\n.rg-table thead th {\n color: var(--dsw-alias-label-secondary);\n font-weight: var(--dsw-font-xxs-strong-12, 600);\n white-space: nowrap;\n border-bottom-color: var(--dsw-alias-border-l2);\n}\n\n.rg-table tbody tr {\n cursor: pointer;\n}\n\n.rg-table tbody tr:hover {\n background: var(--dsw-alias-interactive-bg-hover, var(--dsw-alias-bg-layer-2));\n}\n\n/* \u9009\u4E2D\u884C\uFF1A\u5DE6\u4FA7 2px \u7AD6\u6761 + \u5E95\u8272\uFF08\u53EA\u9760\u5E95\u8272\u5728\u6697\u8272\u4E3B\u9898\u4E0B\u4E0D\u591F\u663E\u773C\uFF09\u3002 */\n.rg-row-selected {\n background: var(--dsw-alias-interactive-bg-active, var(--dsw-alias-bg-layer-2));\n box-shadow: inset 2px 0 0 0 var(--dsw-alias-brand-primary);\n}\n\n/* \u7A84\u5F62\u6001\u4E0B\u8868\u683C\u4F1A\u6324\u6210\u4E00\u56E2 \u2014\u2014 \u5217\u5BBD\u6309\u300C\u80FD\u529B\u540D / \u5173\u7CFB\u300D\u4E24\u680F\u91CD\u6392\u3002 */\n.rg-panel[data-form='narrow'] .rg-table {\n table-layout: auto;\n}\n\n.rg-panel[data-form='narrow'] .rg-table th:nth-child(2),\n.rg-panel[data-form='narrow'] .rg-table td:nth-child(2),\n.rg-panel[data-form='narrow'] .rg-table th:nth-child(3),\n.rg-panel[data-form='narrow'] .rg-table td:nth-child(3) {\n display: none;\n}\n\n.rg-gaps {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.rg-gap {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: var(--dsw-font-xxs-12, 12px);\n}\n\n.rg-gap-detail {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* ---------- \u9879\u76EE\u5206\u533A ---------- */\n\n.rg-partitions {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.rg-partition {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n font-size: var(--dsw-font-xxs-12, 12px);\n padding: 3px 4px;\n border-radius: var(--dsw-radius-xs, 4px);\n}\n\n.rg-partition-selected {\n background: var(--dsw-alias-interactive-bg-active, var(--dsw-alias-bg-layer-2));\n box-shadow: inset 2px 0 0 0 var(--dsw-alias-brand-primary);\n}\n\n.rg-partition-label {\n font-weight: var(--dsw-font-xs-strong-13, 600);\n max-width: 40%;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.rg-partition-workspace {\n flex: 1 1 140px;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n direction: rtl;\n text-align: left;\n font-size: var(--dsw-font-xxxs-11, 11px);\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n}\n\n.rg-partition-time {\n flex: none;\n font-variant-numeric: tabular-nums;\n font-size: var(--dsw-font-xxxs-11, 11px);\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n}\n\n/* ---------- \u5F52\u6863 ---------- */\n\n.rg-archive-run {\n display: flex;\n align-items: flex-end;\n gap: 8px;\n flex-wrap: wrap;\n}\n\n.rg-archives {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.rg-archive {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 6px 8px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: var(--dsw-radius-sm, 8px);\n}\n\n.rg-archive-dir {\n font-family: var(--dsw-font-mono, var(--dsw-font-family-mono, ui-monospace, monospace));\n font-size: var(--dsw-font-xxs-12, 12px);\n overflow-wrap: anywhere;\n}\n\n.rg-archive-meta,\n.rg-archive-summary {\n font-size: var(--dsw-font-xxxs-11, 11px);\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n}\n\n/* ---------- \u533A\u5757 / \u9875\u811A ---------- */\n\n.rg-section {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.rg-section-head {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-wrap: wrap;\n}\n\n.rg-section-title {\n margin: 0;\n font-size: var(--dsw-font-m-18, 18px);\n font-weight: var(--dsw-font-m-18-font-weight, 600);\n}\n\n.rg-selection-chip {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-size: var(--dsw-font-xxs-12, 12px);\n color: var(--dsw-alias-label-secondary);\n padding: 2px 8px;\n border: 1px solid var(--dsw-alias-brand-primary);\n border-radius: 999px;\n}\n\n.rg-foot {\n display: flex;\n flex-wrap: wrap;\n gap: 4px 16px;\n border-top: 1px solid var(--dsw-alias-hairline, var(--dsw-alias-border-l1));\n padding-top: 8px;\n font-size: var(--dsw-font-xxxs-11, 11px);\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n}\n\n/* ---------- \u56FE\u8C31 ---------- */\n\n.rg-graph {\n display: flex;\n flex-direction: column;\n gap: 8px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: var(--dsw-radius-md, 12px);\n background: var(--dsw-alias-bg-layer-1);\n padding: 10px;\n min-width: 0;\n}\n\n.rg-graph-toolbar {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.rg-graph-zoom {\n display: inline-flex;\n gap: 4px;\n}\n\n.rg-graph-hint {\n font-size: var(--dsw-font-xxxs-11, 11px);\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n}\n\n.rg-graph-viewport {\n position: relative;\n overflow: hidden;\n border-radius: var(--dsw-radius-sm, 8px);\n background: var(--dsw-alias-bg-layer-2);\n cursor: grab;\n touch-action: none;\n}\n\n.rg-graph-viewport:active {\n cursor: grabbing;\n}\n\n.rg-graph-viewport:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-alias-brand-primary);\n outline-offset: 2px;\n}\n\n.rg-graph-node:focus-visible {\n outline: none;\n}\n\n/* \u952E\u76D8\u805A\u7126\u7684\u8282\u70B9\u5FC5\u987B\u80FD\u770B\u89C1\u7126\u70B9\uFF08\u5426\u5219 Tab \u8D70\u4E00\u5708\u4E0D\u77E5\u9053\u505C\u5728\u54EA\uFF09\u3002 */\n.rg-graph-node:focus-visible .rg-graph-node-bg {\n stroke: var(--dsw-alias-brand-primary);\n stroke-width: 3px;\n}\n\n.rg-graph-node-label {\n fill: var(--dsw-alias-label-primary);\n font-size: 13px;\n font-weight: 600;\n}\n\n.rg-graph-node-detail {\n fill: var(--dsw-alias-label-secondary);\n font-size: 11px;\n}\n\n.rg-graph-column-title {\n fill: var(--dsw-alias-label-secondary);\n font-size: 12px;\n font-weight: 600;\n}\n\n/* \u66F2\u7EBF\u8FB9\u7684\u8BED\u4E49\u6807\u7B7E\uFF08\u4EC5\u9AD8\u4EAE\u8FB9\u663E\u793A\uFF0C\u907F\u514D\u566A\u58F0\uFF09\u3002 */\n.rg-graph-edge-label {\n fill: var(--dsw-alias-brand-primary);\n font-size: 10px;\n font-weight: 600;\n pointer-events: none;\n}\n\n/* \u8282\u70B9\u5E03\u5C40\u8FC7\u6E21\uFF08v0.11.3\uFF09\uFF1A\u5207\u6362\u5E03\u5C40/\u62D6\u62FD\u56DE\u5F39\u65F6\u4E0D\u518D\u786C\u8DF3\u53D8\u3002\n transform \u7531 style \u63D0\u4F9B\uFF1B\u62D6\u52A8\u4E2D\u7684\u8282\u70B9\u5728\u7EC4\u4EF6\u91CC\u628A transition \u7F6E none\u3002 */\n.rg-graph-node {\n transition: transform var(--rg-motion-medium) var(--rg-ease, ease);\n}\n\n/* \u8FB9\u7684\u547D\u4E2D\u70ED\u533A\uFF1A\u900F\u660E\u5BBD\u63CF\u8FB9\u53EA\u505A\u70B9\u51FB\u76EE\u6807\uFF0C\u89C6\u89C9\u4E0D\u53C2\u4E0E\u3002 */\n.rg-edge-hit {\n fill: none;\n stroke: transparent;\n stroke-width: 14;\n pointer-events: stroke;\n cursor: pointer;\n}\n\n/* \u56FE\u4F8B\uFF08\u7C7B\u578B\u8FC7\u6EE4 chips\uFF0C\u5E26\u8BA1\u6570\uFF09\u3002 */\n.rg-graph-legend {\n display: inline-flex;\n flex-wrap: wrap;\n gap: 6px;\n margin-left: 4px;\n}\n\n.rg-legend-chip {\n appearance: none;\n display: inline-flex;\n align-items: center;\n gap: 5px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n border-radius: 999px;\n padding: 2px 10px;\n font: inherit;\n font-size: var(--dsw-font-xxs-12, 12px);\n cursor: pointer;\n transition: background var(--rg-motion-fast) var(--rg-ease);\n}\n\n.rg-legend-chip:hover {\n background: var(--dsw-alias-interactive-bg-hover, var(--dsw-alias-bg-layer-2));\n}\n\n.rg-legend-chip-off {\n opacity: 0.45;\n text-decoration: line-through;\n}\n\n.rg-legend-chip:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.rg-legend-count {\n font-variant-numeric: tabular-nums;\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n}\n\n/* \u5F62\u72B6\u56FE\u4F8B\uFF08v0.11\uFF09\uFF1A\u56FE\u4F8B\u91CC\u76F4\u63A5\u753B\u8282\u70B9\u5F62\u72B6 \u2014\u2014 \u5F62\u72B6\u662F\u989C\u8272\u4E4B\u5916\u7684\u7B2C\u4E8C\u7F16\u7801\u901A\u9053\uFF0C\n \u56FE\u4F8B\u4E0D\u5C55\u793A\u5B83\uFF0C\u8272\u76F2/\u7070\u5EA6\u6253\u5370\u7528\u6237\u5C31\u6C38\u8FDC\u4E0D\u77E5\u9053\u65B9\u6846=\u5448\u73B0\u3001\u4E09\u89D2=\u7F3A\u53E3\u3002 */\n.rg-legend-shape {\n width: 14px;\n height: 14px;\n flex: none;\n}\n\n/* \u641C\u7D22\u904D\u5386\u6307\u793A\uFF08v0.11\uFF09\uFF1A\u7B2C n/m \u4E2A\u5339\u914D\uFF0C\u56DE\u8F66\u5FAA\u73AF\u8DF3\u8F6C\u65F6\u544A\u8BC9\u7528\u6237\u4F4D\u7F6E\u3002 */\n.rg-search-index {\n font-size: var(--dsw-font-xxs-12, 12px);\n font-variant-numeric: tabular-nums;\n color: var(--dsw-alias-label-secondary);\n white-space: nowrap;\n}\n\n/* \u9A6C\u5C14\u53EF\u592B\u8DE8\u9636\u6BB5\u53BB\u5411\u5FBD\u6807\uFF08v0.11\uFF09\uFF1A`\u2192 \u5D29\u6E83 40%` \u9AD8\u5371\u8FC1\u79FB\u5FC5\u987B\u4E00\u773C\u53EF\u89C1\u3002 */\n.rg-markov-exits {\n display: inline-flex;\n gap: 4px;\n margin-left: 6px;\n flex-wrap: wrap;\n}\n\n.rg-chip-exit {\n font-size: var(--dsw-font-xxs-12, 12px);\n color: var(--dsw-alias-label-secondary);\n border: 1px dashed var(--dsw-alias-border-l2);\n background: transparent;\n white-space: nowrap;\n}\n\n/* \u56FE\u8C31\u4E3B\u4F53\uFF1A\u89C6\u53E3 + \u8BE6\u60C5\u4FA7\u680F\u4E24\u680F\uFF08\u7A84\u5BB9\u5668\u7EB5\u5411\u5806\u53E0\uFF09\u3002 */\n.rg-graph-body {\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n gap: 10px;\n}\n\n@media (min-width: 960px) {\n .rg-graph-body:has(.rg-graph-aside) {\n grid-template-columns: minmax(0, 1fr) 260px;\n }\n}\n\n.rg-graph-status {\n display: flex;\n align-items: center;\n gap: 6px 14px;\n flex-wrap: wrap;\n font-size: var(--dsw-font-xxxs-11, 11px);\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n}\n\n.rg-graph-zoom-label {\n font-variant-numeric: tabular-nums;\n}\n\n.rg-graph-status-selected {\n color: var(--dsw-alias-label-primary);\n}\n\n/* \u60AC\u505C\u6D6E\u5C42\uFF1A\u6D6E\u52A8\u5361\u7247\uFF08\u552F\u4E00\u5E26\u9634\u5F71\u7684\u8868\u9762\uFF09\u3002 */\n.rg-graph-tooltip {\n position: absolute;\n z-index: 5;\n transform: translate(-50%, -100%);\n display: flex;\n flex-direction: column;\n gap: 2px;\n max-width: 260px;\n padding: 6px 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-sm, 8px);\n background: var(--dsw-alias-bg-layer-1);\n box-shadow: var(--dsw-shadow-lv3, var(--dsw-shadow-lv1, none));\n pointer-events: none;\n}\n\n.rg-tooltip-title {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n font-size: var(--dsw-font-xxs-12, 12px);\n font-weight: var(--dsw-font-xxs-strong-12, 600);\n color: var(--dsw-alias-label-primary);\n}\n\n.rg-tooltip-meta,\n.rg-tooltip-detail {\n font-size: var(--dsw-font-xxxs-11, 11px);\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n overflow-wrap: anywhere;\n}\n\n/* \u56FE\u8C31\u641C\u7D22\u6846\u4E0E\u7ED3\u679C\u4E0B\u62C9\u3002 */\n.rg-graph-search {\n position: relative;\n display: inline-flex;\n}\n\n.rg-search-input {\n min-height: var(--rg-control-h);\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n border-radius: var(--dsw-radius-sm, 8px);\n padding: 2px 9px;\n font: inherit;\n font-size: var(--dsw-font-xxs-12, 12px);\n min-width: 150px;\n}\n\n.rg-search-input:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.rg-search-input::placeholder {\n color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary));\n}\n\n.rg-search-results {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n z-index: 10;\n margin: 0;\n padding: 4px;\n list-style: none;\n min-width: 200px;\n max-height: 220px;\n overflow: auto;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-sm, 8px);\n background: var(--dsw-alias-bg-layer-1);\n box-shadow: var(--dsw-shadow-lv3, var(--dsw-shadow-lv1, none));\n}\n\n.rg-search-results button {\n appearance: none;\n border: none;\n background: none;\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n padding: 5px 8px;\n font: inherit;\n font-size: var(--dsw-font-xxs-12, 12px);\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n text-align: left;\n border-radius: var(--dsw-radius-xs, 4px);\n}\n\n.rg-search-results button:hover {\n background: var(--dsw-alias-interactive-bg-hover, var(--dsw-alias-bg-layer-2));\n}\n\n.rg-search-noresult {\n padding: 5px 8px;\n font-size: var(--dsw-font-xxs-12, 12px);\n color: var(--dsw-alias-label-secondary);\n}\n\n/* \u8BE6\u60C5\u4FA7\u680F\u3002 */\n.rg-graph-aside {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 12px 14px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: var(--dsw-radius-md, 12px);\n background: var(--dsw-alias-bg-layer-1);\n min-width: 0;\n align-self: start;\n}\n\n.rg-graph-aside-header {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n.rg-graph-aside-title {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: var(--dsw-font-s-14, 14px);\n}\n\n.rg-graph-aside-detail {\n margin: 0;\n font-size: var(--dsw-font-xxs-12, 12px);\n color: var(--dsw-alias-label-secondary);\n}\n\n.rg-graph-aside-actions {\n display: flex;\n gap: 6px;\n}\n\n/* \u90BB\u5C45\u5BFC\u822A\uFF08\u8BE6\u60C5\u4FA7\u680F\uFF09\uFF1A\u4E0A\u6E38/\u4E0B\u6E38\u5206\u7EC4\u5217\u8868\uFF0C\u70B9\u51FB\u5373\u8DF3\u8F6C\u5B9A\u4F4D\u3002 */\n.rg-graph-neighbors {\n display: flex;\n flex-direction: column;\n gap: 6px;\n border-top: 1px solid var(--dsw-alias-border-l1);\n padding-top: 8px;\n}\n\n.rg-graph-neighbor-title {\n margin: 0;\n display: flex;\n align-items: center;\n font-size: var(--dsw-font-xxs-12, 12px);\n font-weight: var(--dsw-font-xxs-strong-12, 600);\n color: var(--dsw-alias-label-secondary);\n}\n\n.rg-graph-neighbor-list {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.rg-graph-neighbor-link {\n appearance: none;\n border: none;\n background: none;\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n padding: 3px 6px;\n font: inherit;\n font-size: var(--dsw-font-xxs-12, 12px);\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n text-align: left;\n border-radius: var(--dsw-radius-xs, 4px);\n}\n\n.rg-graph-neighbor-link:hover {\n background: var(--dsw-alias-interactive-bg-hover, var(--dsw-alias-bg-layer-2));\n}\n\n.rg-graph-neighbor-link:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* \u52A8\u6548\u4E0E\u504F\u597D\uFF1A\u5C0A\u91CD\u300C\u51CF\u5C11\u52A8\u6001\u6548\u679C\u300D\uFF08\u524D\u5EAD\u5931\u8C03\u7528\u6237\u4F1A\u56E0\u8FC7\u6E21\u4E0D\u9002\uFF09\u3002 */\n@media (prefers-reduced-motion: reduce) {\n .rg-panel *,\n .rg-panel *::before,\n .rg-panel *::after {\n transition-duration: 0.01ms !important;\n animation-duration: 0.01ms !important;\n }\n}\n\n/* ---------- \u6062\u590D\u5224\u5B9A\u6761\uFF08v0.9.1\uFF09 ---------- */\n\n.rg-verdict {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n margin: 0;\n padding: 8px 12px;\n border-radius: var(--dsw-radius-sm, 8px);\n font-size: var(--dsw-font-xs-13, 13px);\n}\n/* act\uFF08\u5173\u95ED\u4E86\u63D2\u4EF6\uFF09\u4E0E watch\uFF08\u89C2\u5BDF\u8F6E\uFF09\u7528**\u8FB9\u6846+\u6807\u7B7E**\u533A\u5206\u800C\u4E0D\u662F\u53EA\u9760\u989C\u8272\uFF1A\n \u7070\u5EA6\u6253\u5370/\u8272\u5F31\u7528\u6237\u4E5F\u80FD\u5206\u8FA8\u3002 */\n.rg-verdict-act {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n}\n.rg-verdict-watch {\n border: 1px dashed var(--dsw-alias-border-l1);\n background: transparent;\n}\n.rg-verdict-tag {\n padding: 1px 8px;\n border-radius: var(--dsw-radius-sm, 8px);\n font-weight: var(--dsw-font-s-strong-14, 600);\n background: var(--dsw-alias-bg-layer-2);\n}\n.rg-verdict-meta {\n margin-left: auto;\n color: var(--dsw-alias-label-tertiary);\n}\n\n/* ---------- v0.18 \u6062\u590D\u6B8B\u4F59\uFF08unresolved\uFF09+ \u5931\u914D\u68C0\u6D4B\u8B66\u793A ---------- */\n\n/* \u6B8B\u4F59\u51B2\u7A81\u5757\uFF1Aalert \u8BED\u4E49\uFF08role=\"alert\"\uFF09\u4F46\u89C6\u89C9\u514B\u5236 \u2014\u2014 \u662F\u300C\u9700\u8981\u77E5\u9053\u300D\n \u4E0D\u662F\u300C\u707E\u96BE\u300D\uFF1B\u5217\u8868\u884C\u7528\u5FBD\u6807 + \u63D2\u4EF6\u5BF9 + \u4EBA\u8BFB\u4E8B\u5B9E\u4E09\u6BB5\u3002 */\n.rg-unresolved {\n margin: 0 0 8px;\n padding: 8px 12px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-sm, 8px);\n background: var(--dsw-alias-bg-layer-2);\n}\n.rg-unresolved-title {\n margin: 0 0 6px;\n font-size: var(--dsw-font-xs-13, 13px);\n font-weight: var(--dsw-font-s-strong-14, 600);\n}\n.rg-unresolved ul {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.rg-unresolved li {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n font-size: var(--dsw-font-xs-13, 13px);\n}\n.rg-unresolved-bundle {\n font-family: var(--dsw-font-mono, monospace);\n font-size: 12px;\n}\n.rg-unresolved-detail {\n color: var(--dsw-alias-label-tertiary);\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* ---------- v0.10 \u6D1E\u5BDF\u5361\uFF1A\u9A6C\u5C14\u53EF\u592B / \u6570\u636E\u6D41 / \u7CFB\u7EDF\u8BCA\u65AD ---------- */\n\n/* \u5361\u7247\u9876\u90E8\u7684\u4E00\u884C\u6458\u8981\uFF08\u6837\u672C\u6570\u3001\u6536\u655B\u6027\u7B49\u767D\u76D2\u5143\u4FE1\u606F\uFF09\u3002 */\n.rg-card-note {\n margin: 0 0 8px;\n font-size: 12px;\n color: var(--dsw-alias-label-tertiary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* \u9A6C\u5C14\u53EF\u592B\u884C\uFF1A\u9636\u6BB5\u540D | \u81EA\u73AF\u6982\u7387\u6761 | \u767E\u5206\u6BD4\u3002 */\n.rg-markov {\n list-style: none;\n margin: 0;\n padding: 0;\n display: grid;\n gap: 6px;\n}\n.rg-markov-row {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n.rg-markov-stage {\n width: 84px;\n flex: none;\n color: var(--dsw-alias-label-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.rg-markov-row .rg-bar {\n flex: 1 1 auto;\n width: auto;\n}\n.rg-markov-value {\n width: 44px;\n flex: none;\n text-align: right;\n font-variant-numeric: tabular-nums;\n color: var(--dsw-alias-label-primary);\n}\n.rg-markov-nodata {\n flex: 1 1 auto;\n color: var(--dsw-alias-label-tertiary);\n font-size: 12px;\n}\n.rg-markov-stationary {\n margin-top: 10px;\n}\n.rg-subhead {\n margin: 0 0 6px;\n font-size: 12px;\n font-weight: var(--dsw-font-s-strong-14, 600);\n color: var(--dsw-alias-label-secondary);\n}\n.rg-chip-row {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n}\n\n/* \u6570\u636E\u6D41\u94FE\u8DEF\uFF1A\u5E8F\u53F7 | \u540D\u79F0+\u8BF4\u660E | \u8BA1\u6570\u3002 */\n.rg-dataflow {\n list-style: none;\n margin: 0;\n padding: 0;\n display: grid;\n gap: 8px;\n counter-reset: rg-flow;\n}\n.rg-dataflow-step {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n min-width: 0;\n}\n.rg-dataflow-index {\n flex: none;\n width: 20px;\n height: 20px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: var(--dsw-radius-full, 999px);\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-secondary);\n font-size: 11px;\n font-weight: var(--dsw-font-s-strong-14, 600);\n}\n\n/* \u6D41\u52A8\u8109\u51B2\uFF08v0.11\u300C\u53EF\u89C6\u5316\u6D41\u52A8\u300D\uFF09\uFF1A\u56DB\u73AF\u94FE\u8DEF\u7684\u5E8F\u53F7\u70B9\u6309\u94FE\u8DEF\u987A\u5E8F\u547C\u5438 \u2014\u2014\n \u6570\u636E\u4ECE journal \u6D41\u5411\u753B\u9762\u7684\u65B9\u5411\u611F\u7528\u5EF6\u8FDF\u9519\u76F8\u8868\u8FBE\uFF08\u6BCF\u73AF\u5EF6\u8FDF 0.3s\uFF09\u3002\n \u52A8\u753B\u53EA\u52A8 opacity\uFF08\u5408\u6210\u5C42\u5C5E\u6027\uFF0C\u4E0D\u89E6\u53D1\u91CD\u6392\uFF09\uFF1B\u7CFB\u7EDF\u300C\u51CF\u5C11\u52A8\u6001\u300D\u65F6\u505C\u7528\uFF0C\n \u9759\u6001\u5E8F\u53F7\u4ECD\u7136\u5B8C\u6574\u627F\u8F7D\u4FE1\u606F\uFF08\u52A8\u753B\u662F\u589E\u5F3A\uFF0C\u4E0D\u662F\u4FE1\u606F\u8F7D\u4F53\uFF09\u3002 */\n.rg-dataflow-step .rg-dataflow-index {\n animation: rg-flow-pulse 1.8s var(--rg-ease, ease) infinite;\n}\n.rg-dataflow-step:nth-child(2) .rg-dataflow-index {\n animation-delay: 0.3s;\n}\n.rg-dataflow-step:nth-child(3) .rg-dataflow-index {\n animation-delay: 0.6s;\n}\n.rg-dataflow-step:nth-child(4) .rg-dataflow-index {\n animation-delay: 0.9s;\n}\n@keyframes rg-flow-pulse {\n 0%,\n 100% {\n opacity: 1;\n box-shadow: 0 0 0 0 color-mix(in srgb, var(--dsw-alias-brand-primary) 0%, transparent);\n }\n 50% {\n opacity: 0.55;\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--dsw-alias-brand-primary) 18%, transparent);\n }\n}\n.rg-dataflow-main {\n min-width: 0;\n display: grid;\n gap: 2px;\n}\n.rg-dataflow-label {\n color: var(--dsw-alias-label-primary);\n font-weight: var(--dsw-font-s-strong-14, 600);\n font-size: 13px;\n}\n.rg-dataflow-detail {\n color: var(--dsw-alias-label-tertiary);\n font-size: 12px;\n overflow: hidden;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n}\n.rg-dataflow-count {\n flex: none;\n margin-left: auto;\n font-variant-numeric: tabular-nums;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* \u7CFB\u7EDF\u8BCA\u65AD\u5361\uFF1A\u7D27\u51D1\u952E\u503C\u5BF9 + \u53CD\u9988\u6309\u94AE\u3002 */\n.rg-issues-button {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n margin-top: 10px;\n text-decoration: none;\n color: var(--dsw-alias-brand-primary);\n border: 1px solid var(--dsw-alias-border-l1);\n}\n.rg-issues-button:hover {\n border-color: var(--dsw-alias-brand-primary);\n}\n\n/* ---------- \u51B3\u7B56\u56E0\u5B50\u5361\uFF08v0.13 \u65B9\u5411\u2462\uFF09 ---------- */\n/* \u4E09\u56E0\u5B50\u52A0\u6743\u8D21\u732E\u7684\u53EF\u89C6\u5316\u5206\u89E3\uFF1A\u6761\u5F62\u957F\u5EA6 = \u8BE5\u56E0\u5B50\u8D21\u732E\uFF080~1\uFF09\uFF0C\n \u8BA9\u300C\u4E3A\u4EC0\u4E48\u662F\u5B83\u300D\u4ECE\u603B\u5206\u53D8\u6210\u4E00\u4E2A\u53EF\u8BFB\u7684\u6210\u56E0\u7ED3\u6784\u3002 */\n.rg-evidence-list {\n display: flex;\n flex-direction: column;\n gap: 10px;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n.rg-evidence {\n padding: 8px 10px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: var(--dsw-radius-m, 8px);\n background: var(--dsw-alias-bg-layer-1, transparent);\n}\n/* \u5934\u53F7\u5ACC\u7591\u52A0\u5DE6\u4FA7\u5F3A\u8C03\u8FB9\uFF1A\u5B83\u662F\u300C\u8FD9\u4E00\u8F6E\u771F\u6B63\u4F1A\u88AB\u5173\u6389\u7684\u90A3\u4E2A\u300D\u3002 */\n.rg-evidence-head {\n border-left: 3px solid var(--dsw-alias-state-error-primary);\n}\n.rg-evidence-head-row {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n}\n.rg-evidence-bundle {\n font-weight: 600;\n word-break: break-all;\n}\n.rg-evidence-risk {\n margin-left: auto;\n font-variant-numeric: tabular-nums;\n color: var(--dsw-alias-label-secondary);\n}\n.rg-evidence-bars {\n display: flex;\n flex-direction: column;\n gap: 3px;\n margin-top: 6px;\n}\n.rg-evidence-bar-row {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 11px;\n}\n.rg-evidence-bar-label {\n flex: none;\n width: 4.5em;\n color: var(--dsw-alias-label-tertiary);\n}\n.rg-evidence-bar-track {\n flex: 1 1 auto;\n height: 5px;\n border-radius: 3px;\n background: var(--dsw-alias-hairline);\n overflow: hidden;\n}\n.rg-evidence-bar {\n display: block;\n height: 100%;\n border-radius: 3px;\n transition: width 200ms ease;\n}\n.rg-evidence-bar-value {\n flex: none;\n width: 3.2em;\n text-align: right;\n font-variant-numeric: tabular-nums;\n color: var(--dsw-alias-label-secondary);\n}\n.rg-evidence-meta {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-wrap: wrap;\n margin-top: 6px;\n font-size: 11px;\n color: var(--dsw-alias-label-tertiary);\n}\n/* \u4E09\u56E0\u5B50\u5404\u81EA\u7684\u8BED\u4E49\u8272\uFF1A\u65B0\u8FD1\u6027=\u4FE1\u606F\u3001\u5B9E\u9A8C\u6027=\u8B66\u544A\u3001\u5386\u53F2=\u9519\u8BEF\u3002 */\n.rg-tone-info {\n background: var(--dsw-alias-brand-primary);\n}\n.rg-tone-warn {\n background: var(--dsw-alias-state-warning-primary, var(--dsw-alias-brand-primary));\n}\n.rg-tone-error {\n background: var(--dsw-alias-state-error-primary);\n}\n@media (prefers-reduced-motion: reduce) {\n .rg-evidence-bar {\n transition: none;\n }\n}\n\n/* ---------- \u56FE\u8C31\u7ED3\u6784\u6D1E\u5BDF\u6761\uFF08v0.13\uFF09 ---------- */\n/* \u628A\u300C\u80FD\u753B\u300D\u5347\u7EA7\u4E3A\u300C\u80FD\u8BFB\u7ED3\u6784\u300D\uFF1A\u4E00\u6761\u6A2A\u5411\u4E8B\u5B9E\u6761\uFF0C\u6BCF\u4E2A chip \u53EF\u70B9\u5373\u5B9A\u4F4D\u3002\n \u8272\u5757\u4E4B\u5916\u8FD8\u6709\u4E00\u6BB5\u53EF\u8BFB\u53E5\u5B50\uFF08rg-struct-detail\uFF09\uFF0C\u4FDD\u8BC1\u7070\u5EA6/\u8272\u76F2\u4E0B\u4FE1\u606F\u4E0D\u4E22\u3002 */\n.rg-graph-structure {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n margin-bottom: 8px;\n padding: 6px 10px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: var(--dsw-radius-m, 8px);\n background: var(--dsw-alias-bg-layer-1, transparent);\n font-size: 11px;\n}\n.rg-struct-heading {\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n.rg-struct-chip {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 2px 8px;\n border-radius: 999px;\n border: 1px solid var(--dsw-alias-border-l1);\n background: var(--dsw-alias-bg-base);\n}\n.rg-struct-label {\n color: var(--dsw-alias-label-secondary);\n}\n.rg-struct-count {\n font-variant-numeric: tabular-nums;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n.rg-struct-node {\n max-width: 12em;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.rg-struct-more,\n.rg-struct-summary,\n.rg-struct-detail {\n color: var(--dsw-alias-label-tertiary);\n}\n.rg-struct-detail {\n flex-basis: 100%;\n font-size: 10px;\n line-height: 1.5;\n}\n/* chip \u7684\u8BED\u4E49\u5E95\u8272\uFF08\u7528\u6781\u4F4E\u4E0D\u900F\u660E\u5EA6\uFF0C\u907F\u514D\u62A2\u8D70\u8282\u70B9\u4E3B\u8272\uFF09\u3002 */\n.rg-tone-bg-info {\n border-color: var(--dsw-alias-brand-primary);\n}\n.rg-tone-bg-warn {\n border-color: var(--dsw-alias-state-warning-primary, var(--dsw-alias-brand-primary));\n}\n.rg-tone-bg-error {\n border-color: var(--dsw-alias-state-error-primary);\n}\n.rg-tone-bg-neutral {\n opacity: 0.75;\n}\n\n/* ---------- \u5171\u73B0\u9A8C\u8BC1\u5361\uFF08v0.13 \u65B9\u5411\u2463\uFF09 ---------- */\n/* \u53EA\u62A5\u300C\u80FD\u5426\u52A0\u6743\u300D\uFF0C\u4E0D\u62A5\u52A0\u6743\u503C\uFF1A\u52A0\u6743\u9700\u8981\u989D\u5916\u7684\u4E25\u683C\u5316\u8BBA\u8BC1\u3002\n \u4E0D\u53EF\u5224\u5B9A\u663E\u793A\u6587\u5B57\u800C\u4E0D\u662F 0%\uFF0C\u907F\u514D\u88AB\u8BFB\u6210\u300C\u8FD9\u7C7B\u5D29\u6E83\u4ECE\u4E0D\u5173\u63D2\u4EF6\u300D\u3002 */\n.rg-note {\n margin: 6px 0 0;\n font-size: 11px;\n line-height: 1.5;\n color: var(--dsw-alias-label-secondary);\n}\n.rg-note-ok {\n color: var(--dsw-alias-brand-primary);\n}\n.rg-note-muted {\n color: var(--dsw-alias-label-tertiary);\n}\n";
|
|
4994
5454
|
|
|
4995
5455
|
// src/client/styles.ts
|
|
4996
5456
|
var STYLE_ELEMENT_ID = "dsh-recency-guard-styles";
|
|
@@ -5251,12 +5711,26 @@ var GRAPH_CSS = `
|
|
|
5251
5711
|
flex: 0 0 auto;
|
|
5252
5712
|
}
|
|
5253
5713
|
|
|
5254
|
-
/* \
|
|
5255
|
-
|
|
5256
|
-
|
|
5257
|
-
|
|
5714
|
+
/* \u8F6E\u8BE2\u95F4\u9694\u5FBD\u6807\uFF08\u64CD\u4F5C\u533A\uFF09\uFF1A\u6BD4\u6309\u94AE\u5F31\u3001\u4F46\u4E0D\u7528\u6EDA\u5230\u9875\u811A\u5C31\u80FD\u8BFB\u5230\u3002 */
|
|
5715
|
+
.rg-poll-chip {
|
|
5716
|
+
align-self: center;
|
|
5717
|
+
padding: 2px 8px;
|
|
5718
|
+
border: 1px solid var(--dsw-alias-border-l1);
|
|
5719
|
+
border-radius: var(--dsw-radius-full, 999px);
|
|
5720
|
+
font-size: var(--dsw-font-xxxs-11, 11px);
|
|
5721
|
+
color: var(--dsw-alias-label-secondary);
|
|
5722
|
+
white-space: nowrap;
|
|
5723
|
+
}
|
|
5724
|
+
|
|
5725
|
+
/* \u6570\u636E\u6D41 / \u9884\u8B66\u5361\uFF1A\u5185\u5BB9\u5FC5\u987B\u5B8C\u6574\u53EF\u8BFB\uFF08v0.16 \u6570\u636E\u6D41\u7B2C 4 \u6B65\u3001v0.17 \u9884\u8B66\u5361
|
|
5726
|
+
CUSUM \u8BF4\u660E\u884C\u4E24\u6B21\u88AB\u56FA\u5B9A 240px body \u88C1\u6389\uFF09\u3002\u8FD9\u4E24\u5F20\u5361\u5185\u5BB9\u957F\u5EA6\u6709\u9650\u4E14\u7528\u6237
|
|
5727
|
+
\u5FC5\u987B\u8BFB\u5168\uFF0C\u56E0\u6B64\u6309\u5185\u5BB9\u4F38\u5C55\uFF1B\u4ECD\u4FDD\u7559 max-height + **\u663E\u5F0F** overflow-y:auto
|
|
5728
|
+
\uFF08\u8D85\u51FA\u65F6\u6EDA\u52A8\u6761\u53EF\u89C1\uFF0C\u4E0D\u662F\u9759\u9ED8\u88C1\u5207\uFF09\u3002 */
|
|
5729
|
+
.rg-card-body:has(.rg-dataflow),
|
|
5730
|
+
.rg-card[data-card-id='preventive'] .rg-card-body {
|
|
5258
5731
|
height: auto;
|
|
5259
|
-
max-height:
|
|
5732
|
+
max-height: 360px;
|
|
5733
|
+
overflow-y: auto;
|
|
5260
5734
|
}
|
|
5261
5735
|
|
|
5262
5736
|
/* \u51CF\u5C11\u52A8\u6001\u6548\u679C\uFF1A\u8282\u70B9\u62D6\u52A8\u3001\u5E03\u5C40\u8FC7\u6E21\u4E0E\u56FE\u4F8B\u90FD\u4E0D\u5F97\u64AD\u653E\u52A8\u753B\u3002 */
|