/* ==========================================================================
   Naveed Mobiles — header, footer, and homepage layout.
   Split from main.css so the token/base layer stays readable as the shop grows.
   ========================================================================== */

/* -------------------------------------------------------------- header -- */

/* Frosted, because it is sticky and genuinely floats over scrolling content.
   Fixed white/light, not theme-variable — see the --header-* token comment
   in main.css. The solid --header-bg-solid fallback is what browsers without
   backdrop-filter get, and navy-ink-on-that measures far past AA — the blur
   is a depth cue, never what makes the text readable. */
.site-header {
  background: var(--header-bg-solid);
  color: var(--header-ink);
  position: sticky;
  top: 0;
  z-index: 40;
  border-bottom: 1px solid var(--header-border);
}
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .site-header {
    background: var(--header-bg);
    -webkit-backdrop-filter: var(--glass-blur);
    backdrop-filter: var(--glass-blur);
  }
}

.site-header__inner {
  position: relative;   /* anchors .mobile-menu below, without affecting the grid */
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 1rem;
  min-height: 64px;
}
@media (min-width: 768px) { .site-header__inner { min-height: 72px; } }

/* Scoped to __inner, not the whole header: the filter bar directly below is
   a SIBLING that keeps its own navy glass + white text (.fbar__clear etc.
   set their own color already) — a broader `.site-header a` rule here would
   win on specificity and silently turn "Clear" navy-on-navy. */
.site-header__inner a { color: var(--header-ink); text-decoration: none; }

.brand { display: inline-flex; align-items: center; gap: 0.5rem; }
/* The icon-only mark, cropped from the user's own lockup (aspect 0.825, so
   width follows height rather than being forced square — forcing 38x38 on a
   536x650 source would squash it). */
.brand__mark { height: 40px; width: auto; flex: 0 0 auto; }
/* Real logo art now (was CSS text) — see the header.php doc comment for why
   it needed a reversed colourway. Height-constrained, width auto, so it
   scales as one unit rather than stretching. */
.brand__word { height: 30px; width: auto; flex: 0 0 auto; }
/* At 360px a full lockup eats a third of the header, so the word drops out
   and only the icon-mark remains. Nearly every mobile session sees this. */
@media (max-width: 767px) { .brand__word { display: none; } }

.site-search { display: flex; gap: 0.5rem; min-width: 0; }
.site-search input {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 44px;
  padding: 0.5rem 0.875rem;
  border: 1px solid var(--header-border);
  border-radius: var(--r-sm);
  background: #F2F3F7;
  color: var(--header-ink);
}
.site-search input::placeholder { color: var(--header-ink-soft); }
.site-search input:focus { background: #FFFFFF; border-color: var(--cyan); }
/* The search field is the header's whole middle column on desktop; on mobile
   it moves below the brand row rather than shrinking to uselessness. */
@media (max-width: 639px) {
  .site-header__inner { grid-template-columns: auto auto; grid-template-rows: auto auto; }
  .site-search { grid-column: 1 / -1; order: 3; padding-bottom: 0.75rem; }
  .site-search .btn { display: none; }   /* Enter submits; the button is noise here */
}

.site-header__actions { display: flex; align-items: center; gap: 0.5rem; }
/* Scoped to __inner for the same reason as the `a` rule above — .btn--quiet
   is not used inside the filter bar, but scoping precisely costs nothing
   and keeps this file honest about what it actually touches. */
.site-header__inner .btn--quiet {
  color: var(--header-ink);
  border-color: var(--header-border);
}
.site-header__inner .btn--quiet:hover { background: var(--header-hover); }
.site-header__inner .btn:not(.btn--quiet) { background: var(--cyan); color: var(--navy-deep); }
.site-header__inner .btn:not(.btn--quiet):hover { background: #03B4F5; }

/* Mobile menu: 3-bar toggle + the dropdown it opens. Desktop never sees
   either — see the header.php comment for why. */
.menu-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1px solid var(--header-border);
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--header-ink);
  cursor: pointer;
  transition: background var(--dur-base) var(--ease-out), border-color var(--dur-base) var(--ease-out);
}
.menu-toggle:hover { background: var(--header-hover); }
/* #E4F4FB is the light theme's own --cyan-wash value, hardcoded rather than
   referenced: --cyan-wash flips to a DARK navy under [data-theme="dark"],
   which would leave --header-ink (dark) text sitting on a dark background —
   the header stays fixed-white regardless of theme, so nothing inside it may
   pull from a token that swaps for dark mode. */
.menu-toggle[aria-expanded="true"] { background: #E4F4FB; border-color: var(--cyan); }
@media (max-width: 767px) { .menu-toggle { display: inline-flex; } }

/* Light glass now, matching the white header it opens from — was dark navy
   when the header itself was navy. */
.mobile-menu {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 45;
  padding: 0.375rem;
  border-radius: 0 0 var(--r-md) var(--r-md);
  box-shadow: var(--shadow-float);
  background: var(--header-bg-solid);
  border: 1px solid var(--header-border);
  border-top: none;
}
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .mobile-menu {
    background: var(--header-bg);
    -webkit-backdrop-filter: var(--glass-blur);
    backdrop-filter: var(--glass-blur);
  }
}
.mobile-menu[hidden] { display: none; }
.mobile-menu nav { display: grid; gap: 1px; }
.mobile-menu a {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding: 0.625rem 0.875rem;
  border-radius: var(--r-sm);
  color: var(--header-ink);
  text-decoration: none;
  font-weight: 600;
}
.mobile-menu a:hover, .mobile-menu a:focus-visible { background: var(--header-hover); }

/* Urdu monogram at the header's right edge, where Cart used to sit. It is
   the only thing in this block now — the "Wholesale Dealers" caption moved
   to the filter bar — so it can run the header's full height rather than
   splitting the space with text. The header's min-height (64/72px) is the
   ceiling; the monogram sits just inside it.
   1024px+ only: there is no room for a fifth element in the actions row
   below that without crowding the tap targets already there. */
.brand__urdu {
  display: none;
  align-items: center;
  padding-left: 0.875rem;
  margin-left: 0.25rem;
  border-left: 1px solid var(--header-border);
}
.brand__urdu img {
  height: 56px;
  width: auto;
  flex: 0 0 auto;
  display: block;
}
@media (min-width: 1024px) { .brand__urdu { display: inline-flex; } }
/* The header grows to 72px min-height at 768px+, so above 1280px there is
   room for the monogram to fill more of it. */
@media (min-width: 1280px) { .brand__urdu img { height: 64px; } }
/* Belt and suspenders: even if JS state were somehow left open across a
   resize (e.g. rotating a tablet through the breakpoint), desktop never
   shows this panel. */
@media (min-width: 768px) { .mobile-menu { display: none !important; } }

.theme-toggle { padding-inline: 0.75rem; }
.theme-toggle__icon {
  width: 18px; height: 18px;
  border-radius: 50%;
  background: currentColor;
  /* A half-filled disc: unambiguous in both themes without an icon font. */
  clip-path: polygon(0 0, 50% 0, 50% 100%, 0 100%);
  box-shadow: 0 0 0 2px currentColor inset;
}

.cart-count {
  display: inline-grid;
  place-items: center;
  min-width: 22px; height: 22px;
  padding-inline: 5px;
  border-radius: 11px;
  background: var(--navy-deep);
  color: #FFFFFF;
  font-size: 0.75rem;
}
/* Confirms the action registered. 200ms, once, on real change only. */
.cart-count.is-bump { animation: nm-bump 200ms var(--ease-out); }
@keyframes nm-bump { 50% { transform: scale(1.15); } }

/* ----------------------------------------------------------- filter bar --
   Replaced the flat category nav: 30 categories in a horizontal scroll row is
   a list nobody reaches the end of. Category and brand are dropdowns, price is
   a two-handle range. Still a plain GET form — see the comment in header.php.
   -------------------------------------------------------------------------- */

/* Solid brand NAVY BLUE (#252265), not the near-black --glass-navy it used to
   share with the old dark header. Deliberately opaque rather than frosted:
   the bar sits directly beneath a white header, and a translucent tint over
   scrolling white content washed the navy out to grey. It is also hardcoded
   rather than using var(--navy), which flips to #3F3B93 under
   [data-theme="dark"] — this bar must stay the same navy in both themes, for
   the same reason the white header above it does. White text on #252265
   measures 12.6:1. */
.filterbar {
  background: #252265;
  position: sticky;
  top: 64px;      /* sits directly under the sticky header */
  z-index: 30;    /* above page content so the open panels are not clipped */
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}
@media (min-width: 768px) { .filterbar { top: 72px; } }
/* Under 640px the header grows a third row for the search field, so a sticky
   filter bar would cover the content it filters. It scrolls away there. */
@media (max-width: 639px) { .filterbar { position: relative; top: auto; } }
.filterbar__inner {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding-block: 0.5rem;
  flex-wrap: wrap;
}

.fbar__field { position: relative; display: flex; align-items: center; gap: 0.5rem; }

.fbar__label {
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: rgba(255, 255, 255, 0.62);
}

.fbar__toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 44px;
  padding: 0.375rem 0.75rem;
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: var(--r-sm);
  background: rgba(255, 255, 255, 0.10);
  color: #FFFFFF;
  cursor: pointer;
  transition: background var(--dur-base) var(--ease-out),
              border-color var(--dur-base) var(--ease-out);
}
.fbar__toggle:hover { background: rgba(255, 255, 255, 0.18); border-color: rgba(255, 255, 255, 0.4); }
.fbar__toggle[aria-expanded="true"] { background: rgba(255, 255, 255, 0.2); border-color: var(--cyan); }

.fbar__value { font-size: 0.875rem; font-weight: 600; max-width: 12ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fbar__chev { flex: 0 0 auto; transition: transform var(--dur-base) var(--ease-out); }
.fbar__toggle[aria-expanded="true"] .fbar__chev { transform: rotate(180deg); }

/* The dropdown itself. Opacity+translate rather than height, so it can be
   transitioned smoothly and is collapsed to ~0ms by the global
   prefers-reduced-motion rule in main.css without a second override here. */
.fbar__panel {
  position: absolute;
  top: calc(100% + 0.375rem);
  left: 0;
  z-index: 50;
  min-width: 240px;
  max-height: min(60vh, 420px);
  overflow-y: auto;
  padding: 0.375rem;
  border-radius: var(--r-md);
  box-shadow: var(--shadow-float);
  display: grid;
  gap: 1px;
  /* Glass, with the opaque fallback first — see the .glass utility in main.css. */
  background: var(--glass-bg-solid);
  border: 1px solid var(--glass-border);
}
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .fbar__panel {
    background: var(--glass-bg);
    -webkit-backdrop-filter: var(--glass-blur);
    backdrop-filter: var(--glass-blur);
  }
}
.fbar__panel[hidden] { display: none; }
.fbar__panel.is-open { animation: fbar-in var(--dur-base) var(--ease-out); }
@keyframes fbar-in { from { opacity: 0; transform: translateY(-4px); } }

.fbar__opt {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 40px;
  padding: 0.375rem 0.625rem;
  border-radius: var(--r-sm);
  color: var(--ink);
  font-size: 0.9375rem;
  cursor: pointer;
}
.fbar__opt:hover { background: var(--cyan-wash); }
.fbar__opt input { accent-color: var(--cyan); flex: 0 0 auto; }
.fbar__opt-icon { display: inline-flex; color: var(--ink-soft); flex: 0 0 auto; }
.fbar__opt:has(input:checked) { background: var(--cyan-wash); font-weight: 600; }

/* ---- price range: a dropdown like Category and Brand, not exposed in the
   bar itself. The panel is a light glass surface (see .fbar__panel), so its
   contents use the same ink/hairline tokens as the Category/Brand options,
   not the white-on-navy colours the bar chrome uses. ---- */
.fbar__panel--price {
  min-width: 270px;
  display: grid;
  gap: 0.75rem;
  padding: 1rem 0.875rem;
}
.fbar__price-out {
  display: block;
  font-size: 0.9375rem;
  font-weight: 700;
  color: var(--ink);
  text-align: center;
}
.fbar__range { position: relative; width: 100%; height: 44px; display: flex; align-items: center; }
.fbar__track {
  position: absolute;
  inset-inline: 0;
  height: 4px;
  border-radius: 2px;
  background: var(--hairline);
}
.fbar__fill {
  position: absolute;
  height: 100%;
  border-radius: 2px;
  background: var(--cyan);
}
.fbar__panel-apply { width: 100%; min-height: 44px; }
/* Both inputs stack on the same track. pointer-events are re-enabled on the
   thumbs only, so whichever handle is under the cursor is the one that drags
   instead of the topmost input swallowing every press. */
.fbar__range input[type="range"] {
  position: absolute;
  inset-inline: 0;
  width: 100%;
  margin: 0;
  background: none;
  pointer-events: none;
  -webkit-appearance: none;
  appearance: none;
  height: 44px;
}
.fbar__range input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  pointer-events: auto;
  width: 18px; height: 18px;
  border-radius: 50%;
  background: #FFFFFF;
  border: 2px solid var(--cyan);
  cursor: grab;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
}
.fbar__range input[type="range"]::-moz-range-thumb {
  pointer-events: auto;
  width: 18px; height: 18px;
  border-radius: 50%;
  background: #FFFFFF;
  border: 2px solid var(--cyan);
  cursor: grab;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
}
.fbar__range input[type="range"]::-moz-range-track { background: none; }

.fbar__go { min-height: 44px; padding-inline: 1.25rem; }
.filterbar .fbar__go { background: var(--cyan); color: var(--navy-deep); }
.filterbar .fbar__go:hover { background: #03B4F5; }
.fbar__clear {
  color: rgba(255, 255, 255, 0.8);
  font-size: 0.875rem;
  text-decoration: underline;
  padding: 0.5rem;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
}
.fbar__clear:hover { color: #FFFFFF; }

/* Wholesale Dealers — far right of the filter bar. margin-left:auto pushes it
   there without a spacer element, and the hairline on its left keeps it from
   reading as a fourth filter control. Cyan-tinted rather than plain white so
   it registers as a destination, not another toggle; #4FC4FA on this navy
   measures 7.4:1. */
.fbar__wholesale {
  display: inline-flex;
  align-items: center;
  gap: 0.4375rem;
  margin-left: auto;
  padding: 0.5rem 0.25rem 0.5rem 0.875rem;
  min-height: 44px;
  border-left: 1px solid rgba(255, 255, 255, 0.18);
  color: #4FC4FA;
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  transition: color var(--dur-base) var(--ease-out);
}
.fbar__wholesale svg { flex: 0 0 auto; opacity: 0.9; }
.fbar__wholesale:hover { color: #FFFFFF; }
.fbar__wholesale:hover svg { opacity: 1; }
/* Stacked layout under 720px: margin-left:auto would strand it on a row of
   its own with a dangling border, so the divider becomes a top rule instead. */
@media (max-width: 719px) {
  .fbar__wholesale {
    margin-left: 0;
    flex: 1 1 100%;
    justify-content: center;
    padding: 0.5rem 0;
    border-left: none;
    border-top: 1px solid rgba(255, 255, 255, 0.18);
  }
}

/* ---- mobile: one "Filters" disclosure instead of three stacked rows ----
   Category, brand and price each claim a full row under 720px (see the block
   below). That is five rows before the first product on a 360px screen, so
   below this breakpoint the three collapse behind .fbar__more and the bar is
   a single row again.

   display:contents is the DESKTOP default: the wrapper adds no box of its own
   there, so .fbar__field / .fbar__go / .fbar__clear stay direct flex items of
   .filterbar__inner and the row lays out exactly as it did before the wrapper
   was introduced — including .fbar__wholesale's margin-left:auto, which is
   measured against that same flex line. */
.fbar__controls { display: contents; }

.fbar__more {
  display: none;    /* mobile-only; the 720px row has space for the real controls */
  align-items: center;
  gap: 0.5rem;
  flex: 1 1 100%;
  min-height: 44px;
  padding: 0.375rem 0.75rem;
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: var(--r-sm);
  background: rgba(255, 255, 255, 0.10);
  color: #FFFFFF;
  font-size: 0.9375rem;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--dur-base) var(--ease-out),
              border-color var(--dur-base) var(--ease-out);
}
.fbar__more:hover { background: rgba(255, 255, 255, 0.18); border-color: rgba(255, 255, 255, 0.4); }
.fbar__more[aria-expanded="true"] { background: rgba(255, 255, 255, 0.2); border-color: var(--cyan); }
/* Pushes the chevron to the far edge, so the button reads as a disclosure
   rather than a submit. */
.fbar__more .fbar__chev { margin-left: auto; }

/* How many filters are actually applied. Only meaningful while the controls
   are collapsed: without it a narrowed-down bar looks identical to a fresh
   one. Rendered only when the count is non-zero (see header.php), so there is
   no "0" state to style. */
.fbar__more-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding-inline: 0.375rem;
  border-radius: 999px;
  background: var(--cyan);
  color: var(--navy-deep);
  font-size: 0.75rem;
  font-weight: 700;
}

/* At 360px the bar stacks: each control (including the Price dropdown's
   toggle) gets a full row rather than being squeezed under the 44px floor.
   The price range widens to fill its panel, which itself goes full-width. */
@media (max-width: 719px) {
  .filterbar__inner { gap: 0.375rem; }
  .fbar__field { flex: 1 1 100%; justify-content: space-between; }
  .fbar__toggle { flex: 1 1 auto; justify-content: space-between; }
  .fbar__value { max-width: none; }
  .fbar__range { flex: 1 1 auto; width: auto; min-width: 120px; }
  .fbar__panel { left: 0; right: 0; min-width: 0; }
  .fbar__go { flex: 1 1 auto; }

  .fbar__more { display: inline-flex; }

  /* The wrapper becomes a real box here so the collapsed state has something
     to hide, and so the controls keep their own gap when open. */
  .fbar__controls {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.375rem;
    flex: 1 1 100%;
  }
  /* Collapsed ONLY when JavaScript is present to reopen it — .has-js is set in
     the head script. With JS off .fbar__more does nothing, so hiding these
     would strand the filters behind a dead button. */
  .has-js .fbar__controls { display: none; }
  .has-js .fbar__controls.is-open { display: flex; }
}

/* ------------------------------------------------------------ homepage -- */

/* Hero slideshow — a deliberate, user-approved exception to design §6 ("no
   auto-rotating carousels"); see CLAUDE.md for the record and JS mitigations
   (slow interval, pause on hover/focus, permanent stop after interaction,
   silent under prefers-reduced-motion). Crossfade via opacity, not a sliding
   transform: an opacity-only transition is what the site-wide
   prefers-reduced-motion rule in main.css already collapses to ~0ms, so
   "no transition under reduced motion" falls out of the existing rule for
   free rather than needing a second, carousel-specific override. */
.slideshow {
  position: relative;
  overflow: hidden;
  border-radius: var(--r-lg);
  border: 1px solid var(--hairline);
  background: var(--surface-raised);
  aspect-ratio: 4 / 3;
}

/* Full-bleed hero: edge to edge, no rounded corners or side border, and no
   section padding above it so it sits flush under the filter bar. The
   horizontal border is kept as a hairline separator from the content below. */
.section--hero { padding-block: 0 clamp(2rem, 1.2rem + 3vw, 3.5rem); }
.slideshow--bleed {
  border-radius: 0;
  border-inline: none;
  border-top: none;
}
@media (min-width: 640px)  { .slideshow { aspect-ratio: 21 / 9; } }
@media (min-width: 900px)  { .slideshow { aspect-ratio: 2.6 / 1; } }

.slideshow__track { position: relative; width: 100%; height: 100%; }

.slideshow__slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-slow) var(--ease-out);
}
.slideshow__slide.is-active { opacity: 1; pointer-events: auto; }
.slideshow__slide a, .slideshow__slide.is-active { display: block; width: 100%; height: 100%; }
.slideshow__slide img { width: 100%; height: 100%; object-fit: cover; }

.slideshow--static .slideshow__slide { position: relative; }

.slideshow__headline {
  position: absolute;
  left: 1rem; right: 1rem; bottom: 1rem;
  padding: 0.5rem 0.75rem;
  border-radius: var(--r-sm);
  background: rgba(26, 24, 71, 0.86);
  color: #FFFFFF;
  font-family: var(--font-display);
  font-size: 1.0625rem;
  width: fit-content;
}

/* Arrows and dots: 44px tap targets, visible against any photo via a solid
   scrim rather than relying on image contrast. */
.slideshow__arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border: none;
  border-radius: 50%;
  background: rgba(26, 24, 71, 0.55);
  color: #FFFFFF;
  cursor: pointer;
  transition: background var(--dur-base) var(--ease-out);
}
.slideshow__arrow:hover, .slideshow__arrow:focus-visible { background: rgba(26, 24, 71, 0.8); }
.slideshow__arrow--prev { left: 0.625rem; }
.slideshow__arrow--next { right: 0.625rem; }

.slideshow__dots {
  position: absolute;
  z-index: 2;
  left: 50%;
  bottom: 0.75rem;
  transform: translateX(-50%);
  display: flex;
  gap: 0.5rem;
  padding: 0.375rem 0.5rem;
  border-radius: 999px;
  background: rgba(26, 24, 71, 0.4);
}
.slideshow__dot {
  width: 44px;
  height: 44px;
  margin: -12px 0;   /* visual dot stays small; tap target stays 44px */
  display: grid;
  place-items: center;
  border: none;
  background: transparent;
  cursor: pointer;
}
.slideshow__dot::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.55);
  transition: background var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
}
.slideshow__dot.is-active::before { background: #FFFFFF; transform: scale(1.25); }

.cat-rail {
  display: flex;
  gap: 0.75rem;
  margin-top: 1rem;
  padding-bottom: 0.5rem;
  scroll-snap-type: x mandatory;
}
.cat-rail__item {
  flex: 0 0 168px;
  scroll-snap-align: start;
  padding: 0.75rem;
  text-decoration: none;
  color: inherit;
  transition: transform var(--dur-slow) var(--ease-out);
}
@media (hover: hover) { .cat-rail__item:hover { transform: translateY(-2px); } }
.cat-rail__media { position: relative; }
.cat-rail__item img { border-radius: var(--r-sm); aspect-ratio: 4 / 3; object-fit: cover; width: 100%; }
.cat-rail__icon {
  position: absolute; left: 0.5rem; bottom: 0.5rem;
  display: grid; place-items: center;
  width: 34px; height: 34px;
  border-radius: 50%;
  background: var(--surface-raised);
  color: var(--navy);
  box-shadow: 0 2px 6px rgba(26, 24, 71, 0.22);
}
/* --navy is already theme-aware (redefined under [data-theme="dark"] in
   main.css), so the icon stays readable against --surface-raised in both
   themes without a separate override here. */
.cat-rail__name { display: block; margin-top: 0.5rem; font-weight: 600; }
.cat-rail__ur   { display: block; font-size: 0.9rem; color: var(--ink-soft); }

/* D. Shop by Price band chips. .chip already gives the 44px tap target and
   theme-aware surface/border; this just lays the row out and stops it
   overflowing at 360px. */
.price-bands {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 1rem;
}
.price-bands__chip {
  text-decoration: none;
  color: var(--ink);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 0.875rem;
}
.price-bands__chip:hover { border-color: var(--cyan); background: var(--cyan-wash); }

.shop-block__card { overflow: hidden; }
.shop-block__card img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; }
.shop-block__body { padding: 1.25rem; display: grid; gap: 0.75rem; }

/* -------------------------------------------------------------- footer -- */

.site-footer {
  margin-top: clamp(2.5rem, 1.5rem + 4vw, 5rem);
  background: var(--navy-deep);
  color: rgba(255, 255, 255, 0.88);
  padding-top: 2.5rem;
}
.site-footer a { color: rgba(255, 255, 255, 0.88); text-decoration: none; }
.site-footer a:hover { color: #FFFFFF; text-decoration: underline; }
.site-footer h3 {
  font-size: 0.8125rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--cyan);
  margin-bottom: 0.625rem;
}
.site-footer .u-muted, .site-footer .u-faint { color: rgba(255, 255, 255, 0.66); }
.site-footer__name { font-size: 1.25rem; margin-bottom: 0.375rem; }
.site-footer__grid {
  display: grid;
  gap: 2rem;
  grid-template-columns: 1fr;
}
@media (min-width: 640px) { .site-footer__grid { grid-template-columns: 1fr 1fr; } }
@media (min-width: 960px) { .site-footer__grid { grid-template-columns: 2fr 1fr 1fr 1.5fr; } }
.site-footer__base {
  margin-top: 2rem;
  padding-block: 1rem;
  border-top: 1px solid rgba(255, 255, 255, 0.14);
}

.plain { list-style: none; display: grid; gap: 0.375rem; }
