{{-- An M3 card: content and actions about one subject. `variant` is M3's three (FilledCardTokens, ElevatedCardTokens, OutlinedCardTokens, androidx Compose Material 3, Apache-2.0): `filled` (surface-container-highest, the default), `elevated` (surface-container-low at elevation 1) and `outlined` (surface, an outline-variant edge); all with a medium corner. maryUI's props keep their meaning: `title`, `subtitle`, `separator` (a divider under the header), and the `menu` (top-end, beside the title), `figure` (full-bleed media on top) and `actions` (end-aligned, under the content) slots. M3 draws two kinds of card a person can press, and they differ in the keyboard: on a **non-actionable card with actionable elements** Tab moves through each control inside before the next card; on a **directly actionable card** Tab moves to the card, then to the next card (docs/reference/m3/components-actions-communication-containment.md § Cards → Accessibility). Both are a row: give the card `data-list-row` and one `data-list-open` control inside (the title link or a button), and a press anywhere on it reaches that control while its other buttons keep their own (resources/js/list-rows.js). That is the first kind — the opener is the tab stop, the accessible name and the owner of the `href` or the `wire:click`. `actionable` makes it the second: the card takes `tabindex="0"` and `role="button"` (pass `role="link"` where it goes somewhere), is named by its `title`, and Enter or Space on it reaches the opener. Put `tabindex="-1"` on that opener so the card is the one stop, and leave the card's other actions as they are — they follow it in the tab order. A row answers with M3's state layer and one step of elevation (elevated 1 → 2 hovered, filled and outlined 0 → 1); its corner does not move, because M3 gives a card one shape. Never a stretched link, and never a whole-card `` around buttons. `data-dragged` is M3's dragged card: the top of a card's elevation scale — 8dp elevated, 6dp filled and outlined — under the 16% dragged state layer, and it holds while the pointer is down rather than falling back to the press state. Nothing in the browser tells a card it is being carried, so the application sets the attribute when its drag starts and takes it off on drop. M3 requires a single-pointer alternative beside any drag, so keep the same reorder or delete actions in a menu on the card (docs/reference/m3/components-actions-communication-containment.md § Cards → Specs, Accessibility; resources/css/components/list.css draws it). Do not pass a `bg-*` class to change its fill — it races the card's own in Tailwind's emit order; use `variant`, or colour a wrapper inside. --}} @props([ 'title' => null, 'subtitle' => null, 'variant' => 'filled', 'separator' => false, 'actionable' => false, ]) @php $variant = in_array($variant, ['filled', 'elevated', 'outlined'], true) ? $variant : 'filled'; $role = $actionable ? ($attributes->get('role') ?: 'button') : null; $attributes = $actionable ? $attributes->except('role') : $attributes; @endphp
class([ 'relative flex flex-col overflow-hidden rounded-corner-md text-on-surface', 'bg-surface-container-highest' => $variant === 'filled', 'bg-surface-container-low shadow-elevation-1' => $variant === 'elevated', 'border border-outline-variant bg-surface' => $variant === 'outlined', ]) }} > @isset($figure)
{{ $figure }}
@endisset
@if ($title || $subtitle || isset($menu))
@if ($title)

{{ $title }}

@endif @if ($subtitle)

{{ $subtitle }}

@endif
@isset($menu)
{{ $menu }}
@endisset
@if ($separator) @endif
@endif @if ($slot->isNotEmpty())
{{ $slot }}
@endif @isset($actions)
{{ $actions }}
@endisset