Owner's first review of the combo rework (2026-08-09): remove the face padding, make the
field taller and narrower at about a 4:5 width:height ratio, and center the symbol glyph in
its face. All three land in ComboFieldMetrics, so ColorComboControl and SymbolComboControl
stay the identical shape they were built to share.
- ComboFieldMetrics grows a width figure (height * widthToHeightRatio, 0.8), replacing
NSView.noIntrinsicMetric — every combo now carries its own taller, narrower intrinsic size
instead of stretching to whatever a caller's frame proposed.
- facePaddingH/facePaddingV/glyphPadding are gone; a face fills its zone edge to edge.
glyphPointSize is now whichever of the face's own width/height is smaller, with nothing
subtracted for padding that no longer exists.
- SymbolComboControl.drawFace centers the glyph on both axes — it only ever centered
vertically before, despite its own doc comment claiming otherwise.
- ComboFieldControl.drawTrigger bounds its chevron square by the smaller of the trigger
strip's own width/height, not height alone, since the strip is no longer close to square
once the field is much taller than it is wide.
- CardSidebarSections drops the sidebar's old '* 0.55' fixed-width frame on both combo rows;
each control now sizes itself, and both anchors (card sidebar, board popover) compose the
narrower field with no other changes needed.
- ComboFieldMetricsTests updated for the new figures, plus a ratio-holds-at-every-size test
and a rewritten glyph-fit test matching the no-padding rule.
Verification: xcodebuild build succeeded; xcodebuild test -only-testing:KanbanTests — 3220
tests in 559 suites, 3 failures, all PointerLatencyTests (documented locked-screen
environmental mode, confirmed unrelated by isolated rerun). Pixel verification unexercised —
same locked-screen constraint the first pass hit.
Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
The colour combo was a wide two-zone field with a second door onto the Colors
panel; the symbol picker was a small square button with one. Both now subclass
one `ComboFieldControl`, so they are the same width, height, radius and trigger
by construction: click the face for the standalone picker, click the chevron for
the quick list. The symbol face opens a new floating browser over the OS's own
category, ordering and keyword plists out of CoreGlyphs.bundle — searchable,
categorised, trademark-restricted glyphs withheld.
The palette grows twelve to sixteen per table, filling the hue ring's four
widest gaps with lime, jade, indigo and magenta at each table's own saturation
and brightness. That gives the Style… popover's background grid a third row and
the tint grid its third row of four, and both grids gain an Other… row onto the
system colour picker — which the card sidebar's combo has had all along and the
primary styling surface never did. An arbitrary hex already round-tripped; it is
asserted now, including that an unquoted one is a YAML comment and no value.
Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
`CuratedSymbols` was one flat ~65-glyph list serving every style-editor target alike. It is
now three level-specific sets — `boards` (project/container/identity), `lanes`
(workflow/stage/status), `cards` (work-item/content) — each ~30-40 entries, seeded from the
original list and `SymbolPickerCatalog.defaultSet`, reorganized by which level a glyph actually
reads as being about. Overlap is kept where a glyph genuinely fits everywhere (`flag`, `star`).
Wiring:
- `BoardInfoPopover`'s board-glyph `SymbolPicker` now passes `CuratedSymbols.availableBoards`
instead of the picker's domain-agnostic default.
- The card sidebar's `SymbolPicker` (`CardSidebarSections`) now passes
`CuratedSymbols.availableCards` instead of the old flat `available`.
- The style editor's own curated grid (`StyleEditorView`, the Style… popover's only remaining
anchor) reads `CuratedSymbols.availableForStyleEditor(level:spansLevels:)`: a homogeneous
target reads its own level's set, and a target that somehow spans more than one level (today
unreachable — 04-interactions.md's cards-XOR-lanes rule keeps a live selection homogeneous)
reads the three combined, via a new `BoardStore.styleTargetSpansLevels` seam that asks the
question `styleLevel(of:)` deliberately collapses.
- `CuratedSymbols.combined` (the three sets' stable-order union) also replaces the old `.all`
in `SymbolPickerCatalog`'s full-catalog fallback.
- `SymbolPickerCatalog.defaultSet` is kept as the fallback for a caller naming no level (a
future saved-search picker, say) rather than retired.
DESIGN/03-board-ui.md and DESIGN/05-card-window.md's Styling/sidebar prose amended minimally
where they named "the curated set" as a single list.
Tests: three new/rewritten suites in KanbanTests/StyleModelTests.swift (set shape, availability,
overlap, `combined`, the style-editor level/span decision, the board-anchor width tripwire), one
new test in KanbanTests/StyleWriteTests.swift (`styleTargetSpansLevels`), and the old
single-list-pinning tests in KanbanTests/SymbolPickerTests.swift and KanbanTests/CardSidebarTests.swift
updated to the new set names. 2834 tests, 487 suites green (KanbanTests, arm64); one unrelated
flaky failure (RootRecoveryTests.vanishAndReturn under full-suite load) passed clean in isolation.
Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
iconColor stops being hand-written-only (user-ruled, superseding 03's
"schema yes, control no"): it rides StyleCommand.apply → applyStyle as
the third styled dimension — per-dimension no-op skip, one bracket, one
history step, ExpectedField.iconColor for staleness. The SymbolPicker
grows an opt-in colour row (leading None plus seven Palette.foregrounds
hues, None removes the key); the board popover is its one caller. The
window-title widget now draws the board's resolved glyph in that tint
beside the name. Doc realignment filed on the Redesign board (Minor).
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
SymbolPicker: one well at rest, a 6x6 curated grid in a popover (leading
well = the level default, clearing the key), and an optional search over
the OS's full symbol inventory read from CoreGlyphs metadata. Geometry
font-derived off StyleEditorLayout's base, grid enlarged by a deliberate
1.3x. Wired inline with the rename field in the board info popover
through the StyleCommand funnel; the Title header retires. Curated set
and the search's standing vs 03's full-browser refusal await ratification.