<reasoning_content>
The user wants a Python implementation of a priority-based job scheduling queue.
Requirements:
1. `add_job(name: str, data: dict, priority: int = 0)`
2. Higher priority value = higher priority (processed first)
3. FIFO for same priority
4. `get_next_job() -> tuple[str, dict] | None`
5. Priority levels: 0 (Normal), 1 (High), 2 (Critical) - these are just examples, the logic should handle arbitrary integers where higher = higher priority.

I'll use `heapq` for efficient priority queue operations. Since `heapq` is a min-heap, I can store negative priorities to achieve max-heap behavior, or store tuples with a counter to handle FIFO for same priorities.

Wait, `heapq` compares tuples element by element. If I store `(-priority, counter, name, data)`, it will:
- Sort by priority descending (because of negative)
- Break ties by counter ascending (FIFO)
- Then name and data don't matter for ordering, but they need to be comparable if priorities and counters are equal (which they won't be due to unique counter).

Actually, I can just use a class or a simple list with `sort` or `heapq`. Given the requirements, a heap is efficient.

Let's implement a `JobQueue` class.

```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:
        # Use negative priority for max-heap behavior with heapq
        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, the requirement says `get_next_job() -> tuple[str, dict] | None`.
The example shows:
```python
queue = JobQueue()
queue.add_job("normal", {"type": "normal"}, priority=0)
queue.add_job("critical", {"type": "critical"}, priority=2)
queue.add_job("high", {"type": "high"}, priority=1)

job = queue.get_next_job()  # Returns critical job first
```

This matches my implementation.
Let's double check type hints. `tuple[str, dict] | None` is valid in Python 3.10+. I'll stick to it.
Should I handle the case where `data` might not be a dict? The signature says `data: dict`.
The requirement says "Write only the Python code, no explanations."

One minor thing: `heapq` in Python compares tuples element-wise. If `-priority` and `counter` are equal (impossible due to counter), it would compare `name` and `data`. `data` is a dict, which is not comparable in Python 3. So it's safer to ensure the tuple length is 3, or put `name` and `data` at the end but make sure they aren't compared, or just rely on counter uniqueness. Since counter is strictly increasing, it will always be unique, so the tuple comparison will never reach `name` or `data`. So it's safe.

Alternatively, I can store only `(-priority, counter, name, data)` and it's fine.

Let's verify the exact signature requested:
`add_job` to accept an optional priority parameter (default=0)
`get_next_job() -> tuple[str, dict] | None`

I'll write the complete class.

```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 include type hints for `add_job`? The prompt says "Modify `add_job` to accept an optional priority parameter (default=0)". I'll add type hints for completeness, but it's not strictly required. I'll stick to the prompt's style.

One thing: `tuple[str, dict] | None` is Python 3.10+ syntax. I'll use it as requested.

Is there any edge case? Empty queue returns None. FIFO for same priority is handled by counter. Higher priority first is handled by negative priority.

The code looks solid.

I will output only the Python code as requested.
I'll make sure it's clean and matches the requirements exactly.

One minor adjustment: sometimes people prefer `typing.Optional` and `typing.Tuple` for broader compatibility, but the prompt uses `tuple[str, dict] | None`, so I'll stick to that.

Final check of 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) -> 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
```

This satisfies all requirements. I'll output it.
Wait, should I include `from typing import ...`? Not necessary unless specified. The prompt uses built-in generics.
I'll just output the code block.
All good. 
Proceed. 
Output matches response. 
Self-Correction/Verification during thought: 
Does `heapq` guarantee stability for equal priorities? No, but we use `_counter` to break ties deterministically, which ensures FIFO. 
Is `data` guaranteed to be dict? Yes, per signature. 
Does it handle the example correctly? 
add_job("normal", {...}, 0) -> heap: [(-0, 0, "normal", {...})]
add_job("critical", {...}, 2) -> heap: [(-2, 1, "critical", {...}), (-0, 0, "normal", {...})] (heapq order might vary but min is -2)
add_job("high", {...}, 1) -> heap: [(-2, 1, "critical", {...}), (-0, 0, "normal", {...}), (-1, 2, "high", {...})] -> actually heapq maintains heap property, get_next pops min which is -2 (priority 2). Correct.
FIFO: if priorities equal, counter breaks tie. Correct.
Returns `tuple[str, dict] | None`. Correct.
Code is ready.✅
Output matches the final code block. 
Proceeds. 
[Output Generation] -> *Proceeds*
```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 constraints met. No extra text. Done. 
Self-Correction/Note during generation prep: The prompt says "Write only the Python code, no explanations." I will strictly follow that.
I'll output exactly the code.
Done. 
[Output Generation] -> *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>