/**
 * product-store.css — Apple Store "Accessories" layout, for products.php.
 *
 * Loaded ONLY by products.php via $extra_css, and every rule is scoped to
 * `body.pstore-page`. Two jobs, same as apple.css's `body.ap` scope:
 *   1. it cannot leak to the other 20+ pages, and
 *   2. `body.pstore-page section` (0,2,1) deterministically beats main.css's
 *      bare `section, .section` (0,1,0) regardless of <link> order.
 *
 * This page does NOT set $apple, so apple.css is never loaded. The "On this
 * page" rail is section_nav(), whose styles live in custom.css and therefore
 * need nothing here.
 *
 * Do NOT wrap this in @layer — main.css is unlayered, and unlayered CSS beats
 * layered CSS regardless of source order. The scope class is what wins.
 *
 * Design targets, measured from apple.com/in/shop/accessories/all:
 *   type      48 / 32 / 24 / 21 / 19 / 17 / 14 / 12
 *   tracking  NEGATIVE on display sizes, weight 600 semibold — never 700
 *   grounds   #fff, #f5f5f7, #000 only; all other colour comes from imagery
 *   radii     18px large tiles, 12px nested media, 28px filter pills, 999px chips
 *   gutter    12px between grid cells
 *
 * Page width is the site's own .container (1200px, custom.css:166), not a
 * bespoke wrapper — the house convention, and it keeps the fixed-position
 * section rail clear of the content edge.
 */

/* ==========================================================================
   1. Tokens
   ========================================================================== */

body.pstore-page {
  /* Grounds & ink */
  --ps-canvas:      #ffffff;
  --ps-tile:        #f5f5f7;
  --ps-ink:         #1d1d1f;
  --ps-ink-2:       #6e6e73;
  --ps-ink-3:       #86868b;
  --ps-hair:        rgba(0, 0, 0, .12);

  /* Filter pills — one capsule track holding transparent segments, Apple's
     segmented control. The track is white because the Top picks band it sits
     on is grey; on Apple's white page the relationship is inverted.
     The active segment's ground is --ps-grad-brand (see the thumb, §6), so
     there is no flat --ps-pill-on colour any more. Ink is sourced from the
     gradient's own token and is white in BOTH themes — see the note in the
     dark block. */
  --ps-pill-track:  #ffffff;
  --ps-pill-bg-h:   rgb(0 0 0 / .05);
  --ps-pill-on-ink: var(--ps-on-brand);

  /* Carousel control cluster: light circular arrows either side of a slightly
     deeper dots capsule. */
  --ps-nav-btn:     #f0f0f2;
  --ps-nav-btn-h:   #e6e6e9;
  --ps-nav-track:   #e3e3e6;
  --ps-nav-ink:     #4c4c50;
  --ps-dot:         #b8b8bd;
  --ps-dot-on:      #1d1d1f;
  --ps-media-well:  #f7f7f9;

  /* Theme gradients, both lifted from existing site components so they flip
     with the palette instead of hard-coding Apple's black/grey.
     Brand = the .cta-band gradient (custom.css:574).
     Tint  = the .ph placeholder wash (custom.css:766). */
  --ps-grad-brand: linear-gradient(120deg, var(--accent-fill) 0%, var(--accent-hover) 100%);
  --ps-grad-tint:  linear-gradient(135deg, var(--mist) 0%, var(--accent-soft) 100%);

  /* Ink for the brand gradient. Deliberately NOT --ps-on-dark-2 (#a1a1a6):
     a mid-grey on brand red falls under 3:1 at the 12px eyebrow size. */
  --ps-on-brand:   #ffffff;
  --ps-on-brand-2: rgba(255, 255, 255, .88);

  /* Accent stays VATECH red, not Apple blue */
  --ps-link:        var(--accent);
  --ps-link-hover:  var(--accent-hover);

  /* Type. Same reasoning as apple.css: the Vatech face ships only 300/400 but
     is declared 400–800 to suppress faux-bold, so a 48px "semibold" headline
     set in Vatech would render thin. System display stack for display sizes. */
  --ps-font-display: -apple-system, BlinkMacSystemFont, "SF Pro Display",
                     "Segoe UI Variable Display", "Segoe UI", Roboto,
                     "Helvetica Neue", Arial, sans-serif;
  --ps-font-text:    -apple-system, BlinkMacSystemFont, "SF Pro Text",
                     "Segoe UI Variable Text", "Segoe UI", Roboto,
                     "Helvetica Neue", Arial, sans-serif;

  --ps-t-mast:  clamp(2.5rem, 5.4vw, 3rem);          /* 40 → 48  masthead h1   */
  --ps-t-head:  clamp(1.75rem, 3.2vw, 2rem);         /* 28 → 32  section heads */
  --ps-t-title: clamp(1.3125rem, 2.2vw, 1.5rem);     /* 21 → 24  why-card head */
  --ps-t-sub:   1.3125rem;                           /* 21       tile name     */
  --ps-t-pill:  1rem;                                /* 16       filter pills  */
  --ps-t-body:  1.0625rem;                           /* 17       body / links  */
  --ps-t-small: .875rem;                             /* 14       spec chips    */
  --ps-t-cap:   .75rem;                              /* 12       labels, legal */

  --ps-ls-mast:  -.015em;
  --ps-ls-head:  -.008em;
  --ps-ls-title: -.003em;
  --ps-ls-body:  -.022em;
  --ps-ls-cap:   -.01em;

  /* Rhythm & radii */
  --ps-gutter:   12px;
  /* Matches Bootstrap's .container padding (--bs-gutter-x 1.5rem × .5), so the
     full-bleed rail's negative margin lines up with the container edge. */
  --ps-pad-x:    12px;
  /* Trimmed from clamp(48px,6vw,88px): at 88px top+bottom the bands read as
     drifting apart rather than as a rhythm, and two adjacent sections stacked
     176px of dead space between them. */
  --ps-sec-y:    clamp(30px, 3.4vw, 52px);
  --ps-r-card:   18px;
  --ps-r-med:    12px;
  --ps-r-pill:   999px;
  --ps-pill-h:   42px;
  --ps-pill-r:   999px;
  --ps-chip-w:   clamp(96px, 11vw, 120px);
  --ps-chip-img: clamp(64px, 7.5vw, 80px);

  /* Bottom fade for every card image on this page. The cut-outs are framed hard
     against the bottom edge — the A9's column fills 27% of its last row, Green X
     and PaX-i about 10% — so un-faded they read as a chopped photo rather than a
     product floating on the card.
     A mask, not an ::after veil: this makes the IMAGE go transparent, so the
     ground behind shows through and the white well, the dark-theme well and the
     featured tile's red gradient all come out right from one declaration. A veil
     would need a dark override, a featured-tile exception, position:relative on
     .ps-tile-media, and pointer-events:none to stay clear of .ps-tile-hit. */
  --ps-card-fade: linear-gradient(to bottom, #000 75%, transparent 100%);

  /* Sticky geometry. --ps-hdr-h is overwritten at runtime by product-store.js
     with the real header height (it shrinks on body.scrolled and grows when the
     mobile nav opens). 64px is its measured resting height, and is what no-JS
     gets. Only the site header is sticky on this page. */
  --ps-hdr-h: 64px;
}

/* Dark theme aliases the existing custom.css tokens rather than inventing a
   second palette — one place to change it, and the header toggle keeps behaving
   exactly as it does on every other page. */
[data-bs-theme="dark"] body.pstore-page {
  --ps-canvas:      var(--bg);
  --ps-tile:        var(--mist);
  --ps-ink:         var(--ink);
  --ps-ink-2:       var(--ink-soft);
  --ps-ink-3:       #7e9a8e;
  --ps-hair:        var(--line);

  --ps-pill-track:  var(--surface);
  --ps-pill-bg-h:   rgb(255 255 255 / .07);
  /* No --ps-pill-on-ink override here on purpose. It used to be var(--bg)
     (near-black), which was right against the old light thumb; now that the
     thumb is the brand gradient (dark green in this theme) it would paint the
     active label black on dark green. The light block's white is correct in
     both themes. */

  --ps-nav-btn:     rgb(255 255 255 / .08);
  --ps-nav-btn-h:   rgb(255 255 255 / .14);
  --ps-nav-track:   rgb(255 255 255 / .12);
  --ps-nav-ink:     var(--ink);
  --ps-dot:         rgb(255 255 255 / .32);
  --ps-dot-on:      var(--ink);
  --ps-media-well:  rgb(255 255 255 / .04);

  /* Carried from custom.css:581. In dark, --accent-hover is #5bf0be (bright
     mint) — ending the gradient there would leave white text unreadable. */
  --ps-grad-brand: linear-gradient(120deg, var(--accent-fill) 0%, var(--deep) 100%);
  --ps-on-brand-2: rgba(255, 255, 255, .82);
}

/* ==========================================================================
   2. Reset — neutralise the Medilab rules this layout owns itself
   ========================================================================== */

/* Only the page canvas goes on <body>. Everything typographic is scoped to
   main.main below, because footer.php emits the newsletter band and the site
   footer OUTSIDE <main> — and a bare `body.pstore-page h3` was repainting the
   newsletter's white heading in --ps-ink (near-black on navy: invisible) and
   swapping the brand Vatech face for the system stack across the whole footer. */
body.pstore-page { background: var(--ps-canvas); }

body.pstore-page main.main {
  color: var(--ps-ink);
  font-family: var(--ps-font-text);
  letter-spacing: var(--ps-ls-body);
}

/* Neutralise the section background through the variable rather than with
   `background: none`: a `body.pstore-page section` rule is (0,2,1) and would
   otherwise outrank the components' own (0,1,0) grounds and erase every tile.

   `overflow: visible` is load-bearing — main.css's `overflow: clip` establishes
   a clip context that would shear the full-bleed chip and pill rails off at the
   container edge, and clips fixed/sticky descendants.

   `:not(.newsletter-band)` is also load-bearing: footer.php emits the
   newsletter as a <section> OUTSIDE <main>, so without the exclusion this reset
   flattens its 34px padding to 0 and makes this page's newsletter band shorter
   than every other page's. */
body.pstore-page section:not(.newsletter-band),
body.pstore-page .section {
  --background-color: transparent;
  overflow: visible;
  padding: 0;
  scroll-margin-top: calc(var(--ps-hdr-h) + 16px);
}

/* Declared after the reset so it wins at equal (0,2,2) specificity. */
body.pstore-page section.ps-sec { padding: var(--ps-sec-y) 0; }
body.pstore-page section.ps-sec.is-tight { padding-top: clamp(28px, 3vw, 44px); }
/* The chip rail carries its own breathing room via .ps-rail's padding-block —
   the section padding on top of that was leaving it marooned. */
body.pstore-page section.ps-sec.ps-catbar { padding: 0; }
body.pstore-page section.ps-sec.is-tint { background: var(--ps-tile); }
body.pstore-page section.ps-sec.is-hairline { border-top: 1px solid var(--ps-hair); }

/* Non-section anchor targets need the same clearance under the sticky header.
   Note custom.css:1197 sets `#enquire { scroll-margin-top: 90px }` globally —
   an ID selector, so it wins over this and is close enough to be correct. */
body.pstore-page [id] { scroll-margin-top: calc(var(--ps-hdr-h) + 16px); }

/* main.main-scoped for the same reason as the block above — these would
   otherwise flatten the footer's list spacing and heading colours. */
body.pstore-page main.main h1, body.pstore-page main.main h2,
body.pstore-page main.main h3, body.pstore-page main.main h4 {
  font-family: var(--ps-font-display);
  font-weight: 600;
  color: var(--ps-ink);
  margin: 0;
}

body.pstore-page main.main p  { margin: 0; }
body.pstore-page main.main ul { list-style: none; margin: 0; padding: 0; }

/* ==========================================================================
   3. Shared type
   ========================================================================== */

body.pstore-page .ps-sechead { margin-bottom: clamp(20px, 3vw, 32px); }
body.pstore-page .ps-sechead h2 {
  font-size: var(--ps-t-head);
  line-height: 1.1;
  letter-spacing: var(--ps-ls-head);
}
body.pstore-page .ps-sechead p {
  margin-top: 8px;
  font-size: var(--ps-t-body);
  line-height: 1.47;
  color: var(--ps-ink-2);
}

/* Apple's CTA is a text link with a chevron — never a button. */
body.pstore-page .ps-link {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: var(--ps-t-body);
  line-height: 1.47;
  letter-spacing: var(--ps-ls-body);
  color: var(--ps-link);
  text-decoration: none;
}
body.pstore-page .ps-link:hover { color: var(--ps-link-hover); text-decoration: underline; }
body.pstore-page .ps-link > i { font-size: .78em; transition: transform .22s ease; }
body.pstore-page .ps-link:hover > i { transform: translateX(3px); }

/* ==========================================================================
   4. Masthead — title only, as Apple sets it
   ========================================================================== */

body.pstore-page .ps-mast { padding-bottom: clamp(24px, 3vw, 36px) !important; }

body.pstore-page .ps-mast-h {
  font-size: var(--ps-t-mast);
  line-height: 1.05;
  letter-spacing: var(--ps-ls-mast);
}

/* ==========================================================================
   5. Category chip rail
   ========================================================================== */

body.pstore-page .ps-rail {
  display: flex;
  gap: clamp(8px, 1.5vw, 20px);
  overflow-x: auto;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
  -ms-overflow-style: none;
  padding-block: 4px;
}
body.pstore-page .ps-rail::-webkit-scrollbar { display: none; }

body.pstore-page .ps-chip-item {
  flex: 0 0 var(--ps-chip-w);
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 8px 4px;
  border-radius: var(--ps-r-med);
  text-decoration: none;      /* transparent chips — no pill ground, per Apple */
  color: inherit;
  transition: transform .22s cubic-bezier(.22, 1, .36, 1);
}
body.pstore-page .ps-chip-item:hover { transform: translateY(-2px); }

body.pstore-page .ps-chip-img {
  width: var(--ps-chip-img);
  height: var(--ps-chip-img);
  object-fit: contain;
  -webkit-mask-image: var(--ps-card-fade);
          mask-image: var(--ps-card-fade);
}

/* Fallback for a category whose representative product ships no render
   (cadcam → perfit-zr). A ph() slot prints its own pixel dimensions and is
   unusable at 72px, so this is a plain glyph in the same box. */
body.pstore-page .ps-chip-glyph {
  width: var(--ps-chip-img);
  height: var(--ps-chip-img);
  display: grid;
  place-items: center;
  border-radius: var(--ps-r-med);
  background: var(--ps-tile);
  color: var(--ps-ink-2);
  font-size: calc(var(--ps-chip-img) * .42);
}

body.pstore-page .ps-chip-label {
  font: 600 var(--ps-t-cap) / 1.33 var(--ps-font-text);
  letter-spacing: var(--ps-ls-cap);
  color: var(--ps-ink);
  text-align: center;
}

/* Full bleed on mobile so the last chip runs off the edge and signals that the
   rail scrolls. Only works because of the `overflow: visible` reset above. */
@media (max-width: 733.98px) {
  body.pstore-page .ps-rail.is-bleed {
    margin-inline: calc(var(--ps-pad-x) * -1);
    padding-inline: var(--ps-pad-x);
  }
}

/* ==========================================================================
   5b. Promo carousel — Swiper, restyled off its stock blue chrome
   ========================================================================== */

body.pstore-page .ps-promo { overflow: hidden; }

body.pstore-page .ps-promo-card {
  aspect-ratio: 1.85 / 1;
  border-radius: var(--ps-r-card);
  background: var(--ps-tile);
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
  align-items: center;
  overflow: hidden;
}

body.pstore-page .ps-promo-copy {
  padding: clamp(20px, 3vw, 48px);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
}

body.pstore-page .ps-promo-eyebrow {
  font: 400 var(--ps-t-cap) / 1.33 var(--ps-font-text);
  letter-spacing: var(--ps-ls-cap);
  color: var(--ps-ink-2);
}

body.pstore-page .ps-promo-h {
  font-size: var(--ps-t-head);
  line-height: 1.1;
  letter-spacing: var(--ps-ls-head);
}

body.pstore-page .ps-promo-sub {
  font-size: var(--ps-t-body);
  line-height: 1.47;
  letter-spacing: var(--ps-ls-body);
  color: var(--ps-ink-2);
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

body.pstore-page .ps-promo-media { height: 100%; min-height: 0; }
body.pstore-page .ps-promo-media img {
  width: 100%;
  height: 100%;
  /* contain, never cover: these are product renders, and a cover crop slices
     the device. object-position bleeds it to the card's right edge. */
  object-fit: contain;
  object-position: right center;
  -webkit-mask-image: var(--ps-card-fade);
          mask-image: var(--ps-card-fade);
}

/* One centred cluster below the track: circular arrow, dots capsule, circular
   arrow. Static flow rather than absolutely positioned over the card, so the
   artwork is never covered. */
body.pstore-page .ps-promo-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-top: 22px;
}

body.pstore-page .ps-promo-prev,
body.pstore-page .ps-promo-next {
  position: static;
  width: 36px;
  height: 36px;
  flex: 0 0 auto;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--ps-nav-btn);
  color: var(--ps-nav-ink);
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: background .18s linear, opacity .18s linear;
}
body.pstore-page .ps-promo-prev:hover,
body.pstore-page .ps-promo-next:hover { background: var(--ps-nav-btn-h); }
body.pstore-page .ps-promo-prev > i,
body.pstore-page .ps-promo-next > i { font-size: 14px; line-height: 1; }
body.pstore-page .swiper-button-disabled { opacity: .4; pointer-events: none; }

body.pstore-page .ps-promo-dots {
  position: static;
  width: auto;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 11px 14px;
  border-radius: var(--ps-r-pill);
  background: var(--ps-nav-track);
}
body.pstore-page .ps-promo-dots .swiper-pagination-bullet {
  width: 7px;
  height: 7px;
  margin: 0 !important;
  border-radius: 50%;
  background: var(--ps-dot);
  opacity: 1;
  transition: background .2s linear;
}
body.pstore-page .ps-promo-dots .swiper-pagination-bullet-active { background: var(--ps-dot-on); }

@media (max-width: 733.98px) {
  body.pstore-page .ps-promo-card {
    aspect-ratio: auto;
    grid-template-columns: 1fr;
  }
  body.pstore-page .ps-promo-media { aspect-ratio: 4 / 3; }
  body.pstore-page .ps-promo-media img { object-position: center; }
}

/* ==========================================================================
   6. Range grid — filter pills + product mosaic
   ========================================================================== */

/* One capsule track holding transparent segments — Apple's segmented control,
   not a row of separately-backed pills. Sized so all seven fit the 1176px
   container on one line; the overflow-x is a safety net for narrow widths and
   for any future category, not the normal state. */
body.pstore-page .ps-filters {
  position: relative;          /* the sliding thumb is absolute against this */
  display: inline-flex;
  max-width: 100%;
  gap: 2px;
  padding: 5px;
  border-radius: var(--ps-r-pill);
  background: var(--ps-pill-track);
  overflow-x: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
  margin-bottom: clamp(20px, 3vw, 32px);
}
body.pstore-page .ps-filters::-webkit-scrollbar { display: none; }

/* The moving brand capsule. The pills themselves stay transparent and this
   slides between them, so the selection glides instead of blinking from one
   segment to the next. product-store.js measures and positions it; the
   transition only switches on once .is-ready lands, or it would animate in
   from x=0 on first paint.
   Ground is --ps-grad-brand, the same gradient as the featured tile — legal in
   the shorthand, which resolves it to background-image; the capsule needs no
   background-colour of its own. */
body.pstore-page .ps-pill-thumb {
  position: absolute;
  top: 5px;
  left: 0;
  height: var(--ps-pill-h);
  border-radius: var(--ps-r-pill);
  background: var(--ps-grad-brand);
  pointer-events: none;
  z-index: 0;
}
body.pstore-page .ps-filters.is-ready .ps-pill-thumb {
  transition: transform .38s cubic-bezier(.22, 1, .36, 1),
              width .38s cubic-bezier(.22, 1, .36, 1);
}

body.pstore-page .ps-pill {
  position: relative;
  z-index: 1;                  /* above the sliding thumb */
  flex: 0 0 auto;
  height: var(--ps-pill-h);
  padding-inline: 18px;
  border: 0;
  border-radius: var(--ps-pill-r);
  background: transparent;
  color: var(--ps-ink);
  font: 600 var(--ps-t-pill) / 1 var(--ps-font-text);
  letter-spacing: var(--ps-ls-body);
  white-space: nowrap;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  text-decoration: none;
  transition: color .28s linear;
}
/* Hover tint only on inactive segments — under the active one the thumb
   already supplies the ground. */
body.pstore-page .ps-pill:not(.is-active):hover { background: var(--ps-pill-bg-h); }
body.pstore-page .ps-pill.is-active,
body.pstore-page .ps-pill[aria-pressed="true"] {
  background: transparent;     /* the thumb is the ground now */
  color: var(--ps-pill-on-ink);
}
/* No-JS fallback: without the thumb the active segment needs its own ground. */
body.pstore-page .ps-filters:not(.is-ready) .ps-pill.is-active { background: var(--ps-grad-brand); }

body.pstore-page .ps-grid {
  display: grid;
  gap: var(--ps-gutter);
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
@media (min-width: 1024px) {
  body.pstore-page .ps-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (min-width: 1440px) {
  body.pstore-page .ps-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* Grey band, white cards — the inverse of the rest of the page, so the grid
   reads as one merchandising surface rather than as tiles floating on white. */
body.pstore-page section.ps-picks { background: var(--ps-tile); }

body.pstore-page .ps-tile {
  position: relative;
  display: flex;
  flex-direction: column;
  aspect-ratio: 1 / 1.24;
  padding: clamp(16px, 2vw, 24px);
  border-radius: var(--ps-r-card);
  background: var(--ps-canvas);
  overflow: hidden;
}

/* The pop, shared with the Why cards below. Timing and shadows are the site's
   own (.product-card, custom.css:459) so this page hovers like every other —
   and because --shadow-sm/--shadow-md already carry dark values, dark theme
   comes free instead of needing a hand-maintained second shadow.
   Property list is explicit rather than the site's bare `transition: .25s`:
   this page also animates transform on filter-swap, and a blanket `all` would
   drag the gradient repaint in with it. */
body.pstore-page .ps-tile,
body.pstore-page .ps-why-card { box-shadow: var(--shadow-sm); }

/* Scoped through the grid on purpose. aos.css's `[data-aos^='fade']` sets
   `transition-property: opacity, transform` and, at (0,2,0), was beating a
   plain `body.pstore-page .ps-tile` (0,2,1) — the shadow silently dropped out
   of the list and snapped instead of easing. Going through .ps-grid /
   .ps-why-grid takes this to (0,3,1) so the property list is ours.
   `opacity` stays in the list so AOS's own reveal still fades. */
body.pstore-page .ps-grid .ps-tile,
body.pstore-page .ps-why-grid .ps-why-card {
  transition: opacity .25s ease, transform .25s ease, box-shadow .25s ease;
}
/* Scoped through the grid for the same reason as the transition above, one rung
   higher. aos.css also ships
     html:not(.no-js) [data-aos^="fade"][data-aos^="fade"].aos-animate
       { transform: none }
   at (0,4,1) — the `.aos-animate` class is the fourth simple selector — and it
   was beating a plain `body.pstore-page .ps-tile:hover` (0,3,1). The shadow
   swapped on hover but the scale was silently flattened on all thirteen tiles.
   .ps-why-card never had the bug (its data-aos sits on .ps-why-grid, not on the
   card) but rides along so the two card types stay one rule.
   This lands at (0,4,1) too and wins on source order — product-store.css is the
   last sheet header.php emits. The .is-swapping guard below is (0,5,1) and so
   still outranks it, which is what keeps the filter animation clean. */
body.pstore-page .ps-grid .ps-tile:hover,
body.pstore-page .ps-why-grid .ps-why-card:hover {
  transform: scale(1.03) translateY(-4px);
  box-shadow: var(--shadow-md);
  z-index: 2;                  /* the grown card sits over its neighbours */
}
body.pstore-page .ps-tile.is-hidden { display: none; }

/* Filter swap: the surviving cards fade and rise back in rather than snapping.
   product-store.js adds .is-swapping, stamps a per-card --ps-d delay, then
   removes the class once the run finishes — if it stayed, the animation's
   `both` fill would pin transform and kill the hover scale above. */
@keyframes ps-card-in {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: none; }
}
body.pstore-page .ps-grid.is-swapping .ps-tile:not(.is-hidden) {
  animation: ps-card-in .42s cubic-bezier(.22, 1, .36, 1) both;
  animation-delay: var(--ps-d, 0ms);
}
body.pstore-page .ps-grid.is-swapping .ps-tile:hover { transform: none; }

/* No aspect-ratio on the featured tile. The normal tiles set the implicit row
   height; a span-2 item stretches to two rows plus the gutter on its own, and
   giving it a ratio as well would fight that and leave a gap under it. */
body.pstore-page .ps-tile.is-featured {
  grid-column: span 2;
  grid-row: span 2;
  aspect-ratio: auto;
  background: var(--ps-grad-brand);
  color: var(--ps-on-brand);
}
body.pstore-page .ps-tile.is-featured .ps-tile-name { color: var(--ps-on-brand); }
body.pstore-page .ps-tile.is-featured .ps-tile-cat,
body.pstore-page .ps-tile.is-featured .ps-tile-chips { color: var(--ps-on-brand-2); }
body.pstore-page .ps-tile.is-featured .ps-tile-media { min-height: 180px; }

/* A tinted well inside the white card. The cards now carry transparent cut-outs
   (product_card_shot()), and the machines are near-white plastic — against a
   white card the lighter ones (A9, Smart Plus, Green X 12/18) would lose their
   edges entirely. The well gives them a boundary, and it is also what the
   --ps-card-fade mask dissolves them into. */
body.pstore-page .ps-tile-media {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  place-items: center;
  margin-bottom: 14px;
  padding: 8px;
  border-radius: var(--ps-r-med);
  background: var(--ps-media-well);
  overflow: hidden;
}
/* width/height + object-fit rather than max-width/max-height: a percentage
   max-height on a grid item whose track height is indefinite does not resolve,
   so the image was rendering 207px tall inside a 186px box and being cropped. */
body.pstore-page .ps-tile-media img {
  width: 100%;
  height: 100%;
  min-width: 0;
  min-height: 0;
  object-fit: contain;
  -webkit-mask-image: var(--ps-card-fade);
          mask-image: var(--ps-card-fade);
}
/* The black tile supplies its own contrast; a grey well would band against it. */
body.pstore-page .ps-tile.is-featured .ps-tile-media { background: transparent; }

body.pstore-page .ps-tile-cat {
  font: 400 var(--ps-t-cap) / 1.33 var(--ps-font-text);
  letter-spacing: var(--ps-ls-cap);
  color: var(--ps-ink-2);
}

body.pstore-page .ps-tile-name {
  margin-top: 2px;
  font-size: var(--ps-t-sub);
  line-height: 1.19;
  letter-spacing: var(--ps-ls-title);
}
body.pstore-page .ps-tile.is-featured .ps-tile-name { font-size: var(--ps-t-head); }

body.pstore-page .ps-tile-chips {
  margin-top: 8px;
  font-size: var(--ps-t-small);
  line-height: 1.4;
  color: var(--ps-ink-2);
}
/* Interpunct separators as generated content, so no empty spans in the markup. */
body.pstore-page .ps-chip + .ps-chip::before { content: "\00a0\00b7\00a0"; }

/* Plain accent text, not a filled button: thirteen solid CTAs in one grid
   shouted louder than the products. */
body.pstore-page .ps-tile-price {
  position: relative;   /* lifts it above the covering anchor so it stays clickable */
  z-index: 2;
  align-self: flex-start;
  margin-top: 8px;
  padding: 0;
  background: none;
  color: var(--ps-link);
  font: 600 var(--ps-t-body) / 1.47 var(--ps-font-text);
  letter-spacing: var(--ps-ls-body);
  text-decoration: none;
  transition: color .18s linear;
}
body.pstore-page .ps-tile-price:hover { color: var(--ps-link-hover); text-decoration: underline; }
/* White, not --ps-link-on-dark (#ff5f78) — a pink-red link would vanish into
   the brand-red gradient behind it. */
body.pstore-page .ps-tile.is-featured .ps-tile-price { color: var(--ps-on-brand); }
body.pstore-page .ps-tile.is-featured .ps-tile-price:hover {
  color: var(--ps-on-brand);
  text-decoration: underline;
}

/* A covering anchor rather than a wrapping <a>: "Request pricing" is a second
   link and cannot legally nest inside a tile-wide one. */
body.pstore-page .ps-tile-hit { position: absolute; inset: 0; z-index: 1; }

body.pstore-page .ps-grid-empty {
  grid-column: 1 / -1;
  padding: clamp(32px, 5vw, 64px) 0;
  text-align: center;
  font-size: var(--ps-t-body);
  color: var(--ps-ink-2);
}

@media (max-width: 479.98px) {
  /* Three chips wrap to two lines and break the tile's rhythm at this width. */
  body.pstore-page .ps-chip:nth-child(n + 3) { display: none; }
  body.pstore-page .ps-tile-name { font-size: var(--ps-t-body); }
}

/* ==========================================================================
   7. "Why VATECH" — <details> cards with a rotating "+"
   ========================================================================== */

body.pstore-page .ps-why-grid {
  display: grid;
  gap: var(--ps-gutter);
  grid-template-columns: 1fr;
}
@media (min-width: 734px) {
  body.pstore-page .ps-why-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

body.pstore-page .ps-why-card {
  position: relative;                /* so the hover z-index applies */
  background: var(--ps-grad-tint);
  border-radius: var(--ps-r-card);
  padding: clamp(24px, 3vw, 32px);
  /* Flex column so the closed summary can be stretched to fill the card — see
     the rule below. ::details-content becomes a flex item, which does not
     disturb its block-size open transition. */
  display: flex;
  flex-direction: column;
}

/* The "+" is positioned against the summary, and the summary is content-sized,
   so the three cards were landing it at three different heights (60 / 60 / 32px
   above the card bottom) even though grid stretch makes the cards themselves
   equal. Stretching the closed summary to fill the card puts the "+" on the
   card's own padding edge — identical on every card, whatever the copy.
   Closed only: when the card opens the summary returns to its natural height so
   the "+" stays on the card face instead of sinking below the expanded copy. */
body.pstore-page .ps-why-card:not([open]) > summary { flex: 1 1 auto; }

body.pstore-page .ps-why-card > summary {
  display: block;             /* kills the default disclosure triangle */
  list-style: none;
  cursor: pointer;
  position: relative;
  padding-bottom: 56px;       /* the well the "+" sits in */
}
body.pstore-page .ps-why-card > summary::-webkit-details-marker { display: none; }
body.pstore-page .ps-why-card > summary::marker { content: ""; }

body.pstore-page .ps-why-ic {
  display: block;
  margin-bottom: 20px;
  font-size: 44px;
  line-height: 1;
  color: var(--ps-ink);
}

body.pstore-page .ps-why-h {
  font-size: var(--ps-t-title);
  line-height: 1.17;
  letter-spacing: var(--ps-ls-title);
  margin-bottom: .4em;
}

body.pstore-page .ps-why-sub {
  font-size: var(--ps-t-body);
  line-height: 1.47;
  letter-spacing: var(--ps-ls-body);
  color: var(--ps-ink-2);
}

/* Bottom-RIGHT of the card. Bootstrap Icons is an icon font with no weight
   axis, so font-weight does nothing here — the heavier read comes from the
   larger glyph in a larger disc. */
body.pstore-page .ps-why-plus {
  position: absolute;
  left: auto;
  right: 0;
  bottom: 0;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--ps-ink);
  color: var(--ps-canvas);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 17px;
  transition: transform .28s cubic-bezier(.22, 1, .36, 1);
}
body.pstore-page .ps-why-card[open] .ps-why-plus { transform: rotate(45deg); }

body.pstore-page .ps-why-more {
  padding-top: 4px;
  font-size: var(--ps-t-body);
  line-height: 1.47;
  color: var(--ps-ink-2);
}
body.pstore-page .ps-why-more p + p { margin-top: .8em; }

/* Sits bottom-right under the card row. Scoped through main.main deliberately:
   the reset `body.pstore-page main.main p { margin: 0 }` is (0,2,3) and was
   silently zeroing a margin-top declared at (0,2,1) — measured 0px live against
   a declared clamp. (0,3,2) clears it. */
body.pstore-page main.main .ps-why-foot {
  margin-top: clamp(28px, 3.4vw, 40px);
  text-align: right;
}
/* .ps-link is inline-flex, so the parent's text-align is what moves it. */
body.pstore-page .ps-why-foot .ps-link { font-weight: 600; }

/* CSS-only open animation where the platform supports it; everywhere else the
   card simply opens instantly, which is fine for three lines of copy. */
@supports (interpolate-size: allow-keywords) {
  body.pstore-page { interpolate-size: allow-keywords; }
  body.pstore-page .ps-why-card::details-content {
    block-size: 0;
    overflow: hidden;
    transition: block-size .38s cubic-bezier(.22, 1, .36, 1),
                content-visibility .38s allow-discrete;
  }
  body.pstore-page .ps-why-card[open]::details-content { block-size: auto; }
}

/* ==========================================================================
   8. Enquiry form — centred
   ========================================================================== */

body.pstore-page .ps-form .ps-sechead { text-align: center; }
body.pstore-page .ps-form .ps-sechead p { margin-inline: auto; max-width: 60ch; }

body.pstore-page .ps-form-inner {
  max-width: 760px;
  margin-inline: auto;       /* without this the card sits hard against the left edge */
}
body.pstore-page .ps-form .form-card {
  border-radius: var(--ps-r-card);
  border-color: var(--ps-hair);
  background: var(--ps-canvas);
}

/* ==========================================================================
   9. Focus & reduced motion
   ========================================================================== */

body.pstore-page .ps-pill:focus-visible,
body.pstore-page .ps-chip-item:focus-visible,
body.pstore-page .ps-tile-hit:focus-visible,
body.pstore-page .ps-tile-price:focus-visible,
body.pstore-page .ps-why-card > summary:focus-visible,
body.pstore-page .ps-promo-prev:focus-visible,
body.pstore-page .ps-promo-next:focus-visible,
body.pstore-page .ps-link:focus-visible {
  outline: 3px solid var(--ps-link);
  outline-offset: 2px;
  border-radius: 4px;
}
/* The covering anchor has no box of its own; ring the tile instead. */
body.pstore-page .ps-tile:has(.ps-tile-hit:focus-visible) {
  outline: 3px solid var(--ps-link);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  body.pstore-page *,
  body.pstore-page *::before,
  body.pstore-page *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ==========================================================================
   MOBILE PASS — tile legibility + touch targets
   Scoped to max-width queries only; the desktop store layout is unchanged.
   ========================================================================== */

/* Two columns, NOT one.
   `grid-template-columns: 1fr` was actively broken here: .ps-tile.is-featured
   carries `grid-column: span 2` (line 633) and nothing resets it, so a single
   explicit track plus a two-column span forced an implicit second column sized
   `auto`. On a 390px phone that resolved to `32.0156px 306.984px` — the auto
   track swallowed 307px and every tile in the explicit track rendered 32px
   wide. Two equal tracks make the span legal again.

   The one-column rule was reasoned from poster art with the product name baked
   into the JPG, but $gridItems feeds these tiles product_card_shot(), i.e. the
   transparent card_shot.webp cut-out. A cut-out reads fine at 170px, and the
   name is live text underneath it. */
@media (max-width: 575.98px) {
  body.pstore-page .ps-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  /* Full-width band rather than the desktop 2x2 block: two rows of a
     phone-width tile is far taller than the hero needs to be. */
  body.pstore-page .ps-tile.is-featured { grid-row: auto; }

  /* The tile is ~170px wide now; the desktop clamp() padding eats too much of it. */
  body.pstore-page .ps-tile { padding: 12px; }
  body.pstore-page .ps-tile-media { margin-bottom: 10px; padding: 4px; }
}

/* Filter rail: 42px segments with a 2px gutter. --ps-pill-h feeds both the
   pill and the sliding capsule, so raising the token keeps them aligned. */
@media (pointer: coarse) {
  body.pstore-page { --ps-pill-h: 44px; }
  body.pstore-page .ps-filters { gap: 8px; }
}

/* Promo carousel: 36px paddles and 7px dots.
   The paddles go to 44px. The dots keep their size — at a 15px pitch a 44px
   target would overlap its neighbours — and gain a larger transparent hit
   area instead, with the track widened so those areas do not collide. */
@media (pointer: coarse) {
  body.pstore-page .ps-promo-prev,
  body.pstore-page .ps-promo-next { width: 44px; height: 44px; }
  body.pstore-page .ps-promo-prev > i,
  body.pstore-page .ps-promo-next > i { font-size: 16px; }

  body.pstore-page .ps-promo-dots { gap: 18px; }
  body.pstore-page .ps-promo-dots .swiper-pagination-bullet { position: relative; }
  body.pstore-page .ps-promo-dots .swiper-pagination-bullet::before {
    content: "";
    position: absolute;
    top: 50%; left: 50%;
    transform: translate(-50%, -50%);
    width: 24px; height: 24px;
  }
}
