/* * : M3's three card variants (ElevatedCardTokens.kt, FilledCardTokens.kt, * OutlinedCardTokens.kt, androidx Compose Material 3, Apache-2.0; docs/reference/m3 * § Cards → Specs) — filled (surface-container-highest), elevated (surface-container-low at * elevation 1) and outlined (surface, an outline-variant edge); one 12dp corner for all three, * which never morphs (M3 specifies shape morph for buttons, FABs and list items, never cards — * docs/audits/m3-alignment/containment.md, C-23). * * Every card renders the shared `md-state-layer` class, and a row (`data-md-list-row`, * `resources/js/list-rows.js`) `md-focus-ring` too (foundation/interaction.css), for its tint and * its ring; this file adds only what a card needs beyond them: * * - *no layer* on a card that is neither a row nor dragged: a card that does not open anything * answers no pointer, but any card can be carried, and the application sets `data-md-dragged` * from script long after the view rendered; * - per-state *elevation*, which the shared class has no opinion on: elevated 1dp rest → 2dp * hover → 1dp focus/pressed; filled and outlined 0dp rest → 1dp hover → 0dp focus/pressed * (the cross-check table's Hover/Focus/Pressed rows). Pressed and focus fall back to the rest * level, so the `:active` rule (declared after `:hover`, same specificity) resets it even * while still hovering; * - the *press/hover exclusion*: a card's own nested button (the "Copy link" in a card that is * also a row) should light only itself, never the row's tint or elevation. `material.components` * out-layers `material.base`, so these two rules win over the shared class's plain `:hover`/ * `:active` without needing extra specificity; * - the *opener-focused ring*: a non-actionable row's focus never lands on the card itself (its * opener carries the tab stop), so `md-focus-ring`'s own `:focus-visible` never fires for it; * `:has([data-md-list-open]:focus-visible)` draws the same ring from here instead. An * actionable card (`tabindex="0"`) is focused directly, which `md-focus-ring` already covers. * * `data-md-dragged` (an application sets it while its drag is in progress) is the top of the * elevation scale — Level4 (8dp) elevated, Level3 (6dp) filled and outlined — under the shared * class's own 16% dragged tint, which already reads `data-md-dragged` without any help from here. */ @layer material.reset, material.tokens, material.base, material.layout, material.components, material.text, material.visibility; @import './divider.css'; @layer material.components { [data-md-card] { position: relative; display: flex; flex-direction: column; overflow: hidden; border-radius: var(--md-sys-shape-corner-md); color: var(--md-sys-color-on-surface); } [data-md-card='filled'] { background-color: var(--md-sys-color-surface-container-highest); } [data-md-card='elevated'] { background-color: var(--md-sys-color-surface-container-low); box-shadow: var(--md-sys-elevation-1); } [data-md-card='outlined'] { border: 1px solid var(--md-sys-color-outline-variant); background-color: var(--md-sys-color-surface); } [data-md-card]:not([data-md-list-row], [data-md-dragged])::before { display: none; } [data-md-card][data-md-list-row] { cursor: pointer; transition-property: box-shadow; transition-duration: var(--md-sys-motion-spatial-default-duration); transition-timing-function: var(--md-sys-motion-spatial-default); } @media (hover: hover) { [data-md-card][data-md-list-row]:not([data-md-dragged]):hover:not(:has(:is(a, button, input, select, textarea, label, summary):not([data-md-list-open]):hover)) { box-shadow: var(--md-sys-elevation-1); } [data-md-card='elevated'][data-md-list-row]:not([data-md-dragged]):hover:not(:has(:is(a, button, input, select, textarea, label, summary):not([data-md-list-open]):hover)) { box-shadow: var(--md-sys-elevation-2); } [data-md-card][data-md-list-row]:not([data-md-dragged]):hover:has(:is(a, button, input, select, textarea, label, summary):not([data-md-list-open]):hover)::before { opacity: 0; } } [data-md-card][data-md-list-row]:not([data-md-dragged]):active:not(:has(:is(a, button, input, select, textarea, label, summary):not([data-md-list-open]):active)) { box-shadow: none; } [data-md-card='elevated'][data-md-list-row]:not([data-md-dragged]):active:not(:has(:is(a, button, input, select, textarea, label, summary):not([data-md-list-open]):active)) { box-shadow: var(--md-sys-elevation-1); } [data-md-card][data-md-list-row]:not([data-md-dragged]):has(:is(a, button, input, select, textarea, label, summary):not([data-md-list-open]):active)::before { opacity: 0; } [data-md-card][data-md-dragged] { box-shadow: var(--md-sys-elevation-3); } [data-md-card='elevated'][data-md-dragged] { box-shadow: var(--md-sys-elevation-4); } [data-md-card][data-md-list-row]:has([data-md-list-open]:focus-visible) { outline: 3px solid var(--md-sys-color-secondary); outline-offset: 2px; } [data-md-card][data-md-list-row] [data-md-list-open]:focus-visible { outline: none; } [data-md-card-figure] { flex-shrink: 0; overflow: hidden; & > img { width: 100%; object-fit: cover; } } [data-md-card-body] { display: flex; flex: 1 1 0%; flex-direction: column; gap: var(--md-sys-measurement-space200); padding: var(--md-sys-measurement-space200); } [data-md-card-header-row] { display: flex; align-items: flex-start; gap: var(--md-sys-measurement-space100); } [data-md-card-heading] { min-width: 0; flex: 1 1 0%; } [data-md-card-title] { font: var(--md-sys-typescale-title-md); letter-spacing: var(--md-sys-typescale-title-md-tracking); } [data-md-card-subtitle] { margin-top: var(--md-sys-measurement-space25); color: var(--md-sys-color-on-surface-variant); font: var(--md-sys-typescale-body-md); letter-spacing: var(--md-sys-typescale-body-md-tracking); } [data-md-card-menu] { display: flex; flex-shrink: 0; align-items: center; gap: var(--md-sys-measurement-space50); margin-block-start: calc(-1 * var(--md-sys-measurement-space100)); margin-inline-end: calc(-1 * var(--md-sys-measurement-space100)); } [data-md-card-header] > [data-md-divider] { margin-top: var(--md-sys-measurement-space200); } [data-md-card-content] { flex: 1 1 0%; font: var(--md-sys-typescale-body-md); letter-spacing: var(--md-sys-typescale-body-md-tracking); } [data-md-card-actions] { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: var(--md-sys-measurement-space100); } }