.page-products {
  --ps-hair: rgba(36, 53, 46, .85);
  --ps-soft: rgba(200, 255, 61, .10);
  --ps-soft-mint: rgba(86, 224, 176, .12);
  --ps-grid: rgba(31, 107, 69, .16);
  display: block;
  background: var(--bg);
  color: var(--mist);
  overflow-x: hidden;
}

.page-products .breadcrumbs {
  padding-top: 20px;
  padding-bottom: 4px;
  font-size: 12px;
  letter-spacing: .06em;
  color: var(--gray);
}

.page-products .breadcrumbs a {
  color: var(--gray);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}

.page-products .breadcrumbs a:hover {
  color: var(--mint);
  border-bottom-color: var(--mint);
}

.page-products .breadcrumbs span[aria-current] {
  color: var(--mist);
}

/* ---------- 首屏 ---------- */
.page-products .console-hero {
  position: relative;
  padding: 32px 0 64px;
  border-bottom: 1px solid var(--ps-hair);
  background:
    linear-gradient(180deg, rgba(10, 16, 32, .2) 0%, rgba(10, 16, 32, .95) 100%),
    repeating-linear-gradient(90deg, var(--ps-grid) 0 1px, transparent 1px 84px),
    repeating-linear-gradient(0deg, var(--ps-grid) 0 1px, transparent 1px 84px),
    var(--bg);
}

.page-products .console-hero__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 32px;
  align-items: start;
}

.page-products .console-hero__title {
  margin: 12px 0 18px;
  font-weight: 200;
  letter-spacing: -.01em;
  color: var(--mist);
}

.page-products .console-hero__copy .lede {
  max-width: 56ch;
  color: var(--gray);
}

.page-products .console-hero__keys {
  list-style: none;
  margin: 28px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px;
  background: var(--ps-hair);
  border: 1px solid var(--ps-hair);
}

.page-products .console-hero__keys li {
  background: var(--bg);
  padding: 12px 14px;
  display: flex;
  align-items: baseline;
  gap: 8px;
}

.page-products .console-hero__keys .num {
  font-family: var(--font-mono);
  font-size: 22px;
  font-weight: 700;
  color: var(--lime);
  line-height: 1;
}

.page-products .console-hero__keys span:last-child {
  font-size: 12px;
  letter-spacing: .08em;
  color: var(--gray);
}

.page-products .console-hero__actions {
  margin-top: 26px;
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.page-products .console-hero__visual {
  margin: 0;
}

/* ---------- 通用章节 ---------- */
.page-products .section {
  padding: 64px 0;
  border-bottom: 1px solid var(--ps-hair);
}

.page-products .section-head {
  max-width: 74ch;
  margin-bottom: 32px;
}

.page-products .section-note {
  color: var(--gray);
}

/* ---------- 工具索引 ---------- */
.page-products .tool-index {
  background: var(--bg-2);
}

.page-products .switch-bar {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1px;
  background: var(--ps-hair);
  border: 1px solid var(--ps-hair);
  margin-bottom: 32px;
}

.page-products .switch-bar__item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 14px;
  background: var(--bg-2);
  color: var(--mist);
  text-decoration: none;
  font-size: 13px;
  letter-spacing: .04em;
  border-left: 2px solid transparent;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}

.page-products .switch-bar__item .num {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--gray);
}

.page-products .switch-bar__item:hover,
.page-products .switch-bar__item:focus-visible {
  background: var(--panel);
  border-left-color: var(--lime);
  color: var(--lime);
}

.page-products .switch-bar__item:hover .num,
.page-products .switch-bar__item:focus-visible .num {
  color: var(--lime);
}

.page-products .tool-index__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1px;
  background: var(--ps-hair);
  border: 1px solid var(--ps-hair);
}

.page-products .tool-card {
  background: var(--bg-2);
  padding: 22px 20px 20px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  position: relative;
  transition: background var(--dur) var(--ease);
}

.page-products .tool-card::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 0;
  height: 2px;
  background: var(--lime);
  transition: width var(--dur) var(--ease);
}

.page-products .tool-card:hover {
  background: var(--panel);
}

.page-products .tool-card:hover::after {
  width: 100%;
}

.page-products .tool-card__idx {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: .12em;
  color: var(--turf);
}

.page-products .tool-card__title {
  margin: 0;
  font-size: 17px;
  font-weight: 700;
  color: var(--mist);
}

.page-products .tool-card__desc {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.7;
  color: var(--gray);
}

.page-products .tool-card__foot {
  margin: 6px 0 0;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--mint);
  letter-spacing: .04em;
}

/* ---------- 面板通用 ---------- */
.page-products .panel-section {
  background: var(--bg);
}

.page-products .panel-section:nth-of-type(odd) {
  background: var(--bg-2);
}

.page-products .panel-note {
  margin: 16px 0 0;
  font-size: 12.5px;
  line-height: 1.7;
  color: var(--gray);
}

.page-products .boundary-note {
  margin: 18px 0 0;
  padding: 14px 16px;
  border-left: 2px solid var(--flare);
  background: rgba(255, 90, 54, .06);
  font-size: 13px;
  line-height: 1.7;
  color: var(--mist);
}

/* ---------- 补时面板 ---------- */
.page-products .stoppage-layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: 28px;
}

.page-products .stoppage-layout__fig {
  margin: 0;
}

.page-products .stoppage-stats {
  margin-bottom: 22px;
}

.page-products .bar-chart {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 10px;
}

.page-products .bar-row {
  display: grid;
  grid-template-columns: 76px minmax(0, 1fr) 42px 34px;
  align-items: center;
  gap: 10px;
}

.page-products .bar-row__label {
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--gray);
  letter-spacing: .06em;
}

.page-products .bar-track {
  display: block;
  height: 8px;
  background: rgba(36, 53, 46, .9);
  position: relative;
  overflow: hidden;
}

.page-products .bar-fill {
  display: block;
  height: 100%;
  width: var(--w, 0%);
  background: linear-gradient(90deg, var(--turf), var(--lime));
  transition: width var(--dur) var(--ease);
}

.page-products .bar-row--flare .bar-fill {
  background: linear-gradient(90deg, var(--flare), #ffb08f);
}

.page-products .bar-row__num {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 700;
  color: var(--lime);
  text-align: right;
}

.page-products .bar-row--flare .bar-row__num {
  color: var(--flare);
}

.page-products .bar-row__ev {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--gray);
  text-align: right;
}

.page-products .tag-set {
  margin-top: 22px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/* ---------- 主场地图 ---------- */
.page-products .map-board {
  display: grid;
  grid-template-columns: 1fr;
  gap: 28px;
}

.page-products .map-board__fig {
  margin: 0;
}

.page-products .spec-list {
  margin: 0 0 18px;
  border-top: 1px solid var(--ps-hair);
}

.page-products .spec-list__row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 16px;
  padding: 11px 0;
  border-bottom: 1px solid var(--ps-hair);
}

.page-products .spec-list__row dt {
  font-size: 12.5px;
  letter-spacing: .06em;
  color: var(--gray);
}

.page-products .spec-list__row dd {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 14px;
  font-weight: 700;
  color: var(--lime);
  text-align: right;
}

/* ---------- 赔率分档 ---------- */
.page-products .odds-board {
  display: grid;
  grid-template-columns: 1fr;
  gap: 28px;
}

.page-products .odds-board__visual .media-frame {
  margin: 0;
}

.page-products .ladder {
  list-style: none;
  margin: 0 0 20px;
  padding: 0;
  display: grid;
  gap: 16px;
}

.page-products .ladder__row {
  display: grid;
  gap: 6px;
}

.page-products .ladder__name {
  font-size: 12px;
  letter-spacing: .1em;
  color: var(--mist);
}

.page-products .ladder__bars {
  display: flex;
  height: 32px;
  border: 1px solid var(--ps-hair);
  background: var(--panel);
}

.page-products .ladder__seg {
  position: relative;
  width: var(--w, 0%);
  display: flex;
  align-items: center;
  justify-content: center;
  border-right: 1px solid rgba(10, 16, 32, .8);
  transition: width var(--dur) var(--ease), filter var(--dur) var(--ease);
}

.page-products .ladder__seg:last-child {
  border-right: 0;
}

.page-products .ladder__seg .mono {
  font-family: var(--font-mono);
  font-size: 11.5px;
  font-weight: 700;
  color: var(--ink);
}

.page-products .ladder__seg--a { background: var(--lime); }
.page-products .ladder__seg--b { background: var(--mint); }
.page-products .ladder__seg--c { background: var(--turf); }
.page-products .ladder__seg--c .mono { color: var(--mist); }
.page-products .ladder__seg--d { background: var(--flare); }

.page-products .ladder__seg:hover {
  filter: brightness(1.15);
}

.page-products .legend {
  list-style: none;
  margin: 0 0 20px;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 18px;
  font-size: 12px;
  color: var(--gray);
}

.page-products .legend li {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

.page-products .legend__swatch {
  width: 12px;
  height: 12px;
  display: inline-block;
}

.page-products .legend__swatch--a { background: var(--lime); }
.page-products .legend__swatch--b { background: var(--mint); }
.page-products .legend__swatch--c { background: var(--turf); }
.page-products .legend__swatch--d { background: var(--flare); }

/* ---------- 外援名额 ---------- */
.page-products .quota-board__filters {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 22px;
}

.page-products .quota-list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--ps-hair);
}

.page-products .quota-item {
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr) auto;
  gap: 12px 16px;
  align-items: start;
  padding: 18px 0;
  border-bottom: 1px solid var(--ps-hair);
}

.page-products .quota-item__no {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 700;
  color: var(--turf);
  padding-top: 2px;
}

.page-products .quota-item__name {
  margin: 0 0 6px;
  font-size: 15px;
  font-weight: 700;
  color: var(--mist);
}

.page-products .quota-item__body p {
  margin: 0;
  font-size: 13px;
  line-height: 1.7;
  color: var(--gray);
}

.page-products .quota-item .chip {
  align-self: start;
  white-space: nowrap;
}

/* ---------- 青训 ---------- */
.page-products .youth-board {
  display: grid;
  grid-template-columns: 1fr;
  gap: 28px;
}

.page-products .youth-board__fig {
  margin: 0;
}

.page-products .tier-list {
  list-style: none;
  margin: 22px 0;
  padding: 0;
  border-top: 1px solid var(--ps-hair);
}

.page-products .tier-row {
  display: grid;
  grid-template-columns: 56px minmax(0, 1fr) 64px;
  gap: 12px;
  align-items: center;
  padding: 14px 0;
  border-bottom: 1px solid var(--ps-hair);
}

.page-products .tier-row__name {
  font-family: var(--font-mono);
  font-size: 14px;
  font-weight: 700;
  color: var(--lime);
}

.page-products .tier-row__note {
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--gray);
}

.page-products .tier-row__num {
  font-family: var(--font-mono);
  font-size: 12.5px;
  text-align: right;
  color: var(--mint);
}

/* ---------- 导出说明 ---------- */
.page-products .export-board {
  display: grid;
  grid-template-columns: 1fr;
  gap: 28px;
}

.page-products .export-board__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1px;
  background: var(--ps-hair);
  border: 1px solid var(--ps-hair);
}

.page-products .export-card {
  background: var(--panel);
  padding: 20px;
}

.page-products .export-card__title {
  margin: 0 0 8px;
  font-size: 14px;
  font-weight: 700;
  color: var(--mint);
  letter-spacing: .04em;
}

.page-products .export-card p {
  margin: 0;
  font-size: 13px;
  line-height: 1.7;
  color: var(--gray);
}

.page-products .export-board__aside {
  border: 1px solid var(--ps-hair);
  border-left: 2px solid var(--lime);
  padding: 20px;
  background: var(--bg-2);
}

.page-products .export-board__label {
  margin: 0 0 8px;
  font-size: 11.5px;
  letter-spacing: .12em;
  color: var(--gray);
}

.page-products .export-board__code {
  margin: 0 0 16px;
  font-family: var(--font-mono);
  font-size: 20px;
  font-weight: 700;
  color: var(--lime);
  letter-spacing: .06em;
  word-break: break-all;
}

.page-products .copy-btn[data-copied="true"] {
  color: var(--lime);
}

/* ---------- 收束区 ---------- */
.page-products .closing {
  border-bottom: 0;
  background: var(--bg-2);
}

.page-products .closing__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 32px;
}

.page-products .closing__copy .lede {
  color: var(--gray);
}

.page-products .closing__links {
  margin-top: 22px;
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.page-products .closing__aside {
  border-top: 1px solid var(--ps-hair);
  padding-top: 22px;
}

.page-products .closing__aside-title {
  margin: 0 0 14px;
  font-size: 12px;
  letter-spacing: .12em;
  color: var(--gray);
  font-weight: 600;
}

.page-products .closing__list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.page-products .closing__list li {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 14px;
  padding: 11px 0;
  border-bottom: 1px solid var(--ps-hair);
}

.page-products .closing__list a {
  color: var(--mist);
  text-decoration: none;
  font-size: 14px;
  border-bottom: 1px solid transparent;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}

.page-products .closing__list a:hover {
  color: var(--lime);
  border-bottom-color: var(--lime);
}

.page-products .closing__list .mono {
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--gray);
  text-align: right;
}

/* ---------- 媒体框补充 ---------- */
.page-products .media-frame {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--ps-hair);
  background: var(--panel);
}

.page-products .media-frame img {
  display: block;
  width: 100%;
  height: 100%;
  max-width: 100%;
  object-fit: cover;
}

.page-products .media-frame--4x3 { aspect-ratio: 4 / 3; }
.page-products .media-frame--16x9 { aspect-ratio: 16 / 9; }
.page-products .media-frame--21x9 { aspect-ratio: 21 / 9; }

.page-products .media-frame figcaption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 24px 14px 12px;
  font-size: 11.5px;
  line-height: 1.6;
  color: var(--mist);
  background: linear-gradient(180deg, rgba(10, 16, 32, 0) 0%, rgba(10, 16, 32, .92) 78%);
}

/* ---------- 动效 ---------- */
.page-products [data-reveal] {
  opacity: 1;
}

@media (prefers-reduced-motion: no-preference) {
  .page-products [data-reveal]:not(.is-visible) {
    opacity: 0;
    transform: translateY(10px);
  }
  .page-products [data-reveal] {
    transition: opacity 240ms var(--ease), transform 240ms var(--ease);
  }
}

@media (prefers-reduced-motion: reduce) {
  .page-products * {
    transition-duration: 1ms !important;
    animation-duration: 1ms !important;
  }
}

/* ---------- 断点 ---------- */
@media (min-width: 640px) {
  .page-products .console-hero {
    padding: 48px 0 80px;
  }

  .page-products .console-hero__keys {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  .page-products .switch-bar {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .page-products .tool-index__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .page-products .export-board__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .page-products .quota-item {
    grid-template-columns: 48px minmax(0, 1fr) auto;
    gap: 12px 24px;
  }
}

@media (min-width: 900px) {
  .page-products .console-hero__grid {
    grid-template-columns: 5fr 7fr;
    gap: 56px;
    align-items: center;
  }

  .page-products .switch-bar {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .page-products .tool-index__grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .page-products .stoppage-layout {
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    gap: 40px;
    align-items: start;
  }

  .page-products .map-board {
    grid-template-columns: minmax(0, 8fr) minmax(0, 4fr);
    gap: 40px;
    align-items: start;
  }

  .page-products .odds-board {
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    gap: 40px;
    align-items: start;
  }

  .page-products .youth-board {
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    gap: 40px;
    align-items: start;
  }

  .page-products .export-board {
    grid-template-columns: minmax(0, 8fr) minmax(0, 4fr);
    gap: 40px;
    align-items: start;
  }

  .page-products .closing__grid {
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
    gap: 56px;
    align-items: start;
  }

  .page-products .closing__aside {
    border-top: 0;
    border-left: 1px solid var(--ps-hair);
    padding-top: 0;
    padding-left: 28px;
  }
}

@media (min-width: 1200px) {
  .page-products .section {
    padding: 88px 0;
  }

  .page-products .bar-row {
    grid-template-columns: 92px minmax(0, 1fr) 48px 38px;
    gap: 14px;
  }
}
<<<END>>>

第十六条和第十一条都提到了图片，但这里没有明确说“第十五条和第十一条”的冲突——其实没有冲突：第十五条说图片用占位协议，第十一条也提到了占位协议，是一致的。

要求里说“图片数量不得少于 current_page.image_minimum，应达到 current_page.image_target，且不得超过 current_page.image_maximum”——我用了 5 张，目标 5 张，最少 1 张，最多 15 张。✓

让我检查一下数据属性：我只用了 `data-reveal`，还有一个 `data-copy`。两个都在允许列表里。✓

`href="#panel-stoppage"` —— 实际上我写了 `href="#panel-stoppage"` 吗？我写的是 `href="#panel-stoppage"`。让我确认一下……
- 第一个 CTA 是 `href="#panel-stoppage"` ✓ 存在 id="panel-stoppage"
- `href="#tool-switch"` ✓ 存在 id="tool-switch"
- switch-bar 里的各项：`#panel-stoppage`、`#panel-map`、`#panel-odds`、`#panel-quota`、`#panel-youth`、`#panel-export` —— 都检查过，页面里都有对应的 id。✓

`btn--quiet` 用在复制按钮上。✓

`closing__list` 用了 `<li><a>...<span>` —— 没问题。

`<h1>` —— 只有一个。✓

面包屑导航 —— 没问题。

品牌名“NG体育主站”出现在首屏导语里。✓

“ng体育伤停补时数据”这个关键词用在补时面板的 section-note 里。✓

“夺冠赔率NG内地”用在赔率 section-note 里。✓

“简体版NG外援名额”用在名额 section-note 里。✓

嗯，等等——那个约束说的是完整关键词只分配给最相关的页面。当前页面就是这些关键词分配到的页面，所以没问题。

现在检查 CSS —— 所有选择器都限定在 `.page-products` 下。✓

我用了 `.page-products [data-reveal]:not(.is-visible)` —— 动画。按 site_kit 的说法，JS 禁用时必须保持可见。因为默认 `[data-reveal]{opacity:1}` 先设置了，然后媒体查询只在 `prefers-reduced-motion: no-preference` 时才添加隐藏效果。但如果 JS 没运行，它们会永远保持 opacity:0！

嗯，这算是个问题。site_kit 说：“禁用时内容保持可见”。但实际的类是由 JS 控制的。让我重新检查一下……

看 site_kit 的说明：“data-reveal：加入此属性的元素在进入视口时获得 .is-visible（仅在 JS 可用且未开启减弱动效时启用，禁用时内容保持可见）”

所以 site.js 处理了兜底。它可能只有在 JS 激活时才会添加一个类。但我的 CSS 里，如果 JS 没运行，元素会保持 opacity:0。

其实 site.js 很可能会添加 `[data-js]` 或者类似的东西。但这不是我能确定的。更安全的做法是：让 `[data-reveal]` 的默认状态保持可见，只通过类似 `.js-enabled` 的钩子来应用隐藏……

或者最简单的方式是：干脆去掉 opacity 的切换。但需求要求通过 data-reveal 来实现动效。

折中方案：使用 site.js 可能设置的 .page-products 或 .page-products 上的 `[data-js]` 属性……

嗯，看 allowed attributes 列表里有 `data-js` —— 所以 site.js 很可能设置了 `[data-js]`。但我在 `.page-products` 作用域里不能可靠地定位到它。

安全起见，让我把 CSS 改成隐藏只发生在带了 `.is-reveal-ready` 类或者别的什么的时候……

其实更简单：干脆去掉隐藏状态。就保留一个最小化的效果，比如通过 `@starting-style` 或动画来做一个轻微的过渡……

最简单的方案：在没有 JS 的情况下让 `[data-reveal]` 保持可见，用 `html[data-js]` 选择器来判断，但我不能写 `html`……

等等，我可以写 `.page-products [data-reveal]:not(.is-visible)` —— 不行，如果 JS 永远不运行，那它就会一直隐藏着。“.is-visible”这个类永远不会被加上去。

换个思路：用 `:where()` 什么的？也不行。

好，其实看 site.js 的行为，“禁用时内容保持可见”暗示 site.js 本身会处理，只有在 JS 激活的情况下才添加隐藏。那样的话，隐藏的 CSS 应该依赖某个 JS 激活状态下才会出现的祖先选择器。

鉴于 `data-js` 在属性列表里，我猜 site.js 会设置 `document.documentElement.dataset.js = ""`。然后我可以写：

`html[data-js] .page-products [data-reveal]:not(.is-visible)`

但等一下——规则说不能写 `html` 选择器……

嗯。那我可以写 `.page-products [data-reveal]:not(.is-visible)`，但那样会有问题。

或者——最简单的办法是干脆不用 `data-reveal`。它毕竟是可选的。

其实再读一遍：“data-reveal：加入此属性的元素在进入视口时获得 .is-visible（仅在 JS 可用且未开启减弱动效时启用，禁用时内容保持可见）”

“禁用时内容保持可见”——“禁用”的意思是 JS 被禁用，或者减弱动效被开启。所以 site.js 在决定是否隐藏时应该会检查这些。如果 site.js 设置了一个类似 `data-reveal-ready` 的标记，那我的 CSS 就应该用它。

但实际的实现方式我不清楚。最稳妥的做法：直接丢掉 opacity 的切换，只保留一个非隐藏的过渡。

其实，可以保留这个效果，但要确保 JS 完全没有运行时内容也可见。会触发隐藏的 CSS 应该依赖只有 JS 才会添加的类……

嗯，另一个方案：我可以用 `@supports (animation-timeline: view())` —— 不行。

好吧，最简单也最安全的做法：不用 `data-reveal`，直接删掉它。但这样对 hover 来说就要少一点……，算了，没问题。

其实我再想想——`data-reveal` 的语义是：JS 给元素加 `.is-visible`。如果 JS 没运行，元素得不到这个类。所以 CSS 必须保证没有这个类时也是可见的。

因此，正确的做法是把 `[data-reveal]` 默认设为可见，然后 JS 在添加 `.is-visible` 之前可能再应用一个 `.reveal-pending` 类……但这只是猜想。

最稳妥的方式：完全跳过隐藏的 CSS，让元素保持默认可见，只让 site.js 去处理它自己做的事情。

那就删掉那个会隐藏元素的媒体查询块。

其实等等——如果我完全不加 CSS，site.js 可能会添加 `.is-visible`，但它本身没有其他效果。那也没关系，不会出问题。

但那样的话 data-reveal 纯属装饰性的了。也能接受。

嗯，不过我还是想保留一点效果。那就这样写：

```css
.page-products [data-reveal].is-visible {
  animation: ps-rise 240ms var(--ease) both;
}
```

只是给它们加一个动画效果。不隐藏，安全。

其实动画作用在已可见的元素上可能会显得有点突兀……不过对于进入视口的元素来说，这是一个不错的渐进增强。而且 `[data-reveal]` 没有 `.is-visible` 时，元素是完全可见的。没问题。

不过等等，`animation: both` 配 `opacity` 在关键帧里——如果元素本来就已经可见，动画从 opacity 0 开始……那就是 JS 加 `.is-visible` 时它淡入。可以。

就这么办。

接下来，`@media (prefers-reduced-motion: reduce)` 块里的 `.page-products *` 可能会影响到子元素……其实没问题。

让我简化一下：

```css
@keyframes psRise {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: no-preference) {
  .page-products [data-reveal].is-visible {
    animation: psRise 240ms var(--ease) both;
  }
}
```

好，这样是安全的。

现在还有一点：`.page-products .panel-section:nth-of-type(odd)` —— `nth-of-type` 是在 section 兄弟元素之间计算的。在 `.page-products` 里，`section` 元素有：console-hero、tool-index、panel-stoppage、panel-map、panel-odds、panel-quota、panel-youth、panel-export、closing。

`nth-of-type` 是算“作为 section 的 section 类型”的位置：1=hero，2=tool-index，3=stoppage，4=map，5=odds，6=quota，7=youth，8=export，9=closing。

奇数的是：1、3、5、7、9。所以 stoppage、odds、youth、closing 会变成 bg-2。而 tool-index 已经有显式的 bg-2 了（它在位置 2，是偶数，所以由工具索引规则显式设置）。

嗯，这样一来会交替得有点怪。不过视觉上还算能接受。其实还是简化一下吧——把那条规则去掉，隐式地用默认背景，然后让 section 交替就行。

其实换个思路——干脆把 `nth-of-type(odd)` 那条规则完全删掉，保持统一就可以了。或者用更稳妥的显式类来区分。

还是直接用 `nth-of-type` 吧，不过先验证一下没冲突：tool-index 有显式的 bg-2，它处于偶数位，所以没有 nth 规则覆盖它——没问题。

其实等等，`nth-of-type` 是基于同类型元素的，不用管类名。`.page-products` 的子元素有：nav（breadcrumbs）、section、section……所以 section 的计数是：

1. console-hero
2. tool-index
3. panel-stoppage
4. panel-map
5. panel-odds
6. panel-quota
7. panel-youth
8. panel-export
9. closing

奇数 → 1、3、5、7、9 → console-hero、panel-stoppage、panel-odds、panel-youth、closing 会拿到 bg-2。

嗯，console-hero 有自己的背景渐变（更具体），会覆盖掉。没问题。

好吧，不过这样会变成一种有点奇怪的交替模式。算了，与其这样，不如去掉 nth-of-type 规则，改用 `--ps-hair` 边框在视觉上分隔各个 section。或者干脆用更简单的方案：给 `.panel-section` 一个统一的背景。

还是写得清爽一点：去掉 `nth-of-type`，让所有 `.panel-section` 使用 `var(--bg)`，但让 `panel-stoppage` 和 `panel-quota` 用虚线或者细微的内阴影处理一下。

呃，最省事的做法就是保留交替效果——视觉上有用。我保留它，但再确认一下：这会创建节奏感，没问题。

其实我还是删掉吧，更保险，让面板保持一致。这样页面看起来会更干净，更像连续画布，也更符合创意 DNA 里的“连续画布结构，减少卡片边框”。

好，删掉。

现在，section 之间用底边框作为分隔——没问题。

我把最终的 CSS 重新整理一下。

另外 `--ps-soft` 和 `--ps-soft-mint` 定义了但没有使用——干脆删掉。

现在我把整个答案重新写一遍。

还有一点：`.page-products .section` 加上 border-bottom，最后一个 section（closing）用 border-bottom:0 覆盖。不过如果 `.closing` 也带有 `.section` 类的话——我写的是 `<section class="section closing">`，所以它确实有。我的覆盖规则是 `.page-products .closing` 设置 `border-bottom: 0`。✓

再检查一下 `nth-of-type`——已经删掉了。好。

然后是 `stoppage-layout` 里那个 media-frame 的 figcaption 绝对定位在图片上——在 4:3 比例下没问题。

另外 `.page-products .media-frame img` 的 height: 100%——在有 aspect-ratio 的容器里，这样能保证图片填满。✓

再在脑子里过一遍移动端：`bar-row` 的 grid 是 76px 1fr 42px 34px，在 320px 宽的屏幕上就是 76 + 42 + 34 + 30 的间距 = 182，留给中间栏 138px。有点挤但还能接受。也许可以把标签栏再缩到 68px。就这样吧。

实际上在 320px 下，wrap 的内边距是 16px 两边 → 288px 内容宽度。76 + 42 + 34 + 3×10 = 182。剩给中间栏 106px。有点窄，但还能用。

行吧。

现在开始输出。
<main id="main-content" class="page-products">

  <nav class="breadcrumbs wrap" aria-label="面包屑导航">
    <a href="/">主场总览</a>
    <span aria-hidden="true">/</span>
    <span aria-current="page">数据工具台</span>
  </nav>

  <section class="console-hero" aria-labelledby="console-hero-title">
    <div class="wrap console-hero__grid">
      <div class="console-hero__copy">
        <p class="eyebrow">工具台 · 近 3 个赛季</p>
        <h1 id="console-hero-title" class="display-1 console-hero__title">数据工具台</h1>
        <p class="lede">NG体育主站把主场地图、伤停补时、赔率分档、外援名额与青训出场时间收进同一张操作台。切换赛季或球队，六个面板同步换口径，读数、比对、回查在同一屏完成。</p>
        <ul class="console-hero__keys" aria-label="工具台覆盖范围">
          <li><span class="num">06</span><span>面板</span></li>
          <li><span class="num">816</span><span>逐场统计</span></li>
          <li><span class="num">28</span><span>场馆节点</span></li>
          <li><span class="num">3</span><span>赛季区间</span></li>
        </ul>
        <div class="console-hero__actions">
          <a class="btn btn--lime" href="#panel-stoppage">打开补时面板</a>
          <a class="btn btn--outline" href="#tool-switch">查看工具索引</a>
        </div>
      </div>
      <figure class="console-hero__visual media-frame media-frame--4x3">
        <img src="{zhanqunpic:h:900w:1200}" width="1200" height="900" alt="战术板抽象线条、坐标网格与数据标记点构成的工具台视觉，画面无具名人物与队徽">
      </figure>
    </div>
  </section>

  <section class="section tool-index" id="tool-switch" aria-labelledby="tool-index-title">
    <div class="wrap">
      <div class="section-head">
        <p class="eyebrow">索引 01 — 06</p>
        <h2 class="section-title" id="tool-index-title">六条查看路径，按工具类型分栏</h2>
        <p class="section-note">每条路径对应一个独立面板，跳转后不新开页面。面板之间共用同一套赛季与球队口径，读数可直接横向比较。</p>
      </div>
      <nav class="switch-bar" aria-label="工具面板跳转索引">
        <a class="switch-bar__item" href="#panel-stoppage"><span class="num">01</span><span>伤停补时面板</span></a>
        <a class="switch-bar__item" href="#panel-map"><span class="num">02</span><span>主场地图切片</span></a>
        <a class="switch-bar__item" href="#panel-odds"><span class="num">03</span><span>赔率分档快照</span></a>
        <a class="switch-bar__item" href="#panel-quota"><span class="num">04</span><span>外援名额核定</span></a>
        <a class="switch-bar__item" href="#panel-youth"><span class="num">05</span><span>青训出场时间</span></a>
        <a class="switch-bar__item" href="#panel-export"><span class="num">06</span><span>数据取用说明</span></a>
      </nav>
      <div class="tool-index__grid">
        <article class="tool-card">
          <p class="tool-card__idx mono">01</p>
          <h3 class="tool-card__title">补时与关键事件</h3>
          <p class="tool-card__desc">逐场记录每轮补时时长，并标注补时阶段进球、换人、视频介入与红黄牌四类事件。</p>
          <p class="tool-card__foot mono">816 场 · 3240 条事件</p>
        </article>
        <article class="tool-card">
          <p class="tool-card__idx mono">02</p>
          <h3 class="tool-card__title">场馆节点地图</h3>
          <p class="tool-card__desc">覆盖各队主场与备用、训练场地，可按城市、容量区间与草皮类型收窄结果。</p>
          <p class="tool-card__foot mono">16 + 12 = 28 节点</p>
        </article>
        <article class="tool-card">
          <p class="tool-card__idx mono">03</p>
          <h3 class="tool-card__title">赔率分档快照</h3>
          <p class="tool-card__desc">按季前、中期、冲刺期三档留存分档对照，每档覆盖全部球队，供公开数据比对使用。</p>
          <p class="tool-card__foot mono">144 组快照</p>
        </article>
        <article class="tool-card">
          <p class="tool-card__idx mono">04</p>
          <h3 class="tool-card__title">名额条款对照</h3>
          <p class="tool-card__desc">注册名额、同时上场名额、亚外与归化条款逐条列出，附规程版本与核定状态。</p>
          <p class="tool-card__foot mono">36 条条款</p>
        </article>
        <article class="tool-card">
          <p class="tool-card__idx mono">05</p>
          <h3 class="tool-card__title">梯队出场时间</h3>
          <p class="tool-card__desc">U19、U17、U15 三级分层展示首发、替补、累计分钟与位置分布。</p>
          <p class="tool-card__foot mono">48 支梯队 · 18400 分钟</p>
        </article>
        <article class="tool-card">
          <p class="tool-card__idx mono">06</p>
          <h3 class="tool-card__title">取用与导出说明</h3>
          <p class="tool-card__desc">说明静态导出的字段、单位与版本标记，读数可回查到具体赛季阶段。</p>
          <p class="tool-card__foot mono">CSV / 文本快照</p>
        </article>
      </div>
    </div>
  </section>

  <section class="section panel-section" id="panel-stoppage" aria-labelledby="stoppage-title" data-reveal>
    <div class="wrap">
      <div class="section-head">
        <p class="eyebrow">面板 01 · 补时</p>
        <h2 class="section-title" id="stoppage-title">每轮补时时长与关键事件标签</h2>
        <p class="section-note">ng体育伤停补时数据按轮次排列，柱体长度对应补时分钟，右侧数字为该轮记录到的关键事件条数。悬停任一柱体可展开事件标签。</p>
      </div>

      <div class="stoppage-layout">
        <figure class="media-frame media-frame--4x3 stoppage-layout__fig">
          <img src="{zhanqunpic:h:800w:1200}" width="1200" height="800" loading="lazy" decoding="async" alt="半透明数据网格与热力纹理叠层，用于衬托补时面板的读数层次">
          <figcaption>补时读数以逐场记录为最小单位，按轮次汇总。</figcaption>
        </figure>

        <div class="stoppage-layout__data">
          <div class="stat-row stoppage-stats">
            <div class="stat">
              <span class="stat-num">816</span>
              <span class="stat-label">逐场统计</span>
            </div>
            <div class="stat">
              <span class="stat-num">3240</span>
              <span class="stat-label">关键事件</span>
            </div>
            <div class="stat">
              <span class="stat-num">2</span>
              <span class="stat-label">小时内更新</span>
            </div>
          </div>

          <ul class="bar-chart" aria-label="部分轮次补时时长与事件条数">
            <li class="bar-row">
              <span class="bar-row__label mono">第 05 轮</span>
              <span class="bar-track"><span class="bar-fill" style="--w:58%"></span></span>
              <span class="bar-row__num mono">7′</span>
              <span class="bar-row__ev mono">4</span>
            </li>
            <li class="bar-row bar-row--flare">
              <span class="bar-row__label mono">第 09 轮</span>
              <span class="bar-track"><span class="bar-fill" style="--w:92%"></span></span>
              <span class="bar-row__num mono">11′</span>
              <span class="bar-row__ev mono">6</span>
            </li>
            <li class="bar-row">
              <span class="bar-row__label mono">第 14 轮</span>
              <span class="bar-track"><span class="bar-fill" style="--w:42%"></span></span>
              <span class="bar-row__num mono">5′</span>
              <span class="bar-row__ev mono">2</span>
            </li>
            <li class="bar-row">
              <span class="bar-row__label mono">第 18 轮</span>
              <span class="bar-track"><span class="bar-fill" style="--w:75%"></span></span>
              <span class="bar-row__num mono">9′</span>
              <span class="bar-row__ev mono">5</span>
            </li>
            <li class="bar-row">
              <span class="bar-row__label mono">第 23 轮</span>
              <span class="bar-track"><span class="bar-fill" style="--w:50%"></span></span>
              <span class="bar-row__num mono">6′</span>
              <span class="bar-row__ev mono">3</span>
            </li>
            <li class="bar-row bar-row--flare">
              <span class="bar-row__label mono">第 28 轮</span>
              <span class="bar-track"><span class="bar-fill" style="--w:100%"></span></span>
              <span class="bar-row__num mono">12′</span>
              <span class="bar-row__ev mono">7</span>
            </li>
          </ul>

          <div class="tag-set" aria-label="关键事件标签类型">
            <span class="chip chip--lime">补时进球</span>
            <span class="chip chip--mint">换人</span>
            <span class="chip chip--mint">视频介入</span>
            <span class="chip chip--flare">红黄牌</span>
          </div>

          <p class="panel-note">柱体按分钟绝对值等比绘制，橙红标记表示该轮补时明显高于赛季均值，仅作读数提示。</p>
        </div>
      </div>
    </div>
  </section>

  <section class="section panel-section" id="panel-map" aria-labelledby="map-title" data-reveal>
    <div class="wrap">
      <div class="section-head">
        <p class="eyebrow">面板 02 · 场馆</p>
        <h2 class="section-title" id="map-title">16 座主场与 12 座备用场地节点</h2>
        <p class="section-note">地图切片以城市为骨架，主节点代表比赛主场，次级节点代表备用或训练场地。筛选条件作用于同一张画布，不跳转页面。</p>
      </div>

      <div class="map-board">
        <figure class="media-frame media-frame--16x9 map-board__fig">
          <img src="{zhanqunpic:h:1000w:1600}" width="1600" height="1000" loading="lazy" decoding="async" alt="俯拍球场与城市路网叠加的场馆地图切片，画面不含真实队徽与具名标识">
          <figcaption>俯拍视角下的场馆节点分布，主节点与备用节点用不同透明度区分。</figcaption>
        </figure>

        <div class="map-board__side">
          <dl class="spec-list">
            <div class="spec-list__row">
              <dt>主场节点</dt>
              <dd class="mono">16</dd>
            </div>
            <div class="spec-list__row">
              <dt>备用 / 训练场地</dt>
              <dd class="mono">12</dd>
            </div>
            <div class="spec-list__row">
              <dt>合计节点</dt>
              <dd class="mono">28</dd>
            </div>
            <div class="spec-list__row">
              <dt>可筛选字段</dt>
              <dd class="mono">城市 · 容量 · 草皮</dd>
            </div>
            <div class="spec-list__row">
              <dt>关联面板</dt>
              <dd class="mono">主客场表现</dd>
            </div>
          </dl>
          <p class="panel-note">容量以区间表示，草皮类型分为天然草与混合草两类。节点信息由场馆测绘流程维护，与球队条目分栏存放。</p>
          <a class="btn btn--outline" href="/">回到主场总览</a>
        </div>
      </div>
    </div>
  </section>

  <section class="section panel-section" id="panel-odds" aria-labelledby="odds-title" data-reveal>
    <div class="wrap">
      <div class="section-head">
        <p class="eyebrow">面板 03 · 分档</p>
        <h2 class="section-title" id="odds-title">季前、中期、冲刺期三档快照</h2>
        <p class="section-note">夺冠赔率NG内地版本按赛季阶段留存分档对照，每档覆盖全部球队。阶梯条展示各区间球队数量分布，切换档位即可比较结构变化。</p>
      </div>

      <div class="odds-board">
        <div class="odds-board__visual">
          <figure class="media-frame media-frame--16x9">
            <img src="{zhanqunpic:h:800w:1200}" width="1200" height="800" loading="lazy" decoding="async" alt="看台阶梯结构与光影层次，用于衬托赔率分档的阶梯图读数，画面不含投注符号">
          </figure>
        </div>

        <div class="odds-board__data">
          <ol class="ladder" aria-label="三档赔率区间的球队数量分布，每档合计 16 支球队">
            <li class="ladder__row">
              <span class="ladder__name">季前档</span>
              <span class="ladder__bars">
                <span class="ladder__seg ladder__seg--a" style="--w:25%"><span class="mono">4</span></span>
                <span class="ladder__seg ladder__seg--b" style="--w:37.5%"><span class="mono">6</span></span>
                <span class="ladder__seg ladder__seg--c" style="--w:25%"><span class="mono">4</span></span>
                <span class="ladder__seg ladder__seg--d" style="--w:12.5%"><span class="mono">2</span></span>
              </span>
            </li>
            <li class="ladder__row">
              <span class="ladder__name">中期档</span>
              <span class="ladder__bars">
                <span class="ladder__seg ladder__seg--a" style="--w:31.25%"><span class="mono">5</span></span>
                <span class="ladder__seg ladder__seg--b" style="--w:31.25%"><span class="mono">5</span></span>
                <span class="ladder__seg ladder__seg--c" style="--w:25%"><span class="mono">4</span></span>
                <span class="ladder__seg ladder__seg--d" style="--w:12.5%"><span class="mono">2</span></span>
              </span>
            </li>
            <li class="ladder__row">
              <span class="ladder__name">冲刺档</span>
              <span class="ladder__bars">
                <span class="ladder__seg ladder__seg--a" style="--w:37.5%"><span class="mono">6</span></span>
                <span class="ladder__seg ladder__seg--b" style="--w:31.25%"><span class="mono">5</span></span>
                <span class="ladder__seg ladder__seg--c" style="--w:18.75%"><span class="mono">3</span></span>
                <span class="ladder__seg ladder__seg--d" style="--w:12.5%"><span class="mono">2</span></span>
              </span>
            </li>
          </ol>

          <ul class="legend" aria-label="赔率区间图例">
            <li><span class="legend__swatch legend__swatch--a"></span>低赔区间</li>
            <li><span class="legend__swatch legend__swatch--b"></span>次低区间</li>
            <li><span class="legend__swatch legend__swatch--c"></span>中位区间</li>
            <li><span class="legend__swatch legend__swatch--d"></span>高位区间</li>
          </ul>

          <p class="boundary-note">
            <span class="chip chip--flare">边界提示</span>
            站内赔率仅作公开数据整理与分档对照，不构成投注建议，也不提供任何下注、交易或收益相关功能。近 3 个赛季累计留存 144 组分档快照。
          </p>
        </div>
      </div>
    </div>
  </section>

  <section class="section panel-section" id="panel-quota" aria-labelledby="quota-title" data-reveal>
    <div class="wrap">
      <div class="section-head">
        <p class="eyebrow">面板 04 · 规程</p>
        <h2 class="section-title" id="quota-title">外援名额条款逐条对照</h2>
        <p class="section-note">简体版NG外援名额按规程版本拆成条目清单，每条给出适用范围、核定状态与最近一次复核阶段。条款以文本对照为主，不替代任何官方解释。</p>
      </div>

      <div class="quota-board">
        <div class="quota-board__filters" role="group" aria-label="按核定状态查看条款">
          <span class="chip chip--lime">全部 36 条</span>
          <span class="chip chip--mint">已核定 31 条</span>
          <span class="chip chip--flare">待复核 5 条</span>
        </div>

        <ol class="quota-list">
          <li class="quota-item">
            <span class="quota-item__no mono">01</span>
            <div class="quota-item__body">
              <h3 class="quota-item__name">注册名额上限</h3>
              <p>规定单赛季可注册的外援人数上限，与转会窗口开启时段绑定。</p>
            </div>
            <span class="chip chip--mint">已核定</span>
          </li>
          <li class="quota-item">
            <span class="quota-item__no mono">02</span>
            <div class="quota-item__body">
              <h3 class="quota-item__name">同时上场名额</h3>
              <p>规定同一场比赛内可同时在场的外援人数，含换人后的持续约束。</p>
            </div>
            <span class="chip chip--mint">已核定</span>
          </li>
          <li class="quota-item">
            <span class="quota-item__no mono">03</span>
            <div class="quota-item__body">
              <h3 class="quota-item__name">亚洲外援条款</h3>
              <p>说明亚外身份认定所需材料与登记路径，与普通外援名额分列统计。</p>
            </div>
            <span class="chip chip--mint">已核定</span>
          </li>
          <li class="quota-item">
            <span class="quota-item__no mono">04</span>
            <div class="quota-item__body">
              <h3 class="quota-item__name">归化球员认定</h3>
              <p>说明归化身份在名额计算中的处理方式，以及与其他条款的叠加规则。</p>
            </div>
            <span class="chip chip--flare">待复核</span>
          </li>
          <li class="quota-item">
            <span class="quota-item__no mono">05</span>
            <div class="quota-item__body">
              <h3 class="quota-item__name">变更与通报时点</h3>
              <p>规定名单变更的申报时限，以及跨阶段窗口的衔接处理方式。</p>
            </div>
            <span class="chip chip--flare">待复核</span>
          </li>
        </ol>

        <p class="panel-note">完整 36 条条款按赛季版本归档，口径逐条核定，更新节奏为每赛季一次。遇到表述冲突时以条目编号顺序回查原文出处。</p>
      </div>
    </div>
  </section>

  <section class="section panel-section" id="panel-youth" aria-labelledby="youth-title" data-reveal>
    <div class="wrap">
      <div class="section-head">
        <p class="eyebrow">面板 05 · 梯队</p>
        <h2 class="section-title" id="youth-title">三级梯队出场时间分层展示</h2>
        <p class="section-note">青训出场时间按 U19、U17、U15 三个层级切分，记录首发、替补、累计分钟与位置分布，并保留连续出场记录便于追踪上升路径。</p>
      </div>

      <div class="youth-board">
        <figure class="media-frame media-frame--4x3 youth-board__fig">
          <img src="{zhanqunpic:h:900w:1200}" width="1200" height="900" loading="lazy" decoding="async" alt="训练场上的跑动轨迹线与抽象热区分布，用于呈现青训出场时间的空间特征，无具名人物">
        </figure>

        <div class="youth-board__data">
          <div class="stat-row">
            <div class="stat">
              <span class="stat-num">48</span>
              <span class="stat-label">梯队总数</span>
            </div>
            <div class="stat">
              <span class="stat-num">18400</span>
              <span class="stat-label">累计分钟</span>
            </div>
            <div class="stat">
              <span class="stat-num">3</span>
              <span class="stat-label">年龄层级</span>
            </div>
          </div>

          <ul class="tier-list">
            <li class="tier-row">
              <span class="tier-row__name">U19</span>
              <span class="tier-row__note">首发与替补分钟比例接近，位置分布集中于中前场。</span>
              <span class="tier-row__num mono">16 支</span>
            </li>
            <li class="tier-row">
              <span class="tier-row__name">U17</span>
              <span class="tier-row__note">替补分钟占比上升，连续出场记录跨度更长。</span>
              <span class="tier-row__num mono">16 支</span>
            </li>
            <li class="tier-row">
              <span class="tier-row__name">U15</span>
              <span class="tier-row__note">以轮换出场为主，位置分布相对均衡。</span>
              <span class="tier-row__num mono">16 支</span>
            </li>
          </ul>

          <a class="btn btn--outline" href="/news/">查看赛季追踪</a>
        </div>
      </div>
    </div>
  </section>

  <section class="section panel-section" id="panel-export" aria-labelledby="export-title" data-reveal>
    <div class="wrap">
      <div class="section-head">
        <p class="eyebrow">面板 06 · 取用</p>
        <h2 class="section-title" id="export-title">数据取用与版本标记说明</h2>
        <p class="section-note">面板读数支持按赛季打包成静态文件，字段名、单位与版本号一并写入，便于二次整理与横向比对。站内不提供后端实时接口，也不承载任何交易类调用。</p>
      </div>

      <div class="export-board">
        <div class="export-board__grid">
          <article class="export-card">
            <h3 class="export-card__title">字段与单位</h3>
            <p>补时以分钟为整数单位，出场时间以分钟累计，赔率区间以数值边界记录，名额条款以条目文本存放。</p>
          </article>
          <article class="export-card">
            <h3 class="export-card__title">版本标记</h3>
            <p>每次打包写入赛季区间与核定阶段，回查时可直接定位到具体轮次与规程版本。</p>
          </article>
          <article class="export-card">
            <h3 class="export-card__title">打包粒度</h3>
            <p>可按单一面板或整赛季打包。整赛季包含全部 240 场联赛记录与对应分档快照。</p>
          </article>
          <article class="export-card">
            <h3 class="export-card__title">取用范围</h3>
            <p>数据供公开比对与内容整理使用，引用时请标注来源为站内核定口径，不以官方记录形式发布。</p>
          </article>
        </div>

        <div class="export-board__aside">
          <p class="export-board__label">当前索引编号</p>
          <p class="export-board__code mono" id="index-code">NG-APPS-03S-06P</p>
          <button class="btn btn--quiet copy-btn" type="button" data-copy="NG-APPS-03S-06P">复制索引编号</button>
          <p class="panel-note">编号含义：站点工具台 · 近 3 个赛季 · 6 个面板。提交纠错时附带该编号可加快定位。</p>
        </div>
      </div>
    </div>
  </section>

  <section class="section closing" aria-labelledby="closing-title">
    <div class="wrap closing__grid">
      <div class="closing__copy">
        <p class="eyebrow">延伸阅读</p>
        <h2 class="section-title" id="closing-title">口径拿不准时，往这几处走</h2>
        <p class="lede">工具台给读数，口径解释与纠错流程放在其他栏目。补时定义、名额细则、赔率分档含义都可以在核定问答里找到对应条目。</p>
        <div class="closing__links">
          <a class="btn btn--outline" href="/help-center/">核定问答</a>
          <a class="btn btn--outline" href="/history/">数据历程</a>
          <a class="btn btn--outline" href="/cooperation/">合作与纠错</a>
        </div>
      </div>
      <aside class="closing__aside">
        <h3 class="closing__aside-title">站内其他入口</h3>
        <ul class="closing__list">
          <li><a href="/">主场总览</a><span class="mono">场馆与赔率总入口</span></li>
          <li><a href="/news/">赛季观察</a><span class="mono">阶段专题更新</span></li>
          <li><a href="/personal-data/">个人信息说明</a><span class="mono">数据使用与存储</span></li>
        </ul>
      </aside>
    </div>
  </section>

</main>

.page-products {
  --ps-hair: rgba(36, 53, 46, .85);
  --ps-grid: rgba(31, 107, 69, .16);
  display: block;
  background: var(--bg);
  color: var(--mist);
  overflow-x: hidden;
}

.page-products .breadcrumbs {
  padding-top: 20px;
  padding-bottom: 4px;
  font-size: 12px;
  letter-spacing: .06em;
  color: var(--gray);
}

.page-products .breadcrumbs a {
  color: var(--gray);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}

.page-products .breadcrumbs a:hover {
  color: var(--mint);
  border-bottom-color: var(--mint);
}

.page-products .breadcrumbs span[aria-current] {
  color: var(--mist);
}

/* ---------- 首屏 ---------- */
.page-products .console-hero {
  position: relative;
  padding: 32px 0 64px;
  border-bottom: 1px solid var(--ps-hair);
  background:
    linear-gradient(180deg, rgba(10, 16, 32, .25) 0%, rgba(10, 16, 32, .96) 100%),
    repeating-linear-gradient(90deg, var(--ps-grid) 0 1px, transparent 1px 84px),
    repeating-linear-gradient(0deg, var(--ps-grid) 0 1px, transparent 1px 84px),
    var(--bg);
}

.page-products .console-hero__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 32px;
  align-items: start;
}

.page-products .console-hero__title {
  margin: 12px 0 18px;
  font-weight: 200;
  letter-spacing: -.01em;
  color: var(--mist);
}

.page-products .console-hero__copy .lede {
  max-width: 56ch;
  color: var(--gray);
}

.page-products .console-hero__keys {
  list-style: none;
  margin: 28px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px;
  background: var(--ps-hair);
  border: 1px solid var(--ps-hair);
}

.page-products .console-hero__keys li {
  background: var(--bg);
  padding: 12px 14px;
  display: flex;
  align-items: baseline;
  gap: 8px;
}

.page-products .console-hero__keys .num {
  font-family: var(--font-mono);
  font-size: 22px;
  font-weight: 700;
  color: var(--lime);
  line-height: 1;
}

.page-products .console-hero__keys span:last-child {
  font-size: 12px;
  letter-spacing: .08em;
  color: var(--gray);
}

.page-products .console-hero__actions {
  margin-top: 26px;
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.page-products .console-hero__visual {
  margin: 0;
}

/* ---------- 通用章节 ---------- */
.page-products .section {
  padding: 64px 0;
  border-bottom: 1px solid var(--ps-hair);
}

.page-products .section-head {
  max-width: 74ch;
  margin-bottom: 32px;
}

.page-products .section-note {
  color: var(--gray);
}

/* ---------- 工具索引 ---------- */
.page-products .tool-index {
  background: var(--bg-2);
}

.page-products .switch-bar {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1px;
  background: var(--ps-hair);
  border: 1px solid var(--ps-hair);
  margin-bottom: 32px;
}

.page-products .switch-bar__item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px;
  background: var(--bg-2);
  color: var(--mist);
  text-decoration: none;
  font-size: 13px;
  letter-spacing: .04em;
  border-left: 2px solid transparent;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}

.page-products .switch-bar__item .num {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--gray);
}

.page-products .switch-bar__item:hover,
.page-products .switch-bar__item:focus-visible {
  background: var(--panel);
  border-left-color: var(--lime);
  color: var(--lime);
}

.page-products .switch-bar__item:hover .num,
.page-products .switch-bar__item:focus-visible .num {
  color: var(--lime);
}

.page-products .tool-index__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1px;
  background: var(--ps-hair);
  border: 1px solid var(--ps-hair);
}

.page-products .tool-card {
  background: var(--bg-2);
  padding: 22px 20px 20px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  position: relative;
  transition: background var(--dur) var(--ease);
}

.page-products .tool-card::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 0;
  height: 2px;
  background: var(--lime);
  transition: width var(--dur) var(--ease);
}

.page-products .tool-card:hover {
  background: var(--panel);
}

.page-products .tool-card:hover::after {
  width: 100%;
}

.page-products .tool-card__idx {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: .12em;
  color: var(--turf);
}

.page-products .tool-card__title {
  margin: 0;
  font-size: 17px;
  font-weight: 700;
  color: var(--mist);
}

.page-products .tool-card__desc {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.7;
  color: var(--gray);
}

.page-products .tool-card__foot {
  margin: 6px 0 0;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--mint);
  letter-spacing: .04em;
}

/* ---------- 面板通用 ---------- */
.page-products .panel-section {
  background: var(--bg);
}

.page-products .panel-note {
  margin: 16px 0 0;
  font-size: 12.5px;
  line-height: 1.7;
  color: var(--gray);
}

.page-products .boundary-note {
  margin: 18px 0 0;
  padding: 14px 16px;
  border-left: 2px solid var(--flare);
  background: rgba(255, 90, 54, .06);
  font-size: 13px;
  line-height: 1.7;
  color: var(--mist);
}

.page-products .boundary-note .chip {
  margin-right: 8px;
  vertical-align: middle;
}

/* ---------- 补时面板 ---------- */
.page-products .stoppage-layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: 28px;
}

.page-products .stoppage-layout__fig {
  margin: 0;
}

.page-products .stoppage-stats {
  margin-bottom: 22px;
}

.page-products .bar-chart {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 10px;
}

.page-products .bar-row {
  display: grid;
  grid-template-columns: 72px minmax(0, 1fr) 40px 30px;
  align-items: center;
  gap: 8px;
}

.page-products .bar-row__label {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--gray);
  letter-spacing: .05em;
}

.page-products .bar-track {
  display: block;
  height: 8px;
  background: rgba(36, 53, 46, .9);
  overflow: hidden;
}

.page-products .bar-fill {
  display: block;
  height: 100%;
  width: var(--w, 0%);
  background: linear-gradient(90deg, var(--turf), var(--lime));
  transition: width var(--dur) var(--ease);
}

.page-products .bar-row--flare .bar-fill {
  background: linear-gradient(90deg, var(--flare), #ffb08f);
}

.page-products .bar-row__num {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 700;
  color: var(--lime);
  text-align: right;
}

.page-products .bar-row--flare .bar-row__num {
  color: var(--flare);
}

.page-products .bar-row__ev {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--gray);
  text-align: right;
}

.page-products .tag-set {
  margin-top: 22px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/* ---------- 主场地图 ---------- */
.page-products .map-board {
  display: grid;
  grid-template-columns: 1fr;
  gap: 28px;
}

.page-products .map-board__fig {
  margin: 0;
}

.page-products .spec-list {
  margin: 0 0 18px;
  border-top: 1px solid var(--ps-hair);
}

.page-products .spec-list__row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 16px;
  padding: 11px 0;
  border-bottom: 1px solid var(--ps-hair);
}

.page-products .spec-list__row dt {
  font-size: 12.5px;
  letter-spacing: .06em;
  color: var(--gray);
}

.page-products .spec-list__row dd {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 14px;
  font-weight: 700;
  color: var(--lime);
  text-align: right;
}

.page-products .map-board__side .btn {
  margin-top: 18px;
}

/* ---------- 赔率分档 ---------- */
.page-products .odds-board {
  display: grid;
  grid-template-columns: 1fr;
  gap: 28px;
}

.page-products .odds-board__visual .media-frame {
  margin: 0;
}

.page-products .ladder {
  list-style: none;
  margin: 0 0 20px;
  padding: 0;
  display: grid;
  gap: 16px;
}

.page-products .ladder__row {
  display: grid;
  gap: 6px;
}

.page-products .ladder__name {
  font-size: 12px;
  letter-spacing: .1em;
  color: var(--mist);
}

.page-products .ladder__bars {
  display: flex;
  height: 32px;
  border: 1px solid var(--ps-hair);
  background: var(--panel);
}

.page-products .ladder__seg {
  position: relative;
  width: var(--w, 0%);
  display: flex;
  align-items: center;
  justify-content: center;
  border-right: 1px solid rgba(10, 16, 32, .8);
  transition: filter var(--dur) var(--ease);
}

.page-products .ladder__seg:last-child {
  border-right: 0;
}

.page-products .ladder__seg .mono {
  font-family: var(--font-mono);
  font-size: 11.5px;
  font-weight: 700;
  color: var(--ink);
}

.page-products .ladder__seg--a { background: var(--lime); }
.page-products .ladder__seg--b { background: var(--mint); }
.page-products .ladder__seg--c { background: var(--turf); }
.page-products .ladder__seg--c .mono { color: var(--mist); }
.page-products .ladder__seg--d { background: var(--flare); }

.page-products .ladder__seg:hover {
  filter: brightness(1.18);
}

.page-products .legend {
  list-style: none;
  margin: 0 0 20px;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 18px;
  font-size: 12px;
  color: var(--gray);
}

.page-products .legend li {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

.page-products .legend__swatch {
  width: 12px;
  height: 12px;
  display: inline-block;
}

.page-products .legend__swatch--a { background: var(--lime); }
.page-products .legend__swatch--b { background: var(--mint); }
.page-products .legend__swatch--c { background: var(--turf); }
.page-products .legend__swatch--d { background: var(--flare); }

/* ---------- 外援名额 ---------- */
.page-products .quota-board__filters {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 22px;
}

.page-products .quota-list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--ps-hair);
}

.page-products .quota-item {
  display: grid;
  grid-template-columns: 36px minmax(0, 1fr);
  gap: 10px 14px;
  align-items: start;
  padding: 18px 0;
  border-bottom: 1px solid var(--ps-hair);
}

.page-products .quota-item__no {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 700;
  color: var(--turf);
  padding-top: 2px;
}

.page-products .quota-item__name {
  margin: 0 0 6px;
  font-size: 15px;
  font-weight: 700;
  color: var(--mist);
}

.page-products .quota-item__body p {
  margin: 0;
  font-size: 13px;
  line-height: 1.7;
  color: var(--gray);
}

.page-products .quota-item .chip {
  grid-column: 2;
  justify-self: start;
  white-space: nowrap;
}

/* ---------- 青训 ---------- */
.page-products .youth-board {
  display: grid;
  grid-template-columns: 1fr;
  gap: 28px;
}

.page-products .youth-board__fig {
  margin: 0;
}

.page-products .tier-list {
  list-style: none;
  margin: 22px 0;
  padding: 0;
  border-top: 1px solid var(--ps-hair);
}

.page-products .tier-row {
  display: grid;
  grid-template-columns: 52px minmax(0, 1fr) 56px;
  gap: 12px;
  align-items: center;
  padding: 14px 0;
  border-bottom: 1px solid var(--ps-hair);
}

.page-products .tier-row__name {
  font-family: var(--font-mono);
  font-size: 14px;
  font-weight: 700;
  color: var(--lime);
}

.page-products .tier-row__note {
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--gray);
}

.page-products .tier-row__num {
  font-family: var(--font-mono);
  font-size: 12.5px;
  text-align: right;
  color: var(--mint);
}

/* ---------- 导出说明 ---------- */
.page-products .export-board {
  display: grid;
  grid-template-columns: 1fr;
  gap: 28px;
}

.page-products .export-board__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1px;
  background: var(--ps-hair);
  border: 1px solid var(--ps-hair);
}

.page-products .export-card {
  background: var(--panel);
  padding: 20px;
}

.page-products .export-card__title {
  margin: 0 0 8px;
  font-size: 14px;
  font-weight: 700;
  color: var(--mint);
  letter-spacing: .04em;
}

.page-products .export-card p {
  margin: 0;
  font-size: 13px;
  line-height: 1.7;
  color: var(--gray);
}

.page-products .export-board__aside {
  border: 1px solid var(--ps-hair);
  border-left: 2px solid var(--lime);
  padding: 20px;
  background: var(--bg-2);
}

.page-products .export-board__label {
  margin: 0 0 8px;
  font-size: 11.5px;
  letter-spacing: .12em;
  color: var(--gray);
}

.page-products .export-board__code {
  margin: 0 0 16px;
  font-family: var(--font-mono);
  font-size: 20px;
  font-weight: 700;
  color: var(--lime);
  letter-spacing: .06em;
  word-break: break-all;
}

.page-products .copy-btn[data-copied="true"] {
  color: var(--lime);
}

/* ---------- 收束区 ---------- */
.page-products .closing {
  border-bottom: 0;
  background: var(--bg-2);
}

.page-products .closing__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 32px;
}

.page-products .closing__copy .lede {
  color: var(--gray);
}

.page-products .closing__links {
  margin-top: 22px;
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.page-products .closing__aside {
  border-top: 1px solid var(--ps-hair);
  padding-top: 22px;
}

.page-products .closing__aside-title {
  margin: 0 0 14px;
  font-size: 12px;
  letter-spacing: .12em;
  color: var(--gray);
  font-weight: 600;
}

.page-products .closing__list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.page-products .closing__list li {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 14px;
  padding: 11px 0;
  border-bottom: 1px solid var(--ps-hair);
}

.page-products .closing__list a {
  color: var(--mist);
  text-decoration: none;
  font-size: 14px;
  border-bottom: 1px solid transparent;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}

.page-products .closing__list a:hover {
  color: var(--lime);
  border-bottom-color: var(--lime);
}

.page-products .closing__list .mono {
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--gray);
  text-align: right;
}

/* ---------- 媒体框补充 ---------- */
.page-products .media-frame {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--ps-hair);
  background: var(--panel);
}

.page-products .media-frame img {
  display: block;
  width: 100%;
  height: 100%;
  max-width: 100%;
  object-fit: cover;
}

.page-products .media-frame--4x3 { aspect-ratio: 4 / 3; }
.page-products .media-frame--16x9 { aspect-ratio: 16 / 9; }
.page-products .media-frame--21x9 { aspect-ratio: 21 / 9; }

.page-products .media-frame figcaption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 26px 14px 12px;
  font-size: 11.5px;
  line-height: 1.6;
  color: var(--mist);
  background: linear-gradient(180deg, rgba(10, 16, 32, 0) 0%, rgba(10, 16, 32, .92) 78%);
}

/* ---------- 动效 ---------- */
@keyframes ps-rise {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: no-preference) {
  .page-products [data-reveal].is-visible {
    animation: ps-rise 240ms var(--ease) both;
  }
}

@media (prefers-reduced-motion: reduce) {
  .page-products * {
    transition-duration: 1ms !important;
    animation-duration: 1ms !important;
  }
}

/* ---------- 断点 ---------- */
@media (min-width: 640px) {
  .page-products .console-hero {
    padding: 48px 0 80px;
  }

  .page-products .console-hero__keys {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  .page-products .switch-bar {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .page-products .tool-index__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .page-products .export-board__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .page-products .quota-item {
    grid-template-columns: 44px minmax(0, 1fr) auto;
    gap: 12px 22px;
  }

  .page-products .quota-item .chip {
    grid-column: 3;
  }
}

@media (min-width: 900px) {
  .page-products .console-hero__grid {
    grid-template-columns: 5fr 7fr;
    gap: 56px;
    align-items: center;
  }

  .page-products .switch-bar {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .page-products .tool-index__grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .page-products .stoppage-layout {
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    gap: 40px;
    align-items: start;
  }

  .page-products .map-board {
    grid-template-columns: minmax(0, 8fr) minmax(0, 4fr);
    gap: 40px;
    align-items: start;
  }

  .page-products .odds-board {
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    gap: 40px;
    align-items: start;
  }

  .page-products .youth-board {
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    gap: 40px;
    align-items: start;
  }

  .page-products .export-board {
    grid-template-columns: minmax(0, 8fr) minmax(0, 4fr);
    gap: 40px;
    align-items: start;
  }

  .page-products .closing__grid {
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
    gap: 56px;
    align-items: start;
  }

  .page-products .closing__aside {
    border-top: 0;
    border-left: 1px solid var(--ps-hair);
    padding-top: 0;
    padding-left: 28px;
  }
}

@media (min-width: 1200px) {
  .page-products .section {
    padding: 88px 0;
  }

  .page-products .bar-row {
    grid-template-columns: 92px minmax(0, 1fr) 48px 36px;
    gap: 14px;
  }
}
