diff --git a/src/app_state.h b/src/app_state.h
index 1bebb20..d194b45 100644
--- a/src/app_state.h
+++ b/src/app_state.h
@@ -36,7 +36,7 @@ struct App_State {
 
   // Cache the last info node selected for faster lookup of offsets
   const Page_Info_Node *last_pinfo;
-  const Other_Root_Obj_Info *last_other_root_obj;
+  const Section *last_other_root_obj;
 };
 
 internal
diff --git a/src/hover.cpp b/src/hover.cpp
index ff8426c..77044d1 100644
--- a/src/hover.cpp
+++ b/src/hover.cpp
@@ -901,7 +901,6 @@ struct Sec_Hover_Fn {
       u32 version = bswap(version_be);
       b8 is_big = version > 1000;
 
-      // FIXME: this is not correct in all cases
       while (cur_field_off < section.range.end()) {
         titled_section("Free Slot", [this, is_big] {
           field<u16>("Version: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 x) { 
@@ -1069,8 +1068,8 @@ struct Sec_Hover_Fn {
 
   void other_root_obj()
   {
-    Other_Root_Obj_Info *info = (Other_Root_Obj_Info *)section.info;
-    String8 name = (info && info->class_name.size) ? info->class_name : str8("(Unknown)");
+    String8 *class_name = (String8 *)section.info;
+    String8 name = class_name->size ? *class_name : str8("(Unknown)");
     titled_section(name.c(), [this] {
       tkey();
       range("Payload", section.range.len - section.post_size); 
diff --git a/src/render.cpp b/src/render.cpp
index 2b3f547..ae06f45 100644
--- a/src/render.cpp
+++ b/src/render.cpp
@@ -220,54 +220,6 @@ Page_Info_Node *viewer_jump_to_page(App_State &app, u64 page_idx)
   return page;
 }
 
-internal
-void viewer_jump_to_page_list(App_State &app, u64 page_list_idx)
-{
-  if (app.rndata.n_cluster_groups == 0)
-    return;
-  page_list_idx = (page_list_idx + app.rndata.n_cluster_groups) % app.rndata.n_cluster_groups;
-  
-  Cluster_Group_Info &cg_info = app.rndata.cluster_groups[page_list_idx];
-
-  app.viewer.latest_section_gone_to[Sec_Page_List] = page_list_idx;
-  viewer_jump_to(app, cg_info.rng_page_list.start);
-}
-
-internal
-void viewer_jump_to_free_slot(App_State &app, u64 free_slot_idx)
-{
-  u64 n_free_slots = app.tfile_data.sections[Sec_Free_Slot].count;
-  assert(n_free_slots > 0);
-
-  u64 idx = (free_slot_idx + n_free_slots) % n_free_slots;
-  
-  Section *sec = app.tfile_data.sections[Sec_Free_Slot].head;
-  for (u64 i = 0; i < idx; ++i) {
-    sec = sec->next;
-    assert(sec);
-  }
-
-  app.viewer.latest_section_gone_to[Sec_Free_Slot] = idx;
-  viewer_jump_to(app, sec->range.start);
-}
-
-internal
-void viewer_jump_to_other_root_obj(App_State &app, u64 obj_idx)
-{
-  u64 n_other_root_objs = app.tfile_data.tkeys_data.n_other_root_obj;
-  if (n_other_root_objs == 0)
-    return;
-  
-  obj_idx = (obj_idx + n_other_root_objs) % n_other_root_objs;
-  
-  Other_Root_Obj_Info *info = app.tfile_data.tkeys_data.other_root_obj;
-  for (u64 i = 0; i < obj_idx; ++i)
-    info = info->next;
-
-  app.viewer.latest_section_gone_to[Sec_Other] = obj_idx;
-  viewer_jump_to(app, info->section.range.start);
-}
-
 internal
 void viewer_jump_to_cluster(App_State &app, u64 cluster_idx)
 {
@@ -284,6 +236,45 @@ void viewer_jump_to_cluster(App_State &app, u64 cluster_idx)
   viewer_jump_to(app, page->range.start);
 }
 
+internal
+void viewer_jump_to_page_list(App_State &app, u64 page_list_idx)
+{
+  if (app.rndata.n_cluster_groups == 0)
+    return;
+
+  page_list_idx = (page_list_idx + app.rndata.n_cluster_groups) % app.rndata.n_cluster_groups;
+
+  Cluster_Group_Info &cg_info = app.rndata.cluster_groups[page_list_idx];
+
+  app.viewer.latest_section_gone_to[Sec_Page_List] = page_list_idx;
+  viewer_jump_to(app, cg_info.rng_page_list.start);
+}
+
+internal
+void viewer_jump_to_section(App_State &app, Section_Id id, u64 sec_idx)
+{
+  // special cases
+  if (id == Sec_Page_List) {
+    viewer_jump_to_page_list(app, sec_idx);
+    return;
+  }
+  
+  const Sections &sections = app.tfile_data.sections[id];
+  if (sections.count == 0)
+    return;
+  
+  Section *sec = sections.head;
+  assert(sec);
+
+  sec_idx = (sec_idx + sections.count) % sections.count;
+
+  for (u64 i = 0; i < sec_idx; ++i) {
+    sec = sec->next;
+    assert(sec);
+  }
+  viewer_jump_to(app, sec->range.start);
+}
+
 internal
 void imgui_render_string_tree(Arena *arena, String8_Node *root, String8_Node *highlighted, u16 indent = 0)
 {
@@ -381,7 +372,7 @@ void update_and_render(Arena *arena, App_State &app, f32 delta_time_ms)
       assert(app.base_display_addr < app.inspected_file.size);
       void *content = app.inspected_file.mem + app.base_display_addr;
       app.last_pinfo = &invalid_pinfo;
-      app.last_other_root_obj = &invalid_other_root_obj_info;
+      app.last_other_root_obj = &invalid_section;
       app.viewer.mem_edit.DrawContents(content, content_size, app.base_display_addr);
 
       ImGui::TableNextColumn();
@@ -391,19 +382,34 @@ void update_and_render(Arena *arena, App_State &app, f32 delta_time_ms)
       // -------------------------------
 
       // Unique sections: just display a button that jumps to the start of it and show their size
-      for (u32 i = 0; i < Sec_COUNT; ++i) {
-        u32 sec_idx = 0;
-        for (Section *sec = app.tfile_data.sections[i].head; sec; sec = sec->next, ++sec_idx) {
-          if (!sec->range.len) continue;
+      for (u32 i = 1; i < Sec_COUNT; ++i) {
+        if (!app.tfile_data.sections[i].head)
+          continue;
 
-          String8 sec_name = section_names[i];
-          String8 col_label = push_str8f(scratch.arena, "_%s", sec_name.c());
-          ImGui::ColorEdit3(col_label.c(), app.viewer.col_section[i], edit_flags);
+        // TODO: handle pages like other sections
+        if (i == Sec_Page)
+          continue;
+        
+        String8 sec_name = section_names[i];
+        String8 col_label = push_str8f(scratch.arena, "_%s", sec_name.c());
+        ImGui::ColorEdit3(col_label.c(), app.viewer.col_section[i], edit_flags);
+        ImGui::SameLine(); 
+        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());
+
+        if (app.tfile_data.sections[i].count > 1) {
           ImGui::SameLine(); 
-          if (ImGui::Button(push_str8f(scratch.arena, "%s_%u", sec_name.c(), sec_idx).c())) 
-            viewer_jump_to(app, sec->range.start);
-          ImGui::SameLine(); 
-          ImGui::Text("%s", to_pretty_size(scratch.arena, sec->range.len).c());
+          i64 sec_to_go_to = app.viewer.latest_section_gone_to[i];
+          ImGui::PushItemWidth(80.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);
+          }
+          ImGui::PopItemWidth();
         }
       }
 
@@ -446,62 +452,6 @@ void update_and_render(Arena *arena, App_State &app, f32 delta_time_ms)
       ImGui::SameLine(); 
       if (ImGui::Button("Checksum")) {} // TODO jump to next checksum
 
-      ImGui::ColorEdit3("_Page List", app.viewer.col_section[Sec_Page_List], edit_flags);
-      ImGui::SameLine(); 
-      if (ImGui::Button("Page List"))
-        viewer_jump_to_page_list(app, app.viewer.latest_section_gone_to[Sec_Page_List]);
-
-      ImGui::SameLine();
-      {
-        i64 page_list_to_go_to = app.viewer.latest_section_gone_to[Sec_Page_List];
-        ImGui::PushItemWidth(80.f);
-        if (ImGui::InputScalar("##page_list_viewed", ImGuiDataType_S64, &page_list_to_go_to, &step_i64, nullptr, "%u") 
-            && ImGui::IsItemDeactivatedAfterEdit())
-        {
-          viewer_jump_to_page_list(app, page_list_to_go_to);
-        }
-        ImGui::PopItemWidth();
-      }
-      ImGui::SameLine(); 
-      ImGui::Text("%s", to_pretty_size(scratch.arena, app.rndata.tot_page_list_size).c());
-
-      if (app.tfile_data.tkeys_data.n_other_root_obj > 0) {
-        ImGui::ColorEdit3("_Other", app.viewer.col_section[Sec_Other], edit_flags);
-        ImGui::SameLine(); 
-        if (ImGui::Button("Other"))
-          viewer_jump_to_other_root_obj(app, app.viewer.latest_section_gone_to[Sec_Other]);
-
-        ImGui::SameLine(); 
-        {
-          i64 other_root_obj_to_go_to = app.viewer.latest_section_gone_to[Sec_Other];
-          ImGui::PushItemWidth(80.f);
-          if (ImGui::InputScalar("##other_root_objviewed", ImGuiDataType_S64, &other_root_obj_to_go_to, &step_i64, nullptr, "%u") 
-              && ImGui::IsItemDeactivatedAfterEdit())
-          {
-            viewer_jump_to_other_root_obj(app, other_root_obj_to_go_to);
-          }
-          ImGui::PopItemWidth();
-        }
-      }
-
-      if (app.tfile_data.sections[Sec_Free_Slot].count) {
-        ImGui::ColorEdit3("_Free Slot", app.viewer.col_section[Sec_Free_Slot], edit_flags);
-        ImGui::SameLine(); 
-        if (ImGui::Button("Free Slot"))
-          viewer_jump_to_free_slot(app, app.viewer.latest_section_gone_to[Sec_Free_Slot]);
-        ImGui::SameLine();
-        {
-          i64 free_slot_to_go_to = app.viewer.latest_section_gone_to[Sec_Free_Slot];
-          ImGui::PushItemWidth(80.f);
-          if (ImGui::InputScalar("##free_slot_viewed", ImGuiDataType_S64, &free_slot_to_go_to, &step_i64, nullptr, "%u") 
-              && ImGui::IsItemDeactivatedAfterEdit())
-          {
-            viewer_jump_to_free_slot(app, free_slot_to_go_to);
-          }
-          ImGui::PopItemWidth();
-        }
-      }
-
       // Misc information
       // -------------------------------
       ImGui::Separator();
diff --git a/src/render_term.cpp b/src/render_term.cpp
index aea77cc..006ca40 100644
--- a/src/render_term.cpp
+++ b/src/render_term.cpp
@@ -141,7 +141,7 @@ String8 render_range_bytes_to_string(Arena *arena, App_State &app, Term_Viewer &
 
   // We need to properly initialize this before calling mem_edit_bg_color_fn!
   app.last_pinfo = &invalid_pinfo;
-  app.last_other_root_obj = &invalid_other_root_obj_info;
+  app.last_other_root_obj = &invalid_section;
 
   const u8 *data = app.inspected_file.mem;
   assert(range.start <= max_addr);
diff --git a/src/rntuple.cpp b/src/rntuple.cpp
index 8c06040..4cfe89f 100644
--- a/src/rntuple.cpp
+++ b/src/rntuple.cpp
@@ -8,6 +8,17 @@ Section *push_section(Arena *arena, TFile_Data &tdata, Section_Id id)
   return sec;
 }
 
+internal
+void compute_tot_sections_size(Sections *sections)
+{
+  for (u64 i = 0; i < Sec_COUNT; ++i) {
+    u64 tot_size = 0;
+    for (Section *sec = sections[i].head; sec; sec = sec->next)
+      tot_size += sec->range.len;
+    sections[i].tot_size = tot_size;
+  }
+}
+
 internal
 b8 rntuple_is_old_version(const ROOT::RNTuple &ntuple)
 {
@@ -475,7 +486,6 @@ Section find_section(App_State &app, u64 off, i64 hilite_cluster = -1)
 {
   // These are supposed to never be null. If they are invalid, they must be set to `&invalid_pinfo` etc.
   assert(app.last_pinfo);
-  assert(app.last_other_root_obj);
   
   const RNTuple_Data &rdata = app.rndata;
 
@@ -491,8 +501,6 @@ Section find_section(App_State &app, u64 off, i64 hilite_cluster = -1)
 
   u64 rblob_sz = app.tfile_data.sections[Sec_Page].head->pre_size;
 
-  const TKeys_Data &tdata = app.tfile_data.tkeys_data;
-
   /// Page fast lookup (relative to app.last_pinfo)
   {
     // fast case: `off` is in the same page info as previous `off`.
@@ -567,10 +575,10 @@ Section find_section(App_State &app, u64 off, i64 hilite_cluster = -1)
   }
 
   // Copypasted from the fast page lookup
-  if (tdata.n_other_root_obj > 0) {
-    // fast case: `off` is in the same page info as previous `off`.
+  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->section;
+      const Section &other_sec = *app.last_other_root_obj;
       if (other_sec.range.start - other_sec.pre_size < off && off < other_sec.range.end()) {
         return other_sec;
       }
@@ -582,10 +590,10 @@ 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.
-    for (Other_Root_Obj_Info *other = tdata.other_root_obj; other; other = other->next) {
-      if (other->section.range.start - other->section.pre_size <= off && off < other->section.range.end()) {
-        app.last_other_root_obj = other;
-        return other->section;
+    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;
+        return *other_sec;
       }
     }
   }
diff --git a/src/rntuple.h b/src/rntuple.h
index cb2b0e9..535d50b 100644
--- a/src/rntuple.h
+++ b/src/rntuple.h
@@ -3,12 +3,6 @@ struct Byte_Range {
   inline u64 end() const { return start + len; }
 };
 
-// Used to store location information about stuff like checksums, page lists, etc
-struct Range_Seq {
-  Range_Seq *next;
-  Byte_Range range;
-};
-
 struct Page_Info_Node {
   Page_Info_Node *next;
   Page_Info_Node *prev;
@@ -32,11 +26,16 @@ struct Page_Info_Node {
 
 static const Page_Info_Node invalid_pinfo {};
 
+// A page group is a grouping of a fixed number of page infos, whose range is equal to the combined ranges
+// of its components. It is an acceleration structure used to more quickly find the correct page info
+// that an offset belongs to.
 struct Page_Info_Group {
   Byte_Range range;
   Page_Info_Node *first;
 };
 
+// A page chunk is a grouping of adjacent pages, used to quickly determine if an offset is part
+// of a page or not.
 struct Page_Info_Chunk {
   Page_Info_Chunk *next;
   Byte_Range range;
@@ -62,11 +61,11 @@ enum Section_Id {
   Sec_TFile_Info,
   Sec_TFile_FreeList,
   Sec_TKey_List,
+  Sec_RNTuple_Anchor,
   Sec_RNTuple_Header,
   Sec_RNTuple_Footer,
   Sec_Page_List,
   Sec_Page, 
-  Sec_RNTuple_Anchor,
   Sec_Free_Slot,
   // any other object stored in a TKey
   Sec_Other,
@@ -84,9 +83,13 @@ struct Section {
   b8 highlighted;
 
   // Optional pointer to the specific information for the section.
-  // e.g. if the section is a Page this points to the relative Page_Info_Node
+  // Here are the actual types:
+  //   - Sec_RNTuple_Anchor => ROOT::RNTuple
+  //   - Sec_Page => Page_Info_Node (aliased from RNTuple_Data::pages)
+  //   - Sec_Other => String8 (the class name of the object)
   const void *info;
 };
+static const Section invalid_section {};
 
 // @Volatile with Section_Id
 internal const String8 section_names[] = {
@@ -96,11 +99,11 @@ internal const String8 section_names[] = {
   str8("TFile Streamer Info"),
   str8("TFile FreeList"),
   str8("TKey List"),
+  str8("RNTuple Anchor"),
   str8("RNTuple Header"),
   str8("RNTuple Footer"),
   str8("Page List"),
   str8("Page"),
-  str8("RNTuple Anchor"),
   str8("Free Slot"),
   str8("Other"),
 };
@@ -117,24 +120,15 @@ struct RNTuple_Anchor_Info {
   u64 offset_in_file;
 };
 
-struct Other_Root_Obj_Info {
-  Other_Root_Obj_Info *next;
-  String8 class_name;
-  Section section;
-};
-static const Other_Root_Obj_Info invalid_other_root_obj_info {};
-
 struct Sections {
   Section *head, *tail;
   u32 count;
+  u64 tot_size;
 };
 
 struct TKeys_Data {
   RNTuple_Anchor_Info *rntuples;
   Byte_Range_Node *rblob_keys;
-
-  Other_Root_Obj_Info *other_root_obj;
-  u64 n_other_root_obj;
 };
 
 struct TFile_Data {
diff --git a/src/rntviewer.cpp b/src/rntviewer.cpp
index 3feb5a6..4d23096 100644
--- a/src/rntviewer.cpp
+++ b/src/rntviewer.cpp
@@ -176,6 +176,8 @@ int main(int argc, char **argv)
   // else if (success)
     app.rndata = get_rntuple_data(arena, app.inspected_file, app.tfile_data, args.extended_info);
 
+  compute_tot_sections_size(app.tfile_data.sections);
+
   if (args.print_to_terminal) {
     u64 nbytes_displayed = args.nbytes_displayed;
     if (!nbytes_displayed)
diff --git a/src/tfile.cpp b/src/tfile.cpp
index 9d6ff61..2a49933 100644
--- a/src/tfile.cpp
+++ b/src/tfile.cpp
@@ -201,7 +201,6 @@ b8 walk_tkeys(Arena *arena, const u8 *data, u64 data_len, u32 flags, TFile_Data
   cur = pre + tfile_obj_nbytes;
 
   RNTuple_Anchor_Info *rntuple_info_tail = nullptr;
-  Other_Root_Obj_Info *other_root_obj_tail = nullptr;
 
   Sections *sections = tfile_data.sections;
 
@@ -322,17 +321,14 @@ b8 walk_tkeys(Arena *arena, const u8 *data, u64 data_len, u32 flags, TFile_Data
         tkeys_data.rblob_keys = rblob_key;
 
       } else if (flags & WTK_COLLECT_OTHER_ROOT_OBJS) {
-        Other_Root_Obj_Info *oth_info = arena_push<Other_Root_Obj_Info>(arena);
-        if (cname_len) {
-          oth_info->class_name = str8_from_buf(arena, data + cname_off + 1, cname_len);
-        }
-        oth_info->section.id = Sec_Other;
-        oth_info->section.info = oth_info;
-        oth_info->section.range.start = cur + keylen;
-        oth_info->section.range.len = n_bytes - keylen;
-        oth_info->section.pre_size = keylen;
-        push_to_sll(tkeys_data.other_root_obj, other_root_obj_tail, oth_info);
-        tkeys_data.n_other_root_obj++;
+        Section *sec_other = push_section(arena, tfile_data, Sec_Other);
+        String8 *class_name = arena_push<String8>(arena);
+        sec_other->info = class_name;
+        if (cname_len)
+          *class_name = str8_from_buf(arena, data + cname_off + 1, cname_len);
+        sec_other->range.start = cur + keylen;
+        sec_other->range.len = n_bytes - keylen;
+        sec_other->pre_size = keylen;
       }
     }
     cur += n_bytes;