Split text into overlapping chunks for RAG ingestion — by characters (default) or by exact LLM tokens. Returns the chunks plus offsets. Deterministic, no model needed.