/**
 * Barcodes Market — theme component layer (E7).
 *
 * Consumes ONLY the semantic custom properties in tokens.css (var(--bm-*)).
 * No raw colour values are hard-coded here. The single token entry point is
 * tokens.css (visual-designer handoff v2.1); when the designer updates tokens,
 * this file's colour behaviour follows automatically.
 *
 * Naming: every theme-owned class is prefixed `bm-`. Bootstrap 5 is the base
 * grid/utility system (OC4 default, v5.3.8 — RTL logical utilities available).
 *
 * RTL: all directional layout uses logical properties (margin-inline-*,
 * padding-inline-*, inset-inline-*, text-align: end, etc.) so Arabic
 * (dir=rtl) mirrors automatically. Directional icons get `.bm-icon--dir`
 * (flipped by tokens.css). Never use physical left/right in layout rules.
 */

/* ============================================================ base */
body {
  font-family: var(--bm-font-body);
  font-size: var(--bm-fs-body);
  line-height: var(--bm-lh-body);
  color: var(--bm-ink);
  background-color: var(--bm-bg);
}

a {
  color: var(--bm-cyan-text);
  text-decoration: none;
}

a:hover {
  color: var(--bm-navy);
}

h1, h2, h3, h4, h5, h6 {
  color: var(--bm-navy);
  font-weight: var(--bm-fw-display);
}

/* ============================================================ layout */
.bm-container {
  width: 100%;
  max-width: var(--bm-container);
  margin-inline: auto;
  padding-inline: var(--bm-space-6);
}

@media (max-width: 767.98px) {
  .bm-container { padding-inline: var(--bm-space-4); }
}

/* ============================================================ icons */
.bm-icon {
  width: 1em;
  height: 1em;
  display: inline-block;
  vertical-align: -0.125em;
  fill: none;
}

.bm-icon--lg { font-size: 1.5rem; }

/* ============================================================ typography */
.bm-kicker {
  display: inline-block;
  font-size: var(--bm-fs-kicker);
  font-weight: var(--bm-fw-bold);
  letter-spacing: var(--bm-ls-kicker);
  text-transform: uppercase;
  color: var(--bm-cyan-text);
}

.bm-brand-line {
  font-size: var(--bm-fs-micro);
  font-weight: var(--bm-fw-bold);
  letter-spacing: var(--bm-ls-brand);
  text-transform: uppercase;
  color: var(--bm-muted);
}

.bm-latin,
.bm-ltr { direction: ltr; unicode-bidi: isolate; }

.bm-link-arrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 13.5px;
  font-weight: var(--bm-fw-semibold);
  color: var(--bm-cyan-text);
}

.bm-link-arrow .bm-icon { font-size: 17px; color: var(--bm-cyan-text); }

.bm-link-arrow:hover { color: var(--bm-navy); }

/* ============================================================ utility bar */
.bm-utility {
  background-color: var(--bm-navy-deep);
  color: var(--bm-on-dark-72);
  height: var(--bm-h-utility);
  font-size: var(--bm-fs-sm-2);
}

.bm-utility a {
  color: var(--bm-on-dark-72);
}

.bm-utility a:hover { color: var(--bm-on-dark); }

.bm-utility .bm-lang-switch {
  display: inline-flex;
  align-items: center;
  gap: var(--bm-space-3);
}

.bm-utility .bm-lang-switch a {
  font-size: 12.5px;
  font-weight: var(--bm-fw-semibold);
  color: rgba(255, 255, 255, 0.6);
  padding: 0;
}

.bm-utility .bm-lang-switch a.is-active {
  color: #fff;
  font-weight: var(--bm-fw-bold);
  border-bottom: 2.2px solid var(--bm-cyan);
  line-height: 1.4;
}

.bm-utility .bm-utility-divider {
  width: 1px;
  height: 16px;
  background: rgba(255, 255, 255, 0.2);
  margin-inline: var(--bm-space-3);
}

/* ============================================================ header */
.bm-header {
  background-color: var(--bm-surface);
  height: var(--bm-h-header);
  border-bottom: 1px solid var(--bm-border);
}

.bm-header .bm-logo {
  display: inline-block;
  line-height: 0;
}

.bm-header .bm-logo img {
  height: 44px;
  width: auto;
}

.bm-header .bm-icon-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12.2px;
  font-weight: var(--bm-fw-semibold);
  color: var(--bm-navy);
  white-space: nowrap;
}

.bm-header .bm-icon-link .bm-icon { font-size: 19px; }

.bm-header .bm-cart-count {
  position: absolute;
  top: -6px;
  inset-inline-end: -8px;
  min-width: 17px;
  height: 17px;
  border-radius: var(--bm-radius-pill);
  background: var(--bm-cyan);
  color: var(--bm-navy);
  font-size: 10px;
  font-weight: var(--bm-fw-bold);
  line-height: 17px;
  text-align: center;
  padding-inline: 4px;
}

/* ============================================================ category nav */
.bm-nav {
  background-color: var(--bm-navy);
  height: var(--bm-h-nav);
  color: #fff;
}

.bm-nav .nav-link {
  color: rgba(255, 255, 255, 0.92);
  font-size: var(--bm-fs-nav);
  font-weight: var(--bm-fw-semibold);
  padding-inline: 0;
  margin-inline-end: 30px;
}

.bm-nav .nav-link:hover,
.bm-nav .nav-link:focus-visible {
  color: var(--bm-cyan-lt);
}

.bm-nav .bm-all-categories {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 34px;
  padding-inline: 14px;
  border-radius: var(--bm-radius-tile);
  background: rgba(255, 255, 255, 0.1);
  border: 1.3px solid rgba(255, 255, 255, 0.9);
  color: #fff;
  font-size: var(--bm-fs-nav);
  font-weight: var(--bm-fw-semibold);
}

.bm-nav .bm-all-categories .bm-icon--chevron { color: var(--bm-cyan-lt); }

/* ============================================================ mega menu */
.bm-mega-panel {
  border: 1px solid var(--bm-border);
  border-radius: var(--bm-radius-card);
  box-shadow: var(--bm-shadow-float);
  padding: var(--bm-space-4);
  min-width: 560px;
}

.bm-mega-panel .dropdown-item {
  padding-inline: var(--bm-space-2);
  border-radius: var(--bm-radius-btn);
  color: var(--bm-ink);
  font-size: var(--bm-fs-body);
}

.bm-mega-panel .dropdown-item:hover {
  background-color: var(--bm-tint);
  color: var(--bm-cyan-text);
}

.bm-mega-panel__footer {
  margin-block-start: var(--bm-space-3);
  padding-block-start: var(--bm-space-3);
  border-block-start: 1px solid var(--bm-border);
}

.bm-mega-panel__footer a {
  font-weight: var(--bm-fw-semibold);
  color: var(--bm-cyan-text);
}

/* ============================================================ service promises */
.bm-promises {
  background-color: var(--bm-surface);
  border-block-start: 1px solid var(--bm-border);
}

.bm-promise {
  display: flex;
  align-items: center;
  gap: var(--bm-space-3);
}

.bm-promise__icon {
  width: 44px;
  height: 44px;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--bm-radius-tile);
  background-color: var(--bm-tint);
  color: var(--bm-cyan-text);
  font-size: 20px;
}

.bm-promise__title {
  font-weight: var(--bm-fw-bold);
  color: var(--bm-navy);
  font-size: var(--bm-fs-body);
}

.bm-promise__text {
  font-size: var(--bm-fs-sm-2);
  color: var(--bm-muted);
}

/* ============================================================ footer */
.bm-footer {
  background-image: linear-gradient(180deg, var(--bm-navy-deep), var(--bm-navy));
  color: var(--bm-on-dark-72);
  font-size: var(--bm-fs-sm);
}

.bm-footer h5 {
  color: #fff;
  font-size: 12.3px;
  font-weight: var(--bm-fw-bold);
  letter-spacing: 1.6px;
  text-transform: uppercase;
  margin-block-end: var(--bm-space-4);
}

.bm-footer a {
  color: var(--bm-on-dark-62);
  line-height: 2.2;
}

.bm-footer a:hover {
  color: #fff;
  text-decoration: underline;
  text-decoration-color: var(--bm-cyan-lt);
}

.bm-footer .bm-footer-brand-desc {
  color: rgba(255, 255, 255, 0.7);
  line-height: var(--bm-lh-small);
}

.bm-footer .bm-footer-domain {
  color: var(--bm-cyan-lt);
  font-weight: var(--bm-fw-semibold);
}

.bm-footer .bm-footer-logistics {
  color: rgba(255, 255, 255, 0.62);
  font-weight: var(--bm-fw-semibold);
  font-size: var(--bm-fs-sm-2);
}

.bm-footer .bm-footer-bottom {
  color: rgba(255, 255, 255, 0.5);
  font-size: 11.3px;
}

.bm-footer .bm-footer-divider {
  border-color: rgba(255, 255, 255, 0.14);
}

/* ============================================================ dark band */
.bm-band--dark {
  background-image: linear-gradient(135deg, var(--bm-navy), var(--bm-navy-2));
  color: var(--bm-on-dark-72);
}

.bm-band--dark h1,
.bm-band--dark h2,
.bm-band--dark h3 { color: #fff; }

/* ============================================================ warm CodeMark zone */
.bm-band--warm {
  background-color: var(--bm-warm);
  border-block: 1px solid var(--bm-warm-border);
}

/* ============================================================ section primitives */
.bm-section {
  padding-block: var(--bm-section-pad-y);
}

.bm-section--hairline {
  border-block-start: 1px solid var(--bm-border);
}

/* ============================================================ product card */
.bm-card {
  position: relative;
  background-color: var(--bm-surface);
  border: 1px solid var(--bm-border);
  border-radius: var(--bm-radius-card);
  box-shadow: var(--bm-shadow-card);
  overflow: hidden;
  transition: border-color .15s, box-shadow .15s;
}

.bm-card:hover {
  border-color: var(--bm-cyan);
  box-shadow: var(--bm-shadow-float);
}

.bm-card__img {
  --bm-card-img-h: 170px;          /* well height — reused to cap the thumb */
  margin: var(--bm-space-4);
  margin-block-end: var(--bm-space-2);
  height: var(--bm-card-img-h);
  background-color: var(--bm-img);
  border-radius: var(--bm-radius-img);
  display: flex;
  align-items: center;
  justify-content: center;
}

/* E9 — the OpenCart thumb is square (250×250) while this well is 170px tall, so
   it overflowed ~40px per side and the card's `overflow: hidden` sliced 16–23px
   off the top (3px of which was the product itself: README-prepare-product-images
   §5.3). Cap it to the well. `display: block` also drops the inline-baseline
   descent, which would otherwise push the box back out by ~2px.               */
.bm-card__img img {
  display: block;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: var(--bm-card-img-h);
}

.bm-card__badge {
  position: absolute;
  top: var(--bm-space-4);
  display: inline-flex;
  align-items: center;
  height: var(--bm-h-chip);
  padding-inline: 10px;
  border-radius: var(--bm-radius-pill);
  font-size: var(--bm-fs-micro);
  font-weight: var(--bm-fw-bold);
}

.bm-card__badge--identity { inset-inline-start: 26px; background: var(--bm-cyan); color: var(--bm-navy); }
.bm-card__badge--promo    { inset-inline-end: 18px; background: var(--bm-orange-strong); color: #fff; }

.bm-card__body {
  padding-inline: var(--bm-space-4);
  padding-block-end: var(--bm-space-4);
}

.bm-card__topline {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-block-end: var(--bm-space-2);
}

.bm-card__model {
  font-size: var(--bm-fs-model);
  font-weight: var(--bm-fw-bold);
  color: var(--bm-ink);
  line-height: 1.3;
}

.bm-card__sku {
  font-family: var(--bm-font-mono);
  font-size: var(--bm-fs-micro-2);
  color: var(--bm-muted);
}

.bm-card__spec {
  font-size: 11.8px;
  color: var(--bm-muted);
}

.bm-card__hairline {
  border-block-start: 1px solid var(--bm-border);
  margin-block: var(--bm-space-3);
}

.bm-card__price {
  font-size: var(--bm-fs-price);
  font-weight: var(--bm-fw-display);
  color: var(--bm-navy);
}

.bm-card__price-list {
  font-size: 12.5px;
  color: var(--bm-muted);
  text-decoration: line-through;
}

.bm-card__cta {
  display: flex;
  align-items: center;
  gap: var(--bm-space-2);
  margin-block-start: var(--bm-space-3);
}

/* stock dot chip */
.bm-stock { display: inline-flex; align-items: center; gap: 6px; font-size: var(--bm-fs-micro); font-weight: var(--bm-fw-bold); }
.bm-stock::before { content: ""; width: 3.4px; height: 3.4px; border-radius: 50%; background: currentColor; }
.bm-stock--in   { color: var(--bm-success-strong); }
.bm-stock--low  { color: var(--bm-orange-on-tint); }
.bm-stock--preorder { color: var(--bm-muted); }
.bm-stock--out  { color: var(--bm-danger); }
/* E9-T5 — card chip for a status that is shippable but not on the shelf
   (OC default "2-3 Days", or any status the workbench adds later). Neutral:
   it used to render as the green --in state. */
.bm-stock--delay { color: var(--bm-muted); }

/* ============================================================ barcode motif */
.bm-barcode {
  display: flex;
  align-items: stretch;
  gap: 5px;
  height: 40px;
  pointer-events: none;
}

.bm-barcode i {
  width: var(--w, 4px);
  height: 100%;
  background: currentColor;
}

.bm-barcode--light { color: var(--bm-navy-05); }
.bm-barcode--dark  { color: var(--bm-on-dark-05); }

/* ============================================================ buttons (extra) */
.bm-btn--icon {
  width: var(--bm-h-btn);
  padding-inline: 0;
}

.bm-btn--icon-lg {
  width: var(--bm-h-btn-lg);
  padding-inline: 0;
}

/* danger outline (cart remove) — complements tokens.css solid variants */
.bm-btn--outline-danger {
  border: 1.5px solid var(--bm-danger);
  color: var(--bm-danger);
  background: transparent;
}

.bm-btn--outline-danger:hover,
.bm-btn--outline-danger:focus-visible {
  background: var(--bm-danger);
  color: #fff;
}

.bm-btn--outline-danger .bm-icon { color: currentColor; }

/* ============================================================ focus */
.bm-header a:focus-visible,
.bm-footer a:focus-visible,
.bm-nav a:focus-visible {
  outline: var(--bm-border-w-focus) solid var(--bm-cyan);
  outline-offset: 2px;
  box-shadow: var(--bm-focus-ring-dark);
}

/* ============================================================ RTL helpers */
/* long compounded words (ru) must wrap, not overflow */
.bm-break-word {
  overflow-wrap: break-word;
  word-break: break-word;
  -webkit-hyphens: auto;
  hyphens: auto;
}

/* Arabic never letter-spaces or transforms (tokens.css already resets these
   under [dir=rtl]); keep the margin/inset pairs logical above so no extra
   mirror rules are needed. */

/* ============================================================ hero */
.bm-hero {
  /* E11: 64/48 → 48/40 so hero → solutions reads 40+40 = 80px like every
     other band join. The hero is the first band under the nav, so the extra
     16px on top was pure offset, not emphasis. */
  padding-block: var(--bm-space-9) var(--bm-space-8);
}

.bm-hero__chip {
  display: inline-flex;
  align-items: center;
  height: 30px;
  padding-inline: 12px;
  border-radius: var(--bm-radius-pill);
  background: var(--bm-tint);
  color: var(--bm-cyan-text);
  font-size: 10.5px;
  font-weight: var(--bm-fw-bold);
}

.bm-hero__title {
  font-size: var(--bm-fs-h1);
  font-weight: var(--bm-fw-display);
  letter-spacing: var(--bm-ls-display);
  line-height: var(--bm-lh-display);
  color: var(--bm-navy);
  margin-block: var(--bm-space-4);
}

.bm-hero__title .bm-accent { color: var(--bm-cyan-text); }

.bm-hero__sub {
  font-size: var(--bm-fs-body-lg);
  line-height: var(--bm-lh-body);
  color: var(--bm-muted);
  max-width: 660px;
}

.bm-hero__cta {
  display: flex;
  gap: var(--bm-space-4);
  margin-block-start: var(--bm-space-7);
}

.bm-hero__trust {
  display: flex;
  align-items: center;
  gap: 34px;
  margin-block-start: var(--bm-space-5);
}

.bm-hero__trust span {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: var(--bm-fs-sm);
  font-weight: var(--bm-fw-semibold);
  color: var(--bm-ink);
}

.bm-hero__trust .bm-icon { color: var(--bm-success); }

.bm-hero__collage {
  position: relative;
  background: var(--bm-surface);
  border: 1.2px solid var(--bm-border);
  border-radius: var(--bm-radius-hero);
  box-shadow: var(--bm-shadow-float);
  height: 380px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.bm-hero__collage-ring {
  width: 236px;
  height: 236px;
  border-radius: 50%;
  background: var(--bm-tint);
  display: flex;
  align-items: center;
  justify-content: center;
}

.bm-hero__collage-ring .bm-icon {
  font-size: 96px;
  color: var(--bm-navy);
}

.bm-hero__scanline {
  position: absolute;
  inset-inline: 40px;
  top: 50%;
  border-top: 2px dashed var(--bm-cyan);
  opacity: .5;
}

.bm-hero__barcode {
  position: absolute;
  inset-inline-end: 40px;
  bottom: 24px;
}

/* ============================================================ data-loop strip */
.bm-loop {
  background: var(--bm-surface);
  border-top: 1px solid var(--bm-border);
  padding-block: var(--bm-space-8);
}

.bm-loop__node {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--bm-space-2);
}

.bm-loop__node-circle {
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: var(--bm-tint);
  display: flex;
  align-items: center;
  justify-content: center;
}

.bm-loop__node-circle .bm-icon {
  font-size: 26px;
  color: var(--bm-navy);
}

.bm-loop__node-name {
  font-size: 14.5px;
  font-weight: var(--bm-fw-display);
  letter-spacing: 1.4px;
  color: var(--bm-navy);
}

.bm-loop__node-sub {
  font-size: 11.5px;
  color: var(--bm-muted);
}

/* ============================================================ brand wall */
.bm-brand-wall {
  padding-block: var(--bm-section-pad-y);
}

.bm-brand-wall__header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  margin-block-end: var(--bm-space-6);
}

.bm-brand-tile {
  height: 92px;
  background: var(--bm-surface);
  border: 1px solid var(--bm-border);
  border-radius: var(--bm-radius-tile);
  box-shadow: var(--bm-shadow-card);
  display: flex;
  align-items: center;
  justify-content: center;
  padding-inline: var(--bm-space-3);
}

.bm-brand-tile span {
  font-size: 17px;
  font-weight: var(--bm-fw-display);
  letter-spacing: 2.4px;
  text-transform: uppercase;
  color: var(--bm-brand-gray);
}

/* E9 — official brand mark (image/brands/<slug>-on-{light,dark}.svg, viewBox
   176×64). Sized to the same optical weight as the 17px/800 text tile it
   replaces (~60% of the 154px tile); max-width keeps it inside the tile on the
   3-up mobile grid and in RTL. */
.bm-brand-tile__logo {
  display: block;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 34px;
}

/* Dark asset is only correct on a navy surface — flip both together. */
.bm-brand-tile--on-dark { background: var(--bm-navy); border-color: var(--bm-navy); }
.bm-brand-tile--on-dark span { color: var(--bm-cyan-lt); }

/* Text fallback: rendered only when the tile has no bundled logo, or when the
   logo fails to load at runtime (the <img> hooks its own `onerror`). */
.bm-brand-tile__fallback { display: none; }
.bm-brand-tile--fallback .bm-brand-tile__logo { display: none; }
.bm-brand-tile--fallback .bm-brand-tile__fallback { display: inline; }

.bm-brand-tile--codemark {
  position: relative;
  background: var(--bm-navy);
  border-color: var(--bm-navy);
  flex-direction: column;
  gap: 6px;
}

.bm-brand-tile--codemark img { height: 24px; width: auto; }

.bm-brand-tile--codemark .bm-own-brand {
  position: absolute;
  top: -8px;
  inset-inline-start: 14px;
  height: 20px;
  padding-inline: 8px;
  border-radius: var(--bm-radius-pill);
  background: var(--bm-cyan);
  color: var(--bm-navy);
  font-size: 9.5px;
  font-weight: var(--bm-fw-bold);
  line-height: 20px;
  letter-spacing: 1px;
}

.bm-brand-tile--codemark .bm-own-caption {
  font-size: 9.5px;
  color: var(--bm-cyan-lt);
}

/* ============================================================ industry solutions */
.bm-solutions {
  padding-block: var(--bm-section-pad-y);
  border-top: 1px solid var(--bm-border);
}

.bm-solution-card {
  height: 100%;
  background: var(--bm-surface);
  border: 1px solid var(--bm-border);
  border-radius: var(--bm-radius-card);
  box-shadow: var(--bm-shadow-card);
  padding: var(--bm-space-6);
  display: flex;
  flex-direction: column;
  transition: border-color .15s, box-shadow .15s;
}

.bm-solution-card:hover {
  border-color: var(--bm-cyan);
  box-shadow: var(--bm-shadow-float);
}

.bm-solution-card__icon {
  width: 54px;
  height: 54px;
  border-radius: 50%;
  background: var(--bm-tint);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-block-end: var(--bm-space-4);
}

.bm-solution-card__icon .bm-icon {
  font-size: 28px;
  color: var(--bm-navy);
}

.bm-solution-card__title {
  font-size: var(--bm-fs-h3);
  font-weight: var(--bm-fw-bold);
  color: var(--bm-navy);
  margin-block-end: var(--bm-space-2);
}

.bm-solution-card__desc {
  font-size: 12.3px;
  color: var(--bm-muted);
  flex-grow: 1;
}

.bm-solution-card__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-block: var(--bm-space-4);
}

.bm-solution-card__tag {
  height: 25px;
  padding-inline: 10px;
  border-radius: var(--bm-radius-tile);
  background: var(--bm-gray);
  border: 1px solid var(--bm-border);
  font-size: 10.5px;
  font-weight: var(--bm-fw-semibold);
  color: var(--bm-ink);
  line-height: 23px;
}

/* ============================================================ why band */
.bm-why {
  /* E11: 80/80 → 48/48. It is the page's one full-bleed dark band, so it keeps
     a touch more air than the 40px sections: brand wall(40) + 48 = 88px above
     and 48 + codemark(32) = 80px below. 160px of band padding for a 3-column
     icon row was the single biggest waste on the home page. */
  padding-block: var(--bm-space-9);
}

.bm-why-col {
  display: flex;
  flex-direction: column;
  gap: var(--bm-space-3);
}

.bm-why-col__icon {
  width: 60px;
  height: 60px;
  border-radius: 50%;
  background: var(--bm-on-dark-08);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-block-end: var(--bm-space-2);
}

.bm-why-col__icon .bm-icon {
  font-size: 30px;
  color: var(--bm-cyan-lt);
}

.bm-why-col__title {
  font-size: 16.5px;
  font-weight: var(--bm-fw-bold);
  color: #fff;
}

.bm-why-col__body {
  font-size: 12.3px;
  line-height: 1.8;
  color: var(--bm-on-dark-72);
}

/* ============================================================ CodeMark zone */
.bm-codemark {
  padding-block: var(--bm-space-7);
}

.bm-codemark__logo { height: 34px; width: auto; }

.bm-codemark__chip {
  display: inline-flex;
  height: 26px;
  padding-inline: 10px;
  border-radius: var(--bm-radius-pill);
  background: var(--bm-cyan);
  color: var(--bm-navy);
  font-size: 9.5px;
  font-weight: var(--bm-fw-bold);
  letter-spacing: 1px;
  line-height: 26px;
}

.bm-codemark__copy {
  font-size: 14.5px;
  color: var(--bm-ink);
}

.bm-codemark__copy-muted {
  font-size: 12px;
  color: var(--bm-muted);
}

/* ============================================================ quote CTA */
.bm-quote-cta {
  padding-block: var(--bm-space-9);
  text-align: center;
}

.bm-quote-cta__title {
  font-size: var(--bm-fs-h2);
  font-weight: var(--bm-fw-display);
  color: var(--bm-navy);
}

.bm-quote-cta__sub {
  font-size: 13.5px;
  color: var(--bm-muted);
  margin-block: var(--bm-space-3) var(--bm-space-6);
}

.bm-quote-cta__actions {
  display: flex;
  justify-content: center;
  gap: var(--bm-space-4);
}

/* ============================================================ payment chips */
.bm-payment-chip {
  display: inline-flex;
  align-items: center;
  height: 30px;
  padding-inline: 10px;
  border: 1px solid rgba(255, 255, 255, 0.45);
  border-radius: var(--bm-radius-btn);
  color: rgba(255, 255, 255, 0.6);
  font-size: 11px;
  font-weight: var(--bm-fw-semibold);
}

/* ============================================================ promo band (banner module) */
/* Rendered by the bm override of the core banner module
   (template/extension/opencart/module/banner.twig, E9-T4). Sits inside the
   host section's .bm-container, so it adds no container of its own.
   White title on --bm-navy = 15.39:1; the media well is --bm-surface so the
   white padding OC's resizer adds around aspect-preserved product shots is
   invisible. */
.bm-promo__band {
  margin-block-end: var(--bm-space-9);
}

.bm-promo__card {
  display: flex;
  align-items: center;
  gap: var(--bm-space-5);
  height: 100%;
  padding: var(--bm-space-5);
  background: linear-gradient(135deg, var(--bm-navy) 0%, var(--bm-navy-2) 100%);
  border-radius: var(--bm-radius-card);
  text-decoration: none;
  overflow: hidden;
}

.bm-promo__card--link {
  transition: box-shadow .15s, transform .15s;
}

.bm-promo__card--link:hover {
  box-shadow: var(--bm-shadow-float);
  transform: translateY(-2px);
}

.bm-promo__card--link:focus-visible {
  outline: 2px solid var(--bm-cyan);
  outline-offset: 3px;
}

.bm-promo__media {
  flex: 0 0 auto;
  width: 150px;
  height: 150px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background-color: var(--bm-surface);
  border-radius: var(--bm-radius-img);
}

.bm-promo__media img {
  display: block;
  max-width: 100%;
  max-height: 100%;
}

.bm-promo__copy {
  min-width: 0;
}

.bm-promo__title {
  display: block;
  font-size: var(--bm-fs-h3);
  font-weight: var(--bm-fw-display);
  line-height: 1.3;
  color: var(--bm-on-dark);
}

/* ============================================================ responsive */
@media (max-width: 991.98px) {
  .bm-hero__collage { height: 260px; }
}

@media (max-width: 575.98px) {
  .bm-hero__collage { display: none; }
  .bm-hero__trust { flex-wrap: wrap; gap: var(--bm-space-3); }
  .bm-hero__cta { flex-direction: column; }
}

/* ============================================================ breadcrumb */
.bm-breadcrumb {
  margin-block: var(--bm-space-4);
  font-size: 12.3px;
  background: transparent;
  padding: 0;
}

.bm-breadcrumb .breadcrumb-item + .breadcrumb-item::before {
  content: "/";
  color: var(--bm-muted);
}

.bm-breadcrumb a { color: var(--bm-cyan-text); }
.bm-breadcrumb .active { color: var(--bm-muted); }

/* ============================================================ inputs */
.bm-input,
.form-select.bm-input,
.form-control.bm-input {
  border: var(--bm-border-w-input) solid var(--bm-border);
  border-radius: var(--bm-radius-btn);
  height: var(--bm-h-input);
  color: var(--bm-ink);
}

.bm-input:focus,
.form-select.bm-input:focus,
.form-control.bm-input:focus {
  border-color: var(--bm-cyan);
  box-shadow: var(--bm-focus-ring);
  outline: none;
}

/* ============================================================ facet sidebar (PLP) */
.bm-facet-card {
  background: var(--bm-surface);
  border: 1px solid var(--bm-border);
  border-radius: var(--bm-radius-card);
  overflow: hidden;
}

.bm-facet-card__title {
  font-size: 14px;
  font-weight: var(--bm-fw-bold);
  color: var(--bm-navy);
  padding: var(--bm-space-3) var(--bm-space-4);
  border-bottom: 1px solid var(--bm-border);
}

.bm-facet-card__list {
  padding: var(--bm-space-2) 0;
}

.bm-facet-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--bm-space-3);
  min-height: 28px;
  padding: 6px var(--bm-space-4);
  font-size: 12.5px;
  color: var(--bm-ink);
  text-decoration: none;
}

.bm-facet-row:hover {
  background: var(--bm-gray);
  color: var(--bm-ink);
}

.bm-facet-row:focus-visible {
  outline: var(--bm-border-w-focus) solid var(--bm-cyan);
  outline-offset: -2px;
}

.bm-facet-row--own {
  font-weight: var(--bm-fw-bold);
  border-top: 1px solid var(--bm-border);
  margin-top: var(--bm-space-2);
}

.bm-facet-row__label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.bm-facet-row__count {
  font-size: 11.5px;
  color: var(--bm-muted);
}

.bm-chip--mini {
  height: 17px;
  padding-inline: 6px;
  font-size: 9px;
  letter-spacing: 0.4px;
  border-radius: var(--bm-radius-pill);
  background: var(--bm-cyan);
  color: var(--bm-navy);
  text-transform: uppercase;
}

.bm-chip--stock-preorder { background: var(--bm-gray); color: var(--bm-muted); }

/* ============================================================ gallery (PDP) */
.bm-gallery__main {
  background: var(--bm-img);
  border-radius: var(--bm-radius-card);
  padding: var(--bm-space-7);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-block-end: var(--bm-space-4);
}

.bm-gallery__main img {
  max-width: 100%;
  max-height: 460px;
  width: auto;
}

.bm-gallery__thumbs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--bm-space-3);
}

.bm-gallery__thumb {
  width: 88px;
  height: 88px;
  background: var(--bm-img);
  border-radius: var(--bm-radius-img);
  border: 2px solid transparent;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.bm-gallery__thumb:hover,
.bm-gallery__thumb:focus-visible {
  border-color: var(--bm-cyan);
}

.bm-gallery__thumb img { max-width: 100%; max-height: 100%; }

/* ============================================================ PDP info */
.bm-pdp__title {
  font-size: 28px;
  font-weight: var(--bm-fw-display);
  color: var(--bm-navy);
  line-height: 1.25;
  margin-block-end: var(--bm-space-2);
}

.bm-pdp__sku {
  font-family: var(--bm-font-mono);
  font-size: 11px;
  color: var(--bm-muted);
  margin-block-end: var(--bm-space-4);
}

.bm-pdp__price {
  font-size: var(--bm-fs-price-lg);
  font-weight: var(--bm-fw-display);
  color: var(--bm-navy);
}

.bm-pdp__price-list {
  font-size: 14px;
  color: var(--bm-muted);
  text-decoration: line-through;
}

.bm-pdp__vat {
  font-size: 11.5px;
  color: var(--bm-muted);
}

.bm-pdp__actions {
  display: flex;
  align-items: center;
  gap: var(--bm-space-3);
  margin-block-start: var(--bm-space-5);
}

.bm-qty {
  display: flex;
  align-items: center;
}

.bm-qty .form-control {
  width: 64px;
  height: var(--bm-h-btn-lg);
  text-align: center;
  border: var(--bm-border-w-input) solid var(--bm-border);
  border-radius: var(--bm-radius-btn);
  color: var(--bm-ink);
  font-family: var(--bm-font-mono);
}

.bm-pdp__trust {
  display: flex;
  flex-wrap: wrap;
  gap: var(--bm-space-4);
  margin-block-start: var(--bm-space-5);
  padding-block-start: var(--bm-space-5);
  border-block-start: 1px solid var(--bm-border);
}

.bm-pdp__trust span {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 12.3px;
  font-weight: var(--bm-fw-semibold);
  color: var(--bm-ink);
}

.bm-pdp__trust .bm-icon { color: var(--bm-success); }

.bm-pdp__logistics {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin-block-start: var(--bm-space-4);
  padding: var(--bm-space-3) var(--bm-space-4);
  background: var(--bm-gray);
  border-radius: var(--bm-radius-tile);
  font-size: 12px;
  color: var(--bm-muted);
}

.bm-pdp__logistics .bm-icon { color: var(--bm-cyan); margin-block-start: 2px; }

.bm-pdp__bulk {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-block-start: var(--bm-space-3);
  font-size: 12.5px;
  color: var(--bm-ink);
}

.bm-pdp__bulk .bm-icon { color: var(--bm-orange-strong); }

.bm-pdp__bulk .bm-link {
  font-weight: var(--bm-fw-bold);
  color: var(--bm-cyan-text);
  text-decoration: none;
}

.bm-pdp__bulk .bm-link:hover { text-decoration: underline; }

/* ============================================================ tabs */
.bm-tabs {
  border-bottom: 1px solid var(--bm-border);
  gap: var(--bm-space-6);
}

.bm-tabs .nav-link {
  border: none;
  color: var(--bm-muted);
  font-weight: var(--bm-fw-semibold);
  font-size: var(--bm-fs-body);
  padding-inline: 0;
  padding-block: var(--bm-space-3);
}

.bm-tabs .nav-link.active {
  color: var(--bm-navy);
  font-weight: var(--bm-fw-bold);
  border-bottom: 2px solid var(--bm-cyan);
  background: transparent;
}

.bm-tabs__content {
  padding-block: var(--bm-space-6);
  font-size: var(--bm-fs-body);
  color: var(--bm-ink);
}

/* ============================================================ table */
.bm-table {
  border-collapse: separate;
  border-spacing: 0;
}

.bm-table thead th {
  background: var(--bm-tint-navy);
  color: var(--bm-navy);
  font-size: 11px;
  font-weight: var(--bm-fw-bold);
  border: none;
  border-radius: var(--bm-radius-tile);
}

.bm-table tbody td {
  font-size: var(--bm-fs-sm-2);
  color: var(--bm-ink);
  border-bottom: 1px solid var(--bm-border);
  vertical-align: middle;
}

.bm-table tbody tr:nth-child(even) td { background: var(--bm-gray); }

@media (max-width: 767.98px) {
  .bm-pdp__actions { flex-wrap: wrap; }
  .bm-pdp__actions .flex-grow-1 { width: 100%; }
}

/* ============================================================
   Bootstrap 5 → Barcodes Market mapping (core OC4 components).
   Loaded after bootstrap.css so BM tokens win. Keeps checkout /
   account sub-templates on-brand without overriding each one. */
.btn-primary {
  background-color: var(--bm-navy);
  border-color: var(--bm-navy);
}

.btn-primary:hover,
.btn-primary:focus-visible {
  background-color: var(--bm-navy-2);
  border-color: var(--bm-navy-2);
}

.btn-outline-primary {
  color: var(--bm-navy);
  border-color: var(--bm-navy);
}

.btn-outline-primary:hover {
  background-color: var(--bm-navy);
  border-color: var(--bm-navy);
  color: #fff;
}

.btn-danger {
  background-color: var(--bm-danger);
  border-color: var(--bm-danger);
}

.bg-primary { background-color: var(--bm-navy) !important; }
.text-primary { color: var(--bm-cyan-text) !important; }

.nav-pills .nav-link.active {
  background-color: var(--bm-navy);
}

.pagination .page-link { color: var(--bm-navy); }
.pagination .active > .page-link {
  background-color: var(--bm-navy);
  border-color: var(--bm-navy);
  color: #fff;
}

.form-control:focus,
.form-select:focus {
  border-color: var(--bm-cyan);
  box-shadow: var(--bm-focus-ring);
}

/* ============================================================ category entry tiles */
.bm-categories {
  padding-block: var(--bm-section-pad-y);
}

.bm-category-tile {
  height: 100%;
  background: var(--bm-surface);
  border: 1px solid var(--bm-border);
  border-radius: var(--bm-radius-card);
  padding: var(--bm-space-5) var(--bm-space-6);
  transition: border-color var(--bm-trans, .15s ease), box-shadow var(--bm-trans, .15s ease);
}

.bm-category-tile:hover {
  border-color: var(--bm-cyan);
  box-shadow: var(--bm-shadow-float);
}

.bm-category-tile__title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--bm-space-3);
  font-size: 17px;
  font-weight: var(--bm-fw-bold);
  color: var(--bm-navy);
  text-decoration: none;
  margin-bottom: var(--bm-space-4);
}

.bm-category-tile__title:hover { color: var(--bm-cyan-text); }

.bm-category-tile__title .bm-icon {
  color: var(--bm-cyan-text);
  transition: transform var(--bm-trans, .15s ease);
}

.bm-category-tile:hover .bm-category-tile__title .bm-icon { transform: translateX(3px); }

[dir="rtl"] .bm-category-tile:hover .bm-category-tile__title .bm-icon { transform: translateX(-3px); }

.bm-category-tile__children {
  list-style: none;
  margin: 0;
  padding: 0;
}

.bm-category-tile__children li + li {
  margin-top: var(--bm-space-2);
}

.bm-category-tile__children a {
  font-size: 13px;
  color: var(--bm-ink);
  text-decoration: none;
}

.bm-category-tile__children a:hover { color: var(--bm-cyan-text); text-decoration: underline; }

.bm-category-tile__empty {
  font-size: 13px;
  color: var(--bm-muted);
  margin: 0;
}

/* ============================================================ ru long-word tiered sizing */
/* Long Cyrillic compounds («Промышленные», «штрихкодовые») overflow at EN
   display sizes. Step display type down one notch and enable hyphenation so
   they wrap instead of clipping. Active once the ru theme strings land
   (theme language ships en-gb only today; ar/ru theme translation is a
   separate line — see SUMMARY for the key list). */
html[lang="ru"] .bm-hero__title { font-size: calc(var(--bm-fs-h1) * 0.88); }
html[lang="ru"] .bm-quote-cta__title { font-size: calc(var(--bm-fs-h2) * 0.9); }

html[lang="ru"] h1,
html[lang="ru"] h2,
html[lang="ru"] h3,
html[lang="ru"] .bm-hero__title,
html[lang="ru"] .bm-btn,
html[lang="ru"] .bm-category-tile__title {
  -webkit-hyphens: auto;
  hyphens: auto;
}

/* Buttons hold action verbs («Добавить в корзину») — allow wrap and keep
   the pill/rect intact instead of clipping on narrow viewports. */
html[lang="ru"] .bm-btn {
  white-space: normal;
  height: auto;
  min-height: var(--bm-h-btn);
  padding-block: var(--bm-space-2);
}

/* ==========================================================================
   E10 — responsive layer · S1 “地基”  ·  2026-09-12
   Owner: 大司空 tVBN8t · plan: e10/E10-B-plan.md (approved 2026-09-12)
   Every E10 rule lives in this single section so the whole layer can be
   reverted with one `git revert` / one block delete.

   E10-1 core leftovers off   (R1 absolute footer / absolute #container,
                              core #menu/#cart/#search/#content overrides)
   E10-2 fluid container      (no max-width + graded padding-inline)
   E10-3 breakpoint tokens    (padding + grid column ladder, used from S2)
   E10-4 mobile overflow floor(375/414/552/600) — hard gate ①
   ========================================================================== */

/* ---------------------------------------------------- E10-3 token ladder */
:root {
  --bm-pad-inline:  var(--bm-space-4);   /* 16px @<576                     */
  --bm-cols-cards:  1;                   /* home product grid (S2)         */
  --bm-cols-plp:    1;                   /* catalog grid, sidebar aware    */
  --bm-cols-taxonomy: 1;                 /* Shop by category tiles         */
  --bm-gutter:      var(--bm-space-6);   /* 24px grid gutter               */
  --bm-measure:     72ch;                /* prose line length cap          */
  --bm-content-max: 1560px;              /* content-grid cap on wide screens */
  --bm-sidebar-w:   clamp(240px, 18vw, 300px);
}

@media (min-width: 576px) {
  :root { --bm-pad-inline: var(--bm-space-5); --bm-cols-cards: 2; --bm-cols-plp: 2; --bm-cols-taxonomy: 2; }
}
@media (min-width: 768px) {
  :root { --bm-pad-inline: var(--bm-space-6); --bm-cols-cards: 2; --bm-cols-plp: 2; --bm-cols-taxonomy: 2; }
}
@media (min-width: 992px) {
  :root { --bm-pad-inline: var(--bm-space-7); --bm-cols-cards: 3; --bm-cols-plp: 2; --bm-cols-taxonomy: 2; }
}
@media (min-width: 1200px) {
  :root { --bm-pad-inline: var(--bm-space-7); --bm-cols-cards: 4; --bm-cols-plp: 3; --bm-cols-taxonomy: 4; }
}
@media (min-width: 1400px) {
  :root { --bm-pad-inline: var(--bm-space-8); --bm-cols-cards: 4; --bm-cols-plp: 3; --bm-cols-taxonomy: 4; }
}
@media (min-width: 1600px) {
  :root { --bm-pad-inline: var(--bm-space-9); --bm-cols-cards: 5; --bm-cols-plp: 4; --bm-cols-taxonomy: 4; }
}
@media (min-width: 1920px) {
  :root { --bm-pad-inline: var(--bm-space-10); --bm-cols-cards: 6; --bm-cols-plp: 5; --bm-cols-taxonomy: 4; }
}
@media (min-width: 2400px) {
  :root { --bm-pad-inline: var(--bm-space-11); --bm-cols-cards: 8; --bm-cols-plp: 7; --bm-cols-taxonomy: 4; }
}

/* ---------------------------------------------------- E10-1 core reset */
/* OpenCart core catalog/view/stylesheet/stylesheet.css ships a sticky-footer
   hack built on absolute positioning. Measured 2026-09-12 @1440: the 498px
   tall absolute <footer> is painted over the last ~500px of EVERY page
   (PDP description, catalog pagination, home CodeMark band + quote CTA +
   promises strip). We switch #container to a flex column instead, so short
   pages still push the footer down — no absolute positioning, no !important.
   Specificity: #container/#content are (1,0,0) and theme.css is the last
   stylesheet in <head> (…bootstrap, icons, stylesheet, tokens, theme) — so
   an equal-specificity override wins on source order.                        */
#container {
  position: static;
  min-height: 100vh;
  margin-bottom: 0;
  display: flex;
  flex-direction: column;
}

#container > main { flex: 1 0 auto; }

footer.bm-footer {
  position: static;
  bottom: auto;
  border: 0;
}

/* Core reserves 730px (400px ≥576) under the content column to clear that
   absolute footer — pure dead space once the footer is in normal flow.      */
#content,
#column-left,
#column-right { padding-bottom: 0; }

/* Core #menu (ID beats our .bm-nav class) repainted the nav band OpenCart
   blue: measured background rgb(34,154,200) instead of the design navy.
   Only the paint/box is reverted here; the nav *layout* rework is S3.       */
#menu.bm-nav {
  background-color: var(--bm-navy);
  background-image: none;
  background-repeat: no-repeat;
  border: 0;
  border-radius: 0;
  min-height: var(--bm-h-nav);
  padding: 0;
  margin-bottom: 0;
}

/* Core #cart / #search leftovers that shift the header box. */
#cart { margin-bottom: 0; }
#search { margin-bottom: 0; }

/* ---------------------------------------------------- E10-2 fluid container */
/* "全宽无上限" — the container fills the viewport; readability is protected
   by (a) a padding-inline ladder and (b) an inner measure cap on prose.      */
.bm-container {
  max-width: none;
  padding-inline: var(--bm-pad-inline);
}

/* ---------------------------------------------------- E10-4 mobile floor */
/* Measured before: scrollWidth 552 on all three pages at both 375 and 414 —
   the header row could not shrink below logo + 24px gap + 245px action group
   (#cart's core `padding:14px 35px` pinned the button at 202px).            */
@media (max-width: 767.98px) {
  /* gap-4 is a Bootstrap utility (gap:1.5rem !important) — the only way to
     override it is an equally-important rule; kept to this one declaration. */
  .bm-header .bm-container { gap: var(--bm-space-3) !important; }
  .bm-header { height: auto; min-height: var(--bm-h-header); padding-block: var(--bm-space-3); }
  .bm-header .bm-logo img { height: 34px; }
  #cart { margin-bottom: 0; }
  #cart .btn-lg { padding: 10px 12px; font-size: 13px; line-height: 1; }
}

@media (max-width: 575.98px) {
  /* Icon-only cart on phones so logo + account + cart fit one 343px row. */
  #cart .btn-lg { padding: 10px 12px; font-size: 0; }
  #cart .btn-lg .fa-solid { font-size: 16px; }
  .bm-header .bm-logo img { height: 28px; }
}

/* Bootstrap g-5 = 48px gutter → 24px negative inline margin, which exceeds
   the 16px container padding below 768 and pushed hero / #product-info 8px
   past the viewport (reproduced at 375, 552 and 600). */
@media (max-width: 767.98px) {
  .bm-hero .row.g-5,
  #product-info > .row.g-5 { --bs-gutter-x: var(--bm-space-4); }
}

/* ==========================================================================
   E10-S2 — 网格统一 + 卡片等高  ·  2026-09-12
   Approved plan §2 (column ladder) / §3.3 (content caps) / §5.3 (C1, H3).

   Why CSS Grid instead of Bootstrap's `.row-cols-*`: the same product row
   shipped four different column sets (`row-cols-sm-2/md-3/xl-4` on the home
   rows vs `sm-1/md-2/xl-3` on the catalog row, plus a third set injected by
   common.js on the view toggle), so a page could mix 3- and 4-column rows.
   One variable per grid, one ladder, no page-local overrides.

   `minmax(0, 1fr)` — NOT `1fr`: a grid track is `min-width:auto` by default,
   so one unbreakable ru/ar token would blow the column open (this is the new
   overflow risk the switch from float/percentage columns introduces).
   ========================================================================== */

/* ------------------------------------------------------- E10-S2 grid rows */
#product-list,
.bm-section--hairline > .bm-container > .row {
  display: grid;
  gap: var(--bm-gutter);
  margin: 0;
}

#product-list { grid-template-columns: repeat(var(--bm-cols-plp), minmax(0, 1fr)); }
/* home Bestselling shelf + the core featured module (both are direct `.row`
   children of that section's container — the featured module is rendered from
   `content_top`, i.e. a core template we must not edit) */
.bm-section--hairline > .bm-container > .row { grid-template-columns: repeat(var(--bm-cols-cards), minmax(0, 1fr)); }

/* Bootstrap `.row > *` provides the gutter through 12px paddings and a -12px
   row margin; `gap` replaces both. */
#product-list > *,
.bm-section--hairline > .bm-container > .row > * {
  width: auto;
  max-width: none;
  min-width: 0;
  padding-inline: 0;
  margin-block: 0;
}

/* The core featured module renders `<div class="col mb-3">`; Bootstrap spacing
   utilities carry `!important`, so an equally-important rule is the only way
   to hand the vertical rhythm back to `gap`. Scoped to that one row. */
.bm-section--hairline > .bm-container > .row > * { margin-bottom: 0 !important; }

/* The catalog view toggle (theme JS) swaps in `.product-list` for list mode —
   it must stay a single column. */
#product-list.product-list { grid-template-columns: minmax(0, 1fr); }

/* ------------------------------------------------ E10-S2 catalog scaffold */
/* Plan §3.5 / L3: the sidebar was a fixed 282px inside `.col-lg-3` (which also
   pushed the grid 12px in from the container edge). One grid, one gap, both
   edges flush with `.bm-container`'s padding. */
#product-category > .row {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--bm-gutter);
  margin: 0;
}

#product-category > .row > * {
  width: auto;
  max-width: none;
  min-width: 0;
  padding-inline: 0;
}

@media (min-width: 992px) {
  #product-category > .row {
    grid-template-columns: var(--bm-sidebar-w) minmax(0, 1fr);
  }
}

/* --------------------------------------------- E10-S2 card frame (C1, H3) */
/* Measured before: two cards of the same row were 469 vs 489px tall (one extra
   title line) and their CTAs sat 20px apart. The card stretches to the row
   height, the body absorbs the slack, the CTA is pinned to the shared
   baseline. */
.bm-card {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.bm-card__body {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
}

.bm-card__cta { margin-block-start: auto; }

/* Fixed 2-line model + 3-line spec: without them a long CodeMark title would
   set the row height for every card in it. `min-height` keeps the two blocks
   the same size even when the copy is shorter. */
.bm-card__model,
.bm-card__spec {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.bm-card__model {
  -webkit-line-clamp: 2;
  line-height: 1.3;
  min-height: calc(2 * 1.3em);
}

.bm-card__spec {
  -webkit-line-clamp: 3;
  line-height: 1.45;
  min-height: calc(3 * 1.45em);
}

/* ------------------------------------------- E10-S2 content rhythm caps */
/* Plan §3.3: the four-up bands keep the design's content rhythm instead of
   stretching their cards across a 2400px container. Backgrounds stay
   full-bleed; only the inner grid is capped. */
.bm-solutions > .bm-container > .row,
.bm-why > .bm-container > .row,
.bm-brand-wall > .bm-container > .row,
.bm-promises > .bm-container > .row {
  max-width: var(--bm-content-max);
  margin-inline: auto;
}

/* ------------------------------------------- E10-S2 prose measure (plan §3.3) */
/* Line length, not container width, is what breaks readability on a 2560
   screen. Applied to the hero sub, the catalog intro copy and any block that
   opts in with `.bm-measure`. */
.bm-measure,
.bm-hero__sub { max-width: var(--bm-measure); }

/* ==========================================================================
   E10-S3 — 导航条布局重做 (N1/N3/N4/N5/N6/N7)  ·  2026-09-12
   Plan §5.2. Measured before (e10/nav-s3-before.json):
     N3  .bm-all-categories scrollHeight 40 > clientHeight 34  → label wrapped
         inside the pill and was clipped (root cause below).
     N4  @1920 the menu group ended at x=735 and Deals started at x=1792 —
         1057px of dead space (1661px @2560); Deals read as a stray fragment.
     N5  nav link 13.5px / utility bar 12px at 1920, 2560.
     N6  OC4's own bootstrap.css defines ONLY `.dropend/.dropstart
         .dropdown-toggle::after` (lines 3480/3491) — there is no base
         `.dropdown-toggle::after`, so the caret relies entirely on the
         "Font Awesome 7 Free" webfont being loaded.
     N7  no toggler anywhere: below 992 the menu was display:none with no way
         to open it, so the category tree was unreachable.
   ========================================================================== */

/* ---------------------------------------------------- E10-S3 N5 type floor */
/* A *floor*, not an override: RU/AR step the nav up to 14.5px (tokens.css
   `html[lang=ar]`), and a plain `13.5px` at >=1600 would have silently made
   Arabic SMALLER. max() keeps whichever is larger. */
:root { --bm-fs-nav-wide: 0px; --bm-fs-utility-wide: 0px; }
@media (min-width: 1600px) { :root { --bm-fs-nav-wide: 13.5px; --bm-fs-utility-wide: 13.5px; } }
@media (min-width: 1920px) { :root { --bm-fs-nav-wide: 14px;   --bm-fs-utility-wide: 14px; } }

.bm-nav .nav-link { font-size: max(var(--bm-fs-nav), var(--bm-fs-nav-wide)); }
.bm-utility { font-size: max(var(--bm-fs-sm-2), var(--bm-fs-utility-wide)); }
.bm-utility .bm-lang-switch a { font-size: max(12.5px, var(--bm-fs-utility-wide)); }

/* ------------------------------------------------- E10-S3 N3/N4 menu group */
/* `.navbar-collapse` carries `flex-basis:100%` in bootstrap.css. As a flex
   item that basis is clamped against the trigger, so the *trigger* was the
   one that got shrunk to min-content and wrapped. `flex-basis:auto` + no
   growth lets the group hug its own content: trigger → menu → Deals, with no
   void in between. (`.collapse` is included in the selector so this beats
   `.collapse:not(.show)` on specificity alone — no !important.) */
.bm-nav .navbar-collapse.collapse {
  flex-basis: auto;
  flex-grow: 0;
  min-width: 0;
}

/* `white-space:nowrap` stops the label breaking; `height:36px` keeps the pill
   from being clipped by the 52px band.
   The gutter to the menu group is `margin-inline-end` here, NOT Bootstrap's
   `me-4`: that utility is physical (`margin-right:1.5rem !important`), so
   under RTL it landed on the inline-START side and pushed the trigger 24px in
   from the container's content edge (measured /ar@1920: trigger right edge at
   x=1832, content edge 1856; `margin-inline-start:24px`). Logical margin
   mirrors correctly and keeps the LTR geometry identical. */
.bm-nav .bm-all-categories {
  white-space: nowrap;
  height: 36px;
  margin-inline-end: var(--bm-space-6);
}

/* --------------------------------------------------------- E10-S3 N6 glyphs */
/* Caret drawn in CSS instead of the icon font (RTL-safe: the triangle is
   symmetric, only the trailing gap is logical). If "Font Awesome 7 Free"
   fails to load, the core `<i class="fa-solid fa-caret-down">` renders as a
   zero-width box — after this rule it is removed from the visual tree. */
.bm-utility .dropdown-toggle::after {
  content: "";
  display: inline-block;
  width: 0;
  height: 0;
  border-block-start: 4.5px solid currentColor;
  border-inline: 4px solid transparent;
  margin-inline-start: 5px;
  vertical-align: 1px;
}
.bm-utility .dropdown-toggle > i.fa-solid { display: none; }

/* Any icon-only glyph must keep a box even if its font is missing. */
.bm-icon,
i.fa-solid { min-width: 1em; min-height: 1em; }

/* ---------------------------------------------------------- E10-S3 N7 drawer */
.bm-nav { position: relative; }
.bm-nav .bm-nav__toggler { display: none; }

@media (min-width: 992px) {
  /* The group is always open on desktop, independently of Bootstrap's
     `.show` class (equal-specificity tie broken by source order: theme.css is
     the last stylesheet in <head>; the (0,3,0) selector settles it anyway). */
  .bm-nav .navbar-collapse.collapse { display: flex; }
}

@media (max-width: 991.98px) {
  .bm-nav .bm-nav__toggler {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    margin-inline-start: auto;
    width: 42px;
    height: 36px;
    padding: 0;
    background: rgba(255, 255, 255, 0.1);
    border: 1.3px solid rgba(255, 255, 255, 0.9);
    border-radius: var(--bm-radius-tile);
    color: #fff;
  }
  .bm-nav .bm-nav__toggler[aria-expanded="true"] { background: rgba(255, 255, 255, 0.2); }

  /* Overlay instead of in-flow: the band keeps its 52px height and the page
     below is never reflowed, so opening the drawer cannot introduce vertical
     or horizontal overflow. `inset-inline:0` mirrors under RTL. */
  .bm-nav .navbar-collapse.collapse.show {
    display: block;
    position: absolute;
    inset-inline: 0;
    top: 100%;
    z-index: 60;
    max-height: min(70vh, 560px);
    overflow-y: auto;
    overscroll-behavior: contain;
    padding-block: var(--bm-space-3);
    padding-inline: var(--bm-pad-inline);
    background: var(--bm-navy);
    border-block-start: 1px solid rgba(255, 255, 255, 0.16);
    box-shadow: var(--bm-shadow-float);
  }

  .bm-nav .navbar-collapse > ul { flex-direction: column; align-items: stretch; }
  .bm-nav .navbar-collapse > ul > li { width: 100%; }
  .bm-nav .navbar-collapse > ul > li > .nav-link {
    display: block;
    margin-inline-end: 0;
    padding-block: 11px;
  }
  /* Plan §5.2 N7 asks for an *accordion*, not a floating menu. Left as a
     Bootstrap dropdown, a parent tap made Popper position the mega panel
     against the viewport: at 375 the panel's box ran 185px past the viewport
     edge (measured e10/drawer-s3.json → after_parent_tap.worstOverflow=185,
     `DIV.dropdown-menu bm-mega-panel show`). The page itself never gained a
     horizontal scrollbar (the drawer clips it), but the sub-menu sat half
     off-screen behind a horizontal scroll region — unusable.
     Root cause of the width: `.dropdown-item{white-space:nowrap}` makes the
     panel's min-content as wide as its longest category name.
     Popper writes `position`/`inset`/`transform` as INLINE styles, and no
     selector can outrank an inline style — so these two declarations need
     `!important`. Scoped to `<992` + inside the drawer only; the two are the
     entire `!important` budget of S3 and they only ever neutralise
     positioning, never paint. */
  .bm-nav .navbar-collapse .dropdown-menu {
    position: static !important;
    transform: none !important;
    inset: auto;
    min-width: 0;
    width: 100%;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    background: transparent;
    padding: var(--bm-space-2) 0 var(--bm-space-3);
  }
  .bm-nav .navbar-collapse .dropdown-item { white-space: normal; }
  /* the panel's 2–3 Bootstrap columns stack: at phone width a `.row` of
     `col`s just narrows every label to its longest word. */
  .bm-nav .navbar-collapse .bm-mega-panel .row { display: block; }
  .bm-nav .navbar-collapse .bm-mega-panel .dropdown-item { padding-inline: var(--bm-space-3); }
  .bm-nav .navbar-collapse { overflow-x: clip; }
}

/* ==========================================================================
   E10-S4 — 首页栏目重排 (H1 环带断行 / D3+C4 分类四列 / C2 子分类 chip / C3 药丸)
   2026-09-12  ·  plan §4/§5.1
   home.twig 的 section 顺序已在同一 commit 内调整为渔夫口径：
   Hero → Industry solutions → Bestselling(+Featured, D4 选 A) → Shop by
   category → Data-loop → Brand wall → Why → CodeMark → Quote CTA。
   ========================================================================== */

/* ------------------------------------------------------------- E10-S4 H1 */
/* Before: `.row` held `col-6 col-md-3` ×4 + `col-1` ×3 = 15 of 12 columns, so
   the 4th node (DATA) wrapped onto its own row — measured y 1326 vs 1217 for
   the other three. Fixed 4-track grid; `minmax(0,1fr)` keeps long ru/ar
   labels from widening the track (grid items default to min-width:auto). */
.bm-loop__grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--bm-space-4);
  /* NOT `align-items:center`: the nodes have unequal content heights (1-line
     vs 2-line sub labels), so centring left the icon circles at different
     y-positions — the exact "ragged ring" the H1 fix is meant to remove.
     Stretching pins every node's top edge to the row top. */
  align-items: stretch;
}

.bm-loop__cell { position: relative; min-width: 0; }

/* The connector: a triangle pointing along the inline axis, so it mirrors
   under RTL exactly like the old `bm-icon--dir` SVG did. Only drawn where the
   4-up row is actually one row with room for gutters (>=768, which is where
   the old `d-none d-md-block` arrow cells used to appear). */
@media (min-width: 768px) {
  .bm-loop__cell:not(:last-child)::after {
    content: "";
    position: absolute;
    /* half the gutter, plus half of the 7px triangle itself — so the triangle
       ends up centred in the gap rather than hugging the previous node.
       `translate` shifts on the block axis only: it is already accounted for
       on the inline axis by the 3.5px above (a -50% inline shift as well
       would move it again, landing it 3.5px left of the gap centre). */
    inset-inline-end: calc(-1 * var(--bm-space-4) / 2 - 3.5px);
    top: 50%;
    width: 0;
    height: 0;
    translate: 0 -50%;
    border-block: 6px solid transparent;
    border-inline-start: 7px solid var(--bm-border);
  }
}

/* --------------------------------------------- E10-S4 D3/C4 taxonomy grid */
/* 3 real categories + the template-only entry card = 4 cells. `--bm-cols-taxonomy`
   is now 1 / 2 / 2 / 2 / 4 / 4 / 4 / 4 / 4 (was 1/2/2/3/4/4/4/4/6 from plan §2,
   which assumed a 3-tile row): with 4 cells, 3 columns would strand the 4th on
   its own row and 6 columns would leave two empty slots. Both were exactly the
   "混排/留空" the plan set out to remove. */
.bm-cat-grid {
  display: grid;
  grid-template-columns: repeat(var(--bm-cols-taxonomy), minmax(0, 1fr));
  gap: var(--bm-gutter);
  align-items: stretch;
}

.bm-cat-grid__cell { min-width: 0; display: flex; }

/* C2 — tiles are equal height and the children are a chip flow, not a
   vertical list. Before: Scanners/Printers carried 1 child line against
   Accessories' 5, so the tile body was mostly empty; chips keep the same
   information in ~2 rows and wrap instead of stacking. */
.bm-category-tile {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  min-height: 0;
}

.bm-category-tile__children {
  display: flex;
  flex-wrap: wrap;
  gap: var(--bm-space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.bm-category-tile__children li + li { margin-top: 0; }

.bm-category-tile__children a {
  display: inline-block;
  max-width: 100%;
  padding: 5px 10px;
  border: 1px solid var(--bm-border);
  border-radius: var(--bm-radius-pill);
  background: var(--bm-bg);
  font-size: 12.5px;
  line-height: 1.35;
  color: var(--bm-ink);
  text-decoration: none;
  overflow-wrap: anywhere;   /* ru/ar compound names must wrap inside the chip */
}

.bm-category-tile__children a:hover {
  border-color: var(--bm-cyan);
  background: var(--bm-surface);
  color: var(--bm-cyan-text);
  text-decoration: none;
}

.bm-category-tile__empty { margin: 0; }

/* The 4th (entry) card: title block on top, note pinned to the bottom so it
   reads as a CTA rather than as another chip list. */
.bm-category-tile--all { text-decoration: none; }
.bm-category-tile__all-note {
  margin-block-start: auto;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--bm-brand-gray);
}

/* --------------------------------------------------------------- E10-S4 C3 */
/* `OUR BRAND` pill sat at top:-8px, i.e. 8px ABOVE the tile, landing on the
   tile border (the ~11px artefact on the review list). 6px puts it inside the
   card; the extra top padding keeps it clear of the logo below. */
.bm-brand-tile--codemark { padding-block-start: 8px; }
.bm-brand-tile--codemark .bm-own-brand { top: 6px; }

/* C3 accompaniment: the brand wall mixes SVG tiles with text tiles; keep the
   row from going ragged when a name wraps. */
.bm-brand-tile { height: 100%; min-height: 92px; }

/* --------------------------------------------------------------- E10-S4 H2 */
/* Band seam audit: R1 already removed the 20px gap (the white sliver *was* the
   CodeMark band showing between the absolutely-positioned footer and the
   content). These make an accidental 1–2px seam impossible at the joins. */
.bm-band--warm { border-block-end: 0; }
.bm-codemark, .bm-why, .bm-loop, .bm-categories, .bm-brand-wall { margin-block: 0; }

/* ==========================================================================
   E10-S5 — PDP 排版 (P1..P9)  ·  2026-09-12
   P6 (相关商品) 不在本轮：`{{ related }}` 为空是后台没挂模块，主题侧无法凭空造数据。
   ========================================================================== */

/* ---------------------------------------------------------------- E10-S5 P1 */
/* The well used to be `padding: var(--bm-space-7)` (32px) around a 460px-capped
   image: measured well 656×524 vs img 460×460 → 196px of horizontal and 64px of
   vertical background, i.e. the "grey bands". Now the image box IS the well box
   (0px difference) and `object-fit:contain` letterboxes inside it instead of the
   well padding doing it — and the white card replaces the tinted `--bm-img`. */
.bm-gallery__main {
  aspect-ratio: 1 / 1;
  /* Approved S6 revision (was `min(72vh,640px)`): a 720px hard ceiling with
     85vh elasticity. Both bounds are applied to the BLOCK axis, and the same
     expression is mirrored on the INLINE axis — a `max-height` alone breaks the
     square the instant it bites (measured 765 wide × 640 tall at 1440).
     72vh was dropped as the flex term on purpose: at a 900px-tall window
     72vh = 648 and the well shrank back to 648, i.e. the ceiling stopped being
     720. 85vh keeps 720 binding from a 847px-tall window upward. */
  max-height: min(85vh, 720px);
  max-width: min(100%, 85vh, 720px);
  margin-inline: auto;
  padding: 0;
  background: var(--bm-surface);
  border: 1px solid var(--bm-border);
}

/* The `<a>` is the flex item, so it sized to the image's intrinsic 500px and
   `width:100%` on the img then resolved against *that* — the img box stayed
   500×500 inside a 640 well (140px of well background on each side). The anchor
   has to fill the well first. */
.bm-gallery__main > a {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}

.bm-gallery__main img {
  width: 100%;
  height: 100%;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

/* ---------------------------------------------------------------- E10-S5 P3 */
/* Info column → buy-box card. `height:100%` + flex column: the card fills the
   stretched column, and the trust/logistics/bulk tail is pushed to its bottom
   edge (P9), so the card's bottom edge lines up with the gallery's. */
.bm-pdp__buybox {
  display: flex;
  flex-direction: column;
  height: 100%;
  background: var(--bm-surface);
  border: 1px solid var(--bm-border);
  border-radius: var(--bm-radius-card);
  padding: var(--bm-space-6);
  /* Sticky is conditional by design: while the card is exactly as tall as the
     column (the P9 equal-height case) it has zero travel and this is inert.
     It only displaces when the card ends up shorter than the column — i.e. a
     product whose options/price block is small. */
  position: sticky;
  top: var(--bm-space-6);
}

/* ---------------------------------------------------------------- E10-S5 P4 */
/* Measured before: qty 64 + cart 650 + quote 134 at a 1017px column → 4.83:1
   (7.09:1 at 2560). The cart was `flex-grow-1` with no cap. */
.bm-pdp__actions {
  flex-wrap: wrap;
  gap: var(--bm-space-3);
}

.bm-pdp__actions #button-cart {
  flex: 1 1 auto;
  max-width: 360px;
  min-width: 0;
}

.bm-pdp__actions > a.bm-btn {
  flex: 0 0 auto;
  min-width: 148px;
  text-align: center;
}

/* ---------------------------------------------------------------- E10-S5 P5 */
/* R1 (S1) already put the description back in flow; this only caps the prose
   line length. */
#tab-description { max-width: var(--bm-measure); }

/* ---------------------------------------------------------------- E10-S5 P7 */
/* `justify-content:space-between` stranded the stock chip at the far right of a
   656px row — measured 537px of dead space at 1440, 753px at 1920, 1057px at
   2560. Flex-start puts it next to the brand line; the gap is logical so RTL
   mirrors on its own. */
.bm-pdp__topline { justify-content: flex-start; gap: 12px; }

/* ---------------------------------------------------------------- E10-S5 P8 */
.bm-breadcrumb { margin-block: 12px 16px; }

/* ---------------------------------------------------------------- E10-S5 P9 */
/* The tail group (trust → logistics → bulk) is pinned to the card's bottom.
   `auto` beats the existing `margin-block-start: var(--bm-space-5)`, and the
   trust block keeps its own top border + padding as a divider. */
.bm-pdp__buybox .bm-pdp__trust { margin-block-start: auto; }

/* Below lg the two PDP columns stack, so there is no sibling column to equalise
   with and no sidebar to be sticky against. */
@media (max-width: 991.98px) {
  .bm-pdp__buybox { position: static; height: auto; }
  .bm-pdp__buybox .bm-pdp__trust { margin-block-start: var(--bm-space-5); }
}

/* ==========================================================================
   E10-S6 — 全量回归收尾  ·  2026-09-12
   Only defects surfaced by the widened S6 path×viewport×language matrix land
   here. It is a continuation of the E10 partition above, so the whole E10 layer
   still reverts as one block.
   ========================================================================= */

/* ----------------------------------------------------- S6-1 pagination RTL */
/* Found by S6 only: /ar PLP @375 overflowed by 15px while /en and /ru did not.
   Cause is a physical-vs-logical reset, not a theme layout choice — Bootstrap
   zeroes the list indent with `padding-left: 0`, which does nothing for the
   UA's `padding-inline-start: 40px` under RTL, so `ul.pagination` measured
   404px instead of 360px. Centred in a 343px container it poked 15px past the
   viewport. The logical property neutralises the indent in both directions and
   leaves LTR byte-for-byte identical (padding-left is still 0).
   Measured /ar/catalog/barcode-scanners @375: scrollWidth 390 → 375. */
.pagination { padding-inline-start: 0; }
