import { Canvas, Controls, Meta } from "@storybook/addon-docs/blocks";

import * as CardStories from "./Card.stories";

<Meta of={CardStories} />

# Card

Five repos, and the reason it is P0 is the `<section>`: give a card a heading and it becomes
a **landmark**, so `getByRole("region", { name: "Bay 3" })` scopes every query inside it.
Without that, an agent driving a 16-bay tower sees sixteen identical "Start" buttons and no
way to say which one it means. The `Interactive` story asserts exactly that.

<Canvas of={CardStories.Playground} />

## Props

<Controls />

## Density is not a prop

The withdrawn bambuddy evidence included a `CardDensityProvider`, and it is the wrong shape
for this fleet: density is a global axis on `<html>`, so a compact bay list is
`data-density="compact"` on the page rather than a context around the cards. `padding`
stays a prop because a card wrapping a poster grid genuinely has none — a layout fact, not
a density one.

## Names must be unique

Two `<section>`s sharing an accessible name is axe's `landmark-unique`, and it is a real
finding rather than a technicality: a screen-reader user navigating by landmark gets two
"Bay 3" regions and no way to tell them apart. A card with no heading is not a landmark at
all, deliberately — it has nothing to be named.

`raised` means *more separated from base*, not *lighter*, which is why light mode's base is
`#F5F7FA` and its raised is white.

### A card the app names itself

Pass `aria-labelledby` and no `heading` when the app draws its own title row — a name beside
a count is one line that `heading` cannot express, so mail-sifter's tiles render it and point
at it. The card keeps that pointer.

> **It has to be a fallback, not a default.** The attribute is written after the caller's
> props are spread, so the obvious `heading ? headingId : undefined` **overwrites** the call
> site's pointer rather than leaving it alone. React then drops the attribute, the card's name
> falls back to its entire subtree, and nothing reports it: the markup is valid, the types are
> satisfied, and axe is content with a name made of everything. Both of mail-sifter's
> `role="button"` tiles announced their whole contents — "Recent Mail 6 40 arrived in the last
> 24 hours, 34 done" for a tile called "Recent Mail".

`heading` still wins where both are given, because the heading is text the reader can see and
this component renders it. `aria-label` needs no fallback at all — `Card` never writes one, so
the spread carries the caller's through.

<Canvas of={CardStories.CallerNamed} />

<Canvas of={CardStories.AllVariants} />

## Container queries, not media queries

> **One constraint that comes with the territory.** `container-type: inline-size` implies
> `contain: inline-size`, so a `Card` may not be sized by its own contents. In a grid track,
> a block flow, or a `flex-1` slot it is fine — that is nearly every real placement. Drop one
> into a shrink-to-fit parent (`items-start`, an `inline-flex` row) and it collapses to
> min-content, wrapping every line after one word. Give it a definite inline size there.


The header stacks below `--cq-sm` and sits on one row above it, and the container is the
**card**. The same card in a sidebar and full-bleed on a dashboard is the case a media query
cannot tell apart, and it is where the fleet's poster grids look wrong today.

<Canvas of={CardStories.Responsive} />

## The accent edge follows the corner

`accentEdge` draws a coloured bar down the leading edge. `{ categorical: 3 }` is a colour a
user picked, from the ten-wide contrast-audited family; `{ color }` is one the app computed,
for the case where ten indices are not enough — Folio hashes a repo's name so a repo added
tomorrow already has a hue and nobody maintains a palette.

> **It is a pseudo-element, not a border, and that is the whole point.** Three apps grew this
> shape independently and all three drew a straight border beside a rounded box, so the bar
> ran past the curve and stopped square while the card was round. A border is painted on the
> border box; it cannot follow a corner. The overlay here takes `border-radius: inherit`, so
> the bar reads the radius off whatever card it is on and nobody states one twice.

Two shapes this deliberately is not. **Not `box-shadow: inset` on the card itself** — `Card`
carries `shadow-low` from the elevation scale, and a `box-shadow` at the call site outranks
that utility and takes the elevation with it. **Not a 3px-wide pseudo-element with a rounded
leading edge** — a `0.5rem` radius on a 3px box is clamped to fit, so it caps the bar instead
of following the curve.

<Canvas of={CardStories.AccentEdge} />
