diff --git a/src/hover.cpp b/src/hover.cpp
index 77044d1..ae2ecf5 100644
--- a/src/hover.cpp
+++ b/src/hover.cpp
@@ -307,7 +307,7 @@ struct Sec_Hover_Fn {
   // An unspecified range of bytes
   void range(const char *desc, u64 range_len, Display_Range_Fn display_val = hover_display_generic_range)
   {
-    if (cur_field_off + range_len > section.range.end())
+    if (range_len == 0 || cur_field_off + range_len > section.range.end())
       return;
     String8_Node *dsc = display_val(arena, info.desc, desc, data + cur_field_off, range_len);
     b8 hovered = cur_field_off <= off && off < cur_field_off + range_len;
@@ -340,11 +340,9 @@ struct Sec_Hover_Fn {
     return was_zipped;
   }
 
-  // Returns the key len
-  u16 tkey(const char *title = "TKey")
+  void tkey(const char *title = "TKey")
   {
-    u16 keylen = 0;
-    titled_section(title, [this, &keylen] {
+    titled_section(title, [this] {
       u16 version_be;
       if (!read(&version_be, cur_field_off + 4))
         return;
@@ -363,7 +361,7 @@ struct Sec_Hover_Fn {
       });
       field_be<u32>("Obj Len: %u");
       field<u32>("Datetime: ", hover_display_datetime_str);
-      field_be<u16>("Key Len: %u", &keylen);
+      field_be<u16>("Key Len: %u");
       field_be<u16>("Cycle: %u");
       if (is_big) {
         field_be<u64>("Seek Key: 0x%" PRIX64);
@@ -376,8 +374,6 @@ struct Sec_Hover_Fn {
       field_str8<u8>("Obj Name: %s");
       field_str8<u8>("Obj Title: %s");
     }, HoverSec_HideIfNotHovered);
-
-    return keylen;
   }
 
   void envelope_preamble()
@@ -1072,6 +1068,9 @@ struct Sec_Hover_Fn {
     String8 name = class_name->size ? *class_name : str8("(Unknown)");
     titled_section(name.c(), [this] {
       tkey();
+      // Not sure what this is, but sometimes we get extra bytes from the end of the key
+      // to the start of the actual payload.
+      range("???", section.range.start - cur_field_off);
       range("Payload", section.range.len - section.post_size); 
     });
   }
diff --git a/src/render.cpp b/src/render.cpp
index ae06f45..9cb6e8a 100644
--- a/src/render.cpp
+++ b/src/render.cpp
@@ -137,10 +137,30 @@ MemoryEditor make_memory_editor(App_State &app, i32 n_cols)
 }
 
 internal
-void init_viewer(App_State &app, u16 n_cols)
+void init_viewer(Arena *arena, App_State &app, u16 n_cols)
 {
   Viewer &viewer = app.viewer;
   viewer.mem_edit = make_memory_editor(app, (i32)n_cols);
+  
+  // Init title
+  if (app.tfile_data.sections[Sec_RNTuple_Anchor].head) {
+    Temp scratch = scratch_begin(&arena, 1);
+    defer { scratch_end(scratch); };
+
+    const ROOT::RNTuple &anchor = *(const ROOT::RNTuple *)app.tfile_data.sections[Sec_RNTuple_Anchor].head->info;
+    String8 ntpl_desc = rntuple_description(scratch.arena, anchor);
+    if (rntuple_is_old_version(anchor)) {
+      viewer.col_title[0] = 1.f;
+      viewer.title = push_str8f(arena, "\"%s\" (%s) from file \"%s\" ** old version, some data missing! **", 
+                                app.ntpl_name.c(), ntpl_desc.c(), app.inspected_file.name.c());
+    } else {
+      viewer.col_title[0] = viewer.col_title[1] = viewer.col_title[2] = 1.f;
+      viewer.title = push_str8f(arena, "\"%s\" (%s) from file \"%s\"", app.ntpl_name.c(), ntpl_desc.c(), app.inspected_file.name.c());
+    }
+  } else {
+    viewer.col_title[0] = viewer.col_title[1] = viewer.col_title[2] = 1.f;
+    viewer.title = push_str8f(arena, "(no RNTuple) from file \"%s\"", app.inspected_file.name.c());
+  }
 
 #define COL(c, r, g, b) viewer.c[0] = r/255.0, viewer.c[1] = g/255.0, viewer.c[2] = b/255.0
   COL(col_key,    0, 100, 50);
@@ -251,7 +271,7 @@ void viewer_jump_to_page_list(App_State &app, u64 page_list_idx)
 }
 
 internal
-void viewer_jump_to_section(App_State &app, Section_Id id, u64 sec_idx)
+void viewer_jump_to_section(App_State &app, Section_Id id, u64 &sec_idx)
 {
   // special cases
   if (id == Sec_Page_List) {
@@ -314,17 +334,14 @@ void update_and_render(Arena *arena, App_State &app, f32 delta_time_ms)
   Temp scratch = scratch_begin(&arena, 1);
   defer { scratch_end(scratch); };
 
+  printf("-----------------------\n");
+
   const auto main_win_flags = ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoDecoration;
   if (ImGui::Begin("main", nullptr, main_win_flags)) {
         
-    // FIXME :multiple_anchors:
-    const ROOT::RNTuple &anchor = *(const ROOT::RNTuple *)app.tfile_data.sections[Sec_RNTuple_Anchor].head->info;
-    String8 ntpl_desc = rntuple_description(scratch.arena, anchor);
-    if (rntuple_is_old_version(anchor)) {
-      ImGui::TextColored(ImColor(1.f, 0.f, 0.f), "\"%s\" (%s) from file \"%s\" ** old version, some data missing! **", 
-                         app.ntpl_name.c(), ntpl_desc.c(), app.inspected_file.name.c());
-    } else {
-      ImGui::Text("\"%s\" (%s) from file \"%s\"", app.ntpl_name.c(), ntpl_desc.c(), app.inspected_file.name.c());
+    {
+      f32 *c = app.viewer.col_title;
+      ImGui::TextColored(ImColor(c[0], c[1], c[2]), "%s", app.viewer.title.c());
     }
 
     // Draw stats
@@ -397,19 +414,24 @@ void update_and_render(Arena *arena, App_State &app, f32 delta_time_ms)
         if (ImGui::Button(sec_name.c()))
           viewer_jump_to_section(app, static_cast<Section_Id>(i), app.viewer.latest_section_gone_to[i]);
         ImGui::SameLine(); 
-        ImGui::Text("%s", to_pretty_size(scratch.arena, app.tfile_data.sections[i].tot_size).c());
 
+        ImGui::Text("%s", to_pretty_size(scratch.arena, app.tfile_data.sections[i].tot_size).c());
         if (app.tfile_data.sections[i].count > 1) {
+        // } else {
+        //   ImGui::Text("%s (%u)", to_pretty_size(scratch.arena, app.tfile_data.sections[i].tot_size).c(), app.tfile_data.sections[i].count);
           ImGui::SameLine(); 
           i64 sec_to_go_to = app.viewer.latest_section_gone_to[i];
-          ImGui::PushItemWidth(80.f);
+          ImGui::PushItemWidth(120.f);
           if (ImGui::InputScalar(push_str8f(scratch.arena, "##%s_viewed", sec_name.c()).c(), ImGuiDataType_S64,
                                  &sec_to_go_to, &step_i64, nullptr, "%u") 
               && ImGui::IsItemDeactivatedAfterEdit())
           {
-            viewer_jump_to_section(app, static_cast<Section_Id>(i), sec_to_go_to);
+            app.viewer.latest_section_gone_to[i] = sec_to_go_to;
+            viewer_jump_to_section(app, static_cast<Section_Id>(i), app.viewer.latest_section_gone_to[i]);
           }
           ImGui::PopItemWidth();
+          ImGui::SameLine();
+          ImGui::Text(" / %u", app.tfile_data.sections[i].count);
         }
       }
 
@@ -494,7 +516,7 @@ void update_and_render(Arena *arena, App_State &app, f32 delta_time_ms)
         ImGui::TextColored(ImColor(0.f, 0.65f, 0.f), "Offset: 0x%" PRIX64, hovered_off - 1);
         Section hovered_section = find_section(app, hovered_off - 1);
         b8 hover_display_grouped = !(app.user_input.key_state[KEY_ALT] & KEY_STATE_IS_DOWN);
-        b8 old_version = rntuple_is_old_version(anchor);
+        b8 old_version = hovered_section.from_old_version_rntuple;
         Sec_Hover_Info hover_info = get_section_hover_info(scratch.arena, hovered_section, hovered_off - 1, 
                                                            app.inspected_file.mem, hover_display_grouped, old_version);
         ImGui::TextColored(ImColor(0.5f, 0.5f, 0.5f), "(Hint: hold Alt for single-field hover information)");
diff --git a/src/render.h b/src/render.h
index f29a4df..a1d05b9 100644
--- a/src/render.h
+++ b/src/render.h
@@ -10,6 +10,9 @@ struct Viewer {
 #ifndef RNT_NO_GFX
   MemoryEditor mem_edit;
 
+  String8 title;
+  f32 col_title[3];
+
   b8  highlight_cluster;
   u64 highlighted_cluster;
 
diff --git a/src/rntuple.cpp b/src/rntuple.cpp
index 4cfe89f..dd674fe 100644
--- a/src/rntuple.cpp
+++ b/src/rntuple.cpp
@@ -19,12 +19,6 @@ void compute_tot_sections_size(Sections *sections)
   }
 }
 
-internal
-b8 rntuple_is_old_version(const ROOT::RNTuple &ntuple)
-{
-  return ntuple.GetVersionEpoch() == 0 && ntuple.GetVersionMajor() < 3;
-}
-  
 internal
 String8 rntuple_description(Arena *arena, const ROOT::RNTuple &ntuple)
 {
@@ -491,7 +485,7 @@ Section find_section(App_State &app, u64 off, i64 hilite_cluster = -1)
 
   Section sec {};
 
-  for (u32 i = 1; i < Sec_COUNT; ++i) {   
+  for (u32 i = 1; i < Sec_COUNT_Regular; ++i) {   
     for (Section *sec = app.tfile_data.sections[i].head; sec; sec = sec->next) {
       if (sec->range.start - sec->pre_size <= off && off < sec->range.end()) {
         return *sec;
@@ -499,90 +493,104 @@ Section find_section(App_State &app, u64 off, i64 hilite_cluster = -1)
     }
   }
 
-  u64 rblob_sz = app.tfile_data.sections[Sec_Page].head->pre_size;
+  // Page / PageList lookup.
+  // If we don't have a Sec_Page section it means we don't have any RNTuple, so skip it.
+  if (app.tfile_data.sections[Sec_Page].head) {
+    u64 rblob_sz = app.tfile_data.sections[Sec_Page].head->pre_size;
 
-  /// Page fast lookup (relative to app.last_pinfo)
-  {
-    // fast case: `off` is in the same page info as previous `off`.
-    for (i32 i = 0; i < 2; ++i) {
-      u64 pre_size = app.last_pinfo->is_first_in_cluster ? rblob_sz : 0;
-      if (app.last_pinfo->range.start - pre_size < off && off < app.last_pinfo->range.end()) {
+    /// Page fast lookup (relative to app.last_pinfo)
+    {
+      // fast case: `off` is in the same page info as previous `off`.
+      for (i32 i = 0; i < 2; ++i) {
+        u64 pre_size = app.last_pinfo->is_first_in_cluster ? rblob_sz : 0;
+        if (app.last_pinfo->range.start - pre_size <= off && off < app.last_pinfo->range.end()) {
+          sec.id = Sec_Page;
+          sec.range = app.last_pinfo->range;
+          sec.pre_size = pre_size;
+          sec.post_size = app.last_pinfo->checksum_size();
+          sec.highlighted = hilite_cluster >= 0 && app.last_pinfo->cluster_id == (u64)hilite_cluster;
+          sec.info = app.last_pinfo;
+          return sec;
+        }
+
+        // Try another common and still fast case: `off is in the next page info as the previous.
+        if (app.last_pinfo->next) // don't check if it's checksum, since it's the first byte of the page
+          app.last_pinfo = app.last_pinfo->next;
+        else
+          break;
+      }
+    }
+  
+    // Check if we're in a page list
+    // @Speed: linear search through all cluster groups
+    for (u64 cg_idx = 0; cg_idx < rdata.n_cluster_groups; ++cg_idx) {
+      Cluster_Group_Info &cg_info = rdata.cluster_groups[cg_idx];
+      if (cg_info.rng_page_list.start - rblob_sz <= off && off < cg_info.rng_page_list.end()) {
+        sec.id = Sec_Page_List;
+        sec.range = cg_info.rng_page_list;
+        sec.pre_size = rblob_sz;
+        sec.post_size = 8;
+        return sec;
+      }
+    }
+
+    // Slow page group lookup, ideally only done once per render when last_pinfo is invalid.
+    for (Page_Info_Chunk *chunk = rdata.page_chunks; chunk; chunk = chunk->next) {
+      // If we're at the start of a chunk, return a fake Sec_Page used to highlight the RBlob header bytes. 
+      if (chunk->range.start - rblob_sz <= off && off < chunk->range.start) {
         sec.id = Sec_Page;
-        sec.range = app.last_pinfo->range;
-        sec.pre_size = pre_size;
-        sec.post_size = app.last_pinfo->checksum_size();
-        sec.highlighted = hilite_cluster >= 0 && app.last_pinfo->cluster_id == (u64)hilite_cluster;
-        sec.info = app.last_pinfo;
+        sec.range = { chunk->range.start, 0 };
+        sec.pre_size = rblob_sz;
         return sec;
       }
 
-      // Try another common and still fast case: `off is in the next page info as the previous.
-      if (app.last_pinfo->next) // don't check if it's checksum, since it's the first byte of the page
-        app.last_pinfo = app.last_pinfo->next;
-      else
-        break;
-    }
-  }
-  
-  // Check if we're in a page list
-  // @Speed: linear search through all cluster groups
-  for (u64 cg_idx = 0; cg_idx < rdata.n_cluster_groups; ++cg_idx) {
-    Cluster_Group_Info &cg_info = rdata.cluster_groups[cg_idx];
-    if (cg_info.rng_page_list.start - rblob_sz <= off && off < cg_info.rng_page_list.end()) {
-      sec.id = Sec_Page_List;
-      sec.range = cg_info.rng_page_list;
-      sec.pre_size = rblob_sz;
-      sec.post_size = 8;
-      return sec;
-    }
-  }
+      if (chunk->range.start <= off && off < chunk->range.end()) {
+        for (u64 group_idx = chunk->first_group; group_idx < rdata.n_page_groups; ++group_idx) {
+          const Page_Info_Group &group = rdata.page_groups[group_idx];
+          if (off < group.range.start || off >= group.range.end())
+            continue;
 
-  // Slow page group lookup, ideally only done once per render when last_pinfo is invalid.
-  for (Page_Info_Chunk *chunk = rdata.page_chunks; chunk; chunk = chunk->next) {
-    // If we're at the start of a chunk, return a fake Sec_Page used to highlight the RBlob header bytes. 
-    if (chunk->range.start - rblob_sz <= off && off < chunk->range.start) {
-      sec.id = Sec_Page;
-      sec.range = { chunk->range.start, 0 };
-      sec.pre_size = rblob_sz;
-      return sec;
-    }
-
-    if (chunk->range.start <= off && off < chunk->range.end()) {
-      for (u64 group_idx = chunk->first_group; group_idx < rdata.n_page_groups; ++group_idx) {
-        const Page_Info_Group &group = rdata.page_groups[group_idx];
-        if (off < group.range.start || off >= group.range.end())
-          continue;
-
-        for (Page_Info_Node *pinfo = group.first; pinfo; pinfo = pinfo->next) {
-          u64 pre_size = pinfo->is_first_in_cluster ? rblob_sz : 0;
-          if (pinfo->range.start - pre_size <= off && off < pinfo->range.end()) {
-            app.last_pinfo = pinfo;
-            sec.id = Sec_Page;
-            sec.range = pinfo->range;
-            sec.pre_size = pre_size;
-            sec.post_size = pinfo->checksum_size();
-            sec.highlighted = hilite_cluster >= 0 && pinfo->cluster_id == (u64)hilite_cluster;
-            sec.info = pinfo;
-            return sec;
+          for (Page_Info_Node *pinfo = group.first; pinfo; pinfo = pinfo->next) {
+            u64 pre_size = pinfo->is_first_in_cluster ? rblob_sz : 0;
+            if (pinfo->range.start - pre_size <= off && off < pinfo->range.end()) {
+              app.last_pinfo = pinfo;
+              sec.id = Sec_Page;
+              sec.range = pinfo->range;
+              sec.pre_size = pre_size;
+              sec.post_size = pinfo->checksum_size();
+              sec.highlighted = hilite_cluster >= 0 && pinfo->cluster_id == (u64)hilite_cluster;
+              sec.info = pinfo;
+              return sec;
+            }
           }
         }
-      }
 
-      fprintf(stderr, "Offset 0x%" PRIX64 " is in chunk 0x%" PRIX64 " - 0x%" PRIX64 ", but found in no page_info range!\n", 
-              off, chunk->range.start, chunk->range.end());
-      assert(false);
+        fprintf(stderr, "Offset 0x%" PRIX64 " is in chunk 0x%" PRIX64 " - 0x%" PRIX64 ", but found in no page_info range!\n", 
+                off, chunk->range.start, chunk->range.end());
+        assert(false);
+      }
     }
   }
 
-  // Copypasted from the fast page lookup
+  // Lookup other root objects.
+  // @Copypasted from the fast page lookup
   if (app.tfile_data.sections[Sec_Other].count > 0) {
     // fast case: `off` is in the same obj as previous `off`.
     for (i32 i = 0; i < 2; ++i) {
       const Section &other_sec = *app.last_other_root_obj;
-      if (other_sec.range.start - other_sec.pre_size < off && off < other_sec.range.end()) {
+      if (i == 1) 
+        printf("checking if 0x%lX is in the next root obj, i.e. 0x%lX - 0x%lX - %s\n",
+          off, other_sec.range.start - other_sec.pre_size, other_sec.range.end(),
+        (other_sec.range.start - other_sec.pre_size <= off && off < other_sec.range.end()) ? "yes" : "no");
+      // else
+      //   printf("checking if 0x%lX is in the first root obj, i.e. 0x%lX - 0x%lX - %s\n",
+      //     off, other_sec.range.start - other_sec.pre_size, other_sec.range.end(),
+      //   (other_sec.range.start - other_sec.pre_size < off && off < other_sec.range.end()) ? "yes" : "no");
+      if (other_sec.range.start - other_sec.pre_size <= off && off < other_sec.range.end()) {
         return other_sec;
       }
 
+      // Try another common and still fast case: `off is in the next root object as the previous.
       if (app.last_other_root_obj->next)
         app.last_other_root_obj = app.last_other_root_obj->next;
       else
@@ -590,9 +598,12 @@ Section find_section(App_State &app, u64 off, i64 hilite_cluster = -1)
     }
 
     // Slow linear lookup, ideally only done once per render when last_other_root_obj is invalid.
+    printf("page fault\n");
     for (Section *other_sec = app.tfile_data.sections[Sec_Other].head; other_sec; other_sec = other_sec->next) {
       if (other_sec->range.start - other_sec->pre_size <= off && off < other_sec->range.end()) {
         app.last_other_root_obj = other_sec;
+        printf("off 0x%lX: last root obj set to 0x%lX - 0x%lX\n",
+               off, other_sec->range.start - other_sec->pre_size, other_sec->range.end());
         return *other_sec;
       }
     }
diff --git a/src/rntuple.h b/src/rntuple.h
index 535d50b..bd2049c 100644
--- a/src/rntuple.h
+++ b/src/rntuple.h
@@ -65,8 +65,11 @@ enum Section_Id {
   Sec_RNTuple_Header,
   Sec_RNTuple_Footer,
   Sec_Page_List,
-  Sec_Page, 
   Sec_Free_Slot,
+
+  Sec_COUNT_Regular,
+  // sections past this have a special handling in find_section() (i.e. fast lookup)
+  Sec_Page = Sec_COUNT_Regular, 
   // any other object stored in a TKey
   Sec_Other,
 
@@ -78,9 +81,10 @@ struct Section {
 
   Section_Id id;
   Byte_Range range;
-  u64 pre_size;  // usually the TKey header, excluded from `range`
-  u64 post_size; // usually the checksum, included in `range`
+  u32 pre_size;  // usually the TKey header, excluded from `range`
+  u32 post_size; // usually the checksum, included in `range`
   b8 highlighted;
+  b8 from_old_version_rntuple;
 
   // Optional pointer to the specific information for the section.
   // Here are the actual types:
@@ -103,8 +107,8 @@ internal const String8 section_names[] = {
   str8("RNTuple Header"),
   str8("RNTuple Footer"),
   str8("Page List"),
-  str8("Page"),
   str8("Free Slot"),
+  str8("Page"),
   str8("Other"),
 };
 static_assert(countof(section_names) == Sec_COUNT);
@@ -169,3 +173,10 @@ struct RNTuple_Data {
 
 internal
 Section *push_section(Arena *arena, TFile_Data &tdata, Section_Id id);
+
+internal
+b8 rntuple_is_old_version(const ROOT::RNTuple &ntuple)
+{
+  return ntuple.GetVersionEpoch() == 0 && ntuple.GetVersionMajor() < 3;
+}
+  
diff --git a/src/rntviewer.cpp b/src/rntviewer.cpp
index 4d23096..8cd5200 100644
--- a/src/rntviewer.cpp
+++ b/src/rntviewer.cpp
@@ -191,7 +191,7 @@ int main(int argc, char **argv)
   }
   
 #ifndef RNT_NO_GFX
-  init_viewer(app, args.n_cols);
+  init_viewer(arena, app, args.n_cols);
 
   // Init imgui and GLFW
   GLFWwindow *window = init_glfw(app, 1600, 900);
diff --git a/src/tfile.cpp b/src/tfile.cpp
index 2a49933..24dea1b 100644
--- a/src/tfile.cpp
+++ b/src/tfile.cpp
@@ -249,7 +249,7 @@ b8 walk_tkeys(Arena *arena, const u8 *data, u64 data_len, u32 flags, TFile_Data
           (u64)(n_bytes - keylen) != sections[Sec_TKey_List].head->range.len) 
       {
         fprintf(stderr, "Warning: inconsistent key list data, the file may have not parsed properly.\n");
-        fprintf(stderr, "  (keylen: %u vs %lu, nbytes: %u vs %lu)\n",
+        fprintf(stderr, "  (keylen: %u vs %u, nbytes: %u vs %lu)\n",
                 keylen, sections[Sec_TKey_List].head->pre_size,
                 n_bytes, sections[Sec_TKey_List].head->range.len);
       }
@@ -304,6 +304,7 @@ b8 walk_tkeys(Arena *arena, const u8 *data, u64 data_len, u32 flags, TFile_Data
         sec_anchor->range.len = n_bytes - keylen;
         sec_anchor->pre_size = keylen;
         sec_anchor->post_size = 8;
+        sec_anchor->from_old_version_rntuple = rntuple_is_old_version(*rntuple);
         
       } else if (key_has_class_name("RBlob")) {
         if (!sections[Sec_Page].head) {
@@ -415,11 +416,12 @@ void map_rntuple_rblobs(Arena *arena, TFile_Data &tfile_data)
       }
       if (best_anchor_idx >= 0) {
         found_sec[best_anchor_idx] = true;
-        Section *sec_header = push_section(arena, tfile_data, sec_id);
-        sec_header->range.start = tkey->rng.start + tkey->rng.len;
-        sec_header->range.len = sec_id == Sec_RNTuple_Header ? best_anchor->GetNBytesHeader() : best_anchor->GetNBytesFooter();
-        sec_header->pre_size = tkey->rng.len;
-        sec_header->post_size = 8;
+        Section *section = push_section(arena, tfile_data, sec_id);
+        section->range.start = tkey->rng.start + tkey->rng.len;
+        section->range.len = sec_id == Sec_RNTuple_Header ? best_anchor->GetNBytesHeader() : best_anchor->GetNBytesFooter();
+        section->pre_size = tkey->rng.len;
+        section->post_size = 8;
+        section->from_old_version_rntuple = rntuple_is_old_version(*best_anchor);
       }
     }
   }