/* Recipe card.

   Editorial layout — image-dominant, metadata strip + title only.
   No description on cards (lives on the recipe-detail page).
   Time chip overlays the image bottom-right; save heart sits absolutely
   over the top-right (must NOT live inside the <a> — button-in-anchor
   is invalid HTML and breaks AT keyboard interaction).

   Used in: /recipes (grid), /saved (grid), /dev/playground/recipe-card.
   Variants: default. `--skeleton` shows shimmer placeholders while data
   is in flight.

   State forcing:
       <article class="recipe-card" data-force="hover">    — local
       <div data-force="hover"><article class="recipe-card">…</article></div> — ancestor

   Both forms work; the ancestor form is useful for the dev playground
   page that drives state via URL query params. The selector below uses
   :is() to accept either, and `~=` (whitespace-token match) lets
   data-force compose multiple states ("hover focus", etc.).

   Cascade-layer note: lives in `components` so reset/layout never
   overrides it, and utility classes (.label-caps used by the metadata
   strip) always do. */

@layer components {
  .recipe-card {
    /* `position: relative` is load-bearing — `.recipe-card__save-wrap`
       and `.recipe-card__time-chip` are absolutely positioned against
       this. */
    position: relative;
    /* `min-width: 0` lets the card shrink inside grid/flex parents whose
       columns are `1fr`. Without this, the no-wrap meta strip's
       min-content width pushes grid columns wider than their share and
       the layout overflows. Mirrors the sandbox MasonryGrid pattern. */
    min-width: 0;
    background: var(--md-surface-container-low);
    border-radius: var(--radius-lg);
    overflow: hidden;
    box-shadow: var(--shadow-xs);
    transition:
      transform var(--motion-spring-fast-effects-duration) var(--motion-spring-fast-effects),
      box-shadow var(--motion-spring-fast-effects-duration) var(--motion-spring-fast-effects);

    &:is(:hover, :focus-within, [data-force~="hover"], [data-force~="focus"]),
    [data-force~="hover"] &,
    [data-force~="focus"] & {
      transform: translateY(-2px);
      box-shadow: var(--shadow-md);
    }

    &:is(:active, [data-force~="active"]),
    [data-force~="active"] & {
      transform: translateY(-1px);
      box-shadow: var(--shadow-sm);
    }
  }

  .recipe-card__link {
    display: flex;
    flex-direction: column;
    height: 100%;

    /* Hide the default focus ring (we draw our own that respects the
       card's border-radius). :focus is the broader trigger so mouse-click
       keeps the ring suppressed; :focus-visible re-enables for keyboard. */
    &:focus { outline: none; }

    &:is(:focus-visible, [data-force~="focus"]),
    [data-force~="focus"] & {
      outline: 2px solid var(--md-ring);
      outline-offset: 2px;
      border-radius: var(--radius-lg);
    }
  }

  .recipe-card__media {
    position: relative;
    width: 100%;
    /* Default 3:2 matches the sandbox; cards with explicit hero dimensions
       override via the `--ratio` inline style on the element. */
    aspect-ratio: var(--ratio, 3 / 2);
    background: var(--md-surface-container);
    overflow: hidden;
  }

  .recipe-card__image {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform var(--motion-spring-default-spatial-duration) var(--motion-spring-default-spatial);

    /* Image scales when the parent card is hovered/focused — locally OR
       via a data-force ancestor. Mirrors the .recipe-card hover rule. */
    .recipe-card:is(:hover, :focus-within, [data-force~="hover"], [data-force~="focus"]) &,
    [data-force~="hover"] &,
    [data-force~="focus"] & {
      transform: scale(1.03);
    }
  }

  .recipe-card__fallback {
    position: absolute;
    inset: 0;
    background: linear-gradient(
      145deg,
      var(--md-surface-container) 0%,
      var(--md-primary-container) 100%
    );
  }

  /* Time chip — frosted light pill overlaying the image bottom-right.
     88% white + backdrop blur reads cleanly against arbitrary photo
     content while keeping the dark editorial cap-style of the title.
     IBM Plex Mono at 11px gives the numerals a slight tabular feel
     ("1h 30m" lines up cleanly with "30m"). */
  .recipe-card__time-chip {
    position: absolute;
    inset-block-end: var(--space-2);
    inset-inline-end: var(--space-2);
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    /* 3px block padding is a sub-token micro-gap (allowlisted); inline snapped 6px -> --space-2. */
    padding: 3px var(--space-2);
    font-family: var(--font-mono);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--md-on-surface);
    background: color-mix(in srgb, var(--md-surface-container-low) 88%, transparent);
    backdrop-filter: blur(8px) saturate(1.4);
    -webkit-backdrop-filter: blur(8px) saturate(1.4);
    border-radius: var(--radius-pill);
    box-shadow: var(--shadow-xs);
    z-index: 1;
    pointer-events: none;
  }

  .recipe-card__time-icon {
    display: block;
    flex-shrink: 0;
    color: var(--md-on-surface-variant);
  }

  .recipe-card__body {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding: var(--space-3) var(--space-4) var(--space-4);
    flex: 1;
  }

  /* Metadata strip — uppercased domain + dietary flags joined by " · ".
     Owns its own typography (mono, 10px, tight tracking) rather than
     borrowing the global .label-caps utility — the card's strip is
     content-shaped (single-line, slightly numeric character) while
     .label-caps is a generic UI helper (sans, looser tracking). The
     two should not converge. */
  .recipe-card__meta {
    margin: 0;
    font-family: var(--font-mono);
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--md-on-surface-variant);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .recipe-card__title {
    font-family: var(--font-heading);
    /* 17px ≈ 1.0625rem — sandbox-matched. Smaller than UI defaults; the
       editorial weight comes from Fraunces opsz, not size. */
    font-size: 1.0625rem;
    font-weight: 500;
    line-height: 1.25;
    color: var(--md-on-surface);
    text-wrap: balance;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }

  /* Save-heart wrapper — sibling of the link <a>, not nested. Positioned
     absolutely over the top-right of the media area; z-index lifts it
     above the link so clicks hit the button, not the underlying anchor.
     The `.save-heart` button visual lives in save-heart.css (it's reused
     by the peek_panel topbar). 10px top/right matches the legacy
     SaveButton.tsx position (Tailwind `top-2.5 right-2.5`), locked in
     docs/ui-bugs/12-target.md for issue #317 PR1. */
  .recipe-card__save-wrap {
    position: absolute;
    inset-block-start: 10px;
    inset-inline-end: 10px;
    z-index: 2;
  }

  /* === Skeleton variant ===
     Used in playground previews and as a loading placeholder while real
     card data is in flight. Pointer-events disabled so the placeholder
     can't be clicked into a broken navigation. */
  .recipe-card--skeleton {
    pointer-events: none;
  }

  .recipe-card__media--shimmer {
    position: relative;
    background: var(--md-surface-container);
    overflow: hidden;

    &::before {
      content: "";
      position: absolute;
      inset: 0;
      background: linear-gradient(
        90deg,
        transparent 0%,
        color-mix(in srgb, white 50%, transparent) 50%,
        transparent 100%
      );
      background-size: 200% 100%;
      animation: var(--animate-shimmer);
    }
  }

  .recipe-card__skeleton-line {
    height: 0.875rem;
    background: var(--md-surface-container);
    border-radius: var(--radius-xs);
    position: relative;
    overflow: hidden;

    &::before {
      content: "";
      position: absolute;
      inset: 0;
      background: linear-gradient(
        90deg,
        transparent 0%,
        color-mix(in srgb, white 60%, transparent) 50%,
        transparent 100%
      );
      background-size: 200% 100%;
      animation: var(--animate-shimmer);
    }

    &--xs { width: 30%; height: 0.625rem; }
    &--md { width: 60%; }
    &--lg { width: 80%; }
    &--xl { width: 95%; height: 1.25rem; }
  }
}
