@nelsonlongxiang/dsh-open-a2a-net 0.6.29 → 0.6.30
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 +2 -0
- package/README_zh.md +2 -0
- package/assets/nexusDist/assets/index-C_x3iAth.js +9 -0
- package/assets/nexusDist/assets/index-Dz8N80tI.css +1 -0
- package/assets/nexusDist/index.html +2 -2
- package/cli/a2a.mjs +624 -624
- package/lib/canvas-store.js +21 -1
- package/lib/client.js +64 -64
- package/lib/client.js.map +1 -1
- package/lib/faces/admin.js +12 -1
- package/lib/faces/canvas-notify.js +138 -0
- package/lib/faces/wire.js +669 -0
- package/lib/flood-guard.js +106 -0
- package/lib/index.js +69 -663
- package/lib/skill/SKILL.md +1 -0
- package/lib/skill/references/collaboration.md +355 -0
- package/lib/task-ledger.js +34 -4
- package/lib/types/canvas-store.d.ts +10 -1
- package/lib/types/faces/admin.d.ts +2 -1
- package/lib/types/faces/canvas-notify.d.ts +74 -0
- package/lib/types/faces/wire.d.ts +171 -0
- package/lib/types/flood-guard.d.ts +29 -0
- package/lib/types/runtime.d.ts +1 -0
- package/lib/types/task-ledger.d.ts +9 -1
- package/nexus-stage/src/main.ts +5 -1
- package/nexus-stage/src/planning-edges.ts +26 -0
- package/nexus-stage/src/planning-mirror.ts +31 -0
- package/nexus-stage/src/planning-overlap.ts +36 -11
- package/nexus-stage/src/planning-types.ts +1 -0
- package/nexus-stage/src/planning-undo.ts +68 -0
- package/nexus-stage/src/planning-view.ts +58 -34
- package/nexus-stage/src/planning.css +2 -0
- package/nexus-stage/src/world.ts +8 -20
- package/package.json +1 -1
- package/assets/nexusDist/assets/index-BqepxJ7E.css +0 -1
- package/assets/nexusDist/assets/index-CTWH6QRh.js +0 -9
|
@@ -27,7 +27,8 @@
|
|
|
27
27
|
|
|
28
28
|
import type { LampState } from './layout-wire'
|
|
29
29
|
import { buildLayoutDoc, clampDoc, type LayoutDoc, type LayoutRect } from './layout-doc'
|
|
30
|
-
import { FRAME_HEAD_LIFT
|
|
30
|
+
import { FRAME_HEAD_LIFT } from './edges'
|
|
31
|
+
import { drawMemberEdges } from './planning-edges'
|
|
31
32
|
import { createFederationOverlay } from './federation-overlay'
|
|
32
33
|
import { displayName } from './stage-name'
|
|
33
34
|
import {
|
|
@@ -43,7 +44,9 @@ import { FRAME_HUES } from './tokens'
|
|
|
43
44
|
import { createPlanningMenus } from './planning-menus'
|
|
44
45
|
import { createNodeFlyer, mountBoardSearch } from './planning-search'
|
|
45
46
|
import { applyBoardRelayout } from './planning-relayout'
|
|
47
|
+
import { mirrorRoute } from './planning-mirror'
|
|
46
48
|
import { settleBoard, tidyMembers } from './planning-overlap'
|
|
49
|
+
import { createLayoutUndo, type LayoutSnap } from './planning-undo'
|
|
47
50
|
import { createNodeList } from './planning-nodelist'
|
|
48
51
|
import { cardText } from './planning-card-text'
|
|
49
52
|
import { createLegend } from './planning-legend'
|
|
@@ -85,6 +88,8 @@ export function createPlanningView(deps: PlanningDeps): PlanningView {
|
|
|
85
88
|
/** Until the first reconcile with nodes (or an adopted viewport), frame the content once. */
|
|
86
89
|
let firstFitPending = true
|
|
87
90
|
let settledOnce = false
|
|
91
|
+
const layoutUndo = createLayoutUndo(model) // 撤销 (planning-undo)
|
|
92
|
+
let undoBefore: LayoutSnap | undefined
|
|
88
93
|
let viewportAdopted = false
|
|
89
94
|
const bucket = (): ViewportBucket => viewportBucket(globalThis.innerWidth || viewW)
|
|
90
95
|
const markDirty = (): void => {
|
|
@@ -183,6 +188,7 @@ export function createPlanningView(deps: PlanningDeps): PlanningView {
|
|
|
183
188
|
// (constructively disjoint); multi-team members never enter the size
|
|
184
189
|
// math and never move; remote org frames and frameless nodes stay put.
|
|
185
190
|
mkButton('一键重排', '全板队框+成员重排:框尺寸随内容自适应、框位行流式平铺(远端队框与多归属成员不动)', () => relayoutBoard()),
|
|
191
|
+
mkButton('撤销', '撤销上一次布局改动:拖动、缩放、整理、重排、载入时避让(Ctrl+Z;入队离队不撤销)', () => undoLayout()),
|
|
186
192
|
)
|
|
187
193
|
// Unjoined sessions ride a toolbar chip + dropdown: the panel-slim
|
|
188
194
|
// migration made the planning view the join surface — without this, an
|
|
@@ -276,8 +282,10 @@ export function createPlanningView(deps: PlanningDeps): PlanningView {
|
|
|
276
282
|
* — the same persistence path a hand drag takes.
|
|
277
283
|
*/
|
|
278
284
|
function tidyTeamMembers(): void {
|
|
285
|
+
const before = layoutUndo.capture()
|
|
279
286
|
tidyMembers(model) // gh#48 grid (planning-overlap); then nothing may overlap
|
|
280
287
|
settleBoard(model, new Set(remoteFramesRef.keys()))
|
|
288
|
+
layoutUndo.commit(before)
|
|
281
289
|
markDirty()
|
|
282
290
|
render()
|
|
283
291
|
}
|
|
@@ -290,8 +298,10 @@ export function createPlanningView(deps: PlanningDeps): PlanningView {
|
|
|
290
298
|
* markDirty()/render() persistence path a hand drag takes.
|
|
291
299
|
*/
|
|
292
300
|
function relayoutBoard(): void {
|
|
301
|
+
const before = layoutUndo.capture()
|
|
293
302
|
if (!applyBoardRelayout(model, new Set(remoteFramesRef.keys()))) return
|
|
294
303
|
settleBoard(model, new Set(remoteFramesRef.keys())) // vs remote frames + stray cards
|
|
304
|
+
layoutUndo.commit(before)
|
|
295
305
|
markDirty()
|
|
296
306
|
render()
|
|
297
307
|
}
|
|
@@ -302,7 +312,7 @@ export function createPlanningView(deps: PlanningDeps): PlanningView {
|
|
|
302
312
|
renderedRevision = model.revision
|
|
303
313
|
renderFrames()
|
|
304
314
|
renderNodes()
|
|
305
|
-
|
|
315
|
+
drawMemberEdges(svg, model) // planning-edges
|
|
306
316
|
}
|
|
307
317
|
renderFederation()
|
|
308
318
|
}
|
|
@@ -371,8 +381,15 @@ export function createPlanningView(deps: PlanningDeps): PlanningView {
|
|
|
371
381
|
}
|
|
372
382
|
const cntText = `${members} 成员` + (cross > 0 ? ` +${cross} 跨队` : '')
|
|
373
383
|
if (cnt.textContent !== cntText) cnt.textContent = cntText
|
|
374
|
-
const
|
|
384
|
+
const mirror = mirrorRoute(remoteFramesRef.get(name), pendingTeams.has(name)) // PR#96 single owner + mirror
|
|
385
|
+
const routeText0 = mirror?.text ?? routeText(name)
|
|
375
386
|
if (route.textContent !== routeText0) route.textContent = routeText0
|
|
387
|
+
route.title = mirror?.title ?? ''
|
|
388
|
+
el.classList.toggle('is-mirror', mirror !== undefined)
|
|
389
|
+
el.classList.toggle('is-syncing', mirror?.syncing === true)
|
|
390
|
+
const label = `团队框 ${name}${mirror !== undefined ? `(${mirror.text})` : ''}(拖动整组,回车菜单)`
|
|
391
|
+
const headEl = el.querySelector('.p-frame-head')!
|
|
392
|
+
if (headEl.getAttribute('aria-label') !== label) headEl.setAttribute('aria-label', label) // a rewrite re-announces
|
|
376
393
|
}
|
|
377
394
|
for (const [name, el] of [...frameEls]) {
|
|
378
395
|
if (!seen.has(name)) { el.remove(); frameEls.delete(name) }
|
|
@@ -449,28 +466,11 @@ export function createPlanningView(deps: PlanningDeps): PlanningView {
|
|
|
449
466
|
search.refresh()
|
|
450
467
|
}
|
|
451
468
|
|
|
452
|
-
// ── edges: stateless, rebuilt wholesale ──
|
|
453
|
-
// Derived from the MODEL (not lastTeams): optimistic membership changes
|
|
454
|
-
// must repaint their edges immediately, before the host confirms.
|
|
455
|
-
function renderEdges(): void {
|
|
456
|
-
while (svg.firstChild !== null) svg.firstChild.remove()
|
|
457
|
-
const teams = model.allFrames().map(([name]) => ({ name, members: model.teamMemberIds(name).map(id => ({ id })) }))
|
|
458
|
-
for (const e of starEdges(teams, new Map(model.allFrames()), model.positions())) {
|
|
459
|
-
const line = document.createElementNS('http://www.w3.org/2000/svg', 'line')
|
|
460
|
-
line.setAttribute('class', 'e-member' + (e.dashed ? ' dashed' : ''))
|
|
461
|
-
line.setAttribute('x1', String(e.x1))
|
|
462
|
-
line.setAttribute('y1', String(e.y1))
|
|
463
|
-
line.setAttribute('x2', String(e.x2))
|
|
464
|
-
line.setAttribute('y2', String(e.y2))
|
|
465
|
-
svg.appendChild(line)
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
|
|
469
469
|
// ── federation overlay (PR D): peer cards' activity/federal edges ──
|
|
470
470
|
// Runs on EVERY render, outside the model-revision gate: the poll's
|
|
471
471
|
// inFlight ages must tick even when the model is unchanged, and the
|
|
472
472
|
// badge column tracks the content bounds each reconcile. Its SVG
|
|
473
|
-
// children are tracked separately because
|
|
473
|
+
// children are tracked separately because drawMemberEdges clears the svg
|
|
474
474
|
// wholesale - this appends after it (render() orders the two).
|
|
475
475
|
// gh#49: the DOM drawing lives in federation-overlay.ts (module-size
|
|
476
476
|
// ruling); this view keeps only the seams (facts + fly).
|
|
@@ -497,17 +497,14 @@ export function createPlanningView(deps: PlanningDeps): PlanningView {
|
|
|
497
497
|
// ── status counts ──
|
|
498
498
|
function renderStatus(input: PlanningInput): void {
|
|
499
499
|
const live = input.sessions.filter(s => s.live !== false).length
|
|
500
|
-
const
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
bCold.className = 'warn'
|
|
509
|
-
bCold.textContent = `● ${cold} cold`
|
|
510
|
-
statusCold.appendChild(bCold)
|
|
500
|
+
const dot = (host: HTMLElement, cls: string, text: string): void => {
|
|
501
|
+
const b = document.createElement('b')
|
|
502
|
+
b.className = cls
|
|
503
|
+
b.textContent = text
|
|
504
|
+
host.replaceChildren(b)
|
|
505
|
+
}
|
|
506
|
+
dot(statusLive, 'ok', `● ${live} live`)
|
|
507
|
+
dot(statusCold, 'warn', `● ${input.sessions.length - live} cold`)
|
|
511
508
|
statusAct.textContent = `${input.inFlight?.length ?? 0} inFlight`
|
|
512
509
|
statusMut.className = 'mut'
|
|
513
510
|
statusMut.textContent = `${input.teams.length} 队 · ${input.peerCount} peer`
|
|
@@ -518,8 +515,10 @@ export function createPlanningView(deps: PlanningDeps): PlanningView {
|
|
|
518
515
|
// up until BOTH settle (a Set deleted per action let a mid-queue poll wipe
|
|
519
516
|
// the second action's optimistic membership).
|
|
520
517
|
const pendingTeams = new Map<string, number>()
|
|
521
|
-
|
|
518
|
+
// Each change re-renders frames: the mirror 「同步中…」 marker reads pendingTeams, not the model revision.
|
|
519
|
+
const pendingAdd = (team: string): void => { pendingTeams.set(team, (pendingTeams.get(team) ?? 0) + 1); renderedRevision = -1 }
|
|
522
520
|
const pendingRelease = (team: string): void => {
|
|
521
|
+
renderedRevision = -1
|
|
523
522
|
const n = (pendingTeams.get(team) ?? 0) - 1
|
|
524
523
|
if (n <= 0) pendingTeams.delete(team)
|
|
525
524
|
else pendingTeams.set(team, n)
|
|
@@ -705,6 +704,7 @@ export function createPlanningView(deps: PlanningDeps): PlanningView {
|
|
|
705
704
|
return
|
|
706
705
|
}
|
|
707
706
|
if (target !== null && target.closest('button, input, textarea, select, .p-toolbar, .p-search, .p-lamp, .p-status, .p-legend') !== null) return // HUD chrome owns its presses (no marquee / preventDefault: that stole the search box's focus — and, first, its native right-click menu)
|
|
707
|
+
undoBefore = layoutUndo.capture() // committed at pointerUp only if this press moved something
|
|
708
708
|
const p = localXY(ev)
|
|
709
709
|
// 右键按下:按住拖动 = 平移(Figma 惯例),原地抬起 = 上下文菜单。
|
|
710
710
|
// Pan actually starts on the first move beyond RIGHT_DRAG_THRESHOLD px;
|
|
@@ -923,6 +923,21 @@ export function createPlanningView(deps: PlanningDeps): PlanningView {
|
|
|
923
923
|
render()
|
|
924
924
|
}
|
|
925
925
|
gesture = { kind: 'none' }
|
|
926
|
+
if (undoBefore !== undefined) { layoutUndo.commit(undoBefore); undoBefore = undefined }
|
|
927
|
+
try { root.releasePointerCapture(ev.pointerId ?? 0) } catch { /* not captured */ }
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
/** The OS took the pointer (touch scroll, system gesture): abandon the press — no drop, no menu, layout back. */
|
|
931
|
+
function pointerCancel(ev: SeamPointer): void {
|
|
932
|
+
for (const el of frameEls.values()) el.classList.remove('drop-target')
|
|
933
|
+
if (gesture.kind === 'node') gesture.el?.classList.remove('dragging')
|
|
934
|
+
const panned = (gesture.kind === 'pan' && gesture.moved) || rightPress?.moved === true // right-drag pans live in rightPress
|
|
935
|
+
marquee.style.display = 'none'
|
|
936
|
+
rightPress = null
|
|
937
|
+
gesture = { kind: 'none' }
|
|
938
|
+
if (undoBefore !== undefined && layoutUndo.revert(undoBefore)) render()
|
|
939
|
+
if (panned) markDirty() // the pan stays (it is the view, not the layout) and persists like a finished one
|
|
940
|
+
undoBefore = undefined
|
|
926
941
|
try { root.releasePointerCapture(ev.pointerId ?? 0) } catch { /* not captured */ }
|
|
927
942
|
}
|
|
928
943
|
|
|
@@ -953,6 +968,10 @@ export function createPlanningView(deps: PlanningDeps): PlanningView {
|
|
|
953
968
|
markDirty()
|
|
954
969
|
}
|
|
955
970
|
|
|
971
|
+
function undoLayout(): void {
|
|
972
|
+
if (layoutUndo.undo()) { markDirty(); render() } else notice('info', '没有可撤销的布局改动')
|
|
973
|
+
}
|
|
974
|
+
|
|
956
975
|
function fitToContent(): void {
|
|
957
976
|
syncViewSize()
|
|
958
977
|
vp = fitBelowHud(boardBounds(model.contentBounds(), model.allNodes()), viewW, viewH, hudBottomOf(toolbar, status))
|
|
@@ -963,6 +982,7 @@ export function createPlanningView(deps: PlanningDeps): PlanningView {
|
|
|
963
982
|
function key(ev: SeamKey): void {
|
|
964
983
|
if (menus.isDialogOpen() || (ev.target as Element | null)?.closest?.('.p-search') !== null) return // modal / search box own their keys
|
|
965
984
|
if ((ev.ctrlKey || ev.metaKey) && ev.key.toLowerCase() === 'k') { ev.preventDefault(); search.focus(); return } // W1 Ctrl+K
|
|
985
|
+
if ((ev.ctrlKey || ev.metaKey) && !ev.shiftKey && ev.key.toLowerCase() === 'z') { ev.preventDefault(); undoLayout(); return }
|
|
966
986
|
if (ev.ctrlKey || ev.metaKey) return // browser/OS chords stay browser/OS
|
|
967
987
|
if (menus.isMenuOpen()) {
|
|
968
988
|
// The menu owns most keys (its own handler navigates); Escape still
|
|
@@ -1016,7 +1036,9 @@ export function createPlanningView(deps: PlanningDeps): PlanningView {
|
|
|
1016
1036
|
ev.preventDefault()
|
|
1017
1037
|
const ids = model.selectedIds()
|
|
1018
1038
|
if (ids.length > 0) {
|
|
1039
|
+
const before = layoutUndo.capture()
|
|
1019
1040
|
model.nudge(ids, d[0]!, d[1]!)
|
|
1041
|
+
layoutUndo.commit(before)
|
|
1020
1042
|
render()
|
|
1021
1043
|
markDirty()
|
|
1022
1044
|
}
|
|
@@ -1072,6 +1094,7 @@ export function createPlanningView(deps: PlanningDeps): PlanningView {
|
|
|
1072
1094
|
root.addEventListener('pointerdown', (ev) => pointerDown(ev as unknown as SeamPointer), signal)
|
|
1073
1095
|
root.addEventListener('pointermove', (ev) => pointerMove(ev as unknown as SeamPointer), signal)
|
|
1074
1096
|
root.addEventListener('pointerup', (ev) => pointerUp(ev as unknown as SeamPointer), signal)
|
|
1097
|
+
root.addEventListener('pointercancel', (ev) => pointerCancel(ev as unknown as SeamPointer), signal)
|
|
1075
1098
|
root.addEventListener('wheel', (ev) => wheel(ev as unknown as SeamPointer), { ...signal, passive: false })
|
|
1076
1099
|
root.addEventListener('keydown', (ev) => key(ev as unknown as SeamKey), signal)
|
|
1077
1100
|
root.addEventListener('keyup', (ev) => keyUp(ev as unknown as SeamKey), signal)
|
|
@@ -1370,7 +1393,7 @@ export function createPlanningView(deps: PlanningDeps): PlanningView {
|
|
|
1370
1393
|
// (adopted at any point) keeps its own viewport and cancels this.
|
|
1371
1394
|
// Once per load, a board that arrives overlapped is shown settled (not
|
|
1372
1395
|
// saved: no write without a user action; the next edit persists it).
|
|
1373
|
-
if (!settledOnce && gesture.kind === 'none' && model.nodeIds().length > 0) { settledOnce = true; settleBoard(model, new Set(remoteFramesRef.keys())) }
|
|
1396
|
+
if (!settledOnce && gesture.kind === 'none' && model.nodeIds().length > 0) { settledOnce = true; const b = layoutUndo.capture(); settleBoard(model, new Set(remoteFramesRef.keys())); layoutUndo.commit(b) }
|
|
1374
1397
|
if (firstFitPending && gesture.kind === 'none' && model.nodeIds().length > 0) {
|
|
1375
1398
|
syncViewSize()
|
|
1376
1399
|
if (viewW > 0 && viewH > 0) {
|
|
@@ -1466,6 +1489,7 @@ export function createPlanningView(deps: PlanningDeps): PlanningView {
|
|
|
1466
1489
|
pointerDown,
|
|
1467
1490
|
pointerMove,
|
|
1468
1491
|
pointerUp,
|
|
1492
|
+
pointerCancel,
|
|
1469
1493
|
wheel,
|
|
1470
1494
|
key,
|
|
1471
1495
|
keyUp,
|
|
@@ -82,6 +82,8 @@
|
|
|
82
82
|
#dsh-plan .p-frame-head:hover{border-color:var(--card-line-hover)}
|
|
83
83
|
#dsh-plan .p-frame-head .cnt{color:var(--ink-muted); font-weight:400}
|
|
84
84
|
#dsh-plan .p-frame-head .route{font-size:10.5px; color:var(--ink-muted)}
|
|
85
|
+
#dsh-plan .p-frame.is-mirror{border-style:dashed}
|
|
86
|
+
#dsh-plan .p-frame.is-syncing .p-frame-head .route{color:var(--accent)}
|
|
85
87
|
|
|
86
88
|
/* ── node card (fixed 56px border-box height = world.NODE_H) ── */
|
|
87
89
|
#dsh-plan .p-node{position:absolute; width:172px; height:56px; padding:8px 26px 8px 14px;
|
package/nexus-stage/src/world.ts
CHANGED
|
@@ -195,11 +195,10 @@ export interface WorldNode {
|
|
|
195
195
|
/** A team frame rectangle in world space (top-left + size). */
|
|
196
196
|
export interface FrameGeom { x: number; y: number; w: number; h: number }
|
|
197
197
|
|
|
198
|
-
/** Snapshot for
|
|
198
|
+
/** Snapshot for a frame drag: the frame rect at pointerdown (owner ruling 2026-10-28: a frame always moves only itself — members never ride along). */
|
|
199
199
|
export interface FrameDragSnapshot {
|
|
200
200
|
readonly name: string
|
|
201
201
|
readonly rect: FrameGeom
|
|
202
|
-
readonly centers: ReadonlyArray<readonly [string, number, number]>
|
|
203
202
|
}
|
|
204
203
|
|
|
205
204
|
/** The card rectangle (top-left + size) for a node centered at (x, y). */
|
|
@@ -274,38 +273,27 @@ export class WorldModel {
|
|
|
274
273
|
}
|
|
275
274
|
|
|
276
275
|
/**
|
|
277
|
-
* Start a frame
|
|
278
|
-
*
|
|
279
|
-
*
|
|
276
|
+
* Start a frame drag: snapshot the rect so the drag applies total deltas
|
|
277
|
+
* from this origin (no float drift). Returns undefined for an unknown
|
|
278
|
+
* frame. Owner ruling 2026-10-28: the snapshot carries NO member state —
|
|
279
|
+
* a frame drag moves only the rect; members stay where the user put them.
|
|
280
280
|
*/
|
|
281
281
|
beginFrameDrag(name: string): FrameDragSnapshot | undefined {
|
|
282
282
|
const rect = this.frames.get(name)
|
|
283
283
|
if (rect === undefined) return undefined
|
|
284
|
-
|
|
285
|
-
for (const n of this.nodes.values()) {
|
|
286
|
-
for (const m of n.memberships) {
|
|
287
|
-
if (m.team === name) { centers.push([n.id, n.x, n.y] as const); break }
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
return { name, rect: { ...rect }, centers }
|
|
284
|
+
return { name, rect: { ...rect } }
|
|
291
285
|
}
|
|
292
286
|
|
|
293
|
-
/** Apply a total world-space delta from the drag origin to rect
|
|
287
|
+
/** Apply a total world-space delta from the drag origin to the rect ONLY. */
|
|
294
288
|
applyFrameDrag(snap: FrameDragSnapshot, dx: number, dy: number): void {
|
|
295
289
|
const rect = this.frames.get(snap.name)
|
|
296
290
|
if (rect === undefined) return
|
|
297
291
|
rect.x = snap.rect.x + dx
|
|
298
292
|
rect.y = snap.rect.y + dy
|
|
299
|
-
for (const [id, cx, cy] of snap.centers) {
|
|
300
|
-
const n = this.nodes.get(id)
|
|
301
|
-
if (n === undefined) continue
|
|
302
|
-
n.x = cx + dx
|
|
303
|
-
n.y = cy + dy
|
|
304
|
-
}
|
|
305
293
|
this.bump()
|
|
306
294
|
}
|
|
307
295
|
|
|
308
|
-
/** Nudge (keyboard micro-move)
|
|
296
|
+
/** Nudge (keyboard micro-move): moves the SELECTED CARDS only — frames are never in the card selection, so nudging already honours the owner ruling (a frame always moves only itself). */
|
|
309
297
|
nudge(ids: ReadonlyArray<string>, dx: number, dy: number): void { this.dragNodes(ids, dx, dy) }
|
|
310
298
|
|
|
311
299
|
/** Set selection: nodes whose card rect intersects the world-space marquee. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nelsonlongxiang/dsh-open-a2a-net",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.30",
|
|
4
4
|
"description": "Open A2A network plugin for DeepSeek Harness: signed agent cards, decentralized peer/zone discovery, direct routing model tools, and joinable session nodes with a sidebar control",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
#dsh-plan *,#dsh-plan *:before,#dsh-plan *:after{box-sizing:border-box}#dsh-plan{--uupm-ink-0:var(--n-ink,#dde3f0);--uupm-ink-1:var(--n-ink-muted,#7a86a0);--uupm-bg-0:var(--n-bg,#060a12);--uupm-bg-1:var(--n-panel,#0d1322);--uupm-bg-2:var(--n-raised,#131b2e);--uupm-accent:var(--n-accent,#9673f7);--uupm-live:var(--n-live,#4ade80);--uupm-cold:var(--n-cold,#7a86a0);--uupm-edge-member:var(--n-canvas,#22d3ee);--uupm-warn:var(--n-act,#f59e0b);--uupm-error:var(--n-danger,#f87171);--uupm-indigo:var(--n-federal,#6366f1);--uupm-wash-5:color-mix(in srgb,var(--uupm-accent) 5%,transparent);--uupm-wash-8:color-mix(in srgb,var(--uupm-accent) 8%,transparent);--uupm-wash-12:color-mix(in srgb,var(--uupm-accent) 12%,transparent);--uupm-wash-15:color-mix(in srgb,var(--uupm-accent) 15%,transparent);--uupm-wash-18:color-mix(in srgb,var(--uupm-accent) 18%,transparent);--surface:var(--uupm-bg-1);--ink:var(--uupm-ink-0);--ink-muted:var(--uupm-ink-1);--accent:var(--uupm-accent);--edge-live:var(--uupm-live);--edge-cold:var(--uupm-cold);--federal:var(--uupm-indigo);--card-bg:var(--surface);--card-line:var(--n-card-line,#5c6680);--card-line-hover:var(--uupm-ink-1);--toolbar-bg:color-mix(in srgb,var(--uupm-bg-1) 92%,transparent);--grid-dot:color-mix(in srgb,var(--uupm-ink-1) 22%,transparent);--scrim:color-mix(in srgb,var(--uupm-bg-0) 60%,transparent);--error-ink:var(--n-error-ink,#fecaca);--error-panel:var(--n-error-panel,#2a0d10f2)}#dsh-plan{position:absolute;top:0;right:0;bottom:0;left:0;overflow:hidden;background:var(--uupm-bg-0);color:var(--ink);font-size:13px;line-height:1.5;outline:none}#dsh-plan .mono{font-family:ui-monospace,Cascadia,Consolas,monospace}#dsh-plan:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}#dsh-plan .p-grid{position:absolute;top:0;right:0;bottom:0;left:0;z-index:0;pointer-events:none;background-image:radial-gradient(circle,var(--grid-dot) 1px,transparent 1px);background-size:24px 24px;background-position:0 0}#dsh-plan .p-world{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;transform-origin:0 0}#dsh-plan .p-layer{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none}#dsh-plan .p-edges{position:absolute;overflow:visible;width:100%;height:100%;pointer-events:none}#dsh-plan .p-frame{pointer-events:none}#dsh-plan .p-frame-head,#dsh-plan .p-node{pointer-events:auto}#dsh-plan .e-member{stroke:var(--uupm-edge-member);stroke-opacity:.38;stroke-width:1.5}#dsh-plan .e-member.dashed{stroke-dasharray:3 4}#dsh-plan .p-frame{--frame-ink:var(--frame-line,#8B5CF6)}@media (prefers-color-scheme: light){#dsh-plan .p-frame{--frame-ink:color-mix(in srgb,var(--frame-line,#8B5CF6) 72%,black)}}#dsh-plan .p-frame{position:absolute;border:1px solid var(--frame-ink);border-radius:10px;background:var(--frame-bg,var(--uupm-wash-5));min-width:120px;min-height:60px}#dsh-plan .p-frame-head{position:absolute;top:-13px;left:50%;transform:translate(-50%);height:24px;padding:0 10px;border-radius:6px;display:flex;gap:8px;align-items:center;background:var(--uupm-bg-2);border:1px solid var(--frame-ink);font-size:12px;font-weight:600;letter-spacing:.02em;white-space:nowrap;cursor:grab}#dsh-plan .p-frame-head:active{cursor:grabbing}#dsh-plan .p-frame-head:hover{border-color:var(--card-line-hover)}#dsh-plan .p-frame-head .cnt{color:var(--ink-muted);font-weight:400}#dsh-plan .p-frame-head .route{font-size:10.5px;color:var(--ink-muted)}#dsh-plan .p-node{position:absolute;width:172px;height:56px;padding:8px 26px 8px 14px;background:var(--card-bg);border:1px solid var(--card-line);border-left:3px solid var(--edge-live);border-radius:8px;cursor:grab;-webkit-user-select:none;user-select:none;transition:border-color .12s cubic-bezier(.2,0,0,1),transform .12s cubic-bezier(.2,0,0,1)}#dsh-plan .p-node:hover{border-color:var(--card-line-hover)}#dsh-plan .p-node:active{cursor:grabbing}#dsh-plan .p-node:focus-visible{outline:2px solid var(--accent);outline-offset:2px}#dsh-plan .p-node.selected{outline:2px solid var(--accent);outline-offset:1px}#dsh-plan .p-node.dragging{transform:scale(1.02);border-color:var(--accent)}#dsh-plan .p-node.cold{border-left-color:var(--edge-cold)}#dsh-plan .p-node .nm{font-weight:600;display:flex;align-items:center;gap:7px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}#dsh-plan .p-node .nm-text{min-width:0;overflow:hidden;white-space:normal;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;line-height:1.25}#dsh-plan .p-node.remote .nm-text{overflow-wrap:anywhere}#dsh-plan .p-node .dot{width:8px;height:8px;border-radius:50%;background:var(--edge-live);flex:none}#dsh-plan .p-node.cold .dot{background:transparent;border:1.5px solid var(--edge-cold)}#dsh-plan .p-node .sub{font-size:11px;color:var(--ink-muted);margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}#dsh-plan .p-node.pulse{box-shadow:0 0 0 2px var(--accent),0 0 14px 4px var(--uupm-wash-15);border-color:var(--accent)}#dsh-plan .p-search{position:relative}#dsh-plan .p-search-input{width:170px;min-height:28px;padding:2px 8px;font-size:12px;background:transparent;color:var(--ink);border:1px solid var(--card-line);border-radius:6px}#dsh-plan .p-search-input:focus-visible{outline:2px solid var(--accent);outline-offset:1px}#dsh-plan .p-search-list{position:absolute;top:100%;left:0;margin-top:4px;display:none;min-width:240px;max-height:220px;overflow:auto;z-index:9;background:var(--toolbar-bg);border:1px solid var(--card-line);border-radius:6px}#dsh-plan .p-search-hit{padding:5px 10px;font-size:12px;color:var(--ink);cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#dsh-plan .p-search-hit:hover,#dsh-plan .p-search-hit.active{background:var(--uupm-wash-15)}#dsh-plan .p-node .prio{position:absolute;top:6px;right:8px;font-size:10px;color:var(--ink-muted);border:1px solid var(--card-line);border-radius:4px;padding:0 5px}#dsh-plan .p-marquee{position:absolute;z-index:2;display:none;pointer-events:none;border:1px solid var(--accent);background:var(--uupm-wash-8)}#dsh-plan .p-toolbar{position:absolute;top:16px;left:16px;z-index:3;display:flex;gap:6px;align-items:center;background:var(--toolbar-bg);border:1px solid var(--card-line);border-radius:8px;padding:6px 8px}#dsh-plan .p-tabs{position:absolute;top:16px;left:50%;transform:translate(-50%);z-index:3;display:flex;gap:4px;background:var(--toolbar-bg);border:1px solid var(--card-line);border-radius:8px;padding:4px}#dsh-plan .p-tabs [role=tab]{background:transparent;color:var(--ink-muted);border:1px solid transparent;border-radius:6px;padding:4px 12px;font:inherit;cursor:pointer}#dsh-plan .p-tabs [role=tab]:hover{color:var(--ink);border-color:var(--card-line)}#dsh-plan .p-tabs [role=tab][aria-selected=true]{color:var(--ink);border-color:var(--accent);background:var(--uupm-wash-12)}#dsh-plan .p-tabs [role=tab]:focus-visible{outline:2px solid var(--accent);outline-offset:1px}#dsh-plan .p-toolbar button{background:transparent;color:var(--ink);border:1px solid var(--card-line);border-radius:6px;padding:4px 10px;font:inherit;cursor:pointer;white-space:nowrap}#dsh-plan .p-toolbar button:hover{border-color:var(--accent)}#dsh-plan .p-toolbar button:active{background:var(--uupm-wash-15)}#dsh-plan .p-toolbar button:focus-visible{outline:2px solid var(--accent);outline-offset:1px}#dsh-plan .p-zoom{min-width:44px;text-align:center;font-size:11px;color:var(--ink-muted)}#dsh-plan .p-sep{align-self:stretch;width:1px;margin:2px 4px;background:var(--card-line)}#dsh-plan .p-lamp{display:flex;align-items:center;gap:6px;font-size:11px;color:var(--ink-muted);padding:0 6px}#dsh-plan .p-lamp i{width:7px;height:7px;border-radius:50%;background:var(--ink-muted);transition:background .14s ease}#dsh-plan .p-lamp.saved i{background:var(--edge-live)}#dsh-plan .p-lamp.pending i{background:var(--uupm-warn)}#dsh-plan .p-lamp.error{color:var(--uupm-error);cursor:pointer}#dsh-plan .p-lamp.error i{background:var(--uupm-error)}#dsh-plan .p-lamp.error:hover{border:1px solid var(--uupm-error);border-radius:4px}#dsh-plan .p-status{position:absolute;top:16px;right:16px;z-index:3;display:flex;gap:14px;background:var(--toolbar-bg);border:1px solid var(--card-line);border-radius:8px;padding:8px 14px;font-size:12px}#dsh-plan .p-status b{font-weight:600}#dsh-plan .ok{color:var(--edge-live)}#dsh-plan .warn{color:var(--uupm-warn)}#dsh-plan .mut{color:var(--ink-muted)}#dsh-plan .p-legend{position:absolute;bottom:16px;left:16px;z-index:3;font-size:11px;color:var(--ink-muted);background:var(--toolbar-bg);border:1px solid var(--card-line);border-radius:8px;padding:4px 10px}#dsh-plan .p-legend summary{cursor:pointer;padding:2px 0;-webkit-user-select:none;user-select:none}#dsh-plan .p-legend summary:focus-visible{outline:2px solid var(--accent);outline-offset:2px}#dsh-plan .p-legend[open]{padding-bottom:8px}#dsh-plan .p-legend-rows{display:grid;gap:4px;margin-top:4px}#dsh-plan .p-legend i{display:inline-block;width:18px;border-top:2px solid var(--uupm-edge-member);vertical-align:middle;margin-right:6px}#dsh-plan .p-legend i.dashed{border-top-style:dashed}@media (max-width:680px){#dsh-plan .p-toolbar{position:relative;top:auto;left:auto;margin:8px 8px 0;flex-wrap:wrap;row-gap:6px}#dsh-plan .p-toolbar>*{flex:none}#dsh-plan .p-toolbar .p-search{order:-1;flex:1 1 100%}#dsh-plan .p-toolbar .p-sep{display:none}#dsh-plan .p-toolbar .p-search-input{width:100%;box-sizing:border-box}#dsh-plan .p-status{position:relative;top:auto;right:auto;left:auto;width:fit-content;margin:6px 8px 0;padding:6px 10px;gap:10px;flex-wrap:wrap}#dsh-plan .p-legend{display:none}}@media (pointer:coarse){#dsh-plan .p-toolbar button{min-height:36px;min-width:36px}}@media (prefers-reduced-motion: reduce){#dsh-plan *{transition:none!important;animation:none!important}}#dsh-plan .p-frame.drop-target{border-color:var(--accent);border-width:2px;background:var(--uupm-wash-12)}#dsh-plan .p-frame-head:focus-visible{outline:2px solid var(--accent);outline-offset:1px}#dsh-plan .p-node.remote{border-left-color:var(--federal);padding-right:46px}#dsh-plan .p-node.remote .dot{background:var(--federal)}#dsh-plan .p-node.remote .prio{color:var(--ink)}#dsh-plan .p-node .prio.lnk-linked{color:var(--live, #2e9e5b);border-color:var(--live, #2e9e5b)}#dsh-plan .p-node .prio.lnk-stranger{color:var(--ink-muted);border-color:var(--card-line)}#dsh-plan .e-activity{stroke:var(--accent);stroke-width:2;stroke-dasharray:8 6;stroke-opacity:.9}#dsh-plan .e-federal{stroke:var(--federal);stroke-width:1.5;stroke-dasharray:6 5;stroke-opacity:.5}#dsh-plan .edge-label{font-size:10.5px;fill:var(--ink-muted)}@media (prefers-reduced-motion: no-preference){#dsh-plan .e-activity{animation:p-activity-flow 1.1s linear infinite}}@keyframes p-activity-flow{to{stroke-dashoffset:-28}}#dsh-plan .p-status{cursor:pointer}#dsh-plan .p-status:hover{border-color:var(--accent)}#dsh-plan .p-status:active{background:var(--uupm-wash-12)}#dsh-plan .p-status:focus-visible{outline:2px solid var(--accent);outline-offset:2px}#dsh-plan .p-menu{position:fixed;z-index:5;min-width:170px;display:grid;padding:4px;gap:2px;background:var(--toolbar-bg);border:1px solid var(--card-line);border-radius:8px}#dsh-plan .p-menu [role=menuitem]{background:transparent;color:var(--ink);border:1px solid transparent;border-radius:6px;padding:6px 10px;font:inherit;text-align:left;cursor:pointer;white-space:nowrap}#dsh-plan .p-menu [role=menuitem]:hover{border-color:var(--card-line);background:var(--uupm-wash-8)}#dsh-plan .p-menu [role=menuitem]:active{background:var(--uupm-wash-18)}#dsh-plan .p-menu [role=menuitem]:focus-visible{outline:2px solid var(--accent);outline-offset:1px}#dsh-plan .p-menu [role=menuitem][aria-disabled=true]{color:var(--ink-muted);cursor:not-allowed}#dsh-plan .p-dialog{position:absolute;top:0;right:0;bottom:0;left:0;z-index:6;display:grid;place-items:center;background:var(--scrim)}#dsh-plan .p-dialog-panel{min-width:300px;padding:14px 16px;display:grid;gap:10px;background:var(--uupm-bg-2);border:1px solid var(--card-line);border-radius:10px}#dsh-plan .p-dialog-title{font-weight:600;font-size:12.5px;color:var(--ink)}#dsh-plan .p-dialog-input{font:inherit;color:var(--ink);background:var(--uupm-bg-0);border:1px solid var(--card-line);border-radius:6px;padding:7px 10px}#dsh-plan .p-dialog-input:hover{border-color:color-mix(in srgb,var(--uupm-ink-1) 55%,transparent)}#dsh-plan .p-dialog-input:focus-visible{outline:2px solid var(--accent);outline-offset:1px;border-color:var(--accent)}#dsh-plan .p-dialog-err{min-height:1.2em;font-size:11px;color:var(--uupm-error)}#dsh-plan .p-dialog-row{display:flex;gap:8px;justify-content:flex-end}#dsh-plan .p-dialog-row button{background:transparent;color:var(--ink);border:1px solid var(--card-line);border-radius:6px;padding:5px 12px;font:inherit;cursor:pointer}#dsh-plan .p-dialog-row button:hover{border-color:var(--accent)}#dsh-plan .p-dialog-row button:active{background:var(--uupm-wash-15)}#dsh-plan .p-dialog-row button:focus-visible{outline:2px solid var(--accent);outline-offset:1px}#dsh-plan .p-notice-stack{position:absolute;bottom:52px;left:50%;transform:translate(-50%);z-index:5;display:grid;gap:6px;justify-items:center;pointer-events:none}#dsh-plan .p-notice{max-width:60ch;padding:7px 12px;font-size:12px;color:var(--ink);background:var(--toolbar-bg);border:1px solid var(--card-line);border-radius:8px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#dsh-plan .p-notice.error{color:var(--error-ink);border-color:var(--uupm-error);background:var(--error-panel)}#dsh-plan .p-netbtn{color:var(--ink-muted)}#dsh-plan .p-netbtn:not([disabled]){color:var(--ink)}#dsh-plan .p-netmenu{max-height:240px;overflow:auto}#dsh-plan .p-nodebtn{color:var(--ink)}#dsh-plan .p-nodelist{min-width:300px;max-width:340px;max-height:420px;overflow:auto;padding:6px}#dsh-plan .p-nodelist-head{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:2px 4px 6px;border-bottom:1px solid var(--card-line)}#dsh-plan .p-nodelist-title{font-size:12px;font-weight:600;color:var(--ink)}#dsh-plan .p-nodesel{font:inherit;font-size:11.5px;color:var(--ink);background:var(--uupm-bg-0);border:1px solid var(--card-line);border-radius:6px;padding:2px 6px;max-width:220px}#dsh-plan .p-nodesel:focus-visible{outline:2px solid var(--accent);outline-offset:1px}#dsh-plan .p-nodelist-group{font-size:11px;color:var(--ink-muted);padding:8px 4px 3px;display:flex;align-items:baseline;gap:8px}#dsh-plan .p-nodelist-note{font-size:10px;color:var(--ink-muted);opacity:.8}#dsh-plan .p-noderow{display:flex;align-items:center;gap:6px;padding:3px 4px;border-radius:6px;font-size:12px;color:var(--ink)}#dsh-plan .p-noderow:hover{background:var(--uupm-wash-8)}#dsh-plan .p-nodedot{flex:none;width:7px;height:7px;border-radius:50%;background:var(--edge-live)}#dsh-plan .p-nodedot.cold{background:var(--ink-muted)}#dsh-plan .p-nodedot.off{background:transparent;border:1px solid var(--ink-muted)}#dsh-plan .p-nodename{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}#dsh-plan .p-nonet{flex:none;font-size:10px;color:var(--uupm-warn);border:1px solid var(--uupm-warn);border-radius:4px;padding:0 4px}#dsh-plan .p-teamcount{flex:none;font-size:10px;color:var(--ink-muted);border:1px solid var(--card-line);border-radius:4px;padding:0 4px}#dsh-plan .p-listbtn{flex:none;background:transparent;color:var(--ink);border:1px solid var(--card-line);border-radius:5px;padding:1px 7px;font:inherit;font-size:11px;cursor:pointer}#dsh-plan .p-listbtn:hover{border-color:var(--card-line-hover);background:var(--uupm-wash-8)}#dsh-plan .p-listbtn:focus-visible{outline:2px solid var(--accent);outline-offset:1px}#dsh-plan .p-nodelist-empty{padding:10px 4px;font-size:11.5px;color:var(--ink-muted)}#dsh-plan .p-frame{position:absolute}#dsh-plan .p-frame-handle{position:absolute;pointer-events:auto;width:10px;height:10px;z-index:2;opacity:0;transition:opacity .12s ease}#dsh-plan .p-frame:hover .p-frame-handle{opacity:1}#dsh-plan .p-frame-handle:after{content:"";position:absolute;top:2px;right:2px;bottom:2px;left:2px;background:var(--frame-ink);border-radius:2px}#dsh-plan .p-h-n{top:-5px;left:calc(50% - 12px);width:24px;height:8px;cursor:ns-resize}#dsh-plan .p-h-s{bottom:-5px;left:calc(50% - 12px);width:24px;height:8px;cursor:ns-resize}#dsh-plan .p-h-e{right:-5px;top:calc(50% - 12px);width:8px;height:24px;cursor:ew-resize}#dsh-plan .p-h-w{left:-5px;top:calc(50% - 12px);width:8px;height:24px;cursor:ew-resize}#dsh-plan .p-h-ne{top:-5px;right:-5px;cursor:nesw-resize}#dsh-plan .p-h-nw{top:-5px;left:-5px;cursor:nwse-resize}#dsh-plan .p-h-se{bottom:-5px;right:-5px;cursor:nwse-resize}#dsh-plan .p-h-sw{bottom:-5px;left:-5px;cursor:nesw-resize}#dsh-plan .p-h-ne:after,#dsh-plan .p-h-sw:after{transform:rotate(45deg)}#dsh-plan .p-h-nw:after,#dsh-plan .p-h-se:after{transform:rotate(-45deg)}#dsh-plan .p-frame.selected .p-frame-handle{opacity:1}#dsh-plan .p-frame.selected{outline:1px solid var(--frame-ink)}:root{color-scheme:dark;--n-bg:#060a12;--n-ink:#dde3f0;--n-ink-muted:#7a86a0;--n-panel:#0d1322;--n-live:#4ade80;--n-cold:#7a86a0;--n-border:#223052;--n-act:#f59e0b;--n-danger:#f87171;--n-accent:#9673f7;--n-rail-w:300px;--n-canvas:#22d3ee;--n-line:var(--n-border);--n-raised:#131b2e;--n-federal:#6366f1;--n-card-line:#5c6680;--n-error-ink:#fecaca;--n-error-panel:#2a0d10f2;--n-shadow:rgba(0,0,0,.35)}@media (prefers-color-scheme: light){:root{--n-bg:#eef2fa;--n-ink:#1a2438;--n-ink-muted:#5a6580;--n-panel:#ffffff;--n-live:#157a37;--n-border:#c6d0e6;--n-act:#a84d08;--n-danger:#b91c1c;--n-accent:#6d28d9;--n-cold:#636c81;--n-canvas:#0e7490;--n-raised:#ffffff;--n-federal:#4f46e5;--n-card-line:#8a95ae;--n-error-ink:#b91c1c;--n-error-panel:#fef2f2f2;--n-shadow:rgba(26,36,56,.16)}}@media (min-width:1440px){:root{--n-rail-w:340px }}html,body,#app{height:100%;margin:0}body{background:var(--n-bg);color:var(--n-ink);font:13px/1.45 system-ui,Segoe UI,Roboto,PingFang SC,Microsoft YaHei,sans-serif}.wb{display:flex;flex-direction:column;height:100%}.wb-header{display:flex;align-items:center;gap:12px;padding:8px 14px;border-bottom:1px solid var(--n-border);background:var(--n-panel)}.wb-title{display:flex;align-items:center;gap:10px;font-weight:600;font-size:14px;white-space:nowrap}.wb-badge{font-size:11px;font-weight:400;color:var(--n-ink-muted);border:1px solid var(--n-border);border-radius:99px;padding:1px 8px}.wb-badge[hidden]{display:none}.wb-row-remote{margin-left:6px;padding:0 6px;border:1px solid currentColor;border-radius:99px;font-size:10.5px;color:var(--n-ink-muted);vertical-align:1px}.wb-header-stats{display:flex;gap:16px;font-size:12px;color:var(--n-ink-muted);flex-wrap:wrap;min-width:0}.wb-header-stats .wb-kv{display:flex;gap:6px}.wb-header-stats .wb-kv-k{color:var(--n-ink-muted)}.wb-header-stats .wb-kv-v{color:var(--n-ink)}.wb-header-ok{color:var(--n-ink-muted)}.wb-alert{border:1px solid currentColor;border-radius:99px;padding:0 9px;line-height:20px;white-space:nowrap;cursor:pointer;background:transparent;font:inherit}.wb-alert:hover{background:color-mix(in srgb,currentColor 12%,transparent)}.wb-alert:focus-visible{outline:2px solid currentColor;outline-offset:2px}.wb-alert-danger{color:var(--n-danger)}.wb-alert-warn{color:var(--n-act)}.wb-forensics{font-family:ui-monospace,Consolas,monospace;font-size:11px}.wb-icon-btn{background:none;border:1px solid var(--n-border);color:var(--n-ink);border-radius:8px;width:30px;height:30px;display:none;align-items:center;justify-content:center;font:inherit;font-size:14px;cursor:pointer;flex:none}.wb-icon-btn:hover{border-color:var(--n-accent)}.wb-menu{margin-left:0}.wb-rail-toggle{margin-left:auto}.wb.is-rail-collapsed .wb-rail{display:none}.wb-body{position:relative;display:grid;grid-template-columns:minmax(0,var(--n-rail-w)) minmax(0,1fr);flex:1;min-height:0}.wb-rail{border-right:1px solid var(--n-border);min-width:0;min-height:0;display:flex;flex-direction:column;overflow:hidden;background:color-mix(in srgb,var(--n-panel) 60%,var(--n-bg))}.wb-side-head{font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:var(--n-ink-muted);margin:10px 2px 4px}.wb-item{display:flex;gap:7px;align-items:center;width:100%;text-align:left;background:none;border:none;color:var(--n-ink);font:inherit;padding:3px 6px;border-radius:6px;cursor:pointer}.wb-item:hover{background:color-mix(in srgb,var(--n-accent) 14%,transparent)}.wb-dot{font-size:10px}.wb-dot-live{color:var(--n-live)}.wb-dot-cold{color:var(--n-cold)}.wb-dot-canvas{color:var(--n-canvas)}.wb-dot-remote{color:var(--n-act)}.wb-dir-tools{display:flex;flex-direction:column;gap:6px;padding:8px 6px 4px}.wb-search{background:var(--n-panel);border:1px solid var(--n-border);color:var(--n-ink);border-radius:6px;padding:4px 8px;font:inherit;font-size:12.5px;min-width:0}.wb-search:focus{outline:1px solid var(--n-accent)}.wb-filters{display:flex;flex-wrap:wrap;gap:4px}.wb-filter{background:none;border:1px solid var(--n-border);color:var(--n-ink-muted);border-radius:99px;padding:0 10px;min-height:24px;font:inherit;font-size:11.5px;cursor:pointer}.wb-filter:hover{border-color:var(--n-accent);color:var(--n-ink)}.wb-filter.is-active{border-color:var(--n-accent);color:var(--n-ink);background:color-mix(in srgb,var(--n-accent) 16%,transparent)}.wb-item-badge{flex:none;font-size:10.5px;color:var(--n-canvas);border:1px solid color-mix(in srgb,var(--n-canvas) 45%,transparent);border-radius:99px;padding:0 6px;line-height:17px;white-space:nowrap}.wb-item-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wb-member-row{display:flex;align-items:center;gap:8px;padding:3px 2px;border-radius:6px}.wb-member-row:hover{background:color-mix(in srgb,var(--n-accent) 10%,transparent)}.wb-member-dot{flex:none;font-size:11px;color:var(--n-ink-muted);min-width:44px}.wb-member-label{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wb-member-remove,.wb-member-submit{background:none;border:1px solid var(--n-border);color:var(--n-ink);border-radius:6px;padding:1px 8px;font:inherit;font-size:11.5px;cursor:pointer;flex:none}.wb-member-remove:hover:not(:disabled),.wb-member-submit:hover:not(:disabled){border-color:var(--n-danger)}.wb-member-submit:hover:not(:disabled){border-color:var(--n-accent)}.wb-member-add{display:flex;flex-wrap:wrap;gap:6px;margin-top:6px}.wb-member-pick,.wb-member-manual{background:var(--n-panel);border:1px solid var(--n-border);color:var(--n-ink);border-radius:6px;padding:3px 8px;font:inherit;font-size:12px;min-width:0}.wb-member-pick{flex:1 1 150px}.wb-member-manual{flex:1 1 130px}.wb-member-pick:focus,.wb-member-manual:focus{outline:1px solid var(--n-accent)}.wb-hint{margin-top:10px;font-size:11px;color:var(--n-ink-muted);line-height:1.5}.wb-dispatch{margin-top:12px;border-top:1px dashed var(--n-border);padding-top:8px}.wb-dispatch-form{display:flex;flex-direction:column;gap:6px;margin-top:6px}.wb-dispatch-text{background:var(--n-panel);border:1px solid var(--n-border);color:var(--n-ink);border-radius:6px;padding:5px 8px;font:inherit;font-size:12px;min-height:52px;resize:vertical}.wb-dispatch-text:focus{outline:1px solid var(--n-accent)}.wb-dispatch-submit{align-self:flex-end;background:none;border:1px solid var(--n-border);color:var(--n-ink);border-radius:6px;padding:2px 14px;font:inherit;font-size:11.5px;cursor:pointer}.wb-dispatch-submit:hover:not(:disabled){border-color:var(--n-accent)}.wb-dispatch-note{font-size:11px;color:var(--n-ink-muted);line-height:1.4;min-height:0}.wb-stage{position:relative;min-width:0;min-height:0;display:flex;flex-direction:column}.wb-stage-board{position:absolute;top:0;right:0;bottom:0;left:0;overflow:hidden}.wb-stage-board.is-hidden{display:none}.wb-data{display:flex;flex-direction:column;gap:14px;padding:10px 14px;overflow-y:auto;min-height:0}.wb-data.is-hidden{display:none}.wb-pane-head{font-size:12px;color:var(--n-ink-muted);margin:4px 0 8px}.wb-pane-subhead{font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:var(--n-ink-muted);margin:12px 0 6px}.wb-table,.wb-row{display:flex;gap:10px;align-items:baseline}.wb-row{font-family:ui-monospace,Consolas,monospace;font-size:12px;background:color-mix(in srgb,var(--n-panel) 55%,transparent);border:1px solid var(--n-border);border-radius:6px;padding:3px 8px;flex-wrap:wrap}.wb-row-team{color:var(--n-accent);min-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wb-row-meta{color:var(--n-ink-muted)}.wb-row-badges{color:var(--n-live)}.wb-row-dir{min-width:16px}.wb-row-dir.is-fail{color:var(--n-danger)}.wb-btn{background:none;border:1px solid var(--n-border);color:var(--n-ink);border-radius:6px;padding:2px 10px;font:inherit;font-size:12px;cursor:pointer;margin-left:auto}.wb-btn:hover:not(:disabled){border-color:var(--n-accent)}.wb-btn:disabled{opacity:.5;cursor:default}.wb-btn-primary{border-color:var(--n-accent);color:var(--n-ink)}.wb-action{display:flex;gap:10px;align-items:baseline;font-size:12.5px;padding:5px 8px;border-radius:6px;border:1px solid var(--n-border);margin-bottom:4px}.wb-action-high{border-color:var(--n-danger)}.wb-action-text{flex:1}.wb-draft{display:flex;flex-direction:column;gap:8px;max-width:560px;margin-top:6px}.wb-select,.wb-textarea{background:var(--n-panel);border:1px solid var(--n-border);color:var(--n-ink);border-radius:8px;padding:6px 9px;font:inherit}.wb-textarea{resize:vertical}.wb-select:focus,.wb-textarea:focus{outline:1px solid var(--n-accent)}.wb-inspector{position:absolute;top:8px;right:8px;width:280px;max-height:calc(100% - 16px);overflow-y:auto;background:var(--n-panel);border:1px solid var(--n-border);border-radius:10px;padding:10px;z-index:20;box-shadow:0 8px 24px var(--n-shadow);display:none}.wb-inspector.is-open{display:block}.wb-inspector-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:6px}.wb-inspector-title{font-weight:600;font-size:12.5px}.wb-inspector .wb-icon-btn{display:inline-flex;width:24px;height:24px;font-size:12px}.wb-card{display:flex;flex-direction:column;gap:6px}.wb-kv{display:flex;gap:8px;font-size:12px}.wb-kv-k{color:var(--n-ink-muted);min-width:58px;flex:none}.wb-kv-v{word-break:break-all}.wb-muted{color:var(--n-ink-muted)}.wb-chat{position:absolute;top:8px;right:8px;bottom:8px;width:400px;max-width:calc(100% - 16px);display:flex;flex-direction:column;background:var(--n-panel);border:1px solid var(--n-border);border-radius:12px;z-index:22;box-shadow:0 8px 24px var(--n-shadow);overflow:hidden;transform:translate(calc(100% + 12px));transition:transform .18s ease;pointer-events:none}.wb-chat.is-open{transform:translate(0);pointer-events:auto}.wb-chat-head{display:flex;align-items:center;gap:8px;padding:10px 10px 10px 12px;border-bottom:1px solid var(--n-border);flex:none}.wb-chat-dot{flex:none;width:8px;height:8px;border-radius:50%;background:var(--n-ink-muted)}.wb-chat-dot.is-live{background:var(--n-live)}.wb-chat-dot.is-cold{background:transparent;border:1.5px solid var(--n-ink-muted)}.wb-chat-dot.is-peer{background:var(--n-federal)}.wb-chat-titles{display:flex;flex-direction:column;flex:1 1 auto;min-width:0;line-height:1.3}.wb-chat-title{font-weight:600;font-size:13.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wb-chat-sub{font:11px/1.4 ui-monospace,Consolas,monospace;color:var(--n-ink-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wb-chat .wb-icon-btn{display:inline-flex;width:28px;height:28px;font-size:13px;flex:none;border-color:transparent}.wb-chat .wb-icon-btn:hover{border-color:var(--n-border)}.wb-chat .wb-icon-btn:focus-visible{outline:2px solid var(--n-accent);outline-offset:1px}.wb-chat .wb-chat-back[hidden]{display:none}.wb-chat-info-btn[aria-expanded=true]{border-color:var(--n-accent);color:var(--n-accent)}.wb-chat-info{flex:none;display:flex;flex-direction:column;gap:4px;padding:8px 12px;font-size:12px;border-bottom:1px solid var(--n-border);background:color-mix(in srgb,var(--n-bg) 55%,var(--n-panel))}.wb-chat-info[hidden]{display:none}.wb-chat-info .wb-kv-v{font-family:ui-monospace,Consolas,monospace;font-size:11.5px}.wb-chat-thread{flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;display:flex;flex-direction:column;gap:10px;padding:12px}.wb-chat-thread:focus-visible{outline:2px solid var(--n-accent);outline-offset:-2px}.wb-chat-log,.wb-chat-sent{display:flex;flex-direction:column;gap:10px}.wb-chat-notice{align-self:center;max-width:92%;text-align:center;font-size:11.5px;line-height:1.5;color:var(--n-ink-muted);border:1px dashed var(--n-border);border-radius:8px;padding:6px 10px}.wb-chat-notice[hidden]{display:none}.wb-chat-empty{align-self:center;padding:24px 8px;font-size:12px;color:var(--n-ink-muted);text-align:center}.wb-chat-empty.is-error{color:var(--n-danger)}.wb-msg{display:flex;flex-direction:column;gap:4px;max-width:86%;padding:8px 11px;border-radius:12px;font-size:13px;line-height:1.55}.wb-msg-assistant{align-self:flex-start;background:var(--n-raised);border:1px solid var(--n-border);border-bottom-left-radius:4px}.wb-msg-user{align-self:flex-end;background:color-mix(in srgb,var(--n-accent) 16%,var(--n-panel));border:1px solid color-mix(in srgb,var(--n-accent) 35%,transparent);border-bottom-right-radius:4px}.wb-msg-ledger{align-self:center;max-width:92%;background:transparent;border:1px dashed var(--n-border);font-size:12px}.wb-msg-ledger .wb-msg-text{color:var(--n-ink-muted)}.wb-msg-ledger .wb-msg-meta{justify-content:center}.wb-msg-in .wb-msg-meta{justify-content:flex-start}.wb-msg-who{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.wb-msg-text{color:var(--n-ink);white-space:pre-wrap;word-break:break-word;overflow-wrap:anywhere}.wb-msg-meta{display:flex;flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:6px;font-size:11px}.wb-msg-task{font-family:ui-monospace,Consolas,monospace;color:var(--n-ink-muted)}.wb-msg-status{border:1px solid currentColor;border-radius:99px;padding:0 7px;line-height:18px;white-space:nowrap}.wb-msg-status.is-wait,.wb-msg-status.is-muted{color:var(--n-ink-muted)}.wb-msg-status.is-ok{color:var(--n-live)}.wb-msg-status.is-warn{color:var(--n-act)}.wb-msg-status.is-danger{color:var(--n-danger)}.wb-chat-divider{display:flex;align-items:center;gap:8px;font-size:11px;color:var(--n-ink-muted);margin-top:4px}.wb-chat-divider:before,.wb-chat-divider:after{content:"";flex:1;border-top:1px solid var(--n-border)}.wb-chat-sessions{display:flex;flex-direction:column;gap:6px}.wb-chat-session{display:flex;flex-direction:column;align-items:flex-start;gap:2px;width:100%;text-align:left;background:var(--n-raised);border:1px solid var(--n-border);border-radius:8px;padding:7px 10px;color:var(--n-ink);font:inherit;cursor:pointer}.wb-chat-session:hover{border-color:var(--n-accent)}.wb-chat-session:focus-visible{outline:2px solid var(--n-accent);outline-offset:1px}.wb-chat-session-id{font:12px ui-monospace,Consolas,monospace}.wb-chat-session-meta{font-size:11px;color:var(--n-ink-muted)}.wb-chat-foot{flex:none;border-top:1px solid var(--n-border);padding:8px 10px 10px;background:var(--n-panel)}.wb-chat-composer{display:flex;flex-direction:column;gap:4px}.wb-chat-composer-row{display:flex;align-items:flex-end;gap:8px}.wb-chat-composer .wb-dispatch-text{flex:1 1 auto;min-height:38px;max-height:160px;resize:none;border-radius:10px;padding:8px 10px;font-size:13px;line-height:1.5}.wb-chat-composer .wb-dispatch-submit{align-self:auto;height:38px;padding:0 16px;border-radius:10px;background:var(--n-accent);border-color:var(--n-accent);color:var(--n-bg);font-size:13px;font-weight:600}.wb-chat-composer .wb-dispatch-submit:hover:not(:disabled){border-color:var(--n-accent);filter:brightness(1.08)}.wb-chat-composer .wb-dispatch-submit:disabled{opacity:.45;cursor:default}.wb-chat-composer .wb-dispatch-note{font-size:11px;padding-left:2px}.wb-chat-composer .wb-dispatch-note.is-error{color:var(--n-danger)}.wb-chat-readonly{font-size:12px;color:var(--n-ink-muted);text-align:center;padding:4px 0}.nexus-fault{display:none;position:fixed;top:10px;right:12px;z-index:50;max-width:420px;font:12px/1.5 ui-monospace,Consolas,monospace;color:var(--n-error-ink);background:var(--n-error-panel);border:1px solid var(--n-danger);border-radius:8px;padding:6px 10px;pointer-events:none}@media (max-width:1023px){.wb-menu{display:inline-flex}.wb-rail-toggle{display:none}.wb-body{grid-template-columns:minmax(0,1fr)}.wb-rail{position:fixed;left:0;top:0;bottom:0;width:min(86vw,320px);z-index:40;background:var(--n-panel);border-right:1px solid var(--n-border);transform:translate(-102%);transition:transform .18s ease;box-shadow:8px 0 24px var(--n-shadow)}.wb.is-rail-open .wb-rail{transform:translate(0)}.wb-inspector{left:8px;right:8px;width:auto;top:auto;bottom:8px;max-height:45%}.wb-chat{left:8px;right:8px;width:auto;top:auto;bottom:8px;height:85%;max-height:85%;transform:translateY(102%)}.wb-chat.is-open{transform:translateY(0)}}@media (pointer:coarse){.wb-filter,.wb-item,.wb-tab{min-height:36px}.wb-icon-btn,.wb-inspector .wb-icon-btn,.wb-chat .wb-icon-btn{width:36px;height:36px}}@media (max-width:680px){.wb-header{flex-wrap:wrap;row-gap:4px}.wb-header-stats{order:3;width:100%}.wb-row-team{min-width:0;flex:1 1 auto}.wb-data{padding:8px}}.wb-host-row{display:flex;align-items:center;gap:7px;padding:4px 6px;border:1px solid var(--n-border);border-radius:7px;margin-bottom:4px;cursor:pointer;font-size:12px}.wb-host-row:hover{border-color:var(--n-accent);background:color-mix(in srgb,var(--n-accent) 8%,transparent)}.wb-host-row:focus-visible{outline:2px solid var(--n-accent);outline-offset:1px}.wb-host-lamp{flex:none;width:8px;height:8px;border-radius:50%;background:var(--n-ink-muted)}.wb-host-lamp.is-live{background:var(--n-live)}.wb-host-lamp.is-warm{background:var(--n-act)}.wb-host-lamp.is-cold{background:var(--n-ink-muted)}.wb-host-lamp.is-fail{background:var(--n-danger)}.wb-host-lamp.is-unknown{background:transparent;border:1px solid var(--n-ink-muted)}.wb-host-name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--n-ink)}.wb-host-badge{flex:none;font-size:10.5px;border-radius:99px;padding:0 7px;line-height:17px;border:1px solid var(--n-border)}.wb-host-badge.is-linked{color:var(--n-live);border-color:var(--n-live)}.wb-host-badge.is-stranger{color:var(--n-ink-muted);border-color:var(--n-border)}.wb-host-ver{flex:none;font-size:10px;color:var(--n-ink-muted);border:1px solid var(--n-border);border-radius:4px;padding:0 4px}.wb-host-url{flex:none;max-width:40%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--n-ink-muted);font-size:10.5px}.wb-tabs{flex:none;display:flex;gap:2px;padding:6px 6px 0;border-bottom:1px solid var(--n-border);overflow-x:auto;scrollbar-width:none}.wb-tab{flex:1 1 auto;display:inline-flex;align-items:center;justify-content:center;gap:5px;min-width:0;background:none;border:none;border-bottom:2px solid transparent;color:var(--n-ink-muted);font:inherit;font-size:12.5px;padding:6px 6px 7px;cursor:pointer;white-space:nowrap}.wb-tab:hover{color:var(--n-ink)}.wb-tab.is-active{color:var(--n-ink);border-bottom-color:var(--n-accent);font-weight:600}.wb-tab:focus-visible{outline:2px solid var(--n-accent);outline-offset:-2px;border-radius:6px 6px 0 0}.wb-tab[hidden]{display:none}.wb-tab-badge{font:10.5px/16px ui-monospace,Consolas,monospace;color:var(--n-ink-muted);font-weight:400}.wb-tab-badge:empty{display:none}.wb-tab-badge.is-danger,.wb-tab-badge.is-warn,.wb-tab-badge.is-accent{padding:0 6px;border-radius:99px;border:1px solid currentColor}.wb-tab-badge.is-danger{color:var(--n-danger)}.wb-tab-badge.is-warn{color:var(--n-act)}.wb-tab-badge.is-accent{color:var(--n-accent)}.wb-tabpanels{flex:1 1 auto;min-height:0;display:flex;flex-direction:column}.wb-tabpanel{flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:8px 10px 16px}.wb-tabpanel[hidden]{display:none}.wb-tabpanel:focus-visible{outline:2px solid var(--n-accent);outline-offset:-2px}.wb-tabpanel .wb-pane{display:flex;flex-direction:column;gap:8px}.wb-tabpanel .wb-dir-tools{padding:0 0 6px}.wb-dir-group{display:flex;flex-direction:column;gap:1px;margin-top:10px}.wb-dir-group:first-child{margin-top:2px}.wb-dir-head{display:flex;align-items:baseline;justify-content:space-between;gap:8px;padding:0 6px 4px;font-size:11px;letter-spacing:.04em;color:var(--n-ink-muted)}.wb-dir-head-label{font-weight:600;color:var(--n-ink)}.wb-dir-head-note{font-size:10.5px}.wb-dir-day{padding:6px 6px 2px;font-size:10.5px;color:var(--n-ink-muted)}.wb-dir-empty{padding:24px 8px;text-align:center;font-size:12px;color:var(--n-ink-muted)}.wb-directory .wb-item{gap:9px;padding:5px 6px;border-radius:8px}.wb-directory .wb-item:focus-visible{outline:2px solid var(--n-accent);outline-offset:-2px}.wb-item-text{display:flex;flex-direction:column;flex:1 1 auto;min-width:0;line-height:1.35}.wb-item-sub{font:11px/1.35 ui-monospace,Consolas,monospace;color:var(--n-ink-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wb-item.is-untitled .wb-item-label{color:var(--n-ink-muted);font-family:ui-monospace,Consolas,monospace;font-size:12px}.wb-dot-log{color:var(--n-ink-muted)}.wb-led-tiles{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px}.wb-led-tile{display:flex;flex-direction:column;align-items:flex-start;gap:1px;padding:7px 8px;border-radius:8px;border:1px solid var(--n-border);background:var(--n-raised);cursor:help;min-width:0}.wb-led-tile-v{font:600 17px/1.15 ui-monospace,Consolas,monospace;color:var(--n-ink)}.wb-led-tile-k{font-size:11px;color:var(--n-ink-muted)}.wb-led-tile.is-warn{border-color:var(--n-act)}.wb-led-tile.is-warn .wb-led-tile-v{color:var(--n-act)}.wb-led-tile.is-danger{border-color:var(--n-danger)}.wb-led-tile.is-danger .wb-led-tile-v{color:var(--n-danger)}.wb-led-split{display:flex;flex-direction:column;gap:4px}.wb-led-split-bar{display:flex;height:6px;border-radius:99px;overflow:hidden;background:var(--n-border)}.wb-led-seg{display:block;height:100%}.wb-led-split-legend{display:flex;flex-wrap:wrap;gap:4px 10px;font-size:11px;color:var(--n-ink-muted)}.wb-led-split-item{display:inline-flex;align-items:center;gap:4px}.wb-led-swatch{display:inline-block;width:8px;height:8px;border-radius:2px}.wb-led-seg.is-completed,.wb-led-swatch.is-completed{background:var(--n-live)}.wb-led-seg.is-rejected,.wb-led-swatch.is-rejected{background:var(--n-act)}.wb-led-seg.is-failed,.wb-led-swatch.is-failed{background:var(--n-danger)}.wb-led-seg.is-abandoned,.wb-led-swatch.is-abandoned{background:var(--n-ink-muted)}.wb-led-seg.is-unclassified,.wb-led-swatch.is-unclassified,.wb-led-seg.is-other,.wb-led-swatch.is-other{background:color-mix(in srgb,var(--n-ink-muted) 45%,var(--n-border))}.wb-led-group{display:flex;flex-direction:column;gap:6px;margin-top:4px}.wb-led-group-head{display:flex;align-items:baseline;justify-content:space-between;gap:8px;font-size:11.5px;font-weight:600;color:var(--n-ink)}.wb-led-group-hint{font-size:10.5px;font-weight:400;color:var(--n-ink-muted)}.wb-led-group.is-danger .wb-led-group-head{color:var(--n-danger)}.wb-led-group.is-warn .wb-led-group-head{color:var(--n-act)}.wb-led-card{position:relative;display:flex;flex-direction:column;gap:3px;padding:7px 9px;border-radius:8px;border:1px solid var(--n-border);background:var(--n-raised);min-width:0}.wb-led-card.is-danger{border-color:var(--n-danger)}.wb-led-card.is-warn{border-left:3px solid var(--n-act)}.wb-led-card.is-muted,.wb-led-card.is-quiet{background:transparent}.wb-led-card.is-link{cursor:pointer}.wb-led-card.is-link:hover{border-color:var(--n-accent)}.wb-led-card.is-link:focus-visible{outline:2px solid var(--n-accent);outline-offset:1px}.wb-led-card-head{display:flex;align-items:flex-start;gap:6px;min-width:0}.wb-led-dir{flex:none;font-size:12px;color:var(--n-ink-muted);line-height:1.45}.wb-led-dir.is-in{color:var(--n-federal)}.wb-led-brief{flex:1 1 auto;min-width:0;font-size:12.5px;line-height:1.45;color:var(--n-ink);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;overflow-wrap:anywhere}.wb-led-card.is-muted .wb-led-brief,.wb-led-card.is-quiet .wb-led-brief{color:var(--n-ink-muted)}.wb-led-card.is-danger .wb-led-brief{color:var(--n-danger)}.wb-led-brief.is-missing{font-style:italic}.wb-led-meta{display:flex;flex-wrap:wrap;gap:2px 8px;font:11px/1.45 ui-monospace,Consolas,monospace;color:var(--n-ink-muted);min-width:0}.wb-led-meta>span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}.wb-led-chip{border:1px solid var(--n-border);border-radius:99px;padding:0 6px;font-family:inherit}.wb-led-abandon{position:absolute;top:6px;right:6px;margin-left:0;padding:1px 9px;font-size:11.5px}.wb-led-abandon.is-quiet{border-color:transparent;background:transparent;color:var(--n-ink-muted)}.wb-led-abandon.is-quiet:hover{border-color:var(--n-border);color:var(--n-ink)}.wb-led-card:has(.wb-led-abandon) .wb-led-card-head{padding-right:52px}.wb-led-empty{padding:24px 8px;text-align:center;font-size:12px;color:var(--n-ink-muted)}.wb-led-forensics{font-size:11px;color:var(--n-ink-muted);border-top:1px dashed var(--n-border);padding-top:6px;margin-top:4px}.wb-led-forensics summary{cursor:pointer}.wb-led-forensics summary:focus-visible{outline:2px solid var(--n-accent);outline-offset:1px}.wb-led-forensics-body{display:flex;flex-direction:column;gap:2px;padding:4px 0 0 12px;font-family:ui-monospace,Consolas,monospace}
|