/* ============================================================================
   Peptide Portal — product card + expandable catalog
   Structure and behaviour follow Origin Science's ProductCard / home catalog
   (glass card, square product well, COA strip, name + stock + CAS, chips,
   "From" price with a round add button; category chips + "View all N").
   Colours, type and radii are Peptide Portal' own tokens.

   Markup is generated by tools/catalog/build_catalog.py from WooCommerce data.
   Behaviour (filter, expand, live stock) is catalog.js. The COA strip is a
   .dp-coa__lot link, so DP's existing COA viewer (coa.js) opens it; the + is
   a [data-dp-card-add] button, so DP's existing picker (picker.js) handles it.
   ============================================================================ */

:root {
  --dp-pc-bg:         rgba(255, 255, 255, .64);
  --dp-pc-strip:      #FFFFFF;
  --dp-pc-line:       rgba(46, 36, 30, .10);
  --dp-pc-line-hover: rgba(46, 36, 30, .30);
  /* Completely white in light mode — no blue well behind the vials; the
     contact shadow alone grounds the cutout. */
  --dp-pc-well:       #FFFFFF;
  --dp-pc-well-2:     #FFFFFF;
  --dp-pc-img-shadow: drop-shadow(0 10px 8px rgba(72, 46, 36, .18)) drop-shadow(0 2px 3px rgba(72, 46, 36, .10));
  --dp-pc-floor:      rgba(72, 46, 36, .20);
  --dp-pc-shadow:     0 1px 2px rgba(72, 46, 36, .06), 0 1px 3px rgba(72, 46, 36, .04);
  --dp-pc-check:      #DC4920;
  --dp-pc-strip-fg:   #33251E;
  --dp-pc-strip-go:   #3F4462;
  --dp-pc-muted:      #4A4E66;
  --dp-pc-chip:       rgba(46, 36, 30, .06);
  --dp-pc-in-bg:      #ECFDF3;  --dp-pc-in-fg: #15803D;  --dp-pc-in-line: #BBF7D0;
  --dp-pc-out-bg:     #FEF2F2;  --dp-pc-out-fg: #DC2626; --dp-pc-out-line: #FECACA;
  --dp-cat-pill:      rgba(255, 255, 255, .55);
  --dp-cat-pill-on:   #DC4920;          /* brand blue — the navy pill read off-brand on white */
  --dp-cat-pill-on-fg:#FFFFFF;
}
:root[data-theme="dark"] {
  --dp-pc-bg:         rgba(35, 27, 24, .62);
  --dp-pc-strip:      #241B17;
  --dp-pc-line:       rgba(255, 255, 255, .08);
  --dp-pc-line-hover: rgba(255, 255, 255, .24);
  --dp-pc-well:       #2D1D17;
  --dp-pc-well-2:     #221612;
  --dp-pc-img-shadow: drop-shadow(0 10px 8px rgba(0, 0, 0, .5)) drop-shadow(0 2px 3px rgba(0, 0, 0, .35));
  --dp-pc-floor:      rgba(0, 0, 0, .55);
  --dp-pc-shadow:     0 1px 2px rgba(0, 0, 0, .3);
  --dp-pc-check:      #FF8057;
  --dp-pc-strip-fg:   #F9F6F5;
  --dp-pc-strip-go:   #C9CCDA;
  --dp-pc-muted:      #B4B8CA;
  --dp-pc-chip:       rgba(255, 255, 255, .07);
  --dp-pc-in-bg:      rgba(34, 197, 94, .12);  --dp-pc-in-fg: #4ADE80;  --dp-pc-in-line: rgba(74, 222, 128, .28);
  --dp-pc-out-bg:     rgba(239, 68, 68, .12);  --dp-pc-out-fg: #F87171; --dp-pc-out-line: rgba(248, 113, 113, .3);
  --dp-cat-pill:      rgba(35, 27, 24, .55);
  --dp-cat-pill-on:   rgba(242, 236, 230, .9);
  --dp-cat-pill-on-fg:#16100C;
}
@media (prefers-color-scheme: dark) {
  :root[data-theme="dark"] {
    --dp-pc-bg:         rgba(35, 27, 24, .62);
    --dp-pc-strip:      #241B17;
    --dp-pc-line:       rgba(255, 255, 255, .08);
    --dp-pc-line-hover: rgba(255, 255, 255, .24);
    --dp-pc-well:       #2D1D17;
    --dp-pc-well-2:     #221612;
    --dp-pc-img-shadow: drop-shadow(0 10px 8px rgba(0, 0, 0, .5)) drop-shadow(0 2px 3px rgba(0, 0, 0, .35));
    --dp-pc-floor:      rgba(0, 0, 0, .55);
    --dp-pc-shadow:     0 1px 2px rgba(0, 0, 0, .3);
    --dp-pc-check:      #FF8057;
    --dp-pc-strip-fg:   #F9F6F5;
    --dp-pc-strip-go:   #C9CCDA;
    --dp-pc-muted:      #B4B8CA;
  --dp-pc-strip-fg:   #F9F6F5;
  --dp-pc-strip-go:   #C9CCDA;
  --dp-pc-muted:      #B4B8CA;
    --dp-pc-chip:       rgba(255, 255, 255, .07);
    --dp-pc-in-bg:      rgba(34, 197, 94, .12);  --dp-pc-in-fg: #4ADE80;  --dp-pc-in-line: rgba(74, 222, 128, .28);
    --dp-pc-out-bg:     rgba(239, 68, 68, .12);  --dp-pc-out-fg: #F87171; --dp-pc-out-line: rgba(248, 113, 113, .3);
    --dp-cat-pill:      rgba(35, 27, 24, .55);
    --dp-cat-pill-on:   rgba(242, 236, 230, .9);
    --dp-cat-pill-on-fg:#16100C;
  }
}

/* --- Card ----------------------------------------------------------------- */
.dp-pc {
  position: relative;
  display: flex; flex-direction: column;
  min-width: 0;
  overflow: hidden;
  border: 1px solid var(--dp-pc-line);
  border-radius: var(--dp-r-2xs);                    /* 16px, as Origin's rounded-2xl */
  background: var(--dp-pc-bg);
  -webkit-backdrop-filter: blur(18px) saturate(1.6);
          backdrop-filter: blur(18px) saturate(1.6);
  box-shadow: var(--dp-pc-shadow);
  color: var(--dp-ink);
  transition: border-color .2s var(--dp-ease-cta), transform .25s var(--dp-ease-cta);
}
.dp-pc[hidden] { display: none; }
@media (hover: hover) { .dp-pc:hover { border-color: var(--dp-pc-line-hover); } }
.dp-pc:focus-within { border-color: var(--dpx-fg-blue, var(--dp-blue)); }

.dp-pc__shot {
  position: relative;
  display: block;
  aspect-ratio: 1;
  overflow: hidden;
  /* A studio-cove gradient (deeper at the floor) behind the transparent-cutout
     renders. */
  background: linear-gradient(180deg, var(--dp-pc-well) 46%, var(--dp-pc-well-2));
}
.dp-pc__shot img {
  position: relative; z-index: 1;
  width: 100%; height: 100%;
  object-fit: contain;
  /* The renders are trimmed edge-to-edge; the scale zooms the vial in further,
     cropping a hair of cap and base against the well. No grounding shadow. */
  transform: scale(1.15);
  transition: transform .5s var(--dp-ease-rot);
}
@media (hover: hover) { .dp-pc:hover .dp-pc__shot img { transform: scale(1.2); } }
/* The vial drifts up and down a hair, like it is suspended. It animates the
   `translate` property so it stacks with the scale transform above instead of
   fighting the hover transition. Neighbouring cards get offset phases and
   slightly different periods so the shelf never bobs in unison. */
@keyframes dp-pc-float { from { translate: 0 2.5px; } to { translate: 0 -2.5px; } }
.dp-pc__shot img { animation: dp-pc-float 4.8s ease-in-out infinite alternate; }
.dp-pc:nth-child(3n+2) .dp-pc__shot img { animation-duration: 5.6s; animation-delay: -3.1s; }
.dp-pc:nth-child(3n) .dp-pc__shot img { animation-duration: 5.2s; animation-delay: -1.7s; }
.dp-pc:nth-child(4n+1) .dp-pc__shot img { animation-delay: -2.4s; }

/* COA strip — the verified line between image and body.
   The strip also carries .dp-coa__lot (so coa.js opens the viewer), and coa.css
   styles that class as a blue pill. coa.css loads AFTER this file on /products/,
   so every property it sets is pinned here at higher specificity. */
.dp-pc a.dp-pc__coa,
.dp-pc a.dp-pc__coa.dp-coa__lot {
  position: relative; z-index: 2;
  display: flex; align-items: center; justify-content: flex-start; gap: 5px;
  margin: 0;
  padding: 7px 12px;
  border: 0;
  border-bottom: 1px solid var(--dp-pc-line);
  border-radius: 0;
  background: var(--dp-pc-strip);
  filter: none;
  font-size: 12px; line-height: 1.3; letter-spacing: 0;
  white-space: nowrap;
  color: var(--dp-pc-strip-fg);
  text-decoration: none;
  transition: background-color .18s var(--dp-ease-cta);
}
.dp-pc__check { width: 15px; height: 15px; flex: none; color: var(--dp-pc-check); }
.dp-pc .dp-pc__coaTxt { margin-right: auto; font-weight: var(--dp-fw-bold); color: var(--dp-pc-strip-fg); transition: color .18s; }
.dp-pc .dp-pc__coaGo { font-weight: var(--dp-fw-semi); color: var(--dp-pc-strip-go); white-space: nowrap; transition: color .18s; }
.dp-pc a.dp-pc__coa:hover { background: var(--dp-pc-well); filter: none; }
.dp-pc a.dp-pc__coa:hover .dp-pc__coaGo,
.dp-pc a.dp-pc__coa:focus-visible .dp-pc__coaGo { color: var(--dp-pc-check); }
.dp-pc a.dp-pc__coa:focus-visible { outline: 2px solid var(--dp-pc-check); outline-offset: -2px; }

.dp-pc__body { display: flex; flex-direction: column; flex: 1; padding: 16px; }
.dp-pc__name { margin: 0; font-size: 15px; font-weight: var(--dp-fw-bold); color: var(--dp-pc-strip-fg); line-height: 1.25; letter-spacing: -.01em; }
.dp-pc__link { color: inherit; text-decoration: none; }
.dp-pc__link::after { content: ""; position: absolute; inset: 0; z-index: 1; }   /* whole card opens the product */
.dp-pc__link:focus-visible { outline: none; }

.dp-pc__stock {
  align-self: flex-start;
  display: inline-flex; align-items: center;
  margin-top: 6px; padding: 2px 6px;
  border: 1px solid var(--dp-pc-in-line); border-radius: 4px;
  background: var(--dp-pc-in-bg); color: var(--dp-pc-in-fg);
  font-size: 10px; font-weight: var(--dp-fw-bold); line-height: 1.3;
}
.dp-pc__stock[hidden] { display: none; }
.dp-pc__stock.is-out { border-color: var(--dp-pc-out-line); background: var(--dp-pc-out-bg); color: var(--dp-pc-out-fg); }

.dp-pc__cas { margin: 6px 0 0; font-size: 12px; font-weight: var(--dp-fw-medium); color: var(--dp-pc-muted); }

.dp-pc__chips { display: flex; flex-wrap: wrap; gap: 6px; padding: 8px 0 14px; }
.dp-pc__chip {
  display: inline-flex; align-items: center;
  padding: 2px 8px;
  border: 1px solid var(--dp-pc-line); border-radius: var(--dp-r-pill);
  background: var(--dp-pc-chip);
  font-size: 11px; font-weight: var(--dp-fw-semi); line-height: 1.5;
  color: var(--dp-pc-muted);
}
.dp-pc__chip--soft { background: transparent; }

.dp-pc__foot { margin-top: auto; display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.dp-pc__price { margin: 0; display: flex; flex-direction: column; line-height: 1; }
.dp-pc__from { margin-bottom: 4px; font-size: 11px; font-weight: var(--dp-fw-medium); color: var(--dp-pc-muted); }
.dp-pc__amt { font-size: 17px; font-weight: var(--dp-fw-bold); letter-spacing: -.01em; color: var(--dp-pc-strip-fg); }

.dp-pc__add {
  position: relative; z-index: 2;
  flex: none;
  display: grid; place-items: center;
  width: 28px; height: 28px; padding: 0;
  border: 0; border-radius: 50%;
  background: var(--dp-blue); color: var(--dpx-fg-ffffff, #FFFFFF);
  cursor: pointer;
  transition: opacity .18s, transform .18s var(--dp-ease-cta);
}
.dp-pc__add::before { content: ""; position: absolute; inset: -8px; }   /* 44px touch target */
.dp-pc__add svg { width: 14px; height: 14px; }
@media (hover: hover) { .dp-pc__add:hover { opacity: .9; transform: scale(1.06); } }
.dp-pc__add:focus-visible { outline: 2px solid var(--dpx-fg-blue, var(--dp-blue)); outline-offset: 2px; }
.dp-pc__add:disabled { opacity: .35; cursor: not-allowed; transform: none; }

/* Reveal: fade up, staggered (Origin: 0.75s, 0.13s per card, capped at 0.65s). */
@keyframes dp-pc-in { from { opacity: 0; transform: translateY(28px); } to { opacity: 1; transform: none; } }
.dp-pc.is-in { animation: dp-pc-in .75s cubic-bezier(.22, 1, .36, 1) both; animation-delay: calc(min(var(--d, 0), 5) * .13s); }
[data-dp-cat-pending] .dp-pc { opacity: 0; }
/* Waiting for its own scroll-in (class added by catalog.js; absent without JS). */
.dp-pc--rv { opacity: 0; }
@media (prefers-reduced-motion: reduce) { .dp-pc.is-in { animation: none; } .dp-pc__shot img { animation: none; transition: none; } }

/* --- Home catalog section --------------------------------------------------- */
.dp-cat { padding: 24px 0 8px; }
.dp-cat__in { max-width: var(--dp-maxw); margin-inline: auto; padding-inline: var(--dp-gutter); }
.dp-cat__head { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; margin-bottom: 12px; }
.dp-cat__h a { color: inherit; text-decoration: none; transition: color .18s; }
.dp-cat__h a:hover { color: var(--dpx-fg-blue, var(--dp-blue)); }
.dp-cat__all { font-size: var(--dp-fs-base); font-weight: var(--dp-fw-semi); color: var(--dpx-fg-blue, var(--dp-blue)); text-decoration: none; white-space: nowrap; }
.dp-cat__all:hover { text-decoration: underline; }

.dp-cat__chips {
  display: flex; align-items: center; gap: 8px;
  margin: 0 calc(var(--dp-gutter) * -1) 24px;
  padding: 8px var(--dp-gutter);
  overflow-x: auto; scrollbar-width: none;
}
.dp-cat__chips::-webkit-scrollbar { display: none; }
.dp-cat__chip {
  flex: none;
  height: 40px; padding: 0 20px;
  border: 1px solid var(--dp-pc-line); border-radius: var(--dp-r-pill);
  background: var(--dp-cat-pill);
  -webkit-backdrop-filter: blur(20px) saturate(1.6);
          backdrop-filter: blur(20px) saturate(1.6);
  font: inherit; font-size: var(--dp-fs-base); font-weight: var(--dp-fw-semi);
  color: var(--dp-ink);
  cursor: pointer;
  transition: background-color .2s, color .2s, border-color .2s;
}
@media (hover: hover) { .dp-cat__chip:not(.is-active):hover { border-color: var(--dp-pc-line-hover); } }
.dp-cat__chip.is-active { border-color: transparent; background: var(--dp-cat-pill-on); color: var(--dp-cat-pill-on-fg); }
.dp-cat__chip:focus-visible { outline: 2px solid var(--dpx-fg-blue, var(--dp-blue)); outline-offset: 2px; }

.dp-cat__grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 24px; }
@media (max-width: 1023px) { .dp-cat__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 767px)  { .dp-cat__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; } }

.dp-cat__empty { padding: 40px 0; text-align: center; font-size: var(--dp-fs-base); font-weight: var(--dp-fw-semi); }
.dp-cat__moreWrap { display: flex; justify-content: center; margin-top: 20px; }
.dp-cat__more {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 4px; border: 0; background: none;
  font: inherit; font-size: var(--dp-fs-base); font-weight: var(--dp-fw-semi);
  color: var(--dp-ink); cursor: pointer;
  transition: color .18s;
}
.dp-cat__more[hidden] { display: none; }
.dp-cat__more:hover { color: var(--dpx-fg-blue, var(--dp-blue)); }
.dp-cat__more svg { width: 20px; height: 20px; transition: transform .2s; }
.dp-cat__more[aria-expanded="true"] svg { transform: rotate(180deg); }
.dp-cat__more:focus-visible { outline: 2px solid var(--dpx-fg-blue, var(--dp-blue)); outline-offset: 2px; border-radius: 6px; }

/* --- Shop grid --------------------------------------------------------------- */
.dp-shop__grid--pc { gap: 24px; }
@media (max-width: 809px) {
  /* Three-up on phones: ~110px cards at 390, so the datasheet compacts another
     step. Scoped to the shop grid; reel cards keep their fixed width. */
  .dp-shop__grid--pc { gap: 8px; }
  /* Narrow cards: "COA VERIFIED" truncated, so the strip carries the short
     action label instead; the whole strip stays the link. */
  .dp-shop__grid--pc .dp-pc__coa { gap: 4px; padding: 5px 8px; font-size: 9px; }
  .dp-shop__grid--pc .dp-pc__check { width: 11px; height: 11px; }
  .dp-shop__grid--pc .dp-pc__coaTxt { display: none; }
  .dp-shop__grid--pc .dp-pc__coaGo { margin-right: auto; letter-spacing: .02em; }
  .dp-shop__grid--pc .dp-pc__body { padding: 8px 9px 10px; }
  .dp-shop__grid--pc .dp-pc__name { font-size: 12.5px; }
  .dp-shop__grid--pc .dp-pc__cas { font-size: 9px; letter-spacing: 0; }
  .dp-shop__grid--pc .dp-pc__chip { padding: 2px 5px; font-size: 8.5px; }
  .dp-shop__grid--pc .dp-pc__from { font-size: 8px; }
  .dp-shop__grid--pc .dp-pc__amt { font-size: 13px; }
  .dp-shop__grid--pc .dp-pc__add { width: 24px; height: 24px; border-radius: 7px; }
}

/* --- Reel variant ----------------------------------------------------------
   The PDP "Related compounds" ticker reuses this card compacted (markup from
   build_catalog.py's reel_card). Differences from the grid card: the COA strip
   is a plain badge (a <span>, no "View COA" affordance, no viewer), there is
   no CAS line, and the card rides the reel at a fixed narrow width. */
.dp-pc span.dp-pc__coa {
  display: flex; align-items: center; justify-content: flex-start; gap: 5px;
  padding: 7px 12px;
  border-bottom: 1px solid var(--dp-pc-line);
  background: var(--dp-pc-strip);
  font-size: 12px; line-height: 1.3;
  white-space: nowrap;
  color: var(--dp-pc-strip-fg);
}
.dp-pc span.dp-pc__coa .dp-pc__coaTxt { margin-right: 0; }

.dp-reel .dp-pc {
  flex: 0 0 var(--dp-reel-card);
  width: var(--dp-reel-card);
}
/* Narrower cards than the old rail, so more of the ticker shows at once. */
.dp-rail--related .dp-reel { --dp-reel-card: 236px; }
.dp-pc--reel .dp-pc__body { padding: 12px 14px 14px; }
.dp-pc--reel .dp-pc__chips { padding: 7px 0 11px; }
/* While the strip is being dragged nothing under the pointer should react. */
.dp-reel.is-dragging .dp-pc__add,
.dp-reel.is-dragging .dp-pc a { pointer-events: none; }

/* ============================================================================
   Compact spec-sheet restyle (2026-10): the card reads like a lab datasheet —
   tighter spacing, squarer corners, monospaced identifiers (CAS, strengths,
   price), micro-label "FROM", hairline chips. Markup untouched; these override
   the softer retail look above.
   ============================================================================ */
.dp-pc {
  --dp-pc-mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
  border-radius: 10px;
}
.dp-pc__shot { aspect-ratio: 1 / 0.82; }
.dp-pc a.dp-pc__coa,
.dp-pc a.dp-pc__coa.dp-coa__lot,
.dp-pc span.dp-pc__coa {
  padding: 6px 12px;
  font-family: var(--dp-pc-mono);
  font-size: 10.5px; letter-spacing: .04em; text-transform: uppercase;
}
.dp-pc__check { width: 13px; height: 13px; }
.dp-pc__body { padding: 12px 14px 13px; }
.dp-pc__name { font-size: 14.5px; letter-spacing: 0; }
.dp-pc__cas {
  margin-top: 4px;
  font-family: var(--dp-pc-mono);
  font-size: 10.5px; letter-spacing: .05em; text-transform: uppercase;
}
.dp-pc__chips { gap: 5px; padding: 7px 0 11px; }
.dp-pc__chip {
  padding: 2px 7px;
  border-radius: 4px;
  background: transparent;
  font-family: var(--dp-pc-mono);
  font-size: 10px; font-weight: var(--dp-fw-medium); letter-spacing: .03em;
}
.dp-pc__from {
  margin-bottom: 3px;
  font-family: var(--dp-pc-mono);
  font-size: 9.5px; letter-spacing: .08em; text-transform: uppercase;
}
.dp-pc__amt { font-family: var(--dp-pc-mono); font-size: 16px; letter-spacing: -.02em; }
.dp-pc__add { width: 26px; height: 26px; border-radius: 8px; }
.dp-pc__stock { font-family: var(--dp-pc-mono); font-size: 9.5px; letter-spacing: .06em; text-transform: uppercase; }
.dp-pc--reel .dp-pc__body { padding: 11px 13px 12px; }

/* --- Floating cart bar (shop page; element built by shop.js) ----------------
   Same glass panel and spring entrance as the PDP's sticky buy bar, scaled to
   one row: what the cart holds on the left, the way in on the right. */
.dp-shopbar {
  position: fixed; left: 0; right: 0; bottom: 11px;
  z-index: 120;                     /* above the page, below the drawer (1000) */
  padding-inline: var(--dp-gutter);
  pointer-events: none;
}
.dp-shopbar__in {
  display: flex; align-items: center; gap: var(--dp-s-7);
  width: 100%; max-width: 560px; margin-inline: auto;
  padding: 12px 12px 12px 20px;
  border-radius: var(--dp-r-xs);
  background: var(--dpx-bg-a250250250p7, rgba(250, 250, 250, .7));
  -webkit-backdrop-filter: blur(10px);
          backdrop-filter: blur(10px);
  box-shadow: 0 0 0 1px var(--dpx-shadow-a414676p06, rgba(46, 36, 30, .06)),
              0 18px 50px -20px var(--dpx-shadow-a172248p6, rgba(45, 28, 20, .45));
  pointer-events: auto;
  visibility: hidden;
  opacity: 0;
  transform: translateY(72px) scale(.9);
  transition: transform .4s cubic-bezier(.22, 1.2, .36, 1), opacity .3s ease, visibility .4s;
  will-change: transform;
}
.dp-shopbar.is-live .dp-shopbar__in { visibility: visible; opacity: 1; transform: none; }
.dp-shopbar__txt { flex: 1 1 auto; min-width: 0; display: grid; gap: 1px; }
.dp-shopbar__n   { font-size: 15px; font-weight: var(--dp-fw-semi); color: var(--dp-ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dp-shopbar__sub { font-size: 12.5px; color: var(--dp-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dp-shopbar__btn {
  flex: 0 0 auto; display: inline-flex; align-items: center;
  height: 42px; padding: 0 22px;
  border-radius: var(--dp-r-pill);
  background: var(--dpx-bg-017eff, var(--dp-blue)); color: var(--dpx-fg-fff, #fff);
  font-size: 14px; font-weight: var(--dp-fw-semi); text-decoration: none;
}
.dp-shopbar__btn:hover { filter: brightness(1.06); }
@media (prefers-reduced-motion: reduce) { .dp-shopbar__in { transition: none; } }
