# `MishkaBlogWeb.Templates.TeamCard`
[🔗](https://github.com/mishka-group/mishka_blog/blob/v0.0.1/lib/mishka_blog_web/templates/team_card.ex#L5)

The teams grid: one card per editorial team, in as many columns as fit the screen.

Declared only by `MishkaBlog.Team`, and it reads that record directly rather than by column
position. Same shape as `MishkaBlogWeb.Templates.BloggerCard` — a tile beside its actions, a name
over its size, the members' faces, and a footer of real counts — because a team and a blogger are
read the same way.

## No fabricated engagement

The prototype's card ends in an "Engagement 86%" bar, invented for every team; `MishkaBlog.Team`
has no engagement metric. The footer shows the two figures that are real — `member_count` and
`follower_count` — and the card carries the team's real `status` (active / inactive / draft) as a
badge, which is the axis the Status filter turns on.

## Features
- `:filter` - the labelled filter row: search, site, status
- `:select` - per-card selection for bulk operations
- `:bulk_actions` - bulk actions on the selected cards
- `:paginate` - the page-size picker and Load more under the grid

The furniture is `MishkaCmsCoreWeb.Templates.CardChrome` and the controls are
`MishkaCmsCoreWeb.UIAdapters.Admin`, both shared with every other blog card page.

# `count`

```elixir
@spec count(map(), atom()) :: non_neg_integer()
```

One aggregate off the record, or 0 when it arrived unloaded.

# `icon`

The switcher draws the grid-of-squares glyph, identical to every other blog card page.

# `member_initial`

```elixir
@spec member_initial(map()) :: String.t()
```

The single letter a member's face shows.

# `member_name`

```elixir
@spec member_name(map()) :: String.t()
```

A member's display name, or a dash when the join row has no blogger.

# `member_tint`

```elixir
@spec member_tint(non_neg_integer()) :: String.t()
```

The tint a member's face wears at a given position, cycling so neighbours never match.

# `member_tints`

```elixir
@spec member_tints() :: [String.t()]
```

The whole face palette, in order, for the `:avatars` column type to cycle itself.

The table row draws the same stack this card does, so it takes the palette from here rather than
keeping a second copy that would drift.

# `members`

```elixir
@spec members(map()) :: [map()]
```

The team's members, always a list.

Only the read the viewer is entitled to is preloaded — a tenant gets `members`, a master the
tenancy-bypassing alias — so an unloaded relationship (a truthy `%Ash.NotLoaded{}`) becomes an
empty list rather than a render crash.

# `render_bulk_actions`

# `render_empty`

# `render_error`

# `render_filters`

# `render_header`

# `render_item`

One team card.

# `render_pagination`

# `render_template_switcher`

# `status_badge`

```elixir
@spec status_badge(map()) :: %{label: String.t(), chip: String.t()}
```

How a team's status badge reads and what colour it wears.

One entry per value of the `status` attribute, falling back to `:draft` — the attribute's own
default.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
