diff --git a/src/slidr/render/templates/base.css b/src/slidr/render/templates/base.css index 8f3aa02..6776338 100644 --- a/src/slidr/render/templates/base.css +++ b/src/slidr/render/templates/base.css @@ -429,6 +429,20 @@ section[data-transition]:not([data-transition="none"]).outgoing { max-height: none; overflow: visible; } + + /* WeasyPrint mis-sizes 1fr grid tracks when a full-width spanning + grid-heading (grid-column: 1 / -1) is present, collapsing the + sibling cards to near-zero width. Fall back to flexbox for these + grids in print only; grids without a grid-heading are untouched. */ + .grid:has(> .grid-heading) { + display: flex !important; + flex-wrap: wrap; + align-items: flex-start; + gap: var(--gap); + } + .grid:has(> .grid-heading) > .grid-heading { flex: 0 0 100%; } + .grid:has(> .grid-heading) > .card:not(.grid-heading) { flex: 1 1 0; min-width: 0; } + .grid:has(> .grid-heading) > .card.side-image { flex: 0 0 auto; } } @page { diff --git a/tests/test_html.py b/tests/test_html.py index ab8c328..ae2a8f2 100644 --- a/tests/test_html.py +++ b/tests/test_html.py @@ -1,9 +1,24 @@ """Tests for the HTML renderer's element rendering.""" -from slidr.render.html import _render_elem +from slidr.render.html import _render_elem, base_css from slidr.render.ir import Elem +def test_print_css_flexes_grids_with_a_grid_heading(): + """Print stylesheet falls back to flexbox for grids with a grid-heading. + + WeasyPrint mis-sizes `1fr` grid tracks when a full-width spanning + grid-heading (`grid-column: 1 / -1`) is present, collapsing the sibling + cards to near-zero width. The print CSS must convert those grids to + flexbox; grids without a grid-heading must stay on the grid path. + """ + css = base_css() + assert ".grid:has(> .grid-heading)" in css + assert ".grid:has(> .grid-heading) > .grid-heading" in css + # The grid-heading spans a full row in the flex fallback. + assert "flex: 0 0 100%" in css + + def test_speaker_linkedin_uses_brand_svg_not_placeholder(): """linkedin= renders the inlined brand mark, never a Lucide placeholder.