# Team — the URL is the API

A team is the one thing the tools share about a coach: a name, a game format,
a game length, and the players with the spots they play. It lives in the
browser (`localStorage`, key `marple.teams`) and in a link. Nothing is on a
server, so you don't need this site to make one: build the JSON, base64url
it, and hand the coach the link. Opening it saves the team in that browser
and makes it current; every tool then opens with it filled in.

## The link

```
https://tools.marplecoaching.com/team/#t=<payload>
```

`payload` is base64url of UTF-8 JSON: standard base64 with `+` → `-`,
`/` → `_`, trailing `=` stripped. Browsers never send the fragment with a
request, so names stay out of server logs — but anyone holding the link can
decode it, so treat a link like the roster it contains.

## The JSON

```json
{
  "v": 1,
  "id": "k3j9x2",
  "name": "Marple U11",
  "format": 9,
  "slots": { "GK": 1, "CB": 2, "FB": 2, "WB": 0, "DM": 1, "CM": 0, "AM": 2, "W": 0, "ST": 1 },
  "game": 60,
  "players": [
    { "n": "Ada", "p": ["CB"] },
    { "n": "Bex", "p": ["FB", "CB"] },
    { "n": "Posy", "p": ["GK", "ST"] }
  ]
}
```

- **v** — schema version, `1`.
- **id** — 4–12 lowercase letters and digits. Opening a link whose `id` is
  already saved replaces that team; a new `id` adds one. Leave it out and one
  is made up (a new team every time the link is opened — usually not what you
  want).
- **name** — ≤40 characters. Empty becomes `My team`.
- **format** — players per side, keeper included: `7`, `9`, or `11`. Anything
  else reads as `9`.
- **slots** — the formation: how many of each position code are on the field
  at once (`GK` 0 or 1, the rest 0–4; a code left out is 0). The Team page
  offers these presets per format, and shows anything else as "Custom":

  | | GK | CB | FB | WB | DM | CM | AM | W | ST |
  |---|---|---|---|---|---|---|---|---|---|
  | 7v7 2-3-1 | 1 | 2 | | | 1 | | 2 | | 1 |
  | 9v9 4-3-1 | 1 | 2 | 2 | | 1 | | 2 | | 1 |
  | 9v9 3-2-3 | 1 | 3 | | | 2 | | | 2 | 1 |
  | 11v11 4-3-3 | 1 | 2 | 2 | | 1 | | 2 | 2 | 1 |
  | 11v11 4-4-2 diamond | 1 | 2 | 2 | | 1 | 2 | 1 | | 2 |
  | 11v11 4-2-3-1 | 1 | 2 | 2 | | 2 | | 1 | 2 | 1 |
  | 11v11 3-5-2 | 1 | 3 | | 2 | 1 | 2 | | | 2 |
  | 11v11 3-4-3 | 1 | 3 | | 2 | | 2 | | 2 | 1 |

  Leave `slots` out and the team gets the first preset for its format. The
  formation decides which spots the Team page offers a player (a 4-3-3 has no
  `WB` button), so give a player only codes the formation has.
- **game** — whole-game minutes, 10–120 in steps of 5.
- **players** — up to 40. Per player: `n` name (≤30 characters; empty rows are
  dropped), `p` the spots they play, best first, using Rotation's codes, back
  to front: `GK` keeper, `CB` centerback, `FB` fullback, `WB` wingback (the
  wide player in a back three), `DM` defensive mid, `CM` central / box-to-box
  mid (the 8s), `AM` attacking mid, `W` winger, `ST` striker. Two plain
  forwards are two `ST`s. The first entry is her main spot and the second her
  backup — Rotation flags her as in a new role when she's placed anywhere
  else; the rest of the list is "also plays" and the order there doesn't
  matter. A bare string works too: `"Ada"` means `{ "n": "Ada", "p": [] }`.

Bad values never error — they're clamped or dropped — so a sloppy payload
still loads, just maybe not as you meant. Decode your own link once to check.

## What each tool reads

The team is read-only to the tools; this page is the only editor. A tool may
switch *which* saved team is current (Rotation and the board offer the other
saved teams as buttons), but never changes a team.

| Tool | Reads | Overridden by |
|---|---|---|
| Activity | `players.length` as tonight's headcount | `?players=` in its own URL |
| Playing Time | `format` as the game size, `game`, `players.length` | nothing — it's a starting point, edit away |
| Rotation | everything: `slots` as the formation, `game`, the roster with spots | a lineup in its own `#r=` / `#v=` link |

A tool visited with its own state in the URL ignores the team. Rotation's
lineup link still carries the whole squad, so a lineup shared to a parent
works without the team.

## Storage

```json
{ "v": 1, "current": "k3j9x2", "teams": [ { …team… }, { …team… } ] }
```

Up to 12 teams; `current` is the one every tool reads. The module
[`team.js`](./team.js) is the whole API — `currentTeam()`, `upsertTeam()`,
`setCurrent()`, `removeTeam()`, `encodeTeam()` / `decodeTeam()`,
`shareLink()`. Tools import it as `../team/team.js`.

## Recipe

1. Decode the coach's link if you got one; otherwise start from the schema
   and make up an `id`.
2. Edit: names, spots, format, formation, game length.
3. Encode and reply with the `#t=` link. Opening it is the save.
