/* TT-SHOP-REDO-01: shop redesign CSS layer (landing + tray + catalogue).
   Source of truth: scratch/new_shop/poc-shop.html / poc-tray.html /
   poc-catalogue.html <style> blocks -- ported verbatim, values copied not
   re-derived (the lane-title cqw clamp and the ledge clip-path tuck numbers
   were hand-tuned against the POC). Pages using this file must also link
   brand-tokens.css first (shop.html already does) -- this file reuses those
   vars (--primary-color, --primary-dark, --primary-light, --accent-color,
   --accent-orange, --bg-white, --bg-polar, --border-color) rather than
   redeclaring them.

   Tokens below are the ones with NO sitewide equivalent: the three
   wood-ledge tones (shelf mechanics, tickets 03/05) and three per-lane
   icon-tint accents (no brand equivalent exists for these decorative
   circles). --shop-text-gray/--shop-border are NOT redeclared here --
   custom.css's ":root" (the pre-existing "WEBSHOP-STYLE ADDITIONS FOR
   HOMEPAGE" block) already defines both with the same values this file
   was independently using; every var(--shop-text-gray)/var(--shop-border)
   reference below resolves from that existing global instead. */
:root {
  --ledge: #f0c98f;
  --ledge-edge: #dfa95e;
  --ledge-shade: #c08b45;
  --tint-play: #ffd4e5;
  --tint-family: #fff0e0;
  --tint-else: #e2f1f1;
}

/* ============================================================
   Shared: title-face variables. Fraunces everywhere titles appear
   (hero, lane bands, tray-card titles, product names, catalogue
   shelf rows); Spectral for body text; Playwrite RO exclusively for
   the four lane band titles (loaded only on the landing).
   ============================================================ */
.shop-lanes,
.shop-tray,
.shop-catalogue {
  --f-title: 'Fraunces';
  --f-title-wght: 600;
  --f-body: 'Spectral';
  font-family: var(--f-body), serif;
}

/* TT-SHOP-REDO-06 follow-up: style.css's sitewide `.boxed-container` caps
   at 1440px -- widened for shop pages only (scoped via the body class,
   not a sitewide change) so the lane grid gets more breathing room at
   wide viewports.
   TT-SHOP-REDO-08 note: shop pages now wear the shared `.base-header`, whose
   inner caps at 1440px (site-header.css), so above 1440px viewport the header
   band is narrower than this 1680px content. That divergence is accepted --
   unifying the header across families outranks re-aligning this one edge, and
   the ticket's 1440x900 verification has them flush. If it ever matters,
   revisit widening `.base-header-inner` for shop pages rather than
   resurrecting a shop-specific header. */
.shop-lanes .boxed-container,
.shop-tray .boxed-container,
.shop-catalogue .boxed-container {
  max-width: 1680px;
}

/* ============================================================
   Landing: open lanes (poc-shop.html)
   ============================================================ */
.shop-lanes .hero {
  max-width: 1320px;
  margin: 0 auto;
  padding: 0 1.5rem 0;
  /* Bug fix (shop_UX_redo, main-shop-gap-too-wide): custom.css's sitewide
     `.hero { padding-top: var(--hero-padding-top) !important }` (3rem) wins
     over a plain (non-!important) padding-top here regardless of
     specificity, so the reduced top gap needs its own !important too. */
  padding-top: 1rem !important;
  /* TT-SHOP-REDO-06 follow-up: custom.css's sitewide `.hero { text-align:
     left !important }` (homepage hero rule) otherwise wins over this --
     matching !important is the only way to actually center the title. */
  text-align: center !important;
  /* Bug fix (shop_UX_redo): custom.css's sitewide `.hero` rule also sets
     `position: relative !important; z-index: var(--z-content) !important`
     (1000) -- the SAME z-index as `.base-header` (site-header.css). Tied
     z-index falls back to DOM order, and this hero comes AFTER the sticky
     header in the markup, so it was winning the tie and painting over the
     header's opaque background as the hero title scrolled up underneath
     it. Dropping it out of that stacking fight (position: static, so
     z-index no longer applies at all) lets the sticky header's own
     z-index:1000 do its job uncontested. */
  position: static !important;
  z-index: auto !important;
}
.shop-lanes .hero h1 {
  margin: 0; /* style.css's sitewide h1 rule adds 48px/16px margin otherwise -- POC resets it globally, we reset per-heading */
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  font-family: var(--f-title), serif;
  font-weight: var(--f-title-wght);
  font-optical-sizing: auto;
  font-size: 2.2rem;
  color: var(--primary-color);
}
.shop-lanes .hero h1 .hero-wordmark {
  /* TT-SHOP-REDO-06 follow-up: the header logo was dropped (fought over
     across two sizing rounds, never sat right in the compact nav bar) --
     the hero is the wordmark's only home on this page now, so it gets to
     be the prominent size the header couldn't give it. 2.6em scales with
     the h1's own font-size (~114px at the current 2.2rem/44px h1). */
  height: 2.6em;
  width: auto;
  display: block;
}
.shop-lanes .hero p { color: var(--shop-text-gray); font-size: 1.05rem; max-width: 620px; margin: 0.4rem auto 0; }
.shop-lanes .hero .catalogue-link { margin-top: 0.7rem; font-size: 0.95rem; color: var(--shop-text-gray); }
.shop-lanes .hero .catalogue-link a { color: var(--accent-color); font-weight: 600; }

/* one standing panel per shelf group, filled (not bordered), capped by a
   collapsible dark-green band. */
.shop-lanes .lanes {
  position: relative;
  margin: 2.5rem auto 4rem;
  /* TT-SHOP-REDO-06 follow-up: was `calc(100% - 8rem)` (64px each side) --
     narrower side margins give each lane column more width, which is what
     actually keeps the four-lane row on one viewport (wider columns wrap
     tray-card text onto fewer lines each). */
  width: calc(100% - 3rem);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(255px, 1fr));
  gap: 1.25rem;
}
.shop-lanes .lane {
  display: flex;
  flex-direction: column;
  background: var(--primary-light); /* the lane background -- deliberately NOT the page background */
  border-radius: 12px;
  padding: 0 0 1.1rem;
  overflow: hidden;
}
.shop-lanes .lane-head {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  width: 100%;
  padding: 0.55rem 1rem 0.75rem;
  border: none;
  background: var(--primary-color);
  box-shadow: inset 0 -4px 0 var(--primary-light); /* per-group tint underline, overridden below */
  font: inherit;
  text-align: left;
  cursor: pointer;
  container-type: inline-size;
}
.shop-lanes .lane.g1 .lane-head { box-shadow: inset 0 -4px 0 var(--tint-play); }
.shop-lanes .lane.g2 .lane-head { box-shadow: inset 0 -4px 0 var(--tint-family); }
.shop-lanes .lane.g3 .lane-head { box-shadow: inset 0 -4px 0 var(--tint-else); }
.shop-lanes .lane-head:hover { background: var(--primary-dark); }
.shop-lanes .lane-head h2 {
  margin: 0; /* TT-SHOP-REDO-06: sitewide h2 margin (48px/16px) was inflating the band to 115px vs the POC's 46px */
  font-family: 'Playwrite RO', cursive;
  font-weight: 400;
  font-size: clamp(0.95rem, 7cqw, 1.35rem); /* longest lane title never wraps -- do not re-derive */
  white-space: nowrap;
  color: #fff;
  flex: 1;
  line-height: 1.3;
}
.shop-lanes .lane-head .chev {
  width: 0.55rem;
  height: 0.55rem;
  border-right: 2px solid #fff;
  border-bottom: 2px solid #fff;
  transform: rotate(45deg); /* down = open */
  transition: transform 0.15s ease;
  flex: 0 0 auto;
  margin-left: 0.15rem;
}
.shop-lanes .lane.collapsed .lane-head .chev { transform: rotate(-45deg); }
.shop-lanes .lane.collapsed .lane-body { display: none; }
.shop-lanes .lane-summary { display: none; }
.shop-lanes .lane.collapsed .lane-summary { display: block; padding: 1.3rem 1rem 0.6rem; }
.shop-lanes .lane-summary .sum-count {
  display: block;
  text-align: center;
  font-family: var(--f-title), serif;
  font-weight: var(--f-title-wght);
  font-size: 1.2rem;
  color: var(--accent-orange);
}
.shop-lanes .lane-summary p { margin-top: 0.7rem; font-size: 1.02rem; color: var(--shop-text-gray); line-height: 1.65; }

/* Cards fill the lane evenly so rows align across lanes. */
.shop-lanes .lane-body { flex: 1; display: flex; flex-direction: column; gap: 1.15rem; padding: 0.85rem 0.8rem 0; }
.shop-lanes .compartment { flex: 1; display: flex; flex-direction: column; }
.shop-lanes .tray-card {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.4rem;
  width: 100%;
  min-height: 140px;
  background: var(--bg-white);
  border: 1.5px solid var(--shop-border);
  border-radius: 10px;
  padding: 1.1rem 1.1rem 1rem;
  font: inherit;
  text-align: left;
  text-decoration: none;
  color: inherit;
  cursor: pointer;
  transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.1s ease;
}
.shop-lanes .tray-card:hover,
.shop-lanes .tray-card:focus-visible {
  border-color: var(--primary-color);
  box-shadow: 0 10px 20px rgba(12, 58, 40, 0.14);
  transform: translateY(-3px);
}
.shop-lanes .tray-card .row { display: flex; align-items: center; gap: 0.5rem; width: 100%; }
.shop-lanes .tray-icon {
  font-size: 1.3rem;
  line-height: 1;
  width: 2.3rem;
  height: 2.3rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--primary-light);
  flex: 0 0 auto;
}
.shop-lanes .lane.g1 .tray-icon { background: var(--tint-play); }
.shop-lanes .lane.g2 .tray-icon { background: var(--tint-family); }
.shop-lanes .lane.g3 .tray-icon { background: var(--tint-else); }
.shop-lanes .tray-card h3 {
  margin: 0; /* TT-SHOP-REDO-06: sitewide h3 margin compounds across every card in every lane -- the single biggest contributor to the page's excess height */
  font-family: var(--f-title), serif;
  font-weight: var(--f-title-wght);
  font-optical-sizing: auto;
  font-size: 1.2rem;
  color: var(--primary-color);
  line-height: 1.25;
}
.shop-lanes .tray-card.tray-pink h3 { color: var(--accent-color); } /* Free Tray: title text only, card stays white */
.shop-lanes .tray-card p {
  font-size: 0.95rem;
  color: var(--shop-text-gray);
  line-height: 1.45;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.shop-lanes .tray-card .count {
  margin-top: auto;
  padding-top: 0.4rem;
  font-family: var(--f-title), serif;
  font-weight: var(--f-title-wght);
  font-size: 0.85rem;
  color: var(--accent-orange);
}

@media (max-width: 640px) {
  .shop-lanes .lanes { width: calc(100% - 2rem); }
}
@media (prefers-reduced-motion: reduce) {
  .shop-lanes .tray-card:hover { transform: none; }
}

/* ============================================================
   Tray detail: products on drawn shelf ledges (poc-tray.html)
   ============================================================ */
/* min-width: 0 overrides the flex-item default of min-width: auto --
   .body-wrap is a flex container, and without this override main.shelf-view
   refuses to shrink below its content's intrinsic width (the shelf-row
   grid's 4-column min-content), which silences the mobile shelf-row's own
   overflow-x:auto entirely (the whole page grows past the viewport
   instead of scrolling internally per shelf). */
/* max-width widened 1100 -> 1320 (owner 2026-07-20): the shop container
   allows 1680px and the landing hero uses 1320px, so the ledges no longer
   need to sit in a narrow column. 1320px keeps four cards roomy (~296px
   each -- buttons no longer wrap) and stays flush with the 1440px header. */
.shop-tray .shelf-view { width: 100%; max-width: 1320px; min-width: 0; margin: 0 auto; padding: 2rem 1.5rem 4rem; box-sizing: border-box; }
.shop-tray .top-links {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1.2rem;
}
.shop-tray .back-link,
.shop-tray .catalogue-link {
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--accent-color);
  text-decoration: none;
}
.shop-tray .back-link:hover,
.shop-tray .catalogue-link:hover { text-decoration: underline; }

/* Full tray blurb (shop.html truncates the same string with an ellipsis
   in the lane card -- this is where the rest of it lives). */
.shop-tray .tray-description {
  font-family: var(--f-body), serif;
  font-size: 1.05rem;
  line-height: 1.6;
  color: var(--primary-color);
  max-width: 66%;
  margin: 0 auto 1.5rem;
  text-align: center;
}

.shop-tray .filter-row {
  display: flex;
  gap: 0.75rem;
  flex-wrap: wrap;
  align-items: center;
  background: var(--bg-white);
  border: 1px solid var(--border-color);
  border-radius: 12px;
  padding: 1rem 1.2rem;
  margin: 0 0 1.5rem;
}
.shop-tray .filter-row select {
  padding: 0.55rem 0.9rem;
  border: 1px solid var(--shop-border);
  border-radius: 8px;
  background: var(--bg-white);
  font-family: inherit;
  font-size: 0.9rem;
  color: var(--text-color);
}
.shop-tray .filter-row .count { margin-left: auto; font-size: 0.85rem; color: var(--shop-text-gray); }

/* Products stand on drawn shelf ledges (the settled option-c mechanics),
   no titles on the shelves themselves. TT-SHOP-REDO-14: three to a shelf
   (was four) so each card is wider and the contain-fitted product art gets
   a legible well. The count MUST match TRAY_CARDS_PER_SHELF in shop.py --
   the Python chunker and this grid track count are one decision. */
.shop-tray .shelf-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.1rem;
  align-items: stretch;
  padding: 1.1rem 1.1rem 0;
  position: relative;
  margin-bottom: -12px; /* tray bottoms tuck 12px behind the board's front lip */
}
.shop-tray .shelf-row::before { /* shelf back surface -- visible only in the gaps */
  content: '';
  position: absolute;
  left: calc(0.2rem + 5px);
  right: calc(0.2rem + 5px);
  bottom: 11px;
  height: 8px;
  z-index: -1;
  background: linear-gradient(180deg, #f9e3ba, var(--ledge));
  clip-path: polygon(1.8% 0, 98.2% 0, 100% 100%, 0 100%);
}
.shop-tray .shelf-ledge { /* board with depth: lit top edge, shaded under-lip */
  position: relative;
  z-index: 1; /* the front lip paints over the tray bottoms */
  height: 18px;
  margin: 0 0.2rem;
  border-radius: 2px 2px 5px 5px;
  background: linear-gradient(180deg, var(--ledge) 0%, var(--ledge-edge) 65%, var(--ledge-shade) 100%);
  box-shadow:
    inset 0 2px 0 rgba(255, 244, 220, 0.55),
    inset 0 -3px 4px rgba(115, 72, 20, 0.35);
}
.shop-tray .shelf-ledge::after { /* shadow pooling under the board */
  content: '';
  position: absolute;
  left: 3%;
  right: 3%;
  bottom: -13px;
  height: 13px;
  background: radial-gradient(ellipse 50% 100% at 50% 0, rgba(115, 72, 20, 0.30), transparent 72%);
  filter: blur(2px);
  pointer-events: none;
}
.shop-tray .shelf-unit { margin-bottom: 1.6rem; }

.shop-tray .product-card {
  /* TT-SHOP-REDO-06 follow-up: was itself the `<a>` -- now a plain
     container so a quick-add form (add-to-cart / download) can sit
     alongside the link without nesting a <form>/<button> inside an <a>
     (invalid HTML, browsers silently break that). `.product-card-link`
     below carries the actual anchor + the flex column that used to live
     here.
     TT-SHOP-REDO-06 follow-up 2: `min-width`/`max-width: 340px` reset --
     a generic, unscoped `.product-card { min-width: 340px; max-width:
     340px }` rule in custom.css (written for a different, non-grid card
     layout elsewhere on the site) was leaking in here since this ruleset
     never declared its own width. A hard min-width on a grid item blocks
     `repeat(4, 1fr)` from shrinking its tracks below 340px each --
     4×340px + gaps (1426px) blew past the 1040px shelf-row box, pushing
     the 4th card off past the viewport edge (silently clipped by
     `.body-wrap`'s `overflow-x: hidden`, so no scrollbar ever appeared --
     the row just looked like it "bled off the shelf"). */
  min-width: 0;
  max-width: none;
  display: flex;
  flex-direction: column;
  background: var(--bg-white);
  border: 1.5px solid var(--shop-border);
  border-bottom-color: var(--ledge-edge);
  border-radius: 12px 12px 4px 4px;
  overflow: hidden;
  box-shadow: 0 7px 10px -3px rgba(115, 72, 20, 0.38); /* tray casting shade onto the board */
  z-index: 2; /* always in front of the board -- the "tuck" comes from the clip */
  clip-path: inset(-40px -40px 12px -40px); /* hide own bottom 12px; the board shows through */
  transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.1s ease, clip-path 0.15s ease;
}
.shop-tray .product-card:hover,
.shop-tray .product-card:focus-within {
  border-color: var(--primary-color);
  box-shadow: 0 14px 26px rgba(12, 58, 40, 0.18); /* deeper drop = tray lifted off the board */
  transform: translateY(-7px);
  clip-path: inset(-40px -40px -40px -40px); /* bottom edge emerges as it rises */
}
.shop-tray .product-card-link {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  text-decoration: none;
  color: inherit;
}
.shop-tray .product-thumb {
  /* TT-SHOP-REDO-14: taller well (was 130px) so art reads clearly in the
     now-wider card. Most product art is ~4:3/3:2 landscape (photos 4080x3072,
     covers 1200x896); a 375x230 well sits close to that ratio, so landscape
     art fills most of the width with only slim tint bars, and squares/portraits
     letterbox onto the tint instead of cropping. */
  height: 230px;
  background: var(--primary-light);
  display: grid;
  place-items: center;   /* centres the emoji-fallback <span> when there's no image */
  position: relative;    /* positioning context for the absolutely-placed <img> below */
  font-size: 2.2rem;
  overflow: hidden;
}
.shop-tray .product-thumb img {
  /* TT-SHOP-REDO-14 fix: the well is `display:grid; place-items:center`, which
     leaves the grid row auto/content-sized -- so the grid area's height reads
     as INDEFINITE and a grid-item `height:100%` (or `max-height:100%`) won't
     resolve against it. The img therefore kept its intrinsic aspect at 100%
     WIDTH, grew taller than the well, and `overflow:hidden` sliced it to a
     middle strip (the "cut off, can't tell what it is" bug -- present since the
     130px version, just less obvious). Absolutely filling the well gives the
     img a DEFINITE 375x230 box (from the relative parent), so `object-fit:
     contain` can scale the WHOLE image to fit and centre it: never cropped,
     never overflowing. */
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain; /* real product images never crop, matches the sitewide featured-image rule */
}
.shop-tray .product-card:nth-child(even) .product-thumb { background: var(--tint-family); }
.shop-tray .product-body { padding: 0.85rem 1rem 1.3rem; /* extra bottom: 12px hide behind the lip */ }
.shop-tray .product-body h3 {
  margin: 0; /* TT-SHOP-REDO-06: same missing-reset issue as the landing lanes */
  font-family: var(--f-title), serif;
  font-weight: var(--f-title-wght);
  font-optical-sizing: auto;
  font-size: 1.05rem;
  color: var(--primary-color);
  line-height: 1.3;
}
.shop-tray .product-body .variants { margin-top: 0.25rem; font-size: 0.85rem; color: var(--shop-text-gray); }
/* TT-SHOP-REDO-14: price + gating badge laid side-by-side. `1fr auto` keeps
   the price at the left and the badge hugging the right ("what it costs |
   how you get it"); when there's no badge (paid cards) the price simply
   fills the single populated cell and the CTA below stays aligned. */
.shop-tray .product-body .product-meta {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.5rem;
}
.shop-tray .product-body .price {
  margin: 0; /* meta grid owns the vertical rhythm now */
  font-family: var(--f-title), serif;
  font-weight: var(--f-title-wght);
  font-size: 0.95rem;
}
.shop-tray .product-body .price.free { color: #3e8c28; }
.shop-tray .product-body .gating-badge {
  display: inline-block;
  justify-self: end;
  margin: 0; /* aligned by the meta grid, not stacked below the price */
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  white-space: nowrap; /* one line inside its now-constrained meta column */
  padding: 0.15rem 0.5rem;
  border-radius: 999px;
  background: var(--primary-light);
  color: var(--primary-color);
}
.shop-tray .product-body .gating-badge.gated { background: #fff0e0; color: var(--accent-orange); }
.shop-tray .product-body .gating-badge.ungated { background: var(--primary-light); color: #3e8c28; }
/* TT-SHOP-REDO-14 follow-up: freemium (games -- free to play, free account for
   more) badges in the playful pink, distinct from ungated-green/gated-orange. */
.shop-tray .product-body .gating-badge.freemium { background: var(--tint-play); color: var(--accent-color); }

/* TT-SHOP-REDO-06 follow-up: single-qualifying-variant products get a
   quick-add button right on the shelf card (only case where "add to cart"
   is unambiguous without a variant picker -- multi-variant products still
   route through the card link to the product page to choose). Sits below
   `.product-card-link` as its own flex item, padding matches
   `.product-body`'s side padding. */
.shop-tray .quick-add-form { padding: 0 1rem 0.85rem; }
.shop-tray .quick-add-btn {
  width: 100%;
  border: 1.5px solid var(--primary-color);
  background: var(--bg-white);
  color: var(--primary-color);
  border-radius: 8px;
  padding: 0.5rem 0.75rem;
  font: inherit;
  font-family: var(--f-title), serif;
  font-weight: var(--f-title-wght);
  font-size: 0.88rem;
  white-space: nowrap; /* label is a short verb now ("Add to cart"); price lives on its own .price line above -- never wrap */
  box-sizing: border-box; /* the <summary> variant computes content-box otherwise, so width:100% + padding + border overran the card's right edge (overflow:hidden sliced it) */
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.shop-tray .quick-add-btn:hover,
.shop-tray .quick-add-btn:focus-visible {
  background: var(--primary-color);
  color: #fff;
}

/* TT-SHOP-REDO-14 follow-up: freemium (games) card = two stacked buttons.
   Primary "Play free" is filled (the free, no-account action we want tapped);
   the secondary offline/login button keeps the default outline style below it. */
.shop-tray .freemium-actions {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.shop-tray .quick-add-btn.freemium-primary {
  background: var(--primary-color);
  color: #fff;
}
.shop-tray .quick-add-btn.freemium-primary:hover,
.shop-tray .quick-add-btn.freemium-primary:focus-visible {
  background: var(--primary-dark);
  border-color: var(--primary-dark);
}

.shop-tray .empty { color: var(--shop-text-gray); }

/* TT-SHOP-REDO-09: upcoming ("coming soon") teaser cards. Same shelf-ledge
   chassis as a live card, but visually muted and inert -- no anchor, no
   quick-add form, so nothing here is focusable or clickable (skipped in tab
   order for free). Overrides the live card's hover lift and pointer. */
.shop-tray .upcoming-heading {
  margin: 2.4rem 0 0.4rem;
  font-family: var(--f-title), serif;
  font-weight: var(--f-title-wght);
  font-size: 0.8rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--shop-text-gray);
}
.shop-tray .product-card.coming-soon {
  cursor: default;
  box-shadow: 0 7px 10px -3px rgba(115, 72, 20, 0.20); /* lighter than a live card's */
}
.shop-tray .product-card.coming-soon .product-thumb { filter: grayscale(0.4); opacity: 0.75; }
.shop-tray .product-card.coming-soon .product-body { opacity: 0.85; }
.shop-tray .product-card.coming-soon:hover,
.shop-tray .product-card.coming-soon:focus-within {
  border-color: var(--shop-border);      /* no highlight */
  border-bottom-color: var(--ledge-edge);
  box-shadow: 0 7px 10px -3px rgba(115, 72, 20, 0.20);
  transform: none;                        /* no lift */
  clip-path: inset(-40px -40px 12px -40px);
}
/* Ported from freebies_games.html's .soon-pill (the ticket's "don't invent a
   third pill style") -- scoped under .shop-tray so it can't leak. */
.shop-tray .product-card.coming-soon .soon-pill {
  display: inline-block;
  margin-top: 0.35rem;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--bg-white);
  background: var(--accent-orange);
  border-radius: 999px;
  padding: 0.15rem 0.55rem;
}
.shop-tray .product-card.coming-soon .coming-soon-blurb {
  margin: 0.5rem 0 0;
  font-size: 0.82rem;
  line-height: 1.4;
  color: var(--shop-text-gray);
}
/* teaser_tag sits where a live card's price line would be. */
.shop-tray .product-card.coming-soon .teaser-tag {
  margin-top: 0.45rem;
  font-family: var(--f-title), serif;
  font-weight: var(--f-title-wght);
  font-size: 0.9rem;
  color: var(--primary-color);
}
@media (max-width: 700px) {
  .shop-tray .product-card.coming-soon { clip-path: inset(-40px -40px 7px -40px); }
  .shop-tray .product-card.coming-soon:hover,
  .shop-tray .product-card.coming-soon:focus-within { clip-path: inset(-40px -40px 7px -40px); }
}

@media (max-width: 700px) {
  /* Mobile: each shelf becomes a horizontal swipe on its ledge. Explicit
     width (not just max-width on an ancestor) is required here -- without
     it the grid sizes to fit its content (4 columns wide) instead of the
     viewport, so overflow-x:auto never actually triggers: the whole page
     grows past the viewport instead of scrolling internally per shelf. */
  .shop-tray .shelf-row {
    width: 100%;
    grid-auto-flow: column;
    grid-auto-columns: minmax(200px, 70%);
    grid-template-columns: none;
    overflow-x: auto;
    padding-bottom: 0.3rem;
    scrollbar-width: none;
  }
  .shop-tray .shelf-row::-webkit-scrollbar { display: none; }
  .shop-tray .shelf-row::before { display: none; }
  /* mobile board overlap is ~7px (12px tuck minus the row padding) -- match the clip */
  .shop-tray .product-card { clip-path: inset(-40px -40px 7px -40px); }
  .shop-tray .product-card:hover, .shop-tray .product-card:focus-within { clip-path: inset(-40px -40px -40px -40px); }
  /* TT-SHOP-REDO-14: the side-by-side meta grid is a wide-card affordance.
     On the ~70%-width swipe cards the badge ("Free with account") would be
     clipped beside the price, so stack it (as it was pre-14) -- the full
     card width fits the pill on one line. */
  .shop-tray .product-body .product-meta { grid-template-columns: 1fr; gap: 0.3rem; }
  .shop-tray .product-body .gating-badge { justify-self: start; }
}
@media (prefers-reduced-motion: reduce) {
  .shop-tray .product-card:hover { transform: none; }
}

/* ============================================================
   Catalogue: the "ugly browse" collapsible tree (poc-catalogue.html)
   ============================================================ */
.shop-catalogue .wrap { max-width: 900px; margin: 0 auto; padding: 1.6rem 1.5rem 4rem; }
.shop-catalogue .top { display: flex; align-items: baseline; gap: 1rem; flex-wrap: wrap; }
.shop-catalogue .top h1 {
  margin: 0; /* TT-SHOP-REDO-06: same missing-reset issue as the landing lanes */
  font-family: var(--f-title), serif;
  font-weight: var(--f-title-wght);
  font-optical-sizing: auto;
  font-size: 1.7rem;
  color: var(--primary-color);
}
.shop-catalogue .top .back { font-size: 0.9rem; font-weight: 500; text-decoration: none; color: var(--accent-color); }
.shop-catalogue .top .back:hover { text-decoration: underline; }
.shop-catalogue .intro { color: var(--shop-text-gray); font-size: 0.95rem; margin-top: 0.3rem; }

.shop-catalogue .controls {
  display: flex;
  gap: 0.75rem;
  align-items: center;
  flex-wrap: wrap;
  margin: 1.3rem 0 1.5rem;
}
.shop-catalogue .controls input[type="search"] {
  flex: 1;
  min-width: 220px;
  padding: 0.6rem 0.9rem;
  border: 1.5px solid var(--shop-border);
  border-radius: 8px;
  font-family: inherit;
  font-size: 0.95rem;
  background: var(--bg-white);
}
.shop-catalogue .controls input[type="search"]:focus { outline: none; border-color: var(--primary-color); }
.shop-catalogue .controls select {
  padding: 0.6rem 0.9rem;
  border: 1.5px solid var(--shop-border);
  border-radius: 8px;
  font-family: inherit;
  font-size: 0.9rem;
  background: var(--bg-white);
  color: var(--text-color);
  cursor: pointer;
}
.shop-catalogue .controls select:focus { outline: none; border-color: var(--primary-color); }
.shop-catalogue .result-count { font-size: 0.85rem; color: var(--shop-text-gray); margin-bottom: 0.9rem; }
.shop-catalogue mark { background: var(--accent-orange-light, #ffbc48); border-radius: 2px; padding: 0 1px; }

.shop-catalogue .tree details { border: 1px solid var(--shop-border); border-radius: 8px; background: var(--bg-white); margin-bottom: 0.5rem; }
.shop-catalogue .tree details[open] { padding-bottom: 0.4rem; }
.shop-catalogue .tree summary {
  cursor: pointer;
  padding: 0.6rem 0.9rem;
  font-family: var(--f-title), serif;
  font-weight: var(--f-title-wght);
  font-optical-sizing: auto;
  color: var(--primary-color);
  list-style-position: inside;
}
.shop-catalogue .tree summary .n { font-family: var(--f-body), serif; font-weight: 400; color: var(--shop-text-gray); font-size: 0.85rem; }
.shop-catalogue .tree summary .p-name { color: inherit; text-decoration: none; }
.shop-catalogue .tree summary .p-name:hover,
.shop-catalogue .tree summary .p-name:focus-visible { text-decoration: underline; }
.shop-catalogue .tree details details { margin: 0.3rem 0.8rem; border-style: dashed; }
.shop-catalogue .tree details details summary { font-weight: 500; font-size: 0.95rem; }
.shop-catalogue .tree ul { list-style: none; margin: 0.15rem 0.9rem 0.4rem 2rem; }
/* TT-SHOP-REDO-11: three columns per row -- name (link, flexes) | price
   (fixed, right) | action (fixed, right). The action cell reserves its
   width even when empty (generate / fallback / book rows) so the price
   column stays vertically aligned down the list. */
.shop-catalogue .tree li {
  display: flex;
  align-items: baseline;
  gap: 1rem;
  font-size: 0.88rem;
  padding: 0.22rem 0;
  border-bottom: 1px dotted var(--primary-light);
}
.shop-catalogue .tree li:last-child { border-bottom: none; }
.shop-catalogue .tree .hidden { display: none !important; }
.shop-catalogue .tree .v-link {
  flex: 1 1 auto;
  min-width: 0;
  color: inherit;
  text-decoration: none;
}
.shop-catalogue .tree .v-link:hover .v-name,
.shop-catalogue .tree .v-link:focus-visible .v-name { text-decoration: underline; }
.shop-catalogue .tree .price {
  /* TT-SHOP-REDO-06 follow-up: custom.css has a bare `.price { font-size:
     1.5rem }` rule (written for the product-detail/shop-card price tag) --
     with no font-size declared here it was winning by specificity,
     rendering catalogue row prices (and the green "Free" case) far larger
     than the row text around them. Pin it explicitly instead. */
  font-size: 0.88rem;
  white-space: nowrap;
  font-weight: 600;
  flex: 0 0 auto;
  margin-left: auto;   /* pin price + action to the right when name is short */
  text-align: right;
}
.shop-catalogue .tree .price.free { color: #3e8c28; }
.shop-catalogue .tree .v-action {
  flex: 0 0 auto;
  min-width: 6.75rem;  /* == a rendered "Add to cart" button, so empty cells hold the column */
  display: flex;
  justify-content: flex-end;
}
/* Reuse the tray quick-add look at a smaller scale (TT-SHOP-REDO-11:
   restyle, don't fork a fourth button style). */
.shop-catalogue .tree .quick-add-form { margin: 0; padding: 0; }
.shop-catalogue .tree .quick-add-btn {
  border: 1.5px solid var(--primary-color);
  background: var(--bg-white);
  color: var(--primary-color);
  border-radius: 6px;
  padding: 0.18rem 0.6rem;
  font: inherit;
  font-family: var(--f-title), serif;
  font-weight: var(--f-title-wght);
  font-size: 0.78rem;
  white-space: nowrap;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.shop-catalogue .tree .quick-add-btn:hover,
.shop-catalogue .tree .quick-add-btn:focus-visible {
  background: var(--primary-color);
  color: #fff;
}
/* TT-SHOP-REDO-13: logged-out cart/gated rows render the action as an <a>
   login link (new tab); strip the anchor underline so it matches the button. */
.shop-catalogue .tree a.quick-add-btn { text-decoration: none; }

/* TT-SHOP-REDO-13: the per-product "Learn more" row -> the landing page,
   sitting in the action column aligned with the Add-to-cart buttons but read
   as secondary: a quiet accent link (transparent border keeps its baseline
   level with the bordered action buttons above/below it). */
.shop-catalogue .tree .learn-more-row .lm-label {
  font-size: 0.82rem;
  font-style: italic;
  color: var(--shop-text-gray);
}
.shop-catalogue .tree .learn-more-btn {
  font-family: var(--f-title), serif;
  font-weight: var(--f-title-wght);
  font-size: 0.78rem;
  color: var(--accent-color);
  text-decoration: none;
  padding: 0.18rem 0.6rem;
  border: 1.5px solid transparent;
  white-space: nowrap;
}
.shop-catalogue .tree .learn-more-btn:hover,
.shop-catalogue .tree .learn-more-btn:focus-visible { text-decoration: underline; }

/* Mobile: the action must never force horizontal overflow. Below 480px
   the name+price share the first line and the button wraps to its own
   full-width line (empty cells collapse to nothing). */
@media (max-width: 480px) {
  .shop-catalogue .tree ul { margin-left: 1rem; }
  .shop-catalogue .tree li { flex-wrap: wrap; gap: 0.3rem 0.8rem; }
  .shop-catalogue .tree .v-link { flex: 1 1 55%; }
  .shop-catalogue .tree .v-action { flex: 1 1 100%; min-width: 0; }
  .shop-catalogue .tree .v-action .quick-add-form,
  .shop-catalogue .tree .v-action .quick-add-btn { width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  .shop-catalogue * { transition: none !important; }
}
