Here is the refactored package structure with clean separation of concerns, proper relative imports, and a focused public API.

### `queue/__init__.py`
```python
"""
Queue package public API.
"""
from .core import Job, JobQueue
from .priority import PriorityQueue
from .retry import process_with_retry

__all__ = ["Job", "JobQueue", "PriorityQueue", "process_with_retry"]
```

### `queue/core.py`
```python
"""
Core data structures and basic FIFO queue operations.
"""
from __future__ import annotations

import time
from dataclasses import dataclass, field
from collections import deque
from typing import Any, Optional


@dataclass
class Job:
    """Represents a unit of work to be processed."""
    id: str
    payload: Any
    status: str = "pending"
    created_at: float = field(default_factory=time.time)
    retries: int = 0
    last_error: Optional[str] = None


class JobQueue:
    """Thread-unsafe FIFO queue for Job objects."""
    
    def __init__(self) -> None:
        self._queue: deque[Job] = deque()

    def enqueue(self, job: Job) -> None:
        """Add a job to the back of the queue."""
        self._queue.append(job)

    def dequeue(self) -> Optional[Job]:
        """Remove and return the job at the front of the queue."""
        return self._queue.popleft() if self._queue else None

    def is_empty(self) -> bool:
        """Return True if the queue contains no jobs."""
        return len(self._queue) == 0

    def __len__(self) -> int:
        return len(self._queue)
```

### `queue/priority.py`
```python
"""
Priority queue implementation using a min-heap.
"""
from __future__ import annotations

import heapq
from typing import Optional, Tuple

from .core import Job


class PriorityQueue:
    """Priority-based queue where lower integer values indicate higher priority."""
    
    def __init__(self) -> None:
        self._heap: list[Tuple[int, int, Job]] = []
        self._counter = 0  # Ensures FIFO order for equal priorities

    def enqueue(self, job: Job, priority: int = 0) -> None:
        """Add a job with a given priority to the queue."""
        self._counter += 1
        heapq.heappush(self._heap, (priority, self._counter, job))

    def dequeue(self) -> Optional[Job]:
        """Remove and return the job with the highest priority."""
        if not self._heap:
            return None
        _, _, job = heapq.heappop(self._heap)
        return job

    def is_empty(self) -> bool:
        """Return True if the queue contains no jobs."""
        return len(self._heap) == 0

    def __len__(self) -> int:
        return len(self._heap)
```

### `queue/retry.py`
```python
"""
Retry logic with exponential backoff for job execution.
"""
from __future__ import annotations

import time
from typing import Callable, Any, Optional

from .core import Job


def process_with_retry(
    func: Callable[[Job], Any],
    job: Job,
    max_retries: int = 3,
    base_delay: float = 1.0,
    max_delay: float = 60.0,
) -> Job:
    """
    Execute a job function with exponential backoff on failure.
    
    Args:
        func: Callable that accepts a Job and processes it.
        job: The Job instance to process.
        max_retries: Maximum number of retry attempts.
        base_delay: Initial delay in seconds between retries.
        max_delay: Maximum delay in seconds between retries.
        
    Returns:
        The updated Job instance with final status.
    """
    for attempt in range(max_retries + 1):
        try:
            func(job)
            job.status = "completed"
            job.last_error = None
            return job
        except Exception as e:
            job.last_error = str(e)
            job.retries = attempt + 1
            job.status = "failed"

            if attempt < max_retries:
                delay = min(base_delay * (2 ** attempt), max_delay)
                time.sleep(delay)
            else:
                job.status = "permanently_failed"
                
    return job
```

### Key Refactoring Decisions:
1. **Single Responsibility**: `core.py` handles data & FIFO logic, `priority.py` handles ordering, `retry.py` handles execution/backoff, and `__init__.py` exposes the public surface.
2. **Relative Imports**: All inter-module imports use `.` notation, making the package portable and avoiding circular import risks.
3. **Interface Consistency**: `PriorityQueue` mirrors `JobQueue`'s public interface (`enqueue`, `dequeue`, `is_empty`, `__len__`) without forced inheritance, keeping dependencies explicit and testable.
4. **Type Safety & Docs**: Added `from __future__ import annotations`, proper type hints, and concise docstrings for maintainability.
5. **Exponential Backoff**: Implements standard `base_delay * 2^attempt` with a `max_delay` cap, and correctly updates job state on each attempt.