/* ===========================================================================
   SHOP

   Catalogue-driven pages (merch grid, product, cart, checkout, payment).
   Loaded only on /shop* routes - see head.ejs.

   Product cards speak the site's "ignition gate" card language (site.css
   §11.22): the heat keyline across the top, the skewed licence-plate chip,
   the corner bruise, lift + red glow when armed. Direction from Rick,
   2026-08-05: match the Festival Hub cards, with the product image starting
   BELOW the keyline (its 3px matches the gate cards' own ribbon exactly).

   House rules that apply here:
   - No hard-coded design values beyond the 3px keyline the gate cards
     themselves established. Everything else comes from tokens.css.
   - Nothing hides itself waiting for JavaScript. The .is-entering /
     .is-flying states are only ever ADDED by shop.js mid-interaction, never
     present in initial HTML, so a script failure cannot blank the storefront.
   - transform / opacity only; nothing here animates layout.
   =========================================================================== */

/* ---- shared -------------------------------------------------------------- */

/* Vertical rhythm tightened 5 Aug 2026 (Rick: "compress the wasted vertical
   space in the title and sorting / searching bar"). The storefront's job is to
   get product on screen - the title block was spending most of a fold before
   the first row of merch appeared. Top padding 12 -> 8, bottom 6 -> 3, and the
   lede sits closer to the title. */
.shop-hero {
  padding-block: var(--space-8) var(--space-3);
  background: var(--surface-1);
}
.shop-hero__title {
  font-family: var(--font-display);
  font-size: var(--text-display-3);
  color: var(--ink-1);
  margin: 0 0 var(--space-1);
}
.shop-hero__lede {
  font-size: var(--text-body-lg);
  color: var(--ink-2);
  max-width: var(--prose-max);
  margin: 0;
}

.shop-empty {
  padding-block: var(--space-12);
  font-size: var(--text-body-lg);
  color: var(--ink-2);
}

.shop-crumb {
  padding-block: var(--space-6);
  font-size: var(--text-body);
}
.shop-crumb a { color: var(--ink-2); text-decoration: none; }
.shop-crumb a:hover { color: var(--ink-1); }

/* ---- toolbar (thin filter + live search) --------------------------------- */
/* The heat seam underlines it - same device as the footer's separating edge,
   so the toolbar reads as part of the site's furniture, not a bolt-on. */

.shop-toolbar {
  background:
    var(--seam-heat) bottom / 100% 1px no-repeat,
    var(--surface-1);
  /* 3/4 -> 2/2, part of the same vertical compression as .shop-hero above. */
  padding-block: var(--space-2);
}

/* TWO COLUMNS ON DESKTOP: search 1/3 left, filters 2/3 right (Rick, 5 Aug).
   Grid rather than flex because the ask is explicit COLUMN PROPORTIONS - flex
   would size the tracks from their content and the split would drift as tags
   are added or renamed. `start` on the tag track keeps the chips left-aligned
   inside their two-thirds instead of stretching across it. */
.shop-toolbar__row {
  display: grid;
  grid-template-columns: 1fr;
  align-items: center;
  gap: var(--space-2) var(--space-6);
}
@media (min-width: 60rem) {
  .shop-toolbar__row { grid-template-columns: 1fr 2fr; }
}
.shop-toolbar__tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  justify-content: start;
}

/* Chips borrow the plate chip at interactive scale: skewed frame, ochre at
   rest, armed red when active - one accent colour per element (§C).

   SCALED TO 80% - text AND box - 5 Aug 2026 (Rick: "reduce the font size and
   overall size of those filter chip by 20%"). Done as a calc off the SAME
   tokens rather than new hard-coded px, so the chips still track
   --text-small / --space-* if those ever move (hard rule 6). The factor is
   declared ONCE and applied to every dimension, so the chip shrinks
   proportionally instead of the text shrinking inside a full-size box.
   letter-spacing needs no factor - --tracking-plate is in `em`, so it
   follows the font size down on its own. */
.shop-chip {
  --chip-scale: 0.8;
  display: inline-block;
  padding: calc(var(--space-1) * var(--chip-scale))
           calc(var(--space-3) * var(--chip-scale));
  border: 1px solid var(--border-strong);
  border-radius: calc(var(--radius-sm) * var(--chip-scale));
  transform: skewX(var(--skew-emphasis));
  font-family: var(--font-body);
  font-weight: 800;
  font-size: calc(var(--text-small) * var(--chip-scale));
  letter-spacing: var(--tracking-plate);
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink-2);
  transition: color var(--duration-fast) var(--ease-throttle),
              border-color var(--duration-fast) var(--ease-throttle),
              background-color var(--duration-fast) var(--ease-throttle);
}
.shop-chip:hover { color: var(--color-ochre-300); border-color: var(--color-ochre-500); }
.shop-chip.is-active {
  color: var(--ink-1);
  background: var(--color-red-600);
  border-color: var(--color-red-600);
}
.shop-chip--sale:not(.is-active) { color: var(--color-red-300); border-color: var(--color-red-500); }
.shop-chip:focus-visible { outline: 2px solid var(--color-ochre-500); outline-offset: 2px; }

/* The grid owns the width now, so the old `margin-inline-start: auto` (which
   shoved search to the far RIGHT) and the flex-basis/max-width that fought it
   are all gone - they would pull against the 1fr track. */
.shop-toolbar__search {
  display: flex;
  gap: var(--space-2);
  min-width: 0;
}
.shop-toolbar__search input {
  flex: 1;
  min-width: 0;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--ink-1);
  font: inherit;
}
.shop-toolbar__search input:focus-visible { outline: 2px solid var(--color-ochre-500); outline-offset: 1px; }
.shop-toolbar__go {
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: none;
  color: var(--ink-2);
  font: inherit;
  cursor: pointer;
}
.shop-count {
  color: var(--ink-3);
  font-size: var(--text-small);
  margin: 0 0 var(--space-4);
}

/* ---- grid ---------------------------------------------------------------- */

/* Top 6 -> 4: last of the vertical compression, so the first row of product
   sits closer to the toolbar. Bottom padding is untouched. */
.shop-grid-section { padding-block: var(--space-4) var(--space-24); }

.shop-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--gutter);
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
}
@media (max-width: 26rem) {
  /* one comfortable column instead of two cramped ones on small phones */
  .shop-grid { grid-template-columns: 1fr; }
}

/* ---- product card: the ignition gate, product edition -------------------- */

.shop-card {
  position: relative;
  background:
    radial-gradient(120% 90% at 88% -12%, var(--fx-glow-red-soft), transparent 62%),
    var(--surface-card);
  border-radius: var(--radius-md);
  overflow: hidden;
  box-shadow: var(--shadow-1);
  transition: transform var(--duration-fast) var(--ease-throttle),
              box-shadow var(--duration-fast) var(--ease-throttle),
              opacity var(--duration-base) var(--ease-drift);
}
/* The heat keyline. 3px, matching the gate cards' ribbon exactly; the media
   below starts under it (margin on __media), per the direction. */
.shop-card::before {
  content: '';
  position: absolute;
  inset-inline: 0;
  top: 0;
  height: 3px;
  z-index: 1;
  background: linear-gradient(90deg, var(--color-red-500), var(--color-ochre-500) 72%, transparent);
  opacity: 0.5;
  transition: opacity var(--duration-fast) var(--ease-throttle),
              box-shadow var(--duration-fast) var(--ease-throttle);
}
.shop-card:hover,
.shop-card:focus-within {
  transform: translateY(calc(var(--space-1) * -1));
  box-shadow: var(--shadow-3), var(--glow-red);
}
.shop-card:hover::before,
.shop-card:focus-within::before {
  opacity: 1;
  box-shadow: var(--glow-red);
}
.shop-card:active { transition-timing-function: var(--ease-brake); }

.shop-card__link {
  display: flex;
  flex-direction: column;
  height: 100%;
  text-decoration: none;
  color: inherit;
}
.shop-card__media {
  position: relative;
  display: block;
  margin-block-start: 3px; /* image starts under the keyline, never behind it */
  aspect-ratio: 1;
  background: var(--surface-2);
  overflow: hidden;
}
.shop-card__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  transition: transform var(--duration-base) var(--ease-throttle);
}
.shop-card:hover .shop-card__media img,
.shop-card:focus-within .shop-card__media img { transform: scale(1.04); }
.shop-card__noimg { display: block; width: 100%; height: 100%; }

.shop-card__flag {
  position: absolute;
  inset-block-start: var(--space-2);
  inset-inline-start: var(--space-2);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
  background: var(--scrim-strong);
  color: var(--ink-1);
  font-size: var(--text-small);
  font-weight: 800;
  letter-spacing: var(--tracking-plate);
  text-transform: uppercase;
}

.shop-card__body {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-5) var(--space-5);
  flex: 1; /* fill under the square image so the price can pin to the foot */
}
/* Same baseline principle as the hub cards (site.css §11.15): content is
   top-anchored and the PRICE pins to the card's foot, so a row of cards
   shares one price baseline whether a name runs one line or three. */
.shop-card__price { margin-block-start: auto; }

/* The plate chip, carrying the product's type (or SALE) instead of a gate
   number - same skewed frame, same rest/armed colours as §11.22. */
.shop-card__chip {
  display: inline-block;
  font-family: var(--font-body);
  font-weight: 800;
  font-size: var(--text-small);
  letter-spacing: var(--tracking-plate);
  color: var(--color-ochre-300);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  padding: calc(var(--space-1) / 2) var(--space-2);
  transform: skewX(var(--skew-emphasis));
  transition: color var(--duration-fast) var(--ease-throttle),
              border-color var(--duration-fast) var(--ease-throttle);
}
.shop-card:hover .shop-card__chip,
.shop-card:focus-within .shop-card__chip {
  color: var(--color-red-300);
  border-color: var(--color-red-500);
}
/* one accent per card: the sale chip is ALREADY red at rest, so hover adds
   nothing further to it */
.shop-card__chip--sale { color: var(--color-red-300); border-color: var(--color-red-500); }

.shop-card__name {
  color: var(--ink-1);
  font-weight: 600;
  transition: color var(--duration-fast) var(--ease-throttle);
}
.shop-card:hover .shop-card__name,
.shop-card:focus-within .shop-card__name { color: var(--color-red-300); }
.shop-card__price { color: var(--ink-2); }
.shop-card__was { color: var(--ink-3); margin-inline-end: var(--space-1); }

/* Sold out is dimmed, never hidden - people need to see we stocked their size */
.shop-card.is-sold-out .shop-card__media img { opacity: 0.45; }
.shop-card.is-sold-out:hover { box-shadow: var(--shadow-2); }

/* FLIP states - added by shop.js only, mid-interaction (see header note).
   .is-flying releases a card from its inverted position to its new home;
   .is-entering is the from-state for cards returning to the results. */
.shop-card.is-flying {
  transition: transform var(--duration-base) var(--ease-drift),
              box-shadow var(--duration-fast) var(--ease-throttle),
              opacity var(--duration-base) var(--ease-drift);
}
html.js-ready .shop-card.is-entering {
  opacity: 0;
  transform: scale(0.96);
}
@media (prefers-reduced-motion: reduce) {
  .shop-card, .shop-card__media img, .shop-card.is-flying { transition: none; }
  html.js-ready .shop-card.is-entering { opacity: 1; transform: none; }
}

/* ---- product detail ------------------------------------------------------ */

.shop-detail { padding-block: var(--space-6) var(--space-24); }
.shop-detail__grid {
  display: grid;
  gap: var(--space-12);
  grid-template-columns: 1fr;
}
@media (min-width: 48rem) {
  .shop-detail__grid { grid-template-columns: 1fr 1fr; align-items: start; }
}

.shop-detail__media img {
  width: 100%;
  height: auto;
  border-radius: var(--radius-md);
  background: var(--surface-2);
}
.shop-detail__thumbs {
  list-style: none;
  margin: var(--space-3) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-2);
}
.shop-detail__thumbs img { width: 100%; height: auto; border-radius: var(--radius-sm); }

.shop-detail__title {
  font-family: var(--font-display);
  font-size: var(--text-display-3);
  color: var(--ink-1);
  margin: 0 0 var(--space-3);
}
.shop-detail__price {
  font-size: var(--text-h4);
  color: var(--ink-1);
  margin: 0 0 var(--space-6);
}
.shop-detail__price s { color: var(--ink-3); margin-inline-end: var(--space-2); }
.shop-detail__blurb,
.shop-detail__desc {
  color: var(--ink-2);
  max-width: var(--prose-max);
}
.shop-detail__desc { margin-block-start: var(--space-8); }
.shop-detail__soldout {
  font-size: var(--text-h4);
  color: var(--ink-3);
}

/* ---- buy form ------------------------------------------------------------ */

.shop-buy { display: flex; flex-direction: column; gap: var(--space-5); }

.shop-buy__sizes { border: 0; margin: 0; padding: 0; }
.shop-buy__sizes legend {
  padding: 0 0 var(--space-2);
  color: var(--ink-2);
}
.shop-buy__size { display: inline-block; margin: 0 var(--space-2) var(--space-2) 0; }
/* The radio itself is the focus target; the label is the visible control.
   sr-only-style hiding rather than display:none so it stays keyboard
   reachable. */
.shop-buy__size input {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
}
.shop-buy__size label {
  display: inline-block;
  min-width: var(--target-min);
  text-align: center;
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  color: var(--ink-1);
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-throttle),
              border-color var(--duration-fast) var(--ease-throttle);
}
.shop-buy__size input:checked + label {
  background: var(--color-red-600);
  border-color: var(--color-red-600);
}
.shop-buy__size input:focus-visible + label {
  outline: 2px solid var(--color-ochre-500);
  outline-offset: 2px;
}
.shop-buy__size input:disabled + label {
  color: var(--ink-3);
  border-color: var(--border-subtle);
  cursor: not-allowed;
  text-decoration: line-through;
}

.shop-buy__qty { display: flex; flex-direction: column; gap: var(--space-1); max-width: 8rem; }
.shop-buy__qty span { color: var(--ink-2); }

.shop-buy__submit,
.shop-cart__checkout,
.shop-checkout__submit,
.shop-pay__submit {
  display: inline-block;
  padding: var(--space-3) var(--space-8);
  border: 0;
  border-radius: var(--radius-sm);
  background: var(--gradient-red);
  color: var(--ink-1);
  font-family: var(--font-display);
  font-size: var(--text-body-lg);
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: transform var(--duration-fast) var(--ease-throttle),
              box-shadow var(--duration-fast) var(--ease-throttle);
}
.shop-buy__submit:hover,
.shop-cart__checkout:hover,
.shop-checkout__submit:hover,
.shop-pay__submit:hover { transform: translateY(-2px); box-shadow: var(--glow-red); }

/* ---- cart ---------------------------------------------------------------- */

.shop-cart, .shop-checkout, .shop-pay, .shop-thanks {
  padding-block: var(--space-16) var(--space-24);
}
.shop-cart__title, .shop-checkout__title, .shop-pay__title, .shop-thanks__title {
  font-family: var(--font-display);
  font-size: var(--text-display-3);
  color: var(--ink-1);
  margin: 0 0 var(--space-8);
}

.shop-cart__list { list-style: none; margin: 0; padding: 0; }
.shop-cart__row {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--space-4);
  align-items: center;
  padding-block: var(--space-4);
  border-block-end: 1px solid var(--border-subtle);
}
@media (min-width: 40rem) {
  .shop-cart__row { grid-template-columns: 6rem 1fr auto auto; }
}
.shop-cart__media img { border-radius: var(--radius-sm); display: block; }
.shop-cart__detail { display: flex; flex-direction: column; gap: var(--space-1); }
.shop-cart__name { color: var(--ink-1); text-decoration: none; }
.shop-cart__name:hover { color: var(--color-red-300); }
.shop-cart__opts { color: var(--ink-3); }
.shop-cart__warn { color: var(--color-error-500); }
.shop-cart__qty { display: flex; gap: var(--space-2); align-items: center; }
.shop-cart__qty input { width: 4.5rem; }
.shop-cart__qty button {
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: none;
  color: var(--ink-2);
  font: inherit;
  cursor: pointer;
}
.shop-cart__qty button:hover { color: var(--ink-1); border-color: var(--ink-3); }
.shop-cart__price { color: var(--ink-1); }
.shop-cart__row.is-sold-out { opacity: 0.6; }

.shop-cart__foot {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
  padding-block-start: var(--space-8);
}
.shop-cart__total { font-size: var(--text-h4); color: var(--ink-1); margin: 0; }
.shop-cart__total span { color: var(--ink-2); margin-inline-end: var(--space-3); }
.shop-cart__note, .shop-checkout__note { color: var(--ink-3); margin: 0; }
.shop-cart__continue { color: var(--ink-2); }

/* ---- checkout ------------------------------------------------------------ */

.shop-checkout__grid { display: grid; gap: var(--space-12); grid-template-columns: 1fr; }
@media (min-width: 56rem) {
  .shop-checkout__grid { grid-template-columns: 1.4fr 1fr; align-items: start; }
}

.shop-field { display: flex; flex-direction: column; gap: var(--space-1); margin-block-end: var(--space-5); }
.shop-field > span { color: var(--ink-2); }
.shop-field em { color: var(--ink-3); font-style: normal; }
.shop-field small { color: var(--ink-3); }
.shop-field-row { display: grid; gap: var(--space-4); grid-template-columns: 1fr; }
@media (min-width: 40rem) { .shop-field-row { grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); } }

.shop-field input, .shop-field select, .shop-cart__qty input, .shop-buy__qty input {
  padding: var(--space-3);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--ink-1);
  font: inherit;
}
.shop-field input:focus-visible,
.shop-field select:focus-visible,
.shop-cart__qty input:focus-visible,
.shop-buy__qty input:focus-visible {
  outline: 2px solid var(--color-ochre-500);
  outline-offset: 1px;
}

.shop-errors {
  border: 1px solid var(--color-error-500);
  border-radius: var(--radius-sm);
  padding: var(--space-4);
  margin-block-end: var(--space-6);
  color: var(--ink-1);
}
.shop-errors ul { margin: var(--space-2) 0 0; padding-inline-start: var(--space-5); }

.shop-checkout__summary {
  background:
    radial-gradient(120% 90% at 88% -12%, var(--fx-glow-red-soft), transparent 62%),
    var(--surface-1);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  padding: var(--space-6);
}
.shop-checkout__summary h2 { margin: 0 0 var(--space-4); font-size: var(--text-h4); color: var(--ink-1); }
.shop-checkout__summary ul { list-style: none; margin: 0; padding: 0; }
.shop-checkout__summary li {
  display: flex; justify-content: space-between; gap: var(--space-4);
  padding-block: var(--space-2);
  border-block-end: 1px solid var(--border-subtle);
  color: var(--ink-2);
}
.shop-checkout__summary em { color: var(--ink-3); font-style: normal; }
.shop-checkout__total {
  display: flex; justify-content: space-between;
  padding-block-start: var(--space-4);
  font-size: var(--text-h4); color: var(--ink-1);
}

/* ---- payment / thanks ---------------------------------------------------- */

.shop-pay__ref, .shop-thanks__ref { font-size: var(--text-body-lg); color: var(--ink-2); }
.shop-pay__pending {
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  padding: var(--space-6);
  max-width: var(--prose-max);
  color: var(--ink-2);
}
.shop-pay__pending strong { color: var(--ink-1); }
.shop-pay__secure { color: var(--ink-3); margin-block-start: var(--space-3); }

.shop-thanks__list { list-style: none; margin: var(--space-6) 0; padding: 0; color: var(--ink-2); }
.shop-thanks__list li { padding-block: var(--space-2); border-block-end: 1px solid var(--border-subtle); }
.shop-thanks__list em { color: var(--ink-3); font-style: normal; }
.shop-thanks__total { font-size: var(--text-h4); color: var(--ink-1); }
.shop-thanks__total span { color: var(--ink-2); margin-inline-end: var(--space-3); }
.shop-thanks__ship { color: var(--ink-2); }
