# Claims Desk

A cargo claims desk for a container shipping line, built as a template on the
Reckon design system. Fourteen screens, one fixture set, one route table.

Open `ClaimsDesk.dc.html`. Navigate with the top nav; the theme
toggle sits in the bar.

## The job it models

An adjuster receives a claim when freight arrives damaged, investigates it,
decides what the carrier owes, gets it paid or refused before the one-year time
bar expires, and then pursues whoever actually caused the damage.

## Files

| File | Holds |
|---|---|
| `ClaimsDesk.dc.html` | The template entry. Loads `ds-base.js`, `kit.css`, `boot.js`. |
| `ds-base.js` | Loads this design system. One line to repoint in a consuming project. |
| `boot.js` | Loads the product's files in order and publishes `window.ClaimsDeskApp`. |
| `enums.js` | Five status fields, the classification lists, the alert kinds, the policy constants, the derived flags, the transitions. |
| `nav.js` | The route table and the projections the shell renders. |
| `fixtures.js` | 19 claims, 16 claimants, 5 recoveries, 9 notifications. The only data in the product. |
| `metrics.js` | Every figure any screen renders. Nothing here holds data. |
| `kit.css` | Layout only. Every colour, radius, shadow and step is a token. |
| `lib/` | `contracts.js`, `ui-runtime.js`, `command-palette.js` — copied in, domain-free, byte-identical to every other product's copies. |
| `ClaimsParts.jsx` | The product's local components (below). |
| `ClaimsShell.jsx` | The top-nav shell, the claim's tab strip and the settings tab strip. |
| `*Screen.jsx` | The eleven screens outside settings and auth. |
| `ClaimsSettingsScreens.jsx` | The settings surface and its four views. |
| `ClaimsAuthScreens.jsx` | The auth shell, sign-in and signed-out. |
| `App.jsx` | Routing plus all of the commit machinery. |

## The fourteen screens

| Route | Screen | Primary display | Commit model |
|---|---|---|---|
| `/` | Work queue | Burn-down band over one dense claims table | Instant |
| `/claims/new` | New claim | Form beside a live cap-and-clock panel | **Staged** |
| `/claims/:id` | Assessment | The reconciliation ledger | **Staged** |
| `/claims/:id/evidence` | Evidence | Document checklist | Instant |
| `/claims/:id/decision` | Decision | Three outcomes on a generous surface | **Staged** |
| `/signoff` | Sign-off | Waiting figures over one table, and what came back | Instant |
| `/payments` | Payments | Release pipeline over the settlements table | Instant |
| `/responses` | Responses | The disputed offer, beside the offer ledger | Instant |
| `/recovery` | Recovery | The recovery rate, its breakdown, the files table | Instant |
| `/recovery/new` | New recovery | Form beside the settlement it will pursue | **Staged** |
| `/recovery/:id` | Recovery file | The mirror ledger and the correspondence | Instant |
| `/claimants/:id` | Claimant | The customer's whole history with the desk | Read-only |
| `/notifications` | Notifications | One list, grouped by day | Instant |
| `/settings` (+3) | Settings | Four views behind one tab strip | **Staged** |

`/signin` and `/signout` sit outside the shell entirely; see "Auth" below.

### Why sign-off, claimants and notifications exist

Each closes a hole rather than adding surface.

- **Sign-off** gives `awaiting_signoff` somewhere to land. "Send for sign-off"
  used to move a claim into a status with no screen behind it. The adjuster
  cannot sign her own work, so the two transitions here are the honest ones:
  chase it, or withdraw it and take the assessment back.
- **Claimant** turns `claim.customer` from a dead string into a record. It is
  the answer to the first question any adjuster asks — have we had this one
  before, and how did it go. The fixture holds only what a claim cannot (contact,
  lane, terms, first shipment); every figure is their own claims read through
  the same helpers the queue uses.
- **Notifications** is the destination behind the bar's panel. The panel shows
  the newest five and hands the rest over; without it, anything older than the
  panel's window was unreachable.

## Decisions taken once, for the whole product

- **Shell**: top-nav. Five top-level destinations, wide canvases, and the record
  work happens *inside* a destination rather than across many of them. The bar is
  the only navigation owner; the claim's three views and the four settings views
  are tabs, not a second row.
- **Density**: measured operational tables (44px rows, 16px cell gutters, 14px
  type) against generous decision surfaces (32px padding, 48rem measure). The
  contrast is the point. Prose earns its place: a note states the situation,
  never how the component works.
- **Separation**: hairlines and full-bleed bands on the tinted page plane; cards
  are the only raised surface, one elevation step, never nested.
- **Active state**: foreground token plus a persistent 2px underline.
- **Recession**: an *open* record the adjuster cannot act on is recessed — a claim
  waiting on the customer, a payment already with the bank, a recovery sitting
  with the counterparty. Closed records are plain, not recessed: they are
  finished, not blocked. Recession never comes from a count, always from a
  predicate, and the row always names who is being waited on.
- **Signature devices**: the time bar (one geometry everywhere it appears) and
  the ledger ladder (one track definition, a hard rule at the liability cap).
- **Tables carry one action**: the record's name is the link, and the action
  column holds the single transition its status allows, or nothing.

## The money chain

No screen subtracts anything. `metrics.js` owns it:

```
claimed → − depreciation − salvage − deductible = assessed
                                                   ↓
                             liabilityCap(claim) = higher of
                               packages × 666.67 SDR and kg × 2 SDR, at one rate
                                                   ↓
                                    payable = min(assessed, cap)
```

`assess(claim, draft)` runs the same chain for the saved assessment and for the
one the adjuster is typing, which is why the ledger moves as you type and the cap
collision is visible rather than arithmetic. `payableOf(claim)` is the figure
every other screen reads: the settlement owns it once one exists, the assessment
owns it before that, and a rejected claim is worth nothing.

The recovery rate is money-weighted over **closed** files only
(`recoveryRate`), and says so on screen: an open recovery has not failed yet.

## Act-ability

`CLAIM_FLAGS.isDecidable` is the one predicate — ready for decision **and** every
mandatory document on file. The nav count, the queue lede and the row button all
call it. The queue's first tab is deliberately looser ("On my desk", 3) than the
nav badge (2), and the lede names the claim that accounts for the difference.

## Verbs, named once

New claim · New recovery · Save claim · Save recovery ·
Chase documents · Chase surveyor · Chase sign-off · Withdraw decision ·
Record decision · Approve claim · Send for sign-off · Reject claim ·
Escalate to legal · Recall from legal · Schedule payment · Send payment ·
Record response · Reopen assessment · File notice · Record recovery ·
Write off recovery · Request again · Mark illegible · Mark all read.

Irreversible (confirm dialog): Send payment, Escalate to legal, Recall from
legal, Write off recovery. Consequential and reversible (undo toast): everything
else. Two- and three-field actions (Record response, Record recovery) open a
staged dialog from an instant screen.

## Local components — reported, per §9

Built here because the inventory has no equivalent; all of them are layout or
composition over existing primitives, and none invents a colour or a type size.

- **`TimeBar` / `ClaimClock`** — the burn-down track plus one countdown spelling.
  Used by the queue, all three claim screens, and both recovery screens.
- **`RecordHead`** — the record header shared by the claim's three views.
- **`DocumentPips`** — one pip per checklist row.
- **`LedgerRow` / `ProportionBars`** — the ledger ladder and the three bars
  against the cap wall.
- **`FormDialog`** — a staged dialog with two or three fields, so an instant
  screen can collect a small form without becoming staged itself.
- **`DecisionOption`** — a radio option that can hold its own fields.
- **`Figure`**, **`ExportMenu`**, **`Crumbs`**, **`RouteNotBuilt`** — small,
  repeated, unremarkable.
- **`Floating` / `FloatingTip`** (in `lib/ui-runtime.js`) — portalled menu,
  popover and tooltip. The design system's own overlays now portal too; these stay
  for their different API (one element as the trigger, a render callback that
  receives `close`, no compound Trigger/Popup pair).
- The burn-down band and the release pipeline are CSS in `kit.css`, not
  components: they are one-per-screen compositions.

## Creating records

Two things an adjuster actually creates, each with its own screen rather than a
dialog, because both carry a consequence worth showing before it is committed.

- **New claim** (`/claims/new`, from the work queue and from a claimant record)
  — the panel beside the form runs the real evaluators on the draft:
  `liabilityCap` gives the ceiling the bill of lading imposes from packages and
  weight alone, long before an assessment exists, and `CLAIM_FLAGS.timeBarAt`
  gives the deadline from the delivery date. If the claimed figure is above the
  cap it says so. The file opens `awaiting_documents` with the whole checklist
  requested, and lands on its evidence view.
- **New recovery** (`/recovery/new`, from the recovery destination) — the amount
  sought is never typed. It reads the settlement the claim paid, so the two
  sides of the same money cannot drift apart. Only released settlements with no
  recovery already open are offered; when there are none the screen is an empty
  state, not a form.

Both are staged, both continue the fixture's own id series (the next claim after
CLM-26-0212 is CLM-26-0213), and neither is destructive, so neither opens a
confirm dialog.

## Coverage

Every value of every status field has a fixture except `recovery.status:
written_off`, reachable only by writing a recovery off, which the kit does.
`claim.status: awaiting_signoff` now has two (CLM-26-0195, CLM-26-0207) behind
the sign-off queue.

## Known gaps

- Responsive behaviour is declared once in `kit.css` (1280 / 1024 / 768) and the
  shell's own collapse is declared once in `ClaimsShell.jsx`. Verified at desktop
  width in this pass; the narrow ends want a real check on a device.
- Auth (§7) is deliberately partial: `/signin` and `/signout` are designed;
  reset, MFA and lockout are not, and nothing links to them.
- Pagination: 18 claims and 8 settlements do not need it, so the list screens
  end in a stated count rather than a `Pagination`. A real desk would need it.
- Search results: the ⌘K palette jumps to a known record, but there is no
  `/search` screen for "every claim on this container". At this fixture size the
  palette is enough; a real desk would outgrow it.

## Settings and auth

The account menu has two entries: **Settings** and **Sign out**.

Settings is one surface with four views on a tab strip, reading the route table
the same way the claim's views do. `/settings` *is* the profile view, so the area
has no empty namespace parent and no route that resolves to a redirect.

- **Profile** — photo, name, title, email. Staged; the photo previews in the
  draft avatar and only reaches the account menu on Save.
- **Authority** — read-only. It is set by the carrier, not by the adjuster it
  limits, so it carries no form bar; what it can honestly show is what it costs
  today, counted with the same `CLAIM_FLAGS.needsSignoff` predicate the decision
  screen uses, and it links to the sign-off queue.
- **Alerts** — the six `ALERT_KINDS`, which is the same vocabulary every
  notification carries, so each row can state how many it has actually raised and
  the footer can say how many of the desk's notifications would have been
  emailed.
- **Desk** — three preferences, each naming the screen it changes: where signing
  in lands, the queue's first tab, and whether a decidable claim opens at its
  decision. Nothing cosmetic, and nothing offered that no screen reads.

Auth (`/signin`, `/signout`) renders on its own shell: no navigation owner, one
layout variant (centred card), one credential strategy (password). No providers,
because this project ships no `assets/providers/` marks and §7.4 forbids drawing
them. Designed states: idle, field-invalid, submitting, signed-out. Rate
limiting, lockout, MFA and the four password-reset screens remain out of scope,
so nothing links to them.
