`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
The card window sidebar's Style section embedded StyleEditorView symbols-only
(showsBackground: false, showsSymbols: true), drawing the curated grid whole
inside the sidebar's own scroll view — a permanently open 5-7 row grid ahead
of every other section. Replace it with the reusable compact SymbolPicker
(already used by BoardInfoPopover for the board's glyph): a single well at
rest, the grid only inside its own popover.
- CardStyleSection no longer instantiates StyleEditorView at all. A new
"Symbol" row mirrors the existing "Background" row's inspector shape
(caption leading, control trailing), wiring SymbolPicker's onSelect/
onSelectColor to icon/iconColor through StyleCommand.apply(...on: undo),
the exact funnel the background combo already rides — so the card window's
undo session semantics (13-native-undo.md) are unchanged.
- The picker is fed CuratedSymbols.available rather than its own smaller
general-purpose default, so a card's curated vocabulary doesn't shrink.
- StyleEditorLayout.sidebar and showsBackground stay in StyleEditor.swift
(still correct, still tested) rather than being cut as dead code — a
separate, larger cleanup this card doesn't make (recorded on the card).
- DESIGN/03-board-ui.md and DESIGN/05-card-window.md: updated the sentences
describing the sidebar hosting the style editor's symbol grid to describe
the compact picker instead.
- Tests: CardSessionUndoTests gains a symbol/tint analogue of the existing
background-combo session-routing test; CardSidebarTests gains a curated-set
tripwire and an updated file-header note.
Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
background is {color:, image:} and only a mapping at every level; the board's image paints the full window under a transparent title bar, with a thin-material frost strip keeping the chrome legible and the standard accommodations intact.
Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
Full relative text scaling per DESIGN/10: BoardMetrics is the board
strip's geometry as a pure function of the body point size
(CardWindowMetrics' twin) — lane plate/header/band, card
corner/stripe/padding, masonry spacing, the drop model's nominal card
height, resize-handle geometry, trash hatch pitch, and both window
floors all derive from an em; CardFaceMetrics folded in. The two fixed
font sizes (welcome brand/glyph) went relative; the toolbar search
field is 17 ems like the transient bar's. The no-horizontal-scroll
invariant is pinned by test at six text sizes by twelve lane counts.
Accommodations is Motion's sibling for the visual settings: Increase
Contrast adds a flat point to strokes (monotone, hierarchy-preserving),
gives borderless card/lane plates a resting separator hairline, and
takes faded accents to full alpha; Reduce Transparency turns the
transient search bar's glass solid and does the same for the alpha
washes that composite over a user-chosen board background (trash plate,
hatched header, drag shadow). Reduce Motion audited — every animated
surface already routes through Motion with a reduced variant; no gaps.
Full Keyboard Access: the template chooser's tiles were pointer-only —
now focusable, arrow-navigable (clamped, StyleWellGrid's rule), Space
picks, Return stays the sheet's default action, focus names the
selection one-way. The board's single tab stop shows its focus ring
under FKA (focusEffectDisabled inverts). Style editor verified already
conformant. Edge accents verified text-free; trash hatch pitch now
font-derived so it still reads as hatching at large text.
1549 unit tests green, both schemes build.
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
The sidebar completes: the shared style editor gains a second anchor —
StyleEditorLayout carries the geometry (the popover keeps its settled
268/14/7/8 untouched as the default; the sidebar packs columns to its
width with no inner scroller) while every well, the batch display, the
arrow grammar, and the one applyStyle bracket stay the shared
component's. The card anchor is fixed, not tracking: the target is
this card, and the fate walk retires the window when the card goes.
Details renders every unknown frontmatter key read-only in file order —
Card.document already carried them — showing the author's own bytes
where the raw span is a value and the engine's rendering for block
scalars and empties; reserved enhanced-schema keys are ordinary
unknowns, and no keys means no section. Actions: Delete rides the same
tombstone bytes as Backspace and drop-on-trash through a one-line
seam, says nothing about selection, and lets the fate walk dismiss;
Reveal in Finder resolves through the attachment scope so the two
paths cannot disagree. History reserves its m7 slot without drawing a
header no base board can honor.
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY