# Metrics

> Package `@umriss-ui/calculation`, version 0.40.0. Demo page: <https://romanhaendler.github.io/umriss-ui/calculation/metrics/>. Every page in one line: [llms.txt](https://romanhaendler.github.io/umriss-ui/calculation/llms.txt); every page in full: [llms-full.txt](https://romanhaendler.github.io/umriss-ui/calculation/llms-full.txt).

Several numbers on every line, side by side (columns, measures): headcount and full-time equivalents of the same teams, summed by the same derivation. Reach for it where one sheet has to answer in more than one unit.

```ts
import { Calculation, Given, Sum, Chain, Plus, Minus, Interim } from "@umriss-ui/calculation";
```

Demo page: https://romanhaendler.github.io/umriss-ui/calculation/metrics/

`metrics` on the calculation names each metric once, with its unit and places; every `value` is then an object with a number for each metric id. Each metric is worked on its own - nothing ever takes numbers from two of them ([ADR-0038](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0038-a-calculation-can-carry-several-metrics.md)).

The head names each metric above its column. The unit stands again only where a result closes: the Result, an interim, the line that closes an open derivation.

A number one metric does not have is `null`, and makes absent only what depends on it in that metric; the badge says which metric, the sentence the full reason.

Where the figures leave the labels less room than they need, and less than 10 rem, each line puts them on a line beneath its label, still in their columns. The component measures this: it depends on the labels, the number of metrics and their digits, not on a breakpoint.

## Examples

### Headcount and full-time equivalents

`metrics` puts several numbers on every line, each in its own column; every `value` is then an object with a number per metric.

```tsx
import { Calculation, Given, Sum } from "@umriss-ui/calculation";
import type { Metric } from "@umriss-ui/calculation";

/* Data from the planning world, written out here so the example runs on its own. */

interface Person {
  id: string;
  name: string;
  role: "Developer" | "Designer" | "Product manager" | "QA engineer";
  team: "Web" | "Apps";
  /** Hours a week they can be planned for. */
  capacity: number;
}

const PEOPLE: readonly Person[] = [
  { id: "maya", name: "Maya Lindgren", role: "Product manager", team: "Web", capacity: 32 },
  { id: "arjun", name: "Arjun Mehta", role: "Developer", team: "Web", capacity: 40 },
  { id: "chloe", name: "Chloe Durand", role: "Developer", team: "Web", capacity: 40 },
  { id: "noah", name: "Noah Fischer", role: "Designer", team: "Web", capacity: 24 },
  { id: "eva", name: "Eva Novak", role: "QA engineer", team: "Web", capacity: 40 },
  { id: "luis", name: "Luis Moreno", role: "Product manager", team: "Apps", capacity: 40 },
  { id: "hana", name: "Hana Sato", role: "Developer", team: "Apps", capacity: 40 },
  { id: "kofi", name: "Kofi Mensah", role: "Developer", team: "Apps", capacity: 32 },
  { id: "freya", name: "Freya Olsen", role: "Designer", team: "Apps", capacity: 40 },
  { id: "david", name: "David Kowalski", role: "QA engineer", team: "Apps", capacity: 20 },
];

const METRICS: Metric[] = [
  { id: "heads", label: "Headcount", unit: "HC" },
  { id: "fte", label: "Full-time equivalents", unit: "FTE", decimals: 1 },
];

/* A full-time week is 40 hours. */
const staffOf = (team: "Web" | "Apps") => {
  const people = PEOPLE.filter((person) => person.team === team);
  return { heads: people.length, fte: people.reduce((sum, person) => sum + person.capacity, 0) / 40 };
};

export default function TwoTeams() {
  return (
    <Calculation aria-label="Staff of Tidewell" metrics={METRICS}>
      <Sum label="Tidewell">
        <Given label="Web team" value={staffOf("Web")} />
        <Given label="Apps team" value={staffOf("Apps")} />
      </Sum>
    </Calculation>
  );
}
```

### A number one metric does not have

`null` for one metric makes absent only what depends on it in that metric, with the reason; the other metric sums on.

```tsx
import { Calculation, Given, Sum } from "@umriss-ui/calculation";
import type { Metric } from "@umriss-ui/calculation";

const METRICS: Metric[] = [
  { id: "heads", label: "Headcount", unit: "HC" },
  { id: "fte", label: "Full-time equivalents", unit: "FTE", decimals: 1 },
];

export default function NotRecorded() {
  return (
    <Calculation aria-label="Staff of customer service" metrics={METRICS}>
      <Sum label="Customer service">
        <Given label="Service desk" value={{ heads: 7, fte: 5.9 }} />
        <Given label="Returns" value={{ heads: 3, fte: 2.5 }} />
        <Given
          label="Working students"
          value={{ heads: 4, fte: null }}
          explanation="Paid by the hour; no contracted hours to count."
        />
      </Sum>
    </Calculation>
  );
}
```

### Team, cost centre, business line

A tree of sums, built from data: every cost centre folds to its total and opens into its teams, each metric summed on its own.

```tsx
import { Calculation, Given, Sum } from "@umriss-ui/calculation";
import type { Metric } from "@umriss-ui/calculation";

/* Data from the controlling world, written out here so the example runs on its own. */

interface CostCentre {
  id: string;
  name: string;
  owner: string;
  /** The budget of one month. */
  monthlyBudget: number;
}

const COST_CENTRES: readonly CostCentre[] = [
  { id: "CC-1100", name: "Sales", owner: "Helen Marsh", monthlyBudget: 142_000 },
  { id: "CC-1200", name: "Marketing", owner: "Rafael Ortiz", monthlyBudget: 68_000 },
  { id: "CC-2100", name: "Engineering", owner: "Anika Sørensen", monthlyBudget: 188_000 },
  { id: "CC-2200", name: "Design", owner: "Paul Whitaker", monthlyBudget: 54_000 },
  { id: "CC-3100", name: "Customer service", owner: "Grace Obi", monthlyBudget: 61_000 },
  { id: "CC-4100", name: "Finance", owner: "Martina Vogel", monthlyBudget: 47_000 },
  { id: "CC-4200", name: "People", owner: "Daniel Frost", monthlyBudget: 39_000 },
  { id: "CC-4300", name: "IT", owner: "Kenji Arai", monthlyBudget: 83_000 },
  { id: "CC-4400", name: "Facilities", owner: "Olga Ivanova", monthlyBudget: 72_000 },
];

interface Team {
  /** The cost centre the team books to. */
  costCentre: string;
  name: string;
  /** People employed, whatever their hours. */
  headcount: number;
  /** Full-time equivalents: contracted hours over 40 a week. */
  fte: number;
  /** Staff cost of a month, in thousand euros. */
  monthlyCost: number;
}

/** Every team, on 17 March: 102 people, 91.5 full-time equivalents. */
const TEAMS: readonly Team[] = [
  { costCentre: "CC-1100", name: "Field sales North", headcount: 9, fte: 8.6, monthlyCost: 61.2 },
  { costCentre: "CC-1100", name: "Field sales South", headcount: 8, fte: 7.5, monthlyCost: 53.9 },
  { costCentre: "CC-1100", name: "Inside sales", headcount: 6, fte: 5.2, monthlyCost: 29.8 },
  { costCentre: "CC-1100", name: "Key accounts", headcount: 4, fte: 4.0, monthlyCost: 33.6 },
  { costCentre: "CC-1200", name: "Brand", headcount: 3, fte: 2.8, monthlyCost: 19.4 },
  { costCentre: "CC-1200", name: "Online marketing", headcount: 4, fte: 3.5, monthlyCost: 24.1 },
  { costCentre: "CC-1200", name: "Trade fairs", headcount: 2, fte: 1.5, monthlyCost: 10.2 },
  { costCentre: "CC-3100", name: "Service desk", headcount: 7, fte: 5.9, monthlyCost: 31.3 },
  { costCentre: "CC-3100", name: "Returns", headcount: 3, fte: 2.5, monthlyCost: 12.6 },
  { costCentre: "CC-2100", name: "Seating", headcount: 6, fte: 5.8, monthlyCost: 43.5 },
  { costCentre: "CC-2100", name: "Desks", headcount: 7, fte: 6.5, monthlyCost: 48.1 },
  { costCentre: "CC-2100", name: "Storage", headcount: 5, fte: 4.6, monthlyCost: 33.9 },
  { costCentre: "CC-2100", name: "Test lab", headcount: 3, fte: 2.5, monthlyCost: 16.8 },
  { costCentre: "CC-2200", name: "Industrial design", headcount: 4, fte: 3.6, monthlyCost: 27.2 },
  { costCentre: "CC-2200", name: "Colour and material", headcount: 2, fte: 1.8, monthlyCost: 12.9 },
  { costCentre: "CC-4100", name: "Accounting", headcount: 5, fte: 4.4, monthlyCost: 27.5 },
  { costCentre: "CC-4100", name: "Controlling", headcount: 3, fte: 3.0, monthlyCost: 21.3 },
  { costCentre: "CC-4200", name: "Recruiting", headcount: 2, fte: 1.8, monthlyCost: 12.4 },
  { costCentre: "CC-4200", name: "Payroll", headcount: 2, fte: 1.5, monthlyCost: 9.6 },
  { costCentre: "CC-4300", name: "Workplace", headcount: 4, fte: 3.8, monthlyCost: 24.2 },
  { costCentre: "CC-4300", name: "Applications", headcount: 5, fte: 4.5, monthlyCost: 34.8 },
  { costCentre: "CC-4400", name: "Buildings", headcount: 3, fte: 3.0, monthlyCost: 16.9 },
  { costCentre: "CC-4400", name: "Canteen", headcount: 5, fte: 3.2, monthlyCost: 14.7 },
];

const METRICS: Metric[] = [
  { id: "heads", label: "Headcount", unit: "HC" },
  { id: "fte", label: "Full-time equivalents", unit: "FTE", decimals: 1 },
];

const COMMERCIAL = ["CC-1100", "CC-1200", "CC-3100"];

export default function BusinessLine() {
  return (
    <Calculation aria-label="Staff of the commercial business line, 17 March" metrics={METRICS}>
      <Sum label="Commercial">
        {COMMERCIAL.map((id) => (
          <Sum key={id} label={COST_CENTRES.find((centre) => centre.id === id)!.name}>
            {TEAMS.filter((team) => team.costCentre === id).map((team) => (
              <Given key={team.name} label={team.name} value={{ heads: team.headcount, fte: team.fte }} />
            ))}
          </Sum>
        ))}
      </Sum>
    </Calculation>
  );
}
```

### Staff movement as a chain

The chain works per metric too: joiners added, leavers taken away, and every interim closes with its units.

```tsx
import { Calculation, Chain, Given, Interim, Minus, Plus } from "@umriss-ui/calculation";
import type { Metric } from "@umriss-ui/calculation";

const METRICS: Metric[] = [
  { id: "heads", label: "Headcount", unit: "HC" },
  { id: "fte", label: "Full-time equivalents", unit: "FTE", decimals: 1 },
];

export default function StaffMovement() {
  return (
    <Calculation aria-label="Staff movement of Carrow & Lisle since 1 January" metrics={METRICS}>
      <Chain>
        <Given label="Staff on 1 January" value={{ heads: 100, fte: 89.9 }} source="Payroll" />
        <Plus label="Joiners" value={{ heads: 5, fte: 4.6 }} />
        <Minus label="Leavers" value={{ heads: 2, fte: 1.8 }} />
        <Interim label="Under contract" />
        <Minus label="Gone on parental leave" value={{ heads: 2, fte: 1.6 }} />
        <Plus label="Back from parental leave" value={{ heads: 1, fte: 0.4 }} explanation="Back part-time, 16 hours a week." />
        <Interim label="Staff on 17 March" />
      </Chain>
    </Calculation>
  );
}
```

### A third metric: staff cost

Any number of metrics, each with its unit and places. Narrow, where the figures leave the label too little room, each line puts them beneath its label.

```tsx
import { Calculation, Given, Sum } from "@umriss-ui/calculation";
import type { Metric } from "@umriss-ui/calculation";

/* Data from the controlling world, written out here so the example runs on its own. */

interface CostCentre {
  id: string;
  name: string;
  owner: string;
  /** The budget of one month. */
  monthlyBudget: number;
}

const COST_CENTRES: readonly CostCentre[] = [
  { id: "CC-1100", name: "Sales", owner: "Helen Marsh", monthlyBudget: 142_000 },
  { id: "CC-1200", name: "Marketing", owner: "Rafael Ortiz", monthlyBudget: 68_000 },
  { id: "CC-2100", name: "Engineering", owner: "Anika Sørensen", monthlyBudget: 188_000 },
  { id: "CC-2200", name: "Design", owner: "Paul Whitaker", monthlyBudget: 54_000 },
  { id: "CC-3100", name: "Customer service", owner: "Grace Obi", monthlyBudget: 61_000 },
  { id: "CC-4100", name: "Finance", owner: "Martina Vogel", monthlyBudget: 47_000 },
  { id: "CC-4200", name: "People", owner: "Daniel Frost", monthlyBudget: 39_000 },
  { id: "CC-4300", name: "IT", owner: "Kenji Arai", monthlyBudget: 83_000 },
  { id: "CC-4400", name: "Facilities", owner: "Olga Ivanova", monthlyBudget: 72_000 },
];

interface Team {
  /** The cost centre the team books to. */
  costCentre: string;
  name: string;
  /** People employed, whatever their hours. */
  headcount: number;
  /** Full-time equivalents: contracted hours over 40 a week. */
  fte: number;
  /** Staff cost of a month, in thousand euros. */
  monthlyCost: number;
}

/** Every team, on 17 March: 102 people, 91.5 full-time equivalents. */
const TEAMS: readonly Team[] = [
  { costCentre: "CC-1100", name: "Field sales North", headcount: 9, fte: 8.6, monthlyCost: 61.2 },
  { costCentre: "CC-1100", name: "Field sales South", headcount: 8, fte: 7.5, monthlyCost: 53.9 },
  { costCentre: "CC-1100", name: "Inside sales", headcount: 6, fte: 5.2, monthlyCost: 29.8 },
  { costCentre: "CC-1100", name: "Key accounts", headcount: 4, fte: 4.0, monthlyCost: 33.6 },
  { costCentre: "CC-1200", name: "Brand", headcount: 3, fte: 2.8, monthlyCost: 19.4 },
  { costCentre: "CC-1200", name: "Online marketing", headcount: 4, fte: 3.5, monthlyCost: 24.1 },
  { costCentre: "CC-1200", name: "Trade fairs", headcount: 2, fte: 1.5, monthlyCost: 10.2 },
  { costCentre: "CC-3100", name: "Service desk", headcount: 7, fte: 5.9, monthlyCost: 31.3 },
  { costCentre: "CC-3100", name: "Returns", headcount: 3, fte: 2.5, monthlyCost: 12.6 },
  { costCentre: "CC-2100", name: "Seating", headcount: 6, fte: 5.8, monthlyCost: 43.5 },
  { costCentre: "CC-2100", name: "Desks", headcount: 7, fte: 6.5, monthlyCost: 48.1 },
  { costCentre: "CC-2100", name: "Storage", headcount: 5, fte: 4.6, monthlyCost: 33.9 },
  { costCentre: "CC-2100", name: "Test lab", headcount: 3, fte: 2.5, monthlyCost: 16.8 },
  { costCentre: "CC-2200", name: "Industrial design", headcount: 4, fte: 3.6, monthlyCost: 27.2 },
  { costCentre: "CC-2200", name: "Colour and material", headcount: 2, fte: 1.8, monthlyCost: 12.9 },
  { costCentre: "CC-4100", name: "Accounting", headcount: 5, fte: 4.4, monthlyCost: 27.5 },
  { costCentre: "CC-4100", name: "Controlling", headcount: 3, fte: 3.0, monthlyCost: 21.3 },
  { costCentre: "CC-4200", name: "Recruiting", headcount: 2, fte: 1.8, monthlyCost: 12.4 },
  { costCentre: "CC-4200", name: "Payroll", headcount: 2, fte: 1.5, monthlyCost: 9.6 },
  { costCentre: "CC-4300", name: "Workplace", headcount: 4, fte: 3.8, monthlyCost: 24.2 },
  { costCentre: "CC-4300", name: "Applications", headcount: 5, fte: 4.5, monthlyCost: 34.8 },
  { costCentre: "CC-4400", name: "Buildings", headcount: 3, fte: 3.0, monthlyCost: 16.9 },
  { costCentre: "CC-4400", name: "Canteen", headcount: 5, fte: 3.2, monthlyCost: 14.7 },
];

const METRICS: Metric[] = [
  { id: "heads", label: "Headcount", unit: "HC" },
  { id: "fte", label: "Full-time equivalents", unit: "FTE", decimals: 1 },
  { id: "cost", label: "Staff cost a month", unit: "k€", decimals: 1 },
];

const PRODUCT = ["CC-2100", "CC-2200"];

export default function StaffCost() {
  return (
    <Calculation aria-label="Staff and staff cost of the product business line" metrics={METRICS}>
      <Sum label="Product">
        {PRODUCT.map((id) => (
          <Sum key={id} label={COST_CENTRES.find((centre) => centre.id === id)!.name}>
            {TEAMS.filter((team) => team.costCentre === id).map((team) => (
              <Given
                key={team.name}
                label={team.name}
                value={{ heads: team.headcount, fte: team.fte, cost: team.monthlyCost }}
              />
            ))}
          </Sum>
        ))}
      </Sum>
    </Calculation>
  );
}
```

### The whole company

Three levels from data - business line, cost centre, team - and three metrics: 23 teams folded to three lines a reader opens one by one.

```tsx
import { Calculation, Given, Sum } from "@umriss-ui/calculation";
import type { Metric } from "@umriss-ui/calculation";

/* Data from the controlling world, written out here so the example runs on its own. */

interface CostCentre {
  id: string;
  name: string;
  owner: string;
  /** The budget of one month. */
  monthlyBudget: number;
}

const COST_CENTRES: readonly CostCentre[] = [
  { id: "CC-1100", name: "Sales", owner: "Helen Marsh", monthlyBudget: 142_000 },
  { id: "CC-1200", name: "Marketing", owner: "Rafael Ortiz", monthlyBudget: 68_000 },
  { id: "CC-2100", name: "Engineering", owner: "Anika Sørensen", monthlyBudget: 188_000 },
  { id: "CC-2200", name: "Design", owner: "Paul Whitaker", monthlyBudget: 54_000 },
  { id: "CC-3100", name: "Customer service", owner: "Grace Obi", monthlyBudget: 61_000 },
  { id: "CC-4100", name: "Finance", owner: "Martina Vogel", monthlyBudget: 47_000 },
  { id: "CC-4200", name: "People", owner: "Daniel Frost", monthlyBudget: 39_000 },
  { id: "CC-4300", name: "IT", owner: "Kenji Arai", monthlyBudget: 83_000 },
  { id: "CC-4400", name: "Facilities", owner: "Olga Ivanova", monthlyBudget: 72_000 },
];

interface Team {
  /** The cost centre the team books to. */
  costCentre: string;
  name: string;
  /** People employed, whatever their hours. */
  headcount: number;
  /** Full-time equivalents: contracted hours over 40 a week. */
  fte: number;
  /** Staff cost of a month, in thousand euros. */
  monthlyCost: number;
}

/** Every team, on 17 March: 102 people, 91.5 full-time equivalents. */
const TEAMS: readonly Team[] = [
  { costCentre: "CC-1100", name: "Field sales North", headcount: 9, fte: 8.6, monthlyCost: 61.2 },
  { costCentre: "CC-1100", name: "Field sales South", headcount: 8, fte: 7.5, monthlyCost: 53.9 },
  { costCentre: "CC-1100", name: "Inside sales", headcount: 6, fte: 5.2, monthlyCost: 29.8 },
  { costCentre: "CC-1100", name: "Key accounts", headcount: 4, fte: 4.0, monthlyCost: 33.6 },
  { costCentre: "CC-1200", name: "Brand", headcount: 3, fte: 2.8, monthlyCost: 19.4 },
  { costCentre: "CC-1200", name: "Online marketing", headcount: 4, fte: 3.5, monthlyCost: 24.1 },
  { costCentre: "CC-1200", name: "Trade fairs", headcount: 2, fte: 1.5, monthlyCost: 10.2 },
  { costCentre: "CC-3100", name: "Service desk", headcount: 7, fte: 5.9, monthlyCost: 31.3 },
  { costCentre: "CC-3100", name: "Returns", headcount: 3, fte: 2.5, monthlyCost: 12.6 },
  { costCentre: "CC-2100", name: "Seating", headcount: 6, fte: 5.8, monthlyCost: 43.5 },
  { costCentre: "CC-2100", name: "Desks", headcount: 7, fte: 6.5, monthlyCost: 48.1 },
  { costCentre: "CC-2100", name: "Storage", headcount: 5, fte: 4.6, monthlyCost: 33.9 },
  { costCentre: "CC-2100", name: "Test lab", headcount: 3, fte: 2.5, monthlyCost: 16.8 },
  { costCentre: "CC-2200", name: "Industrial design", headcount: 4, fte: 3.6, monthlyCost: 27.2 },
  { costCentre: "CC-2200", name: "Colour and material", headcount: 2, fte: 1.8, monthlyCost: 12.9 },
  { costCentre: "CC-4100", name: "Accounting", headcount: 5, fte: 4.4, monthlyCost: 27.5 },
  { costCentre: "CC-4100", name: "Controlling", headcount: 3, fte: 3.0, monthlyCost: 21.3 },
  { costCentre: "CC-4200", name: "Recruiting", headcount: 2, fte: 1.8, monthlyCost: 12.4 },
  { costCentre: "CC-4200", name: "Payroll", headcount: 2, fte: 1.5, monthlyCost: 9.6 },
  { costCentre: "CC-4300", name: "Workplace", headcount: 4, fte: 3.8, monthlyCost: 24.2 },
  { costCentre: "CC-4300", name: "Applications", headcount: 5, fte: 4.5, monthlyCost: 34.8 },
  { costCentre: "CC-4400", name: "Buildings", headcount: 3, fte: 3.0, monthlyCost: 16.9 },
  { costCentre: "CC-4400", name: "Canteen", headcount: 5, fte: 3.2, monthlyCost: 14.7 },
];

interface BusinessLine {
  name: string;
  /** Its cost centres, in the order a report lists them. */
  costCentres: readonly string[];
}

/** How the company reports: three business lines over the nine cost centres. */
const BUSINESS_LINES: readonly BusinessLine[] = [
  { name: "Commercial", costCentres: ["CC-1100", "CC-1200", "CC-3100"] },
  { name: "Product", costCentres: ["CC-2100", "CC-2200"] },
  { name: "Corporate services", costCentres: ["CC-4100", "CC-4200", "CC-4300", "CC-4400"] },
];

const METRICS: Metric[] = [
  { id: "heads", label: "Headcount", unit: "HC" },
  { id: "fte", label: "Full-time equivalents", unit: "FTE", decimals: 1 },
  { id: "cost", label: "Staff cost a month", unit: "k€", decimals: 1 },
];

const centreName = (id: string) => COST_CENTRES.find((centre) => centre.id === id)!.name;

export default function WholeCompany() {
  return (
    <Calculation aria-label="Staff of Carrow & Lisle, 17 March" metrics={METRICS}>
      <Sum label="Carrow & Lisle">
        {BUSINESS_LINES.map((line) => (
          <Sum key={line.name} label={line.name}>
            {line.costCentres.map((id) => (
              <Sum key={id} label={centreName(id)}>
                {TEAMS.filter((team) => team.costCentre === id).map((team) => (
                  <Given
                    key={team.name}
                    label={team.name}
                    value={{ heads: team.headcount, fte: team.fte, cost: team.monthlyCost }}
                  />
                ))}
              </Sum>
            ))}
          </Sum>
        ))}
      </Sum>
    </Calculation>
  );
}
```

### A dense staff report

`density="compact"` closes up the head and every metric's column with the lines; a note stays beneath its label, and the figures move beneath the labels by the same measure as in a regular report.

```tsx
import { Calculation, Given, Sum } from "@umriss-ui/calculation";
import type { Metric } from "@umriss-ui/calculation";

const METRICS: Metric[] = [
  { id: "heads", label: "Headcount", unit: "HC" },
  { id: "fte", label: "Full-time equivalents", unit: "FTE", decimals: 1 },
];

export default function CompactReport() {
  return (
    <Calculation aria-label="Staff of Tidewell, 17 March" metrics={METRICS} density="compact">
      <Sum label="Tidewell">
        <Sum label="Engineering">
          <Given label="Web team" value={{ heads: 31, fte: 27.5 }} />
          <Given label="Apps team" value={{ heads: 22, fte: 20 }} />
          <Given label="Platform team" value={{ heads: 18, fte: 15.8 }} source="HR system" />
          <Given label="Quality assurance" value={{ heads: 25, fte: 21.2 }} />
        </Sum>
        <Sum label="Customer service">
          <Given label="Service desk" value={{ heads: 40, fte: 31.6 }} />
          <Given label="Returns" value={{ heads: 18, fte: 14.1 }} />
          <Given label="Student staff" value={{ heads: 6, fte: null }} explanation="FTE are not recorded for student staff" />
        </Sum>
        <Given label="Administration" value={{ heads: 12, fte: 10.4 }} />
      </Sum>
    </Calculation>
  );
}
```

## When to use something else

- A ratio across two metrics, such as FTE per head → a calculation of its own, a `Quotient` of two givens
- Many figures per row, sorted and filtered → `Table` from @umriss-ui/table

## Keyboard

The keys of [Calculation](https://romanhaendler.github.io/umriss-ui/calculation/calculation/#keyboard-calculation) apply here.

## API

### `Metric`

| Prop | Type | Default | Description |
|---|---|---|---|
| `id` *required* | `string` | — | The key of this metric's number in every `value` object.<br>Shown in: [Headcount and full-time equivalents](https://romanhaendler.github.io/umriss-ui/calculation/metrics/#two-teams), [A number one metric does not have](https://romanhaendler.github.io/umriss-ui/calculation/metrics/#not-recorded), [Team, cost centre, business line](https://romanhaendler.github.io/umriss-ui/calculation/metrics/#business-line) and 5 more |
| `label` *required* | `string` | — | The metric's name, in the head above its column and in each row's sentence.<br>Shown in: [Headcount and full-time equivalents](https://romanhaendler.github.io/umriss-ui/calculation/metrics/#two-teams), [A number one metric does not have](https://romanhaendler.github.io/umriss-ui/calculation/metrics/#not-recorded), [Team, cost centre, business line](https://romanhaendler.github.io/umriss-ui/calculation/metrics/#business-line) and 5 more |
| `unit` | `string` | — | A label written after the number where a result closes, and beneath the metric's name in the head. Never converted and never checked.<br>Shown in: [Headcount and full-time equivalents](https://romanhaendler.github.io/umriss-ui/calculation/metrics/#two-teams), [A number one metric does not have](https://romanhaendler.github.io/umriss-ui/calculation/metrics/#not-recorded), [Team, cost centre, business line](https://romanhaendler.github.io/umriss-ui/calculation/metrics/#business-line) and 5 more |
| `decimals` | `number` | a given as it was given, at most two for a derived number | Fixed number of fraction digits as shown, for every quantity of this metric.<br>Shown in: [Headcount and full-time equivalents](https://romanhaendler.github.io/umriss-ui/calculation/metrics/#two-teams), [A number one metric does not have](https://romanhaendler.github.io/umriss-ui/calculation/metrics/#not-recorded), [Team, cost centre, business line](https://romanhaendler.github.io/umriss-ui/calculation/metrics/#business-line) and 5 more |

## Known limits

- A calculation with metrics only adds and subtracts: `Product`, `Quotient`, `Times` and `DividedBy` fail on the first render, since a factor would need a unit in every metric.
- Unit, format and places belong to the metric; on a quantity they fail on the first render, and so does a missing or unknown metric key in a `value`.
- No target or limits with metrics: an assessment per cell is not there yet.

What umriss deliberately does not build, and why: [ADR-0032](https://romanhaendler.github.io/umriss-ui/what-umriss-ui-is-not/).
