OOKNET                             [ /  search the index  ]  
──────────────────────────────────────────────────────────────────────────────────────
══════════════════════════════════════════════════════════════════════════════════════
OOKNET   [ /  search  ]  
────────────────────────────────────────────────
════════════════════════════════════════════════
 
HASH      2447ab9e5e85
DATE      2025-11-22
SUBJECT   web: status page
FILES     17 CHANGED
HASH      2447ab9e5e85
DATE      2025-11-22
SUBJECT   web: status page
FILES     17 CHANGED
 

diff --git a/web/.astro/data-store.json b/web/.astro/data-store.json
index 94ea62a..50de610 100644
--- a/web/.astro/data-store.json
+++ b/web/.astro/data-store.json
@@ -1 +1 @@
-[["Map",1,2],"meta::meta",["Map",3,4,5,6],"astro-version","5.12.0","astro-config-
digest","{\"root\":{},\"srcDir\":{},\"publicDir\":{},\"outDir\":{},\"cacheDir\":{}
,\"site\":\"https://wowsimstats.com\",\"compressHTML\":true,\"base\":\"/\",\"trail
ingSlash\":\"ignore\",\"output\":\"server\",\"scopedStyleStrategy\":\"attribute\",
\"build\":{\"format\":\"directory\",\"client\":{},\"server\":{},\"assets\":\"_astr
o\",\"serverEntry\":\"entry.mjs\",\"redirects\":false,\"inlineStylesheets\":\"auto
\",\"concurrency\":1},\"server\":{\"open\":false,\"host\":false,\"port\":37287,\"s
treaming\":true,\"allowedHosts\":[]},\"redirects\":{},\"image\":{\"endpoint\":{\"r
oute\":\"/_image\"},\"service\":{\"entrypoint\":\"astro/assets/services/sharp\",\"
config\":{}},\"domains\":[],\"remotePatterns\":[],\"responsiveStyles\":false},\"de
vToolbar\":{\"enabled\":true},\"markdown\":{\"syntaxHighlight\":{\"type\":\"shiki\
",\"excludeLangs\":[\"math\"]},\"shikiConfig\":{\"langs\":[],\"langAlias\":{},\"th
eme\":\"github-dark\",\"themes\":{},\"wrap\":false,\"transformers\":[]},\"remarkPl
ugins\":[],\"rehypePlugins\":[],\"remarkRehype\":{},\"gfm\":true,\"smartypants\":t
rue},\"security\":{\"checkOrigin\":true},\"env\":{\"schema\":{},\"validateSecrets\
":false},\"experimental\":{\"clientPrerender\":false,\"contentIntellisense\":false
,\"headingIdCompat\":false,\"preserveScriptOrder\":false,\"liveContentCollections\
":false,\"csp\":false,\"rawEnvValues\":false},\"legacy\":{\"collections\":false}}"
]
\ No newline at end of file
+[["Map",1,2],"meta::meta",["Map",3,4,5,6],"astro-version","5.12.0","astro-config-
digest","{\"root\":{},\"srcDir\":{},\"publicDir\":{},\"outDir\":{},\"cacheDir\":{}
,\"site\":\"https://wowsimstats.com\",\"compressHTML\":true,\"base\":\"/\",\"trail
ingSlash\":\"ignore\",\"output\":\"server\",\"scopedStyleStrategy\":\"attribute\",
\"build\":{\"format\":\"directory\",\"client\":{},\"server\":{},\"assets\":\"_astr
o\",\"serverEntry\":\"entry.mjs\",\"redirects\":false,\"inlineStylesheets\":\"auto
\",\"concurrency\":1},\"server\":{\"open\":false,\"host\":false,\"port\":26617,\"s
treaming\":true,\"allowedHosts\":[]},\"redirects\":{},\"image\":{\"endpoint\":{\"r
oute\":\"/_image\"},\"service\":{\"entrypoint\":\"astro/assets/services/sharp\",\"
config\":{}},\"domains\":[],\"remotePatterns\":[],\"responsiveStyles\":false},\"de
vToolbar\":{\"enabled\":true},\"markdown\":{\"syntaxHighlight\":{\"type\":\"shiki\
",\"excludeLangs\":[\"math\"]},\"shikiConfig\":{\"langs\":[],\"langAlias\":{},\"th
eme\":\"github-dark\",\"themes\":{},\"wrap\":false,\"transformers\":[]},\"remarkPl
ugins\":[],\"rehypePlugins\":[],\"remarkRehype\":{},\"gfm\":true,\"smartypants\":t
rue},\"security\":{\"checkOrigin\":true},\"env\":{\"schema\":{},\"validateSecrets\
":false},\"experimental\":{\"clientPrerender\":false,\"contentIntellisense\":false
,\"headingIdCompat\":false,\"preserveScriptOrder\":false,\"liveContentCollections\
":false,\"csp\":false,\"rawEnvValues\":false},\"legacy\":{\"collections\":false}}"
]
\ No newline at end of file

diff --git a/web/.astro/data-store.json b/we
b/.astro/data-store.json
index 94ea62a..50de610 100644
--- a/web/.astro/data-store.json
+++ b/web/.astro/data-store.json
@@ -1 +1 @@
-[["Map",1,2],"meta::meta",["Map",3,4,5,6],"
astro-version","5.12.0","astro-config-digest
","{\"root\":{},\"srcDir\":{},\"publicDir\":
{},\"outDir\":{},\"cacheDir\":{},\"site\":\"
https://wowsimstats.com\",\"compressHTML\":t
rue,\"base\":\"/\",\"trailingSlash\":\"ignor
e\",\"output\":\"server\",\"scopedStyleStrat
egy\":\"attribute\",\"build\":{\"format\":\"
directory\",\"client\":{},\"server\":{},\"as
sets\":\"_astro\",\"serverEntry\":\"entry.mj
s\",\"redirects\":false,\"inlineStylesheets\
":\"auto\",\"concurrency\":1},\"server\":{\"
open\":false,\"host\":false,\"port\":37287,\
"streaming\":true,\"allowedHosts\":[]},\"red
irects\":{},\"image\":{\"endpoint\":{\"route
\":\"/_image\"},\"service\":{\"entrypoint\":
\"astro/assets/services/sharp\",\"config\":{
}},\"domains\":[],\"remotePatterns\":[],\"re
sponsiveStyles\":false},\"devToolbar\":{\"en
abled\":true},\"markdown\":{\"syntaxHighligh
t\":{\"type\":\"shiki\",\"excludeLangs\":[\"
math\"]},\"shikiConfig\":{\"langs\":[],\"lan
gAlias\":{},\"theme\":\"github-dark\",\"them
es\":{},\"wrap\":false,\"transformers\":[]},
\"remarkPlugins\":[],\"rehypePlugins\":[],\"
remarkRehype\":{},\"gfm\":true,\"smartypants
\":true},\"security\":{\"checkOrigin\":true}
,\"env\":{\"schema\":{},\"validateSecrets\":
false},\"experimental\":{\"clientPrerender\"
:false,\"contentIntellisense\":false,\"headi
ngIdCompat\":false,\"preserveScriptOrder\":f
alse,\"liveContentCollections\":false,\"csp\
":false,\"rawEnvValues\":false},\"legacy\":{
\"collections\":false}}"]
\ No newline at end of file
+[["Map",1,2],"meta::meta",["Map",3,4,5,6],"
astro-version","5.12.0","astro-config-digest
","{\"root\":{},\"srcDir\":{},\"publicDir\":
{},\"outDir\":{},\"cacheDir\":{},\"site\":\"
https://wowsimstats.com\",\"compressHTML\":t
rue,\"base\":\"/\",\"trailingSlash\":\"ignor
e\",\"output\":\"server\",\"scopedStyleStrat
egy\":\"attribute\",\"build\":{\"format\":\"
directory\",\"client\":{},\"server\":{},\"as
sets\":\"_astro\",\"serverEntry\":\"entry.mj
s\",\"redirects\":false,\"inlineStylesheets\
":\"auto\",\"concurrency\":1},\"server\":{\"
open\":false,\"host\":false,\"port\":26617,\
"streaming\":true,\"allowedHosts\":[]},\"red
irects\":{},\"image\":{\"endpoint\":{\"route
\":\"/_image\"},\"service\":{\"entrypoint\":
\"astro/assets/services/sharp\",\"config\":{
}},\"domains\":[],\"remotePatterns\":[],\"re
sponsiveStyles\":false},\"devToolbar\":{\"en
abled\":true},\"markdown\":{\"syntaxHighligh
t\":{\"type\":\"shiki\",\"excludeLangs\":[\"
math\"]},\"shikiConfig\":{\"langs\":[],\"lan
gAlias\":{},\"theme\":\"github-dark\",\"them
es\":{},\"wrap\":false,\"transformers\":[]},
\"remarkPlugins\":[],\"rehypePlugins\":[],\"
remarkRehype\":{},\"gfm\":true,\"smartypants
\":true},\"security\":{\"checkOrigin\":true}
,\"env\":{\"schema\":{},\"validateSecrets\":
false},\"experimental\":{\"clientPrerender\"
:false,\"contentIntellisense\":false,\"headi
ngIdCompat\":false,\"preserveScriptOrder\":f
alse,\"liveContentCollections\":false,\"csp\
":false,\"rawEnvValues\":false},\"legacy\":{
\"collections\":false}}"]
\ No newline at end of file
 

diff --git a/web/.astro/types.d.ts b/web/.astro/types.d.ts
index f964fe0..03d7cc4 100644
--- a/web/.astro/types.d.ts
+++ b/web/.astro/types.d.ts
@@ -1 +1,2 @@
 /// <reference types="astro/client" />
+/// <reference path="content.d.ts" />
\ No newline at end of file

diff --git a/web/.astro/types.d.ts b/web/.as
tro/types.d.ts
index f964fe0..03d7cc4 100644
--- a/web/.astro/types.d.ts
+++ b/web/.astro/types.d.ts
@@ -1 +1,2 @@
 /// <reference types="astro/client" />
+/// <reference path="content.d.ts" />
\ No newline at end of file
 

diff --git a/web/src/components/Leaderboard/LeaderboardTypeNav/LeaderboardTypeNav.
astro b/web/src/components/Leaderboard/LeaderboardTypeNav/LeaderboardTypeNav.astro
index 544cc09..52e29a3 100644
--- a/web/src/components/Leaderboard/LeaderboardTypeNav/LeaderboardTypeNav.astro
+++ b/web/src/components/Leaderboard/LeaderboardTypeNav/LeaderboardTypeNav.astro
@@ -2,7 +2,8 @@
 import "./LeaderboardTypeNav.scss";
 
 interface Props {
-  currentType: "dungeon" | "player";
+  currentType?: "dungeon" | "player";
+  currentTab?: "dungeon" | "player" | "status";
   currentRegion?: string;
   currentRealm?: string;
   currentSeason?: number;
@@ -11,7 +12,8 @@ interface Props {
 }
 
 const {
-  currentType,
+  currentType = "dungeon",
+  currentTab = currentType,
   currentRegion = "global",
   currentRealm = "",
   currentSeason = 1,
@@ -47,16 +49,22 @@ if (currentRegion === "global") {
 <nav class="leaderboard-type-nav">
   <a
     href={dungeonUrl}
-    class:list={["nav-tab", { active: currentType === "dungeon" }]}
+    class:list={["nav-tab", { active: currentTab === "dungeon" }]}
   >
     Dungeons
   </a>
   <a
     href={playerUrl}
-    class:list={["nav-tab", { active: currentType === "player" }]}
+    class:list={["nav-tab", { active: currentTab === "player" }]}
   >
     Players
   </a>
+  <a
+    href="/challenge-mode/status"
+    class:list={["nav-tab", { active: currentTab === "status" }]}
+  >
+    Status
+  </a>
   <a
     class="nav-tab discord-link"
     href="https://discord.gg/etxRSDNxFr"

diff --git a/web/src/components/Leaderboard/
LeaderboardTypeNav/LeaderboardTypeNav.astro 
b/web/src/components/Leaderboard/Leaderboard
TypeNav/LeaderboardTypeNav.astro
index 544cc09..52e29a3 100644
--- a/web/src/components/Leaderboard/Leaderb
oardTypeNav/LeaderboardTypeNav.astro
+++ b/web/src/components/Leaderboard/Leaderb
oardTypeNav/LeaderboardTypeNav.astro
@@ -2,7 +2,8 @@
 import "./LeaderboardTypeNav.scss";
 
 interface Props {
-  currentType: "dungeon" | "player";
+  currentType?: "dungeon" | "player";
+  currentTab?: "dungeon" | "player" | "stat
us";
   currentRegion?: string;
   currentRealm?: string;
   currentSeason?: number;
@@ -11,7 +12,8 @@ interface Props {
 }
 
 const {
-  currentType,
+  currentType = "dungeon",
+  currentTab = currentType,
   currentRegion = "global",
   currentRealm = "",
   currentSeason = 1,
@@ -47,16 +49,22 @@ if (currentRegion === "g
lobal") {
 <nav class="leaderboard-type-nav">
   <a
     href={dungeonUrl}
-    class:list={["nav-tab", { active: curre
ntType === "dungeon" }]}
+    class:list={["nav-tab", { active: curre
ntTab === "dungeon" }]}
   >
     Dungeons
   </a>
   <a
     href={playerUrl}
-    class:list={["nav-tab", { active: curre
ntType === "player" }]}
+    class:list={["nav-tab", { active: curre
ntTab === "player" }]}
   >
     Players
   </a>
+  <a
+    href="/challenge-mode/status"
+    class:list={["nav-tab", { active: curre
ntTab === "status" }]}
+  >
+    Status
+  </a>
   <a
     class="nav-tab discord-link"
     href="https://discord.gg/etxRSDNxFr"
 

diff --git a/web/src/components/Leaderboard/LeaderboardTypeNav/LeaderboardTypeNav.
scss b/web/src/components/Leaderboard/LeaderboardTypeNav/LeaderboardTypeNav.scss
index 83664a2..0d42c68 100644
--- a/web/src/components/Leaderboard/LeaderboardTypeNav/LeaderboardTypeNav.scss
+++ b/web/src/components/Leaderboard/LeaderboardTypeNav/LeaderboardTypeNav.scss
@@ -6,6 +6,7 @@
   margin-bottom: $spacing-lg;
   border-bottom: 2px solid var(--border-color);
   align-items: center;
+  flex-wrap: wrap;
 }
 
 .nav-tab {
@@ -49,9 +50,19 @@
 }
 
 @media (max-width: 768px) {
+  .leaderboard-type-nav {
+    gap: $spacing-xs;
+  }
+
   .nav-tab {
-    flex: 1;
+    flex: 1 1 calc(50% - $spacing-xs);
     text-align: center;
     padding: $spacing-sm $spacing-md;
   }
+
+  .discord-link {
+    flex: 1 1 100%;
+    margin-left: 0;
+    margin-top: $spacing-xs;
+  }
 }

diff --git a/web/src/components/Leaderboard/
LeaderboardTypeNav/LeaderboardTypeNav.scss b
/web/src/components/Leaderboard/LeaderboardT
ypeNav/LeaderboardTypeNav.scss
index 83664a2..0d42c68 100644
--- a/web/src/components/Leaderboard/Leaderb
oardTypeNav/LeaderboardTypeNav.scss
+++ b/web/src/components/Leaderboard/Leaderb
oardTypeNav/LeaderboardTypeNav.scss
@@ -6,6 +6,7 @@
   margin-bottom: $spacing-lg;
   border-bottom: 2px solid var(--border-col
or);
   align-items: center;
+  flex-wrap: wrap;
 }
 
 .nav-tab {
@@ -49,9 +50,19 @@
 }
 
 @media (max-width: 768px) {
+  .leaderboard-type-nav {
+    gap: $spacing-xs;
+  }
+
   .nav-tab {
-    flex: 1;
+    flex: 1 1 calc(50% - $spacing-xs);
     text-align: center;
     padding: $spacing-sm $spacing-md;
   }
+
+  .discord-link {
+    flex: 1 1 100%;
+    margin-left: 0;
+    margin-top: $spacing-xs;
+  }
 }
 

diff --git a/web/src/components/Leaderboard/RegionRealmFilterSelect/RegionRealmFil
terSelect.astro b/web/src/components/Leaderboard/RegionRealmFilterSelect/RegionRea
lmFilterSelect.astro
index 634cfcf..32cab2a 100644
--- a/web/src/components/Leaderboard/RegionRealmFilterSelect/RegionRealmFilterSele
ct.astro
+++ b/web/src/components/Leaderboard/RegionRealmFilterSelect/RegionRealmFilterSele
ct.astro
@@ -1,10 +1,15 @@
 ---
-import type { LatestRunEntry } from "../../../lib/types";
 import { REGION_OPTIONS } from "../../../lib/wow-constants";
 import "./RegionRealmFilterSelect.scss";
 
+type RealmOptionSource = {
+  region: string;
+  realm_slug: string;
+  realm_name: string;
+};
+
 interface Props {
-  runs: LatestRunEntry[];
+  runs: RealmOptionSource[];
   currentRegion?: string;
   currentRealm?: string;
 }

diff --git a/web/src/components/Leaderboard/
RegionRealmFilterSelect/RegionRealmFilterSel
ect.astro b/web/src/components/Leaderboard/R
egionRealmFilterSelect/RegionRealmFilterSele
ct.astro
index 634cfcf..32cab2a 100644
--- a/web/src/components/Leaderboard/RegionR
ealmFilterSelect/RegionRealmFilterSelect.ast
ro
+++ b/web/src/components/Leaderboard/RegionR
ealmFilterSelect/RegionRealmFilterSelect.ast
ro
@@ -1,10 +1,15 @@
 ---
-import type { LatestRunEntry } from "../../
../lib/types";
 import { REGION_OPTIONS } from "../../../li
b/wow-constants";
 import "./RegionRealmFilterSelect.scss";
 
+type RealmOptionSource = {
+  region: string;
+  realm_slug: string;
+  realm_name: string;
+};
+
 interface Props {
-  runs: LatestRunEntry[];
+  runs: RealmOptionSource[];
   currentRegion?: string;
   currentRealm?: string;
 }
 

diff --git a/web/src/components/Leaderboard/TeamComposition/TeamComposition.astro 
b/web/src/components/Leaderboard/TeamComposition/TeamComposition.astro
index b55252e..cd90cba 100644
--- a/web/src/components/Leaderboard/TeamComposition/TeamComposition.astro
+++ b/web/src/components/Leaderboard/TeamComposition/TeamComposition.astro
@@ -1,12 +1,12 @@
 ---
-import type { LatestRunMember, TeamMember } from "../../../lib/types";
+import type { TeamMember } from "../../../lib/types";
 import PlayerLink from "../PlayerLink/PlayerLink.astro";
 import { getSpecInfo } from "../../../lib/wow-constants";
 import { getEffectiveRealmSlug } from "../../../lib/realms";
 import "./TeamComposition.scss";
 
 interface Props {
-  members: LatestRunMember[] | TeamMember[];
+  members: TeamMember[];
   currentRegion?: string;
   currentRealm?: string;
 }

diff --git a/web/src/components/Leaderboard/
TeamComposition/TeamComposition.astro b/web/
src/components/Leaderboard/TeamComposition/T
eamComposition.astro
index b55252e..cd90cba 100644
--- a/web/src/components/Leaderboard/TeamCom
position/TeamComposition.astro
+++ b/web/src/components/Leaderboard/TeamCom
position/TeamComposition.astro
@@ -1,12 +1,12 @@
 ---
-import type { LatestRunMember, TeamMember }
 from "../../../lib/types";
+import type { TeamMember } from "../../../l
ib/types";
 import PlayerLink from "../PlayerLink/Playe
rLink.astro";
 import { getSpecInfo } from "../../../lib/w
ow-constants";
 import { getEffectiveRealmSlug } from "../.
./../lib/realms";
 import "./TeamComposition.scss";
 
 interface Props {
-  members: LatestRunMember[] | TeamMember[]
;
+  members: TeamMember[];
   currentRegion?: string;
   currentRealm?: string;
 }
 

diff --git a/web/src/components/Status/StatusDungeonContainer/StatusDungeonContain
er.astro b/web/src/components/Status/StatusDungeonContainer/StatusDungeonContainer
.astro
new file mode 100644
index 0000000..b76bef3
--- /dev/null
+++ b/web/src/components/Status/StatusDungeonContainer/StatusDungeonContainer.astr
o
@@ -0,0 +1,69 @@
+---
+import type { CoverageHealth, DungeonCoverage } from "../../../lib/types";
+import "./StatusDungeonContainer.scss";
+import { getDungeonIconUrl } from "../../../lib/dungeonIcons";
+
+interface Props {
+  dungeon: DungeonCoverage;
+  healthLabels: Record<CoverageHealth, string>;
+  formatList: (items?: number[]) => string;
+  latestPeriod?: number | null;
+}
+
+const { dungeon, healthLabels, formatList, latestPeriod } = Astro.props;
+const latestPeriodNumber =
+  typeof latestPeriod === "number" ? latestPeriod : null;
+const coversLatest =
+  latestPeriodNumber !== null &&
+  Array.isArray(dungeon.periods) &&
+  dungeon.periods.includes(latestPeriodNumber);
+const missingLatest =
+  latestPeriodNumber !== null &&
+  (!coversLatest ||
+    (Array.isArray(dungeon.missing_periods) &&
+      dungeon.missing_periods.includes(latestPeriodNumber)));
+
+const latestObserved = (() => {
+  const periods = dungeon.periods || [];
+  const missing = new Set(dungeon.missing_periods || []);
+  const candidates = periods.filter((p) => !missing.has(p));
+  if (candidates.length === 0) {
+    return null;
+  }
+  return candidates.reduce(
+    (max, val) => (val > max ? val : max),
+    candidates[0],
+  );
+})();
+
+const dungeonIconUrl = getDungeonIconUrl(
+  dungeon.dungeon_slug,
+  dungeon.dungeon_name,
+);
+---
+
+<li
+  class={`status-dungeon ${
+    coversLatest ? "status-dungeon--latest" : ""
+  } ${missingLatest ? "status-dungeon--missing" : ""}`}
+>
+  <div class="status-dungeon__head">
+    <span class="status-dungeon__name">
+      {
+        dungeonIconUrl && (
+          <img
+            src={dungeonIconUrl}
+            alt={dungeon.dungeon_name}
+            loading="lazy"
+            class="status-dungeon__icon"
+          />
+        )
+      }
+      {dungeon.dungeon_name}
+    </span>
+  </div>
+
+  <p class="status-dungeon__latest">
+    Latest period seen: {latestObserved ?? "None"}
+  </p>
+</li>

diff --git a/web/src/components/Status/Statu
sDungeonContainer/StatusDungeonContainer.ast
ro b/web/src/components/Status/StatusDungeon
Container/StatusDungeonContainer.astro
new file mode 100644
index 0000000..b76bef3
--- /dev/null
+++ b/web/src/components/Status/StatusDungeo
nContainer/StatusDungeonContainer.astro
@@ -0,0 +1,69 @@
+---
+import type { CoverageHealth, DungeonCovera
ge } from "../../../lib/types";
+import "./StatusDungeonContainer.scss";
+import { getDungeonIconUrl } from "../../..
/lib/dungeonIcons";
+
+interface Props {
+  dungeon: DungeonCoverage;
+  healthLabels: Record<CoverageHealth, stri
ng>;
+  formatList: (items?: number[]) => string;
+  latestPeriod?: number | null;
+}
+
+const { dungeon, healthLabels, formatList, 
latestPeriod } = Astro.props;
+const latestPeriodNumber =
+  typeof latestPeriod === "number" ? latest
Period : null;
+const coversLatest =
+  latestPeriodNumber !== null &&
+  Array.isArray(dungeon.periods) &&
+  dungeon.periods.includes(latestPeriodNumb
er);
+const missingLatest =
+  latestPeriodNumber !== null &&
+  (!coversLatest ||
+    (Array.isArray(dungeon.missing_periods)
 &&
+      dungeon.missing_periods.includes(late
stPeriodNumber)));
+
+const latestObserved = (() => {
+  const periods = dungeon.periods || [];
+  const missing = new Set(dungeon.missing_p
eriods || []);
+  const candidates = periods.filter((p) => 
!missing.has(p));
+  if (candidates.length === 0) {
+    return null;
+  }
+  return candidates.reduce(
+    (max, val) => (val > max ? val : max),
+    candidates[0],
+  );
+})();
+
+const dungeonIconUrl = getDungeonIconUrl(
+  dungeon.dungeon_slug,
+  dungeon.dungeon_name,
+);
+---
+
+<li
+  class={`status-dungeon ${
+    coversLatest ? "status-dungeon--latest"
 : ""
+  } ${missingLatest ? "status-dungeon--miss
ing" : ""}`}
+>
+  <div class="status-dungeon__head">
+    <span class="status-dungeon__name">
+      {
+        dungeonIconUrl && (
+          <img
+            src={dungeonIconUrl}
+            alt={dungeon.dungeon_name}
+            loading="lazy"
+            class="status-dungeon__icon"
+          />
+        )
+      }
+      {dungeon.dungeon_name}
+    </span>
+  </div>
+
+  <p class="status-dungeon__latest">
+    Latest period seen: {latestObserved ?? 
"None"}
+  </p>
+</li>
 

diff --git a/web/src/components/Status/StatusDungeonContainer/StatusDungeonContain
er.scss b/web/src/components/Status/StatusDungeonContainer/StatusDungeonContainer.
scss
new file mode 100644
index 0000000..db1b7e0
--- /dev/null
+++ b/web/src/components/Status/StatusDungeonContainer/StatusDungeonContainer.scss
@@ -0,0 +1,71 @@
+@use "../../../styles/core/tokens" as *;
+
+.status-dungeon {
+  border: 1px solid var(--border-color);
+  border-radius: $radius-md;
+  padding: $spacing-sm;
+  background: rgba(255, 255, 255, 0.01);
+  list-style: none;
+  display: flex;
+  flex-direction: column;
+  gap: $spacing-xs;
+}
+
+.status-dungeon--latest {
+  border-color: var(--success-color);
+}
+
+.status-dungeon__head {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  gap: $spacing-xs;
+}
+
+.status-dungeon__name {
+  font-weight: 600;
+  display: flex;
+  align-items: center;
+  gap: $spacing-xs;
+}
+
+.status-dungeon__icon {
+  width: 28px;
+  height: 28px;
+  border-radius: $radius-sm;
+  border: 1px solid rgba(255, 255, 255, 0.1);
+  object-fit: cover;
+}
+
+.status-dungeon__latest {
+  margin: 0;
+  font-size: $font-size-sm;
+  color: var(--text-secondary);
+}
+
+.status-dungeon__badges {
+  display: flex;
+  flex-wrap: wrap;
+  gap: $spacing-xs;
+}
+
+.status-dungeon__badge {
+  padding: 2px 8px;
+  border-radius: $radius-sm;
+  font-size: $font-size-xs;
+  font-weight: 600;
+  text-transform: uppercase;
+}
+
+.status-dungeon__badge--positive {
+  background: rgba(56, 187, 92, 0.15);
+  color: var(--success-color);
+}
+
+.status-dungeon__badge--negative {
+  background: rgba(239, 68, 68, 0.15);
+  color: var(--error-color);
+}
+.status-dungeon--missing {
+  border-color: var(--error-color);
+}

diff --git a/web/src/components/Status/Statu
sDungeonContainer/StatusDungeonContainer.scs
s b/web/src/components/Status/StatusDungeonC
ontainer/StatusDungeonContainer.scss
new file mode 100644
index 0000000..db1b7e0
--- /dev/null
+++ b/web/src/components/Status/StatusDungeo
nContainer/StatusDungeonContainer.scss
@@ -0,0 +1,71 @@
+@use "../../../styles/core/tokens" as *;
+
+.status-dungeon {
+  border: 1px solid var(--border-color);
+  border-radius: $radius-md;
+  padding: $spacing-sm;
+  background: rgba(255, 255, 255, 0.01);
+  list-style: none;
+  display: flex;
+  flex-direction: column;
+  gap: $spacing-xs;
+}
+
+.status-dungeon--latest {
+  border-color: var(--success-color);
+}
+
+.status-dungeon__head {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  gap: $spacing-xs;
+}
+
+.status-dungeon__name {
+  font-weight: 600;
+  display: flex;
+  align-items: center;
+  gap: $spacing-xs;
+}
+
+.status-dungeon__icon {
+  width: 28px;
+  height: 28px;
+  border-radius: $radius-sm;
+  border: 1px solid rgba(255, 255, 255, 0.1
);
+  object-fit: cover;
+}
+
+.status-dungeon__latest {
+  margin: 0;
+  font-size: $font-size-sm;
+  color: var(--text-secondary);
+}
+
+.status-dungeon__badges {
+  display: flex;
+  flex-wrap: wrap;
+  gap: $spacing-xs;
+}
+
+.status-dungeon__badge {
+  padding: 2px 8px;
+  border-radius: $radius-sm;
+  font-size: $font-size-xs;
+  font-weight: 600;
+  text-transform: uppercase;
+}
+
+.status-dungeon__badge--positive {
+  background: rgba(56, 187, 92, 0.15);
+  color: var(--success-color);
+}
+
+.status-dungeon__badge--negative {
+  background: rgba(239, 68, 68, 0.15);
+  color: var(--error-color);
+}
+.status-dungeon--missing {
+  border-color: var(--error-color);
+}
 

diff --git a/web/src/components/Status/StatusRealmContainer/StatusRealmContainer.a
stro b/web/src/components/Status/StatusRealmContainer/StatusRealmContainer.astro
new file mode 100644
index 0000000..5791995
--- /dev/null
+++ b/web/src/components/Status/StatusRealmContainer/StatusRealmContainer.astro
@@ -0,0 +1,74 @@
+---
+import type { CoverageHealth, RealmCoverage } from "../../../lib/types";
+import StatusDungeonContainer from "../StatusDungeonContainer/StatusDungeonContai
ner.astro";
+import "./StatusRealmContainer.scss";
+
+interface Props {
+  realm: RealmCoverage;
+  healthLabels: Record<CoverageHealth, string>;
+  formatList: (items?: number[]) => string;
+  latestPeriod?: number | null;
+}
+
+const { realm, healthLabels, formatList, latestPeriod } = Astro.props;
+
+const regionLabel = realm.region.toUpperCase();
+const latestPeriodNumber =
+  typeof latestPeriod === "number" ? latestPeriod : null;
+const hasGoodLatest =
+  latestPeriodNumber !== null &&
+  realm.dungeons.some((d) => {
+    const periods = d.periods || [];
+    const missing = d.missing_periods || [];
+    return (
+      periods.includes(latestPeriodNumber) &&
+      !missing.includes(latestPeriodNumber)
+    );
+  });
+
+const latestMissing =
+  !hasGoodLatest &&
+  latestPeriodNumber !== null &&
+  realm.dungeons.some((d) =>
+    (d.missing_periods || []).includes(latestPeriodNumber),
+  );
+
+const derivedHealth: CoverageHealth =
+  latestPeriodNumber !== null
+    ? hasGoodLatest
+      ? "ok"
+      : latestMissing
+        ? "some_missing"
+        : realm.health
+    : realm.health;
+const healthLabel = healthLabels[derivedHealth];
+---
+
+<article
+  class={`status-realm ${
+    hasGoodLatest
+      ? "status-realm--healthy"
+      : latestMissing
+        ? "status-realm--missing"
+        : ""
+  }`}
+>
+  <header class="status-realm__header">
+    <div>
+      <h3>{realm.realm_name}</h3>
+    </div>
+  </header>
+
+  <ul class="status-realm__dungeons">
+    {
+      realm.dungeons.map((dungeon) => (
+        <StatusDungeonContainer
+          dungeon={dungeon}
+          formatList={formatList}
+          healthLabels={healthLabels}
+          latestPeriod={latestPeriodNumber}
+        />
+      ))
+    }
+  </ul>
+</article>

diff --git a/web/src/components/Status/Statu
sRealmContainer/StatusRealmContainer.astro b
/web/src/components/Status/StatusRealmContai
ner/StatusRealmContainer.astro
new file mode 100644
index 0000000..5791995
--- /dev/null
+++ b/web/src/components/Status/StatusRealmC
ontainer/StatusRealmContainer.astro
@@ -0,0 +1,74 @@
+---
+import type { CoverageHealth, RealmCoverage
 } from "../../../lib/types";
+import StatusDungeonContainer from "../Stat
usDungeonContainer/StatusDungeonContainer.as
tro";
+import "./StatusRealmContainer.scss";
+
+interface Props {
+  realm: RealmCoverage;
+  healthLabels: Record<CoverageHealth, stri
ng>;
+  formatList: (items?: number[]) => string;
+  latestPeriod?: number | null;
+}
+
+const { realm, healthLabels, formatList, la
testPeriod } = Astro.props;
+
+const regionLabel = realm.region.toUpperCas
e();
+const latestPeriodNumber =
+  typeof latestPeriod === "number" ? latest
Period : null;
+const hasGoodLatest =
+  latestPeriodNumber !== null &&
+  realm.dungeons.some((d) => {
+    const periods = d.periods || [];
+    const missing = d.missing_periods || []
;
+    return (
+      periods.includes(latestPeriodNumber) 
&&
+      !missing.includes(latestPeriodNumber)
+    );
+  });
+
+const latestMissing =
+  !hasGoodLatest &&
+  latestPeriodNumber !== null &&
+  realm.dungeons.some((d) =>
+    (d.missing_periods || []).includes(late
stPeriodNumber),
+  );
+
+const derivedHealth: CoverageHealth =
+  latestPeriodNumber !== null
+    ? hasGoodLatest
+      ? "ok"
+      : latestMissing
+        ? "some_missing"
+        : realm.health
+    : realm.health;
+const healthLabel = healthLabels[derivedHea
lth];
+---
+
+<article
+  class={`status-realm ${
+    hasGoodLatest
+      ? "status-realm--healthy"
+      : latestMissing
+        ? "status-realm--missing"
+        : ""
+  }`}
+>
+  <header class="status-realm__header">
+    <div>
+      <h3>{realm.realm_name}</h3>
+    </div>
+  </header>
+
+  <ul class="status-realm__dungeons">
+    {
+      realm.dungeons.map((dungeon) => (
+        <StatusDungeonContainer
+          dungeon={dungeon}
+          formatList={formatList}
+          healthLabels={healthLabels}
+          latestPeriod={latestPeriodNumber}
+        />
+      ))
+    }
+  </ul>
+</article>
 

diff --git a/web/src/components/Status/StatusRealmContainer/StatusRealmContainer.s
css b/web/src/components/Status/StatusRealmContainer/StatusRealmContainer.scss
new file mode 100644
index 0000000..7602229
--- /dev/null
+++ b/web/src/components/Status/StatusRealmContainer/StatusRealmContainer.scss
@@ -0,0 +1,52 @@
+@use "../../../styles/core/tokens" as *;
+
+.status-realm {
+  border-radius: $radius-lg;
+  border: 1px solid var(--border-color);
+  background: rgba(255, 255, 255, 0.02);
+  padding: $spacing-sm $spacing-md;
+  display: flex;
+  flex-direction: column;
+  gap: $spacing-sm;
+  min-height: 160px;
+}
+
+.status-realm__header {
+  display: flex;
+  justify-content: space-between;
+  gap: $spacing-md;
+  align-items: flex-start;
+
+  h3 {
+    margin: 0;
+    font-size: 1.2rem;
+  }
+}
+
+.status-realm__region {
+  font-size: $font-size-xs;
+  letter-spacing: 0.12em;
+  text-transform: uppercase;
+  color: var(--text-secondary);
+}
+
+.status-realm__meta {
+  margin: $spacing-xs 0 0;
+  color: var(--text-secondary);
+  font-size: $font-size-sm;
+}
+
+.status-realm__dungeons {
+  list-style: none;
+  padding: 0;
+  margin: $spacing-sm 0 0;
+  display: flex;
+  flex-direction: column;
+  gap: $spacing-sm;
+}
+
+@media (max-width: 768px) {
+  .status-realm__header {
+    flex-direction: column;
+  }
+}

diff --git a/web/src/components/Status/Statu
sRealmContainer/StatusRealmContainer.scss b/
web/src/components/Status/StatusRealmContain
er/StatusRealmContainer.scss
new file mode 100644
index 0000000..7602229
--- /dev/null
+++ b/web/src/components/Status/StatusRealmC
ontainer/StatusRealmContainer.scss
@@ -0,0 +1,52 @@
+@use "../../../styles/core/tokens" as *;
+
+.status-realm {
+  border-radius: $radius-lg;
+  border: 1px solid var(--border-color);
+  background: rgba(255, 255, 255, 0.02);
+  padding: $spacing-sm $spacing-md;
+  display: flex;
+  flex-direction: column;
+  gap: $spacing-sm;
+  min-height: 160px;
+}
+
+.status-realm__header {
+  display: flex;
+  justify-content: space-between;
+  gap: $spacing-md;
+  align-items: flex-start;
+
+  h3 {
+    margin: 0;
+    font-size: 1.2rem;
+  }
+}
+
+.status-realm__region {
+  font-size: $font-size-xs;
+  letter-spacing: 0.12em;
+  text-transform: uppercase;
+  color: var(--text-secondary);
+}
+
+.status-realm__meta {
+  margin: $spacing-xs 0 0;
+  color: var(--text-secondary);
+  font-size: $font-size-sm;
+}
+
+.status-realm__dungeons {
+  list-style: none;
+  padding: 0;
+  margin: $spacing-sm 0 0;
+  display: flex;
+  flex-direction: column;
+  gap: $spacing-sm;
+}
+
+@media (max-width: 768px) {
+  .status-realm__header {
+    flex-direction: column;
+  }
+}
 

diff --git a/web/src/components/Status/StatusRunsTable/StatusRunsTable.astro b/web
/src/components/Status/StatusRunsTable/StatusRunsTable.astro
deleted file mode 100644
index 4f93848..0000000
--- a/web/src/components/Status/StatusRunsTable/StatusRunsTable.astro
+++ /dev/null
@@ -1,87 +0,0 @@
----
-import type { LatestRunEntry } from "../../../lib/types";
-import Table from "../../Table/Table.astro";
-import TableRow from "../../Table/TableRow.astro";
-import TableCell from "../../Table/TableCell.astro";
-import { formatDurationMMSS } from "../../../lib/utils";
-import { getDungeonIconUrl } from "../../../lib/dungeonIcons";
-import TeamComposition from "../../Leaderboard/TeamComposition/TeamComposition.as
tro";
-import "./StatusRunsTable.scss";
-
-interface Props {
-  runs: LatestRunEntry[];
-}
-
-const { runs = [] } = Astro.props;
-
-const timeAgo = (timestamp: number) => {
-  if (!timestamp) return "";
-  const sec = Math.max(0, Math.floor((Date.now() - timestamp) / 1000));
-  const mins = Math.floor(sec / 60);
-  const hours = Math.floor(mins / 60);
-  const days = Math.floor(hours / 24);
-  if (days > 0) return `${days}d ago`;
-  if (hours > 0) return `${hours}h ago`;
-  if (mins > 0) return `${mins}m ago`;
-  return `${sec}s ago`;
-};
----
-
-<Table mode="status">
-  <!-- Header slot -->
-  <div slot="header" class="table-header-cell">Dungeon</div>
-  <div slot="header" class="table-header-cell">Time</div>
-  <div slot="header" class="table-header-cell">Team</div>
-  <div slot="header" class="table-header-cell">Realm</div>
-  <div slot="header" class="table-header-cell">Last Run</div>
-  <div slot="header" class="table-header-cell">Period</div>
-
-  <!-- Body (default slot) -->
-  {
-    runs.length > 0 ? (
-      runs.map((run) => {
-        const duration = formatDurationMMSS(run.latest_run?.duration_ms || 0);
-        const dungeonIconUrl = getDungeonIconUrl(
-          run.dungeon_slug,
-          run.dungeon_name,
-        );
-        const members = run.latest_run?.members || [];
-        const timestamp = run.most_recent_iso || "";
-        const ago = timeAgo(run.most_recent);
-
-        return (
-          <TableRow data-region={run.region.toLowerCase()}>
-            <TableCell label="Dungeon">
-              <div class="dungeon-cell">
-                {dungeonIconUrl && (
-                  <img
-                    src={dungeonIconUrl}
-                    alt={run.dungeon_name}
-                    class="dungeon-icon"
-                  />
-                )}
-                <span>{run.dungeon_name}</span>
-              </div>
-            </TableCell>
-            <TableCell label="Time">{duration}</TableCell>
-            <TableCell label="Team">
-              <TeamComposition members={members} />
-            </TableCell>
-            <TableCell label="Realm">{run.realm_name}</TableCell>
-            <TableCell label="Last Run">
-              <span class="timestamp-cell">
-                {timestamp}
-                {ago && <span class="time-ago">({ago})</span>}
-              </span>
-            </TableCell>
-            <TableCell label="Period">{run.period_id}</TableCell>
-          </TableRow>
-        );
-      })
-    ) : (
-      <div class="table-empty">
-        <p>No runs found.</p>
-      </div>
-    )
-  }
-</Table>

diff --git a/web/src/components/Status/Statu
sRunsTable/StatusRunsTable.astro b/web/src/c
omponents/Status/StatusRunsTable/StatusRunsT
able.astro
deleted file mode 100644
index 4f93848..0000000
--- a/web/src/components/Status/StatusRunsTa
ble/StatusRunsTable.astro
+++ /dev/null
@@ -1,87 +0,0 @@
----
-import type { LatestRunEntry } from "../../
../lib/types";
-import Table from "../../Table/Table.astro"
;
-import TableRow from "../../Table/TableRow.
astro";
-import TableCell from "../../Table/TableCel
l.astro";
-import { formatDurationMMSS } from "../../.
./lib/utils";
-import { getDungeonIconUrl } from "../../..
/lib/dungeonIcons";
-import TeamComposition from "../../Leaderbo
ard/TeamComposition/TeamComposition.astro";
-import "./StatusRunsTable.scss";
-
-interface Props {
-  runs: LatestRunEntry[];
-}
-
-const { runs = [] } = Astro.props;
-
-const timeAgo = (timestamp: number) => {
-  if (!timestamp) return "";
-  const sec = Math.max(0, Math.floor((Date.
now() - timestamp) / 1000));
-  const mins = Math.floor(sec / 60);
-  const hours = Math.floor(mins / 60);
-  const days = Math.floor(hours / 24);
-  if (days > 0) return `${days}d ago`;
-  if (hours > 0) return `${hours}h ago`;
-  if (mins > 0) return `${mins}m ago`;
-  return `${sec}s ago`;
-};
----
-
-<Table mode="status">
-  <!-- Header slot -->
-  <div slot="header" class="table-header-ce
ll">Dungeon</div>
-  <div slot="header" class="table-header-ce
ll">Time</div>
-  <div slot="header" class="table-header-ce
ll">Team</div>
-  <div slot="header" class="table-header-ce
ll">Realm</div>
-  <div slot="header" class="table-header-ce
ll">Last Run</div>
-  <div slot="header" class="table-header-ce
ll">Period</div>
-
-  <!-- Body (default slot) -->
-  {
-    runs.length > 0 ? (
-      runs.map((run) => {
-        const duration = formatDurationMMSS
(run.latest_run?.duration_ms || 0);
-        const dungeonIconUrl = getDungeonIc
onUrl(
-          run.dungeon_slug,
-          run.dungeon_name,
-        );
-        const members = run.latest_run?.mem
bers || [];
-        const timestamp = run.most_recent_i
so || "";
-        const ago = timeAgo(run.most_recent
);
-
-        return (
-          <TableRow data-region={run.region
.toLowerCase()}>
-            <TableCell label="Dungeon">
-              <div class="dungeon-cell">
-                {dungeonIconUrl && (
-                  <img
-                    src={dungeonIconUrl}
-                    alt={run.dungeon_name}
-                    class="dungeon-icon"
-                  />
-                )}
-                <span>{run.dungeon_name}</s
pan>
-              </div>
-            </TableCell>
-            <TableCell label="Time">{durati
on}</TableCell>
-            <TableCell label="Team">
-              <TeamComposition members={mem
bers} />
-            </TableCell>
-            <TableCell label="Realm">{run.r
ealm_name}</TableCell>
-            <TableCell label="Last Run">
-              <span class="timestamp-cell">
-                {timestamp}
-                {ago && <span class="time-a
go">({ago})</span>}
-              </span>
-            </TableCell>
-            <TableCell label="Period">{run.
period_id}</TableCell>
-          </TableRow>
-        );
-      })
-    ) : (
-      <div class="table-empty">
-        <p>No runs found.</p>
-      </div>
-    )
-  }
-</Table>
 

diff --git a/web/src/components/Status/StatusRunsTable/StatusRunsTable.scss b/web/
src/components/Status/StatusRunsTable/StatusRunsTable.scss
index 5371042..1d559f0 100644
--- a/web/src/components/Status/StatusRunsTable/StatusRunsTable.scss
+++ b/web/src/components/Status/StatusRunsTable/StatusRunsTable.scss
@@ -1,36 +1,116 @@
 @use "../../../styles/core/tokens" as *;
 
-.status-page {
-  max-width: 1200px;
-  margin: 0 auto;
-  padding: $spacing-xl;
+.status-content {
+  display: flex;
+  flex-direction: column;
+  gap: $spacing-lg;
+}
 
-  .page-title {
-    margin: $spacing-sm 0 $spacing-lg 0;
-  }
+.status-empty {
+  padding: $spacing-lg;
+  border-radius: $radius-lg;
+  border: 1px dashed rgba(255, 255, 255, 0.08);
+  background: rgba(255, 255, 255, 0.02);
+  color: var(--text-secondary);
+  text-align: center;
 }
 
-.dungeon-cell {
+.region-section {
+  border: 1px solid var(--border-color);
+  border-radius: $radius-lg;
+  padding: $spacing-sm $spacing-md;
+  margin-bottom: $spacing-lg;
+}
+
+.region-section[open] {
+  background: rgba(255, 255, 255, 0.02);
+}
+
+.region-summary {
   display: flex;
-  align-items: center;
+  justify-content: space-between;
+  align-items: baseline;
   gap: $spacing-sm;
+  font-size: 1.1rem;
+  letter-spacing: 0.08em;
+  text-transform: uppercase;
+  color: var(--text-secondary);
+  cursor: pointer;
+  list-style: none;
 }
 
-.dungeon-icon {
-  width: 24px;
-  height: 24px;
-  border-radius: $radius-sm;
-  flex-shrink: 0;
+.region-summary::-webkit-details-marker {
+  display: none;
 }
 
-.timestamp-cell {
-  display: flex;
-  align-items: center;
-  flex-wrap: wrap;
-  gap: $spacing-xs;
+.region-summary::before {
+  content: "?";
+  margin-right: $spacing-sm;
+  transition: transform 0.2s ease;
+}
+
+.region-section:not([open]) .region-summary::before {
+  transform: rotate(-90deg);
 }
 
-.time-ago {
+.region-summary__latest {
+  font-size: $font-size-sm;
+  text-transform: none;
   color: var(--text-secondary);
+  margin-left: auto;
+}
+
+.region-grid {
+  display: grid;
+  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
+  gap: $spacing-md;
+  margin-top: $spacing-md;
+}
+
+.health-pill {
+  padding: $spacing-xs $spacing-sm;
+  border-radius: $radius-md;
+  border: 1px solid rgba(255, 255, 255, 0.18);
+  font-weight: 600;
   font-size: $font-size-sm;
+  text-transform: uppercase;
+
+  &.health-ok {
+    background: rgba(56, 187, 92, 0.15);
+    color: #6ee7b7;
+  }
+
+  &.health-some_missing {
+    background: rgba(251, 191, 36, 0.15);
+    color: #fcd34d;
+  }
+
+  &.health-no_data {
+    background: rgba(239, 68, 68, 0.15);
+    color: #fca5a5;
+  }
+}
+
+.status-pill {
+  padding: $spacing-xs $spacing-sm;
+  border-radius: $radius-sm;
+  border: 1px solid rgba(255, 255, 255, 0.18);
+  font-weight: 600;
+  font-size: $font-size-xs;
+  text-transform: uppercase;
+
+  &.status-ok {
+    background: rgba(56, 187, 92, 0.15);
+    color: #6ee7b7;
+  }
+
+  &.status-some_missing {
+    background: rgba(251, 191, 36, 0.15);
+    color: #fcd34d;
+  }
+
+  &.status-no_data {
+    background: rgba(239, 68, 68, 0.15);
+    color: #fca5a5;
+  }
 }

diff --git a/web/src/components/Status/Statu
sRunsTable/StatusRunsTable.scss b/web/src/co
mponents/Status/StatusRunsTable/StatusRunsTa
ble.scss
index 5371042..1d559f0 100644
--- a/web/src/components/Status/StatusRunsTa
ble/StatusRunsTable.scss
+++ b/web/src/components/Status/StatusRunsTa
ble/StatusRunsTable.scss
@@ -1,36 +1,116 @@
 @use "../../../styles/core/tokens" as *;
 
-.status-page {
-  max-width: 1200px;
-  margin: 0 auto;
-  padding: $spacing-xl;
+.status-content {
+  display: flex;
+  flex-direction: column;
+  gap: $spacing-lg;
+}
 
-  .page-title {
-    margin: $spacing-sm 0 $spacing-lg 0;
-  }
+.status-empty {
+  padding: $spacing-lg;
+  border-radius: $radius-lg;
+  border: 1px dashed rgba(255, 255, 255, 0.
08);
+  background: rgba(255, 255, 255, 0.02);
+  color: var(--text-secondary);
+  text-align: center;
 }
 
-.dungeon-cell {
+.region-section {
+  border: 1px solid var(--border-color);
+  border-radius: $radius-lg;
+  padding: $spacing-sm $spacing-md;
+  margin-bottom: $spacing-lg;
+}
+
+.region-section[open] {
+  background: rgba(255, 255, 255, 0.02);
+}
+
+.region-summary {
   display: flex;
-  align-items: center;
+  justify-content: space-between;
+  align-items: baseline;
   gap: $spacing-sm;
+  font-size: 1.1rem;
+  letter-spacing: 0.08em;
+  text-transform: uppercase;
+  color: var(--text-secondary);
+  cursor: pointer;
+  list-style: none;
 }
 
-.dungeon-icon {
-  width: 24px;
-  height: 24px;
-  border-radius: $radius-sm;
-  flex-shrink: 0;
+.region-summary::-webkit-details-marker {
+  display: none;
 }
 
-.timestamp-cell {
-  display: flex;
-  align-items: center;
-  flex-wrap: wrap;
-  gap: $spacing-xs;
+.region-summary::before {
+  content: "?";
+  margin-right: $spacing-sm;
+  transition: transform 0.2s ease;
+}
+
+.region-section:not([open]) .region-summary
::before {
+  transform: rotate(-90deg);
 }
 
-.time-ago {
+.region-summary__latest {
+  font-size: $font-size-sm;
+  text-transform: none;
   color: var(--text-secondary);
+  margin-left: auto;
+}
+
+.region-grid {
+  display: grid;
+  grid-template-columns: repeat(auto-fit, m
inmax(320px, 1fr));
+  gap: $spacing-md;
+  margin-top: $spacing-md;
+}
+
+.health-pill {
+  padding: $spacing-xs $spacing-sm;
+  border-radius: $radius-md;
+  border: 1px solid rgba(255, 255, 255, 0.1
8);
+  font-weight: 600;
   font-size: $font-size-sm;
+  text-transform: uppercase;
+
+  &.health-ok {
+    background: rgba(56, 187, 92, 0.15);
+    color: #6ee7b7;
+  }
+
+  &.health-some_missing {
+    background: rgba(251, 191, 36, 0.15);
+    color: #fcd34d;
+  }
+
+  &.health-no_data {
+    background: rgba(239, 68, 68, 0.15);
+    color: #fca5a5;
+  }
+}
+
+.status-pill {
+  padding: $spacing-xs $spacing-sm;
+  border-radius: $radius-sm;
+  border: 1px solid rgba(255, 255, 255, 0.1
8);
+  font-weight: 600;
+  font-size: $font-size-xs;
+  text-transform: uppercase;
+
+  &.status-ok {
+    background: rgba(56, 187, 92, 0.15);
+    color: #6ee7b7;
+  }
+
+  &.status-some_missing {
+    background: rgba(251, 191, 36, 0.15);
+    color: #fcd34d;
+  }
+
+  &.status-no_data {
+    background: rgba(239, 68, 68, 0.15);
+    color: #fca5a5;
+  }
 }
 

diff --git a/web/src/layouts/PageLayout.astro b/web/src/layouts/PageLayout.astro
index ba6bce6..3e1932f 100644
--- a/web/src/layouts/PageLayout.astro
+++ b/web/src/layouts/PageLayout.astro
@@ -59,11 +59,13 @@ const fullUrl = new URL(url, Astro.site || Astro.url.origin).t
oString();
       content={new URL(ogImage, Astro.url.origin).toString()}
     />
   </head>
-  <body>
+  <body class="site-body">
     <WoWClassColors />
     <Navigation />
 
-    <slot />
+    <div class="site-content">
+      <slot />
+    </div>
 
     <Footer />
   </body>

diff --git a/web/src/layouts/PageLayout.astr
o b/web/src/layouts/PageLayout.astro
index ba6bce6..3e1932f 100644
--- a/web/src/layouts/PageLayout.astro
+++ b/web/src/layouts/PageLayout.astro
@@ -59,11 +59,13 @@ const fullUrl = new URL(
url, Astro.site || Astro.url.origin).toStrin
g();
       content={new URL(ogImage, Astro.url.o
rigin).toString()}
     />
   </head>
-  <body>
+  <body class="site-body">
     <WoWClassColors />
     <Navigation />
 
-    <slot />
+    <div class="site-content">
+      <slot />
+    </div>
 
     <Footer />
   </body>
 

diff --git a/web/src/lib/types.ts b/web/src/lib/types.ts
index 521168c..15ed8d5 100644
--- a/web/src/lib/types.ts
+++ b/web/src/lib/types.ts
@@ -225,80 +225,35 @@ export interface FuseSearchResult<T> {
 }
 
 // Status page types
-export interface LatestRunMember {
-  name: string;
-  spec_id: number;
-  realm_slug: string;
-  region: string;
-}
+export type CoverageHealth = "ok" | "some_missing" | "no_data";
 
-export interface LatestRunDetails {
-  completed_timestamp: number;
-  duration_ms: number;
-  keystone_level: number;
-  members: LatestRunMember[];
-}
-
-export interface LatestRunEntry {
-  region: string;
-  realm_slug: string;
-  realm_name: string;
-  realm_id: number;
-  most_recent: number;
-  most_recent_iso: string;
-  period_id: string;
-  dungeon_slug: string;
-  dungeon_name: string;
-  run_count: number;
-  has_runs: boolean;
-  latest_run: LatestRunDetails;
-}
-
-export interface PeriodCoverage {
-  period_id: string;
-  has_runs: boolean;
-  latest_ts: number;
-  latest_iso: string;
-  run_count: number;
-}
-
-export interface DungeonStatus {
+export interface DungeonCoverage {
+  dungeon_id: number;
   dungeon_slug: string;
   dungeon_name: string;
-  latest_ts: number;
-  latest_iso: string;
-  latest_period: string;
-  periods: PeriodCoverage[];
-  missing_periods: string[];
-  latest_run?: LatestRunDetails;
+  status: CoverageHealth;
+  periods: number[];
+  missing_periods: number[];
+  error_periods: number[];
 }
 
-export interface RealmStatus {
+export interface RealmCoverage {
   region: string;
   realm_slug: string;
   realm_name: string;
-  realm_id: number;
-  dungeons: DungeonStatus[];
+  health: CoverageHealth;
+  total_periods: number;
+  missing_periods: number;
+  error_periods: number;
+  dungeons: DungeonCoverage[];
 }
 
 export interface StatusApiResponse {
-  generated_at: number;
-  periods: string[];
-  summary: {
-    endpoints_tested: number;
-    success: number;
-    failed: number;
-  };
-  latest_runs: LatestRunEntry[];
-  realm_status: RealmStatus[];
+  generated_at: string;
+  realms: RealmCoverage[];
 }
 
 export interface RealmStatusApiResponse {
-  generated_at: number;
-  region: string;
-  realm_slug: string;
-  realm_name: string;
-  realm_id: number;
-  periods: string[];
-  dungeons: DungeonStatus[];
+  generated_at: string;
+  realm: RealmCoverage;
 }

diff --git a/web/src/lib/types.ts b/web/src/
lib/types.ts
index 521168c..15ed8d5 100644
--- a/web/src/lib/types.ts
+++ b/web/src/lib/types.ts
@@ -225,80 +225,35 @@ export interface FuseS
earchResult<T> {
 }
 
 // Status page types
-export interface LatestRunMember {
-  name: string;
-  spec_id: number;
-  realm_slug: string;
-  region: string;
-}
+export type CoverageHealth = "ok" | "some_m
issing" | "no_data";
 
-export interface LatestRunDetails {
-  completed_timestamp: number;
-  duration_ms: number;
-  keystone_level: number;
-  members: LatestRunMember[];
-}
-
-export interface LatestRunEntry {
-  region: string;
-  realm_slug: string;
-  realm_name: string;
-  realm_id: number;
-  most_recent: number;
-  most_recent_iso: string;
-  period_id: string;
-  dungeon_slug: string;
-  dungeon_name: string;
-  run_count: number;
-  has_runs: boolean;
-  latest_run: LatestRunDetails;
-}
-
-export interface PeriodCoverage {
-  period_id: string;
-  has_runs: boolean;
-  latest_ts: number;
-  latest_iso: string;
-  run_count: number;
-}
-
-export interface DungeonStatus {
+export interface DungeonCoverage {
+  dungeon_id: number;
   dungeon_slug: string;
   dungeon_name: string;
-  latest_ts: number;
-  latest_iso: string;
-  latest_period: string;
-  periods: PeriodCoverage[];
-  missing_periods: string[];
-  latest_run?: LatestRunDetails;
+  status: CoverageHealth;
+  periods: number[];
+  missing_periods: number[];
+  error_periods: number[];
 }
 
-export interface RealmStatus {
+export interface RealmCoverage {
   region: string;
   realm_slug: string;
   realm_name: string;
-  realm_id: number;
-  dungeons: DungeonStatus[];
+  health: CoverageHealth;
+  total_periods: number;
+  missing_periods: number;
+  error_periods: number;
+  dungeons: DungeonCoverage[];
 }
 
 export interface StatusApiResponse {
-  generated_at: number;
-  periods: string[];
-  summary: {
-    endpoints_tested: number;
-    success: number;
-    failed: number;
-  };
-  latest_runs: LatestRunEntry[];
-  realm_status: RealmStatus[];
+  generated_at: string;
+  realms: RealmCoverage[];
 }
 
 export interface RealmStatusApiResponse {
-  generated_at: number;
-  region: string;
-  realm_slug: string;
-  realm_name: string;
-  realm_id: number;
-  periods: string[];
-  dungeons: DungeonStatus[];
+  generated_at: string;
+  realm: RealmCoverage;
 }
 

diff --git a/web/src/pages/challenge-mode/status.astro b/web/src/pages/challenge-m
ode/status.astro
index dbfcf6d..4c7e49a 100644
--- a/web/src/pages/challenge-mode/status.astro
+++ b/web/src/pages/challenge-mode/status.astro
@@ -1,13 +1,20 @@
 ---
 import Callout from "../../components/Callout/Callout.astro";
-import StatusRunsTable from "../../components/Status/StatusRunsTable/StatusRunsTa
ble.astro";
 import PageLayout from "../../layouts/PageLayout.astro";
+import PlayerSearch from "../../components/PlayerSearch/PlayerSearch.astro";
 import "../../styles/global.scss";
 import "../../components/Status/StatusRunsTable/StatusRunsTable.scss";
+import "../../components/Leaderboard/LeaderboardHeader/LeaderboardHeader.scss";
+import type {
+  CoverageHealth,
+  RealmCoverage,
+  StatusApiResponse,
+} from "../../lib/types";
 import { readFile } from "node:fs/promises";
 import { join } from "node:path";
+import StatusRealmContainer from "../../components/Status/StatusRealmContainer/St
atusRealmContainer.astro";
+import LeaderboardTypeNav from "../../components/Leaderboard/LeaderboardTypeNav/L
eaderboardTypeNav.astro";
 
-// Load global status data server-side
 const filePath = join(
   process.cwd(),
   "public",
@@ -16,24 +23,123 @@ const filePath = join(
   "latest-runs.json",
 );
 const fileContent = await readFile(filePath, "utf-8");
-const data = JSON.parse(fileContent);
+const data = JSON.parse(fileContent) as StatusApiResponse;
+const realms = Array.isArray(data.realms) ? data.realms : [];
+
+const healthLabels: Record<CoverageHealth, string> = {
+  ok: "OK",
+  some_missing: "Some missing",
+  no_data: "No data",
+};
+
+const formatList = (items?: number[]) =>
+  items && items.length ? items.join(", ") : "None";
+
+const latestPeriodByRegion = realms.reduce<Record<string, number | null>>(
+  (acc, realm) => {
+    const regionKey = realm.region.toUpperCase();
+    let currentMax = acc[regionKey] ?? null;
+    realm.dungeons.forEach((dungeon) => {
+      (dungeon.periods || []).forEach((period) => {
+        if (currentMax === null || period > currentMax) {
+          currentMax = period;
+        }
+      });
+    });
+    acc[regionKey] = currentMax;
+    return acc;
+  },
+  {},
+);
+
+const realmsByRegion = realms.reduce<Record<string, RealmCoverage[]>>(
+  (acc, realm) => {
+    const regionKey = realm.region.toUpperCase();
+    if (!acc[regionKey]) {
+      acc[regionKey] = [];
+    }
+    acc[regionKey].push(realm);
+    acc[regionKey].sort((a, b) => a.realm_name.localeCompare(b.realm_name));
+    return acc;
+  },
+  {},
+);
+
+const regionEntries = Object.entries(realmsByRegion).sort((a, b) =>
+  a[0].localeCompare(b[0]),
+);
 ---
 
 <PageLayout title="Challenge Mode Status">
-  <main class="status-page">
-    <h1 class="page-title">Challenge Mode Global Status</h1>
+  <main class="leaderboard-page">
+    <h1 class="leaderboard-header status-page__title">
+      <span class="header-text">Challenge Mode Fetch Status</span>
+    </h1>
+    <PlayerSearch />
+    <LeaderboardTypeNav currentTab="status" />
 
-    <Callout type="note" title="About">
+    <Callout type="note">
       <p>
-        Showing the latest run for each realm across all dungeons. Data
-        generated at {new Date(data.generated_at).toLocaleString()}.
+        Periods refer to one week long intervals within a challenge mode season.
       </p>
     </Callout>
 
-    <div id="status-content">
-      <StatusRunsTable runs={data.latest_runs} />
+    <div class="status-content">
+      {
+        regionEntries.length === 0 ? (
+          <p class="status-empty">
+            No fetch results have been recorded yet. Run `ookstats fetch cm`
+            first.
+          </p>
+        ) : (
+          regionEntries.map(([region, realms]) => {
+            const latest = latestPeriodByRegion[region] ?? null;
+            return (
+              <details
+                class="region-section"
+                data-region={region.toLowerCase()}
+              >
+                <summary class="region-summary">
+                  <span>{region}</span>
+                  {latest !== null && (
+                    <span class="region-summary__latest">
+                      Latest period: {latest}
+                    </span>
+                  )}
+                </summary>
+                <div class="region-grid">
+                  {realms.map((realm) => (
+                    <StatusRealmContainer
+                      realm={realm}
+                      healthLabels={healthLabels}
+                      formatList={formatList}
+                      latestPeriod={latest}
+                    />
+                  ))}
+                </div>
+              </details>
+            );
+          })
+        )
+      }
     </div>
   </main>
-
-  <script src="../../client/best-runs-decorate.ts"></script>
 </PageLayout>
+
+<style>
+  .leaderboard-page {
+    max-width: 1200px;
+    margin: 0 auto;
+    padding: 20px;
+  }
+
+  .status-page__title {
+    margin-top: 0;
+  }
+
+  @media (max-width: 768px) {
+    .leaderboard-page {
+      padding: 15px;
+    }
+  }
+</style>

diff --git a/web/src/pages/challenge-mode/st
atus.astro b/web/src/pages/challenge-mode/st
atus.astro
index dbfcf6d..4c7e49a 100644
--- a/web/src/pages/challenge-mode/status.as
tro
+++ b/web/src/pages/challenge-mode/status.as
tro
@@ -1,13 +1,20 @@
 ---
 import Callout from "../../components/Callo
ut/Callout.astro";
-import StatusRunsTable from "../../componen
ts/Status/StatusRunsTable/StatusRunsTable.as
tro";
 import PageLayout from "../../layouts/PageL
ayout.astro";
+import PlayerSearch from "../../components/
PlayerSearch/PlayerSearch.astro";
 import "../../styles/global.scss";
 import "../../components/Status/StatusRunsT
able/StatusRunsTable.scss";
+import "../../components/Leaderboard/Leader
boardHeader/LeaderboardHeader.scss";
+import type {
+  CoverageHealth,
+  RealmCoverage,
+  StatusApiResponse,
+} from "../../lib/types";
 import { readFile } from "node:fs/promises"
;
 import { join } from "node:path";
+import StatusRealmContainer from "../../com
ponents/Status/StatusRealmContainer/StatusRe
almContainer.astro";
+import LeaderboardTypeNav from "../../compo
nents/Leaderboard/LeaderboardTypeNav/Leaderb
oardTypeNav.astro";
 
-// Load global status data server-side
 const filePath = join(
   process.cwd(),
   "public",
@@ -16,24 +23,123 @@ const filePath = join(
   "latest-runs.json",
 );
 const fileContent = await readFile(filePath
, "utf-8");
-const data = JSON.parse(fileContent);
+const data = JSON.parse(fileContent) as Sta
tusApiResponse;
+const realms = Array.isArray(data.realms) ?
 data.realms : [];
+
+const healthLabels: Record<CoverageHealth, 
string> = {
+  ok: "OK",
+  some_missing: "Some missing",
+  no_data: "No data",
+};
+
+const formatList = (items?: number[]) =>
+  items && items.length ? items.join(", ") 
: "None";
+
+const latestPeriodByRegion = realms.reduce<
Record<string, number | null>>(
+  (acc, realm) => {
+    const regionKey = realm.region.toUpperC
ase();
+    let currentMax = acc[regionKey] ?? null
;
+    realm.dungeons.forEach((dungeon) => {
+      (dungeon.periods || []).forEach((peri
od) => {
+        if (currentMax === null || period >
 currentMax) {
+          currentMax = period;
+        }
+      });
+    });
+    acc[regionKey] = currentMax;
+    return acc;
+  },
+  {},
+);
+
+const realmsByRegion = realms.reduce<Record
<string, RealmCoverage[]>>(
+  (acc, realm) => {
+    const regionKey = realm.region.toUpperC
ase();
+    if (!acc[regionKey]) {
+      acc[regionKey] = [];
+    }
+    acc[regionKey].push(realm);
+    acc[regionKey].sort((a, b) => a.realm_n
ame.localeCompare(b.realm_name));
+    return acc;
+  },
+  {},
+);
+
+const regionEntries = Object.entries(realms
ByRegion).sort((a, b) =>
+  a[0].localeCompare(b[0]),
+);
 ---
 
 <PageLayout title="Challenge Mode Status">
-  <main class="status-page">
-    <h1 class="page-title">Challenge Mode G
lobal Status</h1>
+  <main class="leaderboard-page">
+    <h1 class="leaderboard-header status-pa
ge__title">
+      <span class="header-text">Challenge M
ode Fetch Status</span>
+    </h1>
+    <PlayerSearch />
+    <LeaderboardTypeNav currentTab="status"
 />
 
-    <Callout type="note" title="About">
+    <Callout type="note">
       <p>
-        Showing the latest run for each rea
lm across all dungeons. Data
-        generated at {new Date(data.generat
ed_at).toLocaleString()}.
+        Periods refer to one week long inte
rvals within a challenge mode season.
       </p>
     </Callout>
 
-    <div id="status-content">
-      <StatusRunsTable runs={data.latest_ru
ns} />
+    <div class="status-content">
+      {
+        regionEntries.length === 0 ? (
+          <p class="status-empty">
+            No fetch results have been reco
rded yet. Run `ookstats fetch cm`
+            first.
+          </p>
+        ) : (
+          regionEntries.map(([region, realm
s]) => {
+            const latest = latestPeriodByRe
gion[region] ?? null;
+            return (
+              <details
+                class="region-section"
+                data-region={region.toLower
Case()}
+              >
+                <summary class="region-summ
ary">
+                  <span>{region}</span>
+                  {latest !== null && (
+                    <span class="region-sum
mary__latest">
+                      Latest period: {lates
t}
+                    </span>
+                  )}
+                </summary>
+                <div class="region-grid">
+                  {realms.map((realm) => (
+                    <StatusRealmContainer
+                      realm={realm}
+                      healthLabels={healthL
abels}
+                      formatList={formatLis
t}
+                      latestPeriod={latest}
+                    />
+                  ))}
+                </div>
+              </details>
+            );
+          })
+        )
+      }
     </div>
   </main>
-
-  <script src="../../client/best-runs-decor
ate.ts"></script>
 </PageLayout>
+
+<style>
+  .leaderboard-page {
+    max-width: 1200px;
+    margin: 0 auto;
+    padding: 20px;
+  }
+
+  .status-page__title {
+    margin-top: 0;
+  }
+
+  @media (max-width: 768px) {
+    .leaderboard-page {
+      padding: 15px;
+    }
+  }
+</style>
 

diff --git a/web/src/styles/core/_tokens.scss b/web/src/styles/core/_tokens.scss
index 8d68fbf..e1a5faf 100644
--- a/web/src/styles/core/_tokens.scss
+++ b/web/src/styles/core/_tokens.scss
@@ -48,6 +48,8 @@ $font-weight-bold: 700;
   --text-muted: #a9a9a9;
   --blue-color: #7daea3;
   --note-color: #7daea3;
+  --error-color: #ea6962;
+  --success-color: #a9b665;
 
   /* WoW Class Colors */
   --class-death-knight: #c41e3a;

diff --git a/web/src/styles/core/_tokens.scs
s b/web/src/styles/core/_tokens.scss
index 8d68fbf..e1a5faf 100644
--- a/web/src/styles/core/_tokens.scss
+++ b/web/src/styles/core/_tokens.scss
@@ -48,6 +48,8 @@ $font-weight-bold: 700;
   --text-muted: #a9a9a9;
   --blue-color: #7daea3;
   --note-color: #7daea3;
+  --error-color: #ea6962;
+  --success-color: #a9b665;
 
   /* WoW Class Colors */
   --class-death-knight: #c41e3a;
 

diff --git a/web/src/styles/global.scss b/web/src/styles/global.scss
index 9b5d2ac..b584f57 100644
--- a/web/src/styles/global.scss
+++ b/web/src/styles/global.scss
@@ -2,6 +2,11 @@
 @use "./core/utilities";
 @use "./core/best-runs";
 
+html,
+body {
+  min-height: 100%;
+}
+
 body {
   font-family: Arial, sans-serif;
   margin: 0;
@@ -10,6 +15,17 @@ body {
   color: var(--text-primary);
 }
 
+.site-body {
+  min-height: 100vh;
+  display: flex;
+  flex-direction: column;
+}
+
+.site-content {
+  flex: 1 0 auto;
+  width: 100%;
+}
+
 .page-header {
   text-align: center;
   padding: 30px 20px;

diff --git a/web/src/styles/global.scss b/we
b/src/styles/global.scss
index 9b5d2ac..b584f57 100644
--- a/web/src/styles/global.scss
+++ b/web/src/styles/global.scss
@@ -2,6 +2,11 @@
 @use "./core/utilities";
 @use "./core/best-runs";
 
+html,
+body {
+  min-height: 100%;
+}
+
 body {
   font-family: Arial, sans-serif;
   margin: 0;
@@ -10,6 +15,17 @@ body {
   color: var(--text-primary);
 }
 
+.site-body {
+  min-height: 100vh;
+  display: flex;
+  flex-direction: column;
+}
+
+.site-content {
+  flex: 1 0 auto;
+  width: 100%;
+}
+
 .page-header {
   text-align: center;
   padding: 30px 20px;
 
[ BACK TO LOG ]
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET