Why does a gutter of 1fr break this grid layout?

The grid row-gutter is manually set to 2.4cm; I’d like to set it to something that just balanced the gaps, but 1fr breaks the layout entirely, for reasons I’m unclear on.

#set page(
  margin: 0.5cm,
  flipped: true
)
#set text(14pt)
#show heading.where(level: 3): underline
#let sidebar = {
  circle(radius: 55pt)[Logo Here]
  show heading.where(level: 1): set text(18pt)
  show heading.where(level: 2): set text(14pt)
  set align(bottom + center)
  rotate(270deg, reflow: true, {
    text(43pt)[Company Name Here]
  })
}
#let roles = {
  heading(level: 2)[Meeting Roles]
  lorem(50)
}
#let agenda = {
  heading(level: 2)[Meeting Agenda]
  lorem(180)
}

#set rect(width: 100%, stroke: none, inset: 0.2cm)

#grid(
  columns: (4.5cm, 1fr),
  column-gutter: 0.5cm,
  rect(
    height: 100%,
    sidebar
  ),
  {
    heading(level: 1)[26#super[th] March, 2026]
    block(
      height: 1fr,
      grid(
        fill: blue,
        columns: (1fr, 1fr),
        column-gutter: 0.5cm,
        row-gutter: 2.4cm, // Why does 1fr not work here?
        rect(
          roles
        ),
        grid.cell(rowspan: 4, {
          rect(
            height: 100%,
            agenda
          )
        }),
        rect(
          [This is the first announcement.

          #lorem(15)]
        ),
        rect(
          [This is the second announcement.]
        ),
        rect(
          [This is the third announcement.

          #lorem(25)
          ]
        )
      )
    )
  }
)

This is perhaps not quite as minimal an example as I could have come up with, but it’s fairly small. I could probably have made it smaller. Also visible online at Typst

While I don’t know the answer to the question, I can somewhat simplify your attempt at that specific layout.

Unsurprisingly, I believe this is bound to be a single-page layout:

#set page(flipped: true, margin: 0.5cm)
#set par(justify: true)
#set text(1.3em)

#let announcement(ann) = block(above: 1fr, ann)

#let n-day = {
  let day = datetime.today().day()
  let n-days = ("st", "nd", "rd").map(it => super(it))
  str(day) + if calc.rem(day, 10) - 1 not in (0, 1, 2) { return }
  else { n-days.at(calc.rem(day, 10) - 1) } + sym.space
}

#grid(
  rows: (3em, 1fr),
  columns: (2fr, 4fr, 4fr),
  column-gutter: 0.5cm,
  // stroke: black,
  inset: 1em,
  grid.cell(rowspan: 2)[ // Left
    #set align(center)
    #circle(width: 100%)
    #set align(bottom)
    #rotate(
      reflow: true,
      270deg,
      text(2em, lorem(5))
    )
  ],
  grid.cell(
    colspan: 2,
    text(2em, n-day + datetime.today().display("[month repr:long], [year]")),
  ),
  [ // Middle
    = Meeting Roles
    #lorem(10)
    #announcement(lorem(15))
    #announcement(lorem(30))
    #announcement(lorem(20))
    #announcement(lorem(40))
  ],
  [ // Right
    = Meeting Agenda
    #lorem(100)
  ],
)
Output


The question reminds me of these posts: