Symptom

In CronExpressionEditor, when an option with an expanded field is selected (e.g. “Every N seconds” → Seconds input), the gap between the expanded field’s bottom edge and the next radio option appeared visually tighter (~8dp) than the gap between consecutive unselected radio options (~16dp).

Root cause

The outer Column used Arrangement.spacedBy(SPACING_MEDIUM) (12dp), which inserts a uniform gap between all direct children. When an expanded field block appeared as a sibling of two consecutive radio Rows, the spacedBy gap was applied identically on both sides of the field. However, a RadioButton’s implicit touch-target padding adds visual breathing room between consecutive radio Rows, making the inter-option gap appear larger than 12dp. The expanded field (an OutlinedTextField) has no such internal padding, so the field-bottom-to-next-radio gap looked comparatively tight, breaking the 4/8dp grid rhythm.

Fix

Wrapped each radio option Row and its conditionally-rendered expanded content block in an inner Column. The outer Column’s spacedBy(SPACING_MEDIUM) now applies only between complete option groups (radio row + optional field), so the gap from the expanded field to the next option group is the same 12dp as the gap between unselected consecutive options. A Spacer(SPACING_SMALL) is added inside each inner Column between the radio Row and its expanded field to maintain visual breathing room within the group.

File changed: composeApp/src/commonMain/kotlin/krill/zone/app/krillapp/executor/cron/CronExpressionEditor.kt

Prevention

When building vertically scrollable option lists with Arrangement.spacedBy, group logically related sub-items (e.g. a radio button and its reveal) into a single inner Column before placing them in the outer spaced container. This ensures the outer spacing token applies at the option-group level, not at the individual-widget level, regardless of whether the group has conditional children.