/*!
 * ZIC cards — geometry, variants, layouts and states
 * ============================================================================
 * `.card` is this app's panel primitive: 226 uses across 69 templates
 * (`.card-body` 106, `.card-header` 96, `.card-footer` 15). So, as with buttons
 * and the navigation, this layers over the existing class rather than
 * introducing a `zic-card-*` vocabulary that no template uses yet.
 *
 * The lever is again Bootstrap's variable block. One variable —
 * `--bs-card-border-width` — drives the card's own border, the header's bottom
 * divider, the footer's top divider and the list-group separators, because
 * core.css uses it for all four.
 *
 * WHAT WAS BROKEN (measured on /partners/, 7 real cards)
 *
 *   1. `--bs-card-border-width` is `0`. materio-overrides.css already carries
 *      `.card { border-color: var(--zic-border-default) }` and the same for
 *      `.card .card-header, .card .card-footer` — but a colour on a zero-width
 *      border paints nothing. Measured: card `border-width: 0px`,
 *      `.card-header` `border-bottom-width: 0px`. Setting the width to 1px in
 *      section 1 is what makes those three existing rules live; no parallel
 *      border rules are needed.
 *   2. Cards sat at `--zic-shadow-md`. `--bs-card-box-shadow` resolves through
 *      the general `--bs-box-shadow`, which this theme maps to `-md`. The brief
 *      wants `-sm` at rest with `-md` reserved for the elevated variant and the
 *      hover state — so the card's own variable is set, not the general one.
 *   3. Radius was 6px (the spec asks 12px), `.card-body` padding was 20px
 *      (spec: 24px), and `.card-header` was 20px 20px (spec: 20px 24px).
 *   4. No variants, no layouts, no media/horizontal/profile content types, no
 *      async overlay, no compact empty state.
 *
 * Already correct, so not restated: the card surface (`--bs-card-bg` →
 * `--zic-surface-primary`) and the dark-theme values, both measured at
 * #1e293b / #334155 with body text at 9.85:1.
 */

/* ===========================================================================
 * 1. Card chrome.
 *
 * The shell's. `border-width: 0`, `border-radius: 0.375rem`, `box-shadow:
 * var(--bs-box-shadow)` and the cap paddings all come from `vendor/css/core.css`,
 * and the card/header/footer *colours* are mapped onto ZIC tokens by
 * `theme/materio-overrides.css` (which was already doing that job — a colour on a
 * zero-width border painted nothing only because this file insisted on a width).
 *
 * This section used to restate all of it: a 1px border against the shell's 0, a
 * 12px radius against 6px, `-sm` shadow at rest, and — the largest change — it
 * put dividers back between a card's header, body and footer, which the shell
 * deliberately removed (`core.css` carries
 * `.card .card-header, .card .card-footer { --bs-card-border-width: 0 }` at
 * (0,2,0)). The Materio restoration deleted the restatement, so cards are
 * borderless with flush sections again. See docs/MATERIO_DRIFT_AUDIT.md §7.7,
 * Prompt 6 of docs/prompts/MATERIO_RESTORE_BULK_PROMPTS.md.
 *
 * The variants, layouts and content types below are ZIC's own and stay.
 * ======================================================================== */

/* Header layout. This build ships no `min-w-0` utility, and a flex child
   without `min-inline-size: 0` will not shrink — a long title then pushes the
   header's action group out of the card instead of wrapping. */
.card > .zic-card__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--zic-space-2);
}

.zic-card__heading {
  display: flex;
  align-items: center;
  gap: var(--zic-space-2);
  min-inline-size: 0;
}

.zic-card__titles {
  min-inline-size: 0;
}

.zic-card__actions {
  flex: none;
}

.card > .zic-card__footer {
  display: flex;
  justify-content: flex-end;
}

/* A subtitle under a card title — the pattern every section header uses. */
.zic-card__subtitle {
  margin: var(--zic-space-1) 0 0;
  font-size: 14px;
  line-height: 1.4;
  color: var(--zic-text-secondary);
}

/* Card body copy. Not applied to `.card-body` itself: plenty of existing cards
   put tables and forms there, which must keep their own type. */
.zic-card__text {
  margin: 0;
  font-size: 14px;
  line-height: 1.55;
  color: var(--zic-text-secondary);
}

.zic-card__text + .zic-card__text {
  margin-block-start: var(--zic-space-2);
}

/* ===========================================================================
 * 2. Variants.
 *
 * All optional and additive on `.card`, so they compose with the layouts below.
 * ======================================================================== */

/* Elevated: floats above the canvas on shadow alone, with no edge. */
.card.zic-card--elevated {
  --bs-card-border-width: 0;
  --bs-card-box-shadow: var(--zic-shadow-md);
}

/* Outlined: a flat, single-weight edge with no elevation. */
.card.zic-card--outlined {
  --bs-card-box-shadow: none;
}

/* Highlighted: a heavier leading edge instead of a tinted fill, so the card's
   content keeps full contrast. The colour is a hook — set `--zic-card-accent`
   inline to mark a card with a status token. */
.card.zic-card--highlighted {
  border-inline-start: var(--zic-card-accent-width) solid var(--zic-card-accent, var(--zic-primary));
  /* Keep the outer radius while the heavier edge curves into it. */
  border-start-start-radius: var(--zic-card-radius);
  border-end-start-radius: var(--zic-card-radius);
}

/* Interactive: this card is the click target. Only ever applied deliberately —
   a cursor is a promise that the whole surface does something. */
.card.zic-card--interactive {
  cursor: pointer;
}

/* Hover-only, so the lift and its shadow animate while the theme switch stays
   atomic. Colours are intentionally not transitioned. */
.card.zic-card--interactive:hover {
  transition:
    box-shadow var(--zic-transition-fast),
    transform var(--zic-transition-fast);
}

@media (prefers-reduced-motion: no-preference) {
  .card.zic-card--interactive:hover {
    transform: translateY(-2px);
  }
}

.card.zic-card--interactive:hover {
  --bs-card-box-shadow: var(--zic-shadow-md);
}

/* Keyboard parity: an interactive card is reachable and shows the same ring as
   every other control. Two paths, because the card itself is rarely focusable:
   the link's own `:focus-visible` (via the global rule) is hoisted onto the
   card when the browser supports `:has()` — which this codebase's baseline
   already assumes for `color-mix` and `aspect-ratio` — and a card that carries
   its own `tabindex` gets the ring directly. */
.card.zic-card--interactive:focus-visible {
  outline: var(--zic-focus-ring-width) solid var(--zic-border-focus);
  outline-offset: var(--zic-focus-ring-offset);
}

.card.zic-card--interactive:has(.zic-card__link:focus-visible) {
  outline: var(--zic-focus-ring-width) solid var(--zic-border-focus);
  outline-offset: var(--zic-focus-ring-offset);
}

/* Stretched link: the anchor sits on the card's title so the accessible name is
   the card's own heading, while `::after` covers the card to make the whole
   surface clickable. This is the same technique `kpi_card.html` uses, and it is
   why an interactive card does not need a click handler on a <div>. */
.zic-card--interactive {
  position: relative;
}

.zic-card__link {
  color: inherit;
  text-decoration: none;
}

.zic-card__link::after {
  content: '';
  position: absolute;
  inset: 0;
}

/* ===========================================================================
 * 3. Layouts.
 * ======================================================================== */

/* Responsive card grid. `auto-fill` with a 300px floor means the column count
   falls out of the available width — no breakpoints to keep in sync. */
.zic-card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(var(--zic-card-grid-min), 1fr));
  gap: var(--zic-card-gap);
  align-items: start;
}

.zic-card-list {
  display: flex;
  flex-direction: column;
  gap: var(--zic-card-list-gap);
}

/* Masonry via CSS columns. `column-width` (not `column-count`) keeps it
   responsive without media queries. Cards must not be split across columns,
   which is what `break-inside` is for. */
.zic-card-masonry {
  column-width: var(--zic-card-grid-min);
  column-gap: var(--zic-card-gap);
}

.zic-card-masonry > * {
  break-inside: avoid;
  margin-block-end: var(--zic-card-gap);
}

/* ===========================================================================
 * 4. Content types.
 * ======================================================================== */

/* Media band. `.zic-card__media` is the wrapper; the image inside is always a
   block that fills it, so no inline-gap baseline artefact appears. */
.zic-card__media {
  overflow: hidden;
  background-color: var(--zic-surface-tertiary);
}

.zic-card__media > img,
.zic-card__media > video {
  display: block;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

/* Image card: media on top, at a fixed ratio so a row of cards lines up before
   the images have loaded. */
.card.zic-card--media > .zic-card__media {
  aspect-ratio: var(--zic-card-media-ratio, 16 / 9);
  border-start-start-radius: var(--bs-card-inner-border-radius);
  border-start-end-radius: var(--bs-card-inner-border-radius);
}

/* Horizontal card: media beside the body. The media keeps a square-ish column
   and stretches to the card's height. */
.card.zic-card--horizontal {
  flex-direction: row;
}

.card.zic-card--horizontal > .zic-card__media {
  flex: none;
  inline-size: var(--zic-card-media-width, 104px);
  border-start-start-radius: var(--bs-card-inner-border-radius);
  border-end-start-radius: var(--bs-card-inner-border-radius);
}

/* At phone widths a fixed media column squeezes the text to a few characters
   per line, so the card stacks. Override `--zic-card-media-width` instead if a
   particular card should stay side-by-side. */
@media (max-width: 575.98px) {
  .card.zic-card--horizontal {
    flex-direction: column;
  }

  .card.zic-card--horizontal > .zic-card__media {
    inline-size: 100%;
    aspect-ratio: var(--zic-card-media-ratio, 16 / 9);
    border-start-end-radius: var(--bs-card-inner-border-radius);
    border-end-start-radius: 0;
  }
}

/* Profile card. */
.card.zic-card--profile .card-body {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--zic-space-2);
}

.zic-card__avatar {
  display: grid;
  place-items: center;
  flex: none;
  inline-size: var(--zic-card-avatar-size, 56px);
  block-size: var(--zic-card-avatar-size, 56px);
  border-radius: var(--zic-radius-pill);
  overflow: hidden;
  background-color: var(--zic-surface-tertiary);
  color: var(--zic-primary-text);
  font-size: 18px;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.zic-card__avatar > img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

.zic-card__name {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
  color: var(--zic-text-primary);
}

.zic-card__meta {
  margin: 0;
  font-size: 13px;
  color: var(--zic-text-secondary);
}

/* A horizontal profile card puts the avatar and the name on one line. */
.card.zic-card--profile.zic-card--horizontal .card-body {
  flex-direction: row;
  align-items: center;
  text-align: start;
}

/* ===========================================================================
 * 5. States.
 * ======================================================================== */

/* Async overlay. The card keeps its box — and therefore its height — while the
   content underneath is dimmed by a scrim drawn from the card's own surface,
   so the spinner is legible on any surface without a second colour rule.
   `position: relative` already comes from core.css's `.card`. */
.card.is-loading::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: inherit;
  background-color: color-mix(in srgb, var(--zic-surface-primary) 65%, transparent);
}

.card.is-loading::after {
  content: '';
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 50%;
  z-index: 2;
  inline-size: var(--zic-card-spinner-size, 28px);
  block-size: var(--zic-card-spinner-size, 28px);
  margin-block-start: calc(var(--zic-card-spinner-size, 28px) / -2);
  margin-inline-start: calc(var(--zic-card-spinner-size, 28px) / -2);
  border: 2px solid color-mix(in srgb, var(--zic-primary) 25%, transparent);
  border-block-start-color: var(--zic-primary);
  border-radius: var(--zic-radius-pill);
  animation: zic-card-spin 700ms linear infinite;
}

/* The overlay is only a scrim; the card itself must not swallow a click that
   was meant for a control behind it once loading finishes. */
.card.is-loading {
  pointer-events: none;
}

@keyframes zic-card-spin {
  to {
    transform: rotate(360deg);
  }
}

/* Reduced motion: the spinner is the state, not decoration, so it still turns —
   but at a cadence that does not read as flicker. */
@media (prefers-reduced-motion: reduce) {
  .card.is-loading::after {
    animation-duration: 1.6s;
  }
}

/* Skeleton card. The partial draws a real `.card`, so radius, border and shadow
   are inherited rather than restated — but it needs one shape of its own:
   `.zic-skeleton-block` is `height: 100%`, which collapses to nothing inside an
   auto-sized row. */
.zic-skeleton-card-block {
  inline-size: 100%;
  block-size: var(--zic-skeleton-card-block, 5rem);
  border-radius: var(--zic-radius-md);
}

/* Compact empty state: the message without the illustration, for a card that
   is already inside a padded container. */
.zic-empty--compact {
  min-height: 0;
  padding: var(--zic-space-4) var(--zic-space-3);
  gap: var(--zic-space-1);
}

.zic-empty--compact .zic-empty-art {
  display: none;
}

.zic-empty--compact .zic-empty-title {
  margin-block-start: 0;
  font-size: 15px;
}

/* ---------------------------------------------------------------------------
 * The chart card's shell.
 *
 * `components/chart_card.html` renders `class="chart-wrapper card zic-card"`.
 * The class only existed in the dashboard stylesheet, which the dashboard
 * rebuild deleted — but the component is shared, so the rule moved here with
 * the rest of the card layer.
 * ------------------------------------------------------------------------- */
.zic-card {
  height: 100%;
  border: 1px solid var(--zic-border-default);
  box-shadow: var(--zic-shadow-sm);
}

/* Only the hover elevation animates; the card's colours are not transitioned,
   so a theme change cannot leave this card on a later frame than the page. */
.zic-card:hover,
.zic-card:focus-within {
  transition: box-shadow var(--zic-transition-fast);
}

.zic-card:hover {
  border-color: var(--zic-border-strong);
  box-shadow: var(--zic-shadow-md);
}
