# Logical layout `internal/layout.Layout(root, Options{Width, Height, TextEngine})` accepts a transient tree of `Node{ID, Kind, Style, Children, Content, ImageSize, Measure, ScrollX, ScrollY}`. Styles are borrowed immutable `*css.Style` values from `css.Engine.Compute` (normally compiled with `css.UA()`). A nil style receives minimal block defaults; use computed CSS for complete visual defaults. IDs are supplied by the frame-tree adapter and should be unique. Input must be acyclic, with depth at most 256; no renderer resources or parent pointers are retained. The caller owns the decoded images: use `internal/image.Decode` for bounded PNG/JPEG bytes or `internal/image.Size` for existing Go images, then put the intrinsic size on the node. Byte input must itself be bounded by the reader before decoding. `Kind` differentiates image/text intrinsic measurement, Stack overlay, and Scroll clipping. Flex is selected by the computed `display:flex`, with row/column UA defaults overridable by author CSS. Block children flow vertically; Stack children share the origin, paint in input order, and hit-test in reverse order. Flex supports row/column, wrap, grow/shrink/basis, row/column gaps, align-self/items and justify-content. CSS `px` is logical; computed `em`/`rem` have already become `px`; `%` dimensions use the containing content box and padding/margins use containing width. Auto width fills the containing width except images; auto height fits the children. Oversized/negative/nonfinite geometry is clamped to bounded logical coordinates. CSS `display:none` drops a subtree. Overflow hidden/auto/scroll emits a content clip per axis, leaving visible axes unbounded; only scroll/auto (or Scroll kind) consumes offsets, clamped to the measured content extent. The caller supplies offset; there is no scroll event policy here. `Output.Tree` is JSON-safe geometry and measured content extent. `Output.Display` contains ordered JSON-safe commands (`shadow`, `rect`, `border`, `outline`, `clip-push`, `text`, `image`, `clip-pop`). Glyph rune-cluster offsets and shaped glyph positions are copied to text commands. Each display-list `Run` also borrows its shaped `*text.Face` for in-process rasterization and carries serializable `FaceID` and `Size` (the logical font size used for shaping). `Face` is omitted from JSON; decoding JSON alone cannot reconstruct a face, so a renderer consuming serialized commands must resolve `FaceID` to a matching font before rasterizing. The original `text.Line` values remain on tree nodes for in-process use and are omitted from JSON. Image commands reference node IDs; the renderer adapter resolves their pixels. `Hit` applies ancestor clips and reverse child order. Pointer capture, focus and tab ordering are separate runtime responsibilities. `Physical` independently rounds logical rectangle edges using a fractional Wayland scale at the renderer boundary; do not use physical coordinates for hit tests. JSON snapshots under `internal/layout/testdata` validate tree and list structure, not rendered pixels. Known bounds: layout does not implement CSS margin collapse, absolute positioning, baseline alignment, `align-content`, or CSS transforms. Shadow and border commands carry geometry/style data for the renderer; decoration rasterization is not owned here. Text requires a provided `text.Engine` or a synchronous measure callback. Computed line-height repositions shaped baselines, text-align offsets runs within each content line, and letter-spacing is applied to shaped clusters before the text engine wraps (via the additive `text.Request.LetterSpacing` option). A synchronous callback's result must be immutable for the duration of layout; do not share a mutable shaping engine across goroutines.