/* GENERATED from listing-card.css by tools/qa/split-listing-card-css.php (2026-09-23).
   listing-card.css stays frozen for installed themes (the CDN holds one unversioned
   copy per file); new themes load listing-card-common.css plus the active fork's
   card family file only. Edit THESE files from now on. */
/* PPT — the canonical listing card (Ppt\Directory\ListingCard).
   Built on the theme design tokens so the one card adopts each design's
   colours, fonts and radius. Used across every directory surface: search
   results, single-page "related", and the live listing-grid blocks. The card
   is grid-agnostic — it fills whatever grid cell / column the caller provides. */
.ppt-lc{
  display:flex;flex-direction:column;height:100%;
  background:var(--ppt-surface,#fff);
  border:1px solid var(--ppt-line,#e6e8ec);
  border-radius:var(--ppt-radius,8px);
  overflow:hidden;text-decoration:none;color:inherit;
  box-shadow:var(--ppt-shadow,0 1px 2px rgba(16,24,40,.05));
  transition:transform .14s ease, box-shadow .14s ease, border-color .14s ease;
}
.ppt-lc:hover{
  transform:translateY(-3px);
  box-shadow:0 12px 28px rgba(16,24,40,.12);
  border-color:color-mix(in srgb, var(--ppt-brand,#2563eb) 40%, var(--ppt-line,#e6e8ec));
  color:inherit;
}
.ppt-lc.is-highlighted{border-color:var(--ppt-brand,#2563eb);box-shadow:0 0 0 2px color-mix(in srgb,var(--ppt-brand,#2563eb) 30%,transparent);}
/* Media */
.ppt-lc-media{position:relative;}
.ppt-lc-img{display:block;width:100%;aspect-ratio:4/3;object-fit:cover;}
.ppt-lc-noimg{display:block;width:100%;aspect-ratio:4/3;background:linear-gradient(135deg,var(--ppt-brand-tint,#eef2ff),var(--ppt-surface-2,#f5f6f8));}
.ppt-lc-cat{
  position:absolute;top:12px;inset-inline-start:12px;
  background:color-mix(in srgb, var(--ppt-surface,#fff) 88%, transparent);
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);
  color:var(--ppt-brand-strong,var(--ppt-brand,#2563eb));
  font-family:var(--ppt-font-body,inherit);font-weight:600;font-size:12px;
  padding:5px 11px;border-radius:999px;
}
.ppt-lc-feat{
  position:absolute;top:12px;inset-inline-end:12px;
  background:var(--ppt-brand,#2563eb);color:var(--ppt-brand-ink,#fff);
  font-family:var(--ppt-font-display,inherit);font-weight:700;
  font-size:11px;letter-spacing:.03em;text-transform:uppercase;
  padding:5px 10px;border-radius:999px;
}
.ppt-lc-feat.is-soldout{background:#b42318;color:#fff;}
/* Promo chips (Boosted / Featured) share one corner.
   The wrapper takes the absolute position the featured pill used to hold on its own, and
   the chips inside it go static — so a card can carry one, the other or both without a
   second chip having to find a free corner. Additive: a card that emits .ppt-lc-feat on
   its own, as every other fork still does, is untouched by any of this. */
.ppt-lc-promo{
  position:absolute;top:12px;inset-inline-end:12px;
  display:flex;align-items:center;gap:6px;flex-wrap:wrap;justify-content:flex-end;
  max-width:calc(100% - 24px);
}
.ppt-lc-promo .ppt-lc-feat{position:static;inset:auto;}
.ppt-lc-boost{
  background:var(--ppt-ink,#141922);color:var(--ppt-surface,#fff);
  font-family:var(--ppt-font-display,inherit);font-weight:700;
  font-size:11px;letter-spacing:.03em;text-transform:uppercase;
  padding:5px 10px;border-radius:999px;white-space:nowrap;
}
/* The Featured BANNER — the escort/dating alternative to the pill above, drawn only
   where ThemeProfiles::supportsProfileBadges() is on (ListingCard emits one or the
   other, never both). A strip laid across the media's top-right corner at 45°, so it
   reads as part of the photo instead of a sticker on it. The square is the clip
   window; the strip inside is deliberately wider than the square so its cut ends land
   outside it and never show. Coloured from --ppt-brand, so every design keeps its own
   palette rather than inheriting one fixed pink. */
.ppt-lc-ribbon{
  position:absolute;top:0;inset-inline-end:0;z-index:3;
  width:118px;height:118px;overflow:hidden;pointer-events:none;
}
.ppt-lc-ribbon > span{
  position:absolute;display:block;
  top:24px;inset-inline-end:-53px;width:180px;
  transform:rotate(45deg);
  padding:7px 0;text-align:center;
  background:var(--ppt-brand,#b4237f);color:var(--ppt-brand-ink,#fff);
  font-family:var(--ppt-font-display,inherit);
  font-weight:700;font-size:10.5px;line-height:1.35;letter-spacing:.12em;
  text-transform:uppercase;
  box-shadow:0 2px 10px rgba(4,8,15,.28);
}
/* Mirrored, not merely flipped: `inset-inline-end` already moves the clip window to
   the left corner, so only the rotation direction is left to turn round. */
[dir="rtl"] .ppt-lc-ribbon > span{transform:rotate(-45deg);}
/* Badge / ONLINE pills. ONE look, TWO placements: `.ppt-lc-pills` sits in the card
   BODY under the title (the standard card, e.g. dating — the name lives in the text
   column there and the 4:3 photo has no scrim to carry white text), while
   `.ppt-lc-es-pills` further down overlays the escort poster's own scrim. Colours
   ride inline custom properties per badge — the only thing the style attribute on
   these carries; the shape and type stay here so every badge is the same object. */
.ppt-lc-pills{display:flex;flex-wrap:wrap;align-items:center;gap:6px;}
.ppt-lc-pill{
  display:inline-flex;align-items:center;
  border-radius:999px;padding:3px 9px;
  font-family:var(--ppt-font-display,inherit);
  font-weight:700;font-size:10px;line-height:1.4;letter-spacing:.06em;
  text-transform:uppercase;white-space:nowrap;
  color:var(--ppt-pill-fg,#fff);background:var(--ppt-pill-bg,#111827);
}
/* ONLINE is site-observed, not owner-declared, so it is the one pill whose colour is
   fixed — it means the same thing on every design and every listing. Same green as
   the presence ring on avatars (--ppt-online). */
.ppt-lc-pill.is-online{color:#fff;background:var(--ppt-online,#16a34a);}
/* "% match" is about the VIEWER (their preferences against this profile), so like
   ONLINE it takes no owner colour — the brand, so it reads as the site speaking. */
.ppt-lc-pill.is-match{color:var(--ppt-brand-ink,#fff);background:var(--ppt-brand,#111827);}
/* LIVE — a broadcasting-now pill in the ribbon slot. Set by ListingCard when the
   listing's stored broadcast state is "on"; it replaces the Featured ribbon rather
   than stacking with it, because two pills in one corner overlap. Shared here (not
   in live.css) so a card in a grid shows the badge without the live player's CSS. */
.ppt-lc-live{
  position:absolute;top:12px;inset-inline-end:12px;
  display:inline-flex;align-items:center;gap:5px;
  background:#e11d48;color:#fff;
  font-family:var(--ppt-font-display,inherit);font-weight:700;
  font-size:11px;letter-spacing:.03em;text-transform:uppercase;
  padding:5px 10px;border-radius:999px;
}
.ppt-lc-live-dot{
  width:6px;height:6px;border-radius:50%;background:#fff;
  animation:ppt-lc-livedot 1.4s ease-in-out infinite;
}
@keyframes ppt-lc-livedot{0%,100%{opacity:1;}50%{opacity:.35;}}
@media (prefers-reduced-motion: reduce){
  .ppt-lc-live-dot{animation:none;}
}
/* Sold — a diagonal corner ribbon across the media (shared; any theme can set it).
   Clipped by the card's own overflow:hidden, so it reads as a folded corner flag. */
.ppt-lc-sold{
  position:absolute;top:16px;inset-inline-start:-42px;z-index:3;
  width:156px;padding:5px 0;transform:rotate(-45deg);
  background:#b42318;color:#fff;text-align:center;pointer-events:none;
  font-family:var(--ppt-font-display,inherit);font-weight:800;
  font-size:11px;letter-spacing:.12em;text-transform:uppercase;
  box-shadow:0 2px 8px rgba(16,24,40,.28);
}
.ppt-lc.is-sold .ppt-lc-img{filter:grayscale(.4) brightness(.92);}
/* Expired — the same corner ribbon in a neutral grey. Nothing went wrong, the
   listing just finished, so it shouldn't shout like the red Sold flag. */
.ppt-lc-sold.is-expired{background:#667085;}
.ppt-lc.is-expired .ppt-lc-img{filter:grayscale(.55) brightness(.94);}
/* Body */
.ppt-lc-body{display:flex;flex-direction:column;gap:8px;padding:18px 20px;flex:1;font-family:var(--ppt-font-body,inherit);}
.ppt-lc-head{display:flex;align-items:flex-start;justify-content:space-between;gap:10px;}
.ppt-lc-title{margin:0;font-family:var(--ppt-font-display,inherit);font-weight:700;font-size:18px;line-height:1.25;color:var(--ppt-ink,#111827);}
.ppt-lc-rating{display:inline-flex;align-items:center;gap:3px;white-space:nowrap;font-weight:600;font-size:14px;color:var(--ppt-amber,#f59e0b);}
.ppt-lc-desc{margin:0;font-size:14px;line-height:1.55;color:var(--ppt-muted,#6b7280);}
/* Booking Theme: a service card's length + price line, e.g. "45 min · £38". */
.ppt-lc-svc{margin:0;font-weight:600;font-size:13.5px;letter-spacing:.01em;font-variant-numeric:tabular-nums;color:var(--ppt-brand-strong,var(--ppt-brand,#2563eb));}
/* Footer */
/* Wraps rather than overflows: on a four-up grid at ~992px a lot card's footer
   (countdown + "View details") no longer fits one line, and both halves are
   white-space:nowrap, so without this the CTA was clipped by the card edge. The
   CTA keeps margin-inline-start:auto, so when it drops it sits right-aligned on
   its own line. Wider cards are unchanged — nothing wraps until it must. */
.ppt-lc-foot{display:flex;flex-wrap:wrap;align-items:center;gap:12px;row-gap:6px;margin-top:auto;padding-top:6px;}
.ppt-lc-price{font-weight:700;font-size:14px;color:var(--ppt-brand-strong,var(--ppt-brand,#2563eb));}
/* "from" prefix — Coupon fork only (Ppt\_cp\ListingCard is the one card that renders
   it). Lighter and smaller than the figure so the number still leads the eye. */
.ppt-lc-from{font-weight:500;font-size:.82em;color:var(--ppt-muted,#94a3b8);}
/* Sale price (Car Dealer): original struck through, discounted price beneath it. */
.ppt-lc-price-sale{display:inline-flex;flex-direction:column;line-height:1.15;}
.ppt-lc-price-was{font-weight:500;font-size:12px;color:var(--ppt-muted,#94a3b8);text-decoration:line-through;}
.ppt-lc-price-now{font-weight:700;font-size:14px;color:var(--ppt-sale,#dc2626);}
/* Auction countdown — replaces the price on lot cards (Ppt\_at\ListingCard).
   Live-ticked by assets/js/listing-card-timer.js; .is-urgent (<1h) and .is-ended
   are toggled by that script (and .is-ended is set server-side for already-closed
   lots so a no-JS render still reads correctly). Uses tabular numerals so the
   digits don't jitter as they count down. */
.ppt-lc-timer{
  display:inline-flex;align-items:center;gap:7px;white-space:nowrap;
  font-weight:700;font-size:14px;color:var(--ppt-brand-strong,var(--ppt-brand,#2563eb));
  font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1;
}
.ppt-lc-timer-dot{
  flex:none;width:7px;height:7px;border-radius:50%;
  background:var(--ppt-brand,#2563eb);
  box-shadow:0 0 0 0 color-mix(in srgb,var(--ppt-brand,#2563eb) 55%,transparent);
  animation:ppt-lc-pulse 1.8s ease-out infinite;
}
.ppt-lc-timer.is-urgent{color:var(--ppt-danger,#e11d48);}
.ppt-lc-timer.is-urgent .ppt-lc-timer-dot{
  background:var(--ppt-danger,#e11d48);
  box-shadow:0 0 0 0 color-mix(in srgb,var(--ppt-danger,#e11d48) 55%,transparent);
  animation-duration:1s;
}
.ppt-lc-timer.is-ended{color:var(--ppt-muted,#6b7280);font-weight:600;}
.ppt-lc-timer.is-ended .ppt-lc-timer-dot{background:var(--ppt-muted,#9aa1ab);animation:none;box-shadow:none;}
@keyframes ppt-lc-pulse{
  0%{box-shadow:0 0 0 0 color-mix(in srgb,currentColor 45%,transparent);}
  70%{box-shadow:0 0 0 6px transparent;}
  100%{box-shadow:0 0 0 0 transparent;}
}
@media(prefers-reduced-motion:reduce){
  .ppt-lc-timer-dot{animation:none;}
}
.ppt-lc-city{display:inline-flex;align-items:center;gap:4px;font-size:13px;color:var(--ppt-muted,#6b7280);}
.ppt-lc-pin{flex:none;}
.ppt-lc-dist{font-size:13px;font-weight:600;color:var(--ppt-ink-2,var(--ppt-muted,#6b7280));}
.ppt-lc-cta{margin-inline-start:auto;font-size:13px;font-weight:600;color:var(--ppt-brand,#2563eb);white-space:nowrap;}
/* Shop: the "Add to cart" pill that replaces the CTA link on every priced card
   (Ppt\_sp\ListingCard) — price left, pill right. It renders as a <button> when
   the card can add to the cart in place (clicks intercepted by
   assets/js/shop-cart.js, which stopPropagation()s so the card's own link isn't
   followed), and as a <span> when the click should fall through to the product
   page instead (a product with variants to pick, or a demo/preview card). Both
   are styled here so the two are visually identical; the span needs the
   inline-flex/line-height/text-decoration resets a button gets for free. */
.ppt-lc-cart{
  margin-inline-start:auto;flex:none;
  display:inline-flex;align-items:center;justify-content:center;
  border:0;border-radius:999px;cursor:pointer;
  background:var(--ppt-brand,#2563eb);color:var(--ppt-brand-ink,#fff);
  font-family:var(--ppt-font-body,inherit);font-weight:700;font-size:13px;
  line-height:1.2;text-decoration:none;
  padding:8px 16px;white-space:nowrap;
  transition:opacity .12s ease;
}
.ppt-lc-cart:hover{opacity:.88;}
.ppt-lc-cart:disabled{opacity:.5;cursor:not-allowed;}
/* Long description — only shown in list view (below). */
.ppt-lc-desc-long{display:none;margin:0;font-size:14px;line-height:1.55;color:var(--ppt-muted,#6b7280);}
/* Card highlighted from a map-marker hover (mirrors the card's own :hover). Used
   by the search results ↔ map hover-sync. */
.ppt-lc.is-mhover{
  transform:translateY(-3px);
  border-color:var(--ppt-brand,#2563eb);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--ppt-brand,#2563eb) 22%,transparent),0 12px 28px rgba(16,24,40,.12);
}
/* List view — any grid marked [data-view="list"] (e.g. the search results grid)
   lays its cards out horizontally and swaps the short description for the long
   one. On phones it falls back to the stacked card. */
[data-view="list"]>.col{flex:0 0 100%!important;max-width:100%!important;width:100%!important;}
[data-view="list"] .ppt-lc{flex-direction:row;align-items:stretch;min-height:150px;}
[data-view="list"] .ppt-lc-media{flex:0 0 34%;max-width:220px;}
[data-view="list"] .ppt-lc-img,[data-view="list"] .ppt-lc-noimg{height:100%;aspect-ratio:auto;min-height:100%;object-fit:cover;}
[data-view="list"] .ppt-lc-desc{display:none;}
[data-view="list"] .ppt-lc-desc-long{display:-webkit-box;-webkit-line-clamp:5;-webkit-box-orient:vertical;overflow:hidden;}
@media(max-width:640px){
  [data-view="list"] .ppt-lc{flex-direction:column;}
  [data-view="list"] .ppt-lc-media{flex:none;max-width:none;}
  [data-view="list"] .ppt-lc-img,[data-view="list"] .ppt-lc-noimg{aspect-ratio:4/3;min-height:0;}
}
/* Two cards per row on a phone gives each card roughly 180px of width, which the full
   card overflows: the title wraps to three lines, the excerpt takes four more, and the
   price and CTA are squeezed onto a line that no longer fits. Trim the card to what
   still reads at that size. The whole card is a link, so dropping the "View details"
   CTA costs no navigation. One-column grids and the list view are untouched. */
@media(max-width:640px){
  .row-cols-2 .ppt-lc-body{padding:12px 13px;gap:5px;}
  .row-cols-2 .ppt-lc-title{
    font-size:15px;line-height:1.22;
    display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
  }
  .row-cols-2 .ppt-lc-desc,.row-cols-2 .ppt-lc-cta{display:none;}
  /* The cart pill stays on two-up phone grids (it's the point of a shop card),
     just tighter so a long price and the pill still share one row. A card that
     narrow can still be beaten by a long price ("$1,299,000.00"), so let the
     footer wrap rather than overflow — the pill keeps its margin-inline-start:auto
     and stays right-aligned on its own line. */
  .row-cols-2 .ppt-lc-cart{padding:6px 11px;font-size:12px;}
  .row-cols-2 .ppt-lc-foot{flex-wrap:wrap;row-gap:6px;}
  .row-cols-2 .ppt-lc-price{min-width:0;}
  .row-cols-2 .ppt-lc-foot{gap:6px;padding-top:2px;}
  .row-cols-2 .ppt-lc-price,.row-cols-2 .ppt-lc-price-now{font-size:13.5px;}
  .row-cols-2 .ppt-lc-badge{font-size:11px;padding:3px 8px;}
}
/* Real Estate fork (_rt): "property details" — the beds · baths · size stat row,
   built from the per-listing structured fields. Sits under the title. Rendered by
   Ppt\_rt\ListingCard (beds · baths · size) and Ppt\_cd\VehicleSpecs
   (year · mileage · fuel · transmission). */
.ppt-lc-stats{
  display:flex;flex-wrap:wrap;align-items:center;gap:6px 16px;
  margin:1px 0 2px;
}
.ppt-lc-stat{
  display:inline-flex;align-items:center;gap:6px;
  font-size:13.5px;font-weight:700;line-height:1.2;
  color:var(--ppt-ink,#111827);
}
.ppt-lc-stat .ppt-lc-amen-ic{color:var(--ppt-brand,#2563eb);}
.ppt-lc-stat-val{white-space:nowrap;}
/* Real Estate fork (_rt): "property features" — a row of icon + label amenity
   chips (e.g. Private suite · Ensuite · 24/7 nursing), edited per-listing on the
   listing form. Sits between the description and the footer. Only rendered by
   Ppt\_rt\ListingCard, so these classes never appear on other profiles. */
.ppt-lc-amen{
  display:flex;flex-wrap:wrap;align-items:center;gap:7px 16px;
  margin:2px 0 2px;
}
.ppt-lc-amen-item{
  display:inline-flex;align-items:center;gap:6px;
  font-size:13px;font-weight:600;line-height:1.2;
  color:var(--ppt-ink-2,var(--ppt-ink,#374151));
}
.ppt-lc-amen-ic{flex:none;color:var(--ppt-brand,#2563eb);}
.ppt-lc-amen-lbl{white-space:nowrap;}
/* In list view the row can breathe a little more. */
[data-view="list"] .ppt-lc-amen{gap:8px 18px;}
/* Coupon fork (_cp): a listing card is a deal card. The merchant name sits under
   the title, the discount badge rides the media ribbon (.ppt-lc-feat), and the
   expiry replaces the price/location line. Unused on non-coupon themes. */
.ppt-lc-merchant{margin:0 0 4px;font-size:12px;font-weight:700;letter-spacing:.02em;text-transform:uppercase;color:var(--ppt-brand-strong,#0b7c72);}
.ppt-lc-expiry{font-size:12.5px;color:var(--ppt-muted,#6b7280);}
/* Top-right cluster: price chip + save-to-collection heart, side by side. */
.ppt-lc-tr{position:absolute;top:11px;inset-inline-end:11px;z-index:3;display:flex;align-items:center;gap:7px;}
.ppt-lc-save{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:50%;cursor:pointer;flex:none;color:#fff;background:color-mix(in srgb,#0b0f17 55%,transparent);-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);box-shadow:0 2px 8px rgba(16,24,40,.16);transition:transform .12s ease,background .12s ease;}
.ppt-lc-save:hover{transform:scale(1.08);background:color-mix(in srgb,#0b0f17 68%,transparent);}
.ppt-lc-save.is-on{background:var(--ppt-brand,#0d9488);color:var(--ppt-brand-ink,#fff);}
.ppt-lc-save.is-on svg{fill:currentColor;}
.ppt-lc-save:focus-visible{outline:2px solid var(--ppt-brand,#0d9488);outline-offset:2px;}
.ppt-lc-cell--ftposter .ppt-lc-cat--link{
  top:11px;inset-inline-start:11px;
  background:var(--ppt-brand,#c8102e);color:var(--ppt-brand-ink,#fff);
  -webkit-backdrop-filter:none;backdrop-filter:none;
  font-family:var(--ppt-font-display,inherit);
  font-weight:700;font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;
  padding:4px 9px;box-shadow:0 2px 8px rgba(4,8,15,.22);
}
/* ---------------------------------------------------------------------------
   Saved / favourite hearts — ONE saved look for every one of them.

   A Save control is anything carrying `.ppt-s-fav` (a listing page's Save
   button, the corner heart card-hitareas.js adopts on a card). Each design
   styles its own resting heart; what none of them had was a SAVED state, so a
   click changed nothing on screen and a visitor could not tell it had landed.
   Filling the heart is the state; the pop is the acknowledgement.

   Scoped to `.is-on` only, so no design's own resting styling is touched.

   `!important` is deliberate and limited to the two properties that ARE the state.
   Each block ships its own stylesheet, emitted after this one and often at the same
   specificity (`.ppt-xx-card .ppt-xx-save`), so a resting colour would otherwise win
   the tie by source order and the heart would look identical saved or not. Set
   `--ppt-fav` on a design to theme the saved colour.
   --------------------------------------------------------------------------- */
.ppt-s-fav{transition:color .15s ease,background-color .15s ease;}
.ppt-s-fav.is-on{color:var(--ppt-fav,#e0245e) !important;border-color:currentColor;}
.ppt-s-fav.is-on svg{fill:currentColor !important;stroke:currentColor !important;}
.ppt-s-fav[disabled]{opacity:.55;cursor:progress;}
.ppt-fav-pop svg{animation:ppt-fav-pop .28s ease;}
@keyframes ppt-fav-pop{
  0%{transform:scale(1);}
  45%{transform:scale(1.32);}
  100%{transform:scale(1);}
}
@media(prefers-reduced-motion:reduce){
  .ppt-fav-pop svg{animation:none;}
}
/* Queued / Watch-later controls — the same contract, one step along.

   `.ppt-s-watch` is the queue's answer to `.ppt-s-fav`: any control that puts a
   listing in the member's Watch-later queue (a _vt hero's "Add to my queue", a
   "Watch later" button). It carries the brand colour rather than the heart's pink,
   because the two states have to be distinguishable on a hero that offers both — a
   video can be saved without being queued.

   Same `!important` reasoning as above: each block ships its stylesheet after this
   one at comparable specificity, so a resting colour would otherwise win on source
   order and the button would look identical queued or not. */
.ppt-s-watch{transition:color .15s ease,background-color .15s ease;}
.ppt-s-watch.is-on{color:var(--ppt-brand,#0d9488) !important;border-color:currentColor;}
.ppt-s-watch.is-on svg{stroke:currentColor !important;}
.ppt-s-watch[disabled]{opacity:.55;cursor:progress;}
