From 249e8d2d61f3650d934582b65200ca8fa0b47495 Mon Sep 17 00:00:00 2001
From: Ralph Amissah <ralph@amissah.com>
Date: Thu, 29 Dec 2016 20:36:41 -0500
Subject: dom structure, levels marked up & collapsed (use e.g. in epub toc)

---
 org/ao_abstract_doc_source.org   | 539 +++++++++++++++++++++++++++++++++++----
 org/ao_defaults.org              |   2 +-
 org/ao_output_debugs.org         | 103 +++++++-
 org/output.org                   |  96 +++++--
 org/sdp.org                      |  52 ++--
 src/sdp.d                        |  49 ++--
 src/sdp/ao_abstract_doc_source.d | 534 +++++++++++++++++++++++++++++++++-----
 src/sdp/ao_object_setter.d       |   5 +
 src/sdp/ao_output_debugs.d       |  93 ++++++-
 src/sdp/ao_rgx.d                 |   2 +-
 src/sdp/output_html.d            | 134 +++++++---
 views/version.txt                |   2 +-
 12 files changed, 1377 insertions(+), 234 deletions(-)

diff --git a/org/ao_abstract_doc_source.org b/org/ao_abstract_doc_source.org
index c4733cc..49f3016 100644
--- a/org/ao_abstract_doc_source.org
+++ b/org/ao_abstract_doc_source.org
@@ -174,6 +174,7 @@ mixin InternalMarkup;
 auto rgx = Rgx();
 ObjGenericComposite[][string] the_table_of_contents_section;
 ObjGenericComposite[] the_document_head_section, the_document_body_section, the_bibliography_section, the_glossary_section, the_blurb_section;
+ObjGenericComposite[] the_dom_tail_section;
 string[string] an_object, processing;
 string an_object_key;
 string[] anchor_tags;
@@ -204,10 +205,10 @@ int bib_entry;
 /+ counters +/
 int cntr, previous_count, previous_length;
 int[string] line_occur;
-int verse_line, heading_ptr;
-string[] html_segnames=[];
+string[] html_segnames=["toc"];
 int html_segnames_ptr=0;
 int html_segnames_ptr_cntr=0;
+int verse_line, heading_ptr;
 /+ paragraph attributes +/
 int[string] indent;
 bool bullet = true;
@@ -217,6 +218,89 @@ auto obj_att = ObjAttributes();
 /+ ocn +/
 int obj_cite_number, obj_cite_number_;
 auto object_citation_number = OCNemitter();
+int[] dom_markedup = [ 0, 0, 0, 0, 0, 0, 0, 0, 0,];
+int[] dom_markedup_buffer = [ 0, 0, 0, 0, 0, 0, 0, 0, 0,];
+int[] dom_collapsed = [ 0, 0, 0, 0, 0, 0, 0, 0, 0,];
+int[] dom_collapsed_buffer = [ 0, 0, 0, 0, 0, 0, 0, 0, 0,];
+enum DomTags { none, open, close, close_and_open, open_still, }
+auto dom_set_markup_tags(int[] dom, int lev) {
+  foreach (i; 0 .. 8) {
+    if (i < lev) {
+      if (dom[i] == DomTags.open
+         || dom[i] == DomTags.close_and_open
+      ) {
+        dom[i] = DomTags.open_still;
+      } else if (dom[i] == DomTags.close) {
+        dom[i] = DomTags.none;
+      }
+    } else if (i == lev) {
+      if (lev  == 0
+        && dom[i] == DomTags.open_still
+      ) {
+        dom[i] = DomTags.close;
+      } else if (dom[i] == DomTags.open
+        || dom[i] == DomTags.open_still
+        || dom[i] == DomTags.close_and_open
+      ) {
+        dom[i] = DomTags.close_and_open;
+      } else {
+        dom[i] = DomTags.open;
+      }
+    } else if (i > lev) {
+      if (dom[i] == DomTags.close) {
+        dom[i] = DomTags.none;
+      } else if (dom[i] == DomTags.open
+        || dom[i] == DomTags.open_still
+        || dom[i] == DomTags.close_and_open
+      ) {
+        dom[i] = DomTags.close;
+      }
+    }
+  }
+  debug(dom) {
+    writeln(lev, ": ", dom);
+  }
+  return dom;
+}
+auto dom_set_collapsed_tags(int[] dom, int lev) {
+  foreach (i; 0 .. 8) {
+    if (i < lev) {
+      if (dom[i] == DomTags.open
+         || dom[i] == DomTags.close_and_open
+      ) {
+        dom[i] = DomTags.open_still;
+      } else if (dom[i] == DomTags.close) {
+        dom[i] = DomTags.none;
+      }
+    } else if (i == lev) {
+      if (lev  == 0
+        && dom[i] == DomTags.open_still
+      ) {
+        dom[i] = DomTags.close;
+      } else if (dom[i] == DomTags.open
+        || dom[i] == DomTags.open_still
+        || dom[i] == DomTags.close_and_open
+      ) {
+        dom[i] = DomTags.close_and_open;
+      } else {
+        dom[i] = DomTags.open;
+      }
+    } else if (i > lev) {
+      if (dom[i] == DomTags.close) {
+        dom[i] = DomTags.none;
+      } else if (dom[i] == DomTags.open
+        || dom[i] == DomTags.open_still
+        || dom[i] == DomTags.close_and_open
+      ) {
+        dom[i] = DomTags.close;
+      }
+    }
+  }
+  debug(dom) {
+    writeln(lev, ": ", dom);
+  }
+  return dom;
+}
 int ocn_emit(int ocn_status_flag) {
   return object_citation_number.ocn_emitter(ocn_status_flag);
 }
@@ -319,7 +403,7 @@ string toc_txt_;
 an_object["glossary_nugget"] = "";
 an_object["blurb_nugget"] = "";
 comp_obj_heading_                       = comp_obj_heading_.init;
-comp_obj_heading_.use                   = "body";
+comp_obj_heading_.use                   = "frontmatter";
 comp_obj_heading_.is_of                 = "para";
 comp_obj_heading_.is_a                  = "heading";
 comp_obj_heading_.text                  = "Table of Contents";
@@ -328,17 +412,20 @@ comp_obj_heading_.obj_cite_number       = "";
 comp_obj_heading_.segment_anchor_tag    = "toc";
 comp_obj_heading_.marked_up_level       = "1";
 comp_obj_heading_.heading_lev_markup    = 4;
-comp_obj_heading_.heading_lev_collapsed = 2;
+comp_obj_heading_.heading_lev_collapsed = 1;
 comp_obj_heading_.parent_ocn            = 1;
 comp_obj_heading_.parent_lev_markup     = 0;
+comp_obj_heading_.ptr_html_segnames     = html_segnames_ptr;
 comp_obj_heading_.anchor_tags           = ["toc"];
-auto toc_head                       = comp_obj_heading_;
+auto toc_head                           = comp_obj_heading_;
+html_segnames_ptr_cntr++;
 the_table_of_contents_section = [
   "seg": [toc_head],
   "scroll": [toc_head],
 ];
 auto mkup = InlineMarkup();
 auto munge = ObjInlineMarkupMunge();
+string[][string] lev4_subtoc;
 #+END_SRC
 
 ** _2. loop: process document body_ [+6]                                 :loop:
@@ -393,9 +480,8 @@ continue;
 #+END_SRC
 
 **** non code objects (other blocks or regular text) [+4]          :non_code:
-
 ***** in section (biblio, glossary, blurb) (block group) [+1]  :block:active:
-****** DONE within block group: biblio                               :biblio:
+****** within section: biblio                                        :biblio:
 
 #+name: abs_in_loop_body_non_code_obj
 #+BEGIN_SRC d
@@ -418,7 +504,7 @@ if ((matchFirst(line, rgx.heading_biblio)
   continue;
 #+END_SRC
 
-****** within section: glossary                               :glossary:
+****** within section: glossary                                    :glossary:
 
 if there is a glossary section you need to:
 - extract it
@@ -480,7 +566,7 @@ if there is a glossary section you need to:
       comp_obj_heading_.parent_ocn            = 1;
       comp_obj_heading_.parent_lev_markup     = 0;
       comp_obj_heading_.anchor_tags           = ["glossary"];
-      the_glossary_section                ~= comp_obj_heading_;
+      the_glossary_section                    ~= comp_obj_heading_;
     // } else if (matchFirst(line, rgx.heading)) {
     //   _heading_matched_(line, line_occur, an_object, an_object_key, lv, collapsed_lev, type, dochead_meta_aa); // levels?
     } else {
@@ -502,7 +588,7 @@ if there is a glossary section you need to:
   continue;
 #+END_SRC
 
-****** within section: blurb                                     :blurb:
+****** within section: blurb                                          :blurb:
 
 if there is a blurb section you need to:
 - extract it
@@ -588,8 +674,8 @@ if there is a blurb section you need to:
       comp_obj_para.is_of                 = "para";
       comp_obj_para.is_a                  = "blurb";
       comp_obj_para.text                  = to!string(line).strip;
-      comp_obj_para.ocn                   = obj_cite_number;
-      comp_obj_para.obj_cite_number       = (obj_cite_number==0) ? "" : to!string(obj_cite_number);
+      comp_obj_para.ocn                   = 0;
+      comp_obj_para.obj_cite_number       = "";
       comp_obj_para.indent_hang           = indent["hang_position"];
       comp_obj_para.indent_base           = indent["base_position"];
       comp_obj_para.bullet                = bullet;
@@ -600,8 +686,8 @@ if there is a blurb section you need to:
   continue;
 #+END_SRC
 
-***** in block group [+1]                                      :block:active:
-****** within block group: poem                                        :poem:
+***** in blocks [+1]                                           :block:active:
+****** within block: poem                                              :poem:
 
 #+name: abs_in_loop_body_non_code_obj
 #+BEGIN_SRC d
@@ -611,7 +697,7 @@ if there is a blurb section you need to:
   continue;
 #+END_SRC
 
-****** within block group: group                                      :group:
+****** within block: group                                            :group:
 
 #+name: abs_in_loop_body_non_code_obj
 #+BEGIN_SRC d
@@ -622,7 +708,7 @@ if there is a blurb section you need to:
   continue;
 #+END_SRC
 
-****** within block group: block                                      :block:
+****** within block: block                                            :block:
 
 #+name: abs_in_loop_body_non_code_obj
 #+BEGIN_SRC d
@@ -632,7 +718,7 @@ if there is a blurb section you need to:
   continue;
 #+END_SRC
 
-****** within block group: quote                                      :quote:
+****** within block: quote                                            :quote:
 
 #+name: abs_in_loop_body_non_code_obj
 #+BEGIN_SRC d
@@ -642,7 +728,7 @@ if there is a blurb section you need to:
   continue;
 #+END_SRC
 
-****** within block group: table                                      :table:
+****** within block: table                                            :table:
 
 #+name: abs_in_loop_body_non_code_obj
 #+BEGIN_SRC d
@@ -653,7 +739,6 @@ if there is a blurb section you need to:
 #+END_SRC
 
 ***** not identified as being within block group (could still be, or not) [+3]
-
 ****** assert
 
 #+name: abs_in_loop_body_open_block_obj_assert
@@ -879,6 +964,7 @@ if ((type["heading"] == State.on)
     dochead_make_aa,
     segment_anchor_tag_that_object_belongs_to,
     _anchor_tag,
+    lev4_subtoc,
     the_table_of_contents_section,
   );
   if (an_object["lev_markup_number"] == "4") {
@@ -1025,8 +1111,8 @@ debug(objectrelated2) { // check
 // obj_im.obj_inline_markup_and_anchor_tags("doc_end_reset", an_object_key, "", dochead_make_aa);
 #+END_SRC
 
-*** document sections
-**** endnotes section (scroll & seg)                          :endnotes:
+*** tie up preparation of document sections
+**** endnotes section (scroll & seg)                               :endnotes:
 
 #+name: abs_post
 #+BEGIN_SRC d
@@ -1047,7 +1133,7 @@ debug(endnotes) {
 }
 #+END_SRC
 
-**** glossary section?
+**** no glossary section?                                          :glossary:
 
 #+name: abs_post
 #+BEGIN_SRC d
@@ -1064,7 +1150,7 @@ if (an_object["glossary_nugget"].length == 0) {
   comp_obj_heading_.heading_lev_collapsed = 1;
   comp_obj_heading_.parent_ocn            = 1;
   comp_obj_heading_.parent_lev_markup     = 0;
-  the_glossary_section                ~= comp_obj_heading_;
+  the_glossary_section                    ~= comp_obj_heading_;
 } else {
   writeln("gloss");
 }
@@ -1075,7 +1161,7 @@ debug(glossary) {
 }
 #+END_SRC
 
-**** [#B] bibliography section (objects)                  :bibliography:
+**** bibliography section (objects)                            :bibliography:
 
 #+name: abs_post
 #+BEGIN_SRC d
@@ -1211,13 +1297,13 @@ auto biblio_entry_tags_jsonstr =  `{
   "id"                               : ""
 }`; // is: book, article, magazine, newspaper, blog, other
 
-**** [#B] bookindex section (scroll & seg)                  :book:index:
+**** bookindex section (scroll & seg)                            :book:index:
 
 #+name: abs_post
 #+BEGIN_SRC d
 auto bi = BookIndexReportSection();
 auto bi_tuple =
-  bi.bookindex_build_section(
+  bi.bookindex_build_abstraction_section(
     bookindex_unordered_hashes,
     obj_cite_number,
     segment_anchor_tag_that_object_belongs_to,
@@ -1233,7 +1319,7 @@ debug(bookindex) {                         // bookindex
 }
 #+END_SRC
 
-**** blurb section?
+**** no blurb section?                                                :blurb:
 
 #+name: abs_post
 #+BEGIN_SRC d
@@ -1245,13 +1331,13 @@ if (an_object["blurb_nugget"].length == 0) {
   comp_obj_heading_.text                  = "(skip) there is no Blurb section";
   comp_obj_heading_.ocn                   = 0;
   comp_obj_para.obj_cite_number           = "";
-  comp_obj_heading_.segment_anchor_tag    = "bibliography";
-  comp_obj_heading_.marked_up_level       = "1";
-  comp_obj_heading_.heading_lev_markup    = 4;
-  comp_obj_heading_.heading_lev_collapsed = 2;
+  comp_obj_heading_.segment_anchor_tag    = "";
+  comp_obj_heading_.marked_up_level       = "B";
+  comp_obj_heading_.heading_lev_markup    = 1;
+  comp_obj_heading_.heading_lev_collapsed = 1;
   comp_obj_heading_.parent_ocn            = 1;
   comp_obj_heading_.parent_lev_markup     = 0;
-  the_blurb_section                   ~= comp_obj_heading_;
+  the_blurb_section                       ~= comp_obj_heading_;
 } else {
   writeln("blurb");
 }
@@ -1262,17 +1348,16 @@ debug(blurb) {
 }
 #+END_SRC
 
-**** [#B] toc, table of contents section (scroll & seg)       :contents:
+**** toc backmatter, table of contents backmatter (scroll & seg)   :contents:
 
 #+name: abs_post
 #+BEGIN_SRC d
-
 indent=[
   "hang_position" : 1,
   "base_position" : 1,
 ];
 comp_obj_toc                       = comp_obj_toc.init;
-comp_obj_toc.use                   = "body";
+comp_obj_toc.use                   = "frontmatter";
 comp_obj_toc.is_of                 = "para";
 comp_obj_toc.is_a                  = "toc";
 comp_obj_toc.ocn                   = 0;
@@ -1387,12 +1472,351 @@ debug(toc) {
 }
 #+END_SRC
 
-*** [#B] the document                                              :document:
+**** doc head (separate document head from body, make space for toc)
 
 #+name: abs_post
 #+BEGIN_SRC d
 the_document_head_section ~= the_document_body_section[0];
 the_document_body_section=the_document_body_section[1..$];
+#+END_SRC
+
+**** loop: backmatter loop up to lev4: html_segnames, set backmatter pointers
+
+could optimise by
+- skipping second and third pass unless the output html seg or epub is being made!
+NOTE there are issues attempting to do this on first pass
+- as
+  - backmatter is created out of sequence and
+  - it is not certain which are present
+it is quite neat to have all in one place as we have here:
+
+#+name: abs_post
+#+BEGIN_SRC d
+if (the_endnotes_section["scroll"].length > 1) {
+  html_segnames ~= "endnotes";
+  html_segnames_ptr = html_segnames_ptr_cntr;
+  foreach (ref section; the_endnotes_section["scroll"]) {
+    if (section.heading_lev_markup == 4) {
+      section.ptr_html_segnames = html_segnames_ptr;
+      break;
+    }
+  }
+  foreach (ref section; the_endnotes_section["seg"]) {
+    if (section.heading_lev_markup == 4) {
+      section.ptr_html_segnames = html_segnames_ptr;
+      break;
+    }
+  }
+  html_segnames_ptr_cntr++;
+}
+if (the_glossary_section.length > 1) {
+  html_segnames ~= "glossary";
+  html_segnames_ptr = html_segnames_ptr_cntr;
+  foreach (ref section; the_glossary_section) {
+    if (section.heading_lev_markup == 4) {
+      section.ptr_html_segnames = html_segnames_ptr;
+      break;
+    }
+  }
+  html_segnames_ptr_cntr++;
+}
+if (the_bibliography_section.length > 1) {
+  html_segnames ~= "bibliography";
+  html_segnames_ptr = html_segnames_ptr_cntr;
+  foreach (ref section; the_bibliography_section) {
+    if (section.heading_lev_markup == 4) {
+      section.ptr_html_segnames = html_segnames_ptr;
+      break;
+    }
+  }
+  html_segnames_ptr_cntr++;
+}
+if (the_bookindex_section["scroll"].length > 1) {
+  html_segnames ~= "bookindex";
+  html_segnames_ptr = html_segnames_ptr_cntr;
+  foreach (ref section; the_bookindex_section["scroll"]) {
+    if (section.heading_lev_markup == 4) {
+      section.ptr_html_segnames = html_segnames_ptr;
+      break;
+    }
+  }
+  foreach (ref section; the_bookindex_section["seg"]) {
+    if (section.heading_lev_markup == 4) {
+      section.ptr_html_segnames = html_segnames_ptr;
+      break;
+    }
+  }
+  html_segnames_ptr_cntr++;
+}
+if (the_blurb_section.length > 1) {
+  html_segnames ~= "blurb";
+  html_segnames_ptr = html_segnames_ptr_cntr;
+  foreach (ref section; the_blurb_section) {
+    if (section.heading_lev_markup == 4) {
+      section.ptr_html_segnames = html_segnames_ptr;
+      break;
+    }
+  }
+  html_segnames_ptr_cntr++;
+}
+#+END_SRC
+
+**** loop: all segments (as needed) up to document heading 1~, lev4 html: segnames & subtoc, backmatter pointers
+
+could optimise by
+- skipping second and third pass unless the output html seg or epub is being made!
+
+during the third pass all previous and next segment names are known
+next are not yet known for backmatter during the second pass
+
+#+name: abs_post
+#+BEGIN_SRC d
+if ((opt_action_bool["html"])
+|| (opt_action_bool["html_scroll"])
+|| (opt_action_bool["html_seg"])
+|| (opt_action_bool["epub"])) {
+  foreach (ref obj; the_document_head_section) {
+    if (obj.is_a == "heading") {
+      debug(dom) {
+        writeln(obj.text);
+      }
+      dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
+      obj.dom_markedup = dom_markedup.dup;
+      dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
+      obj.dom_collapsed = dom_collapsed.dup;
+    }
+  }
+  if (the_table_of_contents_section["scroll"].length > 1) {
+    dom_markedup_buffer = dom_markedup.dup;
+    dom_collapsed_buffer = dom_collapsed.dup;
+    foreach (ref obj; the_table_of_contents_section["scroll"]) {
+      if (obj.is_a == "heading") {
+        debug(dom) {
+        // writeln(obj.text);
+        }
+        if (obj.heading_lev_markup == 4) {
+          obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
+          assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+        }
+        dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
+        obj.dom_markedup = dom_markedup.dup;
+        dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
+        obj.dom_collapsed = dom_collapsed.dup;
+      }
+    }
+    dom_markedup = dom_markedup_buffer.dup;
+    dom_collapsed = dom_collapsed_buffer.dup;
+    foreach (ref obj; the_table_of_contents_section["seg"]) {
+      if (obj.is_a == "heading") {
+        debug(dom) {
+          writeln(obj.text);
+        }
+        if (obj.heading_lev_markup == 4) {
+          obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
+          assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+        }
+        dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
+        obj.dom_markedup = dom_markedup.dup;
+        dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
+        obj.dom_collapsed = dom_collapsed.dup;
+      }
+    }
+  }
+  /+ multiple 1~ levels, loop through document body +/
+  if (the_document_body_section.length > 1) {
+    foreach (ref obj; the_document_body_section) {
+      if (obj.is_a == "heading") {
+        debug(dom) {
+          writeln(obj.text);
+        }
+        if (obj.heading_lev_markup == 4) {
+          obj.lev4_subtoc = lev4_subtoc[obj.segment_anchor_tag];
+          obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
+          if (html_segnames.length > obj.ptr_html_segnames + 1) {
+            obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
+          }
+          assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+        }
+        dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
+        obj.dom_markedup = dom_markedup.dup;
+        dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
+        obj.dom_collapsed = dom_collapsed.dup;
+      }
+    }
+  }
+  /+ optional only one 1~ level +/
+  if (the_endnotes_section["scroll"].length > 1) {
+    dom_markedup_buffer = dom_markedup.dup;
+    dom_collapsed_buffer = dom_collapsed.dup;
+    foreach (ref obj; the_endnotes_section["scroll"]) {
+      if (obj.is_a == "heading") {
+        debug(dom) {
+        }
+        if (obj.heading_lev_markup == 4) {
+          obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
+          if (html_segnames.length > obj.ptr_html_segnames + 1) {
+            obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
+          }
+          assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+        }
+        dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
+        obj.dom_markedup = dom_markedup.dup;
+        dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
+        obj.dom_collapsed = dom_collapsed.dup;
+      }
+    }
+    dom_markedup = dom_markedup_buffer.dup;
+    dom_collapsed = dom_collapsed_buffer.dup;
+    foreach (ref obj; the_endnotes_section["seg"]) {
+      if (obj.is_a == "heading") {
+        debug(dom) {
+          writeln(obj.text);
+        }
+        if (obj.heading_lev_markup == 4) {
+          obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
+          if (html_segnames.length > obj.ptr_html_segnames + 1) {
+            obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
+          }
+          assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+        }
+        dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
+        obj.dom_markedup = dom_markedup.dup;
+        dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
+        obj.dom_collapsed = dom_collapsed.dup;
+      }
+    }
+  }
+  /+ optional only one 1~ level +/
+  if (the_glossary_section.length > 1) {
+    foreach (ref obj; the_glossary_section) {
+      if (obj.is_a == "heading") {
+        debug(dom) {
+          writeln(obj.text);
+        }
+        if (obj.heading_lev_markup == 4) {
+          obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
+          if (html_segnames.length > obj.ptr_html_segnames + 1) {
+            obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
+          }
+          assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+        }
+        dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
+        obj.dom_markedup = dom_markedup.dup;
+        dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
+        obj.dom_collapsed = dom_collapsed.dup;
+      }
+    }
+  }
+  /+ optional only one 1~ level +/
+  if (the_bibliography_section.length > 1) {
+    foreach (ref obj; the_bibliography_section) {
+      if (obj.is_a == "heading") {
+        debug(dom) {
+          writeln(obj.text);
+        }
+        if (obj.heading_lev_markup == 4) {
+          obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
+          if (html_segnames.length > obj.ptr_html_segnames + 1) {
+            obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
+          }
+          assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+        }
+        dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
+        obj.dom_markedup = dom_markedup.dup;
+        dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
+        obj.dom_collapsed = dom_collapsed.dup;
+      }
+    }
+  }
+  /+ optional only one 1~ level +/
+  if (the_bookindex_section["scroll"].length > 1) {
+    dom_markedup_buffer = dom_markedup.dup;
+    dom_collapsed_buffer = dom_collapsed.dup;
+    foreach (ref obj; the_bookindex_section["scroll"]) {
+      if (obj.is_a == "heading") {
+        debug(dom) {
+        // writeln(obj.text);
+        }
+        if (obj.heading_lev_markup == 4) {
+          obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
+          if (html_segnames.length > obj.ptr_html_segnames + 1) {
+            obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
+          }
+          assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+        }
+        dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
+        obj.dom_markedup = dom_markedup.dup;
+        dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
+        obj.dom_collapsed = dom_collapsed.dup;
+      }
+    }
+    dom_markedup = dom_markedup_buffer.dup;
+    dom_collapsed = dom_collapsed_buffer.dup;
+    foreach (ref obj; the_bookindex_section["seg"]) {
+      if (obj.is_a == "heading") {
+        debug(dom) {
+          writeln(obj.text);
+        }
+        if (obj.heading_lev_markup == 4) {
+          obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
+          if (html_segnames.length > obj.ptr_html_segnames + 1) {
+            obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
+          }
+          assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+        }
+        dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
+        obj.dom_markedup = dom_markedup.dup;
+        dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
+        obj.dom_collapsed = dom_collapsed.dup;
+      }
+    }
+  }
+  /+ optional only one 1~ level +/
+  if (the_blurb_section.length > 1) {
+    foreach (ref obj; the_blurb_section) {
+      if (obj.is_a == "heading") {
+        debug(dom) {
+          writeln(obj.text);
+        }
+        if (obj.heading_lev_markup == 4) {
+          obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
+          if (html_segnames.length > obj.ptr_html_segnames + 1) {
+            obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
+          }
+          assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+        }
+        dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
+        obj.dom_markedup = dom_markedup.dup;
+        dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
+        obj.dom_collapsed = dom_collapsed.dup;
+      }
+    }
+  }
+  dom_markedup = dom_set_markup_tags(dom_markedup, 0);
+  dom_collapsed = dom_set_collapsed_tags(dom_collapsed, 0);
+  comp_obj_heading_                       = comp_obj_heading_.init;
+  comp_obj_heading_.use                   = "empty";
+  comp_obj_heading_.is_of                 = "para";
+  comp_obj_heading_.is_a                  = "heading";
+  // comp_obj_heading_.text                  = "(skip) this is the DOM tail";
+  comp_obj_heading_.ocn                   = 0;
+  comp_obj_para.obj_cite_number           = "";
+  comp_obj_heading_.segment_anchor_tag    = "";
+  comp_obj_heading_.marked_up_level       = "";
+  comp_obj_heading_.heading_lev_markup    = 9;
+  comp_obj_heading_.heading_lev_collapsed = 9;
+  comp_obj_heading_.parent_ocn            = 0;
+  comp_obj_heading_.parent_lev_markup     = 0;
+  comp_obj_heading_.dom_markedup          = dom_markedup.dup;
+  comp_obj_heading_.dom_collapsed         = dom_collapsed.dup;
+  the_dom_tail_section                    ~= comp_obj_heading_;
+}
+#+END_SRC
+
+*** [#B] the document                                              :document:
+
+#+name: abs_post
+#+BEGIN_SRC d
 auto document_the = [
   "head":             the_document_head_section,
   "toc_seg":          the_table_of_contents_section["seg"],
@@ -1407,6 +1831,8 @@ auto document_the = [
   "bookindex_scroll": the_bookindex_section["scroll"],
   "bookindex_seg":    the_bookindex_section["seg"],
   "blurb":            the_blurb_section,
+  /+ dom tail only +/
+  "tail":             the_dom_tail_section,
 ];
 #+END_SRC
 
@@ -2772,7 +3198,7 @@ auto _heading_matched_(
         rgx.variable_doc_title, (dochead_meta_aa["title"]["full"] ~ ","));
       an_object[an_object_key]=replaceFirst(an_object[an_object_key],
         rgx.variable_doc_author, dochead_meta_aa["creator"]["author"]);
-      collapsed_lev["h0"] = 1;
+      collapsed_lev["h0"] = 0;
       an_object["lev_collapsed_number"] =
         to!string(collapsed_lev["h0"]);
       lv["lv"] = DocStructMarkupHeading.h_sect_A;
@@ -3201,7 +3627,7 @@ struct ObjInlineMarkupMunge {
 }
 #+END_SRC
 
-***** object inline markup                                     :markup:inline:
+***** toc, tags, object inline markup                         :markup:inline:
 ****** open
 
 #+name: ao_emitters_obj_inline_markup
@@ -3282,7 +3708,7 @@ struct ObjInlineMarkup {
   }
 #+END_SRC
 
-****** table of contents objects                         :markup:inline:
+****** toc, table of contents build, gather headings          :markup:inline:
 
 #+name: ao_emitters_obj_inline_markup_table_of_contents
 #+BEGIN_SRC d
@@ -3303,6 +3729,7 @@ struct ObjInlineMarkup {
     string[string][string]        dochead_make_aa,
     string                        segment_anchor_tag_that_object_belongs_to,
     string                        _anchor_tag,
+    ref string[][string]          lev4_subtoc,
     ObjGenericComposite[][string] the_table_of_contents_section,
   )
   in { }
@@ -3311,7 +3738,7 @@ struct ObjInlineMarkup {
     char[] heading_toc_ = to!(char[])(obj_["body_nugget"].dup.strip);
     heading_toc_ = _clean_heading_toc_(heading_toc_);
     auto attrib="";
-    string toc_txt_;
+    string toc_txt_, subtoc_txt_;
     int[string] indent;
     if (to!int(obj_["lev_markup_number"]) > 0) {
       indent=[
@@ -3325,7 +3752,7 @@ struct ObjInlineMarkup {
       );
       toc_txt_= munge.url_links(toc_txt_);
       comp_obj_toc                       = comp_obj_toc.init;
-      comp_obj_toc.use                   = "body";
+      comp_obj_toc.use                   = "frontmatter";
       comp_obj_toc.is_of                 = "para";
       comp_obj_toc.is_a                  = "toc";
       comp_obj_toc.ocn                   = 0;
@@ -3341,7 +3768,7 @@ struct ObjInlineMarkup {
         "base_position" : 0,
       ];
       comp_obj_toc                       = comp_obj_toc.init;
-      comp_obj_toc.use                   = "body";
+      comp_obj_toc.use                   = "frontmatter";
       comp_obj_toc.is_of                 = "para";
       comp_obj_toc.is_a                  = "toc";
       comp_obj_toc.ocn                   = 0;
@@ -3353,7 +3780,7 @@ struct ObjInlineMarkup {
       the_table_of_contents_section["scroll"] ~= comp_obj_toc;
     }
     comp_obj_toc                       = comp_obj_toc.init;
-    comp_obj_toc.use                   = "body";
+    comp_obj_toc.use                   = "frontmatter";
     comp_obj_toc.is_of                 = "para";
     comp_obj_toc.is_a                  = "toc";
     comp_obj_toc.ocn                   = 0;
@@ -3393,6 +3820,7 @@ struct ObjInlineMarkup {
         heading_toc_,
         segment_anchor_tag_that_object_belongs_to,
       );
+      lev4_subtoc[segment_anchor_tag_that_object_belongs_to] = [];
       toc_txt_= munge.url_links(toc_txt_);
       indent=[
         "hang_position" : to!int(obj_["lev_markup_number"]),
@@ -3410,6 +3838,12 @@ struct ObjInlineMarkup {
         segment_anchor_tag_that_object_belongs_to,
         _anchor_tag,
       );
+      subtoc_txt_ = format(                         // 5 .. 7
+        "{ %s }#%s",
+        heading_toc_,
+        _anchor_tag,
+      );
+      lev4_subtoc[segment_anchor_tag_that_object_belongs_to] ~= obj_["lev_markup_number"] ~ "~ " ~ to!string(subtoc_txt_).strip;
       toc_txt_= munge.url_links(toc_txt_);
       indent=[
         "hang_position" : to!int(obj_["lev_markup_number"]),
@@ -4105,7 +4539,7 @@ struct BookIndexReportSection {
 
 #+name: ao_emitters_book_index_report_section
 #+BEGIN_SRC d
-  auto bookindex_build_section(
+  auto bookindex_build_abstraction_section(
     string[][string][string] bookindex_unordered_hashes,
     int                      obj_cite_number,
     string                   segment_anchor_tag_that_object_belongs_to,
@@ -4126,6 +4560,7 @@ struct BookIndexReportSection {
     if ((mainkeys.length > 0)
     && (opt_action_bool["backmatter"] && opt_action_bool["section_bookindex"])) {
       string bi_tmp_seg, bi_tmp_scroll;
+      string[] bi_tmp_tags;
       comp_obj_heading_                       = comp_obj_heading_.init;
       comp_obj_heading_.use                   = "backmatter";
       comp_obj_heading_.is_of                 = "para";
@@ -4160,8 +4595,14 @@ struct BookIndexReportSection {
       bookindex_section["seg"]                ~= comp_obj_heading_;
       ++obj_cite_number;
       ++mkn;
+      import std.array : appender;
+      auto buffer = appender!(char[])();
+      string[dchar] transTable = [' ' : "_"];
       foreach (mainkey; mainkeys) {
+        bi_tmp_tags = [""];
         bi_tmp_scroll = "!{" ~ mainkey ~ "}! ";
+        buffer.clear();
+        bi_tmp_tags ~= translate(mainkey, transTable);
         bi_tmp_seg = "!{" ~ mainkey ~ "}! ";
         foreach (ref_; bookindex_unordered_hashes[mainkey]["_a"]) {
           auto go = replaceAll(ref_, rgx.book_index_go, "$1");
@@ -4177,6 +4618,8 @@ struct BookIndexReportSection {
           bookindex_unordered_hashes[mainkey].byKey.array.sort().release;
         foreach (subkey; subkeys) {
           bi_tmp_scroll ~= subkey ~ ", ";
+          buffer.clear();
+          bi_tmp_tags ~= translate(subkey, transTable);
           bi_tmp_seg ~= subkey ~ ", ";
           foreach (ref_; bookindex_unordered_hashes[mainkey][subkey]) {
             auto go = replaceAll(ref_, rgx.book_index_go, "$1");
@@ -4198,6 +4641,7 @@ struct BookIndexReportSection {
         comp_obj_para.text                  = to!string(bi_tmp_scroll).strip;
         comp_obj_para.ocn                   = obj_cite_number;
         comp_obj_para.obj_cite_number       = (obj_cite_number==0) ? "" : to!string(obj_cite_number);
+        comp_obj_para.anchor_tags           = bi_tmp_tags;
         comp_obj_para.indent_hang           = 0;
         comp_obj_para.indent_base           = 1;
         comp_obj_para.bullet                = false;
@@ -4619,7 +5063,7 @@ struct NodeStructureMetadata {
   }
 #+END_SRC
 
-***** TODO node metadata emitter heading
+***** TODO node metadata emitter heading, (including most segnames & their pointers)
 
 #+name: ao_emitters_metadata
 #+BEGIN_SRC d
@@ -5053,6 +5497,8 @@ struct ObjGenericComposite {
   string                 syntax                       = "";
   int                    ocn                          = 0;
   string                 segment_anchor_tag           = "";
+  string                 segname_prev                 = "";
+  string                 segname_next                 = "";
   int                    parent_lev_markup            = 0;
   int                    parent_ocn                   = 0;
   int[]                  ancestors                    = [];
@@ -5066,7 +5512,10 @@ struct ObjGenericComposite {
   int                    ptr_heading                  = 0;
   int                    array_ptr                    = 0;
   int                    heading_array_ptr_segments   = 0;
+  string[]               lev4_subtoc                  = [];
   string[string][string] node;
+  int[]                  dom_markedup                          = [ 0, 0, 0, 0, 0, 0, 0, 0,];
+  int[]                  dom_collapsed                         = [ 0, 0, 0, 0, 0, 0, 0, 0,];
 }
 #+END_SRC
 
diff --git a/org/ao_defaults.org b/org/ao_defaults.org
index 2aad14e..24baffb 100644
--- a/org/ao_defaults.org
+++ b/org/ao_defaults.org
@@ -677,7 +677,7 @@ static block_tic_close                                = ctRegex!("^(`{3})$","m")
 #+BEGIN_SRC d
 /+ blocked markup curly +/
 static block_curly_open                               = ctRegex!(`^((code([.][a-z][0-9a-z_]+)?|poem|group|block|quote|table)[{].*?$)`);
-static block_curly_code_open                          = ctRegex!(`^(code([.][a-z][0-9a-z_]+)?[{].*?$)`);
+static block_curly_code_open                          = ctRegex!(`^(code([.][a-z][0-9a-z_]+)?[{](.*?)$)`);
 static block_curly_code_close                         = ctRegex!(`^([}]code)`);
 static block_curly_poem_open                          = ctRegex!(`^(poem[{].*?$)`);
 static block_curly_poem_close                         = ctRegex!(`^([}]poem)`);
diff --git a/org/ao_output_debugs.org b/org/ao_output_debugs.org
index a3b74c9..886adb1 100644
--- a/org/ao_output_debugs.org
+++ b/org/ao_output_debugs.org
@@ -108,6 +108,27 @@ debug(dumpdoc) {
 }
 #+END_SRC
 
+** (segnames)                                                        :objects:
+
+#+name: ao_output_debugs
+#+BEGIN_SRC d
+void out_segnames(S)(
+  auto ref const S         contents,
+  string[]                 keys,
+  string[]                 html_segnames,
+) {
+  foreach (key; keys) {
+    if (contents[key].length > 1) {
+      foreach (obj; contents[key]) {
+        if (obj.heading_lev_markup == 4) {
+          writeln(obj.ptr_html_segnames, ". (", html_segnames[obj.ptr_html_segnames], ") -> ",  obj.text);
+        }
+      }
+    }
+  }
+}
+#+END_SRC
+
 ** shared output section arrange
 *** out toc
 
@@ -223,6 +244,32 @@ debug(section_toc_scroll) {
 }
 #+END_SRC
 
+#+name: ao_output_debugs
+#+BEGIN_SRC d
+debug(segnames) {
+  key="toc_scroll";
+  writeln(__LINE__);
+  string[] keys;
+  keys ~= [ "toc_seg", "body" ];
+  if (contents["endnotes_seg"].length > 1) {
+    keys ~= "endnotes_seg";
+  }
+  if (contents["glossary"].length > 1) {
+    keys ~= "glossary";
+  }
+  if (contents["bibliography"].length > 1) {
+    keys ~= "bibliography";
+  }
+  if (contents["bookindex_seg"].length > 1) {
+    keys ~= "bookindex_seg";
+  }
+  if (contents["blurb"].length > 1) {
+    keys ~= "blurb";
+  }
+  out_segnames(contents, keys, html_segnames);
+}
+#+END_SRC
+
 *** body_section                                                       :body:
 
 #+name: ao_output_debugs
@@ -242,7 +289,61 @@ debug(section_body) {
 }
 #+END_SRC
 
-*** endnotes_section (seg & scroll)                               :endnotes:
+*** dom structure                                                    :body:
+
+#+name: ao_output_debugs
+#+BEGIN_SRC d
+debug(dom) {
+  enum DomTags { none, open, close, close_and_open, open_still, }
+  foreach (sect; document_section_keys_sequenced["seg"]) {
+    foreach (obj; contents[sect]) {
+      if (obj.is_a == "heading") {
+        foreach_reverse (k; 0 .. 7) {
+          switch (obj.dom_markedup[k]) {
+          case DomTags.close :
+            writeln(markup.indent_by_spaces_provided(k), "</", k, ">");
+            break;
+          case DomTags.close_and_open :
+            writeln(markup.indent_by_spaces_provided(k), "</", k, ">");
+            writeln(markup.indent_by_spaces_provided(k), "<", k, ">", obj.text);
+            break;
+          case DomTags.open :
+            writeln(markup.indent_by_spaces_provided(k), "<", k, ">", obj.text);
+            break;
+          default :
+            break;
+          }
+        }
+      }
+    }
+  }
+  writeln("--------------------");
+  foreach (sect; document_section_keys_sequenced["seg"]) {
+    foreach (obj; contents[sect]) {
+      if (obj.is_a == "heading") {
+        foreach_reverse (k; 0 .. 7) {
+          switch (obj.dom_collapsed[k]) {
+          case DomTags.close :
+            writeln(markup.indent_by_spaces_provided(k), "</", k, ">");
+            break;
+          case DomTags.close_and_open :
+            writeln(markup.indent_by_spaces_provided(k), "</", k, ">");
+            writeln(markup.indent_by_spaces_provided(k), "<", k, ">", obj.text);
+            break;
+          case DomTags.open :
+            writeln(markup.indent_by_spaces_provided(k), "<", k, ">", obj.text);
+            break;
+          default :
+            break;
+          }
+        }
+      }
+    }
+  }
+}
+#+END_SRC
+
+*** endnotes_section (seg & scroll)                                :endnotes:
 
 **** endnotes
 
diff --git a/org/output.org b/org/output.org
index eae453a..e9253dc 100644
--- a/org/output.org
+++ b/org/output.org
@@ -117,23 +117,38 @@ auto html_heading(O)(
 ) {
   auto tags = _html_anchor_tags(obj.anchor_tags);
   string o;
-  o = format(q"¶<br><hr /><br>
+  if (obj.obj_cite_number.empty) {
+    o = format(q"¶<br><hr /><br>
+  <div class="substance">
+    <h%s class="%s">%s
+      %s
+    </h%s>
+  </div>¶",
+      obj.heading_lev_markup,
+      obj.is_a,
+      tags,
+      obj.text,
+      obj.heading_lev_markup,
+    );
+  } else {
+    o = format(q"¶<br><hr /><br>
   <div class="substance">
     <label class="ocn"><a href="#%s" class="lnkocn">%s</a></label>
     <h%s class="%s" id="%s"><a name="%s"></a>%s
       %s
     </h%s>
   </div>¶",
-  obj.obj_cite_number,
-  obj.obj_cite_number,
-  obj.heading_lev_markup,
-  obj.is_a,
-  obj.obj_cite_number,
-  obj.obj_cite_number,
-  tags,
-  obj.text,
-  obj.heading_lev_markup,
-  );
+    obj.obj_cite_number,
+    obj.obj_cite_number,
+    obj.heading_lev_markup,
+    obj.is_a,
+    obj.obj_cite_number,
+    obj.obj_cite_number,
+    tags,
+    obj.text,
+    obj.heading_lev_markup,
+    );
+  }
   return o;
 }
 #+END_SRC
@@ -149,13 +164,10 @@ auto html_para(O)(
   string o;
   if (obj.obj_cite_number.empty) {
     o = format(q"¶  <div class="substance">
-  <label class="ocn"><a href="#%s" class="lnkocn">%s</a></label>
   <p class="%s" indent="h%si%s">%s
     %s
   </p>
 </div>¶",
-      obj.obj_cite_number,
-      obj.obj_cite_number,
       obj.is_a,
       obj.indent_hang,
       obj.indent_base,
@@ -191,18 +203,29 @@ auto html_nugget(O)(
   auto ref const O         obj,
 ) {
   string o;
-  o = format(q"¶  <div class="substance">
+  if (obj.obj_cite_number.empty) {
+    o = format(q"¶  <div class="substance">
+  <p class="%s">
+    %s
+  </p>
+</div>¶",
+      obj.is_a,
+      obj.text
+    );
+  } else {
+    o = format(q"¶  <div class="substance">
   <label class="ocn"><a href="#%s" class="lnkocn">%s</a></label>
   <p class="%s" id="%s">
     %s
   </p>
 </div>¶",
-  obj.obj_cite_number,
-  obj.obj_cite_number,
-  obj.is_a,
-  obj.obj_cite_number,
-  obj.text
-  );
+      obj.obj_cite_number,
+      obj.obj_cite_number,
+      obj.is_a,
+      obj.obj_cite_number,
+      obj.text
+    );
+  }
   return o;
 }
 #+END_SRC
@@ -218,7 +241,7 @@ auto scroll_head_html() {
 <head>
   <meta charset="utf-8">
   <title>
-    Title
+    %s%s
   </title>
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
   <meta name="dc.title" content="Title" />
@@ -239,7 +262,10 @@ auto scroll_head_html() {
   <link href="../../../_sisu/css/html.css" rel="stylesheet">
 </head>
 <body lang="en">
-<a name="top" id="top"></a>¶");
+<a name="top" id="top"></a>¶",
+dochead_meta["title"]["full"],
+(dochead_meta["creator"]["author"].empty) ? "" : ", " ~ dochead_meta["creator"]["author"],
+);
   return o;
 }
 #+END_SRC
@@ -319,7 +345,7 @@ void scroll(C)(
   string[] doc;
   foreach (part; document_section_keys_sequenced["scroll"]) {
     foreach (obj; contents[part]) {
-      if (obj.use == "body") {
+      if (obj.use == "frontmatter") {
         switch (obj.is_of) {
         case "para":
           switch (obj.is_a) {
@@ -329,6 +355,22 @@ void scroll(C)(
           case "toc":
             body_html ~= html_toc(obj);
             break;
+          default:
+            writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
+            break;
+          }
+          break;
+        default:
+          writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
+          break;
+        }
+      } else if (obj.use == "body") {
+        switch (obj.is_of) {
+        case "para":
+          switch (obj.is_a) {
+          case "heading":
+            body_html ~= html_heading(obj);
+            break;
           case "para":
             body_html ~= html_para(obj);
             break;
@@ -402,6 +444,12 @@ void scroll(C)(
       }
     }
   }
+#+END_SRC
+
+**** scroll output file
+
+#+name: output_html
+#+BEGIN_SRC d
   doc = scroll_head_html ~ body_html ~ scroll_tail_html;
   auto m = matchFirst(fn_src, rgx.src_fn);
   auto fn = m["fn_base"] ~ ".html";
diff --git a/org/sdp.org b/org/sdp.org
index 274c285..f8734be 100644
--- a/org/sdp.org
+++ b/org/sdp.org
@@ -24,7 +24,7 @@ struct Version {
   int minor;
   int patch;
 }
-enum ver = Version(0, 10, 0);
+enum ver = Version(0, 10, 1);
 #+END_SRC
 
 ** TODO sdp src/sdp.d                                               :sdp.d:
@@ -137,6 +137,7 @@ import sdlang;                            // sdlang.d
 #+END_SRC
 
 ***** notes
+
 sdlang.parser,                       // sdlang/parser.d
 sdlang.exceptions;
 
@@ -430,50 +431,39 @@ auto doc_html_segnames = t[1];
 #+NAME: sdp_each_file_do_document_abstraction
 #+BEGIN_SRC d
 string[][string] document_section_keys_sequenced = [
-  "seg": [
-     "head",
-     "toc_seg",
-     "body",
-   ],
-   "scroll": [
-     "head",
-     "toc_scroll",
-     "body",
-   ]
+  "seg": ["head", "toc_seg", "body",],
+  "scroll": ["head", "toc_scroll", "body",]
 ];
 if (doc_ao_contents["endnotes_seg"].length > 1) {
-  document_section_keys_sequenced["seg"] =
-    document_section_keys_sequenced["seg"] ~= "endnotes_seg";
+  document_section_keys_sequenced["seg"] ~= "endnotes_seg";
 }
 if (doc_ao_contents["endnotes_scroll"].length > 1) {
-  document_section_keys_sequenced["scroll"] =
-    document_section_keys_sequenced["scroll"] ~= "endnotes_scroll";
+  document_section_keys_sequenced["scroll"] ~= "endnotes_scroll";
 }
 if (doc_ao_contents["glossary"].length > 1) {
-  document_section_keys_sequenced["seg"] =
-    document_section_keys_sequenced["seg"] ~= "glossary";
-  document_section_keys_sequenced["scroll"] =
-    document_section_keys_sequenced["scroll"] ~= "glossary";
+  document_section_keys_sequenced["seg"] ~= "glossary";
+  document_section_keys_sequenced["scroll"] ~= "glossary";
 }
 if (doc_ao_contents["bibliography"].length > 1) {
-  document_section_keys_sequenced["seg"] =
-    document_section_keys_sequenced["seg"] ~= "bibliography";
-  document_section_keys_sequenced["scroll"] =
-    document_section_keys_sequenced["scroll"] ~= "bibliography";
+  document_section_keys_sequenced["seg"] ~= "bibliography";
+  document_section_keys_sequenced["scroll"] ~= "bibliography";
 }
 if (doc_ao_contents["bookindex_seg"].length > 1) {
-  document_section_keys_sequenced["seg"] =
-    document_section_keys_sequenced["seg"] ~= "bookindex_seg";
+  document_section_keys_sequenced["seg"] ~= "bookindex_seg";
 }
 if (doc_ao_contents["bookindex_scroll"].length > 1) {
-  document_section_keys_sequenced["scroll"] =
-    document_section_keys_sequenced["scroll"] ~= "bookindex_scroll";
+  document_section_keys_sequenced["scroll"] ~= "bookindex_scroll";
 }
 if (doc_ao_contents["blurb"].length > 1) {
-  document_section_keys_sequenced["seg"] =
-    document_section_keys_sequenced["seg"] ~= "blurb";
-  document_section_keys_sequenced["scroll"] =
-    document_section_keys_sequenced["scroll"] ~= "blurb";
+  document_section_keys_sequenced["seg"] ~= "blurb";
+  document_section_keys_sequenced["scroll"] ~= "blurb";
+}
+if ((opt_action_bool["html"])
+|| (opt_action_bool["html_scroll"])
+|| (opt_action_bool["html_seg"])
+|| (opt_action_bool["epub"])) {
+  document_section_keys_sequenced["seg"] ~= "tail";
+  document_section_keys_sequenced["scroll"] ~= "tail";
 }
 #+END_SRC
 
diff --git a/src/sdp.d b/src/sdp.d
index ff9128f..5ec249b 100755
--- a/src/sdp.d
+++ b/src/sdp.d
@@ -218,50 +218,39 @@ void main(string[] args) {
       auto doc_ao_contents = t[0]; // head ~ toc ~ contents ~ endnotes_seg ~ glossary ~ bibliography ~ bookindex ~blurb;
       auto doc_html_segnames = t[1];
       string[][string] document_section_keys_sequenced = [
-        "seg": [
-           "head",
-           "toc_seg",
-           "body",
-         ],
-         "scroll": [
-           "head",
-           "toc_scroll",
-           "body",
-         ]
+        "seg": ["head", "toc_seg", "body",],
+        "scroll": ["head", "toc_scroll", "body",]
       ];
       if (doc_ao_contents["endnotes_seg"].length > 1) {
-        document_section_keys_sequenced["seg"] =
-          document_section_keys_sequenced["seg"] ~= "endnotes_seg";
+        document_section_keys_sequenced["seg"] ~= "endnotes_seg";
       }
       if (doc_ao_contents["endnotes_scroll"].length > 1) {
-        document_section_keys_sequenced["scroll"] =
-          document_section_keys_sequenced["scroll"] ~= "endnotes_scroll";
+        document_section_keys_sequenced["scroll"] ~= "endnotes_scroll";
       }
       if (doc_ao_contents["glossary"].length > 1) {
-        document_section_keys_sequenced["seg"] =
-          document_section_keys_sequenced["seg"] ~= "glossary";
-        document_section_keys_sequenced["scroll"] =
-          document_section_keys_sequenced["scroll"] ~= "glossary";
+        document_section_keys_sequenced["seg"] ~= "glossary";
+        document_section_keys_sequenced["scroll"] ~= "glossary";
       }
       if (doc_ao_contents["bibliography"].length > 1) {
-        document_section_keys_sequenced["seg"] =
-          document_section_keys_sequenced["seg"] ~= "bibliography";
-        document_section_keys_sequenced["scroll"] =
-          document_section_keys_sequenced["scroll"] ~= "bibliography";
+        document_section_keys_sequenced["seg"] ~= "bibliography";
+        document_section_keys_sequenced["scroll"] ~= "bibliography";
       }
       if (doc_ao_contents["bookindex_seg"].length > 1) {
-        document_section_keys_sequenced["seg"] =
-          document_section_keys_sequenced["seg"] ~= "bookindex_seg";
+        document_section_keys_sequenced["seg"] ~= "bookindex_seg";
       }
       if (doc_ao_contents["bookindex_scroll"].length > 1) {
-        document_section_keys_sequenced["scroll"] =
-          document_section_keys_sequenced["scroll"] ~= "bookindex_scroll";
+        document_section_keys_sequenced["scroll"] ~= "bookindex_scroll";
       }
       if (doc_ao_contents["blurb"].length > 1) {
-        document_section_keys_sequenced["seg"] =
-          document_section_keys_sequenced["seg"] ~= "blurb";
-        document_section_keys_sequenced["scroll"] =
-          document_section_keys_sequenced["scroll"] ~= "blurb";
+        document_section_keys_sequenced["seg"] ~= "blurb";
+        document_section_keys_sequenced["scroll"] ~= "blurb";
+      }
+      if ((opt_action_bool["html"])
+      || (opt_action_bool["html_scroll"])
+      || (opt_action_bool["html_seg"])
+      || (opt_action_bool["epub"])) {
+        document_section_keys_sequenced["seg"] ~= "tail";
+        document_section_keys_sequenced["scroll"] ~= "tail";
       }
       /+ ↓ debugs +/
       debug(checkdoc) {
diff --git a/src/sdp/ao_abstract_doc_source.d b/src/sdp/ao_abstract_doc_source.d
index 0697ae4..c11ee4a 100644
--- a/src/sdp/ao_abstract_doc_source.d
+++ b/src/sdp/ao_abstract_doc_source.d
@@ -19,6 +19,7 @@ template SiSUdocAbstraction() {
     auto rgx = Rgx();
     ObjGenericComposite[][string] the_table_of_contents_section;
     ObjGenericComposite[] the_document_head_section, the_document_body_section, the_bibliography_section, the_glossary_section, the_blurb_section;
+    ObjGenericComposite[] the_dom_tail_section;
     string[string] an_object, processing;
     string an_object_key;
     string[] anchor_tags;
@@ -49,10 +50,10 @@ template SiSUdocAbstraction() {
     /+ counters +/
     int cntr, previous_count, previous_length;
     int[string] line_occur;
-    int verse_line, heading_ptr;
-    string[] html_segnames=[];
+    string[] html_segnames=["toc"];
     int html_segnames_ptr=0;
     int html_segnames_ptr_cntr=0;
+    int verse_line, heading_ptr;
     /+ paragraph attributes +/
     int[string] indent;
     bool bullet = true;
@@ -62,6 +63,89 @@ template SiSUdocAbstraction() {
     /+ ocn +/
     int obj_cite_number, obj_cite_number_;
     auto object_citation_number = OCNemitter();
+    int[] dom_markedup = [ 0, 0, 0, 0, 0, 0, 0, 0, 0,];
+    int[] dom_markedup_buffer = [ 0, 0, 0, 0, 0, 0, 0, 0, 0,];
+    int[] dom_collapsed = [ 0, 0, 0, 0, 0, 0, 0, 0, 0,];
+    int[] dom_collapsed_buffer = [ 0, 0, 0, 0, 0, 0, 0, 0, 0,];
+    enum DomTags { none, open, close, close_and_open, open_still, }
+    auto dom_set_markup_tags(int[] dom, int lev) {
+      foreach (i; 0 .. 8) {
+        if (i < lev) {
+          if (dom[i] == DomTags.open
+             || dom[i] == DomTags.close_and_open
+          ) {
+            dom[i] = DomTags.open_still;
+          } else if (dom[i] == DomTags.close) {
+            dom[i] = DomTags.none;
+          }
+        } else if (i == lev) {
+          if (lev  == 0
+            && dom[i] == DomTags.open_still
+          ) {
+            dom[i] = DomTags.close;
+          } else if (dom[i] == DomTags.open
+            || dom[i] == DomTags.open_still
+            || dom[i] == DomTags.close_and_open
+          ) {
+            dom[i] = DomTags.close_and_open;
+          } else {
+            dom[i] = DomTags.open;
+          }
+        } else if (i > lev) {
+          if (dom[i] == DomTags.close) {
+            dom[i] = DomTags.none;
+          } else if (dom[i] == DomTags.open
+            || dom[i] == DomTags.open_still
+            || dom[i] == DomTags.close_and_open
+          ) {
+            dom[i] = DomTags.close;
+          }
+        }
+      }
+      debug(dom) {
+        writeln(lev, ": ", dom);
+      }
+      return dom;
+    }
+    auto dom_set_collapsed_tags(int[] dom, int lev) {
+      foreach (i; 0 .. 8) {
+        if (i < lev) {
+          if (dom[i] == DomTags.open
+             || dom[i] == DomTags.close_and_open
+          ) {
+            dom[i] = DomTags.open_still;
+          } else if (dom[i] == DomTags.close) {
+            dom[i] = DomTags.none;
+          }
+        } else if (i == lev) {
+          if (lev  == 0
+            && dom[i] == DomTags.open_still
+          ) {
+            dom[i] = DomTags.close;
+          } else if (dom[i] == DomTags.open
+            || dom[i] == DomTags.open_still
+            || dom[i] == DomTags.close_and_open
+          ) {
+            dom[i] = DomTags.close_and_open;
+          } else {
+            dom[i] = DomTags.open;
+          }
+        } else if (i > lev) {
+          if (dom[i] == DomTags.close) {
+            dom[i] = DomTags.none;
+          } else if (dom[i] == DomTags.open
+            || dom[i] == DomTags.open_still
+            || dom[i] == DomTags.close_and_open
+          ) {
+            dom[i] = DomTags.close;
+          }
+        }
+      }
+      debug(dom) {
+        writeln(lev, ": ", dom);
+      }
+      return dom;
+    }
     int ocn_emit(int ocn_status_flag) {
       return object_citation_number.ocn_emitter(ocn_status_flag);
     }
@@ -160,7 +244,7 @@ template SiSUdocAbstraction() {
       an_object["glossary_nugget"] = "";
       an_object["blurb_nugget"] = "";
       comp_obj_heading_                       = comp_obj_heading_.init;
-      comp_obj_heading_.use                   = "content";
+      comp_obj_heading_.use                   = "frontmatter";
       comp_obj_heading_.is_of                 = "para";
       comp_obj_heading_.is_a                  = "heading";
       comp_obj_heading_.text                  = "Table of Contents";
@@ -169,17 +253,20 @@ template SiSUdocAbstraction() {
       comp_obj_heading_.segment_anchor_tag    = "toc";
       comp_obj_heading_.marked_up_level       = "1";
       comp_obj_heading_.heading_lev_markup    = 4;
-      comp_obj_heading_.heading_lev_collapsed = 2;
+      comp_obj_heading_.heading_lev_collapsed = 1;
       comp_obj_heading_.parent_ocn            = 1;
       comp_obj_heading_.parent_lev_markup     = 0;
+      comp_obj_heading_.ptr_html_segnames     = html_segnames_ptr;
       comp_obj_heading_.anchor_tags           = ["toc"];
-      auto toc_head                       = comp_obj_heading_;
+      auto toc_head                           = comp_obj_heading_;
+      html_segnames_ptr_cntr++;
       the_table_of_contents_section = [
         "seg": [toc_head],
         "scroll": [toc_head],
       ];
       auto mkup = InlineMarkup();
       auto munge = ObjInlineMarkupMunge();
+      string[][string] lev4_subtoc;
       /+ abstraction init ↑ +/
       /+ ↓ loop markup document/text line by line +/
       srcDocLoop:
@@ -262,7 +349,7 @@ template SiSUdocAbstraction() {
               an_object_key="glossary_nugget"; //
               if (matchFirst(line, rgx.heading_glossary)) {
                 comp_obj_heading_                       = comp_obj_heading_.init;
-                comp_obj_heading_.use                   = "content";
+                comp_obj_heading_.use                   = "backmatter";
                 comp_obj_heading_.is_of                 = "para";
                 comp_obj_heading_.is_a                  = "heading";
                 comp_obj_heading_.text                  = "Glossary";
@@ -275,7 +362,7 @@ template SiSUdocAbstraction() {
                 comp_obj_heading_.parent_lev_markup     = 0;
                 the_glossary_section                    ~= comp_obj_heading_;
                 comp_obj_heading_                       = comp_obj_heading_.init;
-                comp_obj_heading_.use                   = "content";
+                comp_obj_heading_.use                   = "backmatter";
                 comp_obj_heading_.is_of                 = "para";
                 comp_obj_heading_.is_a                  = "heading";
                 comp_obj_heading_.text                  = "Glossary";
@@ -288,13 +375,13 @@ template SiSUdocAbstraction() {
                 comp_obj_heading_.parent_ocn            = 1;
                 comp_obj_heading_.parent_lev_markup     = 0;
                 comp_obj_heading_.anchor_tags           = ["glossary"];
-                the_glossary_section                ~= comp_obj_heading_;
+                the_glossary_section                    ~= comp_obj_heading_;
               // } else if (matchFirst(line, rgx.heading)) {
               //   _heading_matched_(line, line_occur, an_object, an_object_key, lv, collapsed_lev, type, dochead_meta_aa); // levels?
               } else {
                 _para_match_(line, an_object, an_object_key, indent, bullet, type, line_occur);
                 comp_obj_para                       = comp_obj_para.init;
-                comp_obj_para.use                   = "content";
+                comp_obj_para.use                   = "backmatter";
                 comp_obj_para.is_of                 = "para";
                 comp_obj_para.is_a                  = "glossary";
                 comp_obj_para.text                  = to!string(line).strip;
@@ -333,7 +420,7 @@ template SiSUdocAbstraction() {
               an_object_key="blurb_nugget";
               if (matchFirst(line, rgx.heading_blurb)) {
                 comp_obj_heading_                       = comp_obj_heading_.init;
-                comp_obj_heading_.use                   = "content";
+                comp_obj_heading_.use                   = "backmatter";
                 comp_obj_heading_.is_of                 = "para";
                 comp_obj_heading_.is_a                  = "heading";
                 comp_obj_heading_.text                  = "Blurb";
@@ -346,7 +433,7 @@ template SiSUdocAbstraction() {
                 comp_obj_heading_.parent_lev_markup     = 0;
                 the_blurb_section                       ~= comp_obj_heading_;
                 comp_obj_heading_                       = comp_obj_heading_.init;
-                comp_obj_heading_.use                   = "content";
+                comp_obj_heading_.use                   = "backmatter";
                 comp_obj_heading_.is_of                 = "para";
                 comp_obj_heading_.is_a                  = "heading";
                 comp_obj_heading_.text                  = "Blurb";
@@ -363,7 +450,7 @@ template SiSUdocAbstraction() {
               } else if ((matchFirst(line, rgx.heading))
               && (opt_action_bool["backmatter"] && opt_action_bool["section_blurb"])) {
                 comp_obj_heading_                       = comp_obj_heading_.init;
-                comp_obj_heading_.use                   = "content";
+                comp_obj_heading_.use                   = "backmatter";
                 comp_obj_heading_.is_of                 = "para";
                 comp_obj_heading_.is_a                  = "heading";
                 comp_obj_heading_.text                  = to!string(line);
@@ -379,12 +466,12 @@ template SiSUdocAbstraction() {
               } else {
                 _para_match_(line, an_object, an_object_key, indent, bullet, type, line_occur);
                 comp_obj_para                       = comp_obj_para.init;
-                comp_obj_para.use                   = "content";
+                comp_obj_para.use                   = "backmatter";
                 comp_obj_para.is_of                 = "para";
-                comp_obj_para.is_a                  = "para";
+                comp_obj_para.is_a                  = "blurb";
                 comp_obj_para.text                  = to!string(line).strip;
-                comp_obj_para.ocn                   = obj_cite_number;
-                comp_obj_para.obj_cite_number       = (obj_cite_number==0) ? "" : to!string(obj_cite_number);
+                comp_obj_para.ocn                   = 0;
+                comp_obj_para.obj_cite_number       = "";
                 comp_obj_para.indent_hang           = indent["hang_position"];
                 comp_obj_para.indent_base           = indent["base_position"];
                 comp_obj_para.bullet                = bullet;
@@ -576,6 +663,7 @@ template SiSUdocAbstraction() {
                   dochead_make_aa,
                   segment_anchor_tag_that_object_belongs_to,
                   _anchor_tag,
+                  lev4_subtoc,
                   the_table_of_contents_section,
                 );
                 if (an_object["lev_markup_number"] == "4") {
@@ -633,7 +721,7 @@ template SiSUdocAbstraction() {
                 an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0];
                 anchor_tags = substantive_object_and_anchor_tags_tuple[1];
                 comp_obj_para                       = comp_obj_para.init;
-                comp_obj_para.use                   = "content";
+                comp_obj_para.use                   = "body";
                 comp_obj_para.is_of                 = "para";
                 comp_obj_para.is_a                  = "para";
                 comp_obj_para.text                  = to!string(an_object["substantive"]).strip;
@@ -720,9 +808,8 @@ template SiSUdocAbstraction() {
         }
       }
       if (an_object["glossary_nugget"].length == 0) {
-        writeln("no gloss");
         comp_obj_heading_                       = comp_obj_heading_.init;
-        comp_obj_heading_.use                   = "content";
+        comp_obj_heading_.use                   = "empty";
         comp_obj_heading_.is_of                 = "para";
         comp_obj_heading_.is_a                  = "heading";
         comp_obj_heading_.text                  = "(skip) there is no Glossary section";
@@ -733,7 +820,7 @@ template SiSUdocAbstraction() {
         comp_obj_heading_.heading_lev_collapsed = 1;
         comp_obj_heading_.parent_ocn            = 1;
         comp_obj_heading_.parent_lev_markup     = 0;
-        the_glossary_section                ~= comp_obj_heading_;
+        the_glossary_section                    ~= comp_obj_heading_;
       } else {
         writeln("gloss");
       }
@@ -749,7 +836,7 @@ template SiSUdocAbstraction() {
         biblio._bibliography_(biblio_unsorted_incomplete, bib_arr_json);
       if (biblio_ordered.length > 0) {
         comp_obj_heading_                       = comp_obj_heading_.init;
-        comp_obj_heading_.use                   = "content";
+        comp_obj_heading_.use                   = "backmatter";
         comp_obj_heading_.is_of                 = "para";
         comp_obj_heading_.is_a                  = "heading";
         comp_obj_heading_.text                  = "Bibliography";
@@ -763,7 +850,7 @@ template SiSUdocAbstraction() {
         the_bibliography_section                ~= comp_obj_heading_;
         // ---
         comp_obj_heading_                       = comp_obj_heading_.init;
-        comp_obj_heading_.use                   = "content";
+        comp_obj_heading_.use                   = "backmatter";
         comp_obj_heading_.is_of                 = "para";
         comp_obj_heading_.is_a                  = "heading";
         comp_obj_heading_.text                  = "Bibliography";
@@ -779,7 +866,7 @@ template SiSUdocAbstraction() {
         the_bibliography_section                ~= comp_obj_heading_;
       } else {
         comp_obj_heading_                       = comp_obj_heading_.init;
-        comp_obj_heading_.use                   = "content";
+        comp_obj_heading_.use                   = "empty";
         comp_obj_heading_.is_of                 = "para";
         comp_obj_heading_.is_a                  = "heading";
         comp_obj_heading_.text                  = "(skip) there is no Bibliography";
@@ -809,7 +896,7 @@ template SiSUdocAbstraction() {
           ((entry["url"].str.empty) ? "" : ", [" ~ entry["url"].str ~ "]"),
         );
         comp_obj_para                       = comp_obj_para.init;
-        comp_obj_para.use                   = "content";
+        comp_obj_para.use                   = "backmatter";
         comp_obj_para.is_of                 = "para";
         comp_obj_para.is_a                  = "bibliography";
         comp_obj_para.text                  = to!string(out_).strip;
@@ -828,7 +915,7 @@ template SiSUdocAbstraction() {
       }
       auto bi = BookIndexReportSection();
       auto bi_tuple =
-        bi.bookindex_build_section(
+        bi.bookindex_build_abstraction_section(
           bookindex_unordered_hashes,
           obj_cite_number,
           segment_anchor_tag_that_object_belongs_to,
@@ -843,21 +930,20 @@ template SiSUdocAbstraction() {
         }
       }
       if (an_object["blurb_nugget"].length == 0) {
-        writeln("no blurb");
         comp_obj_heading_                       = comp_obj_heading_.init;
-        comp_obj_heading_.use                   = "content";
+        comp_obj_heading_.use                   = "empty";
         comp_obj_heading_.is_of                 = "para";
         comp_obj_heading_.is_a                  = "heading";
         comp_obj_heading_.text                  = "(skip) there is no Blurb section";
         comp_obj_heading_.ocn                   = 0;
         comp_obj_para.obj_cite_number           = "";
-        comp_obj_heading_.segment_anchor_tag    = "bibliography";
-        comp_obj_heading_.marked_up_level       = "1";
-        comp_obj_heading_.heading_lev_markup    = 4;
-        comp_obj_heading_.heading_lev_collapsed = 2;
+        comp_obj_heading_.segment_anchor_tag    = "";
+        comp_obj_heading_.marked_up_level       = "B";
+        comp_obj_heading_.heading_lev_markup    = 1;
+        comp_obj_heading_.heading_lev_collapsed = 1;
         comp_obj_heading_.parent_ocn            = 1;
         comp_obj_heading_.parent_lev_markup     = 0;
-        the_blurb_section                   ~= comp_obj_heading_;
+        the_blurb_section                       ~= comp_obj_heading_;
       } else {
         writeln("blurb");
       }
@@ -866,13 +952,12 @@ template SiSUdocAbstraction() {
           writeln(blurb.text);
         }
       }
-      
       indent=[
         "hang_position" : 1,
         "base_position" : 1,
       ];
       comp_obj_toc                       = comp_obj_toc.init;
-      comp_obj_toc.use                   = "content";
+      comp_obj_toc.use                   = "frontmatter";
       comp_obj_toc.is_of                 = "para";
       comp_obj_toc.is_a                  = "toc";
       comp_obj_toc.ocn                   = 0;
@@ -987,6 +1072,313 @@ template SiSUdocAbstraction() {
       }
       the_document_head_section ~= the_document_body_section[0];
       the_document_body_section=the_document_body_section[1..$];
+      if (the_endnotes_section["scroll"].length > 1) {
+        html_segnames ~= "endnotes";
+        html_segnames_ptr = html_segnames_ptr_cntr;
+        foreach (ref section; the_endnotes_section["scroll"]) {
+          if (section.heading_lev_markup == 4) {
+            section.ptr_html_segnames = html_segnames_ptr;
+            break;
+          }
+        }
+        foreach (ref section; the_endnotes_section["seg"]) {
+          if (section.heading_lev_markup == 4) {
+            section.ptr_html_segnames = html_segnames_ptr;
+            break;
+          }
+        }
+        html_segnames_ptr_cntr++;
+      }
+      if (the_glossary_section.length > 1) {
+        html_segnames ~= "glossary";
+        html_segnames_ptr = html_segnames_ptr_cntr;
+        foreach (ref section; the_glossary_section) {
+          if (section.heading_lev_markup == 4) {
+            section.ptr_html_segnames = html_segnames_ptr;
+            break;
+          }
+        }
+        html_segnames_ptr_cntr++;
+      }
+      if (the_bibliography_section.length > 1) {
+        html_segnames ~= "bibliography";
+        html_segnames_ptr = html_segnames_ptr_cntr;
+        foreach (ref section; the_bibliography_section) {
+          if (section.heading_lev_markup == 4) {
+            section.ptr_html_segnames = html_segnames_ptr;
+            break;
+          }
+        }
+        html_segnames_ptr_cntr++;
+      }
+      if (the_bookindex_section["scroll"].length > 1) {
+        html_segnames ~= "bookindex";
+        html_segnames_ptr = html_segnames_ptr_cntr;
+        foreach (ref section; the_bookindex_section["scroll"]) {
+          if (section.heading_lev_markup == 4) {
+            section.ptr_html_segnames = html_segnames_ptr;
+            break;
+          }
+        }
+        foreach (ref section; the_bookindex_section["seg"]) {
+          if (section.heading_lev_markup == 4) {
+            section.ptr_html_segnames = html_segnames_ptr;
+            break;
+          }
+        }
+        html_segnames_ptr_cntr++;
+      }
+      if (the_blurb_section.length > 1) {
+        html_segnames ~= "blurb";
+        html_segnames_ptr = html_segnames_ptr_cntr;
+        foreach (ref section; the_blurb_section) {
+          if (section.heading_lev_markup == 4) {
+            section.ptr_html_segnames = html_segnames_ptr;
+            break;
+          }
+        }
+        html_segnames_ptr_cntr++;
+      }
+      if ((opt_action_bool["html"])
+      || (opt_action_bool["html_scroll"])
+      || (opt_action_bool["html_seg"])
+      || (opt_action_bool["epub"])) {
+        foreach (ref obj; the_document_head_section) {
+          if (obj.is_a == "heading") {
+            debug(dom) {
+              writeln(obj.text);
+            }
+            dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
+            obj.dom_markedup = dom_markedup.dup;
+            dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
+            obj.dom_collapsed = dom_collapsed.dup;
+          }
+        }
+        if (the_table_of_contents_section["scroll"].length > 1) {
+          dom_markedup_buffer = dom_markedup.dup;
+          dom_collapsed_buffer = dom_collapsed.dup;
+          foreach (ref obj; the_table_of_contents_section["scroll"]) {
+            if (obj.is_a == "heading") {
+              debug(dom) {
+              // writeln(obj.text);
+              }
+              if (obj.heading_lev_markup == 4) {
+                obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
+                assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+              }
+              dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
+              obj.dom_markedup = dom_markedup.dup;
+              dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
+              obj.dom_collapsed = dom_collapsed.dup;
+            }
+          }
+          dom_markedup = dom_markedup_buffer.dup;
+          dom_collapsed = dom_collapsed_buffer.dup;
+          foreach (ref obj; the_table_of_contents_section["seg"]) {
+            if (obj.is_a == "heading") {
+              debug(dom) {
+                writeln(obj.text);
+              }
+              if (obj.heading_lev_markup == 4) {
+                obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
+                assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+              }
+              dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
+              obj.dom_markedup = dom_markedup.dup;
+              dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
+              obj.dom_collapsed = dom_collapsed.dup;
+            }
+          }
+        }
+        /+ multiple 1~ levels, loop through document body +/
+        if (the_document_body_section.length > 1) {
+          foreach (ref obj; the_document_body_section) {
+            if (obj.is_a == "heading") {
+              debug(dom) {
+                writeln(obj.text);
+              }
+              if (obj.heading_lev_markup == 4) {
+                obj.lev4_subtoc = lev4_subtoc[obj.segment_anchor_tag];
+                obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
+                if (html_segnames.length > obj.ptr_html_segnames + 1) {
+                  obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
+                }
+                assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+              }
+              dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
+              obj.dom_markedup = dom_markedup.dup;
+              dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
+              obj.dom_collapsed = dom_collapsed.dup;
+            }
+          }
+        }
+        /+ optional only one 1~ level +/
+        if (the_endnotes_section["scroll"].length > 1) {
+          dom_markedup_buffer = dom_markedup.dup;
+          dom_collapsed_buffer = dom_collapsed.dup;
+          foreach (ref obj; the_endnotes_section["scroll"]) {
+            if (obj.is_a == "heading") {
+              debug(dom) {
+              }
+              if (obj.heading_lev_markup == 4) {
+                obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
+                if (html_segnames.length > obj.ptr_html_segnames + 1) {
+                  obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
+                }
+                assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+              }
+              dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
+              obj.dom_markedup = dom_markedup.dup;
+              dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
+              obj.dom_collapsed = dom_collapsed.dup;
+            }
+          }
+          dom_markedup = dom_markedup_buffer.dup;
+          dom_collapsed = dom_collapsed_buffer.dup;
+          foreach (ref obj; the_endnotes_section["seg"]) {
+            if (obj.is_a == "heading") {
+              debug(dom) {
+                writeln(obj.text);
+              }
+              if (obj.heading_lev_markup == 4) {
+                obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
+                if (html_segnames.length > obj.ptr_html_segnames + 1) {
+                  obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
+                }
+                assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+              }
+              dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
+              obj.dom_markedup = dom_markedup.dup;
+              dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
+              obj.dom_collapsed = dom_collapsed.dup;
+            }
+          }
+        }
+        /+ optional only one 1~ level +/
+        if (the_glossary_section.length > 1) {
+          foreach (ref obj; the_glossary_section) {
+            if (obj.is_a == "heading") {
+              debug(dom) {
+                writeln(obj.text);
+              }
+              if (obj.heading_lev_markup == 4) {
+                obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
+                if (html_segnames.length > obj.ptr_html_segnames + 1) {
+                  obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
+                }
+                assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+              }
+              dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
+              obj.dom_markedup = dom_markedup.dup;
+              dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
+              obj.dom_collapsed = dom_collapsed.dup;
+            }
+          }
+        }
+        /+ optional only one 1~ level +/
+        if (the_bibliography_section.length > 1) {
+          foreach (ref obj; the_bibliography_section) {
+            if (obj.is_a == "heading") {
+              debug(dom) {
+                writeln(obj.text);
+              }
+              if (obj.heading_lev_markup == 4) {
+                obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
+                if (html_segnames.length > obj.ptr_html_segnames + 1) {
+                  obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
+                }
+                assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+              }
+              dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
+              obj.dom_markedup = dom_markedup.dup;
+              dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
+              obj.dom_collapsed = dom_collapsed.dup;
+            }
+          }
+        }
+        /+ optional only one 1~ level +/
+        if (the_bookindex_section["scroll"].length > 1) {
+          dom_markedup_buffer = dom_markedup.dup;
+          dom_collapsed_buffer = dom_collapsed.dup;
+          foreach (ref obj; the_bookindex_section["scroll"]) {
+            if (obj.is_a == "heading") {
+              debug(dom) {
+              // writeln(obj.text);
+              }
+              if (obj.heading_lev_markup == 4) {
+                obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
+                if (html_segnames.length > obj.ptr_html_segnames + 1) {
+                  obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
+                }
+                assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+              }
+              dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
+              obj.dom_markedup = dom_markedup.dup;
+              dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
+              obj.dom_collapsed = dom_collapsed.dup;
+            }
+          }
+          dom_markedup = dom_markedup_buffer.dup;
+          dom_collapsed = dom_collapsed_buffer.dup;
+          foreach (ref obj; the_bookindex_section["seg"]) {
+            if (obj.is_a == "heading") {
+              debug(dom) {
+                writeln(obj.text);
+              }
+              if (obj.heading_lev_markup == 4) {
+                obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
+                if (html_segnames.length > obj.ptr_html_segnames + 1) {
+                  obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
+                }
+                assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+              }
+              dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
+              obj.dom_markedup = dom_markedup.dup;
+              dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
+              obj.dom_collapsed = dom_collapsed.dup;
+            }
+          }
+        }
+        /+ optional only one 1~ level +/
+        if (the_blurb_section.length > 1) {
+          foreach (ref obj; the_blurb_section) {
+            if (obj.is_a == "heading") {
+              debug(dom) {
+                writeln(obj.text);
+              }
+              if (obj.heading_lev_markup == 4) {
+                obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
+                if (html_segnames.length > obj.ptr_html_segnames + 1) {
+                  obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
+                }
+                assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+              }
+              dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
+              obj.dom_markedup = dom_markedup.dup;
+              dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
+              obj.dom_collapsed = dom_collapsed.dup;
+            }
+          }
+        }
+        dom_markedup = dom_set_markup_tags(dom_markedup, 0);
+        dom_collapsed = dom_set_collapsed_tags(dom_collapsed, 0);
+        comp_obj_heading_                       = comp_obj_heading_.init;
+        comp_obj_heading_.use                   = "empty";
+        comp_obj_heading_.is_of                 = "para";
+        comp_obj_heading_.is_a                  = "heading";
+        // comp_obj_heading_.text                  = "(skip) this is the DOM tail";
+        comp_obj_heading_.ocn                   = 0;
+        comp_obj_para.obj_cite_number           = "";
+        comp_obj_heading_.segment_anchor_tag    = "";
+        comp_obj_heading_.marked_up_level       = "";
+        comp_obj_heading_.heading_lev_markup    = 9;
+        comp_obj_heading_.heading_lev_collapsed = 9;
+        comp_obj_heading_.parent_ocn            = 0;
+        comp_obj_heading_.parent_lev_markup     = 0;
+        comp_obj_heading_.dom_markedup          = dom_markedup.dup;
+        comp_obj_heading_.dom_collapsed         = dom_collapsed.dup;
+        the_dom_tail_section                    ~= comp_obj_heading_;
+      }
       auto document_the = [
         "head":             the_document_head_section,
         "toc_seg":          the_table_of_contents_section["seg"],
@@ -1001,6 +1393,8 @@ template SiSUdocAbstraction() {
         "bookindex_scroll": the_bookindex_section["scroll"],
         "bookindex_seg":    the_bookindex_section["seg"],
         "blurb":            the_blurb_section,
+        /+ dom tail only +/
+        "tail":             the_dom_tail_section,
       ];
       auto t = tuple(
         document_the,
@@ -1430,7 +1824,7 @@ template SiSUdocAbstraction() {
             an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0];
             anchor_tags = substantive_object_and_anchor_tags_tuple[1];
             comp_obj_block                            = comp_obj_block.init;
-            comp_obj_block.use                        = "content";
+            comp_obj_block.use                        = "body";
             comp_obj_block.is_of                      = "block";
             comp_obj_block.is_a                       = "verse";
             comp_obj_block.ocn                        = obj_cite_number;
@@ -1481,7 +1875,7 @@ template SiSUdocAbstraction() {
             an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0];
             anchor_tags = substantive_object_and_anchor_tags_tuple[1];
             comp_obj_block                            = comp_obj_block.init;
-            comp_obj_block.use                        = "content";
+            comp_obj_block.use                        = "body";
             comp_obj_block.is_of                      = "block";
             comp_obj_block.is_a                       = "verse";
             comp_obj_block.ocn                        = obj_cite_number;
@@ -1517,7 +1911,7 @@ template SiSUdocAbstraction() {
             an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0];
             anchor_tags = substantive_object_and_anchor_tags_tuple[1];
             comp_obj_block                            = comp_obj_block.init;
-            comp_obj_block.use                        = "content";
+            comp_obj_block.use                        = "body";
             comp_obj_block.is_of                      = "block";
             comp_obj_block.is_a                       = "verse";
             comp_obj_block.ocn                        = obj_cite_number;
@@ -1568,7 +1962,7 @@ template SiSUdocAbstraction() {
             an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0];
             anchor_tags = substantive_object_and_anchor_tags_tuple[1];
             comp_obj_block                            = comp_obj_block.init;
-            comp_obj_block.use                        = "content";
+            comp_obj_block.use                        = "body";
             comp_obj_block.is_of                      = "block";
             comp_obj_block.is_a                       = "verse";
             comp_obj_block.ocn                        = obj_cite_number;
@@ -1766,7 +2160,7 @@ template SiSUdocAbstraction() {
         an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0];
         anchor_tags = substantive_object_and_anchor_tags_tuple[1];
         comp_obj_code                             = comp_obj_code.init;
-        comp_obj_code.use                         = "content";
+        comp_obj_code.use                         = "body";
         comp_obj_code.is_of                       = "block";
         comp_obj_code.is_a                        = "code";
         comp_obj_code.ocn                         = obj_cite_number;
@@ -1794,7 +2188,7 @@ template SiSUdocAbstraction() {
             an_object["is"]
           );
         comp_obj_poem_ocn                         = comp_obj_poem_ocn.init;
-        comp_obj_poem_ocn.use                     = "content";
+        comp_obj_poem_ocn.use                     = "body";
         comp_obj_poem_ocn.is_of                   = "block";
         comp_obj_poem_ocn.is_a                    = "poem";
         comp_obj_poem_ocn.ocn                     = obj_cite_number;
@@ -1827,7 +2221,7 @@ template SiSUdocAbstraction() {
         an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0];
         anchor_tags = substantive_object_and_anchor_tags_tuple[1];
         comp_obj_block                            = comp_obj_block.init;
-        comp_obj_block.use                        = "content";
+        comp_obj_block.use                        = "body";
         comp_obj_block.is_of                      = "block";
         comp_obj_block.is_a                       = "table";
         comp_obj_block.ocn                        = obj_cite_number;
@@ -1861,7 +2255,7 @@ template SiSUdocAbstraction() {
         an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0];
         anchor_tags = substantive_object_and_anchor_tags_tuple[1];
         comp_obj_block                            = comp_obj_block.init;
-        comp_obj_block.use                        = "content";
+        comp_obj_block.use                        = "body";
         comp_obj_block.is_of                      = "block";
         comp_obj_block.is_a                       = "group";
         comp_obj_block.ocn                        = obj_cite_number;
@@ -1894,7 +2288,7 @@ template SiSUdocAbstraction() {
         an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0];
         anchor_tags = substantive_object_and_anchor_tags_tuple[1];
         comp_obj_block                            = comp_obj_block.init;
-        comp_obj_block.use                        = "content";
+        comp_obj_block.use                        = "body";
         comp_obj_block.is_of                      = "block";
         comp_obj_block.is_a                       = "block";
         comp_obj_block.ocn                        = obj_cite_number;
@@ -1928,7 +2322,7 @@ template SiSUdocAbstraction() {
         an_object["substantive"] = substantive_object_and_anchor_tags_tuple[0];
         anchor_tags = substantive_object_and_anchor_tags_tuple[1];
         comp_obj_block                            = comp_obj_block.init;
-        comp_obj_block.use                        = "content";
+        comp_obj_block.use                        = "body";
         comp_obj_block.is_of                      = "block";
         comp_obj_block.is_a                       = "quote";
         comp_obj_block.ocn                        = obj_cite_number;
@@ -2160,7 +2554,7 @@ template SiSUdocAbstraction() {
             rgx.variable_doc_title, (dochead_meta_aa["title"]["full"] ~ ","));
           an_object[an_object_key]=replaceFirst(an_object[an_object_key],
             rgx.variable_doc_author, dochead_meta_aa["creator"]["author"]);
-          collapsed_lev["h0"] = 1;
+          collapsed_lev["h0"] = 0;
           an_object["lev_collapsed_number"] =
             to!string(collapsed_lev["h0"]);
           lv["lv"] = DocStructMarkupHeading.h_sect_A;
@@ -2655,6 +3049,7 @@ template SiSUdocAbstraction() {
         string[string][string]        dochead_make_aa,
         string                        segment_anchor_tag_that_object_belongs_to,
         string                        _anchor_tag,
+        ref string[][string]          lev4_subtoc,
         ObjGenericComposite[][string] the_table_of_contents_section,
       )
       in { }
@@ -2663,7 +3058,7 @@ template SiSUdocAbstraction() {
         char[] heading_toc_ = to!(char[])(obj_["body_nugget"].dup.strip);
         heading_toc_ = _clean_heading_toc_(heading_toc_);
         auto attrib="";
-        string toc_txt_;
+        string toc_txt_, subtoc_txt_;
         int[string] indent;
         if (to!int(obj_["lev_markup_number"]) > 0) {
           indent=[
@@ -2677,7 +3072,7 @@ template SiSUdocAbstraction() {
           );
           toc_txt_= munge.url_links(toc_txt_);
           comp_obj_toc                       = comp_obj_toc.init;
-          comp_obj_toc.use                   = "content";
+          comp_obj_toc.use                   = "frontmatter";
           comp_obj_toc.is_of                 = "para";
           comp_obj_toc.is_a                  = "toc";
           comp_obj_toc.ocn                   = 0;
@@ -2693,7 +3088,7 @@ template SiSUdocAbstraction() {
             "base_position" : 0,
           ];
           comp_obj_toc                       = comp_obj_toc.init;
-          comp_obj_toc.use                   = "content";
+          comp_obj_toc.use                   = "frontmatter";
           comp_obj_toc.is_of                 = "para";
           comp_obj_toc.is_a                  = "toc";
           comp_obj_toc.ocn                   = 0;
@@ -2705,7 +3100,7 @@ template SiSUdocAbstraction() {
           the_table_of_contents_section["scroll"] ~= comp_obj_toc;
         }
         comp_obj_toc                       = comp_obj_toc.init;
-        comp_obj_toc.use                   = "content";
+        comp_obj_toc.use                   = "frontmatter";
         comp_obj_toc.is_of                 = "para";
         comp_obj_toc.is_a                  = "toc";
         comp_obj_toc.ocn                   = 0;
@@ -2745,6 +3140,7 @@ template SiSUdocAbstraction() {
             heading_toc_,
             segment_anchor_tag_that_object_belongs_to,
           );
+          lev4_subtoc[segment_anchor_tag_that_object_belongs_to] = [];
           toc_txt_= munge.url_links(toc_txt_);
           indent=[
             "hang_position" : to!int(obj_["lev_markup_number"]),
@@ -2762,6 +3158,12 @@ template SiSUdocAbstraction() {
             segment_anchor_tag_that_object_belongs_to,
             _anchor_tag,
           );
+          subtoc_txt_ = format(                         // 5 .. 7
+            "{ %s }#%s",
+            heading_toc_,
+            _anchor_tag,
+          );
+          lev4_subtoc[segment_anchor_tag_that_object_belongs_to] ~= obj_["lev_markup_number"] ~ "~ " ~ to!string(subtoc_txt_).strip;
           toc_txt_= munge.url_links(toc_txt_);
           indent=[
             "hang_position" : to!int(obj_["lev_markup_number"]),
@@ -3300,7 +3702,7 @@ template SiSUdocAbstraction() {
           ++mkn;
         }
       }
-      auto bookindex_build_section(
+      auto bookindex_build_abstraction_section(
         string[][string][string] bookindex_unordered_hashes,
         int                      obj_cite_number,
         string                   segment_anchor_tag_that_object_belongs_to,
@@ -3321,12 +3723,14 @@ template SiSUdocAbstraction() {
         if ((mainkeys.length > 0)
         && (opt_action_bool["backmatter"] && opt_action_bool["section_bookindex"])) {
           string bi_tmp_seg, bi_tmp_scroll;
+          string[] bi_tmp_tags;
           comp_obj_heading_                       = comp_obj_heading_.init;
-          comp_obj_heading_.use                   = "content";
+          comp_obj_heading_.use                   = "backmatter";
           comp_obj_heading_.is_of                 = "para";
           comp_obj_heading_.is_a                  = "heading";
           comp_obj_heading_.text                  = "Book Index";
           comp_obj_heading_.ocn                   = 0;
+          comp_obj_heading_.obj_cite_number       = "";
           comp_obj_heading_.marked_up_level       = "B";
           comp_obj_heading_.heading_lev_markup    = 1;
           comp_obj_heading_.heading_lev_collapsed = 1;
@@ -3337,11 +3741,12 @@ template SiSUdocAbstraction() {
           ++obj_cite_number;
           ++mkn;
           comp_obj_heading_                       = comp_obj_heading_.init;
-          comp_obj_heading_.use                   = "content";
+          comp_obj_heading_.use                   = "backmatter";
           comp_obj_heading_.is_of                 = "para";
           comp_obj_heading_.is_a                  = "heading";
           comp_obj_heading_.text                  = "Index";
           comp_obj_heading_.ocn                   = 0;
+          comp_obj_heading_.obj_cite_number       = "";
           comp_obj_heading_.segment_anchor_tag    = "bookindex";
           comp_obj_heading_.marked_up_level       = "1";
           comp_obj_heading_.heading_lev_markup    = 4;
@@ -3353,8 +3758,14 @@ template SiSUdocAbstraction() {
           bookindex_section["seg"]                ~= comp_obj_heading_;
           ++obj_cite_number;
           ++mkn;
+          import std.array : appender;
+          auto buffer = appender!(char[])();
+          string[dchar] transTable = [' ' : "_"];
           foreach (mainkey; mainkeys) {
+            bi_tmp_tags = [""];
             bi_tmp_scroll = "!{" ~ mainkey ~ "}! ";
+            buffer.clear();
+            bi_tmp_tags ~= translate(mainkey, transTable);
             bi_tmp_seg = "!{" ~ mainkey ~ "}! ";
             foreach (ref_; bookindex_unordered_hashes[mainkey]["_a"]) {
               auto go = replaceAll(ref_, rgx.book_index_go, "$1");
@@ -3370,6 +3781,8 @@ template SiSUdocAbstraction() {
               bookindex_unordered_hashes[mainkey].byKey.array.sort().release;
             foreach (subkey; subkeys) {
               bi_tmp_scroll ~= subkey ~ ", ";
+              buffer.clear();
+              bi_tmp_tags ~= translate(subkey, transTable);
               bi_tmp_seg ~= subkey ~ ", ";
               foreach (ref_; bookindex_unordered_hashes[mainkey][subkey]) {
                 auto go = replaceAll(ref_, rgx.book_index_go, "$1");
@@ -3385,12 +3798,13 @@ template SiSUdocAbstraction() {
             bi_tmp_scroll = replaceFirst(bi_tmp_scroll, rgx.trailing_linebreak, "");
             bi_tmp_seg = replaceFirst(bi_tmp_seg, rgx.trailing_linebreak, "");
             comp_obj_para                       = comp_obj_para.init;
-            comp_obj_para.use                   = "content";
+            comp_obj_para.use                   = "backmatter";
             comp_obj_para.is_of                 = "para";
             comp_obj_para.is_a                  = "bookindex";
             comp_obj_para.text                  = to!string(bi_tmp_scroll).strip;
             comp_obj_para.ocn                   = obj_cite_number;
             comp_obj_para.obj_cite_number       = (obj_cite_number==0) ? "" : to!string(obj_cite_number);
+            comp_obj_para.anchor_tags           = bi_tmp_tags;
             comp_obj_para.indent_hang           = 0;
             comp_obj_para.indent_base           = 1;
             comp_obj_para.bullet                = false;
@@ -3404,6 +3818,7 @@ template SiSUdocAbstraction() {
           comp_obj_heading_                       = comp_obj_heading_.init;
           comp_obj_heading_.text                  = "(skip) there is no Book Index";
           comp_obj_heading_.ocn                   = 0;
+          comp_obj_heading_.obj_cite_number       = "";
           comp_obj_heading_.marked_up_level       = "B";
           comp_obj_heading_.heading_lev_markup    = 1;
           comp_obj_heading_.heading_lev_collapsed = 1;
@@ -3508,11 +3923,12 @@ template SiSUdocAbstraction() {
         if ((endnotes_["seg"].length > 0)
         && (opt_action_bool["backmatter"] && opt_action_bool["section_endnotes"])) {
           comp_obj_heading_                       = comp_obj_heading_.init;
-          comp_obj_heading_.use                   = "content";
+          comp_obj_heading_.use                   = "backmatter";
           comp_obj_heading_.is_of                 = "para";
           comp_obj_heading_.is_a                  = "heading";
           comp_obj_heading_.text                  = "Endnotes";
           comp_obj_heading_.ocn                   = 0;
+          comp_obj_heading_.obj_cite_number       = "";
           comp_obj_heading_.marked_up_level       = "B";
           comp_obj_heading_.heading_lev_markup    = 1;
           comp_obj_heading_.heading_lev_collapsed = 1;
@@ -3523,11 +3939,12 @@ template SiSUdocAbstraction() {
           ++obj_cite_number;
           ++mkn;
           comp_obj_heading_                       = comp_obj_heading_.init;
-          comp_obj_heading_.use                   = "content";
+          comp_obj_heading_.use                   = "backmatter";
           comp_obj_heading_.is_of                 = "para";
           comp_obj_heading_.is_a                  = "heading";
           comp_obj_heading_.text                  = "Endnotes";
           comp_obj_heading_.ocn                   = 0;
+          comp_obj_heading_.obj_cite_number       = "";
           comp_obj_heading_.segment_anchor_tag    = "endnotes";
           comp_obj_heading_.marked_up_level       = "1";
           comp_obj_heading_.heading_lev_markup    = 4;
@@ -3541,11 +3958,12 @@ template SiSUdocAbstraction() {
           ++mkn;
         } else {
           comp_obj_heading_                       = comp_obj_heading_.init;
-          comp_obj_heading_.use                   = "content";
+          comp_obj_heading_.use                   = "empty";
           comp_obj_heading_.is_of                 = "para";
           comp_obj_heading_.is_a                  = "heading";
           comp_obj_heading_.text                  = "(skip) there are no Endnotes";
           comp_obj_heading_.ocn                   = 0;
+          comp_obj_heading_.obj_cite_number       = "";
           comp_obj_heading_.marked_up_level       = "B";
           comp_obj_heading_.heading_lev_markup    = 1;
           comp_obj_heading_.heading_lev_collapsed = 1;
@@ -3557,7 +3975,7 @@ template SiSUdocAbstraction() {
         if (opt_action_bool["backmatter"] && opt_action_bool["section_endnotes"]) {
           ObjGenericComposite comp_obj_endnote_;
           comp_obj_endnote_                       = comp_obj_endnote_.init;
-          comp_obj_endnote_.use                   = "content";
+          comp_obj_endnote_.use                   = "backmatter";
           comp_obj_endnote_.is_of                 = "para";
           comp_obj_endnote_.is_a                  = "endnote";
           comp_obj_endnote_.ocn                   = 0;
@@ -3834,7 +4252,7 @@ template SiSUdocAbstraction() {
         }
         ObjGenericComposite _comp_obj_heading_;
         _comp_obj_heading_                       = _comp_obj_heading_.init;
-        _comp_obj_heading_.use                   = "content";
+        _comp_obj_heading_.use                   = "body";
         _comp_obj_heading_.is_of                 = "para";
         _comp_obj_heading_.is_a                  = "heading";
         _comp_obj_heading_.text                  = to!string(_text).strip;
diff --git a/src/sdp/ao_object_setter.d b/src/sdp/ao_object_setter.d
index 13bcc36..1f10b66 100644
--- a/src/sdp/ao_object_setter.d
+++ b/src/sdp/ao_object_setter.d
@@ -31,6 +31,8 @@ template ObjectSetter() {
     string                 syntax                       = "";
     int                    ocn                          = 0;
     string                 segment_anchor_tag           = "";
+    string                 segname_prev                 = "";
+    string                 segname_next                 = "";
     int                    parent_lev_markup            = 0;
     int                    parent_ocn                   = 0;
     int[]                  ancestors                    = [];
@@ -44,7 +46,10 @@ template ObjectSetter() {
     int                    ptr_heading                  = 0;
     int                    array_ptr                    = 0;
     int                    heading_array_ptr_segments   = 0;
+    string[]               lev4_subtoc                  = [];
     string[string][string] node;
+    int[]                  dom_markedup                          = [ 0, 0, 0, 0, 0, 0, 0, 0,];
+    int[]                  dom_collapsed                         = [ 0, 0, 0, 0, 0, 0, 0, 0,];
   }
   struct TheObjects {
     ObjGenericComposite[] oca;
diff --git a/src/sdp/ao_output_debugs.d b/src/sdp/ao_output_debugs.d
index e4eaccb..35e250c 100644
--- a/src/sdp/ao_output_debugs.d
+++ b/src/sdp/ao_output_debugs.d
@@ -26,7 +26,7 @@ template SiSUoutputDebugs() {
         );
         foreach (key; document_section_keys_sequenced["seg"]) {
           foreach (obj; contents[key]) {
-            if (obj.use == "content") {
+            if (obj.use != "empty") {
               if (obj.is_a == "heading") {
                 writefln(
                   "%s node: %s heading: %s %s",
@@ -48,7 +48,7 @@ template SiSUoutputDebugs() {
           __LINE__,
         );
         foreach (obj; contents) {
-          if (obj.use == "content") {
+          if (obj.use != "empty") {
             writefln(
               "[%s][%s]\n%s",
               obj.obj_cite_number,
@@ -58,6 +58,21 @@ template SiSUoutputDebugs() {
           }
         }
       }
+      void out_segnames(S)(
+        auto ref const S         contents,
+        string[]                 keys,
+        string[]                 html_segnames,
+      ) {
+        foreach (key; keys) {
+          if (contents[key].length > 1) {
+            foreach (obj; contents[key]) {
+              if (obj.heading_lev_markup == 4) {
+                writeln(obj.ptr_html_segnames, ". (", html_segnames[obj.ptr_html_segnames], ") -> ",  obj.text);
+              }
+            }
+          }
+        }
+      }
       void out_toc(S)(
         auto ref const S         contents,
         string                   key,
@@ -128,6 +143,28 @@ template SiSUoutputDebugs() {
         key="toc_scroll";
         out_toc(contents, key);
       }
+      debug(segnames) {
+        key="toc_scroll";
+        writeln(__LINE__);
+        string[] keys;
+        keys ~= [ "toc_seg", "body" ];
+        if (contents["endnotes_seg"].length > 1) {
+          keys ~= "endnotes_seg";
+        }
+        if (contents["glossary"].length > 1) {
+          keys ~= "glossary";
+        }
+        if (contents["bibliography"].length > 1) {
+          keys ~= "bibliography";
+        }
+        if (contents["bookindex_seg"].length > 1) {
+          keys ~= "bookindex_seg";
+        }
+        if (contents["blurb"].length > 1) {
+          keys ~= "blurb";
+        }
+        out_segnames(contents, keys, html_segnames);
+      }
       debug(section_body) {
         key="body";
         if (contents[key].length > 1) {
@@ -141,6 +178,54 @@ template SiSUoutputDebugs() {
           }
         }
       }
+      debug(dom) {
+        enum DomTags { none, open, close, close_and_open, open_still, }
+        foreach (sect; document_section_keys_sequenced["seg"]) {
+          foreach (obj; contents[sect]) {
+            if (obj.is_a == "heading") {
+              foreach_reverse (k; 0 .. 7) {
+                switch (obj.dom_markedup[k]) {
+                case DomTags.close :
+                  writeln(markup.indent_by_spaces_provided(k), "</", k, ">");
+                  break;
+                case DomTags.close_and_open :
+                  writeln(markup.indent_by_spaces_provided(k), "</", k, ">");
+                  writeln(markup.indent_by_spaces_provided(k), "<", k, ">", obj.text);
+                  break;
+                case DomTags.open :
+                  writeln(markup.indent_by_spaces_provided(k), "<", k, ">", obj.text);
+                  break;
+                default :
+                  break;
+                }
+              }
+            }
+          }
+        }
+        writeln("--------------------");
+        foreach (sect; document_section_keys_sequenced["seg"]) {
+          foreach (obj; contents[sect]) {
+            if (obj.is_a == "heading") {
+              foreach_reverse (k; 0 .. 7) {
+                switch (obj.dom_collapsed[k]) {
+                case DomTags.close :
+                  writeln(markup.indent_by_spaces_provided(k), "</", k, ">");
+                  break;
+                case DomTags.close_and_open :
+                  writeln(markup.indent_by_spaces_provided(k), "</", k, ">");
+                  writeln(markup.indent_by_spaces_provided(k), "<", k, ">", obj.text);
+                  break;
+                case DomTags.open :
+                  writeln(markup.indent_by_spaces_provided(k), "<", k, ">", obj.text);
+                  break;
+                default :
+                  break;
+                }
+              }
+            }
+          }
+        }
+      }
       debug(section_endnotes) {
         key="endnotes_seg";
         out_endnotes(contents, key);
@@ -212,7 +297,7 @@ template SiSUoutputDebugs() {
           __LINE__,
         );
         foreach (obj; contents) {
-          if (obj.use == "content") {
+          if (obj.use != "empty") {
             writefln(
               "* [%s][%s] %s",
               obj.obj_cite_number,
@@ -435,7 +520,7 @@ template SiSUoutputDebugs() {
         debug(checkdoc) {
           foreach (k; document_section_keys_sequenced["seg"]) {
             foreach (obj; contents[k]) {
-              if (obj.use == "content") {
+              if (obj.use != "empty") {
                 if (!empty(obj.obj_cite_number)) {
                   check["last_obj_cite_number"] = obj.obj_cite_number;
                 }
diff --git a/src/sdp/ao_rgx.d b/src/sdp/ao_rgx.d
index aa4cd58..6534cdd 100644
--- a/src/sdp/ao_rgx.d
+++ b/src/sdp/ao_rgx.d
@@ -96,7 +96,7 @@ template RgxInit() {
     static block_tic_close                                = ctRegex!("^(`{3})$","m");
     /+ blocked markup curly +/
     static block_curly_open                               = ctRegex!(`^((code([.][a-z][0-9a-z_]+)?|poem|group|block|quote|table)[{].*?$)`);
-    static block_curly_code_open                          = ctRegex!(`^(code([.][a-z][0-9a-z_]+)?[{].*?$)`);
+    static block_curly_code_open                          = ctRegex!(`^(code([.][a-z][0-9a-z_]+)?[{](.*?)$)`);
     static block_curly_code_close                         = ctRegex!(`^([}]code)`);
     static block_curly_poem_open                          = ctRegex!(`^(poem[{].*?$)`);
     static block_curly_poem_close                         = ctRegex!(`^([}]poem)`);
diff --git a/src/sdp/output_html.d b/src/sdp/output_html.d
index 5cd1b26..0390799 100644
--- a/src/sdp/output_html.d
+++ b/src/sdp/output_html.d
@@ -16,23 +16,38 @@ template SiSUoutputHTML() {
     ) {
       auto tags = _html_anchor_tags(obj.anchor_tags);
       string o;
-      o = format(q"¶<br><hr /><br>
+      if (obj.obj_cite_number.empty) {
+        o = format(q"¶<br><hr /><br>
+      <div class="substance">
+        <h%s class="%s">%s
+          %s
+        </h%s>
+      </div>¶",
+          obj.heading_lev_markup,
+          obj.is_a,
+          tags,
+          obj.text,
+          obj.heading_lev_markup,
+        );
+      } else {
+        o = format(q"¶<br><hr /><br>
       <div class="substance">
         <label class="ocn"><a href="#%s" class="lnkocn">%s</a></label>
         <h%s class="%s" id="%s"><a name="%s"></a>%s
           %s
         </h%s>
       </div>¶",
-      obj.obj_cite_number,
-      obj.obj_cite_number,
-      obj.heading_lev_markup,
-      obj.is_a,
-      obj.obj_cite_number,
-      obj.obj_cite_number,
-      tags,
-      obj.text,
-      obj.heading_lev_markup,
-      );
+        obj.obj_cite_number,
+        obj.obj_cite_number,
+        obj.heading_lev_markup,
+        obj.is_a,
+        obj.obj_cite_number,
+        obj.obj_cite_number,
+        tags,
+        obj.text,
+        obj.heading_lev_markup,
+        );
+      }
       return o;
     }
     auto html_para(O)(
@@ -42,13 +57,10 @@ template SiSUoutputHTML() {
       string o;
       if (obj.obj_cite_number.empty) {
         o = format(q"¶  <div class="substance">
-      <label class="ocn"><a href="#%s" class="lnkocn">%s</a></label>
       <p class="%s" indent="h%si%s">%s
         %s
       </p>
     </div>¶",
-          obj.obj_cite_number,
-          obj.obj_cite_number,
           obj.is_a,
           obj.indent_hang,
           obj.indent_base,
@@ -78,18 +90,29 @@ template SiSUoutputHTML() {
       auto ref const O         obj,
     ) {
       string o;
-      o = format(q"¶  <div class="substance">
+      if (obj.obj_cite_number.empty) {
+        o = format(q"¶  <div class="substance">
+      <p class="%s">
+        %s
+      </p>
+    </div>¶",
+          obj.is_a,
+          obj.text
+        );
+      } else {
+        o = format(q"¶  <div class="substance">
       <label class="ocn"><a href="#%s" class="lnkocn">%s</a></label>
       <p class="%s" id="%s">
         %s
       </p>
     </div>¶",
-      obj.obj_cite_number,
-      obj.obj_cite_number,
-      obj.is_a,
-      obj.obj_cite_number,
-      obj.text
-      );
+          obj.obj_cite_number,
+          obj.obj_cite_number,
+          obj.is_a,
+          obj.obj_cite_number,
+          obj.text
+        );
+      }
       return o;
     }
     auto scroll_head_html() {
@@ -99,7 +122,7 @@ template SiSUoutputHTML() {
     <head>
       <meta charset="utf-8">
       <title>
-        Title
+        %s%s
       </title>
     <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
       <meta name="dc.title" content="Title" />
@@ -120,7 +143,10 @@ template SiSUoutputHTML() {
       <link href="../../../_sisu/css/html.css" rel="stylesheet">
     </head>
     <body lang="en">
-    <a name="top" id="top"></a>¶");
+    <a name="top" id="top"></a>¶",
+    dochead_meta["title"]["full"],
+    (dochead_meta["creator"]["author"].empty) ? "" : ", " ~ dochead_meta["creator"]["author"],
+    );
       return o;
     }
     auto html_toc(O)(
@@ -175,7 +201,7 @@ template SiSUoutputHTML() {
       string[] doc;
       foreach (part; document_section_keys_sequenced["scroll"]) {
         foreach (obj; contents[part]) {
-          if (obj.use == "content") {
+          if (obj.use == "frontmatter") {
             switch (obj.is_of) {
             case "para":
               switch (obj.is_a) {
@@ -185,22 +211,23 @@ template SiSUoutputHTML() {
               case "toc":
                 body_html ~= html_toc(obj);
                 break;
-              case "para":
-                body_html ~= html_para(obj);
-                break;
-              case "endnote":
-                body_html ~= html_endnote(obj);
-                break;
-              case "glossary":
-                body_html ~= html_para(obj);
-                break;
-              case "bibliography":
-                body_html ~= html_para(obj);
+              default:
+                writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
                 break;
-              case "bookindex":
-                body_html ~= html_para(obj);
+              }
+              break;
+            default:
+              writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
+              break;
+            }
+          } else if (obj.use == "body") {
+            switch (obj.is_of) {
+            case "para":
+              switch (obj.is_a) {
+              case "heading":
+                body_html ~= html_heading(obj);
                 break;
-              case "blurb":
+              case "para":
                 body_html ~= html_para(obj);
                 break;
               default:
@@ -239,6 +266,37 @@ template SiSUoutputHTML() {
               writeln(__FILE__, ":", __LINE__, ": ", obj.is_of);
               break;
             }
+          } else if (obj.use == "backmatter") {
+            switch (obj.is_of) {
+            case "para":
+              switch (obj.is_a) {
+              case "heading":
+                body_html ~= html_heading(obj);
+                break;
+              case "endnote":
+                body_html ~= html_endnote(obj);
+                break;
+              case "glossary":
+                body_html ~= html_para(obj);
+                break;
+              case "bibliography":
+                body_html ~= html_para(obj);
+                break;
+              case "bookindex":
+                body_html ~= html_para(obj);
+                break;
+              case "blurb":
+                body_html ~= html_para(obj);
+                break;
+              default:
+                writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
+                break;
+              }
+              break;
+            default:
+              writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
+              break;
+            }
           }
         }
       }
diff --git a/views/version.txt b/views/version.txt
index 7ba3377..9c3ba7c 100644
--- a/views/version.txt
+++ b/views/version.txt
@@ -4,4 +4,4 @@ struct Version {
   int minor;
   int patch;
 }
-enum ver = Version(0, 10, 0);
+enum ver = Version(0, 10, 1);
-- 
cgit v1.2.3