/* Equipment Shop (.shp) — Phase 1 catalog */

.shp { background: #fff; }
.shp .cx-eyebrow { font: 800 13px/1.3 var(--sans); letter-spacing: .14em; text-transform: uppercase; color: var(--brand); margin: 0 0 14px; }

/* ---------- catalog head ---------- */
.shp-head { background: linear-gradient(180deg, #FFFFFF 0%, #EEF2F7 100%); padding: 64px 0 44px; }
.shp-head h1 { font-size: clamp(36px, 4.4vw, 52px); line-height: 1.08; font-weight: 800; color: var(--navy); margin: 0; }
.shp-head h1 em { font-style: normal; color: var(--brand); }
.shp-sub { font-size: 16px; color: var(--ink-soft); margin: 16px 0 0; max-width: 520px; }

.shp-cats { display: flex; flex-wrap: wrap; gap: 9px; padding: 30px 0 26px; }
.shp-cat {
  display: inline-flex; align-items: center; gap: 7px;
  font: 700 13px/1 var(--sans); color: var(--navy); text-decoration: none;
  background: #fff; border: 1px solid var(--line); border-radius: 999px; padding: 10px 16px;
  transition: border-color .2s, background .2s, color .2s;
}
.shp-cat small { font-weight: 700; color: var(--ink-soft); }
.shp-cat:hover { border-color: var(--brand); color: var(--brand); }
.shp-cat.on { background: var(--navy); border-color: var(--navy); color: #fff; }
.shp-cat.on small { color: #A9BBD8; }

/* ---------- grid ---------- */
.shp-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 18px; padding-bottom: 20px; }
.shp-card {
  display: flex; flex-direction: column;
  border: 1px solid var(--line); border-radius: 14px; background: #fff; overflow: hidden;
  text-decoration: none; padding-bottom: 18px;
  transition: box-shadow .22s, transform .22s;
}
.shp-card:hover { box-shadow: 0 16px 40px rgba(13,27,51,.1); transform: translateY(-3px); }
.shp-card figure {
  margin: 0 0 12px; aspect-ratio: 1 / 1; background: #F6F7FA;
  position: relative; padding: 0;
  /* As a flex item this defaults to min-height:auto, so a portrait product
     shot pushes the square box taller than its own aspect-ratio and drops that
     card's title below its neighbours'. Letting it shrink keeps the row true. */
  min-height: 0;
}
/* Absolutely positioned and explicitly sized. In flow, a percentage height
   against an aspect-ratio box falls back to auto, so a portrait shot sizes
   itself and either overflows or gets clipped; and `inset` alone does not fix
   it, because an absolutely positioned replaced element with `width: auto`
   takes its intrinsic width rather than the inset box. Stating both dimensions
   pins it to the square and lets object-fit letterbox inside. */
.shp-card figure img {
  position: absolute; left: 18px; top: 18px;
  width: calc(100% - 36px); height: calc(100% - 36px);
  object-fit: contain; mix-blend-mode: multiply;
}
.shp-card small { font: 700 11px/1 var(--sans); letter-spacing: .1em; text-transform: uppercase; color: var(--ink-soft); padding: 0 18px; }
.shp-card h3 { font: 700 15px/1.35 var(--sans); color: var(--navy); margin: 6px 0 10px; padding: 0 18px; }
.shp-card-price { font: 800 16px/1 var(--sans); color: var(--brand); padding: 0 18px; margin-top: auto; }

.shp-empty { padding: 60px 0; color: var(--ink-soft); }

/* ---------- pager ---------- */
.shp-pager { display: flex; gap: 8px; flex-wrap: wrap; padding: 10px 0 60px; }
.shp-pager a {
  font: 700 13.5px/1 var(--sans); color: var(--navy); text-decoration: none;
  border: 1px solid var(--line); border-radius: 9px; padding: 10px 14px;
}
.shp-pager a.on { background: var(--brand); border-color: var(--brand); color: #fff; }
.shp-pager a:hover:not(.on) { border-color: var(--brand); color: var(--brand); }

/* ---------- detail ---------- */
.shp-crumb { font: 600 13px/1 var(--sans); color: var(--ink-soft); padding: 26px 0 6px; display: flex; gap: 9px; }
.shp-crumb a { color: var(--ink-soft); text-decoration: none; }
.shp-crumb a:hover { color: var(--brand); }
.shp-detail { display: grid; grid-template-columns: 1.05fr 1fr; gap: 54px; padding-block: 18px 70px; align-items: start; }
.shp-hero-img {
  margin: 0; background: #F6F7FA; border-radius: 16px; border: 1px solid var(--line);
  aspect-ratio: 1 / 1; display: grid; place-items: center; padding: 34px;
}
.shp-hero-img img { max-width: 100%; max-height: 100%; object-fit: contain; mix-blend-mode: multiply; }
.shp-thumbs { display: flex; gap: 10px; margin-top: 12px; flex-wrap: wrap; }
.shp-thumb {
  width: 72px; height: 72px; border: 1px solid var(--line); border-radius: 10px;
  background: #F6F7FA; padding: 8px; cursor: pointer;
}
.shp-thumb img { width: 100%; height: 100%; object-fit: contain; mix-blend-mode: multiply; }
.shp-thumb:hover { border-color: var(--brand); }

.shp-mfr { font: 700 12px/1 var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--brand); margin: 0 0 8px; }
.shp-info h1 { font-size: clamp(26px, 3vw, 36px); line-height: 1.15; font-weight: 800; color: var(--navy); margin: 0 0 10px; }
.shp-meta { display: flex; gap: 18px; font: 600 13px/1 var(--sans); color: var(--ink-soft); margin: 0 0 14px; }
.shp-price { font: 800 30px/1 var(--sans); color: var(--navy); margin: 0 0 16px; }
.shp-short { font-size: 15.5px; line-height: 1.65; color: var(--ink-soft); margin: 0 0 22px; }
.shp-actions { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; }
.shp-ghost {
  display: inline-flex; align-items: center; font: 700 14.5px/1 var(--sans); color: var(--navy);
  text-decoration: none; padding: 15px 26px; border-radius: 999px; border: 1.5px solid #C9D1DC;
  transition: border-color .2s;
}
.shp-ghost:hover { border-color: var(--navy); }
.shp-note { font-size: 13px; color: var(--ink-soft); margin: 12px 0 0; }
.shp-h2 { font-size: 18px; font-weight: 800; color: var(--navy); margin: 28px 0 10px; }
.shp-desc { font-size: 15px; line-height: 1.7; color: var(--ink-soft); }
.shp-extras { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 24px; }
.shp-chip {
  font: 700 12.5px/1 var(--sans); color: var(--navy);
  background: #F1F5FA; border-radius: 999px; padding: 10px 16px;
}
.shp-chip-link { color: var(--brand); text-decoration: none; background: #EAF3FD; }
.shp-chip-link:hover { text-decoration: underline; }
.shp-missing { padding: 90px 0; }
.shp-missing h1 { color: var(--navy); }
.shp-missing p { color: var(--ink-soft); margin: 10px 0 22px; }

/* ---------- responsive ---------- */
@media (max-width: 1024px) {
  .shp-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .shp-detail { grid-template-columns: 1fr; gap: 30px; }
}
@media (max-width: 760px) {
  .shp-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
}
@media (max-width: 480px) {
  .shp-grid { grid-template-columns: 1fr; }
}


/* ============================================================
   Catalog browsing: search, department rail, facets, chips
   ============================================================ */

/* Search sits in the masthead because it outperforms every facet for people
   who arrive knowing a model number. */
.shp-search {
  position: relative; display: flex; align-items: center; gap: 10px;
  margin: 26px 0 0; max-width: 620px;
  background: #fff; border: 1px solid var(--line); border-radius: 999px;
  padding: 4px 6px 4px 18px; box-shadow: 0 8px 26px rgba(13,27,51,.07);
}
.shp-search:focus-within { border-color: var(--brand); box-shadow: 0 0 0 4px rgba(38,141,238,.12); }
.shp-search svg { flex: none; width: 19px; height: 19px; fill: none; stroke: var(--ink-soft); stroke-width: 2; stroke-linecap: round; }
.shp-search input {
  flex: 1; min-width: 0; border: 0; background: none; outline: none;
  font: 400 15.5px/1.5 var(--sans); color: var(--navy); padding: 12px 0;
}
.shp-search input::placeholder { color: #9AA0AC; }
.shp-search input::-webkit-search-cancel-button { cursor: pointer; }
.shp .shp-search button {
  flex: none; border: 0; border-radius: 999px; background: var(--brand); color: #fff;
  font: 700 14px/1 var(--sans); padding: 13px 22px; cursor: pointer;
}
.shp .shp-search button:hover { background: #1B7AD6; }

.shp-layout { display: grid; grid-template-columns: 246px minmax(0, 1fr); gap: 34px; padding-block: 34px 70px; align-items: start; }

/* Rail sticks below the fixed site nav so filters stay reachable down a long grid. */
.shp-rail { position: sticky; top: 102px; }
.shp-rail-head { display: none; }
.shp-facet { border-bottom: 1px solid var(--line); padding: 0 0 18px; margin: 0 0 18px; }
.shp-facet:last-of-type { border-bottom: 0; }
.shp-facet h2 {
  font: 800 11.5px/1 var(--sans); letter-spacing: .13em; text-transform: uppercase;
  color: var(--navy); margin: 0 0 12px;
}
.shp-opt {
  display: flex; align-items: center; gap: 9px; text-decoration: none;
  padding: 7px 0; font: 500 14.5px/1.35 var(--sans); color: var(--ink-soft);
}
.shp-opt span { flex: 1; min-width: 0; }
.shp-opt small { font: 600 12.5px/1 var(--sans); color: #9AA0AC; }
.shp-opt:hover { color: var(--brand); }
.shp-opt:hover small { color: var(--brand); }
.shp-opt.on { color: var(--navy); font-weight: 700; }

/* Checkbox affordance drawn in CSS — a facet that reads as tickable gets
   used as multi-select, where a plain link reads as "pick one". */
.shp-check i {
  flex: none; width: 17px; height: 17px; border: 1.5px solid #C9CFD9; border-radius: 5px;
  background: #fff; position: relative;
}
.shp-check:hover i { border-color: var(--brand); }
.shp-check.on i { background: var(--brand); border-color: var(--brand); }
.shp-check.on i::after {
  content: ''; position: absolute; left: 5px; top: 1.5px; width: 4px; height: 9px;
  border: solid #fff; border-width: 0 2px 2px 0; transform: rotate(43deg);
}
.shp-extra { display: none; }
[data-collapsible][data-expanded] .shp-extra { display: flex; }
.shp .shp-more {
  border: 0; background: none; padding: 8px 0 0; cursor: pointer;
  font: 700 13px/1 var(--sans); color: var(--brand);
}
.shp .shp-more:hover { text-decoration: underline; }
.shp-clear-all { display: inline-block; margin-top: 4px; font: 700 13.5px/1 var(--sans); color: var(--brand); text-decoration: none; }
.shp-clear-all:hover { text-decoration: underline; }

.shp-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 0 0 16px; flex-wrap: wrap; }
.shp-count { margin: 0; font: 500 15px/1 var(--sans); color: var(--ink-soft); }
.shp-count strong { font-weight: 800; color: var(--navy); }
.shp-sort { display: flex; align-items: center; gap: 9px; }
.shp-sort label { font: 700 12.5px/1 var(--sans); letter-spacing: .1em; text-transform: uppercase; color: var(--ink-soft); }
.shp-sort select {
  font: 600 14px/1 var(--sans); color: var(--navy); background: #fff;
  border: 1px solid var(--line); border-radius: 9px; padding: 10px 12px; cursor: pointer;
}
.shp-sort select:focus { outline: none; border-color: var(--brand); }

/* Applied filters stay visible above the grid: the fastest way out of a
   dead end is seeing what put you there. */
.shp-chips { display: flex; flex-wrap: wrap; gap: 8px; padding: 0 0 20px; align-items: center; }
.shp-chip-f {
  display: inline-flex; align-items: center; gap: 8px; text-decoration: none;
  background: #EEF4FC; border: 1px solid #D5E5F8; border-radius: 999px;
  padding: 7px 12px 7px 14px; font: 600 13px/1 var(--sans); color: var(--navy);
}
.shp-chip-f i { font-style: normal; font-size: 15px; line-height: 1; color: #7D8BA0; }
.shp-chip-f:hover { border-color: var(--brand); color: var(--brand); }
.shp-chip-f:hover i { color: var(--brand); }
.shp-chips-clear { font: 700 13px/1 var(--sans); color: var(--ink-soft); text-decoration: none; padding: 0 4px; }
.shp-chips-clear:hover { color: var(--brand); text-decoration: underline; }

.shp-none { padding: 56px 0 70px; max-width: 520px; }
.shp-none h3 { font: 800 22px/1.25 var(--sans); color: var(--navy); margin: 0 0 10px; }
.shp-none p { font-size: 15.5px; line-height: 1.7; color: var(--ink-soft); margin: 0 0 22px; }

.shp-showmore { display: flex; justify-content: center; padding: 26px 0 60px; }
.shp .shp-showmore button {
  border: 1px solid var(--line); background: #fff; border-radius: 999px; cursor: pointer;
  font: 700 15px/1 var(--sans); color: var(--navy); padding: 15px 30px;
}
.shp .shp-showmore button span { color: var(--ink-soft); font-weight: 500; }
.shp .shp-showmore button:hover { border-color: var(--brand); color: var(--brand); }

.shp .shp-filter-btn { display: none; }

@media (max-width: 1040px) {
  .shp-layout { grid-template-columns: 210px minmax(0, 1fr); gap: 26px; }
  .shp-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* Phones: the rail becomes a sheet. Filters on a narrow screen have to be
   summoned, or they push the products off the first screen entirely. */
@media (max-width: 860px) {
  .shp-layout { display: block; padding-top: 22px; }
  .shp-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  .shp .shp-filter-btn {
    display: inline-flex; align-items: center; gap: 8px; margin: 0 0 16px;
    border: 1px solid var(--line); background: #fff; border-radius: 999px; cursor: pointer;
    font: 700 14.5px/1 var(--sans); color: var(--navy); padding: 13px 22px;
  }
  .shp .shp-filter-btn span {
    background: var(--brand); color: #fff; border-radius: 999px;
    font-size: 12px; padding: 3px 8px; line-height: 1;
  }
  .shp-rail {
    position: fixed; z-index: 300; inset: 0 0 0 auto; width: min(88vw, 340px);
    background: #fff; padding: 18px 22px 40px; overflow-y: auto;
    box-shadow: -18px 0 50px rgba(13,27,51,.18);
    transform: translateX(100%); transition: transform .28s ease; visibility: hidden;
  }
  body.shp-filters-open .shp-rail { transform: none; visibility: visible; }
  body.shp-filters-open { overflow: hidden; }
  body.shp-filters-open::after {
    content: ''; position: fixed; inset: 0; z-index: 299; background: rgba(10,16,28,.5);
  }
  .shp-rail-head {
    display: flex; align-items: center; justify-content: space-between;
    padding: 0 0 14px; margin: 0 0 14px; border-bottom: 1px solid var(--line);
  }
  .shp-rail-head span { font: 800 16px/1 var(--sans); color: var(--navy); }
  .shp .shp-rail-x { border: 0; background: none; font-size: 26px; line-height: 1; color: var(--ink-soft); cursor: pointer; padding: 0 4px; }
  .shp-opt { padding: 10px 0; font-size: 15.5px; }
  .shp-search { margin-top: 20px; }
  .shp .shp-search button { padding: 13px 18px; }
  .shp-toolbar { padding-bottom: 12px; }
}
@media (max-width: 460px) {
  .shp-search { padding-left: 14px; gap: 8px; }
  .shp-search input { font-size: 15px; }
}

/* While retail figures are being verified the catalogue shows no numbers.
   The item page still needs something in the price slot, or the layout
   collapses and the page reads as though data is missing. */
.shp-price-ask {
  color: var(--ink-soft, #6C6E76);
  font-weight: 700;
}

/* ============ Brand storefronts ============
   The storefront borrows the brand's own room from the marketing pages
   (.px-unifi and friends already set --pxa and the hero ground), so the
   shop and the brand page read as one place rather than two designs of
   the same logo. Everything here is layout; the palette comes from there. */
.shb-hero {
  background: linear-gradient(180deg, #FFFFFF 0%, #EDF1F7 100%);
  padding: 122px 0 60px;
  border-bottom: 1px solid rgba(9,15,26,.07);
}
.shb-hero-grid {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 46%);
  gap: 48px; align-items: center;
}
.shb-hero .cx-eyebrow { color: var(--pxa, #006FFF); }
.shb-hero-copy h1 {
  font: 800 clamp(31px, 4.2vw, 50px)/1.08 var(--sans);
  color: #06090F; margin: 0 0 16px; text-wrap: balance;
}
.shb-hero-copy h1 em { font-style: normal; color: var(--pxa, #006FFF); }
.shb-lede {
  font: 500 16.5px/1.72 var(--sans); color: #5B6572;
  margin: 0 0 18px; max-width: 56ch;
}
.shb-count {
  font: 700 13.5px/1 var(--sans); color: #5B6572;
  margin: 0 0 26px; letter-spacing: .01em;
}
.shb-count strong {
  font-size: 21px; color: #06090F; margin-right: 6px;
  font-variant-numeric: tabular-nums;
}
.shb-hero-visual { margin: 0; }
.shb-hero-visual img {
  width: 100%; height: auto; display: block; border-radius: 16px;
  box-shadow: 0 26px 60px -28px rgba(9,15,26,.42);
}
/* the toolbar sits directly under the hero in a storefront, so it loses
   the standalone shop's top padding */
.shp-head-brand { padding-top: 26px; }
.shp-head-brand .wrap > .shp-search { margin-top: 0; }

@media (max-width: 900px) {
  .shb-hero { padding: 104px 0 40px; }
  .shb-hero-grid { grid-template-columns: 1fr; gap: 28px; }
  .shb-hero-visual { order: -1; }
}

/* the door into a brand storefront, sitting above the ordinary facets */
.shb-card {
  display: block; text-decoration: none;
  border: 1px solid var(--line); border-radius: 14px;
  padding: 16px 18px; margin-bottom: 12px;
  background: linear-gradient(180deg, #FFFFFF 0%, #F4F7FB 100%);
  transition: border-color .2s, transform .2s, box-shadow .2s;
}
.shb-card:hover {
  border-color: var(--pxa, #006FFF);
  transform: translateY(-2px);
  box-shadow: 0 12px 26px -14px rgba(9,15,26,.34);
}
.shb-card-label {
  display: block; font: 800 17px/1.2 var(--sans); color: var(--navy);
}
.shb-card-n {
  display: block; font: 600 12.5px/1.4 var(--sans); color: var(--ink-soft);
  margin-top: 3px;
}
.shb-card-go {
  display: block; margin-top: 10px;
  font: 700 12.5px/1 var(--sans); color: var(--pxa, #006FFF);
}
.shb-card:hover .shb-card-go span { padding-left: 3px; }

/* ============================================================
   Storefront layout — taken from store.ui.com's own language
   rather than our shop's.

   Measured off their live store: pure white ground, no card
   chrome at all (their tiles carry no border, no radius and no
   shadow), headings at weight 700 with -0.02em tracking, and a
   two-tone heading where the qualifier drops to grey. Their
   category navigation runs horizontally across the top as
   labelled tiles, which is the most recognisable thing about the
   store and the reason ours stopped being a sidebar here.
   ============================================================ */
.shp-brand { background: #FFFFFF; }

/* --- category strip --- */
.shb-cats {
  background: #FFFFFF;
  border-bottom: 1px solid rgba(210,210,215,.64);
  position: sticky; top: 0; z-index: 40;
}
.shb-cats-row {
  display: flex; gap: 6px; overflow-x: auto; padding: 14px 0 12px;
  scrollbar-width: none;
}
.shb-cats-row::-webkit-scrollbar { display: none; }
.shb-cat {
  flex: none; display: flex; flex-direction: column; align-items: center; gap: 3px;
  min-width: 104px; padding: 12px 14px; border-radius: 12px;
  text-decoration: none; background: transparent;
  transition: background .18s;
}
.shb-cat:hover { background: #F5F5F7; }
.shb-cat.on { background: #F0F1F3; }
.shb-cat-n {
  font: 700 19px/1 var(--sans); color: #000; letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
}
.shb-cat-l {
  font: 500 12.5px/1.35 var(--sans); color: rgba(0,0,0,.55); text-align: center;
}
.shb-cat.on .shb-cat-l { color: #000; font-weight: 600; }

/* --- headings: black, tight, with a grey second half --- */
.shp-brand .shp-count,
.shp-brand .shp-count strong { color: #000; letter-spacing: -.02em; }
.shp-brand .shp-count strong { font-weight: 700; }
.shp-brand .shp-count { font-size: 17px; }
.shp-brand .shp-count em {
  font-style: normal; color: rgba(0,0,0,.45); font-weight: 400;
}

/* --- product tiles: no border, no shadow, image on a soft well --- */
.shp-brand .shp-card {
  background: transparent; border: 0; border-radius: 0;
  box-shadow: none; padding: 0;
  /* The ordinary shop's card clips itself, which it can afford to: it has a
     background and a border of its own, and on hover the whole card moves.
     A storefront card is just a wrapper — the plate inside it is what has the
     edge, and what lifts. Left clipping, the plate's top two pixels were
     sliced off flat on hover, taking the border and the rounded corners with
     them, and the shadow underneath went the same way. The plate keeps its
     own radius and overflow, so the photograph is still contained. */
  overflow: visible;
}
.shp-brand .shp-card figure {
  background: #F5F5F7; border-radius: 14px; margin: 0 0 14px;
  aspect-ratio: 1 / 1; display: flex; align-items: center; justify-content: center;
  overflow: hidden; transition: background .2s;
}
.shp-brand .shp-card:hover figure { background: #EDEEF0; }
.shp-brand .shp-card img { mix-blend-mode: multiply; }
.shp-brand .shp-card small {
  font: 500 11.5px/1 var(--sans); letter-spacing: .04em;
  text-transform: uppercase; color: rgba(0,0,0,.45);
}
.shp-brand .shp-card h3 {
  font: 700 15.5px/1.35 var(--sans); color: #000;
  letter-spacing: -.015em; margin: 5px 0 4px;
}
.shp-brand .shp-card-price {
  font: 600 14.5px/1 var(--sans); color: #006FFF;
  font-variant-numeric: tabular-nums;
}
.shp-brand .shp-grid { gap: 34px 26px; }

/* --- the shop's rail has no place here; the strip replaced it --- */
.shp-brand .shp-rail,
.shp-brand aside,
.shp-brand .shp-filter-btn { display: none; }
.shp-brand .shp-layout { grid-template-columns: 1fr; }
.shp-brand .shp-toolbar { border-bottom: 1px solid rgba(210,210,215,.64); }

@media (max-width: 900px) {
  .shb-cat { min-width: 88px; padding: 10px; }
  .shb-cats-row { padding: 10px 0 8px; }
}

/* the doors sit above the shop proper, not in the rail — shop.js rebuilds
   the rail on load and would erase anything rendered into it server-side */
.shb-doors {
  display: flex; gap: 14px; flex-wrap: wrap;
  padding-top: 26px;
}
.shb-doors .shb-card { flex: 1 1 260px; max-width: 340px; margin-bottom: 0; }

/* the search band goes white inside a storefront so the strip, the search
   and the grid read as one surface rather than three */
.shp-brand .shp-head-brand { background: #FFFFFF; }

/* --- category strip: icon over label over count, as ui.com arranges it --- */
/* Their glyphs are product illustrations with individual aspect ratios, so
   height is the constant and width follows — forcing a uniform box would
   squash the wide ones (cloud gateways is 135x35, wifi is 51x38). */
.shb-cat-i { display: flex; align-items: flex-end; justify-content: center; height: 38px; }
.shb-cat-i img {
  height: 34px; width: auto; max-width: 100%; display: block;
  opacity: .82; transition: opacity .18s;
}
.shb-cat.on .shb-cat-i img, .shb-cat:hover .shb-cat-i img { opacity: 1; }
.shb-cat-n {
  font: 600 11.5px/1 var(--sans); color: rgba(0,0,0,.42);
  font-variant-numeric: tabular-nums;
}
.shb-cat-l { font: 500 12.5px/1.3 var(--sans); color: rgba(0,0,0,.62); }
.shb-cat.on .shb-cat-l { color: #000; font-weight: 600; }
.shb-cat { min-width: 124px; gap: 6px; }

/* --- shelf row: the sub-categories inside a chosen line ---
   Deliberately quieter than the strip above it. A line is picked from
   pictures, a shelf from a word, so the row reads as the second step it
   is rather than competing for the same glance. */
.shb-subs-row {
  display: flex; gap: 4px; overflow-x: auto; padding: 0 0 12px;
  scrollbar-width: none;
}
.shb-subs-row::-webkit-scrollbar { display: none; }
.shb-sub {
  flex: none; display: flex; align-items: center; gap: 6px;
  padding: 6px 13px; border-radius: 999px;
  font: 500 13px/1 var(--sans); color: rgba(0,0,0,.62);
  text-decoration: none; white-space: nowrap;
  border: 1px solid rgba(210,210,215,.85); background: #FFFFFF;
  transition: background .18s, color .18s, border-color .18s;
}
.shb-sub:hover { background: #F5F5F7; color: #000; }
.shb-sub.on {
  background: #0A2540; border-color: #0A2540; color: #FFFFFF; font-weight: 600;
}
.shb-sub-n {
  font: 600 11.5px/1 var(--sans); color: rgba(0,0,0,.42);
  font-variant-numeric: tabular-nums;
}
.shb-sub.on .shb-sub-n { color: rgba(255,255,255,.7); }

/* --- two-tone heading, the way their sections are titled --- */
.shb-h2 {
  font: 700 clamp(24px, 3vw, 32px)/1.15 var(--sans);
  letter-spacing: -.02em; color: #000; margin: 0 0 22px;
}
.shb-h2 em { font-style: normal; color: rgba(0,0,0,.38); }

/* --- feature cards: dark ground, copy up top, product photo below --- */
.shb-show { background: #FFFFFF; padding: 40px 0 0; }
.shb-show-row {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 18px;
}
.shb-show-card {
  position: relative; display: flex; flex-direction: column;
  min-height: 400px; padding: 26px 26px 0; overflow: hidden;
  border-radius: 16px; text-decoration: none;
  background: linear-gradient(168deg, #1B2430 0%, #0E1620 62%, #0A1017 100%);
  transition: transform .22s, box-shadow .22s;
}
.shb-show-card:hover {
  transform: translateY(-3px);
  box-shadow: 0 22px 44px -22px rgba(9,15,26,.6);
}
.shb-show-tag {
  font: 700 11.5px/1 var(--sans); letter-spacing: .1em; text-transform: uppercase;
  color: #F0A93B; margin-bottom: 12px;
}
.shb-show-name {
  font: 700 21px/1.25 var(--sans); letter-spacing: -.02em; color: #fff;
}
.shb-show-desc {
  font: 400 14px/1.6 var(--sans); color: rgba(255,255,255,.62);
  margin-top: 9px; max-width: 34ch;
}
.shb-show-img {
  margin-top: auto; display: block; padding-top: 20px;
}
.shb-show-img img {
  width: 100%; height: auto; display: block;
  max-height: 200px; object-fit: contain; object-position: bottom;
}
@media (max-width: 700px) {
  .shb-show-card { min-height: 340px; }
}

/* The marketing photograph IS the card.
   Ubiquiti shoot these at 770x940 with the top third deliberately darkened —
   measured mean luminance runs 28 at the top of the frame to 155 by 40% down
   — because that is where the name and copy sit. Treating it as a picture in
   the lower half, which is what this did at first, wastes the dark zone and
   leaves the photograph looking cropped and oddly blurry up top.

   So: the image covers the whole card at the artwork's own aspect ratio, and
   the text rides on it. */
.shb-show-card-art {
  aspect-ratio: 770 / 940;
  min-height: 0;
  padding: 26px 26px 24px;
  background: #0A1017;
}
.shb-show-card-art .shb-show-art {
  position: absolute; inset: 0; margin: 0; padding: 0; z-index: 0;
}
.shb-show-card-art .shb-show-art img {
  width: 100%; height: 100%; max-height: none;
  object-fit: cover; object-position: center;
  display: block;
}
/* The photograph carries its own darkening, but our descriptions come from
   the catalogue and vary in length — a long one walks out of the dark band
   and onto the product. This scrim is shaped like the one already in the
   artwork, so it is invisible where the image copes and catches the text
   where it does not. */
.shb-show-card-art::before {
  content: ''; position: absolute; left: 0; right: 0; top: 0; height: 62%;
  background: linear-gradient(180deg, rgba(6,10,16,.72) 0%, rgba(6,10,16,.45) 42%, rgba(6,10,16,0) 100%);
  z-index: 1; pointer-events: none;
}
.shb-show-card-art .shb-show-tag,
.shb-show-card-art .shb-show-name,
.shb-show-card-art .shb-show-desc { position: relative; z-index: 2; }
.shb-show-card-art .shb-show-desc { color: rgba(255,255,255,.78); }
/* the copy stays at the top, in the band the photograph was shot to carry */
.shb-show-card-art .shb-show-desc { margin-bottom: 0; }
/* their row scrolls rather than wrapping once there are more than three */
.shb-show-row {
  /* The first rule above set explicit template columns, and those governed
     the items that fit while grid-auto-columns governed the overflow — so
     the first four cards came out 280px and the rest 330px. A column flow
     needs no template at all. */
  grid-template-columns: none;
  grid-auto-flow: column; grid-auto-columns: minmax(330px, 386px);
  overflow-x: auto; scroll-snap-type: x proximity;
  scrollbar-width: none;
  /* A scroller cannot clip one axis and leave the other alone — overflow-x:
     auto makes overflow-y auto too, so this row was cutting the three pixels
     its own cards lift on hover, and most of the shadow underneath. The
     padding gives that movement somewhere to happen; the negative top margin
     keeps the row sitting where it did. */
  padding-top: 12px; margin-top: -12px;
  padding-bottom: 26px;
}
.shb-show-row::-webkit-scrollbar { display: none; }
.shb-show-card { scroll-snap-align: start; }

/* ============================================================
   UniFi storefront — machined
   ============================================================
   The room was flat white with bright blue prices, which is the
   vocabulary of a discount catalogue: 178 white products floating
   on white, nothing framing any of them.

   The cue that is actually true to this hardware is milled metal.
   Ubiquiti build in anodised aluminium and matte polycarbonate
   with machined edges, so the material here is cool silver and
   graphite with hairline edges and a fine grain — not the gold
   and serif that "luxury" usually reaches for, which would be a
   costume on a rack-mount switch.

   All of it hangs off .px-unifi, which sits on <main> beside
   .shp-brand. The ordinary shop and the other brand rooms keep
   the palette they have.
   ============================================================ */
/* The --m-* palette this room is built from now lives in site.css, so the
   UniFi brand page can be built from the same metal. */

/* The ground. Everything below reads as an object sitting on this
   rather than a hole cut out of white. */
.px-unifi.shp-brand { background: var(--m-ground); }

/* --- grain ---
   A 160px tile, rasterised once and repeated, so this costs one
   small bitmap rather than a full-page filter. Both surfaces it
   lands on are static; the sticky strip deliberately goes
   without, since it repaints on every scroll. */
.px-unifi .shb-hero,
.px-unifi .shb-show { position: relative; }
.px-unifi .shb-hero::after,
.px-unifi .shb-show::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background-image: var(--m-grain); background-size: 160px 160px;
  opacity: .05; mix-blend-mode: multiply;
}
.px-unifi .shb-hero > *,
.px-unifi .shb-show > * { position: relative; z-index: 1; }

/* --- hero: silver rather than white, closed by a machined edge --- */
.px-unifi .shb-hero {
  background: linear-gradient(180deg, #F7F9FB 0%, #DFE4EB 100%);
  border-bottom: 0;
}
/* A hairline that fades out at both ends reads as a milled edge;
   a flat 1px rule across the full width reads as a table border. */
.px-unifi .shb-hero::before,
.px-unifi .shb-cats::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: linear-gradient(90deg, transparent, var(--m-edge) 12%, #FFFFFF 50%, var(--m-edge) 88%, transparent);
  z-index: 2;
}
.px-unifi .shb-hero-copy h1 { color: var(--m-ink); }
.px-unifi .shb-lede { color: var(--m-steel); }
.px-unifi .shb-count strong { color: var(--m-ink); }

/* --- the strip: a brushed plate spanning the page --- */
.px-unifi .shb-cats {
  position: sticky;
  background: linear-gradient(180deg, #FBFCFD 0%, #EFF2F6 100%);
  border-bottom: 0;
  box-shadow: 0 1px 0 rgba(255,255,255,.9) inset, 0 6px 18px -12px rgba(11,16,23,.35);
}
.px-unifi .shb-cat:hover { background: rgba(255,255,255,.72); }
.px-unifi .shb-cat.on {
  background: #FFFFFF;
  box-shadow: 0 1px 0 rgba(255,255,255,1) inset, 0 4px 14px -8px rgba(11,16,23,.4);
}
.px-unifi .shb-cat-l { color: var(--m-steel); }
.px-unifi .shb-cat.on .shb-cat-l { color: var(--m-ink); }
.px-unifi .shb-cat-n { color: rgba(11,16,23,.42); }

/* --- shelf pills --- */
.px-unifi .shb-sub {
  background: linear-gradient(180deg, #FFFFFF 0%, #F4F6F9 100%);
  border-color: var(--m-edge); color: var(--m-steel);
}
.px-unifi .shb-sub:hover { background: #FFFFFF; color: var(--m-ink); }
.px-unifi .shb-sub.on {
  background: linear-gradient(180deg, #22303F 0%, #0B1017 100%);
  border-color: #0B1017; color: #FFFFFF;
  box-shadow: 0 1px 0 rgba(255,255,255,.16) inset;
}

/* --- product plates ---
   The one change that does most of the work. Each product now sits
   on a lit chrome face with a hairline edge instead of dissolving
   into the page. */
.px-unifi .shp-card figure {
  background:
    radial-gradient(120% 92% at 50% 8%, #FFFFFF 0%, var(--m-face-hi) 42%, var(--m-face-lo) 100%);
  border: 1px solid var(--m-edge);
  border-radius: 16px;
  box-shadow:
    0 1px 0 rgba(255,255,255,.95) inset,
    0 1px 2px rgba(11,16,23,.05),
    0 10px 24px -16px rgba(11,16,23,.3);
  transition: box-shadow .24s, border-color .24s, transform .24s;
}
.px-unifi .shp-card:hover figure {
  background:
    radial-gradient(120% 92% at 50% 8%, #FFFFFF 0%, #FFFFFF 46%, #EFF2F6 100%);
  border-color: #BFC7D1;
  box-shadow:
    0 1px 0 rgba(255,255,255,1) inset,
    0 2px 4px rgba(11,16,23,.06),
    0 22px 40px -22px rgba(11,16,23,.45);
  transform: translateY(-2px);
}
/* multiply is what lets these white enclosures pick up the graded
   ground instead of sitting on a grey square — it needs the face to
   stay light, which is why the plate never darkens below #EDF0F4. */
.px-unifi .shp-card h3 { color: var(--m-ink); }
.px-unifi .shp-card small {
  color: var(--m-steel); font-weight: 500; letter-spacing: .06em; opacity: .72;
}
/* Quiet money. Bright blue on every one of 178 tiles reads as a sale
   price; near-black reads as what the thing costs. */
.px-unifi .shp-card-price {
  color: var(--m-ink); font-weight: 600;
  font-variant-numeric: tabular-nums; letter-spacing: -.01em;
}

/* --- controls, in the same material --- */
.px-unifi .shp-search {
  background: linear-gradient(180deg, #FFFFFF 0%, #F6F8FA 100%);
  border-color: var(--m-edge);
  box-shadow: 0 1px 0 rgba(255,255,255,.9) inset, 0 8px 22px -14px rgba(11,16,23,.4);
}
.px-unifi .shp-search:focus-within {
  border-color: #A9B3C0;
  box-shadow: 0 1px 0 rgba(255,255,255,.9) inset, 0 0 0 4px rgba(11,16,23,.06);
}
.px-unifi .shp-search input { color: var(--m-ink); }
.px-unifi .shp-search button {
  background: linear-gradient(180deg, #22303F 0%, #0B1017 100%);
  box-shadow: 0 1px 0 rgba(255,255,255,.16) inset;
}
.px-unifi .shp-search button:hover { background: linear-gradient(180deg, #2C3C4E 0%, #141B24 100%); }
.px-unifi .shp-sort select,
.px-unifi .shp-showmore button {
  background: linear-gradient(180deg, #FFFFFF 0%, #F2F5F8 100%);
  border: 1px solid var(--m-edge); color: var(--m-ink);
  box-shadow: 0 1px 0 rgba(255,255,255,.9) inset;
}
.px-unifi .shp-showmore button:hover { border-color: #A9B3C0; background: #FFFFFF; }
.px-unifi .shp-count { color: var(--m-steel); }
.px-unifi .shp-count strong { color: var(--m-ink); }
.px-unifi .shp-toolbar { border-bottom-color: var(--m-edge); }

/* --- the sections that band the page --- */
.px-unifi .shb-show { background: linear-gradient(180deg, #EFF2F6 0%, var(--m-ground) 100%); }
.px-unifi .shb-h2 { color: var(--m-ink); }
.px-unifi .shb-h2 em { color: rgba(11,16,23,.36); }
.px-unifi .shb-show-card {
  box-shadow: 0 1px 0 rgba(255,255,255,.06) inset, 0 18px 38px -24px rgba(11,16,23,.55);
}

/* --- spending the accent once ---
   The hero was carrying three separate bright blues — eyebrow, the
   headline's second line, and the button — all at full strength on a
   silver ground. Scattered like that the blue reads as consumer tech
   rather than as an accent. It keeps the headline, which is the one
   place it belongs; the label recedes to steel and the controls become
   metal, which is the arrangement the rest of this page already uses. */
.px-unifi .shb-hero .cx-eyebrow {
  color: var(--m-steel); font-weight: 700; letter-spacing: .13em;
}
.px-unifi .cx-hero-actions .btn-blue {
  background: linear-gradient(180deg, #22303F 0%, #0B1017 100%);
  box-shadow: 0 1px 0 rgba(255,255,255,.16) inset, 0 12px 26px -16px rgba(11,16,23,.75);
}
.px-unifi .cx-hero-actions .btn-blue:hover {
  background: linear-gradient(180deg, #2C3C4E 0%, #141B24 100%);
}
.px-unifi .cx-hero-actions { gap: 24px; }
.px-unifi .cx-hero-actions .cx-btn-ghost {
  color: var(--m-steel); border-color: transparent; padding: 16px 2px;
  text-underline-offset: 5px; text-decoration-thickness: 1px;
  text-decoration-color: var(--m-edge);
}
.px-unifi .cx-hero-actions .cx-btn-ghost:hover {
  color: var(--m-ink); background: none; text-decoration-color: var(--m-steel);
}
/* the photograph as a mounted plate rather than a floating rectangle */
.px-unifi .shb-hero-visual img {
  border: 1px solid rgba(255,255,255,.6);
  box-shadow:
    0 0 0 1px rgba(11,16,23,.08),
    0 30px 64px -30px rgba(11,16,23,.5);
}

/* The amber was the only warm thing on a cool page, and it read as a
   sale sticker. An engraved silver chip says the same word without
   breaking the material. */
.px-unifi .shb-show-tag {
  /* a flex item stretches to the column by default, which turned the chip
     into a full-width bar the first time round */
  align-self: flex-start;
  color: rgba(255,255,255,.9);
  border: 1px solid rgba(255,255,255,.28); border-radius: 999px;
  padding: 5px 10px; letter-spacing: .14em; font-size: 10px;
  background: rgba(255,255,255,.06);
  backdrop-filter: blur(2px);
}

/* --- the product page, in the same room ---
   Clicking a product used to land on flat white with a bright blue
   price, which threw away the storefront's material in one step. The
   detail view is the second half of that storefront, so it is built
   from the same silver. Applied only when the product's manufacturer
   actually has a storefront. */
.px-unifi.shp-item-brand { background: var(--m-ground); }
.px-unifi .shp-crumb { color: var(--m-steel); }
.px-unifi .shp-crumb a { color: var(--m-steel); }
.px-unifi .shp-crumb a:hover { color: var(--m-ink); }
.px-unifi .shp-hero-img {
  background: radial-gradient(120% 92% at 50% 8%, #FFFFFF 0%, var(--m-face-hi) 42%, var(--m-face-lo) 100%);
  border: 1px solid var(--m-edge); border-radius: 18px;
  box-shadow:
    0 1px 0 rgba(255,255,255,.95) inset,
    0 1px 2px rgba(11,16,23,.05),
    0 24px 48px -28px rgba(11,16,23,.45);
}
.px-unifi .shp-thumb {
  background: linear-gradient(180deg, #FFFFFF 0%, var(--m-face-lo) 100%);
  border-color: var(--m-edge);
  box-shadow: 0 1px 0 rgba(255,255,255,.9) inset;
}
.px-unifi .shp-thumb:hover { border-color: #A9B3C0; }
.px-unifi .shp-mfr { color: var(--m-steel); letter-spacing: .14em; }
.px-unifi .shp-info h1 { color: var(--m-ink); letter-spacing: -.02em; }
.px-unifi .shp-meta { color: var(--m-steel); font-variant-numeric: tabular-nums; }
.px-unifi .shp-price {
  color: var(--m-ink); font-weight: 700;
  font-variant-numeric: tabular-nums; letter-spacing: -.02em;
}
.px-unifi .shp-short { color: var(--m-steel); }
.px-unifi .shp-actions .btn-blue {
  background: linear-gradient(180deg, #22303F 0%, #0B1017 100%);
  box-shadow: 0 1px 0 rgba(255,255,255,.16) inset, 0 12px 26px -16px rgba(11,16,23,.75);
}
.px-unifi .shp-actions .btn-blue:hover { background: linear-gradient(180deg, #2C3C4E 0%, #141B24 100%); }
.px-unifi .shp-ghost {
  color: var(--m-ink); border: 1px solid var(--m-edge);
  background: linear-gradient(180deg, #FFFFFF 0%, #F2F5F8 100%);
  box-shadow: 0 1px 0 rgba(255,255,255,.9) inset;
}
.px-unifi .shp-ghost:hover { border-color: #A9B3C0; background: #FFFFFF; }
.px-unifi .shp-h2 { color: var(--m-ink); }
.px-unifi .shp-desc,
.px-unifi .shp-note { color: var(--m-steel); }
.px-unifi .shp-info li { color: var(--m-steel); }
.px-unifi .shp-chip {
  color: var(--m-ink); background: rgba(255,255,255,.7);
  border: 1px solid var(--m-edge);
}
.px-unifi .shp-chip-link { color: var(--m-ink); background: rgba(255,255,255,.9); }

/* On a phone the two actions do not fit side by side, and the link was
   breaking across the button. flex-wrap alone does not fix that: a flex
   item shrinks before it wraps, so the link was being squeezed narrow
   and wrapping its own text instead of moving down. It has to be told it
   cannot shrink before the row will break. */
@media (max-width: 600px) {
  .px-unifi .cx-hero-actions { flex-wrap: wrap; gap: 14px 20px; }
  .px-unifi .cx-hero-actions .btn-blue,
  .px-unifi .cx-hero-actions .cx-btn-ghost { flex: 0 0 auto; white-space: nowrap; }
  .px-unifi .cx-hero-actions .cx-btn-ghost { padding: 2px; }
}

/* ============================================================
   Alarm.com storefront — night watch
   ============================================================
   The UniFi room is machined aluminium because that is what
   Ubiquiti build things out of. Alarm.com are not a hardware
   house; they are the platform that is awake at three in the
   morning, and their own site is charcoal with one orange. So
   this room is the opposite arrangement to the other one: a dark
   ground with the products lit on light plates, like a case at
   night, and the orange spent on the thing you press.

   The plates have to be light whatever the mood — every product
   photograph in this catalogue is an opaque JPEG shot on white,
   so a dark tile would just frame a white rectangle.

   Colours are Alarm.com's own, sampled from alarm.com: #1D252D
   charcoal, #E35205 orange, #D7DEE0 mist. --pxa is overridden
   only inside the storefront, so the marketing page keeps the
   slightly different orange it already ships.
   ============================================================ */
.px-adc.shp-brand,
.px-adc.shp-item-brand {
  --pxa:         #E35205;
  --a-ground:    #1A222A;  /* the room */
  --a-deep:      #12181E;  /* bands within it */
  --a-raise:     #232D36;  /* raised surfaces on dark */
  --a-edge:      rgba(215,222,224,.16);
  --a-mist:      #DDE3E6;  /* primary text on dark */
  --a-steel:     #8B98A2;  /* secondary */
  --a-orange:    #E35205;
  --a-orange-hi: #F26A22;
  --a-plate-hi:  #FFFFFF;
  --a-plate-lo:  #E7ECEE;
  --a-grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23g)'/%3E%3C/svg%3E");
  background: var(--a-ground);
}

/* --- grain ---
   Reads harder on charcoal than it did on silver, which is the
   point: it is what stops a large dark field going flat. Screen
   rather than multiply, since it has to lift rather than darken. */
.px-adc .shb-hero,
.px-adc .shb-show { position: relative; }
.px-adc .shb-hero::after,
.px-adc .shb-show::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background-image: var(--a-grain); background-size: 160px 160px;
  opacity: .16; mix-blend-mode: screen;
}
.px-adc .shb-hero > *,
.px-adc .shb-show > * { position: relative; z-index: 1; }

/* --- hero --- */
.px-adc .shb-hero {
  background: radial-gradient(120% 90% at 22% 0%, #26313B 0%, var(--a-ground) 46%, var(--a-deep) 100%);
  border-bottom: 0;
}
.px-adc .shb-hero::before {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: linear-gradient(90deg, transparent, var(--a-edge) 20%, rgba(227,82,5,.55) 50%, var(--a-edge) 80%, transparent);
  z-index: 2;
}
.px-adc .shb-hero .cx-eyebrow { color: var(--a-steel); font-weight: 700; letter-spacing: .13em; }
.px-adc .shb-hero-copy h1 { color: #FFFFFF; }
.px-adc .shb-hero-copy h1 em { color: var(--a-orange); }
.px-adc .shb-lede { color: var(--a-steel); }
.px-adc .shb-count { color: var(--a-steel); }
.px-adc .shb-count strong { color: #FFFFFF; }
.px-adc .shb-hero-visual img {
  border: 1px solid var(--a-edge);
  box-shadow: 0 30px 64px -28px rgba(0,0,0,.8);
}
/* the room is dark, so the accent goes on the thing you press */
.px-adc .cx-hero-actions { gap: 24px; }
.px-adc .cx-hero-actions .btn-blue {
  background: linear-gradient(180deg, var(--a-orange-hi) 0%, var(--a-orange) 100%);
  color: #FFFFFF;
  box-shadow: 0 1px 0 rgba(255,255,255,.22) inset, 0 14px 30px -16px rgba(227,82,5,.9);
}
.px-adc .cx-hero-actions .btn-blue:hover {
  background: linear-gradient(180deg, #FF7A32 0%, #E9581A 100%);
}
.px-adc .cx-hero-actions .cx-btn-ghost {
  color: var(--a-mist); border-color: transparent; padding: 16px 2px;
  text-underline-offset: 5px; text-decoration-thickness: 1px;
  text-decoration-color: var(--a-edge);
}
.px-adc .cx-hero-actions .cx-btn-ghost:hover {
  color: #FFFFFF; background: none; text-decoration-color: var(--a-orange);
}

/* --- category strip --- */
.px-adc .shb-cats {
  background: linear-gradient(180deg, #202932 0%, #19212A 100%);
  border-bottom: 1px solid var(--a-edge);
  box-shadow: 0 1px 0 rgba(255,255,255,.05) inset, 0 10px 24px -16px rgba(0,0,0,.9);
}
.px-adc .shb-cat { color: var(--a-steel); }
.px-adc .shb-cat:hover { background: rgba(255,255,255,.05); color: var(--a-mist); }
/* the selected line is marked the way Alarm.com mark things — a short
   orange rule, the same device their headings use */
.px-adc .shb-cat.on {
  background: var(--a-raise); color: #FFFFFF;
  box-shadow: 0 1px 0 rgba(255,255,255,.07) inset, inset 0 2px 0 var(--a-orange);
}
.px-adc .shb-cat-svg { color: var(--a-steel); opacity: .9; transition: color .18s, opacity .18s; }
.px-adc .shb-cat:hover .shb-cat-svg { color: var(--a-mist); opacity: 1; }
.px-adc .shb-cat.on .shb-cat-svg { color: var(--a-orange); opacity: 1; }
.px-adc .shb-cat-l { color: var(--a-steel); }
.px-adc .shb-cat.on .shb-cat-l { color: #FFFFFF; }
.px-adc .shb-cat-n { color: rgba(221,227,230,.42); }
.px-adc .shb-cat.on .shb-cat-n { color: rgba(255,255,255,.72); }

/* --- shelf pills --- */
.px-adc .shb-sub {
  background: rgba(255,255,255,.04); border-color: var(--a-edge); color: var(--a-steel);
}
.px-adc .shb-sub:hover { background: rgba(255,255,255,.09); color: var(--a-mist); }
.px-adc .shb-sub.on {
  background: linear-gradient(180deg, var(--a-orange-hi) 0%, var(--a-orange) 100%);
  border-color: var(--a-orange); color: #FFFFFF;
  box-shadow: 0 1px 0 rgba(255,255,255,.22) inset;
}
.px-adc .shb-sub-n { color: rgba(221,227,230,.45); }
.px-adc .shb-sub.on .shb-sub-n { color: rgba(255,255,255,.8); }

/* --- the lit case ---
   A light plate on a dark ground, with a cold rim above and a warm
   spill below, so the product looks lit rather than pasted on. */
.px-adc .shp-card figure {
  background: radial-gradient(118% 90% at 50% 6%, var(--a-plate-hi) 0%, #F7F9FA 46%, var(--a-plate-lo) 100%);
  border: 1px solid rgba(255,255,255,.1);
  border-radius: 16px;
  box-shadow:
    0 1px 0 rgba(255,255,255,.5) inset,
    0 18px 34px -20px rgba(0,0,0,.85);
  transition: box-shadow .24s, transform .24s, border-color .24s;
}
.px-adc .shp-card:hover figure {
  border-color: rgba(227,82,5,.5);
  box-shadow:
    0 1px 0 rgba(255,255,255,.6) inset,
    0 24px 44px -20px rgba(0,0,0,.9),
    0 10px 30px -12px rgba(227,82,5,.35);
  transform: translateY(-2px);
}
.px-adc .shp-card h3 { color: #FFFFFF; }
.px-adc .shp-card small { color: var(--a-steel); font-weight: 500; letter-spacing: .06em; }
.px-adc .shp-card-price {
  color: var(--a-mist); font-weight: 600;
  font-variant-numeric: tabular-nums; letter-spacing: -.01em;
}

/* --- controls --- */
.px-adc .shp-search {
  background: rgba(255,255,255,.05); border-color: var(--a-edge);
  box-shadow: 0 1px 0 rgba(255,255,255,.06) inset;
}
.px-adc .shp-search:focus-within {
  border-color: rgba(227,82,5,.6);
  box-shadow: 0 1px 0 rgba(255,255,255,.06) inset, 0 0 0 4px rgba(227,82,5,.14);
}
.px-adc .shp-search svg { stroke: var(--a-steel); }
.px-adc .shp-search input { color: #FFFFFF; }
.px-adc .shp-search input::placeholder { color: var(--a-steel); }
.px-adc .shp-search button {
  background: linear-gradient(180deg, var(--a-orange-hi) 0%, var(--a-orange) 100%);
  box-shadow: 0 1px 0 rgba(255,255,255,.22) inset;
}
.px-adc .shp-search button:hover { background: linear-gradient(180deg, #FF7A32 0%, #E9581A 100%); }
.px-adc .shp-count { color: var(--a-steel); }
.px-adc .shp-count strong { color: #FFFFFF; }
.px-adc .shp-toolbar { border-bottom-color: var(--a-edge); }
.px-adc .shp-sort label { color: var(--a-steel); }
.px-adc .shp-sort select,
.px-adc .shp-showmore button {
  background: rgba(255,255,255,.05); border: 1px solid var(--a-edge); color: var(--a-mist);
}
.px-adc .shp-showmore button:hover { border-color: rgba(227,82,5,.6); color: #FFFFFF; }
.px-adc .shp-empty { color: var(--a-steel); }

/* --- the window ---
   Light cards here too, for the same reason the tiles are light: the
   fallback photograph is an opaque JPEG on white. Their orange marks
   the tag, which is the one warm thing on each card. */
.px-adc .shb-show { background: linear-gradient(180deg, var(--a-deep) 0%, var(--a-ground) 100%); }
.px-adc .shb-h2 { color: #FFFFFF; }
.px-adc .shb-h2 em { color: var(--a-steel); }
.px-adc .shb-show-card {
  background: linear-gradient(178deg, #FFFFFF 0%, #EEF1F3 100%);
  border: 1px solid rgba(255,255,255,.14);
  box-shadow: 0 20px 40px -22px rgba(0,0,0,.85);
}
.px-adc .shb-show-card:hover {
  border-color: rgba(227,82,5,.5);
  box-shadow: 0 26px 48px -22px rgba(0,0,0,.9), 0 12px 32px -14px rgba(227,82,5,.3);
}
.px-adc .shb-show-tag {
  align-self: flex-start; color: var(--a-orange);
  border: 1px solid rgba(227,82,5,.35); border-radius: 999px;
  padding: 5px 10px; letter-spacing: .14em; font-size: 10px;
  background: rgba(227,82,5,.08);
}
.px-adc .shb-show-name { color: #101820; }
.px-adc .shb-show-desc { color: #5B6572; }

/* the inline line icons size like the UniFi artwork they sit in place of */
.shb-cat-svg { display: block; height: 34px; width: auto; }

/* --- the product page, in the same room --- */
.px-adc .shp-crumb,
.px-adc .shp-crumb a { color: var(--a-steel); }
.px-adc .shp-crumb a:hover { color: var(--a-orange); }
.px-adc .shp-hero-img {
  background: radial-gradient(118% 90% at 50% 6%, var(--a-plate-hi) 0%, #F7F9FA 46%, var(--a-plate-lo) 100%);
  border: 1px solid rgba(255,255,255,.12); border-radius: 18px;
  box-shadow: 0 1px 0 rgba(255,255,255,.5) inset, 0 26px 50px -24px rgba(0,0,0,.85);
}
.px-adc .shp-thumb {
  background: #F2F5F6; border-color: rgba(255,255,255,.14);
}
.px-adc .shp-thumb:hover { border-color: rgba(227,82,5,.6); }
.px-adc .shp-mfr { color: var(--a-orange); letter-spacing: .14em; }
.px-adc .shp-info h1 { color: #FFFFFF; letter-spacing: -.02em; }
.px-adc .shp-meta { color: var(--a-steel); font-variant-numeric: tabular-nums; }
.px-adc .shp-price {
  color: #FFFFFF; font-weight: 700;
  font-variant-numeric: tabular-nums; letter-spacing: -.02em;
}
.px-adc .shp-short,
.px-adc .shp-desc,
.px-adc .shp-note,
.px-adc .shp-info li { color: var(--a-steel); }
.px-adc .shp-h2 { color: #FFFFFF; }
.px-adc .shp-actions .btn-blue {
  background: linear-gradient(180deg, var(--a-orange-hi) 0%, var(--a-orange) 100%);
  box-shadow: 0 1px 0 rgba(255,255,255,.22) inset, 0 14px 30px -16px rgba(227,82,5,.9);
}
.px-adc .shp-actions .btn-blue:hover { background: linear-gradient(180deg, #FF7A32 0%, #E9581A 100%); }
.px-adc .shp-ghost {
  color: var(--a-mist); border: 1px solid var(--a-edge);
  background: rgba(255,255,255,.05);
}
.px-adc .shp-ghost:hover { border-color: rgba(227,82,5,.6); color: #FFFFFF; }
.px-adc .shp-chip {
  color: var(--a-mist); background: rgba(255,255,255,.06);
  border: 1px solid var(--a-edge);
}
.px-adc .shp-chip-link { color: var(--a-orange); background: rgba(227,82,5,.1); }

@media (max-width: 600px) {
  .px-adc .cx-hero-actions { flex-wrap: wrap; gap: 14px 20px; }
  .px-adc .cx-hero-actions .btn-blue,
  .px-adc .cx-hero-actions .cx-btn-ghost { flex: 0 0 auto; white-space: nowrap; }
}

/* The band the search sits in is white by default, which cut a light stripe
   across both storefront rooms between the strip and the grid. */
.px-unifi .shp-head { background: linear-gradient(180deg, #F3F5F8 0%, var(--m-ground) 100%); }
.px-adc .shp-head { background: linear-gradient(180deg, #1C242C 0%, var(--a-ground) 100%); }

/* The window's price, where a brand has no copy worth showing. */
.shb-show-price {
  font: 700 20px/1 var(--sans); letter-spacing: -.02em;
  font-variant-numeric: tabular-nums; margin-top: 10px;
}
.px-adc .shb-show-price { color: #101820; }
/* Every one of these photographs is an opaque JPEG shot on white, which on
   an off-white card shows as a paler rectangle with visible edges. Multiply
   drops that ground into the card the way it already does on the tiles. */
.px-adc .shb-show-img img { mix-blend-mode: multiply; }

/* --- a product with no usable photograph ---
   The file behind primary_image_path can go missing — it did, when a delete
   in the app took the image for a product it was not deleting. Hide the
   broken element and leave a quiet mark in its place, so the tile reads as
   "no photo yet" rather than "this page is broken". */
.shp-card figure.img-missing img,
.shp-hero-img.img-missing img,
.shb-show-img.img-missing img,
.shp-thumb.img-missing img { display: none; }
.shp-card figure.img-missing,
.shp-hero-img.img-missing,
.shb-show-img.img-missing,
.shp-thumb.img-missing {
  position: relative;
}
.shp-card figure.img-missing::after,
.shp-hero-img.img-missing::after,
.shb-show-img.img-missing::after,
.shp-thumb.img-missing::after {
  content: '';
  position: absolute; inset: 0;
  background-repeat: no-repeat; background-position: center;
  background-size: 34%;
  opacity: .16;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48' fill='none' stroke='%230B1017' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='5' y='10' width='38' height='28' rx='3.5'/%3E%3Ccircle cx='16' cy='20' r='3.2'/%3E%3Cpath d='M5 31l10.5-9 8 7 7-5.5L43 33'/%3E%3C/svg%3E");
}
/* the storefront tiles are small — keep the mark from filling them */
.shp-card figure.img-missing::after { background-size: 30%; }
.shp-thumb.img-missing::after { background-size: 52%; }

/* ---------- checkout (.chk) — behind SHIELD_SHOP_CHECKOUT ---------- */
.chk { background: #fff; }
.chk-closed { padding: 120px 0 110px; background: linear-gradient(180deg, #FFFFFF 0%, #EEF2F7 100%); }
.chk-closed-card { max-width: 640px; }
.chk-closed-card h1 { font-size: clamp(36px, 4.4vw, 52px); line-height: 1.08; font-weight: 800; color: var(--navy); margin: 0 0 16px; }
.chk-closed-card h1 em { font-style: normal; color: var(--brand); }
.chk-closed-card p { font-size: 16.5px; line-height: 1.7; color: var(--ink-soft); margin: 0 0 26px; }
.chk-closed-card a { color: var(--brand-deep); font-weight: 700; }
.chk-closed-actions { display: flex; gap: 12px; flex-wrap: wrap; }
.chk-closed-actions a { font-weight: 700; }

.chk-head { background: linear-gradient(180deg, #FFFFFF 0%, #EEF2F7 100%); padding: 56px 0 30px; }
.chk-head h1 { font-size: clamp(34px, 4vw, 46px); font-weight: 800; color: var(--navy); margin: 0; }
.chk-preview-tag {
  display: inline-block; margin: 14px 0 0; padding: 8px 14px; border-radius: 999px;
  background: #FFF4E2; border: 1px solid #F0D9AE; color: #8A6210;
  font: 700 12.5px/1 var(--sans);
}
.chk-body { padding: 40px 0 80px; }
.chk-grid { display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); gap: 44px; align-items: start; }

.chk-empty h2 { font: 800 24px/1.2 var(--sans); color: var(--navy); margin: 0 0 8px; }
.chk-empty p { color: var(--ink-soft); margin: 0 0 18px; }
.chk-empty a { color: var(--brand-deep); font-weight: 700; }

.chk-main h2 { font: 800 19px/1.25 var(--sans); color: var(--navy); margin: 26px 0 14px; }
.chk-main h2:first-child { margin-top: 0; }
.chk-fields { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.chk-fields label { display: flex; flex-direction: column; gap: 6px; font: 700 13px/1.3 var(--sans); color: var(--navy); }
.chk-fields .chk-wide { grid-column: 1 / -1; }
.chk-opt { font-weight: 500; color: var(--ink-soft); }
.chk-fields input, .chk-fields textarea {
  font: 500 15px/1.4 var(--sans); color: var(--navy);
  border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px; background: #fff;
}
.chk-fields input:focus, .chk-fields textarea:focus { outline: 2px solid var(--brand); outline-offset: 1px; border-color: var(--brand); }
.chk-delivery { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-bottom: 14px; }
.chk-radio {
  display: flex; gap: 12px; align-items: flex-start; cursor: pointer;
  border: 1px solid var(--line); border-radius: 12px; padding: 14px 16px;
  font: 500 13.5px/1.5 var(--sans); color: var(--ink-soft);
}
.chk-radio strong { color: var(--navy); font-size: 14.5px; }
.chk-radio input { margin-top: 3px; accent-color: var(--brand); }
.chk-radio:has(input:checked) { border-color: var(--brand); background: #F4F8FD; }
.chk-pay { margin-top: 28px; }
.chk-pay .btn-blue[disabled] { opacity: .55; cursor: not-allowed; }
.chk-pay-note { margin: 12px 0 0; font: 500 13.5px/1.5 var(--sans); color: var(--ink-soft); }

.chk-side {
  border: 1px solid var(--line); border-radius: 14px; padding: 24px 24px 20px;
  background: #FAFBFD; position: sticky; top: 90px;
}
.chk-side h2 { font: 800 17px/1.2 var(--sans); color: var(--navy); margin: 0 0 16px; }
.chk-item { display: grid; grid-template-columns: 64px minmax(0, 1fr) auto; gap: 12px; padding: 12px 0; border-top: 1px solid var(--line); }
.chk-item figure { margin: 0; width: 64px; height: 64px; background: #fff; border: 1px solid var(--line); border-radius: 10px; display: flex; align-items: center; justify-content: center; overflow: hidden; }
.chk-item figure img { max-width: 52px; max-height: 52px; object-fit: contain; mix-blend-mode: multiply; }
.chk-item-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.chk-item-body small { font: 700 10.5px/1 var(--sans); letter-spacing: .08em; text-transform: uppercase; color: var(--ink-soft); }
.chk-item-body strong { font: 700 13.5px/1.35 var(--sans); color: var(--navy); }
.chk-item-price { font: 800 13.5px/1 var(--sans); color: var(--brand); margin-top: 4px; }
.chk-item-qty { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; }
.chk-item-qty b { font: 800 14px/1 var(--sans); color: var(--navy); order: 0; }
.chk-item-qty button {
  font: 800 15px/1 var(--sans); color: var(--navy); background: #fff;
  border: 1px solid var(--line); border-radius: 8px; width: 28px; height: 26px; cursor: pointer;
}
.chk-item-qty { flex-direction: row; align-items: center; }
.chk-item-qty .chk-item-rm {
  width: auto; height: auto; border: 0; background: none;
  font: 700 11.5px/1 var(--sans); color: var(--ink-soft); text-decoration: underline; margin-left: 6px;
}
.chk-item-qty .chk-item-rm:hover { color: #B3261E; }
.chk-totals { margin: 16px 0 0; padding: 0; }
.chk-totals div { display: flex; justify-content: space-between; padding: 7px 0; font: 500 14px/1.4 var(--sans); color: var(--ink-soft); }
.chk-totals dd { margin: 0; font-weight: 700; color: var(--navy); font-variant-numeric: tabular-nums; }
.chk-grand { border-top: 1px solid var(--line); margin-top: 6px; padding-top: 12px !important; }
.chk-grand dt { font-weight: 800; color: var(--navy); }
.chk-grand dd { font-size: 18px; font-weight: 800; color: var(--brand); }
.chk-fine { margin: 14px 0 0; font: 500 12.5px/1.6 var(--sans); color: var(--ink-soft); }
.chk-fine a { color: var(--brand-deep); font-weight: 700; }

@media (max-width: 900px) {
  .chk-grid { grid-template-columns: 1fr; }
  .chk-side { position: static; order: -1; }
  .chk-fields, .chk-delivery { grid-template-columns: 1fr; }
}

/* Checkout payment step (NMI Collect.js inline iframes mount into these) */
.chk-card { display: grid; grid-template-columns: 2fr 1fr 1fr; gap: 14px; }
.chk-cc {
  border: 1px solid var(--line); border-radius: 10px; background: #fff;
  height: 46px; padding: 0 6px; overflow: hidden;
}
.chk-cc iframe { height: 44px !important; }
.chk-err {
  margin: 0 0 14px; padding: 12px 16px; border-radius: 10px;
  background: #FDF1F0; border: 1px solid #EFC5C0; color: #8C2B23;
  font: 600 14px/1.5 var(--sans);
}
.chk-done h2 { font: 800 26px/1.2 var(--sans); color: var(--navy); margin: 0 0 10px; }
.chk-done p { font: 500 15.5px/1.7 var(--sans); color: var(--ink-soft); margin: 0 0 14px; }
.chk-done strong { color: var(--navy); font-variant-numeric: tabular-nums; }
.chk-done .btn-blue { margin-top: 8px; }
@media (max-width: 560px) { .chk-card { grid-template-columns: 1fr; } }

/* Brushed-metal grounds for the two flagship storefront heroes — the same
   plates as the Alarm.com hub pages, light for UniFi's silver room, dark
   for Alarm.com's. Layered under each theme's existing grain and edges. */
.px-unifi .shb-hero {
  background: #E8ECF1 url('https://shieldlowvoltage.com/wp-content/uploads/2026/09/hero-brushed-light2.jpg') center / cover no-repeat;
}
.px-adc .shb-hero {
  background: #0c0d0f url('https://shieldlowvoltage.com/wp-content/uploads/2026/09/hero-brushed-dark.jpg') center / cover no-repeat;
}
.shb-logo { display: block; margin: 0 0 16px; }
.shb-logo img { height: 40px; width: auto; max-width: 280px; display: block; }
.px-adc .shb-logo img { height: 78px; }
/* fixed overlay nav: the shop heads were laid out for the in-flow bar */
.nav-overlay .shp-head { padding-top: 140px; }
.nav-overlay .px-unifi .shb-hero, .nav-overlay .px-adc .shb-hero { padding-top: 122px; }

/* ---- storefront cart controls (live when checkout is open) ---- */
.shp-cartlink {
  margin-left: auto; padding: 6px 13px; border-radius: 999px; white-space: nowrap;
  font: 700 13px/1 var(--sans); text-decoration: none;
  color: #fff; background: var(--brand);
}
.shp-cartlink b { font-weight: 800; }
.shp-cartlink:hover { filter: brightness(1.07); }
.shp-crumb { display: flex; align-items: center; gap: 10px; }
.shp-cartlink-head { position: absolute; top: 26px; right: 24px; margin-left: 0; }
.shp-head { position: relative; }
.shp-add.is-added { background: #1E6B4F; pointer-events: none; }
@media (max-width: 560px) {
  .shp-cartlink-head { top: 14px; right: 14px; }
}

/* ============ Josh.ai storefront room ============
   Near-black to match the Josh marketing page, scoped to the hero and
   the lineup band; the catalog below stays on the house light ground.
   Josh blue carries the accents; the white lockup finally has a wall
   it can read against. */
.px-josh.shp-brand { --pxa: #008CFF; }
.px-josh .shb-hero {
  background: radial-gradient(120% 90% at 22% 0%, #17191E 0%, #0B0C0E 55%, #08090B 100%);
  border-bottom: 0; position: relative;
}
.px-josh .shb-hero::before {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.14) 20%, rgba(0,140,255,.6) 50%, rgba(255,255,255,.14) 80%, transparent);
}
.px-josh .shb-hero-copy h1 { color: #FFFFFF; }
.px-josh .shb-hero-copy h1 em { color: #008CFF; }
.px-josh .shb-lede { color: rgba(255,255,255,.74); }
.px-josh .shb-count { color: rgba(255,255,255,.6); }
.px-josh .shb-count strong { color: #FFFFFF; }
.px-josh .shb-hero .cx-btn-ghost { color: #fff; border-color: rgba(255,255,255,.35); }
.px-josh .shb-hero .cx-btn-ghost:hover { border-color: #fff; }
.px-josh .shb-hero-visual img { box-shadow: 0 30px 80px -30px rgba(0,0,0,.9); }
.px-josh .shb-show { background: #0B0C0E; }
.px-josh .shb-h2 { color: #FFFFFF; }
.px-josh .shb-h2 em { color: #008CFF; }
