/* ===========================================================================
   VAULT  —  the catalogue grid
   ---------------------------------------------------------------------------
   THE SHOP IS A GRID OF PRODUCT CARDS NOW, generated from PRODUCTS in
   build.py. This file styles one card and the grid it sits in, and it has to
   hold up at any count: one card, four, or eleven. So there is no rule here
   that assumes a particular number, and nothing is positioned by nth-child
   except the featured span, which is opt-in from the data.

   THREE STATES, AND THEY MUST LOOK DIFFERENT AT A GLANCE.

     .pcard-live   for sale. Gold price, gold hairline on hover, art.
     .pcard-free   free and open. GREEN price - a second accent used for exactly
                one thing, which keeps gold meaning "this costs money".
     .pcard-soon   not built yet. No art, no button, no colour. It is deliberately
                the quietest card on the page: it is there to say the shop is
                not finished, not to compete with the things that are.

   A 'soon' card must never look buyable. That is the whole reason it earns a
   place here rather than being left off - a shop with two products reads as
   abandoned, and a shop with two products and three honest "in the workshop"
   cards reads as a studio mid-stride.
   =========================================================================== */

/* ------------------------------------------------------------- the grid -- */
/* auto-fit rather than a fixed column count, so adding a product to the
   registry never needs a media query written for it. 300px is the width below
   which the art stops reading and the blurb starts to ladder. */
.pgrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: var(--s3);
  align-items: stretch;
}

/* THE FEATURED CARD TAKES TWO TRACKS, but only where there are two to take.
   `grid-column: span 2` on a one-column grid silently creates a phantom second
   column and every other card then sits in half the width - so it is guarded
   on the container width, not on the card. */
@media (min-width: 720px) {
  .pgrid > [data-featured] { grid-column: span 2; }
  .pgrid > [data-featured] .pcard-art { aspect-ratio: 21 / 8; }
  .pgrid > [data-featured] h3 { font-size: clamp(1.5rem, 2.4vw, 2rem); }
}

/* A three-across row with a two-wide feature leaves one orphan. Below the
   point where three fit, the feature stops being special and the row is even.
   Nothing here breaks if it is ignored; it just looks composed rather than
   left over. */
@media (min-width: 720px) and (max-width: 1040px) {
  .pgrid { grid-template-columns: repeat(2, 1fr); }
}

/* -------------------------------------------------------------- the card -- */
.pcard {
  position: relative;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  padding: 0;                       /* the art is flush; .pcard-body pads itself */
  text-decoration: none;
  color: inherit;
  isolation: isolate;
}

/* The hairline that lights on hover. A pseudo-element rather than a border so
   it can be a gradient, and so it cannot shift the layout by one pixel the way
   a border appearing on hover does. */
.pcard::after {
  content: '';
  position: absolute; inset: 0;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(160deg, rgba(255,255,255,.14), transparent 42%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  opacity: .9;
  transition: background .35s var(--ease), opacity .35s var(--ease);
  pointer-events: none;
  z-index: 3;
}
a.pcard-live:hover::after {
  background: linear-gradient(160deg, rgba(224,168,60,.75), rgba(224,168,60,.08) 46%, transparent 70%);
}
a.pcard-free:hover::after {
  background: linear-gradient(160deg, rgba(69,192,122,.7), rgba(69,192,122,.08) 46%, transparent 70%);
}

/* --------------------------------------------------------------- the art -- */
.pcard-art {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--bg-sink);
}
.pcard-art img {
  width: 100%; height: 100%;
  object-fit: cover;
  /* Graded into the page rather than dropped on it, the same treatment the
     old single feature card used. Full-colour renders on a dark card read as
     stickers; this reads as art direction. */
  filter: saturate(1.05) contrast(1.04) brightness(.82);
  transition: transform 1.1s var(--ease), filter .5s var(--ease);
}
a.pcard:hover .pcard-art img { transform: scale(1.05); filter: saturate(1.12) contrast(1.06) brightness(.92); }

/* Fade the art into the card so there is no hard seam where it ends. */
.pcard-art::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(180deg, transparent 38%, rgba(19,21,25,.55) 78%, var(--surf) 100%);
}

/* THE PLATE FOR A PRODUCT WITH NO ART. Drawn, not photographic, and obviously
   a placeholder rather than a screenshot of something else. */
.pcard-art-blank {
  display: grid;
  place-items: center;
  background:
    radial-gradient(120% 90% at 50% 120%, rgba(255,255,255,.05), transparent 70%),
    var(--bg-sink);
}
.pcard-art-blank::before {
  /* the same 24px dot field the page texture uses, so the empty plate belongs
     to this site rather than looking like a missing image */
  content: '';
  position: absolute; inset: 0;
  background-image: radial-gradient(rgba(255,255,255,.075) 1px, transparent 1px);
  background-size: 24px 24px;
  mask-image: radial-gradient(70% 70% at 50% 50%, #000, transparent 78%);
}
.pcard-mark {
  position: relative;
  width: 46px; height: 46px;
  fill: var(--tx-4);
}

/* -------------------------------------------------------------- the body -- */
.pcard-body {
  display: flex;
  flex-direction: column;
  gap: var(--s2);
  padding: var(--s4);
  flex: 1;
}

/* The tag row. Tags ONLY - the status chip lives on the artwork, because the
   two of them sharing this line is what made every card wrap. */
.pcard-top { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s1); }

/* ------------------------------------------------------- the status chip -- */
/* Top-left of the plate, over the image. It needs its own background rather
   than borrowing the card's, because it sits on a photograph whose brightness
   is not ours to predict - hence the solid dark plate and the blur-free,
   fully-opaque backing. */
.pcard-status {
  position: absolute;
  top: var(--s2);
  left: var(--s2);
  z-index: 2;
  font-size: .66rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  padding: .34em .72em;
  border-radius: var(--rp);
  background: rgba(8, 9, 11, .82);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .09);
  /* the plate fades to the card colour at its foot; the chip must not */
  text-shadow: 0 1px 2px rgba(0, 0, 0, .6);
}
.pcard-live .pcard-status { color: var(--gold-lit); }
.pcard-free .pcard-status { color: #6fd79b; }
.pcard-soon .pcard-status { color: var(--tx-3); }

.pcard h3 {
  font-size: clamp(1.2rem, 1.7vw, 1.45rem);
  line-height: 1.15;
  color: var(--tx);
  letter-spacing: -.015em;
}
.pcard p { color: var(--tx-2); font-size: .95rem; }

.pcard .pills { margin: 0; }
.pcard .ticks { margin-top: auto; padding-top: var(--s2); }
.pcard .ticks li { font-size: .88rem; }

/* -------------------------------------------------------------- the foot -- */
.pcard-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s2);
  padding: var(--s3) var(--s4) var(--s4);
  border-top: 1px solid var(--line);
  margin-top: auto;
}

.pcard-price { font-size: 1.35rem; font-weight: 800; letter-spacing: -.02em; color: var(--gold); }
.pcard-is-free { color: var(--green); }
.pcard-is-soon { color: var(--tx-4); font-size: 1rem; font-weight: 600; }

/* The dash while Tebex is answering. It is NOT a skeleton bar - a shimmering
   placeholder where a price goes reads as a price that is being calculated for
   you, which on a shop is the wrong implication entirely. */
.pcard-amount.is-loading::before { content: '—'; color: var(--tx-4); }

.pcard-go {
  display: inline-flex; align-items: center; gap: .45em;
  font-size: .86rem; font-weight: 600;
  color: var(--tx-2);
  transition: color .2s var(--ease), gap .2s var(--ease);
  text-align: right;
}
.pcard-go .i { width: 1em; height: 1em; flex: none; }
a.pcard:hover .pcard-go { color: var(--tx); gap: .75em; }

/* A card with no CTA still needs its price on the same line it would have
   been, rather than stretched across the whole foot. */
.pcard-soon .pcard-foot { justify-content: flex-start; }

/* ----------------------------------------------------------- the workshop -- */
/* The 'soon' cards sit in their own band, quieter than the shop above them. */
.workshop { opacity: .92; }
.workshop .pgrid { gap: var(--s2); }

/* --------------------------------------------------------- reduced motion -- */
@media (prefers-reduced-motion: reduce) {
  .pcard-art img,
  .pcard::after,
  .pcard-go { transition: none; }
  a.pcard:hover .pcard-art img { transform: none; }
}

/* The old price, struck through, and only ever written by js/shop.js when
   Tebex reports a real discount. There is no markup for it in build.py on
   purpose: a card cannot claim a saving the checkout will not give. */
.pcard-was {
  font-size: .82rem;
  font-weight: 600;
  color: var(--tx-4);
  margin-left: .35em;
}

/* The "full catalogue" line under the home page grid. */
.catalogue-more { margin-top: var(--s4); text-align: center; }

/* --------------------------------------------------- narrow: fewer tags -- */
/* THREE TAGS STOP FITTING BEFORE THE CARD STOPS BEING USABLE.
   Below roughly 1100px the grid still gives two columns, so a card is ~360px
   and a third tag drops to a second line - one chip alone under two, which
   reads as a mistake rather than as a row.

   Hiding it is the honest trade. A tag is reinforcement, never the only place
   a fact appears: everything in these chips is also in the blurb, the tick
   list or the product page. Losing the third costs nothing; a ragged row
   costs the card its composure. */
@media (max-width: 1100px) {
  .pcard-top .pill:nth-child(n + 3) { display: none; }
}
