/* ═══════════════════════════════════════════════════════════════════════
   KOBAYASHI SHARED SHELL STYLES, nav, footer, logo slider
   Paired with shell.js. All tokens come from theme.css.
   ═══════════════════════════════════════════════════════════════════════ */

/* Offset body content so fixed nav (top: 24px with a preview banner above) doesn't overlap */
body { padding-top: 0; }

/* ── NAVIGATION ─────────────────────────────────────────────────────── */
.kb-nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 100;
  background: hsl(var(--background));
  /* No bottom rule on the header itself. The only line in the menu is the one
     under the utility strip, between it and the main row. The 1px box-shadow
     layer that used to sit here drew a second identical line, so it goes with
     the border; the soft drop shadow stays for depth. */
  box-shadow: 0 8px 24px -16px hsl(0 0% 0% / 0.5);
}
html.light .kb-nav {
  box-shadow: 0 8px 24px -16px hsl(30 10% 14% / 0.08);
}

/* ── Utility bar: thin desktop-only strip above the main row ─────────── */
.kb-nav__utility {
  display: none;
  border-bottom: 1px solid hsl(var(--border));
}
.kb-nav__utility-inner {
  max-width: 1440px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding: 4px 32px;
}

/* Light mode: the utility strip inverts to a black bar with white text, so
   the header keeps a strong brand edge instead of washing into the page. */
html.light .kb-nav__utility {
  background: hsl(0 0% 7%);
  border-bottom-color: hsl(0 0% 7%);
}
html.light .kb-nav__utility-link,
html.light .kb-nav__utility-phone {
  color: hsl(0 0% 100% / 0.74);
}
html.light .kb-nav__utility-link:hover,
html.light .kb-nav__utility-link.is-active,
html.light .kb-nav__utility-phone:hover {
  color: hsl(0 0% 100%);
}
html.light .kb-nav__utility .kb-nav__social a {
  color: hsl(0 0% 100% / 0.74);
}
html.light .kb-nav__utility .kb-nav__social a:hover {
  color: hsl(0 0% 100%);
  background: hsl(0 0% 100% / 0.12);
}

/* ── Social icons: quiet line icons, shared by the utility bar and the
   mobile menu's Follow Us row ─────────────────────────────────────── */
.kb-nav__social { display: flex; align-items: center; gap: 4px; }
.kb-nav__social a {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px;
  color: hsl(var(--muted-foreground));
  border-radius: 6px;
  transition: color 0.2s, background 0.2s;
  -webkit-tap-highlight-color: transparent;
}
.kb-nav__social a:hover {
  color: hsl(var(--foreground));
  background: hsl(var(--secondary));
}
.kb-nav__social svg {
  width: 15px; height: 15px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* Mobile menu variant: larger tappable tiles in a row */
.kb-nav__social--mobile { gap: 10px; padding: 8px 0 4px; }
.kb-nav__social--mobile a {
  width: 44px; height: 44px;
  border: 1px solid hsl(var(--border));
  border-radius: 10px;
}
.kb-nav__social--mobile svg { width: 19px; height: 19px; }
.kb-nav__utility-phone,
.kb-nav__utility-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-sans);
  font-size: 0.75rem;
  font-weight: 500;
  color: hsl(var(--muted-foreground));
  text-decoration: none;
  transition: color 0.2s;
}
.kb-nav__utility-phone:hover,
.kb-nav__utility-link:hover,
.kb-nav__utility-link.is-active {
  color: hsl(var(--foreground));
}
.kb-nav__utility-phone svg {
  width: 13px; height: 13px;
  stroke: hsl(var(--primary));
  flex: none;
}
.kb-nav__utility-links { display: flex; gap: 18px; }
.kb-nav__inner {
  max-width: 1440px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 32px;
}
.kb-nav__logo { display: flex; height: 34px; flex-shrink: 0; }
.kb-nav__logo img { height: 100%; width: auto; filter: var(--logo-filter); }

.kb-nav__toggle {
  display: none;
  width: 40px; height: 40px;
  align-items: center; justify-content: center;
  background: transparent;
  color: hsl(var(--foreground));
  border: 1px solid hsl(var(--border));
  border-radius: var(--radius);
  cursor: pointer;
}
.kb-nav__toggle svg { width: 20px; height: 20px; }

.kb-nav__links {
  display: flex;
  gap: 2px;
  align-items: center;
  list-style: none;
  margin: 0; padding: 0;
}
.kb-nav__link {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: 0.85rem;
  color: hsl(var(--foreground) / 0.92);
  padding: 8px 14px;
  border-radius: var(--radius);
  transition: color 0.2s, background 0.2s;
  text-decoration: none;
  white-space: nowrap;
  position: relative;
}
.kb-nav__link:hover {
  color: hsl(var(--foreground));
  background: hsl(var(--secondary));
}
.kb-nav__link.is-active {
  color: hsl(var(--foreground));
}
.kb-nav__link.is-active::after {
  content: '';
  position: absolute;
  left: 50%;
  bottom: 2px;
  transform: translateX(-50%);
  width: 16px;
  height: 2px;
  background: hsl(var(--primary));
  border-radius: 2px;
}
.kb-nav__caret {
  width: 12px; height: 12px;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  fill: none;
  transition: transform 0.2s;
}
/* Bar Matcher trigger: small magnifier icon + label */
.kb-nav__matcher { display: inline-flex; align-items: center; gap: 6px; }
.kb-nav__matcher svg { width: 14px; height: 14px; flex: none; }
.kb-nav__has-menu:hover .kb-nav__caret,
.kb-nav__has-menu.is-open .kb-nav__caret {
  transform: rotate(180deg);
}

.kb-nav__has-menu {
  position: relative;
}
.kb-nav__menu {
  position: absolute;
  top: calc(100% + 10px);
  left: 0;
  min-width: 300px;
  /* Cap against the viewport. min-width alone lets a menu anchored part-way
     along the bar overhang the right edge on a narrow screen, and because it
     is absolutely positioned it widens the document while still hidden. The
     mega menu below already had this; these did not. */
  max-width: calc(100vw - 32px);
  padding: 8px;
  background: hsl(var(--background-elev));
  border: 1px solid hsl(var(--border));
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition: opacity 0.2s, transform 0.2s, visibility 0.2s;
  z-index: 10;
}
.kb-nav__has-menu:hover .kb-nav__menu,
.kb-nav__has-menu:focus-within .kb-nav__menu,
.kb-nav__has-menu.is-open .kb-nav__menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}
.kb-nav__menu-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  font-size: 0.85rem;
  color: hsl(var(--foreground));
  border-radius: var(--radius);
  transition: background 0.15s, color 0.15s;
  text-decoration: none;
}
.kb-nav__menu-item:hover {
  background: hsl(var(--secondary));
  color: hsl(var(--primary));
}
.kb-nav__menu-size {
  display: inline-flex;
  align-items: center; justify-content: center;
  min-width: 44px;
  padding: 3px 8px;
  font-family: var(--font-condensed);
  font-size: 0.72rem; font-weight: 700;
  letter-spacing: 0.1em;
  color: hsl(var(--primary));
  background: hsl(350 72% 44% / 0.1);
  border: 1px solid hsl(350 72% 44% / 0.25);
  border-radius: 6px;
}
.kb-nav__menu-divider {
  height: 1px;
  background: hsl(var(--border));
  margin: 6px 8px;
}
.kb-nav__menu-item--all {
  color: hsl(var(--primary));
  font-weight: 500;
}
/* "By Use Case" subhead inside the Cocktail Stations dropdown */
.kb-nav__menu-eyebrow {
  padding: 8px 12px 4px;
  font-family: var(--font-condensed);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: hsl(var(--muted-foreground));
}
.kb-nav__menu-item--usecase {
  padding-left: 12px;
}
.kb-nav__menu-item--usecase span {
  font-size: 0.85rem;
}

/* Neutral variant of the stock-note pill: no green pill, no pulsing dot,
   smaller body-text style. Used for long disclosures (e.g. Portable Bar
   conversion kit notice) rather than fast-ship stock callouts. */
.info__stock-note.info__stock-note--neutral {
  display: block;
  background: transparent;
  color: hsl(var(--muted-foreground));
  border: none;
  padding: 6px 0 0;
  margin-top: 8px;
  border-radius: 0;
  font-size: 0.78rem;
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.5;
  animation: none;
}
.info__stock-note.info__stock-note--neutral::before {
  display: none;
}

.kb-nav__cta {
  background: hsl(var(--primary));
  color: hsl(var(--white));
  padding: 9px 18px;
}
.kb-nav__cta:hover {
  background: hsl(var(--primary-hover));
  color: hsl(var(--white));
}
/* Mobile actions wrapper (theme + hamburger), desktop hides it */
.kb-nav__mobile-actions { display: none; align-items: center; gap: 4px; }
.kb-nav__mobile-actions button {
  /* Skip iOS 300ms tap delay so the hamburger fires reliably on first
     tap. Default touch-action is `auto` which lets the browser wait
     and see if it's a scroll/zoom gesture. */
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
.kb-nav__theme-mobile {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px;
  padding: 0;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius, 0.5rem);
  color: hsl(var(--foreground));
  cursor: pointer;
  position: relative;
}
.kb-nav__theme-mobile:hover { border-color: hsl(var(--border)); background: hsl(var(--secondary)); }
.kb-nav__theme-mobile .kb-nav__theme-icon {
  position: absolute;
  width: 20px; height: 20px;
  color: hsl(var(--primary));
  transition: opacity 0.2s, transform 0.3s;
}
.kb-nav__theme-mobile .kb-nav__theme-icon--sun  { opacity: 0; transform: rotate(-90deg) scale(0.6); }
.kb-nav__theme-mobile .kb-nav__theme-icon--moon { opacity: 1; transform: rotate(0) scale(1); }
html.light .kb-nav__theme-mobile .kb-nav__theme-icon--sun  { opacity: 1; transform: rotate(0) scale(1); }
html.light .kb-nav__theme-mobile .kb-nav__theme-icon--moon { opacity: 0; transform: rotate(90deg) scale(0.6); }

/* Mobile cart icon (top bar, next to theme toggle + hamburger) */
.kb-nav__cart-mobile {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px;
  padding: 0;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius, 0.5rem);
  color: hsl(var(--foreground));
  cursor: pointer;
}
.kb-nav__cart-mobile:hover { border-color: hsl(var(--border)); background: hsl(var(--secondary)); }
.kb-nav__cart-mobile svg { width: 20px; height: 20px; stroke: currentColor; fill: none; }

/* In-menu theme toggle (mobile only) */
.kb-nav__theme-item { display: none; }
.kb-nav__theme {
  display: flex; align-items: center; gap: 10px;
  width: 100%;
  background: transparent;
  border: 0;
  color: hsl(var(--foreground));
  font-family: inherit;
  font-weight: 500;
  cursor: pointer;
  text-align: left;
}
.kb-nav__theme-icon { width: 18px; height: 18px; color: hsl(var(--primary)); flex-shrink: 0; }
.kb-nav__theme-icon--sun { display: none; }
html.light .kb-nav__theme-icon--sun { display: inline-block; }
html.light .kb-nav__theme-icon--moon { display: none; }

/* Top-bar phone link (desktop) */
.kb-nav__phone {
  display: inline-flex; align-items: center; gap: 8px;
  color: hsl(var(--foreground));
  font-weight: 600;
  font-size: 0.88rem;
  letter-spacing: 0.01em;
  white-space: nowrap;
}
.kb-nav__phone:hover { color: hsl(var(--primary)); }
.kb-nav__phone-icon { width: 15px; height: 15px; color: hsl(var(--primary)); flex-shrink: 0; }

/* Cart icon in the nav */
.kb-nav__cart-item { display: flex; align-items: center; margin-right: 8px; }
.kb-nav__cart {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 0;
  padding: 8px;
  color: hsl(var(--foreground));
  cursor: pointer;
  border-radius: var(--radius, 0.5rem);
  transition: color 0.15s var(--ease, ease), background 0.15s var(--ease, ease);
}
.kb-nav__cart:hover { color: hsl(var(--primary)); background: hsl(var(--secondary)); }
.kb-nav__cart-icon { width: 20px; height: 20px; stroke: currentColor; fill: none; }
.kb-nav__cart-badge {
  position: absolute;
  top: 2px; right: 2px;
  min-width: 16px; height: 16px;
  padding: 0 4px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: hsl(var(--primary));
  color: hsl(var(--white));
  font-family: var(--font-condensed, 'Barlow Condensed', sans-serif);
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  line-height: 1;
  border-radius: 100px;
  box-shadow: 0 0 0 2px hsl(var(--background));
}
.kb-nav__cart-badge[hidden] { display: none; }

/* Mobile bottom tab bar (compact shortcut to key pages) */
.kb-mobilebar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  display: none;
  /* 5 equal columns. minmax(0,1fr) (not plain 1fr) so a wider label like
     "Products" can't stretch its column and unbalance the spacing. */
  grid-template-columns: repeat(5, minmax(0, 1fr));
  background: hsl(var(--background));
  border-top: 1px solid hsl(var(--border));
  padding: 6px 6px calc(6px + env(safe-area-inset-bottom, 0px));
  gap: 2px;
  z-index: 90;
  box-shadow: 0 -6px 24px hsl(0 0% 0% / 0.35);
  /* GPU-composite the bar so it sits on its own layer. The browser
     never has to repaint it during page scroll, which makes it feel
     rock-solid and means the first tap after a scroll lands instantly
     instead of waiting for the next paint frame. */
  transform: translateZ(0);
  -webkit-transform: translateZ(0);
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  /* NO paint containment: the raised Build Quote circle overflows the
     bar's top edge and paint containment would clip it. */
  contain: layout style;
  /* No transitions on the bar itself, any animation here would feel
     like the menu is "moving while I scroll". */
  transition: none !important;
  animation: none !important;
}
.kb-mobilebar__item {
  /* Fill the entire grid cell so the WHOLE square is tappable, not just
     the icon/text. */
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  width: 100%;
  height: 100%;
  min-height: 56px;
  place-self: stretch;
  gap: 4px;
  padding: 8px 2px;
  box-sizing: border-box;
  text-decoration: none;
  color: hsl(var(--muted-foreground));
  font-family: var(--font-sans);
  /* Slightly smaller so 6 labels (Portfolio, Matcher) breathe in the bar */
  font-size: 0.58rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  border-radius: 8px;
  /* INSTANT response, zero transition. Every previous transition here
     introduced a perceptible delay between tap and visual change, which
     people read as "I have to tap twice". Now the press feedback fires
     on the first frame. */
  transition: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  cursor: pointer;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}
.kb-mobilebar__item svg {
  width: 20px; height: 20px; stroke-width: 1.8;
  /* SVG children should not absorb the tap, the parent <a> must be the
     event target so the link follows on the first tap. */
  pointer-events: none;
}
.kb-mobilebar__item span { pointer-events: none; white-space: nowrap; }

/* ── Center "Build Quote" action ─────────────────────────────────────
   A raised red circle with the Kobayashi mark, floating above the bar.
   The one thing we want a mobile visitor to do: build their order. */
.kb-mobilebar__item--quote {
  color: hsl(var(--primary));
  font-weight: 700;
  gap: 5px;
  overflow: visible;
}
.kb-mobilebar__fab {
  display: flex; align-items: center; justify-content: center;
  width: 64px; height: 64px;
  margin-top: -32px;
  background: hsl(var(--primary));
  border-radius: 50%;
  border: 3px solid hsl(var(--background));
  box-shadow: 0 6px 18px hsl(350 72% 44% / 0.45), 0 2px 6px hsl(0 0% 0% / 0.45);
  pointer-events: none;
}
.kb-mobilebar__fab img { width: 46px; height: 46px; display: block; }
/* Light mode: the ring is drawn in the page background, which reads as a
   white gap around the mark. Match it to the circle so the whole thing is
   red, and lighten the drop shadow to suit the pale bar. */
html.light .kb-mobilebar__fab {
  border-color: hsl(var(--primary));
  box-shadow: 0 6px 18px hsl(350 72% 44% / 0.34), 0 2px 6px hsl(0 0% 0% / 0.16);
}
.kb-mobilebar__item--quote:active .kb-mobilebar__fab { transform: scale(0.93); }
/* The circle is always red; never restyle it via the active-page tint */
.kb-mobilebar__item--quote.is-active,
:root[data-kb-page="contact"] .kb-mobilebar__item--quote {
  background: transparent;
}
/* Hover styles ONLY apply on devices with a real mouse pointer. On
   touchscreens these used to "stick" after the first tap and force a
   second tap to actually navigate. */
@media (hover: hover) and (pointer: fine) {
  .kb-mobilebar__item:hover,
  .kb-mobilebar__item:focus-visible {
    color: hsl(var(--foreground));
    background: hsl(var(--background-elev));
  }
}
/* Brief tap feedback for touch devices, applies only while the finger
   is actively pressing, then releases instantly so navigation happens. */
.kb-mobilebar__item:active {
  background: hsl(var(--background-elev));
}
/* Active state, set by shell.js highlightActive() based on current
   URL. The Quote item used to live in primary red regardless of page;
   now red is reserved for the actual active page. */
.kb-mobilebar__item.is-active {
  color: hsl(var(--primary));
  background: hsl(var(--primary) / 0.12);
}
.kb-mobilebar__item.is-active svg { stroke: hsl(var(--primary)); }

/* CSS-only active state fallback, keyed off <html data-kb-page="..."> set
   by shell.js before any mount happens. Survives JS timing issues and
   stale-cache scenarios where `.is-active` never gets applied. */
:root[data-kb-page="contact"] .kb-mobilebar__item[href$="/contact/"],
:root[data-kb-page="shop"] .kb-mobilebar__item[href$="/shop/"],
:root[data-kb-page="client-portfolio"] .kb-mobilebar__item[href$="/client-portfolio/"],
:root[data-kb-page="about"] .kb-mobilebar__item[href$="/about/"] {
  color: hsl(var(--primary));
  background: hsl(var(--primary) / 0.12);
}
:root[data-kb-page="contact"] .kb-mobilebar__item[href$="/contact/"] svg,
:root[data-kb-page="shop"] .kb-mobilebar__item[href$="/shop/"] svg,
:root[data-kb-page="client-portfolio"] .kb-mobilebar__item[href$="/client-portfolio/"] svg,
:root[data-kb-page="about"] .kb-mobilebar__item[href$="/about/"] svg {
  stroke: hsl(var(--primary));
}

/* Mobile */
@media (max-width: 900px) {
  .kb-mobilebar { display: grid; }
  /* Keep page content from being hidden behind the fixed bottom bar */
  body { padding-bottom: calc(72px + env(safe-area-inset-bottom, 0px)); }

  /* The body padding above only clears the bar at the END of the document.
     A section revealed mid-page still lands underneath it, and the product
     pages scroll the buy-direct panel into view with block:'nearest', which
     does the minimum scrolling and parks it against the bottom edge. On a
     390x844 screen that put Add to Cart at y=800 with the bar occupying
     763-844, so elementFromPoint at the button's centre returned the tab bar
     and a real tap never reached the button.

     scroll-margin-bottom makes scrollIntoView treat the element as taller
     than it is, so the minimum scroll now clears the bar. */
  #buyDirectSection,
  .info__buy-direct { scroll-margin-bottom: calc(96px + env(safe-area-inset-bottom, 0px)); }
  .kb-nav__logo { height: 30px; }
  .kb-nav__utility { display: none; }
  /* The centered active-state dash looks stray under full-width sheet rows */
  .kb-nav__links .kb-nav__link.is-active::after { display: none; }
  /* Theme toggle lives inside the hamburger menu on mobile */
  .kb-nav__theme-item { display: block; }
  /* Hide the floating theme button on mobile, it's now in the menu */
  .kb-theme-toggle { display: none !important; }

  /* Cart icon already lives in the mobile top bar (next to the theme
     toggle + hamburger), so hide the in-menu cart row on mobile. */
  .kb-nav__cart-item { display: none; }

  /* Pull theme toggle to the TOP of the open mobile menu */
  .kb-nav__theme-item { order: -1; }

  /* Visual divider between the theme row and the link list */
  .kb-nav__theme-item {
    padding-bottom: 8px;
    margin-bottom: 6px;
    border-bottom: 1px solid hsl(var(--border));
  }
}

/* Mobile */
@media (max-width: 900px) {
  .kb-nav__inner { padding: 10px 20px; }
  .kb-nav__toggle { display: inline-flex; }
  .kb-nav__mobile-actions { display: inline-flex; }
  .kb-nav__links {
    position: absolute;
    top: calc(100% + 1px); left: 0; right: 0;
    flex-direction: column;
    align-items: stretch;
    padding: 12px;
    background: hsl(var(--background-elev));
    border-bottom: 1px solid hsl(var(--border));
    box-shadow: var(--shadow-lg);
    gap: 4px;
    max-height: 0;
    overflow: hidden;
    opacity: 0;
    transition: max-height 0.3s, opacity 0.2s;
  }
  .kb-nav__links.is-open {
    max-height: 80vh;
    overflow-y: auto;
    opacity: 1;
  }
  .kb-nav__link { padding: 12px 14px; font-size: 0.9rem; }
  /* Move the Bar Design + Get Quote CTAs to the TOP of the open hamburger sheet
     and make them full-width, tappable buttons (instead of narrow, bottom-stacked). */
  .kb-nav__cta-li { order: -1; }
  .kb-nav__cta-li:last-of-type { margin-bottom: 8px; }
  .kb-nav__links.is-open .kb-nav__cta {
    display: flex;
    justify-content: center;
    width: 100%;
    padding: 14px 16px;
    font-size: 0.95rem;
    font-weight: 600;
    border-radius: var(--radius);
  }
  .kb-nav__menu {
    position: static;
    display: none;
    box-shadow: none;
    border: none;
    padding: 4px 0 4px 24px;
    min-width: 0;
    transform: none;
    opacity: 1;
    visibility: visible;
    background: transparent;
  }
  .kb-nav__has-menu.is-open .kb-nav__menu { display: block; }
  .kb-nav__menu-item { padding: 8px 10px; font-size: 0.82rem; }
  /* Footer-rollup sections inside the hamburger (Support / Contact / Legal) */
  .kb-nav__mobile-section {
    list-style: none;
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid hsl(var(--border));
  }
  .kb-nav__section-label {
    font-family: var(--font-condensed);
    font-size: 0.66rem;
    font-weight: 700;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: hsl(var(--muted-foreground));
    padding: 4px 14px 8px;
  }
  .kb-nav__sublink {
    display: block;
    padding: 10px 14px !important;
    font-size: 0.85rem !important;
    color: hsl(var(--foreground)) !important;
  }
}
/* Hide mobile-only sections on desktop. */
@media (min-width: 901px) {
  .kb-nav__mobile-section { display: none; }
  .kb-nav__utility { display: block; }
  /* Theme toggle joins the main row as an icon-only button on desktop */
  .kb-nav__theme-item { display: block; }
  .kb-nav__theme-label { display: none; }
  .kb-nav__theme { padding: 8px; }
  /* The floating page-corner toggle is redundant once the nav has one */
  .kb-theme-toggle { display: none !important; }
  /* Cap tall dropdowns to the viewport, minus the taller two-row header,
     so their lower items are never clipped below the fold. The nav is fixed,
     so an over-tall dropdown can't be scrolled to, it just gets cut off until
     you zoom out. Scroll inside the menu instead. */
  .kb-nav__menu {
    max-height: calc(100vh - 120px);
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  /* Products mega panel: three grouped columns. Mobile never sees this
     (below 901px the menu is position:static and stacks the columns). */
  .kb-nav__menu--mega {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    min-width: 500px;
    max-width: calc(100vw - 64px);
    flex-wrap: wrap;
  }
  .kb-nav__menu-col { min-width: 210px; flex: 1; }
}

/* ── LOGO SLIDER ────────────────────────────────────────────────────── */
.kb-logos {
  padding: 56px 32px;
  background: hsl(var(--background-elev));
  border-top: 1px solid hsl(var(--border));
  border-bottom: 1px solid hsl(var(--border));
  overflow: hidden;
}
.kb-logos__label {
  text-align: center;
  font-family: var(--font-sans);
  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: hsl(var(--muted-foreground-2));
  margin-bottom: 36px;
}
.kb-logos__track-wrap {
  max-width: 1600px;
  margin: 0 auto;
  overflow: hidden;
  mask-image: linear-gradient(90deg, transparent, black 6%, black 94%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, black 6%, black 94%, transparent);
}
.kb-logos__track {
  display: flex;
  align-items: center;
  gap: 88px;
  width: max-content;
  animation: kb-logo-scroll 120s linear infinite;
}
/* Pause-on-hover and scale-on-hover are scoped to actual mouse devices
   only (`hover: hover` + `pointer: fine`). On touchscreens iOS treats
   the first tap as a sticky :hover, which made tapped logos jitter
   and appear to "disappear" while the track was paused. */
@media (hover: hover) and (pointer: fine) {
  .kb-logos__track:hover { animation-play-state: paused; }
  .kb-logos__track img:hover { opacity: 1; transform: scale(1.06); }
  html.light .kb-logos__track img:hover,
  body.light .kb-logos__track img:hover {
    filter: grayscale(0%);
    opacity: 1;
  }
}

.kb-logos__track img {
  height: 84px;
  max-width: 240px;
  width: auto;
  object-fit: contain;
  flex-shrink: 0;
  opacity: 0.7;
  transition: opacity 0.3s, transform 0.3s, filter 0.3s;
  pointer-events: none; /* logos aren't links, keep iOS hover from latching */
}

/* DARK MODE, per-tone treatment so every logo reads on a #121212 surface:
   - Default (assumed "dark" = black/colored ink on transparent): invert to white
   - data-tone="light"  → already white/light, leave alone (just opacity)       */
.kb-logos__track img                       { filter: brightness(0) invert(1); }
.kb-logos__track img[data-tone="light"]    { filter: none; }
.kb-logos__track img[data-tone="dark"]     { filter: brightness(0) invert(1); }

/* LIGHT MODE, native colors, slight grayscale + dim. */
html.light .kb-logos__track img,
body.light .kb-logos__track img {
  filter: grayscale(100%);
  opacity: 0.55;
}

@keyframes kb-logo-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
@media (max-width: 700px) {
  .kb-logos { padding: 36px 16px; }
  .kb-logos__track { gap: 56px; animation-duration: 80s; }
  /* Bigger on mobile per request, easier to read at thumb distance */
  .kb-logos__track img { height: 80px; max-width: 220px; padding: 6px 0; opacity: 0.85; }
}

/* ── INSTAGRAM GRID ─────────────────────────────────────────────────── */
.kb-ig {
  padding: 64px 32px;
  background: hsl(var(--background));
  border-top: 1px solid hsl(var(--border));
}
.kb-ig__inner { max-width: 1120px; margin: 0 auto; }
.kb-ig__header {
  display: flex; align-items: center; justify-content: center;
  gap: 10px;
  margin: 0 auto 28px;
  color: hsl(var(--foreground));
  transition: color 0.2s;
}
.kb-ig__header:hover { color: hsl(var(--primary)); }
.kb-ig__glyph { width: 22px; height: 22px; flex: none; }
.kb-ig__handle {
  font-family: var(--font-condensed);
  font-size: 1.1rem; font-weight: 700; letter-spacing: 0.04em;
}
.kb-ig__follow {
  font-family: var(--font-condensed);
  font-size: 0.72rem; font-weight: 600;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: hsl(var(--muted-foreground-2));
  padding-left: 10px;
  border-left: 1px solid hsl(var(--border));
}
/* Behold's official widget renders the live grid inside .kb-ig__widget. The
   min-height reserves space so there's no layout jump before it populates. */
.kb-ig__widget { min-height: 220px; }
@media (max-width: 900px) {
  .kb-ig { padding: 48px 16px; }
  .kb-ig__header { flex-wrap: wrap; gap: 6px 10px; }
  .kb-ig__follow { border-left: none; padding-left: 0; }
}

/* ── FOOTER ─────────────────────────────────────────────────────────── */
.kb-footer {
  background: hsl(var(--sidebar-bg));
  border-top: 1px solid hsl(var(--border));
  padding: 60px 32px 28px;
}
.kb-footer__inner {
  max-width: 1280px;
  margin: 0 auto;
}
.kb-footer__grid {
  display: grid;
  grid-template-columns: 2fr repeat(4, 1fr) 2fr;
  gap: 40px 24px;
  margin-bottom: 40px;
}
@media (max-width: 1100px) {
  .kb-footer__grid { grid-template-columns: 1fr 1fr 1fr; }
  .kb-footer__brand { grid-column: 1 / -1; }
}
@media (max-width: 600px) {
  .kb-footer__grid { grid-template-columns: 1fr 1fr; }
}
.kb-footer__brand img {
  height: 28px;
  width: auto;
  margin-bottom: 14px;
  filter: var(--logo-filter);
}
.kb-footer__tagline {
  font-size: 0.85rem;
  color: hsl(var(--muted-foreground-2));
  line-height: 1.65;
  max-width: 300px;
}
.kb-footer__col-title {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: hsl(var(--foreground));
  margin-bottom: 14px;
}
/* Collapsible footer group (Koba Workflows) */
.kb-footer__collapse > summary.kb-footer__summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.kb-footer__collapse > summary.kb-footer__summary::-webkit-details-marker { display: none; }
.kb-footer__collapse > summary.kb-footer__summary::after {
  content: '+';
  font-size: 1.1rem;
  line-height: 1;
  color: hsl(var(--primary));
}
.kb-footer__collapse[open] > summary.kb-footer__summary::after { content: '\2212'; }
/* Koba Workflows links split into two aligned columns under the summary */
.kb-footer__collapse-grid {
  column-count: 2;
  column-gap: 22px;
  margin-top: 2px;
}
.kb-footer__collapse-grid .kb-footer__link { break-inside: avoid; }
@media (max-width: 700px) {
  .kb-footer__collapse-grid { column-count: 1; }
}
.kb-footer__link {
  display: block;
  font-size: 0.85rem;
  color: hsl(var(--muted-foreground-2));
  padding: 4px 0;
  transition: color 0.15s;
  text-decoration: none;
}
.kb-footer__link:hover,
.kb-footer__link.is-active {
  color: hsl(var(--primary));
}
.kb-footer__madein {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 10px;
  padding: 5px 10px;
  font-family: var(--font-condensed);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: hsl(var(--muted-foreground));
  border: 1px solid hsl(var(--border));
  border-radius: 6px;
}
.kb-footer__madein svg {
  width: 14px; height: 14px;
}
.kb-footer__bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-top: 24px;
  border-top: 1px solid hsl(var(--border));
  font-size: 0.78rem;
  color: hsl(var(--muted-foreground-2));
}
@media (max-width: 600px) {
  .kb-footer__bottom { flex-direction: column; gap: 8px; text-align: center; }
}

/* ════════════════════════════════════════════════════════════════════════
   HP-* SHARED COMPONENTS (Client Installations gallery, labels, buttons)
   Originally defined inline on the homepage; moved here so every PDP can
   render the same "Trusted by Bars and Hotels Worldwide" block.
   ══════════════════════════════════════════════════════════════════════ */
.hp-label {
  display: inline-flex; align-items: center;
  font-family: var(--font-condensed, 'Barlow Condensed', sans-serif);
  font-size: 0.72rem; font-weight: 600;
  letter-spacing: 0.25em; text-transform: uppercase;
  color: hsl(var(--primary));
  margin-bottom: 16px;
}
.hp-h2 {
  font-family: var(--font-display, 'Bebas Neue', sans-serif);
  font-size: clamp(2rem, 4vw, 3.2rem);
  line-height: 0.95;
  letter-spacing: 0.02em;
  font-weight: 400;
  color: hsl(var(--foreground));
  margin-bottom: 22px;
}
.hp-h2 em { color: hsl(var(--primary)); font-style: normal; }

.hp-btn {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--font-sans);
  font-weight: 500;
  padding: 12px 24px;
  border-radius: var(--radius);
  border: 1px solid transparent;
  text-decoration: none;
  transition: all 0.2s var(--ease);
}
.hp-btn--ghost {
  background: transparent;
  color: hsl(var(--foreground));
  border-color: hsl(var(--border));
}
.hp-btn--ghost:hover {
  border-color: hsl(var(--primary));
  color: hsl(var(--primary));
}
.hp-btn svg { width: 14px; height: 14px; }

/* ═══ FEATURED IN, press strip ═══
   Monochrome press wordmark strip used on homepage + every PDP.
   Logos are individual SVG files in /images/press/. */
.press-strip {
  padding: 48px 32px;
  background: hsl(var(--background-elev));
  border-top: 1px solid hsl(var(--border));
  border-bottom: 1px solid hsl(var(--border));
}
.press-strip__inner {
  max-width: 1280px;
  margin: 0 auto;
  text-align: center;
}
.press-strip__label {
  font-family: 'Barlow Condensed', sans-serif;
  font-size: 0.76rem; font-weight: 700;
  letter-spacing: 0.22em; text-transform: uppercase;
  color: hsl(var(--muted-foreground-2));
  margin: 0 0 28px;
}
.press-strip__logos {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 28px 56px;
  color: hsl(var(--muted-foreground));
}
.press-logo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 36px;
  opacity: 0.72;
  transition: opacity 0.2s ease;
}
.press-logo:hover { opacity: 1; }
.press-logo img {
  display: block;
  height: 100%;
  width: auto;
  max-width: 180px;
  filter: brightness(0) invert(0);
}
html:not(.light) .press-logo img,
body:not(.light) .press-logo img {
  filter: brightness(0) invert(1);
}
@media (max-width: 700px) {
  .press-strip { padding: 32px 20px; }
  .press-strip__label { margin-bottom: 20px; font-size: 0.7rem; }
  .press-strip__logos { gap: 18px 32px; }
  .press-logo { height: 26px; }
  .press-logo img { max-width: 130px; }
}

.hp-gallery {
  padding: 100px 32px;
  max-width: 1440px;
  margin: 0 auto;
}
.hp-gallery__inner { max-width: 1280px; margin: 0 auto; }
.hp-gallery__header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  margin-bottom: 40px;
  flex-wrap: wrap;
}
.hp-gallery__header-text { max-width: 640px; }
.hp-gallery__header .hp-h2 { margin-bottom: 0; }
.hp-gallery__header-sub {
  font-size: 1rem;
  color: hsl(var(--muted-foreground));
  line-height: 1.6;
  margin: 14px 0 0;
}
.hp-gallery__grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 14px;
}
@media (max-width: 1000px) { .hp-gallery__grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 720px)  { .hp-gallery__grid { grid-template-columns: repeat(2, 1fr); } }

.hp-gallery__item {
  position: relative;
  aspect-ratio: 4/3;
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid hsl(var(--border));
  text-decoration: none;
  display: block;
  background: hsl(var(--background-elev));
  transition: transform 0.3s var(--ease), border-color 0.3s;
}
.hp-gallery__item:hover {
  transform: translateY(-4px);
  border-color: hsl(350 72% 44% / 0.5);
}
.hp-gallery__item img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 0.6s var(--ease);
}
.hp-gallery__item:hover img { transform: scale(1.08); }
.hp-gallery__item-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: flex-end;
  padding: 16px;
  background: linear-gradient(to top,
    hsl(0 0% 0% / 0.85) 0%,
    hsl(0 0% 0% / 0.3) 55%,
    transparent 100%);
}
.hp-gallery__item-name {
  font-family: var(--font-sans);
  font-size: 0.95rem;
  font-weight: 600;
  color: hsl(0 0% 100%);
  line-height: 1.2;
}
.hp-gallery__item-loc {
  font-size: 0.78rem;
  color: hsl(0 0% 80%);
  margin-top: 4px;
}


/* Info-icon + CSS-only tooltip for Optional Add-Ons. Triggered by
   :hover, :focus, or .is-open (tap-to-toggle on mobile, wired in
   sale.js's tooltip helper or the inline addon click handler). */
.addon__info {
  appearance: none;
  flex-shrink: 0;
  width: 18px; height: 18px;
  margin-left: 4px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%;
  border: 1px solid hsl(var(--border-strong));
  background: transparent;
  color: hsl(var(--muted-foreground));
  font-family: 'Times New Roman', serif;
  font-style: italic;
  font-size: 0.78rem;
  font-weight: 700;
  line-height: 1;
  cursor: help;
  padding: 0;
  position: relative;
  transition: color 0.15s, border-color 0.15s;
}
.addon__info:hover,
.addon__info:focus,
.addon__info.is-open {
  color: hsl(var(--foreground));
  border-color: hsl(var(--foreground));
  outline: none;
}
.addon__info::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  width: max-content;
  max-width: 280px;
  padding: 10px 12px;
  background: hsl(var(--background-elev-2));
  color: hsl(var(--foreground));
  font-family: inherit;
  font-style: normal;
  font-size: 0.78rem;
  font-weight: 400;
  line-height: 1.45;
  letter-spacing: 0;
  text-align: left;
  border: 1px solid hsl(var(--border));
  border-radius: var(--radius);
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.3);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s;
  z-index: 60;
  white-space: normal;
}
.addon__info:hover::after,
.addon__info:focus::after,
.addon__info.is-open::after {
  opacity: 1;
  pointer-events: auto;
}
@media (max-width: 640px) {
  /* On mobile the tooltip escapes the row and becomes a viewport-fixed
     banner near the top of the screen (below the nav). The icon's
     position in the row varies based on addon name length, so anchoring
     to the icon's right edge pushed the tooltip off the left side of
     the viewport on long content. Fixed positioning sidesteps all that
     and is the standard mobile tooltip / toast pattern. */
  .addon__info::after {
    position: fixed;
    top: 80px;
    left: 16px;
    right: 16px;
    bottom: auto;
    transform: none;
    width: auto;
    max-width: none;
    font-size: 0.82rem;
    padding: 12px 14px;
    box-shadow: 0 12px 28px rgba(0, 0, 0, 0.55);
    z-index: 999;
  }
}


/* Bar Size picker, portable-bar PDP. Three buttons in a row showing
   the size, "Standalone" subtitle, and per-size estimated lead time.
   Clicking a button is a regular link that reloads with ?sku=… so the
   page re-renders against the new SKU's PRODUCTS data. */
.size-picker {
  margin: 16px 0 4px;
}
.size-picker__label {
  font-family: var(--font-condensed);
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: hsl(var(--muted-foreground));
  margin-bottom: 10px;
}
.size-picker__btns {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}
.size-picker__btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 12px 6px;
  background: hsl(var(--background));
  border: 1px solid hsl(var(--border));
  border-radius: var(--radius);
  color: hsl(var(--foreground));
  text-decoration: none;
  transition: border-color 0.15s, background 0.15s, transform 0.15s;
  text-align: center;
  cursor: pointer;
}
.size-picker__btn:hover {
  border-color: hsl(var(--border-strong));
  background: hsl(var(--background-elev-2));
}
.size-picker__btn.is-active {
  border-color: hsl(var(--primary));
  background: hsla(var(--primary), 0.07);
}
.size-picker__size {
  font-family: var(--font-display);
  font-size: 1.25rem;
  font-weight: 400;
  line-height: 1;
  letter-spacing: 0.02em;
}
.size-picker__sub {
  font-size: 0.62rem;
  color: hsl(var(--muted-foreground));
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.size-picker__lead {
  margin-top: 4px;
  font-size: 0.66rem;
  color: hsl(var(--muted-foreground));
  letter-spacing: 0.02em;
}
@media (max-width: 600px) {
  .size-picker__btn { padding: 10px 4px; }
  .size-picker__size { font-size: 1.1rem; }
  .size-picker__lead { font-size: 0.6rem; }
}

/* On mobile the PDP's .info container becomes display:contents and its
   children get explicit `order` values to control vertical layout (header
   first, gallery second, addons/CTA at order:3, etc.). The size picker
   is a direct child of .info, match the order:3 group so it sits
   right above the Optional Add-Ons block on phone viewports instead of
   jumping to the very top of the column (its default order:0). */
@media (max-width: 960px) {
  .info > .size-picker { order: 3; }
}


/* Wider variant of size picker, 5 buttons for use-case PDPs
   (coffee/juice/mocktail) where size AND installation both vary.
   Auto-fits at 110px min so it gracefully wraps to fewer columns on
   tablet + mobile. */
.size-picker__btns--5 {
  grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
}
@media (max-width: 480px) {
  .size-picker__btns--5 { grid-template-columns: repeat(2, 1fr); }
}

/* ── ElevenLabs voice widget: kill-switch ─────────────────────────────────
   The widget is currently off everywhere (CONVAI_ON in shell.js). This rule
   catches the case shell.js cannot: a stale cached shell.js still injecting
   the element. Narrow it back to (max-width: 900px) when the widget returns
   to desktop, so it stays off mobile where the fixed bottom bar lives. */
elevenlabs-convai { display: none !important; }

/* ═══════════════════════════════════════════════════════════════════════
   LIGHT MODE READABILITY
   The status pill and the product stage were coloured for a dark page and
   wash out on a pale one. Every value below was measured against its own
   tinted background and clears 4.5:1.
   ═══════════════════════════════════════════════════════════════════════ */

/* Scarcity pill: the 400-level status colours sit at 1.8-3.4:1 on light. */
html.light .kb-scarcity__row--green  { color: #15803d; }
html.light .kb-scarcity__row--yellow { color: #a16207; }
html.light .kb-scarcity__row--orange { color: #c2410c; }
html.light .kb-scarcity__row--red    { color: #b91c1c; }
html.light .kb-scarcity__dot--green  { background: #15803d; }
html.light .kb-scarcity__dot--yellow { background: #a16207; }
html.light .kb-scarcity__dot--orange { background: #c2410c; }
html.light .kb-scarcity__dot--red    { background: #b91c1c; }
html.light .kb-scarcity__note        { color: hsl(var(--muted-foreground)); }
/* Firmer tints so the pill still reads as a panel on the off-white page. */
html.light .kb-scarcity--healthy { border-color: rgba(21, 128, 61, 0.34);  background: rgba(21, 128, 61, 0.07); }
html.light .kb-scarcity--last    { border-color: rgba(185, 28, 28, 0.34);  background: rgba(185, 28, 28, 0.06); }
html.light .kb-scarcity--slots   { border-color: rgba(194, 65, 12, 0.34);  background: rgba(194, 65, 12, 0.07); }
html.light .kb-scarcity--booked  { border-color: rgba(185, 28, 28, 0.42);  background: rgba(185, 28, 28, 0.09); }

/* ── "Slots fill up fast" note ─────────────────────────────────────────
   Trails the slot count as quiet text rather than a bordered chip, which
   read as clutter inside a pill that is already outlined and tinted. It
   takes the row's own colour at reduced weight and opacity, so it recedes
   behind the slot count while still carrying the nudge, and follows the
   light-mode overrides above without a second set of rules.
   The two-class selector beats the base .kb-scarcity__row rule that each
   product page still carries inline, so the row can wrap onto a second
   line on narrow screens instead of overflowing the pill. */
.kb-scarcity .kb-scarcity__row { flex-wrap: wrap; row-gap: 2px; align-items: flex-start; }
/* The row text is now its own span so it can shrink and wrap in place. Before
   this it was a bare text node, i.e. an anonymous flex item, which cannot wrap
   beside a sibling: the moment it stopped fitting next to the dot the whole
   item dropped to the next line and left the dot sitting alone on its own row.
   min-width:0 is what actually permits the shrink; flex-basis alone does not. */
/* flex-basis MUST be 0, not auto. With wrap enabled the browser decides line
   breaks from the hypothetical main size, so an auto basis means the text is
   measured at its full width, does not fit beside the dot, and wraps to the
   next line before flex-shrink is ever consulted. A zero basis makes it always
   fit, then grow into the space left over. */
.kb-scarcity .kb-scarcity__text { flex: 1 1 0; min-width: 0; }
/* Rows are top-aligned now so the dot stays on the first line of wrapped text.
   The nudge re-centres the 8px dot against that first line. */
.kb-scarcity .kb-scarcity__dot { margin-top: 0.42em; }
.kb-scarcity__urgent {
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.01em;
  white-space: nowrap;
  color: currentColor;
  opacity: 0.6;
}

/* Product stage only: the page itself stays white, but the panel the station
   hovers on gets a soft off-white field. The renders are near-black and read
   as cut-outs against pure white. The red bloom goes too, which showed as a
   pink smear once the page turned pale. */
html.light .gallery__main,
html.light .cbd-tt__stage {
  background: linear-gradient(180deg, hsl(40 14% 94%) 0%, hsl(42 12% 90%) 100%);
}

/* Quote form: the injected stylesheet hardcodes light-grey helper text that
   drops under 3:1 once the page is pale. */
html.light .kbq-modal__sub,
html.light .kbq-step-sub,
html.light .kbq-progress__label,
html.light .kbq-prod-price,
html.light .kbq-spec,
html.light .kbq-spec--dims,
html.light .kbq-opt { color: hsl(var(--muted-foreground)) !important; }
html.light .kbq-modal__close { color: hsl(var(--muted-foreground)) !important; }
html.light .kbq-prod-name,
html.light .kbq-step-title,
html.light .kbq-section__label { color: hsl(var(--foreground)) !important; }

/* ═══════════════════════════════════════════════════════════════════════
   TOPICAL LINK MESH
   The in-content block that ties each page to its pillar and its siblings.
   Deliberately quiet: no underlines, no bold, so it reads as a related list
   rather than a call to action, while still being real links in the markup.
   ═══════════════════════════════════════════════════════════════════════ */
.kb-mesh {
  max-width: 1080px;
  margin: 0 auto;
  padding: 34px 32px 40px;
  border-top: 1px solid hsl(var(--border));
}
.kb-mesh__label {
  display: block;
  font-family: var(--font-condensed, var(--font-sans));
  font-size: 0.7rem; font-weight: 600;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: hsl(var(--muted-foreground-2));
  margin-bottom: 14px;
}
.kb-mesh__links {
  display: flex; flex-wrap: wrap;
  gap: 10px 26px;
}
.kb-mesh__links a {
  font-size: 0.88rem;
  color: hsl(var(--muted-foreground));
  text-decoration: none;
  border-bottom: 0;
  transition: color 0.15s ease;
}
.kb-mesh__links a:hover { color: hsl(var(--primary)); }
.kb-mesh__links a:focus-visible { outline: 2px solid hsl(var(--primary)); outline-offset: 3px; }
@media (max-width: 700px) {
  .kb-mesh { padding: 26px 20px 30px; }
  .kb-mesh__links { gap: 9px 20px; }
}

/* ── Quote CTA ──────────────────────────────────────────────────────────
   The quote button used .btn--primary, the same crimson as Add to Cart, so
   the page's two calls to action competed rather than ranked. This uses
   --kobayashi-gold, already declared in the palette and otherwise unused, so
   it is on brand while clearly not the buy button.

   Dark ink on gold, not white: white on this gold is 2.25:1 and fails contrast
   outright, while near-black is 8.34:1 and passes AAA. It also reads like a
   brass plate rather than a warning label. */
.btn--quote {
  background: hsl(var(--kobayashi-gold));
  color: #121212;
  border-color: hsl(var(--kobayashi-gold));
  font-weight: 700;
}
.btn--quote:hover {
  background: hsl(43 74% 55%);
  border-color: hsl(43 74% 55%);
  color: #121212;
}
.btn--quote svg { color: #121212; }


/* ── Product page: timeline note + social proof ──────────────────────────
   Injected by shell.js on the station PDPs, so the styling lives here rather
   than inline in nine near-identical pages that would drift apart. */
/* ── PDP: scarcity pill sits below the reassurance strip ─────────────────
   On phones the mobile order rules already put it there. On desktop it sat
   up in the info header, above the price separator and the button, so the
   two screens told the story in a different order. Moving it here on every
   width means the block reads the same way everywhere: price, button, what
   the quote costs you (nothing), then how long the wait is.

   .info__header is display:contents only below 960px, so on desktop the pill
   is still a child of it and cannot be reordered by the grid. Pulling it out
   of flow order is done with a negative-free flex order on .info instead. */
@media (min-width: 961px) {
  .info { display: flex; flex-direction: column; }
  .info > .info__header { display: contents; }
  .info__header > * { order: 1; }
  .info__header > .kb-scarcity-wrap,
  .info__header > .info__stock-note,
  .info__header > .kb-alts { order: 5; margin-top: 12px; }
  .info > .separator      { order: 2; }
  .info > .lead-note      { order: 2; }
  .info > #requestQuoteBtn { order: 3; }
  .info > .cta-assure     { order: 4; }
  .info > *               { order: 6; }
}

/* ── PDP: risk-reversal strip under the quote CTA ────────────────────────
   Injected by shell.js on the station PDPs. Sits directly below the button so
   it answers "what happens if I click" at the moment that question is asked.

   Mobile first, because that is where it has to survive: at 390px the three
   claims stack into a single column and read as a short list, and only from
   560px do they sit on one row. A flex row here would either squeeze the
   labels to two characters a line or push the container wider than the
   viewport, which is the failure mode the rest of this page has already had
   once. min-width:0 on the item lets long labels wrap rather than force the
   grid open. */
.cta-assure {
  list-style: none;
  margin: 10px 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
}
.cta-assure__item {
  display: flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
  font-family: var(--font-sans);
  font-size: 0.78rem;
  line-height: 1.35;
  color: hsl(var(--muted-foreground));
}
.cta-assure__item svg {
  width: 15px;
  height: 15px;
  flex: 0 0 15px;
  color: hsl(var(--kobayashi-gold));
  opacity: 0.95;
}
.cta-assure__item span { min-width: 0; }

/* Wrapping beats a breakpoint here: the three claims sit on one row wherever
   they fit and drop to the next line when they do not, so the strip adapts to
   the label lengths instead of to a width someone guessed. */
@media (min-width: 560px) {
  .cta-assure { gap: 6px 16px; }
  .cta-assure__item { font-size: 0.75rem; }
}

/* The copper A/B arm recolours the CTA, so the icons follow it rather than
   sitting gold against a copper button. */
:root.kb-ab-cta-copper .cta-assure__item svg { color: #C96B2C; }

/* Ordering on the narrow single-column PDP layout, so the strip stays with
   the button instead of drifting below the social proof. */
@media (max-width: 960px) {
  .info > .cta-assure { order: 7; }
}

.lead-note {
  margin: 0 0 8px;
  font-size: 0.8rem;
  line-height: 1.5;
  color: hsl(var(--muted-foreground));
}
.social-proof {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 14px 0 2px;
  font-size: 0.83rem; line-height: 1.5;
  color: hsl(var(--muted-foreground));
}
.social-proof__chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px 4px 8px;
  border: 1px solid hsl(var(--border-strong));
  border-radius: 100px;
  font-family: var(--font-mono);
  font-size: 0.74rem; font-weight: 500;
  color: hsl(var(--foreground));
  text-decoration: none;
  transition: border-color .15s, color .15s;
}
.social-proof__chip:hover { border-color: hsl(var(--primary)); color: hsl(var(--primary)); }
.social-proof__chip svg { width: 14px; height: 14px; flex-shrink: 0; }
/* Brand marks keep their own colour so each platform is recognisable at a
   glance; the hover state recolours the count, not the mark. */
.social-proof__chip--yt svg { color: #FF0000; }
.social-proof__chip--ig svg { color: #E1306C; }

/* Mobile reflow. The .info column is explicitly ordered below 960px, so an
   element without an order rule falls to 0 and jumps above the product title.
   6 matches the quote CTA, and DOM order keeps the note above it; 8 is the
   slot the removed design-help link left behind. */
@media (max-width: 960px) {
  .info > .lead-note    { order: 6; }
  .info > .social-proof { order: 8; }
}


/* ── Narrow screens: let long buttons wrap ───────────────────────────────
   .btn carries `white-space: nowrap` and a fixed 46px height. A button with a
   long label therefore cannot shrink: it sizes to its text and pushes the
   document wider than the viewport. On a 320px screen "Learn more about the
   Portable Bar" measures 325px inside a 272px column, which is what makes the
   page pannable, and because a fixed nav then sizes to that wider document you
   get a full-width header above content that stops short of the right edge.

   Scoped by `body` rather than a bare `.btn`, because each product page ships
   its own inline `.btn` rule after this sheet loads and would otherwise win.
   Height goes auto so a wrapped label is not clipped by the fixed 46px. */
@media (max-width: 430px) {
  body .btn {
    white-space: normal;
    max-width: 100%;
    height: auto;
    min-height: 46px;
    padding-top: 10px;
    padding-bottom: 10px;
    text-align: center;
    line-height: 1.35;
  }
}

/* ── PDP above the fold on phones ────────────────────────────────────────
   Goal: title, price, viewer, thumbnails and the quote button all visible
   without scrolling. Measured at 390x844 the button used to finish at 1298px,
   roughly 550px below the fold once the 81px bottom bar is subtracted.

   These live here rather than in the nine PDP files so one edit reaches all
   of them, which means they load BEFORE each page's inline <style> and have
   to out-specify it. Hence the body/html prefixes: they add specificity, not
   meaning.

   Nothing is deleted. The long description moves below the button, where it
   is still read by anyone who scrolls and by every crawler. */
@media (max-width: 640px) {
  /* 120px of top padding cleared a 60px nav twice over. */
  html body main.pdp { padding-top: 68px; padding-bottom: 40px; }

  /* Back link: still there, just not costing 58px of the first screen. */
  body .back-link {
    padding: 2px 8px 2px 4px;
    font-size: 0.78rem;
    margin-bottom: 2px;
  }
  body .back-link svg { width: 13px; height: 13px; }

  body .pdp__grid { gap: 12px !important; }

  /* The classless wrapper around the H1 and the description is the only one
     in .info__header, and dissolving it lets the two be ordered apart. */
  body .info__header > div:not([class]) { display: contents; }

  body .info__title {
    order: 1;
    font-size: clamp(1.35rem, 6.2vw, 1.7rem);
    line-height: 1.12;
    margin: 0;
  }
  /* Below the CTA. It is the one block on this screen that sells nothing a
     buyer cannot see in the render. */
  body .info__desc { order: 9; margin-top: 10px; }

  /* Same treatment for the portable-bar 3D note. 76px of caster and water-tank
     detail sat between the back link and the title on that page alone, which
     is why it was the only station whose button would not fit. */
  body .pb-3d-note { order: 9; margin-top: 10px; }

  /* Category / SKU / install tags are hidden on phones. They are reference
     detail, not a reason to buy, and they sat between the title and the
     stage. NOTE this leaves the SKU with no visible home on mobile: Quick
     Specs carries dimensions, weight, ice, crew, throughput and lead time,
     but not the item number. It stays in the JSON-LD, on desktop, and on
     every quote and invoice. */
  body .info__badges { display: none; }

  body .info__header > .info__price-row { order: 3; margin-top: 0; }
  body .info__price { font-size: 1.55rem; }

  /* A square-ish stage instead of a portrait one: the station is a wide
     object, so the taller box was mostly empty space above and below it. */
  body .gallery__main { aspect-ratio: 1 / 0.80 !important; }

  /* One scrollable row rather than two stacked rows of six. */
  body .thumbs {
    display: flex !important;
    grid-template-columns: none !important;
    min-width: 0;
    max-width: 100%;
    overflow-x: auto;
    gap: 6px;
    margin-top: 8px;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  body .thumbs::-webkit-scrollbar { display: none; }
  body .thumbs > * {
    flex: 0 0 52px;
    width: 52px;
    scroll-snap-align: start;
  }

  /* The scarcity pill moves to just under the button. It is ~85px, the
     largest block still sitting between the price and the CTA, and urgency
     reads just as well immediately after the action as before it. It stays
     fully visible, directly beneath the button with the reassurance strip. */
  body .info__header > .kb-scarcity-wrap { order: 8; margin-top: 10px; }
  body .info__header > .info__stock-note { order: 8; }
  body .info__header > .kb-alts          { order: 8; }

  /* Size picker: 196px on the four PDPs that carry one, in a wrapping grid of
     five tall buttons. It is a real product choice and belongs before the CTA,
     so it is compacted rather than moved: one horizontally scrollable row of
     short buttons, install type dropped since the badges above already say it.
     Roughly 196px becomes 55px. */
  body .size-picker__label { font-size: 0.7rem; margin-bottom: 3px; }
  /* min-width:0 and max-width:100% are what actually make an overflow-x row
     safe inside a grid/flex parent. Without them the row sizes to its content
     and widens the page instead of scrolling, which is the horizontal-overflow
     bug this site has hit before. */
  body #sizePicker { min-width: 0; max-width: 100%; }
  body .size-picker__btns,
  body .size-picker__btns--5 {
    display: flex !important;
    grid-template-columns: none !important;
    min-width: 0;
    max-width: 100%;
    overflow-x: auto;
    gap: 6px;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  body .size-picker__btns::-webkit-scrollbar { display: none; }
  body .size-picker__btn {
    flex: 0 0 auto;
    flex-direction: row;
    padding: 7px 12px;
    min-height: 0;
    font-size: 0.82rem;
    white-space: nowrap;
    scroll-snap-align: start;
  }
  body .size-picker__sub { display: none; }

  body .info > .separator { margin: 4px 0; }
  body #requestQuoteBtn { margin-top: 0; }
}

/* The narrowest phones still in use (320px, original SE) have ~619px of
   usable height once the bottom bar is subtracted, which is 40px less than
   the layout above needs. A shorter stage closes it. Kept in its own query so
   nothing wider is affected. */
@media (max-width: 340px) {
  body .gallery__main { aspect-ratio: 1 / 0.80 !important; }
  body .thumbs > * { flex: 0 0 44px; width: 44px; }
  body .info__title { font-size: 1.25rem; }
  body .info__price { font-size: 1.4rem; }
  body .pdp__grid { gap: 9px !important; }
}

/* ── Horizontal overflow on phones ───────────────────────────────────────
   A page that scrolls sideways makes every full-bleed image stop short of
   the right edge, because width:100% is the viewport while the document is
   wider. That is why the split-section photos looked inset rather than
   edge-to-edge. Three unrelated causes, found by measuring all 89 pages at
   390px; these were the only three still overflowing. */
@media (max-width: 640px) {
  /* 1. Hand-written pillar-link sections carry an inline
        grid-template-columns:repeat(3,1fr) with no mobile fallback. 1fr has a
        min-content floor, so the cards refuse to shrink and push the page
        open. Inline styles need !important to override. 13 instances of the
        3-column form, 5 of the 4-column, across 29 pages. */
  [style*="grid-template-columns:repeat(3,1fr)"],
  [style*="grid-template-columns:repeat(4,1fr)"] {
    grid-template-columns: 1fr !important;
  }

  /* 2. Covered by the aspect-ratio guard at the end of this file, which
        applies to every such pairing rather than just this one. */

  /* 3. The lead-time comparison table is wider than a phone and had nowhere
        to go. It scrolls now rather than dragging the page with it. */
  body .compare-wrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
}

/* ── aspect-ratio + min-height: pin the width ────────────────────────────
   An element with BOTH aspect-ratio and min-height can resolve either way.
   When min-height wins, the ratio is free to derive the WIDTH from that
   height instead of the height from the width, and the block renders
   narrower than its column:

     .pdp-x-split__img   4/3 + min-height 240px  ->  240 x 4/3 = 320px
     .hp-split__image    4/3 + min-height 320px  ->  320 x 4/3 = 427px

   320px inside a 390px column is 82% of the width, which is exactly the
   short right edge these full-bleed photos have been showing. Chromium
   resolves it the other way, which is why this survived several headless
   passes; Safari does not, and Safari is most of the traffic here.

   Pinning the width settles it in every engine: the ratio can then only
   drive the height. Deliberately outside any media query, because the
   ambiguity is not width-dependent, and applied to every pairing on the site
   rather than the two that were reported, since the next one would fail in
   exactly the same way. */
.pdp-x-split__img,
.hp-split__image,
.hp-gallery__item,
.gallery__main {
  width: 100%;
  max-width: 100%;
}


/* ── PDP: outcome bullets, tighter CTA run, micro review ─────────────────
   All injected by shell.js, so every product page picks them up from here
   rather than from sixteen copies of the same markup. */

/* order:1 matches the title's. Under 961px the wrapper div around the title
   goes display:contents, so the H1 and this list become siblings in the same
   flex layout: the title carries order 1 and this defaulted to 0, which put
   the bullets above the product name. Same order plus later source order puts
   them back underneath. */
.info__wins { list-style: none; margin: 2px 0 0; padding: 0; display: grid; gap: 7px; order: 1; }
.info__wins li {
  display: flex; gap: 8px; align-items: flex-start; min-width: 0;
  font-size: 0.9rem; line-height: 1.45; color: hsl(var(--foreground));
}
.info__wins svg {
  width: 15px; height: 15px; flex: 0 0 15px; margin-top: 2px;
  color: hsl(var(--primary));
}
.info__wins span { min-width: 0; }

/* The price sat 37px clear of the button: an 18px flex gap either side of the
   hairline. Pulling the rule in on both sides closes it to about 21px without
   losing the divider. */
.info > .separator { margin-top: -8px; margin-bottom: -8px; }

/* Micro review under the production-slots note. Fixed height and stacked
   slides, so rotating one in never moves the page under someone's cursor.
   Same flex order as the scarcity pill it follows; source order does the
   rest. */
@media (min-width: 961px) {
  .info__header > .kb-microrev, .info > .kb-microrev { order: 5; }
}
@media (max-width: 960px) {
  .info__header > .kb-microrev, .info > .kb-microrev { order: 4; }
}
.kb-microrev {
  border: 1px solid hsl(var(--border));
  border-radius: var(--radius, 8px);
  background: hsl(var(--background-elev));
  padding: 12px 14px 10px;
}
/* All three slides share one grid cell, so the stage is always as tall as
   the tallest of them and the page cannot step as they rotate. Sizing it by
   hand would mean a magic number that clips the moment a review is reworded,
   which is exactly what happened when the summaries became the customers'
   own sentences. visibility:hidden rather than display:none so the inactive
   slides still contribute their height. */
.kb-microrev__stage { display: grid; }
.kb-microrev__item {
  grid-area: 1 / 1; margin: 0;
  opacity: 0; visibility: hidden;
  transition: opacity .35s ease;
}
.kb-microrev__item.is-on { opacity: 1; visibility: visible; }
.kb-microrev__stars {
  display: block; color: hsl(var(--kobayashi-gold, 43 74% 49%));
  font-size: 0.72rem; letter-spacing: 1px; line-height: 1;
}
.kb-microrev__item blockquote {
  margin: 5px 0 6px; padding: 0;
  font-size: 0.9rem; line-height: 1.4; font-weight: 600;
  color: hsl(var(--foreground));
}
.kb-microrev__item figcaption {
  display: flex; gap: 6px; flex-wrap: wrap;
  font-size: 0.76rem; line-height: 1.3;
}
.kb-microrev__item figcaption b { color: hsl(var(--foreground)); font-weight: 700; }
.kb-microrev__item figcaption span { color: hsl(var(--muted-foreground)); }
.kb-microrev__dots { display: flex; gap: 5px; margin-top: 8px; }
.kb-microrev__dot {
  width: 6px; height: 6px; padding: 0; border: 0; border-radius: 50%;
  background: hsl(var(--border)); cursor: pointer;
  transition: background .2s, width .2s;
}
.kb-microrev__dot.is-on { background: hsl(var(--primary)); width: 14px; border-radius: 3px; }
@media (prefers-reduced-motion: reduce) {
  .kb-microrev__item { transition: none; }
}


/* ── Full review section (homepage block, reused on the PDPs) ────────────
   Injected by shell.js between the spec tabs and the capacity calculator.
   Lives here beside .hp-gallery and .hp-h2, the other homepage components
   the product pages borrow. */
.hp-reviews { padding: 100px 32px; max-width: 1440px; margin: 0 auto; }
.hp-reviews__inner { max-width: 1280px; margin: 0 auto; }
.hp-reviews__header {
  display: flex; justify-content: space-between; align-items: flex-end;
  gap: 24px; margin-bottom: 40px; flex-wrap: wrap;
}
.hp-reviews__header .hp-h2 { margin-bottom: 0; }
.hp-reviews__stars { font-size: 1.5rem; color: hsl(var(--primary)); letter-spacing: 0.1em; }
.hp-reviews__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
@media (max-width: 900px) { .hp-reviews__grid { grid-template-columns: 1fr; } }
@media (max-width: 640px) { .hp-reviews { padding: 64px 16px; } }
.hp-review {
  padding: 28px;
  background: hsl(var(--background-elev));
  border: 1px solid hsl(var(--border));
  border-radius: var(--radius-lg, 12px);
  transition: border-color .25s var(--ease, ease), transform .25s var(--ease, ease), box-shadow .25s var(--ease, ease);
  display: flex; flex-direction: column; gap: 16px;
}
.hp-review:hover {
  border-color: hsl(350 72% 44% / 0.4);
  transform: translateY(-3px);
  box-shadow: var(--shadow-md, 0 10px 30px rgba(0,0,0,.35));
}
.hp-review__stars { font-size: 0.95rem; color: hsl(var(--primary)); letter-spacing: 0.1em; }
.hp-review__text { font-size: 0.95rem; color: hsl(var(--foreground)); line-height: 1.6; font-style: italic; }
.hp-review__author {
  display: flex; align-items: center; gap: 12px;
  padding-top: 14px; border-top: 1px solid hsl(var(--border)); margin-top: auto;
}
.hp-review__avatar {
  width: 42px; height: 42px; border-radius: 50%;
  background: hsl(var(--primary)); color: hsl(var(--white, 0 0% 100%));
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-condensed); font-weight: 700; font-size: 0.9rem;
  letter-spacing: 0.05em; flex-shrink: 0;
}
.hp-review__name { font-size: 0.92rem; font-weight: 600; color: hsl(var(--foreground)); }
.hp-review__venue { font-size: 0.78rem; color: hsl(var(--muted-foreground)); margin-top: 1px; }
.hp-review__verified { font-size: 0.72rem; color: hsl(142 71% 55%); font-weight: 500; margin-top: 3px; }
@media (prefers-reduced-motion: reduce) { .hp-review { transition: none; } .hp-review:hover { transform: none; } }


/* ── Quote CTA: an occasional glow ───────────────────────────────────────
   A slow pulse that draws the eye back to the button without ever being a
   thing that blinks at you. The cycle is 16s and the glow occupies about a
   second and a half of it, so it reads as an occasional breath rather than
   an animation running in your peripheral vision. Delayed 8s so it never
   fires while the page is still settling.

   Tied to the gold the button is actually painted in, and it inherits the
   copper A/B variant below, so the halo can never disagree with the button
   it is around. */
@keyframes kbCtaGlow {
  0%, 84%, 100% { box-shadow: 0 0 0 0 hsl(var(--kb-cta-glow) / 0); }
  90%           { box-shadow: 0 0 0 5px hsl(var(--kb-cta-glow) / 0.16),
                              0 0 24px 3px hsl(var(--kb-cta-glow) / 0.42); }
  96%           { box-shadow: 0 0 0 0 hsl(var(--kb-cta-glow) / 0); }
}
#requestQuoteBtn {
  --kb-cta-glow: var(--kobayashi-gold, 43 74% 49%);
  animation: kbCtaGlow 16s ease-in-out 8s infinite;
}
:root.kb-ab-cta-copper #requestQuoteBtn { --kb-cta-glow: 24 67% 48%; }
/* Never while someone is interacting with it. */
#requestQuoteBtn:hover, #requestQuoteBtn:focus-visible, #requestQuoteBtn:active { animation: none; }
@media (prefers-reduced-motion: reduce) { #requestQuoteBtn { animation: none; } }


/* ── PDP: badge row off ──────────────────────────────────────────────────
   Category, SKU and install type were the first thing in the info column,
   above the product name. The name should lead. The badges stay in the DOM
   because their text is still useful to crawlers and the SKU is read from
   there; they are just no longer the opening line. */
/* body scope, same as the mobile rule further up: each product page
   defines .info__badges in its own inline <style>, which the browser
   applies after this file, so a bare .info__badges here loses to it. */
body .info__badges { display: none; }

/* ══════════════════════════════════════════════════════════════════════
   SHORTS STRIP + VIEWER (product pages)
   A scroll-snapped rail of vertical posters that matches the product
   gallery's video thumbs, and a modal that plays one clip at a time.
   The posters are the only thing that loads with the page; the player
   iframe is created on open and removed on close.
   ══════════════════════════════════════════════════════════════════════ */
.kb-shorts { padding: 0 32px 56px; max-width: 1440px; margin: 0 auto; }
.kb-shorts__inner { max-width: 1280px; margin: 0 auto; }
.kb-shorts__header {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 24px; margin-bottom: 28px;
}
.kb-shorts__header .hp-h2 { margin-bottom: 0; }
.kb-shorts__sub {
  margin: 12px 0 0; max-width: 52ch;
  font-size: 0.95rem; line-height: 1.6;
  color: hsl(var(--muted-foreground));
}
.kb-shorts__nav { display: flex; gap: 8px; flex: 0 0 auto; }
.kb-shorts__arrow {
  width: 40px; height: 40px; display: grid; place-items: center;
  border: 1px solid hsl(var(--border-strong)); border-radius: 999px;
  background: hsl(var(--background-elev)); color: hsl(var(--foreground));
  cursor: pointer; transition: border-color 0.2s, color 0.2s, opacity 0.2s;
}
.kb-shorts__arrow svg { width: 18px; height: 18px; }
.kb-shorts__arrow--next svg { transform: rotate(180deg); }
.kb-shorts__arrow:hover:not(:disabled) { border-color: hsl(var(--primary)); color: hsl(var(--primary)); }
.kb-shorts__arrow:disabled { opacity: 0.3; cursor: default; }

.kb-shorts__rail {
  display: flex; gap: 14px;
  overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  padding-bottom: 6px;
  scrollbar-width: none;
}
.kb-shorts__rail::-webkit-scrollbar { display: none; }

.kb-short {
  position: relative; flex: 0 0 auto;
  width: clamp(132px, 15vw, 186px); aspect-ratio: 9 / 16;
  padding: 0; border: 1px solid hsl(var(--border));
  border-radius: var(--radius); overflow: hidden;
  background: #000; cursor: pointer;
  scroll-snap-align: start;
  transition: border-color 0.2s, transform 0.2s;
}
/* The poster YouTube guarantees for every video is a 480x360 frame with
   the vertical clip pillarboxed in it; cover inside this 9:16 card crops
   the black bars off and leaves the real frame. */
.kb-short img { width: 100%; height: 100%; object-fit: cover; display: block; }
.kb-short:hover { border-color: hsl(var(--primary)); transform: translateY(-2px); }
.kb-short__play {
  position: absolute; inset: 0; margin: auto;
  width: 42px; height: 42px; display: grid; place-items: center;
  border-radius: 999px; background: rgba(0, 0, 0, 0.45);
  color: #fff; backdrop-filter: blur(2px);
  transition: background 0.2s;
}
.kb-short__play svg { width: 16px; height: 16px; margin-left: 2px; }
.kb-short:hover .kb-short__play { background: rgba(0, 0, 0, 0.68); }
.kb-short__ep {
  position: absolute; left: 8px; bottom: 8px;
  font-family: var(--font-mono, monospace);
  font-size: 0.62rem; letter-spacing: 0.08em;
  padding: 3px 7px; border-radius: 4px;
  background: rgba(0, 0, 0, 0.6); color: #fff;
}
.kb-shorts__all {
  display: inline-block; margin-top: 18px;
  font-size: 0.85rem; letter-spacing: 0.04em;
  color: hsl(var(--muted-foreground)); text-decoration: none;
  border-bottom: 1px solid hsl(var(--border-strong));
  padding-bottom: 2px;
}
.kb-shorts__all:hover { color: hsl(var(--primary)); border-bottom-color: hsl(var(--primary)); }

@media (max-width: 900px) {
  .kb-shorts__header { flex-direction: column; align-items: flex-start; }
  .kb-shorts__nav { display: none; }
}
@media (max-width: 640px) {
  .kb-shorts { padding: 0 16px 40px; }
  .kb-short { width: 132px; }
}

/* Viewer. Arrows are flex siblings of the clip rather than absolutely
   placed off the viewport centre, so they stay beside it at any height. */
body.kb-sv-lock { overflow: hidden; }
/* The sticky phone tab bar would otherwise sit under the clip and take the
   corner the Next arrow needs. The viewer is a full-screen surface; the bar
   comes back on close. */
body.kb-sv-lock .kb-mobilebar { display: none; }
.kb-sv {
  position: fixed; inset: 0; z-index: 4000;
  display: flex; align-items: center; justify-content: center;
  gap: 20px; padding: 24px;
}
.kb-sv[hidden] { display: none; }
.kb-sv__bd {
  position: absolute; inset: 0;
  background: rgba(0, 0, 0, 0.92); z-index: 0;
  /* Blur as well as dim: at this opacity white page text is still legible
     behind the clip, and the blur is what actually kills it. */
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
}
.kb-sv__box {
  position: relative; z-index: 1; flex: 0 1 auto;
  display: flex; flex-direction: column; align-items: center; gap: 12px;
  width: min(420px, calc((100vh - 160px) * 0.5625));
  max-width: calc(100vw - 190px);
}
.kb-sv__frame {
  width: 100%; aspect-ratio: 9 / 16;
  border-radius: var(--radius); overflow: hidden; background: #000;
}
.kb-sv__frame iframe { width: 100%; height: 100%; border: 0; display: block; }
.kb-sv__cap {
  margin: 0; text-align: center;
  font-size: 0.8rem; letter-spacing: 0.03em; color: rgba(255, 255, 255, 0.7);
}
.kb-sv__x, .kb-sv__step {
  display: grid; place-items: center;
  border: 1px solid rgba(255, 255, 255, 0.25); border-radius: 999px;
  background: rgba(0, 0, 0, 0.5); color: #fff; cursor: pointer;
  transition: background 0.2s, border-color 0.2s;
}
.kb-sv__x:hover, .kb-sv__step:hover { background: rgba(0, 0, 0, 0.8); border-color: rgba(255, 255, 255, 0.6); }
.kb-sv__x { position: absolute; z-index: 1; top: 18px; right: 18px; width: 42px; height: 42px; }
.kb-sv__x svg { width: 18px; height: 18px; }
/* Explicit z-index, not tree order: the Prev arrow carries order:-1, and
   Chromium then paints it underneath the absolutely positioned backdrop. */
.kb-sv__step { position: relative; z-index: 1; flex: 0 0 auto; width: 52px; height: 52px; }
/* Backdrop and close button are absolute, so the flex row is prev / clip /
   next once these three are ordered. */
.kb-sv__step--prev { order: -1; }
.kb-sv__box { order: 0; }
.kb-sv__step--next { order: 1; }
.kb-sv__step svg { width: 22px; height: 22px; }
.kb-sv__step--next svg { transform: rotate(180deg); }

/* Phones: no room for arrows beside a full-width clip, so they sit in the
   bottom corners where a thumb already is. */
@media (max-width: 620px) {
  .kb-sv { gap: 0; padding: 16px; }
  .kb-sv__box { max-width: 100%; width: min(94vw, calc((100vh - 168px) * 0.5625)); }
  .kb-sv__step { position: absolute; bottom: 20px; width: 48px; height: 48px; }
  .kb-sv__step--prev { left: 18px; }
  .kb-sv__step--next { right: 18px; }
  .kb-sv__cap { max-width: 60vw; }
}

/* ══════════════════════════════════════════════════════════════════════
   "ALSO READY TO SHIP" STRIP
   Sits directly under the scarcity pill on a product page and lists the
   other SKUs with units physically on the shelf. Most stations are
   production-slot only, so without this a visitor on a fully booked page
   has no way of knowing anything is available now.
   Deliberately quiet: this is a helpful aside, not a second CTA.
   ══════════════════════════════════════════════════════════════════════ */
/* .info__header is display:contents on the PDPs, so this strip is laid out by
   the .info flex column and needs the scarcity pill's flex order at each
   breakpoint, or it lands above the CTA instead of under the pill. Source
   order (it is inserted right after the pill) does the rest. */
@media (min-width: 961px) { .info__header > .kb-instock, .info > .kb-instock { order: 5; } }
@media (max-width: 960px) { .info__header > .kb-instock, .info > .kb-instock { order: 4; } }
@media (max-width: 640px) { body .info__header > .kb-instock, body .info > .kb-instock { order: 8; } }
.kb-instock {
  margin-top: 10px;
  border: 1px solid hsl(var(--border));
  border-radius: 10px;
  overflow: hidden;
  background: hsl(var(--background-elev));
}
.kb-instock__head {
  font-family: var(--font-condensed, var(--font-sans));
  font-size: 0.66rem; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: hsl(var(--muted-foreground));
  padding: 8px 12px 6px;
}
.kb-instock__row {
  display: flex; align-items: center; gap: 9px;
  padding: 8px 12px;
  border-top: 1px solid hsl(var(--border));
  text-decoration: none; color: inherit;
  transition: background 0.15s;
}
.kb-instock__row:hover { background: hsl(var(--background-elev-2, var(--secondary))); }
.kb-instock__qty {
  flex: 0 0 auto;
  min-width: 20px; height: 20px; padding: 0 5px;
  display: inline-grid; place-items: center;
  border-radius: 999px;
  background: hsl(142 60% 40% / 0.16); color: hsl(142 62% 52%);
  font-family: var(--font-mono, monospace);
  font-size: 0.68rem; font-weight: 700;
}
.kb-instock__name {
  flex: 1 1 auto; min-width: 0;
  font-size: 0.83rem; line-height: 1.25;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.kb-instock__ship {
  flex: 0 0 auto;
  font-size: 0.7rem; color: hsl(var(--muted-foreground));
}
.kb-instock__go { flex: 0 0 auto; color: hsl(var(--primary)); font-size: 0.85rem; }
.kb-instock__row:hover .kb-instock__name { color: hsl(var(--primary)); }

/* Phones: the despatch time is the first thing to go, the name matters more */
@media (max-width: 480px) {
  .kb-instock__ship { display: none; }
  .kb-instock__name { white-space: normal; }
}
html.light .kb-instock__qty { background: hsl(142 60% 35% / 0.14); color: #15803d; }
