/* ==========================================================================
   store.css — the storefront
   --------------------------------------------------------------------------
   Every page carries data-brand="pneumatics" on <html>, and the block below
   it hangs the brand colours off. Every colour in this file comes from one of
   those tokens, so RESTYLING THE SHOP MEANS EDITING THAT ONE BLOCK and never
   the components.

   The attribute is a leftover from when this stylesheet dressed two shops. It
   is worth keeping: it is where --brand and --brand-hero live, and one
   stylesheet that reads its palette from a single place is easier to restyle
   than one with the red typed into forty rules.
   ========================================================================== */

/* ---------------------------- shared tokens ------------------------------ */
:root {
  --bg: #ffffff;
  --surface: #f5f7f9;
  --surface-2: #eef1f5;
  --line: #e2e6ec;
  --text: #1d1d1f;          /* Apple's ink */
  --muted: #6e6e73;         /* Apple's secondary grey */
  --dark: #0b0f14;
  --dark-2: #131a22;

  --radius: 14px;
  --radius-sm: 10px;
  --radius-lg: 22px;

  --shadow-sm: 0 1px 2px rgba(15, 20, 26, 0.06), 0 2px 8px rgba(15, 20, 26, 0.05);
  --shadow-md: 0 6px 18px rgba(15, 20, 26, 0.09), 0 2px 6px rgba(15, 20, 26, 0.05);
  --shadow-lg: 0 24px 60px rgba(15, 20, 26, 0.18);

  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --font: "Inter", "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;

  --wrap: 1280px;
  --header-h: 72px;
}

/* ------------------------- brand: 5M Pneumatic House ---------------------
   RED, not orange. The ink in the 5M logo is pure red — sampling the artwork
   gives #E00000 — so the orange this site used to run on never actually
   matched the logo it sat next to. --brand is now that exact logo red and
   everything else is a ramp built off it.
   ----------------------------------------------------------------------- */
[data-brand="pneumatics"] {
  --brand: #e00000;
  --brand-2: #a80000;
  --brand-3: #ff3b3b;
  --brand-deep: #3d0000;
  --on-brand: #ffffff;
  --brand-soft: #fdeaea;
  --brand-hero: url("../img/pneumatics-1920.jpg");
  --logo-h: 30px;
}

/* -------------------------------- reset --------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html { scroll-behavior: smooth; scroll-padding-top: calc(var(--header-h) + 16px); }

body {
  margin: 0;
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.55;
  /* a hair of negative tracking is what makes Inter read like SF Pro */
  letter-spacing: -0.012em;
  color: var(--text);
  background: var(--bg);
  /* Apple renders everything grayscale-antialiased — lighter, crisper strokes */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4, p, ul, ol, figure { margin: 0; }
ul, ol { padding: 0; list-style: none; }

/*
  Any author `display` rule outranks the UA stylesheet's [hidden]{display:none},
  so setting el.hidden = true on e.g. .card (display:flex) would not hide it.
  State it explicitly — the search filter relies on this.
*/
[hidden] { display: none !important; }
img, svg { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; }

:focus-visible {
  outline: 3px solid var(--brand);
  outline-offset: 2px;
  border-radius: 4px;
}

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: clamp(1rem, 4vw, 2.5rem);
}

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ============================== buttons ================================= */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  padding: 0.8rem 1.5rem;
  border: 1.5px solid transparent;
  border-radius: 999px;
  font-size: 0.85rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  cursor: pointer;
  white-space: nowrap;
  transition: background 220ms ease, color 220ms ease, border-color 220ms ease,
              transform 220ms var(--ease-out), box-shadow 220ms ease;
}

.btn svg { width: 17px; height: 17px; flex: none; }

.btn--primary { background: var(--brand); color: var(--on-brand); }
.btn--primary:hover { background: var(--brand-2); transform: translateY(-2px); box-shadow: var(--shadow-md); }

.btn--ghost { border-color: currentColor; background: transparent; }
.btn--ghost:hover { background: var(--text); color: var(--bg); border-color: var(--text); }

.btn--on-dark { border-color: rgba(255, 255, 255, 0.5); color: #fff; background: rgba(255, 255, 255, 0.08); }
.btn--on-dark:hover { background: #fff; color: var(--dark); border-color: #fff; }

.btn--sm { padding: 0.55rem 1.05rem; font-size: 0.78rem; }
.btn--lg { padding: 1rem 2.1rem; font-size: 0.98rem; }
.btn--block { width: 100%; }

/* =============================== top bar =============================== */
/* The dark strip above the header. It carried the company chooser when the
   site had two shops; now it is the counter details (phone, hours, street)
   and the hook i18n.js mounts the English / Urdu switch into (.switch__meta). */
.switch {
  background: var(--dark);
  color: rgba(255, 255, 255, 0.72);
  font-size: 0.76rem;
}

.switch__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-height: 40px;
  flex-wrap: wrap;
}

.switch__tabs { display: flex; gap: 0.25rem; }

.switch__tab {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.35rem 0.85rem;
  border-radius: 999px;
  font-weight: 600;
  letter-spacing: 0.03em;
  transition: background 200ms ease, color 200ms ease;
}

.switch__tab::before {
  content: "";
  width: 7px; height: 7px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.65;
}

.switch__tab:hover { background: rgba(255, 255, 255, 0.1); color: #fff; }

.switch__tab[aria-current="true"] {
  background: var(--brand);
  color: var(--on-brand);
}

.switch__tab[aria-current="true"]::before { opacity: 1; }

.switch__meta { display: flex; gap: 1.25rem; align-items: center; }
.switch__meta a:hover { color: #fff; }

/* ================================ header ================================ */
.header {
  position: sticky;
  top: 0;
  z-index: 60;
  background: rgba(255, 255, 255, 0.88);
  backdrop-filter: blur(14px) saturate(160%);
  border-bottom: 1px solid var(--line);
}

.header__inner {
  display: flex;
  align-items: center;
  gap: clamp(0.75rem, 2.5vw, 2rem);
  min-height: var(--header-h);
}

.brandmark { display: flex; align-items: center; gap: 0.7rem; flex: none; }
.brandmark img { height: var(--logo-h); width: auto; }

.nav { display: flex; gap: 0.35rem; margin-inline-start: auto; }

.nav a {
  padding: 0.5rem 0.85rem;
  border-radius: var(--radius-sm);
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--muted);
  white-space: nowrap;          /* never let a nav label break onto two lines */
  transition: background 180ms ease, color 180ms ease;
}

.nav a:hover, .nav a[aria-current="page"] { background: var(--brand-soft); color: var(--brand-2); }

.tools { display: flex; align-items: center; gap: 0.5rem; flex: none; }

.search {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.9rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  transition: border-color 200ms ease, background 200ms ease;
}

.search:focus-within { border-color: var(--brand); background: #fff; }
.search svg { width: 16px; height: 16px; color: var(--muted); flex: none; }

.search input {
  border: 0;
  background: transparent;
  outline: none;
  font: inherit;
  font-size: 0.86rem;
  width: clamp(110px, 15vw, 200px);
}

/*
  The catalogue's own search box. Hidden while the header has room for its own;
  it takes over below the header breakpoint so small screens never lose search.
*/
.search--inline { display: none; }
.search--inline input { width: 100%; }

.icon-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px; height: 42px;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: #fff;
  cursor: pointer;
  transition: border-color 200ms ease, background 200ms ease, transform 200ms var(--ease-out);
}

.icon-btn:hover { border-color: var(--brand); background: var(--brand-soft); transform: translateY(-1px); }
.icon-btn svg { width: 19px; height: 19px; }

.badge {
  position: absolute;
  top: -3px; right: -3px;
  min-width: 20px; height: 20px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--brand);
  color: var(--on-brand);
  font-size: 0.68rem;
  font-weight: 800;
  line-height: 20px;
  text-align: center;
  transform: scale(0);
  transition: transform 260ms var(--ease-out);
}

.badge.is-on { transform: scale(1); }

.burger { display: none; }

/* The "Search" row and its field live in the nav dropdown and only ever show on
   the narrow (burger) layout — the wide header has its own search box. */
.nav__search-toggle,
.nav__searchbar { display: none; }

/* ================================= hero ================================= */
.hero {
  position: relative;
  isolation: isolate;
  color: #fff;
  overflow: hidden;
}

.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -2;
  background-image: var(--brand-hero);
  background-size: cover;
  background-position: center;
  transform: scale(1.02);
}

.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(100deg, var(--brand-deep) 6%, color-mix(in srgb, var(--brand-2) 78%, transparent) 48%, rgba(0, 0, 0, 0.35) 100%),
    linear-gradient(to top, rgba(0, 0, 0, 0.55), rgba(0, 0, 0, 0.1));
}

.hero__inner {
  display: grid;
  gap: clamp(2rem, 5vw, 4rem);
  padding-block: clamp(3.5rem, 9vh, 7rem);
  max-width: 44rem;
}

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.85);
  margin-bottom: 1.1rem;
}

.eyebrow::before {
  content: "";
  width: 32px; height: 2px;
  background: currentColor;
}

.hero h1 {
  font-size: clamp(2.1rem, 5.6vw, 3.9rem);
  font-weight: 800;
  line-height: 1.04;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

.hero p {
  margin-top: 1.25rem;
  font-size: clamp(1rem, 1.5vw, 1.15rem);
  color: rgba(255, 255, 255, 0.88);
  max-width: 34rem;
}

.hero__actions { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 2rem; }

.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 1px;
  background: rgba(255, 255, 255, 0.22);
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: var(--radius);
  overflow: hidden;
}

.stats div {
  padding: 1.1rem 1.25rem;
  background: rgba(0, 0, 0, 0.28);
  backdrop-filter: blur(4px);
}

.stats b { display: block; font-size: 1.5rem; font-weight: 800; letter-spacing: -0.01em; }
.stats span { font-size: 0.74rem; letter-spacing: 0.12em; text-transform: uppercase; color: rgba(255, 255, 255, 0.75); }

/* =============================== sections =============================== */
.section { padding-block: clamp(3rem, 7vh, 5.5rem); }
.section--surface { background: var(--surface); }
.section--dark { background: var(--dark); color: #fff; }

.section__head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1.5rem;
  flex-wrap: wrap;
  margin-bottom: clamp(1.75rem, 4vw, 2.75rem);
}

.section__head h2 {
  font-size: clamp(1.5rem, 3vw, 2.15rem);
  font-weight: 800;
  letter-spacing: -0.02em;
}

.section__head p { color: var(--muted); margin-top: 0.4rem; max-width: 40rem; }
.section--dark .section__head p { color: rgba(255, 255, 255, 0.7); }

.kicker {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--brand);
  margin-bottom: 0.5rem;
}

.section--dark .kicker { color: var(--brand-3); }

/* ============================= category grid ============================ */
.cats {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: clamp(0.75rem, 1.5vw, 1.1rem);
}

.cat {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  padding: 1.4rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: #fff;
  transition: border-color 240ms ease, transform 240ms var(--ease-out), box-shadow 240ms ease;
}

.cat:hover { border-color: var(--brand); transform: translateY(-4px); box-shadow: var(--shadow-md); }

.cat__ico {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 46px; height: 46px;
  border-radius: 12px;
  background: var(--brand-soft);
  color: var(--brand-2);
}

.cat__ico svg { width: 24px; height: 24px; }
.cat b { font-size: 0.98rem; font-weight: 700; }
.cat span { font-size: 0.82rem; color: var(--muted); }

.cat__more {
  margin-top: auto;
  font-size: 0.76rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--brand);
}

/* ============================= product grid ============================= */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(248px, 1fr));
  gap: clamp(1rem, 2vw, 1.5rem);
}

.card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: #fff;
  overflow: hidden;
  transition: border-color 240ms ease, transform 240ms var(--ease-out), box-shadow 240ms ease;
}

.card:hover { border-color: var(--brand); transform: translateY(-4px); box-shadow: var(--shadow-md); }

/*
  Placeholder artwork: a brand gradient plus a line glyph. When you have real
  product photos, replace .card__art's contents with:
      <img src="assets/img/products/xyz.jpg" alt="…" class="card__photo">
  and give .card__art { padding: 0 }.
*/
/*
  SQUARE, not 4:3, and the reason is worth keeping.

  Product photographs here come in two shapes: tall studio shots of a single
  part (the valves and the regulator are all 3:4) and squarish group shots (the
  fitting kit, the FRL, the tube coils). With `contain` on a 4:3 box, every one
  of the tall ones was drawn at 142 x 190 inside a 260 x 190 area -- filling
  55% of the card, with the other 45% empty white either side. The part came
  out at about half the size it could be, which is exactly the "cannot see what
  the product is" complaint.

  Measured across all twenty photographs the catalogue now holds, mean fill by
  card shape: 4:3 -> 77%, square -> 80%, and the tall ones jump from 55% to
  75%. Square also happens to be what every parts catalogue on the web uses,
  because it is the only shape that treats portrait and landscape alike.
*/
.card__art {
  position: relative;
  aspect-ratio: 1 / 1;
  display: grid;
  place-items: center;
  background:
    radial-gradient(120% 120% at 20% 10%, color-mix(in srgb, var(--brand-3) 30%, #fff), transparent 60%),
    linear-gradient(150deg, var(--surface), var(--surface-2));
  border-bottom: 1px solid var(--line);
  overflow: hidden;
}

.card__art svg { width: 42%; height: 42%; color: var(--brand-2); opacity: 0.5; }

/*
  `contain` is the DEFAULT for a product photograph, not an opt-in. Every photo
  in this catalogue is a studio shot of one part on white, and `cover` on any of
  them crops the ends off the part -- it would take the middle third of a valve
  and throw away both ports. Every card already asked for --contain by hand;
  making it the default means a card added later cannot get this wrong by
  forgetting the modifier.
*/
.card__photo { width: 100%; height: 100%; object-fit: contain; }

/*
  Real photographs, as opposed to the drawn placeholder glyphs above. Ours are
  studio shots on a white sweep, so they sit on a white panel rather than on the
  brand gradient.
*/
.card__art--photo { background: #fff; padding: 0.5rem; }

/* Kept because every existing card names it, and because it still says out loud
   what the card wants. It no longer changes anything on its own — see the
   .card__photo rule above, where contain became the default. */
.card__photo--contain { object-fit: contain; }
.card__name a:hover { color: var(--brand-2); }

.tag {
  position: absolute;
  top: 0.7rem; left: 0.7rem;
  padding: 0.22rem 0.6rem;
  border-radius: 999px;
  background: var(--brand);
  color: var(--on-brand);
  font-size: 0.66rem;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.tag--stock { background: #12813f; }
.tag--order { background: #c0261a; }   /* out of stock — red */

.card__body { display: flex; flex-direction: column; gap: 0.45rem; padding: 1.1rem 1.15rem 1.25rem; flex: 1; }
.card__sku { font-size: 0.7rem; font-weight: 700; letter-spacing: 0.1em; color: var(--muted); }
.card__name { font-size: 1.08rem; font-weight: 800; line-height: 1.3; color: #1d1d1f; }
.card__name a { color: inherit; }
.card__spec { font-size: 0.82rem; color: var(--muted); }

.card__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-top: auto;
  padding-top: 0.9rem;
}

.price { font-size: 1.12rem; font-weight: 800; letter-spacing: -0.01em; }
.price small { font-size: 0.72rem; font-weight: 600; color: var(--muted); }

/* --- sale pricing: original struck through in red, discounted price beside it.
   Used by store.js priceHTML(); works inside .price (home/parts cards),
   .catcell__price (category + related) and .pdp__price (product page). --- */
.price-now {
  display: block;
  font-weight: 800;
  color: #e00000;
  font-size: 1.06em;
  line-height: 1.15;
}
.price-was {
  font-size: 0.72em;
  color: var(--muted);
  text-decoration: line-through;
  text-decoration-color: #9aa0a8;
  font-weight: 600;
  margin-right: 0.4em;
}
.price-off {
  font-size: 0.72em;
  font-weight: 800;
  color: #e00000;
  white-space: nowrap;
}

/* shown in place of the price when a product has no price set yet */
.price-tbc {
  font-size: 0.82em;
  font-weight: 700;
  color: var(--muted);
  white-space: nowrap;
}

.empty {
  padding: 3rem 1rem;
  text-align: center;
  color: var(--muted);
  border: 1px dashed var(--line);
  border-radius: var(--radius);
}

/* ============================== trust strip ============================= */
/* NO LONGER USED. The icon grid and the dark CTA these styled were replaced
   by the .vals / .steps / .close sections in story.css. Left in place because
   the rules are small and are the obvious starting point if you ever want a
   compact feature grid back on another page. */
.feats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: clamp(1.25rem, 3vw, 2.5rem);
}

.feat { display: flex; gap: 0.9rem; }

.feat__ico {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px; height: 42px;
  border-radius: 11px;
  background: color-mix(in srgb, var(--brand-3) 22%, transparent);
  color: var(--brand-3);
}

.feat__ico svg { width: 21px; height: 21px; }
.feat b { display: block; font-size: 0.95rem; }
.feat p { font-size: 0.85rem; color: rgba(255, 255, 255, 0.66); }
.section:not(.section--dark) .feat p { color: var(--muted); }

/* ================================ CTA band ============================== */
.cta {
  display: grid;
  gap: 1.5rem;
  align-items: center;
  padding: clamp(2rem, 4vw, 3.25rem);
  border-radius: var(--radius-lg);
  background: linear-gradient(115deg, var(--brand), var(--brand-2));
  color: var(--on-brand);
}

.cta h2 { font-size: clamp(1.4rem, 3vw, 2.1rem); font-weight: 800; letter-spacing: -0.02em; }
.cta p { color: rgba(255, 255, 255, 0.88); margin-top: 0.5rem; max-width: 42rem; }
.cta__actions { display: flex; flex-wrap: wrap; gap: 0.75rem; }

@media (min-width: 860px) {
  .cta { grid-template-columns: 1fr auto; }
}

/* ================================ footer ================================ */
/* ==========================================================================
   THE FOOTER, AND HOW IT ARRIVES
   --------------------------------------------------------------------------
   The dark panel is not a background colour while the reveal runs. It is a row
   of twelve vertical slats that rise from the bottom at staggered times, so the
   footer assembles itself like a blind closing. The footer's own text is
   light-coloured, so until a slat lands behind it, it sits there almost
   invisible against the light page — which is what makes this read as the
   footer arriving rather than as a box being painted in.

   assets/js/footmark.js builds the slats and adds .is-in when the footer comes
   into view, and takes it off again on the way out so the whole thing replays
   the next time down the page.

   THE BACKGROUND BELOW IS THE FALLBACK AND MUST STAY. .footer keeps its own
   dark background and only gives it up once the script has added .has-slats.
   Without that, a visitor with JavaScript off would get a footer with light
   text on a light page — unreadable.
   ========================================================================== */
.footer {
  position: relative;
  isolation: isolate;
  background: var(--dark);
  color: rgba(255, 255, 255, 0.66);
  padding-block: clamp(2.5rem, 5vh, 4rem) 1.5rem;
  /*
    Contains the full-bleed brand name at the bottom, which is 100vw wide and
    therefore a scrollbar's width more than the content area. `clip` rather than
    `hidden` because clip trims without making this a scroll container — hidden
    here would break any sticky positioning inside the footer later on.
    The `hidden` line is the fallback for browsers without `clip`.
  */
  overflow-x: hidden;
  overflow-x: clip;
}

/* the script has taken over: hand the dark ground to the slats */
.footer.has-slats { background: transparent; }

/* everything except the slats sits above them */
.footer > *:not(.footer__slats) { position: relative; z-index: 1; }

.footer__slats {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: flex;
  pointer-events: none;
}

.slat {
  flex: 1 1 0;
  background: var(--dark);
  transform: scaleY(0);
  transform-origin: bottom;
  /*
    A hair of overlap. Twelve flex children of a fractional width land on
    sub-pixel boundaries, and without this you get faint light seams between
    the slats once they are all up.
  */
  margin-inline: -0.5px;
}

.footer.is-in .slat {
  animation: slatUp 520ms cubic-bezier(0.16, 0.84, 0.28, 1) forwards;
  /* --o is this slat's place in the rising order, set by footmark.js from a
     fixed scatter — left to right would read as a wipe, not as slats */
  animation-delay: calc(var(--o, 0) * 46ms);
}

@keyframes slatUp {
  to { transform: scaleY(1); }
}

@media (prefers-reduced-motion: reduce) {
  .slat { transform: scaleY(1); }
  .footer.is-in .slat { animation: none; }
}

.footer__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: clamp(1.75rem, 4vw, 3rem);
}

.footer h3 {
  font-size: 0.76rem;
  font-weight: 800;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #fff;
  margin-bottom: 0.9rem;
}

.footer li { margin-bottom: 0.45rem; font-size: 0.88rem; }
.footer a:hover { color: #fff; }
.footer__logo { height: 30px; width: auto; margin-bottom: 1rem; opacity: 0.95; }
.footer__note { font-size: 0.86rem; max-width: 24rem; }

/* The counter's street address in the footer. <address> is italic by default in
   every browser, which is wrong for a postal address. */
.footer__addr {
  font-style: normal;
  font-size: 0.88rem;
  line-height: 1.7;
  margin-bottom: 0.9rem;
}

.footer__bar {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-top: clamp(2rem, 4vw, 3rem);
  padding-top: 1.25rem;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  font-size: 0.8rem;
}

/* ---- social links (Facebook / Instagram) ---- */
.footer__follow {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  flex-wrap: wrap;
  margin-top: clamp(1.75rem, 4vw, 2.75rem);
}
.footer__follow-label {
  font-size: 0.76rem;
  font-weight: 800;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #fff;
}
.footer__social { display: inline-flex; gap: 0.6rem; }
.footer__soc {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.18);
  background: rgba(255, 255, 255, 0.05);
  color: rgba(255, 255, 255, 0.85);
  transition: background 200ms ease, color 200ms ease, border-color 200ms ease, transform 200ms var(--ease-out);
}
.footer__soc svg { width: 20px; height: 20px; fill: currentColor; display: block; }
.footer__soc:hover { color: #fff; transform: translateY(-2px); }
.footer__soc--fb:hover { background: #1877f2; border-color: #1877f2; }
.footer__soc--ig:hover {
  background: radial-gradient(circle at 30% 107%, #fdf497 0%, #fd5949 45%, #d6249f 60%, #285aeb 90%);
  border-color: transparent;
}

/* ==========================================================================
   THE OVERSIZED BRAND NAME AT THE FOOT OF THE PAGE
   --------------------------------------------------------------------------
   The company name set as large as the page will carry, running the full width
   and cut off by the bottom edge, so it reads as a sign-off rather than as
   another piece of navigation. Letters rise into place as the footer arrives.

   assets/js/footmark.js splits the word into one span per letter and adds
   .is-in when the footer comes into view. Without that script the word simply
   sits there at full size — see the .is-split guard below.

   THE SIZE IS 11vw AND THAT NUMBER IS NOT ARBITRARY. The name is
   "5M Pneumatics" at 13 characters. Archivo Black averages about 0.62em a
   character, so a word that must fit the viewport wants roughly
   100 / (13 x 0.62) = 12.4vw of room; 11vw sits just inside that and leaves a
   margin at both ends at every width from a phone to a wide monitor. (The
   figure was set when the footer also had to fit "TARIQ ELECTRIC" at 14
   characters, which is why there is headroom to spare now.) If you ever change
   the name, recheck this: a longer one will overflow, and the container's
   overflow: hidden will silently crop it rather than warn you.
   ========================================================================== */
.footmark {
  position: relative;
  /*
    Full-bleed out of .wrap's padding.

    100vw INCLUDES THE SCROLLBAR and the content area does not, so on a page
    with a vertical scrollbar this element comes out about 8px wider than there
    is room for — which gave the whole site a horizontal scrollbar. The fix is
    the `overflow-x: clip` on .footer below, not a smaller number here: `clip`
    trims the overhang without turning the footer into a scroll container the
    way `hidden` would.
  */
  margin-inline: calc(50% - 50vw);
  margin-top: clamp(1.5rem, 4vw, 3rem);
  /* the descenders are deliberately cut by the page edge */
  margin-bottom: calc(-1 * clamp(0.6rem, 2.2vw, 2rem));
  overflow: hidden;
  pointer-events: none;
  user-select: none;
}

.footmark__word {
  display: block;
  text-align: center;
  white-space: nowrap;
  font-family: var(--vh-heavy, "Arial Black", "Segoe UI Black", sans-serif);
  font-weight: 900;
  font-size: clamp(1.9rem, 11vw, 11rem);
  line-height: 0.82;
  letter-spacing: -0.03em;
  text-transform: uppercase;

  /*
    Bright at the top, gone by the bottom. That is what stops a word this size
    from shouting over the address and the copyright line sitting above it, and
    it is also what makes the crop at the page edge look intended.
  */
  background: linear-gradient(
    to bottom,
    color-mix(in srgb, var(--brand) 82%, #ffffff) 0%,
    color-mix(in srgb, var(--brand) 55%, transparent) 58%,
    transparent 96%
  );
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* a browser without background-clip: text would show a solid brand block with
   invisible text, so fall back to plain coloured type */
@supports not ((-webkit-background-clip: text) or (background-clip: text)) {
  .footmark__word {
    background: none;
    color: color-mix(in srgb, var(--brand) 70%, #ffffff);
  }
}

/* ---------------------------- the animation --------------------------- */
/*
  Only hide the letters once the script has actually split them. Without that
  guard, a visitor with JavaScript off would get an invisible footer.
*/
.footmark.is-split .footmark__ch {
  display: inline-block;
  transform: translateY(0.42em);
  opacity: 0;
}

.footer.is-in .footmark.is-split .footmark__ch {
  animation: footmarkIn 620ms cubic-bezier(0.18, 0.9, 0.25, 1) forwards;
  /* one step per letter — the word assembles left to right */
  animation-delay: calc(var(--i) * 42ms);
}

@keyframes footmarkIn {
  to { transform: translateY(0); opacity: 1; }
}

/* right to left, the word should assemble from the right instead */
[dir="rtl"] .footer.is-in .footmark.is-split .footmark__ch {
  animation-delay: calc((var(--letters, 14) - var(--i)) * 42ms);
}

@media (prefers-reduced-motion: reduce) {
  .footmark.is-split .footmark__ch { transform: none; opacity: 1; }
  .footer.is-in .footmark.is-split .footmark__ch { animation: none; }
}

/*
  In Urdu the brand name stays in Latin — it is a company name, and the rest of
  the site treats those the same way. So it keeps the Latin display face rather
  than switching to Nastaliq, which has no capitals and would not carry a
  wordmark anyway.
*/
[lang="ur"] .footmark__word {
  font-family: var(--vh-heavy, "Arial Black", sans-serif);
  letter-spacing: -0.03em;
  text-transform: uppercase;
  line-height: 0.82;
}

/* ============================== cart drawer ============================= */
.scrim {
  position: fixed;
  inset: 0;
  z-index: 90;
  background: rgba(8, 12, 16, 0.5);
  backdrop-filter: blur(2px);
  opacity: 0;
  visibility: hidden;
  transition: opacity 300ms ease, visibility 300ms;
}

.scrim.is-open { opacity: 1; visibility: visible; }

.cart {
  position: fixed;
  top: 0; right: 0;
  z-index: 100;
  display: flex;
  flex-direction: column;
  width: min(420px, 100vw);
  height: 100dvh;
  background: #fff;
  box-shadow: var(--shadow-lg);
  transform: translateX(101%);
  transition: transform 380ms var(--ease-out);
}

.cart.is-open { transform: none; }

.cart__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.15rem 1.25rem;
  border-bottom: 1px solid var(--line);
}

.cart__head h2 { font-size: 1.05rem; font-weight: 800; }
.cart__body { flex: 1; overflow-y: auto; padding: 1rem 1.25rem; }

.line {
  display: grid;
  grid-template-columns: 56px 1fr auto;
  gap: 0.85rem;
  align-items: center;
  padding: 0.85rem 0;
  border-bottom: 1px solid var(--line);
}

.line__art {
  display: grid;
  place-items: center;
  width: 56px; height: 56px;
  border-radius: var(--radius-sm);
  background: var(--brand-soft);
  color: var(--brand-2);
}

.line__art svg { width: 26px; height: 26px; }
.line__name { font-size: 0.88rem; font-weight: 700; line-height: 1.3; }
.line__sku { font-size: 0.72rem; color: var(--muted); }

.qty { display: inline-flex; align-items: center; gap: 0.15rem; margin-top: 0.35rem; }

.qty button {
  width: 26px; height: 26px;
  border: 1px solid var(--line);
  border-radius: 7px;
  background: #fff;
  cursor: pointer;
  line-height: 1;
}

.qty button:hover { border-color: var(--brand); color: var(--brand-2); }
.qty span { min-width: 28px; text-align: center; font-size: 0.85rem; font-weight: 700; }

.line__right { text-align: right; }
.line__price { font-size: 0.92rem; font-weight: 800; }

.line__rm {
  margin-top: 0.35rem;
  border: 0;
  background: none;
  padding: 0;
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--muted);
  cursor: pointer;
  text-decoration: underline;
}

.line__rm:hover { color: #c02516; }

.cart__foot { border-top: 1px solid var(--line); padding: 1.15rem 1.25rem; background: var(--surface); }

.cart__row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 0.9rem;
}

.cart__row b { font-size: 1.25rem; font-weight: 800; }
.cart__hint { font-size: 0.76rem; color: var(--muted); margin-top: 0.65rem; text-align: center; }

/* ================================= toast ================================ */
.toast {
  position: fixed;
  left: 50%;
  bottom: 1.5rem;
  z-index: 120;
  transform: translate(-50%, 150%);
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.8rem 1.25rem;
  border-radius: 999px;
  background: var(--dark);
  color: #fff;
  font-size: 0.86rem;
  font-weight: 600;
  box-shadow: var(--shadow-lg);
  transition: transform 420ms var(--ease-out);
  max-width: calc(100vw - 2rem);
}

.toast.is-on { transform: translate(-50%, 0); }
.toast svg { width: 17px; height: 17px; color: #57d98a; flex: none; }

/* ============================== responsive ============================== */
/* Logo + 6 nav links + search + 2 buttons needs ~1030px; below that, burger menu. */
@media (max-width: 1120px) {
  .nav {
    position: fixed;
    inset: var(--header-h) 0 auto 0;
    z-index: 55;
    flex-direction: column;
    gap: 0;
    padding: 0.75rem clamp(1rem, 4vw, 2.5rem) 1.25rem;
    background: #fff;
    border-bottom: 1px solid var(--line);
    box-shadow: var(--shadow-md);
    margin: 0;

    /*
      The panel starts var(--header-h) DOWN the viewport, so translating by its
      own height alone leaves it peeking over the header — the header offset has
      to come off too. visibility:hidden also keeps the closed links out of the
      tab order, which a transform alone does not do.
    */
    transform: translateY(calc(-100% - var(--header-h)));
    visibility: hidden;
    max-height: calc(100dvh - var(--header-h));
    overflow-y: auto;
    transition: transform 320ms var(--ease-out), visibility 320ms;
  }

  .nav.is-open { transform: none; visibility: visible; }
  .nav a { padding: 0.8rem 0.6rem; font-size: 0.95rem; border-radius: 0; border-bottom: 1px solid var(--line); }

  .burger { display: inline-flex; margin-inline-start: auto; }
  .header .search { display: none; }
  .switch__meta { display: none; }

  /* header search is gone, so the catalogue's own field takes over */
  .search--inline {
    display: flex;
    width: 100%;
    margin-bottom: 1.5rem;
    background: #fff;
  }

  /* the "Search" row inside the dropdown, styled like the nav links */
  .nav__search-toggle {
    display: flex;
    order: -1;                 /* Search sits at the TOP of the menu, above Home */
    align-items: center;
    gap: 0.55rem;
    width: 100%;
    padding: 0.8rem 0.6rem;
    font: inherit;
    font-size: 0.95rem;
    color: inherit;
    text-align: left;
    background: none;
    border: 0;
    border-bottom: 1px solid var(--line);
    cursor: pointer;
  }
  .nav__search-toggle svg { width: 18px; height: 18px; color: var(--brand-2); flex: none; }
  .nav__search-toggle[aria-expanded="true"] { color: var(--brand-2); }

  /* the field it reveals — hidden until JS adds .is-open */
  .nav__searchbar {
    order: -1;                 /* stays directly under the Search row at the top */
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.6rem;
    padding: 0.7rem 0.95rem;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: #fff;
  }
  .nav__searchbar.is-open { display: flex; }
  .nav__searchbar svg { width: 16px; height: 16px; color: var(--muted); flex: none; }
  .nav__searchbar input {
    flex: 1;
    min-width: 0;
    border: 0;
    background: none;
    font: inherit;
    font-size: 0.95rem;
    color: inherit;
    outline: none;
  }
}

@media (max-width: 560px) {
  :root { --header-h: 62px; }
  .hero__inner { padding-block: 2.75rem; }
  .stats b { font-size: 1.25rem; }
  .switch__inner { justify-content: center; }
}

/* ========================================================================== */
/* ============================ HERO IMAGE BANNER =========================== */
/* ==========================================================================
   The auto-advancing product banner that replaces the text hero on the
   pneumatics storefront. Deliberately wordless — the photographs are the
   message. Behaviour lives in assets/js/hero-slider.js.

   The product photos are studio shots on a white sweep, so the panel behind
   them is a pale gradient rather than a colour: the image edge then melts
   into the panel instead of sitting on it as an obvious rectangle. That is
   also why the images are object-fit: contain and never cropped — a portrait
   product shot cropped to a wide banner loses the product.
   ========================================================================== */
.hero-banner {
  padding-block: clamp(1rem, 2.5vw, 1.75rem);
  background:
    radial-gradient(90% 120% at 50% -20%, color-mix(in srgb, var(--brand-3) 16%, transparent), transparent 70%),
    var(--surface);
  border-bottom: 1px solid var(--line);
}

.hero-slider {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: linear-gradient(178deg, #ffffff 0%, #ffffff 55%, var(--surface-2) 100%);
  box-shadow: var(--shadow-md);
  /* vertical scrolling still belongs to the page; we only claim horizontal */
  touch-action: pan-y;
}

.hero-slider__track {
  display: flex;
  will-change: transform;
  transition: transform 620ms var(--ease-out);
}

.hero-slide {
  flex: 0 0 100%;
  min-width: 100%;
}

.hero-slide__link {
  display: block;
  position: relative;
  aspect-ratio: 4 / 5;
  max-height: 74vh;
}

/*
  A blurred, scaled-up copy of the same photograph fills the panel behind the
  sharp one. These are studio shots on a white sweep, so the blur resolves to
  a soft neutral wash that the sharp image's own background melts into. The
  banner then reads as one composition instead of a portrait photo stranded
  in a wide white box — which is what you get with `contain` alone.

  The URL comes from a --shot custom property that hero-slider.js copies off
  each slide's own <img>, so the photo is still named in exactly one place in
  the HTML. With scripting off the property is unset, the rule is dropped,
  and you simply get the plain contained image.
*/
.hero-slide__link::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background-image: var(--shot);
  background-size: cover;
  background-position: center;
  filter: blur(34px) saturate(1.18) brightness(1.02);
  transform: scale(1.25);
}

.hero-slide__link img {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  object-fit: contain;
  /* the photos already carry their own soft studio shadow */
  padding: clamp(0.75rem, 3vw, 2.25rem);
  transition: transform 700ms var(--ease-out);
}

.hero-slide__link:hover img { transform: scale(1.035); }

/* Before hero-slider.js runs, .is-live is absent: the track is still a flex
   row of full-width slides, so overflow:hidden shows slide one and it stays
   clickable. Nothing to switch off here — this is just where that is noted. */

/* ------------------------------- arrows -------------------------------- */
.hero-slider__arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 3;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.86);
  backdrop-filter: blur(6px);
  color: var(--text);
  cursor: pointer;
  opacity: 0;
  transition: opacity 240ms ease, background 240ms ease, color 240ms ease,
              border-color 240ms ease, transform 240ms var(--ease-out);
}

.hero-slider__arrow svg { width: 20px; height: 20px; }
.hero-slider__arrow--prev { left: clamp(0.5rem, 1.5vw, 1rem); }
.hero-slider__arrow--next { right: clamp(0.5rem, 1.5vw, 1rem); }

.hero-slider:hover .hero-slider__arrow,
.hero-slider:focus-within .hero-slider__arrow { opacity: 1; }

.hero-slider__arrow:hover {
  background: var(--brand);
  border-color: var(--brand);
  color: var(--on-brand);
}

.hero-slider__arrow--prev:hover { transform: translateY(-50%) translateX(-2px); }
.hero-slider__arrow--next:hover { transform: translateY(-50%) translateX(2px); }

/* Touch devices have no hover, so the arrows would never appear. They also
   do not need them — swiping is the native gesture there. */
@media (hover: none) {
  .hero-slider__arrow { display: none; }
}

/* -------------------------------- dots --------------------------------- */
.hero-slider__dots {
  position: absolute;
  z-index: 3;
  left: 50%;
  bottom: clamp(0.7rem, 2vw, 1.1rem);
  transform: translateX(-50%);
  display: flex;
  gap: 0.45rem;
  padding: 0.4rem 0.6rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.7);
  backdrop-filter: blur(6px);
  border: 1px solid var(--line);
}

.hero-slider__dot {
  width: 9px;
  height: 9px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: color-mix(in srgb, var(--text) 26%, transparent);
  cursor: pointer;
  transition: background 220ms ease, width 260ms var(--ease-out);
}

.hero-slider__dot:hover { background: color-mix(in srgb, var(--text) 45%, transparent); }
.hero-slider__dot.is-on { width: 26px; background: var(--brand); }

/* --------------------------- autoplay progress ------------------------- */
/* A hairline at the top of the panel showing how long the slide has left.
   It is the only "chrome" that hints the banner moves on its own. */
.hero-slider__bar {
  position: absolute;
  z-index: 3;
  top: 0;
  left: 0;
  height: 3px;
  width: 100%;
  transform: scaleX(0);
  transform-origin: left center;
  background: linear-gradient(90deg, var(--brand), var(--brand-2));
}

.hero-slider__bar.is-running {
  animation: hero-bar var(--dur, 5000ms) linear forwards;
}

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

@media (min-width: 640px) {
  .hero-slide__link { aspect-ratio: 16 / 10; }
}

/*
  Kept at 16/9 rather than anything wider. These are portrait product shots,
  and with `contain` the panel's HEIGHT is what decides how big the product
  actually reads — a wider, shorter banner makes it smaller, not grander.
*/
@media (min-width: 1024px) {
  .hero-slide__link { aspect-ratio: 16 / 9; }
}


/* ========================================================================== */
/* ============================= PRODUCT PAGE =============================== */
/* ==========================================================================
   product.html — one template, every product. Rendered by
   assets/js/product-page.js from the list in assets/js/products.js.
   ========================================================================== */

/* ------------------------------ breadcrumb ----------------------------- */
.crumbs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  padding-block: 1.25rem 0;
  font-size: 0.8rem;
  color: var(--muted);
}

.crumbs a:hover { color: var(--brand-2); text-decoration: underline; }
.crumbs span[aria-hidden] { opacity: 0.5; }
.crumbs b { color: var(--text); font-weight: 600; }

/* ------------------------------- layout -------------------------------- */
.pdp {
  display: grid;
  gap: clamp(1.5rem, 4vw, 3rem);
  padding-block: clamp(1.25rem, 3vw, 2rem) clamp(2rem, 5vw, 3.5rem);
}

@media (min-width: 900px) {
  .pdp {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: start;
  }
  /* the gallery follows you down the spec tables */
  .pdp__media { position: sticky; top: calc(var(--header-h) + 1.25rem); }
}

/* ------------------------------- gallery ------------------------------- */
.pdp__stage {
  position: relative;
  aspect-ratio: 1 / 1;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: linear-gradient(178deg, #ffffff 0%, #ffffff 60%, var(--surface-2) 100%);
  overflow: hidden;
}

.pdp__stage img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: clamp(0.75rem, 2.5vw, 1.75rem);
}

.pdp__thumbs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-top: 0.75rem;
}

.pdp__thumb {
  width: 72px;
  height: 72px;
  padding: 4px;
  border: 1.5px solid var(--line);
  border-radius: var(--radius-sm);
  background: #fff;
  cursor: pointer;
  transition: border-color 200ms ease, transform 200ms var(--ease-out);
}

.pdp__thumb img { width: 100%; height: 100%; object-fit: contain; }
.pdp__thumb:hover { border-color: var(--brand-3); transform: translateY(-2px); }
.pdp__thumb.is-on { border-color: var(--brand); }

/* ------------------------------ headline ------------------------------- */
.pdp__eyebrow {
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--brand-2);
}

.pdp h1 {
  margin-top: 0.5rem;
  font-size: clamp(1.45rem, 3.2vw, 2.1rem);
  font-weight: 800;
  line-height: 1.18;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

.pdp__sub { margin-top: 0.6rem; color: var(--muted); font-size: 0.95rem; }

.pdp__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1rem;
  margin-top: 0.9rem;
  padding-bottom: 1.25rem;
  border-bottom: 1px solid var(--line);
  font-size: 0.8rem;
  color: var(--muted);
}

.pdp__sku { font-weight: 700; letter-spacing: 0.08em; color: var(--text); }

.pill {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.24rem 0.62rem;
  border-radius: 999px;
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #fff;
}

.pill--in { background: #12813f; }
.pill--order { background: #c0261a; }   /* out of stock — red */

/* ------------------------------- buy card ------------------------------ */
.buybox {
  margin-top: 1.5rem;
  padding: clamp(1.1rem, 2.5vw, 1.5rem);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}

.buybox__price {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  font-size: clamp(1.6rem, 3.5vw, 2.1rem);
  font-weight: 800;
  letter-spacing: -0.02em;
}

.buybox__price small { font-size: 0.8rem; font-weight: 600; color: var(--muted); }
.buybox__tax { margin-top: 0.2rem; font-size: 0.78rem; color: var(--muted); }

.buybox__lead {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.9rem;
  font-size: 0.85rem;
  font-weight: 600;
  color: #12813f;
}

.buybox__lead svg { width: 17px; height: 17px; flex: none; }

.buybox__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  margin-top: 1.25rem;
}

.pdp__qty {
  display: inline-flex;
  align-items: center;
  border: 1.5px solid var(--line);
  border-radius: 999px;
  background: #fff;
  overflow: hidden;
}

.pdp__qty button {
  width: 40px;
  height: 42px;
  border: 0;
  background: transparent;
  font-size: 1.1rem;
  font-weight: 700;
  cursor: pointer;
  transition: background 180ms ease, color 180ms ease;
}

.pdp__qty button:hover { background: var(--brand-soft); color: var(--brand-2); }

.pdp__qty input {
  width: 46px;
  height: 42px;
  border: 0;
  border-inline: 1.5px solid var(--line);
  text-align: center;
  font: inherit;
  font-weight: 700;
  background: transparent;
  /* the stepper buttons are the control here; the native spinner is noise */
  -moz-appearance: textfield;
  appearance: textfield;
}

.pdp__qty input::-webkit-outer-spin-button,
.pdp__qty input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

.buybox__row .btn { flex: 1 1 12rem; }
.buybox__note { margin-top: 1rem; font-size: 0.78rem; color: var(--muted); }

/* ---------------------------- at-a-glance ------------------------------ */
.pdp__glance { margin-top: 1.75rem; }

.pdp__glance h2 {
  font-size: 0.78rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 0.8rem;
}

.ticks { display: grid; gap: 0.65rem; }

.ticks li {
  display: grid;
  grid-template-columns: 20px 1fr;
  gap: 0.65rem;
  font-size: 0.9rem;
  line-height: 1.5;
}

.ticks svg { width: 17px; height: 17px; margin-top: 0.25rem; color: var(--brand); }

/* ------------------------------- panels -------------------------------- */
.panel { padding-block: clamp(2rem, 5vw, 3.25rem); border-top: 1px solid var(--line); }
.panel--surface { background: var(--surface); }

.panel h2 {
  font-size: clamp(1.15rem, 2.4vw, 1.5rem);
  font-weight: 800;
  letter-spacing: -0.01em;
  margin-bottom: 1.1rem;
}

.prose { max-width: 62ch; display: grid; gap: 1rem; }
.prose p { color: var(--muted); font-size: 0.99rem; line-height: 1.72; }

/* --------------------------- specification ----------------------------- */
/* Wide tables scroll inside their own box rather than pushing the page. */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

.spec {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9rem;
  text-align: left;
}

.spec caption {
  caption-side: top;
  text-align: left;
  padding-bottom: 0.75rem;
  font-size: 0.82rem;
  color: var(--muted);
}

.spec th, .spec td {
  padding: 0.72rem 0.9rem;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}

.spec thead th {
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  background: var(--surface-2);
  white-space: nowrap;
}

.spec tbody th {
  width: 38%;
  min-width: 11rem;
  font-weight: 600;
  color: var(--muted);
}

.spec tbody td { font-weight: 600; }
.spec tbody tr:hover { background: color-mix(in srgb, var(--brand-soft) 60%, transparent); }
.panel--surface .spec thead th { background: var(--surface-2); }

/* ---------------------------- related strip ---------------------------- */
.pdp__missing { padding-block: clamp(3rem, 10vh, 6rem); text-align: center; }
.pdp__missing h1 { font-size: clamp(1.5rem, 4vw, 2.2rem); }
.pdp__missing p { margin-top: 0.75rem; color: var(--muted); }
.pdp__missing .btn { margin-top: 1.5rem; }

/* ========================================================================== */
/* ================================ CHECKOUT ================================ */
/* ==========================================================================
   checkout.html — the order form, the bill and the print layout.

   data-brand="pneumatics" is static on <html>, so the brand tokens just work.
   data-checkout="true" is what strips the header back to a logo and a phone
   number — see [data-checkout] below.
   ========================================================================== */

/* ------------------------------- chrome -------------------------------- */
/*
  A checkout header carries no nav, no search and no cart button. Once
  somebody is typing their phone number, every other link on the page is
  just a way to lose the order.
*/
.co__header .header__inner { justify-content: space-between; }

.co__phone {
  font-size: 0.85rem;
  font-weight: 700;
  color: var(--brand-2);
  white-space: nowrap;
}

.co__phone:hover { text-decoration: underline; }
.co__footer { padding-block: 1.5rem; }
.co__footer .footer__bar { margin-top: 0; border-top: 0; }

/* On a phone the logo + language toggle + "Questions? 042-…" do not fit on one
   row, and the nowrap phone link pushed the whole checkout page wider than the
   screen — the horizontal scroll is what cut the footer (and the right edge)
   off. Let the header wrap and trim the logo/phone a touch so it all stays on
   screen. */
@media (max-width: 560px) {
  .co__header .header__inner { flex-wrap: wrap; row-gap: 0.4rem; }
  .co__header .brandmark img { height: 24px; }
  .co__phone { font-size: 0.78rem; }
}

.co__empty { padding-block: clamp(3rem, 10vh, 6rem); text-align: center; }
.co__empty h1 { font-size: clamp(1.5rem, 4vw, 2.2rem); }
.co__empty p { margin-top: 0.75rem; color: var(--muted); }
.co__empty .btn { margin-top: 1.5rem; }

/* ------------------------------- layout -------------------------------- */
.co {
  display: grid;
  gap: clamp(1.5rem, 3.5vw, 2.5rem);
  padding-block: clamp(1.25rem, 3vw, 2rem) clamp(2.5rem, 6vw, 4rem);
}

/* Grid items default to min-width:auto, so on a phone the bill column refused to
   shrink below the wide Estimate table — that pushed the whole checkout page
   wider than the screen (horizontal scroll) and cut the footer off at the right
   edge. min-width:0 lets the column shrink; the table then scrolls inside
   .table-scroll instead of stretching the page. */
.co > * { min-width: 0; }

/* Belt-and-braces: on phones/tablets, clip any residual horizontal overflow on
   the checkout page so the footer background always spans the full width and the
   page can never scroll sideways. The sticky form is >=940px, so this never
   touches it, and the Estimate table still scrolls inside .table-scroll. */
@media (max-width: 939px) {
  html[data-checkout] { overflow-x: hidden; }
}

/*
  Bill on the left, form on the right. On a phone they stack in source order,
  so the bill comes first: confirm what you are buying, then hand over your
  details. Applying the discount code changes totals up in the bill, which
  may be off screen by then — that is why the code field prints its own
  "15% applied, Rs X off" line right underneath itself.
*/
@media (min-width: 940px) {
  .co {
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
    align-items: start;
  }
  /* the form follows you down a long order */
  .co__form { position: sticky; top: calc(var(--header-h) + 1.25rem); }
}

.co__h2 {
  font-size: 1.05rem;
  font-weight: 800;
  letter-spacing: -0.01em;
  margin-bottom: 0.85rem;
}

.co__lede { color: var(--muted); font-size: 0.92rem; margin-bottom: 1.35rem; }

/* -------------------------- bill: the Estimate --------------------------
   A copy of the counter's own Estimate slip. Everything here is deliberately
   plain — black on white, hairline rules, no brand colour, no rounded
   corners — because this block is what comes out of the printer. What the
   customer sees on screen is what lands in their PDF.

   The one concession to the screen is the outer .co__bill card, which is
   stripped away again in the print block at the bottom of this file.
   ---------------------------------------------------------------------- */
.co__bill {
  padding: clamp(0.9rem, 2.2vw, 1.5rem);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: #fff;
  box-shadow: var(--shadow-sm);
}

/* the sheet itself */
.est {
  color: #000;
  /* Arial ahead of the site's Inter: the paper slip is set in a plain
     grotesque and the numerals should line up in narrow columns. */
  font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
  font-size: 12px;
  line-height: 1.45;
}

/* ------------------------------ letterhead ------------------------------ */
.est__head { text-align: center; padding-bottom: 0.5rem; }

.est__kind {
  font-size: 12px;
  font-weight: 400;
  margin-bottom: 0.15rem;
}

.est__co {
  font-size: 21px;
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.2;
}

.est__addr { font-size: 11px; }

/* ---------------------------- date / to / etc --------------------------- */
.est__meta {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.25rem 1.5rem;
  padding: 0.5rem 0;
  margin-top: 0.35rem;
  border-top: 1px solid #000;
  border-bottom: 1px solid #000;
}

/*
  Each column is a <dl>. Definition lists are the honest markup for
  label/value pairs, and the grid below puts the label and its value on one
  line without needing a wrapper element around each pair.
*/
.est__col {
  display: grid;
  grid-template-columns: 5.5rem 1fr;
  gap: 0.1rem 0.5rem;
  margin: 0;
  align-content: start;
}

.est__col dt { font-size: 11px; }
.est__col dd { margin: 0; font-weight: 700; word-break: break-word; }

/* ------------------------------ line items ----------------------------- */
.est__table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 0.75rem;
  font-size: 11px;
}

.est__table th,
.est__table td {
  padding: 0.4rem 0.35rem;
  vertical-align: top;
  text-align: left;
}

.est__table thead th {
  font-size: 10px;
  font-weight: 700;
  line-height: 1.15;
  border-bottom: 1px solid #000;
  white-space: nowrap;
}

.est__table tbody td { border-bottom: 1px solid #d9d9d9; }

.est__c { text-align: center !important; white-space: nowrap; }
.est__r { text-align: right !important; white-space: nowrap; }

.est__item { min-width: 11rem; }

/* The SKU is not on the paper slip, but a customer quoting an order over the
   phone needs it. Kept small and grey so it reads as a sub-line. */
.est__sku {
  display: block;
  font-size: 9.5px;
  color: #555;
  letter-spacing: 0.03em;
}

/* ------------------------------- totals -------------------------------- */
.est__totals th,
.est__totals td {
  padding-top: 0.5rem;
  font-weight: 700;
  border-bottom: 0;
}

.est__totals th { text-align: right !important; font-weight: 400; }

.est__sum th,
.est__net th { text-align: right !important; padding: 0.12rem 0.35rem; }

.est__sum td,
.est__net td { padding: 0.12rem 0.35rem; }

.est__sum th { font-weight: 400; }
.est__sum i { font-style: normal; font-size: 10px; }

/* "Total Net Sale" carries the double rule from the paper slip */
.est__net th { font-size: 13px; font-weight: 700; padding-top: 0.3rem; }

.est__net td {
  font-size: 13px;
  font-weight: 700;
  padding-top: 0.3rem;
  border-top: 1px solid #000;
  border-bottom: 3px double #000;
}

/* ----------------------------- foot of slip ---------------------------- */
.est__note {
  margin-top: 1.1rem;
  text-align: center;
  font-size: 10.5px;
}

.est__fine {
  margin-top: 0.6rem;
  text-align: center;
  font-size: 9.5px;
  color: #555;
  line-height: 1.5;
}

/* -------------------------------- form --------------------------------- */
.co__form {
  padding: clamp(1.1rem, 2.5vw, 1.75rem);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}

.field { margin-bottom: 1.15rem; }

.field label {
  display: block;
  margin-bottom: 0.4rem;
  font-size: 0.82rem;
  font-weight: 700;
}

.req { color: var(--brand-2); }
.opt { font-weight: 500; color: var(--muted); }

.field input,
.field select,
.field textarea {
  width: 100%;
  padding: 0.72rem 0.9rem;
  border: 1.5px solid var(--line);
  border-radius: var(--radius-sm);
  background: #fff;
  font: inherit;
  font-size: 0.92rem;
  color: var(--text);
  transition: border-color 180ms ease, box-shadow 180ms ease;
}

.field textarea { resize: vertical; min-height: 4.5rem; }

.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--brand);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 22%, transparent);
}

.field [aria-invalid="true"] { border-color: var(--brand-2); }

.field__hint { margin-top: 0.35rem; font-size: 0.76rem; color: var(--muted); }

.field__err {
  margin-top: 0.4rem;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--brand-2);
}

.field__note { margin-top: 0.45rem; font-size: 0.8rem; font-weight: 600; }
.field__note.is-good { color: #12813f; }
.field__note.is-bad { color: var(--brand-2); }

/* code box and its Apply button sit on one line */
.code-row { display: flex; gap: 0.5rem; }
.code-row input { flex: 1 1 auto; min-width: 0; }
.code-row .btn { flex: none; }

.co__privacy {
  margin-top: 0.9rem;
  font-size: 0.74rem;
  line-height: 1.6;
  color: var(--muted);
  text-align: center;
}

/* ------------------------------- result -------------------------------- */
.co__done, .co__warn {
  padding: 1.1rem 1.25rem;
  border-radius: var(--radius-sm);
  margin-bottom: 1.25rem;
}

.co__done { background: #e8f6ed; border: 1px solid #bfe3cd; }
.co__warn { background: #fff6e0; border: 1px solid #f0dca6; }
.co__done p, .co__warn p { font-size: 0.9rem; line-height: 1.65; margin-top: 0.4rem; }

.co__tick {
  display: grid;
  place-items: center;
  width: 34px; height: 34px;
  margin-bottom: 0.6rem;
  border-radius: 999px;
  background: #12813f;
  color: #fff;
  font-size: 1.1rem;
  font-weight: 800;
}

.co__done .co__h2, .co__warn .co__h2 { margin-bottom: 0; }
#result[tabindex]:focus { outline: none; }

.co__again { margin-top: 1rem; text-align: center; font-size: 0.85rem; }
.co__again a { font-weight: 700; color: var(--brand-2); text-decoration: underline; }

.co__raw { margin-top: 1rem; }
.co__raw summary { font-size: 0.82rem; font-weight: 700; cursor: pointer; }

.co__raw textarea {
  width: 100%;
  margin-top: 0.6rem;
  padding: 0.75rem;
  border: 1.5px solid var(--line);
  border-radius: var(--radius-sm);
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  font-size: 0.76rem;
  line-height: 1.5;
  background: #fff;
  resize: vertical;
}


/* ========================================================================== */
/* ======================= PRINT — "SAVE AS PDF" ============================= */
/* ==========================================================================
   There is no PDF library on this site and no build step. There does not need
   to be: every browser can already print a page to a PDF file, and it makes a
   proper one with selectable text. The "Save this bill as a PDF" button calls
   window.print(), and everything below strips the page down to the bill.

   On Windows the destination to choose is "Save as PDF" or "Microsoft Print
   to PDF". On a phone, print then Save as PDF.
   ========================================================================== */
@media print {
  /* the visitor asked for the bill, not the website around it */
  .co__header,
  .co__footer,
  .co__form,
  .crumbs,
  .switch,
  .cart,
  .scrim,
  /* it lives inside .co__header, which is already hidden — but if it ever
     falls back to floating on <body> it would print across the slip */
  .langsw,
  .toast { display: none !important; }

  html, body {
    background: #fff !important;
    color: #000 !important;
  }

  /* backdrop-filter and sticky both misbehave on a printed page */
  .header { position: static !important; }

  .co {
    display: block !important;
    padding: 0 !important;
  }

  .wrap {
    max-width: none !important;
    padding-inline: 0 !important;
  }

  /* the screen card melts away and the slip itself is all that is left */
  .co__bill {
    border: 0 !important;
    border-radius: 0 !important;
    box-shadow: none !important;
    padding: 0 !important;
    background: #fff !important;
  }

  /*
    Sizes move from px to pt so the slip comes out at the same physical size
    on any printer. Everything else about the .est block already prints as it
    stands — it was built black-on-white with hairline rules for exactly this
    reason, so there is very little to undo here.
  */
  .est { font-size: 10pt !important; }
  .est__co { font-size: 17pt !important; }
  .est__kind, .est__addr { font-size: 9pt !important; }
  .est__col dt { font-size: 9pt !important; }
  .est__table { font-size: 9pt !important; }
  .est__table thead th { font-size: 8.5pt !important; }
  .est__sku { font-size: 8pt !important; color: #444 !important; }
  .est__net th, .est__net td { font-size: 11pt !important; }
  .est__note { font-size: 8.5pt !important; }
  .est__fine { font-size: 7.5pt !important; color: #444 !important; }

  /* borders in pt keep their hairline weight instead of rounding to a blob */
  .est__meta { border-block: 0.75pt solid #000 !important; }
  .est__table thead th { border-bottom: 0.75pt solid #000 !important; }
  .est__table tbody td { border-bottom: 0.5pt solid #bbb !important; }
  .est__net td { border-top: 0.75pt solid #000 !important; }

  /* never split a line item, or the totals block, across two sheets */
  tr, .est__head, .est__meta { break-inside: avoid; }
  .est__totals, .est__sum, .est__net { break-inside: avoid; }

  /* if it ever does run to two sheets, repeat the column headings */
  .est__table thead { display: table-header-group; }

  a[href]::after { content: "" !important; }   /* no printed URLs */
  .table-scroll { overflow: visible !important; }
}

@page { margin: 14mm; }

/* =========================== reduced motion ============================= */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    transition-duration: 0.001ms !important;
  }
}

/* =========================================================================
   MOBILE RESPONSIVE PASS  (appended 2026-09-17)
   -------------------------------------------------------------------------
   Compact two-up product cards, guaranteed-visible names, a tidy category
   page and comfortable tap targets — an Apple-style clean mobile layout.
   store.css loads after the other stylesheets on every shop page, so these
   overrides win without needing !important.
   ========================================================================= */
@media (max-width: 640px) {

  /* --- product grid: two compact columns, like a real mobile shop --- */
  .grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.7rem;
  }

  /* --- the catalogue / parts card, compact --- */
  .card { border-radius: 14px; }
  .card__art,
  .card__art--photo {
    aspect-ratio: 1 / 1;
    height: auto;
    padding: 0.4rem;
  }
  .card__body { padding: 0.55rem 0.65rem 0.7rem; gap: 0.28rem; }
  .card__sku { font-size: 0.6rem; letter-spacing: 0.05em; }
  /* the name ALWAYS shows (up to two lines) — never clipped to nothing */
  .card__name {
    font-size: 0.86rem;
    font-weight: 700;
    line-height: 1.25;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
  .card__spec { display: none; }           /* no room beside a two-up card */
  .card__foot {
    flex-direction: column;
    align-items: stretch;
    gap: 0.4rem;
    padding-top: 0.55rem;
  }
  .card__foot .price { font-size: 0.98rem; }
  .card__foot .btn {
    width: 100%;
    padding: 0.55rem 0.6rem;
    min-height: 40px;
  }
  .tag { font-size: 0.55rem; padding: 0.15rem 0.45rem; top: 0.45rem; left: 0.45rem; }

  /* NOTE: the category page (.catgrid/.catcell/.catside) lives in catalog.css,
     which loads AFTER store.css on category.html — its mobile overrides are in
     catalog.css so they win the cascade. See catalog.css MOBILE RESPONSIVE PASS. */

  /* --- comfortable tap targets everywhere --- */
  .btn, .cg-btn { min-height: 40px; }
}

/* very small phones: keep two columns but tighten the gutters a touch more */
@media (max-width: 360px) {
  .grid { gap: 0.55rem; }
  .card__name { font-size: 0.8rem; }
}


/* =========================================================================
   APPLE-INSPIRED TYPOGRAPHY  (appended 2026-09-17)
   -------------------------------------------------------------------------
   Grounded in a read of apple.com + the HIG typography guidance: SF-Pro-style
   grayscale rendering (set on <body> above), confident negative tracking on
   headings, tabular figures for prices, Apple's own ink (#1d1d1f) and grey
   (#6e6e73). It refines the type WITHOUT touching the two deliberate design
   languages — store.css's bold marketing headings and catalog.css's quiet
   light-300 catalogue headings both keep their own weights.
   ========================================================================= */

/* Headings close up the way SF Pro Display does — subtle, and flattering for
   Inter. Class-level headings (e.g. .cg-h1, .vt-heavy) set their own tracking
   and win, so this only tightens the ones that had none. */
h1, h2, h3, h4 { letter-spacing: -0.02em; }
h1 { line-height: 1.08; }

/* A brush script must never be tracked tight — keep the two we have open. */
.vt-brush, .val__brush { letter-spacing: 0.01em; }

/* Product names are the most-repeated heading on the site — confident, dark,
   and closed-up like an Apple product title. */
.card__name, .catcell__name, .cattile__name { letter-spacing: -0.018em; }

/* Prices and any figures line up column-perfect and read cleanly. */
.price, .pdp__price, .card__foot .price, .num,
.price-now, .price-was, .catcell__price {
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}

/* The long product descriptions get Apple's comfortable reading rhythm. */
.pdp-fold__body p { line-height: 1.62; }


/* =========================================================================
   VISIT OUR SHOP  (appended 2026-09-23)
   -------------------------------------------------------------------------
   The map pin in the header (#mapOpen, always visible on desktop AND mobile),
   and the modal it opens: a coverflow of the shop's own photographs in the
   category-carousel style, then the map and a "Directions" link.
   ========================================================================= */

/* the pin lives with the cart button; it shows at every width */
.icon-btn--map svg { width: 20px; height: 20px; }

/* modal shell — its OWN dim backdrop, so it never fights the cart's #scrim */
.storemodal {
  position: fixed;
  inset: 0;
  z-index: 130;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(0.75rem, 3vw, 2rem);
  background: rgba(8, 12, 16, 0.62);
  backdrop-filter: blur(3px);
  opacity: 0;
  visibility: hidden;
  transition: opacity 280ms ease, visibility 280ms;
}
.storemodal.is-open { opacity: 1; visibility: visible; }

.storemodal__panel {
  position: relative;
  width: min(560px, 100%);
  max-height: 92dvh;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: clamp(1.25rem, 3.5vw, 2rem);
  border-radius: var(--radius-lg);
  background: #fff;
  box-shadow: var(--shadow-lg);
  transform: translateY(14px) scale(0.98);
  transition: transform 340ms var(--ease-out);
}
.storemodal.is-open .storemodal__panel { transform: none; }

.storemodal__x {
  position: absolute;
  top: 0.85rem; right: 0.85rem;
  z-index: 2;
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: #fff;
  color: var(--text);
  cursor: pointer;
  transition: border-color 200ms ease, background 200ms ease;
}
.storemodal__x:hover { border-color: var(--brand); background: var(--brand-soft); }
.storemodal__x svg { width: 18px; height: 18px; }

.storemodal__head { margin-bottom: 1.1rem; padding-right: 2.75rem; }
.storemodal__eyebrow {
  font-size: 0.72rem; font-weight: 700; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--brand-2);
  margin-bottom: 0.35rem;
}
.storemodal__title { font-size: clamp(1.35rem, 4vw, 1.9rem); font-weight: 800; letter-spacing: -0.02em; }

/* ---- the shop-photo coverflow (portrait cards, category-carousel look) ---- */
.shopflow {
  position: relative;
  border-radius: var(--radius);
  background: #0d0c0c;
  overflow: hidden;
  padding-block: clamp(1rem, 3vw, 1.5rem);
}
.shopflow__rail {
  position: relative;
  height: clamp(14rem, 54vw, 19rem);
  perspective: 1200px;
}
.shopcard {
  position: absolute;
  top: 50%; left: 50%;
  width: clamp(9.5rem, 38vw, 13rem);
  aspect-ratio: 3 / 4;
  margin: 0; border: 0; padding: 0;
  border-radius: 13px;
  overflow: hidden;
  background: #1b1918;
  cursor: pointer;
  transform: translate(-50%, -50%) translateX(var(--dx, 0)) scale(var(--sk, 1));
  opacity: var(--op, 1);
  filter: grayscale(var(--gs, 0)) brightness(var(--br, 1));
  z-index: var(--z, 1);
  transition: transform 600ms cubic-bezier(0.22, 0.85, 0.24, 1),
              opacity 460ms ease, filter 460ms ease;
}
.shopcard img { width: 100%; height: 100%; object-fit: cover; display: block; }

.shopcard[data-pos="0"]  { --dx: 0;    --sk: 1;    --op: 1;   --gs: 0; --br: 1;   --z: 5;
  box-shadow: 0 22px 50px -18px rgba(0, 0, 0, 0.85); }
.shopcard[data-pos="1"]  { --dx: 60%;  --sk: 0.66; --op: 0.5; --gs: 1; --br: 0.5; --z: 4; }
.shopcard[data-pos="-1"] { --dx: -60%; --sk: 0.66; --op: 0.5; --gs: 1; --br: 0.5; --z: 4; }
.shopcard[data-pos="far"]  { --dx: 96%;  --sk: 0.5; --op: 0; --z: 1; pointer-events: none; }
.shopcard[data-pos="-far"] { --dx: -96%; --sk: 0.5; --op: 0; --z: 1; pointer-events: none; }
.shopcard:not([data-pos="0"]):hover { --op: 0.82; --br: 0.75; }

.shopflow__arrow {
  position: absolute; z-index: 8; top: 50%;
  transform: translateY(-50%);
  display: grid; place-items: center;
  width: 40px; height: 40px;
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.09);
  backdrop-filter: blur(4px);
  color: #fff; cursor: pointer;
  transition: background 200ms ease, border-color 200ms ease;
}
.shopflow__arrow svg { width: 18px; height: 18px; }
.shopflow__arrow--prev { left: clamp(0.4rem, 2vw, 0.9rem); }
.shopflow__arrow--next { right: clamp(0.4rem, 2vw, 0.9rem); }
.shopflow__arrow:hover { background: var(--brand); border-color: var(--brand); }

.shopflow__dots { display: flex; justify-content: center; gap: 0.45rem; margin-top: 1rem; }
.shopflow__dot {
  width: 8px; height: 8px; padding: 0; border: 0;
  border-radius: 999px; background: rgba(255, 255, 255, 0.26); cursor: pointer;
  transition: background 220ms ease, width 260ms var(--ease-out);
}
.shopflow__dot:hover { background: rgba(255, 255, 255, 0.5); }
.shopflow__dot.is-on { width: 24px; background: var(--brand); }

/* ---- the map + directions ---- */
.storemodal__label {
  margin: 1.4rem 0 0.55rem;
  font-size: 0.72rem; font-weight: 700; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--muted);
}
.storemodal__map {
  border-radius: var(--radius);
  overflow: hidden;
  border: 1px solid var(--line);
  aspect-ratio: 16 / 10;
  background: var(--surface);
}
.storemodal__map iframe { width: 100%; height: 100%; border: 0; display: block; }

.storemodal__dir {
  display: flex; align-items: center; justify-content: center; gap: 0.55rem;
  margin-top: 1rem;
  padding: 0.95rem 1.25rem;
  border-radius: 999px;
  background: var(--brand);
  color: var(--on-brand);
  font-weight: 700; font-size: 0.95rem;
  box-shadow: 0 10px 24px -12px rgba(224, 0, 0, 0.7);
  transition: background 200ms ease, transform 200ms var(--ease-out);
}
.storemodal__dir:hover { background: var(--brand-2); transform: translateY(-1px); }
.storemodal__dir svg { width: 18px; height: 18px; }

.storemodal__addr {
  margin-top: 0.75rem;
  font-style: normal;
  text-align: center;
  font-size: 0.85rem;
  color: var(--muted);
}

/* three header icons want a little less room on phones */
@media (max-width: 560px) {
  :root { --logo-h: 26px; }
  .tools { gap: 0.4rem; }
  .icon-btn { width: 38px; height: 38px; }
  .icon-btn svg { width: 17px; height: 17px; }
  .icon-btn--map svg { width: 18px; height: 18px; }
}

/* the carousel stops advancing on its own if the reader asked for less motion */
@media (prefers-reduced-motion: reduce) {
  .shopcard { transition: none; }
}


/* =========================================================================
   FLOATING WHATSAPP BUTTON  (appended 2026-09-26)
   -------------------------------------------------------------------------
   Fixed to the lower-right on every shop page. Sits below the cart drawer /
   modals (z-index) so those still cover it when open, and clear of the toast
   (which is bottom-centre).
   ========================================================================= */
.wa-fab {
  position: fixed;
  right: clamp(0.9rem, 3vw, 1.6rem);
  bottom: clamp(0.9rem, 3vw, 1.6rem);
  z-index: 55;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 58px;
  height: 58px;
  border-radius: 50%;
  background: #25d366;
  color: #fff;
  box-shadow: 0 10px 26px -8px rgba(37, 211, 102, 0.6), 0 4px 10px rgba(0, 0, 0, 0.18);
  transition: transform 220ms var(--ease-out), box-shadow 220ms ease;
}
.wa-fab svg { width: 32px; height: 32px; fill: currentColor; display: block; }
.wa-fab:hover { transform: translateY(-2px) scale(1.05); box-shadow: 0 16px 32px -8px rgba(37, 211, 102, 0.7), 0 6px 14px rgba(0, 0, 0, 0.2); }
.wa-fab:active { transform: translateY(0) scale(0.98); }
.wa-fab:focus-visible { outline: 3px solid #fff; outline-offset: 3px; }

/* a soft pulse ring so the eye finds it */
.wa-fab::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: #25d366;
  z-index: -1;
  animation: waPulse 2.6s var(--ease-out) infinite;
}
@keyframes waPulse {
  0%   { transform: scale(1);   opacity: 0.55; }
  70%  { transform: scale(1.7); opacity: 0; }
  100% { transform: scale(1.7); opacity: 0; }
}

@media (max-width: 560px) {
  .wa-fab { width: 52px; height: 52px; }
  .wa-fab svg { width: 28px; height: 28px; }
}

@media (prefers-reduced-motion: reduce) {
  .wa-fab::before { animation: none; }
}
