/* =========================================================================
 * toydeals · 组件样式
 *
 * 设计约定：
 *  1. 4 种列表视图共用同一份 DOM，只靠根容器上的 [data-td-view] 切换布局。
 *     卡片模板永远只有一套 —— 不为每种视图写一套 HTML。
 *  2. 次级信息常驻小字，不用 hover：deal 站移动端占比高，
 *     hover 对触屏和键盘用户都失效。展开一律走显式按钮。
 *  3. 所有颜色走 token，方便日后整体换肤或接 WP 主题。
 * ====================================================================== */

/* ── 1 · Design tokens ─────────────────────────────────────────────────── */

/* toydeals · 组件样式
 * ---------------------------------------------------------------
 * 移植自 frontend/css/toydeals.css。**已剥掉 :root 令牌块** ——
 * 令牌由 toydeals-core 的 design/tokens.php 输出（D21 单一真源）。
 * 改令牌请改那边，然后 `wp toydeals tokens --css` 打印出来贴回原型。
 *
 * 所有类名带 td- 前缀，无例外（含 is-/tone-/js- 状态类）。
 */


/* ── 2 · Reset（不依赖 Tailwind 的 preflight，断网时页面依然完整） ────── */

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

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--td-font);
  font-size: 15px;
  line-height: 1.5;
  color: var(--td-c-ink);
  background: var(--td-c-bg);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, p, figure { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
img { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
input, select { font: inherit; color: inherit; }
table { border-collapse: collapse; width: 100%; }

:focus-visible { outline: 2px solid var(--td-c-info); outline-offset: 2px; border-radius: var(--td-r-sm); }

/* ── 3 · 布局骨架 ──────────────────────────────────────────────────────── */

.td-wrap { max-width: 1240px; margin: 0 auto; padding: 0 var(--td-sp-5); }

.td-site-head {
  background: var(--td-c-surface);
  border-bottom: 1px solid var(--td-c-border);
  position: sticky; top: 0; z-index: 40;
}
.td-site-head__inner {
  display: flex; align-items: center; gap: var(--td-sp-5);
  height: 60px;
}
.td-brand { display: flex; align-items: center; gap: var(--td-sp-2); font-weight: 700; font-size: 17px; letter-spacing: -.02em; }
.td-brand__mark {
  width: 26px; height: 26px; border-radius: 7px;
  background: linear-gradient(135deg, #ff7a45, var(--td-c-accent));
  display: grid; place-items: center; color: #fff; font-size: 14px;
}
.td-brand__sub { color: var(--td-c-ink-3); font-weight: 500; font-size: 13px; }

.td-search {
  flex: 1; max-width: 420px; position: relative;
}
.td-search input {
  width: 100%; height: 38px; padding: 0 var(--td-sp-3) 0 34px;
  border: 1px solid var(--td-c-border); border-radius: var(--td-r-full);
  background: var(--td-c-surface-alt);
}
.td-search input:focus { background: var(--td-c-surface); border-color: var(--td-c-border-strong); }
.td-search__icon { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); color: var(--td-c-ink-4); }

.td-layout { display: grid; grid-template-columns: 232px 1fr; gap: var(--td-sp-6); padding: var(--td-sp-6) 0 var(--td-sp-10); align-items: start; }

/* ── 4 · 筛选侧栏 ──────────────────────────────────────────────────────── */

.td-filters {
  background: var(--td-c-surface); border: 1px solid var(--td-c-border);
  border-radius: var(--td-r-lg); padding: var(--td-sp-4);
  position: sticky; top: 76px; max-height: calc(100vh - 96px); overflow-y: auto;
}
.td-filters__head { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--td-sp-3); }
.td-filters__title { font-size: 13px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--td-c-ink-3); }
.td-filters__reset { font-size: 12px; color: var(--td-c-info); }
.td-filters__reset[disabled] { color: var(--td-c-ink-4); cursor: default; }

.td-fgroup { border-top: 1px solid var(--td-c-border); padding: var(--td-sp-3) 0; }
.td-fgroup:first-of-type { border-top: 0; padding-top: 0; }
.td-fgroup__label { font-size: 12px; font-weight: 600; color: var(--td-c-ink-2); margin-bottom: var(--td-sp-2); display: block; }
.td-fgroup__list { display: flex; flex-direction: column; gap: 2px; max-height: 190px; overflow-y: auto; }

.td-fopt {
  display: flex; align-items: center; justify-content: space-between; gap: var(--td-sp-2);
  padding: 5px var(--td-sp-2); border-radius: var(--td-r-sm);
  font-size: 13px; color: var(--td-c-ink-2); text-align: left; width: 100%;
}
.td-fopt:hover { background: var(--td-c-surface-alt); }
.td-fopt[aria-pressed="true"] { background: var(--td-c-info-bg); color: var(--td-c-info); font-weight: 600; }
.td-fopt__count { font-size: 11px; color: var(--td-c-ink-4); font-variant-numeric: tabular-nums; }
.td-fopt[aria-pressed="true"] .td-fopt__count { color: var(--td-c-info); }

.td-ftoggle { display: flex; align-items: center; gap: var(--td-sp-2); padding: 6px 0; font-size: 13px; color: var(--td-c-ink-2); cursor: pointer; }
.td-ftoggle input { width: 15px; height: 15px; accent-color: var(--td-c-accent); cursor: pointer; }

/* ── 5 · 工具条：排序 + 视图切换 ───────────────────────────────────────── */

.td-toolbar {
  display: flex; align-items: center; gap: var(--td-sp-3); flex-wrap: wrap;
  margin-bottom: var(--td-sp-4);
}
.td-toolbar__count { font-size: 13px; color: var(--td-c-ink-3); margin-right: auto; }
.td-toolbar__count b { color: var(--td-c-ink); font-variant-numeric: tabular-nums; }

.td-select {
  height: 34px; padding: 0 28px 0 var(--td-sp-3);
  border: 1px solid var(--td-c-border); border-radius: var(--td-r-md);
  background: var(--td-c-surface) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath fill='%237c8798' d='M0 0h10L5 6z'/%3E%3C/svg%3E") no-repeat right 10px center;
  font-size: 13px; appearance: none; cursor: pointer;
}

.td-viewswitch { display: flex; gap: 2px; padding: 3px; background: var(--td-c-neutral-bg); border-radius: var(--td-r-md); }
.td-viewswitch button {
  width: 34px; height: 28px; border-radius: var(--td-r-sm);
  display: grid; place-items: center; color: var(--td-c-ink-3);
}
.td-viewswitch button:hover { color: var(--td-c-ink); }
.td-viewswitch button[aria-pressed="true"] { background: var(--td-c-surface); color: var(--td-c-ink); box-shadow: var(--td-shadow-sm); }
.td-viewswitch svg { width: 15px; height: 15px; }

/* 选中的筛选条件回显 */
.td-activechips { display: flex; flex-wrap: wrap; gap: var(--td-sp-2); margin-bottom: var(--td-sp-4); }
.td-activechips:empty { display: none; }
.td-chip {
  display: inline-flex; align-items: center; gap: 6px;
  height: 26px; padding: 0 var(--td-sp-2) 0 10px;
  background: var(--td-c-surface); border: 1px solid var(--td-c-border);
  border-radius: var(--td-r-full); font-size: 12px; color: var(--td-c-ink-2);
}
.td-chip button { color: var(--td-c-ink-4); font-size: 14px; line-height: 1; }
.td-chip button:hover { color: var(--td-c-critical); }

/* ── 6 · Deal 卡片：基础（row 视图为默认形态） ─────────────────────────── */

.td-deals { display: grid; gap: var(--td-sp-3); }

.td-deal {
  background: var(--td-c-surface);
  border: 1px solid var(--td-c-border);
  border-radius: var(--td-r-lg);
  box-shadow: var(--td-shadow-sm);
  display: grid;
  grid-template-columns: 116px minmax(0, 1fr) 188px;
  grid-template-areas:
    "media body  price"
    "foot  foot  foot"
    "panel panel panel";
  gap: 0 var(--td-sp-4);
  padding: var(--td-sp-4);
  transition: box-shadow .15s, border-color .15s;
}
.td-deal:hover { box-shadow: var(--td-shadow-md); border-color: var(--td-c-border-strong); }
.td-deal.td-is-open { box-shadow: var(--td-shadow-lg); }
.td-deal.td-is-unavailable { opacity: .72; }

/* 媒体区 */
.td-deal__media { grid-area: media; position: relative; }
.td-deal__thumb {
  width: 100%; aspect-ratio: 1; border-radius: var(--td-r-md);
  background: var(--td-c-surface-alt); overflow: hidden;
  display: grid; place-items: center;
}
.td-deal__thumb img, .td-deal__thumb svg { width: 100%; height: 100%; object-fit: cover; }
.td-deal__rank {
  position: absolute; top: -6px; left: -6px;
  min-width: 24px; height: 24px; padding: 0 6px;
  background: var(--td-c-ink); color: #fff; border-radius: var(--td-r-full);
  font-size: 11px; font-weight: 700; display: none; place-items: center;
  font-variant-numeric: tabular-nums;
}

/* 正文区 */
.td-deal__body { grid-area: body; min-width: 0; display: flex; flex-direction: column; gap: 6px; }

.td-deal__badges { display: flex; flex-wrap: wrap; gap: 5px; }
.td-badge {
  display: inline-flex; align-items: center; gap: 4px;
  height: 20px; padding: 0 8px; border-radius: var(--td-r-sm);
  font-size: 11px; font-weight: 600; letter-spacing: .01em; white-space: nowrap;
}
.td-badge--hot       { background: var(--td-c-hot-bg);       color: var(--td-c-hot); }
.td-badge--good      { background: var(--td-c-good-bg);      color: var(--td-c-good); }
.td-badge--critical  { background: var(--td-c-critical-bg);  color: var(--td-c-critical); }
.td-badge--info      { background: var(--td-c-info-bg);      color: var(--td-c-info); }
.td-badge--editorial { background: var(--td-c-editorial-bg); color: var(--td-c-editorial); }
.td-badge--neutral   { background: var(--td-c-neutral-bg);   color: var(--td-c-neutral); }

.td-deal__title {
  font-size: 15px; font-weight: 650; line-height: 1.35; letter-spacing: -.01em;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.td-deal__title a:hover { color: var(--td-c-accent); }
.td-deal__excerpt {
  font-size: 13px; color: var(--td-c-ink-2); line-height: 1.45;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

/* 常驻次级信息条 —— 不用 hover，移动端同样可见 */
.td-deal__facts {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--td-sp-2);
  font-size: 12px; color: var(--td-c-ink-3); margin-top: 2px;
}
.td-deal__facts > * { display: inline-flex; align-items: center; gap: 4px; }
.td-deal__facts .td-sep { color: var(--td-c-border-strong); }
.td-fact--unit { font-family: var(--td-font-num); font-weight: 600; color: var(--td-c-ink-2); }
.td-fact--trend.td-is-lowest { color: var(--td-c-good); font-weight: 600; }
.td-fact--trend.td-is-down   { color: var(--td-c-good); }
.td-fact--trend.td-is-up     { color: var(--td-c-critical); }
/* Holding steady：适配层 tone=neutral，比外层的 ink-3 深一档，读得出这是一条结论而不是占位 */
.td-fact--trend.td-is-flat   { color: var(--td-c-ink-2); }

.td-spark { display: block; }
.td-spark polyline { fill: none; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.td-spark--good polyline     { stroke: var(--td-c-good); }
.td-spark--critical polyline { stroke: var(--td-c-critical); }
.td-spark--neutral polyline  { stroke: var(--td-c-ink-4); }
.td-spark__dot { fill: currentColor; }

/* highlight 药丸（运营字段，结构化后才能按 type 上色 + 一键复制） */
.td-deal__highlights { display: flex; flex-direction: column; gap: 4px; margin-top: 2px; }
.td-hl {
  display: inline-flex; align-items: center; gap: 6px; align-self: flex-start;
  max-width: 100%; padding: 3px 9px; border-radius: var(--td-r-sm);
  font-size: 12px; font-weight: 550; line-height: 1.3;
}
.td-hl__icon { font-weight: 700; opacity: .8; }
.td-hl__text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.td-hl--hot       { background: var(--td-c-hot-bg);       color: var(--td-c-hot); }
.td-hl--good      { background: var(--td-c-good-bg);      color: var(--td-c-good); }
.td-hl--info      { background: var(--td-c-info-bg);      color: var(--td-c-info); }
.td-hl--editorial { background: var(--td-c-editorial-bg); color: var(--td-c-editorial); }
.td-hl--critical  { background: var(--td-c-critical-bg);  color: var(--td-c-critical); }
.td-hl--neutral   { background: var(--td-c-neutral-bg);   color: var(--td-c-neutral); }
.td-hl__code {
  font-family: var(--td-font-num); font-size: 11px; font-weight: 700;
  padding: 1px 5px; border-radius: 4px; border: 1px dashed currentColor;
  opacity: .85; cursor: pointer;
}
.td-hl__code:hover { opacity: 1; }
.td-hl__code.td-is-copied { border-style: solid; }

/* 时间：两个时间必须分开显示 —— 内容发布 ≠ 价格新鲜度 */
.td-deal__times { display: flex; gap: var(--td-sp-2); font-size: 11.5px; color: var(--td-c-ink-4); margin-top: 2px; }
.td-deal__times .td-checked { color: var(--td-c-ink-3); }
.td-deal__times .td-checked b { color: var(--td-c-good); font-weight: 600; }
.td-deal__times .td-stale b { color: var(--td-c-hot); }

/* 价格区 */
.td-deal__price {
  grid-area: price; display: flex; flex-direction: column; gap: 3px;
  align-items: flex-end; text-align: right; padding-left: var(--td-sp-3);
  border-left: 1px solid var(--td-c-border);
}
.td-price__now { font-size: 24px; font-weight: 750; letter-spacing: -.02em; font-variant-numeric: tabular-nums; line-height: 1.1; }
.td-price__row { display: flex; align-items: baseline; gap: 6px; }
.td-price__was { font-size: 13px; color: var(--td-c-ink-4); text-decoration: line-through; font-variant-numeric: tabular-nums; }
.td-price__off {
  font-size: 12px; font-weight: 700; color: var(--td-c-hot);
  background: var(--td-c-hot-bg); padding: 1px 6px; border-radius: var(--td-r-sm);
}
/* 参考价来源必须标注 —— 不标注的划线价是不可信的 */
.td-price__reflabel { font-size: 10.5px; color: var(--td-c-ink-4); }
.td-price__store { font-size: 12.5px; color: var(--td-c-ink-2); margin-top: 2px; }
.td-price__store b { font-weight: 650; color: var(--td-c-ink); }
.td-price__stock { font-size: 11.5px; font-weight: 600; }
.td-price__stock.td-tone-good     { color: var(--td-c-good); }
.td-price__stock.td-tone-info     { color: var(--td-c-info); }
.td-price__stock.td-tone-critical { color: var(--td-c-critical); }
.td-price__stock.td-tone-neutral  { color: var(--td-c-neutral); }
.td-price__nodata { font-size: 11.5px; color: var(--td-c-ink-4); font-style: italic; }

.td-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  height: 34px; padding: 0 var(--td-sp-4); border-radius: var(--td-r-md);
  font-size: 13px; font-weight: 650; white-space: nowrap;
  transition: background .15s, border-color .15s;
}
.td-btn--primary { background: var(--td-c-accent); color: var(--td-c-accent-ink); }
.td-btn--primary:hover { background: var(--td-c-accent-dark); }
.td-btn--ghost { border: 1px solid var(--td-c-border); color: var(--td-c-ink-2); }
.td-btn--ghost:hover { border-color: var(--td-c-border-strong); background: var(--td-c-surface-alt); }
.td-btn--sm { height: 28px; padding: 0 var(--td-sp-3); font-size: 12px; }
.td-btn[disabled] { background: var(--td-c-neutral-bg); color: var(--td-c-ink-4); cursor: not-allowed; }
.td-deal__cta { width: 100%; margin-top: auto; }

/* 卡片页脚 */
.td-deal__foot {
  grid-area: foot; display: flex; align-items: center; gap: var(--td-sp-3);
  margin-top: var(--td-sp-3); padding-top: var(--td-sp-3);
  border-top: 1px solid var(--td-c-border);
}
.td-deal__toggle {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 12.5px; font-weight: 600; color: var(--td-c-info);
}
.td-deal__toggle .td-caret { transition: transform .18s; display: inline-block; }
.td-deal__toggle[aria-expanded="true"] .td-caret { transform: rotate(90deg); }
.td-deal__social { display: flex; align-items: center; gap: var(--td-sp-3); margin-left: auto; font-size: 12px; color: var(--td-c-ink-3); }
.td-deal__social span { display: inline-flex; align-items: center; gap: 4px; font-variant-numeric: tabular-nums; }
.td-deal__heat { font-weight: 700; color: var(--td-c-hot); }

/* ── 7 · 展开面板 ──────────────────────────────────────────────────────── */

.td-deal__panel { grid-area: panel; display: none; }
.td-deal.td-is-open .td-deal__panel { display: block; }
.td-panel {
  margin-top: var(--td-sp-3); padding-top: var(--td-sp-4);
  border-top: 1px dashed var(--td-c-border);
  display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); gap: var(--td-sp-5);
}
.td-panel__title {
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em;
  color: var(--td-c-ink-3); margin-bottom: var(--td-sp-2);
}

/* 比价表 */
.td-stores { font-size: 13px; }
.td-stores th {
  text-align: left; font-size: 11px; font-weight: 600; color: var(--td-c-ink-4);
  padding-bottom: 6px; border-bottom: 1px solid var(--td-c-border); font-weight: 600;
}
.td-stores th:last-child, .td-stores td:last-child { text-align: right; }
.td-stores td { padding: 8px 0; border-bottom: 1px solid var(--td-c-border); vertical-align: middle; }
.td-stores tr:last-child td { border-bottom: 0; }
.td-stores tr.td-is-best td { background: linear-gradient(90deg, var(--td-c-good-bg), transparent 70%); }
.td-stores tr.td-is-out td { color: var(--td-c-ink-4); }

.td-storecell { display: flex; align-items: center; gap: var(--td-sp-2); }
.td-storechip {
  width: 30px; height: 30px; border-radius: 8px; flex: none;
  display: grid; place-items: center;
  font-size: 10px; font-weight: 700; color: #fff; letter-spacing: -.02em;
}
.td-storecell__name { font-weight: 600; }
.td-storecell__sub { font-size: 11px; color: var(--td-c-ink-4); }
.td-storeprice { font-family: var(--td-font-num); font-weight: 650; font-variant-numeric: tabular-nums; }
.td-storeunit { font-size: 11px; color: var(--td-c-ink-4); font-family: var(--td-font-num); }

/* 胜率条：某店在多少比例的日子里最便宜 */
.td-winbar { width: 54px; height: 4px; border-radius: var(--td-r-full); background: var(--td-c-neutral-bg); overflow: hidden; }
.td-winbar i { display: block; height: 100%; background: var(--td-c-good); border-radius: inherit; }
.td-winlabel { font-size: 11px; color: var(--td-c-ink-3); font-variant-numeric: tabular-nums; }

/* 价格走势图 */
.td-chart { background: var(--td-c-surface-alt); border-radius: var(--td-r-md); padding: var(--td-sp-3); }
.td-chart__head { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--td-sp-2); }
.td-chart__range { display: flex; gap: 2px; }
.td-chart__range button {
  height: 22px; padding: 0 8px; border-radius: var(--td-r-sm);
  font-size: 11px; font-weight: 600; color: var(--td-c-ink-3);
}
.td-chart__range button[aria-pressed="true"] { background: var(--td-c-surface); color: var(--td-c-ink); box-shadow: var(--td-shadow-sm); }
.td-chart svg { width: 100%; height: 108px; display: block; overflow: visible; }
.td-chart .td-area { fill: url(#tdGrad); }
.td-chart .td-line { fill: none; stroke: var(--td-c-hot); stroke-width: 1.8; stroke-linejoin: round; stroke-linecap: round; }
.td-chart .td-gridline { stroke: var(--td-c-border); stroke-width: 1; stroke-dasharray: 2 3; }
.td-chart .td-marker { fill: var(--td-c-hot); }
.td-chart .td-marker--low { fill: var(--td-c-good); }
.td-chart__axis { display: flex; justify-content: space-between; font-size: 10.5px; color: var(--td-c-ink-4); margin-top: 4px; }
.td-chart__stats { display: flex; gap: var(--td-sp-4); margin-top: var(--td-sp-2); font-size: 11.5px; color: var(--td-c-ink-3); }
.td-chart__stats b { color: var(--td-c-ink); font-family: var(--td-font-num); font-variant-numeric: tabular-nums; }

/* 近期降价 */
.td-drops li { display: flex; align-items: center; gap: var(--td-sp-2); padding: 5px 0; font-size: 12.5px; border-bottom: 1px solid var(--td-c-border); }
.td-drops li:last-child { border-bottom: 0; }
.td-drops__date { color: var(--td-c-ink-4); font-size: 11px; width: 62px; flex: none; font-variant-numeric: tabular-nums; }
.td-drops__store { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.td-drops__delta { font-weight: 650; font-family: var(--td-font-num); font-variant-numeric: tabular-nums; }
.td-drops__delta.td-is-drop { color: var(--td-c-good); }
.td-drops__delta.td-is-rise { color: var(--td-c-critical); }

/* 附加信息（规格 / 洞察） */
.td-specs { display: flex; flex-wrap: wrap; gap: 6px; }
.td-spec {
  font-size: 11.5px; color: var(--td-c-ink-2);
  background: var(--td-c-surface-alt); border: 1px solid var(--td-c-border);
  padding: 2px 8px; border-radius: var(--td-r-sm);
}
.td-spec b { font-weight: 650; }
.td-note { font-size: 11.5px; color: var(--td-c-ink-4); line-height: 1.45; }

/* ── 8 · 视图 B：Card Grid ─────────────────────────────────────────────── */

[data-td-view="grid"] .td-deals { grid-template-columns: repeat(auto-fill, minmax(258px, 1fr)); gap: var(--td-sp-4); }
[data-td-view="grid"] .td-deal {
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas: "media" "body" "price" "foot" "panel";
  gap: var(--td-sp-3) 0;
}
[data-td-view="grid"] .td-deal__media { margin: calc(var(--td-sp-4) * -1) calc(var(--td-sp-4) * -1) 0; }
[data-td-view="grid"] .td-deal__thumb { border-radius: var(--td-r-lg) var(--td-r-lg) 0 0; aspect-ratio: 4 / 3; }
[data-td-view="grid"] .td-deal__excerpt { -webkit-line-clamp: 2; }
[data-td-view="grid"] .td-deal__price {
  border-left: 0; padding-left: 0; align-items: stretch; text-align: left;
  border-top: 1px solid var(--td-c-border); padding-top: var(--td-sp-3);
}
[data-td-view="grid"] .td-price__row { justify-content: flex-start; }
[data-td-view="grid"] .td-deal__foot { margin-top: 0; }
[data-td-view="grid"] .td-panel { grid-template-columns: minmax(0, 1fr); gap: var(--td-sp-4); }

/* ── 9 · 视图 C：Compact / Price-first ─────────────────────────────────── */

[data-td-view="compact"] .td-deals { gap: 0; background: var(--td-c-surface); border: 1px solid var(--td-c-border); border-radius: var(--td-r-lg); overflow: hidden; }
[data-td-view="compact"] .td-deal {
  border: 0; border-radius: 0; box-shadow: none;
  border-bottom: 1px solid var(--td-c-border);
  grid-template-columns: 44px minmax(0, 1fr) 132px auto;
  grid-template-areas: "media body price foot" "panel panel panel panel";
  align-items: center; padding: var(--td-sp-3) var(--td-sp-4); gap: 0 var(--td-sp-3);
}
[data-td-view="compact"] .td-deal:last-child { border-bottom: 0; }
[data-td-view="compact"] .td-deal:hover { background: var(--td-c-surface-alt); box-shadow: none; }
[data-td-view="compact"] .td-deal__thumb { border-radius: var(--td-r-sm); }
[data-td-view="compact"] .td-deal__excerpt,
[data-td-view="compact"] .td-deal__highlights,
[data-td-view="compact"] .td-deal__times .td-posted { display: none; }
[data-td-view="compact"] .td-deal__title { -webkit-line-clamp: 1; font-size: 14px; }
[data-td-view="compact"] .td-deal__body { gap: 3px; }
[data-td-view="compact"] .td-deal__badges { gap: 4px; }
[data-td-view="compact"] .td-badge { height: 18px; font-size: 10px; padding: 0 6px; }
[data-td-view="compact"] .td-deal__price { border-left: 0; padding-left: 0; gap: 1px; }
[data-td-view="compact"] .td-price__now { font-size: 18px; }
[data-td-view="compact"] .td-price__reflabel, [data-td-view="compact"] .td-price__store { display: none; }
[data-td-view="compact"] .td-deal__cta { display: none; }
[data-td-view="compact"] .td-deal__foot { margin: 0; padding: 0 0 0 var(--td-sp-3); border: 0; }
[data-td-view="compact"] .td-deal__social { display: none; }
[data-td-view="compact"] .td-deal__toggle span:not(.td-caret) { display: none; }

/* ── 10 · 视图 D：Featured Hero ────────────────────────────────────────── */

[data-td-view="hero"] .td-deals { gap: var(--td-sp-4); }
[data-td-view="hero"] .td-deal {
  grid-template-columns: 300px minmax(0, 1fr);
  grid-template-areas: "media body" "media price" "foot foot" "panel panel";
  gap: var(--td-sp-2) var(--td-sp-5); padding: var(--td-sp-5);
}
/* media 区在 areas 里已跨两行，不要再写 grid-row —— 它会覆盖具名区域的行定位 */
[data-td-view="hero"] .td-deal__thumb { aspect-ratio: 4 / 3; height: 100%; }
[data-td-view="hero"] .td-deal__rank { display: grid; }
[data-td-view="hero"] .td-deal__title { font-size: 21px; -webkit-line-clamp: 2; letter-spacing: -.02em; }
[data-td-view="hero"] .td-deal__excerpt { font-size: 14px; -webkit-line-clamp: 3; }
[data-td-view="hero"] .td-badge { height: 22px; font-size: 11.5px; }
[data-td-view="hero"] .td-deal__price {
  border-left: 0; padding-left: 0; align-items: flex-start; text-align: left;
  flex-direction: row; flex-wrap: wrap; align-items: flex-end; gap: var(--td-sp-3);
  margin-top: var(--td-sp-2);
}
[data-td-view="hero"] .td-price__now { font-size: 34px; }
[data-td-view="hero"] .td-price__block { display: flex; flex-direction: column; gap: 2px; }
[data-td-view="hero"] .td-deal__cta { width: auto; margin: 0 0 0 auto; height: 40px; padding: 0 var(--td-sp-6); font-size: 14px; }
[data-td-view="hero"] .td-deal__highlights { flex-direction: row; flex-wrap: wrap; }
[data-td-view="hero"] .td-hl { font-size: 12.5px; padding: 4px 10px; }

/* ── 11 · 空状态与骨架 ─────────────────────────────────────────────────── */

.td-empty {
  background: var(--td-c-surface); border: 1px dashed var(--td-c-border-strong);
  border-radius: var(--td-r-lg); padding: var(--td-sp-10) var(--td-sp-6); text-align: center;
}
.td-empty h3 { font-size: 16px; margin-bottom: 6px; }
.td-empty p { font-size: 13.5px; color: var(--td-c-ink-3); margin-bottom: var(--td-sp-4); }

.td-legend {
  margin-top: var(--td-sp-6); padding: var(--td-sp-4);
  background: var(--td-c-surface); border: 1px solid var(--td-c-border); border-radius: var(--td-r-lg);
  font-size: 12.5px; color: var(--td-c-ink-3); line-height: 1.6;
}
.td-legend b { color: var(--td-c-ink-2); }
.td-legend code { font-family: var(--td-font-num); font-size: 11.5px; background: var(--td-c-surface-alt); padding: 1px 5px; border-radius: 4px; }

/* ── 12 · 响应式 ───────────────────────────────────────────────────────── */

@media (max-width: 1080px) {
  .td-layout { grid-template-columns: 1fr; }
  .td-filters { position: static; max-height: none; }
  .td-fgroup__list { max-height: none; }
  .td-filters__body { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--td-sp-4); }
  .td-fgroup { border-top: 0; padding: 0; }
}

@media (max-width: 720px) {
  .td-wrap { padding: 0 var(--td-sp-4); }
  .td-site-head__inner { height: auto; padding: var(--td-sp-3) 0; flex-wrap: wrap; }
  .td-search { order: 3; max-width: none; flex-basis: 100%; }

  /* 移动端：row / hero 都退化为堆叠，价格区转为横向一行 */
  [data-td-view="row"] .td-deal,
  [data-td-view="hero"] .td-deal {
    grid-template-columns: 84px minmax(0, 1fr);
    grid-template-areas: "media body" "price price" "foot foot" "panel panel";
    gap: 0 var(--td-sp-3); padding: var(--td-sp-3);
  }
  [data-td-view="hero"] .td-deal__thumb { aspect-ratio: 1; height: auto; }
  [data-td-view="hero"] .td-deal__title { font-size: 16px; }
  [data-td-view="hero"] .td-price__now { font-size: 24px; }

  [data-td-view="row"] .td-deal__price,
  [data-td-view="hero"] .td-deal__price {
    border-left: 0; padding-left: 0; margin-top: var(--td-sp-3);
    padding-top: var(--td-sp-3); border-top: 1px solid var(--td-c-border);
    flex-direction: row; flex-wrap: wrap; align-items: center; text-align: left; gap: var(--td-sp-2);
  }
  [data-td-view="row"] .td-price__block,
  [data-td-view="hero"] .td-price__block { display: flex; flex-direction: column; }
  [data-td-view="row"] .td-deal__cta,
  [data-td-view="hero"] .td-deal__cta { width: auto; margin-left: auto; }

  [data-td-view="grid"] .td-deals { grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: var(--td-sp-3); }
  [data-td-view="compact"] .td-deal { grid-template-columns: 36px minmax(0, 1fr) auto; grid-template-areas: "media body price" "panel panel panel"; }
  [data-td-view="compact"] .td-deal__foot { display: none; }

  .td-panel { grid-template-columns: minmax(0, 1fr); gap: var(--td-sp-4); }
  .td-deal__times { flex-wrap: wrap; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

/* ── 13 · 站上的列表外壳（WP 侧 shortcode 与归档页；原型不渲染这些） ────── */

/* [td_deals] / [td_deal] 的区块外框 */
.td-block { margin: var(--td-sp-6) 0; }
.td-block__head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--td-sp-3); margin-bottom: var(--td-sp-3); }
.td-block__title { font-size: 19px; font-weight: 700; letter-spacing: -.01em; }
.td-block__more { font-size: 13px; font-weight: 600; color: var(--td-c-info); white-space: nowrap; }
.td-block__more:hover { text-decoration: underline; }

/* 只在有 JS 时才有意义的控件（视图切换、展开比价）。<html> 上的 td-js 由页头第一行脚本加上 */
html:not(.td-js) .td-js-only { display: none !important; }

/* 侧栏选项在站上是链接（无 JS 也能点），选中态用 aria-current；原型的按钮用 aria-pressed */
.td-fopt[aria-current="true"] { background: var(--td-c-info-bg); color: var(--td-c-info); font-weight: 600; }
.td-fopt[aria-current="true"] .td-fopt__count { color: var(--td-c-info); }
/* 当前结果里一条都不剩的选项置灰（原型写在内联 style 里） */
.td-fopt.td-is-empty { opacity: .4; }
.td-chip a { color: var(--td-c-ink-4); font-size: 14px; line-height: 1; }
.td-chip a:hover { color: var(--td-c-critical); }

/* 排序：GET 表单，无 JS 时多一个提交按钮 */
.td-sortform { display: flex; align-items: center; gap: var(--td-sp-2); }

/* 分页 */
.td-pager { display: flex; flex-wrap: wrap; justify-content: center; gap: 4px; margin-top: var(--td-sp-6); }
.td-pager__link {
  min-width: 34px; height: 34px; padding: 0 var(--td-sp-2);
  display: inline-grid; place-items: center;
  border: 1px solid var(--td-c-border); border-radius: var(--td-r-md); background: var(--td-c-surface);
  font-size: 13px; color: var(--td-c-ink-2); font-variant-numeric: tabular-nums;
}
a.td-pager__link:hover { border-color: var(--td-c-border-strong); }
.td-pager__link[aria-current="page"] { background: var(--td-c-ink); border-color: var(--td-c-ink); color: var(--td-c-surface); font-weight: 600; }
.td-pager__gap { border-color: transparent; background: none; }
.td-pager__link.td-is-disabled { color: var(--td-c-ink-4); }

/* 局部刷新进行中：列表变淡、暂不可点（连点由 JS 取消前一次请求） */
.td-list.td-is-loading .td-deals { opacity: .55; pointer-events: none; transition: opacity .15s; }

/* ── 14 · 文章卡（博客侧，第 7 步）────────────────────────────────────── */
/*
 * **刻意复用 deal 卡的骨架**：同样的 surface / border / 圆角 / 阴影 / 内边距 /
 * 缩略图圆角 / 字阶 / badge。两种卡片会并排出现在 /brand/lego/ 上（D32），
 * 看起来必须是同一个站 —— 这正是 §7.4「共享令牌与骨架」的意思。
 *
 * 不复用类名而是另起 .td-post，是因为 .td-deal 是三列 grid（media/body/price）
 * 且带 4 种视图的覆盖规则；文章没有价格列、也不参与视图切换，
 * 挂上去只会让两边互相牵制。共享的是**令牌**，不是选择器。
 *
 * 编号接在 13 之后而不是插进第 6 节：两份 CSS 要逐字节一致（css-parity.sh），
 * 重排既有编号会让 diff 变得没法看。
 */

.td-posts { display: grid; gap: var(--td-sp-3); }

.td-post {
  background: var(--td-c-surface);
  border: 1px solid var(--td-c-border);
  border-radius: var(--td-r-lg);
  box-shadow: var(--td-shadow-sm);
  display: grid;
  grid-template-columns: 92px minmax(0, 1fr);
  gap: 0 var(--td-sp-3);
  padding: var(--td-sp-3);
  transition: box-shadow .15s, border-color .15s;
}
.td-post:hover { box-shadow: var(--td-shadow-md); border-color: var(--td-c-border-strong); }

.td-post__media { min-width: 0; }
.td-post__thumb {
  width: 100%; aspect-ratio: 4 / 3; border-radius: var(--td-r-md);
  background: var(--td-c-surface-alt); overflow: hidden;
  display: grid; place-items: center;
}
/* `>`：只管封面图与占位图本身 —— 后代选择器会连视频角标里的 ▶ 图标一起拉满（D38，2026-09-30 实测） */
.td-post__thumb > img, .td-post__thumb > svg { width: 100%; height: 100%; object-fit: cover; }

.td-post__body { min-width: 0; display: flex; flex-direction: column; gap: 5px; }
.td-post__kicker { display: flex; }

/* 与 .td-deal__title 同一套排版，只是少收一行 —— 文章标题比商品名短 */
.td-post__title {
  font-size: 15px; font-weight: 650; line-height: 1.35; letter-spacing: -.01em;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.td-post__title a:hover { color: var(--td-c-accent); }

.td-post__excerpt {
  font-size: 13px; color: var(--td-c-ink-2); line-height: 1.45;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

/* 常驻，不用 hover —— 与 .td-deal__facts 同一条理由（D7：移动端同样可见） */
.td-post__meta {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--td-sp-2);
  font-size: 12px; color: var(--td-c-ink-3); margin-top: auto; padding-top: 2px;
}
.td-post__meta .td-sep { color: var(--td-c-border-strong); }

/*
 * 窄容器下缩略图收窄而不是换行 —— 侧栏（/brand/lego/ 的右栏）只有 ~260px，
 * 让图掉到标题上面会把一屏能放的文章数砍半。
 */
@media (max-width: 720px) {
  .td-post { grid-template-columns: 76px minmax(0, 1fr); padding: var(--td-sp-2); }
  .td-post__title { font-size: 14px; }
  .td-post__excerpt { -webkit-line-clamp: 2; font-size: 12.5px; }
}

/* 原型页面上「Reading」那一块的外框。站上由 views/ 出，原型不渲染 views/ —— 
   与第 13 节同理：外壳样式两份 CSS 都留着，省得日后对拍打架 */
.td-postsblock { margin-top: var(--td-sp-6); }
.td-postsblock__title {
  font-size: 15px; font-weight: 650; letter-spacing: -.01em;
  margin-bottom: var(--td-sp-3);
}

/*
 * `[td_posts view="grid"]`：宽区块用自适应多列，侧栏用默认的单列。
 *
 * 复用 `data-td-view` 这个属性名（deal 那边的 board 也用它），但取值完全不同 ——
 * 文章**不参与** deal 的 4 视图切换（D32 ③）。属性名共用只是为了少一个词，
 * 选择器是各自的：`.td-posts[data-td-view]` ↔ `[data-td-view] .td-deal`。
 */
.td-posts[data-td-view="grid"] {
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
}

/*
 * `[td_price]`：正文里引用快照的值。**纯文本，不是链接**。
 *
 * 只做两件事：等宽数字（同一段里出现几个价格时不会跳动），以及轻微加重。
 * 刻意不给颜色 —— 正文里的有色文字会被读作链接，而它点不动。
 */
.td-priceinline {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  color: var(--td-c-ink);
}

/* ── 15 · 共享轴 term 归档的两栏（第 7 步，D32）────────────────────────── */
/*
 * 主栏 deals（带分页）+ 侧栏文章（固定条数）。不是混排流 —— deal 的排序维度
 * 对文章根本不存在，混排要先给文章编一套分数（D22 推迟到形态 B 的东西）。
 *
 * ⚠ **窄屏下侧栏不掉到分页下面，而是折成横向滚动插在首屏之后。**
 * 玩具类目移动端通常过半，让「相关阅读」落在分页后面等于它在多数访客那里
 * 没有曝光。同一份 DOM 只靠断点切换 —— 与 D8「4 视图共用同一份 DOM」同一路子。
 * `order` 负责把它提到列表前面，横滚负责让它只占一屏的一小条。
 */
.td-termlayout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 280px;
  gap: var(--td-sp-5);
  align-items: start;
}
.td-termlayout__main { min-width: 0; }
.td-termlayout__side { min-width: 0; position: sticky; top: var(--td-sp-4); }

.td-archive__desc {
  font-size: 13.5px; color: var(--td-c-ink-2); line-height: 1.5;
  max-width: 68ch; margin-top: var(--td-sp-2);
}

@media (max-width: 900px) {
  .td-termlayout { grid-template-columns: minmax(0, 1fr); }
  .td-termlayout__side { position: static; order: -1; }

  /* 横向滚动：一屏只占一条，不与主列表抢高度 */
  .td-termlayout__side .td-posts {
    grid-auto-flow: column;
    grid-auto-columns: 78%;
    grid-template-columns: none;
    overflow-x: auto;
    scroll-snap-type: x proximity;
    padding-bottom: var(--td-sp-2);
  }
  .td-termlayout__side .td-post { scroll-snap-align: start; }
}

/* ── 16 · 读者报错的入口与报错页（R3，D34）───────────────────────────── */
/*
 * 两块东西：deal 详情页上那个入口链接，以及报错页上的「你报的是哪一条」。
 * 表单本身是 WPForms 渲染的，这里一条规则都不给它 —— 边界在 shortcode（D20），
 * 给它写样式等于把它的 DOM 结构变成我们的依赖，它一升级就错位。
 */

/*
 * 入口刻意做得**不像 CTA**：小、灰、不抢眼。它要能被找到，但页面上真正
 * 重要的是「去买」那个按钮 —— 把报错做成第二个醒目按钮，等于请每个读者
 * 都来试一下。
 */
.td-reportlink {
  font-size: 12.5px; color: var(--td-c-ink-3);
  text-decoration: underline; text-underline-offset: 2px;
}
.td-reportlink:hover { color: var(--td-c-critical); }

.td-reportctx {
  border: 1px solid var(--td-c-border);
  border-radius: var(--td-r-md);
  background: var(--td-c-surface-alt);
  padding: var(--td-sp-3);
  margin-bottom: var(--td-sp-4);
}
.td-reportctx__kicker {
  font-size: 11.5px; font-weight: 650; letter-spacing: .04em; text-transform: uppercase;
  color: var(--td-c-ink-3); margin-bottom: var(--td-sp-2);
}
.td-reportctx__row { display: grid; grid-template-columns: 72px minmax(0, 1fr); gap: var(--td-sp-3); align-items: start; }
.td-reportctx__thumb {
  width: 72px; height: 72px; border-radius: var(--td-r-sm); overflow: hidden;
  background: var(--td-c-surface);
}
.td-reportctx__thumb img, .td-reportctx__thumb svg { width: 100%; height: 100%; object-fit: cover; }
.td-reportctx__body { min-width: 0; }
.td-reportctx__title { font-size: 15px; font-weight: 650; line-height: 1.35; margin-bottom: var(--td-sp-2); }

/*
 * 事实列表用 dl 而不是几个 span：读者要核对的是「我们说的是多少钱、什么时候
 * 确认的」，标签与值成对出现才读得准，屏幕阅读器也能念对。
 * 两列网格让标签右对齐到同一条线上，值不会因为标签长短而参差。
 */
.td-reportctx__facts {
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  gap: 2px var(--td-sp-2); align-items: baseline;
  font-size: 13px;
}
.td-reportctx__label { color: var(--td-c-ink-3); }
.td-reportctx__value { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--td-sp-2); min-width: 0; }
.td-reportctx__price { font-variant-numeric: tabular-nums; font-weight: 650; color: var(--td-c-ink); }
.td-reportctx__discount { font-weight: 650; color: var(--td-c-critical); }
.td-reportctx__store { color: var(--td-c-ink-3); }

.td-reportctx__note { font-size: 13.5px; color: var(--td-c-ink-2); line-height: 1.5; }
.td-reportctx__browse { font-weight: 600; color: var(--td-c-info); }
.td-reportctx__browse:hover { text-decoration: underline; }

@media (max-width: 480px) {
  .td-reportctx__row { grid-template-columns: 56px minmax(0, 1fr); }
  .td-reportctx__thumb { width: 56px; height: 56px; }
}

/* ── 16b · 订阅确认 / 退订页（[td_subscribe]，R6）─────────────────────── */
/*
 * 一句话 + 一个按钮。按钮要像按钮：读者是从邮件里点进来的，这一页唯一的事
 * 就是按下它 —— 与报错入口「刻意不像 CTA」正好相反。
 */
.td-subscribe {
  border: 1px solid var(--td-c-border);
  border-radius: var(--td-r-md);
  background: var(--td-c-surface-alt);
  padding: var(--td-sp-4);
  margin-bottom: var(--td-sp-4);
}
.td-subscribe__msg { font-size: 15px; line-height: 1.5; color: var(--td-c-ink); margin-bottom: var(--td-sp-3); }
.td-subscribe__form { margin-bottom: var(--td-sp-3); }
.td-subscribe__btn {
  font: inherit; font-size: 14px; font-weight: 650;
  padding: var(--td-sp-2) var(--td-sp-4);
  border: 0; border-radius: var(--td-r-sm);
  background: var(--td-c-info); color: #fff; cursor: pointer;
}
.td-subscribe__btn:hover { filter: brightness(1.08); }
.td-subscribe__aside { font-size: 13px; color: var(--td-c-ink-3); }
.td-subscribe__aside + .td-subscribe__aside { margin-top: var(--td-sp-2); }
.td-subscribe__unsub { color: var(--td-c-ink-3); text-decoration: underline; text-underline-offset: 2px; }
.td-subscribe__browse { font-weight: 600; color: var(--td-c-info); }
.td-subscribe__browse:hover { text-decoration: underline; }
.td-subscribe__deal { font-size: 15px; font-weight: 600; margin-bottom: var(--td-sp-3); }
.td-subscribe__deallink { color: var(--td-c-info); }
.td-subscribe__deallink:hover { text-decoration: underline; }

/* ── 16b · 降价提醒表单（[td_watch]，A2）──────────────────────────────── */
/*
 * 措辞三段（legend / 说明 / 复选框文字）逐字来自 Consent::TEXTS，这里只管样子。
 * 蜜罐移出视口而不是 display:none：有的机器人只跳过看不见的字段。
 * 不给它设 display —— 别让一个类选择器盖掉什么（gotchas「hidden 属性」那一条的同类）。
 */
.td-watch {
  border: 1px solid var(--td-c-border);
  border-radius: var(--td-r-md);
  background: var(--td-c-surface-alt);
  padding: var(--td-sp-4);
  margin-bottom: var(--td-sp-4);
  position: relative;
}
.td-watch__set { border: 0; margin: 0; padding: 0; min-width: 0; }
.td-watch__legend { font-size: 15px; font-weight: 650; color: var(--td-c-ink); padding: 0; margin-bottom: var(--td-sp-2); }
.td-watch__desc { font-size: 13px; line-height: 1.5; color: var(--td-c-ink-3); margin-bottom: var(--td-sp-3); }
.td-watch__field { display: block; margin-bottom: var(--td-sp-3); }
.td-watch__label { display: block; font-size: 13px; font-weight: 600; color: var(--td-c-ink); margin-bottom: var(--td-sp-1); }
.td-watch__input {
  font: inherit; font-size: 15px; width: 100%; max-width: 360px;
  padding: var(--td-sp-2) var(--td-sp-3);
  border: 1px solid var(--td-c-border); border-radius: var(--td-r-sm);
  background: var(--td-c-surface); color: var(--td-c-ink);
}
.td-watch__consent { display: flex; gap: var(--td-sp-2); align-items: flex-start; font-size: 14px; line-height: 1.4; color: var(--td-c-ink); margin-bottom: var(--td-sp-3); cursor: pointer; }
.td-watch__check { margin-top: 2px; }
.td-watch__hp { position: absolute; left: -10000px; top: auto; width: 1px; height: 1px; overflow: hidden; }
.td-watch__btn {
  font: inherit; font-size: 14px; font-weight: 650;
  padding: var(--td-sp-2) var(--td-sp-4);
  border: 0; border-radius: var(--td-r-sm);
  background: var(--td-c-info); color: #fff; cursor: pointer;
}
.td-watch__btn:hover { filter: brightness(1.08); }

/* ── 17 · deal 详情页（[td_deal_detail]）──────────────────────────────── */
/*
 * **不是把 hero 卡片放大。** hero 是 `300px + 1fr` 的卡片栅格，它要在一页里跟
 * 别的卡片并排；详情页上这一条是唯一的主角，读者的问题也换了 ——
 * 卡片回答「值不值得点进来」，详情页回答「我该在哪买、现在买对不对」。
 *
 * 所以比价表从折叠面板里拿出来占满宽度，走势图给两个窗口，规格常驻。
 * 复用的是同一批 partial，这里只给容器定位，**不覆写 partial 自己的样式** ——
 * 覆写等于在两份 CSS 之外又开一套，而卡片那边一改这边就悄悄错位。
 */
/*
 * ── 宽度自适应走**容器查询**，不是视口断点 ──────────────────────────
 *
 * 这一块会被放进不同宽度的容器：全宽页、两栏版式的主栏（~720px）、
 * 日后可能还有更窄的位置。视口断点在这里是错的 —— 主栏只有 720px 而视口
 * 有 1440px 时，`@media (max-width: 900px)` **根本不会触发**，于是 420px 的图
 * 挤掉大半、右边只剩三百来px，而浏览器窗口看着一切正常。
 *
 * 全站这是第一处容器查询（其余 7 个 @media 都是视口断点，它们查的是「这一页
 * 有多宽」，那对归档页是对的）。容器查询 2023 年初起全绿，不做视口兜底 ——
 * 万一它没生效，症状是手机上版式变宽，**看得见**，不是静默失效。
 *
 * ⚠ `container-type: inline-size` 展开是 `contain: layout style inline-size`：
 * 它让本元素成为 `position: fixed` 后代的包含块（真会咬人），但**不创建滚动
 * 容器**，所以内部的 `position: sticky` 照常吸附到视口，不受影响。
 * 侧栏那种 sticky 是**外框**的事（侧栏是本元素的兄弟，不在这里面）。
 */
.td-dealdetail {
  display: grid; gap: var(--td-sp-5);
  container-type: inline-size; container-name: td-detail;
}

.td-dealdetail__hero {
  display: grid; grid-template-columns: minmax(0, 420px) minmax(0, 1fr);
  gap: var(--td-sp-5); align-items: start;
}
.td-dealdetail__media {
  border-radius: var(--td-r-lg); overflow: hidden; background: var(--td-c-surface-alt);
  aspect-ratio: 4 / 3;
}
.td-dealdetail__media img, .td-dealdetail__media svg {
  width: 100%; height: 100%; object-fit: contain; display: block;
}
.td-dealdetail__lead { min-width: 0; display: flex; flex-direction: column; gap: var(--td-sp-3); }
.td-dealdetail__social {
  display: flex; gap: var(--td-sp-4); font-size: 12.5px; color: var(--td-c-ink-3);
  font-variant-numeric: tabular-nums;
}

/*
 * 比价表在详情页上是主角，不再是面板里的一栏 —— 撑满宽度、给它一个标题级的间距。
 * `.td-panel` 的两栏栅格在这里用不上，所以容器只负责不让它继承面板的排布。
 */
.td-dealdetail__stores { min-width: 0; }

.td-dealdetail__cols {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 340px);
  gap: var(--td-sp-5); align-items: start;
}
.td-dealdetail__chart { min-width: 0; }
.td-dealdetail__side { min-width: 0; display: grid; gap: var(--td-sp-4); }

.td-dealdetail__charthead {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--td-sp-3); margin-bottom: var(--td-sp-2);
}
.td-dealdetail__h2 { font-size: 16px; font-weight: 650; letter-spacing: -.01em; }

/*
 * 两个窗口都在服务端渲染好，这里切哪一个可见。
 *
 * ⚠ `panel-chart.php` **自带**一对 30d/90d 按钮（`.td-js-range`），
 * 但它们的处理器第一件事是 `closest('.td-deal')` —— 详情页上没有卡片，
 * 点了什么都不会发生。藏掉而不是留着：一个死控件比没有控件糟得多。
 * `display:none` 也会把它们从可访问性树里拿掉，不会被读屏念出来。
 */
.td-dealdetail .td-chart__head .td-chart__range { display: none; }
.td-dealdetail__pane { display: none; }
.td-dealdetail[data-td-range="30"] .td-dealdetail__pane[data-td-pane="30"],
.td-dealdetail[data-td-range="90"] .td-dealdetail__pane[data-td-pane="90"] { display: block; }

.td-dealdetail__browse { font-weight: 600; color: var(--td-c-info); }
.td-dealdetail__browse:hover { text-decoration: underline; }

/*
 * 两级：
 *   ≤ 860px  两栏版式的主栏。图收窄；右边那栏（近期变动 + 规格）掉到图下面 ——
 *            340px 的侧栏塞进 720px 的主栏里，走势图只剩三百多px，不如给它整行
 *   ≤ 560px  手机，或者这一块被放进一个窄位置：全部叠成一列
 */
@container td-detail (max-width: 860px) {
  .td-dealdetail__hero { grid-template-columns: minmax(0, 300px) minmax(0, 1fr); }
  .td-dealdetail__cols { grid-template-columns: minmax(0, 1fr); }
}
@container td-detail (max-width: 560px) {
  .td-dealdetail__hero { grid-template-columns: minmax(0, 1fr); }
}

.td-dealdetail__title { font-size: 26px; font-weight: 700; letter-spacing: -.02em; line-height: 1.25; }
.td-dealdetail__excerpt { font-size: 14.5px; color: var(--td-c-ink-2); line-height: 1.55; max-width: 62ch; }

@container td-detail (max-width: 560px) {
  .td-dealdetail__title { font-size: 21px; }
}

/* ── 18 · 详情页底部的购买条 ─────────────────────────────────────────── */
/*
 * 正文很长时，hero 里那个 Get Deal 早就滚出视口了。这条跟着滚动出现 ——
 * 出现与否由 IntersectionObserver 决定（观察 hero 的价格块），不是 scroll 监听。
 *
 * ⚠ **它靠 JS 挪到 <body> 下才有 `position: fixed`。** 祖先链上任何 transform /
 * filter / perspective / contain 都会劫持 fixed，而 `.td-dealdetail` 自己就有
 * `container-type: inline-size`，Oxygen 的容器还可能带动画。服务端把它渲染成
 * `.td-dealdetail` 的**兄弟**是第一道，JS 挪到 body 是第二道。
 *
 * 整条 `td-js-only`：没有 JS 时它要么恒显、要么恒不显，而恒显会一直挡住
 * 正文最后一行。
 */
.td-buybar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
  background: var(--td-c-surface);
  border-top: 1px solid var(--td-c-border);
  box-shadow: var(--td-shadow-lg);
  /* 收起时也要退出 tab 顺序与读屏，光靠位移不够 */
  transform: translateY(100%); visibility: hidden;
  transition: transform .18s ease, visibility .18s;
  padding-bottom: env(safe-area-inset-bottom);
}
.td-buybar.td-is-on { transform: translateY(0); visibility: visible; }

/* 正文最后一行不该被压在条下面。**一次性加，不跟着开关切** —— 切会抖 */
body.td-has-buybar { padding-bottom: 76px; }

@media (prefers-reduced-motion: reduce) {
  .td-buybar { transition: none; }
}

.td-buybar__inner {
  max-width: 1200px; margin: 0 auto;
  display: flex; align-items: center; gap: var(--td-sp-3);
  padding: var(--td-sp-2) var(--td-sp-4);
}
.td-buybar__thumb {
  width: 44px; height: 44px; flex: none; object-fit: contain;
  border-radius: var(--td-r-sm); background: var(--td-c-surface-alt);
}
.td-buybar__body { min-width: 0; flex: 1; }
.td-buybar__title {
  font-size: 13px; font-weight: 600; line-height: 1.3;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.td-buybar__meta { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--td-sp-2); font-size: 13px; }
.td-buybar__price { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--td-c-ink); }
.td-buybar__discount { font-weight: 650; color: var(--td-c-critical); }
.td-buybar__store { font-size: 12px; color: var(--td-c-ink-3); }

/*
 * 分享：**触屏弹系统原生面板，桌面弹这个浮层**（2026-09-23 用户定）。
 * 桌面的原生面板几乎没有价值 —— 实测点下去转一下就自己消失、没有任何反馈。
 * 浮层里的链接与正文末尾那一行是同一份 `share-list.php`。
 */
.td-buybar__sharewrap { position: relative; flex: none; }
.td-buybar__share {
  display: grid; place-items: center;
  width: 38px; height: 38px; border-radius: var(--td-r-sm);
  border: 1px solid var(--td-c-border); background: var(--td-c-surface);
  color: var(--td-c-ink-2); cursor: pointer;
}
.td-buybar__share:hover { border-color: var(--td-c-border-strong); color: var(--td-c-ink); }
.td-buybar__share[aria-expanded="true"] { border-color: var(--td-c-border-strong); color: var(--td-c-ink); }

/* 往上弹：条本来就贴着视口底边，往下没有空间 */
.td-buybar__pop {
  position: absolute; right: 0; bottom: calc(100% + 8px); z-index: 1;
  display: block;
  background: var(--td-c-surface);
  border: 1px solid var(--td-c-border); border-radius: var(--td-r-md);
  box-shadow: var(--td-shadow-lg);
  padding: var(--td-sp-3);
}
/*
 * ⚠ **这一条不能删。** `hidden` 属性来自 UA 样式表的 `[hidden] { display: none }`，
 * 那是**元素选择器级**的优先级 —— 任何设了 `display` 的**类选择器**都会盖掉它，
 * 而元素就那么一直显示着。2026-09-23 实测踩过：浮层当时还挂着 `.td-share`
 * （`display: flex`），于是默认就展开、JS 改 `hidden` 也毫无反应，而 HTML 里
 * 那个 `hidden` 属性明明在。已写进 gotchas。
 */
.td-buybar__pop[hidden] { display: none; }

.td-buybar__pop .td-share__list { flex-direction: column; }
.td-buybar__pop .td-share__link { justify-content: center; }
.td-buybar__cta { flex: none; }

/* 窄屏把缩略图与门店名让出去，保住标题 / 价格 / 按钮 */
@media (max-width: 560px) {
  .td-buybar__inner { padding: var(--td-sp-2) var(--td-sp-3); gap: var(--td-sp-2); }
  .td-buybar__thumb, .td-buybar__store { display: none; }
  body.td-has-buybar { padding-bottom: 68px; }
}

/* ── 19 · 分享一行（[td_share]）──────────────────────────────────────── */
/*
 * 放正文末尾 —— 人是读完了才分享。全是普通链接，不引任何第三方 SDK
 * （引一个等于在每个页面上多一个跟踪源，换来的只是一个按钮）。
 */
.td-share {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--td-sp-3);
  margin-top: var(--td-sp-6); padding-top: var(--td-sp-4);
  border-top: 1px solid var(--td-c-border);
}
.td-share__label { font-size: 13px; font-weight: 650; color: var(--td-c-ink-2); }
.td-share__list { display: flex; flex-wrap: wrap; gap: var(--td-sp-2); list-style: none; margin: 0; padding: 0; }
.td-share__item { display: flex; }
.td-share__link {
  display: inline-flex; align-items: center; height: 30px; padding: 0 12px;
  border: 1px solid var(--td-c-border); border-radius: var(--td-r-full);
  background: var(--td-c-surface); color: var(--td-c-ink-2);
  font-size: 12.5px; font-weight: 600; cursor: pointer; white-space: nowrap;
}
.td-share__link:hover { border-color: var(--td-c-border-strong); color: var(--td-c-ink); }
.td-share__link.td-is-copied { border-color: var(--td-c-good); color: var(--td-c-good); }

/* ── 20 · 博客归档：精选区与文章列表（B1，D37，blog-archive-module.md §1.6）── */
/*
 * 两块都走**容器查询**：`[td_featured_posts]` 通常满宽，但 `ids` 形态会被放进首页的
 * 某一栏；`[td_post_list]` 在有侧栏的模板里是主栏、没侧栏时是满宽（spec §1.6）。
 * 按视口判断的话，主栏 720px、视口 1440px 时永远拿到宽屏版式（第 17 节同一个坑）。
 *
 * 默认写的是**窄**版式，宽版式在 @container 里覆盖 —— 容器查询万一没生效，
 * 退化成的是一列，看得见，不会是挤成一团的五格。
 *
 * 令牌与 .td-post 同一套（D32 ③：共享令牌，不共享选择器）。
 */

/* 精选区 ---------------------------------------------------------------- */

.td-feature {
  container-type: inline-size; container-name: td-feature;
  margin-bottom: var(--td-sp-6);
}
.td-feature__grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--td-sp-4); }
.td-feature__lead, .td-feature__rest { min-width: 0; display: grid; gap: var(--td-sp-4); }

/* 窄：大卡在上，其余一行横向滚动（与第 15 节侧栏的窄屏形态同一路子） */
.td-feature__rest {
  grid-auto-flow: column;
  grid-auto-columns: minmax(220px, 38%);
  overflow-x: auto;
  scroll-snap-type: x proximity;
  padding-bottom: var(--td-sp-2);
}
.td-feature__rest .td-fpost { scroll-snap-align: start; }
/* 2 篇时只剩一张，横滚没有意义 */
.td-feature[data-count="2"] .td-feature__rest { grid-auto-columns: minmax(0, 1fr); overflow-x: visible; }

/* 卡 */
.td-fpost {
  position: relative; min-width: 0;
  display: flex; flex-direction: column;
  background: var(--td-c-surface);
  border: 1px solid var(--td-c-border);
  border-radius: var(--td-r-lg);
  box-shadow: var(--td-shadow-sm);
  overflow: hidden;
  transition: box-shadow .15s, border-color .15s;
}
.td-fpost:hover { box-shadow: var(--td-shadow-md); border-color: var(--td-c-border-strong); }

/*
 * 图框的比例是**下限**，不是定值：宽版式里同一行的格子被拉到一样高，
 * 多出来的高度给图（flex-grow），不给文字下面的空白。图本身 cover 硬裁。
 */
.td-fpost__media {
  position: relative; flex: 1 0 auto;
  aspect-ratio: 4 / 3;
  background: var(--td-c-surface-alt);
}
.td-fpost--hero .td-fpost__media { aspect-ratio: 16 / 9; }
/* `>` 同上：图框里还有视频角标的 SVG 图标，不能被 inset: 0 铺满 */
.td-fpost__media > img, .td-fpost__media > svg {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; display: block;
}

.td-fpost__body {
  min-width: 0; display: flex; flex-direction: column; gap: 6px;
  padding: var(--td-sp-3) var(--td-sp-4) var(--td-sp-4);
}
.td-fpost--hero .td-fpost__body { gap: var(--td-sp-2); padding: var(--td-sp-4) var(--td-sp-5) var(--td-sp-5); }

/* 分类标签叠在铺满卡片的标题链接上面，仍单独可点；只占标签那么宽，旁边的空白仍点得到卡片 */
.td-fpost__kicker { display: flex; align-self: flex-start; position: relative; z-index: 1; }

.td-fpost__title {
  font-size: 15px; font-weight: 650; line-height: 1.3; letter-spacing: -.01em;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.td-fpost--hero .td-fpost__title { font-size: 22px; font-weight: 700; line-height: 1.22; letter-spacing: -.02em; -webkit-line-clamp: 3; }

/* 整张卡可点：标题链接的 ::after 铺满 .td-fpost（它是 position: relative） */
.td-fpost__link::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.td-fpost:hover .td-fpost__link { color: var(--td-c-accent); }
.td-fpost__link:focus-visible { outline: none; }
.td-fpost__link:focus-visible::after { outline: 2px solid var(--td-c-accent); outline-offset: -2px; border-radius: var(--td-r-lg); }

.td-fpost__excerpt {
  font-size: 14px; color: var(--td-c-ink-2); line-height: 1.5;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.td-fpost__meta {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--td-sp-2);
  font-size: 12px; color: var(--td-c-ink-3);
}
.td-fpost__meta .td-sep { color: var(--td-c-border-strong); }

/*
 * 宽：大卡在左，其余在右。大卡占多宽由 --td-feature-lead 定（默认 1.4fr : 1fr；
 * 3 篇时默认 2fr —— 右边只有两格竖排，1.4fr 下每格的图会被压成 3:1 的长条）。
 * 这一行有多高由**大卡**定（16:9 的图 + 文字）；右边的格子平分这个高度，
 * 所以中卡的图在宽版式里不是严格 4:3 —— 严格 4:3 的话右边两排会比大卡高出一截。
 */
@container td-feature (min-width: 900px) {
  .td-feature__grid { grid-template-columns: minmax(0, var(--td-feature-lead, 1.4fr)) minmax(0, 1fr); }
  .td-feature__rest {
    grid-auto-flow: row; grid-auto-columns: auto; grid-auto-rows: minmax(0, 1fr);
    overflow-x: visible; padding-bottom: 0;
  }
  .td-feature__rest .td-fpost--medium .td-fpost__media { flex: 1 1 0; aspect-ratio: auto; min-height: 110px; }

  /* 1：只有大卡 —— 满宽 16:9 太高，改成左图右文 */
  .td-feature[data-count="1"] .td-feature__grid { grid-template-columns: minmax(0, 1fr); }
  .td-feature[data-count="1"] .td-fpost--hero { flex-direction: row; }
  .td-feature[data-count="1"] .td-fpost--hero .td-fpost__media { flex: 0 0 58%; }
  .td-feature[data-count="1"] .td-fpost--hero .td-fpost__body { flex: 1; justify-content: center; padding: var(--td-sp-6) var(--td-sp-8); }
  .td-feature[data-count="1"] .td-fpost--hero .td-fpost__title { font-size: 26px; }

  /* 2：左右各半，两张都是大卡 */
  .td-feature[data-count="2"] .td-feature__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  /* 3：大卡 + 两张竖排 */
  .td-feature[data-count="3"] .td-feature__grid { grid-template-columns: minmax(0, var(--td-feature-lead, 2fr)) minmax(0, 1fr); }
  .td-feature[data-count="3"] .td-feature__rest { grid-template-rows: repeat(2, minmax(0, 1fr)); }

  /* 4：大卡 + 3 张 —— 一栏竖排三张，每张左图右文，否则三排 4:3 会把这一行撑得比大卡高很多 */
  .td-feature[data-count="4"] .td-feature__rest { grid-template-rows: repeat(3, minmax(0, 1fr)); }
  .td-feature[data-count="4"] .td-fpost--medium { flex-direction: row; }
  .td-feature[data-count="4"] .td-fpost--medium .td-fpost__media { flex: 0 0 44%; min-height: 0; }
  .td-feature[data-count="4"] .td-fpost--medium .td-fpost__body { flex: 1; justify-content: center; padding: var(--td-sp-3); }

  /* 5：大卡 + 2×2 */
  .td-feature[data-count="5"] .td-feature__rest {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-rows: repeat(2, minmax(0, 1fr));
  }
}

/* 文章列表 -------------------------------------------------------------- */

.td-postlist { container-type: inline-size; container-name: td-postlist; }
.td-postlist__grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--td-sp-3); }

/* 主栏够宽时 2 栏、卡片改成图在上（td-card 640×480 就是给这个尺寸准备的，§1.7） */
@container td-postlist (min-width: 600px) {
  .td-postlist__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--td-sp-4); }
  .td-postlist .td-post { grid-template-columns: minmax(0, 1fr); gap: var(--td-sp-3) 0; padding: var(--td-sp-3); }
  .td-postlist .td-post__title { font-size: 16px; }
  .td-postlist .td-post__excerpt { font-size: 13.5px; }
}
/* 没有侧栏的满宽模板：3 栏（每页 12 篇，2 与 3 都整除） */
@container td-postlist (min-width: 960px) {
  .td-postlist__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* ── 21 · 文章的视频角标（D38）──────────────────────────────────────── */
/*
 * 叠在图的左上角，不进分类标签那一行（分类说「讲什么」，视频说「什么形式」）。
 * 默认（小缩略图，76–92px 的横卡）只出 ▶；宽的卡出「▶ Video」。文字一直在 DOM 里，
 * 窄时只是视觉上藏起来 —— 读屏在哪都念得到。不是链接：pointer-events 放过去，
 * 精选区的卡上点它等于点整张卡（标题链接的 ::after 在它下面）。
 */
.td-post__thumb { position: relative; }   /* 角标的定位基准；.td-fpost__media 本来就是 relative */

.td-videobadge {
  position: absolute; top: 6px; left: 6px; z-index: 1;
  display: inline-flex; align-items: center; justify-content: center; gap: 4px;
  width: 22px; height: 22px; padding: 0;
  border-radius: var(--td-r-full);
  background: rgba(15, 23, 42, .78); color: var(--td-c-surface);
  box-shadow: 0 1px 3px rgba(15, 23, 42, .3);
  font-size: 11px; font-weight: 650; letter-spacing: .02em; line-height: 1;
  pointer-events: none;
}
/* 三角形的视觉重心偏左，右移 1px 才看着居中 */
.td-videobadge__icon { position: static; width: 10px; height: 10px; flex: none; margin-left: 1px; }
.td-videobadge__text {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* 宽的卡：▶ Video */
.td-fpost .td-videobadge { top: 10px; left: 10px; width: auto; height: 24px; padding: 0 9px 0 7px; }
.td-fpost .td-videobadge__icon { margin-left: 0; }
.td-fpost .td-videobadge__text { position: static; width: auto; height: auto; margin: 0; overflow: visible; clip: auto; }
.td-fpost--hero .td-videobadge { top: 14px; left: 14px; height: 28px; padding: 0 11px 0 9px; font-size: 12.5px; }
.td-fpost--hero .td-videobadge__icon { width: 11px; height: 11px; }

/* 列表两栏时文章卡是竖卡（第 20 节），图够大，同样出文字 */
@container td-postlist (min-width: 600px) {
  .td-postlist .td-videobadge { top: 8px; left: 8px; width: auto; height: 24px; padding: 0 9px 0 7px; }
  .td-postlist .td-videobadge__icon { margin-left: 0; }
  .td-postlist .td-videobadge__text { position: static; width: auto; height: auto; margin: 0; overflow: visible; clip: auto; }
}

/* ── 22 · compact 视图放进窄栏（博客归档 B3，spec §3.1）─────────────── */
/*
 * compact 是按主栏宽度设计的四列（44px 图 · 标题 · 132px 价格 · 展开按钮），
 * 放进 300px 的侧栏（博客页的 Hot deals）标题只剩三十来 px。窄于 340px 时换成
 * 「图 | 标题 / 价格」两行、去掉展开按钮与次级信息。
 *
 * 用容器查询而不是新加一个 view="mini"：它唯一的触发条件就是「放在窄的地方」，
 * 编辑不用记一个新参数，4 种视图共用一份 DOM 的约定（D8）也不破。
 * 340 而不是更宽：手机上的 /deals/ 列表容器约 343px，不该被这条带着变。
 *
 * `.td-deals` 成为容器 = `contain: layout style inline-size`：它里面没有 position: fixed
 * 的东西（购买条在详情页、不在列表里），sticky 也不受影响（见第 17 节的注）。
 */
.td-deals { container-type: inline-size; container-name: td-deals; }

@container td-deals (max-width: 340px) {
  [data-td-view="compact"] .td-deal {
    grid-template-columns: 44px minmax(0, 1fr);
    grid-template-areas: "media body" "media price";
    padding: var(--td-sp-3); gap: 2px var(--td-sp-3);
  }
  [data-td-view="compact"] .td-deal__title { -webkit-line-clamp: 2; font-size: 13.5px; }
  [data-td-view="compact"] .td-deal__facts,
  [data-td-view="compact"] .td-deal__times,
  [data-td-view="compact"] .td-deal__foot { display: none; }
  [data-td-view="compact"] .td-deal__price {
    flex-direction: row; flex-wrap: wrap; align-items: baseline; justify-content: flex-start;
    text-align: left; gap: 2px var(--td-sp-2);
  }
  [data-td-view="compact"] .td-price__block { display: flex; align-items: baseline; gap: 6px; }
  [data-td-view="compact"] .td-price__now { font-size: 16px; }
}

/* ── 23 · 综述（digest，G3；digest-module.md §1.3、§1.4、§1.7）────────── */
/*
 * 逐件点评：[td_deal id]…[/td_deal] 包着的那一句，贴在卡片下面。
 *
 * 卡片的区块（.td-block）自己带上下外边距。包了点评之后由外面的容器接过外边距、
 * 区块在里面不再留 —— 否则点评悬在两张卡正中间，看不出它说的是上面那张。
 * 左边一道竖线而不是引号或底色：它是编辑的一句话，不是引用，也不是另一张卡。
 */
.td-dealnote { margin: var(--td-sp-6) 0; }
.td-dealnote > .td-block { margin: 0; }
.td-dealnote__text {
  margin: var(--td-sp-2) 0 0; padding-left: var(--td-sp-3);
  border-left: 3px solid var(--td-c-border-strong);
  font-size: 14.5px; line-height: 1.55; color: var(--td-c-ink-2);
}
.td-dealnote__text a { color: var(--td-c-info); text-decoration: underline; text-underline-offset: 2px; }

/* 入口页 /digest/ 顶上摊开的最新一期：标题 + 日期一行，下面是卡片，末尾一条链接 */
.td-digest { margin: var(--td-sp-6) 0; }
.td-digest__head {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--td-sp-1) var(--td-sp-3);
  margin-bottom: var(--td-sp-3);
}
.td-digest__title { font-size: 22px; font-weight: 700; letter-spacing: -.01em; line-height: 1.25; }
.td-digest__title a:hover { text-decoration: underline; }
.td-digest__date { font-size: 13px; color: var(--td-c-ink-3); white-space: nowrap; }
.td-digest__more { display: inline-block; margin-top: var(--td-sp-3); font-size: 14px; font-weight: 600; color: var(--td-c-info); }
.td-digest__more:hover { text-decoration: underline; }

/* 旧期顶部的一行提示。info 的调子，不是警告：这一期没出错，只是不是这一周的 */
.td-digestnotice {
  margin: 0 0 var(--td-sp-4); padding: var(--td-sp-3) var(--td-sp-4);
  border: 1px solid var(--td-c-border); border-radius: var(--td-r-md);
  background: var(--td-c-info-bg);
  font-size: 13.5px; line-height: 1.5; color: var(--td-c-ink-2);
}
.td-digestnotice__link { font-weight: 600; color: var(--td-c-info); white-space: nowrap; }
.td-digestnotice__link:hover { text-decoration: underline; }

/* ── 24 · 搜索结果页（S2，D43；search-module.md §1.5）──────────────────── */
/* 标题、搜索框、没搜到时的一句话。Deals 区块与文章列表用的是现成的 .td-block / .td-postlist，这里不重写 */
.td-search-title {
  font-size: 26px; font-weight: 700; letter-spacing: -.015em; line-height: 1.2;
  margin: 0 0 var(--td-sp-4);
  overflow-wrap: anywhere;      /* 搜索词是读者打的：一长串不带空格的字也不能把页面撑破 */
}
.td-search { display: flex; gap: var(--td-sp-2); align-items: stretch; max-width: 560px; margin: 0 0 var(--td-sp-6); }
.td-search__field { display: block; flex: 1 1 auto; min-width: 0; }
/* 标签只给读屏：移出视口而不是 display:none（同 .td-watch__hp 的做法） */
.td-search__label { position: absolute; left: -10000px; top: auto; width: 1px; height: 1px; overflow: hidden; }
.td-search__input {
  font: inherit; font-size: 15px; width: 100%; height: 40px;
  padding: 0 var(--td-sp-3);
  border: 1px solid var(--td-c-border-strong); border-radius: var(--td-r-md);
  background: var(--td-c-surface); color: var(--td-c-ink);
}
.td-search__btn {
  font: inherit; font-size: 14px; font-weight: 650; height: 40px;
  padding: 0 var(--td-sp-4);
  border: 0; border-radius: var(--td-r-md);
  background: var(--td-c-accent); color: var(--td-c-accent-ink); cursor: pointer; white-space: nowrap;
}
.td-search__btn:hover { background: var(--td-c-accent-dark); }

/* 顶替文章列表的一句话 + 两个出口。外框是 .td-empty，出口是 .td-btn */
.td-search-note { margin: var(--td-sp-6) 0; }
.td-search-note p { overflow-wrap: anywhere; }
.td-search-note p.td-search-note__exits {
  display: flex; flex-wrap: wrap; justify-content: center; gap: var(--td-sp-2);
  margin-bottom: 0;
}

/* ── 25 · newsletter 的订阅表单（[td_newsletter]，N2；newsletter-module.md §4.1）──── */
/*
 * 措辞三段（标题 / 说明 / 按钮上的字）逐字来自 Consent::TEXTS，这里只管样子。没有复选框：按下按钮就是同意。
 * 放页脚与综述页，一页上可以有两个：不定宽度，跟着所在的栏走；邮箱与按钮并排，栏窄了就各占一行。
 * 蜜罐与 .td-watch__hp 同一个做法：移出视口而不是 display:none，也不给它设 display。
 */
.td-newsletter {
  border: 1px solid var(--td-c-border);
  border-radius: var(--td-r-md);
  background: var(--td-c-surface-alt);
  padding: var(--td-sp-4);
  margin-bottom: var(--td-sp-4);
  position: relative;
}
.td-newsletter__set { border: 0; margin: 0; padding: 0; min-width: 0; }
.td-newsletter__legend { font-size: 15px; font-weight: 650; color: var(--td-c-ink); padding: 0; margin-bottom: var(--td-sp-2); }
.td-newsletter__desc { font-size: 13px; line-height: 1.5; color: var(--td-c-ink-3); margin-bottom: var(--td-sp-3); }
.td-newsletter__row { display: flex; flex-wrap: wrap; gap: var(--td-sp-2); align-items: flex-end; }
.td-newsletter__field { display: block; flex: 1 1 220px; min-width: 0; max-width: 360px; }
.td-newsletter__label { display: block; font-size: 13px; font-weight: 600; color: var(--td-c-ink); margin-bottom: var(--td-sp-1); }
.td-newsletter__input {
  font: inherit; font-size: 15px; width: 100%; height: 40px;
  padding: 0 var(--td-sp-3);
  border: 1px solid var(--td-c-border); border-radius: var(--td-r-sm);
  background: var(--td-c-surface); color: var(--td-c-ink);
}
.td-newsletter__hp { position: absolute; left: -10000px; top: auto; width: 1px; height: 1px; overflow: hidden; }
.td-newsletter__btn {
  font: inherit; font-size: 14px; font-weight: 650; height: 40px;
  padding: 0 var(--td-sp-4);
  border: 0; border-radius: var(--td-r-sm);
  background: var(--td-c-info); color: #fff; cursor: pointer; white-space: nowrap;
}
.td-newsletter__btn:hover { filter: brightness(1.08); }
