From 0df84100da1fff4aa7f19b0aecad774861add714 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Sat, 31 Oct 2026 03:20:27 -0700 Subject: [PATCH 1/5] feat(connectors): tile grid for channels and tools (TASK-677 slice a) Layout only, from the D215 artboard: rows render as auto-fill tiles (150px minimum, aside kept per the 2026-10-31 ruling). Same rows, same act and same connect flow. The inactive fold spans the grid. Co-Authored-By: Claude Haiku 5.5 Co-authored-by: kai Agent-Model: claude/claude-haiku-5-5/default --- frontend/src/v2/v2.css | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/frontend/src/v2/v2.css b/frontend/src/v2/v2.css index a27973a1b0..170f6532f4 100644 --- a/frontend/src/v2/v2.css +++ b/frontend/src/v2/v2.css @@ -10743,6 +10743,14 @@ body.modern-ui.v2-canvas { .v2-connectors__inactive-caret { width: 7px; height: 7px; border-right: 1px solid currentColor; border-bottom: 1px solid currentColor; transform: rotate(-45deg); } .v2-root button.v2-connectors__inactive-toggle[aria-expanded="true"] .v2-connectors__inactive-caret { transform: rotate(45deg); } .v2-connectors__inactive-rows > .v2-connector-row:last-child { border-bottom: 0; } +/* TASK-677 slice (a), D215 artboard: channels and tools render as a tile grid + (auto-fill, 150px minimum, per the 2026-10-31 ruling; the aside stays). Layout + only: the same rows, the same act and the same connect flow. The inactive fold + spans the grid, and its own rows reuse the same tile template. */ +.v2-connectors__rows { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px; overflow: visible; border: 0; border-radius: 0; } +.v2-connectors__rows .v2-connector-row { grid-template-columns: minmax(0, 1fr); align-content: center; min-height: 128px; border: 1px solid var(--v2-border-soft); border-radius: 14px; padding: 14px 12px; } +.v2-connectors__inactive-fold { grid-column: 1 / -1; } +.v2-connectors__inactive-rows { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px; padding: 12px 0 0; } .v2-connector-row { display: grid; From e8d673ac6276fa8018fd13d418aa39b4c2a0f015 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Sat, 31 Oct 2026 03:30:51 -0700 Subject: [PATCH 2/5] fix(connectors): keep tile content inside the 150px tile (TASK-677 a) The row's two-track grid and spanning placements sized the name, detail and act past the tile at 1440. Inside a tile the content now stacks in one track and wraps. Layout only. Co-Authored-By: Claude Haiku 5.5 Co-authored-by: kai Agent-Model: claude/claude-haiku-5-5/default --- frontend/src/v2/v2.css | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/frontend/src/v2/v2.css b/frontend/src/v2/v2.css index 170f6532f4..6f6e706417 100644 --- a/frontend/src/v2/v2.css +++ b/frontend/src/v2/v2.css @@ -10751,6 +10751,14 @@ body.modern-ui.v2-canvas { .v2-connectors__rows .v2-connector-row { grid-template-columns: minmax(0, 1fr); align-content: center; min-height: 128px; border: 1px solid var(--v2-border-soft); border-radius: 14px; padding: 14px 12px; } .v2-connectors__inactive-fold { grid-column: 1 / -1; } .v2-connectors__inactive-rows { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px; padding: 12px 0 0; } +/* Lumen's 1440 HOLD (review 5722362448): the row's own two-track grid and its + spanning placements sized the name, detail and act past a 150px tile. Inside a + tile the content stacks in one track and wraps within the tile. */ +.v2-root .v2-connectors__rows button.v2-connector-row__selection { grid-column: 1; grid-template-columns: minmax(0, 1fr); row-gap: 6px; } +.v2-connectors__rows .v2-connector-row__name, +.v2-connectors__rows .v2-connector-row__details { min-width: 0; overflow-wrap: anywhere; } +.v2-connectors__rows .v2-connector-row__details { padding-right: 0; } +.v2-root .v2-connectors__rows .v2-connector-row__action { grid-column: 1; grid-row: 2; justify-self: stretch; } .v2-connector-row { display: grid; From 3bbe8bf66ca7e6c15dd3a7b2a22a749f4793df08 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Sat, 31 Oct 2026 04:25:40 -0700 Subject: [PATCH 3/5] fix(connectors): stop mid-word name splits and the 52px tile reserve (TASK-677 a) overflow-wrap:anywhere on the tile name split words that fit ("Telegra/m"). Keep it on the detail only. Drop the 52px icon-act reserve inside a tile: the act sits in row 2 now, so the reserve only narrowed the text. Layout only. Co-Authored-By: Claude Haiku 5.5 Co-authored-by: kai Agent-Model: claude/claude-haiku-5-5/default --- frontend/src/v2/v2.css | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/frontend/src/v2/v2.css b/frontend/src/v2/v2.css index 6f6e706417..9879dada5a 100644 --- a/frontend/src/v2/v2.css +++ b/frontend/src/v2/v2.css @@ -10755,9 +10755,11 @@ body.modern-ui.v2-canvas { spanning placements sized the name, detail and act past a 150px tile. Inside a tile the content stacks in one track and wraps within the tile. */ .v2-root .v2-connectors__rows button.v2-connector-row__selection { grid-column: 1; grid-template-columns: minmax(0, 1fr); row-gap: 6px; } -.v2-connectors__rows .v2-connector-row__name, -.v2-connectors__rows .v2-connector-row__details { min-width: 0; overflow-wrap: anywhere; } -.v2-connectors__rows .v2-connector-row__details { padding-right: 0; } +.v2-connectors__rows .v2-connector-row__name { min-width: 0; overflow-wrap: normal; } +.v2-connectors__rows .v2-connector-row__details { min-width: 0; overflow-wrap: anywhere; padding-right: 0; } +/* The 760px rule reserved 52px beside the icon act (column 2). The act now sits + in row 2 inside a tile, so the reserve only narrowed the text. */ +.v2-root .v2-connectors__rows .v2-connector-row:has(.v2-connector-row__action--icon) button.v2-connector-row__selection { padding-right: 0; } .v2-root .v2-connectors__rows .v2-connector-row__action { grid-column: 1; grid-row: 2; justify-self: stretch; } .v2-connector-row { From c6689a90c1b7d704f51e4bdeaab59c54ee8b6135 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Sat, 31 Oct 2026 04:32:23 -0700 Subject: [PATCH 4/5] fix(connectors): stack the tile mark above its name (TASK-677 a) At 1440 the mark and name shared a 124px track, so Telegram and GroupMe ran past the tile edge. Inside a tile the name stacks: mark above label, the artboard's anatomy. Layout only. Co-Authored-By: Claude Haiku 5.5 Co-authored-by: kai Agent-Model: claude/claude-haiku-5-5/default --- frontend/src/v2/v2.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/v2/v2.css b/frontend/src/v2/v2.css index 9879dada5a..d6cb8cd6b6 100644 --- a/frontend/src/v2/v2.css +++ b/frontend/src/v2/v2.css @@ -10755,7 +10755,7 @@ body.modern-ui.v2-canvas { spanning placements sized the name, detail and act past a 150px tile. Inside a tile the content stacks in one track and wraps within the tile. */ .v2-root .v2-connectors__rows button.v2-connector-row__selection { grid-column: 1; grid-template-columns: minmax(0, 1fr); row-gap: 6px; } -.v2-connectors__rows .v2-connector-row__name { min-width: 0; overflow-wrap: normal; } +.v2-connectors__rows .v2-connector-row__name { min-width: 0; overflow-wrap: normal; flex-direction: column; align-items: center; gap: 6px; text-align: center; } .v2-connectors__rows .v2-connector-row__details { min-width: 0; overflow-wrap: anywhere; padding-right: 0; } /* The 760px rule reserved 52px beside the icon act (column 2). The act now sits in row 2 inside a tile, so the reserve only narrowed the text. */ From b255a698944b3822763928c9c16d1eb3b884c936 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Sat, 31 Oct 2026 17:38:40 -0700 Subject: [PATCH 5/5] fix(connectors): centre the tile icon act and guard the tile grid (TASK-677 a) Review of the tile grid found three things to fix: - The gear act is 32px or 44px, so stretch did nothing. It now sits centred under the text in its tile, at (0,4,1) so the 760px icon placement does not win. - The name's overflow-wrap is anywhere, so a long unbroken label wraps inside the tile instead of spilling past it. - The channel-row comment no longer claims tools are tiled; tools rows are unchanged in this slice. The layout-invariant suite now guards the tile grid, the fold span and the centred icon act, since jsdom cannot see the cascade. Co-Authored-By: Claude Haiku 5.5 Co-authored-by: kai Agent-Model: claude/claude-haiku-5-5/default --- .../v2/__tests__/v2-layout-invariants.test.ts | 8 ++++++++ frontend/src/v2/v2.css | 17 +++++++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/frontend/src/v2/__tests__/v2-layout-invariants.test.ts b/frontend/src/v2/__tests__/v2-layout-invariants.test.ts index 7f96ca6c82..2724844039 100644 --- a/frontend/src/v2/__tests__/v2-layout-invariants.test.ts +++ b/frontend/src/v2/__tests__/v2-layout-invariants.test.ts @@ -2429,6 +2429,14 @@ describe('v2 layout invariants (CSS rule presence)', () => { expect(layoutBlocks('v2-connectors').filter((b) => b.includes('min-height'))).toEqual([]); expect(layoutBlocks('v2-connectors__content').filter((b) => b.includes('flex: 1'))).toEqual([]); expect(layoutBlocks('v2-connectors__rows').filter((b) => b.includes('flex: 1'))).toEqual([]); + // TASK-677 tile grid: the channel rows tile at 150px minimum, the fold spans + // the grid, and the icon act is centred. jsdom cannot see the cascade, so the + // 760px overrides are guarded by presence here. + // ruleBody takes the first line-start match, which is the base rule, so scan + // every block for the tile declarations instead. + expect(layoutBlocks('v2-connectors__rows').some((b) => b.includes('repeat(auto-fill, minmax(150px, 1fr))'))).toBe(true); + expect(layoutBlocks('v2-connectors__inactive-fold').some((b) => b.includes('grid-column: 1 / -1'))).toBe(true); + expect(layoutBlocks('v2-connector-row__action--icon').some((b) => b.includes('justify-self: center'))).toBe(true); expect(ruleBody(v2, '.v2-page-head__meta')).toContain('var(--v2-font-mono)'); expect(ruleBody(v2, '.v2-connector-row__glyph')).toContain('width: 20px'); expect(ruleBody(v2, '.v2-connector-row__glyph')).toContain('color: inherit'); diff --git a/frontend/src/v2/v2.css b/frontend/src/v2/v2.css index d6cb8cd6b6..4d4afc7623 100644 --- a/frontend/src/v2/v2.css +++ b/frontend/src/v2/v2.css @@ -10743,10 +10743,11 @@ body.modern-ui.v2-canvas { .v2-connectors__inactive-caret { width: 7px; height: 7px; border-right: 1px solid currentColor; border-bottom: 1px solid currentColor; transform: rotate(-45deg); } .v2-root button.v2-connectors__inactive-toggle[aria-expanded="true"] .v2-connectors__inactive-caret { transform: rotate(45deg); } .v2-connectors__inactive-rows > .v2-connector-row:last-child { border-bottom: 0; } -/* TASK-677 slice (a), D215 artboard: channels and tools render as a tile grid +/* TASK-677 slice (a), D215 artboard: channel rows render as a tile grid (auto-fill, 150px minimum, per the 2026-10-31 ruling; the aside stays). Layout - only: the same rows, the same act and the same connect flow. The inactive fold - spans the grid, and its own rows reuse the same tile template. */ + only: the same rows, the same act and the same connect flow. Tools rows are not + tiled in this slice. The inactive fold spans the grid, and its own rows reuse + the same tile template. */ .v2-connectors__rows { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px; overflow: visible; border: 0; border-radius: 0; } .v2-connectors__rows .v2-connector-row { grid-template-columns: minmax(0, 1fr); align-content: center; min-height: 128px; border: 1px solid var(--v2-border-soft); border-radius: 14px; padding: 14px 12px; } .v2-connectors__inactive-fold { grid-column: 1 / -1; } @@ -10755,12 +10756,16 @@ body.modern-ui.v2-canvas { spanning placements sized the name, detail and act past a 150px tile. Inside a tile the content stacks in one track and wraps within the tile. */ .v2-root .v2-connectors__rows button.v2-connector-row__selection { grid-column: 1; grid-template-columns: minmax(0, 1fr); row-gap: 6px; } -.v2-connectors__rows .v2-connector-row__name { min-width: 0; overflow-wrap: normal; flex-direction: column; align-items: center; gap: 6px; text-align: center; } +.v2-connectors__rows .v2-connector-row__name { min-width: 0; overflow-wrap: anywhere; flex-direction: column; align-items: center; gap: 6px; text-align: center; } .v2-connectors__rows .v2-connector-row__details { min-width: 0; overflow-wrap: anywhere; padding-right: 0; } -/* The 760px rule reserved 52px beside the icon act (column 2). The act now sits - in row 2 inside a tile, so the reserve only narrowed the text. */ +/* The 760px rule reserved 52px beside the icon act (column 2). Inside a tile the + icon act is centred under the text, so the reserve only narrowed the text. The + specificity here is (0,5,1), above the 760px padding-right rule (0,4,1). */ .v2-root .v2-connectors__rows .v2-connector-row:has(.v2-connector-row__action--icon) button.v2-connector-row__selection { padding-right: 0; } .v2-root .v2-connectors__rows .v2-connector-row__action { grid-column: 1; grid-row: 2; justify-self: stretch; } +/* The icon act is 32px or 44px wide, so stretch does nothing; centre it under the + text. Specificity (0,4,1) beats the 760px icon placement (0,2,1). */ +.v2-root .v2-connectors__rows button.v2-connector-row__action--icon { grid-column: 1; grid-row: 2; justify-self: center; } .v2-connector-row { display: grid;