<reasoning_content>
The user wants to implement a priority-based job scheduling queue in Python.
Requirements:
1. `add_job` should accept an optional `priority` parameter (default=0)
2. Higher priority jobs processed first
3. Same priority jobs maintain FIFO order
4. `get_next_job()` returns `tuple[str, dict] | None`
5. Priority levels: 0: Normal, 1: High, 2: Critical

I need to implement a `JobQueue` class.
To maintain FIFO order for same priority jobs, I can use a list of queues or a heap with a counter to break ties.
Using `heapq` with a counter is a standard approach:
Store items as `(-priority, counter, job_id, job_data)` so that higher priority comes first, and for same priority, lower counter (earlier insertion) comes first.
Wait, `heapq` is a min-heap. So if I use `-priority`, higher priority becomes smaller number, so it comes out first.
Counter increments with each insertion.
Let's verify:
priority 2 -> -2
priority 1 -> -1
priority 0 -> 0
Min-heap will pop -2 first, then -1, then 0. Correct.
For same priority, counter ensures FIFO.

Structure:
```python
import heapq
from typing import Optional

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

    def add_job(self, job_id: str, job_data: dict, priority: int = 0) -> None:
        heapq.heappush(self._queue, (-priority, self._counter, job_id, job_data))
        self._counter += 1

    def get_next_job(self) -> Optional[tuple[str, dict]]:
        if self._queue:
            _, _, job_id, job_data = heapq.heappop(self._queue)
            return job_id, job_data
        return None
```

Wait, the type hint for `get_next_job` is `tuple[str, dict] | None`. In Python 3.10+, `|` is supported. I'll use that or `Optional[tuple[str, dict]]`. The prompt says `tuple[str, dict] | None`.

Let's check if there are any edge cases.
The prompt says "Write only the Python code, no explanations."
I'll make sure the class matches the example.
Example:
```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
```

My implementation matches this.
I should include `import heapq` at the top.
I'll use type hints as requested.

One minor thing: `tuple[str, dict] | None` requires Python 3.10+. I'll stick to it as requested.
Alternatively, I can use `typing.Optional` if needed, but the prompt explicitly shows `tuple[str, dict] | None`.

Let's write it out carefully.

```python
import heapq
from typing import Optional

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

    def add_job(self, job_id: str, job_data: dict, priority: int = 0) -> None:
        heapq.heappush(self._queue, (-priority, self._counter, job_id, job_data))
        self._counter += 1

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

Wait, should I include `from __future__ import annotations` to support `|` in older Python versions? Not strictly necessary, but good practice. The prompt doesn't specify Python version, but `|` for unions is standard in 3.10+. I'll just use it as is.

Let's double check the requirements:
1. Modify `add_job` to accept an optional priority parameter (default=0) -> Done
2. Higher priority jobs should be processed before lower priority jobs -> Done via `-priority`
3. Jobs with the same priority should maintain FIFO order -> Done via `_counter`
4. Add `get_next_job() -> tuple[str, dict] | None` -> Done

All requirements met.
I will output only the code.
One thing: `tuple[str, dict] | None` might cause a syntax error in Python < 3.10. I'll add `from __future__ import annotations` to be safe, or just use `Optional[tuple[str, dict]]`. The prompt explicitly shows `tuple[str, dict] | None`, so I'll stick to that. It's fine.

I'll write the complete code block.
Check if any imports are needed: `heapq` is needed.
I'll provide exactly what's requested.
Ready. 
Output matches the request.
One minor point: The prompt says "Modify `add_job`", implying there might be an existing class, but since I'm providing the full implementation, I'll just give the class definition.
I'll make sure the code is self-contained.

```python
import heapq

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

    def add_job(self, job_id: str, job_data: dict, priority: int = 0) -> None:
        heapq.heappush(self._queue, (-priority, self._counter, job_id, job_data))
        self._counter += 1

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

This looks solid. I'll output it.
Wait, should I include type hints for `__init__`? Not required but fine.
The prompt says "Write only the Python code, no explanations."
I will output exactly that.
All good. 
Proceeding. 
Self-Correction/Verification during thought:
- Does `heapq` maintain FIFO for same priority? Yes, because tuples are compared element by element. `(-priority, counter, ...)` ensures that when `-priority` is equal, `counter` is compared, and since `counter` increases monotonically, earlier jobs have smaller counters and come out first.
- Type hint `tuple[str, dict] | None` is valid in Python 3.10+. I'll keep it.
- The example shows `queue.add_job("normal", {"type": "normal"}, priority=0)`. My signature matches.
- Everything is correct.

Output matches the code block.✅
I will generate it now. 
No extra text.
Done. 
[Output Generation] -> *Proceeds*
```python
import heapq

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

    def add_job(self, job_id: str, job_data: dict, priority: int = 0) -> None:
        heapq.heappush(self._queue, (-priority, self._counter, job_id, job_data))
        self._counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        if self._queue:
            _, _, job_id, job_data = heapq.heappop(self._queue)
            return job_id, job_data
        return None
```
Matches requirements exactly.✅
Done. 
(Self-Correction/Note during generation prep: I'll make sure to include `from __future__ import annotations` just in case, but it's not strictly necessary. I'll stick to the clean version.)
Actually, `tuple[str, dict] | None` is fine. I'll output exactly as prepared.
All good. 
Output matches response. 
[Final Check]
Requirements:
1. `add_job` accepts optional priority (default=0) -> Yes
2. Higher priority first -> Yes, `-priority` in min-heap
3. Same priority FIFO -> Yes, `_counter` breaks ties
4. `get_next_job() -> tuple[str, dict] | None` -> Yes
Example works -> Yes
Code only -> Yes
Ready. 
Output matches. 
Proceeds. 
[Output Generation] (matches the final code block)
```python
import heapq

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

    def add_job(self, job_id: str, job_data: dict, priority: int = 0) -> None:
        heapq.heappush(self._queue, (-priority, self._counter, job_id, job_data))
        self._counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        if self._queue:
            _, _, job_id, job_data = heapq.heappop(self._queue)
            return job_id, job_data
        return None
```
Done. 
(Self-Correction/Refinement during thought: I should verify if `tuple[str, dict] | None` needs `from __future__ import annotations` for compatibility. It's safer to just use it as is since modern Python supports it. The prompt explicitly uses that syntax, so it's fine.)
All good. 
Output matches. 
Proceeds. 
[Final Output Generation] -> *Outputs code*
(Note: I'll make sure formatting is exact.)
Done. 
[Output] -> *Proceeds*

</reasoning_content>

<content>
```python
import heapq

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

    def add_job(self, job_id: str, job_data: dict, priority: int = 0) -> None:
        heapq.heappush(self._queue, (-priority, self._counter, job_id, job_data))
        self._counter += 1

    def get_next_job(self) -> tuple[str, dict] | None:
        if self._queue:
            _, _, job_id, job_data = heapq.heappop(self._queue)
            return job_id, job_data
        return None
```
</content>