/* Scientech Blocks — assembled by plugin/build.py from redesign/*.css.
   Do not edit this file directly; edit the source and rebuild. */

/* ===========================================================================
   Scientech Mart — shared design tokens
   Palette keyed to the logo blue (sampled #2460CC, range #1854E4–#3084D8).

   Concentric radii
   ----------------
   Nested corners only look right when the inner radius is the outer radius
   minus the gap between them: r_inner = r_outer - padding. The scale below is
   built on a 4px step so the common nestings work out exactly:

     hero (--r-2xl 20) > card (--r-lg 12, inset 8) > media (--r-md 8, inset 4)
     card (--r-lg 12)  > pill/icon (--r-full)

   Use the pair that matches the actual padding rather than picking by eye.
   ========================================================================== */

:root {
  --sm-blue-900: #0b2354;
  --sm-blue-800: #12317a;
  --sm-blue-700: #1a4aad;
  --sm-blue-600: #2460cc; /* core brand blue */
  --sm-blue-500: #1854e4;
  --sm-blue-400: #3084d8;
  --sm-blue-300: #5aa7ea;
  --sm-blue-050: #e8eefb;

  --sm-ink: #16233d;
  --sm-ink-soft: #2a3550;
  --sm-ink-muted: #8a93a6;
  --sm-line: #e4e8f0;

  /* 4px-step radius scale */
  --r-xs: 4px;
  --r-sm: 6px;
  --r-md: 8px;
  --r-lg: 12px;
  --r-xl: 16px;
  --r-2xl: 20px;
  --r-full: 9999px;

  /* Page container. The theme's Elementor sections resolve to a 1520px content
     box with a 15px gutter, so the redesigned sections use the same figures —
     otherwise their edges (and the rules under section headings) sit at a
     different x than every existing section on the page. */
  --sm-gutter: 0.9375rem;
  --sm-container: calc(1520px + 2 * var(--sm-gutter));

  /* Inset that makes each nesting concentric */
  --pad-card: 8px; /* --r-2xl outer -> --r-lg inner is 8px of padding */
  --pad-media: 4px; /* --r-lg outer -> --r-md inner is 4px of padding */
}

/* ===========================================================================
   Scientech Mart — hero
   Design language ported from forsale.com.pk (src/components/site/BannerCarousel.astro)
   Palette and radii come from tokens.css, keyed to the Scientech logo blue.

   The forsale original is Tailwind + oklch shadcn tokens. The mirror has neither,
   so the same design is expressed as plain CSS — nothing here leaks into the
   existing Elementor/Woo styles.
   ========================================================================== */

/* Outer gutter — matches the width the Elementor hero occupied so the swap
   doesn't shift the sections below it. */
/* Matches the theme's section container exactly, so the hero's edges line up
   with every Elementor section below it. */
.sm-hero-wrap {
  width: 100%;
  max-width: var(--sm-container);
  margin: 0 auto;
  padding: 0 var(--sm-gutter);
}

.sm-hero {
  /* Eased, not linear. A two-stop ramp changes slope abruptly where the fade
     starts, and against a flat backdrop the eye reads that kink as a seam —
     which is exactly what showed up as a vertical line down the middle of the
     banner. The stops below trace an S-curve instead: nearly flat where the
     fade begins, steepest in the middle, flattening again at the end, so there
     is no point along it where the rate of change jumps. */
  --sm-fade: linear-gradient(
    to right,
    #000 0%,
    rgba(0, 0, 0, 0.99) 38%,
    rgba(0, 0, 0, 0.94) 50%,
    rgba(0, 0, 0, 0.82) 60%,
    rgba(0, 0, 0, 0.6) 70%,
    rgba(0, 0, 0, 0.34) 80%,
    rgba(0, 0, 0, 0.12) 90%,
    transparent 100%
  );

  /* The single inset used on every side of the card rail. It has to clear the
     story progress bars, which sit at --sm-bars-top and are --sm-bars-h tall —
     otherwise the bars are drawn across the top of the cards. */
  --sm-bars-top: 0.5rem;
  --sm-bars-h: 3px;
  --sm-hero-inset: 1.25rem;

  /* Ceiling on the copy column. Without it a sentence-length headline — which
     has no ch cap on desktop — would measure at its full one-line width and
     leave the cards nothing. Lower it to give the cards more room, at the cost
     of the longest headline wrapping onto another line. */
  --sm-hero-copy-max: 36rem;

  /* The card radius is the one number that sets the whole nesting: the hero is
     this plus the inset, the card media is this minus --pad-media. At --r-xs
     the media resolves to square, which is the floor — going below it would
     break the formula rather than tighten it further. Raise this and the hero
     rounds off with it, no other edit needed. */
  --sm-card-r: var(--r-xs);

  position: relative;
  overflow: hidden;
  /* Concentric by construction: outer radius = card radius + the inset, so the
     formula holds whatever --sm-hero-inset is set to. From sm up the rail
     carries that inset as its own padding and is the hero's only in-flow
     child, so the height resolves to exactly card height + 2 × inset — no
     aspect ratio, no leftover band above or below the cards. */
  border-radius: calc(var(--sm-card-r) + var(--sm-hero-inset));
  /* Phones stack: card rail across the top, copy anchored bottom-left. */
  min-height: 26rem;
  background: var(--sm-blue-900);
}

/* On phones the copy sits at the bottom, so the gradient has to be opaque at
   the bottom rather than on the left. */
@media (max-width: 639px) {
  .sm-hero {
    --sm-fade: linear-gradient(
      to top,
      #000 0%,
      rgba(0, 0, 0, 0.99) 40%,
      rgba(0, 0, 0, 0.94) 52%,
      rgba(0, 0, 0, 0.82) 62%,
      rgba(0, 0, 0, 0.6) 72%,
      rgba(0, 0, 0, 0.34) 82%,
      rgba(0, 0, 0, 0.12) 92%,
      transparent 100%
    );
  }
}

@media (min-width: 640px) {
  .sm-hero { min-height: 0; }
}

/* --- slides ---------------------------------------------------------------- */

.sm-hero__slide {
  position: absolute;
  inset: 0;
  overflow: hidden;
  color: #fff;
  opacity: 0;
  pointer-events: none;
  transition: opacity 500ms ease-out;
}

.sm-hero__slide.is-active {
  opacity: 1;
  pointer-events: auto;
}

/* Brand gradient, masked so it's opaque behind the text and clears the rail. */
.sm-hero__wash {
  position: absolute;
  inset: 0;
  -webkit-mask-image: var(--sm-fade);
  mask-image: var(--sm-fade);
}

.sm-hero__slide[data-wash="1"] .sm-hero__wash {
  background-image: linear-gradient(135deg, var(--sm-blue-900), var(--sm-blue-600) 55%, var(--sm-blue-400));
}
.sm-hero__slide[data-wash="2"] .sm-hero__wash {
  background-image: linear-gradient(135deg, #071b45, var(--sm-blue-700) 50%, var(--sm-blue-500));
}
.sm-hero__slide[data-wash="3"] .sm-hero__wash {
  background-image: linear-gradient(135deg, var(--sm-blue-800), var(--sm-blue-500) 55%, #2ea6c9);
}
.sm-hero__slide[data-wash="4"] .sm-hero__wash {
  background-image: linear-gradient(135deg, #0a1f4f, var(--sm-blue-600) 50%, var(--sm-blue-300));
}

/* --- story-style tap zones (left third = prev, right third = next) --------- */

/* The theme skins every bare <button> (background, border, shadow, hover fill),
   which showed up as grey slabs over the left/right thirds. These zones must be
   invisible, so the reset is deliberately absolute. `display` is deliberately
   NOT set here — see the note on the rail arrows below. */
.sm-hero__nav,
.sm-hero__nav:hover,
.sm-hero__nav:focus,
.sm-hero__nav:active {
  position: absolute;
  top: 0;
  bottom: 0;
  z-index: 3;
  width: 33.3333%;
  padding: 0 !important;
  margin: 0 !important;
  border: 0 !important;
  border-radius: 0 !important;
  background: transparent !important;
  background-image: none !important;
  box-shadow: none !important;
  color: inherit;
  font: inherit;
  transform: none !important;
  transition: none !important;
  cursor: default;
  -webkit-appearance: none;
  appearance: none;
}

.sm-hero__nav::before,
.sm-hero__nav::after { content: none !important; }

.sm-hero__nav:focus { outline: none; }
.sm-hero__nav:focus-visible { outline: 2px solid #fff; outline-offset: -4px; }
.sm-hero__nav--prev { left: 0; }
.sm-hero__nav--next { right: 0; }

/* --- copy ------------------------------------------------------------------ */

/* pointer-events cleared so taps fall through to the nav zones; only the CTA
   re-enables them. */
.sm-hero__copy {
  position: relative;
  z-index: 4;
  display: flex;
  height: 100%;
  width: 100%;
  flex-direction: column;
  align-items: flex-start;
  /* Phones: bottom-left, under the card rail. */
  justify-content: flex-end;
  /* One step between every line of the group — eyebrow, title, price, CTA.
     Nothing adds its own margin on top of this. */
  gap: 0.625rem;
  padding: 1.25rem;
  pointer-events: none;
}

@media (min-width: 640px) {
  /* Leave the right half to the product rail. The copy stays bottom-anchored at
     every width — the same corner it holds on phones — so the block reads from
     one fixed origin rather than drifting up and down with its own length. */
  /* The inset is the rail's, not a value of its own: the copy's left and bottom
     then sit exactly as far from the hero's edges as the cards opposite sit from
     theirs, which is what makes the two halves read as one frame. */
  .sm-hero__copy {
    width: var(--sm-hero-copy-w, 50%);
    padding: var(--sm-hero-inset);
  }

  /* Measurement pass. hero.js adds this class for one frame, reads each copy's
     natural width, then removes it. */
  .sm-hero.is-measuring .sm-hero__copy {
    width: max-content;
    /* The 50% is a floor on what the cards keep: --sm-hero-copy-max is an
       absolute length, so on a narrow desktop it can exceed half the hero. */
    max-width: min(var(--sm-hero-copy-max), 50%);
  }
}

/* --- phones: rail and copy in one column ------------------------------------
   Everything in the hero was absolutely positioned here, so nothing drove its
   height and it fell back to a 26rem minimum — which left a band of empty blue
   between the cards and the copy whenever the two together came up short.

   Laid out as a grid instead: the rail takes the first row, every slide shares
   the second, and the tallest of them sets the height. The gap between the
   cards and the copy is then just the copy's own top padding, which is the same
   inset the rail keeps on its other three sides.

   The slides go static so their wash and tap zones — absolute, inset 0 — resolve
   against the hero rather than the copy row, and so keep covering the whole
   banner. Sharing one grid cell is what preserves the crossfade: the outgoing
   slide is still drawn over the incoming one, exactly as when they were stacked
   by position. */
@media (max-width: 639px) {
  .sm-hero {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    min-height: 0;
  }

  /* Child selector for the weight: the wrapper's own `position: absolute` is
     declared further down the file and would otherwise win on source order. */
  .sm-hero > .sm-hero__rails {
    position: relative;
    grid-row: 1;
    grid-column: 1;
    top: auto;
    left: auto;
    right: auto;
    padding: calc(var(--sm-bars-top) + var(--sm-bars-h) + var(--sm-hero-inset))
             0 0;
  }

  .sm-hero__slide {
    position: static;
    grid-row: 2;
    grid-column: 1;
  }

  /* Height stays at 100% of the shared row so every slide's copy bottom-aligns
     on the same line — the row is as tall as the longest headline, and a short
     one would otherwise float above the hero's bottom edge. */
  .sm-hero__copy { padding-top: var(--sm-hero-inset); }
}

.sm-hero__eyebrow {
  margin: 0;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.8);
}

.sm-hero__title {
  margin: 0;
  font-size: 1.375rem;
  font-weight: 600;
  line-height: 1.15;
  color: #fff;
  /* On phones the copy owns the full width; cap the measure so the headline
     doesn't run edge to edge. */
  max-width: 20ch;
}

@media (min-width: 640px) {
  .sm-hero__title { font-size: 1.5rem; max-width: none; }
}

@media (min-width: 1024px) {
  .sm-hero__title { font-size: 2.25rem; }
}

/* The slide's supporting paragraph. No margin: `.sm-hero__copy` lays its
   children out with a gap, and adding one here is what previously made the
   title-to-price step larger than every other step in this block.

   The measure is capped in ch rather than px so it holds at every hero size —
   the copy column is half the banner from 640up, and a paragraph running its
   full width reads as a wall against a 2.25rem headline. */
.sm-hero__text {
  margin: 0;
  font-size: 0.875rem;
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.85);
  max-width: 42ch;
}

@media (min-width: 1024px) {
  .sm-hero__text { font-size: 1rem; }
}

/* Price sits on its own row with the CTA beneath it. Contents are laid out by
   the same gap as the rest of the copy — no extra margin here, which is what
   made the title-to-price step larger than every other step. */
.sm-hero__actions {
  display: contents;
}

/* Label and amount share one size — the amount is distinguished by weight and
   full-strength white, not by being larger. */
.sm-hero__price {
  margin: 0;
  display: flex;
  align-items: baseline;
  gap: 0.3125rem;
  font-size: 0.8125rem;
  line-height: 1.2;
  text-transform: lowercase;
  color: rgba(255, 255, 255, 0.7);
}

.sm-hero__price b {
  font-size: 0.8125rem;
  font-weight: 700;
  text-transform: none;
  color: #fff;
}

.sm-hero__cta {
  pointer-events: auto;
  flex: none;
  display: inline-flex;
  width: fit-content;
  align-items: center;
  gap: 0.25rem;
  border-radius: var(--r-full);
  background: rgba(255, 255, 255, 0.95);
  padding: 0.4375rem 0.875rem;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--sm-blue-900);
  text-decoration: none;
  transition: background-color 150ms ease, transform 150ms ease;
}

.sm-hero__cta:hover,
.sm-hero__cta:focus-visible {
  background: #fff;
  color: var(--sm-blue-900);
  transform: translateY(-1px);
}

/* --- progress bars --------------------------------------------------------- */

/* Aligned to the same inset as the cards, and the rail's top padding is sized
   from these values so the two never overlap. */
.sm-hero__bars {
  position: absolute;
  top: var(--sm-bars-top);
  left: var(--sm-hero-inset);
  right: var(--sm-hero-inset);
  z-index: 6;
  display: flex;
  gap: 0.25rem;
  pointer-events: none;
}

.sm-hero__bar {
  position: relative;
  height: var(--sm-bars-h);
  flex: 1 1 0;
  overflow: hidden;
  border-radius: var(--r-full);
  background: rgba(255, 255, 255, 0.3);
}

.sm-hero__fill {
  display: block;
  height: 100%;
  width: 100%;
  transform: scaleX(0);
  transform-origin: left;
  border-radius: var(--r-full);
  background: #fff;
}

@keyframes sm-hero-progress {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

/* --- featured product rail (right half) ------------------------------------ */

/* Phones: a full-width carousel across the top, starting at the same left
   edge as the copy below it, scrolling out under the right-hand fade. From sm
   up it becomes the centred right half. */
/* The wrapper holds the rail's place in the layout; the rails themselves
   overlap inside it, one per slide.

   The sizing lives here rather than on `.sm-hero__rail` because this element is
   what the hero takes its height from. The slides are `position: absolute`, so
   without an in-flow sibling the banner has no height at all — that is why the
   rails could not simply be moved inside the slides they belong to. */
.sm-hero__rails {
  position: absolute;
  /* Clears the progress bars by a full inset rather than a guessed offset. */
  top: calc(var(--sm-bars-top) + var(--sm-bars-h) + var(--sm-hero-inset));
  left: 0;
  right: 0;
  z-index: 5;
  display: grid;
}

/* Every rail sits on the same single grid cell, so the wrapper is as tall as
   the tallest one and the hero does not jump when a slide holds fewer cards
   than its neighbour. `position: relative` stays on the rail because the edge
   fades and the arrows are absolutely positioned against it. */
.sm-hero__rails > .sm-hero__rail {
  grid-area: 1 / 1;
  position: relative;
  min-width: 0;
  opacity: 0;
  pointer-events: none;
  transition: opacity 500ms ease-out;
}

.sm-hero__rails > .sm-hero__rail.is-active {
  opacity: 1;
  pointer-events: auto;
}

@media (prefers-reduced-motion: reduce) {
  .sm-hero__rails > .sm-hero__rail { transition: none; }
}

@media (min-width: 640px) {
  /* In flow, so the hero takes its height from the cards. The rail's padding
     is the only top/bottom spacing there is, and it is what makes the hero and
     the cards concentric.

     The inset is measured from *below* the progress bars, not from the hero's
     top edge — the bars are a fixture of the frame, so the gap the eye reads as
     the card inset is the one under them. Left, right and bottom stay at the
     bare inset, which is what the radius formula is keyed to; only the top band
     carries the bars' own height on top of it. */
  .sm-hero__rails {
    position: relative;
    top: auto;
    right: auto;
    width: calc(100% - var(--sm-hero-copy-w, 50%));
    margin-left: auto;
    padding: calc(var(--sm-bars-top) + var(--sm-bars-h) + var(--sm-hero-inset))
             var(--sm-hero-inset)
             var(--sm-hero-inset)
             0;
    transform: none;
  }
}

/* overflow-x: auto makes this a scrollport in *both* axes — the browser has no
   "clip horizontally, spill vertically" mode — so a card's 3px hover lift and
   its shadow were being sliced off at the track's top edge. The padding gives
   the lift somewhere to go and the matching negative margin keeps the track's
   own box, and therefore the rail's spacing, exactly where it was. */
.sm-hero__railtrack {
  display: flex;
  gap: 0.625rem;
  /* Asymmetric because the hover shadow is: it reaches ~6px above the card and
     ~46px below it. */
  margin-block: -0.75rem -3rem;
  overflow-x: auto;
  scroll-behavior: smooth;
  scroll-snap-type: x proximity;
  /* Phones: left padding matches .sm-hero__copy so the first card lines up
     with the headline underneath it. scroll-padding must match, or snapping
     aligns the first card to the scrollport edge and cancels the padding. */
  padding: 0.75rem var(--sm-hero-inset) 3rem;
  scroll-padding-left: var(--sm-hero-inset);
  scrollbar-width: none;
  -ms-overflow-style: none;
}

@media (min-width: 640px) {
  /* The rail's own --pad-card is the inset now, so the track adds none —
     otherwise the cards would sit further from the edge than the padding. */
  .sm-hero__railtrack {
    padding: 0.75rem 0 3rem;
    scroll-padding-left: 0;
  }
}

.sm-hero__railtrack::-webkit-scrollbar { display: none; }

@media (prefers-reduced-motion: reduce) {
  .sm-hero__railtrack { scroll-behavior: auto; }
}

/* Fades: right only at rest, left once scrolled — as a mask on the track, not
   as a tinted slab over it.

   The slab version painted a panel of flat blue over the cards' leading edge.
   The backdrop there is the wash — a diagonal gradient — so no single colour
   ever matched it, and the slab's own left edge read as a hard vertical line
   down the middle of the banner. Masking the track instead dissolves whatever
   is scrolling out into whatever happens to be behind it, so there is nothing
   to colour-match and no edge to see. The elements stay in the markup, unpainted
   — the state classes rail.js sets on the rail are the hook either way. */
.sm-hero__railfade { display: none; }

.sm-hero__rail.can-scroll-start .sm-hero__railtrack {
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 2.5rem);
  mask-image: linear-gradient(to right, transparent 0, #000 2.5rem);
}

.sm-hero__rail.can-scroll-end .sm-hero__railtrack {
  -webkit-mask-image: linear-gradient(to left, transparent 0, #000 2.5rem);
  mask-image: linear-gradient(to left, transparent 0, #000 2.5rem);
}

.sm-hero__rail.can-scroll-start.can-scroll-end .sm-hero__railtrack {
  -webkit-mask-image: linear-gradient(
    to right,
    transparent 0,
    #000 2.5rem,
    #000 calc(100% - 2.5rem),
    transparent 100%
  );
  mask-image: linear-gradient(
    to right,
    transparent 0,
    #000 2.5rem,
    #000 calc(100% - 2.5rem),
    transparent 100%
  );
}

/* Arrows. `display` lives only in the media query below — never in a rule that
   also matches :hover, or the element toggles between none/grid as the pointer
   enters it and flickers. */
.sm-hero__railnav,
.sm-hero__railnav:hover,
.sm-hero__railnav:focus,
.sm-hero__railnav:active {
  position: absolute;
  top: 50%;
  z-index: 3;
  place-items: center;
  width: 1.875rem;
  height: 1.875rem;
  transform: translateY(-50%);
  padding: 0 !important;
  margin: 0 !important;
  border: 0 !important;
  border-radius: var(--r-full) !important;
  background: rgba(255, 255, 255, 0.94) !important;
  background-image: none !important;
  box-shadow: 0 4px 12px -4px rgba(4, 20, 55, 0.4) !important;
  color: var(--sm-blue-900);
  cursor: pointer;
  opacity: 0;
  transition: opacity 200ms ease !important;
}

.sm-hero__railnav--prev { left: -0.25rem; }
.sm-hero__railnav--next { right: 0.375rem; }

@media (hover: hover) and (min-width: 640px) {
  .sm-hero__railnav { display: grid; }
  .sm-hero__rail.can-scroll-start .sm-hero__railnav--prev,
  .sm-hero__rail.can-scroll-end .sm-hero__railnav--next { opacity: 1; }
}

@media not all and (hover: hover) {
  .sm-hero__railnav { display: none; }
}

.sm-hero__railnav:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

/* --- product card ----------------------------------------------------------
   Concentric: the card takes --sm-card-r and pads the media by --pad-media, so
   the media's radius is --sm-card-r − 4. At the current --r-xs (4) that lands
   on square. */

.sm-card {
  position: relative;
  display: flex;
  flex: none;
  width: 6.25rem;
  scroll-snap-align: start;
  flex-direction: column;
  border-radius: var(--sm-card-r);
  background: #fff;
  padding: var(--pad-media);
  box-shadow: 0 14px 30px -12px rgba(4, 20, 55, 0.45);
  color: inherit;
  text-decoration: none;
  transition: transform 200ms ease, box-shadow 200ms ease;
}

@media (min-width: 640px) {
  .sm-card { width: 10rem; }
  .sm-card__name { font-size: 0.75rem; }
}

@media (min-width: 1024px) {
  .sm-card { width: 11.5rem; }
  .sm-card__name { font-size: 0.8125rem; }
}

/* Cards drive the hero's height, so growing them on wide screens is what keeps
   the banner from looking squat. */
@media (min-width: 1280px) {
  .sm-card { width: 13rem; }
}

.sm-card:hover,
.sm-card:focus-visible {
  transform: translateY(-3px);
  box-shadow: 0 20px 38px -12px rgba(4, 20, 55, 0.55);
  color: inherit;
}

.sm-card__media {
  position: relative;
  display: block;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  /* max() so the formula can't go negative if --sm-card-r is ever set below
     the inset it has to clear. */
  border-radius: max(0px, calc(var(--sm-card-r) - var(--pad-media)));
  background: #fff;
}

.sm-card__media img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.sm-card__badge {
  position: absolute;
  top: 0.375rem;
  left: 0.375rem;
  border-radius: var(--r-full);
  background: var(--sm-blue-600);
  padding: 0.125rem 0.4375rem;
  font-size: 0.5625rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #fff;
}

.sm-card__body {
  display: flex;
  flex-direction: column;
  gap: 0.1875rem;
  padding: 0.5rem 0.375rem 0.375rem;
}

.sm-card__name {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  font-size: 0.625rem;
  font-weight: 500;
  line-height: 1.35;
  color: var(--sm-ink);
}

@media (prefers-reduced-motion: reduce) {
  .sm-hero__slide { transition: none; }
  .sm-hero__fill { transform: scaleX(1) !important; animation: none !important; }
  .sm-card { transition: none; }
}

/* ===========================================================================
   Scientech Mart — category promo panel
   Replaces the hand-authored purple banner left of the "Pro Gaming Gear" grid.
   Markup comes from redesign/promo.py; this only dresses it.

   The artwork is whatever the newest product in the category happens to be, so
   nothing here may assume anything about it. The catalogue mixes white-backdrop
   JPEGs, black-backdrop JPEGs and cut-out PNGs, and no blend mode or key-out
   serves all three. So the image is simply laid in and a scrim in the panel's
   own grey is drawn over its top: opaque where the copy sits, fully clear at
   the bottom where the product should show. That reads correctly for any image.
   ========================================================================== */

/* The theme's anchor wraps the panel and is the click target for the whole
   tile, so it has to fill the column rather than shrink to the text. Scoped to
   the banner widget — there is exactly one on the page. */
/* Width too, not just display. The banner widget carries a ~92% width set on it
   in Elementor, emitted as `.elementor-<page> .elementor-element.elementor-element-<id>`
   — a three-class selector this file cannot outrank, hence !important. Left as
   it was, the panel sits ~28px short of its column and the gap to the product
   cards beside it reads as nearly three times the shell's own inset. */
.elementor-widget-tf-woo-products-banner,
.elementor-widget-tf-woo-products-banner .elementor-widget-container,
.elementor-widget-tf-woo-products-banner > .elementor-widget-container > a {
  display: block;
  width: 100% !important;
  text-decoration: none;
}

.sm-promo {
  /* As channels, so the scrim can fade this exact colour out to alpha 0 rather
     than to `transparent` — which some engines interpolate through black and
     leave a dirty band across the middle of the panel. */
  --sm-promo-rgb: 236 239 245;

  position: relative;
  display: block;
  min-height: 18rem;
  overflow: hidden;
  border-radius: var(--r-xl);
  background: rgb(var(--sm-promo-rgb));
  color: var(--sm-ink);
  transition: background-color 200ms ease;
}

/* Portrait from the point the panel sits beside the product grid rather than
   stacked above it. It drives the row's height — the grid opposite is shorter
   and simply centres against it. On phones the column goes full width, where
   the same ratio would be a tower, so it starts here. */
@media (min-width: 768px) {
  .sm-promo { aspect-ratio: 1 / 1.375; }
}

.sm-promo:hover { --sm-promo-rgb: 229 233 241; }

@media (prefers-reduced-motion: reduce) {
  .sm-promo { transition: none; }
}

/* --- artwork ----------------------------------------------------------------
   Full panel width, anchored to the bottom edge at its natural aspect. Anything
   taller than the panel overflows upward and is clipped, which is the safe
   direction: the top is the end the scrim covers. */

.sm-promo__media {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.sm-promo__img {
  position: absolute;
  bottom: 0;
  left: 0;
  display: block;
  width: 100%;
  height: auto;

  /* The fade is measured against the image, not the panel, so it lands on the
     image's own top edge whatever height that edge ends up at — a square shot
     that fills the bottom half and a tall one that overflows the panel both
     dissolve rather than ending on a cut line. Backdrop colour is irrelevant
     here: white, black and cut-out all fade out the same way. */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 52%);
  mask-image: linear-gradient(to bottom, transparent 0%, #000 52%);
}

/* Second line of defence, this one measured against the panel: an image tall
   enough to overflow has its faded top clipped off, so it can still arrive
   behind the copy at partial opacity. This keeps the reading area solid
   regardless, and is clear well before the image's own fade begins. */
.sm-promo__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to bottom,
    rgb(var(--sm-promo-rgb) / 1) 0%,
    rgb(var(--sm-promo-rgb) / 1) 36%,
    rgb(var(--sm-promo-rgb) / 0) 62%
  );
}

/* --- copy ------------------------------------------------------------------ */

.sm-promo__copy {
  position: relative;
  z-index: 1;
  padding: 1.5rem;
}

.sm-promo__title {
  margin: 0 0 0.5rem;
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1.15;
  color: var(--sm-ink);
}

@media (min-width: 1200px) {
  .sm-promo__title { font-size: 1.75rem; }
}

.sm-promo__text {
  margin: 0;
  font-size: 0.8125rem;
  line-height: 1.6;
  color: var(--sm-ink-soft);
}

@media (max-width: 767px) {
  /* Phones turn the panel on its side: it is far wider than it is tall, so the
     bottom-anchored, top-faded arrangement above puts the product squarely in
     the part of the panel the scrim covers — the artwork all but disappears.
     Side by side instead: copy left, artwork bottom-right, and both fades
     rotated a quarter turn to match. Nothing about the image is assumed here
     either; it is still laid in whole and faded out, only along x.

     !important on the box: the theme ships a `width: 100%` on images inside
     this widget that this file cannot outrank on specificity, and it is what
     was stretching the artwork to the full panel. */
  .sm-promo { min-height: 12.5rem; }

  .sm-promo__img {
    right: 0;
    left: auto;
    width: 45% !important;
    max-width: none !important;
    height: auto !important;
    transform: none;
    -webkit-mask-image: linear-gradient(to right, transparent 0%, #000 42%);
    mask-image: linear-gradient(to right, transparent 0%, #000 42%);
  }

  .sm-promo__scrim {
    background: linear-gradient(
      to right,
      rgb(var(--sm-promo-rgb) / 1) 0%,
      rgb(var(--sm-promo-rgb) / 1) 42%,
      rgb(var(--sm-promo-rgb) / 0) 72%
    );
  }

  /* Keeps the copy clear of the artwork's column. */
  .sm-promo__copy { max-width: 62%; }
}

/* ===========================================================================
   Scientech Mart — category rail
   Circular category tiles on a horizontal scroller. Scrollbar is hidden; the
   edge fades are the affordance that there is more to scroll, and they are
   toggled per side by rail.js so a fade only shows where scroll remains.
   Palette and radii come from tokens.css.
   ========================================================================== */

/* Same container as the hero and the theme's sections. */
.sm-cats-wrap {
  width: 100%;
  max-width: var(--sm-container);
  margin: 0 auto;
  padding: 2rem var(--sm-gutter) 0.5rem;
}

@media (min-width: 768px) {
  .sm-cats-wrap { padding: 2.5rem var(--sm-gutter) 0.75rem; }
}

.sm-cats { --sm-cats-fade: 3rem; }

.sm-cats__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1rem;
}

.sm-cats__title {
  margin: 0;
  font-size: 1.125rem;
  font-weight: 700;
  line-height: 1.2;
  color: var(--sm-ink);
}

@media (min-width: 768px) {
  .sm-cats__title { font-size: 1.375rem; }
}

.sm-cats__all {
  display: inline-flex;
  align-items: center;
  gap: 0.125rem;
  flex: none;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--sm-blue-600);
  text-decoration: none;
}

.sm-cats__all:hover { opacity: 0.75; color: var(--sm-blue-600); }

/* --- scroller -------------------------------------------------------------- */

.sm-cats__viewport { position: relative; }

.sm-cats__track {
  display: flex;
  gap: 0.5rem;
  overflow-x: auto;
  scroll-behavior: smooth;
  scroll-snap-type: x proximity;
  /* Bleed to the container edge so tiles scroll out under the fades. */
  margin: 0 -0.25rem;
  padding: 0.25rem;
  /* Hidden scrollbar — the edge fades communicate scrollability instead. */
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.sm-cats__track::-webkit-scrollbar { display: none; }

@media (prefers-reduced-motion: reduce) {
  .sm-cats__track { scroll-behavior: auto; }
}

/* --- tile ------------------------------------------------------------------
   No hover transition here by request: the hover state applies instantly. */

.sm-cats__tile {
  display: flex;
  flex: none;
  width: 6.25rem;
  scroll-snap-align: start;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  padding: 0.25rem 0;
  color: inherit;
  text-decoration: none;
}

@media (min-width: 768px) {
  .sm-cats__tile { width: 7.25rem; }
}

.sm-cats__thumb {
  display: grid;
  place-items: center;
  width: 4.75rem;
  height: 4.75rem;
  overflow: hidden;
  border: 1px solid var(--sm-line);
  border-radius: var(--r-full);
  background: #fff;
}

@media (min-width: 768px) {
  .sm-cats__thumb { width: 5.5rem; height: 5.5rem; }
}

.sm-cats__thumb img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: 0.625rem;
  /* Most category thumbnails are photographs on a white or near-white studio
     backdrop, so inside a white circle they read as a grey square floating on
     it. `multiply` drops anything white to nothing, which makes the artwork
     sit on the circle instead of in a box of its own — and costs nothing on a
     PNG that is already transparent.

     Only white is removed. A thumbnail shot on a dark background still shows
     its backdrop, because there is nothing here that could honestly invent a
     cut-out for it; those need re-shooting or a transparent PNG. */
  mix-blend-mode: multiply;
}

/* No background change on hover — the tile stays white. The border darkens
   instead, which reads as a state without any grey-to-white wash. */
.sm-cats__tile:hover .sm-cats__thumb,
.sm-cats__tile:focus-visible .sm-cats__thumb {
  border-color: #c9d1e0;
}

.sm-cats__label {
  text-align: center;
  font-size: 0.75rem;
  font-weight: 500;
  line-height: 1.3;
  color: var(--sm-ink-soft);
}

.sm-cats__tile:hover .sm-cats__label { color: var(--sm-ink); }

/* --- edge fades ------------------------------------------------------------ */

.sm-cats__fade {
  position: absolute;
  top: 0;
  bottom: 0;
  z-index: 2;
  width: var(--sm-cats-fade);
  pointer-events: none;
  opacity: 0;
  transition: opacity 200ms ease;
}

/* Toggled by rail.js: only the side with remaining scroll is shown. */
.sm-cats__viewport.can-scroll-start .sm-cats__fade--start,
.sm-cats__viewport.can-scroll-end .sm-cats__fade--end { opacity: 1; }

.sm-cats__fade--start {
  left: 0;
  background: linear-gradient(to right, #fff 15%, rgba(255, 255, 255, 0));
}

.sm-cats__fade--end {
  right: 0;
  background: linear-gradient(to left, #fff 15%, rgba(255, 255, 255, 0));
}

/* --- arrows ----------------------------------------------------------------
   `display` must NOT appear in a rule that also matches :hover. It previously
   did, so entering the arrow set display:none, which moved the pointer out,
   which set it back to grid — a flicker loop. Visibility is driven purely by
   opacity; display is set once, in the media query. */

.sm-cats__arrow,
.sm-cats__arrow:hover,
.sm-cats__arrow:focus,
.sm-cats__arrow:active {
  position: absolute;
  top: calc(50% - 0.75rem);
  z-index: 3;
  place-items: center;
  width: 2rem;
  height: 2rem;
  transform: translateY(-50%);
  border: 1px solid var(--sm-line) !important;
  border-radius: var(--r-full) !important;
  background: #fff !important;
  background-image: none !important;
  padding: 0 !important;
  margin: 0 !important;
  color: var(--sm-ink-soft);
  box-shadow: 0 4px 12px -4px rgba(4, 20, 55, 0.25) !important;
  cursor: pointer;
  opacity: 0;
  transition: opacity 200ms ease !important;
}

.sm-cats__arrow--prev { left: -0.5rem; }
.sm-cats__arrow--next { right: -0.5rem; }

/* Pointer devices only — touch users just swipe. */
@media (hover: hover) and (min-width: 768px) {
  .sm-cats__arrow { display: grid; }
  .sm-cats__viewport.can-scroll-start .sm-cats__arrow--prev,
  .sm-cats__viewport.can-scroll-end .sm-cats__arrow--next { opacity: 1; }
}

@media not all and (hover: hover) {
  .sm-cats__arrow { display: none; }
}

.sm-cats__arrow:focus-visible { outline: 2px solid var(--sm-blue-600); outline-offset: 2px; }


/* --- showcase shell (plugin build) ------------------------------------------
   Self-contained: this is the widget's own wrapper, not a class on a section.
   Content is capped and centred like every other block on the page, with the
   shell edge sitting one gutter outside the content box so its cards line up
   with the hero and the product rows above and below.
   ========================================================================== */
.sm-showcase-shell {
  --sm-showcase-pad: var(--sm-gutter);
  --sm-panel-w: 21rem;
  width: calc(100% - 2 * var(--sm-gutter));
  max-width: var(--sm-container);
  margin-inline: auto;
  margin-block: 2.375rem;
  padding: var(--sm-showcase-pad);
  /* Concentric by construction: outer radius = panel radius + the inset. */
  border-radius: calc(var(--r-xl) + var(--sm-showcase-pad));
  background: #eef1f6;
  box-sizing: border-box;
}

/* On the grey, a white panel separates from its background instead of
   dissolving into it — same fade, white instead of grey. */
.sm-showcase-shell .sm-promo { --sm-promo-rgb: 255 255 255; }
.sm-showcase-shell .sm-promo:hover { --sm-promo-rgb: 250 251 253; }

/* The showcase's product cards come from the theme's own template, so they
   arrive as a WooCommerce <ul class="products"> with the theme's column
   widths. The grid below governs the layout instead. */
.sm-show__grid.products { margin: 0 !important; padding: 0 !important; }
.sm-show__grid.products::before,
.sm-show__grid.products::after { content: none !important; }
.sm-show__grid.products > li {
  width: auto !important;
  margin: 0 !important;
  float: none !important;
  clear: none !important;
}

/* --- showcase cards: the artwork IS the card --------------------------------
   Two theme behaviours are undone here, and only inside the showcase — the
   same card elsewhere on the site keeps both.

   1. `.inner` carries 15px of side padding, which insets the photo from the
      card edge. In this row the photo is the card — the white block the eye
      reads as a tile is the product shot's own backdrop — so it must run edge
      to edge or the tile reads as a small picture floating on a white slab.

   2. The theme equalises loop rows by forcing a min-height on the thumbnail
      link (274px against a 207px square photo here). That leaves a band of
      dead space under every image and breaks the square the grid is built on.
      The photo defines the height instead. */
.sm-show__grid .inner { padding: 0 !important; }

.sm-show__grid .product-thumbnail > .woocommerce_loop_product_link {
  min-height: 0 !important;
  display: block !important;
}

.sm-show__grid .product-thumbnail img {
  display: block !important;
  width: 100% !important;
  height: auto !important;
}

/* --- hover: keep the caption on the shell -----------------------------------
   The theme paints `.inner` white on hover and lifts the card to z-index 5.
   Everywhere else on the site the page behind it is already white, so that
   does nothing visible. Over the grey shell it is the whole card turning into
   a white slab — the caption's background flips from #eef1f6 to #fff and the
   block overhangs its neighbours, which is what read as the card "expanding"
   past its artwork.

   Only the fill is undone. The z-index is left alone: the artwork scales to
   1.1 on hover and is clipped by the thumbnail's own overflow, so the lift
   costs nothing now that the card behind it stays transparent. */
.sm-show__grid > li:hover > .inner,
.sm-show__grid > li:focus-within > .inner {
  background: transparent !important;
}

/* --- caption type -----------------------------------------------------------
   These cards come from `wc_get_template_part('content','product')`, so the
   list they land in carries WooCommerce's own `products` class — which the
   mirror's markup does not. That class is enough for the theme's loop rules to
   claim the title and the price: title 14px in link blue, price 20px/500 in
   ink, the scale the Best Sellers row uses.

   The showcase is the editorial block on the page and reads the other way
   round — the name is the headline and the price is a detail under it. Values
   are the mirror's own computed figures, restated here because the selector
   that produced them there no longer wins. The two colours are the theme's own
   body and muted inks, which is what the mirror was resolving to — not
   tokens.css, which has no equivalent pair. */
.sm-show__grid .woocommerce-loop-product__title,
.sm-show__grid .woocommerce-loop-product__title a {
  font-size: 1.375rem !important;
  font-weight: 600 !important;
  line-height: 1.3 !important;
  color: #333e48 !important;
}

/* The theme clips this heading to two lines — `height: 44px`, `overflow:
   hidden` and `-webkit-line-clamp: 2`, all measured against its own 14px type.
   At 22px two lines need 57px, so titles lost their descenders and the longer
   ones lost a word to an ellipsis.

   All three have to go, and the clamp is the one that actually binds: Chrome
   now honours -webkit-line-clamp on a plain block, so this heading stayed two
   lines tall even once the height was released, and the third line spilled
   over the price. Releasing height alone looks fixed on a two-line card and is
   still broken on a three-line one — which is exactly how it read here before
   the clamp was unset.

   That leaves the price sitting lower on a card whose name wraps to three
   lines. It is what the mirror does, and it is the right call for this row:
   four cards, names read as headlines, and a ragged baseline is a fair price
   for not truncating a product's name. */
.sm-show__grid .woocommerce-loop-product__title {
  height: auto !important;
  max-height: none !important;
  overflow: visible !important;
  -webkit-line-clamp: unset !important;
  line-clamp: unset !important;
}

.sm-show__grid .price,
.sm-show__grid .price .woocommerce-Price-amount {
  font-size: 0.875rem !important;
  font-weight: 400 !important;
  color: #73787d !important;
}

/* --- Best Sellers row (plugin build) ------------------------------------
   Retargeted from the mirror's .sm-inset / .sm-bs-model block by
   plugin/build.py — see bestsellers_head() there for what changed and why.
   ====================================================================== */
/* --- section separators: full bleed -----------------------------------------
   The hairline under a section heading is drawn as a border on the heading
   widget, so it could only ever be as wide as the content container. Redrawn as
   a viewport-wide pseudo-element in the same place: the widget keeps its box
   and the rule stops being boxed with it.

   100vw counts the scrollbar's width where the document does not, so the rule
   overhangs the page by a few pixels on each side. `clip` trims that without
   making the body a scroll container the way `hidden` would — no effect on
   anchor jumps or position: sticky. */
html,
body { overflow-x: clip; }

.elementor-top-section:has(.tf-products .owl-carousel) .elementor-widget-heading,
.elementor-top-section:has(.tf-products .swiper-container) .elementor-widget-heading {
  position: relative;
  border-bottom: 0 !important;
}

.elementor-top-section:has(.tf-products .owl-carousel) .elementor-widget-heading::after,
.elementor-top-section:has(.tf-products .swiper-container) .elementor-widget-heading::after {
  content: "";
  position: absolute;
  bottom: 0;
  left: 50%;
  width: 100vw;
  transform: translateX(-50%);
  border-bottom: 1px solid #ebebeb;
}



/* Elementor also sets per-breakpoint side spacing on this row's own widgets —
   a 15/10 margin on the heading and 8px inside the products widget, both phone
   only, neither present on the row above. Cleared so the gutter below is the
   row's single inset at every width. */
.elementor-top-section:has(.tf-products .swiper-container) .elementor-widget {
  margin-left: 0 !important;
  margin-right: 0 !important;
}

.elementor-top-section:has(.tf-products .swiper-container) .elementor-widget > .elementor-widget-container {
  padding-left: 0 !important;
  padding-right: 0 !important;
}

/* The heading takes the gutter directly, as it does in the row above. */
.elementor-top-section:has(.tf-products .swiper-container) .elementor-widget-heading {
  padding-left: var(--sm-gutter) !important;
  padding-right: var(--sm-gutter) !important;
}

/* The row of cards takes it one level in, on the slide — which is how New
   Arrivals is built and why its track runs a gutter wider than its artwork on
   each side. With the same arrangement here, the two rows' artwork columns land
   on the same lines and the gap between two artworks resolves to the same 45
   (15 of slide padding either side of the carousel's own 15). */
.elementor-top-section:has(.tf-products .swiper-container) .swiper-slide {
  padding-left: var(--sm-gutter) !important;
  padding-right: var(--sm-gutter) !important;
}

.elementor-top-section:has(.tf-products .swiper-container) .tf-products .image {
  /* New Arrivals: no side inset, no vertical padding, 19px under the artwork. */
  margin: 0 0 19px !important;
  padding: 0 !important;
  /* The 1px #ebebeb hairline and 3px corner are this row's alone — every other
     card on the page lets the artwork be the card. */
  border: 0 !important;
  border-radius: var(--r-xs) !important;
}

/* The caption lines carry a 15px left margin here and none in the row above,
   which is what pushed the text off the artwork's left edge. */
.elementor-top-section:has(.tf-products .swiper-container) .tf-products .content > * {
  margin-left: 0 !important;
  margin-right: 0 !important;
}

/* Title to price, the one step New Arrivals sets inside the caption. */
.elementor-top-section:has(.tf-products .swiper-container) .tf-products .content .name { margin-bottom: 10px !important; }

/* --- the row's arrows -------------------------------------------------------
   They belong to the swiper, which starts below the heading, so the theme
   reaches them back up into the heading row with a hard `top: 45px` against a
   100px top pad. At 44px tall that overhangs the hairline under the heading —
   at narrow widths, where the heading row is shortest, they sit right on top of
   it. The two offsets the theme's padding creates are constant at every width:
   the heading's centre line is 32px below the container's top edge and the rule
   54px below it. So the arrows are centred on the first and clear the second. */
.elementor-top-section:has(.tf-products .swiper-container) .swiper-button-prev,
.elementor-top-section:has(.tf-products .swiper-container) .swiper-button-next {
  top: 32px !important;
  width: 29px !important;
  height: 29px !important;
  margin-top: -14px !important;
}

/* Right edge on the content line, where New Arrivals' own arrows sit. */
.elementor-top-section:has(.tf-products .swiper-container) .swiper-button-next {
  left: auto !important;
  right: var(--sm-gutter) !important;
}

.elementor-top-section:has(.tf-products .swiper-container) .swiper-button-prev {
  left: auto !important;
  right: calc(var(--sm-gutter) + 30px) !important;
}

/* Same story vertically: the row's own heading margin is 20px, and the 18px the
   media box used to contribute above the artwork (8 margin + 10 padding) is
   gone with the rule above — 46 puts the artwork on New Arrivals' 58px line. */
.elementor-top-section:has(.tf-products .swiper-container) .elementor-widget-heading { margin-bottom: 46px !important; }

/* The theme rounds this card's artwork by 3px, which is off the 4px step every
   other corner on the page sits on. One notch onto the scale. */
.elementor-top-section:has(.tf-products .swiper-container) .tf-products .item img {
  border-radius: var(--r-xs) !important;
}


/* --- slides -----------------------------------------------------------------
   Panel left, that category's own cards right. Every slide occupies the same
   grid cell so the shell keeps one height and the crossfade has something to
   fade between. */

.sm-show__slides { display: grid; }

.sm-show__slide {
  grid-area: 1 / 1;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sm-showcase-pad);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 400ms ease, visibility 0s linear 400ms;
}

.sm-show__slide.is-active {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition-delay: 0s;
}

@media (min-width: 768px) {
  /* The panel column is sized so its 1:1.375 portrait sits comfortably beside
     three cards; the rest of the row goes to the grid. */
  .sm-show__slide {
    grid-template-columns: minmax(0, var(--sm-panel-w)) minmax(0, 1fr);
  }
}

@media (prefers-reduced-motion: reduce) {
  .sm-show__slide { transition: none; }
}

/* --- the card grid ----------------------------------------------------------
   The archive's tiles carry no padding of their own once they are out of the
   theme's product list, so the artwork is the card edge. That makes the rhythm
   simple: one inset everywhere — panel to first card, card to card, and last
   card to the shell's own padding. */

.sm-show__grid {
  /* !important: the theme styles product lists as flex rows with their own
     widths and floats, and a single `li.product` rule is enough to pull the
     cards back out of the grid. */
  display: grid !important;
  grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
  gap: var(--sm-showcase-pad) !important;
  margin: 0 !important;
  padding: 0 !important;
  list-style: none !important;
}

@media (min-width: 992px) {
  .sm-show__grid { grid-template-columns: repeat(4, minmax(0, 1fr)) !important; }
}

.sm-show__grid > li {
  width: auto !important;
  max-width: none !important;
  min-width: 0 !important;
  margin: 0 !important;
  padding: 0 !important;
  float: none !important;
  list-style: none !important;
}

/* The artwork is the card here — the tile itself is transparent, so the white
   block the eye reads as a card is the photo's own backdrop. Rounding the image
   is what gives the card its corner, and the caption needs a step under it or
   the title sits flush against the picture. The corner is the category panel's
   own --r-xl, since the two sit side by side in the same row. */
.sm-show__grid .product-thumbnail,
.sm-show__grid .product-thumbnail img {
  border-radius: var(--r-xl) !important;
}

.sm-show__grid .left-content { margin-bottom: 0.75rem !important; }

.sm-show__grid::before,
.sm-show__grid::after,
.sm-show__grid > li::before,
.sm-show__grid > li::after { content: none !important; }

/* --- story bars -------------------------------------------------------------
   Inactive steps are dots; the active one stretches into a bar and fills left
   to right over the slide's duration. Same progress model as the
   hero, drawn small enough to read as an indicator rather than a control. */

/* Phones: in flow under the slide, left-aligned. The panel is only a couple of
   hundred pixels tall there and its artwork already occupies the bottom-right
   corner, so there is nowhere on it for the bars to go. */
.sm-show__bars {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 0.375rem;
  margin-top: 1.25rem;
  /* + the shell's own 15px padding = the 1.25rem above it. */
  margin-bottom: 0.3125rem;
}

/* From the width the panel becomes a tall portrait beside the grid, the bars
   move onto it — bottom-right corner, inset by the shell's own padding so the
   margin they keep off the panel edge is the one the shell uses everywhere.

   Anchored to the shell rather than to a slide: every slide's panel occupies
   the same grid cell, so one fixed position sits over all five, and the bars
   stay a single shared control rather than being duplicated per slide. The
   panel's own bottom is the slide block's bottom — it is the taller column and
   sets the row's height — hence the offset from the shell's bottom edge. */
@media (min-width: 768px) {
  /* Two containing blocks, because the block is built twice. In the mirror the
     shell is a class stamped onto an Elementor section, so the context is that
     section's container. In the plugin the widget renders its own wrapper and
     no Elementor section is involved — `.sm-show` is then the bars' own parent
     and the nearest box that spans the slide. Naming only the first left the
     plugin build with no positioned ancestor at all, which is what dropped the
     bars out of the panel and under the shell on the live site. */
  .sm-showcase > .elementor-container,
  .sm-show { position: relative; }

  .sm-show__bars {
    position: absolute;
    /* Zero, not the shell's padding: an absolutely positioned child resolves
       against its ancestor's padding box, which is already the panel's own top
       -left corner. The inset off the panel edge is the padding below. */
    left: 0;
    bottom: 0;
    z-index: 2;
    width: var(--sm-panel-w);
    padding: var(--sm-showcase-pad);
    margin: 0;
    justify-content: flex-end;
  }
}

.sm-show__bar,
.sm-show__bar:hover,
.sm-show__bar:focus,
.sm-show__bar:active {
  position: relative;
  display: block;
  width: 0.5rem;
  height: 0.5rem;
  min-width: 0;
  padding: 0 !important;
  margin: 0 !important;
  border: 0 !important;
  border-radius: var(--r-xs) !important;
  background: rgba(22, 35, 61, 0.16) !important;
  background-image: none !important;
  box-shadow: none !important;
  overflow: hidden;
  cursor: pointer;
  /* width animates, so a dot grows into the bar as it takes over */
  transition: width 300ms ease, background-color 300ms ease !important;
  -webkit-appearance: none;
  appearance: none;
}

.sm-show__bar::before,
.sm-show__bar::after { content: none !important; }

.sm-show__bar:hover { background: rgba(22, 35, 61, 0.28) !important; }
.sm-show__bar.is-active { width: 1.25rem; }

.sm-show__bar:focus-visible {
  outline: 2px solid var(--sm-blue-600);
  outline-offset: 3px;
}

.sm-show__fill {
  display: block;
  width: 100%;
  height: 100%;
  transform: scaleX(0);
  transform-origin: left;
  border-radius: var(--r-xs);
  background: var(--sm-blue-600);
}

@keyframes sm-show-progress {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

@media (prefers-reduced-motion: reduce) {
  .sm-show__bar { transition: none !important; }
  .sm-show__fill { animation: none !important; }
  .sm-show__bar.is-active .sm-show__fill { transform: scaleX(1); }
}
