Layout.
Page-agnostic structural patterns: container, full-bleed-to-edge, alternating copy↔media rows, and the mobile blow-out fix. Recipes, not components.
- Content max — 1240px (--content-max)
- Gutters — sm 24px · md 40px · lg 80px
Center content at the max-width; ramp the inline padding across breakpoints.
max-width: var(--content-max); margin-inline: auto; padding-inline: clamp(var(--gutter-sm), 5vw, var(--gutter-md)); The default wrapper for any centered section.
The section background spans the viewport while its content stays aligned to the centered container — content padded on one side, bled to the viewport edge on the other.
Content-side padding: max(var(--gutter-md), calc((100vw - var(--content-max)) / 2 + var(--gutter-lg))); bleed side: var(--gutter-lg). Mirror the two to bleed the other way. Used for media that should kiss the viewport edge while copy stays on the grid.
Full-width 2-col grid; media bleeds to its edge, copy insets to the content margin; the side alternates row to row.
Full-width grid; alternate sides via `:nth-child(odd)` + `order`. The media's edge inset equals the column gap, for balance. The workhorse for product-page feature sections.
Single-column mobile grids must use `grid-template-columns: minmax(0, 1fr)`.
grid-template-columns: minmax(0, 1fr); Otherwise a fixed-width child (a 1180px product shot, a min-width table) sizes the column to its own content and overflows the page. Same fix: horizontal-scroll tables need the scroll wrapper on a NATIVE element (see the scoped-style gotcha).
Any single-column grid that can contain a fixed-width or min-width child gets `minmax(0, 1fr)` columns. This is the single most common marketing-page layout bug.
The highest-value layout gotcha is Astro scoped styles not reaching a child component's root element — put structural classes (grid / order / overflow / gap) on a NATIVE element. See the `astro-scoped-styles` pattern. → astro-scoped-styles