painted is built from a small set of immutable render-layer value types. These are the inputs to every higher-level feature — composition, buffers, the TUI, widgets.
Style is an immutable bundle of attributes — colors plus bold/italic/underline/reverse/dim. Styles combine via merge(), where the overlay wins.
base = Style(fg='blue', bold=True)
merged = base.merge(Style(italic=True))
bold red green blue dim italic reverse cyan
Cell is the atom: one character plus one Style. Most code manipulates Blocks rather than individual cells.
Span is text plus Style, measured in display columns (wide-char aware). A Line is a tuple of spans that paints into a buffer or converts to a Block.
painted pushes complexity up the stack: these immutable values are safe to share and cache, so higher-level systems treat rendering as a pure transformation — state to blocks.
This page is itself a doc-IR node tree. The terminal you are reading it in and the docs site render the same tree through different projectors — so the docs cannot drift from the code.