# 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: combat.spec.ts >> Combat System >> can enter Spire mode by clicking Climb button
- Location: e2e/combat.spec.ts:34:7

# Error details

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

Locator: getByRole('button', { name: 'Enter Spire Mode' })
Expected: visible
Timeout: 5000ms
Error: element(s) not found

Call log:
  - Expect "toBeVisible" with timeout 5000ms
  - waiting for getByRole('button', { name: 'Enter Spire Mode' })

```

# Page snapshot

```yaml
- generic [active] [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:43
          - 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.9 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
        - generic [ref=e40]:
          - generic [ref=e41]: "1"
          - generic [ref=e42]: "2"
          - generic [ref=e43]: "3"
          - generic [ref=e44]: "4"
          - generic [ref=e45]: "5"
          - generic [ref=e46]: "6"
          - generic [ref=e47]: "7"
          - generic [ref=e48]: "8"
          - generic [ref=e49]: "9"
          - generic [ref=e50]: "10"
          - generic [ref=e51]: "11"
          - generic [ref=e52]: "12"
          - generic [ref=e53]: "13"
          - generic [ref=e54]: "14"
          - generic [ref=e55]: "15"
          - generic [ref=e56]: "16"
          - generic [ref=e57]: "17"
          - generic [ref=e58]: "18"
          - generic [ref=e59]: "19"
          - generic [ref=e60]: "20"
          - generic [ref=e61]: "21"
          - generic [ref=e62]: "22"
          - generic [ref=e63]: "23"
          - generic [ref=e64]: "24"
          - generic [ref=e65]: "25"
          - generic [ref=e66]: "26"
          - generic [ref=e67]: "27"
          - generic [ref=e68]: "28"
          - generic [ref=e69]: "29"
          - generic [ref=e70]: "30"
      - generic [ref=e72]:
        - tablist [ref=e73]:
          - tab "⚔️ Spire" [selected] [ref=e74]
          - tab "✨ Attune" [ref=e75]
          - tab "🗿 Golems" [ref=e76]
          - tab "📚 Skills" [ref=e77]
          - tab "🔮 Spells" [ref=e78]
          - tab "🛡️ Gear" [ref=e79]
          - tab "🔧 Craft" [ref=e80]
          - tab "💎 Loot" [ref=e81]
          - tab "🏆 Achieve" [ref=e82]
          - tab "📊 Stats" [ref=e83]
          - tab "🐛 Debug" [ref=e84]
          - tab "📖 Grimoire" [ref=e85]
        - tabpanel "⚔️ Spire" [ref=e86]:
          - generic [ref=e87]:
            - generic [ref=e89]:
              - button "Exit Spire Mode" [ref=e90]:
                - img
                - text: Exit Spire Mode
              - generic [ref=e91]: Climb down to floor 1 to return to the main game
            - generic [ref=e92]:
              - heading "Current Floor ⚔️ Combat" [level=3] [ref=e94]:
                - generic [ref=e95]: Current Floor
                - generic [ref=e96]: ⚔️ Combat
              - generic [ref=e97]:
                - generic [ref=e98]:
                  - generic [ref=e99]: "1"
                  - generic [ref=e100]: / 100
                  - generic [ref=e101]: 🔥 Fire
                - generic [ref=e102]:
                  - text: "Best: Floor"
                  - strong [ref=e103]: "1"
                  - text: "• Pacts:"
                  - strong [ref=e104]: "0"
            - generic [ref=e106]:
              - generic [ref=e108]: Active Spells (1)
              - generic [ref=e110]:
                - generic [ref=e111]:
                  - generic [ref=e112]: Mana BoltBasic
                  - generic [ref=e113]: ✓
                - generic [ref=e114]: ⚔️ 5 dmg • 3 raw • ⚡ 15 dmg/hr
            - generic [ref=e115]:
              - generic [ref=e116]:
                - generic [ref=e117]:
                  - img [ref=e118]
                  - generic [ref=e123]: Inferno Whelp
                - generic [ref=e124]: 🔥 Fire
              - generic [ref=e129]: 151 / 151 HP
            - generic [ref=e130]:
              - generic [ref=e132]: Floor Navigation
              - generic [ref=e133]:
                - generic [ref=e134]:
                  - button "Climb Up" [ref=e135]:
                    - img
                    - text: Climb Up
                  - button "Climb Down" [disabled]:
                    - img
                    - text: Climb Down
                - generic [ref=e136]: Click Climb Up/Down to begin climbing
            - generic [ref=e137]:
              - generic [ref=e139]: Combat Stats
              - generic [ref=e140]:
                - generic [ref=e141]: "Total DPS: —"
                - generic [ref=e142]:
                  - generic [ref=e143]: Active Spells
                  - generic [ref=e144]:
                    - generic [ref=e145]:
                      - generic [ref=e146]:
                        - text: Mana Bolt
                        - generic [ref=e147]: Basic
                      - generic [ref=e148]: ✓
                    - generic [ref=e149]: ⚔️ 5 dmg • 3 raw • ⚡ 15 dmg/hr
                - generic [ref=e151]: "Study Speed: 100%"
            - generic [ref=e152]:
              - generic [ref=e154]: Activity Log
              - generic [ref=e160]: No activity yet...
  - region "Notifications (F8)":
    - list
  - region "Notifications (F8)":
    - list
  - button "Open Next.js Dev Tools" [ref=e166] [cursor=pointer]:
    - img [ref=e167]
  - alert [ref=e170]
```

# Test source

```ts
  1  | import { test, expect } from '@playwright/test';
  2  | 
  3  | /**
  4  |  * E2E tests for combat system:
  5  |  * - Entering spire mode (climbing)
  6  |  * - Casting spells and seeing progress
  7  |  * - Enemy HP reduction
  8  |  * - Floor advancement
  9  |  */
  10 | 
  11 | test.describe('Combat System', () => {
  12 |   test.beforeEach(async ({ page }) => {
  13 |     await page.goto('/');
  14 |     // Clear game state to ensure a fresh start
  15 |     await page.evaluate(() => {
  16 |       Object.keys(localStorage)
  17 |         .filter((k) => k.startsWith('mana-loop-'))
  18 |         .forEach((k) => localStorage.removeItem(k));
  19 |     });
  20 |     await page.reload();
  21 |     await page.waitForLoadState('networkidle');
  22 |   });
  23 | 
  24 |   test('can see the Spire tab and "Climb the Spire" button', async ({ page }) => {
  25 |     // The Spire tab uses an icon + text, so match by the tab role
  26 |     const spireTab = page.getByRole('tab', { name: /⚔️ Spire/ });
  27 |     await expect(spireTab).toBeVisible();
  28 | 
  29 |     // Main page should show "Climb the Spire" button
  30 |     const climbBtn = page.getByRole('button', { name: 'Climb the Spire' });
  31 |     await expect(climbBtn).toBeVisible();
  32 |   });
  33 | 
  34 |   test('can enter Spire mode by clicking Climb button', async ({ page }) => {
  35 |     // Click "Climb the Spire" button on the main page (via left panel)
  36 |     await page.getByRole('button', { name: 'Climb the Spire' }).click();
  37 | 
  38 |     // Should now see Spire mode UI elements
  39 |     // The "Enter Spire Mode" button appears when on the Spire tab
  40 |     const enterBtn = page.getByRole('button', { name: 'Enter Spire Mode' });
> 41 |     await expect(enterBtn).toBeVisible({ timeout: 5000 });
     |                            ^ Error: expect(locator).toBeVisible() failed
  42 |   });
  43 | 
  44 |   test('can navigate to Spire tab', async ({ page }) => {
  45 |     // Click the Spire tab specifically (using role=tab to disambiguate)
  46 |     await page.getByRole('tab', { name: /⚔️ Spire/ }).click();
  47 | 
  48 |     // Should see Spire-specific UI
  49 |     const enterSpireBtn = page.getByRole('button', { name: 'Enter Spire Mode' });
  50 |     await expect(enterSpireBtn).toBeVisible({ timeout: 5000 });
  51 |   });
  52 | 
  53 |   test('can enter spire mode from the Spire tab', async ({ page }) => {
  54 |     await page.getByRole('tab', { name: /⚔️ Spire/ }).click();
  55 | 
  56 |     const enterBtn = page.getByRole('button', { name: 'Enter Spire Mode' });
  57 |     await expect(enterBtn).toBeEnabled();
  58 |     await enterBtn.click();
  59 | 
  60 |     // After entering, should see exit button
  61 |     const exitBtn = page.getByRole('button', { name: 'Exit Spire Mode' });
  62 |     await expect(exitBtn).toBeVisible({ timeout: 5000 });
  63 |   });
  64 | 
  65 |   test('shows floor information in spire mode', async ({ page }) => {
  66 |     await page.getByRole('tab', { name: /⚔️ Spire/ }).click();
  67 |     await page.getByRole('button', { name: 'Enter Spire Mode' }).click();
  68 | 
  69 |     // Should display floor number - look for "Floor" label or the floor counter
  70 |     const floorDisplay = page.locator('text="Floor"').first();
  71 |     await expect(floorDisplay).toBeVisible({ timeout: 5000 });
  72 |   });
  73 | });
```