/* The shop's stylesheet.

   The palette, the radii and the typefaces are the portal's own — var(--bg)
   ground, var(--amber) accent, Fraunces over DM Sans — taken from
   assets/css/portal.css (via tokens.css) rather than chosen again here. A
   buyer moves shop -> checkout -> dashboard without the product changing
   under them, and the shop stops looking like a different company than the
   one it sells for.

   NOTHING IS TRUNCATED, WITH ONE EXCEPTION. No text-overflow and no line-clamp
   on any text container — content wraps or the card grows. The exception is
   .shop-card h3, which clamps to two lines: the card carries a rating line, a
   price pair and a button under the title, and a 250px column cannot hold all
   of that plus an unbounded name. The full name is on the product page, one
   click away. The rule still holds everywhere else, and a second exception
   should be argued for as hard as this one was.

   Several rules use overflow:hidden, each for its own box: .shop-card clips
   to the card's own rounded corners, .shop-card-media clips the hover zoom
   the same way, the two-line clamp on .shop-card h3 needs it to cut the
   third line, and .shop-sr uses it (with a 1px box and clip:rect) to hide
   text visually while leaving it readable by a screen reader. */

* { box-sizing: border-box; }

body.shop {
    /* Layout and type tokens, scoped to the shop rather than tokens.css —
       nothing outside these pages reads them. Colours and radii come from
       tokens.css, loaded before this sheet. */
    --gap:      1.5rem;
    --sans:     'DM Sans', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
    --mono:     'DM Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

    margin: 0;
    background: var(--bg);
    color: var(--text);
    font-family: var(--sans);
    font-size: 16px;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
}

a { color: inherit; }

/* ---- chrome ---- */

.shop-main {
    max-width: 78rem;
    margin: 0 auto;
    padding: 0 var(--gap);
}

/* The shop's own copy of the portal wordmark's accent — "My" plays the
   role .brand-tld's ".in" does. Same dark/light split as that class: amber
   on the pale footer, amber-l on .pt-top's dark strip. */

.shop-main { padding-top: 3.5rem; padding-bottom: 5rem; }

/* ---- mobile bottom nav ---- */

/* Desktop has the sticky .pt-nav row for this; a second persistent nav bar
   stacked under it would be two navigations competing on the same page. Phones
   don't get .pt-nav sticky (chrome.css only stickies it >=769px), so this is
   the one persistent way back to the shop, the search box or the account once
   a visitor has scrolled into a long product page. */
.shop-bottomnav { display: none; }
@media (max-width: 768px) {
  /* Reserves exactly the bar's own footprint so the fixed bar covers empty
     space at the very bottom of the page rather than the footer's last line. */
  body.shop { padding-bottom: calc(60px + env(safe-area-inset-bottom, 0px)); }

  .shop-bottomnav {
    display: flex;
    position: fixed; inset-inline: 0; bottom: 0; z-index: 200;
    background: var(--bg2);
    border-block-start: 1px solid var(--border);
    box-shadow: var(--shadow-nav-stuck);
    padding-block: 8px calc(8px + env(safe-area-inset-bottom, 0px));
  }
  .sbn-item {
    flex: 1;
    display: flex; flex-direction: column; align-items: center; gap: 3px;
    padding: 4px 2px;
    color: var(--text2); text-decoration: none;
    font-size: 11px; font-weight: 500;
    transition: color .18s ease;
  }
  .sbn-item:hover, .sbn-item:active { color: var(--amber-d); }

  /* Signed out, the header's "Sign in" and this bar's "Account" are the same
     control: both point at /login.php with data-auth-modal="in" (see
     portal_chrome.php's signed-out branch and the one in _footer.php above).
     Two taps apart, on a strip that has already given up "Create account", the
     locale name and the currency control to fit 390px — so the duplicate is
     what goes, not another thing that was not a duplicate.

     Scoped with :has() rather than a body class each page would have to
     remember to set, because the condition IS whether the bar is on the page:
     cart.php, verify.php and preview.php all render the header without it and
     must keep their only way in. Following portal.css's .co-thread rule — a
     browser without :has() keeps both controls, which is the harmless way to
     be wrong.

     :not(.has-buysheet) because the product page trades this bar away for the
     buy bar (body.has-buysheet .shop-bottomnav, further down). Hiding the
     header button there too would leave that page no sign-in affordance at
     all — and it is the page where a visitor is most likely to want one. */
  body.shop:has(.shop-bottomnav):not(.has-buysheet) .pt-top__signin { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .sbn-item { transition: none; }
}

/* ---- editorial type ---- */

.shop-heading {
    font-family: var(--display);
    font-weight: 500;
    font-size: clamp(2rem, 1.3rem + 3vw, 3.5rem);
    line-height: 1.08;
    letter-spacing: -.03em;
    margin: 0 0 .5rem;
    text-wrap: balance;
    overflow-wrap: anywhere;
}

.shop-subheading {
    margin: 0 0 3rem;
    color: var(--text2);
    font-size: 1.0625rem;
}

/* ---- hero ---- */

/* A soft two-tone mesh in place of the old single gradient — still nothing
   but --amber, --base and --section-bg, layered as radial blooms rather than
   one linear sweep, which is what reads as "premium SaaS hero" instead of
   "pale banner". A theme change to any of those three tokens carries here
   exactly like it did before. */
.shop-hero {
  position: relative;
  overflow: hidden;
  background: var(--bg);
  border-block-end: 1px solid var(--border);
}
.shop-hero::before {
  content: '';
  position: absolute;
  inset: 0;
  background:
    radial-gradient(60% 55% at 12% 10%, var(--amber-10), transparent 60%),
    radial-gradient(55% 60% at 90% 20%, var(--base-bg), transparent 65%),
    linear-gradient(160deg, var(--section-bg), var(--bg) 72%);
  pointer-events: none;
}

.shop-hero__inner {
  position: relative;
  max-width: 78rem;
  margin: 0 auto;
  padding: 72px 20px 88px;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 440px);
  gap: 48px;
  align-items: center;
}
/* No collage to show — a search or a filter with fewer than two product shots
   falls back to the original centred layout rather than an empty column. */
.shop-hero__inner--solo { grid-template-columns: minmax(0, 1fr); max-width: 700px; text-align: center; padding-bottom: 64px; }
.shop-hero__inner--solo .shop-hero__search { margin-inline: auto; }
.shop-hero__inner--solo .shop-hero__stats { justify-content: center; }
.shop-hero__inner--solo p { margin-inline: auto; }

.shop-hero__copy { min-width: 0; }
.shop-hero h1 {
  font-family: var(--display); font-weight: 600;
  font-size: clamp(30px, 2.6vw + 18px, 50px); line-height: 1.08; margin: 0;
  letter-spacing: -.02em;
  color: var(--text); text-wrap: balance;
}
.shop-hero p { color: var(--text2); font-size: 16.5px; margin: 16px 0 0; max-width: 46ch; }

.shop-hero__search {
  display: flex; gap: 0; margin: 30px 0 0; max-width: 560px;
  background: var(--bg2); border: 1px solid var(--border); border-radius: 999px;
  padding: 5px;
  box-shadow: var(--shadow-card);
  transition: border-color .15s ease, box-shadow .15s ease;
}
.shop-hero__search:focus-within { border-color: var(--base); box-shadow: var(--shadow-card-hover); }
.shop-hero__search input {
  flex: 1; min-width: 0; font: inherit; font-size: 15px; padding: 11px 18px;
  border: 0; border-radius: 999px;
  background: transparent; color: var(--text);
}
.shop-hero__search input:focus { outline: none; }
.shop-hero__search button {
  font: inherit; font-size: 14.5px; font-weight: 600; padding: 12px 26px;
  border: 0; background: var(--base); color: var(--on-base); cursor: pointer;
  border-radius: 999px;
}
.shop-hero__search button:hover { background: var(--base-d); }

.shop-hero__stats { display: flex; flex-wrap: wrap; gap: 10px 22px; margin: 26px 0 0; }
.shop-hero__stat {
  position: relative; padding-inline-start: 16px;
  font-family: var(--mono); font-size: .8125rem; color: var(--text2);
}
.shop-hero__stat::before {
  content: ''; position: absolute; inset-inline-start: 0; top: 50%;
  width: 5px; height: 5px; border-radius: 50%; background: var(--amber);
  transform: translateY(-50%);
}
.shop-hero__stat:first-child { padding-inline-start: 0; }
.shop-hero__stat:first-child::before { display: none; }

/* ---- hero collage: up to four real product shots, never stock art ---- */

.shop-hero__visual { position: relative; min-width: 0; }
/* Shorter than before: a 590x300 (landscape) item is much shallower than the
   old near-square boxes were, so the old 260-380px container left a dead
   band of empty space between the top pair and the bottom pair. This height
   is sized to what a continuously-overlapping stack of 590x300 cards
   actually needs. */
.shop-hero__collage { position: relative; height: clamp(190px, 22vw, 260px); }
/* 590x300 is the shop's own catalogue-artwork ratio (same figure
   .shop-free-item-card-media names) — aspect-ratio derives each item's
   height from its width so the box always matches that ratio instead of an
   arbitrary percentage that forced a hard cover-crop into the wrong shape. */
.shop-hero__collage-item {
  position: absolute;
  aspect-ratio: 590 / 300;
  border-radius: var(--rl);
  overflow: hidden;
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
  background: var(--bg3);
}
/* contain, not cover — a real screenshot only close to 590x300 letterboxes
   instead of losing an edge, same trade-off .shop-free-item-card-media img
   already makes for the identical artwork. */
.shop-hero__collage-item img { display: block; width: 100%; height: 100%; object-fit: contain; }
/* Each item's own top/bottom offset is picked so its box overlaps the one
   before it — with the container height above, this cascades continuously
   from top-left to bottom-right instead of leaving a gap in the middle,
   which is what happened when these percentages were still tuned for the
   old, much taller item boxes. */
.shop-hero__collage-item--0 { inset-inline-start: 0;      top: 0;     width: 64%; z-index: 4; transform: rotate(-2deg); }
.shop-hero__collage-item--1 { inset-inline-end: 0;        top: 22%;   width: 46%; z-index: 3; transform: rotate(3deg); }
.shop-hero__collage-item--2 { inset-inline-start: 12%;    bottom: 0;  width: 44%; z-index: 2; transform: rotate(2deg); }
.shop-hero__collage-item--3 { inset-inline-end: 4%;       bottom: 14%; width: 38%; z-index: 1; transform: rotate(-3deg); }

.shop-hero__badge {
  position: absolute; left: 50%; bottom: -20px; transform: translateX(-50%);
  z-index: 4;
  display: flex; align-items: baseline; gap: 7px;
  background: var(--bg2); border: 1px solid var(--border); border-radius: 999px;
  padding: 11px 22px;
  box-shadow: var(--shadow-menu);
  white-space: nowrap;
}
.shop-hero__badge-label { font-size: .75rem; color: var(--text3); }
.shop-hero__badge-price { font-family: var(--display); font-weight: 600; color: var(--amber); font-size: 1.0625rem; }

@media (max-width: 860px) {
  .shop-hero__inner { grid-template-columns: minmax(0, 1fr); text-align: center; padding-top: 56px; }
  .shop-hero__inner .shop-hero__search { margin-inline: auto; }
  .shop-hero__inner .shop-hero__stats { justify-content: center; }
  .shop-hero p { margin-inline: auto; }
  .shop-hero__visual { order: -1; margin-bottom: 12px; }
  .shop-hero__collage { height: clamp(160px, 44vw, 230px); }
}
@media (max-width: 560px) {
  .shop-hero__search { flex-direction: column; gap: 8px; border-radius: 20px; padding: 8px; }
  .shop-hero__search input { padding: 10px 12px; }
  .shop-hero__search button { border-radius: 14px; }
}

/* ---- categories and sort ---- */

.shop-categories h2,
.shop-sort-label {
    font-size: .6875rem;
    text-transform: uppercase;
    letter-spacing: .12em;
    color: var(--text3);
    font-weight: 600;
    margin: 0 0 .75rem;
}

/* Shared by the categories chip list and the sort pills: both are a single
   scrollable row of chips rather than a wrapping list, with the same
   prev/next-button-over-a-scroll-snap-track mechanics as .shop-testimonials
   below, just compact enough that the buttons sit outside the row instead of
   floating over it. */
.shop-chip-carousel { position: relative; display: flex; align-items: center; margin: 0 0 2rem; }
.shop-chip-carousel__track {
    display: flex; flex-wrap: nowrap; align-items: center;
    overflow-x: auto; scroll-snap-type: x mandatory;
    scrollbar-width: none; padding: 2px 0;
}
.shop-chip-carousel__track::-webkit-scrollbar { display: none; }
.shop-chip-carousel__track > a,
.shop-chip-carousel__track > li {
    flex: 0 0 auto;
    scroll-snap-align: start;
    white-space: nowrap;
}
.shop-chip-carousel__track > li { display: flex; list-style: none; }

.shop-chip-carousel__nav {
    display: none;
    flex: none; align-items: center; justify-content: center;
    width: 32px; height: 32px; margin: 0 6px;
    border-radius: 50%; border: 1px solid var(--border); background: var(--bg2);
    color: var(--text); cursor: pointer; box-shadow: var(--shadow-menu);
}
.shop-chip-carousel__nav:hover { border-color: var(--amber-l); color: var(--amber-d); }
.shop-chip-carousel__nav svg { width: 15px; height: 15px; }
/* Same reasoning as .shop-testimonials__nav: below this width the track's own
   swipe is the whole interaction, and there is no room to spare for a 32px
   button on either side of a chip row. */
@media (min-width: 64rem) {
    .shop-chip-carousel__nav { display: inline-flex; }
}

.shop-categories .shop-chip-carousel__track { gap: .5rem; margin: 0; padding-inline: 0; }

.shop-categories a {
    display: inline-flex;
    gap: .5rem;
    align-items: center;
    min-height: 44px;
    padding: 0 1.1rem;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--bg2);
    text-decoration: none;
    font-size: .9375rem;
    color: var(--text2);
    transition: border-color .15s ease, color .15s ease, box-shadow .15s ease, transform .15s ease;
}

.shop-categories a:hover { border-color: var(--amber); color: var(--text); box-shadow: var(--shadow-card); transform: translateY(-1px); }
@media (prefers-reduced-motion: reduce) { .shop-categories a { transition: none; } .shop-categories a:hover { transform: none; } }

.shop-count { font-family: var(--mono); font-size: .75rem; color: var(--text3); }

/* Landing target for a sort link's own #shop-sort (see browse.php) — without
   this offset the anchor scroll lands the pills right under the sticky nav. */
.shop-sort { margin-bottom: 2rem; scroll-margin-top: calc(var(--pt-sticky-top, 0px) + 16px); }

/* The shop front's #plan-<id> anchors (browse.php), which the product page's
   membership banner and claim card link to — same offset, same reason. An
   empty inline span has no box to scroll to reliably, hence block. */
.pricing-anchor { display: block; scroll-margin-top: calc(var(--pt-sticky-top, 0px) + 16px); }
.shop-sort .shop-chip-carousel__track { gap: .25rem; margin: 0; padding-inline: 0; }

.shop-sort a {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    padding: 0 .9rem;
    border-radius: var(--r);
    color: var(--text3);
    text-decoration: none;
    font-size: .9375rem;
    transition: color .15s ease, background .15s ease;
}

.shop-sort a:hover { color: var(--text); background: var(--bg2); }
.shop-sort a.is-current { color: var(--amber-d); background: var(--amber-bg); font-weight: 500; }

/* ---- the grid: cards that read as a marketplace ---- */

/* No max-width or inset of its own — .shop-main already sets the column
   width, and a second inset here would put the cards out of line with the
   heading above them. padding is zeroed rather than omitted: a <ul> carries a
   default inline-start padding for its marker, list-style:none drops the
   marker but not that padding. */
.shop-grid {
  display: grid; gap: 20px; list-style: none; margin: 40px 0; padding: 0;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
}
/* position: relative is structural, not decorative — the title's stretched
   ::after below is absolutely positioned against this box. */
.shop-card {
  position: relative;
  display: flex; flex-direction: column;
  background: var(--bg2); border: 1px solid var(--border); border-radius: var(--rl);
  overflow: hidden; transition: box-shadow .2s ease, transform .2s ease, border-color .2s ease;
}
.shop-card:hover { box-shadow: var(--shadow-card-hover); transform: translateY(-4px); border-color: var(--amber-l); }

/* Every card gets the same slot whether or not a SKU has an image, so a grid
   that mixes the two keeps its baselines. The image sits in its own
   overflow-hidden wrapper so the hover zoom never clips into the card's own
   rounded corners.

   THE RATIO IS THE CATALOGUE'S OWN, WRITTEN UNREDUCED ON PURPOSE. Every file
   under api/catalog/media/ is 590x300, so 590/300 says which asset this slot
   was cut for; 59/30 is the same number and answers nothing. This used to be
   16/10, which is TALLER than the artwork — object-fit: cover then scaled to
   fill the height and took the difference off the left and right edges, so
   every card silently lost the first inch of its own product's banner. If the
   catalogue's export size changes, change this with it. */
.shop-card-media { position: relative; aspect-ratio: 590 / 300; overflow: hidden; background: var(--bg3); }
.shop-card-media img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .35s ease; }
.shop-card:hover .shop-card-media img { transform: scale(1.05); }

.shop-card-badge {
  position: absolute; inset-block-start: 10px; inset-inline-end: 10px; z-index: 2;
  /* Green, the colour of a saving: red reads as a warning. */
  background: var(--teal-d, var(--teal)); color: var(--on-teal);
  font-size: 12px; font-weight: 600; line-height: 1;
  padding: 6px 10px; border-radius: 999px;
}

/* Hidden until the card is hovered or something inside it is focused. Focus is
   not optional: without :focus-within a keyboard user tabs to an invisible
   link. */
.shop-card-preview {
  position: absolute; inset-block-start: 50%; inset-inline-start: 50%;
  transform: translate(-50%, -50%);
  z-index: 2;
  display: inline-flex; align-items: center; gap: 7px;
  background: var(--bg2); color: var(--text);
  font-size: 13.5px; font-weight: 600; text-decoration: none;
  padding: 9px 16px; border-radius: 999px; box-shadow: var(--shadow-card-hover);
  opacity: 0; visibility: hidden; transition: opacity .18s ease, visibility .18s ease;
}
.shop-card:hover .shop-card-preview,
.shop-card:focus-within .shop-card-preview { opacity: 1; visibility: visible; }
/* A touch screen has no hover, so a control revealed only by hovering is a
   control that does not exist. Shown permanently there instead. */
@media (hover: none) {
  .shop-card-preview { opacity: 1; visibility: visible; }
}

.shop-card h3 { font-size: 15px; font-weight: 600; color: var(--text); margin: 14px 16px 0; overflow-wrap: anywhere; }
/* The one clamp in this stylesheet — see the header comment. */
.shop-card h3 {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.shop-card h3 a { text-decoration: none; color: inherit; }
/* What replaces the anchor that used to wrap the whole card. Everything the
   card links to other than the product page sits above this with its own
   z-index. */
.shop-card h3 a::after { content: ''; position: absolute; inset: 0; z-index: 1; }

.shop-card-rating { color: var(--text3); font-size: 12.5px; margin: 8px 16px 0; }

/* margin-block-start: auto pushes the footer to the bottom, so cards in a row
   align their prices however tall their titles are. */
.shop-card-foot {
  position: relative; z-index: 2;
  display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap;
  margin: auto 16px 16px; padding-block-start: 12px; border-block-start: 1px solid var(--border2);
}
/* Money in amber, the one place the old identity survives on purpose. */
.shop-card-price {
  color: var(--amber); font-weight: 700; font-size: 15px; margin: 0;
  display: flex; align-items: baseline; gap: 7px; flex-wrap: wrap;
}
.shop-card-price.is-free { color: var(--teal); background: var(--teal-bg); padding: 4px 10px; border-radius: 999px; }
.shop-card-was { color: var(--text3); font-weight: 500; font-size: 13px; }
.shop-card-buy {
  background: var(--base); color: var(--on-base);
  font-size: 13.5px; font-weight: 600; text-decoration: none; white-space: nowrap;
  padding: 9px 16px; border-radius: 999px;
  transition: background .18s ease;
}
.shop-card-buy:hover { background: var(--base-d); }
.shop-card-buy:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }

/* Visually hidden, still read aloud. The struck-through price needs a spoken
   label or it is heard as a second bare number. */
.shop-sr {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

@media (prefers-reduced-motion: reduce) {
  .shop-card, .shop-card-media img, .shop-card-preview, .shop-card-buy { transition: none; }
  .shop-card:hover { transform: none; }
  .shop-card:hover .shop-card-media img { transform: none; }
}

/* ---- flash notice (checkout.php bouncing back to the cart) ---- */

.shop-flash {
    margin-block-end: 1rem;
    padding: .75rem 1rem;
    border: 1px solid var(--border);
    border-inline-start: 3px solid var(--danger);
    border-radius: var(--r);
    background: var(--bg2);
    color: var(--text2);
    font-size: .9rem;
}

/* ---- empty state and pagination ---- */

.shop-empty {
    border: 1px dashed var(--border2);
    border-radius: var(--rl);
    padding: 4rem var(--gap);
    text-align: center;
    background: var(--bg2);
}

.shop-empty h2 { font-family: var(--display); font-weight: 500; margin: 0 0 .5rem; font-size: 1.5rem; }
.shop-empty p { margin: 0; color: var(--text2); }

.shop-pagination {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    align-items: center;
    justify-content: center;
    margin-top: 3rem;
    color: var(--text3);
    font-family: var(--mono);
    font-size: .875rem;
}

.shop-pagination a {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    padding: 0 1.2rem;
    border: 1px solid var(--border);
    border-radius: var(--r);
    text-decoration: none;
    color: var(--text2);
    font-family: var(--sans);
}

.shop-pagination a:hover { border-color: var(--amber); color: var(--text); }

/* ---- membership: the catalogue's front-door pitch only, never on a
   category, search or later page — see $isShopFront in browse.php ---- */

.shop-membership {
  margin: 72px 0 0;
  padding: 48px var(--gap) 4px;
  border-top: 1px solid var(--border);
}
.shop-membership__head { text-align: center; max-width: 46rem; margin: 0 auto 40px; }
.shop-membership__head h2 {
  font-family: var(--display); font-weight: 500;
  font-size: clamp(1.5rem, 1.1rem + 1.4vw, 2.25rem); line-height: 1.15;
  margin: 0 0 .6rem; letter-spacing: -.02em; color: var(--text);
}
.shop-membership__head p { margin: 0; color: var(--text2); font-size: 1.0625rem; }

/* The membership pricing cards and their cadence switch used to live here.
   They moved to assets/css/pricing.css when dashboard/membership.php started
   rendering the same component — see that sheet's own header. */

/* ---- free item campaigns ---- */

.shop-free-items { margin: 72px 0 0; padding: 48px var(--gap) 4px; border-top: 1px solid var(--border); }
.shop-free-items__head { text-align: center; max-width: 46rem; margin: 0 auto 32px; }
.shop-free-items__head h2 {
  font-family: var(--display); font-weight: 500;
  font-size: clamp(1.5rem, 1.1rem + 1.4vw, 2.25rem); line-height: 1.15;
  margin: 0 0 .6rem; letter-spacing: -.02em; color: var(--text);
}
.shop-free-items__head p { margin: 0; color: var(--text2); font-size: 1.0625rem; }

.shop-free-items__grid {
  display: grid; gap: 20px; list-style: none; margin: 0 auto; padding: 0;
  max-width: 78rem;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
}
.shop-free-item-card {
  display: flex; flex-direction: column;
  background: var(--bg2); border: 1px solid var(--border); border-radius: var(--rl);
  overflow: hidden;
  transition: box-shadow .2s ease, transform .2s ease, border-color .2s ease;
}
.shop-free-item-card:hover { box-shadow: var(--shadow-card-hover); transform: translateY(-3px); border-color: var(--amber-l); }
@media (prefers-reduced-motion: reduce) { .shop-free-item-card { transition: none; } .shop-free-item-card:hover { transform: none; } }

/* Same 590x300 catalogue artwork as .shop-card-media, so the same slot — at
   16/10 this one letterboxed rather than cropped (object-fit: contain), which
   cost it two grey bars instead of two lost edges. contain stays: a campaign
   can point at a file the catalogue did not export, and a letterbox is the
   safer failure for one of those than a crop. */
.shop-free-item-card-media { aspect-ratio: 590 / 300; overflow: hidden; background: var(--bg3); }
.shop-free-item-card-media img { width: 100%; height: 100%; object-fit: contain; display: block; }

.shop-free-item-card-body { display: flex; flex-direction: column; flex: 1; padding: 18px 20px 22px; }
.shop-free-item-card-body h3 { font-size: 15px; font-weight: 600; color: var(--text); margin: 0; }
.shop-free-item-card-tagline { color: var(--text2); font-size: 13px; margin: 6px 0 0; }
.shop-free-item-card-ends { color: var(--amber-d); font-size: 12px; font-weight: 600; margin: 10px 0 0; }
.shop-free-item-card-rules { display: flex; flex-wrap: wrap; gap: 6px; margin: 4px 0 16px; }
.shop-free-item-badge {
  display: inline-flex; align-items: center; font-size: 11px; font-weight: 600;
  line-height: 1.4; padding: 3px 10px; border-radius: 999px;
  background: var(--bg3); border: 1px solid var(--border2); color: var(--text2);
  white-space: nowrap;
}
.shop-free-item-badge.is-membership-plan { background: var(--amber-bg,var(--amber-10)); border-color: var(--amber-20); color: var(--amber-d); }

.shop-free-item-card-body .shop-cta { margin-top: auto; }

/* "Notify me" on a coming-soon card. It takes the bottom of the card, where
   the button would be, and the product link follows it. The row wraps
   rather than squeezing the address field on a narrow card. */
.shop-free-notify { margin-top: auto; display: flex; flex-direction: column; gap: 6px; }
.shop-free-notify__label { font-size: 12px; font-weight: 600; color: var(--text2); }
.shop-free-notify__row { display: flex; flex-wrap: wrap; gap: 8px; }
.shop-free-notify__row input {
  flex: 1 1 160px; min-width: 0; font: inherit; font-size: 14px;
  padding: 9px 12px; border: 1px solid var(--border2); border-radius: 10px;
  background: var(--bg); color: var(--text);
}
.shop-free-item-card-body .shop-free-notify .shop-cta { margin-top: 0; flex: 0 0 auto; }
.shop-free-notify__status { margin: 0; font-size: 12.5px; color: var(--text2); }
.shop-free-notify__status:empty { display: none; }
.shop-free-notify.is-done .shop-free-notify__status { color: var(--teal-d); }
/* Asked already: the button stays where it was, greyed, saying so. */
.shop-free-notify.is-done .shop-cta,
.shop-free-notify.is-done .shop-cta:hover {
  background: var(--bg3); color: var(--text2); border-color: var(--border2);
  cursor: default; box-shadow: none;
}
.shop-free-notify.is-done input { color: var(--text2); background: var(--bg2); }
.shop-free-notify.is-error .shop-free-notify__status { color: var(--danger-d); }
.shop-free-notify + .shop-cta { margin-top: 10px; }

/* The free files page (/free) and the shop front's link to it. Coming soon and
   recently free cards carry a flag over the artwork; a past card's artwork is
   muted so the ones still free read first. */
.shop-free-items__all { display: inline-block; margin-top: 12px; font-weight: 600; color: var(--base); text-decoration: none; }
.shop-free-items__all:hover { text-decoration: underline; }
.shop-free-page__head { text-align: center; max-width: 46rem; margin: 48px auto 0; padding: 0 var(--gap); }
.shop-free-page__head p { margin: 0; color: var(--text2); font-size: 1.0625rem; }
/* A section here often holds one or two cards; centred rather than left in a
   row sized for five. */
.shop-free-page .shop-free-items__grid { grid-template-columns: repeat(auto-fit, minmax(250px, 300px)); justify-content: center; }
.shop-free-item-card-media { position: relative; }
.shop-free-item-flag {
  position: absolute; top: 10px; inset-inline-start: 10px;
  font-size: 11px; font-weight: 700; line-height: 1.4; padding: 3px 10px; border-radius: 999px;
  background: var(--base); color: var(--on-base, #fff);
}
.shop-free-item-card.is-past .shop-free-item-flag { background: var(--text2); }
.shop-free-item-card.is-past .shop-free-item-card-media img { filter: grayscale(.6); opacity: .85; }
.shop-free-item-card.is-past .shop-free-item-card-ends { color: var(--text3); margin-bottom: 16px; }
.shop-free-item-card.is-upcoming .shop-free-item-card-ends { color: var(--base); }
.shop-free-item-countdown { white-space: nowrap; }

/* ---- trust strip: front-door only, see $isShopFront in browse.php ----
   Same decorative-gradient technique as .shop-hero::before, so the two
   sections that bookend the page read as one premium system rather than a
   plain hero over a flat grey band. */

.shop-trust { position: relative; overflow: hidden; margin: 72px 0 0; padding: 64px var(--gap) 68px; border-top: 1px solid var(--border); background: var(--bg); }
.shop-trust::before {
  content: '';
  position: absolute; inset: 0;
  background:
    radial-gradient(50% 65% at 88% 0%, var(--amber-10), transparent 65%),
    radial-gradient(45% 60% at 6% 100%, var(--base-bg), transparent 60%),
    linear-gradient(180deg, var(--section-bg), var(--bg) 78%);
  pointer-events: none;
}
.shop-trust__head, .shop-trust__grid { position: relative; }
.shop-trust__head { text-align: center; max-width: 46rem; margin: 0 auto 40px; }
.shop-trust__head h2 {
  font-family: var(--display); font-weight: 600;
  font-size: clamp(1.75rem, 1.2rem + 1.8vw, 2.5rem); line-height: 1.12;
  margin: 0 0 .6rem; letter-spacing: -.02em; color: var(--text);
}
.shop-trust__head p { margin: 0; color: var(--text2); font-size: 1.0625rem; }

.shop-trust__grid {
  display: grid; gap: 24px; list-style: none; margin: 0 auto; padding: 0;
  max-width: 78rem;
  grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr));
}
.shop-trust-card {
  position: relative; overflow: hidden;
  display: flex; flex-direction: column; align-items: flex-start; gap: 10px;
  background: var(--bg2); border: 1px solid var(--border2); border-radius: 20px;
  padding: 34px 30px 32px;
  box-shadow: var(--shadow-card);
  transition: box-shadow .25s ease, transform .25s ease, border-color .25s ease;
}
.shop-trust-card:hover { box-shadow: var(--shadow-menu); transform: translateY(-4px); border-color: var(--amber-l); }
@media (prefers-reduced-motion: reduce) { .shop-trust-card { transition: none; } .shop-trust-card:hover { transform: none; } }

/* The oversized, low-opacity icon bleeding off the corner is the whole
   "premium" cue here — a plain small icon beside the text reads as a bullet
   point, this reads as a feature card. */
.shop-trust-card svg {
  position: absolute; top: -14px; right: -14px; z-index: 0;
  width: 92px; height: 92px; color: var(--amber); opacity: .13;
}
/* Same three-tint cycle .pricing-card uses, so a page with both
   sections reads as one system rather than two different card languages. */
.shop-trust-card:nth-child(3n+2) svg { color: var(--base); }
.shop-trust-card:nth-child(3n) svg { color: var(--teal); }
.shop-trust-card-eyebrow {
  position: relative; z-index: 1;
  font-size: .75rem; font-weight: 700; text-transform: uppercase; letter-spacing: .08em;
  color: var(--amber-d);
}
.shop-trust-card:nth-child(3n+2) .shop-trust-card-eyebrow { color: var(--base); }
.shop-trust-card:nth-child(3n) .shop-trust-card-eyebrow { color: var(--teal-d); }
.shop-trust-card strong { position: relative; z-index: 1; font-family: var(--display); font-weight: 700; font-size: 36px; line-height: 1; color: var(--text); }

/* ---- testimonials carousel: front-door only, see shop_wowcodes_testimonials() ---- */

.shop-testimonials { margin: 72px 0 0; padding: 0 0 4px; }
.shop-testimonials__head { text-align: center; max-width: 46rem; margin: 0 auto 36px; }
.shop-testimonials__head h2 {
  font-family: var(--display); font-weight: 600;
  font-size: clamp(1.75rem, 1.2rem + 1.8vw, 2.5rem); line-height: 1.12;
  margin: 0 0 .6rem; letter-spacing: -.02em; color: var(--text);
}
.shop-testimonials__head p { margin: 0; color: var(--text2); font-size: 1.0625rem; }

.shop-testimonials__viewport { position: relative; max-width: 78rem; margin: 0 auto; }
.shop-testimonials__track {
  display: flex; gap: 20px; list-style: none; margin: 0; padding: 4px var(--gap) 20px;
  overflow-x: auto; scroll-snap-type: x mandatory;
  scrollbar-width: none;
}
.shop-testimonials__track::-webkit-scrollbar { display: none; }
.shop-testimonial-card {
  scroll-snap-align: start;
  flex: 0 0 min(340px, 84vw);
  display: flex; flex-direction: column;
  background: var(--bg2); border: 1px solid var(--border2); border-radius: 18px;
  padding: 26px 26px 24px;
  box-shadow: var(--shadow-card);
}
.shop-testimonial-card-rating { color: var(--amber); font-size: 15px; letter-spacing: 1px; margin-bottom: 12px; }
/* Clamped visually, not truncated server-side — these are short curated
   quotes to begin with, and the clamp only guards against an unusually
   long one breaking the card grid. */
.shop-testimonial-card-body {
  color: var(--text); font-size: .9375rem; line-height: 1.55; margin: 0 0 20px; flex: 1;
  display: -webkit-box; -webkit-line-clamp: 6; -webkit-box-orient: vertical; overflow: hidden;
}
.shop-testimonial-card-author {
  display: flex; align-items: center; gap: 12px; margin-top: auto;
  padding-top: 16px; border-top: 1px solid var(--border2);
}
.shop-testimonial-card-avatar {
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 36px; height: 36px; border-radius: 50%;
  background: var(--amber-bg); color: var(--amber-d);
  font-family: var(--display); font-weight: 700; font-size: 14px;
}
.shop-testimonial-card-author span { display: flex; flex-direction: column; font-size: .8125rem; color: var(--text2); min-width: 0; }
.shop-testimonial-card-author strong { color: var(--text); font-size: .8125rem; }
.shop-testimonial-card-author a { color: var(--text2); text-decoration: none; }
.shop-testimonial-card-author a:hover { color: var(--amber-d); text-decoration: underline; }

.shop-testimonials__nav {
  display: none;
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 2;
  width: 40px; height: 40px; align-items: center; justify-content: center;
  border-radius: 50%; border: 1px solid var(--border); background: var(--bg2);
  color: var(--text); cursor: pointer; box-shadow: var(--shadow-menu);
}
.shop-testimonials__nav:hover { border-color: var(--amber-l); color: var(--amber-d); }
.shop-testimonials__nav svg { width: 18px; height: 18px; }
.shop-testimonials__nav.is-prev { left: -8px; }
.shop-testimonials__nav.is-next { right: -8px; }
/* Buttons appear once there's room to place them off the track without
   overlapping the first/last card — below that width, the track's own
   scroll-snap swiping is the whole interaction. */
@media (min-width: 64rem) {
  .shop-testimonials__nav { display: flex; }
}

/* Below the nav-button breakpoint, swiping is the whole interaction, and a
   340px card on a 390px phone left only a couple of stray pixels of the next
   one showing — nothing said "there's more here." Centring the current card
   instead of start-aligning it, and shrinking it a little, gives both
   neighbours real room to show; the 3D lean on top of that (driven by
   browse.php's own script, which reads each card's live position and writes
   the transform every scroll frame) is what makes those slivers read as
   "swipe" on sight rather than as a layout accident. Left alone above 64rem,
   where several cards already sit fully visible side by side. */
@media (max-width: 63.99rem) {
  .shop-testimonials__track {
    perspective: 1400px;
    padding-inline: calc((100% - min(340px, 70vw)) / 2);
  }
  .shop-testimonial-card {
    flex-basis: min(340px, 70vw);
    scroll-snap-align: center;
    transition: transform .18s ease-out, opacity .18s ease-out;
  }
}
@media (max-width: 63.99rem) and (prefers-reduced-motion: reduce) {
  .shop-testimonial-card { transition: none; }
}

/* ---- book a meeting: front-door only, see WC_SHOP_MEETING_URL ---- */

.shop-meeting { margin: 72px 0 0; padding: 48px var(--gap) 4px; border-top: 1px solid var(--border); }
.shop-meeting__head { text-align: center; max-width: 46rem; margin: 0 auto 28px; }
.shop-meeting__head h2 {
  font-family: var(--display); font-weight: 500;
  font-size: clamp(1.5rem, 1.1rem + 1.4vw, 2.25rem); line-height: 1.15;
  margin: 0 0 .6rem; letter-spacing: -.02em; color: var(--text);
}
.shop-meeting__head p { margin: 0; color: var(--text2); font-size: 1.0625rem; }

.shop-meeting__embed {
  max-width: 78rem; margin: 0 auto; border: 1px solid var(--border); border-radius: var(--rl);
  overflow: hidden; background: var(--bg2);
}
.shop-meeting__embed iframe { display: block; width: 100%; height: 700px; border: 0; }
.shop-meeting__fallback { text-align: center; margin: 16px 0 0; font-size: .875rem; }
.shop-meeting__fallback a { color: var(--base); font-weight: 600; }

@media (max-width: 40rem) {
  .shop-meeting__embed iframe { height: 560px; }
}

/* ---- product page ---- */

/* No max-width or side padding of its own — .shop-main already sets the
   column width, and a second inset here would put the gallery and buy box
   out of line with the crumbs above and the section cards below. */
/* grid-template-ROWS, not just columns, because .shop-product-side spans
   "1 / -1" below — and -1 counts from the last line of the EXPLICIT grid,
   not from however many rows the auto-placed items in column 1 end up
   needing. With no template-rows at all, the explicit grid has zero row
   tracks, so -1 resolved to line 1 — the same as 1 — and the "span" was
   never a span: the side column sat in row 1 alone, forcing that one row to
   grow to the side's FULL height while the real row 1 content (the gallery)
   stayed its own short size, opening a gap before row 2 exactly that tall.
   That was this file's own "lands in empty space" bug, just moved rather
   than fixed by an earlier pass that swapped a different broken span for
   this one without giving -1 a real last line to count from.
   4 explicit rows because column 1 can have at most four row-generating
   children: the gallery, the licence spotlight (always rendered), the tabs
   bar (only when there is more than one tab) and whichever ONE panel is not
   [hidden] — every other panel is display:none and, like any display:none
   box, contributes no row at all. A product with no tabs bar leaves the 4th
   track empty, which costs one harmless 28px gap, not a second dead-space
   bug — see probe_shop_pages.php if that count ever needs to grow. */
.shop-product-top {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 340px;
    grid-template-rows: repeat(4, auto);
    gap: 28px;
    align-items: start;
    margin: 32px 0;
}

@media (max-width: 60rem) {
    .shop-product-top { grid-template-columns: minmax(0, 1fr); gap: 2rem; }
}

.shop-gallery { display: flex; flex-direction: column; gap: 1rem; min-width: 0; }
.shop-gallery img { width: 100%; height: auto; border-radius: var(--rl); border: 1px solid var(--border); display: block; }

.shop-buy {
    min-width: 0;
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: var(--rl);
    padding: 22px;
}

/* The free-item claim card (2026-09-24) — above .shop-buy in the side column,
   never instead of it, so other licence types stay buyable. */
.shop-claim {
  margin: 0 0 16px; padding: 18px;
  border: 1px solid var(--teal-border); border-radius: var(--rl);
  background: var(--teal-bg);
  /* #claim links land below the sticky nav, as .shop-sort's do. The sheet
     overrides this at phone width, where the sheet head is what covers it. */
  scroll-margin-top: calc(var(--pt-sticky-top, 0px) + 16px);
}
.shop-claim__eyebrow {
  margin: 0 0 6px; font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--teal-d);
}
.shop-claim__heading { margin: 0; font-size: 18px; line-height: 1.3; color: var(--text); }
.shop-claim__badges { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0 0; }
.shop-claim__grant { margin: 6px 0 14px; font-size: 13px; color: var(--text2); }
.shop-claim__done { margin: 0 0 10px; font-weight: 600; color: var(--teal-d); }
.shop-claim__hint { margin: 10px 0 0; font-size: 13px; color: var(--text2); }
.shop-claim .shop-cta { width: 100%; justify-content: center; }
.shop-claim[data-claim-state="ineligible"],
.shop-claim[data-claim-state="unavailable"] { background: var(--bg3); border-color: var(--border); }
.shop-claim[data-claim-state="ineligible"] .shop-claim__eyebrow,
.shop-claim[data-claim-state="unavailable"] .shop-claim__eyebrow { color: var(--text3); }

/* The single membership banner — wc_membership_offer_for_sku(). */
.shop-member-offer {
  display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap;
  margin: 0 0 16px; padding: 12px 14px;
  border: 1px solid var(--amber-25); border-radius: var(--rl); background: var(--amber-bg);
}
.shop-member-offer__heading { margin: 0; font-size: 14px; font-weight: 600; color: var(--text); }
.shop-member-offer__cta { font-size: 13.5px; font-weight: 600; color: var(--amber-d); text-decoration: none; white-space: nowrap; }
.shop-member-offer__cta:hover { text-decoration: underline; }

/* Sticky moved off .shop-buy and onto the side column, so the buy panel and the
   product-information card below it travel together. Sticking only the panel
   left the card behind and opened a gap the width of the column. */
.shop-product-side {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-width: 0;
    position: sticky;
    /* Below the nav, not below the viewport. A bare top: 20px measures from
       the viewport top, which the sticky nav already occupies, so the panel
       came to rest UNDER it and lost its first rows — the price line and the
       top of the order total. The 20px is the gap that was always wanted;
       --pt-sticky-top is what it is a gap from. */
    top: calc(var(--pt-sticky-top, 0px) + 20px);
}

@media (max-width: 60rem) { .shop-product-side { position: static; } }

.shop-product-brand {
    margin: 0 0 .4rem;
    font-size: .6875rem;
    text-transform: uppercase;
    letter-spacing: .12em;
    color: var(--amber);
    font-weight: 600;
}

.shop-product-tagline { margin: .5rem 0 1.5rem; color: var(--text2); overflow-wrap: anywhere; }

.shop-product-price { margin: 0; color: var(--amber); font-size: 30px; font-weight: 700; line-height: 1; }
.shop-product-price.is-free { color: var(--teal); }
.shop-product-duration { color: var(--text3); font-size: 13px; margin-block-start: 6px; }

.shop-license-options { display: flex; flex-direction: column; gap: 8px; margin-block-start: 16px; }
.shop-license-option {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 2px 12px;
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--bg2);
    color: var(--text);
    text-decoration: none;
}
.shop-license-option:hover { border-color: var(--amber-l); }
.shop-license-option.is-current { border-color: var(--amber); box-shadow: inset 0 0 0 1px var(--amber); }
.shop-license-option-name { font-weight: 600; overflow-wrap: anywhere; }
.shop-license-option-price { font-weight: 700; color: var(--amber); }
.shop-license-option-summary { grid-column: 1 / -1; color: var(--text2); font-size: 13px; overflow-wrap: anywhere; }
@media (max-width: 380px) {
    .shop-license-option { grid-template-columns: minmax(0, 1fr); }
}

.shop-ctas { display: flex; flex-direction: column; gap: 10px; margin-block-start: 18px; }

.shop-cta {
    display: block;
    text-align: center;
    text-decoration: none;
    padding: 13px;
    border-radius: var(--r);
    font-weight: 600;
    font-size: 15px;
    border: 1px solid transparent;
}

.shop-cta.is-primary { background: var(--base); color: var(--on-base); }
.shop-cta.is-primary:hover { background: var(--base-d); }
.shop-cta.is-secondary { background: var(--bg2); color: var(--text); border-color: var(--border); }
.shop-cta.is-secondary:hover { border-color: var(--base); color: var(--base); }

/* .shop-cta is written for <a>, whose display:block already fills the flex
   column above. A <button> needs the same width and the font this sheet
   never had to give an anchor, plus a pointer cursor an anchor gets for free. */
button.shop-cta { width: 100%; font: inherit; cursor: pointer; }
.shop-cart-add { display: block; }
/* The cart control carries its icon beside its words; on the phone sheet
   below, where the control is a square beside Buy now, the icon stands alone.
   A flex row, not a block, or the icon sits on top of the label. */
.shop-cart-add .shop-cta,
.shop-cta-incart {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
}
.shop-cta-icon { display: block; flex: none; }

/* The row under the hero shot: live demo, screenshots, docs, changelog. Centred
   because it reads as one set of choices about the product, not a column of
   facts about it — the sidebar list next to it is for those. */
.shop-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 10px;
    margin-block-start: 4px;
}

.shop-action {
    font: inherit;
    font-size: 14px;
    font-weight: 500;
    padding: 9px 16px;
    border-radius: var(--r);
    border: 1px solid var(--border);
    background: var(--bg2);
    color: var(--text);
    text-decoration: none;
    cursor: pointer;
}

.shop-action:hover { border-color: var(--base); color: var(--base); }
.shop-action:focus-visible { outline: 2px solid var(--amber); outline-offset: 1px; }

.shop-meta { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .5rem; font-size: .9375rem; }
.shop-meta li { color: var(--text2); }
.shop-meta a { color: var(--amber); }

.shop-crumbs {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    margin-bottom: 2rem;
    font-size: .875rem;
    color: var(--text3);
}

.shop-crumbs a { color: var(--text2); text-decoration: none; }
.shop-crumbs a:hover { color: var(--amber); }

/* Each section is its own card, edge to edge with the crumbs and buy box
   above rather than tabbed — this page has no tab markup and a re-skin isn't
   where to add one. No max-width/auto-margin of its own for the same reason
   .shop-product-top has none: .shop-main already sets that column. */
.shop-section {
    margin: 24px 0;
    padding: 24px;
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: var(--rl);
}

.shop-section > h2 {
    font-family: var(--display);
    font-weight: 600;
    font-size: 22px;
    margin: 0 0 14px;
    color: var(--text);
}

/* "You might also need" — a compact horizontal carousel rather than
   .shop-grid's four-wide catalogue layout: this row is secondary to the tabs
   above it on the product page, and full 250px+ cards at that width read as
   a second catalogue rather than a quick add-on prompt. Same prev/next-over-
   a-scroll-snap-track mechanics as .shop-chip-carousel and .shop-testimonials
   elsewhere in this file, sized for product cards instead of chips or quote
   cards. The cards are shop_rec_card()'s (see its rules below), which keep
   .shop-card's behaviour and add the detail a shelf of four has room for.
   The track's block padding leaves room for the cards' resting shadow and
   hover lift, which overflow-x:auto would otherwise clip. */
.shop-related__viewport { position: relative; }
.shop-related__track {
  display: flex; gap: 16px; list-style: none; margin: 0; padding: 8px 2px 12px;
  overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none;
}
.shop-related__track::-webkit-scrollbar { display: none; }
.shop-related__track .shop-rec-card {
  flex: 0 0 min(290px, 78vw);
  scroll-snap-align: start;
}

/* shop_rec_card() — the recommendation shelves on the cart and product
   pages. Builds on .shop-card (stretched title link, hover lift, media slot,
   footer z-index) and only adds what a shelf of four needs that a 24-card
   grid does not: what the product is, and what comes with it.

   Both shelves sit inside a .shop-section, which is --bg2 — the same white as
   .shop-card itself. A flat card on a flat panel read as one grey slab, so
   the card takes a resting --shadow-card and a --bg3 media well to separate
   it, instead of the --bg3 fill the old related-row override used, which
   greyed out the whole card including its text. */
.shop-rec-card { box-shadow: var(--shadow-card); }
.shop-rec-grid { margin: 8px 0 0; grid-template-columns: repeat(auto-fill, minmax(min(260px, 100%), 1fr)); }

.shop-rec-card__flags {
  position: absolute; inset-block-start: 10px; inset-inline-start: 10px; z-index: 2;
  display: flex; gap: 6px; flex-wrap: wrap;
}
.shop-rec-card__flag {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 11.5px; font-weight: 700; line-height: 1; letter-spacing: .01em;
  padding: 6px 9px; border-radius: 999px; box-shadow: var(--shadow-card);
}
.shop-rec-card__flag svg { width: 11px; height: 11px; fill: currentColor; }
.shop-rec-card__flag.is-featured { background: var(--bg2); color: var(--amber-d); }
.shop-rec-card__flag.is-sale { background: var(--teal-d, var(--teal)); color: var(--on-teal); }

.shop-rec-card__body { display: flex; flex-direction: column; padding: 14px 16px 0; }
.shop-rec-card__eyebrow {
  margin: 0 0 4px; font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--base); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.shop-rec-card h3 { margin: 0; font-size: 16px; line-height: 1.3; }
.shop-rec-card__tagline {
  margin: 6px 0 0; color: var(--text2); font-size: 13px; line-height: 1.45; overflow-wrap: anywhere;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

.shop-rec-card__rating {
  position: absolute; inset-block-start: 10px; inset-inline-end: 10px; z-index: 2;
  pointer-events: none;
  display: inline-flex; align-items: center; gap: 4px; margin: 0;
  font-size: 12px; line-height: 1; padding: 6px 9px; border-radius: 999px;
  background: var(--bg2); box-shadow: var(--shadow-card);
}
.shop-rec-card__rating svg { width: 12px; height: 12px; fill: var(--amber-l); }
.shop-rec-card__rating strong { color: var(--text); font-weight: 700; }
.shop-rec-card__rating span { color: var(--text3); }

/* Support and licence always share ONE line. The list is a size container, so
   the pills' type scales with the card's own width (cqi) rather than the
   viewport's — the same card sits four-up on the cart, in a 290px carousel on
   the product page and full-width on a phone. Clamped so it never drops below
   legible or grows past the rest of the card's small print. Ellipsis is the
   last resort for a long licence name on the narrowest card; min-width:0 is
   what lets a flex item shrink below its text at all. */
.shop-rec-card__meta {
  container-type: inline-size;
  list-style: none; margin: 12px 0 0; padding: 0;
  display: flex; flex-wrap: nowrap; gap: 6px;
}
.shop-rec-card__meta li {
  display: inline-flex; align-items: center; gap: .4em; min-width: 0;
  font-size: clamp(10px, 4.6cqi, 12.5px); font-weight: 500; color: var(--text2); line-height: 1;
  background: var(--bg3); border: 1px solid var(--border2);
  padding: .45em .75em; border-radius: 999px; white-space: nowrap;
}
.shop-rec-card__meta li > span { overflow: hidden; text-overflow: ellipsis; }
.shop-rec-card__meta svg { width: 1.05em; height: 1.05em; flex: none; color: var(--text3); }

.shop-rec-card__foot {
  flex-wrap: nowrap; align-items: center;
  margin: auto 16px 16px; padding-block-start: 14px;
}
/* The footer's margin-block-start:auto pins it to the bottom, which gives a
   card with no meta row no gap at all under its tagline. The gap lives on the
   body instead, so the shortest card still has one. */
.shop-rec-card__body { margin-block-end: 16px; }
.shop-rec-card__pricing { min-width: 0; }
.shop-rec-card .shop-card-price { font-size: 19px; font-weight: 800; letter-spacing: -.01em; line-height: 1.1; }
.shop-rec-card .shop-card-price.is-free { font-size: 14px; }
.shop-rec-card__save { margin: 3px 0 0; font-size: 12px; font-weight: 600; color: var(--teal); }
.shop-rec-card .shop-card-buy {
  display: inline-flex; align-items: center; gap: 6px; flex: none;
  padding: 10px 16px; font-size: 13.5px;
}
.shop-rec-card .shop-card-buy svg { transition: transform .18s ease; }
.shop-rec-card .shop-card-buy:hover svg { transform: translateX(3px); }
[dir="rtl"] .shop-rec-card .shop-card-buy svg { transform: scaleX(-1); }
[dir="rtl"] .shop-rec-card .shop-card-buy:hover svg { transform: scaleX(-1) translateX(3px); }
.shop-rec-card .shop-card-preview svg { flex: none; }

@media (prefers-reduced-motion: reduce) {
  .shop-rec-card .shop-card-buy svg { transition: none; }
}

.shop-related__nav {
  display: none;
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 2;
  width: 36px; height: 36px; align-items: center; justify-content: center;
  border-radius: 50%; border: 1px solid var(--border); background: var(--bg2);
  color: var(--text); cursor: pointer; box-shadow: var(--shadow-menu);
}
.shop-related__nav:hover { border-color: var(--amber-l); color: var(--amber-d); }
.shop-related__nav svg { width: 16px; height: 16px; }
.shop-related__nav.is-prev { left: -14px; }
.shop-related__nav.is-next { right: -14px; }
/* Same breakpoint as .shop-chip-carousel__nav and .shop-testimonials__nav:
   below it the track's own swipe is the whole interaction. */
@media (min-width: 64rem) {
  .shop-related__nav { display: flex; }
}

.shop-includes-intro { margin: 0 0 1.25rem; color: var(--text2); }
/* [hidden]'s UA rule loses to an author display rule regardless of
   specificity — without this, a product with more than one licence renders
   every licence's include list stacked at once instead of only the chosen
   one. Same fix already applied to .shop-tabpanel, .pricing-grid,
   .shop-buybar-was and .shop-product-was below. */
.shop-includes[hidden] { display: none; }
/* What upgrading unlocks, above the What's Included list of a licence that has
   add-ons the cheapest one does not. The names wrap as chips rather than
   truncating. */
.shop-bonus-banner {
  display: flex; gap: 14px; align-items: flex-start;
  margin: 0 0 1.5rem; padding: 16px 18px;
  background: var(--amber-bg, var(--amber-10)); border: 1px solid var(--amber-20);
  border-radius: var(--rl, 14px);
}
.shop-bonus-banner__icon { width: 26px; height: 26px; flex: none; color: var(--amber-d); margin-top: 2px; }
.shop-bonus-banner__body { min-width: 0; flex: 1; }
.shop-bonus-banner__title { margin: 0; font-weight: 600; color: var(--text); line-height: 1.45; }
.shop-bonus-banner__worth { font-weight: 600; color: var(--amber-d); white-space: nowrap; }
.shop-bonus-banner__list { list-style: none; margin: 10px 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px; }
.shop-bonus-banner__list li {
  font-size: 12.5px; font-weight: 600; padding: 4px 10px; border-radius: 999px;
  background: var(--bg); border: 1px solid var(--amber-20); color: var(--text2);
}
/* The same for the licence terms chrome.js shows and hides per option: a
   hidden "Sites" row with a flex or grid parent rule still rendered "for 0". */
[data-pm-info-seats][hidden], [data-pm-info-support][hidden],
[data-pm-seats][hidden], [data-pm-support][hidden] { display: none; }
/* Same grid and card treatment as the Add-ons tab, so the two lists of
   products read as one system. */
.shop-include-grid {
    list-style: none; margin: 0; padding: 0;
    display: grid; gap: 12px;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
}
.shop-include-grid > li { display: flex; }
/* The whole card is the control, so it opens the details from anywhere on
   it rather than from a name-sized target. */
.shop-include {
    display: flex; flex-direction: column; width: 100%;
    padding: 16px 18px;
    background: var(--bg2); border: 1px solid var(--border); border-radius: var(--rl);
    font: inherit; color: inherit; text-align: start; cursor: pointer;
    transition: border-color .15s ease;
}
.shop-include:hover { border-color: var(--amber); }
.shop-include:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }
.shop-include-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.shop-include-head strong { font-size: 15px; font-weight: 600; line-height: 1.35; color: var(--text); }
.shop-include-version { flex-shrink: 0; font-size: 12.5px; color: var(--text3); font-variant-numeric: tabular-nums; }
.shop-include-desc {
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; line-clamp: 3; overflow: hidden;
    margin-top: .5rem; font-size: 13.5px; line-height: 1.55; color: var(--text3);
}
.shop-include-more { margin-top: auto; padding-top: .6rem; font-size: 13px; font-weight: 600; color: var(--amber-d); }
.shop-include:hover .shop-include-more { text-decoration: underline; }
@media (max-width: 640px) {
    .shop-include-grid { grid-template-columns: 1fr; }
}
@media (prefers-reduced-motion: reduce) {
    .shop-include { transition: none; }
}
.shop-include:hover strong { text-decoration-color: currentColor; }
.shop-include:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }

/* ---- what the purchase gives back, and what it does not ---- */

/* One reveal, once, on the block beside the button. Motion here competes with
   the only thing on this panel that matters, so it is a short fade and a few
   pixels rather than anything that asks to be watched. */
.shop-meta-cashback {
    color: var(--teal-d, var(--text));
    font-weight: 500;
    animation: shop-assure-in .45s ease-out .15s both;
}
.shop-assurance {
    margin: .9rem 0 0;
    font-size: .8125rem;
    line-height: 1.55;
    color: var(--text3);
    animation: shop-assure-in .45s ease-out .25s both;
}
.shop-assurance a {
    color: var(--text2);
    text-decoration: underline;
    text-underline-offset: .2em;
    white-space: nowrap;
}
.shop-assurance a:hover { color: var(--text); }

@keyframes shop-assure-in {
    from { opacity: 0; transform: translateY(4px); }
    to   { opacity: 1; transform: none; }
}

/* A reveal is decoration. Anyone who has asked for less motion gets the block
   outright, not a slower version of the same thing. */
@media (prefers-reduced-motion: reduce) {
    .shop-meta-cashback,
    .shop-assurance { animation: none; }
}

/* ---- reviews ---- */

.shop-reviews { list-style: none; margin: 0; padding: 0; display: grid; gap: 2rem; }
.shop-review { border-top: 1px solid var(--border); padding-top: 1.5rem; }
.shop-review-head { margin: 0 0 .5rem; display: flex; flex-wrap: wrap; gap: .75rem; align-items: baseline; }
.shop-review-rating { color: var(--amber); letter-spacing: .1em; }
.shop-review-head time { color: var(--text3); font-family: var(--mono); font-size: .75rem; }
.shop-review-title { margin: 0 0 .4rem; font-weight: 600; font-size: 1.0625rem; }
.shop-review-body { margin: 0; color: var(--text2); overflow-wrap: anywhere; }

.shop-review-reply {
    margin-top: 1rem;
    padding: 1rem 1.25rem;
    border-inline-start: 2px solid var(--amber);
    background: var(--bg2);
    border-start-start-radius: 0;
    border-end-start-radius: 0;
    border-start-end-radius: var(--r);
    border-end-end-radius: var(--r);
}

.shop-review-reply-head { margin: 0 0 .35rem; font-size: .6875rem; text-transform: uppercase; letter-spacing: .12em; color: var(--amber); font-weight: 600; }
.shop-review-reply p { margin: 0; color: var(--text2); }

.shop-review-none { color: var(--text3); margin: 0 0 2rem; }
.shop-review-flash { padding: 1rem 1.25rem; border: 1px solid var(--border2); border-radius: var(--r); background: var(--bg2); margin: 0 0 2rem; }

.shop-review-form {
    display: grid;
    gap: .6rem;
    padding: 1.75rem;
    border: 1px solid var(--border);
    border-radius: var(--rl);
    background: var(--bg2);
    margin-bottom: 2.5rem;
    max-width: 40rem;
}

.shop-review-form h3 { font-family: var(--display); font-weight: 500; margin: 0; font-size: 1.25rem; }
.shop-review-form-note { margin: 0 0 .5rem; color: var(--text3); font-size: .875rem; }
.shop-review-form label { font-size: .8125rem; color: var(--text2); font-weight: 500; }

.shop-review-form select,
.shop-review-form input[type="text"],
.shop-review-form textarea {
    font: inherit;
    color: var(--text);
    background: var(--bg3);
    border: 1px solid var(--border2);
    border-radius: var(--r);
    padding: .7rem .85rem;
    min-height: 44px;
    width: 100%;
}

.shop-review-form textarea { min-height: 7rem; resize: vertical; }

.shop-review-form button {
    justify-self: start;
    min-height: 48px;
    padding: 0 1.5rem;
    margin-top: .5rem;
    font: inherit;
    font-weight: 600;
    color: var(--bg);
    background: var(--amber);
    border: 0;
    border-radius: var(--r);
    cursor: pointer;
}

/* ---- changelog and description blocks ---- */

.shop-changelog { margin: 0; padding-left: 1.4rem; display: grid; gap: 1rem; color: var(--text2); }
.shop-changelog strong { color: var(--text); font-family: var(--mono); font-size: .9375rem; }
.shop-changelog time { color: var(--text3); font-family: var(--mono); font-size: .75rem; margin-left: .75rem; }
.shop-changelog p { margin: .35rem 0 0; overflow-wrap: anywhere; }

.shop-block-heading { font-family: var(--display); font-weight: 500; font-size: 1.5rem; margin: 2.5rem 0 .75rem; letter-spacing: -.02em; }
.shop-block-text { margin: 0 0 1.25rem; max-width: 68ch; color: var(--text2); }
.shop-block-bullets { margin: 0 0 1.25rem; padding-left: 1.3rem; max-width: 68ch; color: var(--text2); }
.shop-block-bullets li { margin-bottom: .45rem; }

.shop-block-features {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(16rem, 100%), 1fr));
    gap: var(--gap);
    margin: 0 0 2rem;
}

.shop-feature { border-left: 2px solid var(--border2); padding-left: 1.1rem; }
.shop-feature h3 { font-family: var(--display); font-weight: 500; margin: 0 0 .35rem; font-size: 1.125rem; }
.shop-feature p { margin: 0; color: var(--text2); font-size: .9375rem; }

.shop-faq { margin: 0 0 2rem; max-width: 68ch; }
.shop-faq dt { font-weight: 600; margin-top: 1.5rem; padding-top: 1.5rem; border-top: 1px solid var(--border); }
.shop-faq dt:first-of-type { margin-top: 0; padding-top: 0; border-top: none; }
.shop-faq dd { margin: .4rem 0 0; color: var(--text2); }

/* The one console/affiliate-links promo, same rounded-pill shape as
   .shop-free-item-badge but a real link, so it reads as clickable rather
   than a status tag. Amber like the badge's is-membership-plan variant,
   since this is also a promoted CTA, not neutral metadata. */
.shop-faq-pill {
    display: inline-flex; align-items: center; margin-top: .6rem;
    font-size: 12px; font-weight: 600; line-height: 1.4; padding: 5px 14px;
    border-radius: 999px; text-decoration: none; white-space: nowrap;
    background: var(--amber-bg, var(--amber-10)); border: 1px solid var(--amber-20);
    color: var(--amber-d);
}
.shop-faq-pill:hover { background: var(--amber-20); }
/* The "why" line above a pill — the affiliate link's own admin-edited
   description, not something authored here. Quieter than the pill itself,
   since it's context for the CTA rather than the CTA. */
.shop-faq-pill-reason { margin: .6rem 0 0; font-size: 13px; color: var(--text3); }

/* A code block shown as its output (shop_safe_html()): an author's own
   markup, so every element it may carry gets a sane default here. Wide
   tables scroll inside the block rather than widening the page. */
.shop-block-html { margin: 0 0 1.5rem; color: var(--text2); line-height: 1.65; overflow-wrap: break-word; }
.shop-block-html > :first-child { margin-top: 0; }
.shop-block-html > :last-child { margin-bottom: 0; }
.shop-block-html h2, .shop-block-html h3, .shop-block-html h4,
.shop-block-html h5, .shop-block-html h6 { color: var(--text); margin: 1.5rem 0 .6rem; line-height: 1.3; }
.shop-block-html p, .shop-block-html ul, .shop-block-html ol,
.shop-block-html dl, .shop-block-html blockquote { margin: 0 0 1rem; }
.shop-block-html ul, .shop-block-html ol { padding-inline-start: 1.4rem; }
.shop-block-html li { margin: .25rem 0; }
.shop-block-html a { color: var(--base); }
.shop-block-html img { max-width: 100%; height: auto; border-radius: var(--r); }
.shop-block-html blockquote { padding: .25rem 1rem; border-inline-start: 3px solid var(--border2); }
.shop-block-html pre { padding: 1rem; background: var(--bg2); border: 1px solid var(--border); border-radius: var(--r); overflow-x: auto; font-size: .875rem; }
.shop-block-html code, .shop-block-html kbd { font-family: var(--mono); font-size: .9em; }
.shop-block-html table { display: block; max-width: 100%; overflow-x: auto; border-collapse: collapse; margin: 0 0 1rem; }
.shop-block-html th, .shop-block-html td { padding: .5rem .75rem; border: 1px solid var(--border); text-align: start; }
.shop-block-html th { background: var(--bg2); color: var(--text); }
.shop-block-html hr { border: 0; border-top: 1px solid var(--border); margin: 1.5rem 0; }

.shop-block-image { margin: 0 0 1.5rem; }
.shop-block-image img { width: 100%; height: auto; border-radius: var(--rl); border: 1px solid var(--border); }

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

/* Inside .shop-empty specifically, not .shop-cta generally: the browse and
   product grids have no empty-state button today, and .shop-cta's own
   display:block would otherwise stretch this one across the dashed box. */
.shop-empty .shop-cta { display: inline-block; margin-block-start: 1.5rem; }

/* The cart page's rules moved to shop/cart.css — see its header for why.
   .shop-cart-add stays here: despite the name it is the product page's
   add-to-cart form, not a cart-page rule. */

.shop-404 .shop-main { padding-top: 6rem; text-align: center; }

/* ---------------------------------------------------------------------------
   Product page: title band, licence radios, information card, phone buy bar.

   The phone sheet is a REPOSITIONED .shop-product-side, never a copy. Two
   copies would mean two radio groups sharing one name and two hidden
   sku_price_id inputs, and a form submits the last one in the DOM rather than
   the one the visitor touched — which is how a buyer ends up charged for the
   licence they did not pick.

   Everything below the .has-buysheet gate is opt-in from chrome.js. Without JS
   the class never lands, the panel stays in normal flow at every width, and the
   page degrades to the stacked layout it had before this existed rather than to
   a panel with nothing to open it.
   --------------------------------------------------------------------------- */

.shop-product-head { margin: 24px 0 0; }
.shop-product-head .shop-heading { margin: 0; overflow-wrap: anywhere; }
.shop-product-head .shop-product-tagline { margin: .5rem 0 0; max-width: 60ch; }
.shop-product-head .shop-card-rating { margin: .6rem 0 0; }

.shop-license-heading {
    margin: 0 0 8px;
    font-size: .6875rem;
    text-transform: uppercase;
    letter-spacing: .12em;
    color: var(--text3);
    font-weight: 600;
}

/* The label is the card; the native radio keeps its own column so it is a real
   radio to a screen reader and to a keyboard, not a div wearing a circle. */
.shop-license-option {
    grid-template-columns: auto minmax(0, 1fr) auto;
    cursor: pointer;
    align-items: center;
}
.shop-license-option input[type="radio"] { margin: 0; accent-color: var(--amber); }
.shop-license-option-summary { grid-column: 2 / -1; }
.shop-license-option:focus-within { border-color: var(--amber); box-shadow: 0 0 0 2px var(--amber-l); }

.shop-license-apply {
    margin-block-start: 10px;
    padding: 8px 14px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--bg);
    color: var(--text);
    cursor: pointer;
}
/* Only once the script is running. See initLicences(). */
.shop-license-options.is-live .shop-license-apply { display: none; }

.shop-order-total {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 12px;
    margin: 18px 0 0;
    padding-block-start: 14px;
    border-block-start: 1px solid var(--border);
}
.shop-order-total span { color: var(--text2); }
.shop-order-total strong { font-size: 20px; color: var(--amber); }

.shop-product-info {
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: var(--rl);
    padding: 18px 22px;
}
.shop-product-info h2 { margin: 0 0 10px; font-size: 15px; }
.shop-product-info dl { margin: 0; }
.shop-product-info dl > div {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    padding: 7px 0;
    border-block-start: 1px solid var(--border);
}
.shop-product-info dl > div:first-child { border-block-start: 0; }
.shop-product-info dt { color: var(--text2); font-size: 13px; }
.shop-product-info dd { margin: 0; font-size: 13px; font-weight: 600; text-align: end; }

/* --- Phone: buy bar and sheet ------------------------------------------- */

.shop-buybar { display: none; }
.shop-sheet-scrim { display: none; }

@media (max-width: 60rem) {
    /* :not([hidden]) is load-bearing. The hidden ATTRIBUTE is only a UA
       stylesheet display:none, so any display declaration here outranks it and
       the element shows anyway. Without this the bar would appear even when
       chrome.js never ran to reveal it. */
    body.has-buysheet .shop-buybar:not([hidden]) {
        display: flex;
        align-items: center;
        gap: 12px;
        position: fixed;
        inset-inline: 0;
        inset-block-end: 0;
        z-index: 40;
        padding: 10px 16px calc(10px + env(safe-area-inset-bottom, 0px));
        background: var(--bg2);
        border-block-start: 1px solid var(--border);
    }

    /* The bar takes the edge from the tab nav on this page only. Two stacked
       bars cost a phone about a fifth of its height, and buying is what a
       product page is for. */
    body.has-buysheet .shop-bottomnav { display: none; }

    .shop-buybar-toggle {
        flex: 1 1 auto;
        min-width: 0;
        display: flex;
        flex-direction: column;
        align-items: flex-start;
        gap: 2px;
        padding: 0;
        border: 0;
        background: none;
        color: inherit;
        text-align: start;
        cursor: pointer;
    }
    .shop-buybar-price { font-size: 20px; font-weight: 700; color: var(--amber); line-height: 1; }
    .shop-buybar-licence { font-size: 12px; color: var(--text3); overflow-wrap: anywhere; }
    /* The toggle's hit area, stretched across the bar's start half so the
       price block is tappable and not just the glyph. It STOPS SHORT OF THE
       END CONTROLS — there are two of them now, the cart button and Buy now,
       and an overlay reaching further would sit on top of the cart button and
       swallow its taps into opening the sheet. */
    .shop-buybar-toggle::after {
        content: "";
        position: absolute;
        inset: 0;
        inset-inline-end: 52%;
    }
    /* The chevron sits beside the price on the first row. Grid rather than
       another flex wrapper because the licence name below has to span both
       columns and wrap under the chevron rather than beside it. Overrides the
       flex-column declared above for the same element. */
    .shop-buybar-toggle {
        display: grid;
        /* price, struck retail, chevron, then slack. The retail column is
           `auto` rather than a fixed width because it is empty on a product
           with no anchor, and an empty fixed column would leave the chevron
           floating away from the price. */
        grid-template-columns: auto auto auto 1fr;
        align-items: baseline;
        column-gap: 6px;
    }
    .shop-buybar-was { color: var(--text3); font-size: 13px; font-weight: 500; }
    .shop-buybar-was[hidden] { display: none; }
    .shop-buybar-toggle .shop-buybar-licence { grid-column: 1 / -1; }
    .shop-buybar-chevron {
        width: 12px; height: 12px;
        color: var(--text3);
        transition: transform .2s ease;
    }
    /* Points down once the sheet is open, so the control reads as "close" from
       the same glyph rather than needing a second one. */
    body.sheet-locked .shop-buybar-chevron { transform: rotate(180deg); }

    .shop-buybar-cta {
        flex: 0 0 auto;
        padding: 12px 20px;
        border-radius: 10px;
        background: var(--amber);
        color: var(--bg);
        font-weight: 700;
        text-decoration: none;
    }

    /* The cart control beside it. Square, outlined, and the same 10px radius
       and 44px height as Buy now so the two read as one pair of controls
       rather than a button and an afterthought. The form is only a wrapper —
       it must not become a flex item with a size of its own. */
    .shop-buybar-cart-form { flex: 0 0 auto; display: flex; margin: 0; }
    .shop-buybar-cart {
        flex: 0 0 auto;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 44px;
        height: 44px;
        padding: 0;
        border-radius: 10px;
        border: 1px solid var(--border);
        background: var(--bg2);
        color: var(--text);
        cursor: pointer;
        /* Above .shop-buybar-toggle::after, which is painted over the bar. The
           overlay stops before this button, but the toggle is an earlier
           sibling and would otherwise win on paint order alone. */
        position: relative;
        z-index: 1;
    }
    .shop-buybar-cart:hover { border-color: var(--base); color: var(--base); }
    .shop-buybar-cart:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }
    /* Already in the cart: the same control, filled, so the state is legible
       without a second glyph or a word the bar has no room for. */
    .shop-buybar-cart.is-incart { background: var(--base-bg); border-color: var(--base); color: var(--base); }

    /* The free-item way in (product.php prints it while a campaign runs).
       A row of its own above the price and Buy now: squeezed in beside them
       it would crowd the price, and Buy now keeps the bar's one worded slot. */
    body.has-buysheet .shop-buybar[data-has-claim]:not([hidden]) { flex-wrap: wrap; row-gap: 8px; }
    body.has-buysheet:has(.shop-buybar[data-has-claim]:not([hidden])) { padding-bottom: calc(108px + env(safe-area-inset-bottom, 0px)); }
    .shop-buybar-claim {
        flex: 1 0 100%;
        display: flex;
        align-items: center;
        gap: 8px;
        min-height: 36px;
        padding: 6px 12px;
        border: 1px solid var(--teal-border);
        border-radius: 10px;
        background: var(--teal-bg);
        color: var(--teal-d);
        font: inherit;
        font-size: 13px;
        font-weight: 600;
        text-align: start;
        cursor: pointer;
        /* Above .shop-buybar-toggle::after, for the same reason as the cart
           button: the overlay spans the bar, this row included. */
        position: relative;
        z-index: 1;
    }
    .shop-buybar-claim__tag { font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; }
    .shop-buybar-claim:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }

    body.has-buysheet .shop-product-side {
        position: fixed;
        inset-inline: 0;
        /* The desktop sticky rule sets top: 20px. Left standing it anchors the
           fixed sheet to the TOP edge and inset-block-end is ignored, which
           parks 84px of a shut sheet on screen — visible, but just subtle
           enough to read as a design choice rather than a bug. */
        inset-block-start: auto;
        inset-block-end: 0;
        z-index: 42;
        max-height: 85vh;
        overflow-y: auto;
        margin: 0;
        padding: 16px 16px calc(16px + env(safe-area-inset-bottom, 0px));
        background: var(--bg2);
        border-start-start-radius: var(--rl);
        border-start-end-radius: var(--rl);
        border-block-start: 1px solid var(--border);
        transform: translateY(101%);
        transition: transform .22s ease;
    }
    body.has-buysheet .shop-product-side.is-sheet-open { transform: translateY(0); }

    /* The claim card is the first thing under the sheet head, which is
       sticky over the top of the sheet's own scroll area. Scrolled to with
       no margin, the card's eyebrow and heading sit beneath that head.
       --pm-sheet-head-h is the head's measured height, which chrome.js
       publishes before it scrolls; 61px is the head as designed (14px
       padding either side of the 32px close button, plus its border) for a
       page where it has not run yet. The 28px is the sheet's own 16px top
       padding, inside which the sticky head comes to rest (measured: the
       head sits 16px down the scrolled sheet, not at its edge), plus the
       head's 12px bottom margin — so the card lands exactly where it sits
       when the sheet is unscrolled. */
    body.has-buysheet .shop-product-side .shop-claim { scroll-margin-top: calc(var(--pm-sheet-head-h, 61px) + 28px); }

    /* Sticky so the title and the close stay reachable while a long licence
       list scrolls under them — the sheet is the scroll container, not the
       page. Full-bleed negative margins put its underline across the sheet's
       whole width rather than inside its padding. */
    body.has-buysheet .shop-sheet-head {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 12px;
        position: sticky;
        inset-block-start: 0;
        z-index: 1;
        margin: -16px -16px 12px;
        padding: 14px 16px;
        background: var(--bg2);
        border-block-end: 1px solid var(--border);
    }
    body.has-buysheet .shop-sheet-title {
        margin: 0;
        font-family: var(--display, inherit);
        font-size: 17px;
        font-weight: 600;
        color: var(--text);
    }
    body.has-buysheet .shop-sheet-close {
        flex: 0 0 auto;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 32px; height: 32px;
        padding: 0;
        border: 0;
        border-radius: 999px;
        background: none;
        color: var(--text3);
        cursor: pointer;
    }
    body.has-buysheet .shop-sheet-close svg { width: 16px; height: 16px; }
    body.has-buysheet .shop-sheet-close:hover { color: var(--text); background: var(--bg3); }
    body.has-buysheet .shop-sheet-close:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }

    /* Same rule, and this one shipped broken: display:block beat the hidden
       attribute, so the scrim dimmed the whole page with the sheet shut. That
       is the mobile breakage Krishna screenshotted — every control still
       worked, it just looked disabled. */
    body.has-buysheet .shop-sheet-scrim:not([hidden]) {
        display: block;
        position: fixed;
        inset: 0;
        z-index: 41;
        /* The token, not a literal: probe_portal_theme holds every sheet but
           tokens.css to naming no colour of its own, and --scrim is the
           portal's existing modal ground. */
        background: var(--scrim);
    }

    body.sheet-locked { overflow: hidden; }

    /* The sheet supplies its own surface, so the panel inside it drops the
       second border and the doubled padding that produced. */
    body.has-buysheet .shop-product-side .shop-buy { border: 0; padding: 0; background: none; }

    /* Buy now and the cart, pinned to the foot of the sheet so they are in
       reach however far the licence list runs — the sheet is the scroll
       container, the same reason the head above is sticky. The cart is an
       icon in the left quarter, Buy now the right three quarters.
       Full-bleed like the head: the negative inline margins cross the sheet's
       16px padding, and the negative inset-block-end lets it rest on the
       sheet's bottom edge instead of 16px (plus the safe area) above it,
       which is where a sticky box inside a padded scroller would otherwise
       stop. The padding gives the safe area back to the buttons.
       An owner's extra "Go to downloads" link spans the row above them. */
    body.has-buysheet .shop-product-side .shop-ctas {
        position: sticky;
        inset-block-end: calc(-16px - env(safe-area-inset-bottom, 0px));
        z-index: 1;
        display: grid;
        grid-template-columns: minmax(0, 1fr) minmax(0, 3fr);
        gap: 10px;
        margin-inline: -16px;
        padding: 12px 16px calc(12px + env(safe-area-inset-bottom, 0px));
        background: var(--bg2);
        border-block-start: 1px solid var(--border);
    }
    body.has-buysheet .shop-product-side .shop-ctas > * { grid-column: 1 / -1; order: 0; }
    body.has-buysheet .shop-product-side .shop-ctas > .shop-cart-add,
    body.has-buysheet .shop-product-side .shop-ctas > .shop-cta-incart { grid-column: 1; order: 1; }
    body.has-buysheet .shop-product-side .shop-ctas > [data-pm-buy] { grid-column: 2; order: 2; }
    body.has-buysheet .shop-product-side .shop-cart-add { display: flex; }
    body.has-buysheet .shop-product-side .shop-cart-add .shop-cta,
    body.has-buysheet .shop-product-side .shop-cta-incart {
        display: flex;
        align-items: center;
        justify-content: center;
        padding-inline: 0;
    }
    body.has-buysheet .shop-product-side .shop-cta-incart { background: var(--base-bg); border-color: var(--base); color: var(--base); }
    body.has-buysheet .shop-product-side .shop-cta-icon { display: block; }
    body.has-buysheet .shop-product-side .shop-cta-label {
        position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
        overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
    }

    /* The sheet stops at the checkout note.
       Everything the side column carries below that line is reference rather
       than decision: .shop-meta repeats the support, seats and cashback the
       licence rows above already state, .shop-assurance is a refund sentence
       pointing at the terms and privacy pages, and .shop-product-info is a spec table.
       On desktop they sit in a column with room to spare. In a sheet opened
       over the page to answer "which licence, and how much", they push the
       price, the licence choice and the button off-screen — the reader in the
       screenshot had to scroll past all three to reach Buy now.
       Scoped to the sheet: the desktop side column keeps all of it. */
    body.has-buysheet .shop-product-side .shop-meta,
    body.has-buysheet .shop-product-side .shop-assurance,
    body.has-buysheet .shop-product-side .shop-product-info { display: none; }
}

@media (prefers-reduced-motion: reduce) {
    body.has-buysheet .shop-product-side { transition: none; }
}

/* --- Licence spotlight ----------------------------------------------------
   The gradient card above the tabs. grid-column: 1 puts it in the same
   column as the gallery, the tabs and the panels beside it; it never sets
   its own grid-row, so it auto-places into the second of .shop-product-top's
   four declared rows (grid-template-rows: repeat(4, auto) — see that rule's
   own comment for why four, and for the bug a THIRD row-generating item
   here exposed in the row-span math above it).
   -------------------------------------------------------------------------- */
.shop-licence-spotlight {
    grid-column: 1;
    margin: 28px 0 0;
    padding: 22px;
    border-radius: var(--rl);
    border: 1px solid var(--border);
    background: linear-gradient(135deg, var(--amber-14), var(--teal-12) 75%);
}

.shop-licence-spotlight-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}
.shop-licence-spotlight-head h2 { margin: 0; font-size: 1.0625rem; }

/* A fixed 2-column matrix rather than flex-wrap: with flex-wrap, a third
   licence would sit alone on its own line at any width where two names
   plus their prices don't both fit, and how many fit was purely a function
   of how long the names happened to be. Two equal columns show two options
   side by side whatever their width, wrapping to a second ROW of two
   (rather than a ragged line) once there are more than two, and each
   column stretches or shrinks with the card — "auto resize" is this grid
   sizing its own columns, not a font-size trick, which is what keeps the
   price beside the name from truncating at typical card widths. */
.shop-licence-pills {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
}
@media (max-width: 24rem) {
    /* Two names plus two prices in two ~150px columns is tight enough on a
       small phone that even wrapping starts to look cramped — one column
       there reads better than two squeezed ones. */
    .shop-licence-pills { grid-template-columns: minmax(0, 1fr); }
}

/* A <button role="radio">, not a real radio input — see the comment beside
   its markup in product.php for why a genuine second radio sharing the
   sidebar's value could never both read as checked. font/appearance reset
   because this is a <button>, styled to read as the same pill either way.
   A rounded RECTANGLE rather than the fully-pill 999px radius the single-
   licence, unconstrained-width version used — a shape that reads as "pill"
   at its natural width reads as "just a rounded box" once the grid above
   stretches it to a whole column, so the radius here matches every other
   card's (var(--r)) rather than keeping a shape sized for content it no
   longer wraps tightly around. */
.shop-licence-pill {
    display: flex;
    min-width: 0;
    align-items: baseline;
    justify-content: center;
    flex-wrap: wrap;
    gap: 6px;
    padding: 9px 12px;
    border-radius: var(--r);
    border: 1px solid var(--border);
    background: var(--bg2);
    font: inherit;
    font-size: .875rem;
    line-height: 1.3;
    color: inherit;
    text-align: center;
    appearance: none;
    cursor: pointer;
    transition: background .15s ease, border-color .15s ease, color .15s ease;
}
.shop-licence-pill:hover { border-color: var(--amber); }
.shop-licence-pill:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }
.shop-licence-pill.is-current {
    background: var(--amber);
    border-color: var(--amber);
    color: var(--on-amber);
}
.shop-licence-pill.is-current:hover { border-color: var(--amber); }
.shop-licence-pill.is-solo { cursor: default; grid-column: 1 / -1; justify-content: flex-start; }
.shop-licence-pill-name { font-weight: 600; overflow-wrap: anywhere; }
.shop-licence-pill-price { font-size: .8125rem; color: var(--text2); white-space: nowrap; }
.shop-licence-pill.is-current .shop-licence-pill-price { color: var(--on-amber); opacity: .85; }

/* Same matrix as the pills above, and for the same reason: support and
   seats read as a pair (one licence's two headline terms), so they sit in
   the two columns together rather than wherever flex-wrap happened to
   break the line. Cashback has no natural partner to pair with — it spans
   both columns instead of stretching alone into just the left one. */
.shop-licence-benefits {
    list-style: none;
    margin: 18px 0 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
}
.shop-licence-benefit.is-cashback { grid-column: 1 / -1; }
@media (max-width: 24rem) {
    .shop-licence-benefits { grid-template-columns: minmax(0, 1fr); }
    .shop-licence-benefit.is-cashback { grid-column: 1; }
}
.shop-licence-benefit {
    display: flex;
    min-width: 0;
    align-items: center;
    gap: 6px;
    /* Trimmed from 14px side padding: reclaiming those 8px/chip is what lets
       "3 months of support" stay one line at a normal size in a two-column
       card, rather than fitTextToLines() having to shrink it to get there. */
    padding: 8px 10px;
    border-radius: var(--r);
    background: var(--bg-94);
    font-size: .8125rem;
    font-weight: 500;
    color: var(--text2);
}
/* The text alone shrinks to fit its chip — see [data-pm-fit-lines] in
   chrome.js — so it, not the icon beside it or the chip itself, needs
   min-width: 0 to be allowed to size below its own content's natural
   width in this flex row. */
.shop-licence-benefit > span { min-width: 0; }
.shop-licence-benefit svg { width: 15px; height: 15px; flex: 0 0 auto; color: var(--amber); }
.shop-licence-benefit.is-cashback { color: var(--teal-d, var(--text)); }
.shop-licence-benefit.is-cashback svg { color: var(--teal); }

/* The referral pitch — full width and visually its own card nested inside
   the spotlight, the same relationship .shop-product-info has to .shop-buy
   beside it: a distinct thing sitting inside a shared container rather than
   a fourth benefit chip, because it is an invitation to a different
   purchase, not a term of this one. */
.shop-referral-banner {
    margin: 18px 0 0;
    padding: 18px 20px;
    border-radius: var(--r);
    background: var(--bg-94);
    border: 1px solid var(--border);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
}
.shop-referral-copy h3 { margin: 0 0 4px; font-size: .9375rem; }
.shop-referral-copy p { margin: 0; font-size: .8125rem; line-height: 1.45; color: var(--text2); max-width: 38rem; }

/* No-JS fallback for every [data-pm-fit-lines] element — the referral
   pitch (2 lines) and the three benefit chips (1 line each; see
   .shop-licence-benefit span below). chrome.js's initFitText() shrinks each
   one's font until its own text fits that many lines; without it there is
   no font-size to shrink, so this clamps instead of letting the text run
   past its line count and push the layout around it taller than intended.
   .chrome-js is set at parse time by chrome.js itself, so these selectors
   only ever apply when that script genuinely did not run. */
html:not(.chrome-js) [data-pm-fit-lines="2"] {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
}
html:not(.chrome-js) [data-pm-fit-lines="1"] {
    display: block;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}
.shop-referral-code { display: flex; gap: 8px; flex: 0 0 auto; }
.shop-referral-code input {
    width: 8rem;
    padding: 8px 10px;
    border-radius: var(--r);
    border: 1px solid var(--border);
    background: var(--bg3);
    font: inherit;
    font-weight: 600;
    letter-spacing: .02em;
    color: var(--text);
}
.shop-referral-code button {
    padding: 8px 14px;
    border-radius: var(--r);
    border: 1px solid var(--amber);
    background: none;
    color: var(--amber);
    font: inherit;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
}
.shop-referral-code button:hover { background: var(--amber-bg); }

@media (max-width: 26rem) {
    /* Narrow enough that the banner's two halves no longer fit on one row
       without crowding — full width beats a cramped side-by-side. */
    .shop-referral-banner { flex-direction: column; align-items: stretch; }
    .shop-referral-code { flex: 1 1 auto; }
    .shop-referral-code input { flex: 1 1 auto; width: auto; }
}

/* --- Product section tabs ------------------------------------------------
   Sticky under the header so the section a reader is in stays named while a
   long description scrolls. Horizontally scrollable at phone width rather
   than wrapping to two rows: a wrapped tab bar changes height as tabs move
   between rows, and a sticky element that changes height shifts the page
   under the reader every time.
   -------------------------------------------------------------------------- */

.shop-tabs {
    display: flex;
    gap: 4px;
    margin: 32px 0 0;
    padding-block-end: 2px;
    border-block-end: 1px solid var(--border);
    overflow-x: auto;
    scrollbar-width: none;
    position: sticky;
    /* Same correction as the side column, and it was the same bug one scroll
       further down the page: the tab row is what names the section being read,
       so it is the last thing that can afford to be hidden by the nav. No
       extra gap — a tab strip reads as attached to the bar above it. */
    top: var(--pt-sticky-top, 0px);
    /* And the same distance again for scrollIntoView(), which chrome.js calls
       on this strip when a #panel- deep link names a tab other than the one
       the page opens on. Without it that call aligns the strip with the
       VIEWPORT top, which is where the nav is. Sticky would peel it back into
       view a moment later, but the panel beneath it starts a nav's height too
       high either way. */
    scroll-margin-block-start: var(--pt-sticky-top, 0px);
    z-index: 20;
    background: var(--bg);
}
.shop-tabs::-webkit-scrollbar { display: none; }

.shop-tab {
    flex: 0 0 auto;
    padding: 12px 16px;
    color: var(--text2);
    text-decoration: none;
    font-weight: 600;
    font-size: 14px;
    white-space: nowrap;
    border-block-end: 2px solid transparent;
    border-radius: var(--r) var(--r) 0 0;
    margin-block-end: -3px;
    transition: color .15s ease, background .15s ease;
}
.shop-tab:hover { color: var(--text); background: var(--bg2); }
/* Stronger than a thin underline alone: a filled pill behind the label so the
   active tab reads at a glance, matching .shop-sort a.is-current's treatment
   for the same kind of state elsewhere on this page. */
.shop-tab.is-current { color: var(--amber-d); background: var(--amber-bg); border-block-end-color: var(--amber); }
.shop-tab:focus-visible { outline: 2px solid var(--amber); outline-offset: -2px; }

/* A panel the script has not hidden is simply a section, which is what a page
   with no JS shows for all of them. */
.shop-tabpanel[hidden] { display: none; }

/* The tabs and panels are grid children of .shop-product-top, pinned to the
   left column so the buy panel keeps the right one and stays stuck beside
   them the whole way down. Pinned explicitly rather than left to auto-flow:
   the side column is the second child in the DOM and would otherwise take a
   row of its own below the gallery. */
.shop-gallery,
.shop-tabs,
.shop-tabpanel { grid-column: 1; }

/* -1, not a literal span count (99, say, to comfortably outrun any panel):
   a literal span forces that many row TRACKS to exist even though column 1
   only ever has up to four rows with real content in them, and
   .shop-product-top's gap applies between every track that span creates —
   dozens of empty 28px gaps stacked under a short panel like Support or
   Comments, which was the dead space a reader landed in on a direct link
   to one of them.
   -1 only works as "however many rows column 1 really needs" because
   .shop-product-top now DECLARES that many rows explicitly
   (grid-template-rows: repeat(4, auto), see its own comment) — -1 counts
   from the last line of the EXPLICIT grid, not from wherever auto-placed
   items end up, so with no explicit row template at all -1 was equal to 1
   and this never spanned anything: see that same comment for the gap this
   produced instead once .shop-product-side had nothing but its own full
   height to force into that single row. */
.shop-product-side { grid-column: 2; grid-row: 1 / -1; }

/* Above the buy panel's z-index so a sticky tab bar scrolling under the
   sidebar does not slide over its edge. */
.shop-tabs { z-index: 21; }

@media (max-width: 60rem) {
    /* One column: every child takes it, and the pinned side column would
       otherwise ask for a second that does not exist. */
    .shop-gallery,
    .shop-tabs,
    .shop-tabpanel,
    .shop-product-side { grid-column: 1; grid-row: auto; }
}

/* The information card's changelog row. A button, not a link: it opens the
   same modal the action row opens and goes to no URL of its own. */
.shop-info-link {
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    font-weight: 600;
    color: var(--amber);
    cursor: pointer;
    text-decoration: underline;
}

/* --- Reference-marketplace skin -----------------------------------------
   The palette itself lives in tokens.css under body.shop; these are the shape
   and order changes that palette cannot express. No colour literals here —
   probe_portal_theme holds this sheet to naming none.
   ------------------------------------------------------------------------ */

/* The reference sets the price in body text, not in the accent, and spends the
   accent on the order total instead. */
.shop-product-price { color: var(--text); }

/* Add to cart above, Buy below — the reference's order. Done with flex order
   rather than by moving the markup, because the buy link and the add form are
   in different branches of an if/else and reordering the PHP would duplicate
   both. */
.shop-ctas .shop-cta.is-secondary,
.shop-ctas .shop-cart-add { order: 1; }
.shop-ctas .shop-cta.is-primary { order: 2; }

.shop-checkout-note {
    margin: 10px 0 0;
    text-align: center;
    font-size: 12px;
    color: var(--text3);
}

/* The reference separates label from value with a colon column. */
.shop-product-info dl > div { display: grid; grid-template-columns: minmax(0, 1fr) 10px auto; }
.shop-product-info dt::after { content: ":"; display: block; grid-column: 2; }
.shop-product-info dt { display: contents; }

.shop-tab { display: inline-flex; align-items: center; gap: 7px; }
.shop-tab svg { width: 15px; height: 15px; flex: 0 0 auto; }

/* NO desktop buy bar. The reference has one because its sidebar eventually
   scrolls off; ours does not — .shop-product-side spans the whole grid and
   stays stuck, and measured at the very bottom of the document the buy panel
   is still on screen. A bar restoring access to a panel that never leaves is
   a duplicate of a visible control, so it exists on phones only, where the
   panel really is a closed sheet. */

/* --- Support panel ------------------------------------------------------- */
.shop-support-intro { margin: 0 0 18px; color: var(--text2); }
.shop-support-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
    gap: 14px;
}
.shop-support-card {
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: var(--rl);
    padding: 18px;
}
.shop-support-card h3 { margin: 0 0 8px; font-size: 15px; }
.shop-support-card p { margin: 0 0 10px; color: var(--text2); font-size: 14px; }
.shop-support-note { font-size: 13px !important; color: var(--text3) !important; }
.shop-support-link { font-weight: 600; color: var(--amber); text-decoration: none; }
.shop-support-link:hover { text-decoration: underline; }

/* The licence card's own terms — support, seats and cashback for THAT line,
   so the difference between two licences is legible before one is chosen. */
.shop-license-option-terms {
    grid-column: 2 / -1;
    color: var(--text3);
    font-size: 12px;
    overflow-wrap: anywhere;
}

/* The sheet's header is a phone affordance only. On every wider viewport
   .shop-product-side is simply the sticky side column, where a panel that
   titles itself "Purchase options" and offers to close is noise — there is
   nothing to close it from. Hidden by default and revealed inside the
   has-buysheet block above, so the default state is the quiet one. */
.shop-sheet-head { display: none; }

/* The struck-through retail price on a licence card. Sits after the live
   price, quieter and smaller, the same relationship the grid card uses. */
.shop-license-option-was {
    margin-inline-start: 6px;
    color: var(--text3);
    font-weight: 500;
    font-size: 0.85em;
}

/* The hero price's struck-through retail figure. [hidden] needs the explicit
   display:none because the rule above it sets one — the attribute alone loses
   to any display declaration, which is the bug the sheet scrim shipped with. */
.shop-product-was {
    margin-inline-start: 8px;
    color: var(--text3);
    font-size: 0.6em;
    font-weight: 500;
}
.shop-product-was[hidden] { display: none; }

/* --- Buyer-written posts: questions and suggestions ---------------------- */
.shop-post-intro { margin: 0 0 16px; color: var(--text2); }
.shop-post-flash {
    margin: 0 0 14px; padding: 11px 14px; border-radius: var(--r);
    background: var(--teal-bg); color: var(--teal-d); font-weight: 600; font-size: 14px;
}
.shop-post-form { display: flex; flex-direction: column; gap: 8px; margin-block-end: 22px; }
.shop-post-label { font-weight: 600; font-size: 14px; }
.shop-post-form textarea {
    width: 100%; padding: 11px 13px; border: 1px solid var(--border);
    border-radius: var(--r); background: var(--bg2); color: var(--text);
    font: inherit; resize: vertical;
}
.shop-post-form textarea:focus-visible { outline: 2px solid var(--amber); outline-offset: 1px; }
.shop-post-note { margin: 0; font-size: 12.5px; color: var(--text3); }
.shop-post-form button {
    align-self: flex-start; padding: 10px 20px; border: 0; border-radius: var(--r);
    background: var(--base); color: var(--on-base); font-weight: 700; cursor: pointer;
}
.shop-post-signin { margin: 0 0 18px; }
.shop-post-none { margin: 0; color: var(--text2); }
.shop-posts { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 14px; }
.shop-post { border: 1px solid var(--border); border-radius: var(--rl); padding: 15px 17px; background: var(--bg2); }
.shop-post-head { margin: 0 0 6px; display: flex; gap: 10px; align-items: baseline; font-size: 13px; }
.shop-post-head time { color: var(--text3); }
.shop-post-body { margin: 0; color: var(--text2); line-height: 1.55; overflow-wrap: anywhere; }
.shop-post-reply {
    margin-block-start: 12px; padding-inline-start: 13px;
    border-inline-start: 3px solid var(--amber);
}
.shop-post-reply-head { margin: 0 0 3px; font-size: 12.5px; font-weight: 700; color: var(--amber); }
.shop-post-reply p { margin: 0; color: var(--text2); font-size: 14px; }

/* FAQs sit at the foot of the Support panel rather than a tab of their own. */
.shop-support-faqs { margin-top: 2.5rem; }

/* Add-ons tab. Information only — nothing here links or buys — so the cards
   are plain panels in the Support cards' treatment, with the price or the
   "Included" mark as the one thing on each that reads first. */
.shop-addons-intro { margin: 0 0 1.25rem; color: var(--text2); }
.shop-addons[hidden], .shop-addon-group[hidden], .shop-addon-filters[hidden] { display: none; }

.shop-addon-filters {
    display: flex; gap: 8px; flex-wrap: wrap;
    margin: 0 0 1.75rem;
}
.shop-addon-filter {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 7px 12px; border-radius: 999px;
    border: 1px solid var(--border); background: var(--bg2);
    color: var(--text2); font: inherit; font-size: 13.5px; cursor: pointer;
}
.shop-addon-filter span { color: var(--text3); font-size: 12.5px; font-variant-numeric: tabular-nums; }
.shop-addon-filter:hover { border-color: var(--border2); color: var(--text); }
.shop-addon-filter.is-current { border-color: var(--amber); background: var(--amber-bg); color: var(--text); }
.shop-addon-filter.is-current span { color: var(--amber-d); }
.shop-addon-filter:focus-visible, .shop-addon-more:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }

.shop-addon-group + .shop-addon-group { margin-top: 2rem; }
.shop-addon-group h3 { margin: 0 0 .85rem; font-size: 15px; color: var(--text); }

.shop-addon-grid {
    list-style: none; margin: 0; padding: 0;
    display: grid; gap: 12px;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
}
.shop-addon-card {
    display: flex; flex-direction: column;
    background: var(--bg2); border: 1px solid var(--border);
    border-radius: var(--rl); padding: 16px 18px;
}
.shop-addon-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.shop-addon-head h4 { margin: 0; font-size: 15px; font-weight: 600; line-height: 1.35; color: var(--text); }
.shop-addon-price { flex-shrink: 0; font-weight: 700; color: var(--amber-d); font-variant-numeric: tabular-nums; white-space: nowrap; }
.shop-addon-included {
    flex-shrink: 0; display: inline-flex; align-items: center; gap: 4px;
    font-size: 13px; font-weight: 600; color: var(--teal-d); white-space: nowrap;
}
.shop-addon-card.is-included { background: var(--bg); }

.shop-addon-tagline { margin: .35rem 0 0; font-size: 13.5px; color: var(--text2); }
.shop-addon-desc { margin: .5rem 0 0; font-size: 13.5px; line-height: 1.55; color: var(--text3); }
.shop-addon-desc.is-clamped {
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; line-clamp: 3; overflow: hidden;
}
.shop-addon-more {
    align-self: flex-start; margin-top: .5rem; padding: 0;
    background: none; border: 0; font: inherit; font-size: 13px; font-weight: 600;
    color: var(--amber-d); cursor: pointer;
}
.shop-addon-more:hover { text-decoration: underline; }

@media (max-width: 640px) {
    .shop-addon-filters { flex-wrap: nowrap; overflow-x: auto; margin-inline: -16px; padding-inline: 16px; scrollbar-width: none; }
    .shop-addon-filters::-webkit-scrollbar { display: none; }
    .shop-addon-filter { flex-shrink: 0; }
    .shop-addon-grid { grid-template-columns: 1fr; }
}

/* ---- theme gallery (_theme_gallery.php) ----
   Shop front only. Real showcase screenshots in a browser frame, one swipeable
   row, so twenty-odd themes cost one band of the page rather than a grid of
   their own. */

.shop-themes { margin: 0 0 72px; }
.shop-themes__head {
  display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between;
  gap: 18px 32px; margin: 0 0 22px;
}
.shop-themes__eyebrow {
  margin: 0 0 8px; font-family: var(--mono); font-size: .75rem; letter-spacing: .08em;
  text-transform: uppercase; color: var(--amber-d);
}
.shop-themes__head h2 {
  margin: 0; font-family: var(--display); font-weight: 600;
  font-size: clamp(26px, 1.6vw + 16px, 38px); line-height: 1.12; letter-spacing: -.015em;
  text-wrap: balance;
}
.shop-themes__sub { margin: 10px 0 0; color: var(--text2); font-size: 1.0625rem; max-width: 52ch; }

.shop-themes__views {
  display: inline-flex; align-items: center; gap: 2px; padding: 4px;
  background: var(--bg3); border: 1px solid var(--border); border-radius: 999px;
}
.shop-themes__views button {
  font: inherit; font-size: 13px; font-weight: 600; padding: 7px 14px;
  border: 0; border-radius: 999px; background: transparent; color: var(--text2); cursor: pointer;
}
.shop-themes__views button:hover { color: var(--text); }
.shop-themes__views button.is-active { background: var(--bg2); color: var(--text); box-shadow: var(--shadow-card); }
.shop-themes__views-sep { width: 1px; height: 18px; margin: 0 4px; background: var(--border); }

.shop-themes__upnext {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px;
  margin: 0 0 18px; padding: 12px 14px;
  border: 1px dashed var(--border); border-radius: var(--rl); background: var(--amber-bg);
}
.shop-themes__upnext-label { font-size: 13px; font-weight: 700; color: var(--amber-d); }
.shop-themes__upnext ul { display: flex; flex-wrap: wrap; gap: 8px; margin: 0; padding: 0; list-style: none; }
.shop-themes__upnext button {
  display: inline-flex; align-items: baseline; gap: 8px;
  font: inherit; font-size: 13px; padding: 6px 12px; cursor: pointer;
  border: 1px solid var(--border); border-radius: 999px; background: var(--bg2); color: var(--text);
}
.shop-themes__upnext button:hover { border-color: var(--amber-l); }
.shop-themes__upnext button span { font-family: var(--mono); font-size: 12px; color: var(--text2); }

.shop-themes__tabs { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 18px; }
.shop-themes__tabs button, .shop-themes__tabs a {
  font: inherit; font-size: 14px; font-weight: 600; padding: 8px 16px; cursor: pointer;
  border: 1px solid var(--border); border-radius: 999px; background: var(--bg2); color: var(--text2);
}
.shop-themes__tabs a { text-decoration: none; }
.shop-themes__tabs button span { margin-inline-start: 4px; font-family: var(--mono); font-size: 12px; font-weight: 400; color: var(--text3); }
.shop-themes__tabs button:hover, .shop-themes__tabs a:hover { color: var(--text); }
.shop-themes__tabs button.is-active, .shop-themes__tabs a.is-active { background: var(--text); border-color: var(--text); color: var(--bg2); }
.shop-themes__tabs button.is-active span { color: inherit; opacity: .7; }

.shop-themes__viewport { position: relative; }
.shop-themes__track {
  display: flex; gap: 20px; margin: 0; padding: 4px 2px 14px; list-style: none;
  overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: thin;
  overscroll-behavior-x: contain;
}
.shop-theme-card {
  flex: 0 0 min(360px, 82vw); scroll-snap-align: start;
  display: flex; flex-direction: column;
  background: var(--bg2); border: 1px solid var(--border); border-radius: var(--rl);
  overflow: hidden; box-shadow: var(--shadow-card);
  transition: box-shadow .18s ease, transform .18s ease;
}
.shop-theme-card[hidden] { display: none; }
.shop-theme-card:hover { box-shadow: var(--shadow-menu); transform: translateY(-2px); }

.shop-theme-card__media {
  position: relative; display: block; width: 100%; padding: 0; cursor: zoom-in;
  border: 0; border-block-end: 1px solid var(--border); background: var(--bg3);
  aspect-ratio: 16 / 10; overflow: hidden;
}
.shop-theme-card__chrome {
  position: absolute; inset-inline: 0; inset-block-start: 0; z-index: 1;
  display: flex; gap: 5px; align-items: center; height: 20px; padding-inline: 10px;
  background: var(--bg2); border-block-end: 1px solid var(--border);
}
.shop-theme-card__chrome i { width: 7px; height: 7px; border-radius: 50%; background: var(--border); }
.shop-theme-card__media img {
  position: absolute; inset: 20px 0 0; width: 100%; height: calc(100% - 20px);
  object-fit: cover; object-position: top center;
}
/* Phone view: the tall shot stands in a phone outline, centred in the same
   box, so switching view never changes the card's height. */
.shop-themes.is-phone .shop-theme-card__chrome { display: none; }
.shop-themes.is-phone .shop-theme-card__media img {
  inset: 12px auto 0 50%; width: auto; height: calc(100% - 12px); aspect-ratio: 390 / 844;
  transform: translateX(-50%);
  border: 4px solid var(--text); border-block-end: 0; border-radius: 18px 18px 0 0;
}
[dir="rtl"] .shop-themes.is-phone .shop-theme-card__media img { transform: translateX(50%); inset: 12px 50% 0 auto; }

.shop-theme-card__body { display: flex; flex-direction: column; flex: 1; padding: 16px 18px 18px; }
.shop-theme-card__title { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.shop-theme-card__title h3 { margin: 0; font-size: 1.0625rem; font-weight: 700; }
.shop-theme-card__date {
  flex-shrink: 0; font-family: var(--mono); font-size: 12px; color: var(--amber-d);
  padding: 2px 8px; border-radius: 999px; background: var(--amber-bg);
}
.shop-theme-card__foot {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin-top: auto; padding-top: 14px;
}
.shop-theme-card__badge {
  font-size: 12px; font-weight: 600; padding: 4px 10px; border-radius: 999px;
  background: var(--bg3); color: var(--text2);
}
.shop-theme-card__badge.is-included { background: var(--teal-bg); color: var(--teal-d); }
.shop-theme-card__more {
  font: inherit; font-size: 13px; font-weight: 600; padding: 0; cursor: pointer;
  border: 0; background: none; color: var(--base);
}
.shop-theme-card__more:hover { text-decoration: underline; }

.shop-themes__nav {
  display: none;
  position: absolute; top: 38%; transform: translateY(-50%); z-index: 2;
  width: 42px; height: 42px; align-items: center; justify-content: center;
  border-radius: 50%; border: 1px solid var(--border); background: var(--bg2);
  color: var(--text); cursor: pointer; box-shadow: var(--shadow-menu);
}
.shop-themes__nav:hover { border-color: var(--amber-l); color: var(--amber-d); }
.shop-themes__nav svg { width: 18px; height: 18px; }
.shop-themes__nav.is-prev { inset-inline-start: -14px; }
.shop-themes__nav.is-next { inset-inline-end: -14px; }
[dir="rtl"] .shop-themes__nav svg { transform: scaleX(-1); }
@media (min-width: 64rem) { .shop-themes__nav { display: flex; } }

.shop-themes__how { margin: 10px 0 0; font-size: 14px; color: var(--text2); }
.shop-themes__how a { font-weight: 600; color: var(--base); }

/* The modal: one theme, every screen, in the view the section is set to. */
.shop-theme-modal {
  width: min(960px, calc(100vw - 32px)); max-height: calc(100vh - 48px); padding: 0;
  border: 1px solid var(--border); border-radius: var(--rl);
  background: var(--bg2); color: var(--text); box-shadow: var(--shadow-menu);
}
.shop-theme-modal::backdrop { background: rgba(16, 24, 40, .55); backdrop-filter: blur(2px); }
.shop-theme-modal__head {
  position: sticky; inset-block-start: 0; z-index: 1;
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px;
  padding: 18px 22px; background: var(--bg2); border-block-end: 1px solid var(--border);
}
.shop-theme-modal__head > div:first-child { flex: 1 1 200px; min-width: 0; }
.shop-theme-modal__head h2 { margin: 0; font-family: var(--display); font-size: 1.5rem; font-weight: 600; }
.shop-theme-modal__head p { margin: 4px 0 0; font-size: 13px; color: var(--teal-d); font-weight: 600; }
.shop-theme-modal__x {
  display: inline-flex; padding: 9px; border: 0; border-radius: 10px; cursor: pointer;
  background: var(--bg3); color: var(--text2);
}
.shop-theme-modal__x:hover { color: var(--text); }
.shop-theme-modal__desc { margin: 16px 22px 0; color: var(--text2); line-height: 1.6; }
.shop-theme-modal__shots { display: grid; gap: 22px; padding: 18px 22px 24px; color: var(--text2); }
.shop-theme-modal__shots.is-phone { grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); }
.shop-theme-modal__shots figure { margin: 0; }
.shop-theme-modal__shots img {
  display: block; width: 100%; height: auto; background: var(--bg3);
  border: 1px solid var(--border); border-radius: var(--r);
}
.shop-theme-modal__shots figcaption { display: flex; flex-wrap: wrap; gap: 4px 10px; margin-top: 8px; font-size: 13px; }
.shop-theme-modal__shots figcaption strong { color: var(--text); }
.shop-theme-modal__shots figcaption span { color: var(--amber-d); }

@media (max-width: 560px) {
  .shop-themes__head { align-items: flex-start; }
  /* One swipeable line each rather than a column of pills that pushes the
     cards a screen down. */
  .shop-themes__upnext { display: block; padding-inline: 0; }
  .shop-themes__upnext-label { display: block; margin-bottom: 8px; padding-inline: 14px; }
  .shop-themes__upnext ul,
  .shop-themes__tabs { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
  .shop-themes__upnext ul { min-width: 0; padding-inline: 14px; }
  .shop-themes__upnext ul::-webkit-scrollbar,
  .shop-themes__tabs::-webkit-scrollbar { display: none; }
  .shop-themes__upnext li, .shop-themes__tabs button { flex-shrink: 0; }
  .shop-themes__upnext button, .shop-themes__tabs button { white-space: nowrap; }
  /* The look tabs (addon.php) are few enough to wrap instead. */
  .shop-themes__tabs.is-wrap { flex-wrap: wrap; overflow: visible; }
  .shop-theme-modal__head { padding: 14px 16px; }
  .shop-theme-modal__desc { margin-inline: 16px; }
  .shop-theme-modal__shots { padding-inline: 16px; }
}
@media (prefers-reduced-motion: reduce) {
  .shop-theme-card, .shop-theme-card:hover { transition: none; transform: none; }
}

/* ---- shop front bands (_home_platforms.php, _home_categories.php) ----
   The front reads as a sequence of bands — platforms, themes, free items,
   add-ons by need — before the full catalogue grid. Each band opens with the
   same left-aligned head so the page scans as one system. */

.shop-section-head { max-width: 46rem; margin: 0 0 24px; }
.shop-section-head__eyebrow {
  margin: 0 0 8px; font-family: var(--mono); font-size: .75rem; letter-spacing: .08em;
  text-transform: uppercase; color: var(--amber-d);
}
.shop-section-head h2 {
  margin: 0; font-family: var(--display); font-weight: 600;
  font-size: clamp(26px, 1.6vw + 16px, 38px); line-height: 1.12; letter-spacing: -.015em;
  text-wrap: balance;
}
.shop-section-head p:not(.shop-section-head__eyebrow) { margin: 10px 0 0; color: var(--text2); font-size: 1.0625rem; }

.shop-hero__ctas { display: flex; flex-wrap: wrap; gap: 10px; margin: 22px 0 0; }
.shop-hero__ctas .shop-cta { padding: 12px 22px; border-radius: 999px; font-size: 14.5px; }
.shop-hero__inner--solo .shop-hero__ctas { justify-content: center; }
@media (max-width: 860px) { .shop-hero__ctas { justify-content: center; } }

.shop-platforms { margin: 0 0 72px; }
.shop-platforms__grid {
  display: grid; gap: 20px; margin: 0; padding: 0; list-style: none;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr));
}
.shop-platform-card {
  display: flex; flex-direction: column; min-width: 0;
  background: var(--bg2); border: 1px solid var(--border); border-radius: var(--rl);
  overflow: hidden; box-shadow: var(--shadow-card);
  transition: box-shadow .18s ease, transform .18s ease;
}
.shop-platform-card:hover { box-shadow: var(--shadow-menu); transform: translateY(-2px); }
/* A featured platform takes the whole first row, picture beside the copy, so
   the flagship reads as the flagship and the rest line up beneath it. */
@media (min-width: 64rem) {
  .shop-platform-card.is-featured { grid-column: 1 / -1; flex-direction: row; }
  .shop-platform-card.is-featured .shop-platform-card__media { flex: 0 0 56%; }
  .shop-platform-card.is-featured .shop-platform-card__body { justify-content: center; padding: 28px 36px; }
  .shop-platform-card.is-featured .shop-platform-card__body h3 { font-size: 1.75rem; font-family: var(--display); font-weight: 600; }
  .shop-platform-card.is-featured .shop-platform-card__tagline { font-size: 15.5px; }
  .shop-platform-card.is-featured .shop-platform-card__foot { margin-top: 22px; }
}
/* Phones: one swipeable row instead of five full-height cards in a column. */
@media (max-width: 640px) {
  .shop-platforms__grid {
    display: flex; overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none;
    margin-inline: calc(var(--gap) * -1); padding: 2px var(--gap) 10px;
  }
  .shop-platforms__grid::-webkit-scrollbar { display: none; }
  .shop-platform-card { flex: 0 0 82%; scroll-snap-align: center; }
}
.shop-platform-card__media {
  position: relative; display: block; aspect-ratio: 590 / 300; overflow: hidden; background: var(--bg3);
}
.shop-platform-card__media img { display: block; width: 100%; height: 100%; object-fit: cover; transition: transform .35s ease; }
.shop-platform-card:hover .shop-platform-card__media img { transform: scale(1.04); }
.shop-platform-card__body { display: flex; flex-direction: column; flex: 1; padding: 18px 20px 20px; }
.shop-platform-card__body h3 { margin: 0; font-size: 1.1875rem; font-weight: 700; line-height: 1.25; }
.shop-platform-card__body h3 a { color: var(--text); text-decoration: none; }
.shop-platform-card__body h3 a:hover { color: var(--base); }
.shop-platform-card__tagline { margin: 8px 0 0; font-size: 14px; line-height: 1.55; color: var(--text2); }
.shop-platform-card .shop-card-rating { margin: 10px 0 0; }
.shop-platform-card__foot {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px;
  margin-top: auto; padding-top: 18px;
}
.shop-platform-card__price { margin: 0; display: flex; align-items: baseline; gap: 8px; }
.shop-platform-card__price strong { font-size: 1.375rem; font-weight: 700; color: var(--text); }
.shop-platform-card__actions { display: flex; gap: 8px; }
.shop-platform-card__actions .shop-cta { padding: 9px 16px; font-size: 14px; }

.shop-needs { margin: 72px 0 72px; }
.shop-needs__grid {
  display: grid; gap: 14px; margin: 0; padding: 0; list-style: none;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr));
}
.shop-need-tile {
  display: flex; gap: 14px; align-items: flex-start; height: 100%; box-sizing: border-box;
  padding: 18px; text-decoration: none; color: var(--text);
  background: var(--bg2); border: 1px solid var(--border); border-radius: var(--rl);
  transition: border-color .15s ease, box-shadow .15s ease;
}
.shop-need-tile:hover { border-color: var(--base); box-shadow: var(--shadow-card); }
.shop-need-tile__icon {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 42px; height: 42px; border-radius: 10px; background: var(--base-bg); color: var(--base);
}
.shop-need-tile__icon svg { width: 22px; height: 22px; }
.shop-need-tile__text { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.shop-need-tile__text strong { font-size: 15.5px; }
.shop-need-tile__count { font-family: var(--mono); font-size: 12px; color: var(--text3); }
.shop-need-tile__subs { margin-top: 4px; font-size: 13px; line-height: 1.45; color: var(--text2); }

/* The free-items band now follows the theme gallery near the top of the
   front, which already closes on its own spacing. */
/* On the front it sits among the left-aligned bands, so it takes their head;
   the free files page keeps its own centred one. */
.shop-themes + .shop-free-items { margin-top: 0; padding: 0; border-top: 0; }
.shop-themes + .shop-free-items .shop-free-items__head { text-align: start; margin-inline: 0; }

@media (prefers-reduced-motion: reduce) {
  .shop-platform-card, .shop-platform-card:hover,
  .shop-platform-card:hover .shop-platform-card__media img { transition: none; transform: none; }
}
@media (max-width: 560px) {
  /* Two tiles a row on a phone, name and count only — the subcategory line is
     what the category page itself shows. */
  .shop-needs__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .shop-need-tile { flex-direction: column; gap: 10px; padding: 14px; }
  .shop-need-tile__subs { display: none; }
  .shop-platform-card__actions .shop-cta { padding: 9px 12px; white-space: nowrap; }
}

/* ---- richer product cards (shop_product_card()) ---- */
.shop-card-kicker {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px;
  margin: 14px 16px 0; font-size: 12px; color: var(--text3);
}
.shop-card-kicker + h3 { margin-top: 6px; }
.shop-card-kind {
  font-size: 11px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  padding: 3px 8px; border-radius: 999px;
}
.shop-card-kind.is-platform { background: var(--base-bg); color: var(--base); }
.shop-card-kind.is-service { background: var(--amber-bg); color: var(--amber-d); }
.shop-card-works {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px 6px;
  margin: 10px 16px 0; font-size: 12px; color: var(--text3);
}
.shop-card-works-chip {
  padding: 2px 8px; border-radius: 999px; border: 1px solid var(--border);
  color: var(--text2); background: var(--bg);
}

/* ---- catalogue filters (_filters.php) ---- */
.shop-filters {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  margin: 0 0 14px;
}
.shop-filters__label {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 13px; font-weight: 600; color: var(--text2);
}
.shop-filter select {
  font: inherit; font-size: 13.5px; color: var(--text);
  padding: 8px 32px 8px 14px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--border); background-color: var(--bg2);
  appearance: none; -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%238a929c' stroke-width='2.5' stroke-linecap='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 12px center;
}
[dir="rtl"] .shop-filter select { padding: 8px 14px 8px 32px; background-position: left 12px center; }
.shop-filter select:hover { border-color: var(--text3); }
.shop-filter select:focus-visible { outline: 2px solid var(--base); outline-offset: 2px; }
.shop-filter.is-set select { border-color: var(--base); background-color: var(--base-bg); color: var(--base); font-weight: 600; }
.shop-filters__apply {
  font: inherit; font-size: 13.5px; font-weight: 600; padding: 8px 16px; cursor: pointer;
  border: 0; border-radius: 999px; background: var(--base); color: var(--on-base);
}
.shop-filters__apply[hidden] { display: none; }
.shop-filters__active { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; flex-basis: 100%; }
.shop-filters__chip {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 13px; font-weight: 600; text-decoration: none;
  padding: 5px 10px 5px 12px; border-radius: 999px;
  background: var(--text); color: var(--bg2);
}
.shop-filters__chip:hover { opacity: .85; }
.shop-filters__clear { font-size: 13px; font-weight: 600; color: var(--base); }

@media (max-width: 560px) {
  /* One swipeable line of selects; the active chips wrap beneath. */
  .shop-filters { flex-wrap: wrap; }
  .shop-filters__label { flex-basis: 100%; }
  .shop-filter { flex: 1 1 calc(50% - 5px); }
  .shop-filter select { width: 100%; }
}

/* ---- theme pages (theme.php, themes.php) ---- */
.shop-themes__all { display: inline-block; margin-top: 10px; font-size: 14px; font-weight: 600; color: var(--base); }
.shop-themes__head h1 {
  margin: 0; font-family: var(--display); font-weight: 600;
  font-size: clamp(30px, 2.4vw + 18px, 48px); line-height: 1.08; letter-spacing: -.02em;
}
.shop-theme-card__title h3 a { color: inherit; text-decoration: none; }
.shop-theme-card__title h3 a:hover { color: var(--base); text-decoration: underline; }
.shop-theme-modal__page { margin: 10px 22px 0; font-size: 14px; font-weight: 600; }
.shop-theme-modal__page a { color: var(--base); }
/* /themes: the same cards, wrapped into a grid instead of one row. */
.shop-themes--grid .shop-themes__track {
  display: grid; overflow: visible; scroll-snap-type: none;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));
}

.shop-theme-page { padding-top: 2.5rem; }
.shop-theme-hero {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr); gap: 48px; align-items: center;
  margin-bottom: 64px;
}
.shop-theme-hero h1 {
  margin: 0; font-family: var(--display); font-weight: 600;
  font-size: clamp(34px, 2.6vw + 20px, 56px); line-height: 1.05; letter-spacing: -.02em;
}
.shop-theme-hero__desc { margin: 14px 0 0; font-size: 1.0625rem; line-height: 1.6; color: var(--text2); }
.shop-theme-hero__facts { display: flex; flex-wrap: wrap; gap: 8px; margin: 18px 0 0; padding: 0; list-style: none; }
.shop-theme-hero__facts li {
  font-size: 13px; padding: 5px 12px; border-radius: 999px;
  background: var(--bg2); border: 1px solid var(--border); color: var(--text2);
}
.shop-theme-hero__facts li.is-occasion { background: var(--amber-bg); border-color: transparent; color: var(--amber-d); font-weight: 600; }
.shop-theme-get {
  margin-top: 24px; padding: 18px 20px; border-radius: var(--rl);
  background: var(--bg2); border: 1px solid var(--border);
}
.shop-theme-get p { margin: 0; font-size: 14px; line-height: 1.55; color: var(--text2); }
.shop-theme-get__badge.shop-theme-get__badge {
  display: inline-block; margin-bottom: 8px; font-size: 12px; font-weight: 700;
  padding: 4px 10px; border-radius: 999px; background: var(--bg3); color: var(--text2);
}
.shop-theme-get__badge.is-included { background: var(--teal-bg); color: var(--teal-d); }
.shop-theme-get__actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 14px; }
.shop-theme-get__actions .shop-cta { padding: 10px 18px; font-size: 14px; border-radius: 999px; }

.shop-theme-hero__visual { position: relative; padding-bottom: 28px; }
.shop-theme-hero__desktop {
  position: relative; border-radius: var(--rl); overflow: hidden;
  border: 1px solid var(--border); box-shadow: var(--shadow-menu); background: var(--bg3);
  padding-top: 20px;
}
.shop-theme-hero__desktop img { display: block; width: 100%; height: auto; }
.shop-theme-hero__phone {
  position: absolute; inset-inline-end: -10px; bottom: 0; width: 24%;
  border: 5px solid var(--text); border-radius: 22px; overflow: hidden;
  box-shadow: var(--shadow-menu); background: var(--text);
}
.shop-theme-hero__phone img { display: block; width: 100%; height: auto; }

.shop-theme-screens, .shop-theme-videos, .shop-theme-games, .shop-theme-compare, .shop-theme-changelog, .shop-theme-more { margin-bottom: 64px; }
.shop-theme-screens__head {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 14px;
  margin-bottom: 18px;
}
.shop-theme-screens__head h2, .shop-theme-changelog h2 {
  margin: 0; font-family: var(--display); font-weight: 600; font-size: clamp(24px, 1.2vw + 16px, 32px);
}
.shop-theme-screens__head > a { font-size: 14px; font-weight: 600; color: var(--base); }
.shop-theme-shots {
  display: grid; gap: 24px; margin: 0; padding: 0; list-style: none;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 340px), 1fr));
}
.shop-theme-page.is-phone .shop-theme-shots { grid-template-columns: repeat(auto-fill, minmax(min(100%, 200px), 1fr)); }
.shop-theme-shot[hidden] { display: none; }
.shop-theme-shot__media {
  display: block; width: 100%; padding: 0; cursor: zoom-in; overflow: hidden;
  border: 1px solid var(--border); border-radius: var(--r); background: var(--bg3);
  transition: box-shadow .18s ease, transform .18s ease;
}
.shop-theme-shot__media:hover { box-shadow: var(--shadow-menu); transform: translateY(-2px); }
.shop-theme-shot__media img { display: block; width: 100%; height: auto; }
.shop-theme-shot__cap { display: flex; flex-wrap: wrap; gap: 4px 10px; margin: 8px 0 0; font-size: 13.5px; }
.shop-theme-shot__cap span { color: var(--amber-d); }

/* The view switches: a second group (right to left) wraps under the first. */
.shop-theme-switches { display: flex; flex-wrap: wrap; gap: 8px; max-width: 100%; }
.shop-theme-switches .shop-themes__views { flex-wrap: wrap; max-width: 100%; }

/* "Works with": the add-ons the theme's screens need. */
.shop-theme-fits { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px; margin-top: 14px; }
.shop-theme-fits__label { margin: 0; font-size: 13px; font-weight: 700; color: var(--text2); }
.shop-theme-fits ul { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; padding: 0; list-style: none; }
.shop-theme-fits li { font-size: 13px; padding: 4px 10px; border-radius: 999px; background: var(--bg3); color: var(--text2); }
.shop-theme-fits a { color: var(--base); font-weight: 600; text-decoration: none; }
.shop-theme-fits a:hover { text-decoration: underline; }

.shop-theme-videos__list {
  display: grid; gap: 24px; margin: 0; padding: 0; list-style: none;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 420px), 1fr));
}
.shop-theme-video.is-phone .shop-theme-video__frame { max-width: 300px; }
.shop-theme-video__frame {
  position: relative; overflow: hidden;
  border: 1px solid var(--border); border-radius: var(--r); background: var(--bg3);
}
.shop-theme-video video { display: block; width: 100%; height: auto; min-height: 120px; }
.shop-theme-video__play {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  display: inline-flex; align-items: center; justify-content: center; width: 64px; height: 64px;
  padding: 0 0 0 4px; border: 0; border-radius: 50%; cursor: pointer;
  background: var(--scrim); color: var(--on-dark); box-shadow: var(--shadow-menu);
  backdrop-filter: blur(2px);
}
.shop-theme-video__play:hover { background: var(--text); color: var(--bg2); }
.shop-theme-video__play[hidden] { display: none; }

.shop-theme-games__grid {
  display: grid; gap: 18px 14px; margin: 0; padding: 0; list-style: none;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 200px), 1fr));
}
@media (max-width: 560px) {
  .shop-theme-games__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* addon.php: one look per storefront theme. */
.shop-themes__tabs.is-wrap { flex-wrap: wrap; scroll-margin-top: calc(var(--pt-sticky-top, 0px) + 16px); }
.shop-addon-look { scroll-margin-top: calc(var(--pt-sticky-top, 0px) + 16px); }
.shop-addon-look + .shop-addon-look { margin-top: 40px; }
.shop-addon-look[hidden] { display: none; }
.shop-addon-look__head {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 6px 14px;
  margin-bottom: 14px;
}
.shop-addon-look__head h3 { margin: 0; font-family: var(--display); font-weight: 600; font-size: 1.25rem; }
.shop-addon-look__head a { font-size: 14px; font-weight: 600; color: var(--base); }

.shop-theme-compare__pair { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
.shop-theme-compare__pair.is-phone { grid-template-columns: repeat(2, minmax(0, 260px)); justify-content: center; }
.shop-theme-compare__pair figure { margin: 0; }
.shop-theme-compare__pair img {
  display: block; width: 100%; height: auto; min-height: 120px; background: var(--bg3);
  border: 1px solid var(--border); border-radius: var(--r);
}
.shop-theme-compare__pair figcaption { margin-top: 8px; font-size: 14px; font-weight: 600; }
.shop-theme-compare__pair figcaption a { color: var(--base); }
.shop-theme-compare__all { margin: 18px 0 0; text-align: center; }
.shop-theme-compare__all .shop-cta { display: inline-block; padding: 10px 18px; font-size: 14px; border-radius: 999px; }

/* compare.php: two themes, one row per screen both have. */
.shop-compare-head { margin-bottom: 56px; }
.shop-compare-head h1 {
  margin: 0; font-family: var(--display); font-weight: 600;
  font-size: clamp(32px, 2.4vw + 18px, 52px); line-height: 1.08; letter-spacing: -.02em;
  overflow-wrap: anywhere;
}
.shop-compare-head h1 a { color: inherit; text-decoration: none; }
.shop-compare-head h1 a:hover { color: var(--base); }
.shop-compare-head__sub { margin: 12px 0 0; font-size: 1.0625rem; line-height: 1.6; color: var(--text2); max-width: 60ch; }
.shop-compare-sides { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px; margin-top: 24px; }
.shop-compare-side {
  min-width: 0; padding: 16px 18px; border-radius: var(--rl);
  background: var(--bg2); border: 1px solid var(--border);
}
.shop-compare-side__swap { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.shop-compare-side__swap .shop-filter { min-width: 0; max-width: 100%; }
.shop-compare-side__swap select { max-width: 100%; font-size: 15px; }
.shop-compare-side__meta { margin: 10px 0 0; font-size: 13.5px; color: var(--text2); }
.shop-compare-side__meta a { color: var(--base); font-weight: 600; }
.shop-compare-side .shop-theme-get__actions { align-items: center; }
.shop-compare-side .shop-theme-get__badge { margin: 0; }
.shop-compare-count { display: inline-block; white-space: nowrap; margin-inline-start: 8px; font-family: var(--mono); font-size: 14px; font-weight: 400; color: var(--text3); }
.shop-compare-empty { margin: 0; color: var(--text2); }
.shop-compare-rows { display: grid; gap: 40px; margin: 0; padding: 0; list-style: none; }
.shop-compare-row__title { margin: 0 0 12px; font-size: 1.0625rem; font-weight: 700; }
.shop-compare-row__pair { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px; }
.shop-compare.is-phone .shop-compare-row__pair { grid-template-columns: repeat(2, minmax(0, 300px)); justify-content: center; }
.shop-compare-cell { min-width: 0; }
.shop-compare-cell__name {
  margin: 0 0 6px; font-size: 12px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  color: var(--text3);
}
.shop-compare-buy { margin-bottom: 64px; }
.shop-compare-buy .shop-compare-sides { margin-top: 0; }
.shop-compare-buy .shop-theme-get { margin-top: 0; }
.shop-compare-buy__name { margin: 0 0 10px; font-family: var(--display); font-size: 1.375rem; font-weight: 600; }
.shop-compare-buy__name a { color: inherit; text-decoration: none; }
.shop-compare-buy__name a:hover { color: var(--base); }
.shop-theme-lightbox__flip { margin: 12px 0 0; text-align: center; }
.shop-theme-lightbox__flip .shop-cta { display: inline-block; width: auto; padding: 8px 16px; font-size: 14px; border-radius: 999px; }
.shop-theme-lightbox.is-phone:has(.shop-theme-lightbox__flip) img { max-height: calc(100vh - 176px); }
@media (max-width: 640px) {
  .shop-compare-head { margin-bottom: 40px; }
  .shop-compare-sides { grid-template-columns: minmax(0, 1fr); gap: 12px; }
  .shop-compare-rows { gap: 32px; }
  /* A desktop shot is too wide to read two-up, so the themes stack; two
     phone shots still fit side by side. */
  .shop-compare-row__pair { grid-template-columns: minmax(0, 1fr); gap: 14px; }
  .shop-compare.is-phone .shop-compare-row__pair { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
}

.shop-theme-rels { margin: 18px 0 0; padding: 0; list-style: none; display: grid; gap: 12px; max-width: 46rem; }
.shop-theme-rel { padding: 16px 18px; border: 1px solid var(--border); border-radius: var(--rl); background: var(--bg2); }
.shop-theme-rel__head { display: flex; align-items: baseline; gap: 10px; margin: 0; }
.shop-theme-rel__head span { font-family: var(--mono); font-size: 12px; color: var(--text3); }
.shop-theme-rel__cat { margin: 10px 0 2px; font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--text3); }
.shop-theme-rel ul { margin: 6px 0 0; padding-inline-start: 18px; font-size: 14px; line-height: 1.55; color: var(--text2); }
.shop-theme-rel__prose { margin: 8px 0 0; font-size: 14px; line-height: 1.55; color: var(--text2); }

.shop-theme-more__grid {
  display: grid; gap: 18px; margin: 0; padding: 0; list-style: none;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 240px), 1fr));
}
.shop-theme-more__card { display: block; text-decoration: none; color: var(--text); }
.shop-theme-more__media {
  display: block; aspect-ratio: 16 / 10; overflow: hidden; border-radius: var(--r);
  border: 1px solid var(--border); background: var(--bg3);
}
.shop-theme-more__media img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: top; }
.shop-theme-more__card strong { display: block; margin-top: 8px; font-size: 15px; }
.shop-theme-more__card:hover strong { color: var(--base); }

.shop-theme-lightbox {
  width: min(1200px, calc(100vw - 32px)); max-height: calc(100vh - 32px); padding: 16px 56px;
  border: 0; border-radius: var(--rl); background: var(--bg2); color: var(--text); overflow: auto;
}
.shop-theme-lightbox::backdrop { background: rgba(16, 24, 40, .7); }
.shop-theme-lightbox figure { margin: 0; }
.shop-theme-lightbox img { display: block; width: 100%; height: auto; border-radius: var(--r); }
.shop-theme-lightbox.is-phone img { width: auto; max-width: 100%; max-height: calc(100vh - 120px); margin: 0 auto; }
.shop-theme-lightbox figcaption { margin-top: 10px; font-size: 14px; text-align: center; color: var(--text2); }
.shop-theme-lightbox .shop-theme-modal__x { position: absolute; inset-block-start: 12px; inset-inline-end: 12px; z-index: 1; }
.shop-theme-lightbox__nav {
  position: absolute; top: 50%; transform: translateY(-50%);
  display: inline-flex; align-items: center; justify-content: center; width: 38px; height: 38px;
  border-radius: 50%; border: 1px solid var(--border); background: var(--bg2); color: var(--text); cursor: pointer;
}
.shop-theme-lightbox__nav.is-prev { inset-inline-start: 10px; }
.shop-theme-lightbox__nav.is-next { inset-inline-end: 10px; }
[dir="rtl"] .shop-theme-lightbox__nav svg { transform: scaleX(-1); }

@media (max-width: 860px) {
  .shop-theme-hero { grid-template-columns: minmax(0, 1fr); gap: 28px; }
  .shop-theme-hero__visual { order: -1; }
}
@media (max-width: 560px) {
  .shop-theme-compare__pair { gap: 10px; }
  .shop-theme-lightbox { padding: 48px 12px 16px; }
  .shop-theme-lightbox__nav { top: 24px; transform: none; }
  .shop-theme-lightbox__nav.is-prev { inset-inline-start: 12px; }
  .shop-theme-lightbox__nav.is-next { inset-inline-start: 58px; inset-inline-end: auto; }
}
@media (prefers-reduced-motion: reduce) {
  .shop-theme-shot__media, .shop-theme-shot__media:hover { transition: none; transform: none; }
}
.shop-theme-modal__page { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 16px; }
.shop-theme-modal__page .shop-cta { padding: 8px 16px; font-size: 14px; border-radius: 999px; }
.shop-theme-modal__page .shop-cta[hidden] { display: none; }

/* The "which demo?" chooser a card's Live Preview opens (shop-demos.js). */
.shop-demo-chooser {
  width: min(440px, calc(100vw - 32px)); max-height: calc(100vh - 48px); padding: 0;
  border: 1px solid var(--border); border-radius: var(--rl);
  background: var(--bg2); color: var(--text); box-shadow: var(--shadow-menu);
}
.shop-demo-chooser::backdrop { background: rgba(16, 24, 40, .55); backdrop-filter: blur(2px); }
.shop-demo-chooser__head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 18px 22px; border-block-end: 1px solid var(--border);
}
.shop-demo-chooser__head h2 { margin: 0; font-family: var(--display); font-size: 1.35rem; font-weight: 600; }
.shop-demo-chooser__x {
  display: inline-flex; padding: 9px; border: 0; border-radius: 10px; cursor: pointer;
  background: var(--bg3); color: var(--text2);
}
.shop-demo-chooser__x:hover { color: var(--text); }
.shop-demo-chooser__list { list-style: none; margin: 0; padding: 18px 22px 22px; display: flex; flex-direction: column; gap: 8px; }
.shop-demo-chooser__item {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 13px 15px; border: 1px solid var(--border); border-radius: var(--r);
  background: var(--bg2); color: var(--text); text-decoration: none; font-weight: 600;
}
.shop-demo-chooser__item:hover, .shop-demo-chooser__item:focus-visible { border-color: var(--amber); color: var(--amber); }
.shop-demo-chooser__item svg { flex: none; }

/* The private demo band under the platforms (_private_demo.php). */
.shop-private-demo {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 20px 32px;
  margin: 0 0 72px; padding: 24px 28px;
  border: 1px solid var(--border); border-radius: var(--rl); background: var(--bg2);
}
.shop-private-demo__text { flex: 1 1 360px; min-width: 0; }
.shop-private-demo__text h2 { margin: 4px 0 8px; font-family: var(--display); font-size: 1.5rem; font-weight: 600; }
.shop-private-demo__text p:last-child { margin: 0; color: var(--text2); line-height: 1.6; }
.shop-private-demo__buy { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 18px; }
.shop-private-demo__price { margin: 0; font-weight: 600; }
@media (max-width: 640px) {
  .shop-private-demo { padding: 20px; }
  .shop-private-demo__buy { width: 100%; }
  .shop-private-demo__buy .shop-cta { flex: 1 1 auto; justify-content: center; }
}

/* An offer's crossed-out list price inside a button (theme page Buy now). */
.shop-cta__was { font-weight: 500; opacity: .7; }
