/* ==========================================================================
   Inter —— 自托管，不依赖 Google Fonts CDN
   可变字重字体（400 700），一个文件覆盖正文到标题。
   拆成 latin / latin-ext 两个子集，浏览器按 unicode-range 只下用得到的那个：
   全英文站点实际只会拉 latin（47KB）。
   路径相对本 CSS 文件：extension/ocmod/catalog/view/{stylesheet → fonts}
   字体文件放在 extension/ocmod/ 下而不是核心 catalog/view/，
   是为了跟其余定制文件一起，OpenCart 升级覆盖核心目录时不会丢。
   ========================================================================== */
/* Inter —— 全站唯一字体。可变字重 400-700，一个文件覆盖正文到标题。
   自托管而不是引 Google Fonts CDN：直连 CDN 会把访客 IP 发给 Google，
   英国站点这一条有 GDPR 风险（德国已有判例）。字体文件放在
   extension/ocmod/catalog/view/fonts/，换服务器时别漏传。
   授权：SIL Open Font License 1.1，可商用、可自托管。 */
/* latin */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/inter-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* latin-ext */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/inter-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ==========================================================================
   商品卡片圆角化
   仅覆盖样式，不改动任何模板结构
   加载位置：extension/ocmod/catalog/view/template/common/header.twig
   ========================================================================== */

/* ==========================================================================
   头部布局
   菜单已被移进 header 的栅格里（见 header.twig 的 #menu-col），
   这里消除 menu.twig 自带 .container 造成的嵌套内边距
   ========================================================================== */
#menu-col > .container {
  max-width: none;
  width: 100%;
  padding-left: 0;
  padding-right: 0;
}

/* --------------------------------------------------------------------------
   搜索框：胶囊造型，放大镜内嵌
   圆角和描边由外层 .input-group 统一承载，内部的输入框与按钮
   全部去掉自身边框/背景，融成一个整体
   -------------------------------------------------------------------------- */
header .input-group {
  flex-wrap: nowrap;
  border: 1px solid var(--bs-border-color);
  border-radius: 50rem;
  background-color: #fff;
  overflow: hidden;
  transition: border-color .2s ease, box-shadow .2s ease;
}

/* 聚焦时整个胶囊亮起，而不是内部输入框单独描边 */
header .input-group:focus-within {
  border-color: rgba(var(--bs-primary-rgb), .55);
  box-shadow: 0 0 0 3px rgba(var(--bs-primary-rgb), .12);
}

header .input-group > .form-control {
  border: 0;
  background-color: transparent;
  padding-left: 20px;
  box-shadow: none;
}

header .input-group > .form-control:focus {
  border: 0;
  background-color: transparent;
  box-shadow: none;
}

header .input-group > .btn {
  border: 0;
  background-color: transparent;
  color: var(--bs-secondary-color);
  padding: 0 18px;
  box-shadow: none;
}

header .input-group > .btn:hover,
header .input-group > .btn:focus,
header .input-group > .btn:active {
  border: 0;
  background-color: transparent;
  color: var(--bs-primary);
  box-shadow: none;
}

/* --- 设计变量：统一圆角与控件高度 --- */
:root {
  --oc-radius: 10px;
  --oc-control-h: 44px; /* 移动端触控目标下限 */
  /* 电脑端吸顶后的头部高度（logo 行 ~52 + 导航 ~40）。
     所有 position:sticky 的元素都得按它留出 top，
     否则会滑到吸顶头部底下去。 */
  --oc-header-stuck: 96px;
}

/* --- 折叠断点以下（<992px）：☰ 排到 Categories 文字前面 --- */
@media (max-width: 991.98px) {
  #menu {
    justify-content: flex-start;
    gap: 8px;
  }

  #menu .navbar-toggler {
    order: 1;
  }

  #menu #category {
    order: 2;
  }

  /* 展开的分类列表必须保持在最后一位 */
  #menu #navbar-menu {
    order: 3;
  }
}

/* --- 手机（<768px） --- */
@media (max-width: 767.98px) {
  header {
    /* 底部留白原本靠 #menu 的 margin-bottom:20px，那条已清零，改由这里补 */
    padding: 12px 0 16px;
  }

  /* ------------------------------------------------------------------
     手机端把 .row 从 flex-wrap 换成 CSS Grid。
     Bootstrap 的 .row 靠换行来分行，两列内部嵌套层级又不同
     （#menu-col 里有 .container，#cart 里有 .d-grid），
     高度传递链对不齐，用 align-items / align-self 是调不准的。
     Grid 具名区域直接指定「谁在第几行第几列」，同一行的两格
     由浏览器保证垂直居中，不存在错位的可能。
     ------------------------------------------------------------------ */
  header .row {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-areas:
      "logo search"
      "menu cart";
    column-gap: 12px;
    row-gap: 12px;
    align-items: center;
    margin: 0;
  }

  /* 清掉 Bootstrap 栅格给 col 的宽度和内外边距，布局全部交给 grid */
  header .row > * {
    width: auto;
    max-width: none;
    flex: none;
    padding-left: 0;
    padding-right: 0;
    margin-top: 0;
    margin-left: 0;
  }

  header .row > #logo-col {
    grid-area: logo;
  }

  header .row > #search-col {
    grid-area: search;
  }

  header .row > #menu-col {
    grid-area: menu;
    justify-self: start;
  }

  header .row > #cart {
    grid-area: cart;
    justify-self: end;
  }

  /* Logo：靠左、垂直居中 */
  #logo {
    text-align: left;
    margin: 0;
    line-height: 0;
  }

  /* 必须给绝对上限。grid 第一列是 auto（由内容定宽），
     此时 img-fluid 的 max-width:100% 没有参照物，
     logo 会按原始尺寸把整列撑开，挤飞右侧的搜索框和购物车 */
  #logo img {
    max-width: 150px;
    width: auto;
    height: auto;
  }

  /* 搜索框：注意 4.1 的 search.twig 没有 #search 这个 id，
     必须从 .input-group 入手；下边距来自 form 上的 mb-3 */
  header .input-group {
    margin-bottom: 0 !important;
    flex-wrap: nowrap; /* 列宽紧张时输入框和按钮不许上下折行 */
  }

  header .input-group > .form-control,
  header .input-group > .btn {
    /* .form-control-lg 自带 min-height ≈48px，会压制 height，必须清零 */
    min-height: 0;
    /* 减掉外层胶囊的上下 1px 边框，整体仍是 44px */
    height: calc(var(--oc-control-h) - 2px);
    font-size: .95rem;
    line-height: 1;
  }

  header .input-group > .form-control {
    padding-left: 16px;
    padding-right: 4px;
  }

  header .input-group > .btn {
    width: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
  }

  /* Categories 宽度自适应内容 */
  #menu-col > .container {
    width: auto;
    display: flex;
    align-items: center;
  }

  /* 两个控件都锁死同一高度，grid 再把它们在同一行里居中 */
  #menu-col #menu,
  #cart > .dropdown,
  #cart .btn {
    height: var(--oc-control-h);
    min-height: var(--oc-control-h);
  }

  /* ☰ 与文字禁止换行，否则会把 Categories 栏撑成两行高 */
  #menu {
    flex-wrap: nowrap;
    /* 核心样式表 stylesheet.css:200 给了 margin-bottom: 20px。
       grid 的 align-items 居中的是「外边距盒」，这 20px 会把行高
       撑成 64px，于是 44px 的购物车居中后比 Categories 低 10px。
       行间距已由 grid 的 row-gap 提供，这里必须清零。 */
    margin-bottom: 0;
  }

  /* 按钮的 focus 光晕会让它看起来比左边高一圈，收掉 */
  #cart .btn:focus,
  #cart .btn:focus-visible,
  #cart .btn.show {
    box-shadow: none;
    outline: none;
  }

  /* Categories 栏：与购物车按钮等高等圆角 */
  #menu {
    /* 只能用 min-height：☰ 展开时分类列表要把导航撑高，
       写死 height 会把展开的菜单裁掉 */
    min-height: var(--oc-control-h);
    padding: 6px 10px;
    border-radius: var(--oc-radius);
    /* 去掉拟物渐变和描边，扁平化后与其他控件观感一致 */
    background-image: none;
    border-color: transparent;
  }

  #menu .navbar-toggler {
    padding: 0;
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: .9rem;
    border-radius: 8px;
    border-color: var(--brand-line-strong);
    color: var(--brand-ink);
  }

  #menu #category {
    font-size: .95rem;
    font-weight: 600;
    color: var(--brand-ink);
    line-height: 1;
  }

  /* 购物车按钮：与左侧 Categories 严格等高等圆角 */
  #cart .btn {
    height: var(--oc-control-h);
    padding: 0 10px;
    font-size: .82rem;
    font-weight: 500;
    line-height: 1;
    border-radius: var(--oc-radius);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    white-space: nowrap;
  }

  /* 去掉 Bootstrap 下拉箭头，窄屏省出空间 */
  #cart .dropdown-toggle::after {
    display: none;
  }

  /* --- 展开的分类列表做成悬浮下拉，不再把 Categories 栏撑高 --- */
  #menu {
    position: relative;
  }

  /* Categories 宽度已随内容自适应，面板改用视口宽度铺满 */
  #menu #navbar-menu {
    position: absolute;
    top: calc(100% + 8px);
    left: 0;
    width: calc(100vw - 24px); /* 视口宽减去容器左右各 12px 内边距 */
    padding: 6px;
    background-color: #fff;
    border-radius: var(--oc-radius);
    box-shadow: 0 10px 30px rgba(0, 0, 0, .15);
    z-index: 1030;
  }

  /* 面板里的链接显式指定颜色，不依赖从 #menu 继承 */
  #menu #navbar-menu .nav-link,
  #menu #navbar-menu .dropdown-item {
    color: #212529;
    text-shadow: none;
    padding: 11px 12px;
    border-radius: 8px;
  }

  #menu #navbar-menu .nav-link:hover,
  #menu #navbar-menu .dropdown-item:hover,
  #menu #navbar-menu .nav-link:focus,
  #menu #navbar-menu .dropdown-item:focus {
    background-color: var(--bs-tertiary-bg);
    color: var(--bs-primary);
  }

  /* 二级分类面板去掉边框和阴影，避免面板套面板 */
  #menu #navbar-menu .dropdown-menu {
    border: 0;
    box-shadow: none;
    padding-left: 8px;
  }

  /* --- 购物车下拉：改成铺满视口宽度的悬浮面板 --- */
  #cart .dropdown-menu {
    width: calc(100vw - 24px) !important;
    max-width: none !important;
    max-height: 72vh;
    overflow-y: auto;
    padding: 12px !important;
    border: 0;
    border-radius: var(--oc-radius);
    box-shadow: 0 12px 32px rgba(0, 0, 0, .18);
  }

  /* --- 商品明细表：允许换行，缩略图列固定 --- */
  #cart .dropdown-menu .table-striped {
    table-layout: auto;
    margin-bottom: 8px;
  }

  #cart .dropdown-menu .table-striped td {
    white-space: normal;
    word-break: normal;
    vertical-align: middle;
    padding: 8px 6px;
  }

  #cart .dropdown-menu .table-striped td:first-child {
    width: 64px;
  }

  #cart .dropdown-menu .table-striped img {
    width: 56px;
    height: auto;
    border-radius: 8px;
  }

  /* --- 合计表：名称列吃满剩余宽度、不换行；金额列收缩到内容宽 --- */
  #cart .dropdown-menu .table-bordered td {
    vertical-align: middle;
    padding: 8px 10px;
  }

  #cart .dropdown-menu .table-bordered td:first-child {
    width: auto;
    white-space: nowrap;
    text-align: left; /* 名称左对齐、金额右对齐，账单式排版更易读 */
  }

  #cart .dropdown-menu .table-bordered td:last-child {
    width: 1%; /* 经典写法：收缩到内容所需的最小宽度 */
    white-space: nowrap;
    text-align: right;
  }

  #cart .dropdown-menu .btn-danger {
    padding: 0;
    width: 30px;
    height: 30px;
    border-radius: 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  /* 底部「查看购物车 / 结账」按钮排布 */
  #cart .dropdown-menu .text-end a {
    display: inline-block;
    padding: 8px 4px;
  }
}

/* ==========================================================================
   移动端底部固定导航栏（tab bar）
   ========================================================================== */
@media (max-width: 767.98px) {
  /* 导航栏高度锁死成变量，页脚按同一个变量留白，两边不会算错 */
  :root {
    --oc-tabbar-h: 58px;
  }

  #mobile-tabbar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1040;
    display: flex;
    height: calc(var(--oc-tabbar-h) + env(safe-area-inset-bottom, 0px));
    background-color: #fff;
    border-top: 1px solid var(--bs-border-color);
    box-shadow: 0 -2px 12px rgba(0, 0, 0, .06);
    /* iPhone 底部小横条的安全区，不加会被遮住一截 */
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }

  #mobile-tabbar .tab-item {
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    height: var(--oc-tabbar-h);
    padding: 6px 2px;
    color: var(--bs-secondary-color);
    text-decoration: none;
    font-size: .65rem;
    line-height: 1.1;
    text-align: center;
    /* "My Account" / "Wish List" 是两个词，不禁止换行会折成两行，
       导航栏被撑高，预留的空间就不够了 */
    white-space: nowrap;
  }

  #mobile-tabbar .tab-item span {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  #mobile-tabbar .tab-item i {
    font-size: 1.15rem;
  }

  #mobile-tabbar .tab-item:hover,
  #mobile-tabbar .tab-item:active {
    color: var(--bs-primary);
  }

  /* 留白放在 footer 上而不是 body 上：
     footer 是最后一个可见元素，它的背景会一直延伸到导航栏下方，
     不会出现「页脚背景断掉、下面一截空白」的割裂感。
     +16px 是内容与导航栏之间的呼吸距离。 */
  /* 见文件末尾「页脚脱离绝对定位」一段，那里统一处理 */
  footer {
    padding-bottom: calc(var(--oc-tabbar-h) + env(safe-area-inset-bottom, 0px) + 16px);
  }
}

/* ==========================================================================
   商品卡片圆角化
   ========================================================================== */

/* --- 卡片本体：圆角 + hover 微浮起 --- */
.product-thumb {
  border: 1px solid var(--bs-border-color);
  border-radius: 14px;
  overflow: hidden;
  background-color: var(--bs-body-bg);
  transition: box-shadow .25s ease, transform .25s ease, border-color .25s ease;
}

.product-thumb:hover {
  border-color: rgba(var(--bs-primary-rgb), .35);
  box-shadow: 0 8px 24px rgba(0, 0, 0, .08);
  transform: translateY(-3px);
}

/* --- 图片区：正方形容器 + 内圆角，图片撑满 --- */
.product-thumb .image {
  margin: 12px;
  padding: 0;
  /* 商品图是白底 JPG 时用 #fff；换成透明 PNG 后可改回 #f5f6f8 显出灰底 */
  background-color: #fff;
  border-radius: 12px;
  overflow: hidden;
  /* 7:9 竖版（336:432）。统一比例才能保证卡片高矮一致；
     后台模块的 Image Width/Height 必须同比例，否则 OpenCart 生成缩略图时
     会按 contain 填白边，和容器比例对不上就会露出白条。 */
  aspect-ratio: 7 / 9;
}

.product-thumb .image a {
  display: block;
  width: 100%;
  height: 100%;
}

.product-thumb .image img {
  width: 100%;
  height: 100%;
  /* contain=完整显示不裁切；想彻底铺满可改成 cover，但会裁掉图片边缘 */
  object-fit: contain;
  border-radius: 0; /* 圆角交给外层容器裁切 */
  transition: transform .3s ease;
}

/* 默认 hover 是整张图变半透明，换成轻微放大 */
.product-thumb .image a:hover {
  opacity: 1;
}

.product-thumb .image a:hover img {
  transform: scale(1.04);
}

/* --------------------------------------------------------------------------
   按钮条改用 flex 贴底，不再绝对定位

   ⚠ 修的是一个真实 bug：价格被按钮条盖住，列表页看不到价格。

   OpenCart 核心（catalog/view/stylesheet/stylesheet.css:388）把按钮条设成
   position:absolute + bottom:0，于是它脱离文档流，需要上面的 .description
   用 margin-bottom 手动"猜"它有多高给它让位。原来猜的是 62px。

   但本主题的按钮条是**两行**（加购一行、快速查看+收藏一行），实测 99px ——
   猜少了 37px。而价格恰好排在描述文字之后、落进这段缺口，
   被后绘制的绝对定位按钮条整个盖住（实测重叠 24px）。
   描述短的商品价格位置高、躲得过去，所以只有部分卡片看不到价格，
   更难被发现。

   把 62 改成 99 只是把魔法数字换一个 —— 以后按钮增减、字号一变又会错。
   改成 flex 贴底之后按钮条回到文档流，高度多少都自动让位，不用任何数字。
   -------------------------------------------------------------------------- */
.product-thumb {
  display: flex;
  flex-direction: column;
}

.product-thumb .content {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
}

/* 描述撑开剩余空间，把它下面的表单（按钮条）顶到底部 */
.product-thumb .content > form {
  margin-top: auto;
}

.product-thumb .button {
  position: static;
}

/* --- 文字区：图片区已有外边距，去掉顶部内边距 --- */
.product-thumb .description {
  padding: 0 18px 12px;
  /* margin-bottom 归零：按钮条已经在文档流里，不需要再给它预留空间 */
  margin-bottom: 0;
}

/* --- 底部按钮条：药丸化 --- */
.product-thumb .button {
  gap: 8px;
  padding: 0 12px 14px;
  background-color: transparent;
}

.product-thumb .button button {
  width: auto;
  border: 1px solid var(--bs-border-color);
  border-radius: 50rem;
  line-height: 36px;
  min-height: 38px;
  transition: background-color .2s ease, color .2s ease, border-color .2s ease;
}

/* 第一个按钮＝加入购物车：图标 + 文字，主题蓝实心，占满剩余宽度 */
.product-thumb .button button:first-child {
  flex: 1 1 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 0 14px;
  white-space: nowrap;
  background-color: var(--brand-ink);
  border-color: var(--brand-ink);
  color: #fff;
}

/* 文字统一白色，防止被其他规则覆盖 */
.product-thumb .button button:first-child .btn-label,
.product-thumb .button button:first-child i {
  color: #fff;
}

/* 收藏 / 对比：只有图标，固定宽度 */
.product-thumb .button button:not(:first-child) {
  flex: 0 0 48px;
}

.product-thumb .button button:first-child:hover {
  background-color: var(--brand-accent);
  border-color: var(--brand-accent);
  color: #fff;
  filter: none;
}

/* 收藏 / 对比：描边按钮，hover 转主题蓝 */
.product-thumb .button button:not(:first-child):hover {
  background-color: var(--bs-tertiary-bg);
  border-color: rgba(var(--bs-primary-rgb), .5);
  color: var(--bs-primary);
}

/* ==========================================================================
   手机端商品列表改两列（<576px）
   featured/latest/special/bestseller 等模块都用
   row-cols-1 row-cols-sm-2 ...，576px 以下只有 row-cols-1 生效＝一行一个。
   限定在 main 内，避免波及头尾部的栅格。
   ========================================================================== */
@media (max-width: 575.98px) {
  /* ⚠ 必须用 :has(.product-thumb) 精确锁定商品栅格。
     早先这里写的是 `main .row-cols-1`，本意是「限定在 main 内不波及头尾部」，
     但结账表单的 row-cols-1 也在 main 里 —— 结果把姓名、城市、国家、电话
     全压成了两列，沟槽还被压到 4px，窄屏上完全没法填。
     .product-thumb 只出现在商品卡里，是最可靠的判据。 */
  main .row-cols-1:has(.product-thumb) > * {
    flex: 0 0 auto;
    width: 50%;
  }

  /* 卡片间距收紧：
     横向来自栅格沟槽（默认 1.5rem＝24px，列两侧各一半）
     纵向来自 featured.twig 里 <div class="col mb-3"> 的 1rem
     Bootstrap 的间距工具类带 !important，覆盖时也要加 */
  main .row-cols-1:has(.product-thumb) {
    --bs-gutter-x: 4px;
    --bs-gutter-y: 0; /* 显式归零，避免 Bootstrap 给 .row > * 加 margin-top */
  }

  main .row-cols-1:has(.product-thumb) > .col {
    margin-bottom: 4px !important;
  }

  /* --- 半宽卡片下的内容瘦身 --- */
  .product-thumb .image {
    margin: 8px;
    /* 与桌面保持同一比例，避免跨断点观感跳变 */
    aspect-ratio: 7 / 9;
  }

  .product-thumb .description {
    padding: 0 10px 8px;
    /* 同上：按钮条已回到文档流，这里也不用再预留 */
    margin-bottom: 0;
  }

  .product-thumb .description h4 {
    font-size: .92rem;
    line-height: 1.3;
    margin-bottom: .35rem;
  }

  /* 描述按你的要求保留，但限制两行，防止卡片高矮不齐 */
  .product-thumb .description p {
    font-size: .78rem;
    line-height: 1.45;
    margin-bottom: .4rem;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }

  .product-thumb .price {
    font-size: .92rem;
  }

  .product-thumb .price-tax {
    font-size: .72rem;
  }

  /* --- 按钮条：半宽放不下 "Add to Cart" 文字，退回纯图标 --- */
  .product-thumb .button {
    gap: 5px;
    padding: 0 8px 10px;
  }

  .product-thumb .button button {
    line-height: 32px;
    min-height: 34px;
  }

  .product-thumb .button button:first-child .btn-label {
    display: none;
  }

  .product-thumb .button button:not(:first-child) {
    flex: 0 0 34px;
  }
}

/* ==========================================================================
   头部 v2 —— Journal 风格
   本段位于文件末尾，同选择器会覆盖上面「手机（<768px）」里的旧规则。
   布局：  [☰] [logo] ........ [👤 ♡ 🛒①]
          [ All Categories ▾ | 搜索…  🔍 ]
   ========================================================================== */
@media (max-width: 767.98px) {
  header .row {
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas:
      "menu   logo   icons"
      "search search search";
    column-gap: 8px;
    row-gap: 10px;
  }

  header .row > #menu-col {
    grid-area: menu;
    justify-self: start;
  }

  header .row > #logo-col {
    grid-area: logo;
    justify-self: start;
  }

  header .row > #header-icons {
    grid-area: icons;
    justify-self: end;
  }

  header .row > #search-col {
    grid-area: search;
  }

  /* --- ☰：去掉蓝底和 Categories 文字，只留汉堡按钮 --- */
  #menu-col > .container {
    padding: 0;
  }

  #menu {
    background-color: transparent;
    background-image: none;
    border: 0;
    border-radius: 0;
    padding: 0;
    min-height: 0;
    height: auto;
    margin-bottom: 0;
  }

  #menu #category {
    display: none;
  }

  #menu .navbar-toggler {
    width: 40px;
    height: 40px;
    border: 0;
    border-radius: 8px;
    color: #212529;
    font-size: 1.3rem;
  }

  /* 汉堡挪到最左后，展开面板仍从容器左边缘铺满 */
  #menu #navbar-menu {
    top: calc(100% + 12px);
  }

  /* --- 右侧图标组 --- */
  #header-icons {
    display: flex;
    align-items: center;
    gap: 2px;
  }

  #header-icons .header-icon {
    width: 40px;
    height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: #212529;
    font-size: 1.15rem;
    text-decoration: none;
  }

  /* --- 购物车：图标 + 角标，取代原来的金额栏 --- */
  #cart,
  #cart > .dropdown {
    width: auto;
    height: auto;
    min-height: 0;
    display: block;
  }

  #cart .btn {
    position: relative;
    width: 40px;
    height: 40px;
    min-height: 0;
    padding: 0;
    border: 0;
    border-radius: 8px;
    background-color: transparent;
    color: #212529;
    font-size: 1.15rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0;
  }

  #cart .btn:hover,
  #cart .btn:active,
  #cart .btn.show {
    background-color: transparent;
    color: var(--bs-primary);
  }

  #cart .cart-text {
    display: none;
  }

  #cart .cart-badge {
    position: absolute;
    top: 1px;
    right: 0;
    min-width: 17px;
    height: 17px;
    padding: 0 4px;
    border-radius: 50rem;
    /* 同底部标签栏角标：统一到品牌粉，不留 Bootstrap 红 */
    background-color: var(--brand-accent);
    color: #fff;
    font-size: .6rem;
    font-weight: 700;
    line-height: 17px;
    text-align: center;
  }

  /* --- 搜索行：分类下拉嵌在胶囊左侧 --- */
  header .input-group > .form-select {
    min-height: 0;
    height: calc(var(--oc-control-h) - 2px);
    width: auto;
    max-width: 42%;
    flex: 0 0 auto;
    border: 0;
    border-right: 1px solid var(--bs-border-color);
    border-radius: 0;
    background-color: transparent;
    box-shadow: none;
    padding: 0 26px 0 16px;
    font-size: .82rem;
  }

  header .input-group > .form-control {
    padding-left: 12px;
  }

  /* logo 紧贴汉堡，尺寸再收一点给右侧图标让位 */
  #logo img {
    max-width: 120px;
  }
}

/* 桌面端：购物车仍显示金额文字，不显示角标 */
@media (min-width: 768px) {
  #cart .cart-badge {
    display: none;
  }
}

/* ==========================================================================
   头部 v3 —— 两行结构（覆盖上面 v1/v2 的同名规则）
     第一行：[☰] [logo] ……… [$ ▾] [🏳 ▾]
     第二行：[ All Categories ▾ │ 搜索…  🔍 ]
   账户/心愿单/购物车全部下放到底部导航栏
   ========================================================================== */
@media (max-width: 767.98px) {
  /* 原顶栏（电话/账户/心愿单/购物车/结账）整条隐藏 */
  #top {
    display: none;
  }

  header {
    padding: 10px 0 14px;
  }

  header .row {
    /* 第四列给吸顶后出现的搜索图标（未吸顶时该格 display:none，宽度归零），
       第五列给顶部购物车 —— 最右侧是找购物车的通用约定位置 */
    grid-template-columns: auto minmax(0, 1fr) auto auto auto auto;
    grid-template-areas:
      "menu   logo   coa    tools  find   cart"
      "search search search search search search";
    column-gap: 6px;
    row-gap: 10px;
  }

  header .row > #mobile-cart-slot {
    grid-area: cart;
    justify-self: end;
  }

  header .row > #menu-col {
    grid-area: menu;
    justify-self: start;
  }

  header .row > #logo-col {
    grid-area: logo;
    justify-self: start;
  }

  header .row > #header-coa-slot {
    grid-area: coa;
    justify-self: end;
  }

  header .row > #header-tools {
    grid-area: tools;
    justify-self: end;
    display: flex;
    align-items: center;
    gap: 10px;
  }

  header .row > #search-col {
    grid-area: search;
  }

  /* 购物车模块留在 DOM 里（加购 AJAX 的目标是 #cart），但手机不显示，
     件数由底部导航栏的角标镜像展示 */
  header .row > #cart {
    display: none;
  }

  #header-tools .tool-item .dropdown-toggle {
    font-size: .9rem;
    color: #212529;
    white-space: nowrap;
  }

  #header-tools .tool-item img {
    vertical-align: -2px;
  }

  /* logo 紧贴汉堡 */
  #logo img {
    max-width: 128px;
  }
}

/* --- 底部导航栏的购物车角标 --- */
@media (max-width: 767.98px) {
  #mobile-tabbar .tab-item {
    position: relative;
  }

  #mobile-tabbar .tab-cart-badge {
    position: absolute;
    top: 4px;
    left: 50%;
    margin-left: 3px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: 50rem;
    /* 原来是 Bootstrap 红 #dc3545。红色在本站是「错误/警告」语义，
       购物车件数不是错误，统一到强调色。 */
    background-color: var(--brand-accent);
    color: #fff;
    font-size: .58rem;
    font-weight: 700;
    line-height: 16px;
    text-align: center;
  }
}

/* ==========================================================================
   头部 v3.1 —— ☰ 去蓝底 / 去 Categories 文字
   与 v2 段重复，但加 !important 并置于文件末尾，确保压过一切先前规则
   （含核心 stylesheet.css:191 的 #menu 蓝底渐变）
   ========================================================================== */
@media (max-width: 767.98px) {
  #menu-col > .container {
    padding: 0 !important;
    width: auto !important;
  }

  #menu {
    background-color: transparent !important;
    background-image: none !important;
    border: 0 !important;
    border-radius: 0 !important;
    padding: 0 !important;
    min-height: 0 !important;
    height: auto !important;
    margin-bottom: 0 !important;
    box-shadow: none !important;
  }

  /* "Categories" 文字不显示，只留汉堡按钮 */
  #menu #category {
    display: none !important;
  }

  #menu .navbar-toggler {
    width: 40px !important;
    height: 40px !important;
    padding: 0 !important;
    border: 0 !important;
    border-radius: 8px !important;
    background-color: transparent !important;
    color: #212529 !important;
    font-size: 1.3rem !important;
  }

  #menu .navbar-toggler:focus {
    box-shadow: none !important;
  }
}

/* ==========================================================================
   头部 v3.2
   ① ☰ 换成内联 SVG（不依赖 FontAwesome，颜色可控，永远看得见）
   ② 币种/语言：桌面留在顶栏，手机由 JS 搬进 logo 行（见 footer.twig）
   ========================================================================== */

/* --- 币种/语言工具组 ---
   桌面端保持官方的 ul.list-inline 结构不动，
   核心样式表的 #top .list-inline-item .dropdown > span { line-height: 40px }
   会自然生效，与右侧图标同基线。这里只处理被搬到手机端后的样式。 */

/* --- ☰ 汉堡：用 SVG 背景图，隐藏原来的 FontAwesome 图标 --- */
@media (max-width: 767.98px) {
  #menu .navbar-toggler i {
    display: none !important;
  }

  #menu .navbar-toggler {
    background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23212529'%20stroke-width='2'%20stroke-linecap='round'%3E%3Cpath%20d='M4%207h16M4%2012h16M4%2017h16'/%3E%3C/svg%3E") !important;
    background-repeat: no-repeat !important;
    background-position: center !important;
    background-size: 24px 24px !important;
  }

  /* 手机端顶栏整条隐藏，但 JS 会把工具组搬出来，所以它自己要能显示 */
  #top {
    display: none !important;
  }

  #header-tools-slot {
    grid-area: tools;
    justify-self: end;
  }

  /* 被 JS 搬出 #top 之后，核心那套 #top .list-inline-item 规则不再匹配，
     所以手机端要自己给一套 */
  #header-tools {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 0;
    padding-left: 0;
    list-style: none;
  }

  #header-tools .list-inline-item {
    margin-right: 0 !important;
  }

  #header-tools .dropdown-toggle {
    font-size: .88rem;
    line-height: 1;
    color: #212529;
    white-space: nowrap;
    padding: 0;
  }

  #header-tools img {
    vertical-align: -2px;
  }
}

/* ==========================================================================
   手机端：页脚脱离绝对定位 + 购物车表格改卡片式
   ========================================================================== */
@media (max-width: 767.98px) {
  /* ① 页脚脱离绝对定位的修复已提升为全局（见文末“页脚与页面高度”一节）。
     这里只保留手机端的底部内边距——比桌面紧凑一些。 */
  #content,
  #column-left,
  #column-right {
    padding-bottom: 24px;
  }

  /* ②③④ 原先在这里的购物车手机版规则已删除。
     那一套是把 <table> 的 tbody/tr/td 改成 display:block、
     缩略图用 position:absolute 钉在卡片左上角、卡片写死 padding-left:94px
     来「伪装」成卡片。购物车改成真正的 grid 卡片后（见文末“购物车”一节），
     #output-cart 里已经没有 table 了，这些选择器全部失效。 */

}

/* ==========================================================================
   移除商品对比功能
   卡片上的 ⇄ 按钮已从 thumb.twig 覆盖版里删掉；
   分类页/搜索页/特价页/品牌页顶部的「Product Compare (N)」按钮在此隐藏。
   两处都去掉才不会出现「点不了对比、却还有个对比入口」的割裂。
   ========================================================================== */
#compare-total {
  display: none !important;
}

/* 对比按钮原本占据的那一列，收掉后让工具栏其余部分自然铺开 */
#product-list .col-md-2:has(> #compare-total),
#product-search .col-md-2:has(> #compare-total) {
  display: none;
}

/* ==========================================================================
   两列卡片恢复显示 "Add to Cart" 文字
   之前隐藏是因为卡片里有 3 个按钮（加购/收藏/对比），加购按钮只剩约 80px；
   对比按钮删掉后剩 2 个，宽度够了。
   375px 屏实测：卡片内宽约 155px − 收藏 32px − 间距 5px = 加购约 118px，
   图标 12 + 间距 4 + 文字约 63 + 内边距 12 ≈ 91px，放得下。
   ========================================================================== */
@media (max-width: 575.98px) {
  .product-thumb .button button:first-child .btn-label {
    display: inline;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .product-thumb .button button:first-child {
    font-size: .72rem;
    padding: 0 6px;
    gap: 4px;
    overflow: hidden;
  }

  .product-thumb .button button:first-child i {
    font-size: .8rem;
    flex: 0 0 auto;
  }

  /* 收藏按钮再收窄一点，把宽度让给文字 */
  .product-thumb .button button:not(:first-child) {
    flex: 0 0 32px;
  }
}

/* ==========================================================================
   手机端页脚：四个分组排成 2×2，左右贴边
       Information        My Account
       Customer Service   Extras
   DOM 顺序是 Information → Customer Service → Extras → My Account，
   靠 flex order 把 My Account 提到第 2 位、其余顺延。
   （用 id 而不是 :nth-child —— Information 分组外面套了
     {% if informations or blog %}，没有文章和信息页时整块不渲染，
     nth-child 的序号会整体错位。）
   ========================================================================== */
@media (max-width: 575.98px) {
  footer .row {
    display: flex;
    flex-wrap: wrap;
    row-gap: 4px;
  }

  footer .row > div {
    width: 50%;
    flex: 0 0 50%;
    max-width: 50%;
  }

  /* 公司信息块独占整行，排在四个链接分组之前。
     内部再切两栏：左边 logo + 联系方式，右边信任声明 ——
     右半边原来一直是空的。 */
  #footer-company {
    width: 100%;
    flex: 0 0 100%;
    max-width: 100%;
    order: 0;
    margin-bottom: 8px;

    display: grid;
    /* minmax(0,…) 是必须的：网格列默认 min-width:auto，
       地址那种长串会把列撑破，右栏被挤没。 */
    grid-template-columns: minmax(0, 1fr) minmax(0, 44%);
    column-gap: 16px;
    align-items: start;
  }

  #footer-company .fc-main {
    min-width: 0;
  }

  /* 和 logo 顶部对齐，而不是跟着上面的 margin 往下掉 */
  #footer-company .fc-trust {
    margin-top: 4px;
  }

  #footer-company .fc-trust li {
    font-size: .8rem;
    margin-bottom: 13px;
  }

  #footer-information {
    order: 1;
  }

  /* 两列都左对齐。链接列表右对齐会造成左边缘参差（ragged left），
     每行起点不同，视线扫描时没有稳定锚点，明显更难读。
     「靠右」由布局位置（占据右半栏）实现，不靠文字对齐。 */
  #footer-account {
    order: 2;
    padding-left: 14px;
  }

  #footer-service {
    order: 3;
  }

  #footer-extra {
    order: 4;
    padding-left: 14px;
  }
}

/* ==========================================================================
   页脚法定信息区：公司名 / 注册地址 / 邮箱 / 版权行
   结构见 footer.twig 覆盖版的 .footer-legal
   ========================================================================== */
footer .footer-legal {
  text-align: center;
  padding-bottom: 4px;
}

footer .footer-company {
  margin-bottom: 8px;
  font-size: .85rem;
  line-height: 1.75;
  color: #b0b0b0;
}

footer .footer-company a {
  color: #ccc;
  text-decoration: underline;
}

footer .footer-company a:hover {
  color: #fff;
}

footer .footer-copyright {
  margin-bottom: 0;
  font-size: .85rem;
  color: #d0d0d0;
}

/* ==========================================================================
   页脚公司信息块
   桌面在最左一列，手机端占满整行并排在链接分组之前
   ========================================================================== */
#footer-company .footer-contact {
  margin-bottom: 0;
}

#footer-company .footer-contact li {
  display: flex;
  gap: 8px;
  margin-bottom: 10px;
  font-size: .88rem;
  line-height: 1.65;
  color: #b8b8b8;
}

#footer-company .footer-contact i {
  flex: 0 0 14px;
  margin-top: 5px;
  font-size: .82rem;
  color: #8f8f8f;
}

#footer-company .footer-contact a {
  color: #ccc;
  text-decoration: underline;
}

#footer-company .footer-contact a:hover {
  color: #fff;
}

/* 页脚 Logo —— 深色底上如果 logo 是深色的，用 brightness 提亮兜底 */
#footer-logo {
  margin-bottom: 12px;
}

#footer-logo img {
  max-width: 170px;
  height: auto;
}

@media (max-width: 575.98px) {
  #footer-logo img {
    max-width: 140px;
  }
}


/* ==========================================================================
   博客模块 —— 特色文章 + 侧列
   模板：extension/ocmod/.../module/blog.twig（两份）
   左 60% 一篇大图文章，右 40% 最多三篇横向小卡。
   不复用客户评价的品字型：博客有时间序，最新一篇需要独占首要位置。
   ========================================================================== */
.blog-module {
  margin-bottom: 28px;
}

/* 标题居中 + 副标题，与 Images Gallery / 客户评价对齐同一套版式 */
.blog-head {
  text-align: center;
  margin-bottom: 26px;
}

.blog-head h3 {
  margin: 0;
  font-size: clamp(1.6rem, 3vw, 2.6rem);
  font-weight: 600;
  letter-spacing: -0.01em;
}

.blog-head p {
  margin: 10px 0 0;
  color: var(--brand-muted);
}

.blog-layout {
  display: grid;
  grid-template-columns: 1.5fr 1fr;   /* 约 60 / 40 */
  gap: 28px;
  align-items: start;
}

/* --- 左侧：特色文章 --- */
.blog-feature .blog-media {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: var(--oc-radius);
}

.blog-feature .blog-media img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  transition: transform .6s cubic-bezier(.22, .61, .36, 1);
}

.blog-feature .blog-media:hover img {
  transform: scale(1.04);
}

/* 日期徽章 */
.blog-date {
  position: absolute;
  top: 14px;
  left: 14px;
  min-width: 52px;
  padding: 8px 6px;
  border-radius: 8px;
  background-color: var(--brand-accent);
  color: #fff;
  text-align: center;
  line-height: 1.1;
}

.blog-date strong {
  display: block;
  font-size: 1.15rem;
  font-weight: 700;
}

.blog-date small {
  display: block;
  font-size: .68rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  opacity: .9;
}

.blog-feature .blog-body {
  padding-top: 16px;
}

.blog-feature .blog-body h4 {
  margin: 0 0 10px;
  font-size: clamp(1.15rem, 1.6vw, 1.5rem);
  line-height: 1.3;
}

.blog-feature .blog-body h4 a {
  color: var(--brand-ink);
}

.blog-feature .blog-body h4 a:hover {
  color: var(--brand-accent-deep);
}

.blog-feature .blog-body p {
  margin: 0 0 14px;
  font-size: .92rem;
  line-height: 1.7;
  color: var(--brand-muted);
}

.blog-more {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: .875rem;
  font-weight: 600;
  letter-spacing: .01em;
  text-transform: none;
  color: var(--brand-accent-deep);
}

.blog-more i {
  font-size: .7rem;
  transition: transform .2s ease;
}

.blog-more:hover i {
  transform: translateX(3px);
}

/* --- 右侧：小卡列表 --- */
.blog-side {
  display: flex;
  flex-direction: column;
  gap: 18px;
}

/* 小卡加浅色底 + 内边距，成为真正的卡片而不是裸列表项 ——
   这是"看起来更大"最有效的一步，比单纯拉宽缩图有用。
   align-items:center 让图与文字块在高度不等时也保持居中。 */
.blog-mini {
  display: flex;
  gap: 16px;
  align-items: center;
  padding: 14px;
  background-color: var(--brand-surface);
  border-radius: var(--oc-radius);
  transition: box-shadow .25s ease, transform .25s ease;
}

.blog-mini:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 18px rgba(0, 0, 0, .07);
}

.blog-mini-media {
  flex: 0 0 190px;
  display: block;
  overflow: hidden;
  border-radius: 8px;
}

.blog-mini-media img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  transition: transform .5s ease;
}

.blog-mini:hover .blog-mini-media img {
  transform: scale(1.06);
}

.blog-mini-body {
  min-width: 0;
}

.blog-mini-date {
  display: block;
  font-size: .7rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--brand-muted);
  margin-bottom: 5px;
}

.blog-mini-body h5 {
  margin: 0;
  font-size: 1.05rem;
  line-height: 1.4;
}

.blog-mini-body h5 a {
  color: var(--brand-ink);
}

.blog-mini-body h5 a:hover {
  color: var(--brand-accent-deep);
}

/* 摘要只出一行。line-clamp 需要配合 display:-webkit-box 才生效，
   这三条是一套，缺一不可（-webkit- 前缀在所有现代浏览器里都仍是标准写法）。 */
.blog-mini-text {
  margin: 6px 0 8px;
  font-size: .84rem;
  line-height: 1.55;
  color: var(--brand-muted);
  display: -webkit-box;
  -webkit-line-clamp: 1;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.blog-more-sm {
  font-size: .7rem;
  letter-spacing: .06em;
}

/* --- 平板及以下：两栏塌成单栏 --- */
@media (max-width: 767.98px) {
  .blog-layout {
    grid-template-columns: 1fr;
    gap: 22px;
  }

  .blog-feature .blog-media img {
    aspect-ratio: 16 / 10;   /* 单栏时大图不必那么高 */
  }

  /* 小卡多了摘要和按钮，文字区需要更多宽度，缩图相应收到 38% */
  .blog-mini-media {
    flex: 0 0 min(150px, 38%);
  }

  .blog-mini {
    padding: 12px;
    gap: 12px;
  }
}

/* ==========================================================================
   桌面端商品网格：每行 4 个 → 3 个
   图片改成 7:9 竖版后，4 列时每张图只有约 282px 宽（和原来 280 几乎没差别），
   等于白改。3 列才能把单图放大到目标尺寸：
     1140px 容器 ÷ 3 − 沟槽 ≈ 356px 列宽 → 图约 332px 宽 × 427px 高 ≈ 336×432 ✓
     1320px 容器下会更大，属于自适应放大，不影响比例。
   商品模块（featured/latest/special/bestseller）用的都是 row-cols-xl-4；
   博客模块是 row-cols-xl-3，不受影响。
   ========================================================================== */
@media (min-width: 1200px) {
  main .row-cols-xl-4 > * {
    width: 33.33333333%;
  }
}

/* ==========================================================================
   顶部公告条
   ========================================================================== */
#announcement-bar {
  position: relative;
  background-color: #6b2130;
  color: #fff;
  text-align: center;
  font-size: .85rem;
  letter-spacing: .01em;
  padding: 10px 44px;
}

/* 三条文案叠在一起，靠 .is-active 淡入淡出，容器高度固定不跳动 */
.announcement-track {
  position: relative;
  height: 1.3em;
}

.announcement-item {
  position: absolute;
  left: 0;
  right: 0;
  opacity: 0;
  transition: opacity .5s ease;
  pointer-events: none;
}

.announcement-item.is-active {
  opacity: 1;
}

.announcement-close {
  position: absolute;
  top: 50%;
  right: 12px;
  transform: translateY(-50%);
  width: 26px;
  height: 26px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background-color: transparent;
  color: rgba(255, 255, 255, .75);
  font-size: 1.2rem;
  line-height: 1;
  transition: color .2s ease, background-color .2s ease;
}

.announcement-close:hover {
  color: #fff;
  background-color: rgba(255, 255, 255, .15);
}

/* ==========================================================================
   首页轮播图：通栏满屏 + 按屏幕高度自适应
   .banner-hero 由模板打上（items==1 且模块宽度 >= 1200）。
   不能只看 items==1 —— 分类页侧栏的小横幅也是 items=1，
   靠尺寸阈值才能把它和真正的通栏英雄图分开。
   ========================================================================== */
.banner-hero {
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-bottom: 36px;
}

.banner-hero .carousel-item > .row {
  margin-left: 0;
  margin-right: 0;
}

.banner-hero .carousel-item > .row > [class*="col-"] {
  padding-left: 0;
  padding-right: 0;
}

/* 英雄图完整显示，任何宽度都不裁。

   ── 之前为什么会裁（两种，方向还相反）────────────────────────────
   原来这里是 height: clamp(300px, 40vw, 620px) + object-fit: cover。
   那意味着显示框的比例随视口变，而图是固定的 3.10:1，
   只有 1920 这一个宽度上两者恰好相等：
       1280 → 框 1280x512（2.50:1）比图窄 → 横向只剩 81%，左右被切
       1440 → 框 1440x576（2.50:1）        → 同上 81%
       1920 → 框 1920x620（3.10:1）        → 刚好，100%
       2000 → 高度被 620 卡住、宽度还在长  → 框变得比图更宽，
                                             改成上下被切，纵向 96%
       2560 → 同理，纵向只剩 75%
   也就是说除了 1920，所有屏幕看到的都不是完整的图。

   ── 为什么不是「后台传更大的图」能解决的 ──────────────────────────
   ⚠ 换更大的源图只会把「唯一正确的那个宽度」挪到别处，其余照裁。
     裁切发生在显示框这一层，和源文件分辨率无关。

   ── 现在的做法 ────────────────────────────────────────────────
   height: auto —— 框的比例由 <img> 的 width/height 属性决定，
   而那两个属性来自后台模块配置（见 banner.twig）。
   于是框永远等于图的比例，cover 无从下手，100% 完整。
   在后台改模块尺寸时这里不用跟着改。

   代价：高度随宽度等比长。1440 → 465px，1920 → 620px，2560 → 827px。
   超宽屏嫌高的话，给这条加 max-width: 1920px + margin-inline: auto，
   1920 以上就不再长、居中留边。 */
/* ⚠ 限定 .banner-bg（背景图自己）。叠层里现在也有 <img>
   （第三方实验室 logo），写成裸 img 会把它们一起拉成满宽 ——
   这几条是在「一个格子里只有一张图」的年代写的。 */
.banner-hero .carousel-item > .row > [class*="col-"] img.banner-bg {
  display: block;
  width: 100%;
  height: auto;
  /* 比例已经对齐，cover 裁不到东西；留着是防手改坏比例时兜底 */
  object-fit: cover;
}


/* 100vw 会比可视区宽出一个滚动条的宽度，用 clip 兜住。
   clip 不像 hidden 那样创建滚动容器，不会影响内部绝对定位元素 */
main {
  overflow-x: clip;
}

/* ==========================================================================
   桌面端分类栏扁平化（手机端之前已处理，这里补上桌面）
   去掉 stylesheet.css:191 那套 2013 年的拟物渐变
   ========================================================================== */
@media (min-width: 768px) {
  #menu {
    background-image: none;
    border-color: transparent;
    border-radius: var(--oc-radius);
    box-shadow: none;
  }
}

/* ==========================================================================
   品牌配色 —— 白底 + 单一冷色强调
   本段必须放在文件最末尾，靠加载顺序压制 bootstrap.css 与 stylesheet.css。

   三条规则，改色时不要破坏：

   1) 红色是标志色，不是界面色。
      logo 红 #C8102E 只出现在 logo 和促销角标。医疗界面里红色已经被
      「错误 / 警告 / 过敏」占用，拿它当主色等于把出事信号铺满全站。

   2) 交互色只有一个：--brand-accent。
      按钮、链接、选中态、焦点环全部用它，不再有第二个强调色。

   3) 中性色走冷调（色相 ~210°）。
      原方案是暖粉灰（#7A6E73 等），配冷蓝主色会发脏。

   避开的颜色：
   - NHS 蓝 #005EB8 —— 英国私营机构靠太近会被认为暗示 NHS 背书。
     本主色 ΔE=38.7，安全；常见企业蓝 #0079C8 只有 14.9，别用。
   - 红十字 —— 英国《1957 年日内瓦公约法》保护，商用违法。图标别画十字。
   - 绿十字 —— 英国药房法定标识，用了等于宣称自己是 GPhC 注册药房。
   - 洋红 #ED1E79 —— 健康语境下会被读成乳腺癌粉丝带，与本店无关。
   ========================================================================== */
:root {
  /* ---------- 字体 ---------- */
  /* 全站一个字体，靠字重和字号分层级，不再有「标题衬线 + 正文无衬线」的对比。
     Inter 没有中文字形，中文会落到后面的 PingFang / 微软雅黑，不会出豆腐块。
     Arial 兜底放在 sans-serif 之前，保证最老的环境也有确定结果。 */
  --brand-font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
                "Helvetica Neue", "PingFang SC", "Hiragino Sans GB",
                "Microsoft YaHei", Arial, sans-serif;

  /* ---------- 中性色（冷调，色相 ~210°） ---------- */
  --brand-bg: #FFFFFF;
  --brand-surface: #F4F7F9;       /* 冷白块面，取代 Bootstrap 的 #F8F9FA */
  --brand-surface-rgb: 244, 247, 249;
  --brand-line: #DCE3E8;          /* 装饰分隔线。1.30:1，纯装饰不受对比度约束 */
  /* 控件边框专用，必须比装饰线深得多。
     WCAG 1.4.11：边框若是输入框唯一的边界提示，须对白底 >= 3:1。
     #7E8B96 = 白底 3.49:1、surface 上 3.24:1，两处都有余量。
     不要拿 --brand-line 去描输入框，那个值只有 1.30:1。 */
  --brand-line-strong: #7E8B96;
  --brand-ink: #16212B;           /* 正文。带一丝蓝的黑，白底 16.32:1 */
  --brand-muted: #5B6B78;         /* 次要文字、面包屑、旧价。白底 5.50:1 */
  /* 大块暗色「面」：页脚。
     与 ink 分开是因为两者诉求相反 —— 正文色要柔和，
     而暗色面必须暗到不高于照片的黑，否则夹在深色轮播图下方会显成横带。 */
  --brand-dark: #0D1520;

  /* ---------- 交互色（全站唯一强调色） ---------- */
  /* 深临床蓝。白字压它 7.43:1，它压白底 7.43:1 —— 按钮和链接同一个值即可，
     不必像旧方案那样再单独准备一个「深一档的链接色」。 */
  --brand-accent: #0B5C7A;
  --brand-accent-rgb: 11, 92, 122;  /* rgba() 焦点环用，改色时这里要跟着改 */
  --brand-accent-deep: #084459;   /* 悬停 / 按下。白字 10.60:1 */
  --brand-tint: #E8F1F5;          /* 选中态浅底。主色压它 6.49:1 */
  --brand-tint-line: #B9D3E0;     /* 选中态边框 */

  /* ---------- 语义色 ---------- */
  /* 促销红 = logo 红。给品牌红一个明确职务：只出现在折扣角标和促销价，
     不进按钮、不进链接、不铺块面。白字压它 5.88:1，它压白底 5.88:1。 */
  --brand-sale: #C8102E;
  /* 「安全 / 已验证」专用绿。全站三处（支付通道名、卡表单加密标记、
     信任区 Trusted Store）共用，避免出现三种深浅不一的绿。
     白底 5.03:1、选中底 4.80:1，都过 WCAG AA。
     更亮的一档见 --secure-green-bright。
     与主蓝在红绿色盲下 ΔE >= 28，不会混淆。 */
  --secure-green: #157F4C;
  /* 同一族的「亮一档」版本。目前只有手机头部的 COA 入口用它 ——
     那三个字母要在一排黑图标里跳出来，#157F4C 掺了灰（R=21）显得沉。
     #00853F 是 R=0 的全饱和绿，白底 4.74:1，是**还能过 AA 的最亮的一档**：
       #008A45 → 4.45:1，差一点；
       #00A651 → 3.19:1；
       #22C55E → 2.28:1（常见的「亮绿」，三个小字母用它基本看不清）。
     ⚠ 想再亮就只能配深色底或加大字号，别直接改这个值。
     悬停/按下回落到 --secure-green（亮度更低），是同族的加深不是换色。 */
  --secure-green-vivid: #00853F;
  /* 再亮一档，白底 3.21:1 —— 只够「大号文字」和「图形」用（都是 3:1 门槛），
     ⚠ 不要拿它写正文或小字，那里要 4.5:1，用 --secure-green-vivid。
     现在的用处：COA 页那个 H1 尺寸的证书计数、以及信任区的盾牌图形。 */
  --secure-green-bright: #1FA463;
  /* 评分星。原来的 #C0A062 对白底只有 2.49:1，达不到「有信息含义的图形」
     所需的 3:1。#A67C1F 是 3.80:1。 */
  --brand-star: #A67C1F;

  /* ---------- 接管 Bootstrap 色板，组件不用逐个改 ---------- */
  --bs-primary: var(--brand-accent);
  --bs-primary-rgb: var(--brand-accent-rgb);
  --bs-body-color: var(--brand-ink);
  --bs-border-color: var(--brand-line);
  --bs-tertiary-bg: var(--brand-surface);
  --bs-link-color: var(--brand-accent);
  --bs-link-hover-color: var(--brand-accent-deep);
  /* bootstrap.css:345 的 a{} 读的是 -rgb 版本，只改上面两个是无效的 */
  --bs-link-color-rgb: var(--brand-accent-rgb);
  --bs-link-hover-color-rgb: var(--brand-accent-rgb);
  --bs-secondary-color: var(--brand-muted);
  --bs-body-font-family: var(--brand-font);
}

/* stylesheet.css:7 直接写死了 body{color:#444}，变量覆盖不到，必须显式重写 */
body {
  font-family: var(--brand-font);
  color: var(--brand-ink);
  background-color: var(--brand-bg);
}

/* --------------------------------------------------------------------------
   标题
   全站同一个字体，标题只靠字重（600）和轻微收紧的字距区分。
   -0.011em 是给 Inter 这类大 x-height 的 UI 无衬线用的：
   大字号下默认字距会显松，收一点才紧实；正文不要跟着收。
   -------------------------------------------------------------------------- */
h1, h2, h3, h4,
.h1, .h2, .h3, .h4,
#logo h1,
#content > h1,
.blog-body h4,
.blog-head h3 {
  font-family: var(--brand-font);
  font-weight: 600;
  letter-spacing: -0.011em;
}

/* 导航与按钮：句首大写、正常字距。
   原来是「小字号 + 宽字距 + 全大写」——那是美妆/时装站的排版腔调，
   医疗零售要的是一眼读完。去掉大写后同样的字宽能装更多字，
   所以字号从 .8rem 提到 .9rem，整体占位反而比原来窄。

   ⚠ 微型标签不在此列：表单 label、状态角标、表头、eyebrow 文字
   仍然保持大写 —— 那是通用 UI 惯例，不是美妆特征。 */
#menu .navbar-nav > li > a,
.btn,
.announcement-item {
  letter-spacing: 0;
  text-transform: none;
  font-size: .9rem;
  font-weight: 500;
}

/* 商品标题不参与全大写，否则长名字会糊成一片 */
.product-thumb .description h4,
.product-thumb h4 {
  text-transform: none;
  letter-spacing: 0;
}

/* --------------------------------------------------------------------------
   顶部三条横带：公告条 / 工具栏 / 导航
   -------------------------------------------------------------------------- */
#announcement-bar {
  /* 试过用强调色，铺满一条通栏后颜色浓度压过了下面的内容 ——
     强调色只适合小面积点缀。这里回到 ink。 */
  background-color: var(--brand-ink);
}

#top {
  background-color: var(--brand-surface);
  border-bottom-color: var(--brand-line);
}

header {
  border-bottom-color: var(--brand-line);
}

/* 桌面端：整条蓝色横带去掉，换成白底 + 上下发丝线。
   这一步是本次改动里视觉提升最大的一条 —— 导航条不该是页面上最重的色块 */
@media (min-width: 768px) {
  #menu {
    background-color: transparent;
    background-image: none;
    border: 0;
    border-top: 1px solid var(--brand-line);
    border-bottom: 1px solid var(--brand-line);
    border-radius: 0;
    box-shadow: none;
    padding: 0;
  }

  #menu .navbar-nav > li > a {
    color: var(--brand-ink);
    text-shadow: none;              /* 原来是给深色底用的，白底上会发虚 */
    padding: 14px 18px;
    border-bottom: 2px solid transparent;
    transition: color .2s ease, border-color .2s ease;
  }

  #menu .navbar-nav > li > a:hover,
  #menu .navbar-nav > li > a:focus,
  #menu .navbar-nav > li.show > a {
    background-color: transparent;  /* 原来是 rgba(0,0,0,.1) 的灰块，白底上很脏 */
    color: var(--brand-accent);
    border-bottom-color: var(--brand-accent);
  }
}

/* 手机端：Categories 仍是独立药丸，底色跟右侧购物车按钮统一成 ink。
   白字规则在前面的移动端区块里已经写好，这里只换底色 */
@media (max-width: 767.98px) {
  #menu {
    background-color: var(--brand-ink);
  }
}

/* --------------------------------------------------------------------------
   按钮
   主按钮用 ink 而不是强调色 —— 极简派的做法是把彩色额度全留给产品图
   -------------------------------------------------------------------------- */
.btn-primary,
.btn-dark {
  --bs-btn-color: #fff;
  --bs-btn-bg: var(--brand-ink);
  --bs-btn-border-color: var(--brand-ink);
  --bs-btn-hover-color: #fff;
  --bs-btn-hover-bg: var(--brand-accent);
  --bs-btn-hover-border-color: var(--brand-accent);
  --bs-btn-active-color: #fff;
  --bs-btn-active-bg: var(--brand-accent);
  --bs-btn-active-border-color: var(--brand-accent);
  --bs-btn-focus-shadow-rgb: var(--brand-accent-rgb);
}

.btn-outline-secondary {
  --bs-btn-color: var(--brand-ink);
  --bs-btn-border-color: var(--brand-line);
  --bs-btn-hover-color: #fff;
  --bs-btn-hover-bg: var(--brand-ink);
  --bs-btn-hover-border-color: var(--brand-ink);
}

/* 表单控件的边框必须比装饰线深得多。
   WCAG 1.4.11：界面组件的边界对相邻颜色要有 3:1。
   --brand-line (#DCE3E8) 对白底只有 1.30:1 —— 那个值只够做装饰分隔线，
   拿它描输入框等于没有边界，低视力用户看不到输入区在哪。
   --brand-line-strong (#7E8B96) 白底 3.49:1、surface 上 3.24:1。
   注意：header 里的搜索框是胶囊造型，边框由外层 .input-group 承载，
   内部 .form-control 的 border:0 特异度更高，不受这条影响。 */
.form-control,
.form-select,
.form-check-input,
.input-group-text {
  border-color: var(--brand-line-strong);
}

/* 表单聚焦：bootstrap.css 里写死了蓝色描边和光晕 */
.form-control:focus,
.form-select:focus {
  border-color: rgba(var(--brand-accent-rgb), .5);
  box-shadow: 0 0 0 .2rem rgba(var(--brand-accent-rgb), .15);
}

/* --------------------------------------------------------------------------
   价格与评分
   -------------------------------------------------------------------------- */
.price {
  color: var(--brand-ink);
}

.price-new {
  color: var(--brand-sale);
}

.price-old {
  color: var(--brand-muted);
}

.fa-star, .fa-star-half-stroke,
.rating .fa-stack .fa-star {
  color: var(--brand-star);
}

/* --------------------------------------------------------------------------
   页脚：stylesheet.css:300 的 #303030 偏冷，统一到 ink
   -------------------------------------------------------------------------- */
footer {
  background-color: var(--brand-ink);
  border-top-color: var(--brand-ink);
  color: rgba(255, 255, 255, .75);
}

footer a,
footer a:visited {
  color: rgba(255, 255, 255, .75);
}

footer a:hover {
  color: #fff;
}

footer h5 {
  color: #fff;
  letter-spacing: .06em;
  text-transform: uppercase;
  font-size: .8rem;
}

/* --------------------------------------------------------------------------
   剩余冷灰扫尾：这些是 stylesheet.css 里零散写死的 #ddd / #eee / #e5e5e5
   单独看不明显，全站累积起来就是"发青"的来源
   -------------------------------------------------------------------------- */
.list-group-item,
.thumbnails > li img,
.image-additional,
.table,
.table th,
.table td,
.card,
.dropdown-menu {
  border-color: var(--brand-line);
}

.breadcrumb,
.breadcrumb a {
  color: var(--brand-muted);
}

/* 分区背景（Bootstrap 的 .bg-light 到处都在用） */
.bg-light {
  background-color: var(--brand-surface) !important;
}

/* 手机端展开的分类面板不跟着全大写 —— 那里是一列长分类名，
   全大写会明显拖慢阅读速度，桌面横排导航才适合大写 */
@media (max-width: 767.98px) {
  #menu #navbar-menu .nav-link,
  #menu #navbar-menu .dropdown-item {
    text-transform: none;
    letter-spacing: 0;
    font-size: .95rem;
  }
}

/* ==========================================================================
   Banner 模块的文字叠层
   靠根元素上的 data-items 分流三种形态：
     1 = 首页大轮播（通栏，大字）
     2 = 促销双图块（并排，中字）
     其他 = 图册等，不出叠层
   文案来自后台 banner 的 Title 字段，约定：主标题|副标题|按钮文字
   ========================================================================== */
.banner-tile {
  position: relative;
  display: block;
  overflow: hidden;
  text-decoration: none;
}

.banner-tile img.banner-bg {
  display: block;
  width: 100%;
  transition: transform .6s cubic-bezier(.22, .61, .36, 1);
}

/* ⚠ 只有**可点**的横幅才放大。
   .banner-tile 这个类同时用在 <a>（有链接）、<button>（图册灯箱）
   和 <span>（没链接）上。首页英雄图通常没链接，是个 <span> ——
   鼠标移上去放大，却点了没反应，是假的交互暗示。
   加上元素选择器之后，<span> 不再响应。 */
a.banner-tile:hover img.banner-bg,
button.banner-tile:hover img.banner-bg {
  transform: scale(1.04);
}

.banner-copy {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  text-align: left;
  padding: 0 clamp(20px, 5%, 60px);
}

.banner-title {
  font-family: var(--brand-font);
  font-weight: 600;
  line-height: 1.12;
  letter-spacing: -0.015em;
  color: var(--brand-ink);
}

.banner-sub {
  margin-top: 10px;
  color: var(--brand-muted);
  line-height: 1.5;
}

/* 药丸形。站内的动作按钮已经统一是这个形状 ——
   .product-thumb .button button（Add to Cart）和结账的 Place Order
   都是 border-radius:50rem，首页 CTA 若是直角就成了唯一的例外。
   按钮语言只该有一套，这比"方角还是圆角更高级"重要得多。 */
.banner-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-top: 22px;
  padding: 13px 32px;
  border-radius: 50rem;
  /* 白底而不是品牌粉：这层文案压在任意宣传图上，而两块促销图一块是
     粉红唇釉、一块是紫黑背景 —— 粉色按钮在第一块里会糊进背景。
     白色对任何照片都能分离出来，是压图 CTA 最稳的选择。
     品牌色留给 hover，点之前是中性的，手放上去才亮成粉色。 */
  background-color: #fff;
  color: var(--brand-ink);
  font-size: .875rem;
  font-weight: 600;
  letter-spacing: .01em;
  text-transform: none;
  white-space: nowrap;
  /* 照片明暗不可控，给一点投影把按钮从背景里"抬"起来 */
  box-shadow: 0 2px 12px rgba(0, 0, 0, .22);
  transition: background-color .25s ease, color .25s ease, transform .25s ease;
}

.banner-tile:hover .banner-cta {
  background-color: var(--brand-accent);
  color: #fff;
  transform: translateY(-1px);
}

/* 整块图才是那个 <a>，键盘焦点落在外层。焦点圈必须画在按钮上，
   否则 Tab 到这里看不出选中了什么。 */
.banner-tile:focus-visible {
  outline: none;
}

.banner-tile:focus-visible .banner-cta {
  background-color: var(--brand-accent);
  color: #fff;
  box-shadow: 0 0 0 3px rgba(255, 255, 255, .9), 0 0 0 6px var(--brand-accent);
}

/* --------------------------------------------------------------------------
   文案块在图上的九宫格位置（bc-<横><纵>，来自后台的 position 字段）

   .banner-copy 是 flex-direction: column，所以：
     横向 = align-items   纵向 = justify-content
   text-align 跟着横向走，否则多行文字的对齐和整块的对齐会打架。

   ⚠ 只有 t/b 才加纵向内边距。给居中那几个也加的话，
     文案块会被内边距挤得不再真正居中。
   -------------------------------------------------------------------------- */
/* ⚠ 一律写成 .banner-copy.bc-xx，不要图省事只写 .bc-xx。
      本文件后面还有一条 .banner-copy { padding: 0 clamp(...) }，
      同权重且在后，会把这里的 padding-top / padding-bottom 压成 0 ——
      实测就是 lt 贴顶、lb 贴底，一点余量都没有。
      带上 .banner-copy 提到 (0,2,0) 之后就和书写顺序无关了。 */
.banner-copy.bc-lt, .banner-copy.bc-lc, .banner-copy.bc-lb { align-items: flex-start; text-align: left; }
.banner-copy.bc-ct, .banner-copy.bc-cc, .banner-copy.bc-cb { align-items: center;     text-align: center; }
.banner-copy.bc-rt, .banner-copy.bc-rc, .banner-copy.bc-rb { align-items: flex-end;   text-align: right; }

.banner-copy.bc-lt, .banner-copy.bc-ct, .banner-copy.bc-rt { justify-content: flex-start; padding-top: clamp(20px, 6%, 56px); }
.banner-copy.bc-lc, .banner-copy.bc-cc, .banner-copy.bc-rc { justify-content: center; }
.banner-copy.bc-lb, .banner-copy.bc-cb, .banner-copy.bc-rb { justify-content: flex-end;   padding-bottom: clamp(20px, 6%, 56px); }

/* 只有按钮、没有标题副标题时（促销双图块的常见形态：标题烧在图里），
   居中悬在图正中会显得没有着落，压到底部更像一个入口。
   ⚠ 这条要排在九宫格之后：同权重时后者胜，
     否则后台明确选了位置也会被它覆盖掉。
     但只在后台没另外指定（仍是默认 lc）时才接管。 */
.banner-copy.bc-lc:has(.banner-cta:only-child) {
  justify-content: flex-end;
  padding-bottom: clamp(18px, 4%, 34px);
}

.banner-copy:has(.banner-cta:only-child) .banner-cta {
  margin-top: 0;
}

/* --- 形态一：首页大轮播 --- */
.banner-hero .banner-title {
  font-size: clamp(1.9rem, 4.4vw, 4rem);
}

.banner-hero .banner-sub {
  font-size: clamp(.95rem, 1.3vw, 1.25rem);
}

/* 通栏时文案不能贴着屏幕边缘，跟着 .container 的中轴收进来 */
.banner-hero .banner-copy {
  padding-left: max(24px, calc(50vw - 660px + 12px));
}

/* --- 形态二：促销双图块 --- */
.banner-tiles {
  margin-bottom: 40px;
}

.banner-tiles .carousel-item > .row {
  --bs-gutter-x: 24px;
}

.banner-tiles .banner-tile {
  border-radius: var(--oc-radius);
}

.banner-tiles .banner-tile img.banner-bg {
  aspect-ratio: 2 / 1;
  object-fit: cover;
}

.banner-tiles .banner-title {
  font-size: clamp(1.2rem, 2vw, 1.9rem);
}

.banner-tiles .banner-sub {
  font-size: clamp(.85rem, 1vw, 1rem);
}

.banner-tiles .banner-cta {
  margin-top: 16px;
  padding: 11px 28px;
  font-size: .72rem;
}

/* 手机端两块并排太挤，改上下堆叠。
   模板输出的是不带断点前缀的 col-6，只能在这里强制改宽 */
@media (max-width: 767.98px) {
  .banner-tiles .carousel-item > .row > [class*="col-"] {
    flex: 0 0 100%;
    max-width: 100%;
    width: 100%;
  }

  .banner-tiles .carousel-item > .row > [class*="col-"] + [class*="col-"] {
    margin-top: 16px;
  }
}

/* --- 其余形态（图册等）不出叠层 --- */
.carousel:not(.banner-hero):not(.banner-tiles) .banner-copy {
  display: none;
}

/* ==========================================================================
   修正：menu.twig 的根元素带 class="bg-primary"，
   Bootstrap 的 .bg-primary 用了 !important（bootstrap.css:8603），
   压过前面 #menu 的 ID 选择器 —— 前面那两处 background-color 其实一直没生效。
   只能同样用 !important 打回去。
   ========================================================================== */
@media (min-width: 768px) {
  #menu.bg-primary {
    background-color: transparent !important;
  }
}

@media (max-width: 767.98px) {
  #menu.bg-primary {
    background-color: transparent !important;
  }

  /* 汉堡按钮：透明底 + ink 图标，不要实心黑块 */
  #menu .navbar-toggler {
    color: var(--brand-ink);
    background-color: transparent;
  }
}

/* 商品标题用 ink 而不是链接色 —— 卡片里标题是内容不是链接，
   一片摩卡褐的标题会让整个列表显得脏 */
.product-thumb h4 a,
.product-thumb .description h4 a {
  color: var(--brand-ink);
}

.product-thumb h4 a:hover {
  color: var(--brand-accent);
}



/* ==========================================================================
   结账页地址字段：改成英国信封顺序
   模板 catalog/view/template/checkout/register.twig 是**核心文件，没有 OCMOD
   覆盖版**，所以不改标记，用 flex 的 order 重排 —— Bootstrap 的 .row 本身
   就是 flex 容器，order 直接生效，手机端单列时同样按这个顺序纵向排列。

   原顺序（DOM）：公司 → 地址1 → 地址2 → 城镇 → 邮编 → 国家 → 郡
   问题：邮编跑到郡前面、国家夹在中间，读起来不是任何国家的地址顺序。

   英国顺序：地址1 → 地址2 → 城镇 → 郡 → 邮编 → 国家 → 公司(可选，殿后)

   选择器用 [name$="..."] 而不是 id：同一套规则要同时命中账单块的
   payment_address_1 和配送块的 shipping_address_1。
   :has() 作用在行上，把个人信息那一行（姓名/邮箱/电话，同样是
   row-cols-md-2）排除在外 —— 那行不含 address_1。
   ========================================================================== */
#checkout-register .row:has([name$="address_1"]) > .col {
  /* 兜底：地址自定义字段等未点名的项，排在勾选框之前 */
  order: 9;
}

#checkout-register .row:has([name$="address_1"]) > .col:has([name$="address_1"])  { order: 1; }
#checkout-register .row:has([name$="address_1"]) > .col:has([name$="address_2"])  { order: 2; }
#checkout-register .row:has([name$="address_1"]) > .col:has([name$="_city"])      { order: 3; }
#checkout-register .row:has([name$="address_1"]) > .col:has([name$="zone_id"])    { order: 4; }
#checkout-register .row:has([name$="address_1"]) > .col:has([name$="postcode"])   { order: 5; }
#checkout-register .row:has([name$="address_1"]) > .col:has([name$="country_id"]) { order: 6; }
#checkout-register .row:has([name$="address_1"]) > .col:has([name$="_company"])   { order: 7; }

/* ⚠ 电话和「账单地址与收货一致」勾选框必须显式点名。
   checkout-onepage.js 的 placeTelephone()（:1530）会把电话列插到**郡字段之后**
   —— 郡被隐藏后仍在 DOM 里，插入照做。但电话列不匹配上面任何一条规则，
   会掉进兜底桶，结果排到公司和勾选框后面去（实际出过这个问题）。

   勾选框是「收货地址填完了」的收尾控件，必须排在所有地址字段之后、
   自定义字段之前。电话放在地址末尾（快递要用它发送达短信），在勾选框之前。 */
#checkout-register .row:has([name$="address_1"]) > .col:has([name="telephone"])     { order: 8; }
#checkout-register .row:has([name$="address_1"]) > .col:has([name="address_match"]) { order: 10; }

/* ==========================================================================
   County 字段：没有可选地区时整个隐藏

   英国 1996 年起地址就不再要求写郡，让顾客从 107 个郡里挑一个是纯摩擦。
   做法不是「标成选填」——那要改 7 个核心控制器（register / payment_address /
   shipping_address / account.address / 3 个 api），升级必被覆盖。
   改成把英国的郡在 oc_zone 里停用：OpenCart 的校验是
       if ($zone_total && !$zone_id) 报错
   而 $zone_total 按 status=1 统计，停用后变 0，**7 处校验同时自动失效**。

   ⚠ 配套 SQL 必须一起执行，否则 VAT 会断：
     税率查询用 `z2gz.zone_id = '0' OR z2gz.zone_id = '<顾客 zone>'`，
     zone_id=0 是「该国全部地区」通配符。UK VAT Zone 现在逐个挂了 107 条
     具体 zone、没有通配行，顾客 zone 一空就匹配不上 → 不收税。

   下面这条只负责视觉：停用后下拉框只剩占位项（value="" 或 "0"），
   此时把整个字段藏掉。用 CSS 而不是 JS —— 结账页是 AJAX 重绘的，
   CSS 自动跟上，不需要挂 MutationObserver。
   顾客改选有地区的国家（美国、爱尔兰等）时，下拉框会被填入真实选项，
   选择器不再命中，字段自动出现。
   ========================================================================== */
#checkout-register .col:has(select[name$="zone_id"]):not(:has(select[name$="zone_id"] option[value]:not([value=""]):not([value="0"]))),
.au-field:has(select[name="zone_id"]):not(:has(select[name="zone_id"] option[value]:not([value=""]):not([value="0"]))) {
  display: none;
}

/* ==========================================================================
   订单追踪页（访客可用）
   模板：extension/ocmod/catalog/view/template/information/track.twig
   控制器：extension/ocmod/catalog/controller/information/track.php

   访客结账是开着的，而这些人除了那封状态邮件之外没有别的查询途径。
   这一页是「我的货呢」这类工单的解药，所以它要让人一眼就会用、
   并且看起来值得信任 —— 查单页是顾客付完款之后最常回来的页面。

   设计上走细线 + 直角 + 大写小标签，不用圆角药丸和大色块。
   强调色（--brand-accent）全页只出现三处：焦点环、按钮、链接。
   ========================================================================== */
.tk-intro {
  max-width: 46ch;
  margin-bottom: 26px;
  color: var(--brand-muted);
  line-height: 1.65;
}

.tk-error {
  max-width: 560px;
  margin-bottom: 22px;
  padding: 13px 16px;
  border-left: 3px solid var(--brand-sale);
  background-color: #FCEAEA;
  color: #96131F;
  font-size: .875rem;
  line-height: 1.55;
}

/* --- 表单面板 ---------------------------------------------------------- */
/* 白底 + 一条细线。在白页面上几乎看不见边界，正是要的效果 ——
   高端零售很少用投影和灰底去"框"东西，那是后台管理界面的语言。 */
.tk-form {
  max-width: 560px;
  margin-bottom: 34px;
  padding: 28px;
  border: 1px solid var(--brand-line);
}

.tk-fields {
  display: flex;
  flex-wrap: wrap;
  gap: 22px;
}

/* flex-basis 给 100%：默认就是每行一个。
   ≥576px 时下面的媒体查询再让它们并排 —— 移动优先，
   而不是反过来在小屏上"修"一个本来就挤的两列布局。 */
.tk-field {
  flex: 1 1 100%;
  min-width: 0;
}

.tk-form .form-label {
  display: block;
  margin-bottom: 8px;
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--brand-muted);
}

.tk-form .form-control {
  height: 52px;
  padding: 0 14px;
  /* ⚠ 不能用 --brand-line：那个值只有 1.30:1，是装饰线的亮度，
        描输入框边界达不到对比度要求（见令牌定义处的注释）。 */
  border: 1px solid var(--brand-line-strong);
  border-radius: 2px;
  background-color: var(--brand-bg);
  font-size: .95rem;
  color: var(--brand-ink);
  transition: border-color .15s ease, box-shadow .15s ease;
}

.tk-form .form-control:focus {
  border-color: var(--brand-accent);
  box-shadow: 0 0 0 3px var(--brand-tint);
  outline: 0;
}

/* 参考号是一串要逐位核对的码，等宽字体让 0/O、1/l 分得开，
   也让顾客一眼看出"这是个编号"而不是一句话。 */
#input-track-order {
  font-family: Consolas, "SF Mono", Menlo, monospace;
  letter-spacing: .04em;
  text-transform: uppercase;
}

#input-track-order::placeholder {
  color: #9AA7B1;
  text-transform: none;
  letter-spacing: normal;
}

/* 说明文字：贴着它解释的那个框，静音色，不抢视线。
   改之前这个类没有任何样式，继承出一个蓝色，和表单抢注意力。 */
.tk-help {
  display: block;
  margin-top: 9px;
  font-size: .78rem;
  line-height: 1.55;
  color: var(--brand-muted);
}

/* --- 提交按钮 ---------------------------------------------------------- */
/* 直角 + 大写 + 字距，和邮件模板里的按钮同一套语言（那边已经是
   letter-spacing:1px + uppercase），两处一致比各自好看更重要。 */
.tk-submit {
  width: 100%;
  margin-top: 26px;
  padding: 0 32px;
  height: 52px;
  border: 0;
  border-radius: 2px;
  background-color: var(--brand-ink);
  color: #fff;
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color .18s ease;
}

.tk-submit:hover,
.tk-submit:focus-visible {
  background-color: var(--brand-accent);
}

.tk-submit:focus-visible {
  outline: 2px solid var(--brand-accent);
  outline-offset: 2px;
}

/* 面板外面的一句轻声提示。不放进面板里 —— 面板里的每一行都该是
   "要填的东西"，求助入口属于旁白。 */
.tk-aside {
  max-width: 560px;
  margin: -18px 0 34px;
  font-size: .82rem;
  line-height: 1.6;
  color: var(--brand-muted);
}

.tk-aside a {
  color: var(--brand-accent);
  text-underline-offset: 3px;
}

/* --- 结果卡片 ---------------------------------------------------------- */
.tk-card {
  max-width: 640px;
  padding: 0;
  border: 1px solid var(--brand-line);
}

.tk-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 22px 26px;
  border-bottom: 1px solid var(--brand-line);
}

/* 标签安静、号码突出。整串都用等宽的话，「Order」这个词会跟着
   变成代码的质感，读起来像系统日志而不是给人看的单据。 */
.tk-order {
  font-size: .88rem;
  color: var(--brand-muted);
  word-break: break-all;
}

.tk-order b {
  font-family: Consolas, "SF Mono", Menlo, monospace;
  font-size: .95rem;
  font-weight: 600;
  letter-spacing: .03em;
  color: var(--brand-ink);
}

.tk-status {
  flex: none;
  padding: 6px 12px;
  border-radius: 2px;
  background-color: var(--brand-tint);
  color: var(--brand-accent-deep);
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* 事实清单用「每行一条 + 细线分隔」而不是两列网格 ——
   网格在窄屏上必然塌成一列，塌了之后 dt/dd 的对应关系就看不出来了。 */
.tk-facts {
  margin: 0;
  padding: 22px 26px;
}

.tk-facts dt {
  float: left;
  clear: left;
  width: 42%;
  padding: 9px 0;
  font-size: .82rem;
  color: var(--brand-muted);
}

.tk-facts dd {
  margin: 0;
  padding: 9px 0;
  padding-left: 42%;
  border-bottom: 1px solid var(--brand-line);
  font-size: .9rem;
  color: var(--brand-ink);
}

.tk-facts dd:last-child {
  border-bottom: 0;
}

.tk-code {
  font-family: Consolas, "SF Mono", Menlo, monospace;
  letter-spacing: .03em;
  word-break: break-all;
}

/* --- 承运商按钮 / 状态说明 --------------------------------------------- */
.tk-cta {
  display: block;
  margin: 0 26px 26px;
  padding: 0 28px;
  height: 52px;
  line-height: 52px;
  border-radius: 2px;
  background-color: var(--brand-accent);
  color: #fff;
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  text-align: center;
  text-decoration: none;
  transition: background-color .18s ease;
}

.tk-cta:hover,
.tk-cta:focus {
  background-color: var(--brand-accent-deep);
  color: #fff;
}

.tk-pending {
  margin: 0 26px 22px;
  padding: 14px 16px;
  background-color: var(--brand-surface);
  color: var(--brand-ink);
  font-size: .86rem;
  line-height: 1.6;
}

.tk-hint,
.tk-ddp {
  margin: -12px 26px 22px;
  font-size: .8rem;
  line-height: 1.55;
  color: var(--brand-muted);
}

.tk-ddp {
  color: var(--secure-green);
  font-weight: 600;
}

/* --- 进度时间线 -------------------------------------------------------- */
.tk-sub {
  margin: 0 26px 16px;
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--brand-muted);
}

.tk-timeline {
  margin: 0;
  padding: 0 26px 26px 42px;
  list-style: none;
}

.tk-step {
  position: relative;
  padding: 0 0 20px 22px;
  border-left: 1px solid var(--brand-line);
}

.tk-step:last-child {
  padding-bottom: 0;
  border-left-color: transparent;
}

.tk-step::before {
  content: "";
  position: absolute;
  left: -4.5px;
  top: 5px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background-color: var(--brand-muted);
}

.tk-step.is-current::before {
  width: 10px;
  height: 10px;
  left: -5.5px;
  background-color: var(--brand-accent);
  box-shadow: 0 0 0 3px var(--brand-tint);
}

.tk-step-date {
  display: block;
  font-size: .75rem;
  color: var(--brand-muted);
}

.tk-step-status {
  display: block;
  margin-top: 2px;
  font-size: .9rem;
  font-weight: 600;
  color: var(--brand-ink);
}

.tk-step-note {
  display: block;
  margin-top: 3px;
  font-size: .82rem;
  line-height: 1.55;
  color: var(--brand-muted);
}

/* --- 平板及以上 -------------------------------------------------------- */
@media (min-width: 576px) {
  /* 两个输入框并排。576px 时每列约 250px，放得下参考号不换行；
     再窄就维持上面的每行一个。 */
  .tk-field {
    flex: 1 1 220px;
  }

  .tk-submit {
    width: auto;
    min-width: 220px;
  }

  .tk-cta {
    display: inline-block;
    margin-left: 26px;
    margin-right: 26px;
  }
}

/* --------------------------------------------------------------------------
   DDP 简短版：商品页价格下方 / 快速查看弹窗
   这里不做成色块 —— 它是一句安心话，不是需要抢注意力的告示。
   摘要里那个带底色的框是因为顾客正在核对金额，这里只要一行就够。
   -------------------------------------------------------------------------- */
.p-ddp {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  margin-top: 6px;
  font-size: .78rem;
  line-height: 1.45;
  font-weight: 600;
  color: var(--secure-green);
}

.p-ddp::before {
  content: "✓";
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-top: 1px;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background-color: var(--secure-green);
  color: #fff;
  font-size: .58rem;
}

/* 弹窗里空间更紧，收一点上边距 */
.qv-ddp {
  margin: 4px 0 0;
}

/* ==========================================================================
   DDP 完税说明（订单摘要里紧贴 VAT 行）
   模板：checkout/confirm.twig、checkout/cart_list.twig

   沿用站内已有的「安全/已验证」视觉语言：绿色勾 + 浅绿底 + --secure-green，
   和 .op-note-free、卡表单的加密标记是同一套，不另造一种绿。
   ========================================================================== */
.op-ddp {
  display: block;
  margin: 8px 0 4px;
  padding: 10px 12px;
  border-left: 3px solid var(--secure-green);
  border-radius: 0 8px 8px 0;
  background-color: #F1FAF4;
}

.op-ddp-title {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: .78rem;
  font-weight: 700;
  color: var(--secure-green);
}

/* 勾用文字符号而不是字体图标：这块可能出现在
   AJAX 重绘的摘要里，少依赖一个字体就少一次字形未加载的闪烁 */
.op-ddp-title::before {
  content: "✓";
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background-color: var(--secure-green);
  color: #fff;
  font-size: .62rem;
}

.op-ddp-text {
  display: block;
  margin-top: 5px;
  font-size: .73rem;
  line-height: 1.55;
  color: var(--brand-muted);
}

/* ==========================================================================
   头部：白底 + 一条底边
   原方案是整块高饱和色铺满 #top 和 header。那是美妆站的做法 ——
   医疗/医学护肤零售（La Roche-Posay、Eucerin 一类）一律白底大留白，
   强调色只出现在按钮和角标上。整条彩色横幅在这个品类里读起来像促销页。

   白底之后 logo 必须换成深色版：后台「设置 → 图片 → Logo」
   要指向 biouman-logo.svg，不是 biouman-logo-white.svg。

   stylesheet.css 给 #top 的 margin-bottom:20px 和 padding-bottom:5px
   会在两块之间露出缝，仍须清零。
   ========================================================================== */
#top,
header {
  background-color: var(--brand-bg);
}

#top {
  margin-bottom: 0;
  padding-top: 6px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--brand-line);
}

header {
  padding-top: 14px;
  padding-bottom: 6px;
  border-bottom: 0;
}

/* --- 头部文字：白底上用深色 --- */
/* #top 那行（货币/语言/账户）是次要信息，用 muted；
   logo 文字和主导航才用 ink。这样层级靠颜色就分开了，不必再加字号差。 */
#top,
#top a,
#top a:visited,
#top .list-inline-item > a,
#top .list-inline-item .dropdown > a,
#top .list-inline-item .dropdown > span,
#top .list-inline-item > a i {
  color: var(--brand-muted);
}

#logo h1 a {
  color: var(--brand-ink);
}

#top a:hover,
#top .list-inline-item .dropdown > span:hover {
  color: var(--brand-accent);
}

/* --- 分类导航：白底深字，hover 用主色下划线 --- */
@media (min-width: 768px) {
  #menu {
    border-top: 0;
    border-bottom: 0;
  }

  #menu .navbar-nav > li > a {
    color: var(--brand-ink);
  }

  #menu .navbar-nav > li > a:hover,
  #menu .navbar-nav > li > a:focus,
  #menu .navbar-nav > li.show > a {
    color: var(--brand-accent);
    border-bottom-color: var(--brand-accent);
  }
}

@media (max-width: 767.98px) {
  #menu .navbar-toggler {
    color: var(--brand-ink);
  }
}

/* --- 搜索框：白底上要看得见边界，用控件线而不是装饰线 --- */
header .input-group {
  border-color: var(--brand-line-strong);
}

header .input-group:focus-within {
  border-color: var(--brand-accent);
  box-shadow: 0 0 0 3px rgba(var(--brand-accent-rgb), .18);
}

/* ==========================================================================
   Banner 文案回到图片上层，不加任何蒙版
   可读性完全依赖图片本身左侧是否留了纯色空间 —— 这是 Flipmart 那类
   宣传图的前提。若某张图文字读不清，是该换图，不是加蒙版。
   ========================================================================== */
.banner-copy {
  position: absolute;
  inset: 0;
  padding: 0 clamp(20px, 5%, 60px);
  background-color: transparent;
}

.banner-hero .banner-copy {
  padding-left: max(24px, calc(50vw - 660px + 12px));
  padding-right: max(24px, calc(50vw - 660px + 12px));
}

.banner-tile img.banner-bg {
  height: auto;
}

.banner-hero .banner-tile img.banner-bg {
  height: clamp(300px, 40vw, 620px);
  object-fit: cover;
}

/* ⚠ 这里原本有一段把 .banner-cta 强制刷成品牌粉、hover 转黑的覆盖。
   它排在基础规则之后，会把上面「白底药丸 + hover 转粉」整个吃掉。
   配色决策已经统一到上面那一处，这里不再重复声明 ——
   同一个属性在一份文件里被两处相反地定义，是最难查的那类样式 bug。 */

@media (max-width: 767.98px) {
  .banner-copy,
  .banner-hero .banner-copy {
    padding: 0 20px;
  }

  /* ⚠ 这里原本还有一条 .banner-hero .banner-tile img { height: clamp(...) }。
     它和现在「英雄图 height:auto 完整显示」的做法正好相反，
     只是权重低于那一条 ((0,2,1) < (0,4,1)) 才一直没生效 ——
     属于本文件开头就警告过的「同一属性两处相反定义」，已删除。
     手机端的高度由图片自身比例决定，不要再在这里钉死。 */

  /* 手机上这是拇指要点的目标，不能跟着字号一起缩。
     靠 padding 凑高度算不准（12px 上下 + 15px 行高只有 39px），
     直接用 min-height 钉死 44px —— 配合 inline-flex 居中，文字照样在正中。 */
  .banner-cta,
  .banner-tiles .banner-cta {
    min-height: 44px;
    padding: 12px 26px;
    font-size: .72rem;
  }

  .banner-copy:has(.banner-cta:only-child) {
    padding-bottom: 18px;
  }
}

/* ==========================================================================
   按钮与链接跟随新色板
   主按钮改品牌粉（Flipmart 的 ADD TO CART 就是粉的）；
   头部购物车按钮保持 ink 黑 —— 粉底上黑块才有对比，粉底粉按钮会糊在一起。
   ========================================================================== */
.btn-primary {
  --bs-btn-bg: var(--brand-accent);
  --bs-btn-border-color: var(--brand-accent);
  /* hover 转黑而不是深粉：深粉和品牌粉只差一个明度档，
     悬停时几乎看不出变化，按钮会显得"没反应" */
  --bs-btn-hover-bg: var(--brand-ink);
  --bs-btn-hover-border-color: var(--brand-ink);
  --bs-btn-active-bg: var(--brand-ink);
  --bs-btn-active-border-color: var(--brand-ink);
}

.product-thumb .button button:first-child {
  background-color: var(--brand-accent);
  border-color: var(--brand-accent);
}

.product-thumb .button button:first-child:hover {
  background-color: var(--brand-ink);
  border-color: var(--brand-ink);
}

.product-thumb h4 a:hover {
  color: var(--brand-accent-deep);
}

/* 收藏按钮 hover 也跟着转黑，跟左边的主按钮成对 */
.product-thumb .button button:not(:first-child):hover {
  background-color: var(--brand-ink);
  border-color: var(--brand-ink);
  color: #fff;
}

/* ==========================================================================
   促销双图：两张各自成为独立卡片
   模板结构是 .carousel > .carousel-inner > .carousel-item > .row > .col-6 ×2，
   外层那些容器全部透明化，视觉上的"卡片"只由 .banner-tile 自己承担，
   这样两张图之间有真实间隔，读起来是两个东西而不是一块面板被切成两半。
   ========================================================================== */
.banner-tiles,
.banner-tiles .carousel-inner,
.banner-tiles .carousel-item,
.banner-tiles .carousel-item > .row {
  background-color: transparent;
  border: 0;
  box-shadow: none;
}

.banner-tiles .carousel-item > .row {
  --bs-gutter-x: 28px;
}

.banner-tiles .banner-tile {
  border-radius: var(--oc-radius);
  overflow: hidden;
  background-color: #fff;
  box-shadow: 0 2px 12px rgba(0, 0, 0, .08);
}

.banner-tiles .banner-tile:hover {
  box-shadow: 0 6px 20px rgba(0, 0, 0, .12);
}

/* Bootstrap 的 .carousel-inner 是 overflow:hidden，阴影会被裁掉，
   两侧留出等于模糊半径的内边距把阴影放出来 */
.banner-tiles .carousel-inner {
  padding: 4px 0 14px;
}

/* 手机端两块上下堆叠时，间距要够大才像两张卡片 */
@media (max-width: 767.98px) {
  .banner-tiles .carousel-item > .row > [class*="col-"] + [class*="col-"] {
    margin-top: 22px;
  }
}

/* 手机端大轮播：文案保持叠在图上、无底色，只把字号收小 */
@media (max-width: 767.98px) {
  .banner-hero .banner-title {
    font-size: 1.6rem;
  }

  .banner-hero .banner-cta {
    margin-top: 14px;
  }
}

/* ==========================================================================
   首页英雄图：信任徽章 + 第三方实验室
   模板见 extension/ocmod/.../module/banner.twig（两份，须同步）

   ── 背景图换成了纯背景 ────────────────────────────────────────────────
   原来那张 banner 把全部文案和实验室 logo 都 P 在图里：放大糊、
   改一个字要重做图、读屏软件读不到、而且在任何非原始宽度上都会被缩。
   现在图只负责背景和药瓶，文字和 logo 都是真实元素。

   ── 配色取自图本身 ────────────────────────────────────────────────────
   顶边 #F3E4D5、底边 #DCCCB8（竖向有渐变）。手机版文字区接在图下方，
   所以用**底边色**打底才看不出接缝 —— 取平均色或随便挑个米色都会露边。
   ========================================================================== */

/* ── 信任徽章 ──────────────────────────────────────────────────────── */
.banner-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 16px;
}

.bb-pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 16px 7px 12px;
  border-radius: 50rem;
  /* 半透明白底：图本身左侧是米色且带渐变，纯白药丸会显得贴在上面，
     半透明能让它和背景咬合，同时保证字的对比度。 */
  background: rgba(255, 255, 255, 0.82);
  color: var(--brand-ink);
  font-size: .82rem;
  font-weight: 600;
  line-height: 1.25;
  white-space: nowrap;
}

.bb-pill i {
  /* 橙色对勾。不用品牌粉 —— 粉是动作色（加购、CTA），
     这里表达的是「已核实」，和页脚的绿勾同一类语义。
     橙色取自原图里那个图标，保持视觉延续。 */
  color: #E8742C;
  font-size: .95rem;
}

/* ── 第三方实验室 ──────────────────────────────────────────────────── */
.banner-labs {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 20px;
}

.bl-cap {
  color: var(--brand-muted);
  font-size: .9rem;
  line-height: 1.4;
}

.bl-row {
  display: flex;
  align-items: center;
  gap: clamp(18px, 2.4vw, 40px);
  flex-wrap: wrap;
}

/* ⚠ 按**高度**约束、宽度自适应。三个 logo 原始比例差很多
   （janoshik 390x102 很扁，vanguard 175x168 接近方形），
   写死宽度会把它们挤成不同的视觉大小。
   高度统一才看起来是一排。 */
.bl-row img {
  display: block;
  width: auto;
  height: clamp(26px, 2.6vw, 38px);
  /* 原图是深色透明 PNG，压在米底上不用处理；
     留 opacity 让它们退到文字之后，不抢标题。 */
  opacity: .88;
}

/* janoshik 是扁长条，和另外两个等高会显得过宽，单独收一点 */
.bl-row img[alt="Janoshik Analytical"] {
  height: clamp(20px, 2vw, 30px);
}

/* ── 高度：取「图片原比例」和「内容实际高度」的较大者 ────────────────
   ⚠ 这一段是整个英雄图最关键的布局决定，改之前先读完。

   原来的做法是「<img> 在文档流里 + .banner-copy 绝对定位叠上去」，
   于是容器高度**只由图片比例决定**：高度 = 视口宽 × 784/2560 = 0.306。
   那在「文案全部 P 在图里」的年代没问题 —— 叠层里只有一个标题。

   现在叠层有五段（标题 / 三个徽章 / 副标题 / 实验室说明 / 三个 logo），
   实测需要约 300px。于是：
       1440px 宽 → 图高 441px → 放得下
        980px 宽 → 图高 300px → 刚好
        800px 宽 → 图高 245px → **溢出**，logo 和说明文字被切掉
   也就是说笔记本和平板上全是坏的，而且是静默的 —— 没有报错，
   只是内容被容器边缘裁掉。

   改成 grid 单元格堆叠：图和文案占同一格，格子高度自然取两者的较大值。
       内容矮（宽屏）→ min-height 生效 → 图按原比例完整显示，不裁
       内容高（窄屏）→ 格子被内容撑高 → 图 cover 填满

   ⚠ object-position: right center —— 被裁的时候裁左边那片空白米色，
     右边的药瓶必须留住，那是这张图唯一的产品信息。
   ⚠ min-height 用 vw 而不是写死像素：30.625vw = 784/2560，
     和图片原始比例完全相等，所以宽屏上 cover 裁不掉任何东西。
     换图之后这个数要跟着换（新图高÷宽×100）。 */
@media (min-width: 768px) {
  .banner-hero .banner-tile {
    display: grid;
    min-height: 30.625vw;
  }

  .banner-hero .banner-tile > img.banner-bg,
  .banner-hero .banner-tile > .banner-copy {
    grid-area: 1 / 1;
  }

  .banner-hero .banner-tile > img.banner-bg {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: right center;
  }

  /* 不再需要绝对定位 —— 它现在是 grid 单元里的一层，
     而且**必须**参与高度计算，否则格子又回到只由图决定高度。

     ⚠ 但也**不能用 static**。背景图上挂着 hover 时的
       transform: scale(1.04)，而带 transform 的元素会创建层叠上下文，
       绘制时等同于 z-index:0 的定位元素 —— 静态的文案会被它盖住。
       表现是「鼠标移上去标题和徽章整块消失，移开又回来」。
       relative 同样参与 grid 定高，加上 z-index 就压得住。 */
  .banner-hero .banner-copy {
    position: relative;
    z-index: 1;
    /* 上下留白，内容撑高时不要贴着边 */
    padding-top: clamp(24px, 3vw, 48px);
    padding-bottom: clamp(24px, 3vw, 48px);
  }
}

/* ── 桌面端：限宽，不许压到右侧药瓶上 ───────────────────────────────
   图里药瓶从约 62% 处开始，文字必须停在它左边。

   ⚠ **不要**给 .banner-copy 本身设 max-width。它带着一对很大的左右
     padding（padding-left: max(24px, calc(50vw - 660px + 12px))，
     用来对齐 .container 的中轴），而全站是 box-sizing: border-box，
     padding 会被算进 max-width 里：
         1920 宽 → padding 左右各 312px → 760 - 312 - 312 = 136px
     标题于是被挤成四行，容器被撑到 898px（图才 588px），
     下面空出一大片米色。这个坑很隐蔽 —— max-width 看起来是「限制内容宽」，
     实际限制的是边框盒。

     改成限制**子元素**，和 padding 互不干扰。
   ⚠ 右侧 padding 对左对齐的英雄图没有意义，收掉，把空间让给文字。 */
@media (min-width: 768px) {
  .banner-hero .banner-copy {
    padding-right: 24px;
  }

  .banner-hero .banner-title,
  .banner-hero .banner-sub,
  .banner-hero .banner-badges,
  .banner-hero .banner-labs {
    max-width: min(56vw, 720px);
  }
}

/* 超宽屏上图会被等比拉得很高（2560 → 827px），
   文案块跟着居中即可，不额外处理。 */

/* ── 手机端：图在上、文字在下 ─────────────────────────────────────────
   ⚠ 这里必须换布局，不能只是把字缩小。
     图是 2560x784（3.27:1），375px 宽的屏上只有 **115px 高** ——
     标题 + 三个徽章 + 副标题 + 实验室行 + 三个 logo 叠上去绝对塞不下，
     缩字号也不行（会小到读不了）。
     所以手机上让 .banner-copy 从绝对定位回到文档流，排在图下面，
     背景用图的底边色接住，看起来仍是一整块。 */
@media (max-width: 767.98px) {
  .banner-hero .carousel-item > .row > [class*="col-"] {
    /* 图 + 文字是一个整体，底色统一 */
    background: #DCCCB8;
  }

  /* ── 图：裁成 2.3:1 并锚定右侧 ──────────────────────────────────
     比例是算出来的，不是试出来的。药瓶（含阴影）从原图 x=1638 起，
     右侧占 922px。375px 宽、右对齐裁切时，可见原图宽 V 决定一切：

         V=2560 → 图高 115px，左侧米色 240px，药瓶 135px
         V=1800 → 图高 163px，左侧米色 183px，药瓶 192px
         V=1500 → 图高 196px，左侧米色 144px，药瓶 230px

     米色区越宽，图越矮、药瓶越小 —— 硬权衡。取 2.3:1（≈V=1800）：
     米色 183px 放得下折行后的徽章，药瓶 192px 仍然看得清。

     ⚠ 原来的 16:9 米色区只有约 150px，徽章会压到药瓶上。
     ⚠ object-position: right center —— 裁掉左边空白，药瓶必须留住。 */
  .banner-hero .banner-tile img.banner-bg {
    aspect-ratio: 2.3 / 1;
    height: auto;
    object-fit: cover;
    object-position: right center;
  }

  /* ── 徽章挪到图上的左侧空白处 ──────────────────────────────────
     目的是压低整个头部高度，让商品更早进入视野。

     ⚠ 用绝对定位把它**抽离文档流** —— 这才是省高度的关键：
       下面那块文案（标题/副标题/实验室）会自动收缩 96px。
       只是视觉上挪过去、仍占着流，是一点高度都省不下来的。
     ⚠ 定位基准是 .banner-tile（它有 position: relative）。
     ⚠ 宽度钉死 183px = 上面算出来的米色区宽度。超过就会压到药瓶。 */
  .banner-hero .banner-badges {
    position: absolute;
    top: 0;
    left: 0;
    z-index: 2;
    /* ⚠ 用 vw 不用固定 px。米色区占可见宽度的比例由**裁切比例**决定，
       和视口宽度无关：2.3:1 裁切下可见原图宽 1803，
       米色 = (1638 - (2560-1803)) / 1803 = 48.9%。
       写死 183px 的话，320px 的屏上米色只有 156px，徽章会压到药瓶上。
       取 46vw 留一点余量。 */
    width: 46vw;
    /* ⚠ 高度要**正好等于图片那一段**，不能用 100%。
       .banner-tile 包含图 + 下方文案，100% 会让徽章跨整块垂直居中，
       结果压到标题上（亲眼见过）。
       图是 width:100vw、aspect-ratio:2.3 → 高度就是 100vw/2.3。 */
    height: calc(100vw / 2.3);
    margin: 0;
    padding: 0 0 0 16px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 6px;
  }

  /* 药丸允许内部折行 —— 不折的话「180-Day Money Back Guarantee」
     要 216px，放不进 183px 的米色区。 */
  .banner-hero .banner-badges .bb-pill {
    width: 100%;
    white-space: normal;
    align-items: flex-start;
    padding: 5px 10px 5px 8px;
    font-size: .66rem;
    line-height: 1.25;
  }

  .banner-hero .banner-badges .bb-pill i {
    font-size: .8rem;
    /* 图标跟首行文字对齐，不要跟着两行文字居中 */
    margin-top: 1px;
  }

  .banner-hero .banner-copy {
    position: static;
    padding: 18px 20px 24px;
    /* 从图的底边色渐变到稍浅，接着图本身的竖向渐变往下走，
       不会在交界处出现一条生硬的线 */
    background: linear-gradient(180deg, #DCCCB8 0%, #E9DBC8 70%, #E9DBC8 100%);
    text-align: left;
    align-items: flex-start;
  }

  /* ⚠ bc-* 九宫格定位在手机上全部失效（已经不是绝对定位了），
     但那些类还挂在元素上，justify-content 会残留。统一压平。 */
  .banner-hero .banner-copy[class*="bc-"] {
    justify-content: flex-start;
    align-items: flex-start;
    text-align: left;
    padding-top: 18px;
    padding-bottom: 24px;
  }

  .banner-hero .banner-title {
    font-size: 1.45rem;
  }

  .banner-hero .banner-sub {
    font-size: .9rem;
    margin-top: 8px;
  }

  .banner-badges {
    gap: 7px;
    margin-top: 12px;
  }

  .bb-pill {
    padding: 6px 12px 6px 10px;
    font-size: .74rem;
    /* 手机上三个药丸排不下一行，允许折行；
       但单个药丸内部不能断词，否则「180-Day Money Back」会被拆开 */
    white-space: nowrap;
  }

  .banner-labs {
    margin-top: 14px;
    gap: 8px;
  }

  .bl-cap {
    font-size: .78rem;
  }

  .bl-row {
    gap: 18px;
  }

  .bl-row img {
    height: 22px;
  }

  .bl-row img[alt="Janoshik Analytical"] {
    height: 17px;
  }
}

/* 很窄的屏（320px 一类）再收一档，否则药丸会挤成三行 */
@media (max-width: 359.98px) {
  .bb-pill {
    font-size: .68rem;
    padding: 5px 10px 5px 8px;
  }

  .banner-hero .banner-title {
    font-size: 1.28rem;
  }
}

/* ==========================================================================
   品牌 logo 尺寸
   SVG 是矢量的，靠高度约束、宽度自适应；写死 width 会在换 logo 时变形。
   ========================================================================== */
#logo img {
  height: 40px;
  width: auto;
  max-width: 100%;
}

footer #logo img,
footer .footer-logo img {
  height: 32px;
  width: auto;
}

@media (max-width: 767.98px) {
  #logo img {
    /* ⚠ 固定 height + 固定 max-width 的组合会让 logo 溢出自己的网格格子。
       手机头部那一行是 grid，logo 占 minmax(0, 1fr)，格子会被右边的
       ☰ / COA / 图标组挤窄；max-width 写死时图片不跟着缩 ——
       320px 实测溢出 45px，直接压在 COA 上。

       改成两个都是「上限」：max-height + max-width: min(…, 100%)。
       浏览器按原始比例取先触发的那个，宽度不够时等比缩小，不会变形。
       （若写成 height:26px + max-width:100%，宽度被夹住而高度是定值，
         图片会被横向压扁。） */
    height: auto;
    width: auto;
    max-height: 26px;
    max-width: 150px;
    max-width: min(150px, 100%);
  }
}

/* ==========================================================================
   Banner 文案：白字，为深色背景图设计
   主标题加到 700：白字压深色照片有反白光渗效应，笔画会视觉变细，
   重一档才能稳住。副标题 500 就够，再重会跟主标题抢。
   阴影只作用在字形本身，不是覆盖在图上的蒙版；不需要的话删掉两行 text-shadow。
   ========================================================================== */
.banner-title {
  color: #fff;
  font-weight: 700;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .45);
}

.banner-sub {
  color: rgba(255, 255, 255, .92);
  font-weight: 500;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .45);
}

/* --------------------------------------------------------------------------
   深字变体（bi-dark，来自后台的 ink 字段）

   上面那套白字是为深色照片写的。浅底图上白字只有 1.29:1，基本看不清；
   同一块米色底换成 --brand-ink 是 12.65:1。这个只能一张图一张图地定，
   所以做成后台可选，而不是全站改一个值。

   投影方向也要跟着翻：白字配暗投影，深字配浅投影，
   否则深字压浅底时那圈黑影会像脏东西。

   ⚠ 选择器权重：
     · .banner-copy.bi-dark .banner-title 是 (0,3,0)，压得过
       后面那条 .banner-title { color:#fff }（(0,1,0)），和书写顺序无关。
     · 但按钮的 hover/focus 原本就是 (0,3,0)，和这里打平会看顺序。
       所以下面把深字的 hover/focus 显式写成 (0,4,0)，锁死。
   -------------------------------------------------------------------------- */
.banner-copy.bi-dark .banner-title {
  color: var(--brand-ink);
  text-shadow: 0 1px 3px rgba(255, 255, 255, .55);
}

/* ⚠ 副标题这里**不能**用 --brand-muted。
      那个令牌是按「白底 5.50:1」标定的，可这层文字压的是照片不是白底：
      实测压米色底（#E8E2D5）只剩 4.26:1，而副标题约 15px / 500 字重
      算正文，门槛 4.5:1 —— 不达标。
      背景由运营换图决定，我们控制不了，所以副标题也用满色的 --brand-ink
      （同一块米底 12.65:1）。层级靠字号和字重拉开（30px/700 对 15px/500），
      不靠降低对比度。 */
.banner-copy.bi-dark .banner-sub {
  color: var(--brand-ink);
  text-shadow: 0 1px 3px rgba(255, 255, 255, .55);
}

/* 按钮同样要翻过来：浅底上的白按钮几乎看不见边界 */
.banner-copy.bi-dark .banner-cta {
  background-color: var(--brand-ink);
  color: #fff;
  box-shadow: 0 2px 12px rgba(0, 0, 0, .18);
}

.banner-tile:hover .banner-copy.bi-dark .banner-cta,
.banner-tile:focus-visible .banner-copy.bi-dark .banner-cta {
  background-color: var(--brand-accent);
  color: #fff;
}

/* ==========================================================================
   Images Gallery：通栏满屏 + 极细缝 + 点击放大
   模板给 items>=3 的实例加了 .banner-gallery 类。
   三种形态的类名都由模板判定后打上：banner-hero / banner-tiles / banner-gallery，
   CSS 一律用类名定位，不再依赖 items 数值或 col-N 列名。
   ========================================================================== */
.banner-gallery {
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-bottom: 0;
  background-color: transparent;
  border: 0;
}

.banner-gallery .carousel-inner {
  padding: 0;
}

.banner-gallery .carousel-item > .row {
  --bs-gutter-x: 0;
  margin: 0;
  flex-wrap: nowrap;
  gap: 3px;                 /* 就是这条「非常细小的间距」 */
}

/* 清掉 Bootstrap 栅格给 col 的内外边距和宽度；
   实际宽度在文件末尾按断点统一定义（≥992 六张 / 768-991 四张 / <768 78%）。 */
.banner-gallery .carousel-item > .row > [class*="col-"] {
  padding: 0;
  max-width: none;
  width: auto;
}

.banner-gallery .banner-tile {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  border-radius: 0;
  background-color: transparent;
  box-shadow: none;
  cursor: zoom-in;
  overflow: hidden;
}

.banner-gallery .banner-tile img.banner-bg {
  display: block;
  width: 100%;
  height: auto;
  /* 竖构图 3:4。桌面手机统一，卡片体量比方图大三分之一，
     人像和产品图在竖幅里也更占画面。
     后台模块尺寸必须同步改成 3:4（如 720x960），否则 resize()
     会先按方形补白边，再被 object-fit:cover 裁一次，中间的图反而更小。 */
  aspect-ratio: 3 / 4;
  object-fit: cover;
  transition: transform .5s cubic-bezier(.22, .61, .36, 1);
}

.banner-gallery .banner-tile:hover img.banner-bg {
  transform: scale(1.05);
}

/* 手机端六张挤成一排每张只有 6x px，看不清也点不准。
   改成横向滑动，一屏露出两张半，靠 scroll-snap 对齐。 */
@media (max-width: 767.98px) {
  .banner-gallery .carousel-item > .row {
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }

  .banner-gallery .carousel-item > .row::-webkit-scrollbar {
    display: none;
  }

}

/* ==========================================================================
   灯箱
   ========================================================================== */
.oc-lightbox {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: none;
  align-items: center;
  justify-content: center;
  background-color: rgba(12, 10, 11, .93);
  padding: 5vh 6vw;
}

.oc-lightbox.is-open {
  display: flex;
}

.oc-lb-stage {
  margin: 0;
  max-width: 100%;
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
}

.oc-lb-stage img {
  display: block;
  max-width: 100%;
  /* 减去下方图注和上下留白，保证长图也不会溢出视口 */
  max-height: calc(90vh - 46px);
  object-fit: contain;
  border-radius: 4px;
  animation: oc-lb-in .25s ease;
}

@keyframes oc-lb-in {
  from { opacity: 0; transform: scale(.97); }
  to   { opacity: 1; transform: none; }
}

.oc-lb-stage figcaption {
  color: rgba(255, 255, 255, .8);
  font-size: .85rem;
  letter-spacing: .04em;
  text-align: center;
}

.oc-lightbox button {
  position: absolute;
  border: 0;
  background-color: rgba(255, 255, 255, .1);
  color: #fff;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background-color .2s ease;
}

.oc-lightbox button:hover {
  background-color: var(--brand-accent);
}

.oc-lb-close {
  top: 20px;
  right: 24px;
  width: 44px;
  height: 44px;
  font-size: 1.7rem;
  line-height: 1;
}

.oc-lb-prev,
.oc-lb-next {
  top: 50%;
  transform: translateY(-50%);
  width: 48px;
  height: 48px;
  font-size: 1.1rem;
}

.oc-lb-prev { left: 24px; }
.oc-lb-next { right: 24px; }

.oc-lb-counter {
  position: absolute;
  bottom: 22px;
  left: 50%;
  transform: translateX(-50%);
  color: rgba(255, 255, 255, .6);
  font-size: .8rem;
  letter-spacing: .1em;
}

/* 只有一张图时藏掉翻页控件 */
.oc-lightbox.is-single .oc-lb-prev,
.oc-lightbox.is-single .oc-lb-next,
.oc-lightbox.is-single .oc-lb-counter {
  display: none;
}

@media (max-width: 767.98px) {
  .oc-lightbox {
    padding: 8vh 4vw;
  }

  .oc-lb-prev { left: 8px; }
  .oc-lb-next { right: 8px; }

  .oc-lb-close {
    top: 12px;
    right: 12px;
  }
}

/* ==========================================================================
   客户评价「品」字排版（extension/ecommerce/module/testimonial）
   每屏 5 张：上排 2 张居中，下排 3 张铺满。
   用 6 列网格实现 —— 每张卡跨 2 列，上排从第 2、4 列起就天然居中，
   不需要额外的容器或计算。
   ========================================================================== */
.tm-module {
  margin: 56px 0;
}

.tm-head {
  position: relative;
  text-align: center;
  margin-bottom: 32px;
}

.tm-head h2 {
  margin: 0;
  font-size: clamp(1.6rem, 3vw, 2.6rem);
}

.tm-head p {
  margin: 10px 0 0;
  color: var(--brand-muted);
}

.tm-nav {
  position: absolute;
  top: 50%;
  right: 0;
  transform: translateY(-50%);
  display: flex;
  gap: 8px;
}

.tm-arrow {
  width: 40px;
  height: 40px;
  border: 1px solid var(--brand-line);
  border-radius: 50%;
  background-color: #fff;
  color: var(--brand-ink);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background-color .2s ease, color .2s ease, border-color .2s ease;
}

.tm-arrow:hover:not(:disabled) {
  background-color: var(--brand-ink);
  border-color: var(--brand-ink);
  color: #fff;
}

.tm-arrow:disabled {
  opacity: .35;
  cursor: default;
}

/* 一屏一页，scroll-snap 保证不会停在两页之间 */
.tm-track {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}

.tm-track::-webkit-scrollbar {
  display: none;
}

.tm-page {
  flex: 0 0 100%;
  scroll-snap-align: start;
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 22px;
}

/* 「品」字的五个格位。每张卡跨 2 列：
   上排第 1 张从第 2 列起、第 2 张从第 4 列起 —— 两张合起来占中间 4 列，居中；
   下排三张从第 1、3、5 列起，铺满 6 列。 */
.tm-page .tm-card:nth-child(1) { grid-column: 2 / span 2; }
.tm-page .tm-card:nth-child(2) { grid-column: 4 / span 2; }
.tm-page .tm-card:nth-child(3) { grid-column: 1 / span 2; }
.tm-page .tm-card:nth-child(4) { grid-column: 3 / span 2; }
.tm-page .tm-card:nth-child(5) { grid-column: 5 / span 2; }

.tm-card {
  margin: 0;
  padding: 24px;
  background-color: var(--brand-surface);
  border-radius: var(--oc-radius);
  display: flex;
  flex-direction: column;
  gap: 14px;
  transition: box-shadow .25s ease, transform .25s ease;
}

.tm-card:hover {
  transform: translateY(-3px);
  box-shadow: 0 8px 24px rgba(0, 0, 0, .08);
}

.tm-top {
  position: relative;
  display: flex;
  align-items: center;
  gap: 14px;
}

.tm-avatar {
  flex: 0 0 54px;
  width: 54px;
  height: 54px;
  border-radius: 50%;
  overflow: hidden;
  background-color: var(--brand-accent);
  display: flex;
  align-items: center;
  justify-content: center;
}

.tm-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* 没上传头像时用姓名首字母顶上，避免破图 */
.tm-initial {
  color: #fff;
  font-family: var(--brand-font);
  font-size: 1.3rem;
  font-weight: 700;
  line-height: 1;
}

.tm-who {
  min-width: 0;
}

.tm-stars {
  color: var(--brand-star);
  font-size: .78rem;
  letter-spacing: .05em;
  margin-bottom: 3px;
}

.tm-name {
  font-family: var(--brand-font);
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--brand-ink);
  line-height: 1.2;
}

.tm-title {
  font-size: .78rem;
  color: var(--brand-muted);
  margin-top: 2px;
}

/* 「已核实买家」的绿勾。由后台每行的勾选项控制，见
   extension/ecommerce/catalog/controller/module/testimonial.php。

   ⚠ 用绿色而不是品牌色：绿色是「已核实 / 通过」的通用语义，
     换成品牌蓝会被读成装饰图标，那这个勾就白加了。
   ⚠ 别用浅绿：这一行本身是 .78rem 的次要灰字，
     对比度不够的话勾在浅色卡片底上几乎看不见。 */
.tm-verified {
  margin-right: 4px;
  color: #157F4C;              /* 和落地页的 --lp-ok 同一个绿，全站一致 */
  font-size: .82rem;
  vertical-align: -1px;
}

.tm-quote {
  position: absolute;
  top: 0;
  right: 0;
  font-size: 1.5rem;
  color: var(--brand-accent);
  opacity: .28;
}

.tm-text {
  margin: 0;
  font-size: .9rem;
  line-height: 1.65;
  color: #4a4245;
}

/* 平板：品字塌成两列，格位重排 */
@media (max-width: 991.98px) {
  .tm-page {
    grid-template-columns: repeat(2, 1fr);
    gap: 16px;
  }

  .tm-page .tm-card:nth-child(n) {
    grid-column: auto;
  }

  /* 5 是奇数，最后一张单独占满一行才不会留半个空格 */
  .tm-page .tm-card:nth-child(5) {
    grid-column: 1 / -1;
  }
}

/* 手机：单列，标题下方的箭头挪到标题下面居中 */
@media (max-width: 575.98px) {
  .tm-module {
    margin: 36px 0;
  }

  .tm-page {
    grid-template-columns: 1fr;
  }

  .tm-page .tm-card:nth-child(5) {
    grid-column: auto;
  }

  .tm-nav {
    position: static;
    transform: none;
    justify-content: center;
    margin-top: 14px;
  }
}

/* ==========================================================================
   移动端：评价与图册统一改成「单卡横滑 + 露出下一张」
   露出一角是唯一可靠的可滑动信号 —— 卡片正好铺满一屏时，
   用户无法从静止画面判断右边还有内容。
   ========================================================================== */
@media (max-width: 767.98px) {
  /* --- 客户评价 --- */

  /* 让页容器让位，5 张卡直接成为轨道的 flex 项。
     display:contents 的元素自身不生成盒子，但子元素保留在原层级，
     所以品字网格在这里自动失效，不用逐条覆盖 grid-column。 */
  .tm-page {
    display: contents;
  }

  .tm-track {
    gap: 14px;
    padding: 4px 16px 10px;
    /* 吸附时给左侧留出和 padding 等宽的余量，否则卡片会顶死屏幕边缘 */
    scroll-padding-left: 16px;
  }

  .tm-card {
    flex: 0 0 78%;          /* 剩下 22% 用来露出下一张 */
    scroll-snap-align: start;
  }

  /* --- Images Gallery --- */
  .banner-gallery .carousel-item > .row {
    gap: 10px;
    padding: 0 14px 6px;
    scroll-padding-left: 14px;
  }

  .banner-gallery .banner-tile {
    border-radius: 12px;
  }

  /* 通栏时图册两端不再贴死，和上面的 padding 呼应 */
  .banner-gallery {
    margin-bottom: 8px;
  }
}

/* ==========================================================================
   图册：横向滚动条 + 箭头
   原来桌面端用 flex:1 1 0 等分，六张正好铺满就没有可滚动的余量，
   箭头也就无事可做。改成固定基准宽度，超出部分横向滚动。
   ========================================================================== */
.banner-gallery .carousel-item > .row {
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}

.banner-gallery .carousel-item > .row::-webkit-scrollbar {
  display: none;
}

/* 吸附对齐对所有断点都要，宽度则按断点分三档 */
.banner-gallery .carousel-item > .row > [class*="col-"] {
  scroll-snap-align: start;
}

/* 桌面一屏六张：减掉 5 条 3px 的缝再六等分 */
/* 一屏 4 张。原来是 6 张，减到 4 张单卡宽度正好 ×1.5。
   3px × 3 条缝，所以减 9px 再四等分。 */
@media (min-width: 992px) {
  .banner-gallery .carousel-item > .row > [class*="col-"] {
    flex: 0 0 calc((100% - 9px) / 4);
  }
}

@media (min-width: 768px) and (max-width: 991.98px) {
  .banner-gallery .carousel-item > .row > [class*="col-"] {
    flex: 0 0 calc((100% - 6px) / 3);
  }
}

/* 手机端只能加到 88%，做不到 ×1.5（78% × 1.5 = 117%，超出屏宽）。
   88% 是保留「露出下一张」这个可滑动信号的前提下的实际上限 ——
   再宽就看不出右边还有内容了。 */
@media (max-width: 767.98px) {
  .banner-gallery .carousel-item > .row > [class*="col-"] {
    flex: 0 0 88%;
  }
}

/* --- 箭头 --- */
.gal-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 3;
  width: 46px;
  height: 46px;
  border: 0;
  border-radius: 50%;
  background-color: rgba(255, 255, 255, .92);
  color: var(--brand-ink);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 12px rgba(0, 0, 0, .16);
  opacity: 0;
  transition: opacity .25s ease, background-color .2s ease, color .2s ease;
}

/* 桌面端默认隐藏，鼠标进入图册才浮现，不挡图 */
.banner-gallery:hover .gal-arrow,
.gal-arrow:focus-visible {
  opacity: 1;
}

.gal-arrow:hover {
  background-color: var(--brand-ink);
  color: #fff;
}

.gal-prev { left: 18px; }
.gal-next { right: 18px; }

/* 既滚不动又只有一屏时，JS 打上 is-idle，箭头整对藏掉 */
.banner-gallery.is-idle .gal-arrow {
  display: none;
}

/* 手机端没有 hover，箭头常驻但压低存在感；尺寸也收小一档 */
@media (max-width: 767.98px) {
  .gal-arrow {
    opacity: 1;
    width: 38px;
    height: 38px;
    font-size: .85rem;
    background-color: rgba(255, 255, 255, .86);
  }

  .gal-prev { left: 8px; }
  .gal-next { right: 8px; }
}

/* ==========================================================================
   图册标题块的字号对齐客户评价
   标题来自紧挨在图册之前的那个 HTML Content 模块。
   content_bottom.twig 是 {% for module in modules %}{{ module }}{% endfor %}，
   模块之间没有包裹层，所以相邻兄弟选择器能精确命中前一个模块的 div。
   ========================================================================== */
div:has(+ .banner-gallery) {
  text-align: center;
  margin-bottom: 18px;
}

div:has(+ .banner-gallery) h1,
div:has(+ .banner-gallery) h2,
div:has(+ .banner-gallery) h3,
div:has(+ .banner-gallery) h4,
div:has(+ .banner-gallery) h5 {
  /* 与 .tm-head h2 完全同值，两个区块标题才在同一视觉层级 */
  font-family: var(--brand-font);
  font-size: clamp(1.6rem, 3vw, 2.6rem);
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 0;
}

div:has(+ .banner-gallery) p {
  margin: 10px 0 0;
  color: var(--brand-muted);
}

/* ==========================================================================
   清掉 Banner 轮播的默认外框
   bootstrap.css:11805 给所有 .carousel 加了：
     border: 4px solid #fff;  border-radius: 4px;
     box-shadow: 0 1px 4px rgba(0,0,0,.2);
   普通轮播上这圈投影只是一点柔光，但大轮播和图册是 100vw 通栏，
   投影会被拉成横跨整个视口的两条横线，跟前后区块的过渡就断了。

   只作用于带 data-items 的 banner 模块轮播，商品详情页那些原生轮播不动。
   margin-bottom 不在这里重置 —— 三种形态各自有自己的值。
   ========================================================================== */
.carousel[data-items] {
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

/* ==========================================================================
   修正：图册横滑时第一张被切
   模板根元素是 <div class="row justify-content-center">（OpenCart 原版就有）。
   flex 容器内容溢出时，justify-content:center 会让溢出同时发生在两端，
   而起始端那截落在负坐标上，scrollLeft 最小只能到 0，永远滚不回去。
   桌面端 4 张正好铺满不溢出所以没暴露，手机端一溢出第一张就被吃掉一截。
   Bootstrap 的工具类带 !important，只能同样用 !important 压回去。
   ========================================================================== */
.banner-gallery .carousel-item > .row {
  justify-content: flex-start !important;
}

/* 「查看全部」按钮：仅当还有未展示的文章时才由控制器输出 */
.blog-foot {
  text-align: center;
  margin-top: 28px;
}

.blog-all {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 13px 34px;
  border: 1px solid var(--brand-ink);
  border-radius: 50rem;
  color: var(--brand-ink);
  font-size: .875rem;
  font-weight: 600;
  letter-spacing: .01em;
  text-transform: none;
  transition: background-color .25s ease, color .25s ease;
}

.blog-all:hover {
  background-color: var(--brand-ink);
  color: #fff;
}

.blog-all i {
  font-size: .72rem;
  transition: transform .2s ease;
}

.blog-all:hover i {
  transform: translateX(4px);
}

/* 导航项变多后（HOME/SHOP + 分类 + SPECIALS/BLOG/CONTACT），
   1320px 容器在分类较多时会放不下。收紧左右内边距并允许换行，
   换行时整行居中，不会左满右空。 */
@media (min-width: 992px) {
  #menu .navbar-nav {
    flex-wrap: wrap;
    justify-content: center;
    width: 100%;
  }

  #menu .navbar-nav > li > a {
    padding-left: 14px;
    padding-right: 14px;
  }
}

/* HOME 的图标与文字之间留一点间距，并稍微缩小图标 ——
   Font Awesome 的房子图标在 .8rem 正文里默认偏大，会压过旁边的字母。
   ⚠ 选择器绑死了具体图标类：换 HOME 图标时这里必须同步改，
     否则规则直接失配，图标会变大并贴住文字。 */
#menu .nav-link i.fa-house-medical {
  font-size: .82em;
  margin-right: 5px;
}

/* ==========================================================================
   Masthead 保持白底
   这里原本有一条把 #top/header 改成深色的覆盖（配合更下面的 --brand-dark
   那条，最终头部是近黑色）。深色头部是美妆/时装的语言；医疗零售用白底。
   覆盖已删除，头部底色由上面 :2169 那条 --brand-bg 决定，不要再加覆盖。
   ========================================================================== */

/* 导航 hover：文字和下划线一起转强调色。
   白底上只动下划线不动文字，指示性不够。 */
@media (min-width: 768px) {
  #menu .navbar-nav > li > a:hover,
  #menu .navbar-nav > li > a:focus,
  #menu .navbar-nav > li.show > a {
    color: var(--brand-accent);
    border-bottom-color: var(--brand-accent);
  }
}

/* 购物车按钮：白底头部上唯一的实心色块，正好承担 CTA 角色。
   注意别改成描边样式 —— 它要在一排图标里被一眼认出来。 */
#cart .btn,
#cart .btn:focus {
  background-color: var(--brand-accent);
  border-color: var(--brand-accent);
  color: #fff;
}

#cart .btn:hover,
#cart .btn.show {
  background-color: var(--brand-accent-deep);
  border-color: var(--brand-accent-deep);
  color: #fff;
}

/* ==========================================================================
   移动端头部图标
   头部是白底，图标一律深色。
   汉堡不是字体图标而是内嵌 SVG 背景图（描边色烧在 data URI 里，且带
   !important），改 color 无效，必须整条 background-image 换掉 ——
   stroke 里的 %2316212B 就是 --brand-ink，改主题色时这里要手动跟着改。
   ========================================================================== */
@media (max-width: 767.98px) {
  #menu .navbar-toggler {
    color: var(--brand-ink) !important;
    background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%2316212B'%20stroke-width='2'%20stroke-linecap='round'%3E%3Cpath%20d='M4%207h16M4%2012h16M4%2017h16'/%3E%3C/svg%3E") !important;
  }

  #header-icons .header-icon,
  #header-tools .dropdown-toggle,
  #header-tools .tool-item .dropdown-toggle,
  #header-tools .tool-item a {
    color: var(--brand-ink);
  }

  #header-tools .dropdown-toggle::after,
  #header-icons .header-icon i {
    color: var(--brand-muted);
  }
}

/* ==========================================================================
   公告条：深蓝窄条
   40px 的深蓝窄条给强调色一个固定的小位置。头部改白底之后，
   这条是首屏唯一的大块颜色，压不过内容，又能和下方的按钮呼应。
   ========================================================================== */
#announcement-bar {
  background-color: var(--brand-accent);
}

/* ==========================================================================
   页脚暗色面
   全站只剩页脚一块暗色。用 --brand-dark 而不是 --brand-ink：
   ink 是正文色，要柔和；暗色「面」必须暗到不高于照片里的黑，
   否则页脚压在深色图片下面会显成一条更亮的横带。
   （头部原来也用这个值，改白底后已移除。）
   ========================================================================== */
footer {
  background-color: var(--brand-dark);
  border-top-color: var(--brand-dark);
}

/* ==========================================================================
   下拉菜单文字
   #top a 那条会一起命中下拉面板里的 .dropdown-item，
   所以这里显式指定，不依赖继承。
   下拉面板保持白底 —— 和手机端展开的分类面板一致，全站下拉是同一套语言。
   ========================================================================== */
#top .dropdown-menu .dropdown-item,
#top .dropdown-menu .dropdown-item:visited {
  color: var(--brand-ink);
}

#top .dropdown-menu .dropdown-item:hover,
#top .dropdown-menu .dropdown-item:focus {
  color: var(--brand-accent-deep);
  background-color: var(--brand-surface);
}

/* 面板本身给一点圆角和阴影，从黑色 masthead 上浮出来 */
#top .dropdown-menu,
#menu .dropdown-menu {
  border: 0;
  border-radius: var(--oc-radius);
  box-shadow: 0 10px 30px rgba(0, 0, 0, .35);
}

/* ==========================================================================
   指示点拉回轮播内部
   bootstrap.css:11850 把 .carousel-indicators 设成了 bottom: -50px，
   再叠加基础规则的 margin-bottom: 1rem，圆点净落在轮播下方 34px 处 ——
   于是轮播和下一个区块之间凭空多出一条空白带。
   只作用于带 data-items 的 banner 轮播，商品详情页的原生轮播不动。
   ========================================================================== */
.carousel[data-items] .carousel-indicators {
  bottom: 0;
  margin-bottom: 16px;
}

/* 圆点重做：OpenCart 给的是黑描边 + 内阴影的样式，压在深色图上看不见。
   改成半透明白点 + 一层投影，浅图深图上都能分辨；当前项用品牌粉。 */
.carousel[data-items] .carousel-indicators [data-bs-target] {
  width: 9px;
  height: 9px;
  margin: 0 5px;
  border: 0;
  border-radius: 50%;
  background-color: rgba(255, 255, 255, .55);
  box-shadow: 0 1px 3px rgba(0, 0, 0, .45);
  opacity: 1;
  text-indent: 0;
  transition: background-color .2s ease, transform .2s ease;
}

.carousel[data-items] .carousel-indicators [data-bs-target]:hover {
  background-color: rgba(255, 255, 255, .85);
}

.carousel[data-items] .carousel-indicators .active {
  background-color: var(--brand-accent);
  opacity: 1;
  transform: scale(1.15);
}

/* ==========================================================================
   博客列表页（cms/blog）
   模板：extension/ocmod/catalog/view/template/cms/blog.twig
   右侧两列卡片网格，左侧栏由布局挂模块（分类 / 最新文章 / 推广图）。
   ========================================================================== */
#blog-list .bp-head {
  margin-bottom: 22px;
}

#blog-list .bp-head h1 {
  margin: 0;
  font-size: clamp(1.7rem, 3vw, 2.6rem);
}

#blog-list .bp-intro {
  margin-top: 10px;
  color: var(--brand-muted);
}

/* --- 工具条：搜索 + 排序压成一行 --- */
.blog-toolbar {
  display: flex;
  gap: 12px;
  align-items: center;
  margin-bottom: 26px;
}

.blog-toolbar .bp-search {
  flex: 1 1 auto;
  max-width: 460px;
}

.blog-toolbar .bp-sort {
  flex: 0 0 auto;
  width: auto;
  margin-left: auto;
}

/* --- 卡片网格 --- */
.blog-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 26px;
}

.bp-card {
  border: 1px solid var(--brand-line);
  border-radius: var(--oc-radius);
  overflow: hidden;
  background-color: #fff;
  display: flex;
  flex-direction: column;
  transition: box-shadow .25s ease, transform .25s ease;
}

.bp-card:hover {
  transform: translateY(-3px);
  box-shadow: 0 10px 26px rgba(0, 0, 0, .08);
}

.bp-media {
  display: block;
  overflow: hidden;
}

.bp-media img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  transition: transform .6s cubic-bezier(.22, .61, .36, 1);
}

.bp-card:hover .bp-media img {
  transform: scale(1.04);
}

.bp-body {
  padding: 20px 22px 24px;
  display: flex;
  flex-direction: column;
  /* 卡片等高时让按钮贴底对齐，两列不会一高一低 */
  flex: 1 1 auto;
}

.bp-body h2 {
  margin: 0 0 8px;
  font-family: var(--brand-font);
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.3;
}

.bp-body h2 a {
  color: var(--brand-ink);
}

.bp-body h2 a:hover {
  color: var(--brand-accent-deep);
}

.bp-date {
  display: block;
  font-size: .78rem;
  color: var(--brand-muted);
  margin-bottom: 10px;
}

.bp-body p {
  margin: 0 0 18px;
  font-size: .88rem;
  line-height: 1.7;
  color: var(--brand-muted);
  /* 摘要限两行，两列卡片高度才不会因文案长短参差 */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.bp-more {
  align-self: flex-start;
  margin-top: auto;
  padding: 10px 22px;
  border: 1px solid var(--brand-line);
  border-radius: 4px;
  color: var(--brand-ink);
  font-size: .875rem;
  font-weight: 600;
  letter-spacing: .01em;
  text-transform: none;
  transition: background-color .25s ease, color .25s ease, border-color .25s ease;
}

.bp-more:hover {
  background-color: var(--brand-ink);
  border-color: var(--brand-ink);
  color: #fff;
}

.bp-foot {
  margin-top: 30px;
  align-items: center;
}

@media (max-width: 767.98px) {
  .blog-grid {
    grid-template-columns: 1fr;
    gap: 20px;
  }

  .blog-toolbar {
    flex-wrap: wrap;
  }

  .blog-toolbar .bp-sort {
    margin-left: 0;
    width: 100%;
  }
}

/* ==========================================================================
   左侧栏的模块盒子
   ========================================================================== */
.side-box {
  border: 1px solid var(--brand-line);
  border-radius: var(--oc-radius);
  padding: 18px 20px 20px;
  margin-bottom: 24px;
}

.side-box-title {
  margin: 0 0 12px;
  font-family: var(--brand-font);
  font-size: 1.3rem;
  font-weight: 600;
}

/* 分类列表：去掉 Bootstrap 的边框和圆角，做成纯文字列表 */
.side-topics .list-group {
  margin-bottom: 0;
  border: 0;
}

.side-topics .list-group-item {
  border: 0;
  padding: 7px 0;
  background-color: transparent;
  color: var(--brand-ink);
  font-size: .92rem;
}

.side-topics .list-group-item:hover {
  color: var(--brand-accent-deep);
}

.side-topics .list-group-item.active {
  color: var(--brand-accent);
  font-weight: 600;
}

/* --------------------------------------------------------------------------
   侧栏里的「最新文章」= 首页那个博客模块换个形态。
   模板无法感知自己被挂在哪个位置，所以形态切换只能靠 CSS 用祖先选择器判断。
   特色文章那张大卡在窄栏里放不下，这里把它压成和下面小卡一样的横向条目。
   -------------------------------------------------------------------------- */
#column-left .blog-module {
  border: 1px solid var(--brand-line);
  border-radius: var(--oc-radius);
  padding: 18px 20px 20px;
  margin-bottom: 24px;
}

#column-left .blog-head {
  text-align: left;
  margin-bottom: 12px;
}

#column-left .blog-head h3 {
  font-size: 1.3rem;
}

/* 副标题和「查看全部」在侧栏里是噪音 */
#column-left .blog-head p,
#column-left .blog-foot {
  display: none;
}

#column-left .blog-layout {
  grid-template-columns: 1fr;
  gap: 14px;
}

/* 特色文章压成横向小条，与下面的 .blog-mini 视觉一致 */
#column-left .blog-feature {
  display: flex;
  gap: 12px;
  align-items: center;
}

#column-left .blog-feature .blog-media {
  flex: 0 0 68px;
  border-radius: 6px;
}

#column-left .blog-feature .blog-media img {
  aspect-ratio: 1 / 1;
}

#column-left .blog-feature .blog-date,
#column-left .blog-feature .blog-body p,
#column-left .blog-feature .blog-more,
#column-left .blog-mini-text,
#column-left .blog-mini .blog-more {
  display: none;
}

#column-left .blog-feature .blog-body {
  padding-top: 0;
}

#column-left .blog-feature .blog-body h4 {
  margin: 0;
  font-size: .95rem;
  line-height: 1.35;
}

#column-left .blog-side {
  gap: 14px;
}

#column-left .blog-mini {
  padding: 0;
  background-color: transparent;
  gap: 12px;
  align-items: center;
}

#column-left .blog-mini:hover {
  transform: none;
  box-shadow: none;
}

#column-left .blog-mini-media {
  flex: 0 0 68px;
  border-radius: 6px;
}

#column-left .blog-mini-media img {
  aspect-ratio: 1 / 1;
}

#column-left .blog-mini-body h5 {
  font-size: .95rem;
}

/* 侧栏里的横幅模块（推广图）。
   bootstrap.css:11808 给所有 .carousel 设了 margin-bottom: 50px，
   在窄侧栏里会空出一大块；圆角与上面两个 .side-box 对齐。 */
#column-left .carousel {
  margin-bottom: 24px;
  border-radius: var(--oc-radius);
  overflow: hidden;
}

#column-left .carousel .carousel-item > .row {
  margin: 0;
}

#column-left .carousel .carousel-item > .row > [class*="col-"] {
  padding: 0;
}

#column-left .carousel img {
  display: block;
  width: 100%;
  height: auto;
}

/* ==========================================================================
   联系页（information/contact）
   模板：extension/ocmod/catalog/view/template/information/contact.twig
   左栏联系方式清单 + 右栏表单。
   ========================================================================== */
#information-contact .ct-head {
  text-align: center;
  margin-bottom: 40px;
}

#information-contact .ct-head h1 {
  margin: 0;
  font-size: clamp(1.8rem, 3.4vw, 2.8rem);
}

#information-contact .ct-head p {
  margin: 12px auto 0;
  max-width: 560px;
  color: var(--brand-muted);
  line-height: 1.7;
}

.ct-layout {
  display: grid;
  grid-template-columns: 2fr 3fr;
  gap: 40px;
  align-items: start;
  margin-bottom: 56px;
}

/* --- 左栏：联系方式清单 --- */
.ct-store-image {
  border-radius: var(--oc-radius);
  overflow: hidden;
  margin-bottom: 24px;
}

.ct-store-image img {
  display: block;
  width: 100%;
  height: auto;
}

.ct-item {
  display: flex;
  gap: 16px;
  padding: 18px 0;
  border-bottom: 1px solid var(--brand-line);
}

.ct-item:last-of-type {
  border-bottom: 0;
}

/* 图标用淡粉圆底 + 品牌粉图标：面积小，是粉色最合适的用法 */
.ct-icon {
  flex: 0 0 42px;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  background-color: var(--brand-surface);
  color: var(--brand-accent);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: .95rem;
}

.ct-text {
  min-width: 0;
}

.ct-text strong {
  display: block;
  font-size: .78rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--brand-muted);
  margin-bottom: 5px;
  font-weight: 600;
}

.ct-text address,
.ct-text p {
  margin: 0;
  font-size: .95rem;
  line-height: 1.65;
  color: var(--brand-ink);
  font-style: normal;
}

.ct-text > a {
  font-size: .95rem;
  color: var(--brand-ink);
}

.ct-text > a:hover {
  color: var(--brand-accent-deep);
}

.ct-map {
  display: inline-block;
  margin-top: 8px;
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--brand-accent-deep);
}

.ct-map::after {
  content: " →";
}

.ct-note {
  margin-top: 18px;
  padding: 14px 16px;
  border-radius: var(--oc-radius);
  background-color: var(--brand-surface);
  font-size: .88rem;
  line-height: 1.7;
  color: var(--brand-muted);
}

/* --- 右栏：表单 --- */
.ct-form-wrap {
  border: 1px solid var(--brand-line);
  border-radius: var(--oc-radius);
  padding: 32px 34px 34px;
}

.ct-form-wrap h2 {
  margin: 0 0 24px;
  font-size: 1.5rem;
}

/* 标签放输入框上方而不是左侧 —— 左标签布局在窄栏里会把输入框挤成一条缝，
   而且视线要横向折返，填写速度更慢 */
.ct-row {
  margin-bottom: 18px;
}

.ct-row label {
  display: block;
  margin-bottom: 7px;
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--brand-muted);
}

.ct-row.required label::after {
  content: " *";
  color: var(--brand-sale);
}

.ct-row .form-control {
  border-radius: 6px;
  padding: 12px 14px;
  font-size: .95rem;
}

.ct-row textarea.form-control {
  min-height: 150px;
  resize: vertical;
}

/* invalid-feedback 默认 display:none，只有 .is-invalid 兄弟元素才显示；
   OpenCart 的 ajax 校验是直接往里塞文字，所以这里强制显示非空的那些 */
.ct-row .invalid-feedback:not(:empty) {
  display: block;
  margin-top: 6px;
}

.ct-submit {
  width: 100%;
  margin-top: 8px;
  padding: 14px 24px;
  border-radius: 50rem;
  font-size: .78rem;
  letter-spacing: .12em;
}

/* --- 其他门店 --- */
.ct-stores {
  margin-bottom: 56px;
}

.ct-stores h2 {
  font-size: 1.5rem;
  margin-bottom: 18px;
}

.ct-stores .accordion-item {
  border-color: var(--brand-line);
}

.ct-stores .accordion-button:not(.collapsed) {
  background-color: var(--brand-surface);
  color: var(--brand-ink);
  box-shadow: none;
}

.ct-stores .accordion-button:focus {
  box-shadow: none;
  border-color: var(--brand-line);
}

.ct-loc {
  display: flex;
  gap: 20px;
}

.ct-loc-image {
  flex: 0 0 140px;
  border-radius: 8px;
  overflow: hidden;
}

.ct-loc-image img {
  display: block;
  width: 100%;
  height: auto;
}

.ct-loc-body p,
.ct-loc-body address {
  margin: 0 0 6px;
  font-size: .92rem;
  font-style: normal;
}

@media (max-width: 767.98px) {
  .ct-layout {
    grid-template-columns: 1fr;
    gap: 28px;
  }

  .ct-form-wrap {
    padding: 24px 20px 26px;
  }

  .ct-loc {
    flex-direction: column;
  }

  .ct-loc-image {
    flex: none;
    max-width: 180px;
  }
}

/* ==========================================================================
   单页结账
   模板：extension/ocmod/catalog/view/template/checkout/{checkout,shipping_method,payment_method}.twig
   编排：extension/ocmod/catalog/view/javascript/checkout-onepage.js
   ========================================================================== */

/* --- 隐藏被单页流程取代的原生控件 ---
   都不是删除而是隐藏：CONTINUE 的表单提交逻辑仍在（我们复用它的端点），
   支付扩展的 #button-confirm 更是要留着让 JS 在链条末尾程序化点击。 */
#button-register,
#checkout-register .form-check:has(#input-newsletter),
#checkout-register #register-agree,
#checkout-confirm #button-confirm,
#checkout-confirm .text-end > .btn[disabled] {
  display: none !important;
}

/* --- 地址栅格：长字段在窄屏独占一行 ---
   原版是 row-cols-1 row-cols-md-2，手机端本来就是单列，
   但 768–991 那一档是两列，公司名和两行地址塞不下。 */
@media (max-width: 991.98px) {
  #checkout-register .row-cols-md-2 > .col:has(input[name$="_company"]),
  #checkout-register .row-cols-md-2 > .col:has(input[name$="_address_1"]),
  #checkout-register .row-cols-md-2 > .col:has(input[name$="_address_2"]) {
    flex: 0 0 100%;
    max-width: 100%;
    width: 100%;
  }
}

/* --- 「账单地址与收货地址一致」勾选框 ---
   后台开启「账单地址必填」(config_checkout_payment_address) 后才会出现。
   OpenCart 把它塞进地址两列栅格里，混在输入框中间毫不起眼；
   它是决定「要不要再填一整块地址」的开关，权重远高于一个普通字段，
   所以拉成整行的卡片，跟输入框区分开。默认勾选（register.php:72）。

   checkout-onepage.js 的 reorderAddressBlocks() 把它挪到了账单块的最前面
   （紧跟标题），所以这里不再需要 margin-top 把它和上方字段拉开，
   改成 margin-bottom 和下方字段拉开。 */
#checkout-register .col:has(#input-address-match) {
  flex: 0 0 100%;
  max-width: 100%;
  width: 100%;
  margin-bottom: 6px;
}

#checkout-register .form-check:has(#input-address-match) {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  padding: 12px 14px;
  border: 1px solid var(--brand-line);
  border-radius: 8px;
  background: var(--brand-surface);
  transition: border-color .18s ease, background-color .18s ease;
}

#checkout-register .form-check:has(#input-address-match:checked) {
  border-color: var(--brand-tint-line);
  background: var(--brand-tint);
}

#checkout-register #input-address-match {
  flex: none;
  float: none;
  margin: 0;
  width: 18px;
  height: 18px;
  cursor: pointer;
}

#checkout-register #input-address-match:checked {
  background-color: var(--brand-accent);
  border-color: var(--brand-accent);
}

#checkout-register #input-address-match:focus {
  border-color: var(--brand-accent);
  box-shadow: 0 0 0 .2rem rgba(var(--brand-accent-rgb), .18);
}

#checkout-register .form-check:has(#input-address-match) .form-check-label {
  margin: 0;
  font-size: .94rem;
  line-height: 1.35;
  cursor: pointer;
}

/* 收货地址块被勾选框隐藏后，上方 legend 的间距会显得突兀 —— 收一下 */
#checkout-register #shipping-address {
  margin-top: 6px;
}

/* --- 电话 + 国际区号 --- */
.op-tel {
  flex-wrap: nowrap;
}

.op-tel .op-dial {
  flex: 0 0 96px;
  width: 96px;
  border-right: 0;
  background-position: right .5rem center;
  padding-right: 1.6rem;
}

/* --- 配送 / 支付：内联单选 --- */
.op-block {
  margin-bottom: 22px;
}

.op-block legend {
  font-family: var(--brand-font);
  font-size: 1.4rem;
  font-weight: 600;
  border-bottom: 1px solid var(--brand-line);
  padding-bottom: 10px;
  margin-bottom: 14px;
}

.op-options {
  border: 1px solid var(--brand-line);
  border-radius: var(--oc-radius);
  overflow: hidden;
}

.op-option {
  display: flex;
  /* 卡组织标志固定另起一行（.op-option-brands 的 flex-basis:100%），
     所以必须允许换行 */
  flex-wrap: wrap;
  /* 顶对齐：通道带描述时是三行高，居中会让圆点飘到第二行中间，
     和它要标记的标题对不上 */
  align-items: flex-start;
  gap: 12px;
  padding: 16px;
  cursor: pointer;
  border-bottom: 1px solid var(--brand-line);
  transition: background-color .18s ease;
}

.op-option:last-child {
  border-bottom: 0;
}

/* 排除已选中项 —— 否则悬停色比选中色还深，鼠标一划过就像选中态被取消了 */
.op-option:hover:not(.is-selected) {
  background-color: var(--brand-surface);
}

/* 选中项整行提示，不只是那个小圆点 —— 结账页的选择要一眼看清。
   底色比 --brand-surface 更淡：只有一个通道且默认选中时，
   整块粉底占满视野，用「左侧色条 + 极淡底」表达选中就够了。 */
.op-option.is-selected {
  background-color: var(--brand-surface);
  box-shadow: inset 3px 0 0 var(--brand-accent);
}

.op-option input[type="radio"] {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  accent-color: var(--brand-accent);
  /* 标题行高约 23px，圆点 18px —— 顶对齐之后补 3px 才和文字视觉齐平 */
  margin: 3px 0 0;
}

/* ⚠ flex-basis 必须是 0，不能是 auto。
   auto 时这一项的「假想主尺寸」等于 max-content —— 描述是一整句长句，
   max-content 远宽于容器，于是在 flex-wrap 开启后它整块掉到第二行，
   把 18px 的圆点孤零零留在第一行。basis 归零后它只占剩余空间，
   圆点和标题才会回到同一行。 */
.op-option-body {
  flex: 1 1 0;
  min-width: 0;
}

.op-option-name {
  display: block;
  font-size: .95rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--brand-ink);
}

/* 安全卡通道的名称用绿字，和左边的盾牌成一组「已验证」信号。
   is-secure 由 checkout-onepage.js 按 option.secure 加，
   银行转账 / 货到付款这些普通通道仍是常规深色。 */
.op-option-name.is-secure {
  display: inline-flex;
  align-items: center;
  color: var(--secure-green);
}

.op-option-price {
  flex: 0 0 auto;
  font-weight: 600;
  font-size: .95rem;
}

.op-note {
  padding: 14px 16px;
  font-size: .88rem;
  color: var(--brand-muted);
}

.op-note-error {
  color: var(--brand-sale);
}

/* 自动切到免邮的提示。放在配送方式列表最上方，
   下一次重新报价时随整块 html() 一起消失 —— 它说明的是「刚刚发生的这次变化」，
   不是一条常驻声明。 */
.op-note-free {
  display: flex;
  align-items: center;
  gap: 8px;
  border-bottom: 1px solid var(--brand-line);
  background-color: #F1FAF4;
  color: var(--secure-green);
  font-weight: 600;
}

.op-note-free::before {
  content: "✓";
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background-color: var(--secure-green);
  color: #fff;
  font-size: .7rem;
}

.op-loading {
  padding: 18px 16px;
  color: var(--brand-muted);
  letter-spacing: .3em;
}

.op-comment {
  margin-bottom: 22px;
}

.op-comment .form-label {
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--brand-muted);
}

/* --- 下单按钮 + 条款说明 --- */
#onepage-actions {
  margin-top: 20px;
}

#button-place-order {
  width: 100%;
  padding: 16px 24px;
  border-radius: 50rem;
  font-size: .875rem;
  font-weight: 600;
  letter-spacing: .01em;
  text-transform: none;
}

#button-place-order.is-busy {
  opacity: .6;
  cursor: progress;
}

#onepage-terms {
  margin-top: 12px;
  font-size: .78rem;
  line-height: 1.6;
  color: var(--brand-muted);
  text-align: center;
}

#onepage-terms a {
  color: var(--brand-accent-deep);
  text-decoration: underline;
}

/* ==========================================================================
   单页结账 —— 分栏与订单摘要卡片
   左栏：个人信息 → 地址 → 配送 → 支付 → 备注
   右栏：订单摘要 + 下单按钮，sticky 跟随滚动
   ========================================================================== */
.op-layout {
  --op-gap: 40px;
  gap: 0;
}

.op-col-form {
  padding-right: calc(var(--op-gap) / 2);
}

.op-col-summary {
  padding-left: calc(var(--op-gap) / 2);
}

/* 摘要跟随滚动。top 必须留出**吸顶后的头部高度**，不是一个随手写的小数值 ——
   这条规则写在头部吸顶之前，当时 top:24px 是对的；头部改成 sticky 之后
   摘要卡就会滑到头部底下去，顶部一截被盖住。 */
@media (min-width: 992px) {
  .op-sticky {
    position: sticky;
    top: calc(var(--oc-header-stuck) + 32px);
  }
}

/* 摘要栏里现在还装着卡表单和信任区，整块可能比视口还高。
   sticky 元素一旦高过视口就会被钉在 top 处，下半截（Place Order、信任区）
   永远滑不出来 —— 用户点不到下单按钮。checkout-onepage.js 的 syncSticky()
   量完高度后决定挂不挂这个类。
   两个类名的特异度（0,2,0）压过上面媒体查询里的 .op-sticky（0,1,0）。 */
.op-sticky.is-static {
  position: static;
}

/* 左栏各区块之间的分隔 */
.op-col-form > div {
  margin-bottom: 26px;
}

.op-col-form legend,
.op-col-form fieldset > legend {
  font-family: var(--brand-font);
  font-size: 1.4rem;
  font-weight: 600;
  border-bottom: 1px solid var(--brand-line);
  padding-bottom: 10px;
  margin-bottom: 16px;
}

.op-col-form .form-label {
  font-size: .74rem;
  font-weight: 600;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--brand-muted);
  margin-bottom: 6px;
}

.op-col-form .form-control,
.op-col-form .form-select {
  border-radius: 8px;
  padding: 11px 13px;
  font-size: .95rem;
}

/* ==========================================================================
   订单摘要卡片
   ========================================================================== */
.op-summary {
  border: 1px solid var(--brand-line);
  border-radius: var(--oc-radius);
  overflow: hidden;
  background-color: #fff;
}

.op-summary-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 16px 20px;
  border-bottom: 1px solid var(--brand-line);
}

.op-summary-title {
  font-family: var(--brand-font);
  font-size: 1.15rem;
  font-weight: 600;
}

.op-summary-count {
  min-width: 22px;
  height: 22px;
  padding: 0 7px;
  border-radius: 50rem;
  background-color: var(--brand-accent);
  color: #fff;
  font-size: .72rem;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.op-summary-items {
  padding: 4px 20px;
  /* 商品很多时不要把右栏拉得比左栏还长，超出部分内部滚动。
     卡片带加减器之后一张约 92px，400px 正好露出第 4 张的一角，
     用户能看出「下面还有」。 */
  max-height: 400px;
  overflow-y: auto;
}

/* --------------------------------------------------------------------------
   商品卡片
   电脑端和手机端同一套版式 —— 右栏最窄（col-lg-5 @992px）约 330px 内宽，
   手机端约 345px，两者差不多，没必要分两套。
   -------------------------------------------------------------------------- */
.op-item {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  padding: 16px 0;
  border-bottom: 1px solid var(--brand-line);
}

.op-item:last-child {
  border-bottom: 0;
}

/* 数量提交期间整张卡压暗。加减器本身保持可点 ——
   连点几下由 450ms 的防抖合并成一次请求，不该在这里挡住用户 */
.op-item.is-updating {
  opacity: .55;
  transition: opacity .15s ease;
}

.op-item-media {
  flex: 0 0 62px;
  width: 62px;
  height: 62px;
  border: 1px solid var(--brand-line);
  border-radius: 10px;
  overflow: hidden;
  display: block;
  background-color: var(--brand-surface);
}

.op-item-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.op-item-body {
  flex: 1 1 auto;
  min-width: 0;
}

.op-item-name {
  display: block;
  font-size: .92rem;
  font-weight: 600;
  line-height: 1.35;
  color: var(--brand-ink);
}

.op-item-name:hover {
  color: var(--brand-accent-deep);
}

.op-item-meta {
  list-style: none;
  margin: 6px 0 0;
  padding: 0;
  font-size: .76rem;
  line-height: 1.5;
  color: var(--brand-muted);
}

/* 缺货 / 低于起订量。这一行会让 confirm.php 拒发支付按钮，
   所以必须在卡片上说清楚是哪个商品，而不是等用户点了下单才报错。 */
.op-item-warn {
  margin-top: 4px;
  font-weight: 600;
  color: #B3261E;
}

.op-item.is-blocked .op-item-media {
  border-color: #B3261E;
}

/* 右侧一列：单价在上，加减器在下 */
.op-item-side {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 10px;
}

/* 单行金额压成次要色 —— 真正要被看清的是下面那个 Order Total。
   一屏里三种金额都用黑体加粗，等于一种都没突出。 */
.op-item-total {
  font-size: .92rem;
  font-weight: 600;
  white-space: nowrap;
  color: var(--brand-muted);
}

/* --------------------------------------------------------------------------
   数量加减器
   -------------------------------------------------------------------------- */
.op-qty {
  display: inline-flex;
  align-items: stretch;
  border: 1px solid var(--brand-line);
  border-radius: 8px;
  overflow: hidden;
  background-color: #fff;
}

.op-qty-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  /* 30px 已经小于 44px 的触摸目标建议值，但摘要区宽度有限，
     再大就挤掉金额了。上下 padding 由卡片间距补偿。 */
  width: 30px;
  height: 30px;
  padding: 0;
  border: 0;
  background: none;
  font-size: 1rem;
  line-height: 1;
  color: var(--brand-ink);
  cursor: pointer;
  transition: background-color .15s ease;
}

.op-qty-btn:hover:not(:disabled) {
  background-color: var(--brand-surface);
}

.op-qty-btn:disabled {
  color: #C2C9CE;
  cursor: default;
}

.op-qty-num {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 34px;
  padding: 0 4px;
  border-left: 1px solid var(--brand-line);
  border-right: 1px solid var(--brand-line);
  font-size: .85rem;
  font-weight: 600;
  /* 数量变化时数字宽度不该让整个控件抖动 */
  font-variant-numeric: tabular-nums;
  color: var(--brand-ink);
}

.op-summary-totals {
  padding: 14px 20px 18px;
  border-top: 1px solid var(--brand-line);
  background-color: var(--brand-surface);
}

.op-total-row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 5px 0;
  font-size: .88rem;
  color: var(--brand-muted);
}

.op-total-row.is-grand {
  margin-top: 8px;
  padding-top: 12px;
  border-top: 1px solid var(--brand-line);
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--brand-ink);
}

/* 摘要区块之间的间距由 .op-sticky 统一给 */
#checkout-confirm {
  margin-bottom: 0;
}

/* ==========================================================================
   窄屏：单列
   不把摘要提到最前面 —— 下单按钮和摘要在同一个容器里，摘要上移的话
   按钮会跑到表单前面，用户还没填就看到「下单」，反而更糟。
   顺序保持：表单 → 摘要 → 下单按钮，符合从上到下的完成顺序。
   ========================================================================== */
@media (max-width: 991.98px) {
  /* ⚠ 这里绝不能设成 0。父级 .row 带着 -12px 负外边距，
     col 的正内边距是用来抵消它的；抽掉正的，内容就被拉到容器外，
     整片表单会贴死屏幕边缘。恢复 Bootstrap 的默认半沟槽。 */
  .op-col-form,
  .op-col-summary {
    padding-left: calc(var(--bs-gutter-x, 1.5rem) * .5);
    padding-right: calc(var(--bs-gutter-x, 1.5rem) * .5);
  }

  .op-col-summary {
    margin-top: 4px;
  }

  /* 商品列表在窄屏不限高，内部再套一层滚动会和页面滚动打架 */
  .op-summary-items {
    max-height: none;
    overflow-y: visible;
  }
}

/* ==========================================================================
   结账表单在窄屏一律单列
   不依赖 Bootstrap 的 row-cols-1 —— 它太容易被别处的通用规则压掉
   （上面那条商品栅格规则就干过一次）。这里显式声明，作用域限定在结账页。
   ========================================================================== */
@media (max-width: 767.98px) {
  #checkout-checkout .op-col-form .row > .col,
  #checkout-checkout .op-col-form .row > [class*="col-"] {
    flex: 0 0 100% !important;
    max-width: 100% !important;
    width: 100% !important;
  }

  /* 沟槽恢复默认，别被商品栅格那条 4px 波及 */
  #checkout-checkout .op-col-form .row {
    --bs-gutter-x: 1.5rem;
    --bs-gutter-y: 0;
  }

  #checkout-checkout .op-col-form .row > .col {
    margin-bottom: 1rem !important;
  }
}

/* 电话输入框：区号下拉收窄，把宽度让给号码本身 */
.op-tel .op-dial {
  flex: 0 0 84px;
  width: 84px;
}

@media (max-width: 575.98px) {
  .op-tel .op-dial {
    flex: 0 0 78px;
    width: 78px;
    padding-left: .5rem;
    padding-right: 1.3rem;
    background-position: right .35rem center;
  }
}

/* ==========================================================================
   结账页手机端：留白与字号
   ========================================================================== */
@media (max-width: 767.98px) {
  /* 容器整体加宽留白。改容器而不是改内层某一级，
     标题、表单、摘要才会对齐在同一条基线上（16px）。 */
  #checkout-checkout {
    padding-left: 16px;
    padding-right: 16px;
  }

  #checkout-checkout > h1,
  #checkout-checkout #content > h1 {
    font-size: 1.65rem;
  }

  /* 区块标题从桌面的 1.4rem 收到 1.15rem —— 手机上 1.4rem 一行只放得下几个词，
     和正文的层级差也过大 */
  #checkout-checkout .op-col-form legend,
  #checkout-checkout .op-col-form fieldset > legend {
    font-size: 1.15rem;
    padding-bottom: 8px;
    margin-bottom: 12px;
  }

  #checkout-checkout .op-col-form .form-label {
    font-size: .68rem;
    letter-spacing: .06em;
  }

  /* 必须 ≥16px。iOS Safari 在聚焦小于 16px 的输入框时会自动放大整个页面，
     用户填完还得手动缩回去，是移动端表单最常见的体验事故。 */
  #checkout-checkout .form-control,
  #checkout-checkout .form-select,
  #checkout-checkout textarea {
    font-size: 16px;
    padding: 10px 12px;
  }

  #checkout-checkout .op-block legend {
    font-size: 1.15rem;
  }

  #checkout-checkout .op-summary-title {
    font-size: 1.05rem;
  }

  #checkout-checkout .op-option {
    padding: 13px 14px;
  }

  #checkout-checkout #button-place-order {
    padding: 15px 20px;
    font-size: .78rem;
  }
}

/* 下单按钮的忙碌态：换文案 + 转圈。
   下单要跑多个串行请求，末尾还要通过 SMTP 发订单邮件，
   慢的时候有好几秒 —— 没有进度反馈用户会以为没点上，然后重复点击。 */
#button-place-order.is-busy {
  opacity: 1;
  cursor: progress;
  background-color: var(--brand-ink);
  border-color: var(--brand-ink);
}

.op-spinner {
  display: inline-block;
  width: 14px;
  height: 14px;
  margin-right: 9px;
  vertical-align: -2px;
  border: 2px solid rgba(255, 255, 255, .35);
  border-top-color: #fff;
  border-radius: 50%;
  animation: op-spin .7s linear infinite;
}

@keyframes op-spin {
  to { transform: rotate(360deg); }
}

/* ==========================================================================
   通用结果页（common/success.twig）
   下单成功 / 支付失败 / 注册成功 / 退出登录 / 联系表单提交 共用一套版式
   ========================================================================== */
.rs-panel {
  max-width: 560px;
  margin: 40px auto 80px;
  text-align: center;
}

.rs-icon {
  width: 68px;
  height: 68px;
  margin: 0 auto 24px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.7rem;
  color: #fff;
}

.rs-success .rs-icon {
  background-color: var(--brand-accent);
  /* 粉底外扩一圈同色淡光，比纯色圆点更有分量 */
  box-shadow: 0 0 0 10px rgba(var(--brand-accent-rgb), .12);
}

.rs-failure .rs-icon {
  background-color: var(--brand-sale);
  box-shadow: 0 0 0 10px rgba(158, 58, 76, .12);
}

.rs-panel h1 {
  margin: 0 0 18px;
  font-size: clamp(1.7rem, 3.2vw, 2.5rem);
  line-height: 1.2;
}

/* 订单号：等宽字体 + 可选中。客户要复制它去问客服，
   衬线体和字距会让数字难辨认 */
.rs-order {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 22px;
  padding: 10px 18px;
  border: 1px solid var(--brand-line);
  border-radius: 50rem;
  background-color: var(--brand-surface);
}

.rs-order-label {
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--brand-muted);
}

.rs-order-id {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: 1rem;
  font-weight: 600;
  color: var(--brand-ink);
  user-select: all;
}

/* ── 下单成功页：确认邮件提示 ──────────────────────────────────
   ⚠ 只在 checkout/success 出现。common/success.twig 被 7 个控制器共用，
     模板里按「有没有 text_mail_notice」判断，这里只管样式。

   ⚠ 块内**左对齐**，和结果页其它部分的居中不同 —— 这是故意的：
     居中排版的多行正文每行起点都不一样，两行以上就难读。
     整块本身仍然居中（margin-inline:auto），所以不破坏页面轴线。 */
.rs-mail {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  max-width: 560px;
  margin: 22px auto 0;
  padding: 16px 18px;
  border: 1px solid var(--brand-line);
  border-left: 3px solid var(--brand-accent);
  border-radius: 10px;
  background: var(--brand-tint);
  text-align: left;
}

.rs-mail-ico {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: #FFFFFF;
  border: 1px solid var(--brand-line);
  color: var(--brand-accent);
  font-size: 15px;
  line-height: 1;
}

/* ⚠ min-width:0 必须写。flex 子项默认 min-width:auto，正文里那个
   长邮箱地址会把它撑开、把卡片挤出容器 —— 手机上直接横向溢出。 */
.rs-mail-body { min-width: 0; }

.rs-mail-h {
  margin: 0 0 6px;
  font-size: 0.9375rem;
  font-weight: 700;
  line-height: 1.5;
  color: var(--brand-ink);
}

.rs-mail-p {
  margin: 0;
  font-size: 0.875rem;
  line-height: 1.7;
  color: var(--brand-muted);
  overflow-wrap: anywhere;
}

.rs-mail-p a {
  font-weight: 600;
  color: var(--brand-accent);
  text-decoration: none;
}

.rs-mail-p a:hover { text-decoration: underline; }

/* 手机：图标挪到文字上方，正文拿到整个宽度。
   34px 的图标 + 14px 间距在 320px 屏上要吃掉 15% 的行宽。 */
@media (max-width: 575.98px) {
  .rs-mail {
    flex-direction: column;
    gap: 10px;
    padding: 14px 16px;
  }
}

.rs-message {
  font-size: .95rem;
  line-height: 1.8;
  color: var(--brand-muted);
}

.rs-message p {
  margin: 0 0 10px;
}

.rs-message a {
  color: var(--brand-accent-deep);
}

.rs-actions {
  margin-top: 30px;
}

.rs-continue {
  min-width: 240px;
  padding: 15px 32px;
  border-radius: 50rem;
  font-size: .875rem;
  font-weight: 600;
  letter-spacing: .01em;
  text-transform: none;
}

@media (max-width: 575.98px) {
  .rs-panel {
    margin: 24px auto 56px;
  }

  .rs-continue {
    width: 100%;
  }
}

/* ==========================================================================
   会员中心
   模板：extension/ocmod/catalog/view/template/account/account.twig
         extension/ocmod/.../extension/opencart/module/account.twig（侧栏，双路径）
   数据：catalog/controller/account/account.php 的自定义补丁

   原版是四组等权重的纯文字链接，登录后连自己是谁都看不到；
   手机端侧栏还被 column_right.twig 的 d-none d-md-block 整个隐藏，
   只剩一列光秃秃的链接。这里整体改成「会员卡 + 图标卡片网格」。
   ========================================================================== */

/* --------------------------------------------------------------------------
   顶部会员卡
   -------------------------------------------------------------------------- */
.ac-hero {
  margin: 4px 0 34px;
  border-radius: 16px;
  overflow: hidden;
  background:
    radial-gradient(120% 160% at 12% 0%, rgba(var(--brand-accent-rgb), .30) 0%, rgba(var(--brand-accent-rgb), 0) 58%),
    var(--brand-dark);
  color: #fff;
}

.ac-hero-main {
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 26px 30px;
}

.ac-avatar {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: var(--brand-accent);
  font-family: var(--brand-font);
  font-size: 1.6rem;
  font-weight: 600;
  line-height: 1;
  letter-spacing: .02em;
  color: #fff;
  /* 首字母基线偏上，向下推 2px 才是视觉居中 */
  padding-top: 2px;
}

.ac-hero-id {
  flex: 1 1 auto;
  min-width: 0;
}

.ac-hero-name {
  margin: 0 0 4px;
  font-family: var(--brand-font);
  font-size: 1.7rem;
  font-weight: 600;
  line-height: 1.2;
  color: #fff;
  /* 姓名过长时截断，不能把退出按钮挤出卡片 */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ac-hero-email {
  display: block;
  font-size: .88rem;
  color: rgba(255, 255, 255, .62);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ac-logout {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 20px;
  border: 1px solid rgba(255, 255, 255, .28);
  border-radius: 50rem;
  font-size: .875rem;
  font-weight: 600;
  letter-spacing: .01em;
  text-transform: none;
  text-decoration: none;
  color: rgba(255, 255, 255, .82);
  transition: border-color .18s ease, background-color .18s ease, color .18s ease;
}

.ac-logout:hover,
.ac-logout:focus {
  border-color: #fff;
  background: rgba(255, 255, 255, .1);
  color: #fff;
}

/* --- 统计块：整块可点，直达对应列表页 --- */
.ac-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  border-top: 1px solid rgba(255, 255, 255, .12);
}

/* 积分未开启时只有两块，此时按两列均分，避免右侧留一段空白 */
.ac-stats:has(.ac-stat:nth-child(2):last-child) {
  grid-template-columns: repeat(2, 1fr);
}

.ac-stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 16px 10px 18px;
  text-decoration: none;
  color: #fff;
  transition: background-color .18s ease;
}

.ac-stat + .ac-stat {
  border-left: 1px solid rgba(255, 255, 255, .12);
}

.ac-stat:hover,
.ac-stat:focus {
  background: rgba(255, 255, 255, .07);
  color: #fff;
}

.ac-stat strong {
  font-family: var(--brand-font);
  font-size: 1.5rem;
  font-weight: 600;
  line-height: 1.1;
}

.ac-stat span {
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .58);
}

/* --------------------------------------------------------------------------
   分组与卡片网格
   -------------------------------------------------------------------------- */
.ac-section {
  margin-bottom: 32px;
}

.ac-section-title {
  margin: 0 0 14px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--brand-line);
  font-family: var(--brand-font);
  font-size: 1.3rem;
  font-weight: 600;
  color: var(--brand-ink);
}

.ac-grid {
  display: grid;
  /* auto-fill + minmax：宽屏自动排 3 列，中屏 2 列，窄屏 1 列，
     不用写死断点；某组只有 1 项时也不会被拉满整行 */
  grid-template-columns: repeat(auto-fill, minmax(258px, 1fr));
  gap: 14px;
}

.ac-tile {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 16px 16px 16px 18px;
  border: 1px solid var(--brand-line);
  border-radius: 12px;
  background: var(--brand-bg);
  text-decoration: none;
  color: var(--brand-ink);
  transition: border-color .18s ease, box-shadow .18s ease, transform .18s ease;
}

.ac-tile:hover,
.ac-tile:focus {
  border-color: var(--brand-accent);
  box-shadow: 0 6px 20px rgba(var(--brand-accent-rgb), .12);
  transform: translateY(-2px);
  color: var(--brand-ink);
}

.ac-tile-icon {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 11px;
  background: var(--brand-surface);
  font-size: 1rem;
  color: var(--brand-accent-deep);
  transition: background-color .18s ease, color .18s ease;
}

.ac-tile:hover .ac-tile-icon {
  background: var(--brand-accent);
  color: #fff;
}

.ac-tile-body {
  flex: 1 1 auto;
  min-width: 0;
}

.ac-tile-title {
  display: block;
  font-size: .97rem;
  font-weight: 600;
  line-height: 1.3;
}

.ac-tile-desc {
  display: block;
  margin-top: 2px;
  font-size: .8rem;
  line-height: 1.35;
  color: var(--brand-muted);
  /* 长描述（法语普遍比英语长 20%）截断到一行，卡片高度才能对齐 */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ac-tile-arrow {
  flex: none;
  font-size: .7rem;
  color: var(--brand-line);
  transition: transform .18s ease, color .18s ease;
}

.ac-tile:hover .ac-tile-arrow {
  transform: translateX(3px);
  color: var(--brand-accent);
}

/* --------------------------------------------------------------------------
   侧栏导航（会员中心所有子页共用）
   -------------------------------------------------------------------------- */
.ac-nav {
  margin-bottom: 24px;
  border: 1px solid var(--brand-line);
  border-radius: 12px;
  background: var(--brand-bg);
  overflow: hidden;
}

.ac-nav-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 11px 15px;
  font-size: .89rem;
  text-decoration: none;
  color: var(--brand-ink);
  transition: background-color .16s ease, color .16s ease;
}

.ac-nav-item + .ac-nav-item {
  border-top: 1px solid var(--brand-line);
}

.ac-nav-item i {
  flex: none;
  /* 定宽：图标本身宽度不一，不定宽的话文字左边缘会参差不齐 */
  width: 17px;
  text-align: center;
  font-size: .88rem;
  color: var(--brand-muted);
  transition: color .16s ease;
}

.ac-nav-item:hover,
.ac-nav-item:focus {
  background: var(--brand-surface);
  color: var(--brand-accent-deep);
}

.ac-nav-item:hover i,
.ac-nav-item:focus i {
  color: var(--brand-accent-deep);
}

/* 当前页：左侧粉色标条 + 加粗。标条用 ::before 而不是 border-left，
   否则整行内容会被推移 3px，翻页时列表看起来在抖 */
.ac-nav-item.is-active {
  background: var(--brand-surface);
  font-weight: 600;
  color: var(--brand-accent-deep);
}

.ac-nav-item.is-active::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 3px;
  background: var(--brand-accent);
}

.ac-nav-item.is-active i {
  color: var(--brand-accent);
}

.ac-nav-out {
  color: var(--brand-muted);
}

/* --------------------------------------------------------------------------
   手机端
   侧栏被 column_right.twig 的 d-none d-md-block 隐藏，
   所以手机上卡片网格是唯一入口，触控目标必须够大。
   -------------------------------------------------------------------------- */
@media (max-width: 767.98px) {
  .ac-hero {
    margin-bottom: 26px;
    border-radius: 14px;
  }

  .ac-hero-main {
    /* 姓名 + 退出并排在 375px 下必然挤，退出改到下一行整行 */
    flex-wrap: wrap;
    gap: 14px;
    padding: 22px 20px;
  }

  .ac-avatar {
    width: 54px;
    height: 54px;
    font-size: 1.35rem;
  }

  .ac-hero-name {
    font-size: 1.35rem;
    /* 手机上换行比截断好读 */
    white-space: normal;
  }

  .ac-logout {
    width: 100%;
    justify-content: center;
    padding: 11px 20px;
  }

  .ac-stat {
    padding: 14px 6px 15px;
  }

  .ac-stat strong {
    font-size: 1.3rem;
  }

  .ac-stat span {
    font-size: .64rem;
    letter-spacing: .08em;
  }

  .ac-section {
    margin-bottom: 26px;
  }

  .ac-section-title {
    font-size: 1.15rem;
  }

  .ac-grid {
    grid-template-columns: 1fr;
    gap: 10px;
  }

  .ac-tile {
    /* 图标 38 + 上下 28 = 66px 行高，远超 44px 触控下限 */
    padding: 14px 14px 14px 16px;
    gap: 12px;
  }

  .ac-tile-icon {
    width: 38px;
    height: 38px;
    border-radius: 10px;
  }

  /* 手机上没有 hover，位移动画只会在点击后留残影 */
  .ac-tile:hover {
    transform: none;
  }
}

/* ==========================================================================
   订单详情
   模板：extension/ocmod/catalog/view/template/account/{order_info,order_history}.twig
   数据：catalog/controller/account/order.php 的自定义补丁（缩略图 + order_status_id）

   原版把商品做成 5 列 table，把地址/方式做成 5 个 .form-control 假卡片，
   把整段银行汇款说明塞进 order_history 的一个 <td>。手机端全线崩。
   这里全部改成卡片/网格/时间线，页面上不再有任何 table。
   ========================================================================== */

/* --------------------------------------------------------------------------
   头部：订单号 + 日期/发票号 + 状态徽章
   -------------------------------------------------------------------------- */
.oi-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin: 4px 0 22px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--brand-line);
}

.oi-title {
  margin: 0 0 5px;
  font-family: var(--brand-font);
  font-size: 1.85rem;
  font-weight: 600;
  line-height: 1.15;
  color: var(--brand-ink);
}

.oi-head-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 7px;
  font-size: .85rem;
  color: var(--brand-muted);
}

.oi-dot {
  color: var(--brand-line);
}

.oi-status {
  flex: none;
  padding: 7px 16px;
  border-radius: 50rem;
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* 处理中（Pending / Processing …）—— 品牌粉，对比度 5.87:1 达 AA */
.oi-status.is-live {
  background: var(--brand-tint);
  color: var(--brand-accent-deep);
}

/* 已发货 / 已完成 —— 绿色，#1B6E4B 在此浅底上约 6.3:1 */
.oi-status.is-done {
  background: #E8F5EE;
  color: #1B6E4B;
}

/* 取消 / 退款 / 失败一族 —— 中性灰，不用红：这些状态对用户不是「错误」，
   染成红色会让正常的退款流程看起来像出了问题 */
.oi-status.is-dead {
  background: var(--brand-surface);
  color: var(--brand-muted);
}

/* --------------------------------------------------------------------------
   信息卡：地址 / 配送方式 / 支付方式
   -------------------------------------------------------------------------- */
.oi-facts {
  display: grid;
  /* auto-fit：开了「账单地址必填」就是 4 张，没开就是 3 张，
     两种情况都自动铺满，不用为每种数量写断点 */
  grid-template-columns: repeat(auto-fit, minmax(232px, 1fr));
  gap: 12px;
  margin-bottom: 24px;
}

.oi-fact {
  padding: 15px 17px;
  border: 1px solid var(--brand-line);
  border-radius: 12px;
  background: var(--brand-bg);
}

.oi-fact-label {
  display: block;
  margin-bottom: 7px;
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--brand-muted);
}

.oi-fact-body {
  font-size: .9rem;
  line-height: 1.6;
  color: var(--brand-ink);
}

/* --------------------------------------------------------------------------
   商品卡
   -------------------------------------------------------------------------- */
.oi-card {
  margin-bottom: 24px;
  border: 1px solid var(--brand-line);
  border-radius: 14px;
  background: var(--brand-bg);
  overflow: hidden;
}

.oi-card-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--brand-line);
  background: var(--brand-surface);
}

.oi-card-title {
  font-family: var(--brand-font);
  font-size: 1.15rem;
  font-weight: 600;
  color: var(--brand-ink);
}

.oi-card-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 22px;
  padding: 0 7px;
  border-radius: 50rem;
  background: var(--brand-accent);
  font-size: .74rem;
  font-weight: 600;
  color: #fff;
}

/* 四块的位置由 grid-area 排，手机端只换 grid-template 即可整体重排，
   不用改任何 DOM 顺序 */
.oi-item {
  display: grid;
  grid-template-columns: 84px minmax(0, 1fr) auto;
  grid-template-areas:
    "media body  money"
    "media body  action";
  align-items: start;
  gap: 4px 16px;
  padding: 18px;
}

.oi-item + .oi-item {
  border-top: 1px solid var(--brand-line);
}

.oi-item-media {
  grid-area: media;
  position: relative;
  display: block;
  width: 84px;
  height: 84px;
  border: 1px solid var(--brand-line);
  border-radius: 10px;
  background: var(--brand-surface);
  overflow: hidden;
}

.oi-item-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.oi-item-noimg {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  font-size: 1.3rem;
  color: var(--brand-line);
}

/* 数量角标：贴在图右上角，省掉一整列表格 */
.oi-item-qty {
  position: absolute;
  top: -7px;
  right: -7px;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 22px;
  padding: 0 6px;
  border: 2px solid var(--brand-bg);
  border-radius: 50rem;
  background: var(--brand-dark);
  font-size: .7rem;
  font-weight: 600;
  line-height: 1;
  color: #fff;
}

.oi-item-body {
  grid-area: body;
  min-width: 0;
}

.oi-item-name {
  display: block;
  margin-bottom: 4px;
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.35;
  text-decoration: none;
  color: var(--brand-ink);
}

.oi-item-name:hover {
  color: var(--brand-accent-deep);
}

.oi-item-meta {
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: .82rem;
  line-height: 1.55;
  color: var(--brand-muted);
}

.oi-item-money {
  grid-area: money;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  text-align: right;
  white-space: nowrap;
}

.oi-item-total {
  font-size: 1rem;
  font-weight: 600;
  color: var(--brand-ink);
}

.oi-item-unit {
  font-size: .78rem;
  color: var(--brand-muted);
}

.oi-item-actions {
  grid-area: action;
  display: flex;
  align-items: flex-end;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 10px;
}

/* --------------------------------------------------------------------------
   按钮
   原版用 .btn-primary / .btn-danger 两个满宽大按钮堆在表格单元格里，
   视觉重量比商品本身还大。这里改成小号胶囊，且「退货」不再用危险红 ——
   退货是正常服务入口，不是危险操作。
   -------------------------------------------------------------------------- */
.oi-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 8px 18px;
  border: 1px solid transparent;
  border-radius: 50rem;
  font-size: .875rem;
  font-weight: 600;
  letter-spacing: .01em;
  text-transform: none;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color .18s ease, border-color .18s ease, color .18s ease;
}

.oi-btn-primary {
  background: var(--brand-accent);
  color: #fff;
}

.oi-btn-primary:hover,
.oi-btn-primary:focus {
  background: var(--brand-dark);
  color: #fff;
}

.oi-btn-ghost {
  border-color: var(--brand-line);
  background: transparent;
  color: var(--brand-muted);
}

.oi-btn-ghost:hover,
.oi-btn-ghost:focus {
  border-color: var(--brand-ink);
  color: var(--brand-ink);
}

.oi-btn-lg {
  padding: 13px 34px;
  font-size: .78rem;
  letter-spacing: .12em;
}

/* --------------------------------------------------------------------------
   合计
   -------------------------------------------------------------------------- */
.oi-totals {
  padding: 16px 18px;
  border-top: 1px solid var(--brand-line);
  background: var(--brand-surface);
}

.oi-total-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  padding: 4px 0;
  font-size: .9rem;
  color: var(--brand-muted);
}

.oi-total-row.is-grand {
  margin-top: 8px;
  padding-top: 12px;
  border-top: 1px solid var(--brand-line);
  font-size: 1.15rem;
  font-weight: 600;
  color: var(--brand-ink);
}

/* --------------------------------------------------------------------------
   备注 + 分节标题 + 页脚
   -------------------------------------------------------------------------- */
.oi-note {
  margin-bottom: 24px;
  padding: 15px 17px;
  border: 1px solid var(--brand-line);
  border-radius: 12px;
  background: var(--brand-bg);
}

.oi-section-title {
  margin: 0 0 14px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--brand-line);
  font-family: var(--brand-font);
  font-size: 1.3rem;
  font-weight: 600;
  color: var(--brand-ink);
}

.oi-foot {
  margin-top: 24px;
  text-align: right;
}

/* --------------------------------------------------------------------------
   订单历史时间线
   -------------------------------------------------------------------------- */
.oh-timeline {
  padding: 20px 20px 6px;
  border: 1px solid var(--brand-line);
  border-radius: 14px;
  background: var(--brand-bg);
}

.oh-entry {
  position: relative;
  display: flex;
  gap: 14px;
  padding-bottom: 20px;
}

/* 连接线画在圆点正中：marker 宽 11px，左边距 0 → 中心在 5.5px */
.oh-entry:not(:last-child)::before {
  content: "";
  position: absolute;
  top: 16px;
  bottom: -2px;
  left: 5px;
  width: 1px;
  background: var(--brand-line);
}

.oh-marker {
  flex: none;
  width: 11px;
  height: 11px;
  margin-top: 5px;
  border: 2px solid var(--brand-line);
  border-radius: 50%;
  background: var(--brand-bg);
}

/* 最后一条 = 当前状态 */
.oh-entry.is-current .oh-marker {
  border-color: var(--brand-accent);
  background: var(--brand-accent);
  box-shadow: 0 0 0 3px rgba(var(--brand-accent-rgb), .16);
}

.oh-body {
  flex: 1 1 auto;
  min-width: 0;
}

.oh-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}

.oh-status {
  font-size: .95rem;
  font-weight: 600;
  color: var(--brand-ink);
}

.oh-entry.is-current .oh-status {
  color: var(--brand-accent-deep);
}

.oh-date {
  font-size: .8rem;
  color: var(--brand-muted);
}

/* 银行汇款说明这类整段文本：独占整行宽度，保留换行，字号收小 */
.oh-comment {
  margin-top: 9px;
  padding: 13px 15px;
  border-radius: 9px;
  background: var(--brand-surface);
  font-size: .86rem;
  line-height: 1.65;
  color: var(--brand-ink);
  /* 长的银行账号 / IBAN 不会撑破容器 */
  overflow-wrap: anywhere;
}

.oh-empty {
  padding: 28px 20px;
  border: 1px solid var(--brand-line);
  border-radius: 14px;
  background: var(--brand-bg);
  text-align: center;
  color: var(--brand-muted);
}

.oh-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-top: 14px;
  font-size: .84rem;
  color: var(--brand-muted);
}

.oh-foot .pagination {
  margin: 0;
}

/* --------------------------------------------------------------------------
   手机端
   -------------------------------------------------------------------------- */
@media (max-width: 767.98px) {
  .oi-head {
    /* 标题和状态徽章并排在 375px 下会把标题挤断行 */
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
  }

  .oi-title {
    font-size: 1.5rem;
  }

  .oi-facts {
    grid-template-columns: 1fr;
    gap: 10px;
  }

  .oi-item {
    /* 图 | 名称 ／ 图 | 价格 ／ 操作整行铺满 */
    grid-template-columns: 64px minmax(0, 1fr);
    grid-template-areas:
      "media body"
      "media money"
      "action action";
    gap: 6px 13px;
    padding: 15px;
  }

  .oi-item-media {
    width: 64px;
    height: 64px;
  }

  .oi-item-money {
    /* 左对齐跟名称成一列，价格和数量并排省高度 */
    flex-direction: row;
    align-items: baseline;
    justify-content: flex-start;
    gap: 8px;
    text-align: left;
  }

  .oi-item-actions {
    margin-top: 13px;
  }

  .oi-item-actions .oi-btn {
    /* 两个按钮各占一半，触控目标 38px 高 */
    flex: 1 1 0;
    padding: 11px 10px;
  }

  .oi-card-head,
  .oi-totals {
    padding: 13px 15px;
  }

  .oi-total-row.is-grand {
    font-size: 1.08rem;
  }

  .oi-section-title {
    font-size: 1.15rem;
  }

  .oh-timeline {
    padding: 18px 16px 4px;
  }

  .oh-head {
    /* 状态和日期分两行，避免长状态名把日期挤出去 */
    flex-direction: column;
    gap: 2px;
  }

  .oh-comment {
    padding: 12px 13px;
    font-size: .83rem;
  }

  .oi-foot .oi-btn {
    display: flex;
    width: 100%;
  }
}

/* ==========================================================================
   会员中心通用版式（14 个列表页共用）
   脚本：extension/ocmod/catalog/view/javascript/account-tables.js
   模板：extension/ocmod/catalog/view/template/account/{order_list,wishlist_list,address_list}.twig

   会员中心有 14 个页面用 .table 列数据，全部是 table-bordered + table-hover 的
   默认灰框样式，手机端 4–7 列必然溢出。逐个改模板意味着 14 个核心文件要在
   每次 OpenCart 升级后重新合并，所以这里分两层：

     · 本段 CSS + account-tables.js —— 覆盖全部会员表格，模板零改动。
       桌面端重画表格，手机端由 JS 写入的 data-label 转成卡片。
     · order_list / wishlist_list / address_list 三个高频页另做了专用卡片模板
       （订单要突出状态和金额、心愿单有商品图、地址本来就是块状数据，
       通用转换给不了这些）。

   全段作用域 [id^="account-"]，不影响商品页、购物车等其它表格。
   ========================================================================== */

[id^="account-"] #content > h1 {
  margin: 4px 0 18px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--brand-line);
  font-family: var(--brand-font);
  font-size: 1.75rem;
  font-weight: 600;
  color: var(--brand-ink);
}

/* --------------------------------------------------------------------------
   通用表格：桌面
   -------------------------------------------------------------------------- */
.ap-table-wrap {
  margin-bottom: 18px;
  border: 1px solid var(--brand-line);
  border-radius: 14px;
  /* .table-responsive 自带 overflow-x:auto，圆角能正常裁切；
     裸表格新套的容器这里补上，两种情况表现一致 */
  overflow: auto;
}

[id^="account-"] .ap-table {
  margin: 0;
  --bs-table-bg: transparent;
  --bs-table-hover-bg: var(--brand-surface);
}

/* table-bordered 会给每个单元格四面描边，网格感太重，全部抹掉 */
[id^="account-"] .ap-table.table-bordered > :not(caption) > *,
[id^="account-"] .ap-table.table-bordered > :not(caption) > * > * {
  border-width: 0;
}

[id^="account-"] .ap-table > thead > tr > th {
  padding: 13px 16px;
  border-bottom: 1px solid var(--brand-line);
  background: var(--brand-surface);
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .11em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--brand-muted);
}

[id^="account-"] .ap-table > tbody > tr > td {
  padding: 15px 16px;
  border-top: 1px solid var(--brand-line);
  vertical-align: middle;
  font-size: .9rem;
  color: var(--brand-ink);
}

[id^="account-"] .ap-table > tbody > tr:first-child > td {
  border-top: 0;
}

/* 心愿单等表格里的商品图 */
[id^="account-"] .ap-table img {
  border-radius: 8px;
}

/* --------------------------------------------------------------------------
   会员中心内的 Bootstrap 按钮
   原版混用 btn-info（蓝）/ btn-danger（红）/ btn-light（灰），
   和整站的粉+黑完全脱节；红色更是把「删除地址」「移除心愿单」这类
   可撤销操作渲染得像危险动作。统一收成品牌色系。
   类名一个都不动 —— 多个核心模板的内联 JS 拿 .btn-danger 当事件钩子。
   -------------------------------------------------------------------------- */
[id^="account-"] .btn-info,
[id^="account-"] .btn-primary {
  border-color: var(--brand-accent);
  background: var(--brand-accent);
  color: #fff;
}

[id^="account-"] .btn-info:hover,
[id^="account-"] .btn-primary:hover,
[id^="account-"] .btn-info:focus,
[id^="account-"] .btn-primary:focus {
  border-color: var(--brand-dark);
  background: var(--brand-dark);
  color: #fff;
}

[id^="account-"] .btn-danger,
[id^="account-"] .btn-light {
  border-color: var(--brand-line);
  background: transparent;
  color: var(--brand-muted);
}

[id^="account-"] .btn-danger:hover,
[id^="account-"] .btn-light:hover,
[id^="account-"] .btn-danger:focus,
[id^="account-"] .btn-light:focus {
  border-color: var(--brand-ink);
  background: transparent;
  color: var(--brand-ink);
}

/* --------------------------------------------------------------------------
   分页 / 计数 / 底部按钮 / 空状态
   -------------------------------------------------------------------------- */
/* 只作用于自己的 .ap-foot。没重写的页面那一行是 Bootstrap 的
   .row > .col-sm-6，改它的 margin 会破坏栅格的负外边距配对
   （结账页已经踩过一次这个坑），保持原样即可。 */
.ap-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin: 0 0 18px;
  font-size: .84rem;
  color: var(--brand-muted);
}

.ap-foot .pagination,
[id^="account-"] .pagination {
  margin: 0;
}

[id^="account-"] .page-link {
  border-color: var(--brand-line);
  color: var(--brand-ink);
}

[id^="account-"] .page-item.active .page-link {
  border-color: var(--brand-accent);
  background: var(--brand-accent);
  color: #fff;
}

.ap-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 22px;
}

.ap-empty {
  padding: 44px 24px;
  border: 1px solid var(--brand-line);
  border-radius: 14px;
  background: var(--brand-bg);
  text-align: center;
}

.ap-empty-icon {
  display: block;
  margin-bottom: 12px;
  font-size: 2rem;
  color: var(--brand-line);
}

.ap-empty p {
  margin: 0;
  color: var(--brand-muted);
}

.ap-sep {
  color: var(--brand-line);
}

/* --------------------------------------------------------------------------
   订单列表：每单一行卡片
   -------------------------------------------------------------------------- */
.ap-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 18px;
}

.ap-row {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr) auto auto;
  grid-template-areas: "icon main tag end";
  align-items: center;
  gap: 16px;
  padding: 15px 18px;
  border: 1px solid var(--brand-line);
  border-radius: 12px;
  background: var(--brand-bg);
  text-decoration: none;
  color: var(--brand-ink);
  transition: border-color .18s ease, box-shadow .18s ease, transform .18s ease;
}

.ap-row:hover,
.ap-row:focus {
  border-color: var(--brand-accent);
  box-shadow: 0 6px 20px rgba(var(--brand-accent-rgb), .12);
  transform: translateY(-2px);
  color: var(--brand-ink);
}

.ap-row-icon {
  grid-area: icon;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 11px;
  background: var(--brand-surface);
  font-size: .95rem;
  color: var(--brand-accent-deep);
}

.ap-row:hover .ap-row-icon {
  background: var(--brand-accent);
  color: #fff;
}

.ap-row-main {
  grid-area: main;
  min-width: 0;
}

.ap-row-title {
  display: block;
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.3;
}

.ap-row-sub {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px;
  margin-top: 2px;
  font-size: .8rem;
  color: var(--brand-muted);
}

/* 状态：列表页拿不到 order_status_id（model 的 SELECT 没取），
   不按名称猜配色，统一中性描边 */
.ap-row-tag {
  grid-area: tag;
  padding: 6px 14px;
  border: 1px solid var(--brand-line);
  border-radius: 50rem;
  font-size: .71rem;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--brand-muted);
}

.ap-row-end {
  grid-area: end;
  display: flex;
  align-items: center;
  gap: 12px;
}

.ap-row-amount {
  font-size: 1rem;
  font-weight: 600;
  white-space: nowrap;
}

.ap-row-go {
  font-size: .7rem;
  color: var(--brand-line);
  transition: transform .18s ease, color .18s ease;
}

.ap-row:hover .ap-row-go {
  transform: translateX(3px);
  color: var(--brand-accent);
}

/* --------------------------------------------------------------------------
   心愿单：商品卡
   -------------------------------------------------------------------------- */
.ap-cards {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 18px;
}

.ap-card {
  display: grid;
  grid-template-columns: 92px minmax(0, 1fr) auto;
  grid-template-areas: "media body action";
  align-items: center;
  gap: 16px;
  padding: 16px 18px;
  border: 1px solid var(--brand-line);
  border-radius: 12px;
  background: var(--brand-bg);
}

.ap-card-media {
  grid-area: media;
  display: block;
  width: 92px;
  height: 92px;
  border: 1px solid var(--brand-line);
  border-radius: 10px;
  background: var(--brand-surface);
  overflow: hidden;
}

.ap-card-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.ap-card-body {
  grid-area: body;
  min-width: 0;
}

.ap-card-name {
  display: block;
  margin-bottom: 4px;
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.35;
  text-decoration: none;
  color: var(--brand-ink);
}

.ap-card-name:hover {
  color: var(--brand-accent-deep);
}

.ap-card-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px;
  font-size: .82rem;
  color: var(--brand-muted);
}

.ap-card-price {
  margin-top: 7px;
}

.ap-price {
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--brand-ink);
}

.ap-price.is-special {
  color: var(--brand-sale);
}

.ap-price-old {
  margin-left: 7px;
  font-size: .88rem;
  color: var(--brand-muted);
}

.ap-card-actions {
  grid-area: action;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* --------------------------------------------------------------------------
   地址簿
   -------------------------------------------------------------------------- */
.ap-addr-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(266px, 1fr));
  gap: 12px;
  margin-bottom: 18px;
}

.ap-addr {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 18px;
  border: 1px solid var(--brand-line);
  border-radius: 12px;
  background: var(--brand-bg);
}

.ap-addr.is-default {
  border-color: var(--brand-accent);
}

.ap-addr-flag {
  position: absolute;
  top: -9px;
  left: 16px;
  padding: 3px 11px;
  border-radius: 50rem;
  background: var(--brand-accent);
  font-size: .64rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #fff;
}

.ap-addr-body {
  flex: 1 1 auto;
  font-size: .9rem;
  line-height: 1.6;
}

.ap-addr-actions {
  display: flex;
  gap: 8px;
}

.ap-addr-actions .oi-btn {
  flex: 1 1 0;
  gap: 7px;
}

/* --------------------------------------------------------------------------
   手机端
   -------------------------------------------------------------------------- */
@media (max-width: 767.98px) {
  [id^="account-"] #content > h1 {
    font-size: 1.4rem;
  }

  /* --- 通用表格 → 卡片 ---
     data-label 由 account-tables.js 从 <thead> 抄进每个 <td>。
     这是唯一能同时覆盖 14 个页面（含我没打开过的）而不动模板的办法。 */
  .ap-table-wrap {
    border: 0;
    border-radius: 0;
    overflow: visible;
  }

  [id^="account-"] .ap-table.is-carded,
  [id^="account-"] .ap-table.is-carded > tbody,
  [id^="account-"] .ap-table.is-carded > tbody > tr,
  [id^="account-"] .ap-table.is-carded > tbody > tr > td {
    display: block;
    width: 100%;
  }

  [id^="account-"] .ap-table.is-carded > thead {
    display: none;
  }

  [id^="account-"] .ap-table.is-carded > tbody > tr {
    margin-bottom: 10px;
    padding: 4px 16px;
    border: 1px solid var(--brand-line);
    border-radius: 12px;
    background: var(--brand-bg);
  }

  [id^="account-"] .ap-table.is-carded > tbody > tr > td {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 14px;
    padding: 11px 0;
    border: 0;
    border-top: 1px solid var(--brand-line);
    /* 模板里的 .text-end 在 flex 布局下没有意义，但会影响
       td 内部多节点时的对齐，统一压掉 */
    text-align: left;
  }

  [id^="account-"] .ap-table.is-carded > tbody > tr > td:first-child {
    border-top: 0;
  }

  [id^="account-"] .ap-table.is-carded > tbody > tr > td[data-label]::before {
    content: attr(data-label);
    flex: none;
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--brand-muted);
  }

  /* 无表头的操作列：按钮整行铺开，不跟标签挤在一行 */
  [id^="account-"] .ap-table.is-carded > tbody > tr > td:not([data-label]) {
    display: block;
  }

  [id^="account-"] .ap-table.is-carded .d-grid .btn,
  [id^="account-"] .ap-table.is-carded > tbody > tr > td:not([data-label]) > .btn {
    width: 100%;
  }

  /* colspan 撑满的「暂无记录」行 */
  [id^="account-"] .ap-table.is-carded .ap-cell-full {
    display: block;
    padding: 18px 0;
    text-align: center;
    color: var(--brand-muted);
  }

  /* --- 订单列表 --- */
  .ap-row {
    grid-template-columns: 40px minmax(0, 1fr) auto;
    grid-template-areas:
      "icon main end"
      "tag  tag  tag";
    gap: 12px;
    padding: 14px 15px;
  }

  .ap-row-icon {
    width: 40px;
    height: 40px;
  }

  .ap-row-tag {
    /* 状态徽章挪到第二行左对齐，别和金额抢宽度 */
    justify-self: start;
    margin-top: 2px;
  }

  .ap-row:hover {
    transform: none;
  }

  /* --- 心愿单 --- */
  .ap-card {
    grid-template-columns: 76px minmax(0, 1fr);
    grid-template-areas:
      "media body"
      "action action";
    align-items: start;
    gap: 12px 14px;
    padding: 15px;
  }

  .ap-card-media {
    width: 76px;
    height: 76px;
  }

  .ap-card-actions {
    flex-direction: row;
  }

  .ap-card-actions .oi-btn {
    flex: 1 1 0;
    padding: 11px 10px;
  }

  /* --- 地址簿 --- */
  .ap-addr-grid {
    grid-template-columns: 1fr;
  }

  /* --- 底部按钮整行 --- */
  .ap-actions {
    margin-top: 18px;
  }

  .ap-actions .oi-btn {
    display: flex;
    width: 100%;
  }

  [id^="account-"] #content > .text-end > .btn {
    display: block;
    width: 100%;
  }
}

/* ==========================================================================
   购物车
   模板：extension/ocmod/catalog/view/template/checkout/{cart,cart_list}.twig

   原版是 5 列 table，合计塞在 tfoot 里用 colspan="4" 撑空单元格，
   「去结算」按钮压在整页最底部。改成电商通用两栏：
   左栏商品卡 + 折叠模块，右栏订单摘要 sticky 跟随，结算按钮首屏可见。

   手机端不再用上一版「table display:block + 缩略图绝对定位」的伪卡片，
   电脑手机共用同一套 grid，窄屏只换 grid-template-areas。
   ========================================================================== */

.ck-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 10px;
  margin: 4px 0 20px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--brand-line);
}

.ck-title {
  margin: 0;
  font-family: var(--brand-font);
  font-size: 1.85rem;
  font-weight: 600;
  line-height: 1.15;
  color: var(--brand-ink);
}

.ck-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  height: 24px;
  padding: 0 8px;
  border-radius: 50rem;
  background: var(--brand-accent);
  font-size: .76rem;
  font-weight: 600;
  color: #fff;
}

/* 重量原版是直接拼在 h1 里的 —— 「Shopping Cart (10.00kg)」，
   衬线大标题里夹一串数字很脏。拆成独立的次要标签。 */
.ck-weight {
  margin-left: auto;
  font-size: .82rem;
  color: var(--brand-muted);
}

.ck-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 336px;
  gap: 24px;
  align-items: start;
}

.ck-col-main {
  min-width: 0;
}

.ck-col-side {
  position: sticky;
  /* 同 .op-sticky：头部现在是吸顶的，必须按它的高度留位。
     （这条注释原本写着「masthead 不是 fixed，只留一点呼吸位即可」——
     那在头部吸顶之后就不成立了。） */
  top: calc(var(--oc-header-stuck) + 32px);
}

/* --------------------------------------------------------------------------
   商品卡
   -------------------------------------------------------------------------- */
.ck-items {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 22px;
}

.ck-item {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr) auto auto;
  grid-template-areas: "media body qty money";
  align-items: center;
  gap: 16px;
  padding: 16px 18px;
  border: 1px solid var(--brand-line);
  border-radius: 12px;
  background: var(--brand-bg);
}

.ck-item.is-oos {
  border-color: var(--brand-tint-line);
  background: var(--brand-surface);
}

.ck-item-media {
  grid-area: media;
  display: block;
  width: 96px;
  height: 96px;
  border: 1px solid var(--brand-line);
  border-radius: 10px;
  background: var(--brand-surface);
  overflow: hidden;
}

.ck-item-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.ck-item-body {
  grid-area: body;
  min-width: 0;
}

.ck-item-name {
  display: block;
  margin-bottom: 4px;
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.35;
  text-decoration: none;
  color: var(--brand-ink);
}

.ck-item-name:hover {
  color: var(--brand-accent-deep);
}

.ck-item-meta {
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: .82rem;
  line-height: 1.55;
  color: var(--brand-muted);
}

.ck-oos {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 7px;
  padding: 4px 11px;
  border-radius: 50rem;
  background: var(--brand-tint);
  font-size: .74rem;
  font-weight: 600;
  color: var(--brand-accent-deep);
}

.ck-item-money {
  grid-area: money;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  min-width: 88px;
  text-align: right;
  white-space: nowrap;
}

.ck-item-total {
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--brand-ink);
}

.ck-item-unit {
  font-size: .78rem;
  color: var(--brand-muted);
}

/* --------------------------------------------------------------------------
   数量加减器
   原版是「输入框 + 蓝色刷新图标 + 红色叉号」挤在一个 input-group 里，
   两个图标按钮谁也看不懂，红叉更是紧挨着输入框、极易误点。
   改成 − / + 加减器（点一下就提交），移除单独成一个弱化的文字按钮。
   -------------------------------------------------------------------------- */
.ck-item-qty {
  grid-area: qty;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}

.ck-stepper {
  display: inline-flex;
  align-items: stretch;
  border: 1px solid var(--brand-line);
  border-radius: 50rem;
  overflow: hidden;
  background: var(--brand-bg);
}

.ck-step {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  padding: 0;
  border: 0;
  background: transparent;
  font-size: .72rem;
  color: var(--brand-muted);
  cursor: pointer;
  transition: background-color .16s ease, color .16s ease;
}

.ck-step:hover {
  background: var(--brand-surface);
  color: var(--brand-accent-deep);
}

.ck-qty {
  width: 42px;
  height: 36px;
  padding: 0;
  border: 0;
  border-left: 1px solid var(--brand-line);
  border-right: 1px solid var(--brand-line);
  background: transparent;
  font-size: .92rem;
  font-weight: 600;
  text-align: center;
  color: var(--brand-ink);
}

.ck-qty:focus {
  outline: 0;
  background: var(--brand-surface);
}

.ck-qty.is-invalid {
  color: var(--brand-accent-deep);
}

.ck-remove {
  padding: 0;
  border: 0;
  background: none;
  font-size: .76rem;
  text-decoration: underline;
  text-underline-offset: 3px;
  color: var(--brand-muted);
  transition: color .16s ease;
}

.ck-remove:hover,
.ck-remove:focus {
  color: var(--brand-accent-deep);
}

.ck-minimum {
  font-size: .74rem;
  text-align: center;
  color: var(--brand-accent-deep);
}

/* 提交中：整块变淡并锁住，避免连点造成多次加减 */
.ck-item-qty.is-busy,
.ck-remove.is-busy {
  opacity: .45;
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   右栏订单摘要
   -------------------------------------------------------------------------- */
.ck-summary {
  padding: 20px;
  border: 1px solid var(--brand-line);
  border-radius: 14px;
  background: var(--brand-surface);
}

.ck-summary-head {
  margin-bottom: 14px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--brand-line);
  font-family: var(--brand-font);
  font-size: 1.2rem;
  font-weight: 600;
  color: var(--brand-ink);
}

.ck-total-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
  padding: 5px 0;
  font-size: .9rem;
  color: var(--brand-muted);
}

.ck-total-row.is-grand {
  margin-top: 8px;
  padding-top: 13px;
  border-top: 1px solid var(--brand-line);
  font-size: 1.2rem;
  font-weight: 600;
  color: var(--brand-ink);
}

.ck-checkout {
  display: flex;
  width: 100%;
  margin-top: 18px;
}

.ck-continue {
  display: block;
  margin-top: 12px;
  font-size: .82rem;
  text-align: center;
  text-decoration: underline;
  text-underline-offset: 3px;
  color: var(--brand-muted);
}

.ck-continue:hover {
  color: var(--brand-accent-deep);
}

/* --------------------------------------------------------------------------
   优惠券 / 积分 / 运费估算折叠区
   三个模块是 extension/opencart 下的独立模板（各自还要双路径覆盖），
   这里只用 CSS 重画 Bootstrap 手风琴，不动那三个文件。
   -------------------------------------------------------------------------- */
.ck-extras-head {
  margin-bottom: 12px;
}

.ck-extras-title {
  display: block;
  font-family: var(--brand-font);
  font-size: 1.2rem;
  font-weight: 600;
  color: var(--brand-ink);
}

.ck-extras-sub {
  margin: 4px 0 0;
  font-size: .84rem;
  line-height: 1.5;
  color: var(--brand-muted);
}

#checkout-cart .accordion {
  --bs-accordion-border-color: var(--brand-line);
  --bs-accordion-border-radius: 12px;
  --bs-accordion-inner-border-radius: 11px;
  --bs-accordion-btn-color: var(--brand-ink);
  --bs-accordion-btn-bg: var(--brand-bg);
  --bs-accordion-active-color: var(--brand-accent-deep);
  --bs-accordion-active-bg: var(--brand-surface);
  --bs-accordion-btn-focus-box-shadow: none;
}

#checkout-cart .accordion-button {
  padding: 15px 18px;
  font-size: .92rem;
  font-weight: 600;
}

#checkout-cart .accordion-button::after {
  width: .95rem;
  height: .95rem;
  background-size: .95rem;
}

#checkout-cart .accordion-body {
  padding: 18px;
}

/* --------------------------------------------------------------------------
   空购物车
   原版只有一行「Your shopping cart is empty!」外加一个孤零零的 CONTINUE，
   剩下整屏是白的。
   -------------------------------------------------------------------------- */
.ck-empty {
  max-width: 520px;
  margin: 0 auto;
}

.ck-empty .oi-btn {
  display: inline-flex;
  margin-top: 18px;
}

/* --------------------------------------------------------------------------
   手机端
   -------------------------------------------------------------------------- */
@media (max-width: 991.98px) {
  /* 中屏先让摘要落到下面，336px 的右栏在 992 以下会把商品卡挤得太窄 */
  .ck-layout {
    grid-template-columns: 1fr;
  }

  .ck-col-side {
    position: static;
  }
}

@media (max-width: 767.98px) {
  .ck-title {
    font-size: 1.5rem;
  }

  .ck-weight {
    /* 窄屏不再顶到最右，跟在数量角标后面 */
    margin-left: 0;
    flex-basis: 100%;
  }

  .ck-item {
    grid-template-columns: 76px minmax(0, 1fr);
    grid-template-areas:
      "media body"
      "media money"
      "qty   qty";
    align-items: start;
    gap: 8px 14px;
    padding: 15px;
  }

  .ck-item-media {
    width: 76px;
    height: 76px;
  }

  .ck-item-money {
    /* 左对齐跟商品名成一列，价格和单价并排省高度 */
    flex-direction: row;
    align-items: baseline;
    justify-content: flex-start;
    gap: 8px;
    min-width: 0;
    text-align: left;
  }

  .ck-item-qty {
    /* 加减器和移除左右分开，别都堆在中间 */
    flex-direction: row;
    align-items: center;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 12px;
    margin-top: 6px;
    padding-top: 12px;
    border-top: 1px solid var(--brand-line);
  }

  .ck-step {
    /* 触控目标放大到 42px */
    width: 42px;
  }

  .ck-qty {
    width: 48px;
    height: 42px;
    /* iOS Safari 对 <16px 的输入框会自动放大页面 */
    font-size: 1rem;
  }

  .ck-minimum {
    flex-basis: 100%;
    text-align: left;
  }

  .ck-summary {
    padding: 18px 16px;
  }
}

/* ==========================================================================
   购物车数量指示
   模板：extension/ocmod/catalog/view/template/common/{header,footer}.twig

   三处共用一个数据源（footer.twig 里的 [data-oc-cart-count] 同步器）：
     · 顶栏 Shopping Cart (n) —— 括号，与旁边 Wish List (0) 保持一致
     · 手机头部购物车气泡     —— 0 时隐藏
     · 底部标签栏气泡         —— 0 时隐藏
   ========================================================================== */

/* --- 手机头部购物车（<768px 才出现，桌面由 d-md-none 隐藏） --- */
#mobile-cart-slot {
  padding-left: 4px;
}

#mobile-cart {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  /* 44px 是触控目标下限；图标本身小，靠内边距把热区撑到位 */
  width: 40px;
  height: 40px;
  font-size: 1.05rem;
  text-decoration: none;
  /* ⚠ 这里曾经是 #fff —— 头部还是深色块的时候是对的。
     头部改白底后没跟着改，结果白底白图标，只剩角标看得见。
     头部里任何写死的白色都要跟着头部底色走。 */
  color: var(--brand-ink);
}

#mobile-cart:hover,
#mobile-cart:active {
  color: var(--brand-accent);
}

.mobile-cart-badge {
  position: absolute;
  top: 1px;
  right: 0;
  min-width: 17px;
  height: 17px;
  padding: 0 5px;
  border: 2px solid var(--brand-dark);
  border-radius: 50rem;
  background: var(--brand-accent);
  font-size: .6rem;
  font-weight: 700;
  line-height: 13px;
  text-align: center;
  color: #fff;
}

/* --- 顶栏括号数字 --- */
#top [data-oc-cart-count] {
  font-variant-numeric: tabular-nums;
}

/* --- 数量增加时的回弹 ---
   手机上加购的提示 alert 在页面顶部，用户滚到中部时看不见，
   加完不知道成没成 —— 这个动画是唯一的即时反馈。 */
@keyframes oc-cart-bump {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.45); }
  70%  { transform: scale(.92); }
  100% { transform: scale(1); }
}

[data-oc-cart-count].is-bump {
  animation: oc-cart-bump .4s ease-out;
}

/* 顶栏那个数字在一行文字里，放大会顶开相邻文字，只做颜色闪烁 */
#top [data-oc-cart-count].is-bump {
  animation: none;
}

@media (prefers-reduced-motion: reduce) {
  [data-oc-cart-count].is-bump {
    animation: none;
  }
}

/* ==========================================================================
   头部吸顶
   模板：extension/ocmod/catalog/view/template/common/header.twig
        （#header-sentinel + #header-search-toggle + IntersectionObserver）

   原来整个头部随页面滚走，往下翻两屏就是一张「无头页面」——
   想回首页、想看购物车、想换个分类，都得先滚回顶部。

   吸顶的是 <header>（logo / 搜索 / 购物车 / 导航），
   公告条和 #top（币种·语言·账户行）**不参与**，滑走就滑走：
     · 公告条是轮播促销，不是导航。手机视口 667px，
       它常驻就是永久吃掉 6.6%，而用户读过一遍就不再需要。
     · #top 里的账户/心愿单/结账在浏览过程中不是高频操作，
       手机端本来也已经被搬到 logo 行和底部标签栏了。
   面包屑同理不吸顶 —— 它是「读一次确认自己在哪」的信息，
   吸顶要多占 46px，代价和收益不成比例。

   实现放在 header 本身，所以**全站每个页面自动生效**，
   不需要逐页改（结算页、商品页、首页、分类页、会员中心……都一样）。
   ========================================================================== */

/* 1px 的哨兵，滑出视口即代表 header 已吸顶。
   高度不能是 0 —— IntersectionObserver 对零高度元素的行为在
   各浏览器上不一致。 */
#header-sentinel {
  height: 1px;
  margin-bottom: -1px;
  pointer-events: none;
}

/* ⚠ 必须关掉浏览器的「滚动锚定」（scroll anchoring），
   否则头部在即将吸顶时会疯狂闪烁。

   成因是一个闭环：
     1. sentinel 滑出视口 → 加 .is-stuck
     2. .is-stuck 把头部从 120px 压到 86px（内边距 + logo + 搜索框
        + 购物车按钮 + 导航一起收小，共 33px）
     3. position: sticky 的元素**仍在文档流里**，高度一变文档就短 33px
     4. Chrome 为了「让你正在看的内容别跳」，自动把 scrollY 减 33
     5. scrollY 减了 → sentinel 又回到视口 → 去掉 .is-stuck
     6. 头部弹回 120px → Chrome 又把 scrollY 加回 33 → 回到第 1 步

   实测：滑过阈值附近会在 342ms 内切换 24~44 次，scrollY 在 67↔100 之间弹。
   加上这条后降到 1 次（即正常的那一次）。

   为什么不用别的办法：
     · 让 .is-stuck 不改变高度 —— 实测也能降到 1 次，但吸顶压缩效果就没了，
       而那正是这个设计的目的。
     · 改用 position: fixed + 占位元素 —— 能从根上避开，但要用 JS 量高度、
       监听 resize，改动面大、风险高。

   副作用：视口上方的内容中途变高时（比如图片迟加载）页面会跳。
   本站影响很小 —— 商品图容器已经用 aspect-ratio: 7/9 预留了空间，
   图片加载不会引起重排。Safari 本来就没实现 scroll anchoring。 */
html,
body {
  overflow-anchor: none;
}

header {
  position: sticky;
  top: 0;
  /* 1030 = Bootstrap 的 fixed-top 档位。底部标签栏是 1040，
     两者不重叠，谁也不会盖住谁。 */
  z-index: 1030;
  transition: padding .18s ease, box-shadow .18s ease;
}

/* 吸顶后给一道投影，让头部和下方内容分层；不吸顶时没有，
   避免静止状态下多一条无意义的暗边 */
header.is-stuck {
  box-shadow: 0 4px 18px rgba(0, 0, 0, .3);
}

header #logo img {
  transition: max-height .18s ease, max-width .18s ease;
}

/* --------------------------------------------------------------------------
   手机端（<768px）
   吸顶后一行：☰ | logo | 🔍 | 🛒
   搜索行整行收起（它占 56px），币种/语言也收起（浏览中几乎不用），
   腾出的位置给一个搜索图标 —— 点一下把搜索行展开，不丢入口。
   -------------------------------------------------------------------------- */
@media (max-width: 767.98px) {
  /* 搜索按钮默认不存在，只有吸顶后才出现 */
  #header-search-slot {
    display: none;
  }

  #header-search-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    font-size: 1.05rem;
    color: var(--brand-ink);
  }

  #header-search-toggle:active {
    background: var(--brand-surface);
  }

  header.is-stuck {
    padding-top: 8px;
    padding-bottom: 8px;
  }

  header.is-stuck #search-col {
    display: none;
  }

  /* 点了搜索图标才把整行放回来 */
  header.is-stuck.is-search-open #search-col {
    display: block;
  }

  header.is-stuck.is-search-open {
    padding-bottom: 12px;
  }

  header.is-stuck #header-tools-slot {
    display: none;
  }

  header.is-stuck #header-search-slot {
    display: block;
  }

  header.is-stuck #logo img {
    max-width: 104px;
  }

  /* 搜索图标被隐藏时该列宽度归零，不留空隙 */
  header .row > #header-search-slot {
    grid-area: find;
    justify-self: end;
  }

  /* 展开的分类面板挂在吸顶头部下方，必须限高可滚 ——
     否则条目一多就顶出视口，底下的够不着 */
  #menu #navbar-menu {
    max-height: calc(100vh - 150px);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }
}

/* --------------------------------------------------------------------------
   电脑端（≥768px）
   桌面横向有空间，搜索框**不收起** —— 收起反而让用户多点一次。
   只做等比压缩：内边距、logo、搜索框、购物车按钮一起收小，
   两行（logo+搜索+购物车 / 导航）压到 ~95px。
   -------------------------------------------------------------------------- */
@media (min-width: 768px) {
  header.is-stuck {
    padding-top: 6px;
    padding-bottom: 2px;
  }

  header.is-stuck #logo img {
    max-height: 34px;
  }

  header.is-stuck .input-group .form-control,
  header.is-stuck .input-group .btn {
    padding-top: .34rem;
    padding-bottom: .34rem;
    font-size: .92rem;
  }

  header.is-stuck #cart .btn {
    padding-top: .42rem;
    padding-bottom: .42rem;
    font-size: .82rem;
  }

  header.is-stuck #cart {
    margin-bottom: 0 !important;
  }

  header.is-stuck #menu .nav-link {
    padding-top: .4rem;
    padding-bottom: .4rem;
  }
}

/* 用户开了「减少动态效果」就不做尺寸过渡，直接切换 */
@media (prefers-reduced-motion: reduce) {
  header,
  header #logo img {
    transition: none;
  }
}

/* ==========================================================================
   页脚邮件订阅 + 支付图标
   模板：extension/ocmod/catalog/view/template/common/footer.twig
   端点：extension/ocmod/catalog/controller/common/subscribe.php

   原来页脚的 Newsletter 只是一个跳转到 account/newsletter 的文字链接，
   而那个页面第一件事就是要求登录 —— 访客点进去看到的是登录表单。
   现在改成页脚直接收邮箱。
   ========================================================================== */

.fn-subscribe {
  display: flex;
  align-items: center;
  gap: 40px;
  margin-top: 8px;
  padding-top: 26px;
  border-top: 1px solid rgba(255, 255, 255, .1);
}

.fn-subscribe-intro {
  /* 不再 grow —— 余量留给中间的信任块（见 .fn-subscribe .fc-trust） */
  flex: 0 1 auto;
  max-width: 34ch;
  min-width: 0;
}

.fn-subscribe-intro h5 {
  position: relative;
  margin: 0 0 10px;
  padding-bottom: 9px;
  font-family: var(--brand-font);
  font-size: 1.15rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: #fff;
}

/* 页脚其它栏目标题下都有一条短下划线，这里跟上，不然它会像外挂的一块 */
.fn-subscribe-intro h5::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 34px;
  height: 2px;
  background: var(--brand-accent);
}

.fn-subscribe-intro p {
  margin: 0;
  max-width: 46ch;
  font-size: .88rem;
  line-height: 1.6;
  color: rgba(255, 255, 255, .62);
}

.fn-subscribe-form {
  flex: 0 1 460px;
  min-width: 0;
}

/* 输入框和按钮融成一个整体：圆角和描边由外层承担，
   内部两个元素各自去掉边框，和顶部搜索框同一套做法 */
.fn-field {
  display: flex;
  align-items: stretch;
  border-radius: 50rem;
  background: #fff;
  overflow: hidden;
}

.fn-field input {
  flex: 1 1 auto;
  min-width: 0;
  padding: 13px 20px;
  border: 0;
  background: transparent;
  /* iOS Safari 对 <16px 的输入框会自动放大页面 */
  font-size: 1rem;
  color: var(--brand-ink);
}

.fn-field input::placeholder {
  color: var(--brand-muted);
}

.fn-field input:focus {
  outline: 0;
}

.fn-field button {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 58px;
  padding: 0;
  border: 0;
  background: var(--brand-accent);
  font-size: 1rem;
  color: #fff;
  cursor: pointer;
  transition: background-color .18s ease;
}

.fn-field button:hover,
.fn-field button:focus {
  background: var(--brand-accent-deep);
}

.fn-subscribe-form.is-busy .fn-field {
  opacity: .55;
  pointer-events: none;
}

/* 蜜罐字段：不能用 display:none —— 部分脚本会跳过不可见字段，
   挪出视口之外才既骗得过脚本又不占版面。aria-hidden + tabindex=-1
   保证读屏和键盘用户碰不到它。 */
.fn-hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.fn-consent {
  margin: 10px 2px 0;
  font-size: .75rem;
  line-height: 1.5;
  color: rgba(255, 255, 255, .42);
}

.fn-subscribe-msg {
  margin-top: 8px;
  padding: 0 2px;
  font-size: .82rem;
}

.fn-subscribe-msg.is-success {
  color: #7BD8A6;
}

.fn-subscribe-msg.is-error {
  /* 深底上的红要提亮才够对比：#FFA39E 压在 --brand-dark 上 9.59:1 */
  color: #FFA39E;
}

/* --------------------------------------------------------------------------
   版权行下方的支付图标
   -------------------------------------------------------------------------- */
.footer-pay {
  margin-top: 14px;
  text-align: center;
}

.footer-pay img {
  height: 24px;
  width: auto;
  max-width: 100%;
  /* 图标本身是彩色的，在黑底上略微压一点亮度，
     避免它比上方的公司信息还抢眼 */
  opacity: .9;
}

/* --------------------------------------------------------------------------
   手机端：上下堆叠
   -------------------------------------------------------------------------- */
@media (max-width: 991.98px) {
  .fn-subscribe {
    flex-direction: column;
    align-items: stretch;
    gap: 18px;
    padding-top: 22px;
  }

  .fn-subscribe-form {
    flex: none;
  }

  .fn-subscribe-intro p {
    max-width: none;
  }
}

@media (max-width: 767.98px) {
  .fn-field input {
    padding: 12px 16px;
  }

  .fn-field button {
    width: 52px;
  }

  .footer-pay img {
    height: 22px;
  }
}

/* ==========================================================================
   页脚与页面高度（全站，电脑手机通用）

   OpenCart 默认主题用的是 2010 年代那套「绝对定位粘底页脚」：
     stylesheet.css:27   #container { position: absolute; margin-bottom: 300px }
     stylesheet.css:296  footer     { position: absolute; bottom: -1px }
     stylesheet.css:36   #content   { padding-bottom: 730px }
     stylesheet.css:41   @media (min-width:576px) { #content { padding-bottom: 400px } }

   页脚脱离文档流钉在容器底部，内容靠一个**写死的** 400px 下内边距去躲它。
   这套只在「页脚高度 ≤ 400px」时成立，而这是个没人会去维护的隐含契约：
   我们往页脚加了公司信息栏、四个链接栏、邮件订阅条、支付图标之后，
   电脑端页脚早就超过 450px —— 超出的部分直接盖在内容最后 50~100px 上。
   表现就是分页器和「Add to Cart」按钮被页脚的 logo 压住。

   ⚠ 这影响**每一个电脑版页面**，不只是商品列表页；页面越短越明显
   （空购物车、联系页、登录页、会员中心的少行列表都会被盖）。
   之前只在手机端修过，这里提升为全局。

   改用 flex 实现粘底页脚：容器纵向排列、main 吃掉剩余高度、页脚跟在后面。
   内容再长页脚也在下面，内容再短页脚也贴在视口底部，
   而且不需要任何一个写死的避让数值。
   ========================================================================== */
#container {
  position: static;
  display: flex;
  flex-direction: column;
  /* 100vh 兜底给不支持 dvh 的旧浏览器；dvh 在移动端会跟随地址栏收放，
     不会像 vh 那样在滚动时突然多出一截空白 */
  min-height: 100vh;
  min-height: 100dvh;
  margin-bottom: 0;
}

/* main 撑开剩余高度，页脚被推到底部。
   flex-shrink 必须是 0 —— 默认的 1 会在内容超高时反过来压缩 main。 */
#container > main {
  flex: 1 0 auto;
}

footer {
  position: static;
  bottom: auto;
  flex: 0 0 auto;
}

/* 那个用来躲绝对定位页脚的巨额内边距不再需要。
   手机端（<768px）已有自己的 24px 覆盖，这里只管平板以上。 */
@media (min-width: 768px) {
  #content,
  #column-left,
  #column-right {
    padding-bottom: 40px;
  }
}

/* ==========================================================================
   顶栏下拉（My Account / 币种 / 语言）
   模板：extension/ocmod/catalog/view/template/common/header.twig

   ── 修复：下拉被 header 盖住 ────────────────────────────────────────────
   这是上一轮加吸顶时带出的回归。header 拿了 position:sticky + z-index:1030，
   于是它建立了自己的层叠上下文并压在所有 static 兄弟元素之上；
   而 #top 是 position:static，z-index 对它完全无效，
   所以从 #top 里弹出的下拉一进入 header 的区域就被盖掉。
   ⚠ #top 在 common/header.twig 里，所以**每个页面都有这个问题**，不只是首页。

   给 #top 一个高于 header 的层级即可；同时把吸顶后的 header 再抬高一档 ——
   否则页面滚动时 #top 往上走、会反过来盖在吸顶的 header 上，出现穿帮。
   层级排布：header 1030 < #top 1031 < header.is-stuck 1032 < 底部标签栏 1040
   ========================================================================== */
#top {
  position: relative;
  z-index: 1031;
}

header.is-stuck {
  z-index: 1032;
}

/* --------------------------------------------------------------------------
   三个下拉共用的卡片外观
   原版是 Bootstrap 默认的白盒子：直角、1px 灰边、紧贴触发器。
   -------------------------------------------------------------------------- */
#top .dropdown-menu {
  margin-top: 10px;
  padding: 8px;
  border: 0;
  border-radius: 12px;
  background: #fff;
  box-shadow: 0 12px 34px rgba(0, 0, 0, .28);
  /* #top a 的颜色规则会继承进这块白底面板，必须显式指定 */
  color: var(--brand-ink);
  min-width: 200px;
}

/* 小三角，指回触发器，说明这块面板属于谁 */
#top .dropdown-menu::before {
  content: "";
  position: absolute;
  top: -6px;
  right: 18px;
  width: 12px;
  height: 12px;
  background: #fff;
  transform: rotate(45deg);
}

/* 左对齐的两个（币种/语言）三角跟到左边 */
#top #top-tools .dropdown-menu::before,
#top #header-tools .dropdown-menu::before {
  right: auto;
  left: 18px;
}

#top .dropdown-item {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 10px 12px;
  border-radius: 8px;
  font-size: .89rem;
  color: var(--brand-ink);
  cursor: pointer;
  transition: background-color .16s ease, color .16s ease;
}

#top .dropdown-item i {
  flex: none;
  /* 定宽：图标本身宽度不一，不定宽的话文字左边缘会参差不齐 */
  width: 16px;
  text-align: center;
  font-size: .85rem;
  color: var(--brand-muted);
  transition: color .16s ease;
}

#top .dropdown-item:hover,
#top .dropdown-item:focus {
  background: var(--brand-surface);
  color: var(--brand-accent-deep);
}

#top .dropdown-item:hover i,
#top .dropdown-item:focus i {
  color: var(--brand-accent-deep);
}

#top .dropdown-divider {
  margin: 6px 4px;
  border-top-color: var(--brand-line);
  opacity: 1;
}

/* 退出弱化，避免和上面的功能项抢注意力 */
#top .ac-menu-out {
  color: var(--brand-muted);
}

/* --------------------------------------------------------------------------
   未登录状态
   原版是「Register / Login」两条一模一样的链接，用户得先读完才知道
   哪个是自己要的。登录是主动作，做成按钮；注册是次要选项，做成文字链接。
   -------------------------------------------------------------------------- */
/* ⚠ 下面这两个类必须带 #top 前缀。
   #top a 那条（特异度 1,0,1）会压过裸类选择器（0,1,0），
   结果是这里的颜色根本不生效。
   上面 .dropdown-item 已经防过这一手，这两个新类当时漏了。 */
.ac-menu-cta {
  padding: 6px 6px 4px;
}

#top .ac-menu-btn {
  display: block;
  padding: 11px 18px;
  border-radius: 50rem;
  background: var(--brand-accent);
  font-size: .875rem;
  font-weight: 600;
  letter-spacing: .01em;
  text-transform: none;
  text-align: center;
  text-decoration: none;
  color: #fff;
  transition: background-color .18s ease;
}

#top .ac-menu-btn:hover,
#top .ac-menu-btn:focus {
  background: var(--brand-dark);
  color: #fff;
}

#top .ac-menu-alt {
  display: block;
  margin-top: 9px;
  padding-bottom: 3px;
  font-size: .82rem;
  text-align: center;
  text-decoration: underline;
  text-underline-offset: 3px;
  color: var(--brand-muted);
}

#top .ac-menu-alt:hover,
#top .ac-menu-alt:focus {
  color: var(--brand-accent-deep);
}

/* ==========================================================================
   登录 / 注册页
   模板：extension/ocmod/catalog/view/template/account/{login,register}.twig

   两页共用一套「单列居中窄卡片」。原版的问题不是配色：
     · 登录页是两张等权重的卡片并排，用户点进 /login 就是要登录，
       注册卡却占了一半版面，且两卡高度对不齐、左卡下方一大块空白；
     · 注册页是 col-sm-2 标签 + col-sm-10 输入框的水平表单，
       长标签在桌面端就断行，手机端每行都被撑得很高；
     · 两页右侧都挂着会员中心侧栏 —— 给一个**没登录/还没有账号**的人
       列出 Payment Methods / Address Book / Order History，
       每一条点进去都会被打回来。
   ========================================================================== */

/* 认证页不需要会员侧栏。#content 是 .col（flex-grow），
   侧栏 display:none 之后它自动占满整行。 */
#account-login #column-right,
#account-register #column-right,
#account-forgotten #column-right,
#account-reset #column-right {
  display: none;
}

.au-page {
  max-width: 452px;
  margin: 10px auto 48px;
}

/* 注册页字段多，放宽一点，姓名才排得下两列 */
.au-page.is-wide {
  max-width: 620px;
}

.au-card {
  padding: 34px 32px 32px;
  border: 1px solid var(--brand-line);
  border-radius: 16px;
  background: var(--brand-bg);
  box-shadow: 0 10px 34px rgba(0, 0, 0, .05);
}

.au-title {
  margin: 0 0 26px;
  font-family: var(--brand-font);
  font-size: 1.75rem;
  font-weight: 600;
  line-height: 1.2;
  text-align: center;
  color: var(--brand-ink);
}

/* --------------------------------------------------------------------------
   字段
   ⚠ .au-field 必须保持 display:block。注册页那段自定义字段脚本用的是
   jQuery 的 .hide()/.show()，.show() 会把内联样式还原成元素的默认
   display（div 即 block）—— 这里若写成 flex/grid，字段被显示回来时
   就会被 .show() 写死成 block，布局直接塌掉。
   -------------------------------------------------------------------------- */
.au-field {
  margin-bottom: 18px;
}

.au-field .form-label,
.au-field > .form-label {
  display: block;
  margin-bottom: 7px;
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--brand-muted);
}

.au-field .form-control,
.au-field .form-select {
  height: 48px;
  padding: 0 15px;
  border: 1px solid var(--brand-line);
  border-radius: 10px;
  /* iOS Safari 对 <16px 的输入框会自动放大页面 */
  font-size: 1rem;
  color: var(--brand-ink);
}

.au-field textarea.form-control {
  height: auto;
  padding: 12px 15px;
}

.au-field .form-control:focus,
.au-field .form-select:focus {
  border-color: var(--brand-accent);
  box-shadow: 0 0 0 .2rem rgba(var(--brand-accent-rgb), .14);
}

.au-field .form-control::placeholder {
  color: #AEB8BF;
}

/* 密码标签和「忘记密码」同一行 —— 用户想起要点它，
   正是在看密码框的那一刻，而不是填完之后 */
.au-label-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.au-forgot {
  font-size: .78rem;
  text-decoration: underline;
  text-underline-offset: 3px;
  color: var(--brand-muted);
  white-space: nowrap;
}

.au-forgot:hover,
.au-forgot:focus {
  color: var(--brand-accent-deep);
}

.au-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 14px;
}

.au-choices {
  padding-top: 2px;
}

.au-choices .form-check-input:checked {
  background-color: var(--brand-accent);
  border-color: var(--brand-accent);
}

/* --------------------------------------------------------------------------
   分组小标题
   原版每组一个 <fieldset><legend>，视觉权重和页面 h1 差不多，
   连「Newsletter」这种只有一个开关的分组也顶着一个大标题。
   -------------------------------------------------------------------------- */
.au-section {
  margin-bottom: 22px;
}

.au-section-label {
  display: block;
  margin-bottom: 16px;
  padding-bottom: 9px;
  border-bottom: 1px solid var(--brand-line);
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--brand-muted);
}

/* --------------------------------------------------------------------------
   订阅 / 条款勾选
   -------------------------------------------------------------------------- */
.au-consents {
  margin-bottom: 22px;
}

.au-check {
  display: flex;
  align-items: flex-start;
  gap: 11px;
  padding: 11px 0;
}

.au-check + .au-check {
  border-top: 1px solid var(--brand-line);
}

.au-check .form-check-input {
  flex: none;
  float: none;
  margin: 2px 0 0;
  width: 18px;
  height: 18px;
  cursor: pointer;
}

.au-check .form-check-input:checked {
  background-color: var(--brand-accent);
  border-color: var(--brand-accent);
}

.au-check .form-check-input:focus {
  border-color: var(--brand-accent);
  box-shadow: 0 0 0 .2rem rgba(var(--brand-accent-rgb), .16);
}

.au-check label {
  margin: 0;
  font-size: .88rem;
  line-height: 1.45;
  cursor: pointer;
}

/* --------------------------------------------------------------------------
   主按钮
   -------------------------------------------------------------------------- */
.au-submit {
  display: block;
  width: 100%;
  margin-top: 4px;
  padding: 14px 24px;
  border: 0;
  border-radius: 50rem;
  background: var(--brand-accent);
  font-size: .875rem;
  font-weight: 600;
  letter-spacing: .01em;
  text-transform: none;
  color: #fff;
  cursor: pointer;
  transition: background-color .18s ease;
}

.au-submit:hover,
.au-submit:focus {
  background: var(--brand-dark);
  color: #fff;
}

/* --------------------------------------------------------------------------
   卡片下方的另一条路
   登录页 → 去注册；注册页 → 去登录
   -------------------------------------------------------------------------- */
.au-alt {
  margin-top: 24px;
  padding: 22px 24px;
  border: 1px solid var(--brand-line);
  border-radius: 14px;
  background: var(--brand-surface);
  text-align: center;
}

.au-alt-head {
  display: block;
  margin-bottom: 7px;
  font-size: .74rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--brand-ink);
}

.au-alt-text {
  margin: 0;
  font-size: .86rem;
  line-height: 1.6;
  color: var(--brand-muted);
}

.au-alt-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-top: 16px;
  padding: 12px 32px;
  border: 1px solid var(--brand-ink);
  border-radius: 50rem;
  font-size: .875rem;
  font-weight: 600;
  letter-spacing: .01em;
  text-transform: none;
  text-decoration: none;
  color: var(--brand-ink);
  transition: background-color .18s ease, color .18s ease;
}

.au-alt-btn:hover,
.au-alt-btn:focus {
  background: var(--brand-ink);
  color: #fff;
}

/* 注册页那条提示自带一个指向登录页的链接 */
.au-alt-text a {
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 3px;
  color: var(--brand-accent-deep);
}

/* --------------------------------------------------------------------------
   手机端
   -------------------------------------------------------------------------- */
@media (max-width: 575.98px) {
  .au-page,
  .au-page.is-wide {
    max-width: none;
    margin-bottom: 32px;
  }

  .au-card {
    padding: 26px 20px 24px;
    border-radius: 14px;
  }

  .au-title {
    margin-bottom: 22px;
    font-size: 1.45rem;
  }

  /* 姓名并排在 375px 下每格只剩 ~150px，放不下 "E-Mail Address" 这类占位符 */
  .au-row {
    grid-template-columns: 1fr;
  }

  .au-alt {
    padding: 20px 18px;
  }

  .au-alt-btn {
    display: flex;
    width: 100%;
  }
}

/* --------------------------------------------------------------------------
   认证页补充件 + 会员中心表单页
   模板：account/{forgotten,forgotten_reset,password,edit,address_form}.twig

   会员中心里的表单页（改密码 / 改资料 / 地址表单）保留侧栏，所以**不套**
   .au-page（那是给认证页用的窄居中容器），直接用 .au-card 占满 #content。
   字段、标签、必填星号全部沿用同一套 .au-* 类。
   -------------------------------------------------------------------------- */

.au-lead {
  margin: -12px 0 22px;
  font-size: .88rem;
  line-height: 1.6;
  text-align: center;
  color: var(--brand-muted);
}

/* 认证页卡片下方的「返回」—— 次要动作，不做成按钮 */
.au-back {
  margin-top: 18px;
  text-align: center;
}

.au-back a {
  font-size: .84rem;
  text-decoration: underline;
  text-underline-offset: 3px;
  color: var(--brand-muted);
}

.au-back a:hover,
.au-back a:focus {
  color: var(--brand-accent-deep);
}

/* 表单底部的操作行：返回靠左、提交靠右 */
.au-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 26px;
  padding-top: 20px;
  border-top: 1px solid var(--brand-line);
}

/* 单选/复选组横排（地址表单的「设为默认」用） */
.au-choices-inline {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 24px;
}

.au-field-inline {
  margin-top: 4px;
  padding-top: 18px;
  border-top: 1px solid var(--brand-line);
}

@media (max-width: 575.98px) {
  .au-actions {
    /* 375px 下两个按钮并排会各自被压到放不下文字 */
    flex-direction: column-reverse;
    align-items: stretch;
  }

  .au-actions .oi-btn {
    display: flex;
    width: 100%;
  }
}

/* --------------------------------------------------------------------------
   注册页 / 资料页的电话区号
   脚本：extension/ocmod/catalog/view/javascript/dial-code.js
   它复用了结账页那套 .op-tel / .op-dial 类名，但结账页的字段外观
   （高度、圆角）和这里不同，所以在 .au-field 作用域内重写一遍。

   边框和圆角由外层 .op-tel 统一承载，内部下拉和输入框各自去边框，
   融成一个整体 —— 和顶部搜索框、页脚订阅框是同一套做法。
   -------------------------------------------------------------------------- */
.au-field .op-tel {
  flex-wrap: nowrap;
  border: 1px solid var(--brand-line);
  border-radius: 10px;
  background: #fff;
  overflow: hidden;
  transition: border-color .18s ease, box-shadow .18s ease;
}

/* 焦点环画在外层，否则内部两个元素会各画一圈 */
.au-field .op-tel:focus-within {
  border-color: var(--brand-accent);
  box-shadow: 0 0 0 .2rem rgba(var(--brand-accent-rgb), .14);
}

.au-field .op-tel .form-select,
.au-field .op-tel .form-control {
  height: 46px;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

.au-field .op-tel .op-dial {
  flex: 0 0 104px;
  width: 104px;
  border-right: 1px solid var(--brand-line);
  padding-left: 14px;
  padding-right: 1.6rem;
  background-position: right .5rem center;
  font-size: .95rem;
}

@media (max-width: 575.98px) {
  .au-field .op-tel .op-dial {
    flex: 0 0 92px;
    width: 92px;
    padding-left: 11px;
  }
}

/* ==========================================================================
   信用卡安全支付（AlpPay）
   模板：extension/ecommerce/catalog/view/template/payment/alppay_form.twig
   编排：extension/ocmod/catalog/view/javascript/checkout-onepage.js

   卡表单在 #onepage-card —— 右栏里 #checkout-confirm 的兄弟节点，
   夹在订单摘要和 Place Order 之间。绝不能放进 #checkout-confirm 或
   #onepage-payment：那两块每次刷新都被整块覆盖，卡号输到一半改个
   地址就全没了。这里只加载一次，之后只切显示/隐藏。
   ========================================================================== */

/* --------------------------------------------------------------------------
   支付方式选项里的安全信号
   小锁字体图标已换成绿色盾牌对勾（.op-option-shield，内联 SVG）——
   字体图标只能单色，表达不了「盾牌绿 + 对勾白」这套通行的安全视觉。
   -------------------------------------------------------------------------- */
.op-option-desc {
  display: block;
  margin-top: 4px;
  font-size: .8rem;
  line-height: 1.55;
  color: var(--brand-muted);
}

/* 卡组织标志固定另起一行、与上方文字左对齐（30px = 18px 圆点 + 12px gap）。
   不做「宽屏右对齐、窄屏换行」两套 —— 右对齐时描述会被挤到只剩三百来像素，
   在 992~1200px 之间直接变成四行；而且电脑端和手机端本来就要求统一。 */
.op-option-brands {
  flex: 0 0 100%;
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  padding: 12px 0 0 30px;
}

/* 三个标志同为 70×26 视框，写死高度后宽度也完全一致，排出来是齐的 */
.op-option-brands img {
  display: block;
  height: 22px;
  width: auto;
}

/* --------------------------------------------------------------------------
   卡表单
   -------------------------------------------------------------------------- */
/* 卡表单现在夹在订单摘要和 Place Order 之间（右栏；手机端堆叠后
   就是摘要正下方）。上下都要留出间距 —— 原来的 -8px 负边距是为了
   贴住左栏的支付单选列表，换了位置就不适用了。 */
#onepage-card {
  margin: 18px 0;
}

#onepage-card[hidden] {
  display: none;
}

.ap-card-pay {
  padding: 18px 18px 6px;
  border: 1px solid var(--brand-accent);
  border-radius: 12px;
  background: var(--brand-surface);
}

.ap-card-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 16px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--brand-line);
}

/* 卡表单头部的盾牌跟着放大，两处不能一大一小 */
.ap-card-secure .op-shield {
  width: 22px;
  height: 22px;
}

.ap-card-secure {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--secure-green);
}

/* 卡表单头部的卡组织标志。和支付方式单选里那排同源同尺寸 */
.ap-card-brands {
  display: flex;
  align-items: center;
  gap: 8px;
}

.ap-card-brands img {
  display: block;
  width: auto;
  height: 22px;
}

.ap-card-field {
  margin-bottom: 14px;
}

.ap-card-field .form-label {
  display: block;
  margin-bottom: 6px;
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--brand-muted);
}

.ap-card-field .form-control {
  height: 46px;
  padding: 0 14px;
  border: 1px solid var(--brand-line);
  border-radius: 9px;
  background: #fff;
  /* 卡号 / 有效期 / CVV 用等宽数字：分组之后每一位对齐，
     用户核对卡面时不容易看串行。iOS 对 <16px 的输入框会放大页面，
     所以最小也得是 1rem。 */
  font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace;
  font-size: 1rem;
  letter-spacing: .04em;
  color: var(--brand-ink);
}

/* 卡面姓名是文字不是数字，用回常规字体 */
#alppay-holder {
  font-family: inherit;
  letter-spacing: .06em;
  text-transform: uppercase;
}

.ap-card-field .form-control:focus {
  border-color: var(--brand-accent);
  box-shadow: 0 0 0 .2rem rgba(var(--brand-accent-rgb), .14);
}

.ap-card-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 14px;
}

.ap-card-help {
  display: block;
  margin-top: 5px;
  font-size: .72rem;
  line-height: 1.4;
  color: var(--brand-muted);
}

/* --------------------------------------------------------------------------
   卡种指示
   JS 按 BIN 前缀写 data-brand，这里只做一个小色块 + 文字缩写 ——
   不引卡组织的真实商标：那些是注册商标，逐个嵌进来要授权，
   而表单头部那排卡组织 SVG 已经把「我们收哪些卡」说清楚了。
   -------------------------------------------------------------------------- */
.ap-card-number {
  position: relative;
}

.ap-card-type {
  position: absolute;
  top: 50%;
  right: 12px;
  transform: translateY(-50%);
  font-size: .64rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--brand-muted);
  pointer-events: none;
}

.ap-card-type[data-brand="visa"]::after       { content: "VISA"; }
.ap-card-type[data-brand="mastercard"]::after { content: "MC"; }
.ap-card-type[data-brand="amex"]::after       { content: "AMEX"; }
.ap-card-type[data-brand="jcb"]::after        { content: "JCB"; }
.ap-card-type[data-brand="unionpay"]::after   { content: "UNIONPAY"; }
.ap-card-type[data-brand="discover"]::after   { content: "DISCOVER"; }

/* 识别出卡种时给卡号右侧留出位置，避免数字压到标签下面 */
.ap-card-number:has(.ap-card-type[data-brand]:not([data-brand=""])) .form-control {
  padding-right: 84px;
}

/* --------------------------------------------------------------------------
   手机端
   -------------------------------------------------------------------------- */
@media (max-width: 575.98px) {
  .ap-card-pay {
    padding: 16px 14px 4px;
  }

  .ap-card-head {
    /* 375px 下安全标记和卡组织图并排会把图压得看不清 */
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
  }

  /* 顶对齐、圆点补偿、卡组织标志换行 —— 这些现在都是全局默认值，
     窄屏不需要再单独覆盖一遍（三个 70×26 的标志排开只有 193px，
     313px 的窄屏内宽装得下，不必再缩小）。 */
  .op-option-brands img {
    height: 20px;
  }
}

/* ==========================================================================
   结账页：信任区 + 手机端底部悬浮金额条
   模板：extension/ocmod/catalog/view/template/checkout/checkout.twig
   ========================================================================== */

/* --------------------------------------------------------------------------
   绿色打勾盾牌
   内联 SVG，跟着字号缩放。不用图片：安全标识一旦变成破图，
   比没有标识更伤转化。
   -------------------------------------------------------------------------- */
.op-shield {
  flex: none;
  vertical-align: -3px;
}

/* 盾牌从 15px 放大到 24px（约 1.6 倍）。
   没有做到字面上的 2 倍（30px）—— 标题行高只有 21px，30px 会上下
   顶出行外，把整行撑高、和描述挤在一起。24px 已经明显高过文字，
   是这一行里最先被看到的元素。 */
.op-option-shield {
  width: 24px;
  height: 24px;
  margin-right: 8px;
}

/* --------------------------------------------------------------------------
   信任区（Place Order + 条款说明之下）
   -------------------------------------------------------------------------- */
.op-trust {
  margin-top: 20px;
}

.op-trust-badges {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  margin-bottom: 14px;
  padding: 12px 16px;
  border: 1px solid var(--brand-line);
  border-radius: var(--oc-radius);
  background-color: var(--brand-surface);
}

.op-trust-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.op-trust-strong {
  font-size: .95rem;
  font-weight: 600;
  color: var(--secure-green);
}

.op-trust-sub {
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--brand-muted);
}

.op-trust-box {
  padding: 14px 14px 16px;
  border: 1px solid var(--brand-line);
  border-radius: var(--oc-radius);
  background-color: var(--brand-surface);
}

.op-trust-title {
  display: block;
  margin-bottom: 12px;
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .11em;
  text-transform: uppercase;
  text-align: center;
  color: var(--brand-ink);
}

/* 9 个图正好 3×3；固定三列，不用 auto-fit ——
   auto-fit 在中间宽度会排成 4+4+1，最后一行孤零零一个格子。 */
.op-trust-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}

.op-trust-tile {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 9px 6px;
  border: 1px solid var(--brand-line);
  border-radius: 7px;
  background-color: #FFFFFF;
}

.op-trust-tile img {
  display: block;
  width: 100%;
  max-width: 70px;
  height: auto;
}

/* --------------------------------------------------------------------------
   手机端底部悬浮金额条
   桌面端不需要：右栏摘要本来就吸顶跟随，金额一直在视野里。
   -------------------------------------------------------------------------- */
.op-bar {
  display: none;
}

@media (max-width: 767.98px) {
  .op-bar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    /* 高于 #mobile-tabbar，也高于吸顶头部的 1030/1032 */
    z-index: 1041;
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 11px 14px calc(11px + env(safe-area-inset-bottom, 0px));
    background-color: #FFFFFF;
    border-top: 1px solid var(--brand-line);
    box-shadow: 0 -3px 16px rgba(0, 0, 0, .1);
  }

  /* 金额还没算出来之前（首屏、地址未填完）整条不出现，
     免得先闪一个空白的价格框 */
  .op-bar[hidden] {
    display: none;
  }

  .op-bar-total {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
  }

  .op-bar-label {
    font-size: .62rem;
    font-weight: 600;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--brand-muted);
  }

  .op-bar-amount {
    font-size: 1.2rem;
    font-weight: 700;
    line-height: 1.15;
    white-space: nowrap;
    color: var(--brand-ink);
  }

  .op-bar-btn {
    flex: 1 1 auto;
    padding: 14px 16px;
    border: 0;
    border-radius: 50rem;
    background-color: var(--brand-accent);
    font-size: .875rem;
    font-weight: 600;
    letter-spacing: .01em;
    text-transform: none;
    color: #FFFFFF;
  }

  .op-bar-btn:disabled {
    opacity: .55;
  }

  /* 忙碌态跟主按钮同一套观感：转圈 + 换成深色，不做半透明 ——
     半透明会让人以为按钮失效了 */
  .op-bar-btn.is-busy {
    opacity: 1;
    cursor: progress;
    background-color: var(--brand-ink);
    /* 「Processing…」比「Place Order」长，窄屏别把金额挤没了 */
    font-size: .7rem;
    letter-spacing: .06em;
  }

  /* 结账页收起全局底部标签栏。
     两条固定栏叠起来是 58 + 66 ≈ 124px，在 667px 的视口上占掉 18%；
     而且结账是聚焦流程，这时候放「回首页 / 逛分类」的入口是在劝退。 */
  body.is-checkout #mobile-tabbar,
  body:has(#checkout-checkout) #mobile-tabbar {
    display: none;
  }

  /* 页脚原本给标签栏留的位置，改留给悬浮条 */
  body.is-checkout footer,
  body:has(#checkout-checkout) footer {
    padding-bottom: calc(76px + env(safe-area-inset-bottom, 0px));
  }

  /* 流内的下单按钮在手机端收起：悬浮条已经是随时可点的 CTA，
     两颗一模一样的粉色按钮只会让人犹豫点哪个。
     条款说明和信任区留在流内不动 —— 它们是要被读到的。

     ⚠ 必须由 .is-bar-on 把关（syncBar() 在合计到手后才加上它）：
     无条件隐藏的话，合计还没算出来、悬浮条还是 hidden 的那段时间里，
     页面上会一颗可点的下单按钮都没有。 */
  body.is-bar-on #onepage-actions #button-place-order {
    display: none;
  }

  .op-trust-grid {
    gap: 7px;
  }

  .op-trust-tile {
    padding: 8px 4px;
  }
}

/* ==========================================================================
   商品模块标签页（Latest / Featured / Bestseller）
   模板：extension/ocmod/.../module/{latest,featured,bestseller,special}.twig
   编排：extension/ocmod/catalog/view/javascript/product-collection.js
   ========================================================================== */
.pc {
  margin-bottom: 44px;
}

.pc-title {
  margin: 0 0 14px;
  font-family: var(--brand-font);
  font-size: clamp(1.5rem, 3vw, 2.1rem);
  font-weight: 700;
  letter-spacing: .02em;
  text-align: center;
  text-transform: uppercase;
  color: var(--brand-ink);
}

.pc-tabs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: clamp(14px, 3vw, 40px);
  margin-bottom: 26px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--brand-line);
}

.pc-tab {
  position: relative;
  padding: 6px 2px;
  border: 0;
  background: none;
  font-size: clamp(.82rem, 1.5vw, .98rem);
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--brand-muted);
  cursor: pointer;
  transition: color .2s ease;
}

.pc-tab:hover {
  color: var(--brand-ink);
}

/* 选中态用品牌粉，不用效果图里的琥珀黄 ——
   那个黄是原主题的强调色，站内任何地方都没有，引进来就多一个孤立的颜色。 */
.pc-tab.is-active {
  color: var(--brand-accent);
}

/* 下划线压在 .pc-tabs 的那条细线上：bottom 取负值等于边框位置 + 自身高度 */
.pc-tab.is-active::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -15px;
  height: 2px;
  background-color: var(--brand-accent);
}

/* 细线下方的小三角。用 border 画而不是 clip-path —— 兼容面更广，
   且这里只要一个 5px 的实心三角，没必要动用裁剪路径。 */
.pc-tab.is-active::before {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -20px;
  width: 0;
  height: 0;
  margin-left: -5px;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-top: 5px solid var(--brand-accent);
}

.pc-tab:focus-visible {
  outline: 2px solid var(--brand-accent);
  outline-offset: 3px;
  border-radius: 3px;
}

/* 组装成标签页之后，各模块自己的 <h3> 就多余了 —— 标题已经在标签上。
   ⚠ 只在 .pc 内部隐藏：分类页上单独出现的模块不会被组装，
     那里的 <h3> 必须照常显示。 */
.pc .pc-pane-title {
  display: none;
}

.pc-pane[hidden] {
  display: none;
}

/* ==========================================================================
   商品卡角标
   ========================================================================== */
.product-thumb .image {
  position: relative;
}

.pt-badge {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  padding: 5px 12px;
  border-radius: 4px;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  line-height: 1;
  /* 角标压在商品图上，图的明暗不可控，给一点投影保证边界清楚 */
  box-shadow: 0 1px 6px rgba(0, 0, 0, .18);
}

/* 折扣用品牌粉。效果图里 Sale 是黑底，但站内黑色已经是「主按钮 / 正文」的角色，
   再拿去做促销标识会削弱它；促销本来就是全站唯一允许高饱和的地方。 */
.pt-badge-sale {
  background-color: var(--brand-sale);
  color: #fff;
}

@media (max-width: 575.98px) {
  .pt-badge {
    top: 7px;
    left: 7px;
    padding: 4px 9px;
    font-size: .62rem;
  }
}

/* ==========================================================================
   快速查看（Quick View）
   控制器：extension/ocmod/catalog/controller/product/quickview.php
   模板　：extension/ocmod/catalog/view/template/product/quickview.twig
   脚本　：extension/ocmod/catalog/view/javascript/quickview.js
   ========================================================================== */
.qv-modal {
  position: fixed;
  inset: 0;
  z-index: 1080;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}

.qv-modal[hidden] {
  display: none;
}

.qv-backdrop {
  position: absolute;
  inset: 0;
  background-color: rgba(26, 26, 26, .55);
}

.qv-dialog {
  position: relative;
  width: 100%;
  max-width: 900px;
  /* 弹窗自身限高并内部滚动 —— 内容比屏幕高时，
     整页滚动会把弹窗顶出视野，用户以为它消失了 */
  max-height: calc(100vh - 40px);
  overflow-y: auto;
  border-radius: 14px;
  background-color: #fff;
  box-shadow: 0 18px 60px rgba(0, 0, 0, .3);
}

/* 弹窗打开时锁住页面滚动，否则背后的列表会跟着滚轮一起动 */
body.qv-open {
  overflow: hidden;
}

.qv-close {
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 2;
  width: 36px;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: 50%;
  background-color: var(--brand-accent);
  color: #fff;
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
}

.qv-loading,
.qv-error {
  padding: 70px 20px;
  text-align: center;
  color: var(--brand-muted);
}

.qv-spinner {
  display: inline-block;
  width: 26px;
  height: 26px;
  border: 3px solid var(--brand-line);
  border-top-color: var(--brand-accent);
  border-radius: 50%;
  animation: op-spin .7s linear infinite;
}

/* --------------------------------------------------------------------------
   内容
   -------------------------------------------------------------------------- */
.qv {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 26px;
  padding: 26px;
}

.qv-media {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
}

.qv-stage img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 10px;
  background-color: var(--brand-surface);
}

.qv-thumbs {
  display: flex;
  gap: 8px;
  overflow-x: auto;
}

.qv-thumb {
  flex: 0 0 62px;
  padding: 0;
  border: 2px solid transparent;
  border-radius: 8px;
  background: none;
  overflow: hidden;
  cursor: pointer;
}

.qv-thumb.is-active {
  border-color: var(--brand-accent);
}

.qv-thumb img {
  display: block;
  width: 100%;
  height: auto;
}

.qv-info {
  min-width: 0;
}

.qv-name {
  margin: 0 0 8px;
  /* 关闭按钮是绝对定位的，压在右上角（36px + 12px 边距）。
     长标题不留出这段宽度就会钻到它底下 —— 实测重叠 22px。 */
  padding-right: 44px;
  font-family: var(--brand-font);
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1.2;
  color: var(--brand-ink);
}

.qv-rating {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-bottom: 14px;
  color: var(--brand-star);
  font-size: .85rem;
}

.qv-rating-count {
  margin-left: 6px;
  color: var(--brand-muted);
}

.qv-meta {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 4px 12px;
  margin: 0 0 16px;
  font-size: .88rem;
}

.qv-meta dt {
  font-weight: 600;
  color: var(--brand-ink);
}

.qv-meta dd {
  margin: 0;
  color: var(--brand-muted);
}

.qv-stock {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 4px;
  background-color: #E8F5EC;
  color: var(--secure-green);
  font-size: .76rem;
  font-weight: 600;
}

.qv-stock.is-out {
  background-color: #FCEAEA;
  color: #B3261E;
}

/* 单价 + 加减器同一行：价格靠左，加减器顶到最右。
   分隔线挪到这一层 —— 原来画在 .qv-price 上，现在那只是行内的左半边。 */
.qv-priceline {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 6px;
  padding-top: 14px;
  border-top: 1px solid var(--brand-line);
}

.qv-price {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 10px;
  min-width: 0;
}

.qv-price-new {
  font-size: 1.7rem;
  font-weight: 700;
  color: var(--brand-ink);
}

.qv-price-old {
  font-size: 1.05rem;
  text-decoration: line-through;
  color: var(--brand-muted);
}

/* --------------------------------------------------------------------------
   折扣幅度徽章

   出现在四处：商品卡角标（.pt-badge-sale 里直接换文字）、商品详情页、
   心愿单、快速查看。后三处共用下面这一条 —— 快速查看原有的
   .qv-price-off 保留为别名，免得改动它已经调好的字号。

   ⚠ 幅度一律由 extension/ocmod/system/helper/price.php 计算，
     四处同一个数。不要在任何模板里另算一遍。

   颜色用 --brand-sale（#C8102E，白底 5.88:1）—— 它在本站的职务就是
   「折扣与促销价」，不进按钮、不进链接。
   -------------------------------------------------------------------------- */
.price-off,
.qv-price-off {
  font-size: .9rem;
  font-weight: 700;
  color: var(--brand-sale);
  white-space: nowrap;
}

/* 商品页的划线原价和徽章在同一行，给一点间距 */
.price-old + .price-off {
  margin-left: 8px;
}

/* 心愿单卡片的价格行是 flex，徽章不要被压缩 */
.ap-card-price .price-off {
  flex: 0 0 auto;
}

/* 真实库存提示。这里没有倒计时、没有「x% 已抢购」——
   那两个数字 OpenCart 里没有任何字段能支撑，只能靠编。 */
.qv-stock-low {
  margin: 0 0 14px;
  font-size: .82rem;
  font-weight: 600;
  color: #B3261E;
}

/* 加购靠左、立即买靠右，各占一半。
   不留 flex-wrap —— 两颗按钮必须同排，这是本次要求的重点；
   文字由下面的 nowrap + 基准宽度保证不断词。 */
.qv-buy {
  display: flex;
  gap: 10px;
  margin: 18px 0 16px;
}

.qv-qty {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: stretch;
  border: 1px solid var(--brand-line);
  border-radius: 50rem;
  overflow: hidden;
}

.qv-qty-btn {
  width: 36px;
  border: 0;
  background: none;
  font-size: 1.05rem;
  line-height: 1;
  color: var(--brand-ink);
  cursor: pointer;
}

.qv-qty input {
  width: 46px;
  border: 0;
  border-left: 1px solid var(--brand-line);
  border-right: 1px solid var(--brand-line);
  text-align: center;
  font-size: .95rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.qv-btn {
  /* 基准归零 + 等分：两颗按钮宽度一致，不因文字长短一大一小。
     加减器已经挪到价格行，这一排只剩它俩，宽度够。 */
  flex: 1 1 0;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 46px;
  padding: 0 20px;
  border: 0;
  border-radius: 50rem;
  font-size: .875rem;
  font-weight: 600;
  letter-spacing: .01em;
  text-transform: none;
  text-align: center;
  cursor: pointer;
  transition: background-color .2s ease;
}

.qv-btn-full {
  flex: 1 1 100%;
  margin: 18px 0 16px;
}

.qv-btn-dark {
  background-color: var(--brand-ink);
  color: #fff;
}

.qv-btn-dark:hover:not(:disabled) {
  background-color: var(--brand-accent);
}

.qv-btn-primary {
  background-color: var(--brand-accent);
  color: #fff;
  text-decoration: none;
}

.qv-btn-primary:hover:not(:disabled) {
  background-color: var(--brand-ink);
  color: #fff;
}

.qv-btn:disabled {
  opacity: .55;
  cursor: progress;
}

.qv-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--brand-line);
}

.qv-link {
  padding: 0;
  border: 0;
  background: none;
  font-size: .85rem;
  color: var(--brand-muted);
  text-decoration: none;
  cursor: pointer;
}

.qv-link:hover {
  color: var(--brand-accent-deep);
}

.qv-link.is-done {
  color: var(--secure-green);
}

/* --------------------------------------------------------------------------
   手机端：上下堆叠
   -------------------------------------------------------------------------- */
@media (max-width: 767.98px) {
  .qv-modal {
    padding: 0;
    align-items: flex-end;
  }

  .qv-dialog {
    max-height: 92vh;
    border-radius: 16px 16px 0 0;
  }

  .qv {
    grid-template-columns: minmax(0, 1fr);
    gap: 18px;
    padding: 18px;
  }

  .qv-name {
    font-size: 1.25rem;
  }

  .qv-price-new {
    font-size: 1.45rem;
  }

  /* 手机端两颗按钮仍然同排、各占一半（本次要求）。
     375 屏弹窗内宽约 341px，减去 10px 间距每颗约 165px，
     放得下「ADD TO CART」。字号收一档留出余量。 */
  .qv-btn {
    flex: 1 1 0;
    padding: 0 8px;
    font-size: .72rem;
    letter-spacing: .06em;
  }

  .qv-priceline {
    gap: 10px;
  }
}

/* ==========================================================================
   商品卡上的「快速查看」按钮
   ⚠ 必须排在 .product-thumb .button button:not(:first-child) 之后 ——
     两者特异度相同（均为 0,3,1），靠源码顺序决胜负。
   ========================================================================== */
/* 三颗按钮要在最挤的布局里并排放下：xl 四列时卡宽约 306px，
   减去 .button 的左右内边距只剩 282px。实测按原字号
   「Add to Cart + Quick View + 心愿单」合计约 336px，会把文字截成「Q…」——
   一个写着「Q…」的按钮比纯图标更糟。所以整排字号收到 .8rem、内边距收紧。 */
.product-thumb .button button {
  font-size: .8rem;
}

.product-thumb .button button:first-child {
  gap: 6px;
  padding: 0 10px;
}

.product-thumb .button button:not(:first-child) {
  flex: 0 0 42px;
}

.product-thumb .button button.pt-quickview {
  /* 覆盖 :not(:first-child) 的固定宽度：带文字时要按内容撑宽。
     1 1 auto 而不是 0 0 auto —— 空间不够时允许它先收缩，
     总比把「加入购物车」挤没了好。 */
  flex: 1 1 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-width: 0;
  padding: 0 10px;
  white-space: nowrap;
}

.product-thumb .button button.pt-quickview .btn-label {
  overflow: hidden;
  text-overflow: ellipsis;
}

.product-thumb .button button.pt-quickview i {
  flex: 0 0 auto;
}

/* 窄屏退回纯图标方块，和改造前一致（手机版保持现状）。
   固定 34px 与同断点下心愿单按钮的宽度一致，两个方块才对齐。 */
@media (max-width: 575.98px) {
  .product-thumb .button button.pt-quickview {
    flex: 0 0 32px;
    gap: 0;
    padding: 0;
  }

  .product-thumb .button button.pt-quickview .btn-label {
    display: none;
  }
}

/* ==========================================================================
   快速查看按钮的换行策略
   ⚠ 判据必须是【卡片宽度】而不是视口宽度：同样 1920 的屏，
     xl 四列时卡片只有 306px，而两列时有 600px —— 视口断点区分不了这两种。
     所以用容器查询。
   
   .pt-badge 是 .product-thumb 里唯一的绝对定位元素，它锚在
   .image（position:relative）上，所以 container-type 带来的
   containing block 变化不会移动它（已核对）。
   
   不支持容器查询的浏览器（Chrome<105 / Safari<16 / Firefox<110）
   拿到的是「三颗一排」的默认样式，与本次改动前一致，不会坏。
   ========================================================================== */
.product-thumb {
  container-type: inline-size;
}

/* 卡片放不下三颗带文字的按钮时（实测阈值约 340px），
   让加购独占一行、快速查看和心愿单排第二行。
   宁可多一行高度，也不把「Quick View」截成「Q…」——
   截断的按钮比纯图标更难认。 */
@container (max-width: 339.98px) {
  .product-thumb .button {
    flex-wrap: wrap;
  }

  .product-thumb .button button:first-child {
    flex: 1 1 100%;
  }
}

/* 手机端保持改造前的样子：三颗一排、快速查看是纯图标方块。
   必须排在容器查询之后 —— 两者选择器特异度相同，靠源码顺序决胜负。 */
@media (max-width: 575.98px) {
  .product-thumb .button {
    flex-wrap: nowrap;
  }

  .product-thumb .button button:first-child {
    flex: 1 1 auto;
  }
}

/* ==========================================================================
   手机端商品卡只留【加购 + 快速查看】两颗按钮
   卡片内宽约 127px（375 屏两列），三颗挤进去每颗都不到 40px，
   误触率高；心愿单在商品页和快速查看弹窗里都还有入口，这里收起代价最小。
   
   :not(:first-child):not(.pt-quickview) 精确指向心愿单那一颗，
   不依赖它是第几个 —— 以后按钮顺序变了这条也不会误伤。
   ========================================================================== */
@media (max-width: 575.98px) {
  .product-thumb .button button:not(:first-child):not(.pt-quickview) {
    display: none;
  }

  /* 只剩两颗时加购可以放宽一点，文字不至于被缩成一个词 */
  .product-thumb .button button:first-child {
    padding: 0 8px;
  }
}

/* --------------------------------------------------------------------------
   手机端头部的订单追踪图标（货币符号左侧）

   字号跟 #header-tools 里的币种/语言下拉对齐（.88rem），
   否则图标会比旁边的「£ ∨」明显大一圈。

   触控目标：min-width/height 40px 是移动端下限，
   但用 margin 负值把多出来的点击区吐回去，
   不让它把 flex 行擑高。
   -------------------------------------------------------------------------- */
.hdr-track {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 40px;
  height: 40px;
  margin: -10px -8px;
  font-size: .88rem;
  line-height: 1;
  color: var(--brand-ink);
  text-decoration: none;
}

.hdr-track:hover,
.hdr-track:focus {
  color: var(--brand-accent);
}

/* --------------------------------------------------------------------------
   手机端头部的 COA 证书库入口（货车图标左侧）

   为什么是三个字母不是图标：检测报告没有公认图标，
   烧瓶 / 证书 / 盾牌都得让人猜，猜错比不放更糟。

   排版上要和旁边的图标「同重」：图标是实心块面，等大的常规字重
   文字摆在旁边会显得轻飘。所以用 700 字重 + 一点字距把分量补回来，
   而不是把字号调大 —— 调大会把这一行整体撑高。

   触控目标 40px 高，多出来的用负 margin 吐回去，
   不让它撑高这一行（和 .hdr-track 同一套做法）。
   -------------------------------------------------------------------------- */
.hdr-coa {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 40px;
  padding: 0 4px;
  margin: -10px -4px;
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .06em;
  line-height: 1;
  /* 绿色在本站已经有确定含义：「安全 / 已验证」（支付通道、加密标记、
     信任区）。检测报告正是同一类东西，所以 COA 用绿不是多加一种颜色，
     是沿用已有的语义 —— 也顺带把它和旁边中性色的图标区分开。 */
  color: var(--secure-green-vivid);
  text-decoration: none;
  white-space: nowrap;
}

.hdr-coa:hover,
.hdr-coa:focus {
  color: var(--secure-green);
}

/* --------------------------------------------------------------------------
   页脚信任声明（≥99% 纯度 / 180 天退款 / 三重检测）

   桌面端：接在地址下面纵向排开。公司那一栏只有 ~370px，
           再切两半两边都难看，所以不做左右分栏。
   手机端：见下面 575.98px 的媒体查询 —— 那里才是它真正要填的空间。

   图标用品牌红（--brand-sale）。这是全站唯一允许出现高饱和红的
   两个地方之一（另一个是促销角标）—— 信任标记需要被一眼看到，
   而页脚深底上只有红能在不喧宾夺主的前提下跳出来。
   字形已验：f3ed / f2ea / f0c3 都在 fa-solid-900.woff2 里。
   -------------------------------------------------------------------------- */
.fc-trust {
  margin: 22px 0 0;
}

/* 电脑端：落在订阅行 intro 和输入框之间的空档里。
   intro 原本是 flex:1 1 auto，会把所有余量吃掉，信任块就被顶到
   表单边上贴着；改成不伸展，再给信任块 margin:auto 居中。 */
.fn-subscribe .fc-trust {
  flex: 0 0 auto;
  margin: 0 auto;
}

.fn-subscribe .fc-trust li {
  margin-bottom: 9px;
  white-space: nowrap;
}

.fc-trust li {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  margin-bottom: 11px;
  font-size: .84rem;
  font-weight: 600;
  line-height: 1.45;
  color: #fff;
}

.fc-trust li:last-child {
  margin-bottom: 0;
}

.fc-trust i {
  flex: 0 0 15px;
  margin-top: 2px;
  font-size: .95rem;
  text-align: center;
  color: var(--brand-sale);
}

/* ==========================================================================
   检测报告（COA）查询页
   模板：extension/ocmod/catalog/view/template/information/coa.twig
   控制器：extension/ocmod/catalog/controller/information/coa.php

   客户手里拿着瓶子上印的批号来核对，和查单页是同一种行为，
   所以视觉语言保持一致：细线、直角、大写字距标签、等宽数字。

   数字一律 tabular-nums：纯度和日期成列排布时，比例字体会让小数点
   对不齐，一眼扫下去看不出哪批高哪批低。
   ========================================================================== */
/* 这一页最后一块是研究用途声明，紧贴页脚会局促 */
#coa-page {
  padding-bottom: 20px;
}

/* --- 页头 --------------------------------------------------------------- */
/* 导语限宽 56ch 是为了可读性，但限宽之后右边会空出一大片 ——
   ≥992px 时右栏放三条信任要点把它填实，窄屏自动堆到导语下方。 */
.coa-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 24px;
  margin-bottom: 32px;
  padding-bottom: 28px;
  border-bottom: 1px solid var(--brand-line);
}

@media (min-width: 992px) {
  .coa-head {
    grid-template-columns: minmax(0, 1fr) 280px;
    gap: 56px;
    align-items: start;
  }
}

/* 网格子项默认 min-width:auto，长单词撑不下时会把整列顶宽、
   把右边的信任栏挤出去。栅格里的文本容器都要显式归零。 */
.coa-head-main {
  min-width: 0;
}

.coa-eyebrow {
  margin: 0 0 10px;
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--brand-accent);
}

.coa-title {
  margin: 0 0 14px;
  letter-spacing: -.01em;
}

.coa-intro {
  max-width: 56ch;
  margin: 0;
  color: var(--brand-muted);
  line-height: 1.7;
}

.coa-trust {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* 第一条也带上边线：右栏顶端有一道细线才成其为「栏」，
   否则三行字浮在空白里，看着像漏排了什么 */
.coa-trust li {
  padding: 11px 0;
  border-top: 1px solid var(--brand-line);
  font-size: .85rem;
  line-height: 1.5;
  color: var(--brand-ink);
}

.coa-trust li:last-child {
  padding-bottom: 0;
}

/* --- 工具条 ------------------------------------------------------------- */
.coa-tools {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  margin-bottom: 16px;
}

.coa-search {
  position: relative;
  flex: 1 1 320px;
  max-width: 460px;
}

/* 放大镜是内联 SVG，不是图标字体 —— 字体是子集化过的，
   少一个字形就是一个空框，这里不值得冒这个险 */
.coa-search-i {
  position: absolute;
  top: 50%;
  left: 15px;
  margin-top: -8px;
  color: var(--brand-muted);
  pointer-events: none;
}

.coa-search .form-control {
  height: 50px;
  padding: 0 14px 0 42px;
  /* ⚠ 不能用 --brand-line：那个值只有 1.30:1，是装饰线的亮度，
        描输入框边界达不到对比度要求（见令牌定义处的注释）。 */
  border: 1px solid var(--brand-line-strong);
  border-radius: 2px;
  font-size: .95rem;
}

.coa-search .form-control:focus {
  border-color: var(--brand-accent);
  box-shadow: 0 0 0 3px var(--brand-tint);
  outline: 0;
}

/* WebKit 给 type=search 自带的清除叉默认贴着右边缘，和其余内边距不搭 */
.coa-search .form-control::-webkit-search-cancel-button {
  margin-right: 2px;
}

/* 排序下拉只在手机端出现：那边整个 <thead> 是隐藏的，
   表头上的排序按钮点不到。≥768px 用表头排序，这个收起来。 */
.coa-sortbox {
  flex: 0 0 auto;
}

.coa-sortbox .form-select {
  height: 50px;
  padding: 0 34px 0 14px;
  border: 1px solid var(--brand-line-strong);
  border-radius: 2px;
  font-size: .9rem;
}

@media (min-width: 768px) {
  .coa-sortbox {
    display: none;
  }
}

/* 证书总数。放大到和 H1 同字号 —— 28 张证书是拿得出手的规模，
   缩在角落里当小标签是浪费。
   margin-left:auto 把它推到行尾，紧挨着搜索框的话右边会空出大半行。 */
.coa-count {
  margin: 0 0 0 auto;
  /* ⚠ 不要写死 2.5rem。Bootstrap 的 h1 在 <1200px 走 RFS 的
        calc(1.375rem + 1.5vw)，写死的话手机上计数会比标题大一圈。
        这里照抄 h1 的同一组值，两者永远同步。 */
  font-size: calc(1.375rem + 1.5vw);
  font-weight: 600;
  /* 字距从 .1em 收到 .02em。两个理由：
       · 本文件开头就立了规矩 ——「大字号下默认字距会显松，收一点才紧实」；
       · 收紧之后最长的一种文案（"128 of 128 certificates"）
         在 375px 上才放得下一行。 */
  letter-spacing: .02em;
  line-height: 1.15;
  text-transform: uppercase;
  /* 3.21:1。这个字号属于「大号文字」，门槛是 3:1 而不是 4.5:1，
     所以能用比头部 COA 更亮的一档绿。 */
  color: var(--secure-green-bright);
  /* ⚠ 原来这里有 white-space:nowrap。放大之后不能留 ——
        最窄的机型上长文案会顶出视口，横向滚动。让它折行。 */
  font-variant-numeric: tabular-nums;
}

@media (min-width: 1200px) {
  .coa-count {
    font-size: 2.5rem;
  }
}

/* --- 表格（桌面） ------------------------------------------------------- */
/* ==========================================================================
   检测报告的图：Description 末尾的窄条 + COA 标签里的缩略图横条

   为什么要有：原本这一页关于「这东西被测过吗」的全部证据，就是 COA 标签
   里的一张表。数字是抽象的，一张真实报告的缩略图是具体的。
   而且 Description 是**默认打开**的标签，报告藏在要点一下才看得到的
   标签里 —— 大多数访客根本不会点。

   ⚠ 预览图是 918x1188（约 0.773），**不是整数比**。
     不要写 aspect-ratio，高度一律交给 height:auto 跟着图本身走。
   ⚠ 白底 + 细边框是必要的：报告本身白纸黑字，没有边框会和页面背景
     糊成一片，看不出那是一份文件。
   ========================================================================== */

/* ── Description 末尾：最新批次 ─────────────────────────────────── */
.coa-strip {
  display: flex;
  gap: 16px;
  align-items: flex-start;
  margin: 24px 0 0;
  padding: 16px;
  border: 1px solid var(--brand-line);
  border-radius: 12px;
  background: var(--brand-tint);
}

/* ⚠ 这是个 <button> 不是 <a>（理由见 product.twig 里那段注释：
     Bootstrap 5.3 的 Tab 不认 .nav 外面的触发器，而 <base> 会让裸
     #tab-coa 跳回首页）。按钮自带边框/底色/内边距/字体，必须重置，
     否则缩略图外面会多一圈灰框。 */
.coa-strip-img {
  flex: 0 0 auto;
  display: block;
  width: 96px;
  padding: 0;
  border: 0;
  background: transparent;
  line-height: 0;
  cursor: pointer;
}

/* ⚠ 宽度写在 <a> 上、img 只写 width:100%。
     主题里有更高特指度的 img 规则（和落地页 body.lp img 同一类问题），
     直接给 .coa-strip img 写固定宽会被压掉。 */
.coa-strip-img img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--brand-line);
  border-radius: 6px;
  background: #fff;
}

.coa-strip-body { min-width: 0; }

.coa-strip-h {
  margin: 0 0 6px;
  font-weight: 700;
  font-size: 0.9375rem;
  color: var(--brand-ink);
}

/* 批号 / 纯度 / 实验室：标签在上、值在下，横向排开 */
.coa-strip-kv {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 20px;
  margin: 0 0 10px;
  font-size: 0.8125rem;
}

.coa-strip-kv dt {
  margin: 0;
  color: var(--brand-muted);
  font-weight: 400;
}

.coa-strip-kv dd {
  margin: 0 0 0 6px;
  font-weight: 600;
  color: var(--brand-ink);
  overflow-wrap: anywhere;
}

/* 同样是 <button>。做成「看起来像链接」而不是像按钮 ——
   它的动作是切标签，不是提交什么，长得像按钮会被误认为「加入购物车」那一类。 */
.coa-strip-cta {
  padding: 0;
  border: 0;
  background: transparent;
  font-family: inherit;
  font-size: 0.8125rem;
  font-weight: 700;
  text-align: left;
  text-decoration: none;
  color: var(--brand-accent);
  cursor: pointer;
}

.coa-strip-cta:hover { text-decoration: underline; }

@media (max-width: 575.98px) {
  .coa-strip { flex-direction: column; }

  .coa-strip-img { width: 120px; }
}

/* ── COA 标签里：报告缩略图横条 ─────────────────────────────────── */
/* 放在表格上方而不是给表格加一列 —— .coa-table 在手机端整体变成卡片，
   多一列要同步改那套转换规则，横条完全不碰它。 */
.coa-thumbs {
  display: flex;
  gap: 10px;
  margin: 0 0 16px;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}

.coa-thumbs::-webkit-scrollbar { display: none; }

.coa-thumb {
  flex: 0 0 auto;
  width: 104px;
  text-decoration: none;
  color: inherit;
}

.coa-thumb img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--brand-line);
  border-radius: 6px;
  background: #fff;
  transition: border-color .18s ease;
}

.coa-thumb:hover img,
.coa-thumb:focus-visible img { border-color: var(--brand-accent); }

.coa-thumb-lot {
  display: block;
  margin-top: 5px;
  font-size: 0.6875rem;
  line-height: 1.3;
  color: var(--brand-muted);
  overflow-wrap: anywhere;
}

.coa-wrap {
  border: 1px solid var(--brand-line);
  background-color: var(--brand-bg);
}

.coa-table {
  width: 100%;
  margin: 0;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}

.coa-table thead th {
  position: sticky;
  /* ⚠ 不是随手写的 0：站点头部是吸顶的（header{position:sticky}，
        z-index:1030）。粘顶表头必须让开它的高度，否则一滚动就钻到
        头部底下，只剩半截。--oc-header-stuck 是全站统一的这个高度。 */
  top: var(--oc-header-stuck);
  z-index: 2;
  padding: 0;
  background-color: var(--brand-bg);
  border-bottom: 1px solid var(--brand-line-strong);
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--brand-muted);
  white-space: nowrap;
}

/* 不可排序的两列没有内层按钮，内边距得自己补上 */
.coa-table thead th.coa-c-identity,
.coa-table thead th.coa-c-pdf {
  padding: 15px 16px;
}

/* 排序按钮撑满整格：点击目标是整个表头格，不是那几个字 */
.coa-sort {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  padding: 15px 16px;
  border: 0;
  background: none;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: inherit;
  cursor: pointer;
}

.coa-sort:focus-visible {
  outline: 2px solid var(--brand-accent);
  outline-offset: -2px;
}

th[aria-sort="ascending"] .coa-sort,
th[aria-sort="descending"] .coa-sort {
  color: var(--brand-ink);
}

th.coa-c-purity .coa-sort {
  justify-content: flex-end;
}

/* 箭头用 visibility 而不是 display 隐藏：六个表头一直挂着灰箭头很吵，
   但真的抽掉会让表头宽度在排序前后跳一下。 */
.coa-sort-i::after {
  content: "\2191";
}

th[aria-sort="descending"] .coa-sort-i::after {
  content: "\2193";
}

th[aria-sort="none"] .coa-sort-i {
  visibility: hidden;
}

.coa-sort:hover .coa-sort-i {
  visibility: visible;
  opacity: .45;
}

.coa-table tbody td {
  /* 分隔线画在 border-bottom 而不是 border-top：首行不会和表头那道
     深色下边线叠成双线，而且筛选把首行藏起来时也不会露馅。 */
  padding: 17px 16px;
  border-bottom: 1px solid var(--brand-line);
  font-size: .9rem;
  color: var(--brand-ink);
  vertical-align: middle;
}

.coa-table tbody tr:last-child td {
  border-bottom: 0;
}

.coa-table tbody tr:hover td {
  background-color: var(--brand-surface);
}

/* 深链进来的那一行。左侧一道品牌色竖条 + 浅底 ——
   客户扫码进来要的就是「就是这条」，不能让他自己在表里找。 */
.coa-table tbody tr.is-current td,
.coa-table tbody tr.is-current:hover td {
  background-color: var(--brand-tint);
}

.coa-table tbody tr.is-current td:first-child {
  box-shadow: inset 3px 0 0 var(--brand-accent);
}

.coa-c-compound {
  font-weight: 600;
}

.coa-c-lot {
  width: 1%;
  white-space: nowrap;
}

.coa-c-lot a {
  font-family: Consolas, "SF Mono", Menlo, monospace;
  font-size: .86rem;
  letter-spacing: .02em;
  color: var(--brand-ink);
  text-decoration: none;
}

.coa-c-lot a:hover,
.coa-c-lot a:focus {
  color: var(--brand-accent);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* 纯度是这张表上唯一被真正扫视的数字：右对齐 + 等宽 + 加重，
   小数点逐行对齐，哪批高哪批低一眼看得出来。 */
.coa-c-purity {
  width: 1%;
  text-align: right;
  white-space: nowrap;
  font-size: .98rem;
  font-weight: 600;
}

.coa-c-identity {
  width: 1%;
  white-space: nowrap;
}

/* LC-MS / HPLC 这种是标签不是句子，做成胶囊比裸文字更像数据 */
.coa-chip {
  display: inline-block;
  padding: 3px 9px;
  border: 1px solid var(--brand-line);
  border-radius: 2px;
  background-color: var(--brand-surface);
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--brand-muted);
}

.coa-c-reported {
  width: 1%;
  white-space: nowrap;
  color: var(--brand-muted);
}

.coa-c-lab {
  min-width: 140px;
}

/* 外链箭头。跳出站的链接要让人事先知道，回头才不会以为页面丢了 */
.coa-ext {
  color: var(--brand-accent);
  text-decoration: none;
}

.coa-ext::after {
  content: "\2197";
  margin-left: 4px;
  font-size: .85em;
}

.coa-ext:hover,
.coa-ext:focus {
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* 固定宽度：不固定的话按钮被推到最右，和实验室名之间空出比任何一列
   都宽的一道缝，整张表看着散了 */
.coa-c-pdf {
  width: 132px;
  text-align: right;
}

.coa-pdf {
  display: inline-block;
  padding: 9px 16px;
  border: 1px solid var(--brand-line-strong);
  border-radius: 2px;
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--brand-ink);
  text-decoration: none;
  white-space: nowrap;
  transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}

.coa-pdf:hover,
.coa-pdf:focus {
  background-color: var(--brand-accent);
  border-color: var(--brand-accent);
  color: #fff;
}

/* --- 深链详情卡（二维码落地） ------------------------------------------ */
/* 一个批号挂着多份报告时，卡片上方的说明。
   ⚠ 这不是错误提示 —— 批号按日期+序号编，同一批物料灌成不同规格是常态。
     所以用中性的静音色，不要用 .coa-miss 那套警示黄，
     否则客户会以为自己扫错了。 */
.coa-single-multi {
  max-width: 620px;
  margin: 0 0 16px;
  font-size: .9rem;
  line-height: 1.6;
  color: var(--brand-muted);
}

.coa-single {
  max-width: 620px;
  margin-bottom: 34px;
  border: 1px solid var(--brand-line);
}

.coa-single-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding: 22px 26px;
  border-bottom: 1px solid var(--brand-line);
}

.coa-single-lot {
  font-family: Consolas, "SF Mono", Menlo, monospace;
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: .03em;
  color: var(--brand-ink);
  word-break: break-all;
}

.coa-single-purity {
  font-family: Consolas, "SF Mono", Menlo, monospace;
  font-size: 1.35rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--secure-green);
}

.coa-single-intro {
  margin: 0;
  padding: 18px 26px 0;
  font-size: .86rem;
  color: var(--brand-muted);
}

.coa-single-facts {
  margin: 0;
  padding: 16px 26px 0;
}

.coa-single-facts dt {
  float: left;
  clear: left;
  width: 38%;
  padding: 9px 0;
  font-size: .78rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--brand-muted);
}

.coa-single-facts dd {
  margin: 0;
  padding: 9px 0 9px 38%;
  border-bottom: 1px solid var(--brand-line);
  font-size: .9rem;
  color: var(--brand-ink);
}

.coa-single-facts dd:last-child {
  border-bottom: 0;
}

.coa-single-facts a {
  color: var(--brand-accent);
}

.coa-single-cta {
  display: block;
  margin: 8px 26px 26px;
  height: 52px;
  line-height: 52px;
  border-radius: 2px;
  background-color: var(--brand-ink);
  color: #fff;
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  text-align: center;
  text-decoration: none;
  transition: background-color .18s ease;
}

.coa-single-cta:hover,
.coa-single-cta:focus {
  background-color: var(--brand-accent);
  color: #fff;
}

/* --- 提示 / 空状态 / 脚注 ----------------------------------------------- */
.coa-miss {
  max-width: 620px;
  margin-bottom: 26px;
  padding: 14px 16px;
  border-left: 3px solid var(--brand-star);
  background-color: #FCF6E8;
  color: #6B4E0F;
  font-size: .88rem;
  line-height: 1.6;
}

/* 筛不到时给的是一块有设计的空状态，不是一行裸文字 ——
   一行字容易被读成「页面坏了」，而且不给下一步动作。 */
.coa-none {
  margin: 0;
  padding: 52px 24px;
  border: 1px solid var(--brand-line);
  text-align: center;
}

.coa-none-t {
  margin: 0;
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--brand-ink);
}

.coa-none-h {
  max-width: 44ch;
  margin: 10px auto 0;
  font-size: .88rem;
  line-height: 1.6;
  color: var(--brand-muted);
}

.coa-none-b {
  margin-top: 20px;
  padding: 11px 22px;
  border: 1px solid var(--brand-line-strong);
  border-radius: 2px;
  background: none;
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--brand-ink);
  cursor: pointer;
  transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}

.coa-none-b:hover,
.coa-none-b:focus {
  background-color: var(--brand-accent);
  border-color: var(--brand-accent);
  color: #fff;
}

.coa-help {
  margin: 22px 0 0;
  font-size: .84rem;
  color: var(--brand-muted);
}

.coa-help a {
  color: var(--brand-accent);
  text-underline-offset: 3px;
}

/* ⚠ 分隔线画在 .coa-foot 上，不要画回 .coa-note ——
      .coa-note 自己限宽 68ch，边框会跟着截断，在页面中间断掉，
      看着像渲染坏了。外层画线、内层限宽，两件事分开。 */
.coa-foot {
  margin-top: 30px;
  padding-top: 18px;
  border-top: 1px solid var(--brand-line);
}

/* 研究用途声明。静音、小字 —— 它是边界不是卖点，
   但必须和数据在同一屏里看得到。 */
.coa-note {
  max-width: 68ch;
  margin: 0;
  font-size: .78rem;
  line-height: 1.65;
  color: var(--brand-muted);
}

/* --- 手机端：每行变成一张卡片 ------------------------------------------ */
/* 七列在 440px 上必然横滚，而横滚表格在手机上几乎没人会滑 ——
   第一屏只看到「化合物 / 批号」，客户会以为没有纯度数据。
   所以整张表拆成卡片。<table> 语义保留，屏幕阅读器仍读得到表头关系。

   卡片内部是「标签列 + 值列」的两栏网格，视线只走一条竖线；
   之前那版左右交替对齐，读起来是锯齿状的。

   ⚠ 权重陷阱：下面的结构复位写成了 `.coa-table tbody td`，权重 (0,2,2)。
     按列细分的规则如果只写 `.coa-c-lot`（(0,1,0)）会被整个压掉 ——
     display:grid 变回 block、padding 归零，标签和值直接粘成
     「LOTSD-260729-1」。所以每条细分规则都带上 `.coa-table tbody td`
     前缀，并排在复位之后（同权重时后者胜）。 */
@media (max-width: 767.98px) {
  .coa-wrap {
    border: 0;
    background: none;
  }

  .coa-table,
  .coa-table tbody,
  .coa-table tr {
    display: block;
    width: 100%;
  }

  /* 表头视觉上隐藏但仍在无障碍树里 —— display:none 会让屏幕阅读器
     也读不到列名，卡片里的 data-label 才是给视觉用户的 */
  .coa-table thead {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }

  .coa-table tbody tr {
    position: relative;
    margin-bottom: 12px;
    padding: 16px 18px;
    border: 1px solid var(--brand-line);
    background-color: var(--brand-bg);
  }

  .coa-table tbody tr:hover td,
  .coa-table tbody tr.is-current:hover td,
  .coa-table tbody tr.is-current td {
    background: none;
  }

  .coa-table tbody tr.is-current {
    border-color: var(--brand-tint-line);
    background-color: var(--brand-tint);
    box-shadow: inset 3px 0 0 var(--brand-accent);
  }

  .coa-table tbody tr.is-current td:first-child {
    box-shadow: none;
  }

  /* ── 结构复位（权重 0,2,2）───────────────────────────────── */
  .coa-table tbody td {
    display: block;
    width: auto;
    padding: 0;
    border-bottom: 0;
  }

  /* ── 卡片头：化合物在左，纯度在右上角 ───────────────────── */
  .coa-table tbody td.coa-c-compound {
    /* 92px 是给右上角纯度留的位置，不能省 —— 化合物名一长就会压上去 */
    padding-right: 92px;
    font-size: 1rem;
    line-height: 1.35;
  }

  .coa-table tbody td.coa-c-purity {
    position: absolute;
    top: 16px;
    right: 18px;
    width: auto;
    font-size: 1.1rem;
  }

  /* ── 其余字段：左标签右值，两栏对齐 ─────────────────────── */
  .coa-table tbody td.coa-c-lot,
  .coa-table tbody td.coa-c-identity,
  .coa-table tbody td.coa-c-reported,
  .coa-table tbody td.coa-c-lab {
    display: grid;
    grid-template-columns: 82px minmax(0, 1fr);
    gap: 10px;
    align-items: baseline;
    width: auto;
    padding: 7px 0;
    font-size: .875rem;
    white-space: normal;
  }

  .coa-table tbody td.coa-c-lot::before,
  .coa-table tbody td.coa-c-identity::before,
  .coa-table tbody td.coa-c-reported::before,
  .coa-table tbody td.coa-c-lab::before {
    content: attr(data-label);
    font-size: .68rem;
    font-weight: 600;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--brand-muted);
  }

  /* 胶囊是网格子项，默认会被拉满整列 —— 一个 LC-MS 标签占掉
     半张卡片的宽度，看着像个输入框 */
  .coa-table tbody td.coa-c-identity .coa-chip {
    justify-self: start;
  }

  /* 第一条字段上方来一道线，把卡片头和明细分开 */
  .coa-table tbody td.coa-c-lot {
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px solid var(--brand-line);
  }

  .coa-c-lot a {
    word-break: break-all;
  }

  .coa-table tbody td.coa-c-pdf {
    width: auto;
    margin-top: 12px;
    padding: 14px 0 0;
    border-top: 1px solid var(--brand-line);
    text-align: center;
  }

  /* 整宽按钮：手机上拇指够得到才算数 */
  .coa-pdf {
    display: block;
    padding: 13px 16px;
  }

  .coa-search {
    max-width: none;
  }

  .coa-sortbox .form-select {
    height: 46px;
  }

  /* 手机端不独占一行：回到和排序下拉同行、靠右。
     同行可用宽度只有 188px（375px 机型 = 内容栏 351 − 下拉 151 − 间距 12），
     H1 那个 27.6px 放不下，所以这里单独调小。

     20px 是「常态文案还能同行」的合适档位：
       "19 certificates"  @20px = 158px ✓（余 30px，多一位数也够）
                          @22px = 174px（只余 14px，太紧）
     筛选时文案会变成 "12 of 19 certificates"（197px），掉到下一行 ——
     ⚠ 这不是没调好。任何 >= 18px 的字号都挡不住它，要塞进同行得缩到 16px，
       那就和改版前那个小标签没区别了。所以按常态文案定字号，
       掉行时靠右对齐，读起来是有意为之而不是溢出。 */
  .coa-count {
    flex: 0 1 auto;
    margin-left: auto;
    font-size: 1.25rem;
    /* ⚠ 字重必须 700，不能留 600。
          20px 低于 WCAG「大号文字」的 24px 线，只剩「>= 18.66px 且粗体」
          这一条能让它继续按 3:1 判定 —— --secure-green-bright 正好 3.21:1。
          留 600 的话这里按正文算，门槛 4.5:1，亮绿就得换成
          --secure-green-vivid 那一档深绿。 */
    font-weight: 700;
    text-align: right;
  }

  .coa-single-head,
  .coa-single-intro,
  .coa-single-facts {
    padding-left: 18px;
    padding-right: 18px;
  }

  .coa-single-cta {
    margin-left: 18px;
    margin-right: 18px;
  }

  .coa-single-facts dt {
    float: none;
    width: auto;
    padding-bottom: 0;
  }

  .coa-single-facts dd {
    padding-left: 0;
    padding-top: 0;
  }

  /* 没值的字段整条不出现 —— 顶着一个「IDENTITY」后面却空着，
     客户读到的不是「这项没测」，而是「我这批少了点什么」。
     两个前提，少一个都不生效：
       · :empty 要求标签里一个空白字符都没有 ——
         模板里那几个 <td> 因此必须写成单行、不留换行；
       · ⚠ 这条必须排在所有按列规则**之后**。
         `.coa-table tbody td:empty` 和 `.coa-table tbody td.coa-c-identity`
         权重同为 (0,2,2)，写在前面会被后者的 display:grid 压掉。 */
  .coa-table tbody td:empty {
    display: none;
  }
}

/* ══ 商品页：数量加减器 ═══════════════════════════════════════════
   原来是「Qty | 裸文本框 | Add to Basket」挤在一行。手机上要调键盘，
   而且文本框和按钮同宽级别，看不出哪个是主操作。
   改成左边一个 − / + 步进器、右边一个填满剩余宽度的主按钮。

   配套模板：extension/ocmod/catalog/view/template/product/product.twig
   （标记 [自定义补丁] 数量加减器 的那一段）
   ══════════════════════════════════════════════════════════════ */
/* 「Qty」标签。和上面「* Strength」那种字段标签同级，
   不再挤在加减器左边白占宽度。 */
.qty-label {
  display: block;
  margin-bottom: 6px;
  color: var(--brand-muted);
  font-size: 0.875rem;
  font-weight: 600;
}

.qty-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: stretch;
}

/* 电脑版右栏有 900px 上下，让加购按钮一路横到底并不显得更重要，
   只是显得松散。收成一块，和上面的规格选项对齐着看更像一组操作。
   手机上不限宽 —— 那里满宽反而是对的。 */
@media (min-width: 768px) {
  .qty-row {
    max-width: 440px;
  }
}

/* 步进器宽度固定：数量最多三四位，给再多也用不上，
   省下的宽度全给主按钮。加购才是这一行真正要人点的东西。 */
.qty-stepper {
  display: flex;
  flex: 0 0 132px;
  align-items: stretch;
  min-height: 48px;          /* 和 .btn-lg 对齐，两者不等高很扎眼 */
  border: 1px solid var(--brand-line-strong);
  border-radius: 0.375rem;
  background: #fff;
  overflow: hidden;
}

.qty-stepper:focus-within {
  border-color: var(--brand-ink);
  box-shadow: 0 0 0 0.2rem rgba(22, 33, 43, 0.12);
}

.qty-btn {
  flex: 0 0 44px;            /* 44px 是触摸目标下限，别再调小 */
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--brand-ink);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.qty-btn:hover {
  background: #F2F5F7;
}

.qty-btn:active {
  background: #E6EBEF;
}

.qty-input {
  flex: 1 1 auto;
  width: 100%;
  min-width: 0;              /* 不写这条，flex 子项不肯缩到内容宽度以下 */
  padding: 0 2px;
  border: 0;
  border-left: 1px solid var(--brand-line);
  border-right: 1px solid var(--brand-line);
  background: transparent;
  color: var(--brand-ink);
  text-align: center;
  /* ⚠ 不能小于 16px：iOS Safari 聚焦到小于 16px 的输入框时会放大整页，
     而且退出输入后不会自己缩回去。 */
  font-size: 16px;
  font-weight: 600;
  /* 等宽数字：1 和 2 的字形宽度不同，不锁住的话点 + 时数字会左右抖一下。
     快速查看里那个加减器用的也是这条。 */
  font-variant-numeric: tabular-nums;
}

.qty-input:focus {
  outline: none;
  box-shadow: none;
}

.qty-cart {
  flex: 1 1 180px;           /* 撑满剩余宽度；窄到放不下时整条换行占满 */
  /* ⚠ 换行独占一行以后，align-items: stretch 就没有同行的兄弟可对齐了，
     按钮会掉回 .btn-lg 的自然高度（约 39px）—— 主 CTA 在手机上低于
     44px 是不行的。这里显式兜住。 */
  min-height: 48px;
}

/* 「立即购买」。加购成功后直跳结账，省掉购物车那一步。

   为什么用深墨色实心、而不是描边：
   描边读起来是「次要动作」，但这颗恰恰是意图最强的那一批人在点。
   两颗都实心、颜色不同，顾客一眼能分清是两件事，
   又不会觉得其中一颗是「算了不买」。
   宽度对齐上面那一行（含 440px 上限），两行看起来是一组。 */
.qty-buynow {
  display: block;
  width: 100%;
  min-height: 48px;
  margin-top: 12px;
  padding: 0 16px;
  border: 1px solid var(--brand-ink);
  border-radius: 0.5rem;
  background-color: var(--brand-ink);
  color: #fff;
  font-size: 1.125rem;       /* 和 .btn-lg 一致 */
  font-weight: 600;
  cursor: pointer;
}

.qty-buynow:hover,
.qty-buynow:focus {
  background-color: #0C1118;
  border-color: #0C1118;
  color: #fff;
}

.qty-buynow:focus-visible {
  outline: 2px solid var(--brand-ink);
  outline-offset: 2px;
}

@media (min-width: 768px) {
  .qty-buynow {
    max-width: 440px;
  }
}

/* 小计。上面那个大号数字是**单件**价格（旁边就是 −15% 和划线原价，
   都是一件的事）；「一共多少钱」放这里，两个意思分开说。
   刻意做得比价格轻 —— 它是补充说明，不是新的主角。 */
.p-subtotal {
  margin-top: -2px;
  color: var(--brand-muted);
  font-size: 0.9375rem;
  font-variant-numeric: tabular-nums;
}

/* ══ 规格选择（详情页 + 快速查看共用）═══════════════════════════
   原先只要商品有必选规格，弹窗就只给一颗「Select Options」赶人去商品页。
   颜色、尺码、包装规格这些在弹窗里选完全没问题，多跳一页是白白的流失。

   芯片式（而不是原生 radio 列表）：手机上点得准，一眼看得出选了哪个，
   而且一行能排下三四个，不会把弹窗撑长。

   配套模板：extension/ocmod/catalog/view/template/product/quickview.twig
   ══════════════════════════════════════════════════════════════ */
.opt-list {
  margin: 4px 0 18px;
}

.opt-item + .opt-item {
  margin-top: 14px;
}

.opt-label {
  margin-bottom: 8px;
  color: var(--brand-muted);
  font-size: 0.875rem;
  font-weight: 600;
}

.opt-req {
  color: var(--brand-sale);
}

.opt-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/* 真正的 input 藏在 label 里：这样点整块芯片都能选中，
   而且键盘 Tab / 方向键的原生行为一个都没丢。
   ⚠ 不能用 display:none 藏 —— 那会让它从 Tab 序列里消失，
     键盘用户就选不了了。用 opacity:0 + 绝对定位盖在芯片上。 */
.opt-chip {
  position: relative;
  display: inline-flex;
  cursor: pointer;
}

.opt-chip input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.opt-chip-face {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;          /* 触摸目标下限 */
  padding: 8px 14px;
  border: 1px solid var(--brand-line-strong);
  border-radius: 50rem;      /* 弹窗里其余按钮都是胶囊形，保持一致 */
  background: #fff;
  color: var(--brand-ink);
  font-size: 0.9375rem;
  line-height: 1.25;
}

/* 值自带的小图。只在同一组里出现两张以上**不同**的图时才渲染 ——
   判断在控制器里（show_images），前后台都不用手动配。
   三个一模一样的缩略图不传递任何信息，只会把芯片撑大。 */
.opt-chip-img {
  width: 28px;
  height: 28px;
  margin: -4px 0;
  border-radius: 4px;
  object-fit: cover;
  background: #fff;
}

.opt-chip-face em {
  color: var(--brand-muted);
  font-style: normal;
  font-variant-numeric: tabular-nums;
}

.opt-chip input:checked + .opt-chip-face {
  border-color: var(--brand-ink);
  background: var(--brand-ink);
  color: #fff;
}

.opt-chip input:checked + .opt-chip-face em {
  color: rgba(255, 255, 255, 0.78);
}

.opt-chip input:focus-visible + .opt-chip-face {
  outline: 2px solid var(--brand-ink);
  outline-offset: 2px;
}

.opt-chip input:hover:not(:checked) + .opt-chip-face {
  border-color: var(--brand-ink);
}

.opt-select,
.opt-input {
  width: 100%;
  min-height: 44px;
  padding: 10px 12px;
  border: 1px solid var(--brand-line-strong);
  border-radius: 0.5rem;
  background: #fff;
  color: var(--brand-ink);
  /* ⚠ 不能小于 16px：iOS Safari 聚焦时会放大整页且不缩回 */
  font-size: 16px;
}

.opt-select:focus,
.opt-input:focus {
  outline: none;
  border-color: var(--brand-ink);
  box-shadow: 0 0 0 0.2rem rgba(22, 33, 43, 0.12);
}

/* 服务端校验错误。就地显示，弹窗不关 —— 关掉再让人重开一次才是真的烦人。 */
.opt-error {
  margin: 6px 0 0;
  color: var(--brand-sale);
  font-size: 0.875rem;
}

/* 划线原价 + 折扣角标。整块可以被 JS 隐藏（某些规格没有折扣）。 */
.qv-was[hidden] {
  display: none;
}

/* 小计。上面那个大号数字是**单件**价，这里回答「一共多少钱」。 */
.qv-subtotal {
  margin: -6px 0 14px;
  color: var(--brand-muted);
  font-size: 0.9375rem;
  font-variant-numeric: tabular-nums;
}

/* 详情页的校验反馈。核心那段加购 JS 会给 #input-option-<id> 加 .is-invalid
   （product.twig 底部 $('#input-' + key...)）。芯片和自定义下拉都不是
   Bootstrap 的表单控件，拿不到它自带的红框，这里补上 ——
   否则「必选规格没选」时只有一行红字，视线还停在按钮上根本注意不到。 */
.opt-chips.is-invalid .opt-chip-face,
.opt-select.is-invalid {
  border-color: var(--brand-sale);
}

/* ==========================================================================
   结账页：收起全站导航

   目的只有一个：**在付款这一步，页面上不该有任何「去别处」的入口。**
   实测改之前 390px 下可见链接 29 个（DOM 里 92 个）——
   完整的分类大菜单、搜索框、购物车挂件、COA 入口、页脚五栏。
   这些在商品页是导航，在结账页是漏斗上的洞。改完剩 6 个。

   ── 和已有规则的关系 ──────────────────────────────────────────────
   本文件 @media (max-width: 767.98px) 里已经做过结账页的移动端部分：
   收起 #mobile-tabbar、悬浮下单条、地址栅格、address-match 卡片。
   这一段是**补头部导航和页脚**，而且不限宽度，所以放在顶层。

   ── 为什么用 CSS 而不是改模板 ──────────────────────────────────────
   header / footer 由 common/header、common/footer 渲染，全站共用。
   要按路由分支就得改核心控制器 + 核心模板，OpenCart 升级必被覆盖。
   body:has(#checkout-checkout) 精确命中结账页 ——
   #checkout-checkout 是结账页独有的容器 id，
   和上面藏 #mobile-tabbar 用的是同一个钩子。

   ⚠ display:none 会把元素移出 tab 顺序，键盘用户也不会再误进大菜单。
   ⚠ 不支持 :has() 的老浏览器（Safari < 15.4）导航照常显示，
     只是没优化，不会坏。
   ⚠ 不碰任何 JS：checkout-onepage.js 和悬浮下单条照常工作。
   ========================================================================== */

/* 顶部工具条、搜索、分类大菜单 */
body:has(#checkout-checkout) #top,
body:has(#checkout-checkout) #header-search-slot,
body:has(#checkout-checkout) #search-col,
body:has(#checkout-checkout) #menu {
  display: none !important;
}

/* 购物车挂件和 COA 入口。
   ⚠ 购物车挂件是个下拉，里面是「View Basket / Checkout」两个链接。
     顾客要看买了什么，右边（手机上是下面）的订单摘要已经在显示，
     不需要第二个入口 —— 而那个下拉里的链接是真的会把人带走。
   ⚠ COA 入口在商品页是最强的信任资产，在结账页是出口：
     人已经决定买了，这时候让他去翻证书库只会中断流程。 */
body:has(#checkout-checkout) #cart,
body:has(#checkout-checkout) #mobile-cart-slot,
body:has(#checkout-checkout) #header-coa-slot {
  display: none !important;
}

/* 搜索栏藏掉之后 logo 还被 Bootstrap 的 col-5 卡着，放宽 */
body:has(#checkout-checkout) #logo-col {
  flex: 0 0 auto !important;
  width: 100% !important;
  max-width: 100% !important;
}

/* 页脚只留法务和支付标识，五栏链接全部收起 */
body:has(#checkout-checkout) #footer-information,
body:has(#checkout-checkout) #footer-service,
body:has(#checkout-checkout) #footer-extra,
body:has(#checkout-checkout) #footer-account {
  display: none !important;
}

/* ⚠ #footer-company **不能**无条件整列藏掉。
     footer.twig 底部的 fc-trust-move 脚本在 575.98px 以下
     会把 .fc-trust（≥99% 纯度 / 180 天退款 / 三重检测）
     **搬进 #footer-company 的第二栏** —— 藏了整列，
     手机端那三条信任声明就一起消失了（上一版就是这么丢的）。

     所以按脚本的同一个断点分开处理：
       < 576px  只藏 .fc-main（logo + 电话 / 邮箱 / WhatsApp / 地址
                 —— 这些才是出口），留着容器让 .fc-trust 有地方待
       ≥ 576px  .fc-trust 在 .fn-subscribe 里，整列可以藏

     ⚠ 脚本没跑的时候（JS 被拦），.fc-trust 留在 .fn-subscribe 里，
       而那个容器我只藏了 intro 和 form，所以两条路径都不会丢内容。 */
body:has(#checkout-checkout) #footer-company .fc-main {
  display: none !important;
}

/* .fc-main 藏掉之后，#footer-company 仍然是
   grid-template-columns: minmax(0,1fr) minmax(0,44%) 的两栏网格，
   搬进来的 .fc-trust 只拿到 1fr 那一栏 —— 实测 188px，
   「180-Day Money Back Guarantee」被挤成两行。
   结账页这里只剩一个子元素，改成单栏，并整体居中
   （和下面的版权行、支付图标对齐；文字本身保持左对齐，
     三条带图标的声明左对齐比居中好读）。 */
body:has(#checkout-checkout) #footer-company {
  grid-template-columns: 1fr !important;
}

body:has(#checkout-checkout) #footer-company .fc-trust {
  width: fit-content;
  margin-inline: auto;
}

/* .fn-subscribe 的 intro 和 form 都藏了，如果 .fc-trust 又被 JS
   搬去了 #footer-company，这个容器就是个空盒子 ——
   实测 22px 内边距 + 8px 外边距 + 23px 高 ≈ 53px 纯空白，
   夹在信任三条和版权行中间。

   ⚠ 用 :not(:has(.fc-trust)) 而不是按断点藏：
     JS 没跑的时候 .fc-trust 还留在这个容器里，
     按断点无条件藏掉的话，信任三条又会消失 ——
     那正是上一版刚修掉的 bug。
     这样写两条路径都对：搬走了才塌掉，没搬走就留着。 */
body:has(#checkout-checkout) .fn-subscribe:not(:has(.fc-trust)) {
  display: none !important;
}

@media (min-width: 576px) {
  body:has(#checkout-checkout) #footer-company {
    display: none !important;
  }
}

/* 面包屑只收起「首页」那一格。
   ⚠ 「Basket」那一格**保留** —— 它是顾客改数量、删商品的唯一入口。
     把它一起删掉，想改数量的人会直接放弃；省下的那一个链接
     远不值这个代价。右侧订单摘要只显示、不可编辑。 */
body:has(#checkout-checkout) .breadcrumb .breadcrumb-item:first-child {
  display: none !important;
}

/* 导航拿掉之后顶部空一截，补回节奏；页脚瘦身后上下留白过大 */
body:has(#checkout-checkout) #checkout-checkout {
  padding-top: 24px;
}

/* ⚠ padding-bottom **不能**在这里设。
     本文件 @media (max-width: 767.98px) 里（约 9026 行）已经有

         body:has(#checkout-checkout) footer {
           padding-bottom: calc(76px + env(safe-area-inset-bottom, 0px));
         }

     那是给悬浮下单条留的位置。这条规则在文件更靠后、特异度相同，
     无条件写 padding-bottom 会把它整个盖掉 ——
     症状就是手机端页脚最后一行（版权）被悬浮条压住看不全。
     （这个 bug 是我上一版引入的，就是这么来的。）

     所以：padding-top 全宽度生效；padding-bottom 只在 768px 以上
     （那里没有悬浮条）才收紧。 */
body:has(#checkout-checkout) footer {
  padding-top: 24px;
}

@media (min-width: 768px) {
  body:has(#checkout-checkout) footer {
    padding-bottom: 24px;
  }
}

/* ── 结账页：收起页脚的邮件订阅 ────────────────────────────────────
   ⚠ 订阅框里是**第二个邮箱输入框**。顾客正在上面的表单里填 E-Mail，
     页脚又出现一个「Enter your e-mail」—— 分不清该填哪个，
     填错了还以为自己已经下单了。
   ⚠ 它底下那句「By subscribing you agree to our Privacy Policy」
     还带一个链接，是出口。
   ⚠ **但 .fc-trust 要留着**（≥99% 纯度 / 180 天退款 / 三重检测）——
     那三条正是下单按钮旁边最该出现的东西，和订阅无关，
     只是恰好被放在同一个容器里。 */
body:has(#checkout-checkout) .fn-subscribe-intro,
body:has(#checkout-checkout) .fn-subscribe-form {
  display: none !important;
}

/* ── 结账页：收起订单追踪和币种切换 ────────────────────────────────
   #header-tools 这个 <ul> 里是「订单追踪(货车图标) / 币种 / 语言」。
   电脑端它在 #top 里（上面已经整条藏掉），
   **但手机端 JS 会把它搬进 #header-tools-slot**，也就是 logo 那一行 ——
   所以电脑端看不见、手机端还在。直接藏这个 ul，两端一起解决。

   ⚠ 订单追踪在结账页是最不该出现的链接之一：顾客正在下单，
     「追踪订单」会让他以为自己已经下过单了，点进去就离开了结账流程。
   ⚠ 币种切换藏掉还有第二个理由：中途换币种会触发整单重算，
     而广告和落地页承诺的是英镑价格。GBP/USD/EUR 三个币种在
     其他页面照常可切，只在结账这一步固定下来。
   ========================================================================== */
body:has(#checkout-checkout) #header-tools {
  display: none !important;
}

/* ── 结账页顶部的安全提示 ──────────────────────────────────────────
   ⚠ 这个元素在**每一页**都渲染（header.twig 里没法按路由分支，
     那要改核心控制器）。这条规则负责把它在非结账页藏掉。
     代价是每页多 60 字节，换来的是不碰核心文件。 */
body:not(:has(#checkout-checkout)) #checkout-assure {
  display: none !important;
}

.ck-assure {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 0;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: .8125rem;
  line-height: 1.3;
  color: var(--brand-muted, #5B6B78);
}

.ck-assure li {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  white-space: nowrap;
}

/* 分隔竖线用伪元素画。
   ⚠ 不写成文本「|」：手机端这三项会折行，写死的竖线会落在行首。
     用 ::before + :first-child 排除，折到第二行的第一项也不会带竖线…
     —— 做不到「每行首项都不带」，但 flex 换行时第一项必定是
     第 2 或第 3 个 li，所以退而求其次：窄屏直接改成每项一行（见下）。 */
.ck-assure li + li::before {
  content: "";
  width: 1px;
  height: 12px;
  margin: 0 12px;
  background: var(--brand-line, #E3E9ED);
}

.ck-assure i {
  color: var(--brand-ok, #157F4C);
  font-size: .875rem;
}

/* 不论宽度，都在 logo 下面单独一行、左对齐。
   ⚠ 这个主题把 .row 重写成了 display:grid，不是 flex ——
     flex:0 0 100% 完全不起作用（实测宽度还是 286px）。
     要整行必须用 grid-column 跨满所有列。
     flex 那一行留着，是为了万一哪天 .row 变回 flex 也不会坏。 */
#checkout-assure {
  grid-column: 1 / -1;
  flex: 0 0 100%;
  width: auto;
  max-width: 100%;
  margin-left: 0 !important;
  margin-top: 4px;
}

/* ── 窄屏：保持一行 ────────────────────────────────────────────────
   客户要求三项必须同一行，不接受竖排。

   ⚠ 系数是**实测反推**的，不是估的。过程：
     先用 11px + 收紧间距 → 内容 380px / 容器 366px，溢出 14px
     再用 clamp(9px, 2.7vw, 13px) → 391px 下算出 10.53px，内容仍 379px
     由 379px @ 10.53px 反推：要塞进 366px 需要 ≈ 9.8px，即 2.5vw
   （我两次估算都偏小，原因是 Font Awesome 的字形盒比预想宽。
     所以这里记的是量出来的数，不要凭感觉改。）

   clamp(9px, 2.5vw, 13px)：
     360px → 9px（下限）   内容 ~324 / 容器 336  ✓
     390px → 9.8px         内容 ~351 / 容器 366  ✓
     440px → 11px          内容 ~396 / 容器 416  ✓
     520px+ → 13px 封顶
   间距用 em，跟着字号一起缩。

   ⚠ nowrap 是硬要求：允许折行的话，第二行行首会出现悬空的分隔线。

   ⚠ **360px 以下放弃一行**。三条全文在 320px 上要压到 8px 才塞得下，
     那已经不是「小」而是「看不清」—— 一个读不了的信任提示等于没有。
     这个宽度现在基本只剩 iPhone SE 一代（2016），让它折行更合理。 */
.ck-assure {
  flex-wrap: nowrap;
  font-size: clamp(0.5625rem, 2.5vw, 0.8125rem);
}

.ck-assure li {
  gap: .3em;
}

.ck-assure li + li::before {
  margin: 0 .55em;
}

.ck-assure i {
  font-size: .95em;
}

@media (max-width: 359.98px) {
  .ck-assure {
    flex-wrap: wrap;
    gap: 2px 0;
  }

  /* 折行之后竖线会落在行首，去掉 */
  .ck-assure li + li::before {
    width: 0;
    margin: 0 8px 0 0;
    background: none;
  }
}

/* ── 结账页：信任三条在宽屏改横排 ──────────────────────────────────
   手机端竖排（三行）是对的 —— 那个宽度横排放不下。
   但结账页在 768px 以上，.fn-subscribe 整行都是空的
   （intro 和 form 都藏了），实测可用 1116px @ 1280，
   三条竖着排浪费一整块纵向空间，还把版权行推下去。

   ⚠ **只作用于结账页**，不动全站页脚。
     非结账页的 .fn-subscribe 是「intro | 信任块 | 订阅框」三栏，
     信任块只占中间一小格，改成横排会把那一行撑破。
   ⚠ li 上原有的 white-space: nowrap（9827 行）正好防止单条内部折行，
     这里不用再写。 */
@media (min-width: 768px) {
  body:has(#checkout-checkout) .fc-trust {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 10px 34px;
    width: auto;
  }

  body:has(#checkout-checkout) .fc-trust li {
    margin-bottom: 0;
  }
}

/* ══ 支付未完成：重试页 ═══════════════════════════════════════════
   顾客刚被拒付，正在怀疑三件事：钱扣了没？这是不是我下的那单？
   是不是地址填错才没过？这一页要在第一屏把这三个问题答完，
   然后只留一个动作。

   版式：桌面两栏（左订单摘要、右付款），和结账页同构 —— 顾客一眼
   认得出还是同一家店，而不是被甩到一个陌生的报错页。
   手机单栏，**付款栏排在前面**：他来这一页就是为了付款，
   不该先滚过一屏商品列表才看到卡表单。 */
.rt-head {
  max-width: 980px;
  margin: 20px auto 0;
}

.rt-h {
  margin: 0 0 10px;
  font-size: 26px;
  font-weight: 700;
  color: #16212B;
}

.rt-lead {
  margin: 0 0 22px;
  max-width: 620px;
  font-size: 15px;
  line-height: 1.7;
  color: #55595E;
}

.rt-grid {
  display: grid;
  /* 付款栏固定 380px：卡表单的理想宽度是固定的，剩下的给商品名换行 */
  grid-template-columns: minmax(0, 1fr) 380px;
  gap: 28px;
  align-items: start;
  max-width: 980px;
  margin: 0 auto 48px;
}

/* ── 左：订单摘要 ──────────────────────────────────────────── */
.rt-sum {
  padding: 18px 20px;
  background: #F4F7F9;
  border-radius: 10px;
}

.rt-sum-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  padding-bottom: 12px;
  border-bottom: 1px solid #DCE3E8;
}

.rt-sum-title {
  font-size: 15px;
  font-weight: 700;
  color: #16212B;
}

.rt-sum-date {
  font-size: 12px;
  color: #8A8F94;
}

.rt-line {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 14px 0;
  border-bottom: 1px solid #E6EBEF;
}

.rt-line-img {
  flex: 0 0 auto;
  width: 54px;
  height: 54px;
  border-radius: 6px;
  background: #FFFFFF;
  object-fit: contain;
}

/* 商品被删或没配图时的占位。不画图标 —— 一个灰块比一个破图标安静 */
.rt-line-noimg {
  display: block;
  border: 1px solid #E6EBEF;
}

.rt-line-body {
  flex: 1 1 auto;
  /* ⚠ 必须给 min-width:0，否则长商品名会把 grid 撑破、
     右边的金额被挤出容器 */
  min-width: 0;
}

.rt-line-name {
  font-size: 14px;
  font-weight: 600;
  line-height: 1.45;
  color: #16212B;
}

.rt-line-opt {
  margin-top: 2px;
  font-size: 12px;
  line-height: 1.6;
  color: #6B7075;
}

.rt-line-qty {
  margin-top: 4px;
  font-size: 12px;
  color: #8A8F94;
}

.rt-line-total {
  flex: 0 0 auto;
  font-size: 14px;
  font-weight: 600;
  color: #16212B;
  white-space: nowrap;
}

.rt-totals {
  padding: 12px 0 0;
}

.rt-total-row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  font-size: 13.5px;
  line-height: 2;
  color: #55595E;
}

/* 合计。顾客只核对这一个数，但前面几行决定他信不信它 */
.rt-total-last {
  margin-top: 6px;
  padding-top: 10px;
  border-top: 1px solid #DCE3E8;
  font-size: 16px;
  font-weight: 700;
  color: #16212B;
}

.rt-order-no {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid #DCE3E8;
  font-size: 13px;
  color: #6B7075;
}

/* 客服要照着订单号和顾客逐位核对，等宽字体才不会把 0/O、1/l 看混 */
.rt-mono {
  font-family: Consolas, Menlo, monospace;
  font-size: 13px;
  color: #16212B;
  word-break: break-all;
}

.rt-copy {
  padding: 2px 10px;
  border: 1px solid #C7CBD0;
  border-radius: 12px;
  background: #FFFFFF;
  font-size: 11px;
  color: #55595E;
  cursor: pointer;
}

.rt-copy.is-done {
  border-color: #0A7D4B;
  color: #0A7D4B;
}

.rt-addr {
  margin-top: 14px;
  font-size: 13px;
  line-height: 1.75;
}

.rt-addr-k {
  margin-bottom: 2px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .4px;
  text-transform: uppercase;
  color: #8A8F94;
}

.rt-addr-v { color: #55595E; }

/* ── 右：付款 ──────────────────────────────────────────────── */
.rt-due {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 14px;
}

.rt-due-k {
  font-size: 14px;
  color: #6B7075;
}

.rt-due-v {
  font-size: 24px;
  font-weight: 700;
  color: #16212B;
}

.rt-error {
  margin: 0 0 14px;
  padding: 12px 14px;
  background: #FDECEC;
  border-left: 3px solid #C02420;
  font-size: 14px;
  line-height: 1.6;
  color: #58151C;
}

.rt-btn {
  display: block;
  width: 100%;
  margin: 16px 0 0;
  padding: 14px 20px;
  border: 0;
  border-radius: 28px;
  background: #16212B;
  font-size: 16px;
  font-weight: 700;
  color: #FFFFFF;
  cursor: pointer;
}

.rt-btn:disabled {
  opacity: .6;
  cursor: default;
}

.rt-hint {
  margin: 14px 0 0;
  font-size: 13px;
  line-height: 1.7;
  color: #6B7075;
}

.rt-cancel {
  margin: 16px 0 0;
  text-align: center;
  font-size: 14px;
}

.rt-cancel a {
  color: #8A8F94;
  text-decoration: underline;
}

/* ── 手机 ──────────────────────────────────────────────────────
   单栏，并且把付款栏提到摘要前面。order 只影响视觉顺序，
   DOM 顺序不变 —— 键盘和读屏仍然按「先看买了什么、再付款」走，
   那对它们才是合理的阅读顺序。 */
@media (max-width: 860px) {
  .rt-grid {
    grid-template-columns: 1fr;
    gap: 22px;
  }

  .rt-pay { order: 1; }
  .rt-sum { order: 2; }

  .rt-h { font-size: 22px; }
}

/* 商品行容器。最后一行不要底边框 —— 它紧挨着金额明细的分隔线，
   两条线贴在一起会看成一条粗线。 */
.rt-lines .rt-line:last-child {
  border-bottom: 0;
}

/* 订单号那一行的标签 */
.rt-order-k {
  color: #8A8F94;
}

/* ══ 重试页的安心文案 ═══════════════════════════════════════
   这一组全是辅助文字，字号和颜色故意压得比正文低：
   它们是给犹豫的人看的，不该和「Amount due」、「Pay now」
   争视线。全页只有 .rt-once 一处加粗—— 承诺只能有一个重点。 */

/* 授权冻结的解释。紧贴金额下方，左边一条细线把它和
   金额绑在一起，读起来就是「关于这个数的说明」。 */
.rt-hold {
  margin: 10px 0 18px;
  padding: 0 0 0 11px;
  border-left: 2px solid #D8DCE0;
  font-size: 13px;
  line-height: 1.65;
  color: #6B7075;
}

/* 不留卡号。跟在按钮下面，居中，比其他辅助文字再小一号。 */
.rt-safe {
  margin: 12px 0 0;
  font-size: 12px;
  line-height: 1.6;
  text-align: center;
  color: #8A8F94;
}

/* 「只会收一次」—— 全页唯一的加粗处。颜色跟着正文走，
   别用绿色：保证不是「成功」，绿色在收银台上只代表一件事。 */
.rt-once {
  font-weight: 700;
  color: #3C4146;
}

/* 客服入口 */
.rt-help {
  margin: 12px 0 0;
  font-size: 13px;
  line-height: 1.7;
  color: #6B7075;
}

.rt-help a {
  color: #16212B;
  text-decoration: underline;
  /* 邮箱很长，手机端要允许它断行，否则会撑出横向滚动 */
  word-break: break-word;
}

.rt-help-sep {
  margin: 0 2px;
  color: #C3C7CB;
}

/* 「为什么会失败」面板。灰底无边框—— 带边框会像警告框，
   而这一块的语气应该是帮忙，不是报错。 */
.rt-why {
  margin: 20px 0 0;
  padding: 14px 16px;
  border-radius: 8px;
  background: #F4F6F8;
}

.rt-why-k {
  margin: 0 0 8px;
  font-size: 13px;
  font-weight: 700;
  color: #3C4146;
}

.rt-why-l {
  margin: 0;
  padding: 0 0 0 18px;
  font-size: 13px;
  line-height: 1.65;
  color: #6B7075;
}

.rt-why-l li + li {
  margin-top: 7px;
}
