/* 搜索建议面板
   与站内卡片同一套语言：白底、1px 冷灰描边、16px 圆角、大范围低透明投影。
   位置由 JS 用 fixed 跟随搜索框，宽度与搜索框严格一致，
   所以它读起来是"搜索框的下半部分"，而不是另一个浮层。 */
.search-suggest{
  position:fixed;
  z-index:40;
  box-sizing:border-box;
  padding:0;
  border:1px solid #e8ecf4;
  border-radius:16px;
  background:#fff;
  box-shadow:0 1px 2px #0b26540a,0 28px 60px -28px #0b26544d;
  overflow-y:auto;
  overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch;
  animation:suggest-in .16s cubic-bezier(.22,.61,.36,1);
}
@keyframes suggest-in{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:translateY(0)}}
.search-suggest[hidden]{display:none}

/* 分组标题：小字、字距拉开，像搜索引擎的分组标签。
   2026-09-22：「最近搜索」这组右侧要挂「清空」，所以标题行改成两端对齐的 flex
   （只有标题、没有按钮的组视觉不变）。 */
.search-suggest .suggest-head{
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:10px;
  margin:0;
  padding:12px 16px 8px;
  font-size:10px;
  font-weight:700;
  letter-spacing:1.4px;
  color:#98a0b2;
}
.search-suggest .suggest-clear{
  border:0;
  padding:2px 6px;
  border-radius:6px;
  background:none;
  color:#98a0b2;
  font:inherit;
  font-size:10.5px;
  letter-spacing:.4px;
  cursor:pointer;
}
.search-suggest .suggest-clear:hover{background:#f2f5ff;color:#1a3ba8}

/* 历史行：时钟图标代替缩略图（无图无价，3 列布局） */
.search-suggest .suggest-row.is-history{grid-template-columns:44px minmax(0,1fr) 18px}
.search-suggest .suggest-row.is-history .suggest-name{font-weight:600}
.search-suggest .suggest-art.is-icon{
  display:grid;
  place-items:center;
  border-color:#e6ecfa;
  background:#f4f7ff;
  color:#8ea2cc;
}
.search-suggest .suggest-art.is-icon svg{width:20px;height:20px}

.search-suggest .suggest-list{margin:0;padding:4px 0;list-style:none}
.search-suggest .suggest-row{
  display:grid;
  grid-template-columns:44px minmax(0,1fr) auto 18px;
  align-items:center;
  gap:12px;
  width:100%;
  padding:9px 16px;
  border:0;
  background:none;
  text-align:left;
  cursor:pointer;
  transition:background .14s ease;
}
.search-suggest .suggest-row:hover,
.search-suggest .suggest-row.is-active{background:#f5f8ff}
.search-suggest .suggest-row:active{background:#eef3ff}
.search-suggest .suggest-art{
  display:block;
  width:44px;
  height:44px;
  border:1px solid #eef1f6;
  border-radius:10px;
  background:#fff;
  overflow:hidden;
  flex:none;
}
.search-suggest .suggest-art img{display:block;width:100%;height:100%;padding:3px;object-fit:contain;mix-blend-mode:multiply}
.search-suggest .suggest-copy{display:block;min-width:0}
.search-suggest .suggest-name{
  display:block;
  font-size:13.5px;
  font-weight:700;
  line-height:18px;
  letter-spacing:-.2px;
  color:#101c3d;
  overflow:hidden;
  text-overflow:ellipsis;
  white-space:nowrap;
}
.search-suggest .suggest-spec{
  display:block;
  margin-top:3px;
  font-size:11px;
  line-height:15px;
  color:#7b8499;
  overflow:hidden;
  text-overflow:ellipsis;
  white-space:nowrap;
}
/* 命中的词：暖色底 + 加粗。用 mark 而不是自定义标签，读屏也能听懂"这是命中片段" */
.search-suggest mark{
  padding:0 1px;
  border-radius:3px;
  background:#ffe7cd;
  color:#8a4a12;
  font:inherit;
  font-weight:750;
}
.search-suggest .suggest-price{
  font-size:12px;
  font-weight:700;
  color:#5b6b8c;
  white-space:nowrap;
  font-variant-numeric:tabular-nums;
}
.search-suggest .suggest-go{
  width:18px;
  height:18px;
  color:#c3cad8;
  transition:transform .18s ease,color .18s ease;
}
.search-suggest .suggest-row:hover .suggest-go,
.search-suggest .suggest-row.is-active .suggest-go{color:#1a3ba8;transform:translateX(2px)}

/* 底部「查看全部商品 N」：锚在列表末尾，左侧竖线呼应搜索框的图标轴 */
.search-suggest .suggest-all{
  display:flex;
  align-items:center;
  gap:8px;
  width:100%;
  padding:12px 16px;
  border:0;
  border-top:1px solid #f0f3f9;
  background:#fbfcff;
  border-radius:0 0 15px 15px;
  color:#1a3ba8;
  font-size:12.5px;
  font-weight:700;
  text-align:left;
  cursor:pointer;
}
.search-suggest .suggest-all:hover{background:#f4f7ff}
.search-suggest .suggest-all b{
  display:inline-grid;
  place-items:center;
  min-width:20px;
  height:20px;
  padding:0 6px;
  border-radius:10px;
  background:#e8eeff;
  color:#1a3ba8;
  font-size:11px;
  font-variant-numeric:tabular-nums;
}

/* 无结果：复用站内空态的语气（换个方向，继续找找。） */
.search-suggest .suggest-empty{padding:18px 16px}
.search-suggest .suggest-empty strong{display:block;font-size:13.5px;color:#101c3d;letter-spacing:-.2px}
.search-suggest .suggest-empty small{display:block;margin-top:6px;font-size:11.5px;line-height:1.6;color:#8b93a6}

/* 搜索框本身：聚焦时给搜索框一个不刺眼的强化，
   与面板连成一体（不再是被 3px 橙框套住的输入框） */
.search:focus-within{box-shadow:inset 0 0 0 1px #c9d6f5,0 6px 18px -12px #0b265447}
#search input:focus-visible{outline:none}

@media(max-width:720px){
  .search-suggest{border-radius:14px}
  .search-suggest .suggest-row{grid-template-columns:40px minmax(0,1fr) 16px;gap:10px;padding:9px 14px}
  .search-suggest .suggest-art{width:40px;height:40px;border-radius:9px}
  .search-suggest .suggest-price{display:none}
  .search-suggest .suggest-head{padding:11px 14px 7px}
  .search-suggest .suggest-all{padding:12px 14px;border-radius:0 0 13px 13px}
}

/* 放宽检索提示：有结果但无精确命中时，在商品网格上方给一句说明。
   没有它，用户会把「放宽召回」的结果当成「店里就这些」。 */
.catalog-relaxed-note{grid-column:1/-1;margin:0 0 14px;padding:11px 15px;border-radius:12px;
  background:#f4f1e9;border:1px solid #14234914;color:var(--muted);
  font-size:13px;line-height:1.7}
.catalog-relaxed-note strong{display:inline-block;margin-right:8px;padding:1px 7px;
  border-radius:5px;background:var(--blue);color:#fff;font-size:11px;font-weight:600;
  vertical-align:1px;letter-spacing:.4px}

/* 逐商品警示：同类商品不能因规格相近就被误认为同款。 */
.goods-spec-warning{display:inline-block;margin:0 6px 3px 0;padding:1px 6px;
  border-radius:6px;background:#fff1df;color:#8b4a08;font-size:11px;font-weight:700;
  line-height:1.5;vertical-align:baseline}

/* ═════════════════════════════════════════════════════════════════════════
   搜索栏扫码（2026-09-26，逻辑在 st-scan-v1.js）
   -------------------------------------------------------------------------
   需求：对着商品标签扫条码直接搜（实际在用的是 Code128B）；电脑端不显示入口。

   ⚠️ 入口按钮写在 index.html 的 `#search` 表单里，而 `#search` 会被
      st-home-v1.js `host.append(form)` **搬进** `#st-search-dialog`；
      页面顶部那个 `.searcharea` 本身是 display:none（st-home-v1.css）。
      ⇒ 按钮必须按「弹层里的搜索条」来定位：`.st-search-dialog .search .st-scan-open`。
   ⚠️ 「电脑端不显示」用 CSS 断点实现（默认 display:none，只在 ≤720px 打开），
      不判 UA：窗口拉窄、平板横竖屏都能自然跟随，也没有额外 JS 分支。
   ⚠️ 扫码层必须是 `<dialog>` + showModal()：站内弹层都进 top layer，
      普通 fixed 元素无论 z-index 多大都会被压在搜索弹层下面（见 .st-scan 注释）。
   ═════════════════════════════════════════════════════════════════════════ */

/* 入口：桌面端直接不占位（连焦点都拿不到） */
.st-scan-open{display:none}

/* ---------- 扫码层 ---------- */
dialog.st-scan{
  width:100%;height:100%;max-width:none;max-height:none;
  margin:0;padding:0;border:0;background:transparent;
  display:grid;place-items:center;
}
/* ⚠️ 上面那条 `display:grid` 是**作者**样式，会盖掉 UA 的
   `dialog:not([open]){display:none}`（作者优先）⇒ 这两条必须显式写回来，
   否则弹层关掉之后仍占着整屏、挡住所有点击。 */
dialog.st-scan:not([open]),
dialog.st-scan[hidden]{display:none}
dialog.st-scan::backdrop{
  background:rgba(8,14,30,.74);
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);
}

.st-scan-panel{
  position:relative;
  width:min(420px,calc(100vw - 28px));
  box-sizing:border-box;
  display:grid;gap:12px;
  padding:16px 16px 14px;
  border-radius:20px;
  background:#fff;
  box-shadow:0 30px 70px -24px rgba(6,14,34,.7);
  text-align:center;
}
.st-scan-head{display:flex;align-items:center;justify-content:space-between;gap:12px}
.st-scan-head strong{font-size:14px;font-weight:650;color:#101c3d}
.st-scan-close{
  width:34px;height:34px;flex:none;
  border:0;border-radius:50%;background:rgba(26,51,101,.07);
  color:#34476e;font:inherit;font-size:18px;line-height:1;cursor:pointer;
}
.st-scan-close:focus-visible{outline:2px solid #001c81;outline-offset:2px}

/* 取景区：黑底 + 框线 + 来回扫的橙线。
   手机摄像头出 4:3 / 16:9 都可能，用 aspect-ratio 钉住高度，免得弹层跟着跳。 */
.st-scan-stage{position:relative;border-radius:14px;overflow:hidden;background:#0b1020;aspect-ratio:4/3}
.st-scan-stage[hidden]{display:none}
.st-scan-video{display:block;width:100%;height:100%;object-fit:cover}
.st-scan-frame{
  position:absolute;inset:20% 8%;
  border:2px solid rgba(255,255,255,.9);
  border-radius:12px;
  /* 超大 spread 的「反向遮罩」：只把框外压暗，视线自然落到框内。
     靠父级的 overflow:hidden 裁掉溢出部分。 */
  box-shadow:0 0 0 9999px rgba(8,14,30,.28);
}
.st-scan-frame::after{
  content:"";position:absolute;left:6%;right:6%;top:2%;height:2px;border-radius:2px;
  background:linear-gradient(90deg,transparent,#ff8a3d,transparent);
  animation:st-scan-sweep 2s ease-in-out infinite;
}
@keyframes st-scan-sweep{0%,100%{top:2%}50%{top:96%}}

.st-scan-hint{margin:0;font-size:12px;line-height:1.6;color:#6b7280}
.st-scan-hint[hidden]{display:none}
.st-scan-error{margin:0;font-size:12.5px;line-height:1.7;color:#c2410c}
.st-scan-error[hidden]{display:none}
/* 诊断码：只在失败时出现，供客户截图报障（错误名 + 取流尝试次数）。
   刻意做得很轻（等宽、灰色、11px），不抢主提示的注意力 ——
   它的读者是排查的人，不是客户。 */
.st-scan-code{
  display:flex;align-items:center;justify-content:center;gap:6px;
  margin:0;font-size:11px;line-height:1.5;color:var(--muted);
}
.st-scan-code[hidden]{display:none}
.st-scan-code b{
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-weight:600;letter-spacing:.2px;
}

/* 「拍照识别 / 从相册选」：**完全绕开 getUserMedia** 的第二条路（见 st-scan-v1.js 注释）。
   做成一行低调的次级动作贴在底部，而不是等失败才冒出来 ——
   它本身就有用（给标签拍一张、或从相册选一张现成的照片）。 */
.st-scan-foot{display:flex;justify-content:center;align-items:center;flex-wrap:wrap;gap:4px;margin-top:2px}
.st-scan-shot{
  display:inline-flex;align-items:center;gap:7px;
  min-height:38px;padding:0 15px;
  border:1px solid rgba(26,51,101,.14);border-radius:12px;
  background:rgba(26,51,101,.04);color:#34476e;
  font:inherit;font-size:12.5px;font-weight:600;cursor:pointer;
}
.st-scan-shot svg{width:16px;height:16px;flex:none}
.st-scan-shot:hover{background:rgba(26,51,101,.09)}
.st-scan-shot:focus-visible{outline:2px solid #001c81;outline-offset:2px}
.st-scan-shot[disabled]{opacity:.55;cursor:default}
/* 相机不可用（unsupported / nocamera）时，「拍照识别」升为主按钮：
   取景区已经收起来了，剩下的唯一出路就是它，得让人一眼看到。 */
.st-scan-shot--primary{border-color:transparent;background:#001c81;color:#fff}
.st-scan-shot--primary:hover{background:#00177a}
/* 「从相册选」：与「拍照识别」并列的第二条路，只差一个 `capture` 属性。
   为什么两个都要：`capture` 走的是宿主 App 的 onShowFileChooser(ACTION_IMAGE_CAPTURE)，
   内置浏览器若没实现这一支，点了**什么都不会发生**（无报错、无弹窗，最难查的一种死法）；
   去掉 `capture` 的系统选择器（相机 / 相册 / 文件三选一）几乎所有内核都支持。
   刻意做成文字链接：它是备选，不该和主按钮抢注意力。 */
.st-scan-pick{
  display:inline-flex;align-items:center;min-height:38px;padding:0 10px;
  border:0;border-radius:12px;background:transparent;
  color:#5b6b86;font:inherit;font-size:12.5px;font-weight:600;
  text-decoration:underline;text-underline-offset:3px;text-decoration-color:rgba(91,107,134,.42);
  cursor:pointer;
}
.st-scan-pick:hover{color:#34476e;background:rgba(26,51,101,.05)}
.st-scan-pick:focus-visible{outline:2px solid #001c81;outline-offset:2px}
.st-scan-pick[disabled]{opacity:.55;cursor:default}
/* 原生 file 控件彻底藏起来（用按钮代点它）：不能 display:none，
   个别内核会拒绝「点一个不可见控件」的合成触发。两个 input（带/不带 capture）共用这条。 */
.st-scan-file{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0;
}

/* 扫码时锁住页面滚动：手机上下拉通知栏/回弹最容易误触 */
body.st-scanning{overflow:hidden}

@media(max-width:720px){
  .st-search-dialog .search .st-scan-open{
    display:grid;place-items:center;flex:0 0 auto;
    width:34px;height:34px;margin-left:-2px;
    border:0;border-radius:10px;background:rgba(26,51,101,.06);
    color:#34476e;cursor:pointer;
  }
  .st-search-dialog .search .st-scan-open svg{width:19px;height:19px}
  .st-scan-open:active{background:rgba(26,51,101,.14)}
}

@media(prefers-color-scheme:dark){
  .st-scan-panel{background:#171a21;box-shadow:0 30px 70px -24px #000}
  .st-scan-head strong{color:#f2f3f5}
  .st-scan-close{background:rgba(255,255,255,.09);color:#c9ced8}
  .st-scan-hint{color:#a8adb8}
  .st-scan-error{color:#f59e6b}
  .st-scan-code{color:#7c8595}
  .st-scan-shot{border-color:rgba(255,255,255,.16);background:rgba(255,255,255,.06);color:#c9ced8}
  .st-scan-shot:hover{background:rgba(255,255,255,.12)}
  /* ⚠️ 必须在这里再写一遍：上面那条 `.st-scan-shot{…}` 与 `.st-scan-shot--primary`
     特异度相同（都是 0,1,0），深色块在后面 ⇒ 会把浅色块里的主按钮样式覆盖掉。
     「媒体查询/深色块不改变特异度，谁后加载谁赢」——别只改浅色那份。 */
  .st-scan-shot--primary{border-color:transparent;background:#2f52c9;color:#fff}
  .st-scan-shot--primary:hover{background:#3b60dd}
  .st-scan-pick{color:#9aa3b2;text-decoration-color:rgba(154,163,178,.42)}
  .st-scan-pick:hover{color:#c9ced8;background:rgba(255,255,255,.07)}
}
@media(prefers-reduced-motion:reduce){
  .st-scan-frame::after{animation:none;top:50%}
}
