docs: park the new handoff bundles (android, shared foundations, tui) #269

Merged
nalum merged 13 commits from docs/park-handoff-bundles into main 2026-08-26 18:37:36 +00:00
Owner

The thirteen demo-stylesheet conformance commits that sat between the jobs stack and the calendar stack, previously without a PR of their own.

The thirteen demo-stylesheet conformance commits that sat between the jobs stack and the calendar stack, previously without a PR of their own.
job-card-demo.dc.html now carries the card's stylesheet as the contract
(three layers: token roles, base blocks, delta-only modifiers), and the
build had drifted from it in a dozen small values. Aligned by role, not
by name — the demo's --ec-* names map onto the generated theme roles
(--ec-sunken=--surface-sunken, --ec-ink-subtle=--ink-soft,
--ec-late=--warning).

Value fixes, demo → app:
- panel floor 4.71em on EVERY panel state (was 5.9556rem on the plain
  panel only, with is-offer/is-ticked/waiting exempted — the demo floors
  all four rungs and lets the spacer absorb the difference)
- panel body 1.05em (was 1.02rem); eyebrow 0.8em / 0.15em gap (was
  0.78/0.2)
- waiting stack gap 0.65em (was 0.55), face overlap -10px (was -9)
- progress caption ink-soft with the % in ink-muted (was one shade up:
  ink-muted/ink)
- meta row 0.95em with only the DUE half bold and in --ink (was the
  whole row 700 at 0.85rem in ink-soft); meta gap 0.5em
- quiet line 1em (was 0.95)
- card action row: primary in Fredoka 600 1.05em, both buttons on the
  btn radius role (radius - 8 = the demo's meadow 14), the ⋯ in
  ink-soft; tap sizes in rem so they grow with text scale
- the card is borderless (fill against the board, rail only) and an
  unowned card's rail is transparent, not line-coloured (§4e)

Verdicts on the demo values NOT taken literally:
- tap 2.7em → 2.6667rem: 48px at the 18px base, exactly the measured
  height the 312px card was built around; 2.7em's extra 0.6px would
  clip against the capped card. Scales identically.
- marks/faces stay the mark system's 28px: the mark renders the same
  everywhere by its own ruling, and resizing identity is a mark-system
  change, not a card one.
- the meta separator stays --border-strong: the demo's --ec-ink-faint
  is a fourth ink role no generated theme carries; minting one is a §9
  tokens.yaml change to challenge separately.
- title keeps its 2-line clamp (build-review-01 slot 1); the demo sheet
  has no clamp but its titles never wrap.
- min-height keeps its max twin: the demo floors only, but the cap is
  what makes 'one height for every state' structural on a live board.
The demo locks the completion moment (job-card-demo.dc.html ec-stamp):
the owner's mark stamps EVERY completion — 96px, 700ms, the springier
(.2,1.4,.4,1) curve settling at 45% — and points on the line add
confetti BESIDE the stamp, never a different overlay in its place. The
build swapped the stamp for the Rewards page's 🎉 claim burst when
points were attached, and tinted the card celebrate underneath; the
demo tints nothing.

The points celebration itself stays the board's viewport confetti
burst (confetti.ts / ConfettiOverlay) fired from the card — the
built-out implementation of the demo's own 16-piece stand-in, which
draws inside one card only because the demo page has no board layer to
burst into. One overlay grammar per moment: job done = stamp (+ the
burst when points are on the line), reward claimed = 🎉.

Reduce motion keeps dropping the movement, never the moment: the stamp
appears as an instant state and holds the same 700ms; the burst bows
out entirely (frontend-plan).
The demo's card (job-card-demo.dc.html) always fills the points half:
'22 points' or 'No points', never a due phrase standing alone. The
build dropped the half when nothing was linked, which made a worthless
job's row read as if worth simply wasn't a thing here. Emptiness is
named by the value (the row grammar's own rule), and the meta row now
mirrors its existing 'No date' complement in the other direction.

A job with neither a date nor points still has no meta row at all —
two named absences on one line would be the card talking to itself,
and the demo never poses that state. Both surfaces; the render
fixtures carry the new inventory.
The demo's detail sheet (job-card-demo.dc.html buildDetail) follows a
linked worth with one quiet line — '<Owner> gets them the moment this
is ticked.', or 'Whoever takes it …' on an unowned job — so the
promise names its beneficiary instead of leaving the reader to infer
that worth follows ownership. Both surfaces; the sheet render fixture
carries the line.
The demo's offline grammar (job-card-demo.dc.html): an optimistic
write keeps its result and the CARD carries the news — a quiet
'◍ Saved on this device' pill above the meta row — while the board
strip states the whole app's condition. The build had the strip and
the sync sheet but nothing on the card itself, so a member reading one
job couldn't tell their change hadn't left the device yet.

The queue's is-this-yours test moves out of JobSheet into the queue
package (entryTargetsUid) — the sheet's refusal rows and the card's
chip must agree on what 'targets this record' means, and a second
inline copy is how they'd stop agreeing. Cards are never dimmed; the
chip names the state and everything stays live. Both surfaces.
job-card-demo.dc.html's board strip reads 'Showing the board as of
14:05 — you're offline.' — it names what the reader is looking at (a
board frozen at a local moment) rather than only the network's state.
The app-wide strip takes that sentence, with the shared minute clock
supplying the time; the sync strip beneath keeps the queue's story.
Both surfaces.
The Compose twin of the two web conformance commits, value for value
(job-card-demo.dc.html; AGENTS.md rule 1 — parity, not resemblance):

- the panel floor (--ec-panel-floor, 84.8px incl. padding) applies to
  EVERY panel state, text-scaled, not only the plain card — the demo
  sheet has one .job-panel min-height with no per-state exemption
- panel bodies and the waiting names line at the demo's 1.05em with its
  1.3 line height (bodyLarge, tightened), eyebrows at labelMedium
- waiting stack: -10px face overlap and the 0.65em stack→text gap the
  demo draws (the shipped 3dp start padding had the text overlapping
  the last face)
- progress caption drops a shade to ink-soft with the % in ink-muted
- meta row at the demo's 0.95em: the DUE half bold in full ink (late
  keeps amber), the points half quiet in ink-soft
- the quiet line and primary label sizes follow the same scale; the ⋯
  glyph drops to ink-soft
- JobStamp: the mark stamps EVERY completion — 96dp, 700ms on the
  springier (.2,1.4,.4,1) curve settling at 45% — the 🎉 branch retires
  to the reward claim, the celebrate tint comes off the job card, and
  the points celebration stays ConfettiOverlay, fired from the card as
  before
The demo's pickers title themselves with the question they answer —
'Who's doing this?', 'When's it due?' (job-card-demo.dc.html; Worth
already asked 'What's this worth?') — where the build reused the row's
bare label. The rows keep their Who/When labels; only the sheets ask.
Both surfaces; the picker render fixture carries the wording.
Every visual in the stack below moves pixels — the panel floor on all
four rungs, the borderless card with its transparent unowned rail, the
meta row's bold due half, the Fredoka primary, the ink-soft ⋯, the
caption shades, the 96px stamp — so the gallery and Roborazzi goldens
re-record here, on their own, where the diff is the pictures.

Also adds the queued card as a fixture case on both surfaces (its
image rides in this commit, per the new-case rule): the offline
queue's 'Saved on this device' pill, posed as client state.
The demo's stylesheet names three per-theme radius roles —
--ec-radius-card / --ec-radius-panel / --ec-radius-btn (meadow
22/12/14) — 'read it, never pin it' (job-card-demo.dc.html §9).
design/tokens.yaml carried only the card radius, so each surface
derived the smaller two with its own formula: web calc(radius - 10) /
calc(radius - 8), Android minOf(radius, 12) and a fixed 13dp. They
agree on meadow's panel and nowhere else — hearth's panel was 2px on
web and 12dp on Android, the same theme wearing different corners per
surface. Silent divergence is a defect (rule 1); shape is now a token
like colour is.

radius-panel and radius-btn join every theme in tokens.yaml: meadow
takes the demo's exact 12/14, every other theme scales by the same
ratios (panel = card·6/11, btn = card·7/11 — hearth 7/8, clear 3/4,
the 12-radius ports 7/8). cmd/tokengen emits them as
--radius-panel/--radius-btn and Themes.kt radiusPanelDp/radiusBtnDp,
and both surfaces' components read the role instead of deriving:
web .job-panel and the card action buttons, Compose jobPanel(),
AppButton and JobMoreButton. The generator requires all three per
theme, so a new theme cannot ship without its shapes.
Live validation caught the tick-confirm diverging from the locked demo
(job-card-demo.dc.html): the demo draws a TRUE dialog — question in
Fredoka with curly quotes, the consequence in the rule's own words
('This mints the next one straight away — Every Tuesday — and this one
can never be reopened.'), a survives-note behind a hairline, and two
right-aligned BUTTONS: outline 'Not yet', filled accent 'Tick it off'
(destructive fill on delete). The build had the two-answers-are-rows
sheet grammar with an X and the successor's DATE where the demo names
the RULE.

The rows ruling came from the form-fragment sweep's 'a dialog's two
answers are two rows'; the demo overrides it for the two law-3
confirms — a centred dialog is not a screen of rows, and its buttons
sit right-aligned on their own line. The X goes (a dialog is answered,
not dismissed; Escape still answers 'Not yet'), the note about
sub-jobs takes the demo's sentence ('The N under it come back unticked
on the next one.'), and the buttons wear the btn radius role. Both
surfaces; the sheet render fixture carries the wording.
The radius roles move hearth's panel and button corners on both
surfaces (they now agree), and the two law-3 confirms are dialogs with
right-aligned buttons — the pictures re-record here, on their own.
docs: park the new handoff bundles (android, shared foundations, tui)
Some checks failed
check / commits (push) Has been cancelled
check / go (push) Has been cancelled
check / report (push) Has been cancelled
check / web (push) Has been cancelled
tag / tag (push) Has been cancelled
android / build (push) Has been cancelled
android / report (push) Has been cancelled
check / commits (pull_request) Successful in 1m5s
check / go (pull_request) Successful in 5m1s
check / web (pull_request) Successful in 9m58s
check / report (pull_request) Successful in 4s
android / build (pull_request) Successful in 25m1s
android / report (pull_request) Successful in 4s
2a21c57143
Found in docs/ untracked mid-session - parked here unreviewed so they
ride no unrelated commit. Describe or move as you see fit.
nalum merged commit 2a21c57143 into main 2026-08-26 18:37:36 +00:00
nalum deleted branch docs/park-handoff-bundles 2026-08-26 18:37:37 +00:00

Test report

Suite Tests Result Skipped
Unit 1435 ✅ pass 1
Integration 131 ✅ pass —

Coverage: 27.0%

Updated by the check workflow · commit 2a21c57143

<!-- ci-test-report --> ## Test report | Suite | Tests | Result | Skipped | | --- | --: | --- | --: | | Unit | 1435 | ✅ pass | 1 | | Integration | 131 | ✅ pass | — | **Coverage:** 27.0% <sub>Updated by the check workflow · commit 2a21c571438fe50eea24b0e49d71db0d0f0395f5</sub>

Android test report

Suite Tests Result Skipped
Unit (debug) 188 ✅ pass 0

Coverage: 9.6% of lines

Updated by the android workflow · commit 2a21c57143

<!-- android-test-report --> ## Android test report | Suite | Tests | Result | Skipped | | --- | --: | --- | --: | | Unit (debug) | 188 | ✅ pass | 0 | **Coverage:** 9.6% of lines <sub>Updated by the android workflow · commit 2a21c571438fe50eea24b0e49d71db0d0f0395f5</sub>
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
eagraiclainne/app!269
No description provided.