UTS Phase 22.3 — Flutter post-body blocks (adopt the 22.2 atoms into the 4 content blocks)
The adoption layer. 22.1 laid the tokens; 22.2 built + restyled the shared atoms; 22.3 wires them into the four post-body guide content blocks so the post body reaches web parity. Element-complete: every edit below is pinned to a
file:linein TWO grounded sources — nothing is "verify at build", nothing is guessed. (This is the bar that let 22.2's rebuild go one-pass; the 22.2 spike needed a redo precisely because its doc wasn't yet here.) - Look/values + target markup ←static/css/kon_guide_v2.css+ the kontent templates (_block_*,_mat_thumb,block-interaction-compiler.js). The web is the reference. - What's there + the app idiom ← the existing Flutter blocks (lib/content_blocks/widgets/…) + the 22.2 atoms. Where source and any summary differ, the source wins. Brand viacolorScheme.primary; values viag-*tokens.
Program: Under the Tuscan Sun → Phase 22 → builds on 22.1 tokens + 22.2 shared components. Owner: Flutter (with Travis). Tooling: Android Studio (device + hot-reload + on-device smoke).
Goal
Make the four post-body guide blocks render at web parity by adopting the 22.2 atoms, moving qty to the trailing edge, and repointing the last rainbow colors to neutral: 1. StepCollectionBlock — TimelineCircle → StepDisc (brand ordinal disc, no halo; done→✓ / wrong→✗). 2. StepBlock — gain a StepDisc type glyph (3-bar instruction / ? question) it currently lacks; .g-step row. 3. MaterialRow — restructure to .g-mat ([thumb][body flex:1][qty-trailing]): qty blue→ink and moved to the trailing edge; inline image thumb → type-aware MaterialThumb; row separator (border-bottom, not striping). 4. MaterialCollectionBlock — static blue group headers → collapsible GuideSection ("Materials" fallback). Plus: verify §5C chrome (.g-sectiontitle / .g-md-v / .g-empty / .g-progress) and retire TimelineCircle.
Scope
In: the 4 blocks + MaterialRow adopt the 22.2 atoms; the qty move; the row separator; the group expander; repoint material-qty + group colors to neutral; retire the TimelineCircle widget; add the new g-* metric tokens. Out: - The lightbox (shell/cook/learn/review/picker) — separate surface → 22.4 / 22.5 (still uses old rainbow). - The nonsequential learn-flow behavior → 22.5 (D22.1). - Deleting the old DesignTokens.guide* consts → 22.6 (still read by the lightbox). 22.3 stops using the post-body ones; 22.6 removes them.
Patterns this phase follows (compose, don't reinvent) — grounded
| Need | The atom/idiom to use (cited) | The web rule it satisfies |
|---|---|---|
| Step disc (ordinal / type glyph / done / wrong) | StepDisc (step_disc.dart:32-37) |
.g-step-num (kon_guide_v2.css:91-93; _block_step.gohtml:9,29; _block_step_collection.gohtml:39) |
| Per-material type-aware thumb + count | MaterialThumb (material_thumb.dart:22-27) |
_mat_thumb.gohtml + .g-mat-gal |
| Collapsible material group (open-default, −/+) | GuideSection (guide_section.dart:14) |
<details class="g-acc" open> (_block_material_collection.gohtml:23) |
| Neutral qty / labels | gInk, gFaint, gMuted |
.g-mat-qty neutral ink (kon_guide_v2.css:86) |
| Block chrome | block_wrapper.dart:5-48 + content_block_renderer.dart:49-102 |
.g-sectiontitle/.g-md-v (:48,289) |
Element-level resolution (pinned — this is literally what the builder builds)
22.3-A — StepCollectionBlock: TimelineCircle → StepDisc (2 sites)
Sites: read-only step_collection_block.dart:209, interactive :395 — both sit in Padding(bottom:16, child: Row(crossAxisAlignment: start)[ <circle>, SizedBox(width:12), Expanded(<body>) ]). Replace TimelineCircle(number: n, circleState: cs) → StepDisc(content: StepDiscContent.number, number: n, state: <map(cs)>). Keep the Row/SizedBox(12)/Expanded. State map (port the existing derivation verbatim): - read-only (:200-202): cs = stepType=='instruction' ? instruction : question → both → StepDiscState.normal (a collection shows the ordinal; the type no longer colors the disc — de-rainbow). - interactive (:382-388): cs = hasInteraction ? (isIncorrect ? answeredIncorrect : completed) : <type>, where isIncorrect = isSubmitted && correctOptionId != null && selectedOptionId != correctOptionId (:378-380). → completed → StepDiscState.done (✓); answeredIncorrect → StepDiscState.wrong (✗); else normal. Web confirms (block-interaction-compiler.js): completed or answered-correct → ✓ ✓ (--completed/--answered, g-ok); answered-incorrect → ✗ ✗ (--answered-incorrect, g-bad); pending → ordinal. StepDisc already renders done→gOk+✓ / wrong→gBad+✗ (step_disc.dart:41-57) — exact match. No halo; 24dp→30dp.