<reasoning_content>
Here's a thinking process:

1.  **Understand the Goal**: The user wants a priority-based job scheduling queue in Python. The queue needs to support adding jobs with optional priority (default 0), processing higher priority jobs first, maintaining FIFO for same priority, and a `get_next_job()` method that returns the highest priority job as a tuple `(str, dict) | None`.

2.  **Identify Key Requirements**:
   - `add_job(name: str, data: dict, priority: int = 0)`
   - Higher priority number = higher priority (2 > 1 > 0)
   - FIFO for same priority
   - `get_next_job() -> tuple[str, dict] | None`
   - Priority levels: 0 (Normal), 1 (High), 2 (Critical)
   - Output: Only Python code, no explanations.

3.  **Choose Data Structure**:
   - A priority queue is ideal. Python's `heapq` module provides a min-heap.
   - To use `heapq` for max-heap behavior (higher priority first), I can negate the priority.
   - To maintain FIFO for same priority, I need a tie-breaker. I can use a counter that increments with each addition. The heap will then sort by `(-priority, counter, name, data)`.
   - Alternatively, I could use `queue.PriorityQueue` from `queue` module, but `heapq` is more flexible and doesn't require threading locks unless specified (not required here). I'll stick with `heapq`.
   - Actually, `queue.PriorityQueue` is synchronous and thread-safe, but the problem doesn't mention concurrency. I'll use `heapq` for simplicity and direct control.

4.  **Design the Class**:
   ```python
   import heapq

   class JobQueue:
       def __init__(self):
           self._queue = []
           self._counter = 0

       def add_job(self, name: str, data: dict, priority: int = 0):
           # Use negative priority for max-heap behavior
           heapq.heappush(self._queue, (-priority, self._counter, name, data))
           self._counter += 1

       def get_next_job(self) -> tuple[str, dict] | None:
           if not self._queue:
               return None
           _, _, name, data = heapq.heappop(self._queue)
           return name, data
   ```

5.  **Check Requirements**:
   - `add_job` accepts optional priority parameter (default=0)? Yes.
   - Higher priority jobs processed before lower? Yes, `-priority` ensures 2 becomes -2, 1 becomes -1, 0 becomes 0. Min-heap pops -2 first, which corresponds to priority 2. Correct.
   - Same priority maintains FIFO? Yes, `_counter` increments monotonically, so lower counter (earlier added) comes first for same priority. Correct.
   - `get_next_job() -> tuple[str, dict] | None`? Yes.
   - Priority levels mentioned? Just for context, the implementation handles any int, which covers 0, 1, 2.
   - Example matches? Let's trace:
     - add "normal", {}, 0 -> (-0, 0, "normal", {})
     - add "critical", {}, 2 -> (-2, 1, "critical", {})
     - add "high", {}, 1 -> (-1, 2, "high", {})
     - heap: [(-2, 1, "critical", {}), (-1, 2, "high", {}), (0, 0, "normal", {})]
     - pop -> (-2, 1, "critical", {}) -> returns ("critical", {})
     - Matches example.

6.  **Refine Code**:
   - Type hints are good.
   - The problem says `tuple[str, dict] | None`, which is Python 3.10+ syntax. I'll keep it.
   - I should make sure the class name matches the example: `JobQueue`.
   - Add necessary imports.
   - Ensure no extra text.

   Let's write it out carefully.

   ```python
   import heapq

   class JobQueue:
       def __init__(self):
           self._heap = []
           self._counter = 0

       def add_job(self, name: str, data: dict, priority: int = 0) -> None:
           heapq.heappush(self._heap, (-priority, self._counter, name, data))
           self._counter += 1

       def get_next_job(self) -> tuple[str, dict] | None:
           if not self._heap:
               return None
           _, _, name, data = heapq.heappop(self._heap)
           return name, data
   ```

   Wait, should I handle the case where `name` and `data` might need to be compared if priorities and counters are equal? Counters are unique, so no need to compare name/data. The tuple comparison will stop at `_counter` since it's unique. This is safe.

   Check Python version compatibility: `tuple[str, dict] | None` is 3.10+. The prompt uses it, so it's fine. I'll keep it as is.

   One minor thing: The prompt says `get_next_job() -> tuple[str, dict] | None`. I'll stick to that.

   Is there any edge case? Empty queue returns None. Correct.
   Priority levels: 0, 1, 2. Handled.
   FIFO for same priority: Handled by counter.
   Higher priority first: Handled by negating priority.

   All requirements met. I'll output only the code.
   I'll make sure formatting is clean.
   No extra comments or explanations.
   Ready.✅
   Output matches the refined code.✅
   One thing: `tuple[str, dict] | None` might need `from __future__ import annotations` for older Python, but the prompt uses it directly, so I'll assume Python 3.10+. I'll just write it as requested.
   I'll produce the exact code block.✅
   Final check of the prompt: "Write only the Python code, no explanations."
   I will output just the code.
   ```python
   import heapq

   class JobQueue:
       def __init__(self):
           self._heap = []
           self._counter = 0

       def add_job(self, name: str, data: dict, priority: int = 0):
           heapq.heappush(self._heap, (-priority, self._counter, name, data))
           self._counter += 1

       def get_next_job(self) -> tuple[str, dict] | None:
           if not self._heap:
               return None
           _, _, name, data = heapq.heappop(self._heap)
           return name, data
   ```
   Looks solid. Proceeds. 
   Self-Correction/Verification during thought:
   - Does `heapq` guarantee stability for same priority? Yes, because `_counter` ensures unique ordering, and it increments per job, preserving insertion order for same priority.
   - Type hints: The prompt uses `tuple[str, dict] | None`. I'll keep it.
   - The example uses `queue = JobQueue()`. My class name matches.
   - All good. Output matches.✅
   I will generate the response now. 
   Output matches the refined code exactly.✅
   [Done] 
   Output Generation. 
   *(Self-Correction/Refinement during thought)*: 
   Wait, should I include `from __future__ import annotations`? Not strictly necessary if Python 3.10+ is assumed, but it's safer to just use the syntax as given. I'll stick to the prompt's syntax.
   Also, should `add_job` return anything? The prompt doesn't specify, so `None` is fine.
   The code is minimal and correct.
   Proceeds. 
   Output matches. 
   [Final Check of the Prompt]: "Write only the Python code, no explanations." -> I will output exactly that.
   Code:
   ```python
   import heapq

   class JobQueue:
       def __init__(self):
           self._heap = []
           self._counter = 0

       def add_job(self, name: str, data: dict, priority: int = 0) -> None:
           heapq.heappush(self._heap, (-priority, self._counter, name, data))
           self._counter += 1

       def get_next_job(self) -> tuple[str, dict] | None:
           if not self._heap:
               return None
           _, _, name, data = heapq.heappop(self._heap)
           return name, data
   ```
   All good.✅
   Output matches. 
   [Proceeds]

</reasoning_content>

<content>
```python
import heapq

class JobQueue:
    def __init__(self):
        self._heap = []
        self._counter = 0

    def add_job(self, name: str, data: dict, priority: int = 0) -> None:
        heapq.heappush(self._heap, (-priority, self._counter, name, data))
        self._counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        if not self._heap:
            return None
        _, _, name, data = heapq.heappop(self._heap)
        return name, data
```
</content>