<reasoning_content>
*   Goal: Implement priority-based job scheduling for a `JobQueue` class.
    *   Requirements:
        1. `add_job` must accept `priority` (default=0).
        2. Higher priority (larger numbers) processed first.
        3. Tie-break: FIFO (First-In, First-Out).
        4. `get_next_job()` returns `tuple[str, dict]` or `None`.
    *   Priorities: 0 (Normal), 1 (High), 2 (Critical).

    *   To maintain priority and FIFO order efficiently, a Priority Queue (using `heapq`) is the standard tool.
    *   `heapq` is a min-heap. To make it a max-heap (since higher numbers = higher priority), I need to negate the priority values.
    *   To maintain FIFO for equal priorities, I need a secondary sorting key (an incrementing counter).

    *   `self.queue`: A list to be used with `heapq`.
    *   `self.counter`: An integer to track order.

    *   `add_job(name: str, data: dict, priority: int = 0)`:
        *   Push `(-priority, self.counter, name, data)` into the heap.
        *   Increment `self.counter`.
    *   `get_next_job() -> tuple[str, dict] | None`:
        *   If heap is empty, return `None`.
        *   Pop the smallest item (highest actual priority due to negation).
        *   Return `(name, data)`.

    *   `heapq.heappush(heap, item)`
    *   `heapq.heappop(heap)`

    *   `priority=0` (Normal), `priority=1` (High), `priority=2` (Critical).
    *   Higher priority = larger number.
    *   Negation logic:
        *   Priority 2 -> -2
        *   Priority 1 -> -1
        *   Priority 0 -> 0
        *   Min-heap sorts -2 < -1 < 0. So -2 comes out first. Correct.

    ```python
    import heapq

    class JobQueue:
        def __init__(self):
            self.heap = []
            self.counter = 0

        def add_job(self, name: str, data: dict, priority: int = 0):
            # Use negative priority for max-heap behavior
            # Use counter to maintain FIFO for same priority
            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)
    ```

    *   Modify `add_job`? Yes.
    *    Higher priority first? Yes (-2 < -1 < 0).
    *    Same priority FIFO? Yes (counter).
    *    `get_next_job` returns `tuple[str, dict] | None`? Yes.

    Wait, the prompt says "Write only the Python code, no explanations."

    Double check `get_next_job` return type. `tuple[str, dict] | None`.

    One edge case: Is `counter` needed? Yes, because if two jobs have priority 2, `heapq` will try to compare the next item in the tuple, which is `name`. If names aren't comparable or if we want strict FIFO, `counter` is necessary. `name` is a string, so it would compare lexicographically if priorities are equal. FIFO requires an auto-incrementing integer.
</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):
        # Negate priority to turn min-heap into max-heap
        # Use counter to maintain FIFO order for identical priorities
        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>