A card grid that goes from four columns to two to one has always meant three breakpoints, chosen by guessing at device widths rather than at the content.
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
gap: 1rem;
}
The browser fits as many 16rem columns as there is room for and shares the remainder — so the breakpoints are wherever the content needs them, at any container width, including ones nobody tested. auto-fill is the sibling and differs only when there are fewer items than columns: auto-fit collapses the empty tracks and lets the items stretch, auto-fill keeps them.