# Instructions

- Following Playwright test failed.
- Explain why, be concise, respect Playwright best practices.
- Provide a snippet of code with the fix, if possible.

# Test info

- Name: equipment.spec.ts >> Equipment Management >> can unequip an item from a slot
- Location: e2e/equipment.spec.ts:113:7

# Error details

```
Error: expect(locator).toBeVisible() failed

Locator: locator('text=Hands').locator('..').locator('button').first()
Expected: visible
Timeout: 5000ms
Error: element(s) not found

Call log:
  - Expect "toBeVisible" with timeout 5000ms
  - waiting for locator('text=Hands').locator('..').locator('button').first()

```

# Page snapshot

```yaml
- generic [ref=e1]:
  - generic [ref=e2]:
    - banner [ref=e3]:
      - generic [ref=e4]:
        - heading "MANA LOOP" [level=1] [ref=e5]
        - generic [ref=e7]:
          - generic [ref=e8]:
            - generic [ref=e9]: Day 1
            - generic [ref=e10]: 01:55
          - generic [ref=e11]:
            - generic [ref=e12]: "0"
            - generic [ref=e13]: Insight
    - main [ref=e14]:
      - generic [ref=e15]:
        - generic [ref=e17]:
          - generic [ref=e18]:
            - generic [ref=e19]:
              - generic [ref=e20]: "14"
              - generic [ref=e21]: / 100
            - generic [ref=e22]:
              - text: +2.8 mana/hr
              - generic [ref=e23]: (1.4x med)
          - progressbar [ref=e24]
          - button "Gather +1 Mana" [ref=e26]:
            - img
            - text: Gather +1 Mana
          - generic [ref=e27]:
            - button "Elemental Mana (1)" [ref=e28]:
              - generic [ref=e29]: Elemental Mana (1)
              - img [ref=e30]
            - generic [ref=e33]:
              - generic [ref=e34]:
                - generic [ref=e35]: 🔗
                - generic [ref=e36]: Transference
              - generic [ref=e39]: 0/10
        - button "Climb the Spire" [ref=e40]:
          - img
          - text: Climb the Spire
        - generic [ref=e42]:
          - generic [ref=e43]:
            - img [ref=e44]
            - generic [ref=e46]: Current Activity
          - generic [ref=e47]: Meditating
        - generic [ref=e48]:
          - generic [ref=e49]: "1"
          - generic [ref=e50]: "2"
          - generic [ref=e51]: "3"
          - generic [ref=e52]: "4"
          - generic [ref=e53]: "5"
          - generic [ref=e54]: "6"
          - generic [ref=e55]: "7"
          - generic [ref=e56]: "8"
          - generic [ref=e57]: "9"
          - generic [ref=e58]: "10"
          - generic [ref=e59]: "11"
          - generic [ref=e60]: "12"
          - generic [ref=e61]: "13"
          - generic [ref=e62]: "14"
          - generic [ref=e63]: "15"
          - generic [ref=e64]: "16"
          - generic [ref=e65]: "17"
          - generic [ref=e66]: "18"
          - generic [ref=e67]: "19"
          - generic [ref=e68]: "20"
          - generic [ref=e69]: "21"
          - generic [ref=e70]: "22"
          - generic [ref=e71]: "23"
          - generic [ref=e72]: "24"
          - generic [ref=e73]: "25"
          - generic [ref=e74]: "26"
          - generic [ref=e75]: "27"
          - generic [ref=e76]: "28"
          - generic [ref=e77]: "29"
          - generic [ref=e78]: "30"
      - generic [ref=e80]:
        - tablist [ref=e81]:
          - tab "⚔️ Spire" [ref=e82]
          - tab "✨ Attune" [ref=e83]
          - tab "🗿 Golems" [ref=e84]
          - tab "📚 Skills" [ref=e85]
          - tab "🔮 Spells" [ref=e86]
          - tab "🛡️ Gear" [active] [selected] [ref=e87]
          - tab "🔧 Craft" [ref=e88]
          - tab "💎 Loot" [ref=e89]
          - tab "🏆 Achieve" [ref=e90]
          - tab "📊 Stats" [ref=e91]
          - tab "🐛 Debug" [ref=e92]
          - tab "📖 Grimoire" [ref=e93]
        - tabpanel "🛡️ Gear" [ref=e94]:
          - generic [ref=e95]:
            - generic [ref=e96]:
              - generic [ref=e97]:
                - heading "Equipped Gear" [level=3] [ref=e98]
                - generic [ref=e100]: 4 / 8 slots filled
              - generic [ref=e101]:
                - generic [ref=e102]:
                  - heading "Weapon & Shield" [level=4] [ref=e103]
                  - generic [ref=e104]:
                    - 'button "Main Hand slot: Basic Staff" [ref=e106]':
                      - generic [ref=e107]:
                        - generic [ref=e108]:
                          - img [ref=e109]
                          - generic [ref=e114]: Main Hand
                        - button "Unequip Basic Staff" [ref=e115]:
                          - img [ref=e116]
                      - generic [ref=e119]:
                        - generic [ref=e120]:
                          - text: Basic Staff
                          - generic [ref=e121]: 2-Handed
                        - generic [ref=e122]: "Enchantments: 1/50"
                        - generic [ref=e124]: Mana Bolt
                    - button "Off Hand slot (blocked by 2-handed weapon) (empty)" [ref=e125]:
                      - generic [ref=e127]:
                        - img [ref=e128]
                        - generic [ref=e130]: Off Hand
                        - generic [ref=e131]:
                          - img
                          - text: Occupied — 2H Weapon
                      - generic [ref=e132]:
                        - img [ref=e133]
                        - text: Blocked by 2-handed weapon
                - generic [ref=e135]:
                  - heading "Armor" [level=4] [ref=e136]
                  - generic [ref=e137]:
                    - button "Head slot (empty)" [ref=e139]:
                      - generic [ref=e141]:
                        - img [ref=e142]
                        - generic [ref=e147]: Head
                      - generic [ref=e148]: Head
                    - 'button "Body slot: Civilian Shirt" [ref=e150]':
                      - generic [ref=e151]:
                        - generic [ref=e152]:
                          - img [ref=e153]
                          - generic [ref=e155]: Body
                        - button "Unequip Civilian Shirt" [ref=e156]:
                          - img [ref=e157]
                      - generic [ref=e160]:
                        - generic [ref=e161]: Civilian Shirt
                        - generic [ref=e162]: "Enchantments: 0/30"
                    - 'button "Hands slot: Civilian Gloves" [ref=e164]':
                      - generic [ref=e165]:
                        - generic [ref=e166]:
                          - img [ref=e167]
                          - generic [ref=e172]: Hands
                        - button "Unequip Civilian Gloves" [ref=e173]:
                          - img [ref=e174]
                      - generic [ref=e177]:
                        - generic [ref=e178]: Civilian Gloves
                        - generic [ref=e179]: "Enchantments: 0/20"
                    - 'button "Feet slot: Civilian Shoes" [ref=e181]':
                      - generic [ref=e182]:
                        - generic [ref=e183]:
                          - img [ref=e184]
                          - generic [ref=e187]: Feet
                        - button "Unequip Civilian Shoes" [ref=e188]:
                          - img [ref=e189]
                      - generic [ref=e192]:
                        - generic [ref=e193]: Civilian Shoes
                        - generic [ref=e194]: "Enchantments: 0/15"
                - generic [ref=e195]:
                  - heading "Accessories" [level=4] [ref=e196]
                  - generic [ref=e197]:
                    - button "Accessory 1 slot (empty)" [ref=e199]:
                      - generic [ref=e201]:
                        - img [ref=e202]
                        - generic [ref=e205]: Accessory 1
                      - generic [ref=e206]: Accessory 1
                    - button "Accessory 2 slot (empty)" [ref=e208]:
                      - generic [ref=e210]:
                        - img [ref=e211]
                        - generic [ref=e214]: Accessory 2
                      - generic [ref=e215]: Accessory 2
            - generic [ref=e216]:
              - heading "Equipment Inventory (0 items)" [level=3] [ref=e218]
              - status [ref=e219]: No unequipped items. Craft new gear in the Crafting tab.
            - generic [ref=e220]:
              - heading "Equipment Stats Summary" [level=3] [ref=e222]
              - generic [ref=e223]:
                - generic [ref=e224]:
                  - generic [ref=e225]: "4"
                  - generic [ref=e226]: Total Items
                - generic [ref=e227]:
                  - generic [ref=e228]: "4"
                  - generic [ref=e229]: Equipped
                - generic [ref=e230]:
                  - generic [ref=e231]: "0"
                  - generic [ref=e232]: In Inventory
                - generic [ref=e233]:
                  - generic [ref=e234]: "1"
                  - generic [ref=e235]: Total Enchantments
              - generic [ref=e236]:
                - heading "✨ Enchantment Power" [level=3] [ref=e238]
                - generic [ref=e239]:
                  - generic [ref=e240]:
                    - generic [ref=e241]: "Enchantment Power:"
                    - generic [ref=e242]: 1.00×
                  - paragraph [ref=e243]: Increases the power of all enchantments by 0%. Multiplier applied to all enchantment effects.
              - generic [ref=e244]:
                - generic [ref=e245]: "Active Effects from Equipment:"
                - generic [ref=e247]: No active effects
  - region "Notifications (F8)":
    - list
  - region "Notifications (F8)":
    - list
  - button "Open Next.js Dev Tools" [ref=e253] [cursor=pointer]:
    - img [ref=e254]
  - alert [ref=e257]
```

# Test source

```ts
  28  | 
  29  |     // Verify equipment UI elements
  30  |     const equippedGearHeading = page.locator('text="Equipped Gear"');
  31  |     await expect(equippedGearHeading).toBeVisible({ timeout: 5000 });
  32  |   });
  33  | 
  34  |   test('shows equipment slots with labels', async ({ page }) => {
  35  |     await page.goto('/');
  36  |     await page.evaluate(() => {
  37  |       Object.keys(localStorage)
  38  |         .filter((k) => k.startsWith('mana-loop-'))
  39  |         .forEach((k) => localStorage.removeItem(k));
  40  |     });
  41  |     await page.reload();
  42  |     await page.waitForLoadState('networkidle');
  43  | 
  44  |     await page.getByRole('tab', { name: /🛡️ Gear/ }).click();
  45  | 
  46  |     // Check for expected slot labels - use role=heading or more specific selectors
  47  |     // Main Hand slot
  48  |     const mainHandSection = page.locator('text=Main Hand');
  49  |     await expect(mainHandSection.first()).toBeVisible();
  50  | 
  51  |     // Off Hand
  52  |     const offHandSection = page.locator('text=Off Hand');
  53  |     await expect(offHandSection.first()).toBeVisible();
  54  | 
  55  |     // Head
  56  |     const headSection = page.locator('text=Head');
  57  |     await expect(headSection.first()).toBeVisible();
  58  | 
  59  |     // Body
  60  |     const bodySection = page.locator('text=Body');
  61  |     await expect(bodySection.first()).toBeVisible();
  62  | 
  63  |     // Hands
  64  |     const handsSection = page.locator('text=Hands');
  65  |     await expect(handsSection.first()).toBeVisible();
  66  | 
  67  |     // Feet
  68  |     const feetSection = page.locator('text=Feet');
  69  |     await expect(feetSection.first()).toBeVisible();
  70  | 
  71  |     // Accessory 1 and 2
  72  |     const acc1Section = page.locator('text=Accessory 1');
  73  |     await expect(acc1Section.first()).toBeVisible();
  74  |     const acc2Section = page.locator('text=Accessory 2');
  75  |     await expect(acc2Section.first()).toBeVisible();
  76  |   });
  77  | 
  78  |   test('shows starting equipment already equipped', async ({ page }) => {
  79  |     await page.goto('/');
  80  |     await page.evaluate(() => {
  81  |       Object.keys(localStorage)
  82  |         .filter((k) => k.startsWith('mana-loop-'))
  83  |         .forEach((k) => localStorage.removeItem(k));
  84  |     });
  85  |     await page.reload();
  86  |     await page.waitForLoadState('networkidle');
  87  | 
  88  |     await page.getByRole('tab', { name: /🛡️ Gear/ }).click();
  89  | 
  90  |     // The player starts with a Basic Staff in main hand (as an equipped item)
  91  |     const mainHandSlot = page.locator('text=Main Hand >> .. >> text=Basic Staff');
  92  |     await expect(mainHandSlot).toBeVisible({ timeout: 5000 });
  93  |   });
  94  | 
  95  |   test('2-handed weapon blocks offhand slot', async ({ page }) => {
  96  |     await page.goto('/');
  97  |     await page.evaluate(() => {
  98  |       Object.keys(localStorage)
  99  |         .filter((k) => k.startsWith('mana-loop-'))
  100 |         .forEach((k) => localStorage.removeItem(k));
  101 |     });
  102 |     await page.reload();
  103 |     await page.waitForLoadState('networkidle');
  104 | 
  105 |     await page.getByRole('tab', { name: /🛡️ Gear/ }).click();
  106 | 
  107 |     // The starting basic staff is 2-handed
  108 |     // The offhand slot should show as blocked with "Occupied — 2H Weapon"
  109 |     const offHandBlocked = page.locator('text=Occupied').first();
  110 |     await expect(offHandBlocked).toBeVisible({ timeout: 5000 });
  111 |   });
  112 | 
  113 |   test('can unequip an item from a slot', async ({ page }) => {
  114 |     await page.goto('/');
  115 |     await page.evaluate(() => {
  116 |       Object.keys(localStorage)
  117 |         .filter((k) => k.startsWith('mana-loop-'))
  118 |         .forEach((k) => localStorage.removeItem(k));
  119 |     });
  120 |     await page.reload();
  121 |     await page.waitForLoadState('networkidle');
  122 | 
  123 |     await page.getByRole('tab', { name: /🛡️ Gear/ }).click();
  124 | 
  125 |     // Find an equiped slot with an unequip button (the X button)
  126 |     // The hands slot has civilian gloves equipped
  127 |     const handsSlot = page.locator('text=Hands >> .. >> button').first();
> 128 |     await expect(handsSlot).toBeVisible({ timeout: 5000 });
      |                             ^ Error: expect(locator).toBeVisible() failed
  129 |     // Note: exact behavior of unequip depends on implementation state
  130 |   });
  131 | });
```