/* ============================================================
   云卡商城 · 样式模块 04/11 —— 04-components.css
   ------------------------------------------------------------
   职责：通用组件：按钮、表单、卡片、徽标、价格、商品卡、分类导航
   涵盖：§7 §8 §9 §10 §11 §12 §13

   ⚠️ 加载顺序即层叠顺序，请勿调整 <link> 的先后。
      本文件由 style.css 按分节边界切出，规则未做任何重排。
   ============================================================ */

/* ============================================================
   7 · 按钮
   ============================================================ */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-1h);
  height: var(--ctl-h);
  padding: 0 var(--sp-4);
  border: 1px solid var(--line-2);
  border-radius: var(--r-md);
  background: var(--surface-2);
  color: var(--text);
  font-size: var(--fs-base);
  font-weight: var(--fw-semi);
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
  transition: background var(--tr), border-color var(--tr), color var(--tr), transform var(--d-press) var(--e-out);
}
.btn:hover { background: var(--surface-3); border-color: var(--line-strong); }
.btn:active { background: var(--surface-hover); }
.btn:disabled,
.btn[disabled] { opacity: .45; cursor: not-allowed; }
.btn:disabled:hover { background: var(--surface-2); border-color: var(--line-2); }

/* ============================================================
   按压反馈（全站统一的"按下去有反应"）
   ------------------------------------------------------------
   原来全站只有极少数 :active，于是「hover 会变色、按下去毫无反应」——
   但按下才是"我点到了"的确认，缺了它，按钮看起来就像图片。
   统一走 --d-press（100ms）：比 hover 的 160ms 更快，
   因为反馈必须抢在感知之前（80ms 内最佳）。
   disabled / 缺货的规格不缩放 —— 它们本来就不该有"按到了"的错觉。

   ● 数量加减按钮（.qty button）**故意不在这里**：它的容器是 overflow:hidden
     且两个按钮严丝合缝，缩放 3% 会在接缝处露出容器的底色，看起来像裂开。
     宁可这里不缩，也不要那 1px 的缝隙。
   ============================================================ */
.btn,
.spec,
.gal-btn,
.cat-chip { transition: background var(--tr), border-color var(--tr), color var(--tr), transform var(--d-press) var(--e-out); }

.btn:active:not(:disabled),
.spec:active:not(.dis),
.gal-btn:active,
.cat-chip:active { transform: scale(.97); }
.btn-primary:active:not(:disabled) { background: var(--brand-hover); border-color: var(--brand-hover); }

/* 「加入购物车」按完的短暂确认态（由 pages/product.js 在重绘后续上）。
   用成功色而不是品牌色：这一步的语义是"办成了"，不是"可以点"。 */
.btn.is-done {
  background: var(--ok);
  border-color: var(--ok);
  color: var(--text-on);
}

/* 按钮里的状态标记（如第三方登录占位上的「即将开放」） */
.btn .badge { margin-left: var(--sp-2); vertical-align: middle; }

.btn-primary { background: var(--brand); border-color: var(--brand); color: var(--text-on); }
.btn-primary:hover { background: var(--brand-hover); border-color: var(--brand-hover); }
.btn-primary:active { background: var(--brand-active); border-color: var(--brand-active); }

.btn-gold { background: var(--gold); border-color: var(--gold); color: var(--gold-on); }
.btn-gold:hover { background: var(--gold-hover); border-color: var(--gold-hover); }
.btn-gold:active { background: var(--gold); border-color: var(--gold); }

.btn-ghost { background: transparent; border-color: var(--line-2); color: var(--text-2); }
.btn-ghost:hover { background: var(--surface-2); border-color: var(--line-strong); color: var(--text); }

.btn-ok { background: var(--ok-bg); border-color: var(--ok-line); color: var(--ok-fg); }
.btn-ok:hover { background: var(--ok-bg); border-color: var(--ok); color: var(--ok-fg); }

.btn-danger { background: var(--danger-bg); border-color: var(--danger-line); color: var(--danger-fg); }
.btn-danger:hover { background: var(--danger-bg); border-color: var(--danger); color: var(--danger-fg); }

.btn-sm { height: var(--ctl-h-sm); padding: 0 var(--sp-3); border-radius: var(--r-sm); font-size: var(--fs-sm); }
.btn-xs { height: 26px; padding: 0 var(--sp-2); border-radius: var(--r-xs); font-size: var(--fs-xs); }
.btn-lg { height: var(--ctl-h-lg); padding: 0 var(--sp-6); font-size: var(--fs-md); }
.btn-block { display: flex; width: 100%; }

/* ============================================================
   8 · 表单
   ============================================================ */
.field { margin-bottom: var(--sp-4); }
.field > label {
  display: block;
  margin-bottom: var(--sp-1h);
  color: var(--text-2);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semi);
}
.field .hint {
  margin-top: var(--sp-1h);
  color: var(--text-3);
  font-size: var(--fs-xs);
  line-height: var(--lh-normal);
}
.field .err { margin-top: var(--sp-1h); color: var(--danger-fg); font-size: var(--fs-xs); }
.field .req { color: var(--danger-fg); }

.input,
.select,
.textarea {
  width: 100%;
  height: var(--ctl-h);
  padding: 0 var(--sp-3);
  background: var(--inset);
  border: 1px solid var(--line-2);
  border-radius: var(--r-md);
  color: var(--text);
  outline: none;
  transition: border-color var(--tr), box-shadow var(--tr), background var(--tr);
}
.input:hover,
.select:hover,
.textarea:hover { border-color: var(--line-strong); }
.input:focus,
.select:focus,
.textarea:focus { background: var(--bg); border-color: var(--brand); box-shadow: var(--ring); }
.input::placeholder,
.textarea::placeholder { color: var(--text-3); }
.input:disabled,
.select:disabled,
.textarea:disabled,
.input[disabled] { background: var(--surface-2); color: var(--text-3); cursor: not-allowed; }

.textarea {
  height: auto;
  min-height: 96px;
  padding: var(--sp-3);
  line-height: var(--lh-normal);
  resize: vertical;
}

.select {
  appearance: none;
  cursor: pointer;
  padding-right: var(--sp-8);
  background-image:
    linear-gradient(45deg, transparent 50%, var(--text-3) 50%),
    linear-gradient(135deg, var(--text-3) 50%, transparent 50%);
  background-position: calc(100% - 17px) 17px, calc(100% - 12px) 17px;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
.select option { background: var(--surface-2); color: var(--text); }

.input-group { display: flex; align-items: stretch; gap: var(--sp-2); }
.input-group .input,
.input-group .select { flex: 1; min-width: 0; }
.input-group .btn { flex: none; }

.checkbox {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  color: var(--text-2);
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
  cursor: pointer;
}
.checkbox input {
  flex: none;
  width: 16px;
  height: 16px;
  margin: 0;
  accent-color: var(--brand);
  cursor: pointer;
}

/* 权限分配（管理员管理）
   ★ 角色模板已从「radio 列表」改为「下拉框」（行业普遍做法，见 admin/admins.js）。
     原来的 .radio / .preset-list 也随之删除 —— 留着就是永远不会被引用的死样式，
     还会让 tests 的「JS 用到的类名是否都有规则」反向检查失去意义。 */
.perm-groups { display: flex; flex-direction: column; gap: var(--sp-3); }
.perm-group { border: 1px solid var(--line); border-radius: var(--r-md); padding: var(--sp-2) var(--sp-3); }
.perm-group .pg-title { font-size: var(--fs-xs); color: var(--text-3); font-weight: var(--fw-semi); margin-bottom: var(--sp-2); }
.perm-group .pg-body { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4); }
.perm-summary { display: flex; flex-wrap: wrap; gap: var(--sp-1); max-width: 320px; }

/* 密码强度条 */
.pwd-meter { margin-top: var(--sp-2); }
.pwd-meter .bars { display: flex; gap: var(--sp-1); margin-bottom: var(--sp-1h); }
.pwd-meter .bar { flex: 1; height: 4px; border-radius: var(--r-full); background: var(--surface-3); }

/* ============================================================
   9 · 卡片 / 区块
   ============================================================ */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-1);
  overflow: hidden;
}
.card-pad { padding: var(--sp-5); }
.card-body { padding: var(--sp-5); }
.card-body.tight { padding: var(--sp-2) var(--sp-5); }
.card-body.flush { padding: 0; }

.card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  flex-wrap: wrap;
  padding: var(--sp-4) var(--sp-5);
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
}
.card-head h3 {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
  font-size: var(--fs-md);
  font-weight: var(--fw-semi);
}
.card-head h3::before {
  content: "";
  flex: none;
  width: 3px;
  height: 15px;
  border-radius: var(--r-full);
  background: var(--brand);
}
.card-head .more { color: var(--text-2); font-size: var(--fs-sm); transition: color var(--tr); }
.card-head .more:hover { color: var(--brand-fg); }

.section-title {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--sp-4);
  margin: var(--sp-8) 0 var(--sp-4);
}
.section-title h2 {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-xl);
}
.section-title h2::before {
  content: "";
  flex: none;
  width: 4px;
  height: 20px;
  border-radius: var(--r-full);
  background: var(--brand);
}
.section-title .more { color: var(--text-2); font-size: var(--fs-sm); }
.section-title .more:hover { color: var(--brand-fg); }

/* ============================================================
   10 · 徽标
   ============================================================ */
.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding: 2px var(--sp-2);
  border: 1px solid transparent;
  border-radius: var(--r-xs);
  background: var(--neutral-bg);
  color: var(--neutral-fg);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-semi);
  line-height: 1.6;
  white-space: nowrap;
}
.badge-brand { background: var(--brand-bg); border-color: var(--brand-line); color: var(--brand-fg); }
.badge-gold { background: var(--gold-bg); border-color: var(--gold-line); color: var(--gold-fg); }
.badge-ok { background: var(--ok-bg); border-color: var(--ok-line); color: var(--ok-fg); }
.badge-warn { background: var(--warn-bg); border-color: var(--warn-line); color: var(--warn-fg); }
.badge-danger { background: var(--danger-bg); border-color: var(--danger-line); color: var(--danger-fg); }
.badge-info { background: var(--info-bg); border-color: var(--info-line); color: var(--info-fg); }
.badge-purple { background: var(--purple-bg); border-color: var(--purple-line); color: var(--purple-fg); }

/* 数值/角标变化时"弹"一下。
   数字硬切等于没有反馈 —— 用户会怀疑"到底加进去没有"，然后再点一次。
   420ms（--d-pop）故意比状态切换（160ms）慢：变化量越重要，越需要被看见。 */
.badge.is-pop { animation: badgePop var(--d-pop) var(--e-out); }
@keyframes badgePop {
  0% { transform: scale(1); }
  35% { transform: scale(1.38); }
  100% { transform: scale(1); }
}

/* ============================================================
   11 · 价格
   ============================================================ */
.price {
  color: var(--gold);
  font-weight: var(--fw-bold);
  font-variant-numeric: tabular-nums;
  letter-spacing: -.2px;
}
.price .cur { margin-right: 1px; font-size: .72em; font-weight: var(--fw-semi); }
.price-old {
  color: var(--text-3);
  font-size: var(--fs-sm);
  font-weight: var(--fw-normal);
  text-decoration: line-through;
}

/* ============================================================
   12 · 商品卡
   ============================================================ */
.goods-card {
  position: relative;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  transition: border-color var(--tr), transform var(--tr), background var(--tr);
}
.goods-card:hover {
  background: var(--surface-hover);
  border-color: var(--brand-line);
  transform: translateY(-2px);
}
.goods-card .thumb {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  border-radius: 0;
  border-bottom: 1px solid var(--line);
  background: var(--surface-2);
}
/* 注意：这里只补 z-index，不要再写 position ——
   图片的定位由上面那条「图片铺满媒体容器」统一负责（绝对定位），
   这里若写成 position:relative 会把它顶回文档流、撑破卡位。 */
.goods-card .thumb img { z-index: var(--z-base);object-fit:contain;object-position:center; }
.goods-card .thumb > .brand-tile { width:70%;height:70%;border-radius:var(--r-lg); }
.goods-card .thumb .ph {
  position: relative;
  z-index: var(--z-base);
  font-size: var(--ico-lg);
  line-height: 1;
  transition: transform var(--tr);
}
.goods-card:hover .thumb .ph { transform: scale(1.08); }

.goods-card .corner {
  position: absolute;
  top: var(--sp-2);
  left: var(--sp-2);
  z-index: 2;
  padding: 2px var(--sp-2);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-xs);
  background: var(--surface-3);
  color: var(--text-2);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-bold);
  line-height: 1.7;
}
.goods-card .corner.hot { background: var(--danger); border-color: var(--danger); color: var(--text-on); }
.goods-card .corner.new { background: var(--brand); border-color: var(--brand); color: var(--text-on); }

.goods-card .info {
  display: flex;
  flex: 1;
  flex-direction: column;
  padding: var(--sp-4) var(--sp-4) var(--sp-5);
}
.goods-card .name {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  min-height: 3em;
  overflow: hidden;
  color: var(--text);
  font-size: var(--fs-base);
  font-weight: var(--fw-semi);
  line-height: 1.5;
  overflow-wrap: anywhere;
  text-overflow: ellipsis;
}
.goods-card .sub {
  margin-top: var(--sp-1);
  overflow: hidden;
  color: var(--text-3);
  font-size: var(--fs-xs);
  line-height: 1.5;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.goods-card .foot {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--sp-2);
  margin-top: var(--sp-3);
}
.goods-card .price { font-size: var(--fs-xl); }
.goods-card .price .cur { font-size: var(--fs-sm); }
.goods-card .sold { color: var(--text-3); font-size: var(--fs-2xs); white-space: nowrap; }
.goods-card .tags { display: flex; flex-wrap: wrap; gap: var(--sp-1h); margin-top: var(--sp-3); }

/* ============================================================
   13 · 分类导航
   ============================================================ */
.cat-row { display: grid; grid-template-columns: repeat(8, minmax(0, 1fr)); gap: 10px; }
.cat-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
  min-height: 52px;
  padding: 9px 10px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface);
  color: var(--text-2);
  font-size: 14px;
  font-weight: var(--fw-medium);
  white-space: normal;
  cursor: pointer;
  transition: background var(--tr), border-color var(--tr), color var(--tr);
}
.cat-chip:hover { background: var(--surface-2); border-color: var(--brand-line); color: var(--text); }
.cat-chip.on { background: var(--brand); border-color: var(--brand); color: var(--text-on); }
.cat-chip.on:hover { background: var(--brand-hover); border-color: var(--brand-hover); }
.cat-chip:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; }
.cat-chip-label { min-width: 0; line-height: 1.4; overflow-wrap: anywhere; }
@media (max-width: 1150px) { .cat-row { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (max-width: 640px) { .cat-row { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 420px) { .cat-row { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* ============================================================
   代充信息表单（.rf-*）
   ------------------------------------------------------------
   商品详情页 / 结算页 / 订单详情共用，所以放在通用组件层而不是某个页面里。
   输入框本身复用上面 §8 的 .input / .select，这里只加外层容器与提示。
   ============================================================ */
.rf-block {
  padding: var(--sp-5);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
}
.rf-head { margin-bottom: var(--sp-4); }
.rf-head .t { color: var(--text); font-size: var(--fs-md); font-weight: var(--fw-semi); }
.rf-head .s {
  margin-top: var(--sp-1h);
  color: var(--text-3);
  font-size: var(--fs-xs);
  line-height: var(--lh-normal);
}
.rf-field { margin-bottom: var(--sp-4); }
.rf-field:last-child { margin-bottom: 0; }
.rf-confirm { margin-top: var(--sp-2); }

/* 敏感字段标记：让用户知道这个值会被特殊处理 */
.rf-tag {
  margin-left: var(--sp-2);
  padding: 0 var(--sp-1h);
  border: 1px solid var(--warn-line);
  border-radius: var(--r-xs);
  background: var(--warn-bg);
  color: var(--warn-fg);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-normal);
}
.rf-field.has-err .input,
.rf-field.has-err .select { border-color: var(--danger); }

/* 只读展示时敏感值被打码 */
.rf-lock { margin-left: var(--sp-2); color: var(--text-3); font-size: var(--fs-2xs); }
.rf-info { margin-top: 0; }

/* ============================================================
   页面内搜索栏（.search-bar）
   ------------------------------------------------------------
   页头那个 .search-box 是给桌面用的，窄屏会被隐藏；
   页面里需要一个任何尺寸都在的搜索入口，所以单独做一条。
   ============================================================ */
.search-bar {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  height: var(--ctl-h);
  padding: 0 var(--sp-3);
  background: var(--inset);
  border: 1px solid var(--line-2);
  border-radius: var(--r-md);
  transition: border-color var(--tr), box-shadow var(--tr), background var(--tr);
}
.search-bar:hover { border-color: var(--line-strong); }
.search-bar:focus-within { background: var(--bg); border-color: var(--brand); box-shadow: var(--ring); }
.search-bar .ico { flex: none; display: grid; place-items: center; color: var(--text-3); }
.search-bar input {
  flex: 1;
  min-width: 0;
  height: 100%;
  border: 0;
  background: none;
  color: var(--text);
  font-size: var(--fs-base);
  outline: none;
}
.search-bar input::placeholder { color: var(--text-3); }
.list-search-clear{display:grid;place-items:center;flex:none;width:44px;height:44px;border:0;border-radius:8px;background:transparent;color:var(--text-3);cursor:pointer}
.list-search-clear[hidden]{display:none}
.list-search-clear:hover{background:var(--surface-2);color:var(--text)}
.list-search-clear:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
#list-q::-webkit-search-cancel-button{-webkit-appearance:none}
.list-breadcrumb{flex-wrap:wrap;min-width:0;overflow-wrap:anywhere}
.list-breadcrumb #list-search-crumb:empty{display:none}
.list-results-toolbar{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;margin-top:20px;padding-top:16px;border-top:1px solid var(--line)}
.list-sort{flex-wrap:wrap}
.list-sort-mobile{display:none}
.list-empty-actions{display:flex;justify-content:center;flex-wrap:wrap;gap:12px}
.list-empty-actions .btn{min-height:44px}
.list-page #list-results>.empty{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);padding:48px 20px}
@media(max-width:760px){
  .list-page .list-sort{display:none}
  .list-sort-mobile{display:block;flex:0 1 168px;min-width:0}
  .list-sort-mobile .select{width:100%;min-height:44px;font-size:16px}
  .list-results-toolbar{flex-wrap:nowrap;gap:8px;margin-top:16px;padding-top:14px}
  .list-results-toolbar>[role="status"]{white-space:nowrap;font-size:13px}
  .list-page #list-results>.empty{padding:36px 16px}
  .list-page .search-bar{min-height:48px}
}

/* ============================================================
   本地存储不可用时的常驻横幅（.storage-warn）
   ------------------------------------------------------------
   必须显眼且常驻：此时**每一次写操作都会失败**，
   用户会反复遇到"点了没反应"，一闪而过的 toast 等于没提示。
   ============================================================ */
.storage-warn {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: var(--z-toast);
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-5);
  background: var(--warn-bg);
  border-top: 1px solid var(--warn-line);
  color: var(--warn-fg);
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
}
.storage-warn b { display: block; color: var(--text); font-size: var(--fs-base); }
.storage-warn-ico { flex: none; font-size: var(--fs-lg); line-height: 1.2; }
@media (min-width: 961px) {
  .storage-warn { left: 50%; right: auto; bottom: var(--sp-4); transform: translateX(-50%); max-width: 720px; border: 1px solid var(--warn-line); border-radius: var(--r-lg); }
}

/* 组件精修：用同一组间距保持标题、正文、操作区的节奏。 */
.card-pad, .card-body { padding: var(--sp-6); }
.card-head { padding: var(--sp-4) var(--sp-6); }
.card-body.tight { padding: var(--sp-3) var(--sp-6); }
.card-body.flush { padding: 0; }
.field { margin-bottom: var(--sp-5); }
.field > label { margin-bottom: var(--sp-2); }
.field .hint, .field .err { line-height: var(--lh-normal); overflow-wrap: anywhere; }
.btn { gap: var(--sp-2); }
.btn .ico-svg { flex-shrink: 0; }
.goods-card .foot { margin-top: auto; padding-top: var(--sp-4); flex-wrap: wrap; row-gap: var(--sp-1); }
.goods-card .sub { margin-top: var(--sp-2); }
.goods-card:focus-visible { border-color: var(--brand); box-shadow: var(--ring); }
.section-title { margin-top: var(--sp-10); margin-bottom: var(--sp-5); flex-wrap: wrap; }
.btn:disabled:active { transform: none; }

/* 分类的色彩只用于小图标，选中状态由整块按钮与 aria-current 表达。 */
.category-icon { --ci-fg: #475569; --ci-bg: #f1f5f9; display: grid; place-items: center; flex: none; width: 32px; height: 32px; border-radius: 50%; color: var(--ci-fg); background: var(--ci-bg); }
.category-icon > svg, .category-icon .brand-tile.bt-xs { width: 22px; height: 22px; }
.category-icon .brand-tile.bt-xs { background: transparent; color: inherit; border-radius: 4px; }
.category-icon .brand-tile .brand-svg, .category-icon .brand-tile .ico-svg { width: 100%; height: 100%; color: inherit; }
.category-icon .brand-tile img { object-fit: contain; }
.category-icon.ci-blue { --ci-fg: #2563eb; --ci-bg: #eff6ff; }
.category-icon.ci-violet { --ci-fg: #7c3aed; --ci-bg: #f5f3ff; }
.category-icon.ci-orange { --ci-fg: #c2410c; --ci-bg: #fff7ed; }
.category-icon.ci-rose { --ci-fg: #be185d; --ci-bg: #fff1f2; }
.category-icon.ci-gold { --ci-fg: #a16207; --ci-bg: #fffbeb; }
.category-icon.ci-green { --ci-fg: #15803d; --ci-bg: #f0fdf4; }
.category-icon.ci-teal { --ci-fg: #0f766e; --ci-bg: #f0fdfa; }
[data-theme="dark"] .category-icon { --ci-fg: #cbd5e1; --ci-bg: #293548; }
[data-theme="dark"] .category-icon.ci-blue { --ci-fg: #93c5fd; --ci-bg: #203555; }
[data-theme="dark"] .category-icon.ci-violet { --ci-fg: #c4b5fd; --ci-bg: #36294e; }
[data-theme="dark"] .category-icon.ci-orange { --ci-fg: #fdba74; --ci-bg: #462e21; }
[data-theme="dark"] .category-icon.ci-rose { --ci-fg: #fda4af; --ci-bg: #482536; }
[data-theme="dark"] .category-icon.ci-gold { --ci-fg: #fde68a; --ci-bg: #423821; }
[data-theme="dark"] .category-icon.ci-green { --ci-fg: #86efac; --ci-bg: #1e3d32; }
[data-theme="dark"] .category-icon.ci-teal { --ci-fg: #5eead4; --ci-bg: #1d3b3c; }
[data-theme="dark"] .cat-chip.on { background: #2563eb; border-color: #2563eb; }
[data-theme="dark"] .cat-chip.on:hover { background: #1d4ed8; border-color: #1d4ed8; }
.cat-chip.on .category-icon { color: var(--text-on); background: rgba(255, 255, 255, .18); }

/* Card family: quiet content panels and image-led, interactive product cards. */
.card { box-shadow: none; }
.card-head { background: var(--surface); padding-block: var(--sp-5); }
.card-head h3::before { display: none; }
.card-head h3 { line-height: var(--lh-normal); }
.card-head .more { display: inline-flex; align-items: center; min-height: var(--ctl-h-sm); }
.goods-card { border-radius: var(--r-xl); box-shadow: var(--sh-1); transition: border-color var(--tr), box-shadow var(--tr); }
.goods-card .thumb { width: calc(100% - var(--sp-4)); margin: var(--sp-2) var(--sp-2) 0; border: 0; border-radius: var(--r-lg); overflow: hidden; }
.goods-card .info { padding: var(--sp-4) var(--sp-4) var(--sp-5); }
.goods-card .name { font-size: var(--fs-md); font-weight: var(--fw-semi); }
.goods-card .sub { margin-top: var(--sp-1h); color: var(--text-2); }
.goods-card .foot { padding-top: var(--sp-4); padding-bottom: var(--sp-3); align-items: baseline; }
.goods-card .price { font-size: var(--fs-xl); line-height: var(--lh-tight); }
.goods-meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1h); padding-top: var(--sp-3); border-top: 1px solid var(--line); }
.goods-meta .badge:first-child { background: var(--surface-2); border-color: transparent; color: var(--text-2); }
.goods-card .corner { top: var(--sp-2); left: var(--sp-2); border-radius: var(--r-sm); }
.goods-card:hover { background: var(--surface); transform: none; border-color: var(--brand-line); box-shadow: var(--sh-2); }
.goods-card:hover .thumb .ph { transform: none; }
.goods-card:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; }
