Find the Accessories That Fit Your Camera

<!-- GardePro Accessory Compatibility Finder -->
<style>
/* ============================================================
   GardePro — Accessory Compatibility Finder
   作用域限定在 .cp 内,避免与 Shopify 主题样式冲突
   ============================================================ */

.cp {
  --cp-ink: #11161c;
  --cp-body: #3d4653;
  --cp-muted: #6b7683;
  --cp-line: #e4e8ee;
  --cp-line-soft: #eff2f6;
  --cp-bg: #ffffff;
  --cp-soft: #f6f8fa;
  --cp-accent: #e77b1f;          /* 品牌主题橙 */
  --cp-accent-2: #cf6a0d;
  --cp-accent-soft: #fdf1e2;
  --cp-green: #0e7a52;           /* Compatible 语义色 */
  --cp-green-soft: #e7f4ee;
  --cp-warn: #8a5a00;
  --cp-warn-soft: #fdf4e3;
  --cp-radius: 14px;
  --cp-shadow: 0 1px 2px rgba(16, 24, 40, .04), 0 12px 32px -12px rgba(16, 24, 40, .12);

  font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  color: var(--cp-body);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  max-width: 1160px;
  margin: 0 auto;
  padding: 8px 20px 64px;
  box-sizing: border-box;
}

.cp *,
.cp *::before,
.cp *::after { box-sizing: border-box; }

.cp h1, .cp h2, .cp h3, .cp p, .cp dl, .cp dd, .cp dt, .cp ul, .cp li { margin: 0; padding: 0; }
.cp ul { list-style: none; }
.cp button { font: inherit; color: inherit; cursor: pointer; border: 0; background: none; }

/* ---------- Hero ---------- */
.cp-hero { text-align: center; padding: 40px 0 8px; }

.cp-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--cp-accent);
  background: var(--cp-accent-soft);
  padding: 6px 12px;
  border-radius: 999px;
}

.cp-hero h1 {
  font-size: clamp(26px, 4vw, 40px);
  line-height: 1.16;
  letter-spacing: -.02em;
  color: var(--cp-ink);
  margin: 18px auto 12px;
  max-width: 720px;
  font-weight: 700;
}

.cp-lede {
  font-size: 16px;
  color: var(--cp-muted);
  max-width: 640px;
  margin: 0 auto;
  text-align: center;
  text-wrap: balance;   /* 两行均匀换行,视觉上真正居中 */
}

/* ---------- Search ---------- */
.cp-search {
  position: relative;
  max-width: 620px;
  margin: 28px auto 0;
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--cp-bg);
  border: 1.5px solid var(--cp-line);
  border-radius: 999px;
  padding: 6px 6px 6px 18px;
  box-shadow: var(--cp-shadow);
  transition: border-color .18s, box-shadow .18s;
}
.cp-search:focus-within {
  border-color: var(--cp-accent);
  box-shadow: 0 0 0 4px rgba(15, 107, 79, .1), var(--cp-shadow);
}
.cp-search > svg { flex: 0 0 auto; color: var(--cp-muted); }
.cp-search input {
  flex: 1 1 auto;
  min-width: 0;
  border: 0;
  outline: 0;
  background: none;
  font-size: 15.5px;
  padding: 12px 4px;
  color: var(--cp-ink);
}
.cp-search input::placeholder { color: #9aa4b1; }

.cp-search-btn {
  flex: 0 0 auto;
  background: var(--cp-accent);
  color: #fff;
  font-weight: 600;
  font-size: 14.5px;
  padding: 12px 22px;
  border-radius: 999px;
  transition: background .18s;
}
.cp-search-btn:hover { background: var(--cp-accent-2); }

/* 联想下拉 */
.cp-sugg {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  right: 0;
  background: var(--cp-bg);
  border: 1px solid var(--cp-line);
  border-radius: 14px;
  box-shadow: 0 18px 40px -12px rgba(16, 24, 40, .22);
  padding: 6px;
  max-height: 340px;
  overflow: auto;
  z-index: 40;
  display: none;
  text-align: left;
}
.cp-sugg.is-open { display: block; }
.cp-sugg li { border-radius: 9px; }
.cp-sugg button {
  display: flex;
  width: 100%;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 12px;
  border-radius: 9px;
  font-size: 15px;
  color: var(--cp-ink);
  text-align: left;
}
.cp-sugg button:hover,
.cp-sugg button.is-active { background: var(--cp-soft); }
.cp-sugg .cp-sugg-hint { font-size: 12px; color: var(--cp-muted); }
.cp-sugg mark { background: transparent; color: var(--cp-accent); font-weight: 600; }

.cp-quick {
  margin: 18px auto 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: center;
  align-items: center;
  font-size: 13px;
  color: var(--cp-muted);
}
.cp-quick button {
  border: 1px solid var(--cp-line);
  background: var(--cp-bg);
  padding: 5px 12px;
  border-radius: 999px;
  font-size: 13px;
  color: var(--cp-body);
  transition: .15s;
}
.cp-quick button:hover { border-color: var(--cp-accent); color: var(--cp-accent); }

/* ---------- 结果区 ---------- */
.cp-result { margin-top: 40px; scroll-margin-top: 24px; }
.cp-result[hidden] { display: none; }

.cp-cam-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  padding: 18px 20px;
  border: 1px solid var(--cp-line);
  border-radius: var(--cp-radius);
  background: linear-gradient(180deg, #fbfdfc, #f4f9f6);
}
.cp-cam-head .cp-cam-label {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--cp-muted);
  width: 100%;
}
.cp-cam-name {
  font-size: 24px;
  font-weight: 700;
  color: var(--cp-ink);
  letter-spacing: -.01em;
  line-height: 1.2;
}
.cp-cam-sub { font-size: 13.5px; color: var(--cp-muted); }
.cp-cam-head .cp-spacer { flex: 1 1 auto; }

.cp-ghost-btn {
  border: 1px solid transparent;
  background: var(--cp-accent);
  border-radius: 999px;
  padding: 8px 16px;
  font-size: 13.5px;
  font-weight: 600;
  color: #fff;
  transition: .15s;
}
.cp-ghost-btn:hover { background: var(--cp-accent-2); }

.cp-tag {
  display: inline-flex;
  align-items: center;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .02em;
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--cp-line-soft);
  color: var(--cp-muted);
  white-space: nowrap;
}
.cp-tag.is-hw { background: var(--cp-warn-soft); color: var(--cp-warn); }

/* 分类块 */
.cp-cat { margin-top: 34px; }
.cp-cat-title {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--cp-line);
  margin-bottom: 18px;
}
.cp-cat-title h2 {
  font-size: 18px;
  font-weight: 650;
  color: var(--cp-ink);
  letter-spacing: -.01em;
  display: flex;
  align-items: center;
  gap: 9px;
}
.cp-cat-title h2 svg { color: var(--cp-accent); }
.cp-cat-title .cp-count { font-size: 13px; color: var(--cp-muted); }

.cp-cards {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

/* 配件卡 */
.cp-card {
  border: 1px solid var(--cp-line);
  border-radius: var(--cp-radius);
  background: var(--cp-bg);
  padding: 18px 18px 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  transition: border-color .18s, box-shadow .18s, transform .18s;
}
.cp-card:hover {
  border-color: #cfd8e3;
  box-shadow: 0 10px 26px -14px rgba(16, 24, 40, .28);
  transform: translateY(-1px);
}
.cp-card-top { display: flex; align-items: center; gap: 10px; justify-content: space-between; }
.cp-model {
  font-size: 19px;
  font-weight: 700;
  color: var(--cp-ink);
  letter-spacing: -.01em;
}
.cp-badge {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--cp-green);
  background: var(--cp-green-soft);
  padding: 3px 9px;
  border-radius: 999px;
  white-space: nowrap;
}
.cp-badge.is-rec {
  color: var(--cp-accent-2);
  background: var(--cp-accent-soft);
}
.cp-conds { display: flex; flex-wrap: wrap; gap: 6px; }
.cp-note {
  font-size: 13px;
  color: var(--cp-muted);
  background: var(--cp-soft);
  border-left: 2px solid var(--cp-line);
  padding: 7px 10px;
  border-radius: 0 8px 8px 0;
}
.cp-card-foot { margin-top: auto; padding-top: 4px; }
.cp-more {
  font-size: 13.5px;
  font-weight: 600;
  color: var(--cp-accent);
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 0;
}
.cp-more svg { transition: transform .2s; }
.cp-more[aria-expanded="true"] svg { transform: rotate(180deg); }

.cp-specs {
  display: none;
  border-top: 1px dashed var(--cp-line);
  padding-top: 10px;
  margin-top: 4px;
}
.cp-specs.is-open { display: block; }
.cp-specs div {
  display: grid;
  grid-template-columns: 42% 1fr;
  gap: 10px;
  padding: 8px 11px;
  margin-bottom: 6px;
  font-size: 12.5px;
  line-height: 1.45;
  background: #f8fafc;
  border: 1px solid var(--cp-line-soft);
  border-radius: 9px;
}
.cp-specs dt { color: var(--cp-muted); }
.cp-specs dd { color: var(--cp-body); font-weight: 500; }

.cp-empty {
  font-size: 14px;
  color: var(--cp-muted);
  padding: 18px 20px;
  border: 1px dashed var(--cp-line);
  border-radius: var(--cp-radius);
  background: var(--cp-soft);
}

/* ---------- 浏览全部配件 ---------- */
.cp-browse { margin-top: 64px; }
.cp-sec-head {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  align-items: flex-end;
  justify-content: space-between;
  border-bottom: 1px solid var(--cp-line);
  padding-bottom: 14px;
  margin-bottom: 20px;
}
.cp-sec-head h2 {
  font-size: 22px;
  font-weight: 700;
  color: var(--cp-ink);
  letter-spacing: -.015em;
}
.cp-sec-head p { font-size: 14px; color: var(--cp-muted); margin-top: 4px; }

.cp-tabs { display: flex; flex-wrap: wrap; gap: 6px; }
.cp-tabs button {
  padding: 8px 16px;
  border-radius: 999px;
  font-size: 13.5px;
  font-weight: 550;
  color: var(--cp-body);
  border: 1px solid var(--cp-line);
  background: #fff;
  transition: .15s;
}
.cp-tabs button:hover { border-color: #c3ccd8; }
.cp-tabs button.is-active {
  background: var(--cp-accent);
  border-color: var(--cp-accent);
  color: #fff;
  box-shadow: 0 4px 12px -4px rgba(231, 123, 31, .5);
}

.cp-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 12px;
}
.cp-tile {
  text-align: left;
  border: 1px solid var(--cp-line);
  border-radius: 12px;
  padding: 16px;
  background: #fff;
  transition: .16s;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.cp-tile:hover {
  border-color: var(--cp-accent);
  box-shadow: 0 10px 24px -14px rgba(231, 123, 31, .55);
  transform: translateY(-1px);
}
.cp-tile-view {
  margin-top: 7px;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--cp-accent);
}
.cp-tile-view svg { transition: transform .18s; }
.cp-tile:hover .cp-tile-view svg { transform: translateX(3px); }
.cp-tile .cp-tile-model { font-size: 16px; font-weight: 700; color: var(--cp-ink); }
.cp-tile .cp-tile-meta { font-size: 12.5px; color: var(--cp-muted); }

/* ---------- 抽屉 / 弹层 ---------- */
.cp-modal {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(12, 18, 26, .5);
  backdrop-filter: blur(2px);
}
.cp-modal.is-open { display: flex; }
.cp-modal-box {
  background: #fff;
  border-radius: 18px;
  width: 100%;
  max-width: 720px;
  max-height: 86vh;
  overflow: auto;
  padding: 26px 26px 30px;
  position: relative;
  box-shadow: 0 30px 70px -20px rgba(0, 0, 0, .45);
  animation: cp-pop .2s ease-out;
}
@keyframes cp-pop { from { opacity: 0; transform: translateY(8px) scale(.99); } }
.cp-modal-close {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  color: var(--cp-muted);
  background: var(--cp-soft);
}
.cp-modal-close:hover { color: var(--cp-ink); }

.cp-modal-box h3 {
  font-size: 22px;
  font-weight: 700;
  color: var(--cp-ink);
  letter-spacing: -.01em;
  margin-bottom: 2px;
}
.cp-modal-cat { font-size: 12px; font-weight: 600; letter-spacing: .1em; text-transform: uppercase; color: var(--cp-accent); }
.cp-modal-note {
  margin-top: 12px;
  font-size: 13.5px;
  color: var(--cp-body);
  background: var(--cp-warn-soft);
  color: var(--cp-warn);
  border-radius: 10px;
  padding: 10px 12px;
}
.cp-modal-block { margin-top: 22px; }
.cp-modal-block h4 {
  font-size: 13px;
  font-weight: 650;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--cp-muted);
  margin: 0 0 10px;
}
.cp-typegroup { margin-top: 14px; }
.cp-typegroup-head {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--cp-body);
  margin-bottom: 8px;
}
.cp-pills { display: flex; flex-wrap: wrap; gap: 6px; }
.cp-pill {
  font-size: 12.5px;
  padding: 4px 10px;
  border-radius: 7px;
  background: var(--cp-soft);
  border: 1px solid var(--cp-line-soft);
  color: var(--cp-body);
}
.cp-pill:hover { border-color: var(--cp-accent); color: var(--cp-accent); }

/* 弹窗内:机型网格对齐(横竖都对齐,浅色格子) */
.cp-typegroup .cp-pills {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(106px, 1fr));
  gap: 8px;
}
.cp-typegroup .cp-pill {
  text-align: center;
  padding: 7px 6px;
  border-radius: 9px;
  background: #f8fafc;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cp-typegroup .cp-pill:hover {
  background: var(--cp-accent-soft);
  border-color: var(--cp-accent);
}

.cp-spec-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0 7px;
  font-size: 13px;
  margin-top: -2px;
}
.cp-spec-table td {
  padding: 8px 14px;
  background: #f8fafc;
  border-top: 1px solid var(--cp-line-soft);
  border-bottom: 1px solid var(--cp-line-soft);
  vertical-align: top;
}
.cp-spec-table td:first-child {
  color: var(--cp-muted);
  width: 42%;
  padding-right: 14px;
  border-left: 1px solid var(--cp-line-soft);
  border-radius: 10px 0 0 10px;
}
.cp-spec-table td:last-child {
  color: var(--cp-ink);
  font-weight: 500;
  border-right: 1px solid var(--cp-line-soft);
  border-radius: 0 10px 10px 0;
}

/* ---------- HW "?" 提示 ---------- */
.cp-hw {
  display: inline-grid;
  place-items: center;
  width: 15px;
  height: 15px;
  margin-left: 6px;
  border: 1.2px solid currentColor;
  border-radius: 50%;
  font-size: 10px;
  font-weight: 700;
  line-height: 1;
  padding: 0;
  color: inherit;
  background: transparent;
  position: relative;
  cursor: help;
  vertical-align: -2px;
}

/* ---------- HW 提示弹层(body 级,避免被卡片/弹窗裁剪) ---------- */
.cp-hw-pop {
  position: fixed;
  z-index: 99999;
  max-width: min(280px, calc(100vw - 24px));
  background: #1a222c;
  color: #fff;
  font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
  font-size: 12.5px;
  font-weight: 400;
  line-height: 1.55;
  letter-spacing: 0;
  text-transform: none;
  text-align: left;
  padding: 10px 13px;
  border-radius: 10px;
  box-shadow: 0 14px 30px -10px rgba(0, 0, 0, .45);
  pointer-events: none;
  opacity: 0;
  transform: translateY(3px);
  transition: opacity .15s, transform .15s;
}
.cp-hw-pop.is-show { opacity: 1; transform: translateY(0); }

/* ---------- 特殊徽章 ---------- */
.cp-chip {
  display: inline-flex;
  align-items: center;
  font-size: 11.5px;
  font-weight: 600;
  padding: 3px 10px;
  border-radius: 999px;
  background: #f4f6f9;
  border: 1px solid var(--cp-line);
  color: #4a5563;
  white-space: nowrap;
}

/* ---------- 推荐卡 ---------- */
.cp-card.is-rec { border-color: #f5c9ae; background: linear-gradient(180deg, #fffdfb, #fff6f0); }
.cp-note.is-rec-tip {
  border-left-color: var(--cp-accent);
  background: #fdf0e7;
  color: #8a4520;
}

/* ---------- 弹层头部 ---------- */
.cp-modal-head {
  padding-bottom: 14px;
  border-bottom: 1px solid var(--cp-line);
  margin-bottom: 6px;
}
.cp-modal-head h3 { margin-bottom: 0; }
.cp-modal-box h4 { margin-bottom: 10px; }

/* ---------- 页脚 ---------- */
.cp-foot {
  margin-top: 56px;
  padding-top: 20px;
  border-top: 1px solid var(--cp-line);
  font-size: 12.5px;
  color: var(--cp-muted);
  display: flex;
  flex-wrap: wrap;
  gap: 8px 18px;
  justify-content: space-between;
}

.cp-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }

@media (max-width: 640px) {
  .cp { padding: 4px 16px 48px; }
  .cp-hero { padding-top: 26px; }
  .cp-search { padding-left: 14px; }
  .cp-search-btn { padding: 11px 16px; }
  .cp-cam-name { font-size: 20px; }
  .cp-cards { grid-template-columns: 1fr; }

  .cp-specs div { grid-template-columns: 1fr; gap: 2px; }
  .cp-modal-box { padding: 22px 18px 26px; }
}

</style>
<div class="cp" id="cp-app">
  <header class="cp-hero">
    <div class="cp-eyebrow">
      <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>
      Compatibility Finder
    </div>
    <h1>Find the Accessories That Fit Your Camera</h1>

    <div class="cp-search" role="search">
      <svg width="19" height="19" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.6-3.6"/></svg>
      <label class="cp-sr" for="cp-input">Camera model</label>
      <input id="cp-input" type="text" placeholder="Search your camera model, e.g. X66 Pro" autocomplete="off"
             role="combobox" aria-autocomplete="list" aria-expanded="false" aria-controls="cp-sugg">
      <button class="cp-search-btn" id="cp-search-btn" type="button">Search</button>
      <ul class="cp-sugg" id="cp-sugg" role="listbox" aria-label="Model suggestions"></ul>
    </div>

    <div class="cp-quick" id="cp-quick">
      <span>Popular:</span>
    </div>
  </header>

  <section class="cp-result" id="cp-result" hidden aria-live="polite"></section>

  <section class="cp-browse" id="cp-browse">
    <div class="cp-sec-head">
      <div>
        <h2>Browse All Accessories</h2>
        <p id="cp-browse-sub">Select an accessory to see every compatible camera model.</p>
      </div>
      <div class="cp-tabs" id="cp-tabs" role="tablist"></div>
    </div>
    <div class="cp-grid" id="cp-grid"></div>
  </section>

  <footer class="cp-foot">
    <span id="cp-foot-stats"></span>
    <span>Fitment data is continuously updated. Specifications and compatibility are subject to change without notice.</span>
  </footer>
</div>

<div class="cp-modal" id="cp-modal" role="dialog" aria-modal="true" aria-labelledby="cp-modal-title">
  <div class="cp-modal-box">
    <button class="cp-modal-close" id="cp-modal-close" type="button" aria-label="Close">
      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"><path d="M18 6 6 18M6 6l12 12"/></svg>
    </button>
    <div id="cp-modal-body"></div>
  </div>
</div>

<script type="application/json" id="cp-data">{"brands":[{"brand":"GardePro","accessories":[{"category":"solar","categoryLabel":"Solar Panel","model":"SP300","note":"Non-cellular camera without lithium battery; neither is supported.","specs":"Solar Panel MAX Output Power: 3.5W\nOutput Voltage: 6.6V\nMAX Output Current: 0.53A\nOutput Plug Size: 5.5 x 2.1mm\nMounting: Tripod Base (1/4-20)\nWaterproof: IP65\nOperation Temperature: -4 ~ 140°F / -20 ~ 60°C\nOperation Humidity: 5% - 95%\nProduct Dimensions: 6.22 x 5.28 x 0.59 inch (15.80 × 13.41 × 1.50 cm)\nProduct Weight: 255g","groups":[{"type":"Non-Cellular","hw":"","cameras":[]},{"type":"WiFi","hw":"","cameras":["E6P","E6PMB","E6PCF","E6 2.0 Pro","E6 3.0 Pro","E8P","E8PMB","E8PCF","E8PWF","E8 2.0 Pro","E8 3.0 Pro","E9P","E9PMB","E9PCF","E9PWF","E9 2.0 Pro","E9PWF 2.0","E9 3.0 Pro","A80 Pro"]},{"type":"Long Range WiFi","hw":"","cameras":["R3 Pro","R3 2.0 Pro"]},{"type":"Cellular","hw":"","cameras":["X50P","X50PMB","X50PLMB","X60P","X60PMB","X60PLMB","X66 Pro","X66 Pro Max","X66 3.0 Pro","X66 3.0 Ultra","X70 Pro","X70 3.0 Pro","X70 3.0 Ultra","X80 Pro"]}]},{"category":"solar","categoryLabel":"Solar Panel","model":"SP350","note":"All models","specs":"Battery Capacity: 5200 mAh/3.7V,19.24Wh\nSolar Panel MAX\nOutput Power: 12W(12V/1A)\nOutput Voltage: 6V, 9V or 12V\nOutput Current: 1.5A (6V), 1A (9V or 12V)\nOutput Plug Size: 5.5 x 2.1mm, 4.0 x 1.7mm\nPower Adaptor: Input: AC110-220, output: 5V/1A.\nNote: the adaptor is not included.\nMounting: Tripod Base (1/4-20)\nWaterproof: IP65\nOperation Temperature: -4 ~ 140°F / -20 ~ 60°C\nOperation Humidity: 5% - 95%\nProduct Dimensions: 6.89 x 5.79 x 1.09 inch(17.50 × 14.71 × 2.77 cm)\nProduct Weight: 350g","groups":[{"type":"Non-Cellular","hw":"","cameras":["A3","A3S","E5","E5S","E5 2.0","E5WF 2.0","A5","A5CF","A50","A60","T5NG","T5CF","T5WF","T5NG Pro","T5CF Pro","T5WF Pro"]},{"type":"WiFi","hw":"H/W>=V8.2","cameras":["E6","E6P","E6PMB","E6PCF","E6 2.0","E6 2.0 Pro","E6 3.0 Pro","E7","E8","E8P","E8PMB","E8PCF","E8PWF","E8 2.0","E8 2.0 Pro","E8 3.0 Pro","E9","E9P","E9PMB","E9PCF","E9PWF","E9 2.0","E9 2.0 Pro","E9PWF 2.0","E9 3.0 Pro","A80","A80 Pro"]},{"type":"WiFi","hw":"H/W<V8.2","cameras":["E6","E7","E8","E9","A80","T6LRW"]},{"type":"Long Range WiFi","hw":"","cameras":["R3 Pro","R3 2.0 Pro","T6LRW"]},{"type":"Cellular","hw":"H/W>=V8.2","cameras":["X20","X20WF","X20CF","X50","X50S","X50P","X50MB","X50PMB","X50PLMB","X60P","X60PMB","X60PLMB","X66 Pro","X66 Pro Max","X66 3.0 Pro","X66 3.0 Ultra","X70","X70 Pro","X70 3.0 Pro","X70 3.0 Ultra","X80","X80 Pro"]},{"type":"Cellular","hw":"H/W<V8.2","cameras":["X20","X20WF","X20CF","X50","X50S","X60"]}]},{"category":"solar","categoryLabel":"Solar Panel","model":"SP1000","note":"Non-cellular camera without lithium battery; neither is supported.","specs":"Solar Panel MAX Output Power: 10W\nOutput Voltage: 6.6V\nMAX Output Current : 1.52A\nOutput Plug Size: 5.5 x 2.1mm\nWaterproof: IP65\nOperation Temperature: -4 ~ 140°F / -20 ~ 60°C\nOperation Humidity: 5% - 95%\nProduct Dimensions: 10.78 x 9.53 x 4.92 inch (27.38 × 24.21 × 12.50 cm)\nProduct Weight: 962g","groups":[{"type":"Non-Cellular","hw":"","cameras":[]},{"type":"WiFi","hw":"","cameras":["E6P","E6PMB","E6PCF","E6 2.0 Pro","E6 3.0 Pro","E8P","E8PMB","E8PCF","E8PWF","E8 2.0 Pro","E8 3.0 Pro","E9P","E9PMB","E9PCF","E9PWF","E9 2.0 Pro","E9PWF 2.0","E9 3.0 Pro","A80 Pro","R3 Pro","R3 2.0 Pro"]},{"type":"Long Range WiFi","hw":"","cameras":["R3 Pro","R3 2.0 Pro"]},{"type":"Cellular","hw":"","cameras":["X50P","X50PMB","X50PLMB","X60P","X60PMB","X60PLMB","X66 Pro","X66 Pro Max","X66 3.0 Pro","X66 3.0 Ultra","X70 Pro","X70 3.0 Pro","X70 3.0 Ultra","X80 Pro"]}]},{"category":"solar","categoryLabel":"Solar Panel","model":"SP1100","note":"All models","specs":"Battery Capacity\nTotal Capacity : 10400 mAh / 38.48 Wh\nCell : 2600 mAh x 4pcs\nNominal Voltage : 14.8 V\nSolar Panel MAX\nOutput Power: 27W (12V/2.25A)\nOutput Voltage: 6V, 9V or 12V\nOutput Current: 2.25A (6V), 2.25A (9V ), 2.25A (12V)\nNote: Select the appropriate output voltage according to camera requirements\nOutput Plug Size: 5.5 x 2.1mm, 4.0 x 1.7mm\nPower Adaptor\n(Sold Separately) Type-C INPUT (for Charging Solar Panel): 5-20V(Support PD3.0 fast charging protocol)\nNote: the adaptor is not included.\nMounting: Tripod Base (1/4-20)\nWaterproof: IP65\nOperation Temperature: -4 ~ 140°F / -20 ~ 60°C\nOperation Humidity: 5% - 95%\nProduct Dimensions: 10.78 x 9.53 x 1.50 inch\nProduct Weight: 786g","groups":[{"type":"Non-Cellular","hw":"","cameras":["A3","A3S","E5","E5S","E5 2.0","E5WF 2.0","A5","A5CF","A50","A60","T5NG","T5CF","T5WF","T5NG Pro","T5CF Pro","T5WF Pro"]},{"type":"WiFi","hw":"H/W>=V8.2","cameras":["E6","E6P","E6PMB","E6PCF","E6 2.0","E6 2.0 Pro","E6 3.0 Pro","E7","E8","E8P","E8PMB","E8PCF","E8PWF","E8 2.0","E8 2.0 Pro","E8 3.0 Pro","E9","E9P","E9PMB","E9PCF","E9PWF","E9 2.0","E9 2.0 Pro","E9 3.0 Pro","A80","A80 Pro"]},{"type":"WiFi","hw":"H/W<V8.2","cameras":["E6","E7","E8","E9","A80","T6LRW"]},{"type":"Long Range WiFi","hw":"","cameras":["R3 Pro","R3 2.0 Pro","T6LRW"]},{"type":"Cellular","hw":"H/W>=V8.2","cameras":["X20","X20WF","X20CF","X50","X50S","X50P","X50MB","X50PMB","X50PLMB","X60P","X60PMB","X60PLMB","X66 Pro","X66 Pro Max","X66 3.0 Pro","X66 3.0 Ultra","X70","X70 Pro","X70 3.0 Pro","X70 3.0 Ultra","X80","X80 Pro"]},{"type":"Cellular","hw":"H/W<V8.2","cameras":["X20","X20WF","X20CF","X50","X50S","X60"]}]},{"category":"box","categoryLabel":"Security Box","model":"MB100","note":"Compatible only with large-case models.","specs":"Dimensions: 6.77 × 4.57 × 2.48 inch (17.2 × 11.6 × 6.3 cm)\nLock Hole Diameter: 0.28 inch (0.7 cm)\nLock: Not Included\nMounting Options: Strap Mounting or Screw Installation\nMounting Strap: Not Included (Use the Strap Supplied with the Camera)\nMounting Screws: Not Included","groups":[{"type":"Non-Cellular","hw":"","cameras":["A3","A3S"]}]},{"category":"box","categoryLabel":"Security Box","model":"MB200","note":"","specs":"Dimensions: 6.93 × 4.49 × 2.52 inch (17.6 × 11.4 × 6.4 cm)\nLock Hole Diameter: 0.39 inch (1 cm)\nLock: Not Included\nMounting Options: Strap Mounting or Screw Installation\nMounting Strap: Not Included (Use the Strap Supplied with the Camera)\nMounting Screws: Not Included","groups":[{"type":"Non-Cellular","hw":"","cameras":["E5","E5S","A5","A5CF","A50","T5NG","T5CF","T5WF"]},{"type":"WiFi","hw":"","cameras":["E6","E6P","E6PMB","E6PCF","E7","E8","E8P","E8PMB","E8PCF","E8PWF","E9","E9P","E9PMB","E9PCF","E9PWF"]},{"type":"Cellular","hw":"","cameras":["X20","X20WF","X20CF","X50","X50S","X50P","X50MB","X50PMB","X50PLMB","X60P","X60PMB","X60PLMB"]}]},{"category":"box","categoryLabel":"Security Box","model":"MB300","note":"","specs":"Dimensions: 6.93 × 4.49 × 3.07 inch (17.6 × 11.4 × 7.8 cm)\nLock Hole Diameter: 0.39 inch (1 cm)\nLock: Not Included\nMounting Options: Strap Mounting or Screw Installation\nMounting Strap: Not Included (Use the Strap Supplied with the Camera)\nMounting Screws: Not Included","groups":[{"type":"Non-Cellular","hw":"","cameras":["E5 2.0","E5WF 2.0","A60","T5NG Pro","T5CF Pro","T5WF Pro","T6LRW"]},{"type":"WiFi","hw":"","cameras":["E6+","E6 2.0","E8+","E8 2.0","E9 2.0","A80"]},{"type":"Long Range WiFi","hw":"","cameras":["T6LRW"]},{"type":"Cellular","hw":"","cameras":["X70","X80","X80 Pro"]}]},{"category":"box","categoryLabel":"Security Box","model":"MB350","note":"","specs":"Dimensions: 6.93 × 4.49 × 3.26 inch (17.6 × 11.4 × 8.28 cm)\nLock Hole Diameter: 0.39 inch (1 cm)\nLock: Not Included\nMounting Options: Strap Mounting or Screw Installation\nMounting Strap: Not Included (Use the Strap Supplied with the Camera)\nMounting Screws: Not Included","groups":[{"type":"Non-Cellular","hw":"","cameras":[]},{"type":"WiFi","hw":"","cameras":["E6 2.0 Pro","E6 3.0 Pro","E8 2.0 Pro","E8 3.0 Pro","E9 2.0 Pro","E9PWF 2.0","E9 3.0 Pro","A80 Pro","R3 Pro","R3 2.0 Pro"]},{"type":"Long Range WiFi","hw":"","cameras":["R3 Pro","R3 2.0 Pro"]},{"type":"Cellular","hw":"","cameras":["X66 Pro","X66 Pro Max","X66 3.0 Pro","X66 3.0 Ultra","X70","X70 Pro","X70 3.0 Pro","X70 3.0 Ultra"]}]},{"category":"battery","categoryLabel":"Lithium Battery","model":"L800D","note":"Non-cellular camera without lithium battery; neither is supported.","specs":"Rated Capacity: 8000 mAh,29.6Wh\nNominal Voltage: 3.7 V\nLimited Charge Voltage: 5.0 V\nStandard Charging Current (Through the Type-C port): 500 mA\nStandard Charging Time: 16 hours\nStandard Discharging Current: 1600 mA\nMax. Discharging Current: 2000 mA\nCut-off Voltage: 2.75 V\nOperating Charge: 0 ~ 45 ℃\nTemperature Range Discharge: -20 ~ 60 ℃\nOperating humidity Range   ≤ 90% RH\nSize : 107.8 x 60 x 15.2 mm/4.24 × 2.36 × 0.6inches\nWeight: 168 g\nSpecific Energy:176 Wh/kg","groups":[{"type":"Non-Cellular","hw":"","cameras":[]},{"type":"WiFi","hw":"","cameras":["E6P","E6PMB","E6PCF","E6 2.0 Pro","E8P","E8PMB","E8PCF","E8PWF","E8 2.0 Pro","E9P","E9PMB","E9PCF","E9PWF","E9 2.0 Pro","A80 Pro"]},{"type":"Long Range WiFi","hw":"","cameras":["R3 Pro","R3 2.0 Pro"]},{"type":"Cellular","hw":"","cameras":["X50P","X50MB","X50PMB","X50PLMB","X60P","X60PMB","X60PLMB","X66 Pro","X66 Pro Max","X66 3.0 Pro","X70","X70 Pro","X70 3.0 Pro","X80 Pro"]}]},{"category":"battery","categoryLabel":"Lithium Battery","model":"L780D","note":"Non-cellular camera without lithium battery; neither is supported.","specs":"Rated Capacity: 7800 mAh,28.86Wh\nNominal Voltage: 3.7 V\nLimited Charge Voltage: 5.0 V\nStandard Charging Current (Through the Type-C port): 500 mA\nStandard Charging Time: 16 hours\nStandard Discharging Current: 1600 mA\nMax. Discharging Current: 2000 mA\nCut-off Voltage: 2.75 V\nOperating Charge: 0 ~ 45 ℃\nTemperature Range Discharge: -20 ~ 60 ℃\nOperating humidity Range   ≤ 90% RH\nSize : 4.27 x 2.36 x 0.91 inches\nWeight: 186 g\nSpecific Energy:155.0 Wh/kg","groups":[{"type":"Non-Cellular","hw":"","cameras":[]},{"type":"WiFi","hw":"","cameras":["E6 2.0 Pro","E8 2.0 Pro","E9 2.0 Pro","A80 Pro"]},{"type":"Long Range WiFi","hw":"","cameras":["R3 Pro","R3 2.0 Pro"]},{"type":"Cellular","hw":"","cameras":["X66 Pro","X66 Pro Max","X66 3.0 Pro","X70","X70 Pro","X70 3.0 Pro"]}]},{"category":"battery","categoryLabel":"Lithium Battery","model":"L1750E","note":"Non-cellular camera without lithium battery; neither is supported.","specs":"Rated Capacity:17500 mAh,64.75Wh\nNominal Voltage:3.7 V\nCharging Input Voltage (Type-C PD Fast Charge):5.0V / 9.0V / 12.0V\nStandard Charging Current (Through the Type-C port):\n5.0V / 2.9A\n9.0V / 1.6A\n12.0V / 1.2A\nMax Charging Power:14.5 W\nStandard Charging Time Approx.:7 hours\nStandard Discharging Current:1600 mA\nMax. Discharging Current:2000 mA\nCut-off Voltage:2.75 V\nOperating Temperature Range:\nCharge:0 ~ 45 ℃\nDischarge:-20 ~ 60 ℃\nOperating humidity Range:≤ 90% RH\nSize:4.24 x 2.82 x 0.85 inches\nweighet:285g\nSpecific Energy:227 Wh/kg","groups":[{"type":"Non-Cellular","hw":"","cameras":[]},{"type":"WiFi","hw":"","cameras":[]},{"type":"Cellular","hw":"","cameras":["X66 3.0 Ultra","X70 3.0 Ultra"]}]}],"camera_count":71},{"brand":"Meidase","accessories":[{"category":"solar","categoryLabel":"Solar Panel","model":"SP300","note":"单机无带锂电,均不支持","specs":"","groups":[{"type":"Non-Cellular","hw":"","cameras":[]},{"type":"WiFi","hw":"","cameras":["P100 Pro","P200 Pro","P300 Pro","P500 Pro"]},{"type":"Cellular","hw":"","cameras":["S950P","S950PMB","S950PLMB","S965 Pro","S970 Pro","SP980 Pro"]}]},{"category":"solar","categoryLabel":"Solar Panel","model":"SP350","note":"所有型号","specs":"","groups":[{"type":"Non-Cellular","hw":"","cameras":["P60","P60 Pro","P70","S5","S3","S3 Pro"]},{"type":"WiFi","hw":"H/W>=V8.2","cameras":["P80","P80 Pro","P90","P90 Pro","P100","P100 Pro","P200","P200 Pro","P300","P300 Pro","P500 Pro"]},{"type":"WiFi","hw":"H/W<V8.2","cameras":["P80","P80 Pro","P90","P90 Pro","P100","P200","P300"]},{"type":"Cellular","hw":"H/W>=V8.2","cameras":["S600","S900","S950","S950P","S950PMB","S950PLMB","S960","S965","S965 Pro","S970","S970 Pro","SP980 Pro"]},{"type":"Cellular","hw":"H/W<V8.2","cameras":["S950P","S950PMB","S950PLMB","S965 Pro","S970 Pro","SP980 Pro"]}]},{"category":"solar","categoryLabel":"Solar Panel","model":"SP1000","note":"单机无带锂电,均不支持","specs":"","groups":[{"type":"Non-Cellular","hw":"","cameras":[]},{"type":"WiFi","hw":"","cameras":["P100 Pro","P200 Pro","P300 Pro","P500 Pro"]},{"type":"Cellular","hw":"","cameras":["S950P","S950PMB","S950PLMB","S965 Pro","S970 Pro","SP980 Pro"]}]},{"category":"box","categoryLabel":"Security Box","model":"MB100","note":"仅适配大盒子机型","specs":"Dimensions: 6.77 × 4.57 × 2.48 inch (17.2 × 11.6 × 6.3 cm)\nLock Hole Diameter: 0.28 inch (0.7 cm)\nLock: Not Included\nMounting Options: Strap Mounting or Screw Installation\nMounting Strap: Not Included (Use the Strap Supplied with the Camera)\nMounting Screws: Not Included","groups":[{"type":"Non-Cellular","hw":"","cameras":["S3","S3 Pro"]},{"type":"WiFi","hw":"","cameras":[]},{"type":"Cellular","hw":"","cameras":[]}]},{"category":"box","categoryLabel":"Security Box","model":"MB200","note":"","specs":"Dimensions: 6.93 × 4.49 × 2.52 inch (17.6 × 11.4 × 6.4 cm)\nLock Hole Diameter: 0.39 inch (1 cm)\nLock: Not Included\nMounting Options: Strap Mounting or Screw Installation\nMounting Strap: Not Included (Use the Strap Supplied with the Camera)\nMounting Screws: Not Included","groups":[{"type":"Non-Cellular","hw":"","cameras":["P60","P60 Pro","P70","S5"]},{"type":"WiFi","hw":"","cameras":["P80","P80 Pro","P90","P90 Pro","P100","P100 Pro","P200","P200 Pro"]},{"type":"Cellular","hw":"","cameras":["S600","S900","S950","S950P","S950PMB","S950PLMB","S960"]}]},{"category":"box","categoryLabel":"Security Box","model":"MB300","note":"","specs":"Dimensions: 6.93 × 4.49 × 3.07 inch (17.6 × 11.4 × 7.8 cm)\nLock Hole Diameter: 0.39 inch (1 cm)\nLock: Not Included\nMounting Options: Strap Mounting or Screw Installation\nMounting Strap: Not Included (Use the Strap Supplied with the Camera)\nMounting Screws: Not Included","groups":[{"type":"Non-Cellular","hw":"","cameras":[]},{"type":"WiFi","hw":"","cameras":["P300"]},{"type":"Cellular","hw":"","cameras":["S965","S970"]}]},{"category":"box","categoryLabel":"Security Box","model":"MB350","note":"","specs":"Dimensions: 6.93 × 4.49 × 3.26 inch (17.6 × 11.4 × 8.28 cm)\nLock Hole Diameter: 0.39 inch (1 cm)\nLock: Not Included\nMounting Options: Strap Mounting or Screw Installation\nMounting Strap: Not Included (Use the Strap Supplied with the Camera)\nMounting Screws: Not Included","groups":[{"type":"Non-Cellular","hw":"","cameras":[]},{"type":"WiFi","hw":"","cameras":["P300 Pro","P500 Pro"]},{"type":"Cellular","hw":"","cameras":["S965 Pro","S970 Pro","S980 Pro"]}]},{"category":"battery","categoryLabel":"Lithium Battery","model":"L800D","note":"单机无带锂电,均不支持","specs":"","groups":[{"type":"Non-Cellular","hw":"","cameras":[]},{"type":"WiFi","hw":"","cameras":["P300 Pro","P500 Pro"]},{"type":"Cellular","hw":"","cameras":["S950P","S950PMB","S950PLMB","S965 Pro","S970 Pro"]}]},{"category":"battery","categoryLabel":"Lithium Battery","model":"L780D","note":"单机无带锂电,均不支持","specs":"","groups":[{"type":"Non-Cellular","hw":"","cameras":[]},{"type":"WiFi","hw":"","cameras":["P300 Pro","P500 Pro"]},{"type":"Cellular","hw":"","cameras":["S965 Pro","S970 Pro"]}]},{"category":"battery","categoryLabel":"Lithium Battery","model":"L1750E","note":"单机无带锂电,均不支持","specs":"","groups":[{"type":"Non-Cellular","hw":"","cameras":[]},{"type":"WiFi","hw":"","cameras":[]},{"type":"Cellular","hw":"","cameras":["S980 Pro"]}]}],"camera_count":30}]}</script>
<script>
/* ============================================================
   GardePro — Accessory Compatibility Finder
   纯原生 JS,无依赖。数据来自 #cp-data(JSON)
   ============================================================ */
(function () {
  "use strict";

  var CFG = window.CP_CONFIG || {};
  var DEFAULT_BRAND = CFG.brand || "GardePro";

  var CATS = [
    { key: "solar", single: "Solar Panel", plural: "Solar Panels",
      icon: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M4 5h16l2 11H2L4 5Z"/><path d="M9 5 8 16M15 5l1 11M3 10.5h18"/></svg>' },
    { key: "box", single: "Security Box", plural: "Security Boxes",
      icon: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="16" rx="2.5"/><path d="M3 9h18M9 9v11"/></svg>' },
    { key: "battery", single: "Lithium Battery", plural: "Lithium Batteries",
      icon: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="7" width="16" height="10" rx="2.5"/><path d="M21 10.5v3M6 7v10"/></svg>' }
  ];

  var TYPE_ORDER = { "Non-Cellular": 0, "WiFi": 1, "Long Range WiFi": 2, "Cellular": 3 };

  // 面向客户的类型名("WiFi" → "WiFi Camera")
  function typeDisplay(t) { return t ? t + " Camera" : t; }

  // 太阳能板:特殊徽章(显示在相机类型标签下方)与排序(每行两款:无锂电池一行、带锂电池一行)
  var SOLAR_TAGS = {
    "SP1000": ["Recommended · 10W"],
    "SP300": ["Compact · 3.5W"],
    "SP350": ["Compact · 3.5W", "Built-in Lithium Battery · 5200 mAh"],
    "SP1100": ["Recommended · 10W", "Built-in Lithium Battery · 10400 mAh"]
  };
  var SOLAR_ORDER = { "SP1000": 0, "SP300": 1, "SP1100": 2, "SP350": 3 };

  // 内部备注不展示给客户
  function customerNote(note) {
    if (!note) return "";
    var n = String(note).trim();
    if (/neither is supported/i.test(n)) return "";
    if (/^(all models|所有型号)/i.test(n)) return "";
    if (/must meet the hardware version requirements/i.test(n)) return "";
    return n;
  }

  // 硬件版本条件的通俗解释
  function hwTip(hw) {
    if (!hw) return "";
    if (/>=/.test(hw)) {
      return "Fits cameras with hardware version V8.2 or newer. You can check yours in the camera menu: Settings → Version Info.";
    }
    if (/</.test(hw)) {
      return "For cameras with hardware version older than V8.2. If yours is V8.2 or newer, please use the other compatible option listed.";
    }
    return "";
  }

  // HW 标签(带 "?" 提示)
  function hwTagHtml(hw) {
    var tip = hwTip(hw);
    return '<span class="cp-tag is-hw">' + esc(hwLabel(hw)) +
      (tip ? '<button class="cp-hw" type="button" tabindex="0" aria-label="Hardware version info" data-tip="' + esc(tip) + '">?</button>' : "") +
      "</span>";
  }

  var $ = function (s, r) { return (r || document).querySelector(s); };

  function readData() {
    var el = document.getElementById("cp-data");
    if (!el) return null;
    try { return JSON.parse(el.textContent); } catch (e) { return null; }
  }

  var DATA = readData();
  if (!DATA || !DATA.brands || !DATA.brands.length) return;

  var brandKey = DEFAULT_BRAND;
  try {
    var qp = new URLSearchParams(location.search).get("brand");
    if (qp && DATA.brands.some(function (b) { return b.brand === qp; })) brandKey = qp;
  } catch (e) {}

  var BRAND = DATA.brands.filter(function (b) { return b.brand === brandKey; })[0] || DATA.brands[0];
  var ACCS = BRAND.accessories.slice();

  /* ---------- 索引 ---------- */
  function key(s) { return String(s).toLowerCase().replace(/[^a-z0-9]/g, ""); }

  var INDEX = Object.create(null);   // key -> { name, entries: [{acc, group}], types: {} }
  ACCS.forEach(function (acc) {
    acc.groups.forEach(function (g) {
      g.cameras.forEach(function (cam) {
        var k = key(cam);
        if (!INDEX[k]) INDEX[k] = { name: cam, entries: [], types: {} };
        // 同名型号保持首次出现的写法
        INDEX[k].entries.push({ acc: acc, group: g });
        INDEX[k].types[g.type] = true;
      });
    });
  });

  function typeHint(rec) {
    return Object.keys(rec.types)
      .sort(function (a, b) { return (TYPE_ORDER[a] || 9) - (TYPE_ORDER[b] || 9); })
      .map(typeDisplay)
      .join(" · ");
  }

  function naturalCompare(a, b) {
    var re = /(\d+)|(\D+)/g;
    var pa = String(a).match(re) || [], pb = String(b).match(re) || [];
    for (var i = 0; i < Math.min(pa.length, pb.length); i++) {
      var x = pa[i], y = pb[i];
      var nx = parseInt(x, 10), ny = parseInt(y, 10);
      if (!isNaN(nx) && !isNaN(ny)) { if (nx !== ny) return nx - ny; }
      else if (x !== y) return x < y ? -1 : 1;
    }
    return pa.length - pb.length;
  }

  function esc(s) {
    return String(s).replace(/[&<>"']/g, function (c) {
      return ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c];
    });
  }

  function hwLabel(hw) {
    if (!hw) return "";
    return hw.replace(/H\/W\s*/g, "HW ").replace(/>=/g, "≥").replace(/<=/g, "≤").replace(/=/g, "= ");
  }

  /* ---------- 规格解析 ----------
     原表参数列以换行为主、斜杠为辅分隔;斜杠也常出现在值内(如 12V/1A)。
     策略:先按行切,行内只在「斜杠后一段以 Key: 开头」时才切;
     再把无冒号的短字母段视为下一行的键前缀(如 Solar Panel MAX + Output Power: 12W)。 */
  function colonIdx(s) {
    var a = s.indexOf(":"), b = s.indexOf(":");
    if (a === -1) return b;
    if (b === -1) return a;
    return Math.min(a, b);
  }

  function splitSlash(line) {
    var parts = line.split("/");
    if (parts.length === 1) return [line];
    var out = [parts[0]];
    for (var i = 1; i < parts.length; i++) {
      var prev = out[out.length - 1];
      var seg = parts[i];
      var ci = colonIdx(seg);
      var prevEndsColon = /[::]\s*$/.test(prev);
      if (prevEndsColon || (ci > -1 && ci <= 48)) out.push(seg);
      else out[out.length - 1] = prev + "/" + seg;
    }
    return out;
  }

  function parseSpecs(text) {
    if (!text) return [];
    var t = String(text).replace(/\t/g, " ");
    var tokens = [];
    t.split(/\r?\n/).forEach(function (line) {
      if (line.trim()) tokens = tokens.concat(splitSlash(line));
    });

    var pairs = [], pending = [], cur = null;
    tokens.forEach(function (rawTok, i) {
      var tok = rawTok.trim();
      if (!tok) return;
      var ci = colonIdx(tok);
      if (ci > -1 && ci <= 48) {
        var k = tok.slice(0, ci).replace(/\s+/g, " ").trim();
        var v = tok.slice(ci + 1).trim();
        if (pending.length) { k = pending.join(" ") + " " + k; pending = []; }
        cur = [k, v];
        pairs.push(cur);
      } else {
        var nxt = i + 1 < tokens.length ? tokens[i + 1].trim() : "";
        var nci = nxt ? colonIdx(nxt) : -1;
        if (cur && !cur[1]) cur[1] = tok;                                   // 前一对值还空着 → 续值
        else if (!cur || (nci > -1 && nci <= 48 && tok.length <= 22 && !/\d/.test(tok)))
          pending.push(tok);                                                 // 短字母段 → 下一对的键前缀
        else cur[1] = cur[1] ? cur[1] + " / " + tok : tok;                   // 普通续值
      }
    });
    return pairs.filter(function (kv) { return kv[0] && kv[1]; });
  }

  /* ---------- 搜索 ---------- */
  var input = $("#cp-input");
  var sugg = $("#cp-sugg");
  var activeIdx = -1;
  var currentList = [];

  function searchModels(q) {
    var k = key(q);
    if (!k) return [];
    var all = Object.keys(INDEX);
    var exact = [], prefix = [], contains = [];
    all.forEach(function (ik) {
      if (ik === k) exact.push(ik);
      else if (ik.indexOf(k) === 0) prefix.push(ik);
      else if (ik.indexOf(k) > -1) contains.push(ik);
    });
    // 按「词首匹配」优先,其次按包含位置
    contains.sort(function (a, b) { return a.indexOf(k) - b.indexOf(k) || naturalCompare(INDEX[a].name, INDEX[b].name); });
    prefix.sort(function (a, b) { return naturalCompare(INDEX[a].name, INDEX[b].name); });
    return exact.concat(prefix, contains);
  }

  function renderSugg(q) {
    var keys = searchModels(q).slice(0, 8);
    currentList = keys;
    activeIdx = -1;
    if (!keys.length) {
      sugg.innerHTML = '<li><button type="button" disabled style="color:#98a2b3;cursor:default">No model matches “' + esc(q) + '”</button></li>';
      sugg.classList.add("is-open");
      input.setAttribute("aria-expanded", "true");
      return;
    }
    var k = key(q);
    sugg.innerHTML = keys.map(function (ik) {
      var rec = INDEX[ik];
      var name = esc(rec.name);
      if (k) {
        var pos = rec.name.toLowerCase().indexOf(q.toLowerCase().trim());
        if (pos > -1) {
          name = esc(rec.name.slice(0, pos)) + "<mark>" + esc(rec.name.slice(pos, pos + q.trim().length)) + "</mark>" + esc(rec.name.slice(pos + q.trim().length));
        }
      }
      return '<li role="option"><button type="button" data-cam="' + esc(rec.name) + '">' +
        "<span>" + name + '</span><span class="cp-sugg-hint">' + esc(typeHint(rec)) + "</span></button></li>";
    }).join("");
    sugg.classList.add("is-open");
    input.setAttribute("aria-expanded", "true");
  }

  function closeSugg() {
    sugg.classList.remove("is-open");
    input.setAttribute("aria-expanded", "false");
    activeIdx = -1;
  }

  function highlight(i) {
    var btns = sugg.querySelectorAll("button[data-cam]");
    btns.forEach(function (b, n) { b.classList.toggle("is-active", n === i); });
    if (btns[i]) btns[i].scrollIntoView({ block: "nearest" });
  }

  /* ---------- 结果渲染 ---------- */
  var resultEl = $("#cp-result");

  function matchesFor(camName) {
    var k = key(camName);
    var rec = INDEX[k];
    if (!rec) return null;
    var byAcc = [];
    var seen = Object.create(null);
    rec.entries.forEach(function (e) {
      var id = e.acc.category + "|" + e.acc.model;
      if (!seen[id]) { seen[id] = { acc: e.acc, conds: [] }; byAcc.push(seen[id]); }
      seen[id].conds.push({ type: e.group.type, hw: e.group.hw });
    });
    return { camera: rec, items: byAcc };
  }

  // 类型标签(不含硬件版本条件)
  function typeTagsHtml(conds) {
    var seen = Object.create(null), out = [];
    conds.forEach(function (c) { if (!seen[c.type]) { seen[c.type] = 1; out.push(c.type); } });
    return out.map(function (t) {
      return '<span class="cp-tag">' + esc(typeDisplay(t)) + "</span>";
    }).join("");
  }

  // 硬件版本条件标签(带 "?")
  function hwOnlyTags(conds) {
    var seen = Object.create(null), out = [];
    conds.forEach(function (c) { if (c.hw && !seen[c.hw]) { seen[c.hw] = 1; out.push(c.hw); } });
    return out.map(hwTagHtml).join("");
  }

  function cardHtml(m, tagsCfg) {
    var acc = m.acc;
    var specs = parseSpecs(acc.specs);
    var specHtml = specs.length
      ? '<dl class="cp-specs">' + specs.map(function (kv) {
          return "<div><dt>" + esc(kv[0]) + "</dt><dd>" + esc(kv[1]) + "</dd></div>";
        }).join("") + "</dl>"
      : "";
    var badges = (tagsCfg && tagsCfg[acc.model]) || [];
    var badgesHtml = badges.map(function (b) {
      var cls = /Recommended/i.test(b) ? "cp-badge is-rec" : "cp-chip";
      return '<span class="' + cls + '">' + esc(b) + "</span>";
    }).join("");
    var hwHtml = hwOnlyTags(m.conds);
    var isRec = badges.some(function (b) { return /Recommended/i.test(b); });
    return '<article class="cp-card' + (isRec ? " is-rec" : "") + '">' +
      '<div class="cp-card-top"><div class="cp-model">' + esc(acc.model) + '</div>' +
      '<span class="cp-badge">Compatible</span></div>' +
      '<div class="cp-conds">' + typeTagsHtml(m.conds) + "</div>" +
      (badgesHtml ? '<div class="cp-conds">' + badgesHtml + "</div>" : "") +
      (hwHtml ? '<div class="cp-conds">' + hwHtml + "</div>" : "") +
      (customerNote(acc.note) ? '<p class="cp-note">' + esc(customerNote(acc.note)) + "</p>" : "") +
      (specHtml
        ? '<div class="cp-card-foot"><button class="cp-more" type="button" aria-expanded="false">Specifications' +
          '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg></button>' +
          specHtml + "</div>"
        : "") +
      "</article>";
  }

  function showResult(camName, opts) {
    var m = matchesFor(camName);
    if (!m) { showNoMatch(camName); return; }

    var rec = m.camera;
    var html = '<div class="cp-cam-head">' +
      '<span class="cp-cam-label">Compatible accessories for</span>' +
      '<div class="cp-cam-name">' + esc(rec.name) + "</div>" +
      '<span class="cp-tag">' + esc(typeHint(rec)) + "</span>" +
      '<span class="cp-spacer"></span>' +
      '<button class="cp-ghost-btn" type="button" data-act="reset">Search Another Model</button>' +
      "</div>";

    CATS.forEach(function (cat) {
      var tagsCfg = cat.key === "solar" ? SOLAR_TAGS : null;
      var orderMap = cat.key === "solar" ? SOLAR_ORDER : null;
      var items = m.items.filter(function (i) { return i.acc.category === cat.key; })
        .sort(function (a, b) {
          if (orderMap) {
            var oa = orderMap.hasOwnProperty(a.acc.model) ? orderMap[a.acc.model] : 99;
            var ob = orderMap.hasOwnProperty(b.acc.model) ? orderMap[b.acc.model] : 99;
            if (oa !== ob) return oa - ob;
          }
          return naturalCompare(a.acc.model, b.acc.model);
        });
      html += '<section class="cp-cat">' +
        '<div class="cp-cat-title"><h2>' + cat.icon + esc(cat.plural) + "</h2>" +
        '<span class="cp-count">' + (items.length ? items.length + (items.length > 1 ? " compatible models" : " compatible model") : "not listed") + "</span></div>";
      html += items.length
        ? '<div class="cp-cards">' + items.map(function (i) { return cardHtml(i, tagsCfg); }).join("") + "</div>"
        : '<p class="cp-empty">No ' + esc(cat.single.toLowerCase()) + " is listed as compatible with the " + esc(rec.name) +
          ". Please contact support if you need help choosing.</p>";
      html += "</section>";
    });

    resultEl.innerHTML = html;
    resultEl.hidden = false;
    bindResultEvents();
    if (!opts || !opts.silent) {
      resultEl.scrollIntoView({ behavior: "smooth", block: "start" });
    }
    syncUrl(rec.name);
  }

  function showNoMatch(q) {
    var guess = searchModels(q).slice(0, 6);
    var html = '<div class="cp-cam-head"><div class="cp-cam-name">No match for “' + esc(q) + '”</div>' +
      '<span class="cp-cam-sub">Check the model name, or pick one of the closest matches below.</span></div>';
    if (guess.length) {
      html += '<div class="cp-cat"><div class="cp-cat-title"><h2>Did You Mean</h2></div><div class="cp-pills">' +
        guess.map(function (k) {
          return '<button class="cp-pill" type="button" data-cam="' + esc(INDEX[k].name) + '">' + esc(INDEX[k].name) + "</button>";
        }).join("") + "</div></div>";
    }
    resultEl.innerHTML = html;
    resultEl.hidden = false;
    bindResultEvents();
    resultEl.scrollIntoView({ behavior: "smooth", block: "start" });
  }

  function bindResultEvents() {
    bindHwPop(resultEl);
    resultEl.querySelectorAll(".cp-more").forEach(function (btn) {
      btn.addEventListener("click", function () {
        var open = btn.getAttribute("aria-expanded") === "true";
        btn.setAttribute("aria-expanded", String(!open));
        var dl = btn.parentNode.querySelector(".cp-specs");
        if (dl) dl.classList.toggle("is-open", !open);
      });
    });
    var reset = resultEl.querySelector('[data-act="reset"]');
    if (reset) reset.addEventListener("click", function () {
      input.value = "";
      resultEl.hidden = true;
      resultEl.innerHTML = "";
      syncUrl("");
      input.focus();
      window.scrollTo({ top: 0, behavior: "smooth" });
    });
    resultEl.querySelectorAll("[data-cam]").forEach(function (b) {
      b.addEventListener("click", function () {
        input.value = b.getAttribute("data-cam");
        showResult(b.getAttribute("data-cam"));
      });
    });
  }

  function syncUrl(model) {
    try {
      var u = new URL(location.href);
      if (model) u.searchParams.set("model", model); else u.searchParams.delete("model");
      history.replaceState(null, "", u.toString());
    } catch (e) {}
  }

  /* ---------- 浏览 ---------- */
  var tabsEl = $("#cp-tabs");
  var gridEl = $("#cp-grid");
  var activeCat = "solar";

  function renderTabs() {
    tabsEl.innerHTML = CATS.map(function (c) {
      var n = ACCS.filter(function (a) { return a.category === c.key; }).length;
      if (!n) return "";
      return '<button type="button" role="tab" data-cat="' + c.key + '"' +
        (c.key === activeCat ? ' class="is-active" aria-selected="true"' : ' aria-selected="false"') + ">" +
        esc(c.plural) + " (" + n + ")</button>";
    }).join("");
  }

  function renderGrid() {
    var list = ACCS.filter(function (a) { return a.category === activeCat; })
      .sort(function (a, b) { return naturalCompare(a.model, b.model); });
    gridEl.innerHTML = list.map(function (acc) {
      var cams = Object.create(null), n = 0;
      acc.groups.forEach(function (g) { g.cameras.forEach(function (c) { if (!cams[c]) { cams[c] = 1; n++; } }); });
      return '<button class="cp-tile" type="button" data-acc="' + esc(acc.category + "|" + acc.model) + '">' +
        '<span class="cp-tile-model">' + esc(acc.model) + "</span>" +
        '<span class="cp-tile-meta">' + n + " compatible camera" + (n === 1 ? "" : "s") + "</span>" +
        '<span class="cp-tile-view">View details' +
        '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span></button>';
    }).join("");
  }

  /* ---------- 弹层 ---------- */
  var modal = $("#cp-modal");
  var modalBody = $("#cp-modal-body");
  var lastFocus = null;

  function openAcc(categoryKey, model) {
    var acc = ACCS.filter(function (a) { return a.category === categoryKey && a.model === model; })[0];
    if (!acc) return;
    var cat = CATS.filter(function (c) { return c.key === acc.category; })[0];
    var specs = parseSpecs(acc.specs);

    var groupsHtml = acc.groups.map(function (g) {
      var cams = g.cameras.slice();
      if (!cams.length) return "";
      return '<div class="cp-typegroup">' +
        '<div class="cp-typegroup-head">' + esc(typeDisplay(g.type || "All models")) +
        (g.hw ? hwTagHtml(g.hw) : "") +
        '<span class="cp-count" style="font-weight:400;color:#6b7683">' + cams.length + "</span></div>" +
        '<div class="cp-pills">' + cams.map(function (c) {
          return '<button class="cp-pill" type="button" data-cam="' + esc(c) + '">' + esc(c) + "</button>";
        }).join("") + "</div></div>";
    }).join("");

    modalBody.innerHTML =
      '<div class="cp-modal-head">' +
      '<div class="cp-modal-cat">' + esc(cat.single) + "</div>" +
      '<h3 id="cp-modal-title">' + esc(acc.model) + "</h3>" +
      "</div>" +
      (specs.length ? '<div class="cp-modal-block"><h4>Specifications</h4><table class="cp-spec-table"><tbody>' +
        specs.map(function (kv) { return "<tr><td>" + esc(kv[0]) + "</td><td>" + esc(kv[1]) + "</td></tr>"; }).join("") +
        "</tbody></table></div>" : "") +
      '<div class="cp-modal-block"><h4>Compatible Camera Models</h4>' + (groupsHtml || '<p class="cp-empty">No compatible models listed.</p>') + "</div>";

    bindHwPop(modalBody);
    lastFocus = document.activeElement;
    modal.classList.add("is-open");
    document.body.style.overflow = "hidden";
    $("#cp-modal-close").focus();

    modalBody.querySelectorAll("[data-cam]").forEach(function (b) {
      b.addEventListener("click", function () {
        var name = b.getAttribute("data-cam");
        closeModal();
        input.value = name;
        showResult(name);
      });
    });
  }

  function closeModal() {
    modal.classList.remove("is-open");
    document.body.style.overflow = "";
    if (lastFocus && lastFocus.focus) lastFocus.focus();
  }

  /* ---------- 事件绑定 ---------- */
  input.addEventListener("input", function () {
    var q = input.value.trim();
    if (!q) { closeSugg(); return; }
    renderSugg(q);
  });
  input.addEventListener("keydown", function (e) {
    if (e.key === "ArrowDown" || e.key === "ArrowUp") {
      if (!sugg.classList.contains("is-open")) { renderSugg(input.value.trim()); return; }
      e.preventDefault();
      var n = currentList.length;
      if (!n) return;
      activeIdx = e.key === "ArrowDown" ? (activeIdx + 1) % n : (activeIdx - 1 + n) % n;
      highlight(activeIdx);
    } else if (e.key === "Enter") {
      e.preventDefault();
      if (sugg.classList.contains("is-open") && activeIdx > -1 && currentList[activeIdx]) {
        var name = INDEX[currentList[activeIdx]].name;
        input.value = name;
        closeSugg();
        showResult(name);
      } else {
        doSearch();
      }
    } else if (e.key === "Escape") {
      closeSugg();
    }
  });
  sugg.addEventListener("mousedown", function (e) { e.preventDefault(); });
  sugg.addEventListener("click", function (e) {
    var b = e.target.closest("button[data-cam]");
    if (!b) return;
    var name = b.getAttribute("data-cam");
    input.value = name;
    closeSugg();
    showResult(name);
  });

  function doSearch() {
    var q = input.value.trim();
    if (!q) { input.focus(); return; }
    closeSugg();
    var keys = searchModels(q);
    if (!keys.length) { showNoMatch(q); return; }
    var exact = keys.filter(function (k) { return k === key(q); })[0];
    showResult(INDEX[exact || keys[0]].name);
  }

  $("#cp-search-btn").addEventListener("click", doSearch);

  tabsEl.addEventListener("click", function (e) {
    var b = e.target.closest("button[data-cat]");
    if (!b) return;
    activeCat = b.getAttribute("data-cat");
    renderTabs();
    renderGrid();
  });

  gridEl.addEventListener("click", function (e) {
    var b = e.target.closest("[data-acc]");
    if (!b) return;
    var parts = b.getAttribute("data-acc").split("|");
    openAcc(parts[0], parts[1]);
  });

  $("#cp-modal-close").addEventListener("click", closeModal);
  modal.addEventListener("click", function (e) { if (e.target === modal) closeModal(); });
  document.addEventListener("keydown", function (e) {
    if (e.key === "Escape" && modal.classList.contains("is-open")) closeModal();
  });

  /* ---------- HW "?" 弹层(全局唯一,fixed 定位,避免被卡片/弹窗裁剪) ---------- */
  var hwPop = null, hwPopBtn = null;

  function hideHwPop() {
    if (hwPop) {
      var el = hwPop;
      el.classList.remove("is-show");
      setTimeout(function () { if (el.parentNode) el.parentNode.removeChild(el); }, 160);
      hwPop = null; hwPopBtn = null;
    }
  }

  function showHwPop(btn) {
    if (hwPopBtn === btn) return;
    hideHwPop();
    hwPopBtn = btn;
    hwPop = document.createElement("div");
    hwPop.className = "cp-hw-pop";
    hwPop.textContent = btn.getAttribute("data-tip") || "";
    document.body.appendChild(hwPop);
    var r = btn.getBoundingClientRect();
    var vw = document.documentElement.clientWidth;
    requestAnimationFrame(function () {
      if (!hwPop) return;
      var pw = hwPop.offsetWidth, ph = hwPop.offsetHeight;
      var left = Math.min(Math.max(8, r.left + r.width / 2 - pw / 2), vw - pw - 8);
      var top = r.bottom + 8;
      if (top + ph > window.innerHeight - 8) top = r.top - ph - 8;
      hwPop.style.left = left + "px";
      hwPop.style.top = Math.max(8, top) + "px";
      hwPop.classList.add("is-show");
    });
  }

  function bindHwPop(scope) {
    (scope || document).querySelectorAll(".cp-hw").forEach(function (btn) {
      if (btn.__hwBound) return;
      btn.__hwBound = true;
      btn.addEventListener("mouseenter", function () { showHwPop(btn); });
      btn.addEventListener("mouseleave", hideHwPop);
      btn.addEventListener("focus", function () { showHwPop(btn); });
      btn.addEventListener("blur", hideHwPop);
      btn.addEventListener("click", function (e) {
        e.stopPropagation();
        if (hwPopBtn === btn) hideHwPop(); else showHwPop(btn);
      });
    });
  }

  document.addEventListener("scroll", hideHwPop, true);
  window.addEventListener("resize", hideHwPop);
  document.addEventListener("click", hideHwPop);

  /* ---------- 初始化 ---------- */
  function init() {
    renderTabs();
    renderGrid();

    // 常用机型快捷入口
    var popular = ["X66 3.0 Ultra", "X66 Pro", "E9 3.0 Pro", "E8 3.0 Pro", "E8 2.0 Pro", "A3S"];
    var quick = $("#cp-quick");
    popular.filter(function (p) { return INDEX[key(p)]; }).forEach(function (p) {
      var b = document.createElement("button");
      b.type = "button";
      b.textContent = p;
      b.addEventListener("click", function () {
        input.value = p;
        showResult(p);
      });
      quick.appendChild(b);
    });

    var totalCams = Object.keys(INDEX).length;
    $("#cp-foot-stats").textContent = totalCams + " camera models · " + ACCS.length + " accessories";

    // 深链 ?model= 或 ?acc=
    try {
      var sp = new URLSearchParams(location.search);
      var m = sp.get("model");
      if (m && INDEX[key(m)]) {
        input.value = INDEX[key(m)].name;
        showResult(INDEX[key(m)].name, { silent: true });
      }
      var accQ = sp.get("acc");
      if (accQ) {
        var hit = ACCS.filter(function (a) { return key(a.model) === key(accQ); })[0];
        if (hit) openAcc(hit.category, hit.model);
      }
    } catch (e) {}
  }

  if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", init);
  else init();
})();

</script>