Validation waits for webfonts before measuring; sticky wrappers keep fluid width

- The render walk and screenshots now await document.fonts.ready plus a
  bounded state-based poll until every declared face is terminal
  (loaded/error); pending families surface as a font_wait_warning event
  instead of skewing text metrics with fallback-font boxes
- position:sticky full-width wrappers share the static/relative
  fluid-fill branch (a sticky box fills its containing block like any
  in-flow box) instead of freezing at canonical px; fixed-width sticky
  rails still freeze

447 tests pass (12 new), typecheck clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Samraaj Bath
2026-07-04 06:21:07 -07:00
co-authored by Claude Fable 5
parent 5b60ded62d
commit fae44aab93
5 changed files with 215 additions and 7 deletions
+6 -2
View File
@@ -244,9 +244,13 @@ function isFluidFullBleed(node: IRNode, parentNode: IRNode | undefined, viewport
const pos = cs.position || "static";
if (pos === "absolute" || pos === "fixed") {
if (!(nearZero(cs.left) && nearZero(cs.right))) return false; // width is real unless both insets pin it
} else if (pos === "sticky") {
return false;
} else {
// static | relative | sticky. A sticky box generates a normal in-flow box: its WIDTH fills the
// containing block exactly as static/relative does (position:sticky only shifts the box's offset
// while scrolling, never its resolved width). So a sticky wrapper that spans the viewport at
// every captured width was authored fluid (width:100%/auto) and must NOT freeze to the canonical
// px — frozen at 1280, a `justify-content:center` sticky banner pushes its inner content off a
// 375 viewport. Treat sticky identically to the static/relative fluid-fill branch.
if (!(zeroOrAuto(cs.left) && zeroOrAuto(cs.right))) return false; // positioned breakout: width is real
const pdisp = parentNode?.computedByVp[vp]?.display || "";
if (/flex|grid/.test(pdisp)) return false; // flex/grid item: auto width ≠ fill