/** * Split streaming markdown into a stable prefix and a live tail. * * While an answer streams, only the tail can still change; everything before * the last completed block is final. Rendering the prefix through a memoised * component means each frame re-parses a paragraph, not the whole answer. * * The cut is only allowed at a blank line where both sides parse the same on * their own as they would together: never inside a fenced code block, never * between two items of the same list (a second `