OOKNET                             [ /  search the index  ]  
──────────────────────────────────────────────────────────────────────────────────────
══════════════════════════════════════════════════════════════════════════════════════
OOKNET   [ /  search  ]  
────────────────────────────────────────────────
════════════════════════════════════════════════
 
HASH      8554a9275f52
DATE      2025-07-27
SUBJECT   nix: update mage gearsets
FILES     5 CHANGED
HASH      8554a9275f52
DATE      2025-07-27
SUBJECT   nix: update mage gearsets
FILES     5 CHANGED
 

diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 0000000..1a1ff35
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1,206 @@
+# CLAUDE.md
+
+This file provides guidance to Claude Code (claude.ai/code) when working with cod
e in this repository.
+
+## Project Overview
+
+This is a Nix-based data pipeline for generating World of Warcraft simulation lea
derboards and statistics. The project uses the wowsims CLI engine to create a theo
rycrafting website similar to bloodmallet, showing spec performance rankings and t
rinket data for WoW Mists of Pandaria.
+
+### Project Vision
+- Generate spec simulation leaderboards across different encounter types
+- Provide trinket performance data and rankings
+- Serve results via static website with JSON data files
+- Automate updates via GitHub Actions when upstream wowsims changes
+- Use Nix for reproducible builds and server configuration
+
+## Current Development Priorities
+
+### High Priority Tasks
+1. **Chart Web UI Enhancements**
+   - Display detailed loadout information (talents, glyphs, gear) for each charac
ter
+   - Add link to raw JSON input file used for simulation
+   - Future: Generate direct links to wowsims with the character template
+
+2. **Dynamic Buff/Debuff Handling**
+   - Fix warrior and shaman buff inclusion logic
+   - Ensure warriors are part of the 2 skull banners (not in addition to)
+   - Ensure shamans are part of the 4 stormlash totems (not in addition to)
+   - Standardize raid composition buffs across all simulations
+
+3. **Trinket Comparison System**
+   - Implement trinket performance analysis and rankings
+   - Create comparative trinket data for different specs and encounters
+
+### Technical Debt & Configuration Issues
+- Fix skull banner count from 3 to 2 (confirmed by wowsims devs)
+- Fix stormlash totem count from 5 to 4
+- Standardize buff configurations to match wowsims defaults
+- Add missing spec-specific options (e.g., honorAmongThievesCritRate for rogues)
+- Increase simulation iterations from 10,000 to 100,000+
+
+## Development Environment
+
+### Setup
+- Use `nix develop` to enter the development shell which provides `wowsimcli`
+- The project uses a Nix flake with inputs from the wowsims MoP fork
+
+### Key Commands
+- `nix develop` - Enter development environment with wowsimcli available
+- `wowsimcli sim --infile input.json` - Run simulation with input file
+- `wowsimcli sim --infile input.json --outfile results.json` - Save results to fi
le
+- `nix flake show` - Show available flake outputs
+- `nix build` - Build packages (future: website and data generation)
+
+## Architecture
+
+### Core Structure
+- `nix/lib/` - Core simulation library functions
+- `nix/lib/default.nix` - Main library exports (target, encounter, player, raid)
+- `nix/lib/extend.nix` - Extends nixpkgs lib with sim functions
+- `docs/` - Example JSON configurations for CLI input
+
+### Key Components
+
+#### Player Configuration (`nix/lib/player.nix`)
+- `mkPlayer` function creates player configurations from:
+  - Race, class, spec selection
+  - Gearsets loaded from wowsims JSON files
+  - APL (Action Priority List) rotations
+  - Consumables, talents, glyphs, professions
+  - Challenge mode support
+
+#### Target/Encounter System (`nix/lib/target.nix`)
+- Predefined target types: `defaultRaidBoss`, `smallTrash`, `largeTrash`
+- Configurable mob stats, damage, and mechanics
+
+#### Simulation (`nix/lib/simulation.nix`)
+- `mkSim` function creates full simulation configurations
+- Supports iterations, random seeds, different sim types
+
+### Data Sources
+- Gearsets: `${wowsims}/ui/${class}/${spec}/gear_sets/${gearset}.gear.json`
+- APLs: `${wowsims}/ui/${class}/${spec}/apls/${apl}.apl.json`
+- References external wowsims repository for game data
+
+## File Organization
+- Configuration examples in `docs/example_cli_input_windwalker.json`
+- Nix library functions organized by domain (player, target, encounter, simulatio
n)
+- No traditional package.json or test files - this is a pure Nix project
+
+## Input JSON Schema
+
+The wowsimcli expects complex JSON input files with this hierarchy:
+
+### Top-Level Structure
+```json
+{
+  "requestId": "string",
+  "type": "SimTypeIndividual", 
+  "raid": RaidConfig,
+  "encounter": EncounterConfig,
+  "simOptions": SimulationOptions
+}
+```
+
+### Key Schema Components
+- **Raid**: Contains 5 parties (25-person raid), each with 5 player slots, plus r
aid-wide buffs/debuffs
+- **Player**: Complex nested structure with equipment (16 slots), consumables, ta
lents, spec-specific options, and APL rotations
+- **Equipment**: Items with IDs, gems, enchants, reforging, tinkers
+- **APL (Action Priority Lists)**: Deep conditional logic trees for spell rotatio
n decisions
+- **Encounter**: Target configuration, fight duration, execute phases, enemy stat
s
+- **Enumeration Patterns**: Prefixed types like "RaceBloodElf", "ClassMonk", "Mob
TypeMechanical"
+
+### Critical Details
+- Equipment items use game database IDs for items/gems/enchants
+- APL system uses complex nested conditions (and/or/cmp operators)
+- Stats arrays are fixed-length (22 elements for target stats)
+- Empty `{}` objects serve as placeholders for unused slots
+- Spec-specific config uses dynamic keys like `"windwalkerMonk": {...}`
+
+## Data Pipeline
+
+### Planned Workflow
+1. **Input Generation**: Nix functions create JSON input files matching wowsims s
chema
+2. **Simulation**: wowsimcli processes inputs and generates result data
+3. **Aggregation**: Results are collected into static JSON files for website cons
umption
+4. **Website**: Static site serves leaderboards and trinket data
+5. **Automation**: GitHub Actions trigger updates when upstream wowsims changes
+
+### Target Simulations
+- **Encounter Types**: Single Target, Multi-Target, Short Single Target
+- **Scope**: All specs initially, trinket comparisons later
+- **Output**: JSON files for web frontend consumption
+
+## Composable Component Design
+
+### Class Component Pattern
+The project uses a layered composition approach for building reusable class confi
gurations:
+
+```nix
+{
+  lib,
+  components,
+  ...
+}: let
+  inherit (lib.sim.player) mkPlayer;
+  inherit (components.consumables) agilityDps;
+
+  # Spec-specific builder function
+  mkWindwalker = {
+    race,
+    apl,
+    gearset, 
+    talents,
+  }: mkPlayer {
+    class = "monk";
+    spec = "windwalker";
+    inherit race gearset talents apl;
+    consumables = agilityDps;  # Shared consumable set
+  };
+
+  # Organized configurations by tier and scenario
+  windwalker = {
+    talents = {
+      xuen = "213322";  # Single target build
+      rjw = "233321";   # AoE build
+    };
+    p1 = {
+      singleTarget = mkWindwalker {
+        race = "orc";
+        apl = "default";
+        gearset = "dw_p1_bis";
+        talents = windwalker.talents.xuen;
+      };
+      aoeOrc = mkWindwalker {
+        race = "orc";
+        apl = "default"; 
+        gearset = "dw_p1_bis";
+        talents = windwalker.talents.rjw;
+      };
+    };
+  };
+in windwalker
+```
+
+### Design Benefits
+- **Shared Defaults**: Common consumables, base configurations
+- **Scenario Organization**: Grouped by content tier (p1, p2) and encounter type
+- **Talent Variants**: Named talent configurations for different playstyles
+- **Race Flexibility**: Easy to create variants for different races
+- **Inheritance Chain**: `mkWindwalker` ? `mkPlayer` ? JSON output
+
+## Working with the Code
+- Build reusable Nix components following the layered composition pattern
+- Create spec builders that inherit from `mkPlayer` with sensible defaults
+- Organize configurations by content tier and encounter scenario
+- Keep individual functions small and focused for maintainability
+- Test changes by entering `nix develop` and running `wowsimcli` with generated c
onfigs
+- All simulation data comes from the referenced wowsims fork
+- Challenge mode can be enabled on equipment for different stat scaling
+
+## Future Development
+- GitHub Actions integration for automated simulation updates
+- Website packaging and server configuration via Nix
+- Additional fight length variations (2min, 4min encounters)
+- Advanced encounter mechanics simulation
+- Class-specific APL optimization recommendations
\ No newline at end of file

diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 0000000..1a1ff35
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1,206 @@
+# CLAUDE.md
+
+This file provides guidance to Claude Code 
(claude.ai/code) when working with code in t
his repository.
+
+## Project Overview
+
+This is a Nix-based data pipeline for gener
ating World of Warcraft simulation leaderboa
rds and statistics. The project uses the wow
sims CLI engine to create a theorycrafting w
ebsite similar to bloodmallet, showing spec 
performance rankings and trinket data for Wo
W Mists of Pandaria.
+
+### Project Vision
+- Generate spec simulation leaderboards acr
oss different encounter types
+- Provide trinket performance data and rank
ings
+- Serve results via static website with JSO
N data files
+- Automate updates via GitHub Actions when 
upstream wowsims changes
+- Use Nix for reproducible builds and serve
r configuration
+
+## Current Development Priorities
+
+### High Priority Tasks
+1. **Chart Web UI Enhancements**
+   - Display detailed loadout information (
talents, glyphs, gear) for each character
+   - Add link to raw JSON input file used f
or simulation
+   - Future: Generate direct links to wowsi
ms with the character template
+
+2. **Dynamic Buff/Debuff Handling**
+   - Fix warrior and shaman buff inclusion 
logic
+   - Ensure warriors are part of the 2 skul
l banners (not in addition to)
+   - Ensure shamans are part of the 4 storm
lash totems (not in addition to)
+   - Standardize raid composition buffs acr
oss all simulations
+
+3. **Trinket Comparison System**
+   - Implement trinket performance analysis
 and rankings
+   - Create comparative trinket data for di
fferent specs and encounters
+
+### Technical Debt & Configuration Issues
+- Fix skull banner count from 3 to 2 (confi
rmed by wowsims devs)
+- Fix stormlash totem count from 5 to 4
+- Standardize buff configurations to match 
wowsims defaults
+- Add missing spec-specific options (e.g., 
honorAmongThievesCritRate for rogues)
+- Increase simulation iterations from 10,00
0 to 100,000+
+
+## Development Environment
+
+### Setup
+- Use `nix develop` to enter the developmen
t shell which provides `wowsimcli`
+- The project uses a Nix flake with inputs 
from the wowsims MoP fork
+
+### Key Commands
+- `nix develop` - Enter development environ
ment with wowsimcli available
+- `wowsimcli sim --infile input.json` - Run
 simulation with input file
+- `wowsimcli sim --infile input.json --outf
ile results.json` - Save results to file
+- `nix flake show` - Show available flake o
utputs
+- `nix build` - Build packages (future: web
site and data generation)
+
+## Architecture
+
+### Core Structure
+- `nix/lib/` - Core simulation library func
tions
+- `nix/lib/default.nix` - Main library expo
rts (target, encounter, player, raid)
+- `nix/lib/extend.nix` - Extends nixpkgs li
b with sim functions
+- `docs/` - Example JSON configurations for
 CLI input
+
+### Key Components
+
+#### Player Configuration (`nix/lib/player.
nix`)
+- `mkPlayer` function creates player config
urations from:
+  - Race, class, spec selection
+  - Gearsets loaded from wowsims JSON files
+  - APL (Action Priority List) rotations
+  - Consumables, talents, glyphs, professio
ns
+  - Challenge mode support
+
+#### Target/Encounter System (`nix/lib/targ
et.nix`)
+- Predefined target types: `defaultRaidBoss
`, `smallTrash`, `largeTrash`
+- Configurable mob stats, damage, and mecha
nics
+
+#### Simulation (`nix/lib/simulation.nix`)
+- `mkSim` function creates full simulation 
configurations
+- Supports iterations, random seeds, differ
ent sim types
+
+### Data Sources
+- Gearsets: `${wowsims}/ui/${class}/${spec}
/gear_sets/${gearset}.gear.json`
+- APLs: `${wowsims}/ui/${class}/${spec}/apl
s/${apl}.apl.json`
+- References external wowsims repository fo
r game data
+
+## File Organization
+- Configuration examples in `docs/example_c
li_input_windwalker.json`
+- Nix library functions organized by domain
 (player, target, encounter, simulation)
+- No traditional package.json or test files
 - this is a pure Nix project
+
+## Input JSON Schema
+
+The wowsimcli expects complex JSON input fi
les with this hierarchy:
+
+### Top-Level Structure
+```json
+{
+  "requestId": "string",
+  "type": "SimTypeIndividual", 
+  "raid": RaidConfig,
+  "encounter": EncounterConfig,
+  "simOptions": SimulationOptions
+}
+```
+
+### Key Schema Components
+- **Raid**: Contains 5 parties (25-person r
aid), each with 5 player slots, plus raid-wi
de buffs/debuffs
+- **Player**: Complex nested structure with
 equipment (16 slots), consumables, talents,
 spec-specific options, and APL rotations
+- **Equipment**: Items with IDs, gems, ench
ants, reforging, tinkers
+- **APL (Action Priority Lists)**: Deep con
ditional logic trees for spell rotation deci
sions
+- **Encounter**: Target configuration, figh
t duration, execute phases, enemy stats
+- **Enumeration Patterns**: Prefixed types 
like "RaceBloodElf", "ClassMonk", "MobTypeMe
chanical"
+
+### Critical Details
+- Equipment items use game database IDs for
 items/gems/enchants
+- APL system uses complex nested conditions
 (and/or/cmp operators)
+- Stats arrays are fixed-length (22 element
s for target stats)
+- Empty `{}` objects serve as placeholders 
for unused slots
+- Spec-specific config uses dynamic keys li
ke `"windwalkerMonk": {...}`
+
+## Data Pipeline
+
+### Planned Workflow
+1. **Input Generation**: Nix functions crea
te JSON input files matching wowsims schema
+2. **Simulation**: wowsimcli processes inpu
ts and generates result data
+3. **Aggregation**: Results are collected i
nto static JSON files for website consumptio
n
+4. **Website**: Static site serves leaderbo
ards and trinket data
+5. **Automation**: GitHub Actions trigger u
pdates when upstream wowsims changes
+
+### Target Simulations
+- **Encounter Types**: Single Target, Multi
-Target, Short Single Target
+- **Scope**: All specs initially, trinket c
omparisons later
+- **Output**: JSON files for web frontend c
onsumption
+
+## Composable Component Design
+
+### Class Component Pattern
+The project uses a layered composition appr
oach for building reusable class configurati
ons:
+
+```nix
+{
+  lib,
+  components,
+  ...
+}: let
+  inherit (lib.sim.player) mkPlayer;
+  inherit (components.consumables) agilityD
ps;
+
+  # Spec-specific builder function
+  mkWindwalker = {
+    race,
+    apl,
+    gearset, 
+    talents,
+  }: mkPlayer {
+    class = "monk";
+    spec = "windwalker";
+    inherit race gearset talents apl;
+    consumables = agilityDps;  # Shared con
sumable set
+  };
+
+  # Organized configurations by tier and sc
enario
+  windwalker = {
+    talents = {
+      xuen = "213322";  # Single target bui
ld
+      rjw = "233321";   # AoE build
+    };
+    p1 = {
+      singleTarget = mkWindwalker {
+        race = "orc";
+        apl = "default";
+        gearset = "dw_p1_bis";
+        talents = windwalker.talents.xuen;
+      };
+      aoeOrc = mkWindwalker {
+        race = "orc";
+        apl = "default"; 
+        gearset = "dw_p1_bis";
+        talents = windwalker.talents.rjw;
+      };
+    };
+  };
+in windwalker
+```
+
+### Design Benefits
+- **Shared Defaults**: Common consumables, 
base configurations
+- **Scenario Organization**: Grouped by con
tent tier (p1, p2) and encounter type
+- **Talent Variants**: Named talent configu
rations for different playstyles
+- **Race Flexibility**: Easy to create vari
ants for different races
+- **Inheritance Chain**: `mkWindwalker` ? `
mkPlayer` ? JSON output
+
+## Working with the Code
+- Build reusable Nix components following t
he layered composition pattern
+- Create spec builders that inherit from `m
kPlayer` with sensible defaults
+- Organize configurations by content tier a
nd encounter scenario
+- Keep individual functions small and focus
ed for maintainability
+- Test changes by entering `nix develop` an
d running `wowsimcli` with generated configs
+- All simulation data comes from the refere
nced wowsims fork
+- Challenge mode can be enabled on equipmen
t for different stat scaling
+
+## Future Development
+- GitHub Actions integration for automated 
simulation updates
+- Website packaging and server configuratio
n via Nix
+- Additional fight length variations (2min,
 4min encounters)
+- Advanced encounter mechanics simulation
+- Class-specific APL optimization recommend
ations
\ No newline at end of file
 

diff --git a/nix/classes/mage/arcane.nix b/nix/classes/mage/arcane.nix
index 05c10ca..2bf739c 100644
--- a/nix/classes/mage/arcane.nix
+++ b/nix/classes/mage/arcane.nix
@@ -51,7 +51,7 @@
       singleTarget = {
         apl = "default";
         p1.gearset = "p1_bis";
-        preRaid.gearset = "rich_prebis";
+        preRaid.gearset = "p1_prebis";
         talents = arcane.talents.livingBomb;
         glyphs = arcane.glyphs.default;
       };
@@ -59,7 +59,7 @@
       multiTarget = {
         apl = "arcane_cleave";
         p1.gearset = "p1_bis";
-        preRaid.gearset = "rich_prebis";
+        preRaid.gearset = "p1_prebis";
         talents = arcane.talents.netherTempest;
         glyphs = arcane.glyphs.default;
       };
@@ -67,7 +67,7 @@
       cleave = {
         apl = "arcane_cleave";
         p1.gearset = "p1_bis";
-        preRaid.gearset = "rich_prebis";
+        preRaid.gearset = "p1_prebis";
         talents = arcane.talents.netherTempest;
         glyphs = arcane.glyphs.default;
       };

diff --git a/nix/classes/mage/arcane.nix b/n
ix/classes/mage/arcane.nix
index 05c10ca..2bf739c 100644
--- a/nix/classes/mage/arcane.nix
+++ b/nix/classes/mage/arcane.nix
@@ -51,7 +51,7 @@
       singleTarget = {
         apl = "default";
         p1.gearset = "p1_bis";
-        preRaid.gearset = "rich_prebis";
+        preRaid.gearset = "p1_prebis";
         talents = arcane.talents.livingBomb
;
         glyphs = arcane.glyphs.default;
       };
@@ -59,7 +59,7 @@
       multiTarget = {
         apl = "arcane_cleave";
         p1.gearset = "p1_bis";
-        preRaid.gearset = "rich_prebis";
+        preRaid.gearset = "p1_prebis";
         talents = arcane.talents.netherTemp
est;
         glyphs = arcane.glyphs.default;
       };
@@ -67,7 +67,7 @@
       cleave = {
         apl = "arcane_cleave";
         p1.gearset = "p1_bis";
-        preRaid.gearset = "rich_prebis";
+        preRaid.gearset = "p1_prebis";
         talents = arcane.talents.netherTemp
est;
         glyphs = arcane.glyphs.default;
       };
 

diff --git a/nix/classes/mage/frost.nix b/nix/classes/mage/frost.nix
index 849f064..7395597 100644
--- a/nix/classes/mage/frost.nix
+++ b/nix/classes/mage/frost.nix
@@ -51,7 +51,7 @@
       singleTarget = {
         apl = "frost";
         p1.gearset = "p1_bis";
-        preRaid.gearset = "p1_prebis_rich";
+        preRaid.gearset = "p1_prebis";
         talents = frost.talents.livingBomb;
         glyphs = frost.glyphs.default;
       };
@@ -59,7 +59,7 @@
       multiTarget = {
         apl = "frost_aoe";
         p1.gearset = "p1_bis";
-        preRaid.gearset = "p1_prebis_rich";
+        preRaid.gearset = "p1_prebis";
         talents = frost.talents.netherTempest;
         glyphs = frost.glyphs.default;
       };
@@ -67,7 +67,7 @@
       cleave = {
         apl = "frost_cleave";
         p1.gearset = "p1_bis";
-        preRaid.gearset = "p1_prebis_rich";
+        preRaid.gearset = "p1_prebis";
         talents = frost.talents.netherTempest;
         glyphs = frost.glyphs.default;
       };

diff --git a/nix/classes/mage/frost.nix b/ni
x/classes/mage/frost.nix
index 849f064..7395597 100644
--- a/nix/classes/mage/frost.nix
+++ b/nix/classes/mage/frost.nix
@@ -51,7 +51,7 @@
       singleTarget = {
         apl = "frost";
         p1.gearset = "p1_bis";
-        preRaid.gearset = "p1_prebis_rich";
+        preRaid.gearset = "p1_prebis";
         talents = frost.talents.livingBomb;
         glyphs = frost.glyphs.default;
       };
@@ -59,7 +59,7 @@
       multiTarget = {
         apl = "frost_aoe";
         p1.gearset = "p1_bis";
-        preRaid.gearset = "p1_prebis_rich";
+        preRaid.gearset = "p1_prebis";
         talents = frost.talents.netherTempe
st;
         glyphs = frost.glyphs.default;
       };
@@ -67,7 +67,7 @@
       cleave = {
         apl = "frost_cleave";
         p1.gearset = "p1_bis";
-        preRaid.gearset = "p1_prebis_rich";
+        preRaid.gearset = "p1_prebis";
         talents = frost.talents.netherTempe
st;
         glyphs = frost.glyphs.default;
       };
 

diff --git a/web/src/components/ItemDatabase.astro b/web/src/components/ItemDataba
se.astro
new file mode 100644
index 0000000..27c8110
--- /dev/null
+++ b/web/src/components/ItemDatabase.astro
@@ -0,0 +1,151 @@
+---
+// ItemDatabase.astro - Handles item display, reforging, and Wowhead integration
+---
+
+<script>
+// Reforging data mapping
+const reforgeData = {
+  "113": { "id": 113, "i1": 6, "s1": "spi", "i2": 13, "s2": "dodgertng", "v": 0.4
 },
+  "114": { "id": 114, "i1": 6, "s1": "spi", "i2": 14, "s2": "parryrtng", "v": 0.4
 },
+  "115": { "id": 115, "i1": 6, "s1": "spi", "i2": 31, "s2": "hitrtng", "v": 0.4 }
,
+  "116": { "id": 116, "i1": 6, "s1": "spi", "i2": 32, "s2": "critstrkrtng", "v": 
0.4 },
+  "117": { "id": 117, "i1": 6, "s1": "spi", "i2": 36, "s2": "hastertng", "v": 0.4
 },
+  "118": { "id": 118, "i1": 6, "s1": "spi", "i2": 37, "s2": "exprtng", "v": 0.4 }
,
+  "119": { "id": 119, "i1": 6, "s1": "spi", "i2": 49, "s2": "mastrtng", "v": 0.4 
},
+  "120": { "id": 120, "i1": 13, "s1": "dodgertng", "i2": 6, "s2": "spi", "v": 0.4
 },
+  "121": { "id": 121, "i1": 13, "s1": "dodgertng", "i2": 14, "s2": "parryrtng", "
v": 0.4 },
+  "122": { "id": 122, "i1": 13, "s1": "dodgertng", "i2": 31, "s2": "hitrtng", "v"
: 0.4 },
+  "123": { "id": 123, "i1": 13, "s1": "dodgertng", "i2": 32, "s2": "critstrkrtng"
, "v": 0.4 },
+  "124": { "id": 124, "i1": 13, "s1": "dodgertng", "i2": 36, "s2": "hastertng", "
v": 0.4 },
+  "125": { "id": 125, "i1": 13, "s1": "dodgertng", "i2": 37, "s2": "exprtng", "v"
: 0.4 },
+  "126": { "id": 126, "i1": 13, "s1": "dodgertng", "i2": 49, "s2": "mastrtng", "v
": 0.4 },
+  "127": { "id": 127, "i1": 14, "s1": "parryrtng", "i2": 6, "s2": "spi", "v": 0.4
 },
+  "128": { "id": 128, "i1": 14, "s1": "parryrtng", "i2": 13, "s2": "dodgertng", "
v": 0.4 },
+  "129": { "id": 129, "i1": 14, "s1": "parryrtng", "i2": 31, "s2": "hitrtng", "v"
: 0.4 },
+  "130": { "id": 130, "i1": 14, "s1": "parryrtng", "i2": 32, "s2": "critstrkrtng"
, "v": 0.4 },
+  "131": { "id": 131, "i1": 14, "s1": "parryrtng", "i2": 36, "s2": "hastertng", "
v": 0.4 },
+  "132": { "id": 132, "i1": 14, "s1": "parryrtng", "i2": 37, "s2": "exprtng", "v"
: 0.4 },
+  "133": { "id": 133, "i1": 14, "s1": "parryrtng", "i2": 49, "s2": "mastrtng", "v
": 0.4 },
+  "134": { "id": 134, "i1": 31, "s1": "hitrtng", "i2": 6, "s2": "spi", "v": 0.4 }
,
+  "135": { "id": 135, "i1": 31, "s1": "hitrtng", "i2": 13, "s2": "dodgertng", "v"
: 0.4 },
+  "136": { "id": 136, "i1": 31, "s1": "hitrtng", "i2": 14, "s2": "parryrtng", "v"
: 0.4 },
+  "137": { "id": 137, "i1": 31, "s1": "hitrtng", "i2": 32, "s2": "critstrkrtng", 
"v": 0.4 },
+  "138": { "id": 138, "i1": 31, "s1": "hitrtng", "i2": 36, "s2": "hastertng", "v"
: 0.4 },
+  "139": { "id": 139, "i1": 31, "s1": "hitrtng", "i2": 37, "s2": "exprtng", "v": 
0.4 },
+  "140": { "id": 140, "i1": 31, "s1": "hitrtng", "i2": 49, "s2": "mastrtng", "v":
 0.4 },
+  "141": { "id": 141, "i1": 32, "s1": "critstrkrtng", "i2": 6, "s2": "spi", "v": 
0.4 },
+  "142": { "id": 142, "i1": 32, "s1": "critstrkrtng", "i2": 13, "s2": "dodgertng"
, "v": 0.4 },
+  "143": { "id": 143, "i1": 32, "s1": "critstrkrtng", "i2": 14, "s2": "parryrtng"
, "v": 0.4 },
+  "144": { "id": 144, "i1": 32, "s1": "critstrkrtng", "i2": 31, "s2": "hitrtng", 
"v": 0.4 },
+  "145": { "id": 145, "i1": 32, "s1": "critstrkrtng", "i2": 36, "s2": "hastertng"
, "v": 0.4 },
+  "146": { "id": 146, "i1": 32, "s1": "critstrkrtng", "i2": 37, "s2": "exprtng", 
"v": 0.4 },
+  "147": { "id": 147, "i1": 32, "s1": "critstrkrtng", "i2": 49, "s2": "mastrtng",
 "v": 0.4 },
+  "148": { "id": 148, "i1": 36, "s1": "hastertng", "i2": 6, "s2": "spi", "v": 0.4
 },
+  "149": { "id": 149, "i1": 36, "s1": "hastertng", "i2": 13, "s2": "dodgertng", "
v": 0.4 },
+  "150": { "id": 150, "i1": 36, "s1": "hastertng", "i2": 14, "s2": "parryrtng", "
v": 0.4 },
+  "151": { "id": 151, "i1": 36, "s1": "hastertng", "i2": 31, "s2": "hitrtng", "v"
: 0.4 },
+  "152": { "id": 152, "i1": 36, "s1": "hastertng", "i2": 32, "s2": "critstrkrtng"
, "v": 0.4 },
+  "153": { "id": 153, "i1": 36, "s1": "hastertng", "i2": 37, "s2": "exprtng", "v"
: 0.4 },
+  "154": { "id": 154, "i1": 36, "s1": "hastertng", "i2": 49, "s2": "mastrtng", "v
": 0.4 },
+  "155": { "id": 155, "i1": 37, "s1": "exprtng", "i2": 6, "s2": "spi", "v": 0.4 }
,
+  "156": { "id": 156, "i1": 37, "s1": "exprtng", "i2": 13, "s2": "dodgertng", "v"
: 0.4 },
+  "157": { "id": 157, "i1": 37, "s1": "exprtng", "i2": 14, "s2": "parryrtng", "v"
: 0.4 },
+  "158": { "id": 158, "i1": 37, "s1": "exprtng", "i2": 31, "s2": "hitrtng", "v": 
0.4 },
+  "159": { "id": 159, "i1": 37, "s1": "exprtng", "i2": 32, "s2": "critstrkrtng", 
"v": 0.4 },
+  "160": { "id": 160, "i1": 37, "s1": "exprtng", "i2": 36, "s2": "hastertng", "v"
: 0.4 },
+  "161": { "id": 161, "i1": 37, "s1": "exprtng", "i2": 49, "s2": "mastrtng", "v":
 0.4 },
+  "162": { "id": 162, "i1": 49, "s1": "mastrtng", "i2": 6, "s2": "spi", "v": 0.4 
},
+  "163": { "id": 163, "i1": 49, "s1": "mastrtng", "i2": 13, "s2": "dodgertng", "v
": 0.4 },
+  "164": { "id": 164, "i1": 49, "s1": "mastrtng", "i2": 14, "s2": "parryrtng", "v
": 0.4 },
+  "165": { "id": 165, "i1": 49, "s1": "mastrtng", "i2": 31, "s2": "hitrtng", "v":
 0.4 },
+  "166": { "id": 166, "i1": 49, "s1": "mastrtng", "i2": 32, "s2": "critstrkrtng",
 "v": 0.4 },
+  "167": { "id": 167, "i1": 49, "s1": "mastrtng", "i2": 36, "s2": "hastertng", "v
": 0.4 },
+  "168": { "id": 168, "i1": 49, "s1": "mastrtng", "i2": 37, "s2": "exprtng", "v":
 0.4 }
+};
+
+// Stat name mappings
+const statNames = {
+  "spi": "Spirit",
+  "dodgertng": "Dodge",
+  "parryrtng": "Parry", 
+  "hitrtng": "Hit",
+  "critstrkrtng": "Crit",
+  "hastertng": "Haste",
+  "exprtng": "Expertise",
+  "mastrtng": "Mastery"
+};
+
+// Global functions for item database functionality
+window.ItemDatabase = {
+  // Helper function to format reforging
+  formatReforge: (reforgeId) => {
+    if (!reforgeId || reforgeId === 0) return '';
+    const reforge = reforgeData[reforgeId.toString()];
+    if (!reforge) return ` [R:${reforgeId}]`;
+    
+    const fromStat = statNames[reforge.s1] || reforge.s1;
+    const toStat = statNames[reforge.s2] || reforge.s2;
+    return ` [${fromStat} ? ${toStat}]`;
+  },
+
+  // Generate Wowhead URL for items
+  getWowheadUrl: (itemId) => {
+    return `https://www.wowhead.com/mop-classic/item=${itemId}`;
+  },
+
+  // Format equipment item with all details
+  formatEquipmentItem: (item) => {
+    if (!item || !item.id) return null;
+    
+    const itemName = `Item ${item.id}`; // TODO: Replace with actual item names
+    const wowheadUrl = window.ItemDatabase.getWowheadUrl(item.id);
+    
+    // Build details array
+    const details = [];
+    
+    // Reforging
+    if (item.reforging) {
+      const reforge = reforgeData[item.reforging.toString()];
+      if (reforge) {
+        const fromStat = statNames[reforge.s1] || reforge.s1;
+        const toStat = statNames[reforge.s2] || reforge.s2;
+        details.push(`${fromStat} ? ${toStat}`);
+      }
+    }
+    
+    // Gems
+    if (item.gems && item.gems.length > 0) {
+      const activeGems = item.gems.filter(g => g && g !== 0);
+      activeGems.forEach(gemId => {
+        details.push(`Gem ${gemId}`); // TODO: Replace with actual gem names and 
stats
+      });
+    }
+    
+    // Enchant
+    if (item.enchant) {
+      details.push(`Enchant ${item.enchant}`); // TODO: Replace with actual encha
nt names
+    }
+    
+    // Tinker
+    if (item.tinker) {
+      details.push(`Tinker ${item.tinker}`); // TODO: Replace with actual tinker 
names
+    }
+    
+    return {
+      itemId: item.id,
+      itemName: itemName,
+      itemDetails: details,
+      wowheadUrl: wowheadUrl
+    };
+  },
+
+  // Format gem information
+  formatGems: (gems) => {
+    if (!gems || gems.length === 0) return '';
+    const activeGems = gems.filter(g => g && g !== 0);
+    if (activeGems.length === 0) return '';
+    
+    return activeGems.map(gemId => `Gem ${gemId}`).join(', ');
+  }
+};
+</script>
\ No newline at end of file

diff --git a/web/src/components/ItemDatabase
.astro b/web/src/components/ItemDatabase.ast
ro
new file mode 100644
index 0000000..27c8110
--- /dev/null
+++ b/web/src/components/ItemDatabase.astro
@@ -0,0 +1,151 @@
+---
+// ItemDatabase.astro - Handles item displa
y, reforging, and Wowhead integration
+---
+
+<script>
+// Reforging data mapping
+const reforgeData = {
+  "113": { "id": 113, "i1": 6, "s1": "spi",
 "i2": 13, "s2": "dodgertng", "v": 0.4 },
+  "114": { "id": 114, "i1": 6, "s1": "spi",
 "i2": 14, "s2": "parryrtng", "v": 0.4 },
+  "115": { "id": 115, "i1": 6, "s1": "spi",
 "i2": 31, "s2": "hitrtng", "v": 0.4 },
+  "116": { "id": 116, "i1": 6, "s1": "spi",
 "i2": 32, "s2": "critstrkrtng", "v": 0.4 },
+  "117": { "id": 117, "i1": 6, "s1": "spi",
 "i2": 36, "s2": "hastertng", "v": 0.4 },
+  "118": { "id": 118, "i1": 6, "s1": "spi",
 "i2": 37, "s2": "exprtng", "v": 0.4 },
+  "119": { "id": 119, "i1": 6, "s1": "spi",
 "i2": 49, "s2": "mastrtng", "v": 0.4 },
+  "120": { "id": 120, "i1": 13, "s1": "dodg
ertng", "i2": 6, "s2": "spi", "v": 0.4 },
+  "121": { "id": 121, "i1": 13, "s1": "dodg
ertng", "i2": 14, "s2": "parryrtng", "v": 0.
4 },
+  "122": { "id": 122, "i1": 13, "s1": "dodg
ertng", "i2": 31, "s2": "hitrtng", "v": 0.4 
},
+  "123": { "id": 123, "i1": 13, "s1": "dodg
ertng", "i2": 32, "s2": "critstrkrtng", "v":
 0.4 },
+  "124": { "id": 124, "i1": 13, "s1": "dodg
ertng", "i2": 36, "s2": "hastertng", "v": 0.
4 },
+  "125": { "id": 125, "i1": 13, "s1": "dodg
ertng", "i2": 37, "s2": "exprtng", "v": 0.4 
},
+  "126": { "id": 126, "i1": 13, "s1": "dodg
ertng", "i2": 49, "s2": "mastrtng", "v": 0.4
 },
+  "127": { "id": 127, "i1": 14, "s1": "parr
yrtng", "i2": 6, "s2": "spi", "v": 0.4 },
+  "128": { "id": 128, "i1": 14, "s1": "parr
yrtng", "i2": 13, "s2": "dodgertng", "v": 0.
4 },
+  "129": { "id": 129, "i1": 14, "s1": "parr
yrtng", "i2": 31, "s2": "hitrtng", "v": 0.4 
},
+  "130": { "id": 130, "i1": 14, "s1": "parr
yrtng", "i2": 32, "s2": "critstrkrtng", "v":
 0.4 },
+  "131": { "id": 131, "i1": 14, "s1": "parr
yrtng", "i2": 36, "s2": "hastertng", "v": 0.
4 },
+  "132": { "id": 132, "i1": 14, "s1": "parr
yrtng", "i2": 37, "s2": "exprtng", "v": 0.4 
},
+  "133": { "id": 133, "i1": 14, "s1": "parr
yrtng", "i2": 49, "s2": "mastrtng", "v": 0.4
 },
+  "134": { "id": 134, "i1": 31, "s1": "hitr
tng", "i2": 6, "s2": "spi", "v": 0.4 },
+  "135": { "id": 135, "i1": 31, "s1": "hitr
tng", "i2": 13, "s2": "dodgertng", "v": 0.4 
},
+  "136": { "id": 136, "i1": 31, "s1": "hitr
tng", "i2": 14, "s2": "parryrtng", "v": 0.4 
},
+  "137": { "id": 137, "i1": 31, "s1": "hitr
tng", "i2": 32, "s2": "critstrkrtng", "v": 0
.4 },
+  "138": { "id": 138, "i1": 31, "s1": "hitr
tng", "i2": 36, "s2": "hastertng", "v": 0.4 
},
+  "139": { "id": 139, "i1": 31, "s1": "hitr
tng", "i2": 37, "s2": "exprtng", "v": 0.4 },
+  "140": { "id": 140, "i1": 31, "s1": "hitr
tng", "i2": 49, "s2": "mastrtng", "v": 0.4 }
,
+  "141": { "id": 141, "i1": 32, "s1": "crit
strkrtng", "i2": 6, "s2": "spi", "v": 0.4 },
+  "142": { "id": 142, "i1": 32, "s1": "crit
strkrtng", "i2": 13, "s2": "dodgertng", "v":
 0.4 },
+  "143": { "id": 143, "i1": 32, "s1": "crit
strkrtng", "i2": 14, "s2": "parryrtng", "v":
 0.4 },
+  "144": { "id": 144, "i1": 32, "s1": "crit
strkrtng", "i2": 31, "s2": "hitrtng", "v": 0
.4 },
+  "145": { "id": 145, "i1": 32, "s1": "crit
strkrtng", "i2": 36, "s2": "hastertng", "v":
 0.4 },
+  "146": { "id": 146, "i1": 32, "s1": "crit
strkrtng", "i2": 37, "s2": "exprtng", "v": 0
.4 },
+  "147": { "id": 147, "i1": 32, "s1": "crit
strkrtng", "i2": 49, "s2": "mastrtng", "v": 
0.4 },
+  "148": { "id": 148, "i1": 36, "s1": "hast
ertng", "i2": 6, "s2": "spi", "v": 0.4 },
+  "149": { "id": 149, "i1": 36, "s1": "hast
ertng", "i2": 13, "s2": "dodgertng", "v": 0.
4 },
+  "150": { "id": 150, "i1": 36, "s1": "hast
ertng", "i2": 14, "s2": "parryrtng", "v": 0.
4 },
+  "151": { "id": 151, "i1": 36, "s1": "hast
ertng", "i2": 31, "s2": "hitrtng", "v": 0.4 
},
+  "152": { "id": 152, "i1": 36, "s1": "hast
ertng", "i2": 32, "s2": "critstrkrtng", "v":
 0.4 },
+  "153": { "id": 153, "i1": 36, "s1": "hast
ertng", "i2": 37, "s2": "exprtng", "v": 0.4 
},
+  "154": { "id": 154, "i1": 36, "s1": "hast
ertng", "i2": 49, "s2": "mastrtng", "v": 0.4
 },
+  "155": { "id": 155, "i1": 37, "s1": "expr
tng", "i2": 6, "s2": "spi", "v": 0.4 },
+  "156": { "id": 156, "i1": 37, "s1": "expr
tng", "i2": 13, "s2": "dodgertng", "v": 0.4 
},
+  "157": { "id": 157, "i1": 37, "s1": "expr
tng", "i2": 14, "s2": "parryrtng", "v": 0.4 
},
+  "158": { "id": 158, "i1": 37, "s1": "expr
tng", "i2": 31, "s2": "hitrtng", "v": 0.4 },
+  "159": { "id": 159, "i1": 37, "s1": "expr
tng", "i2": 32, "s2": "critstrkrtng", "v": 0
.4 },
+  "160": { "id": 160, "i1": 37, "s1": "expr
tng", "i2": 36, "s2": "hastertng", "v": 0.4 
},
+  "161": { "id": 161, "i1": 37, "s1": "expr
tng", "i2": 49, "s2": "mastrtng", "v": 0.4 }
,
+  "162": { "id": 162, "i1": 49, "s1": "mast
rtng", "i2": 6, "s2": "spi", "v": 0.4 },
+  "163": { "id": 163, "i1": 49, "s1": "mast
rtng", "i2": 13, "s2": "dodgertng", "v": 0.4
 },
+  "164": { "id": 164, "i1": 49, "s1": "mast
rtng", "i2": 14, "s2": "parryrtng", "v": 0.4
 },
+  "165": { "id": 165, "i1": 49, "s1": "mast
rtng", "i2": 31, "s2": "hitrtng", "v": 0.4 }
,
+  "166": { "id": 166, "i1": 49, "s1": "mast
rtng", "i2": 32, "s2": "critstrkrtng", "v": 
0.4 },
+  "167": { "id": 167, "i1": 49, "s1": "mast
rtng", "i2": 36, "s2": "hastertng", "v": 0.4
 },
+  "168": { "id": 168, "i1": 49, "s1": "mast
rtng", "i2": 37, "s2": "exprtng", "v": 0.4 }
+};
+
+// Stat name mappings
+const statNames = {
+  "spi": "Spirit",
+  "dodgertng": "Dodge",
+  "parryrtng": "Parry", 
+  "hitrtng": "Hit",
+  "critstrkrtng": "Crit",
+  "hastertng": "Haste",
+  "exprtng": "Expertise",
+  "mastrtng": "Mastery"
+};
+
+// Global functions for item database funct
ionality
+window.ItemDatabase = {
+  // Helper function to format reforging
+  formatReforge: (reforgeId) => {
+    if (!reforgeId || reforgeId === 0) retu
rn '';
+    const reforge = reforgeData[reforgeId.t
oString()];
+    if (!reforge) return ` [R:${reforgeId}]
`;
+    
+    const fromStat = statNames[reforge.s1] 
|| reforge.s1;
+    const toStat = statNames[reforge.s2] ||
 reforge.s2;
+    return ` [${fromStat} ? ${toStat}]`;
+  },
+
+  // Generate Wowhead URL for items
+  getWowheadUrl: (itemId) => {
+    return `https://www.wowhead.com/mop-cla
ssic/item=${itemId}`;
+  },
+
+  // Format equipment item with all details
+  formatEquipmentItem: (item) => {
+    if (!item || !item.id) return null;
+    
+    const itemName = `Item ${item.id}`; // 
TODO: Replace with actual item names
+    const wowheadUrl = window.ItemDatabase.
getWowheadUrl(item.id);
+    
+    // Build details array
+    const details = [];
+    
+    // Reforging
+    if (item.reforging) {
+      const reforge = reforgeData[item.refo
rging.toString()];
+      if (reforge) {
+        const fromStat = statNames[reforge.
s1] || reforge.s1;
+        const toStat = statNames[reforge.s2
] || reforge.s2;
+        details.push(`${fromStat} ? ${toSta
t}`);
+      }
+    }
+    
+    // Gems
+    if (item.gems && item.gems.length > 0) 
{
+      const activeGems = item.gems.filter(g
 => g && g !== 0);
+      activeGems.forEach(gemId => {
+        details.push(`Gem ${gemId}`); // TO
DO: Replace with actual gem names and stats
+      });
+    }
+    
+    // Enchant
+    if (item.enchant) {
+      details.push(`Enchant ${item.enchant}
`); // TODO: Replace with actual enchant nam
es
+    }
+    
+    // Tinker
+    if (item.tinker) {
+      details.push(`Tinker ${item.tinker}`)
; // TODO: Replace with actual tinker names
+    }
+    
+    return {
+      itemId: item.id,
+      itemName: itemName,
+      itemDetails: details,
+      wowheadUrl: wowheadUrl
+    };
+  },
+
+  // Format gem information
+  formatGems: (gems) => {
+    if (!gems || gems.length === 0) return 
'';
+    const activeGems = gems.filter(g => g &
& g !== 0);
+    if (activeGems.length === 0) return '';
+    
+    return activeGems.map(gemId => `Gem ${g
emId}`).join(', ');
+  }
+};
+</script>
\ No newline at end of file
 

diff --git a/web/src/layouts/ChartLayout.astro b/web/src/layouts/ChartLayout.astro
index f3ffc68..4c148bf 100644
--- a/web/src/layouts/ChartLayout.astro
+++ b/web/src/layouts/ChartLayout.astro
@@ -1,6 +1,7 @@
 ---
 import Navigation from '../components/Navigation.astro';
 import Warning from '../components/Warning.astro';
+import ItemDatabase from '../components/ItemDatabase.astro';
 
 export interface Props {
   title: string;
@@ -231,6 +232,13 @@ const isFixedClassSpec = fixedClass && fixedSpec;
         align-items: center;
         gap: 15px;
         padding: 8px 0;
+        cursor: pointer;
+        border-radius: 4px;
+        transition: background-color 0.2s ease;
+      }
+      
+      .chart-item:hover {
+        background-color: rgba(255,255,255,0.05);
       }
       
       .chart-labels {
@@ -293,6 +301,203 @@ const isFixedClassSpec = fixedClass && fixedSpec;
         text-align: right;
         flex-shrink: 0;
       }
+
+      /* Expandable chart item styles */
+      .chart-item-wrapper {
+        border-radius: 6px;
+        transition: background-color 0.2s ease;
+      }
+
+      .chart-item-header {
+        cursor: pointer;
+        padding: 8px 12px;
+        border-radius: 6px;
+        transition: background-color 0.2s ease;
+      }
+
+      .chart-item-header:hover {
+        background-color: rgba(255,255,255,0.05);
+      }
+
+      .chart-item-expanded .chart-item-header {
+        background-color: rgba(255,255,255,0.08);
+      }
+
+      .chart-item-content {
+        display: grid;
+        grid-template-columns: 180px 1fr;
+        align-items: center;
+        gap: 15px;
+      }
+
+      .chart-expand-icon {
+        margin-left: 8px;
+        font-size: 0.8em;
+        color: var(--text-muted);
+        transition: transform 0.2s ease;
+      }
+
+      .chart-item-expanded .chart-expand-icon {
+        transform: rotate(90deg);
+      }
+
+      .chart-dropdown {
+        grid-column: 1 / -1;
+        margin-top: 12px;
+        padding: 16px;
+        background-color: rgba(255,255,255,0.03);
+        border-radius: 6px;
+        border: 1px solid rgba(255,255,255,0.1);
+        display: none;
+      }
+
+      .chart-item-expanded .chart-dropdown {
+        display: block;
+        animation: dropdown-expand 0.2s ease-out;
+      }
+
+      @keyframes dropdown-expand {
+        from {
+          opacity: 0;
+          transform: translateY(-8px);
+        }
+        to {
+          opacity: 1;
+          transform: translateY(0);
+        }
+      }
+
+      .loadout-section {
+        margin-bottom: 20px;
+      }
+
+      .loadout-section:last-child {
+        margin-bottom: 0;
+      }
+
+      .loadout-title {
+        color: var(--highlight-color);
+        font-size: 1em;
+        font-weight: 600;
+        margin-bottom: 8px;
+        display: flex;
+        align-items: center;
+        gap: 8px;
+      }
+
+      .loadout-grid {
+        display: grid;
+        grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+        gap: 12px;
+      }
+
+      .loadout-item {
+        display: flex;
+        flex-direction: column;
+        gap: 3px;
+      }
+
+      .loadout-label {
+        font-size: 0.8em;
+        color: var(--text-muted);
+        font-weight: 500;
+        text-transform: uppercase;
+        letter-spacing: 0.5px;
+      }
+
+      .loadout-value {
+        font-size: 0.9em;
+        color: var(--text-primary);
+        font-weight: 500;
+      }
+
+      .loadout-talents {
+        font-family: 'Courier New', monospace;
+        font-size: 1.1em;
+        letter-spacing: 2px;
+        color: var(--highlight-color);
+      }
+
+      .loadout-actions {
+        display: flex;
+        gap: 12px;
+        margin-top: 16px;
+        padding-top: 16px;
+        border-top: 1px solid rgba(255,255,255,0.1);
+      }
+
+      .loadout-button {
+        padding: 6px 12px;
+        background-color: var(--bg-primary);
+        border: 1px solid rgba(255,255,255,0.2);
+        border-radius: 4px;
+        color: var(--text-primary);
+        text-decoration: none;
+        font-size: 0.85em;
+        font-weight: 500;
+        transition: all 0.2s ease;
+        cursor: pointer;
+      }
+
+      .loadout-button:hover {
+        background-color: rgba(255,255,255,0.1);
+        border-color: var(--highlight-color);
+      }
+
+      .equipment-grid {
+        display: grid;
+        grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+        gap: 8px;
+      }
+
+      .equipment-slot {
+        display: flex;
+        justify-content: space-between;
+        align-items: flex-start;
+        padding: 8px;
+        background-color: rgba(255,255,255,0.05);
+        border-radius: 3px;
+        font-size: 0.85em;
+        gap: 12px;
+      }
+
+      .equipment-slot-name {
+        color: var(--text-muted);
+        font-weight: 500;
+        min-width: 80px;
+      }
+
+      .equipment-item-link {
+        color: #ffd100;
+        text-decoration: none;
+        font-family: 'Courier New', monospace;
+        font-size: 0.9em;
+        transition: color 0.2s ease;
+      }
+
+      .equipment-item-link:hover {
+        color: #ffed4e;
+        text-decoration: underline;
+      }
+
+      .equipment-item-info {
+        flex: 1;
+        display: flex;
+        flex-direction: column;
+        gap: 2px;
+      }
+
+      .equipment-detail {
+        color: var(--text-muted);
+        font-size: 0.8em;
+        line-height: 1.2;
+      }
+
+      .equipment-item {
+        color: var(--text-primary);
+        text-align: right;
+        font-family: 'Courier New', monospace;
+      }
     </style>
   </head>
   <body>
@@ -456,6 +661,230 @@ const formatSimulationDate = (timestamp) => {
   });
 };
 
+// Loadout formatting functions
+const formatLoadout = (loadout) => {
+  if (!loadout) return null;
+  
+  const sections = [];
+  
+  // Character Info
+  if (loadout.race || loadout.class || loadout.profession1 || loadout.profession2
) {
+    const items = [];
+    if (loadout.race) items.push({ label: 'Race', value: formatRace(loadout.race)
 });
+    if (loadout.class) items.push({ label: 'Class', value: formatClass(loadout.cl
ass) });
+    if (loadout.profession1) items.push({ label: 'Profession 1', value: loadout.p
rofession1 });
+    if (loadout.profession2) items.push({ label: 'Profession 2', value: loadout.p
rofession2 });
+    sections.push({ title: 'Character', items });
+  }
+  
+  // Talents & Glyphs
+  if (loadout.talentsString || loadout.glyphs) {
+    const items = [];
+    if (loadout.talentsString) {
+      items.push({ label: 'Talents', value: loadout.talentsString, isSpecial: 'ta
lents' });
+    }
+    if (loadout.glyphs) {
+      const glyphText = formatGlyphs(loadout.glyphs);
+      if (glyphText) items.push({ label: 'Glyphs', value: glyphText });
+    }
+    sections.push({ title: 'Talents & Glyphs', items });
+  }
+  
+  // Consumables
+  if (loadout.consumables) {
+    const items = formatConsumables(loadout.consumables);
+    if (items.length > 0) sections.push({ title: 'Consumables', items });
+  }
+  
+  // Equipment Summary
+  if (loadout.equipment && loadout.equipment.items) {
+    const equipmentSummary = formatEquipmentSummary(loadout.equipment.items);
+    if (equipmentSummary.length > 0) {
+      sections.push({ title: 'Equipment', items: equipmentSummary, isEquipment: t
rue });
+    }
+  }
+  
+  return sections;
+};
+
+const formatRace = (race) => {
+  return race.replace('Race', '').replace(/([A-Z])/g, ' $1').trim();
+};
+
+const formatClass = (className) => {
+  return className.replace('Class', '').replace(/([A-Z])/g, ' $1').trim();
+};
+
+const formatGlyphs = (glyphs) => {
+  const glyphList = [];
+  ['major1', 'major2', 'major3', 'minor1', 'minor2', 'minor3'].forEach(slot => {
+    if (glyphs[slot]) glyphList.push(`${slot}: ${glyphs[slot]}`);
+  });
+  return glyphList.length > 0 ? glyphList.join(', ') : null;
+};
+
+const formatConsumables = (consumables) => {
+  const items = [];
+  if (consumables.flaskId) {
+    items.push({ 
+      label: 'Flask', 
+      value: consumables.flaskId,
+      wowheadUrl: `https://www.wowhead.com/mop-classic/item=${consumables.flaskId
}`,
+      isItem: true
+    });
+  }
+  if (consumables.foodId) {
+    items.push({ 
+      label: 'Food', 
+      value: consumables.foodId,
+      wowheadUrl: `https://www.wowhead.com/mop-classic/item=${consumables.foodId}
`,
+      isItem: true
+    });
+  }
+  if (consumables.potId) {
+    items.push({ 
+      label: 'Potion', 
+      value: consumables.potId,
+      wowheadUrl: `https://www.wowhead.com/mop-classic/item=${consumables.potId}`
,
+      isItem: true
+    });
+  }
+  if (consumables.prepotId) {
+    items.push({ 
+      label: 'Pre-Potion', 
+      value: consumables.prepotId,
+      wowheadUrl: `https://www.wowhead.com/mop-classic/item=${consumables.prepotI
d}`,
+      isItem: true
+    });
+  }
+  return items;
+};
+
+const formatEquipmentSummary = (items) => {
+  const slotNames = [
+    'Head', 'Neck', 'Shoulders', 'Back', 'Chest', 'Wrists', 
+    'Hands', 'Waist', 'Legs', 'Feet', 'Ring 1', 'Ring 2', 
+    'Trinket 1', 'Trinket 2', 'Main Hand', 'Off Hand'
+  ];
+  
+  const equipment = [];
+  items.forEach((item, index) => {
+    if (item && item.id) {
+      const itemInfo = window.ItemDatabase ? window.ItemDatabase.formatEquipmentI
tem(item) : {
+        itemId: item.id,
+        itemName: `Item ${item.id}`,
+        itemDetails: [],
+        wowheadUrl: `https://www.wowhead.com/mop-classic/item=${item.id}`
+      };
+      
+      if (itemInfo) {
+        equipment.push({
+          slot: slotNames[index] || `Slot ${index + 1}`,
+          ...itemInfo
+        });
+      }
+    }
+  });
+  return equipment;
+};
+
+const generateRawJsonUrl = (chartData) => {
+  // Generate URL to the raw JSON file used for this simulation
+  const fileName = chartData.fileName || 'unknown.json';
+  const dataPath = chartData.dataPath || '/data/';
+  return `${dataPath}${fileName}`;
+};
+
+// Generate loadout dropdown HTML
+const generateLoadoutDropdown = (loadout, chartData) => {
+  const sections = formatLoadout(loadout);
+  if (!sections || sections.length === 0) return '';
+  
+  const sectionsHtml = sections.map(section => {
+    if (section.isEquipment) {
+      // Special handling for equipment
+      const equipmentHtml = section.items.map(eq => {
+        const detailsHtml = eq.itemDetails && eq.itemDetails.length > 0 
+          ? eq.itemDetails.map(detail => `<div class="equipment-detail">${detail}
</div>`).join('')
+          : '';
+        
+        return `
+          <div class="equipment-slot">
+            <span class="equipment-slot-name">${eq.slot}:</span>
+            <div class="equipment-item-info">
+              <a href="${eq.wowheadUrl}" target="_blank" class="equipment-item-li
nk">${eq.itemName}</a>
+              ${detailsHtml}
+            </div>
+          </div>
+        `;
+      }).join('');
+      
+      return `
+        <div class="loadout-section">
+          <h4 class="loadout-title">${section.title}</h4>
+          <div class="equipment-grid">
+            ${equipmentHtml}
+          </div>
+        </div>
+      `;
+    } else {
+      // Regular sections
+      const itemsHtml = section.items.map(item => {
+        const valueClass = item.isSpecial === 'talents' ? 'loadout-value loadout-
talents' : 'loadout-value';
+        const valueContent = item.isItem && item.wowheadUrl 
+          ? `<a href="${item.wowheadUrl}" target="_blank" class="equipment-item-l
ink">Item ${item.value}</a>`
+          : `<span class="${valueClass}">${item.value}</span>`;
+        
+        return `
+          <div class="loadout-item">
+            <span class="loadout-label">${item.label}</span>
+            ${valueContent}
+          </div>
+        `;
+      }).join('');
+      
+      return `
+        <div class="loadout-section">
+          <h4 class="loadout-title">${section.title}</h4>
+          <div class="loadout-grid">
+            ${itemsHtml}
+          </div>
+        </div>
+      `;
+    }
+  }).join('');
+  
+  const rawJsonUrl = generateRawJsonUrl(chartData);
+  
+  return `
+    <div class="chart-dropdown">
+      ${sectionsHtml}
+      <div class="loadout-actions">
+        <a href="${rawJsonUrl}" target="_blank" class="loadout-button">View Raw J
SON</a>
+        <button class="loadout-button" onclick="alert('WowSims link coming soon!'
)">Open in WowSims</button>
+      </div>
+    </div>
+  `;
+};
+
+// Chart interaction handlers - global function for onclick handlers
+window.toggleChartItem = (element) => {
+  const wrapper = element.closest('.chart-item-wrapper');
+  if (!wrapper) return;
+  
+  const isExpanded = wrapper.classList.contains('chart-item-expanded');
+  
+  // Close all other expanded items
+  document.querySelectorAll('.chart-item-expanded').forEach(item => {
+    if (item !== wrapper) {
+      item.classList.remove('chart-item-expanded');
+    }
+  });
+  
+  // Toggle current item
+  wrapper.classList.toggle('chart-item-expanded', !isExpanded);
+};
+
 // Class specs for comparison mode
 const classSpecs = {
   death_knight: [
@@ -912,7 +1341,8 @@ class UnifiedChart {
           value: specData[sortBy] || specData.dps,
           category: className,
           className: className,
-          specName: specName
+          specName: specName,
+          loadout: specData.loadout || null
         });
       }
     }
@@ -941,19 +1371,24 @@ class UnifiedChart {
             const tooltip = sortBy === 'dps' ? displayValue : `${displayValue} (A
vg: ${avgDps})`;
             
             const barColor = classColors[item.className] || '#666';
+            const dropdownContent = item.loadout ? generateLoadoutDropdown(item.l
oadout, this.currentData) : '';
             
             return `
-            <div class="chart-item">
-              <div class="chart-labels">
-                <span class="chart-rank">#${index + 1}</span>
-                <span class="chart-label">${item.label}</span>
-              </div>
-              <div class="chart-bar-container">
-                <div class="chart-bar-track">
-                  <div class="chart-bar" style="width: ${barWidth}%; background-c
olor: ${barColor};"></div>
+            <div class="chart-item-wrapper">
+              <div class="chart-item" onclick="toggleChartItem(this.parentElement
)">
+                <div class="chart-labels">
+                  <span class="chart-rank">#${index + 1}</span>
+                  <span class="chart-label">${item.label}</span>
+                  ${item.loadout ? '<span class="chart-expand-indicator">?</span>
' : ''}
+                </div>
+                <div class="chart-bar-container">
+                  <div class="chart-bar-track">
+                    <div class="chart-bar" style="width: ${barWidth}%; background
-color: ${barColor};"></div>
+                  </div>
+                  <span class="chart-value" title="${tooltip}">${displayValue}</s
pan>
                 </div>
-                <span class="chart-value" title="${tooltip}">${displayValue}</spa
n>
               </div>
+              ${dropdownContent}
             </div>
             `;
           }).join('')}
@@ -977,7 +1412,8 @@ class UnifiedChart {
         stdev: itemData.stdev,
         value: itemData[sortBy] || itemData.dps,
         category: itemName,
-        rawName: itemName
+        rawName: itemName,
+        loadout: itemData.loadout || null
       });
     }
 
@@ -1007,19 +1443,24 @@ class UnifiedChart {
             
             const barColor = currentComparisonType === 'race' ? 
               (classColors[this.getCurrentClass()] || '#666') : '#666';
+            const dropdownContent = item.loadout ? generateLoadoutDropdown(item.l
oadout, this.currentData) : '';
             
             return `
-            <div class="chart-item">
-              <div class="chart-labels">
-                <span class="chart-rank">#${index + 1}</span>
-                <span class="chart-label">${item.label}</span>
-              </div>
-              <div class="chart-bar-container">
-                <div class="chart-bar-track">
-                  <div class="chart-bar" style="width: ${barWidth}%; background-c
olor: ${barColor};"></div>
+            <div class="chart-item-wrapper">
+              <div class="chart-item" onclick="toggleChartItem(this.parentElement
)">
+                <div class="chart-labels">
+                  <span class="chart-rank">#${index + 1}</span>
+                  <span class="chart-label">${item.label}</span>
+                  ${item.loadout ? '<span class="chart-expand-indicator">?</span>
' : ''}
+                </div>
+                <div class="chart-bar-container">
+                  <div class="chart-bar-track">
+                    <div class="chart-bar" style="width: ${barWidth}%; background
-color: ${barColor};"></div>
+                  </div>
+                  <span class="chart-value" title="${tooltip}">${displayValue}</s
pan>
                 </div>
-                <span class="chart-value" title="${tooltip}">${displayValue}</spa
n>
               </div>
+              ${dropdownContent}
             </div>
             `;
           }).join('')}
@@ -1035,5 +1476,8 @@ document.addEventListener('DOMContentLoaded', () => {
   new UnifiedChart();
 });
     </script>
+    
+    <!-- ItemDatabase component for reforge data and item utilities -->
+    <ItemDatabase />
   </body>
 </html>

diff --git a/web/src/layouts/ChartLayout.ast
ro b/web/src/layouts/ChartLayout.astro
index f3ffc68..4c148bf 100644
--- a/web/src/layouts/ChartLayout.astro
+++ b/web/src/layouts/ChartLayout.astro
@@ -1,6 +1,7 @@
 ---
 import Navigation from '../components/Navig
ation.astro';
 import Warning from '../components/Warning.
astro';
+import ItemDatabase from '../components/Ite
mDatabase.astro';
 
 export interface Props {
   title: string;
@@ -231,6 +232,13 @@ const isFixedClassSpec 
= fixedClass && fixedSpec;
         align-items: center;
         gap: 15px;
         padding: 8px 0;
+        cursor: pointer;
+        border-radius: 4px;
+        transition: background-color 0.2s e
ase;
+      }
+      
+      .chart-item:hover {
+        background-color: rgba(255,255,255,
0.05);
       }
       
       .chart-labels {
@@ -293,6 +301,203 @@ const isFixedClassSpec
 = fixedClass && fixedSpec;
         text-align: right;
         flex-shrink: 0;
       }
+
+      /* Expandable chart item styles */
+      .chart-item-wrapper {
+        border-radius: 6px;
+        transition: background-color 0.2s e
ase;
+      }
+
+      .chart-item-header {
+        cursor: pointer;
+        padding: 8px 12px;
+        border-radius: 6px;
+        transition: background-color 0.2s e
ase;
+      }
+
+      .chart-item-header:hover {
+        background-color: rgba(255,255,255,
0.05);
+      }
+
+      .chart-item-expanded .chart-item-head
er {
+        background-color: rgba(255,255,255,
0.08);
+      }
+
+      .chart-item-content {
+        display: grid;
+        grid-template-columns: 180px 1fr;
+        align-items: center;
+        gap: 15px;
+      }
+
+      .chart-expand-icon {
+        margin-left: 8px;
+        font-size: 0.8em;
+        color: var(--text-muted);
+        transition: transform 0.2s ease;
+      }
+
+      .chart-item-expanded .chart-expand-ic
on {
+        transform: rotate(90deg);
+      }
+
+      .chart-dropdown {
+        grid-column: 1 / -1;
+        margin-top: 12px;
+        padding: 16px;
+        background-color: rgba(255,255,255,
0.03);
+        border-radius: 6px;
+        border: 1px solid rgba(255,255,255,
0.1);
+        display: none;
+      }
+
+      .chart-item-expanded .chart-dropdown 
{
+        display: block;
+        animation: dropdown-expand 0.2s eas
e-out;
+      }
+
+      @keyframes dropdown-expand {
+        from {
+          opacity: 0;
+          transform: translateY(-8px);
+        }
+        to {
+          opacity: 1;
+          transform: translateY(0);
+        }
+      }
+
+      .loadout-section {
+        margin-bottom: 20px;
+      }
+
+      .loadout-section:last-child {
+        margin-bottom: 0;
+      }
+
+      .loadout-title {
+        color: var(--highlight-color);
+        font-size: 1em;
+        font-weight: 600;
+        margin-bottom: 8px;
+        display: flex;
+        align-items: center;
+        gap: 8px;
+      }
+
+      .loadout-grid {
+        display: grid;
+        grid-template-columns: repeat(auto-
fit, minmax(200px, 1fr));
+        gap: 12px;
+      }
+
+      .loadout-item {
+        display: flex;
+        flex-direction: column;
+        gap: 3px;
+      }
+
+      .loadout-label {
+        font-size: 0.8em;
+        color: var(--text-muted);
+        font-weight: 500;
+        text-transform: uppercase;
+        letter-spacing: 0.5px;
+      }
+
+      .loadout-value {
+        font-size: 0.9em;
+        color: var(--text-primary);
+        font-weight: 500;
+      }
+
+      .loadout-talents {
+        font-family: 'Courier New', monospa
ce;
+        font-size: 1.1em;
+        letter-spacing: 2px;
+        color: var(--highlight-color);
+      }
+
+      .loadout-actions {
+        display: flex;
+        gap: 12px;
+        margin-top: 16px;
+        padding-top: 16px;
+        border-top: 1px solid rgba(255,255,
255,0.1);
+      }
+
+      .loadout-button {
+        padding: 6px 12px;
+        background-color: var(--bg-primary)
;
+        border: 1px solid rgba(255,255,255,
0.2);
+        border-radius: 4px;
+        color: var(--text-primary);
+        text-decoration: none;
+        font-size: 0.85em;
+        font-weight: 500;
+        transition: all 0.2s ease;
+        cursor: pointer;
+      }
+
+      .loadout-button:hover {
+        background-color: rgba(255,255,255,
0.1);
+        border-color: var(--highlight-color
);
+      }
+
+      .equipment-grid {
+        display: grid;
+        grid-template-columns: repeat(auto-
fit, minmax(250px, 1fr));
+        gap: 8px;
+      }
+
+      .equipment-slot {
+        display: flex;
+        justify-content: space-between;
+        align-items: flex-start;
+        padding: 8px;
+        background-color: rgba(255,255,255,
0.05);
+        border-radius: 3px;
+        font-size: 0.85em;
+        gap: 12px;
+      }
+
+      .equipment-slot-name {
+        color: var(--text-muted);
+        font-weight: 500;
+        min-width: 80px;
+      }
+
+      .equipment-item-link {
+        color: #ffd100;
+        text-decoration: none;
+        font-family: 'Courier New', monospa
ce;
+        font-size: 0.9em;
+        transition: color 0.2s ease;
+      }
+
+      .equipment-item-link:hover {
+        color: #ffed4e;
+        text-decoration: underline;
+      }
+
+      .equipment-item-info {
+        flex: 1;
+        display: flex;
+        flex-direction: column;
+        gap: 2px;
+      }
+
+      .equipment-detail {
+        color: var(--text-muted);
+        font-size: 0.8em;
+        line-height: 1.2;
+      }
+
+      .equipment-item {
+        color: var(--text-primary);
+        text-align: right;
+        font-family: 'Courier New', monospa
ce;
+      }
     </style>
   </head>
   <body>
@@ -456,6 +661,230 @@ const formatSimulation
Date = (timestamp) => {
   });
 };
 
+// Loadout formatting functions
+const formatLoadout = (loadout) => {
+  if (!loadout) return null;
+  
+  const sections = [];
+  
+  // Character Info
+  if (loadout.race || loadout.class || load
out.profession1 || loadout.profession2) {
+    const items = [];
+    if (loadout.race) items.push({ label: '
Race', value: formatRace(loadout.race) });
+    if (loadout.class) items.push({ label: 
'Class', value: formatClass(loadout.class) }
);
+    if (loadout.profession1) items.push({ l
abel: 'Profession 1', value: loadout.profess
ion1 });
+    if (loadout.profession2) items.push({ l
abel: 'Profession 2', value: loadout.profess
ion2 });
+    sections.push({ title: 'Character', ite
ms });
+  }
+  
+  // Talents & Glyphs
+  if (loadout.talentsString || loadout.glyp
hs) {
+    const items = [];
+    if (loadout.talentsString) {
+      items.push({ label: 'Talents', value:
 loadout.talentsString, isSpecial: 'talents'
 });
+    }
+    if (loadout.glyphs) {
+      const glyphText = formatGlyphs(loadou
t.glyphs);
+      if (glyphText) items.push({ label: 'G
lyphs', value: glyphText });
+    }
+    sections.push({ title: 'Talents & Glyph
s', items });
+  }
+  
+  // Consumables
+  if (loadout.consumables) {
+    const items = formatConsumables(loadout
.consumables);
+    if (items.length > 0) sections.push({ t
itle: 'Consumables', items });
+  }
+  
+  // Equipment Summary
+  if (loadout.equipment && loadout.equipmen
t.items) {
+    const equipmentSummary = formatEquipmen
tSummary(loadout.equipment.items);
+    if (equipmentSummary.length > 0) {
+      sections.push({ title: 'Equipment', i
tems: equipmentSummary, isEquipment: true })
;
+    }
+  }
+  
+  return sections;
+};
+
+const formatRace = (race) => {
+  return race.replace('Race', '').replace(/
([A-Z])/g, ' $1').trim();
+};
+
+const formatClass = (className) => {
+  return className.replace('Class', '').rep
lace(/([A-Z])/g, ' $1').trim();
+};
+
+const formatGlyphs = (glyphs) => {
+  const glyphList = [];
+  ['major1', 'major2', 'major3', 'minor1', 
'minor2', 'minor3'].forEach(slot => {
+    if (glyphs[slot]) glyphList.push(`${slo
t}: ${glyphs[slot]}`);
+  });
+  return glyphList.length > 0 ? glyphList.j
oin(', ') : null;
+};
+
+const formatConsumables = (consumables) => 
{
+  const items = [];
+  if (consumables.flaskId) {
+    items.push({ 
+      label: 'Flask', 
+      value: consumables.flaskId,
+      wowheadUrl: `https://www.wowhead.com/
mop-classic/item=${consumables.flaskId}`,
+      isItem: true
+    });
+  }
+  if (consumables.foodId) {
+    items.push({ 
+      label: 'Food', 
+      value: consumables.foodId,
+      wowheadUrl: `https://www.wowhead.com/
mop-classic/item=${consumables.foodId}`,
+      isItem: true
+    });
+  }
+  if (consumables.potId) {
+    items.push({ 
+      label: 'Potion', 
+      value: consumables.potId,
+      wowheadUrl: `https://www.wowhead.com/
mop-classic/item=${consumables.potId}`,
+      isItem: true
+    });
+  }
+  if (consumables.prepotId) {
+    items.push({ 
+      label: 'Pre-Potion', 
+      value: consumables.prepotId,
+      wowheadUrl: `https://www.wowhead.com/
mop-classic/item=${consumables.prepotId}`,
+      isItem: true
+    });
+  }
+  return items;
+};
+
+const formatEquipmentSummary = (items) => {
+  const slotNames = [
+    'Head', 'Neck', 'Shoulders', 'Back', 'C
hest', 'Wrists', 
+    'Hands', 'Waist', 'Legs', 'Feet', 'Ring
 1', 'Ring 2', 
+    'Trinket 1', 'Trinket 2', 'Main Hand', 
'Off Hand'
+  ];
+  
+  const equipment = [];
+  items.forEach((item, index) => {
+    if (item && item.id) {
+      const itemInfo = window.ItemDatabase 
? window.ItemDatabase.formatEquipmentItem(it
em) : {
+        itemId: item.id,
+        itemName: `Item ${item.id}`,
+        itemDetails: [],
+        wowheadUrl: `https://www.wowhead.co
m/mop-classic/item=${item.id}`
+      };
+      
+      if (itemInfo) {
+        equipment.push({
+          slot: slotNames[index] || `Slot $
{index + 1}`,
+          ...itemInfo
+        });
+      }
+    }
+  });
+  return equipment;
+};
+
+const generateRawJsonUrl = (chartData) => {
+  // Generate URL to the raw JSON file used
 for this simulation
+  const fileName = chartData.fileName || 'u
nknown.json';
+  const dataPath = chartData.dataPath || '/
data/';
+  return `${dataPath}${fileName}`;
+};
+
+// Generate loadout dropdown HTML
+const generateLoadoutDropdown = (loadout, c
hartData) => {
+  const sections = formatLoadout(loadout);
+  if (!sections || sections.length === 0) r
eturn '';
+  
+  const sectionsHtml = sections.map(section
 => {
+    if (section.isEquipment) {
+      // Special handling for equipment
+      const equipmentHtml = section.items.m
ap(eq => {
+        const detailsHtml = eq.itemDetails 
&& eq.itemDetails.length > 0 
+          ? eq.itemDetails.map(detail => `<
div class="equipment-detail">${detail}</div>
`).join('')
+          : '';
+        
+        return `
+          <div class="equipment-slot">
+            <span class="equipment-slot-nam
e">${eq.slot}:</span>
+            <div class="equipment-item-info
">
+              <a href="${eq.wowheadUrl}" ta
rget="_blank" class="equipment-item-link">${
eq.itemName}</a>
+              ${detailsHtml}
+            </div>
+          </div>
+        `;
+      }).join('');
+      
+      return `
+        <div class="loadout-section">
+          <h4 class="loadout-title">${secti
on.title}</h4>
+          <div class="equipment-grid">
+            ${equipmentHtml}
+          </div>
+        </div>
+      `;
+    } else {
+      // Regular sections
+      const itemsHtml = section.items.map(i
tem => {
+        const valueClass = item.isSpecial =
== 'talents' ? 'loadout-value loadout-talent
s' : 'loadout-value';
+        const valueContent = item.isItem &&
 item.wowheadUrl 
+          ? `<a href="${item.wowheadUrl}" t
arget="_blank" class="equipment-item-link">I
tem ${item.value}</a>`
+          : `<span class="${valueClass}">${
item.value}</span>`;
+        
+        return `
+          <div class="loadout-item">
+            <span class="loadout-label">${i
tem.label}</span>
+            ${valueContent}
+          </div>
+        `;
+      }).join('');
+      
+      return `
+        <div class="loadout-section">
+          <h4 class="loadout-title">${secti
on.title}</h4>
+          <div class="loadout-grid">
+            ${itemsHtml}
+          </div>
+        </div>
+      `;
+    }
+  }).join('');
+  
+  const rawJsonUrl = generateRawJsonUrl(cha
rtData);
+  
+  return `
+    <div class="chart-dropdown">
+      ${sectionsHtml}
+      <div class="loadout-actions">
+        <a href="${rawJsonUrl}" target="_bl
ank" class="loadout-button">View Raw JSON</a
>
+        <button class="loadout-button" oncl
ick="alert('WowSims link coming soon!')">Ope
n in WowSims</button>
+      </div>
+    </div>
+  `;
+};
+
+// Chart interaction handlers - global func
tion for onclick handlers
+window.toggleChartItem = (element) => {
+  const wrapper = element.closest('.chart-i
tem-wrapper');
+  if (!wrapper) return;
+  
+  const isExpanded = wrapper.classList.cont
ains('chart-item-expanded');
+  
+  // Close all other expanded items
+  document.querySelectorAll('.chart-item-ex
panded').forEach(item => {
+    if (item !== wrapper) {
+      item.classList.remove('chart-item-exp
anded');
+    }
+  });
+  
+  // Toggle current item
+  wrapper.classList.toggle('chart-item-expa
nded', !isExpanded);
+};
+
 // Class specs for comparison mode
 const classSpecs = {
   death_knight: [
@@ -912,7 +1341,8 @@ class UnifiedChart {
           value: specData[sortBy] || specDa
ta.dps,
           category: className,
           className: className,
-          specName: specName
+          specName: specName,
+          loadout: specData.loadout || null
         });
       }
     }
@@ -941,19 +1371,24 @@ class UnifiedChart {
             const tooltip = sortBy === 'dps
' ? displayValue : `${displayValue} (Avg: ${
avgDps})`;
             
             const barColor = classColors[it
em.className] || '#666';
+            const dropdownContent = item.lo
adout ? generateLoadoutDropdown(item.loadout
, this.currentData) : '';
             
             return `
-            <div class="chart-item">
-              <div class="chart-labels">
-                <span class="chart-rank">#$
{index + 1}</span>
-                <span class="chart-label">$
{item.label}</span>
-              </div>
-              <div class="chart-bar-contain
er">
-                <div class="chart-bar-track
">
-                  <div class="chart-bar" st
yle="width: ${barWidth}%; background-color: 
${barColor};"></div>
+            <div class="chart-item-wrapper"
>
+              <div class="chart-item" oncli
ck="toggleChartItem(this.parentElement)">
+                <div class="chart-labels">
+                  <span class="chart-rank">
#${index + 1}</span>
+                  <span class="chart-label"
>${item.label}</span>
+                  ${item.loadout ? '<span c
lass="chart-expand-indicator">?</span>' : ''
}
+                </div>
+                <div class="chart-bar-conta
iner">
+                  <div class="chart-bar-tra
ck">
+                    <div class="chart-bar" 
style="width: ${barWidth}%; background-color
: ${barColor};"></div>
+                  </div>
+                  <span class="chart-value"
 title="${tooltip}">${displayValue}</span>
                 </div>
-                <span class="chart-value" t
itle="${tooltip}">${displayValue}</span>
               </div>
+              ${dropdownContent}
             </div>
             `;
           }).join('')}
@@ -977,7 +1412,8 @@ class UnifiedChart {
         stdev: itemData.stdev,
         value: itemData[sortBy] || itemData
.dps,
         category: itemName,
-        rawName: itemName
+        rawName: itemName,
+        loadout: itemData.loadout || null
       });
     }
 
@@ -1007,19 +1443,24 @@ class UnifiedChart {
             
             const barColor = currentCompari
sonType === 'race' ? 
               (classColors[this.getCurrentC
lass()] || '#666') : '#666';
+            const dropdownContent = item.lo
adout ? generateLoadoutDropdown(item.loadout
, this.currentData) : '';
             
             return `
-            <div class="chart-item">
-              <div class="chart-labels">
-                <span class="chart-rank">#$
{index + 1}</span>
-                <span class="chart-label">$
{item.label}</span>
-              </div>
-              <div class="chart-bar-contain
er">
-                <div class="chart-bar-track
">
-                  <div class="chart-bar" st
yle="width: ${barWidth}%; background-color: 
${barColor};"></div>
+            <div class="chart-item-wrapper"
>
+              <div class="chart-item" oncli
ck="toggleChartItem(this.parentElement)">
+                <div class="chart-labels">
+                  <span class="chart-rank">
#${index + 1}</span>
+                  <span class="chart-label"
>${item.label}</span>
+                  ${item.loadout ? '<span c
lass="chart-expand-indicator">?</span>' : ''
}
+                </div>
+                <div class="chart-bar-conta
iner">
+                  <div class="chart-bar-tra
ck">
+                    <div class="chart-bar" 
style="width: ${barWidth}%; background-color
: ${barColor};"></div>
+                  </div>
+                  <span class="chart-value"
 title="${tooltip}">${displayValue}</span>
                 </div>
-                <span class="chart-value" t
itle="${tooltip}">${displayValue}</span>
               </div>
+              ${dropdownContent}
             </div>
             `;
           }).join('')}
@@ -1035,5 +1476,8 @@ document.addEventListe
ner('DOMContentLoaded', () => {
   new UnifiedChart();
 });
     </script>
+    
+    <!-- ItemDatabase component for reforge
 data and item utilities -->
+    <ItemDatabase />
   </body>
 </html>
 
[ BACK TO LOG ]
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET