/*
 * MythGG storefront layer.
 *
 * Hooks onto the theme's stable `sa-*` classes only, so theme updates never overwrite this and no
 * Tailwind rebuild is needed. Everything below is deliberate: the logo is a cut gem, orange through
 * crimson, so the shop's language is raking light across hard facets rather than neon glow.
 *
 * The buyer's real question is "will I get scammed". So contrast, legible prices and visible proof
 * outrank decoration; motion is short and only ever confirms an interaction.
 */

:root {
  /* Lifted from the mark's own gradient stops (brand/mark.svg). */
  --mg-ember: #ffb347;
  --mg-flame: #ff5a1f;
  --mg-blood: #d81e3a;
  --mg-gradient: linear-gradient(135deg, var(--mg-ember) 0%, var(--mg-flame) 55%, var(--mg-blood) 100%);
  /* Same family, but stopping short of the crimson end: text on the full gradient
     drops to 3.9:1 at the dark stop, which fails for anything but large type. */
  --mg-gradient-text-safe: linear-gradient(135deg, var(--mg-ember) 0%, #ff7a2e 60%, var(--mg-flame) 100%);
  --mg-lift: 0 10px 24px -12px rgb(0 0 0 / 0.65), 0 2px 6px -2px rgb(0 0 0 / 0.4);
  --mg-ease: cubic-bezier(0.2, 0.7, 0.3, 1);
}

/* ── Type ───────────────────────────────────────────────────────────────────
   Chakra Petch is already set in theme settings. Display sizes need the tracking
   pulled in or they read loose and cheap at large sizes. */
.sa-hero-title,
.sa-section-title {
  letter-spacing: -0.035em;
  text-wrap: balance;
}
.sa-hero-title { line-height: 1.02; }
.sa-hero-subtitle,
.sa-section-subtitle { max-width: 58ch; }

/* The theme marks the highlighted word in a title with <span class="mk"> and colours it flat
   accent. Give it the brand gradient as a cut underline instead: gradient *text* drops below 4:1
   at the crimson end, an underline keeps the word at full contrast at every size. */
.hl-accent .mk {
  color: inherit;
  position: relative;
  white-space: nowrap;
}
.hl-accent .mk::after {
  content: "";
  position: absolute;
  left: -0.04em;
  right: -0.04em;
  bottom: 0.02em;
  height: 0.14em;
  background: var(--mg-gradient);
  border-radius: 999px;
}

/* ── Hero ───────────────────────────────────────────────────────────────────
   One authored moment on the page: embers drifting behind the headline, slow
   enough to read as atmosphere. Everything else on the page stays still. */
.sa-hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
}
.sa-hero::before {
  content: "";
  position: absolute;
  inset: -20% -10% auto;
  height: 140%;
  z-index: -1;
  background:
    radial-gradient(38% 46% at 50% 38%, rgb(255 90 31 / 0.18), transparent 70%),
    radial-gradient(26% 34% at 12% 14%, rgb(216 30 58 / 0.14), transparent 72%),
    radial-gradient(28% 36% at 88% 78%, rgb(255 179 71 / 0.10), transparent 72%);
  animation: mg-drift 24s var(--mg-ease) infinite alternate;
}
@keyframes mg-drift {
  from { transform: translate3d(-1.5%, -1%, 0) scale(1); }
  to   { transform: translate3d(1.5%, 1.5%, 0) scale(1.06); }
}

/* ── React Bits runtime ─────────────────────────────────────────────────────
   Styles for the components custom.js mounts (reactbits.dev, MIT). Their shipped CSS hardcodes
   its own dark palette and radii, which would fight the theme's tokens, so the structural parts
   are kept and the cosmetic ones are handed back to the theme. */
.mg-aurora {
  position: absolute;
  /* the shader's band sits at the top of its own canvas with a hard edge, so hang the layer
     above the hero and let the mask decide where it begins */
  inset: -14% -4% 0;
  z-index: -2;
  pointer-events: none;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 26%, #000 52%, transparent 94%);
          mask-image: linear-gradient(to bottom, transparent 0%, #000 26%, #000 52%, transparent 94%);
  opacity: 0.55;                        /* atmosphere behind the headline, not a banner across it */
}
.mg-aurora .aurora-container { width: 100%; height: 100%; }
.mg-aurora canvas { display: block; width: 100%; height: 100%; }
/* The CSS ember wash is the fallback; once the shader is up, one of them has to go. */
.sa-hero.mg-has-aurora::before { display: none; }
:root[data-scheme="light"] .mg-aurora { opacity: 0.5; }

.shiny-text { display: inline-block; }

/* SonarGrid is the page's background field, so it belongs under the content — a dot grid laid
   over the copy is texture on top of text no matter how faint it is. It is the spark that has to
   be above everything, and that is a separate layer below.

   Fixed at a negative z-index, with <body>'s own fill handed up to <html>: body's background is
   opaque and would otherwise paint straight over it. */
.mg-sonar-layer {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
}
/* Both sides read the same token, which is redefined per scheme on <html> itself, so the two can
   never disagree and the toggle repaints the page underneath the field. */
html.mg-has-sonar { background-color: rgb(var(--cl-background)); }
html.mg-has-sonar body { background-color: transparent; }

/* The click spark, on the other hand, is the answer to a click and has to land on whatever was
   clicked — a card, a button, the footer. Fixed to the viewport above every section, taking no
   pointer events so it can never intercept one. */
.mg-spark-layer {
  position: fixed;
  inset: 0;
  z-index: 2147483000;
  pointer-events: none;
}
.mg-spark-layer > div { width: 100%; height: 100%; }
.mg-sonar,
.mg-sonar-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.mg-sonar-canvas { display: block; }
/* The theme ships its own static dot grid in the hero; the live field replaces it rather than
   stacking a second grid on top. */
html.mg-has-sonar .hero-bg-grid { display: none; }

/* Cursor light. custom.js publishes the pointer position onto the card; the edge lights where
   the hand is, using the same masked ring the product cards use. Nothing is drawn over the copy,
   so the effect cannot cost a single point of text contrast — which is exactly what the radial
   fill it replaces was doing. */
.mg-cursor-light { position: relative; }
.mg-cursor-light::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1px;
  background: radial-gradient(170px circle at var(--mouse-x, 50%) var(--mouse-y, 0%),
              rgb(255 196 132 / 0.95), rgb(255 90 31 / 0.35) 42%, transparent 72%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  opacity: 0;
  transition: opacity 220ms var(--mg-ease);
  pointer-events: none;
}
.mg-cursor-light:hover::after,
.mg-cursor-light:focus-within::after { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .mg-cursor-light::after { display: none; }
}

/* ── Buttons ────────────────────────────────────────────────────────────────
   The primary action is the only gradient surface on the page, so it reads as
   the one thing to press. Light sweeps across it on hover, like a facet turning. */
.sa-btn { transition: transform 180ms var(--mg-ease), box-shadow 180ms var(--mg-ease), filter 180ms var(--mg-ease); }
.sa-btn--primary {
  background: var(--mg-gradient-text-safe);
  border: 0;
  color: #140a06;
  font-weight: 700;
  letter-spacing: 0.01em;
  box-shadow: var(--mg-lift);
  position: relative;
  overflow: hidden;
}
.sa-btn--primary::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(105deg, transparent 35%, rgb(255 255 255 / 0.35) 50%, transparent 65%);
  transform: translateX(-120%);
  transition: transform 520ms var(--mg-ease);
}
.sa-btn--primary:hover { transform: translateY(-1px); filter: saturate(1.06); }
.sa-btn--primary:hover::after { transform: translateX(120%); }
.sa-btn--primary:active { transform: translateY(0); }
.sa-btn:focus-visible {
  outline: 2px solid var(--mg-ember);
  outline-offset: 2px;
}

/* ── Product cards ──────────────────────────────────────────────────────────
   The repeated element, so it carries the identity: one chamfered corner echoing
   the mark, and a hairline that ignites along the brand gradient on hover.

   Structure (snippets/product-card.njk, flat-divider): the card is an <a> holding a
   media block and a .p-4 body; the body holds a title row and, after a divider, a
   stock/price row. */
.sa-product-card {
  position: relative;
  /* The gradient hairline below draws the outline, so the theme's own border would double it. */
  border-color: transparent;
}
.sa-product-card::before {
  content: "";
  position: absolute;
  inset: 0;
  padding: 1px;                         /* hairline only; a thick colour bar would shout */
  border-radius: inherit;
  background: var(--mg-gradient);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  opacity: 0.32;                        /* always drawn, so the facet always has an edge */
  transition: opacity 200ms var(--mg-ease);
  pointer-events: none;
  z-index: 1;
}
.sa-product-card:hover::before { opacity: 1; }
/* The theme's own hfx-lift already raises the card; shadow_card is "none" in settings, so
   supply the depth that the lift is missing rather than repeating the transform. */
.sa-product-card:hover { box-shadow: var(--mg-lift); }

/* A title that wraps to two lines pushes that card's price below its neighbours', and a row of
   prices landing on different baselines is the fastest way to make a grid look unmaintained.
   Make the body a column and drop the stock/price row to the bottom of every card. */
.sa-product-card--flat-divider,
.sa-product-card--padded-detail { display: flex; flex-direction: column; }
.sa-product-card--flat-divider > div:last-child,
.sa-product-card--padded-detail > div:last-child { display: flex; flex-direction: column; flex: 1; }
.sa-product-card--flat-divider > div:last-child > div:last-child,
.sa-product-card--padded-detail > div:last-child > div:last-child { margin-top: auto; }

/* Price is what the buyer scans for; give it weight and stop it wrapping oddly. */
.sa-product-card-price {
  font-family: var(--font-heading, inherit);
  font-weight: 700;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.sa-product-card-price-slash { opacity: 0.55; }

/* Sold and Booked must be unmissable: a buyer who asks about a gone account is a
   wasted exchange for both sides. */
.sa-product-card-status {
  font-family: var(--font-heading, inherit);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.sa-product-card[data-status="sold"],
.sa-product-card[data-status="out-of-stock"] { opacity: 0.55; }
.sa-product-card[data-status="sold"]:hover { transform: none; }

/* ── Trust row ──────────────────────────────────────────────────────────────
   Structural, not decorative: this is the section that answers the scam fear, so
   it gets a real surface instead of floating text. */
.sa-trust-badges .sa-trust-badges-item,
.sa-features--icon-grid .sa-features-item {
  position: relative;
  padding-block: 1.25rem;
  transition: border-color 200ms var(--mg-ease);
}
.sa-trust-badges .sa-trust-badges-icon,
.sa-features-icon {
  color: var(--mg-flame);
}

/* ── Steps ──────────────────────────────────────────────────────────────────
   The timeline is the purchase promise; the connecting line reads as progress. */
.sa-steps--timeline .sa-steps-item::before {
  background: var(--mg-gradient);
  opacity: 0.35;
}

/* ── Navbar ─────────────────────────────────────────────────────────────────*/
.sa-navbar-logo img { image-rendering: auto; }
.sa-navbar-link {
  position: relative;
  transition: color 160ms var(--mg-ease);
}
.sa-navbar-link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  height: 2px;
  background: var(--mg-gradient);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 200ms var(--mg-ease);
}
.sa-navbar-link:hover::after,
.sa-navbar-link[aria-current]::after { transform: scaleX(1); }

/* ── Footer ─────────────────────────────────────────────────────────────────*/
.sa-footer { border-top: 1px solid rgb(255 118 43 / 0.14); }

/* ── Respect the visitor's settings ─────────────────────────────────────────*/
@media (prefers-reduced-motion: reduce) {
  .sa-hero::before { animation: none; }
  .sa-btn--primary::after { display: none; }
  .sa-btn,
  .sa-product-card,
  .sa-navbar-link::after { transition: none; }
  .sa-product-card:hover { transform: none; }
}

/* Light scheme: the gradient is tuned for dark surfaces, so deepen it rather than letting
   orange-on-white lose its contrast.

   Keyed on [data-scheme], not a media query: layouts/master.njk sets that attribute from
   localStorage and the scheme toggle writes it, so a visitor on a dark OS who switches the store
   to light would never match `prefers-color-scheme: light`. The media query is kept only for the
   "system" default, guarded so an explicit dark choice still wins. */
:root[data-scheme="light"] .sa-hero::before { opacity: 0.45; }
:root[data-scheme="light"] {
  --mg-gradient: linear-gradient(135deg, #f59120 0%, #e8481a 55%, #b3162f 100%);
  --mg-gradient-text-safe: linear-gradient(135deg, #d9741a 0%, #c53d14 60%, #a82f10 100%);
}
:root[data-scheme="light"] .sa-btn--primary { color: #fff; }

@media (prefers-color-scheme: light) {
  :root:not([data-scheme="dark"]) .sa-hero::before { opacity: 0.45; }
  :root:not([data-scheme="dark"]) {
    --mg-gradient: linear-gradient(135deg, #f59120 0%, #e8481a 55%, #b3162f 100%);
    --mg-gradient-text-safe: linear-gradient(135deg, #d9741a 0%, #c53d14 60%, #a82f10 100%);
  }
  :root:not([data-scheme="dark"]) .sa-btn--primary { color: #fff; }
}


/* ══ Redesign pass ═══════════════════════════════════════════════════════════
   Written against the storefront's real rendered DOM (theme/live.snapshot.html), not against a
   reconstruction of it. Everything below targets classes SellAuth actually emits. */

/* ── Section headings ───────────────────────────────────────────────────────
   The shipped h2 is `text-h2` — around 28px on a 1360 container, which reads as a form label
   rather than the start of a section. A storefront's sections are its argument; give them the
   size that implies. */
.sa-section-title {
  font-size: clamp(2rem, 4vw, 3.15rem);
  line-height: 1.03;
  letter-spacing: -0.04em;
}
/* Centred, and centred properly: the theme emits `max-w-2xl text-left` on the header, so
   overriding the alignment alone would leave the block itself pinned to the left gutter. The
   measure is kept — a centred line longer than about 68 characters is hard to track back. */
.sa-section-header {
  max-width: min(100%, 68ch);
  margin-inline: auto;
  margin-bottom: clamp(26px, 3.4vw, 44px);
  text-align: center;
}
.sa-section-header > * { margin-inline: auto; }
.sa-section-subtitle,
.sa-section-header p {
  max-width: 62ch;
  margin-inline: auto;
  font-size: 1.02rem;
}

/* ── Surfaces ───────────────────────────────────────────────────────────────
   Every panel on the page is the same flat fill with a hairline, which is what makes a dark
   theme read as unfinished. One consistent light source from above, and shadows carrying the
   page's own warmth rather than neutral black. */
/* Cards only. This was applied to .sa-trust-badges too, which is a whole section rather than a
   panel, so it painted a full-width wash starting at the hero's bottom edge — the seam between
   the hero and the stats. A light source belongs on an object, not on a band of the page. */
.sa-product-card,
.sa-features-item,
.sa-faq-item {
  background-image: linear-gradient(rgb(255 255 255 / 0.035), rgb(255 255 255 / 0) 42%);
}
:root {
  --mg-lift: 0 18px 38px -22px rgb(94 18 4 / 0.85), 0 3px 8px -4px rgb(20 8 4 / 0.55);
}

/* Grain. Flat vector dark is the single most synthetic-looking surface there is; a little tooth
   across the whole page breaks it without becoming a texture anyone notices. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 9;
  pointer-events: none;
  opacity: 0.16;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
}
:root[data-scheme="light"] body::after { opacity: 0.07; }

/* ── Products ───────────────────────────────────────────────────────────────
   The grid is fixed at up to four columns, so a shop holding two accounts renders two small cards
   stranded against a half-empty row, which reads as "this place is dead". While the catalogue is
   small, hold the cards at a real size and centre them; past four listings the normal grid is
   back on its own. */
.sa-products-items:has(> :nth-child(1):last-child),
.sa-products-items:has(> :nth-child(2):last-child),
.sa-products-items:has(> :nth-child(3):last-child),
.sa-page-products-items:has(> :nth-child(1):last-child),
.sa-page-products-items:has(> :nth-child(2):last-child),
.sa-page-products-items:has(> :nth-child(3):last-child) {
  grid-template-columns: repeat(auto-fit, minmax(300px, 400px));
  justify-content: center;
}

/* ── Features ────────────────────────────────────────────────────────────── */
.sa-features--icon-grid .sa-features-item { padding: var(--card-pad); }

/* ── Steps ──────────────────────────────────────────────────────────────────
   The timeline is the purchase promise; the connecting line reads as progress. */
.sa-steps--timeline .sa-steps-item::before {
  background: var(--mg-gradient);
  opacity: 0.35;
}

/* ── Navbar ─────────────────────────────────────────────────────────────────*/
.sa-navbar-logo img { image-rendering: auto; }
.sa-navbar-link {
  position: relative;
  transition: color 160ms var(--mg-ease);
}
.sa-navbar-link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  height: 2px;
  background: var(--mg-gradient);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 200ms var(--mg-ease);
}
.sa-navbar-link:hover::after,
.sa-navbar-link[aria-current]::after { transform: scaleX(1); }

/* ── Footer ─────────────────────────────────────────────────────────────────*/
.sa-footer { border-top: 1px solid rgb(255 118 43 / 0.14); }

/* ── Respect the visitor's settings ─────────────────────────────────────────*/
@media (prefers-reduced-motion: reduce) {
  .sa-hero::before { animation: none; }
  .sa-btn--primary::after { display: none; }
  .sa-btn,
  .sa-product-card,
  .sa-navbar-link::after { transition: none; }
  .sa-product-card:hover { transform: none; }
}

/* Light scheme: the gradient is tuned for dark surfaces, so deepen it rather than letting
   orange-on-white lose its contrast.

   Keyed on [data-scheme], not a media query: layouts/master.njk sets that attribute from
   localStorage and the scheme toggle writes it, so a visitor on a dark OS who switches the store
   to light would never match `prefers-color-scheme: light`. The media query is kept only for the
   "system" default, guarded so an explicit dark choice still wins. */
:root[data-scheme="light"] .sa-hero::before { opacity: 0.45; }
:root[data-scheme="light"] {
  --mg-gradient: linear-gradient(135deg, #f59120 0%, #e8481a 55%, #b3162f 100%);
  --mg-gradient-text-safe: linear-gradient(135deg, #d9741a 0%, #c53d14 60%, #a82f10 100%);
}
:root[data-scheme="light"] .sa-btn--primary { color: #fff; }

@media (prefers-color-scheme: light) {
  :root:not([data-scheme="dark"]) .sa-hero::before { opacity: 0.45; }
  :root:not([data-scheme="dark"]) {
    --mg-gradient: linear-gradient(135deg, #f59120 0%, #e8481a 55%, #b3162f 100%);
    --mg-gradient-text-safe: linear-gradient(135deg, #d9741a 0%, #c53d14 60%, #a82f10 100%);
  }
  :root:not([data-scheme="dark"]) .sa-btn--primary { color: #fff; }
}


/* ══ Redesign pass ═══════════════════════════════════════════════════════════
   Written against the storefront's real rendered DOM (theme/live.snapshot.html), not against a
   reconstruction of it. Everything below targets classes SellAuth actually emits. */

/* ── Section headings ───────────────────────────────────────────────────────
   The shipped h2 is `text-h2` — around 28px on a 1360 container, which reads as a form label
   rather than the start of a section. A storefront's sections are its argument; give them the
   size that implies. */
.sa-section-title {
  font-size: clamp(2rem, 4vw, 3.15rem);
  line-height: 1.03;
  letter-spacing: -0.04em;
}
/* Centred, and centred properly: the theme emits `max-w-2xl text-left` on the header, so
   overriding the alignment alone would leave the block itself pinned to the left gutter. The
   measure is kept — a centred line longer than about 68 characters is hard to track back. */
.sa-section-header {
  max-width: min(100%, 68ch);
  margin-inline: auto;
  margin-bottom: clamp(26px, 3.4vw, 44px);
  text-align: center;
}
.sa-section-header > * { margin-inline: auto; }
.sa-section-subtitle,
.sa-section-header p {
  max-width: 62ch;
  margin-inline: auto;
  font-size: 1.02rem;
}

/* ── Surfaces ───────────────────────────────────────────────────────────────
   Every panel on the page is the same flat fill with a hairline, which is what makes a dark
   theme read as unfinished. One consistent light source from above, and shadows carrying the
   page's own warmth rather than neutral black. */
/* Cards only. This was applied to .sa-trust-badges too, which is a whole section rather than a
   panel, so it painted a full-width wash starting at the hero's bottom edge — the seam between
   the hero and the stats. A light source belongs on an object, not on a band of the page. */
.sa-product-card,
.sa-features-item,
.sa-faq-item {
  background-image: linear-gradient(rgb(255 255 255 / 0.035), rgb(255 255 255 / 0) 42%);
}
:root {
  --mg-lift: 0 18px 38px -22px rgb(94 18 4 / 0.85), 0 3px 8px -4px rgb(20 8 4 / 0.55);
}

/* Grain. Flat vector dark is the single most synthetic-looking surface there is; a little tooth
   across the whole page breaks it without becoming a texture anyone notices. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 9;
  pointer-events: none;
  opacity: 0.16;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
}
:root[data-scheme="light"] body::after { opacity: 0.07; }

/* ── Products ───────────────────────────────────────────────────────────────
   The grid is fixed at up to four columns, so a shop holding two accounts renders two small cards
   stranded against a half-empty row, which reads as "this place is dead". While the catalogue is
   small, hold the cards at a real size and centre them; past four listings the normal grid is
   back on its own. */
.sa-products-items:has(> :nth-child(1):last-child),
.sa-products-items:has(> :nth-child(2):last-child),
.sa-products-items:has(> :nth-child(3):last-child),
.sa-page-products-items:has(> :nth-child(1):last-child),
.sa-page-products-items:has(> :nth-child(2):last-child),
.sa-page-products-items:has(> :nth-child(3):last-child) {
  grid-template-columns: repeat(auto-fit, minmax(300px, 400px));
  justify-content: center;
}

/* ── Features ───────────────────────────────────────────────────────────────
   Equal columns and equal padding: a weighted first card was tried and it made one card wider
   than its neighbours and started its copy lower down, so the row read as broken rather than
   as deliberate. Every card in a row is the same box. */
.sa-features--icon-grid .sa-features-items { grid-auto-rows: 1fr; }

/* ── Steps ──────────────────────────────────────────────────────────────────
   A single column of four short steps leaves the right half of a 1360 container empty, which
   makes the section look like it lost its illustration. Two columns fill it and halve the scroll. */
@media (min-width: 1024px) {
  .sa-steps--timeline .sa-steps-items {
    display: grid;
    grid-template-columns: 1fr 1fr;
    column-gap: clamp(32px, 4vw, 72px);
    row-gap: clamp(24px, 3vw, 40px);
  }
}

/* ── Interaction ────────────────────────────────────────────────────────────
   Press feedback, and a focus ring that is visible on both schemes. */
.sa-btn:active,
.sa-product-card:active { transform: translateY(1px) scale(0.995); }
.sa-btn:focus-visible,
.sa-product-card:focus-visible,
.sa-faq-item summary:focus-visible,
.sa-navbar-link:focus-visible {
  outline: 2px solid var(--mg-ember);
  outline-offset: 3px;
  border-radius: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .sa-btn:active,
  .sa-product-card:active { transform: none; }
}

/* ── Section width and rhythm ───────────────────────────────────────────────
   Two sections ship inside their own narrow wrapper — the steps list in a max-w-2xl and the
   why-us panel in a max-w-5xl — both left-aligned, so on a 1360 container each one strands half
   the page. The steps list is two columns now, so its wrapper has to open up; the prose panel
   keeps its measure and is centred instead of stretched, because a 1360-wide paragraph is worse
   than a void. */
.sa-steps--timeline div:has(> .sa-steps-items) { max-width: none; }
/* The shipped connector is one absolute rule down the left edge — correct for a single column,
   wrong the moment there are two. The numbered discs carry the sequence on their own. */
@media (min-width: 1024px) {
  .sa-steps--timeline div:has(> .sa-steps-items) > [aria-hidden="true"] { display: none; }
}
.sa-text-block--accent-tint .wrap > div { margin-inline: auto; }

/* Alternate sections were lifted a few percent to give the scroll some structure. It cost more
   than it bought: the page carries a grid pattern straight through, so every band edge became a
   visible seam where the grid changed tone mid-square. One field, no seams. */


/* ══ Motion ══════════════════════════════════════════════════════════════════
   Every move here is short and answers something the visitor did. Nothing loops except the
   hero's aurora, and everything stops under prefers-reduced-motion. */

/* Cards rise toward the cursor and their edge catches the brand gradient. The whole card moves
   as one piece — separate transitions on the border and the shadow read as two objects. */
.sa-features-item,
.sa-faq-item,
.sa-trust-badges,
.sa-steps-item {
  transition: transform 260ms var(--mg-ease), box-shadow 260ms var(--mg-ease),
              border-color 260ms var(--mg-ease);
}
.sa-features-item:hover,
.sa-faq-item:hover {
  transform: translateY(-3px);
  box-shadow: var(--mg-lift);
  border-color: rgb(255 122 46 / 0.4);
}

/* The icon tile is the card's one spot of colour, so it is what should react. */
.sa-features-item span:first-child,
.sa-steps-item > span:first-child {
  transition: transform 300ms var(--mg-ease), background-color 300ms var(--mg-ease),
              box-shadow 300ms var(--mg-ease);
}
.sa-features-item:hover span:first-child {
  transform: translateY(-2px) rotate(-4deg) scale(1.06);
  background-color: rgb(255 122 46 / 0.18);
  box-shadow: 0 0 0 1px rgb(255 122 46 / 0.3), 0 8px 18px -10px rgb(255 90 31 / 0.6);
}
.sa-steps-item:hover > span:first-child {
  transform: scale(1.08);
  box-shadow: 0 0 0 1px rgb(255 122 46 / 0.35);
}

/* Product cards: the image pushes in, the arrow leans toward the click it is asking for. */
.sa-product-card .sa-product-card-media img { transition: transform 420ms var(--mg-ease); }
.sa-product-card:hover .sa-product-card-media img { transform: scale(1.05); }
.sa-product-card span[class*="size-8"] { transition: transform 240ms var(--mg-ease); }
.sa-product-card:hover span[class*="size-8"] { transform: translateX(3px); }

/* FAQ: the marker turns as the panel opens, so the control explains its own state. */
.sa-faq-item svg { transition: transform 260ms var(--mg-ease); }
.sa-faq-item[open] > summary svg,
.sa-faq-item [aria-expanded="true"] svg { transform: rotate(180deg); }

/* Navigation: the current page keeps its underline instead of waiting for a hover. */
.sa-navbar-link { position: relative; }
.sa-navbar-link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -3px;
  height: 2px;
  background: var(--mg-gradient);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 220ms var(--mg-ease);
}
.sa-navbar-link:hover::after,
.sa-navbar-link[aria-current]::after { transform: scaleX(1); }

/* The hero eyebrow has no dot of its own, so it gets one. Section eyebrows already ship with a
   dot span — adding a second put two in every pill — so theirs is animated in place instead. */
.sa-section-eyebrow > span[aria-hidden="true"]:first-child {
  animation: mg-pulse 2.6s var(--mg-ease) infinite;
}
.sa-hero-eyebrow::before {
  content: "";
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 2px;
  border-radius: 50%;
  background: var(--mg-flame);
  box-shadow: 0 0 0 0 rgb(255 90 31 / 0.55);
  animation: mg-pulse 2.6s var(--mg-ease) infinite;
}
@keyframes mg-pulse {
  0%   { box-shadow: 0 0 0 0 rgb(255 90 31 / 0.5); }
  70%  { box-shadow: 0 0 0 7px rgb(255 90 31 / 0); }
  100% { box-shadow: 0 0 0 0 rgb(255 90 31 / 0); }
}

@media (prefers-reduced-motion: reduce) {
  .sa-section-eyebrow > span[aria-hidden="true"]:first-child { animation: none; }
  .sa-features-item,
  .sa-faq-item,
  .sa-product-card,
  .sa-steps-item,
  .sa-product-card .sa-product-card-media img,
  .sa-navbar-link::after { transition: none; }
  .sa-features-item:hover,
  .sa-faq-item:hover { transform: none; }
  .sa-features-item:hover span:first-child,
  .sa-steps-item:hover > span:first-child,
  .sa-product-card:hover .sa-product-card-media img,
  .sa-product-card:hover span[class*="size-8"] { transform: none; }
  .sa-section-eyebrow::before,
  .sa-hero-eyebrow::before { animation: none; }
}

/* ── HoverBorderGradient ────────────────────────────────────────────────────
   The component ships Tailwind classes pinned to a black pill (bg-black, rounded-[100px]). Those
   are its look, not its mechanism, so only the mechanism is kept: a light layer under a mask that
   covers everything except a 1px rim. The radii and the surface come from the theme. */
.mg-hbg {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 1px;
  border-radius: var(--radius-button);
  /* The light layer is blurred, and the original lets that bleed past the frame. Against a warm
     dark page a white bleed reads as a smudge above the button rather than as a halo, so clip it
     — the rim it is meant to light is inside the frame anyway. */
  overflow: hidden;
  isolation: isolate;
}
/* The inner box has to hug the button exactly. Left as a block it inherits a line box, so the
   wrapper ends up taller than what it wraps and the rim light shows through the gap above it. */
.mg-hbg-inner {
  position: relative;
  z-index: 2;
  display: flex;
  line-height: 0;
  border-radius: inherit;
}
.mg-hbg-inner > span { display: flex; }
.mg-hbg-inner .sa-btn { line-height: normal; }
/* The component sets width/height inline. Pin the box to the frame regardless, so no state of
   the animation can paint a panel outside the button. */
.mg-hbg-light {
  inset: 0 !important;
  width: auto !important;
  height: auto !important;
  z-index: 0;
  border-radius: inherit;
  overflow: hidden;
  flex: none;
}
.mg-hbg-mask {
  position: absolute;
  inset: 1px;
  z-index: 1;
  border-radius: inherit;
  flex: none;
  /* Reads the scheme token, so the button follows the toggle instead of keeping whichever
     surface colour happened to be current when it mounted. */
  background: rgb(var(--cl-surface));
}
/* the wrapper draws the edge now, so the button must not draw a second one */
.mg-hbg-target { border-color: transparent !important; }

/* ── Stats bento ────────────────────────────────────────────────────────────
   Shipped as a custom-html component, so the markup here is exactly the markup that ships —
   no guessing at what the platform will emit. Four tiles of three different weights: the
   headline number gets the room, the rest are read at a glance.

   Every figure is a claim the site already made elsewhere. Nothing here is invented. */
.mg-stats {
  display: grid;
  gap: 10px;
  grid-template-columns: 1fr;
  /* Left to fill the 1360 container these four short tiles become billboards on a wide screen.
     They are a supporting row, not the subject of the page, so cap them and centre them. */
  max-width: 940px;
  margin-inline: auto;
}
@media (min-width: 900px) {
  .mg-stats {
    grid-template-columns: 1.15fr 1fr 1fr;
    grid-template-areas:
      "hero wide wide"
      "hero square row";
  }
  .mg-stat--hero   { grid-area: hero; }
  .mg-stat--wide   { grid-area: wide; }
  .mg-stat--square { grid-area: square; }
  .mg-stat--row    { grid-area: row; }
}

.mg-stat {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 6px;
  padding: 14px 16px;
  border-radius: var(--radius-card);
  border: 1px solid var(--cl-border);
  background: rgb(var(--cl-surface));
  background-image: linear-gradient(rgb(255 255 255 / 0.035), rgb(255 255 255 / 0) 42%);
  overflow: hidden;
}

/* The lead tile carries the brand rather than another grey panel, and the raking lines echo
   the facets the mark is cut from. */
.mg-stat--hero {
  justify-content: center;
  gap: 8px;
  min-height: 150px;
  border-color: rgb(255 122 46 / 0.35);
  background-image:
    linear-gradient(rgb(255 255 255 / 0.05), rgb(255 255 255 / 0) 46%),
    repeating-linear-gradient(115deg, rgb(255 122 46 / 0.07) 0 2px, transparent 2px 13px);
}

.mg-stat-tag {
  align-self: flex-start;
  font-family: var(--ff-heading);
  font-size: 0.58rem;
  font-weight: 600;
  letter-spacing: 0.13em;
  color: rgb(var(--cl-t-muted));
}
.mg-stat--hero .mg-stat-tag {
  padding: 4px 11px;
  border-radius: 999px;
  background: rgb(255 122 46 / 0.12);
  color: var(--mg-ember);
}

.mg-stat-figure {
  margin: 0;
  font-family: var(--ff-heading);
  font-weight: 700;
  font-size: clamp(1.85rem, 2.4vw, 2.35rem);
  line-height: 0.98;
  letter-spacing: -0.045em;
  font-variant-numeric: tabular-nums;
  color: rgb(var(--cl-t-primary));
}
.mg-stat-figure--sm { font-size: clamp(1.25rem, 1.5vw, 1.5rem); }

/* The figures typed into the dashboard never paint: they stay hidden until the runtime has set
   every one to zero, and from there it counts up to the live numbers. Without this the stale
   figure would flash for the moment before the script runs. */
html:not(.mg-stats-on) .mg-stat--hero .mg-stat-figure,
html:not(.mg-stats-on) .mg-stat [data-mg-live],
html:not(.mg-stats-on) .mg-stat--row strong { visibility: hidden; }
.mg-stat-note {
  margin: 0;
  max-width: 32ch;
  font-size: 0.8rem;
  line-height: 1.45;
  color: rgb(var(--cl-t-muted));
}
/* The square tile is the smallest in the bento, so its second line sits closer and lighter —
   a supporting number, not a second statistic competing with the one above it. */
.mg-stat-note--tight { margin-top: 2px; font-size: 0.72rem; opacity: 0.85; }

/* A bar row, not a chart: it says "going up" without pretending to plot anything. */
.mg-stat--wide { flex-direction: row; align-items: center; justify-content: space-between; }
.mg-stat--wide > :first-child { position: absolute; top: 14px; left: 16px; }
.mg-stat--wide .mg-stat-figure { margin-top: 14px; }
/* Five bars, one per star rating, lowest on the left. They plot the real spread, so they are
   wider and further apart than the eleven decorative ones they replaced — at 4px a reader would
   take them for texture rather than a chart. */
.mg-stat-bars {
  display: flex;
  align-items: flex-end;
  gap: 5px;
  height: 26px;
  margin-top: 14px;
}
.mg-stat-bars i {
  width: 7px;
  height: var(--h);
  border-radius: 2px;
  background: var(--mg-gradient);
  opacity: 0.85;
  transform-origin: bottom;
  transition: transform 340ms var(--mg-ease), opacity 340ms var(--mg-ease);
}

.mg-stat--square { align-items: flex-start; justify-content: center; gap: 6px; }

.mg-stat--row { flex-direction: row; align-items: center; gap: 14px; }
.mg-stat-badge {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  flex: none;
  border-radius: 50%;
  background: rgb(255 122 46 / 0.12);
  color: var(--mg-flame);
}
.mg-stat-rowtext { display: flex; flex-direction: column; gap: 2px; }
.mg-stat-rowtext strong { font-family: var(--ff-heading); font-size: 0.9rem; color: rgb(var(--cl-t-primary)); }
.mg-stat-rowtext small { font-size: 0.78rem; color: rgb(var(--cl-t-muted)); }

/* Stat tiles answer the cursor like every other card on the page: the tile rises, its edge warms,
   and the bar row stands up a little. The cursor-lit ring is added by custom.js, which puts these
   tiles in the same set as the feature cards rather than giving them a second hover language. */
.mg-stat {
  transition: transform 260ms var(--mg-ease), box-shadow 260ms var(--mg-ease),
              border-color 260ms var(--mg-ease);
}
.mg-stat:hover {
  transform: translateY(-3px);
  box-shadow: var(--mg-lift);
  border-color: rgb(255 122 46 / 0.42);
}
.mg-stat:hover .mg-stat-bars i { transform: scaleY(1.14); opacity: 1; }
.mg-stat--hero:hover .mg-stat-tag { background: rgb(255 122 46 / 0.2); }

@media (prefers-reduced-motion: reduce) {
  .mg-stat { transition: none; }
  .mg-stat:hover { transform: none; }
  .mg-stat:hover .mg-stat-bars i { transform: none; }
}


/* ── Stats section spacing ──────────────────────────────────────────────────
   The bento is four short tiles, not a section of prose, and it sat between two full py-section
   gaps — roughly 320px of nothing around 200px of content. Pull it in toward the hero above it. */
.sa-custom-html:has(.mg-stats) { padding-block: clamp(24px, 3vw, 44px); }

/* ── Contact ────────────────────────────────────────────────────────────────
   Authored here and shipped as custom-html, so the preview and the shop render the same bytes.
   A lead on the left, the routes on the right: the question is "how do I reach someone", and the
   answer should be three doors rather than a paragraph about how much we care. */
.mg-contact {
  display: grid;
  gap: clamp(20px, 3vw, 44px);
  align-items: center;
  grid-template-columns: 1fr;
}
@media (min-width: 900px) {
  .mg-contact { grid-template-columns: 0.9fr 1.1fr; }
}
.mg-contact-title {
  margin: 0 0 10px;
  font-family: var(--ff-heading);
  font-weight: var(--fw-heading);
  font-size: clamp(1.7rem, 3vw, 2.4rem);
  letter-spacing: -0.035em;
  line-height: 1.05;
  color: rgb(var(--cl-t-primary));
}
.mg-contact-note {
  margin: 0;
  max-width: 44ch;
  font-size: 0.95rem;
  line-height: 1.6;
  color: rgb(var(--cl-t-muted));
}
.mg-contact-links { display: grid; gap: 10px; }
.mg-contact-card {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
  border-radius: var(--radius-card);
  border: 1px solid var(--cl-border);
  background: rgb(var(--cl-surface));
  background-image: linear-gradient(rgb(255 255 255 / 0.035), rgb(255 255 255 / 0) 42%);
  text-decoration: none;
  transition: transform 240ms var(--mg-ease), border-color 240ms var(--mg-ease),
              box-shadow 240ms var(--mg-ease);
}
.mg-contact-card:hover {
  transform: translateY(-2px);
  border-color: rgb(255 122 46 / 0.42);
  box-shadow: var(--mg-lift);
}
.mg-contact-icon {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  flex: none;
  border-radius: var(--radius-input);
  background: rgb(255 122 46 / 0.12);
  color: var(--mg-flame);
  transition: transform 240ms var(--mg-ease);
}
.mg-contact-card:hover .mg-contact-icon { transform: scale(1.06); }
.mg-contact-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.mg-contact-text strong { font-family: var(--ff-heading); font-size: 0.98rem; color: rgb(var(--cl-t-primary)); }
.mg-contact-text small { font-size: 0.83rem; color: rgb(var(--cl-t-muted)); }

@media (prefers-reduced-motion: reduce) {
  .mg-contact-card { transition: none; }
  .mg-contact-card:hover { transform: none; }
  .mg-contact-card:hover .mg-contact-icon { transform: none; }
}


/* ── Card grids, every page ─────────────────────────────────────────────────
   Each card sits inside a wrapper div that the grid stretches, but the card itself is a block
   inside it and only as tall as its own content. So a listing with a slashed price or a stock
   line ends up taller than the one beside it and a row of cards has no common bottom edge.
   The catalogue page uses its own class names (sa-page-products-*), which is why the home page
   looked right while /products did not.

   Make the wrapper a flex container and let the card fill it. One rule, every grid. */
.sa-products-item,
.sa-page-products-item,
.sa-categories-item,
.sa-blog-posts-item,
.sa-feedbacks-item {
  display: flex;
}
.sa-products-item > *,
.sa-page-products-item > *,
.sa-categories-item > *,
.sa-blog-posts-item > *,
.sa-feedbacks-item > * {
  flex: 1;
  min-width: 0;
}

/* ── Surfaces the other pages forgot ────────────────────────────────────────
   Every block of content on this site sits on a bordered, rounded panel — except two, which
   float as bare content on the page background: the product gallery and the empty-cart state.
   Same treatment, so a visitor moving between pages meets one kind of surface. */
.sa-product-gallery,
.sa-tpl-cart .py-16.text-center,
.sa-page-feedback .py-16.text-center,
.sa-tpl-status .py-16.text-center {
  border: 1px solid var(--cl-border);
  border-radius: var(--radius-card);
  background: rgb(var(--cl-surface));
  background-image: linear-gradient(rgb(255 255 255 / 0.035), rgb(255 255 255 / 0) 42%);
}
.sa-product-gallery { padding: 10px; overflow: hidden; }
.sa-product-gallery img { border-radius: calc(var(--radius-card) - 6px); }
.sa-tpl-cart .py-16.text-center,
.sa-page-feedback .py-16.text-center,
.sa-tpl-status .py-16.text-center {
  padding-block: clamp(34px, 4.5vw, 54px);
  padding-inline: 24px;
}

/* The purchase panel is the one thing on a product page a buyer has to act in, so it keeps the
   warm edge the rest of the page's panels only get on hover. */
.sa-product-form { border-color: rgb(255 122 46 / 0.28); }

/* ── Buttons, everywhere else ───────────────────────────────────────────────
   The `sa-btn` classes only exist on the hero component. Every other action on the site — Add to
   Cart, Buy Now, Checkout, Browse products, Contact support — is a plain Tailwind button carrying
   `bg-accent-500`, so the brand treatment was reaching exactly one row of the site and the rest of
   the shop pressed flat orange buttons.

   Restricted to button and a elements on purpose: `bg-accent-500` is also on icon tiles and
   badges, which should stay flat. */
button.bg-accent-500,
a.bg-accent-500 {
  background-image: var(--mg-gradient-text-safe);
  border: 0;
  font-weight: 600;
  box-shadow: var(--mg-lift);
  transition: transform 180ms var(--mg-ease), filter 180ms var(--mg-ease),
              box-shadow 180ms var(--mg-ease);
}
button.bg-accent-500:hover,
a.bg-accent-500:hover { transform: translateY(-1px); filter: saturate(1.06); }
button.bg-accent-500:active,
a.bg-accent-500:active { transform: translateY(1px) scale(0.995); }
button.bg-accent-500:focus-visible,
a.bg-accent-500:focus-visible {
  outline: 2px solid var(--mg-ember);
  outline-offset: 3px;
}
/* A disabled action must not look pressable. */
button.bg-accent-500:disabled,
button.bg-accent-500[disabled] {
  background-image: none;
  box-shadow: none;
  transform: none;
  filter: none;
}
:root[data-scheme="light"] button.bg-accent-500,
:root[data-scheme="light"] a.bg-accent-500 { color: #fff; }

@media (prefers-reduced-motion: reduce) {
  button.bg-accent-500,
  a.bg-accent-500 { transition: none; }
  button.bg-accent-500:hover,
  a.bg-accent-500:hover,
  button.bg-accent-500:active,
  a.bg-accent-500:active { transform: none; }
}

/* ── Light scheme contrast ──────────────────────────────────────────────────
   The brand orange is a dark-surface colour: #FF5A1F on the light background measures 2.86:1,
   which fails for text at any size. Anywhere it is used as *text* in light, it deepens to a tone
   that clears 4.5:1 — the hue is kept, only the value moves. */
:root[data-scheme="light"] .shiny-text {
  /* the component writes its gradient inline, so this has to outrank it */
  background-image: linear-gradient(110deg, #9c3410 0%, #9c3410 35%, #d1571c 50%, #9c3410 65%, #9c3410 100%) !important;
}
:root[data-scheme="light"] .mg-stat--hero .mg-stat-tag { color: #9c3410; }
:root[data-scheme="light"] .sa-section-eyebrow,
:root[data-scheme="light"] .sa-hero-eyebrow { color: #9c3410; }
:root[data-scheme="light"] .mg-stat-rowtext strong,
:root[data-scheme="light"] .mg-contact-text strong { color: rgb(var(--cl-t-primary)); }

/* ── Payments row ───────────────────────────────────────────────────────────
   The theme's trust-badges component draws its icons from Font Awesome, which has no Litecoin,
   Binance or Coinbase mark — so this row is authored instead, with the real marks (simple-icons,
   CC0 icon data) inlined as paths.

   Monochrome on purpose: seven brand palettes side by side would out-colour everything else on
   the page, and a payment row is a reassurance, not a feature. They warm on hover. */
.mg-pay {
  display: grid;
  justify-items: center;
  gap: 14px;
  padding: clamp(20px, 2.4vw, 30px);
  border-radius: var(--radius-card);
  border: 1px solid var(--cl-border);
  background: rgb(var(--cl-surface));
  background-image: linear-gradient(rgb(255 255 255 / 0.035), rgb(255 255 255 / 0) 42%);
  text-align: center;
}
.mg-pay-title {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin: 0;
  font-family: var(--ff-heading);
  font-weight: 600;
  font-size: 0.98rem;
  color: rgb(var(--cl-t-primary));
}
.mg-pay-title svg { color: var(--mg-flame); flex: none; }
.mg-pay-marks {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 18px;
}
.mg-pay-mark {
  display: inline-grid;
  place-items: center;
  color: rgb(var(--cl-t-muted));
  transition: color 200ms var(--mg-ease), transform 200ms var(--mg-ease);
}
.mg-pay-mark svg { width: 24px; height: 24px; display: block; }
.mg-pay-mark:hover { color: var(--mg-flame); transform: translateY(-2px); }
.mg-pay-note {
  margin: 0;
  max-width: 68ch;
  font-size: 0.9rem;
  line-height: 1.55;
  color: rgb(var(--cl-t-muted));
}

@media (prefers-reduced-motion: reduce) {
  .mg-pay-mark { transition: none; }
  .mg-pay-mark:hover { transform: none; }
}

/* Not every mark is a filled glyph — the voucher icon is a stroked one and has to keep its own
   fill:none, or it collapses into a solid blob. */
.mg-pay-mark--stroke svg { fill: none; stroke: currentColor; }

/* ── Group modal filters ────────────────────────────────────────────────────
   Styled here rather than with Tailwind utilities in the template: built.css only contains the
   classes the theme itself already used, and there is no way to rebuild it from this side. The
   logical-property ones this toolbar wanted (ps-9, pe-3, start-3) are not in it, which is how the
   search icon ended up sitting on top of its own placeholder. */
.sa-group-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-bottom: 16px;
}
.sa-group-search {
  position: relative;
  flex: 1 1 13rem;
  min-width: 11rem;
  display: block;
}
.sa-group-search svg {
  position: absolute;
  left: 12px;
  top: 50%;
  width: 16px;
  height: 16px;
  transform: translateY(-50%);
  color: rgb(var(--cl-t-muted));
  pointer-events: none;
}
.sa-group-search input {
  width: 100%;
  padding: 9px 12px 9px 36px;          /* room for the icon, which is the whole point */
  font-size: 0.875rem;
  color: rgb(var(--cl-t-primary));
  background: rgb(var(--cl-surface-raised));
  border: 1px solid var(--cl-border);
  border-radius: var(--radius-input);
  transition: border-color 180ms var(--mg-ease);
}
.sa-group-search input::placeholder { color: rgb(var(--cl-t-muted)); }
.sa-group-search input:focus { outline: none; border-color: var(--mg-flame); }
.sa-group-search input::-webkit-search-cancel-button { filter: invert(0.6); }

.sa-group-toggle,
.sa-group-sort {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 12px;
  font-size: 0.875rem;
  color: rgb(var(--cl-t-muted));
  background: rgb(var(--cl-surface-raised));
  border: 1px solid var(--cl-border);
  border-radius: var(--radius-input);
  cursor: pointer;
  transition: color 180ms var(--mg-ease), border-color 180ms var(--mg-ease),
              background-color 180ms var(--mg-ease);
}
.sa-group-toggle svg { width: 16px; height: 16px; }
.sa-group-toggle:hover,
.sa-group-sort:hover { color: rgb(var(--cl-t-primary)); }
/* The filter has to look switched on, or nobody can tell whether it took. */
.sa-group-toggle.is-on {
  color: var(--mg-flame);
  border-color: rgb(255 122 46 / 0.5);
  background: rgb(255 122 46 / 0.12);
}
.sa-group-toggle:focus-visible,
.sa-group-sort:focus-visible,
.sa-group-search input:focus-visible {
  outline: 2px solid var(--mg-ember);
  outline-offset: 2px;
}
/* The wrapper each card sits in for filtering must not break the equal-height rule. */
.sa-group-item { display: flex; }
.sa-group-item > * { flex: 1; min-width: 0; }

/* ── Reviews ─────────────────────────────────────────────────────────────────────────────────
   Rendered from the reviews file, because SellAuth's own section can only show feedback left on
   this shop's orders and there is none yet. Masonry columns rather than a row of equal cards: a
   review is two words or six lines and forcing them to one height wastes the short ones and
   clips the long ones. */
.mg-reviews {
  max-width: var(--mg-container, 1280px);
  margin: 0 auto;
  padding: clamp(3rem, 7vw, 5.5rem) 16px clamp(3.5rem, 8vw, 6rem);
}
.mg-reviews-head { margin-bottom: clamp(1.75rem, 3vw, 2.5rem); }
.mg-reviews-title {
  margin: 0;
  font-family: var(--ff-heading);
  font-weight: 700;
  font-size: clamp(1.6rem, 3.2vw, 2.4rem);
  line-height: 1.05;
  letter-spacing: -0.035em;
  color: rgb(var(--cl-t-primary));
  text-wrap: balance;
}
.mg-reviews-summary {
  margin: 0.5rem 0 0;
  font-size: 0.95rem;
  font-variant-numeric: tabular-nums;
  color: rgb(var(--cl-t-primary));
}
.mg-reviews-note {
  margin: 0.15rem 0 0;
  font-size: 0.78rem;
  color: rgb(var(--cl-t-muted));
}

/* A grid, not masonry columns. Masonry let each card keep its natural height, which meant one
   six-line review made its column tower over the others and the section ended ragged. Every card
   is the height of its row now, the text clamps, and the sold strip is pinned to the bottom so
   those strips line up straight across. */
.mg-reviews-grid {
  display: grid;
  gap: 14px;
  grid-template-columns: 1fr;
}
@media (min-width: 640px)  { .mg-reviews-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .mg-reviews-grid { grid-template-columns: repeat(3, 1fr); } }

.mg-review {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 12px 16px 0;
  overflow: hidden;
  border: 1px solid var(--cl-border);
  border-radius: calc(var(--mg-radius-card, 14px) - 2px);   /* tighter than the containers */
  background: rgb(var(--cl-surface));
  /* Tinted toward the brand's warm dark rather than pure black, so the lift reads as part of
     the page instead of a grey halo pasted onto it. */
  box-shadow: 0 1px 2px rgba(18, 8, 2, 0.32);
  transition: transform 320ms var(--mg-ease), border-color 320ms var(--mg-ease);
}
.mg-review:hover {
  transform: translateY(-2px);
  border-color: rgba(var(--cl-accent), 0.35);
}
/* On white, --cl-border is a 15%-opacity light grey — technically present, visually absent. The
   card needs its own edge and a softer, warmer lift to sit on the page at all. */
[data-scheme="light"] .mg-review {
  border-color: rgba(31, 22, 16, 0.13);
  box-shadow: 0 1px 2px rgba(120, 60, 20, 0.07), 0 6px 16px -10px rgba(120, 60, 20, 0.16);
}
[data-scheme="light"] .mg-review:hover { border-color: rgba(var(--cl-accent), 0.45); }

.mg-review-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 8px;
}
.mg-review-stars { display: flex; gap: 1px; }
.mg-review-star { width: 15px; height: 15px; fill: var(--mg-ember); }
.mg-review-star.is-off { fill: rgba(var(--cl-t-primary), 0.18); }
.mg-review-date {
  font-size: 0.72rem;
  color: rgb(var(--cl-t-muted));
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.mg-review-body { flex: 1; margin: 0 0 12px; }

.mg-reviews .mg-review .mg-review-text {
  margin: 0;
  font-size: 0.9rem;
  line-height: 1.55;
  color: rgb(var(--cl-t-primary));
  text-wrap: pretty;
  /* Three lines: enough for almost every review here, and the handful that run longer are cut
     at a sentence boundary often enough that the ellipsis reads as "there is more" rather than
     as damage. flex-1 keeps short reviews from collapsing their card. */
  flex: 1;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  /* Two lines, reserved whether or not they are used, so every card is the same height without
     leaving a band of empty space under the short reviews — and most reviews here are short. */
  min-height: calc(2 * 1.55 * 0.9rem);
}

/* Only on cards whose text was actually cut. Sits between the review and the sold strip, styled
   as a link rather than a button: it reveals text already on the page, it does not fetch. */
.mg-review-toggle {
  margin-left: auto;
  padding: 0;
  font: inherit;
  font-size: 0.78rem;
  font-weight: 600;
  color: rgb(var(--cl-accent));
  background: none;
  border: 0;
  cursor: pointer;
}
.mg-review-toggle:hover { text-decoration: underline; }

/* Expanded, the card keeps no reserved height and grows to fit. Its row grows with it, which is
   the honest trade for reading the whole review in place instead of losing it to an ellipsis. */
.mg-reviews .mg-review.is-open .mg-review-text {
  -webkit-line-clamp: unset;
  line-clamp: unset;
  display: block;
  min-height: 0;
}

/* What was bought, on its own inset strip so it reads as a record attached to the review rather
   than as another sentence the buyer wrote. Full-bleed to the card edges, which is why the card
   lost its bottom padding and gained overflow: hidden. */
.mg-review-sold {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 -16px;
  padding: 9px 16px;
  border-top: 1px solid var(--cl-border);
  background: rgba(var(--cl-t-primary), 0.035);
  font-size: 0.78rem;
  font-weight: 500;
  color: rgb(var(--cl-t-muted));
}
.mg-review-sold-icon { width: 15px; height: 15px; flex-shrink: 0; color: rgb(var(--cl-accent)); }
[data-scheme="light"] .mg-review-sold { background: rgba(31, 22, 16, 0.04); }
.mg-reviews-more {
  display: block;
  margin: 0.5rem auto 0;
  padding: 10px 22px;
  font: inherit;
  font-size: 0.88rem;
  font-weight: 600;
  color: rgb(var(--cl-t-primary));
  background: transparent;
  border: 1px solid var(--cl-border);
  border-radius: 999px;
  cursor: pointer;
  transition: border-color 220ms var(--mg-ease), background 220ms var(--mg-ease);
}
.mg-reviews-more:hover {
  border-color: rgba(var(--cl-accent), 0.5);
  background: rgba(var(--cl-accent), 0.08);
}
.mg-reviews-more.is-loading {
  color: rgb(var(--cl-t-muted));
  cursor: default;
  border-color: var(--cl-border);
  background: transparent;
}
@media (prefers-reduced-motion: reduce) {
  .mg-review, .mg-reviews-more { transition: none; }
  .mg-review:hover { transform: none; }
}

/* Rating filter, reviews page only. Chips rather than a select: there are four of them at most,
   and a dropdown hides the counts that make them worth clicking. */
.mg-reviews-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 18px;
}
.mg-reviews-filter {
  padding: 7px 14px;
  font: inherit;
  font-size: 0.82rem;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  color: rgb(var(--cl-t-muted));
  background: transparent;
  border: 1px solid var(--cl-border);
  border-radius: 999px;
  cursor: pointer;
  transition: color 200ms var(--mg-ease), border-color 200ms var(--mg-ease),
              background 200ms var(--mg-ease);
}
.mg-reviews-filter:hover { color: rgb(var(--cl-t-primary)); border-color: rgba(var(--cl-accent), 0.4); }
.mg-reviews-filter[aria-pressed="true"] {
  color: rgb(var(--cl-t-primary));
  border-color: rgba(var(--cl-accent), 0.55);
  background: rgba(var(--cl-accent), 0.12);
}
@media (prefers-reduced-motion: reduce) { .mg-reviews-filter { transition: none; } }

/* Social row in the footer. Icon-only: three destinations, all instantly recognisable, and a
   labelled button each would out-weigh the footer links beside them. */
.mg-socials { display: flex; gap: 10px; margin-top: 18px; }
/* In the copyright bar: level with the copyright, pushed to the right end on anything wider than
   a phone. On a phone the bar stacks and centres, and the icons centre under the copyright. */
.mg-socials--bar { margin-top: 0; }
@media (min-width: 640px) { .mg-socials--bar { margin-left: auto; } }
.mg-social {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border: 1px solid var(--cl-border);
  border-radius: 10px;
  color: rgb(var(--cl-t-muted));
  transition: color 200ms var(--mg-ease), border-color 200ms var(--mg-ease),
              background 200ms var(--mg-ease), transform 200ms var(--mg-ease);
}
.mg-social svg { width: 18px; height: 18px; }
.mg-social:hover {
  color: rgb(var(--cl-accent));
  border-color: rgba(var(--cl-accent), 0.45);
  background: rgba(var(--cl-accent), 0.1);
  transform: translateY(-1px);
}
[data-scheme="light"] .mg-social { border-color: rgba(31, 22, 16, 0.13); }
@media (prefers-reduced-motion: reduce) {
  .mg-social { transition: none; }
  .mg-social:hover { transform: none; }
}

/* Delivery took the wide tile and satisfaction took the row, so the wide one no longer has bars
   to fill its right side — the figure moves up to where they were rather than leaving a gap. */
/* --wide is a row with its tag pinned to the corner, which suited a figure sitting next to a bar
   chart. Delivery has no chart, so it stacks like the hero instead of laying its three lines out
   side by side. */
.mg-stat--delivery {
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 6px;
}
.mg-stat--delivery > :first-child { position: static; }
.mg-stat--delivery .mg-stat-figure { margin-top: 2px; }
.mg-stat--delivery .mg-stat-note { max-width: 34ch; }

/* In the row, the bars stand in for the icon the clock used to be: same size, same left slot. */
.mg-stat--satisfaction .mg-stat-bars { height: 24px; margin-top: 0; flex-shrink: 0; }
.mg-stat--satisfaction .mg-stat-rowtext strong { font-variant-numeric: tabular-nums; }

/* ── Reach-out dialog ────────────────────────────────────────────────────────────────────────
   Named mg-reach rather than mg-contact: the theme already has an .mg-contact section on the
   shop page, and taking its class names silently restyled it.

   A second button beside the shop's own call to action, quieter than it — the primary action is
   still to go and look at the accounts. */
.mg-reach-open {
  display: inline-flex;
  align-items: center;
  margin-left: 10px;
  padding: 10px 20px;
  font: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  color: rgb(var(--cl-t-primary));
  background: transparent;
  border: 1px solid rgba(var(--cl-accent), 0.4);
  border-radius: var(--mg-radius-btn, 999px);
  cursor: pointer;
  transition: border-color 200ms var(--mg-ease), background 200ms var(--mg-ease);
}
.mg-reach-open:hover {
  border-color: rgba(var(--cl-accent), 0.7);
  background: rgba(var(--cl-accent), 0.1);
}

.mg-reach {
  /* No position of its own. A modal <dialog> is centred by the browser through position: fixed
     with auto margins; overriding that with position: relative dropped it at the top of the
     page. Absolutely positioned children still anchor to it, because the UA's fixed is a
     containing block. */
  width: min(440px, calc(100vw - 32px));
  padding: 22px;
  border: 1px solid var(--cl-border);
  border-radius: var(--mg-radius-card, 14px);
  background: rgb(var(--cl-surface));
  color: rgb(var(--cl-t-primary));
  box-shadow: 0 24px 60px -24px rgba(12, 5, 1, 0.75);
}
.mg-reach::backdrop { background: rgba(8, 5, 3, 0.66); backdrop-filter: blur(3px); }
.mg-reach-head h2 {
  margin: 0;
  font-family: var(--ff-heading);
  font-size: 1.3rem;
  letter-spacing: -0.02em;
}
.mg-reach-head p { margin: 4px 0 16px; font-size: 0.85rem; color: rgb(var(--cl-t-muted)); }
.mg-reach-close {
  position: absolute;
  top: 12px;
  right: 14px;
  padding: 2px 6px;
  font-size: 1.3rem;
  line-height: 1;
  color: rgb(var(--cl-t-muted));
  background: none;
  border: 0;
  cursor: pointer;
}
.mg-reach-close:hover { color: rgb(var(--cl-t-primary)); }

.mg-reach-list { display: grid; gap: 8px; }
.mg-reach-way {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 12px;
  border: 1px solid var(--cl-border);
  border-radius: calc(var(--mg-radius-card, 14px) - 4px);
  text-decoration: none;
  color: inherit;
  transition: border-color 200ms var(--mg-ease), background 200ms var(--mg-ease);
}
.mg-reach-way:hover {
  border-color: rgba(var(--cl-accent), 0.45);
  background: rgba(var(--cl-accent), 0.07);
}
.mg-reach-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  flex-shrink: 0;
  border-radius: 9px;
  color: rgb(var(--cl-accent));
  background: rgba(var(--cl-accent), 0.12);
}
.mg-reach-mark svg { width: 18px; height: 18px; }
.mg-reach-text { display: flex; flex-direction: column; min-width: 0; }
.mg-reach-text strong { font-size: 0.9rem; font-weight: 600; }
.mg-reach-text small { font-size: 0.76rem; color: rgb(var(--cl-t-muted)); }
[data-scheme="light"] .mg-reach-way { border-color: rgba(31, 22, 16, 0.13); }
@media (prefers-reduced-motion: reduce) {
  .mg-reach-open, .mg-reach-way { transition: none; }
}

/* SellAuth's own credit line. The shop is the owner's brand end to end; a platform byline in the
   footer is the one piece of the page that is not theirs to show. Hidden rather than removed —
   the element is rendered server-side and would come back on the next deploy. */
.sa-powered-by { display: none !important; }

/* Inside a product tab, the reviews sit in the panel's own space: no page gutters, no top rule,
   and the section's own heading stands down because the tab above it already said "Reviews". */
.mg-cp-reviews { padding: 4px 0 8px; }
.mg-cp-reviews .mg-reviews-title { font-size: clamp(1.1rem, 1.6vw, 1.35rem); }
.mg-cp-reviews .mg-reviews-head { margin-bottom: 14px; }

/* The bot check. It runs on page load with no input from the buyer, so once it has passed there
   is nothing for them to do and a ticked "Verified" box beside the total only reads as another
   thing to worry about. Hidden in the verified state alone — a widget that is still working, or
   that has failed, stays on screen, because that is when it has something to say. */
altcha-widget:has(.altcha[data-state="verified"]) { display: none; }

/* A last row holding a single card. CSS Grid puts it in column one, so a full row of three or
   four is followed by one card hard against the left edge, which reads as a layout fault rather
   than as the fourth item. It gets centred instead.

   With an odd number of columns the middle column is a real column, so the card simply moves
   into it. With an even number there is no middle column, so the card spans the row and is
   centred inside it at exactly one track's width — the same arithmetic the grid uses, gap
   included, so it lines up with the cards above. */
@media (min-width: 640px) and (max-width: 1023px) {          /* two columns */
  .sa-products-items > :last-child:nth-child(2n + 1),
  .sa-page-products-items > :last-child:nth-child(2n + 1) {
    grid-column: 1 / -1;
    justify-self: center;
    width: calc((100% - 20px) / 2);
  }
}
@media (min-width: 1024px) and (max-width: 1279px) {         /* three columns */
  .sa-products-items > :last-child:nth-child(3n + 1),
  .sa-page-products-items > :last-child:nth-child(3n + 1) {
    grid-column: 2;
  }
}
@media (min-width: 1280px) {                                 /* four columns */
  .sa-products-items > :last-child:nth-child(4n + 1),
  .sa-page-products-items > :last-child:nth-child(4n + 1) {
    grid-column: 1 / -1;
    justify-self: center;
    width: calc((100% - 60px) / 4);
  }
}

/* Payment marks: a logo with its name under it. Eight unlabelled glyphs made a buyer guess which
   was Kraken and which was Binance; the names cost one line and answer it. */
.mg-pay-marks { flex-wrap: wrap; gap: 18px 22px; }
.mg-pay-mark {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  opacity: 1;
}
.mg-pay-mark svg { width: 26px; height: 26px; }
.mg-pay-name {
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.01em;
  color: rgb(var(--cl-t-muted));
  white-space: nowrap;
}
/* The coloured marks carry themselves; the gift card has no brand, so it takes the shop's. */
.mg-pay-mark[title*="voucher" i], .mg-pay-mark[title*="gift" i] { color: rgb(var(--cl-accent)); }