 	}
 	
 	private func htmlFor(markdownChunk: RmdDocumentChunk, index: Int) -> String {
-		let html = mdownParser.htmlFor(markdown: parsedDocument!.string(for: markdownChunk))
+		var chunkString = parsedDocument!.string(for: markdownChunk)
+		// replace all inline chunks with a placeholder
+		for (idx, ichunk) in markdownChunk.children.reversed().enumerated() {
+			guard let range = Range<String.Index>(ichunk.chunkRange, in: chunkString) else { fatalError("invalid range") }
+			chunkString = chunkString.replacingCharacters(in: range, with: "!IC-\(idx)!")
+		}
+		// convert markdown to html
+		let html = mdownParser.htmlFor(markdown: chunkString)
+		// restore inline chunks. reverse so don't invalidate later ranges
+		for idx in (0..<markdownChunk.children.count).reversed() {
+			let replacement = textFor(inlineChunk: markdownChunk.children[idx], parent: markdownChunk)
+			html.replaceOccurrences(of: "!IC-\(idx)!", with: replacement, options: [], range: NSRange(location: 0, length: html.length))
+		}
 		// modify source position to include chunk number
 		_ = dataSourceRegex.replaceMatches(in: html, range: NSRange(location: 0, length: html.length), withTemplate: "data-sourcepos=\"\(index).$2")
 		return html as String

	private var emptyNavigations: Set<WKNavigation> = []
	
	private var documentRoot: URL?
	private var headerContents = ""
	private var footerContents = ""
	private var docHtmlLoaded = false

		}
		var html =  ""
		for (chunkNumber, chunk) in curDoc.chunks.enumerated() {
			let descriptor = chunk.isInline ? "inline" : "section"
			html += "<\(descriptor) index=\"\(chunkNumber)\">\n"
			html += htmlFor(chunk: chunk, index: chunkNumber)
			html += "\n</\(descriptor)>\n"
		}
		docHtmlLoaded = true
		load(html: "\(headerContents)\n\(html)\n\(footerContents)")
		outputView?.evaluateJavaScript("MathJax.typeset()", completionHandler: nil)
	}
	
	private func htmlFor(chunk: RmdDocumentChunk, index: Int) -> String {
