/* Pulse commerce attachment card.
 * ===============================
 *
 * The one stylesheet for `section.pulse-commerce-card`, the block emitted by
 * `services/pulse_commerce_card.py` and `static/js/pulse_commerce_card.js`.
 *
 * A separate file, and not a block appended to `pulsesoc-tokens.css`, for a
 * boring operational reason: `static/` is served with a one-year immutable
 * cache and every asset carries a `?v=` token, so editing an existing
 * stylesheet means finding and bumping its token at every site that links it.
 * `pulsesoc-tokens.css` is linked from seven places in `bot.py` and about
 * twenty in `templates/`, and a bump missed at one of them ships two different
 * copies of the same file to the same member. A new asset has exactly one
 * token, introduced here, and cannot desynchronise with anything.
 *
 * Every declaration is scoped under `.pulse-commerce-card`. The card is
 * inserted into a single-post page, into the home feed and into a reel's
 * caption overlay, three surfaces whose own CSS is unrelated and was written
 * over several years. An unscoped rule here would be a change to all three.
 *
 * Colours come from the design tokens where they exist and fall back to a
 * literal for the surfaces that do not load `pulsesoc-tokens.css` -- the reels
 * shell being the important one. A `var(--x, #literal)` is two declarations in
 * one and is why this file can be linked from a page that has no tokens.
 */

.pulse-commerce-card {
  display: block;
  margin: 12px 0 0;
  /* `contain` rather than `overflow:hidden` alone: the card is placed inside a
     reel's absolutely-positioned caption overlay, where an unconstrained child
     can push the overlay past the video's edge on a narrow viewport. */
  contain: layout paint style;
}

.pulse-commerce-card * {
  box-sizing: border-box;
}

.pulse-commerce-main {
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 10px;
  border: 1px solid var(--border-subtle, rgba(110, 223, 246, 0.22));
  border-radius: 14px;
  background: var(--surface-raised, rgba(13, 22, 39, 0.92));
  color: var(--text-primary, #f2fbff);
  text-decoration: none;
  /* The card sits under media that can be any colour. An explicit stacking
     context keeps the reel's gradient scrims from bleeding through it. */
  isolation: isolate;
}

a.pulse-commerce-main:hover,
a.pulse-commerce-main:focus-visible {
  border-color: var(--action-primary, #36e58f);
  background: var(--surface-elevated, rgba(20, 32, 52, 0.96));
}

a.pulse-commerce-main:focus-visible {
  outline: 2px solid var(--pulse-palette-focus, #8df7ff);
  outline-offset: 2px;
}

/* No hover affordance when there is nowhere to go. The renderer already emits a
   `div` rather than an `a` for those states; this makes the difference visible
   rather than leaving a card that looks clickable and is not.

   The dimming is on the product's own content and not on the block, because the
   block is the card's surface and the seller link below it shares that surface
   and is still live. Fading the surface faded the one control on the card that
   still worked, and left the footer looking brighter than the card it belongs
   to. What is unavailable is the product, so the product is what dims. */
.pulse-commerce-main.is-static {
  cursor: default;
}

.pulse-commerce-main.is-static .pulse-commerce-thumb,
.pulse-commerce-main.is-static .pulse-commerce-title,
.pulse-commerce-main.is-static .pulse-commerce-meta {
  opacity: 0.82;
}

.pulse-commerce-thumb {
  display: block;
  width: 64px;
  height: 64px;
  border-radius: 10px;
  overflow: hidden;
  background: var(--surface-inset, #10203a);
  border: 1px solid rgba(255, 255, 255, 0.08);
}

.pulse-commerce-thumb img {
  /* `cover` and a fixed square: the product photo is cropped to the centre
     rather than squashed. A stretched product is the one thing that makes a
     storefront look fake. The `!important` is not decoration -- the single-post
     page sets `img{width:100%;max-height:74vh;object-fit:contain}` in an inline
     `<style>`, which wins on specificity order against a linked stylesheet. */
  display: block;
  width: 100% !important;
  height: 100% !important;
  max-height: none !important;
  object-fit: cover !important;
  border: 0 !important;
  border-radius: 0 !important;
  margin: 0 !important;
  background: transparent !important;
}

.pulse-commerce-thumb.is-empty {
  background: linear-gradient(
    135deg,
    var(--surface-inset, #10203a),
    rgba(110, 223, 246, 0.1)
  );
}

.pulse-commerce-copy {
  display: grid;
  gap: 4px;
  /* `minmax(0, …)` above plus this: without it a long seller-written title
     refuses to shrink and widens the whole grid past its container. */
  min-width: 0;
}

.pulse-commerce-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.pulse-commerce-chip {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  border: 1px solid transparent;
}

.pulse-commerce-chip-label {
  color: var(--action-primary, #36e58f);
  background: var(--action-ghost-bg, rgba(50, 230, 179, 0.12));
  border-color: rgba(50, 230, 179, 0.28);
}

.pulse-commerce-chip-state {
  color: var(--status-warning, #f3c461);
  background: var(--pulse-palette-warning-soft, rgba(243, 196, 97, 0.14));
  border-color: rgba(243, 196, 97, 0.28);
}

/* Withdrawn, suspended, deleted. A different colour from "sold out" because
   they are a different fact: one is worth coming back for and one is not. */
.pulse-commerce-chip-state.is-gone {
  color: var(--status-neutral, #9aa8b7);
  background: rgba(154, 168, 183, 0.12);
  border-color: rgba(154, 168, 183, 0.26);
}

.pulse-commerce-title {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  /* Two lines, then ellipsis. Marketplace titles are seller-written and run
     long; truncating mid-word with no marker reads as a bug. */
  font-size: 14px;
  font-weight: 700;
  line-height: 1.3;
  color: var(--text-primary, #f2fbff);
}

.pulse-commerce-meta {
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
}

.pulse-commerce-price {
  font-size: 16px;
  font-weight: 900;
  color: var(--text-primary, #f2fbff);
  white-space: nowrap;
}

.pulse-commerce-store {
  font-size: 12px;
  color: var(--text-secondary, #9fb5c0);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

.pulse-commerce-cta {
  justify-self: start;
  margin-top: 2px;
  padding: 5px 12px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 800;
  color: var(--text-on-action, #04121a);
  background: linear-gradient(
    135deg,
    var(--action-primary, #36e58f),
    var(--action-secondary, #6edff6)
  );
}

/* The seller link is a *sibling* of the product link, never a child of it.
   An `<a>` cannot contain an `<a>`, and these are two deliberately different
   destinations -- the product and the merchant -- which the payload keeps apart
   so that PulseDrop does not read as the seller of what it publishes.

   The consequence for this file is that the seller link is the one part of the
   card that does not inherit the card's surface, so left plain it renders on
   whatever is behind the card. On the feed and the post page that is a dark
   page and it merely looks orphaned; on a reel it is text sitting directly on
   the video, where one bright frame makes it unreadable. So it carries the
   surface itself rather than borrowing the host's. */
.pulse-commerce-seller {
  display: block;
  margin-top: 6px;
  padding: 7px 10px;
  border: 1px solid var(--border-subtle, rgba(110, 223, 246, 0.22));
  border-radius: 14px;
  background: var(--surface-raised, rgba(13, 22, 39, 0.92));
  font-size: 12px;
  font-weight: 700;
  color: var(--action-secondary, #6edff6);
  text-decoration: none;
  isolation: isolate;
}

/* Where the browser can see the pair, close the seam so the two blocks read as
   one card. `:has()` is the only way to style the product block based on a
   sibling that follows it, and it is doing something cosmetic here on purpose:
   a browser without it keeps both halves rounded and separate, which is a
   card that looks worse rather than a card that is broken. */
.pulse-commerce-card:has(.pulse-commerce-seller) .pulse-commerce-main {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}

.pulse-commerce-card:has(.pulse-commerce-seller) .pulse-commerce-seller {
  /* Pull up by exactly the border width so the two 1px borders become one
     line rather than a 2px rule with a hairline of page showing through. */
  margin-top: -1px;
  border-top-color: transparent;
  border-top-left-radius: 0;
  border-top-right-radius: 0;
}

.pulse-commerce-seller:hover,
.pulse-commerce-seller:focus-visible {
  text-decoration: underline;
  border-color: var(--action-secondary, #6edff6);
}

.pulse-commerce-seller:focus-visible {
  outline: 2px solid var(--pulse-palette-focus, #8df7ff);
  outline-offset: 2px;
}

/* The reel variant sits over video, so it carries its own contrast rather than
   borrowing the page's surface colour -- there is no page surface behind it. */
.pulse-commerce-reel .pulse-commerce-main,
.pulse-commerce-reel .pulse-commerce-seller {
  background: rgba(4, 10, 20, 0.78);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  border-color: rgba(255, 255, 255, 0.16);
}

/* The seam again, for the reel's border colour. Re-stated rather than folded
   into the rule above because that one sets `border-color` on all four sides
   and would paint the joint back in. */
.pulse-commerce-reel:has(.pulse-commerce-seller) .pulse-commerce-seller {
  border-top-color: transparent;
}

.pulse-commerce-reel .pulse-commerce-store,
.pulse-commerce-reel .pulse-commerce-title {
  color: #f2fbff;
}

@media (max-width: 520px) {
  .pulse-commerce-main {
    grid-template-columns: 54px minmax(0, 1fr);
    gap: 10px;
  }

  .pulse-commerce-thumb {
    width: 54px;
    height: 54px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .pulse-commerce-main,
  a.pulse-commerce-main:hover {
    transition: none;
  }
}
