# Navigation shell

The navigation shell provides shared spatial structure and interaction expectations while keeping product routes, labels, permissions, and information architecture application-owned.

## Anatomy

| Region | Canonical size | Purpose |
| --- | --- | --- |
| Product rail | `--navigation-rail-width` (64px) | Stable access to top-level product areas |
| Contextual sidebar | `--navigation-sidebar-width` (240px) | Navigation for the selected product area |
| Topbar | `--navigation-height` (64px) | Page identity and global utilities |
| Content | Up to `--content-max-width` | Product-owned page content on the neutral canvas |

The expanded desktop offset is 304px: the rail and contextual sidebar together. The collapsed desktop state retains the 64px rail and removes the sidebar from the layout.

## Desktop states

### Expanded

- Show the rail and contextual sidebar.
- Identify the selected product area in the rail and the current route in the sidebar.
- Keep the Navigation eyebrow and area switcher visible above its local navigation rows.
- Use this state when the viewport can preserve an appropriate content width.

### Collapsed

- Keep the rail visible; do not reduce navigation to an unlabeled floating trigger.
- Preserve page or area identity in the topbar.
- Provide tooltips for every icon-only rail item.
- Persist the preference using a product-specific storage key.
- Routes, state restoration, and collapse breakpoints remain application-owned.

## Mobile drawer

- Replace the fixed desktop navigation with a menu trigger in the topbar.
- Open navigation as a modal drawer over a scrim.
- Keep the drawer within the viewport and make its content independently scrollable.
- Close after navigation, when the scrim is activated, or when Escape is pressed.
- Return focus to the menu trigger after dismissal.
- Trap focus while the drawer is open and prevent the page behind it from scrolling.

## Item states

Rail items and sidebar rows must define Default, Hover, Active, Focus, and Disabled states. Use `aria-current="page"` for the current route. Disabled navigation is uncommon; when necessary, expose the reason in adjacent help or an accessible tooltip.

### Sidebar row surfaces

| State | Surface | Text | Additional signal |
| --- | --- | --- | --- |
| Default | Transparent | `--text-muted` | None |
| Hover | `--navigation-item-hover-surface` | `--text-strong` | Pointer cursor and 150ms transition |
| Active | `--navigation-item-active-surface` | `--text-strong` | Medium label and `aria-current="page"` |
| Focus visible | State surface plus the canonical focus indicator | `--text-strong` | 2px outline outside the row |
| Disabled | Transparent | Current text at reduced opacity | Non-interactive; explain why when useful |

The hover surface must be visibly distinct from the contextual-sidebar background: it resolves to the panel surface in light mode and the muted surface in dark mode. The active state uses the muted light surface and panel dark surface, plus a persistent medium-weight label. Do not use a product accent, status color, heavy border, or shadow to mark the current route. Hovering the active row keeps the active treatment.

## Sidebar labels and spacing

- Render the `Navigation` eyebrow at approximately 0.65rem, regular weight, uppercase, with 0.35em tracking. It labels the switcher; it is not a subsection heading.
- Render the current product area as the switcher trigger directly below the eyebrow, at approximately 1.125rem and semibold weight.
- Render local subsection titles at 0.6rem, semibold, uppercase, with restrained 0.08em tracking. Place them inside the row gutter and separate them from the switcher with 24px of vertical space.
- Use compact local rows: 6px vertical and 16px horizontal padding, with an 8–12px radius. A destination chevron is visible for the active row and appears on hover or keyboard focus for inactive rows.

## Carets and destination chevrons

The sidebar uses two visually related indicators with different meanings:

- **Section caret:** appears beside a collapsible section title. It points right when collapsed and down when expanded. Make the entire title row the button, expose `aria-expanded` and `aria-controls`, and rotate the icon with `--motion-interface`. Do not show a caret when the section cannot collapse.
- **Destination chevron:** appears at the end of a row that opens another navigation level or a detail destination. It always points right and does not rotate. Omit it on a leaf destination when it adds no useful expectation.

Both indicators use `--navigation-caret-color`, a 16px visual box, and a 1.5–1.75px stroke. They remain secondary to the label and never carry state by color alone.

## Navigation switcher

When the contextual sidebar can represent several top-level product areas, place the canonical Navigation switcher above its local rows. It displays the current area and opens a link-based navigation popup. Follow the separate [Navigation switcher specification](./navigation-switcher.md) for semantics, focus, keyboard behavior, and product boundaries.

## Accessibility

1. Use a `nav` landmark with a concise accessible label.
2. Give icon-only rail actions stable accessible names and visible tooltips.
3. Keep tab order aligned with the visual order.
4. Do not move keyboard focus when the desktop sidebar is collapsed unless the focused control disappears.
5. Announce neither routine route changes nor collapse animation as live-region messages.
6. Respect reduced-motion preferences and avoid animating content width over long durations.
7. Keep the section-caret button and each destination row as separate focus stops; the icon itself is decorative.

## Product boundary

The design system owns dimensions, visual hierarchy, states, and interaction rules. Each product owns its routes, authorization, labels, responsive breakpoint, persistence key, and navigation data.
