OOKNET                             [ /  search the index  ]  
──────────────────────────────────────────────────────────────────────────────────────
══════════════════════════════════════════════════════════════════════════════════════
OOKNET   [ /  search  ]  
────────────────────────────────────────────────
════════════════════════════════════════════════
 
HASH      37332eeea5fd
DATE      2025-08-04
SUBJECT   web: use astro dynamic routing
FILES     3 CHANGED
HASH      37332eeea5fd
DATE      2025-08-04
SUBJECT   web: use astro dynamic routing
FILES     3 CHANGED
 

diff --git a/web/src/pages/challenge-mode.astro b/web/src/pages/challenge-mode.ast
ro.backup
similarity index 100%
rename from web/src/pages/challenge-mode.astro
rename to web/src/pages/challenge-mode.astro.backup

diff --git a/web/src/pages/challenge-mode.as
tro b/web/src/pages/challenge-mode.astro.bac
kup
similarity index 100%
rename from web/src/pages/challenge-mode.ast
ro
rename to web/src/pages/challenge-mode.astro
.backup
 

diff --git a/web/src/pages/challenge-mode/[...slug].astro b/web/src/pages/challeng
e-mode/[...slug].astro
new file mode 100644
index 0000000..a8a2477
--- /dev/null
+++ b/web/src/pages/challenge-mode/[...slug].astro
@@ -0,0 +1,822 @@
+---
+import PageLayout from "../../components/PageLayout.astro";
+import ControlPanel from "../../components/ControlPanel.astro";
+import FormSelect from "../../components/FormSelect.astro";
+import LoadingState from "../../components/LoadingState.astro";
+import WoWClassColors from "../../components/WoWClassColors.astro";
+
+const baseUrl = import.meta.env.BASE_URL;
+
+export async function getStaticPaths() {
+  const DATA_MAP = {
+    us: {
+      realms: {
+        angerforge: "Angerforge",
+        arugal: "Arugal",
+        ashkandi: "Ashkandi", 
+        atiesh: "Atiesh",
+        azursong: "Azuresong",
+        benediction: "Benediction",
+        bloodsailBuccaneers: "Bloodsail Buccaneers",
+        earthfury: "Earthfury",
+        eranikus: "Eranikus",
+        faerlina: "Faerlina",
+        grobbulus: "Grobbulus",
+        maladath: "Maladath",
+        mankrik: "Mankrik",
+        myzrael: "Myzrael",
+        old_blanchy: "Old Blanchy",
+        pagle: "Pagle",
+        remulos: "Remulos",
+        skyfury: "Skyfury",
+        sulfuras: "Sulfuras",
+        westfall: "Westfall",
+        whitemane: "Whitemane",
+        windseeker: "Windseeker",
+        yojamba: "Yojamba",
+      },
+    },
+    eu: {
+      realms: {
+        amnennar: "Amnennar",
+        ashbringer: "Ashbringer",
+        auberdine: "Auberdine",
+        chromie: "Chromie",
+        earthshaker: "Earthshaker",
+        everlook: "Everlook",
+        firemaw: "Firemaw",
+        flamegor: "Flamegor",
+        gehennas: "Gehennas",
+        giantstalker: "Giantstalker",
+        golemagg: "Golemagg",
+        hydraxianWaterlords: "Hydraxian Waterlords",
+        jindo: "Jin'do",
+        lakeshire: "Lakeshire",
+        mandokir: "Mandokir",
+        mirageRaceway: "Mirage Raceway",
+        mograine: "Mograine",
+        nethergardeKeep: "Nethergarde Keep",
+        patchwerk: "Patchwerk",
+        pyrewoodVillage: "Pyrewood Village",
+        razorfen: "Razorfen",
+        sulfuron: "Sulfuron",
+        thekal: "Thekal",
+        transcendence: "Transcendence",
+        venoxis: "Venoxis",
+      },
+    },
+    kr: {
+      realms: {
+        frostmourne: "Frostmourne",
+        iceblood: "Iceblood",
+        lokholar: "Lok'holar",
+        ragnaros: "Ragnaros",
+        shimmeringFlats: "Shimmering Flats",
+      },
+    },
+  };
+
+  const dungeonNames = {
+    "2": "Temple of the Jade Serpent",
+    "56": "Stormstout Brewery", 
+    "57": "Gate of the Setting Sun",
+    "58": "Shado-Pan Monastery",
+    "59": "Siege of Niuzao Temple",
+    "60": "Mogu'shan Palace",
+    "76": "Scholomance",
+    "77": "Scarlet Halls",
+    "78": "Scarlet Monastery",
+  };
+
+  const paths = [];
+
+  // Generate all possible combinations
+  for (const [regionKey, regionData] of Object.entries(DATA_MAP)) {
+    for (const realmKey of Object.keys(regionData.realms)) {
+      for (const [dungeonId, dungeonName] of Object.entries(dungeonNames)) {
+        const dungeonSlug = dungeonName.toLowerCase().replace(/[^a-z0-9]/g, '-');
+        paths.push({
+          params: { 
+            slug: `${regionKey}/${realmKey}/${dungeonSlug}` 
+          },
+          props: {
+            initialRegion: regionKey,
+            initialRealm: realmKey,
+            initialDungeon: dungeonId
+          }
+        });
+      }
+    }
+  }
+
+  return paths;
+}
+
+// Get initial values from props passed by getStaticPaths
+const { initialRegion, initialRealm, initialDungeon } = Astro.props;
+console.log('Initial values from props:', { initialRegion, initialRealm, initialD
ungeon });
+---
+
+<PageLayout
+  title="Challenge Mode Leaderboards"
+  description=""
+  pageTitle="Challenge Mode Leaderboards - MoP Classic"
+>
+  <WoWClassColors />
+
+  <style>
+    .leaderboard-container {
+      background-color: var(--bg-secondary);
+      border-radius: 8px;
+      border: 1px solid var(--border-color);
+      overflow: hidden;
+      margin-top: 20px;
+    }
+
+    .hidden {
+      display: none;
+    }
+
+    .loading-overlay,
+    .error-overlay {
+      position: fixed;
+      top: 50%;
+      left: 50%;
+      transform: translate(-50%, -50%);
+      z-index: 1000;
+      min-width: 300px;
+    }
+
+    #content {
+      min-height: 400px;
+      transition: opacity 0.2s ease;
+    }
+
+    .content-loading {
+      opacity: 0.3;
+      pointer-events: none;
+    }
+
+    .no-data-message {
+      margin: 20px 0;
+    }
+
+    .no-data-content {
+      text-align: center;
+      padding: 40px 20px;
+    }
+
+    .no-data-content h3 {
+      color: var(--highlight-color);
+      margin: 0 0 15px 0;
+      font-size: 1.4em;
+      font-weight: 600;
+    }
+
+    .no-data-content p {
+      color: var(--text-secondary);
+      margin: 0;
+      font-size: 1.1em;
+    }
+
+    #leaderboard-rows {
+      display: table;
+      width: 100%;
+    }
+
+    .info-grid {
+      display: grid;
+      grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+      gap: 15px;
+    }
+
+    .info-item {
+      display: flex;
+      flex-direction: column;
+      gap: 4px;
+    }
+
+    .info-label {
+      font-size: 0.85em;
+      color: var(--text-muted);
+      font-weight: 500;
+      text-transform: uppercase;
+      letter-spacing: 0.5px;
+    }
+
+    .info-value {
+      font-size: 1em;
+      color: var(--text-primary);
+      font-weight: 600;
+    }
+
+    @media (max-width: 768px) {
+      .info-grid {
+        grid-template-columns: 1fr;
+      }
+    }
+    @media (max-width: 1024px) {
+      .leaderboard-header,
+      .leaderboard-row {
+        grid-template-columns: 60px 100px 1fr 80px 120px;
+        gap: 15px;
+      }
+
+      .player {
+        min-width: 75px;
+        font-size: 0.75em;
+      }
+    }
+
+    @media (max-width: 768px) {
+      .container {
+        padding: 10px;
+      }
+
+      .leaderboard-header,
+      .leaderboard-row {
+        grid-template-columns: 1fr;
+        gap: 10px;
+        text-align: center;
+        padding: 10px 15px;
+      }
+
+      .team-composition {
+        justify-content: center;
+      }
+
+      .player {
+        min-width: 70px;
+        font-size: 0.75em;
+      }
+
+      .controls-grid {
+        flex-direction: column;
+      }
+
+      .rank,
+      .duration,
+      .mythic-rating,
+      .completed-time {
+        font-size: 1.1em;
+        margin: 5px 0;
+      }
+    }
+
+    /* Callout component styles */
+    .callout {
+      background-color: #2a3a3a;
+      border: 1px solid #458588;
+      border-left: 4px solid #458588;
+      border-radius: 6px;
+      padding: 16px;
+      margin-bottom: 20px;
+    }
+
+    .callout-header {
+      display: flex;
+      align-items: center;
+      gap: 10px;
+      margin-bottom: 8px;
+    }
+
+    .callout-icon {
+      width: 20px;
+      height: 20px;
+      color: #458588;
+      flex-shrink: 0;
+    }
+
+    .callout-title {
+      color: #458588;
+      margin: 0;
+      font-size: 1em;
+      font-weight: 600;
+    }
+
+    .callout-content {
+      color: var(--text-primary);
+      line-height: 1.5;
+      margin-left: 30px;
+    }
+
+    .callout-content p {
+      margin: 0 0 8px 0;
+    }
+
+    .callout-content p:last-child {
+      margin-bottom: 0;
+    }
+
+    .callout-content a {
+      color: #458588;
+      text-decoration: none;
+    }
+
+    .callout-content a:hover {
+      text-decoration: underline;
+    }
+
+    .callout-content strong {
+      color: #458588;
+    }
+
+    .callout-content code {
+      background-color: rgba(255, 255, 255, 0.1);
+      padding: 2px 4px;
+      border-radius: 3px;
+      font-family: "Courier New", monospace;
+      font-size: 0.9em;
+    }
+  </style>
+
+  <ControlPanel title="Leaderboard Options">
+    <FormSelect
+      id="region"
+      label="Region"
+      options={[
+        { value: "us", label: "US", selected: initialRegion === "us" },
+        { value: "eu", label: "EU", selected: initialRegion === "eu" },
+        { value: "kr", label: "KR", selected: initialRegion === "kr" },
+      ]}
+    />
+    <FormSelect id="realm" label="Realm" options={[]} />
+    <FormSelect
+      id="dungeon"
+      label="Dungeon"
+      options={[
+        { value: "2", label: "Temple of the Jade Serpent", selected: initialDunge
on === "2" },
+        { value: "56", label: "Stormstout Brewery", selected: initialDungeon === 
"56" },
+        { value: "57", label: "Gate of the Setting Sun", selected: initialDungeon
 === "57" },
+        { value: "58", label: "Shado-Pan Monastery", selected: initialDungeon ===
 "58" },
+        { value: "59", label: "Siege of Niuzao Temple", selected: initialDungeon 
=== "59" },
+        { value: "60", label: "Mogu'shan Palace", selected: initialDungeon === "6
0" },
+        { value: "76", label: "Scholomance", selected: initialDungeon === "76" },
+        { value: "77", label: "Scarlet Halls", selected: initialDungeon === "77" 
},
+        { value: "78", label: "Scarlet Monastery", selected: initialDungeon === "
78" },
+      ]}
+    />
+  </ControlPanel>
+
+  <div id="loading" class="loading-overlay">
+    <LoadingState message="Loading Challenge Mode leaderboard data..." />
+  </div>
+
+  <div id="error" class="error-overlay hidden">
+    <LoadingState type="error" />
+  </div>
+
+  <div id="no-data" class="no-data-message hidden">
+    <div class="card">
+      <div class="no-data-content">
+        <h3>No Times Found</h3>
+        <p>
+          No Challenge Mode times were found for this realm and dungeon
+          combination.
+        </p>
+      </div>
+    </div>
+  </div>
+
+  <div id="content">
+    <div class="card">
+      <div class="info-grid">
+        <div class="info-item">
+          <span class="info-label">Dungeon</span>
+          <span class="info-value" id="dungeon-name">Loading...</span>
+        </div>
+        <div class="info-item">
+          <span class="info-label">Period</span>
+          <span class="info-value" id="period">-</span>
+        </div>
+        <div class="info-item">
+          <span class="info-label">Realm</span>
+          <span class="info-value" id="realm-name">-</span>
+        </div>
+        <div class="info-item">
+          <span class="info-label">Period Start</span>
+          <span class="info-value" id="period-start">-</span>
+        </div>
+        <div class="info-item">
+          <span class="info-label">Period End</span>
+          <span class="info-value" id="period-end">-</span>
+        </div>
+      </div>
+    </div>
+
+    <div class="leaderboard-container">
+      <div id="leaderboard-rows"></div>
+    </div>
+  </div>
+</PageLayout>
+
+<style is:global>
+  /* Global styles for dynamically generated content */
+  #leaderboard-rows .leaderboard-row {
+    display: grid !important;
+    grid-template-columns: 80px 120px 2fr 100px 140px !important;
+    gap: 20px !important;
+    align-items: center !important;
+    padding: 15px 20px !important;
+    border-bottom: 1px solid #4a4a4a !important;
+    min-height: 60px !important;
+  }
+
+  #leaderboard-rows .rank {
+    font-size: 1.2em !important;
+    font-weight: bold !important;
+    text-align: center !important;
+    color: #d8a657 !important;
+  }
+
+  #leaderboard-rows .duration {
+    font-family: "Courier New", monospace !important;
+    font-weight: bold !important;
+    color: #00ff88 !important;
+    text-align: right !important;
+  }
+
+  #leaderboard-rows .team-composition {
+    display: flex !important;
+    flex-wrap: wrap !important;
+    gap: 6px !important;
+    justify-content: flex-start !important;
+    align-items: center !important;
+  }
+
+  #leaderboard-rows .mythic-rating {
+    color: #d8a657 !important;
+    font-weight: bold !important;
+    text-align: center !important;
+  }
+
+  #leaderboard-rows .completed-time {
+    color: #aaaaaa !important;
+    font-size: 0.9em !important;
+    text-align: center !important;
+  }
+
+  @media (max-width: 1024px) {
+    #leaderboard-rows .leaderboard-row {
+      grid-template-columns: 60px 100px 1fr 80px 120px !important;
+      gap: 15px !important;
+    }
+  }
+
+  @media (max-width: 768px) {
+    #leaderboard-rows .leaderboard-row {
+      grid-template-columns: 1fr !important;
+      gap: 10px !important;
+      text-align: center !important;
+      padding: 10px 15px !important;
+    }
+
+    #leaderboard-rows .team-composition {
+      justify-content: center !important;
+    }
+
+    #leaderboard-rows .rank,
+    #leaderboard-rows .duration,
+    #leaderboard-rows .mythic-rating,
+    #leaderboard-rows .completed-time {
+      font-size: 1.1em !important;
+      margin: 5px 0 !important;
+    }
+  }
+</style>
+
+<script is:inline define:vars={{ baseUrl, initialRegion, initialRealm, initialDun
geon }}>
+  const DATA_MAP = {
+    us: {
+      name: "US",
+      realms: {
+        angerforge: "Angerforge",
+        arugal: "Arugal",
+        ashkandi: "Ashkandi",
+        atiesh: "Atiesh",
+        azursong: "Azuresong",
+        benediction: "Benediction",
+        bloodsailBuccaneers: "Bloodsail Buccaneers",
+        earthfury: "Earthfury",
+        eranikus: "Eranikus",
+        faerlina: "Faerlina",
+        grobbulus: "Grobbulus",
+        maladath: "Maladath",
+        mankrik: "Mankrik",
+        myzrael: "Myzrael",
+        old_blanchy: "Old Blanchy",
+        pagle: "Pagle",
+        remulos: "Remulos",
+        skyfury: "Skyfury",
+        sulfuras: "Sulfuras",
+        westfall: "Westfall",
+        whitemane: "Whitemane",
+        windseeker: "Windseeker",
+        yojamba: "Yojamba",
+      },
+    },
+    eu: {
+      name: "EU",
+      realms: {
+        amnennar: "Amnennar",
+        ashbringer: "Ashbringer",
+        auberdine: "Auberdine",
+        chromie: "Chromie",
+        earthshaker: "Earthshaker",
+        everlook: "Everlook",
+        firemaw: "Firemaw",
+        flamegor: "Flamegor",
+        gehennas: "Gehennas",
+        giantstalker: "Giantstalker",
+        golemagg: "Golemagg",
+        hydraxianWaterlords: "Hydraxian Waterlords",
+        jindo: "Jin'do",
+        lakeshire: "Lakeshire",
+        mandokir: "Mandokir",
+        mirageRaceway: "Mirage Raceway",
+        mograine: "Mograine",
+        nethergardeKeep: "Nethergarde Keep",
+        patchwerk: "Patchwerk",
+        pyrewoodVillage: "Pyrewood Village",
+        razorfen: "Razorfen",
+        sulfuron: "Sulfuron",
+        thekal: "Thekal",
+        transcendence: "Transcendence",
+        venoxis: "Venoxis",
+      },
+    },
+    kr: {
+      name: "KR",
+      realms: {
+        frostmourne: "Frostmourne",
+        iceblood: "Iceblood",
+        lokholar: "Lok'holar",
+        ragnaros: "Ragnaros",
+        shimmeringFlats: "Shimmering Flats",
+      },
+    },
+  };
+  // Dungeon name mapping
+  const dungeonNames = {
+    "2": "Temple of the Jade Serpent",
+    "56": "Stormstout Brewery",
+    "57": "Gate of the Setting Sun",
+    "58": "Shado-Pan Monastery",
+    "59": "Siege of Niuzao Temple",
+    "60": "Mogu'shan Palace",
+    "76": "Scholomance",
+    "77": "Scarlet Halls",
+    "78": "Scarlet Monastery",
+  };
+
+  function formatDuration(milliseconds) {
+    const totalSeconds = Math.floor(milliseconds / 1000);
+    const minutes = Math.floor(totalSeconds / 60);
+    const seconds = totalSeconds % 60;
+    return `${minutes}:${seconds.toString().padStart(2, "0")}`;
+  }
+
+  function formatTimestamp(timestamp) {
+    return new Date(timestamp).toLocaleDateString("en-US", {
+      month: "short",
+      day: "numeric",
+      hour: "2-digit",
+      minute: "2-digit",
+    });
+  }
+
+  function createLeaderboardRow(group) {
+    console.log("Creating row for group:", group);
+
+    const row = document.createElement("div");
+    row.className = "leaderboard-row";
+
+    let teamHtml = "";
+    group.members.forEach((member) => {
+      // Handle missing specialization data (deleted/transferred characters)
+      const specId = member.specialization?.id;
+      const spec = specId
+        ? window.WoW.getSpecInfo(specId)
+        : {
+            role: "dps",
+            class: "Unknown",
+            spec: "Unknown",
+          };
+      const iconUrl = window.WoW.getSpecIcon(spec.class, spec.spec);
+      const iconHtml = iconUrl
+        ? `<img src="${iconUrl}" alt="${spec.spec} ${spec.class}" style="width: 1
6px; height: 16px; border-radius: 2px; margin-right: 4px; vertical-align: middle; 
flex-shrink: 0;">`
+        : "";
+
+      teamHtml += `<span style="display: inline-flex; align-items: center; margin
-right: 8px; gap: 4px;">
+        ${iconHtml}
+        <span style="color: ${window.WoW.getClassColor(spec.class)}; font-weight:
 600; font-size: 0.9em;">${member.profile.name}</span>
+      </span>`;
+    });
+
+    row.innerHTML = `
+          <div style="display: table-cell; padding: 15px 10px; vertical-align: mi
ddle; font-size: 1.2em; font-weight: bold; color: #d8a657; text-align: center; wid
th: 80px;">#${group.ranking}</div>
+          <div style="display: table-cell; padding: 15px 10px; vertical-align: mi
ddle; font-family: 'Courier New', monospace; font-weight: bold; color: #ffffff; te
xt-align: right; width: 120px;">${formatDuration(group.duration)}</div>
+          <div style="display: table-cell; padding: 15px 10px; vertical-align: mi
ddle;">${teamHtml}</div>
+          <div style="display: table-cell; padding: 15px 10px; vertical-align: mi
ddle; color: #aaaaaa; font-size: 0.9em; text-align: center; width: 140px;">${forma
tTimestamp(group.completed_timestamp)}</div>
+        `;
+
+    // Apply table-row styles
+    row.style.cssText = `
+          display: table-row !important;
+          border-bottom: 1px solid #4a4a4a !important;
+          background-color: #32302f;
+          transition: background-color 0.2s ease;
+        `;
+
+    // Add hover effect
+    row.addEventListener("mouseenter", () => {
+      row.style.backgroundColor = "rgba(255, 215, 0, 0.05)";
+    });
+    row.addEventListener("mouseleave", () => {
+      row.style.backgroundColor = "#32302f";
+    });
+
+    console.log("Row created:", row);
+    return row;
+  }
+
+  function displayLeaderboard(data) {
+    console.log("Displaying leaderboard data:", data);
+
+    // Check if we have no data (missing or empty leading_groups)
+    if (!data.leading_groups || data.leading_groups.length === 0) {
+      showNoData();
+      return;
+    }
+
+    // Handle localized dungeon names
+    const dungeonName =
+      typeof data.map.name === "object"
+        ? data.map.name.en_US || data.map.name
+        : data.map.name;
+    document.getElementById("dungeon-name").textContent = dungeonName;
+    document.getElementById("period").textContent = data.period;
+    document.getElementById("period-start").textContent = formatTimestamp(
+      data.period_start_timestamp,
+    );
+    document.getElementById("period-end").textContent = formatTimestamp(
+      data.period_end_timestamp,
+    );
+
+    const currentRegion = document.getElementById("region").value;
+    const currentRealm = document.getElementById("realm").value;
+    const regionData = DATA_MAP[currentRegion];
+    const realmName = regionData?.realms?.[currentRealm] || currentRealm;
+    document.getElementById("realm-name").textContent = realmName;
+
+    const rowsContainer = document.getElementById("leaderboard-rows");
+    rowsContainer.innerHTML = "";
+
+    console.log("Creating rows for", data.leading_groups.length, "groups");
+    data.leading_groups.forEach((group, index) => {
+      console.log("Creating row for group", index + 1);
+      const row = createLeaderboardRow(group);
+      rowsContainer.appendChild(row);
+    });
+
+    document.getElementById("loading").classList.add("hidden");
+    document.getElementById("error").classList.add("hidden");
+    document.getElementById("no-data").classList.add("hidden");
+    document.getElementById("content").classList.remove("content-loading");
+    document.getElementById("content").classList.remove("hidden");
+
+    console.log("Leaderboard displayed successfully");
+  }
+
+  function showNoData() {
+    document.getElementById("loading").classList.add("hidden");
+    document.getElementById("error").classList.add("hidden");
+    document.getElementById("no-data").classList.remove("hidden");
+    document.getElementById("content").classList.add("hidden");
+  }
+
+  function showError(message) {
+    const errorDiv = document.getElementById("error");
+    const loadingMessage = errorDiv.querySelector(".loading-message");
+    if (loadingMessage) {
+      loadingMessage.textContent = message;
+    } else {
+      // Fallback if LoadingState structure isn't found
+      errorDiv.innerHTML = `<div class="loading-state error"><p class="loading-me
ssage">${message}</p></div>`;
+    }
+    errorDiv.classList.remove("hidden");
+    document.getElementById("loading").classList.add("hidden");
+    document.getElementById("no-data").classList.add("hidden");
+    document.getElementById("content").classList.add("hidden");
+  }
+
+  function showLoading() {
+    document.getElementById("loading").classList.remove("hidden");
+    document.getElementById("error").classList.add("hidden");
+    document.getElementById("no-data").classList.add("hidden");
+    document.getElementById("content").classList.add("content-loading");
+  }
+
+  function updateRealmOptions() {
+    const region = document.getElementById("region").value;
+    const realmSelect = document.getElementById("realm");
+
+    // Clear existing options
+    realmSelect.innerHTML = "";
+
+    // Add realms for selected region
+    const regionData = DATA_MAP[region];
+    if (regionData && regionData.realms) {
+      Object.entries(regionData.realms).forEach(([slug, name]) => {
+        const option = document.createElement("option");
+        option.value = slug;
+        option.textContent = name;
+        realmSelect.appendChild(option);
+      });
+    }
+  }
+
+  function getDataFileName() {
+    const region = document.getElementById("region").value;
+    const realm = document.getElementById("realm").value;
+    const dungeon = document.getElementById("dungeon").value;
+
+    console.log('Getting data filename with:', { region, realm, dungeon });
+    console.log('Dungeon name lookup:', dungeonNames[dungeon]);
+
+    const dungeonName = dungeonNames[dungeon]
+      .toLowerCase()
+      .replace(/[^a-z0-9]/g, "-");
+    const fileName = `${region}/${realm}/${dungeonName}/${realm}-${dungeonName}-l
eaderboard.json`;
+    console.log('Generated filename:', fileName);
+    return fileName;
+  }
+
+  async function loadLeaderboard() {
+    showLoading();
+
+    try {
+      const fileName = getDataFileName();
+      console.log("Loading file:", fileName);
+      const fullUrl = `${baseUrl}data/challenge-mode/${fileName}`.replace('//', '
/');
+      console.log("Full fetch URL:", fullUrl);
+      const response = await fetch(fullUrl);
+
+      if (!response.ok) {
+        throw new Error(
+          `Failed to load leaderboard data: ${response.statusText}`,
+        );
+      }
+
+      const data = await response.json();
+      console.log("Data loaded:", data);
+      displayLeaderboard(data);
+    } catch (error) {
+      console.error("Error loading leaderboard:", error);
+      showError(`Error loading leaderboard data: ${error.message}`);
+    }
+  }
+
+  function updateURL() {
+    const region = document.getElementById("region").value;
+    const realm = document.getElementById("realm").value;
+    const dungeon = document.getElementById("dungeon").value;
+    
+    const dungeonName = dungeonNames[dungeon]
+      .toLowerCase()
+      .replace(/[^a-z0-9]/g, "-");
+    
+    const newURL = `/challenge-mode/${region}/${realm}/${dungeonName}`;
+    window.history.pushState({}, '', newURL);
+  }
+
+  // Event listeners
+  document.addEventListener("DOMContentLoaded", () => {
+    // Initialize realm options
+    updateRealmOptions();
+
+    // Set initial values from route params
+    document.getElementById("region").value = initialRegion;
+    updateRealmOptions();
+    document.getElementById("realm").value = initialRealm;
+    document.getElementById("dungeon").value = initialDungeon;
+    
+    // Load initial data
+    loadLeaderboard();
+
+    // Bind change events
+    document.getElementById("region").addEventListener("change", () => {
+      updateRealmOptions();
+      updateURL();
+      loadLeaderboard();
+    });
+    document.getElementById("realm").addEventListener("change", () => {
+      updateURL();
+      loadLeaderboard();
+    });
+    document.getElementById("dungeon").addEventListener("change", () => {
+      updateURL();
+      loadLeaderboard();
+    });
+  });
+</script>
\ No newline at end of file

diff --git a/web/src/pages/challenge-mode/[.
..slug].astro b/web/src/pages/challenge-mode
/[...slug].astro
new file mode 100644
index 0000000..a8a2477
--- /dev/null
+++ b/web/src/pages/challenge-mode/[...slug]
.astro
@@ -0,0 +1,822 @@
+---
+import PageLayout from "../../components/Pa
geLayout.astro";
+import ControlPanel from "../../components/
ControlPanel.astro";
+import FormSelect from "../../components/Fo
rmSelect.astro";
+import LoadingState from "../../components/
LoadingState.astro";
+import WoWClassColors from "../../component
s/WoWClassColors.astro";
+
+const baseUrl = import.meta.env.BASE_URL;
+
+export async function getStaticPaths() {
+  const DATA_MAP = {
+    us: {
+      realms: {
+        angerforge: "Angerforge",
+        arugal: "Arugal",
+        ashkandi: "Ashkandi", 
+        atiesh: "Atiesh",
+        azursong: "Azuresong",
+        benediction: "Benediction",
+        bloodsailBuccaneers: "Bloodsail Buc
caneers",
+        earthfury: "Earthfury",
+        eranikus: "Eranikus",
+        faerlina: "Faerlina",
+        grobbulus: "Grobbulus",
+        maladath: "Maladath",
+        mankrik: "Mankrik",
+        myzrael: "Myzrael",
+        old_blanchy: "Old Blanchy",
+        pagle: "Pagle",
+        remulos: "Remulos",
+        skyfury: "Skyfury",
+        sulfuras: "Sulfuras",
+        westfall: "Westfall",
+        whitemane: "Whitemane",
+        windseeker: "Windseeker",
+        yojamba: "Yojamba",
+      },
+    },
+    eu: {
+      realms: {
+        amnennar: "Amnennar",
+        ashbringer: "Ashbringer",
+        auberdine: "Auberdine",
+        chromie: "Chromie",
+        earthshaker: "Earthshaker",
+        everlook: "Everlook",
+        firemaw: "Firemaw",
+        flamegor: "Flamegor",
+        gehennas: "Gehennas",
+        giantstalker: "Giantstalker",
+        golemagg: "Golemagg",
+        hydraxianWaterlords: "Hydraxian Wat
erlords",
+        jindo: "Jin'do",
+        lakeshire: "Lakeshire",
+        mandokir: "Mandokir",
+        mirageRaceway: "Mirage Raceway",
+        mograine: "Mograine",
+        nethergardeKeep: "Nethergarde Keep"
,
+        patchwerk: "Patchwerk",
+        pyrewoodVillage: "Pyrewood Village"
,
+        razorfen: "Razorfen",
+        sulfuron: "Sulfuron",
+        thekal: "Thekal",
+        transcendence: "Transcendence",
+        venoxis: "Venoxis",
+      },
+    },
+    kr: {
+      realms: {
+        frostmourne: "Frostmourne",
+        iceblood: "Iceblood",
+        lokholar: "Lok'holar",
+        ragnaros: "Ragnaros",
+        shimmeringFlats: "Shimmering Flats"
,
+      },
+    },
+  };
+
+  const dungeonNames = {
+    "2": "Temple of the Jade Serpent",
+    "56": "Stormstout Brewery", 
+    "57": "Gate of the Setting Sun",
+    "58": "Shado-Pan Monastery",
+    "59": "Siege of Niuzao Temple",
+    "60": "Mogu'shan Palace",
+    "76": "Scholomance",
+    "77": "Scarlet Halls",
+    "78": "Scarlet Monastery",
+  };
+
+  const paths = [];
+
+  // Generate all possible combinations
+  for (const [regionKey, regionData] of Obj
ect.entries(DATA_MAP)) {
+    for (const realmKey of Object.keys(regi
onData.realms)) {
+      for (const [dungeonId, dungeonName] o
f Object.entries(dungeonNames)) {
+        const dungeonSlug = dungeonName.toL
owerCase().replace(/[^a-z0-9]/g, '-');
+        paths.push({
+          params: { 
+            slug: `${regionKey}/${realmKey}
/${dungeonSlug}` 
+          },
+          props: {
+            initialRegion: regionKey,
+            initialRealm: realmKey,
+            initialDungeon: dungeonId
+          }
+        });
+      }
+    }
+  }
+
+  return paths;
+}
+
+// Get initial values from props passed by 
getStaticPaths
+const { initialRegion, initialRealm, initia
lDungeon } = Astro.props;
+console.log('Initial values from props:', {
 initialRegion, initialRealm, initialDungeon
 });
+---
+
+<PageLayout
+  title="Challenge Mode Leaderboards"
+  description=""
+  pageTitle="Challenge Mode Leaderboards - 
MoP Classic"
+>
+  <WoWClassColors />
+
+  <style>
+    .leaderboard-container {
+      background-color: var(--bg-secondary)
;
+      border-radius: 8px;
+      border: 1px solid var(--border-color)
;
+      overflow: hidden;
+      margin-top: 20px;
+    }
+
+    .hidden {
+      display: none;
+    }
+
+    .loading-overlay,
+    .error-overlay {
+      position: fixed;
+      top: 50%;
+      left: 50%;
+      transform: translate(-50%, -50%);
+      z-index: 1000;
+      min-width: 300px;
+    }
+
+    #content {
+      min-height: 400px;
+      transition: opacity 0.2s ease;
+    }
+
+    .content-loading {
+      opacity: 0.3;
+      pointer-events: none;
+    }
+
+    .no-data-message {
+      margin: 20px 0;
+    }
+
+    .no-data-content {
+      text-align: center;
+      padding: 40px 20px;
+    }
+
+    .no-data-content h3 {
+      color: var(--highlight-color);
+      margin: 0 0 15px 0;
+      font-size: 1.4em;
+      font-weight: 600;
+    }
+
+    .no-data-content p {
+      color: var(--text-secondary);
+      margin: 0;
+      font-size: 1.1em;
+    }
+
+    #leaderboard-rows {
+      display: table;
+      width: 100%;
+    }
+
+    .info-grid {
+      display: grid;
+      grid-template-columns: repeat(auto-fi
t, minmax(200px, 1fr));
+      gap: 15px;
+    }
+
+    .info-item {
+      display: flex;
+      flex-direction: column;
+      gap: 4px;
+    }
+
+    .info-label {
+      font-size: 0.85em;
+      color: var(--text-muted);
+      font-weight: 500;
+      text-transform: uppercase;
+      letter-spacing: 0.5px;
+    }
+
+    .info-value {
+      font-size: 1em;
+      color: var(--text-primary);
+      font-weight: 600;
+    }
+
+    @media (max-width: 768px) {
+      .info-grid {
+        grid-template-columns: 1fr;
+      }
+    }
+    @media (max-width: 1024px) {
+      .leaderboard-header,
+      .leaderboard-row {
+        grid-template-columns: 60px 100px 1
fr 80px 120px;
+        gap: 15px;
+      }
+
+      .player {
+        min-width: 75px;
+        font-size: 0.75em;
+      }
+    }
+
+    @media (max-width: 768px) {
+      .container {
+        padding: 10px;
+      }
+
+      .leaderboard-header,
+      .leaderboard-row {
+        grid-template-columns: 1fr;
+        gap: 10px;
+        text-align: center;
+        padding: 10px 15px;
+      }
+
+      .team-composition {
+        justify-content: center;
+      }
+
+      .player {
+        min-width: 70px;
+        font-size: 0.75em;
+      }
+
+      .controls-grid {
+        flex-direction: column;
+      }
+
+      .rank,
+      .duration,
+      .mythic-rating,
+      .completed-time {
+        font-size: 1.1em;
+        margin: 5px 0;
+      }
+    }
+
+    /* Callout component styles */
+    .callout {
+      background-color: #2a3a3a;
+      border: 1px solid #458588;
+      border-left: 4px solid #458588;
+      border-radius: 6px;
+      padding: 16px;
+      margin-bottom: 20px;
+    }
+
+    .callout-header {
+      display: flex;
+      align-items: center;
+      gap: 10px;
+      margin-bottom: 8px;
+    }
+
+    .callout-icon {
+      width: 20px;
+      height: 20px;
+      color: #458588;
+      flex-shrink: 0;
+    }
+
+    .callout-title {
+      color: #458588;
+      margin: 0;
+      font-size: 1em;
+      font-weight: 600;
+    }
+
+    .callout-content {
+      color: var(--text-primary);
+      line-height: 1.5;
+      margin-left: 30px;
+    }
+
+    .callout-content p {
+      margin: 0 0 8px 0;
+    }
+
+    .callout-content p:last-child {
+      margin-bottom: 0;
+    }
+
+    .callout-content a {
+      color: #458588;
+      text-decoration: none;
+    }
+
+    .callout-content a:hover {
+      text-decoration: underline;
+    }
+
+    .callout-content strong {
+      color: #458588;
+    }
+
+    .callout-content code {
+      background-color: rgba(255, 255, 255,
 0.1);
+      padding: 2px 4px;
+      border-radius: 3px;
+      font-family: "Courier New", monospace
;
+      font-size: 0.9em;
+    }
+  </style>
+
+  <ControlPanel title="Leaderboard Options"
>
+    <FormSelect
+      id="region"
+      label="Region"
+      options={[
+        { value: "us", label: "US", selecte
d: initialRegion === "us" },
+        { value: "eu", label: "EU", selecte
d: initialRegion === "eu" },
+        { value: "kr", label: "KR", selecte
d: initialRegion === "kr" },
+      ]}
+    />
+    <FormSelect id="realm" label="Realm" op
tions={[]} />
+    <FormSelect
+      id="dungeon"
+      label="Dungeon"
+      options={[
+        { value: "2", label: "Temple of the
 Jade Serpent", selected: initialDungeon ===
 "2" },
+        { value: "56", label: "Stormstout B
rewery", selected: initialDungeon === "56" }
,
+        { value: "57", label: "Gate of the 
Setting Sun", selected: initialDungeon === "
57" },
+        { value: "58", label: "Shado-Pan Mo
nastery", selected: initialDungeon === "58" 
},
+        { value: "59", label: "Siege of Niu
zao Temple", selected: initialDungeon === "5
9" },
+        { value: "60", label: "Mogu'shan Pa
lace", selected: initialDungeon === "60" },
+        { value: "76", label: "Scholomance"
, selected: initialDungeon === "76" },
+        { value: "77", label: "Scarlet Hall
s", selected: initialDungeon === "77" },
+        { value: "78", label: "Scarlet Mona
stery", selected: initialDungeon === "78" },
+      ]}
+    />
+  </ControlPanel>
+
+  <div id="loading" class="loading-overlay"
>
+    <LoadingState message="Loading Challeng
e Mode leaderboard data..." />
+  </div>
+
+  <div id="error" class="error-overlay hidd
en">
+    <LoadingState type="error" />
+  </div>
+
+  <div id="no-data" class="no-data-message 
hidden">
+    <div class="card">
+      <div class="no-data-content">
+        <h3>No Times Found</h3>
+        <p>
+          No Challenge Mode times were foun
d for this realm and dungeon
+          combination.
+        </p>
+      </div>
+    </div>
+  </div>
+
+  <div id="content">
+    <div class="card">
+      <div class="info-grid">
+        <div class="info-item">
+          <span class="info-label">Dungeon<
/span>
+          <span class="info-value" id="dung
eon-name">Loading...</span>
+        </div>
+        <div class="info-item">
+          <span class="info-label">Period</
span>
+          <span class="info-value" id="peri
od">-</span>
+        </div>
+        <div class="info-item">
+          <span class="info-label">Realm</s
pan>
+          <span class="info-value" id="real
m-name">-</span>
+        </div>
+        <div class="info-item">
+          <span class="info-label">Period S
tart</span>
+          <span class="info-value" id="peri
od-start">-</span>
+        </div>
+        <div class="info-item">
+          <span class="info-label">Period E
nd</span>
+          <span class="info-value" id="peri
od-end">-</span>
+        </div>
+      </div>
+    </div>
+
+    <div class="leaderboard-container">
+      <div id="leaderboard-rows"></div>
+    </div>
+  </div>
+</PageLayout>
+
+<style is:global>
+  /* Global styles for dynamically generate
d content */
+  #leaderboard-rows .leaderboard-row {
+    display: grid !important;
+    grid-template-columns: 80px 120px 2fr 1
00px 140px !important;
+    gap: 20px !important;
+    align-items: center !important;
+    padding: 15px 20px !important;
+    border-bottom: 1px solid #4a4a4a !impor
tant;
+    min-height: 60px !important;
+  }
+
+  #leaderboard-rows .rank {
+    font-size: 1.2em !important;
+    font-weight: bold !important;
+    text-align: center !important;
+    color: #d8a657 !important;
+  }
+
+  #leaderboard-rows .duration {
+    font-family: "Courier New", monospace !
important;
+    font-weight: bold !important;
+    color: #00ff88 !important;
+    text-align: right !important;
+  }
+
+  #leaderboard-rows .team-composition {
+    display: flex !important;
+    flex-wrap: wrap !important;
+    gap: 6px !important;
+    justify-content: flex-start !important;
+    align-items: center !important;
+  }
+
+  #leaderboard-rows .mythic-rating {
+    color: #d8a657 !important;
+    font-weight: bold !important;
+    text-align: center !important;
+  }
+
+  #leaderboard-rows .completed-time {
+    color: #aaaaaa !important;
+    font-size: 0.9em !important;
+    text-align: center !important;
+  }
+
+  @media (max-width: 1024px) {
+    #leaderboard-rows .leaderboard-row {
+      grid-template-columns: 60px 100px 1fr
 80px 120px !important;
+      gap: 15px !important;
+    }
+  }
+
+  @media (max-width: 768px) {
+    #leaderboard-rows .leaderboard-row {
+      grid-template-columns: 1fr !important
;
+      gap: 10px !important;
+      text-align: center !important;
+      padding: 10px 15px !important;
+    }
+
+    #leaderboard-rows .team-composition {
+      justify-content: center !important;
+    }
+
+    #leaderboard-rows .rank,
+    #leaderboard-rows .duration,
+    #leaderboard-rows .mythic-rating,
+    #leaderboard-rows .completed-time {
+      font-size: 1.1em !important;
+      margin: 5px 0 !important;
+    }
+  }
+</style>
+
+<script is:inline define:vars={{ baseUrl, i
nitialRegion, initialRealm, initialDungeon }
}>
+  const DATA_MAP = {
+    us: {
+      name: "US",
+      realms: {
+        angerforge: "Angerforge",
+        arugal: "Arugal",
+        ashkandi: "Ashkandi",
+        atiesh: "Atiesh",
+        azursong: "Azuresong",
+        benediction: "Benediction",
+        bloodsailBuccaneers: "Bloodsail Buc
caneers",
+        earthfury: "Earthfury",
+        eranikus: "Eranikus",
+        faerlina: "Faerlina",
+        grobbulus: "Grobbulus",
+        maladath: "Maladath",
+        mankrik: "Mankrik",
+        myzrael: "Myzrael",
+        old_blanchy: "Old Blanchy",
+        pagle: "Pagle",
+        remulos: "Remulos",
+        skyfury: "Skyfury",
+        sulfuras: "Sulfuras",
+        westfall: "Westfall",
+        whitemane: "Whitemane",
+        windseeker: "Windseeker",
+        yojamba: "Yojamba",
+      },
+    },
+    eu: {
+      name: "EU",
+      realms: {
+        amnennar: "Amnennar",
+        ashbringer: "Ashbringer",
+        auberdine: "Auberdine",
+        chromie: "Chromie",
+        earthshaker: "Earthshaker",
+        everlook: "Everlook",
+        firemaw: "Firemaw",
+        flamegor: "Flamegor",
+        gehennas: "Gehennas",
+        giantstalker: "Giantstalker",
+        golemagg: "Golemagg",
+        hydraxianWaterlords: "Hydraxian Wat
erlords",
+        jindo: "Jin'do",
+        lakeshire: "Lakeshire",
+        mandokir: "Mandokir",
+        mirageRaceway: "Mirage Raceway",
+        mograine: "Mograine",
+        nethergardeKeep: "Nethergarde Keep"
,
+        patchwerk: "Patchwerk",
+        pyrewoodVillage: "Pyrewood Village"
,
+        razorfen: "Razorfen",
+        sulfuron: "Sulfuron",
+        thekal: "Thekal",
+        transcendence: "Transcendence",
+        venoxis: "Venoxis",
+      },
+    },
+    kr: {
+      name: "KR",
+      realms: {
+        frostmourne: "Frostmourne",
+        iceblood: "Iceblood",
+        lokholar: "Lok'holar",
+        ragnaros: "Ragnaros",
+        shimmeringFlats: "Shimmering Flats"
,
+      },
+    },
+  };
+  // Dungeon name mapping
+  const dungeonNames = {
+    "2": "Temple of the Jade Serpent",
+    "56": "Stormstout Brewery",
+    "57": "Gate of the Setting Sun",
+    "58": "Shado-Pan Monastery",
+    "59": "Siege of Niuzao Temple",
+    "60": "Mogu'shan Palace",
+    "76": "Scholomance",
+    "77": "Scarlet Halls",
+    "78": "Scarlet Monastery",
+  };
+
+  function formatDuration(milliseconds) {
+    const totalSeconds = Math.floor(millise
conds / 1000);
+    const minutes = Math.floor(totalSeconds
 / 60);
+    const seconds = totalSeconds % 60;
+    return `${minutes}:${seconds.toString()
.padStart(2, "0")}`;
+  }
+
+  function formatTimestamp(timestamp) {
+    return new Date(timestamp).toLocaleDate
String("en-US", {
+      month: "short",
+      day: "numeric",
+      hour: "2-digit",
+      minute: "2-digit",
+    });
+  }
+
+  function createLeaderboardRow(group) {
+    console.log("Creating row for group:", 
group);
+
+    const row = document.createElement("div
");
+    row.className = "leaderboard-row";
+
+    let teamHtml = "";
+    group.members.forEach((member) => {
+      // Handle missing specialization data
 (deleted/transferred characters)
+      const specId = member.specialization?
.id;
+      const spec = specId
+        ? window.WoW.getSpecInfo(specId)
+        : {
+            role: "dps",
+            class: "Unknown",
+            spec: "Unknown",
+          };
+      const iconUrl = window.WoW.getSpecIco
n(spec.class, spec.spec);
+      const iconHtml = iconUrl
+        ? `<img src="${iconUrl}" alt="${spe
c.spec} ${spec.class}" style="width: 16px; h
eight: 16px; border-radius: 2px; margin-righ
t: 4px; vertical-align: middle; flex-shrink:
 0;">`
+        : "";
+
+      teamHtml += `<span style="display: in
line-flex; align-items: center; margin-right
: 8px; gap: 4px;">
+        ${iconHtml}
+        <span style="color: ${window.WoW.ge
tClassColor(spec.class)}; font-weight: 600; 
font-size: 0.9em;">${member.profile.name}</s
pan>
+      </span>`;
+    });
+
+    row.innerHTML = `
+          <div style="display: table-cell; 
padding: 15px 10px; vertical-align: middle; 
font-size: 1.2em; font-weight: bold; color: 
#d8a657; text-align: center; width: 80px;">#
${group.ranking}</div>
+          <div style="display: table-cell; 
padding: 15px 10px; vertical-align: middle; 
font-family: 'Courier New', monospace; font-
weight: bold; color: #ffffff; text-align: ri
ght; width: 120px;">${formatDuration(group.d
uration)}</div>
+          <div style="display: table-cell; 
padding: 15px 10px; vertical-align: middle;"
>${teamHtml}</div>
+          <div style="display: table-cell; 
padding: 15px 10px; vertical-align: middle; 
color: #aaaaaa; font-size: 0.9em; text-align
: center; width: 140px;">${formatTimestamp(g
roup.completed_timestamp)}</div>
+        `;
+
+    // Apply table-row styles
+    row.style.cssText = `
+          display: table-row !important;
+          border-bottom: 1px solid #4a4a4a 
!important;
+          background-color: #32302f;
+          transition: background-color 0.2s
 ease;
+        `;
+
+    // Add hover effect
+    row.addEventListener("mouseenter", () =
> {
+      row.style.backgroundColor = "rgba(255
, 215, 0, 0.05)";
+    });
+    row.addEventListener("mouseleave", () =
> {
+      row.style.backgroundColor = "#32302f"
;
+    });
+
+    console.log("Row created:", row);
+    return row;
+  }
+
+  function displayLeaderboard(data) {
+    console.log("Displaying leaderboard dat
a:", data);
+
+    // Check if we have no data (missing or
 empty leading_groups)
+    if (!data.leading_groups || data.leadin
g_groups.length === 0) {
+      showNoData();
+      return;
+    }
+
+    // Handle localized dungeon names
+    const dungeonName =
+      typeof data.map.name === "object"
+        ? data.map.name.en_US || data.map.n
ame
+        : data.map.name;
+    document.getElementById("dungeon-name")
.textContent = dungeonName;
+    document.getElementById("period").textC
ontent = data.period;
+    document.getElementById("period-start")
.textContent = formatTimestamp(
+      data.period_start_timestamp,
+    );
+    document.getElementById("period-end").t
extContent = formatTimestamp(
+      data.period_end_timestamp,
+    );
+
+    const currentRegion = document.getEleme
ntById("region").value;
+    const currentRealm = document.getElemen
tById("realm").value;
+    const regionData = DATA_MAP[currentRegi
on];
+    const realmName = regionData?.realms?.[
currentRealm] || currentRealm;
+    document.getElementById("realm-name").t
extContent = realmName;
+
+    const rowsContainer = document.getEleme
ntById("leaderboard-rows");
+    rowsContainer.innerHTML = "";
+
+    console.log("Creating rows for", data.l
eading_groups.length, "groups");
+    data.leading_groups.forEach((group, ind
ex) => {
+      console.log("Creating row for group",
 index + 1);
+      const row = createLeaderboardRow(grou
p);
+      rowsContainer.appendChild(row);
+    });
+
+    document.getElementById("loading").clas
sList.add("hidden");
+    document.getElementById("error").classL
ist.add("hidden");
+    document.getElementById("no-data").clas
sList.add("hidden");
+    document.getElementById("content").clas
sList.remove("content-loading");
+    document.getElementById("content").clas
sList.remove("hidden");
+
+    console.log("Leaderboard displayed succ
essfully");
+  }
+
+  function showNoData() {
+    document.getElementById("loading").clas
sList.add("hidden");
+    document.getElementById("error").classL
ist.add("hidden");
+    document.getElementById("no-data").clas
sList.remove("hidden");
+    document.getElementById("content").clas
sList.add("hidden");
+  }
+
+  function showError(message) {
+    const errorDiv = document.getElementByI
d("error");
+    const loadingMessage = errorDiv.querySe
lector(".loading-message");
+    if (loadingMessage) {
+      loadingMessage.textContent = message;
+    } else {
+      // Fallback if LoadingState structure
 isn't found
+      errorDiv.innerHTML = `<div class="loa
ding-state error"><p class="loading-message"
>${message}</p></div>`;
+    }
+    errorDiv.classList.remove("hidden");
+    document.getElementById("loading").clas
sList.add("hidden");
+    document.getElementById("no-data").clas
sList.add("hidden");
+    document.getElementById("content").clas
sList.add("hidden");
+  }
+
+  function showLoading() {
+    document.getElementById("loading").clas
sList.remove("hidden");
+    document.getElementById("error").classL
ist.add("hidden");
+    document.getElementById("no-data").clas
sList.add("hidden");
+    document.getElementById("content").clas
sList.add("content-loading");
+  }
+
+  function updateRealmOptions() {
+    const region = document.getElementById(
"region").value;
+    const realmSelect = document.getElement
ById("realm");
+
+    // Clear existing options
+    realmSelect.innerHTML = "";
+
+    // Add realms for selected region
+    const regionData = DATA_MAP[region];
+    if (regionData && regionData.realms) {
+      Object.entries(regionData.realms).for
Each(([slug, name]) => {
+        const option = document.createEleme
nt("option");
+        option.value = slug;
+        option.textContent = name;
+        realmSelect.appendChild(option);
+      });
+    }
+  }
+
+  function getDataFileName() {
+    const region = document.getElementById(
"region").value;
+    const realm = document.getElementById("
realm").value;
+    const dungeon = document.getElementById
("dungeon").value;
+
+    console.log('Getting data filename with
:', { region, realm, dungeon });
+    console.log('Dungeon name lookup:', dun
geonNames[dungeon]);
+
+    const dungeonName = dungeonNames[dungeo
n]
+      .toLowerCase()
+      .replace(/[^a-z0-9]/g, "-");
+    const fileName = `${region}/${realm}/${
dungeonName}/${realm}-${dungeonName}-leaderb
oard.json`;
+    console.log('Generated filename:', file
Name);
+    return fileName;
+  }
+
+  async function loadLeaderboard() {
+    showLoading();
+
+    try {
+      const fileName = getDataFileName();
+      console.log("Loading file:", fileName
);
+      const fullUrl = `${baseUrl}data/chall
enge-mode/${fileName}`.replace('//', '/');
+      console.log("Full fetch URL:", fullUr
l);
+      const response = await fetch(fullUrl)
;
+
+      if (!response.ok) {
+        throw new Error(
+          `Failed to load leaderboard data:
 ${response.statusText}`,
+        );
+      }
+
+      const data = await response.json();
+      console.log("Data loaded:", data);
+      displayLeaderboard(data);
+    } catch (error) {
+      console.error("Error loading leaderbo
ard:", error);
+      showError(`Error loading leaderboard 
data: ${error.message}`);
+    }
+  }
+
+  function updateURL() {
+    const region = document.getElementById(
"region").value;
+    const realm = document.getElementById("
realm").value;
+    const dungeon = document.getElementById
("dungeon").value;
+    
+    const dungeonName = dungeonNames[dungeo
n]
+      .toLowerCase()
+      .replace(/[^a-z0-9]/g, "-");
+    
+    const newURL = `/challenge-mode/${regio
n}/${realm}/${dungeonName}`;
+    window.history.pushState({}, '', newURL
);
+  }
+
+  // Event listeners
+  document.addEventListener("DOMContentLoad
ed", () => {
+    // Initialize realm options
+    updateRealmOptions();
+
+    // Set initial values from route params
+    document.getElementById("region").value
 = initialRegion;
+    updateRealmOptions();
+    document.getElementById("realm").value 
= initialRealm;
+    document.getElementById("dungeon").valu
e = initialDungeon;
+    
+    // Load initial data
+    loadLeaderboard();
+
+    // Bind change events
+    document.getElementById("region").addEv
entListener("change", () => {
+      updateRealmOptions();
+      updateURL();
+      loadLeaderboard();
+    });
+    document.getElementById("realm").addEve
ntListener("change", () => {
+      updateURL();
+      loadLeaderboard();
+    });
+    document.getElementById("dungeon").addE
ventListener("change", () => {
+      updateURL();
+      loadLeaderboard();
+    });
+  });
+</script>
\ No newline at end of file
 

diff --git a/web/src/pages/challenge-mode/index.astro b/web/src/pages/challenge-mo
de/index.astro
new file mode 100644
index 0000000..f3194af
--- /dev/null
+++ b/web/src/pages/challenge-mode/index.astro
@@ -0,0 +1,4 @@
+---
+// Redirect to default challenge mode page
+return Astro.redirect('/challenge-mode/us/angerforge/temple-of-the-jade-serpent')
;
+---
\ No newline at end of file

diff --git a/web/src/pages/challenge-mode/in
dex.astro b/web/src/pages/challenge-mode/ind
ex.astro
new file mode 100644
index 0000000..f3194af
--- /dev/null
+++ b/web/src/pages/challenge-mode/index.ast
ro
@@ -0,0 +1,4 @@
+---
+// Redirect to default challenge mode page
+return Astro.redirect('/challenge-mode/us/a
ngerforge/temple-of-the-jade-serpent');
+---
\ No newline at end of file
 
[ BACK TO LOG ]
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET