Is there a nice way of achieving the following, without any additional mark-up? It would be fine to use JavaScript though.
        
For a given element of text, use a text range to find the end of the first line, then wrap the remaining text in a child div. Repeat recursively, using the child div for the next iteration.
This works cross-browser: http://jsfiddle.net/gilly3/CmguZ/4/
It's easiest in IE thanks to textRange.moveToPoint(x, y):
function indent(div) {
    var rng = document.body.createTextRange();
    rng.moveToElementText(div);
    var x = rng.getBoundingClientRect().right;
    rng.collapse();
    var rect = rng.getBoundingClientRect();
    var y = rect.bottom;
    rng.moveToPoint(x - 1, y - 1);
    rng.moveEnd("textedit");
    var html = "" + rng.text + "";
    rng.pasteHTML(html);
    div = $(".indent", div)[0];
    rng.moveToElementText(div);
    var pos = rng.getBoundingClientRect();
    if (pos.bottom > rect.bottom) {
        indent(div);
    }
}
With other browsers, you have to iterate the text to find where the line wraps:
function indent(div) {
    var rng = document.createRange();
    rng.selectNodeContents(div);
    var len = rng.toString().length;
    var start = rng.toString().search(/.\s/);
    if (start < 0) return;
    var txt = div.childNodes[0];
    rng.setEnd(txt, start);
    var startRect = rng.getBoundingClientRect();
    var rect;
    for (var i = start + 1; i < len; i++) {
        rng.setEnd(txt, i);
        rect = rng.getBoundingClientRect();
        if (rect.bottom > startRect.bottom) {
            rng.setStart(txt, i-1);
            rng.setEnd(txt, len);
            div = document.createElement("div");
            div.className = "indent";
            rng.surroundContents(div);
            indent(div);
            break;
        }
    }
}