The native port is finished off with the readability work the earlier rounds
left open, plus the cleanup of everything the shadcn era or the older canvas
left behind.
- Geometry: node height is now composed from named parts (chrome, two title
lines, meta row) and per-node extras, so a teammate card that carries a task
line no longer gets clipped by the old fixed 68px budget; the layout spec
follows the new model and GRAPH_ROW_STRIDE stays exported for it.
- Readability: row rhythm (28-32px), three ink levels for title/meta/owner,
truncation with title hints, current-row and hover expressed as an accent bar
plus a hover fill (no shadows), phase frames and edges back on the l1/l2
hairlines, control cluster uniformly 28px, drawer durations on tabular
figures, kill action revealed on hover/focus without shifting the row, no
horizontal overflow at 360px.
- Task window: the markdown body is pulled onto the page scale (12px body,
12/13px headings, tightened list indent and paragraph spacing) while the
shared MarkdownText/markdownTextProps contract is untouched.
- Cleanup: dead stylesheet rules, unused TSX exports and helpers, stale
comments that still described the retired Variant-D canvas, zero-reference
i18n keys across the dictionaries, and the Tailwind/shadcn/Variant-D
narrative in the design doc, AGENTS.md and the plugin guide (kept as one
short "why it was rolled back" section).
Verified here: typecheck and lint clean; 133 files / 1413 tests; build with no
radix-ui or --tw- strings in lib/client.js (988.9 KiB); the 70-assertion
real-browser contract at 70/70 with the 20 reference screenshots regenerated;
mount e2e 7/7.
Real-device report: the Tasks page "looks like it has no CSS at all, with
blurry borders". Two hypotheses were falsified before the real cause surfaced:
the sheet IS delivered (the chunk carries both the CSS and its injector, and
the bundle route serves it) and the cascade is NOT the problem (with the real
host stylesheet plus the real compiled sheet, a controlled sample keeps our
padding, radius, border, background and font; host CSS-module selectors only
match host nodes, and its global element rules are element-level specificity).
The cause is what we deliberately excluded: PREFLIGHT is also what normalizes
form controls. Measured on a plugin icon button that sets only an icon size,
the UA chrome survived as padding 1px 6px, border 2px outset, background
ButtonFace (#efefef) and a 13.33px system font - gray beveled buttons with a
soft double border, i.e. "no CSS".
- ui/theme.css: a .dsw-tasks-scoped preflight subset (zero margins/padding,
border width+style, background, appearance none, inherit color/spacing,
cursor rules) inside @layer base, written with :where() so it stays at
(0,1,0) and utilities in the later layer still win; plus an explicit
"@layer theme, base, components, utilities;" statement - layer order follows
first appearance, and without it the utilities import registered utilities
BEFORE base, so the reset beat rounded-md (measured: square buttons). The
built chunk's order was re-checked: properties, theme, base, components,
utilities.
- Stock shadcn restyle: static cards carry stock shadow-xs/shadow-sm again
(floating layers keep shadow-lg), body/meta text is text-sm/text-xs instead
of 11-13px, status uses stock Badge variants, controls use stock Button
variants and sizes, row actions appear on hover/focus while staying keyboard
reachable, node cards are 176x68 with shadow-xs.
- bandColsFor budgets columns at the readability floor (width / 0.78) instead
of 1:1, so a 360px panel keeps two columns; FIT_MIN_SCALE moved into the
layout module as GRAPH_FIT_MIN_SCALE so the fit and the column budget share
one constant.
- Guards: tests/ui-foundation.spec.ts pins the scoped reset declarations and
the layer-order statement; tests/ui-shadows.spec.ts now allows shadow-xs and
shadow-sm on static panels and bans md and above; the theme guard's inert
paint rule forced the reset to spell border-width/border-style instead of the
"border: 0 solid" shorthand.
Verified: typecheck and lint clean; 136 files / 1505 tests; build with the
core/chunk bundle guards; mount e2e 7/7 (mount 444ms, longtasks 2 of 8); the
visual mirror page (real host stylesheet + real components) re-shot at 360 and
720 for graph, tree and the 77-node stress fixture.
Review feedback from the live 3384 install, fixed at the root:
- COLORS: the new stylesheet used var(--dsw-alias-accent) in 17 places — a
token the DSH theme does NOT define, so every declaration was dropped
(older files only survived because they carry fallbacks); container edges
used border-l1 (4% black, invisible). Accent now rides
--dsw-alias-state-business-primary, container edges --dsw-alias-border-l4.
- CLICKS: the canvas called setPointerCapture on pointerdown, which
retargets the derived click to the container and killed every node (and
ⓘ) interaction; jsdom cannot see this, a real browser can. Capture is
gone and panning only starts from the background.
- LAYOUT: fit gave up silently at zero container size and never retried,
centered only horizontally, and capped at 100% while a five-child level
scaled to 35%. Now: ResizeObserver + first non-zero fit, both axes
centered, a 0.78 readability floor, and layoutTasksGraphForWidth picks
the flattest sibling arrangement that still meets that floor.
- CARDS: title (one line) + mono meta + live line only; display title,
team role, full model id and latest text moved into the ⓘ popover.
- PANEL: metrics follow the approved 360x660 mockup (132x46 cards, 112 row
stride), explicit line-heights, user-select:none, horizontal control
cluster with a labelled mode button, always-visible team board strip.
- Tokens for two new popover headings across all 20 dictionaries.
Tests: 3 new page-interaction specs (click after background pointerdown,
node gestures never pan, team board visible without a click) and a
rewritten 9-case layout suite (band wrap, row reservation, width solver,
reserved live row). Full suite 1400 passed / 133 files.
- tasks-model.ts: one pre-order node list for graph AND tree modes —
catalog walking, workflow-run attachment with member re-parenting and
synthesis, team enrichment, per-parent settled-leaf fold aggregates.
- tasks-graph-layout.ts: dependency-free tidy-tree layered layout
(bundle-purity: no graph library in the core bundle).
- api.ts: workflowsList/teamsView/teamsTaskCreate/teamsTaskUpdate with
the wire result types mirrored from the host routes.
- 11 unit tests across model derivation, edge classification, fold, and
layout geometry.