1. Mental Model

A Lini file is the body of an implicit root container: a stylesheet of setup first, then the drawn canvas instances and links in source order — and every statement is exactly one of the three:

PartHoldsDrawn?
stylesheetone { } block: scene config (incl. link & routing defaults), rules, classes, definesno — it styles
canvasinstances — boxes (|type#id|) and text ("…")yes
linksa -> b connectionsyes

One character tells a statement’s kind — a leading | opens identity (a node — or, when a link operator follows the closed capsule, a capsule-headed link, SPEC 9), a " text, a bare name a link, and inside the stylesheet a ./#/|…| opens a rule. The capsule is self-delimiting, so one token after it still decides; no prescan, no ambiguity.

Two brackets, one capsule, three sigils — one meaning each (the table in At a glance, SPEC 2): |…| is identity, the only place a type lives; { … } is style, the only place declarations live; [ … ] is content, in source order. A drawn node is |type#id| "label" .class { style } [ children ], only the bars required; a link is the same tail on a different head: a -> b "label" .class { style } [ labels ]. A name goes bare only when referenced, and the one thing you reference is an id; types and classes are never linked, so they are always sigil-marked.

Boxes and text, like HTML. A box has identity, classes, a style block, and children. A string is text content — a leaf with no identity or children, though it may wear classes and carry a style block ("x" .quiet { color: red }, SPEC 3). A string in a box’s [ ] (or trailing the head as its label) is that box’s text; on its own it is a free-standing text node. To give text children, a border, padding, a pin, or a wirable id, wrap it in a box (|block| is the minimal one) — exactly like wrapping a web page’s text in an element.

The file is the root container. The stylesheet { } is the root’s own setup block; the canvas instances are its children (written bare — the file is its [ ]); the links are its internal links. Scene properties (layout, gap, padding, fill, font-size, clearance, routing, …) sit in that block, alongside rules like |-| { stroke: … } for link look; inheritable ones (font-*, color, clearance, routing) cascade to every node and link.

Render order is source order; the cascade is whole-file. Instances draw in the order written (later on top, pinned children above the flow; layer: overrides), and every rule applies to every instance. Links need no declaration: naming an id declared nowhere auto-creates it (SPEC 3).

Two kinds of variable. Visual values that don’t affect layout — colours and the font family — stay live CSS variables (--lini-fill, --lini-accent, …), so a host page can re-theme them; each colour carries a built-in dark variant following the viewer’s OS or a data-theme toggle (SPEC 10). Layout values — sizes, gaps, paddings, widths, and font size — bake into the SVG as literals: text is measured at compile time, so its size can never be a runtime var(), and a standalone SVG always looks right.