fn split_across_lines(text: &str, spans: &[RawSpan]) -> Vec<LineToken>
Split each raw span across line boundaries and compute UTF-16 column offsets. Produces line-local tokens, still in byte-order.