.form {
    display: flex;
    flex-direction: column;
    row-gap: 20px;
    max-width: 420px;
}

/* Wider variant for forms with side-by-side input rows (see .input-row) or
   otherwise denser content than the default 420px column fits. */
.form--wide {
    max-width: 100%;
    width: 100%;
}

.input-row {
    display: flex;
    width: 100%;
    justify-content: space-around;
    flex-wrap: wrap;
    row-gap: 16px;
}

.input-row > .input-wrapper {
    flex: 0 1 460px;
    min-width: 0;
}

.form__hint {
    font-size: 13px;
    color: var(--md-on-surface-variant);
    background: var(--md-surface-container);
    border-radius: 6px;
    padding: 8px 12px;
}

/* ── two things in one submission ─────────────────────────────── */

/* Some forms in this console collect two different objects at once,
   because the domain will not accept them apart: a workflow with its
   first node (NewWorkflow rejects a zero-node graph), a node with the
   flow edge that makes it reachable. A fieldset apiece is the honest
   shape — the legend names each object, the note under it gives the
   reason, so the bundling reads as a rule rather than as a quirk of one
   screen.

   Deliberately not boxed: these sit inside a bordered .workflow-panel in
   a narrow column, and a third nested outline reads as clutter rather
   than as structure. A rule between the groups plus a heading-weight
   legend is the same signal for none of the noise. */
.field-group {
    display: block;
    /* index.css zeroes margin/padding but not border; a fieldset's UA
       groove would otherwise draw the box this deliberately avoids. */
    border: 0;
    /* Fieldsets default to min-content and refuse to shrink: without
       this a textarea inside one overflows the side column. */
    min-inline-size: 0;
    min-width: 0;
}

.field-group + .field-group {
    padding-top: 16px;
    border-top: 1px solid var(--md-outline-variant);
}

.field-group > * + * {
    margin-top: 12px;
}

/* A legend is laid out specially by the UA. With no fieldset border
   there is no notch for it to sit in, and these three declarations keep
   every engine rendering it as the ordinary block heading it is here.
   Heavier and darker than .input-wrapper__label so the level hierarchy —
   section, then field — is unambiguous. */
.field-group__legend {
    display: block;
    float: none;
    width: 100%;
    font-size: 13px;
    font-weight: 650;
    color: var(--md-on-surface);
}

.field-group__note {
    font-size: 12px;
    line-height: 1.5;
    color: var(--md-on-surface-variant);
}

/* What the earlier step settled, carried into the current one so the
   operator never navigates back merely to check. Two labelled rows
   rather than one comma-joined sentence: keeping the two objects apart
   is the whole point of the fieldsets, and a flat recap would undo it
   on the next screen. */
.form__recap {
    display: flex;
    flex-direction: column;
    row-gap: 6px;
    margin-bottom: 12px;
    padding: 10px 12px;
    background: var(--md-surface-container);
    border-radius: var(--md-shape-sm);
}

.form__recap > div {
    display: flex;
    align-items: baseline;
    column-gap: 10px;
}

.form__recap dt {
    flex: 0 0 68px;
    font-size: 11.5px;
    color: var(--md-on-surface-variant);
}

.form__recap dd {
    min-width: 0;
    font-family: var(--md-font-mono);
    font-size: 12.5px;
    overflow-wrap: anywhere;
}

/* Available to a screen reader, absent from the page. */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ── the action picker ────────────────────────────────────────── */

/* Chromium's customizable select (appearance: base-select): the popup
   itself becomes styleable, so the picker wears the console's surfaces,
   every option carries an info mark drawn by ::after, and the option's
   title attribute shows the explanation as the native tooltip on hover —
   inside the open list, where the choosing happens. No script involved.
   A browser without base-select keeps the OS popup and the title
   tooltips: same wire, plainer clothes. */
.action-select,
.action-select::picker(select) {
    appearance: base-select;
}

.action-select::picker(select) {
    background: var(--md-surface-container);
    border: 1px solid var(--md-outline-variant);
    border-radius: 8px;
    padding: 6px;
    box-shadow: 0 8px 28px rgba(0, 0, 0, 0.3);
}

/* The group headings inherit down, so the options reset what the
   heading sets. */
.action-select optgroup {
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--md-on-surface-variant);
    padding: 6px 6px 2px;
}

.action-select option {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 7px 10px;
    border-radius: 6px;
    font-size: 13px;
    font-weight: 400;
    letter-spacing: normal;
    text-transform: none;
    color: var(--md-on-surface);
}

.action-select option:hover,
.action-select option:focus {
    background: color-mix(in srgb, var(--md-primary) 12%, transparent);
}

.action-select option:checked {
    color: var(--md-primary);
    font-weight: 600;
}

/* The info mark on every option: pure CSS — a bordered circle around a
   plain letter i. No glyph (font fallback squashed the circled-i) and no
   image (the console's CSP refuses data: images, and a blocked mask
   renders the element invisible — the lesson of the previous attempt). */
.action-select option::after {
    content: "i";
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 13px;
    height: 13px;
    margin-left: auto;
    border: 1.5px solid var(--md-on-surface-variant);
    border-radius: 50%;
    font-size: 9px;
    font-weight: 700;
    font-style: normal;
    line-height: 1;
    color: var(--md-on-surface-variant);
}

.action-select option:hover::after {
    color: var(--md-primary);
    border-color: var(--md-primary);
}

/* A form that belongs inside running text rather than beneath it — see
   .button--link. Forms are block-level by default, which would break the
   sentence this one lives in. */
.form--inline {
    display: inline;
}
