/* ==========================================================================
   上海世佳特科技有限公司 — Page components
   site.css : hero, live dashboard, capability grid, solutions, timeline,
              ROI calculator, matrices, cases, contact
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Home hero
   -------------------------------------------------------------------------- */
.hero {
  position: relative;
  padding-top: calc(var(--header-h) + clamp(48px, 7vw, 92px));
  padding-bottom: clamp(56px, 7vw, 96px);
  overflow: hidden;
}
.hero__grid {
  position: relative;
  z-index: var(--z-content);
  display: grid;
  grid-template-columns: minmax(0, 1.08fr) minmax(0, 1.06fr);
  gap: clamp(34px, 4.5vw, 60px);
  align-items: center;
}
.hero__copy { max-width: 660px; }
/* 单栏 hero（行业洞察）：文案不再右挂图版，直接铺到版心并加宽到 820 */
.hero__grid--solo { grid-template-columns: minmax(0, 1fr); }
.hero__grid--solo .hero__copy { max-width: 820px; }
/* Slightly tighter than the global h1 so "跑出它该有的效率" holds one line
   inside the left column instead of breaking after "该". */
.hero h1 { margin-top: 26px; font-size: clamp(33px, 4.6vw, 57px); text-wrap: initial; }
.hero h1 .line2 { display: block; }
.hero .lede { margin-top: 26px; max-width: 560px; }
.hero__acts { margin-top: 36px; display: flex; gap: 13px; flex-wrap: wrap; }
.hero__proof {
  margin-top: 38px;
  padding-top: 24px;
  border-top: 1px solid var(--line);
  display: flex;
  gap: 30px;
  flex-wrap: wrap;
}
.hero__proof div { display: flex; flex-direction: column; gap: 3px; }
.hero__proof .v {
  font-size: 21px;
  font-weight: 600;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.hero__proof .k {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* Faint vertical scanline over hero — instrument feel */
.hero::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 1px;
  background: linear-gradient(180deg, transparent, rgba(47, 224, 192, 0.18) 45%, transparent);
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   2. Live line dashboard (hero centrepiece)
   -------------------------------------------------------------------------- */
.dash {
  position: relative;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-lg);
  background: linear-gradient(180deg, #0e1218, #0a0d12);
  box-shadow:
    0 0 0 1px rgba(0, 0, 0, 0.4),
    0 40px 90px -40px rgba(0, 0, 0, 0.95),
    0 0 70px -30px rgba(47, 224, 192, 0.22);
}
.dash__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--line);
  background: rgba(255, 255, 255, 0.015);
  border-radius: calc(var(--r-lg) - 1px) calc(var(--r-lg) - 1px) 0 0;
}
.dash__id {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.dash__id b { color: var(--teal); font-weight: 600; }
/* 品牌名从 SJT 换成 SCATTER 后标签变长，窄屏会挤到胶囊折行 —— 胶囊锁死单行，副标题在 420px 断点隐藏 */
.dash__bar .pill { flex-shrink: 0; white-space: nowrap; }
.dash__body { padding: 18px; display: flex; flex-direction: column; gap: 16px; }

/* Metric tiles */
.mtiles { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; }
.mtile {
  border: 1px solid var(--line);
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.02);
  padding: 11px 12px;
  min-width: 0;
}
.mtile__k {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.mtile__v {
  margin-top: 6px;
  font-size: 20px;
  font-weight: 600;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.mtile__v small { font-size: 11px; color: var(--ink-3); font-weight: 500; margin-left: 2px; }
.mtile__d { margin-top: 5px; font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.05em; }
.mtile__d.up { color: var(--teal); }
.mtile__d.dn { color: var(--amber); }
/* One-shot glow when a metric ticks — site.js retriggers it on each new value */
.mtile.bump { animation: mtile-pulse 0.5s var(--ease-out); }
@keyframes mtile-pulse {
  0%   { box-shadow: 0 0 0 1px var(--line-accent), 0 0 22px -4px rgba(47, 224, 192, 0.35); }
  100% { box-shadow: 0 0 0 0 rgba(47, 224, 192, 0); }
}

/* Chart */
.chart {
  position: relative;
  border: 1px solid var(--line);
  border-radius: 10px;
  background:
    linear-gradient(to bottom, rgba(47, 224, 192, 0.03), transparent 70%),
    rgba(0, 0, 0, 0.22);
  padding: 12px 12px 8px;
  overflow: hidden;
}
.chart__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 8px;
}
.chart__title {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.chart__legend { display: flex; gap: 14px; font-family: var(--font-mono); font-size: 10px; }
.chart__legend i { font-style: normal; color: var(--ink-3); }
.chart__legend b { font-weight: 600; }
.chart__legend .l1 b { color: var(--teal); }
.chart__legend .l2 b { color: var(--amber); }
.chart svg { width: 100%; height: auto; display: block; overflow: hidden; }
.chart .cross-line { stroke: rgba(233, 237, 243, 0.34); stroke-width: 1; stroke-dasharray: 2 3; }
.chart .cross-dot  { fill: var(--teal); stroke: rgba(7, 8, 10, 0.85); stroke-width: 1.5; }
/* 工艺窗口图版：SVG 只画几何，所有文字都走 HTML 叠层并按百分比定位，
   这样 preserveAspectRatio="none" 拉伸时文字不会被压扁。 */
.chart__plot { position: relative; }
.chart__grid line { stroke: var(--line); stroke-width: 1; }
.chart__band { fill: var(--teal-a08); }
/* 验收区间：横着的带，和竖着的稳健区相交成一个真正的"窗口" */
.chart__specband { fill: var(--line); }
.chart__specedge {
  stroke: var(--amber);
  stroke-opacity: 0.5;
  stroke-width: 1;
  stroke-dasharray: 5 4;
}
.chart__play { stroke: var(--teal); stroke-opacity: 0.42; stroke-width: 1; }
#pwLine { stroke: var(--teal); }
#pwDot  { fill: var(--teal); }
#pwRing { stroke: var(--teal); }
#pwEnvA stop { stop-color: var(--teal); }

.chart__lab {
  position: absolute;
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.08em;
  line-height: 1.3;
  white-space: nowrap;
  pointer-events: none;
}
.chart__lab--spec { left: 5px; top: 11%; color: var(--amber); }
/* 稳健区标注放在带子底部：顶部要让给验收区间与失效模式两行标注 */
.chart__lab--band {
  left: 65%;
  top: 86%;
  transform: translateX(-50%);
  color: var(--teal);
}
.chart__lab--fail { color: var(--ink-4); }
.chart__lab--fail.l { left: 5px; top: 46%; }
.chart__lab--fail.r { right: 5px; top: 1px; }
.chart__axis {
  display: flex;
  justify-content: space-between;
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.08em;
  color: var(--ink-4);
  padding: 0 2px 2px;
}
/* Hover readout pinned to the chart's top edge */
.chart__tip {
  position: absolute;
  top: 12px;
  transform: translateX(-50%);
  padding: 5px 9px;
  border: 1px solid var(--line-strong);
  border-radius: 6px;
  background: rgba(10, 12, 16, 0.92);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.05em;
  color: var(--ink-2);
  white-space: nowrap;
  pointer-events: none;
  z-index: var(--z-raised);
}
.chart__tip b    { color: var(--teal); font-weight: 600; }
.chart__tip i    { font-style: normal; color: var(--amber); }
.chart__tip span { color: var(--ink-4); margin-left: 8px; }
.chart__tip[hidden] { display: none; }


/* OFAT 说明行 —— 交代这次扫描动的是哪个因子、恒定的是哪几个 */
.ofat {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.04em;
  color: var(--ink-3);
}
.ofat__tag {
  flex: none;
  color: var(--teal);
  border: 1px solid var(--line-accent);
  border-radius: 4px;
  padding: 1px 6px;
  font-size: 9.5px;
  letter-spacing: 0.1em;
}
.ofat__row b { color: var(--ink); font-weight: 600; }
.ofat__row--var { margin-left: auto; color: var(--ink-2); }

/* 判定条 —— 取代原来的流式日志：一行说清当前落在哪个区、为什么 */
.status {
  display: flex;
  align-items: center;
  gap: 10px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: rgba(0, 0, 0, 0.28);
  padding: 10px 13px;
  font-size: 12.5px;
  min-height: 42px;
}
.status__zone {
  flex: none;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.08em;
  border: 1px solid currentColor;
  border-radius: 4px;
  padding: 2px 7px;
}
.is-ok   { color: var(--teal); }
.is-edge { color: var(--amber); }
.is-fail { color: var(--red); }
.status__m {
  color: var(--ink-2);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.status__t {
  margin-left: auto;
  flex: none;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--ink-4);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 720px) {
  .status { flex-wrap: wrap; row-gap: 4px; }
  .status__t { display: none; }
  .status__m { white-space: normal; }
  /* 标题与图例并排会在 390px 下各自折行断字，改成上下两行各占满宽 */
  .chart__head { flex-direction: column; align-items: flex-start; gap: 4px; }
  .chart__legend { gap: 12px; }
}

/* Floating badge on the dashboard — sits half outside the bottom edge so it
   never covers the log lines behind it. */
.dash__float {
  position: absolute;
  right: 20px;
  bottom: -15px;
  padding: 9px 14px;
  border-radius: var(--r-pill);
  border: 1px solid var(--line-accent);
  background: rgba(10, 14, 18, 0.92);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--teal);
  box-shadow: 0 18px 40px -18px rgba(0, 0, 0, 0.9);
  display: flex;
  align-items: center;
  gap: 9px;
  /* 徽章语义：永远是单行。文案改英文后长度浮动，靠 nowrap 防止折行压住日志区，
     超长时由 max-width + 省略号兜底（当前文案在 360px 下仍有余量）。 */
  white-space: nowrap;
  max-width: calc(100% - 24px);
  overflow: hidden;
  text-overflow: ellipsis;
}
.dash__float > :last-child { overflow: hidden; text-overflow: ellipsis; }
.dash__dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--teal);
  flex: none;
  animation: pulse 2.4s infinite;
}

/* --------------------------------------------------------------------------
   2b. Live state — 呼吸
   dash__dot 的 pulse 是"扩散环"（向外报信），这里补的是"呼吸"（明暗起伏）。
   两者叠加才读得出"这东西在我来之前就在跑"。参数取自 Cursor 生产环境的
   --animate-pulse: pulse 2s cubic-bezier(.4,0,.6,1) infinite。
   全站 reduced-motion 已有全局兜底（animation-duration: 0.001ms !important）。
   -------------------------------------------------------------------------- */
@keyframes breathe {
  0%, 100% { opacity: 0.55; }
  50%      { opacity: 1; }
}
.pill--live,
.is-live {
  animation: breathe 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}

/* --------------------------------------------------------------------------
   3. Trust / vertical marquee row
   -------------------------------------------------------------------------- */
.trust { padding-block: 34px; border-block: 1px solid var(--line); }
.trust__label {
  text-align: center;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-4);
  margin-bottom: 22px;
}

/* --------------------------------------------------------------------------
   4. Capability grid (home)
   -------------------------------------------------------------------------- */
.caps { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.cap {
  position: relative;
  background: var(--bg);
  padding: 30px 28px 32px;
  transition: background-color var(--dur-2);
  min-height: 232px;
  display: flex;
  flex-direction: column;
}
.cap:hover { background: var(--panel); }
.cap::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 1.5px;
  background: linear-gradient(90deg, var(--teal), transparent 70%);
  opacity: 0;
  transition: opacity var(--dur-2);
}
.cap:hover::before { opacity: 1; }
.cap__top { display: flex; align-items: center; justify-content: space-between; gap: 14px; }
.cap h3 { margin-top: 20px; font-size: 18.5px; }
.cap p { margin-top: 12px; font-size: 14.5px; color: var(--ink-2); line-height: 1.72; }
.cap__tags { margin-top: auto; padding-top: 20px; display: flex; flex-wrap: wrap; gap: 6px; }

/* --------------------------------------------------------------------------
   5. Solution explorer (tabs, home)
   -------------------------------------------------------------------------- */
.explorer { margin-top: 40px; }
.explorer__panel {
  margin-top: 24px;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--panel);
  overflow: hidden;
}
.exp-grid { display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); }
.exp-main { padding: clamp(26px, 3.2vw, 40px); border-right: 1px solid var(--line); }
.exp-side {
  padding: clamp(26px, 3.2vw, 40px);
  background: linear-gradient(180deg, rgba(47, 224, 192, 0.035), transparent 60%);
  display: flex;
  flex-direction: column;
  gap: 22px;
}
.exp-main h3 { font-size: clamp(21px, 2.3vw, 27px); }
.exp-main > p { margin-top: 16px; }
.exp-block { margin-top: 26px; }
.exp-block__h {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 14px;
  display: flex;
  align-items: center;
  gap: 10px;
}
.exp-block__h::after { content: ""; flex: 1; height: 1px; background: var(--line); }
.kpis { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
.kpi {
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 14px 15px;
  background: rgba(255, 255, 255, 0.02);
}
.kpi__v { font-size: 24px; font-weight: 600; letter-spacing: -0.02em; color: var(--teal); font-variant-numeric: tabular-nums; line-height: 1.05; }
.kpi__k { margin-top: 7px; font-size: 12.5px; color: var(--ink-2); line-height: 1.5; }

/* --------------------------------------------------------------------------
   6. Process / delivery timeline (numbered, "01 / 05" device)
   -------------------------------------------------------------------------- */
.steps { counter-reset: step; display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.step {
  background: var(--bg);
  padding: 28px 24px 32px;
  position: relative;
  transition: background-color var(--dur-2);
  display: flex;
  flex-direction: column;
}
.step:hover { background: var(--panel); }
.step__n {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.16em;
  color: var(--teal);
}
.step__n::after { content: " / 05"; color: var(--ink-4); }
.step h4 { margin-top: 16px; font-size: 16.5px; }
.step p { margin-top: 10px; font-size: 13.8px; color: var(--ink-2); line-height: 1.7; }
.step__meta {
  margin-top: auto;
  padding-top: 16px;
  border-top: 1px dashed var(--line);
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.08em;
  color: var(--ink-4);
}

/* Vertical variant (detail pages) */
.vsteps { display: flex; flex-direction: column; }
.vstep {
  display: grid;
  grid-template-columns: 54px minmax(0, 1fr);
  gap: 22px;
  padding: 26px 0;
  border-bottom: 1px solid var(--line);
}
.vstep:first-child { padding-top: 0; }
.vstep:last-child { border-bottom: 0; padding-bottom: 0; }
.vstep__n {
  width: 38px;
  height: 38px;
  border-radius: 10px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line-accent);
  background: var(--teal-a08);
  color: var(--teal);
  font-family: var(--font-mono);
  font-size: 12.5px;
  font-weight: 600;
}
.vstep h4 { font-size: 17px; }
.vstep > div > p { margin-top: 9px; font-size: 14.5px; color: var(--ink-2); max-width: 74ch; }

/* --------------------------------------------------------------------------
   7. Solution detail blocks (solutions.html)
   -------------------------------------------------------------------------- */
.sol { border-top: 1px solid var(--line); padding-block: clamp(48px, 6vw, 84px); }
.sol:last-of-type { border-bottom: 1px solid var(--line); }
.sol__head { display: grid; grid-template-columns: 88px minmax(0, 1fr); gap: 26px; align-items: start; }
.sol__num {
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.12em;
  color: var(--teal);
  padding-top: 8px;
}
.sol__title h3 { font-size: clamp(23px, 2.7vw, 32px); }
.sol__title .sub {
  margin-top: 12px;
  font-family: var(--font-mono);
  font-size: 11.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.sol__body {
  margin-top: 34px;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 0.86fr);
  gap: 26px 34px;
}
.sol__col h4 {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-4);
  font-weight: 500;
  margin-bottom: 16px;
}
.sol__col p { font-size: 14.5px; color: var(--ink-2); line-height: 1.75; }
.sol__metrics {
  display: flex;
  flex-direction: column;
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: 10px;
  overflow: hidden;
}
.sol__metric { background: var(--bg); padding: 13px 15px; display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.sol__metric .k { font-size: 13px; color: var(--ink-2); }
.sol__metric .v { font-family: var(--font-mono); font-size: 13.5px; color: var(--teal); font-variant-numeric: tabular-nums; white-space: nowrap; }
.sol__foot {
  margin-top: 30px;
  padding-top: 22px;
  border-top: 1px dashed var(--line);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
}

/* --------------------------------------------------------------------------
   8. Estimator (solutions.html)
      原为 consulting.html 的 ROI 计算器，已改造为材料替代测算器并迁移。
      迁移时只改了这一节的标题注释，样式类名保持不变。
   -------------------------------------------------------------------------- */
.calc {
  border: 1px solid var(--line-accent);
  border-radius: var(--r-lg);
  background:
    radial-gradient(80% 100% at 0% 0%, rgba(47, 224, 192, 0.07), transparent 60%),
    var(--panel);
  overflow: hidden;
}
.calc__grid { display: grid; grid-template-columns: minmax(0, 1.08fr) minmax(0, 1fr); }
.calc__inputs { padding: clamp(26px, 3.2vw, 40px); display: flex; flex-direction: column; gap: 28px; }
.calc__out {
  padding: clamp(26px, 3.2vw, 40px);
  border-left: 1px solid var(--line);
  background: rgba(0, 0, 0, 0.24);
  display: flex;
  flex-direction: column;
  gap: 22px;
}
.range { display: flex; flex-direction: column; gap: 12px; }
.range__top { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; }
.range__label { font-size: 14.5px; font-weight: 550; }
.range__val {
  font-family: var(--font-mono);
  font-size: 15px;
  color: var(--teal);
  font-variant-numeric: tabular-nums;
}
.range input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 4px;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--teal) var(--pct, 50%), rgba(255, 255, 255, 0.1) var(--pct, 50%));
  cursor: pointer;
  outline: none;
}
.range input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--bg);
  border: 2px solid var(--teal);
  box-shadow: 0 0 0 4px rgba(47, 224, 192, 0.14);
  transition: transform var(--dur-1);
}
.range input[type="range"]::-webkit-slider-thumb:hover { transform: scale(1.12); }
.range input[type="range"]::-moz-range-thumb {
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--bg); border: 2px solid var(--teal);
  box-shadow: 0 0 0 4px rgba(47, 224, 192, 0.14);
}
.range__scale {
  display: flex;
  justify-content: space-between;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  color: var(--ink-4);
}
.calc__headline {
  border: 1px solid var(--line-accent);
  border-radius: var(--r);
  padding: 22px;
  background: var(--teal-a08);
}
.calc__headline .k {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.calc__headline .v {
  margin-top: 10px;
  font-size: clamp(32px, 4.4vw, 46px);
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1;
  color: var(--teal);
  font-variant-numeric: tabular-nums;
}
.calc__headline .v small { font-size: 15px; color: var(--ink-2); font-weight: 500; margin-left: 6px; letter-spacing: 0; }
.calc__rows { display: flex; flex-direction: column; gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: 10px; overflow: hidden; }
.calc__row { background: var(--bg); padding: 13px 16px; display: flex; align-items: baseline; justify-content: space-between; gap: 14px; }
.calc__row .k { font-size: 13.5px; color: var(--ink-2); }
.calc__row .v { font-family: var(--font-mono); font-size: 14px; color: var(--ink); font-variant-numeric: tabular-nums; white-space: nowrap; }
.calc__note { font-size: 12px; color: var(--ink-4); line-height: 1.65; }

/* The output column runs taller than four sliders do, which left ~200px of
   dead space under the last one on desktop. .calc__inputs is already a flex
   column, so auto top-margin on the trailing note absorbs the slack and pins
   it to the bottom, level with the CTA opposite. Below the single-column
   breakpoint the column has no slack left, so this collapses to nothing. */
.calc__inputs > .calc__note { margin-top: auto; }

/* --------------------------------------------------------------------------
   9. Technology-transfer components
   -------------------------------------------------------------------------- */
.trls { display: flex; gap: 6px; align-items: center; }
.trl { display: flex; gap: 3px; }
.trl i { width: 13px; height: 4px; border-radius: 1px; background: rgba(255, 255, 255, 0.12); }
.trl i.on { background: var(--teal); }
.trl--amber i.on { background: var(--amber); }

.ipcard { display: flex; flex-direction: column; height: 100%; }
.ipcard__top { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; }
.ipcard h3 { margin-top: 18px; font-size: 17.5px; }
.ipcard p { margin-top: 11px; font-size: 14.2px; color: var(--ink-2); line-height: 1.72; }
.ipcard__spec { margin-top: auto; padding-top: 22px; }

/* --------------------------------------------------------------------------
   技术方向卡（transfer.html，由 tools/gen-knowledge-pages.py 注入）
   结构与 ipcard 同源：同一套 hairline 卡 + 顶部 tag/编号 + 底部 margin-top:auto
   的元信息行。这里多两层 —— 要点带出处 cite，以及「同时覆盖 also」的披露行。
   -------------------------------------------------------------------------- */
.kb-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 20px;
  align-items: stretch;
}
.kb-card {
  display: flex; flex-direction: column; height: 100%;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r);
  padding: 26px; position: relative;
  transition: border-color var(--dur-1), background-color var(--dur-1);
}
.kb-card:hover { border-color: var(--line-strong); background: var(--panel-2); }
/* 仅跟踪：虚线边框区分语气，但正文不降对比度 —— 「不是立项方向」不等于「不重要」 */
.kb-card--track { border-style: dashed; }
.kb-card__top { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; }
.kb-card__t { margin-top: 18px; font-size: 17.5px; }
.kb-card__h { margin-top: 11px; font-size: 14.2px; color: var(--ink-2); line-height: 1.72; }
.kb-card__pts { list-style: none; margin: 18px 0 0; padding: 0; display: grid; gap: 12px; }
.kb-card__pts li { display: grid; gap: 3px; }
.kb-card__k {
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .08em;
  color: var(--teal); text-transform: uppercase;
}
.kb-card__v { font-size: 13.4px; color: var(--ink-2); line-height: 1.66; }
.kb-card__src { font-style: normal; font-size: 11.4px; color: var(--ink-4); }
/* 没写正文的卡片：明说，不用灰字暗示「这里应该还有段话」 */
.kb-card__todo {
  margin-top: 14px; font-size: 13.5px; color: var(--ink-4);
  font-family: var(--font-mono); letter-spacing: .02em;
}
/* 壁垒行只有一条上边框做分隔，**不加「壁垒」标签** —— 正文多半以「壁垒在…」开头，
   标签和正文会连着读成「壁垒壁垒在设备与收率」。上边框 + 略低的字号已经够分区。 */
.kb-card__moat {
  margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--line);
  font-size: 13.6px; color: var(--ink-2); line-height: 1.7;
}
/* also = 这份材料同时讲到、但不作为锚点的节点。虚线小字，与主锚点明确分开 */
.kb-card__alsoes { margin-top: 14px; }
.kb-card__also {
  display: inline-block; margin: 0 8px 6px 0; font-size: 12.4px; color: var(--ink-4);
  border-bottom: 1px dashed var(--line-strong);
}
.kb-card__also:hover { color: var(--teal); }
.kb-card__foot {
  margin-top: auto; padding-top: 22px;
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; flex-wrap: wrap;
}
.kb-card__node { font-size: 12.6px; color: var(--ink-3); }
.kb-card__node:hover { color: var(--teal); }

@media (max-width: 1080px) { .kb-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 720px)  { .kb-grid { grid-template-columns: minmax(0, 1fr); } .kb-card { padding: 22px; } }

/* Comparison table */
.ctable { border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; background: var(--panel); }
.ctable table { font-size: 14px; min-width: 720px; }
.ctable th, .ctable td { padding: 15px 18px; text-align: left; border-bottom: 1px solid var(--line); vertical-align: top; }
.ctable thead th {
  background: rgba(255, 255, 255, 0.025);
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-3);
  font-weight: 500;
  white-space: nowrap;
}
.ctable tbody tr:last-child td { border-bottom: 0; }
.ctable tbody tr:hover td { background: rgba(255, 255, 255, 0.017); }
.ctable td:first-child { color: var(--ink); font-weight: 550; white-space: nowrap; }
.ctable td { color: var(--ink-2); }
.ctable .hl { color: var(--teal); }
.ctable--scroll { overflow-x: auto; }
/* 横向滚动容器：两侧硬边缘截断会让用户以为"内容就到这里"。用 12px 渐隐明确
   传达"还能滑"。本站的响应式设计本就依赖横滑（表格与标签栏），这一层提示
   是必要的可用性信号，不只是装饰。 */
.ctable--scroll {
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 12px, #000 calc(100% - 12px), transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 12px, #000 calc(100% - 12px), transparent 100%);
}

/* --------------------------------------------------------------------------
   9b. Material fingerprint chart (transfer.html)

       双谱叠加图。曲线由 lab 原型迁入时按 transfer 页的两栏版式重排：
       viewBox 从 460 压到 400、绘图区从 296 收到 210，整体高度约为原型的
       6 成，让它能塞进转让页的节奏而不抢「放大阶梯」的位置。
   -------------------------------------------------------------------------- */
.fp {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 330px;
  gap: 24px;
  align-items: start;
}
.fp__chart {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 18px 20px 14px;
  min-width: 0;
}
.fp__legend {
  display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
  font-size: 12.5px; color: var(--ink-2); margin-bottom: 8px;
}
.lg { display: inline-flex; align-items: center; gap: 7px; }
.lg i { width: 16px; height: 3px; border-radius: 2px; display: inline-block; }
.lg--base i { background: var(--ink-3); }
.lg--cand i { background: var(--teal); }
.lg--diff i { background: var(--red); height: 11px; border-radius: 3px; opacity: .55; }
.fp__unit {
  margin-left: auto; color: var(--ink-4); font-size: 11.5px;
  border: 1px dashed var(--line-strong); border-radius: 999px; padding: 2px 10px;
}

.fp__plot { width: 100%; }
.fp__plot svg { display: block; width: 100%; height: auto; }

.fp__grid-line { stroke: var(--line); stroke-width: 1; }
.fp__axis { stroke: var(--line-strong); stroke-width: 1; }
.fp__tick { fill: var(--ink-4); font-size: 11px; }
.fp__axis-title { fill: var(--ink-3); font-size: 12px; }

/* 描线：dasharray 取路径实际长度，dashoffset 归零即画出来 */
.fp__curve { stroke-linecap: round; stroke-linejoin: round; fill: none; }
.fp__curve--base { stroke: var(--ink-3); stroke-width: 2; }
.fp__curve--cand { stroke: var(--teal); stroke-width: 2; }

.fp__band {
  fill: var(--red-a10); stroke: var(--red); stroke-width: 1; stroke-opacity: .45;
  opacity: 0; transition: opacity .5s ease;
}
.fp__band.is-on { opacity: 1; }
.fp__band-cap { stroke: var(--red); stroke-width: 2; stroke-linecap: round; opacity: 0; transition: opacity .5s ease; }
.fp__band-cap.is-on { opacity: .9; }

.fp__note { opacity: 0; transform: translateY(5px); transition: opacity .45s ease, transform .45s ease; }
.fp__note.is-on { opacity: 1; transform: none; }
.fp__note-badge { fill: var(--red); }
.fp__note-badge-t { fill: var(--bg); font-size: 12px; font-weight: 700; }
.fp__note-text { fill: var(--ink); font-size: 12.5px; font-weight: 600; }
.fp__note-sub { fill: var(--ink-3); font-size: 11.5px; }
.fp__note-leader { stroke: var(--line-strong); stroke-width: 1; stroke-dasharray: 3 3; }

.fp__axis-note {
  margin-top: 10px; padding-top: 10px;
  border-top: 1px solid var(--line);
  color: var(--ink-3); font-size: 12px; line-height: 1.7;
}

.fp__side { display: flex; flex-direction: column; gap: 14px; }
.fp__find {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: 16px 18px;
}
.fp__find-k { display: block; font-size: 13.5px; color: var(--ink); margin-bottom: 12px; }
.fp__find-list { list-style: none; padding: 0; margin: 0; display: grid; gap: 11px; }
.fp__find-list li {
  display: grid; grid-template-columns: 18px 1fr; gap: 9px;
  font-size: 12.5px; color: var(--ink-3); line-height: 1.65;
}
.fp__find-list b { color: var(--red); font-size: 12px; }
.fp__find-t { color: var(--ink); }
.fp__side-note {
  background: var(--panel-2); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: 14px 16px;
  font-size: 12.5px; color: var(--ink-3); line-height: 1.75;
}

/* --------------------------------------------------------------------------
   10. Case cards
   -------------------------------------------------------------------------- */
.cases { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px; }
.case {
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 28px;
  transition: border-color var(--dur-2), transform var(--dur-2) var(--ease), background-color var(--dur-2);
}
.case:hover { border-color: var(--line-strong); transform: translateY(-3px); background: var(--panel-2); }
.case__top { display: flex; align-items: center; justify-content: space-between; gap: 14px; }
.case__ind {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.case h3 { margin-top: 20px; font-size: 19px; }
.case__row { margin-top: 18px; display: grid; grid-template-columns: 62px minmax(0, 1fr); gap: 14px; font-size: 14.2px; }
.case__row .k {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-4);
  padding-top: 4px;
}
.case__row .v { color: var(--ink-2); line-height: 1.72; }
.case__kpis {
  margin-top: auto;
  padding-top: 22px;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: 10px;
  overflow: hidden;
}
.case__kpi { background: var(--bg); padding: 13px 12px; text-align: center; }
.case__kpi .v { font-size: 19px; font-weight: 600; color: var(--teal); letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.case__kpi .k { margin-top: 5px; font-size: 11.5px; color: var(--ink-3); line-height: 1.4; }

/* Quote / testimonial */
.quotes { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px; }
.quote {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 28px;
  display: flex;
  flex-direction: column;
  gap: 20px;
}
.quote__mark { color: var(--teal); opacity: 0.5; }
.quote p { font-size: 15px; color: var(--ink); line-height: 1.75; }
.quote__by { margin-top: auto; padding-top: 18px; border-top: 1px solid var(--line); font-size: 13px; color: var(--ink-3); }
.quote__by b { display: block; color: var(--ink-2); font-weight: 550; margin-bottom: 3px; }

/* --------------------------------------------------------------------------
   11. Matrix (capability × industry)
   -------------------------------------------------------------------------- */
.matrix { border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; background: var(--panel); }
.matrix table { font-size: 13.5px; }
.matrix th, .matrix td { padding: 14px 16px; border-bottom: 1px solid var(--line); text-align: center; }
.matrix thead th {
  background: rgba(255, 255, 255, 0.025);
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
  font-weight: 500;
}
.matrix thead th:first-child, .matrix tbody th {
  text-align: left;
  font-family: var(--font-sans);
  font-size: 14px;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink);
  font-weight: 550;
  white-space: nowrap;
}
.matrix tbody tr:last-child th, .matrix tbody tr:last-child td { border-bottom: 0; }
.lvl { display: inline-flex; gap: 3px; }
.lvl i { width: 7px; height: 7px; border-radius: 2px; background: rgba(255, 255, 255, 0.1); }
.lvl i.on { background: var(--teal); }
.lvl i.on-2 { background: var(--teal-dim); }
.matrix__legend { display: flex; gap: 18px; flex-wrap: wrap; font-size: 12px; color: var(--ink-3); margin-top: 14px; }
.matrix__legend span { display: inline-flex; align-items: center; gap: 7px; }

/* --------------------------------------------------------------------------
   12. About — facts, timeline, team
   -------------------------------------------------------------------------- */
.timeline { position: relative; padding-left: 26px; }
.timeline::before {
  content: "";
  position: absolute;
  left: 4px;
  top: 6px;
  bottom: 6px;
  width: 1px;
  background: linear-gradient(180deg, var(--teal-dim), var(--line) 60%, transparent);
}
.tl { position: relative; padding-bottom: 34px; }
.tl:last-child { padding-bottom: 0; }
.tl::before {
  content: "";
  position: absolute;
  left: -26px;
  top: 6px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--bg);
  border: 2px solid var(--teal-dim);
}
.tl:first-child::before { background: var(--teal); border-color: var(--teal); box-shadow: 0 0 12px rgba(47, 224, 192, 0.7); }
.tl__y { font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.12em; color: var(--teal); }
.tl h4 { margin-top: 8px; font-size: 16.5px; }
.tl p { margin-top: 8px; font-size: 14.2px; color: var(--ink-2); max-width: 66ch; }

.team { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.team__item { background: var(--bg); padding: 26px 22px; }
.team__v { font-size: 26px; font-weight: 600; color: var(--teal); letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.team__k { margin-top: 9px; font-size: 13.5px; color: var(--ink-2); }

/* Fact blocks */
.facts { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px; }
.fact { border: 1px solid var(--line); border-radius: var(--r); background: var(--panel); padding: 26px; }
.fact h4 { font-size: 15.5px; }
.fact p { margin-top: 12px; font-size: 14.2px; color: var(--ink-2); line-height: 1.72; }

/* --------------------------------------------------------------------------
   13. Contact page
   -------------------------------------------------------------------------- */
.contact-grid { display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr); gap: 26px; align-items: start; }
.form-card {
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--panel);
  padding: clamp(26px, 3.2vw, 38px);
}
.form-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px; }
.form-grid .span-2 { grid-column: 1 / -1; }

.infolist { display: flex; flex-direction: column; gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.info { background: var(--panel); padding: 22px 24px; display: flex; gap: 16px; }
.info__ico {
  flex: none;
  width: 36px;
  height: 36px;
  border-radius: 9px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line-strong);
  background: rgba(255, 255, 255, 0.03);
  color: var(--teal);
}
.info__ico svg { width: 17px; height: 17px; }
.info__k {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.info__v { margin-top: 7px; font-size: 15px; color: var(--ink); line-height: 1.6; }
.info__v a:hover { color: var(--teal); }
.info__s { margin-top: 5px; font-size: 12.5px; color: var(--ink-3); }

.map {
  position: relative;
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow: hidden;
  background: var(--panel);
  height: 260px;
  display: grid;
  place-items: center;
}
.map__grid {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(to right, rgba(255, 255, 255, 0.05) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(255, 255, 255, 0.05) 1px, transparent 1px);
  background-size: 34px 34px;
}
.map__pin { position: relative; z-index: var(--z-content); text-align: center; }
.map__dot {
  width: 12px; height: 12px;
  border-radius: 50%;
  background: var(--teal);
  margin: 0 auto 14px;
  box-shadow: 0 0 0 6px rgba(47, 224, 192, 0.12), 0 0 24px rgba(47, 224, 192, 0.5);
}
.map__txt { font-family: var(--font-mono); font-size: 11.5px; letter-spacing: 0.1em; color: var(--ink-2); }
.map__sub { margin-top: 6px; font-size: 12px; color: var(--ink-4); }

/* Service tier cards */
.tiers { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px; align-items: stretch; }
.tier {
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--panel);
  padding: 28px;
  display: flex;
  flex-direction: column;
  transition: border-color var(--dur-2), transform var(--dur-2) var(--ease);
}
.tier:hover { border-color: var(--line-strong); transform: translateY(-3px); }
.tier--featured {
  border-color: var(--line-accent);
  background: linear-gradient(180deg, rgba(47, 224, 192, 0.06), transparent 55%), var(--panel);
}
.tier h3 { margin-top: 18px; font-size: 20px; }
.tier__sub { margin-top: 10px; font-size: 14px; color: var(--ink-2); line-height: 1.7; }
.tier__list { margin-top: 22px; }
.tier__foot { margin-top: auto; padding-top: 24px; }
.tier__badge {
  position: absolute;
  top: 16px;
  right: 16px;
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--teal);
  border: 1px solid var(--line-accent);
  background: rgba(7, 8, 10, 0.8);
  padding: 4px 9px;
  border-radius: var(--r-pill);
}
.tier { position: relative; }

/* --------------------------------------------------------------------------
   14. Responsive
   -------------------------------------------------------------------------- */
@media (max-width: 1080px) {
  .hero__grid { grid-template-columns: minmax(0, 1fr); gap: 44px; }
  .hero__copy { max-width: 100%; }
  .hero::after { display: none; }
  .dash__float { right: 16px; }
  .steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .exp-grid { grid-template-columns: minmax(0, 1fr); }
  .exp-main { border-right: 0; border-bottom: 1px solid var(--line); }
  .sol__body { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .calc__grid { grid-template-columns: minmax(0, 1fr); }
  .calc__out { border-left: 0; border-top: 1px solid var(--line); }
  .contact-grid { grid-template-columns: minmax(0, 1fr); }
  .team { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .quotes { grid-template-columns: minmax(0, 1fr); }
  .fp { grid-template-columns: minmax(0, 1fr); }
  .fp__side { flex-direction: row; flex-wrap: wrap; }
  .fp__find, .fp__side-note { flex: 1 1 300px; }
}

@media (max-width: 900px) {
  .caps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cases { grid-template-columns: minmax(0, 1fr); }
  .tiers { grid-template-columns: minmax(0, 1fr); }
  .facts { grid-template-columns: minmax(0, 1fr); }
  .tier__badge { position: static; display: inline-block; margin-bottom: 4px; }
}

/* 谱图按 viewBox 等比缩放，窄屏上缩到约 1/3，12px 的标注文字实际只剩 4px，
   等于没有。窄屏改为只保留放大的序号圆点，文字交给右侧/下方的明细列表。
   放大后的圆点仍与明细按从左到右的顺序一一对应。 */
@media (max-width: 760px) {
  .fp__note-text, .fp__note-sub { display: none; }
  .fp__note-badge { r: 30px; }
  .fp__note-badge-t { font-size: 36px; }
  .fp__note-leader { stroke-width: 2; stroke-dasharray: 5 5; }
}

@media (max-width: 720px) {
  .mtiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .sol__head { grid-template-columns: minmax(0, 1fr); gap: 12px; }
  .sol__body { grid-template-columns: minmax(0, 1fr); }
  .steps { grid-template-columns: minmax(0, 1fr); }
  .step__n::after { content: " / 05"; }
  .form-grid { grid-template-columns: minmax(0, 1fr); }
  .kpis { grid-template-columns: minmax(0, 1fr); }
  .case__kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (max-width: 640px) {
  .caps { grid-template-columns: minmax(0, 1fr); }
  .cap { min-height: 0; }
  .dash__body { padding: 14px; }
  .hero__proof { gap: 22px; }
  .hero__proof .v { font-size: 18px; }
  .team { grid-template-columns: minmax(0, 1fr); }
  .vstep { grid-template-columns: minmax(0, 1fr); gap: 14px; }
  .case { padding: 22px; }
  .dash__float { right: 12px; bottom: -13px; font-size: 10px; }
  /* 窄屏下图区只有 ~330px 宽，标注按比例贴两边，中间留给曲线 */
  .chart__lab { font-size: 9px; letter-spacing: 0.04em; }
}

/* ≤420px：看板标题条放不下「SCATTER · PW-214 / Process window」整行，
   去掉副标题只留主标；414px 以上本来放得下，隐藏副标题也无副作用。 */
@media (max-width: 420px) {
  .dash__id-sub { display: none; }
}

/* --------------------------------------------------------------------------
   产业概览 demo —— chemical-info 框架演示（仅首页 #industry）
   外框是"图框"：bracket 角标 + 顶栏（路由 + 视图切换）+ 视图区 + 底注。
   -------------------------------------------------------------------------- */
.iov {
  margin-top: 44px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--panel);
  /* bracket 角标画在 -1px 处，不能被 overflow 裁掉 */
  overflow: visible;
}
.iov__bar {
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 12px 20px;
  border-bottom: 1px solid var(--line);
  background: var(--panel-2);
  border-radius: var(--r-sm) var(--r-sm) 0 0;
}
.iov__route {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  color: var(--ink-3);
  white-space: nowrap;
}
.iov__route b { color: var(--teal); font-weight: 500; }
.iov__tabs { display: flex; gap: 2px; margin-left: auto; }
.iov__tab {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--ink-3);
  font: 600 13px/1 var(--font-sans);
  padding: 9px 14px;
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: color var(--dur-1), background-color var(--dur-1);
}
.iov__tab:hover { color: var(--ink); background: var(--tint, rgba(255, 255, 255, 0.04)); }
.iov__tab.is-on { color: var(--teal); background: var(--teal-a08); }
.iov__demo {
  border: 1px solid var(--line-strong);
  border-radius: 4px;
  color: var(--ink-3);
  white-space: nowrap;
}
.iov__view { min-height: 0; }

/* 底注 */
.iov__foot {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  padding: 10px 20px;
  border-top: 1px solid var(--line);
  background: var(--panel-2);
  border-radius: 0 0 var(--r-sm) var(--r-sm);
}
.iov__foot span { font-size: 10.5px; color: var(--ink-4); }

/* 视图 1：产业链 8 层级 */
.iov-layers {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1px;
  background: var(--line);
  border-bottom: 1px solid var(--line);
}
.iov-layer {
  appearance: none;
  border: 0;
  text-align: left;
  background: var(--panel);
  padding: 20px 20px 18px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  cursor: pointer;
  transition: background-color var(--dur-1);
}
.iov-layer:hover { background: var(--panel-2); }
.iov-layer__no { font-size: 10.5px; color: var(--ink-4); }
.iov-layer__cn { font-size: 16.5px; font-weight: 600; color: var(--ink); }
.iov-layer__code { font-size: 10px; color: var(--ink-4); letter-spacing: 0.08em; }
.iov-layer__bar { height: 3px; background: var(--tint, rgba(255, 255, 255, 0.05)); margin-top: 6px; }
.iov-layer__bar i { display: block; height: 100%; background: var(--teal); opacity: 0.75; }
.iov-layer__n { font-size: 11.5px; color: var(--ink-3); }
.iov-layer__n b { color: var(--ink); font-weight: 600; }

/* 视图 2：节点速查 */
.iov-tools {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  padding: 16px 20px 0;
}
.iov__search {
  flex: 1 1 260px;
  min-width: 0;
  height: 38px;
  padding: 0 14px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--panel-2);
  color: var(--ink);
  font-size: 13.5px;
}
.iov__search::placeholder { color: var(--ink-4); }
.iov__search:focus { outline: none; border-color: var(--line-accent); box-shadow: 0 0 0 3px var(--teal-a08); }
.iov-bands { display: flex; gap: 6px; flex-wrap: wrap; }
.iov-chip {
  appearance: none;
  border: 1px solid var(--line-strong);
  border-radius: 4px;
  background: transparent;
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  padding: 8px 12px;
  cursor: pointer;
  transition: color var(--dur-1), border-color var(--dur-1), background-color var(--dur-1);
}
.iov-chip:hover { color: var(--ink); }
.iov-chip.is-on { color: var(--teal); border-color: var(--line-accent); background: var(--teal-a08); }
.iov-count { padding: 12px 20px 10px; font-size: 10.5px; color: var(--ink-4); }
.iov-rows { display: flex; flex-direction: column; }
.iov-row {
  appearance: none;
  border: 0;
  border-top: 1px solid var(--line);
  background: transparent;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding: 14px 20px;
  text-align: left;
  cursor: pointer;
  transition: background-color var(--dur-1);
}
.iov-row:hover { background: var(--panel-2); }
.iov-row__main { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.iov-row__cn { font-size: 15px; font-weight: 600; color: var(--ink); }
.iov-row__meta { font-size: 11.5px; color: var(--ink-4); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.iov-row__tags { display: flex; gap: 6px; flex-wrap: wrap; }
.iov-ss { display: flex; align-items: center; gap: 12px; flex: none; }
.iov-ss__bar { width: 88px; height: 4px; background: var(--tint, rgba(255, 255, 255, 0.05)); }
.iov-ss__bar i { display: block; height: 100%; background: var(--teal); }
.iov-ss b { font-family: var(--font-mono); font-size: 19px; font-weight: 500; color: var(--ink); font-variant-numeric: tabular-nums; }
.iov-ss b i { font-style: normal; font-size: 12px; color: var(--ink-4); margin-left: 2px; }
.iov-empty { padding: 28px 20px 34px; color: var(--ink-3); font-size: 13.5px; }

/* 视图 3：卡脖子 */
.iov-bns { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1px; background: var(--line); }
.iov-bngrp { background: var(--panel); padding: 18px 18px 20px; display: flex; flex-direction: column; gap: 10px; }
.iov-bngrp__head { display: flex; align-items: center; gap: 10px; margin-bottom: 4px; }
.iov-bngrp__head .mono { font-size: 10px; color: var(--ink-4); }
.iov-bncard {
  appearance: none;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--panel-2);
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "cn ss" "imp ss";
  gap: 2px 12px;
  padding: 12px 14px;
  text-align: left;
  cursor: pointer;
  transition: border-color var(--dur-1), background-color var(--dur-1);
}
.iov-bncard:hover { border-color: var(--line-strong); background: var(--panel-3); }
.iov-bncard__cn { grid-area: cn; font-size: 13.5px; font-weight: 600; color: var(--ink); }
.iov-bncard__imp { grid-area: imp; font-size: 11px; color: var(--ink-4); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.iov-bncard__ss { grid-area: ss; align-self: center; font-family: var(--font-mono); font-size: 21px; font-weight: 500; color: var(--ink); font-variant-numeric: tabular-nums; }
.iov-bncard__ss i { font-style: normal; font-size: 12px; color: var(--ink-4); }

/* 详情 */
.iov-detail { padding: 20px 20px 24px; }
.iov-back {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--teal);
  font-size: 13px;
  font-weight: 550;
  padding: 0;
  margin-bottom: 14px;
  cursor: pointer;
}
.iov-back:hover { text-decoration: underline; }
.iov-detail__head h3 { display: flex; align-items: center; gap: 10px; font-size: 21px; font-weight: 600; letter-spacing: 0; }
.iov-detail__head .mono { margin-top: 7px; color: var(--ink-4); letter-spacing: 0.06em; }
.iov-caps {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  overflow: hidden;
  margin-top: 18px;
}
.iov-cap { background: var(--panel-2); padding: 14px 16px; display: flex; flex-direction: column; gap: 6px; }
.iov-cap__label { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.12em; color: var(--ink-3); }
.iov-cap__val { font-family: var(--font-mono); font-size: 21px; color: var(--ink); font-variant-numeric: tabular-nums; }
.iov-cap__val b { font-weight: 500; }
.iov-cap__val i { font-style: normal; font-size: 11.5px; color: var(--ink-4); margin-left: 3px; }
.iov-kvs { margin-top: 18px; border-top: 1px solid var(--line); }
.iov-kv { display: grid; grid-template-columns: 130px minmax(0, 1fr); gap: 16px; padding: 11px 2px; border-bottom: 1px solid var(--line); }
.iov-kv__k { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.08em; color: var(--ink-3); padding-top: 2px; }
.iov-kv__v { font-size: 13.5px; color: var(--ink-2); line-height: 1.65; }
.iov-bn {
  margin-top: 18px;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-left: 2px solid var(--red);
  border-radius: var(--r-sm);
  background: var(--red-a10);
}
.iov-bn--orange { border-left-color: var(--amber); background: var(--amber-a12); }
.iov-bn--yellow { border-left-color: var(--blue); background: var(--blue-a12); }
.iov-bn__head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 6px; }
.iov-bn__head b { font-size: 13.5px; color: var(--ink); }
.iov-bn__head .mono { font-size: 10.5px; color: var(--ink-4); }
.iov-bn p { font-size: 13px; color: var(--ink-2); line-height: 1.7; }
.iov-src { margin-top: 16px; font-size: 10px; color: var(--ink-4); }

/* 标签 */
.iov-tag {
  display: inline-flex;
  align-items: center;
  padding: 2.5px 8px;
  border: 1px solid var(--line-strong);
  border-radius: 3px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  color: var(--ink-3);
  white-space: nowrap;
}
.iov-tag--red    { color: var(--red);   border-color: color-mix(in srgb, var(--red) 40%, transparent);   background: var(--red-a10); }
.iov-tag--orange { color: var(--amber); border-color: color-mix(in srgb, var(--amber) 40%, transparent); background: var(--amber-a12); }
.iov-tag--yellow { color: var(--blue);  border-color: color-mix(in srgb, var(--blue) 40%, transparent);  background: var(--blue-a12); }

/* 响应式 */
@media (max-width: 1080px) {
  .iov-layers { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .iov-bns { grid-template-columns: minmax(0, 1fr); }
  .iov-caps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 720px) {
  .iov__bar { flex-wrap: wrap; gap: 10px; padding: 10px 14px; }
  .iov__route { display: none; }
  .iov__tabs { margin-left: 0; }
  .iov__demo { margin-left: auto; }
  .iov__view { min-height: 0; }
  .iov-row { gap: 12px; }
  .iov-ss__bar { width: 52px; }
  .iov-ss b { font-size: 16px; }
  .iov-layer { padding: 14px 16px 12px; }
  .iov-detail { padding: 16px 14px 20px; }
  .iov-kv { grid-template-columns: 96px minmax(0, 1fr); gap: 10px; }
  .iov-caps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* 图谱视图（力导向 canvas） */
.iov-graph-wrap { padding: 18px 20px 20px; }
.iov-graph-head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}
.iov-graph-head b { font-size: 16px; font-weight: 600; color: var(--ink); }
.iov-graph-head .mono { font-size: 10.5px; color: var(--ink-4); }
.iov-graph { position: relative; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--panel-2); overflow: hidden; }
.iov-graph canvas { display: block; touch-action: none; }
.iov-graph__tip {
  position: absolute;
  pointer-events: none;
  max-width: 220px;
  padding: 8px 11px;
  border: 1px solid var(--line-strong);
  border-radius: 6px;
  background: var(--tip-bg, var(--panel-3));
  box-shadow: 0 10px 26px -14px rgba(0, 0, 0, 0.6);
  font-size: 12px;
  line-height: 1.55;
  color: var(--ink);
}
.iov-graph__tip i { font-style: normal; color: var(--ink-4); font-size: 11px; }
.iov-graph-legend {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  margin-top: 12px;
}
.iov-graph-legend__item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11.5px;
  color: var(--ink-3);
}
.iov-graph-legend__item i {
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--panel);
  border: 1.6px solid var(--ink-3);
}
.iov-graph-legend__item i[data-l="base_organic"]  { border-color: var(--teal); }
.iov-graph-legend__item i[data-l="intermediate"] { border-color: var(--blue); }
.iov-graph-legend__item i[data-l="polymer"]      { border-color: var(--violet); }
.iov-graph-legend__item i[data-l="fine_chemical"]{ border-color: var(--amber); }
.iov-graph-legend__note { margin-left: auto; font-size: 10px; color: var(--ink-4); }
.iov-detail__top { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; margin-bottom: 14px; }
.iov-detail__top .iov-back { margin-bottom: 0; }
@media (max-width: 720px) {
  .iov-graph-wrap { padding: 14px 12px 16px; }
  .iov-graph-legend__note { margin-left: 0; flex-basis: 100%; }
}

/* 事件层（P0）：图层 chips + 事件时间线 */
.iov-evchips {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}
.iov-evchips .iov-chip b { font-weight: 500; opacity: 0.72; margin-left: 2px; }
.iov-events { margin-top: 14px; border-top: 1px solid var(--line); }
.iov-events__head { padding: 10px 20px 8px; font-size: 10px; color: var(--ink-4); }
.iov-event-row {
  appearance: none;
  border: 0;
  border-top: 1px solid var(--line);
  background: transparent;
  width: 100%;
  display: grid;
  grid-template-columns: 84px auto minmax(0, 1fr) auto;
  gap: 4px 12px;
  align-items: center;
  padding: 10px 20px;
  text-align: left;
  cursor: pointer;
  transition: background-color var(--dur-1);
}
.iov-event-row:hover { background: var(--panel-2); }
.iov-event-row__date { font-size: 10.5px; color: var(--ink-4); }
.iov-event-row__badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 17px; height: 17px;
  border-radius: 50%;
  font-size: 9px;
  font-weight: 600;
  color: #fff;
}
.iov-event-row__badge.sev-critical { background: var(--red); }
.iov-event-row__badge.sev-high,
.iov-event-row__badge.sev-elevated { background: var(--amber); }
.iov-event-row__badge.sev-watch,
.iov-event-row__badge.sev-info { background: var(--blue); }
.iov-event-row__title {
  font-size: 13px;
  color: var(--ink-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.iov-event-row__title .iov-tag { margin-left: 6px; vertical-align: 1px; }
.iov-event-row__meta { font-size: 10px; color: var(--ink-4); white-space: nowrap; }
.iov-events__more {
  appearance: none;
  border: 0; border-top: 1px solid var(--line);
  background: transparent;
  width: 100%;
  padding: 9px 20px;
  color: var(--teal);
  font-size: 11px;
  text-align: left;
  cursor: pointer;
}
.iov-events__more:hover { text-decoration: underline; }
@media (max-width: 720px) {
  .iov-event-row { grid-template-columns: 70px auto minmax(0, 1fr); }
  .iov-event-row__meta { display: none; }
}

/* --------------------------------------------------------------------------
   Material chains — 四条链总览页（chain-index）与子页（chain-puhe 等）
   复用 .edge / .bracket 等已实施的设计语言；样式与现有 ipcard / case 同源。
   ------------------------------------------------------------------------- */
.chain-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 18px;
}
.chain-card {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 24px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r);
  color: var(--ink);
  text-decoration: none;
  transition: border-color var(--dur-1), background-color var(--dur-1), transform var(--dur-2) var(--ease);
}
.chain-card:hover,
.chain-card:focus-visible {
  border-color: var(--line-strong);
  background: var(--panel-2);
  transform: translateY(-3px);
}
.chain-card__head { display: flex; align-items: center; gap: 10px; }
.chain-card__no {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  color: var(--teal);
}
.chain-card__pill {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  padding: 3px 9px;
  border-radius: var(--r-pill);
  border: 1px solid var(--line);
  color: var(--ink-3);
  text-transform: uppercase;
}
.chain-card__t { margin: 4px 0 0; font-size: 20px; line-height: 1.25; letter-spacing: -0.01em; }
.chain-card__sub {
  margin: 0;
  color: var(--ink-3);
  font-size: 13px;
  line-height: 1.55;
}
.chain-card__nodes {
  margin: 6px 0 0;
  padding-left: 18px;
  color: var(--ink-2);
  font-size: 13.5px;
  line-height: 1.7;
}
.chain-card__nodes li { padding-left: 2px; }
.chain-card__nodes li::marker { color: var(--teal); }
.chain-card__cta {
  margin-top: auto;
  padding-top: 14px;
  border-top: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.08em;
  color: var(--teal);
}
.chain-note {
  font-size: 12.5px;
  color: var(--ink-3);
  line-height: 1.7;
  border-left: 2px solid var(--line-strong);
  padding-left: 14px;
}
@media (max-width: 720px) {
  .chain-grid { grid-template-columns: 1fr; }
}

/* 子页节点卡：参照首页 iov__layers 卡片样式，与 .tc-chain 同源（节点卡模板） */
.node-card {
  position: relative;
  padding: 26px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r);
}
.node-card__head { display: flex; align-items: baseline; gap: 14px; margin-bottom: 14px; }
.node-card__no {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  color: var(--teal);
  flex: none;
}
.node-card__t { margin: 0; font-size: 22px; line-height: 1.2; letter-spacing: -0.01em; }
.node-card__sub { margin: 4px 0 0; color: var(--ink-3); font-size: 13.5px; line-height: 1.55; }
.node-card__body {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 18px;
  padding-top: 18px;
  border-top: 1px solid var(--line);
}
.node-card__col { display: flex; flex-direction: column; gap: 6px; }
.node-card__col h4 {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.12em;
  color: var(--teal);
  text-transform: uppercase;
  font-weight: 600;
}
.node-card__col p { margin: 0; color: var(--ink-2); font-size: 13.5px; line-height: 1.65; }
.node-card__foot {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 18px;
  margin-top: 18px;
  padding-top: 18px;
  border-top: 1px solid var(--line);
}
.node-card__meta { display: flex; flex-direction: column; gap: 6px; }
.node-card__meta h4 {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.12em;
  color: var(--amber);
  text-transform: uppercase;
  font-weight: 600;
}
.node-card__meta p { margin: 0; color: var(--ink-2); font-size: 13px; line-height: 1.65; }
@media (max-width: 720px) {
  .node-card__body, .node-card__foot { grid-template-columns: 1fr; }
}

/* --------------------------------------------------------------------------
   Chain graph — 4 条材料产业链共享的力导向 canvas
   控件条（中心节点下拉 / 回到上一中心 / 简洁模式）横跨整行，下方是
   canvas 与右侧节点信息面板两栏；720px 以下全部单列。
   ------------------------------------------------------------------------- */
.graph-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 16px;
  padding: 12px 16px;
  margin-bottom: 14px;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--panel);
}
.graph-ctl { display: flex; align-items: center; gap: 8px; min-width: 0; }
.graph-ctl__k {
  flex: none;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.graph-select {
  min-width: 200px;
  max-width: 300px;
  padding: 7px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--panel-2);
  color: var(--ink);
  font-size: 13px;
  font-family: inherit;
}
.graph-select:focus-visible { outline: 2px solid var(--teal); outline-offset: 1px; }
.graph-switch { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; user-select: none; }
/* iOS 风格开关：appearance:none 把复选框变成轨道，::after 是滑块 */
.graph-switch input {
  appearance: none;
  -webkit-appearance: none;
  flex: none;
  margin: 0;
  width: 34px;
  height: 20px;
  border-radius: 999px;
  background: var(--line-strong);
  position: relative;
  cursor: pointer;
  transition: background .18s ease;
}
.graph-switch input::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .35);
  transition: transform .18s ease;
}
.graph-switch input:checked { background: var(--teal); }
.graph-switch input:checked::after { transform: translateX(14px); }
.graph-switch input:focus-visible { outline: 2px solid var(--teal); outline-offset: 2px; }
.graph-switch__txt {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
}
/* 状态行一律单行：直链视图开启后文案变长（多出「直链」与「回指 N」），
   允许折行会把工具条顶高一格、把下方画布挤下去。min-width:0 + 省略号是
   兜底——空间真的不够时截断并由 title 显示全文，而不是换行。 */
.graph-stat {
  margin-left: auto;
  color: var(--ink-4);
  font-size: 11px;
  white-space: nowrap;
  min-width: 0;
  flex: 0 1 auto;
  overflow: hidden;
  text-overflow: ellipsis;
}
.btn--sm { padding: 7px 14px; font-size: 13px; }
.graph-wrap {
  display: grid;
  /* 图谱优先：canvas 占约 77%（相对旧 1.6fr 的 +25%），右侧两个面板缩到约 23% */
  grid-template-columns: minmax(0, 3.33fr) minmax(0, 1fr);
  gap: 22px;
  align-items: start;
}
.graph-canvas-frame {
  position: relative;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--panel);
  overflow: hidden;
  /* 高度声明在这一层：chain-graph.js 的 resize() 读的是 canvas 的父元素
     （就是本框）的 computed height。原先高度只写在 .graph-canvas 上，
     父框会被 canvas 撑开、自身高度等于引擎上一次写的值，于是引擎读到
     自己的旧输出形成自锁，只能退回视口分档。声明在父框上就没有这个环。 */
  height: 540px;
}
.graph-canvas {
  display: block;
  width: 100%;
  height: 100%;
  cursor: pointer;
  background: radial-gradient(ellipse 80% 60% at 50% 50%, rgba(47,224,192,0.04), transparent 70%);
}
.graph-empty {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  padding: 24px; text-align: center;
  color: var(--ink-3); font-size: 13.5px;
  background: var(--panel);
}
/* 显式让 [hidden] 生效（CSS 的 .graph-empty{display:flex} 覆盖了 UA 默认的 [hidden]{display:none}） */
.graph-empty[hidden] { display: none; }
.graph-panels { display: flex; flex-direction: column; gap: 16px; }
.graph-panel {
  padding: 18px;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--panel);
}
.graph-panel__h {
  margin: 0 0 10px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--teal);
}
.graph-panel__row {
  display: flex;
  gap: 10px;
  margin: 0 0 6px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink-2);
}
.graph-panel__row b { color: var(--ink); font-weight: 600; }
.graph-panel__row .k {
  flex: none;
  width: 64px;
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.05em;
}

/* 转让机会链接：与画布悬停浮窗里的「N 个转让机会」同色。
   那行是引擎 ensureStyles() 注入的 .tip-hl，用 var(--amber) —— 这里用同一个
   token，深浅两个主题自动一致，不会出现面板橙色、浮窗黄色这种错位。 */
.graph-panel__row a.graph-xfer {
  color: var(--amber);
  text-decoration: none;
  border-bottom: 1px solid transparent;
}
.graph-panel__row a.graph-xfer:hover { border-bottom-color: var(--amber); }
.graph-meta {
  margin: 0;
  color: var(--ink-3);
  font-size: 11.5px;
  text-align: center;
}
@media (max-width: 1080px) {
  /* 中档宽度收一档，避免两个面板被压到不可读（1080 视口下仍 ~300px） */
  .graph-wrap { grid-template-columns: minmax(0, 2.4fr) minmax(0, 1fr); }
}
@media (max-width: 720px) {
  .graph-wrap { grid-template-columns: 1fr; }
  .graph-canvas-frame { height: 420px; }
  /* 控件条在窄屏换行：下拉独占一行，按钮与开关并列 */
  .graph-ctl { width: 100%; }
  .graph-select { min-width: 0; max-width: none; flex: 1; }
  .graph-stat { margin-left: 0; width: 100%; }
}

/* --------------------------------------------------------------------------
   Member area（会员区 / 管理页 / VIP 弹层 / 信息图层 intel 面板）
   VIP 标识用琥珀（amber,第二声部）,不动 teal 的动作色地位。
   -------------------------------------------------------------------------- */
.member-entry {
  display: inline-flex; align-items: center; flex-shrink: 0;
  height: 32px; padding: 0 12px;
  font-size: 12.5px; color: var(--ink-2);
  background: var(--panel-2);
  border: 1px solid var(--line-strong); border-radius: 3px;
  white-space: nowrap;
  transition: color var(--dur-2), border-color var(--dur-2), background-color var(--dur-2);
}
.member-entry:hover { color: var(--teal); border-color: var(--line-accent); background: var(--panel-3); }
.member-entry.is-member {
  width: 32px; padding: 0; justify-content: center;
  color: var(--amber); border-color: var(--amber-a12); font-weight: 600;
}
.member-entry.is-member:hover { border-color: var(--amber); background: var(--amber-a12); }

.vip-chip {
  display: inline-block; padding: 2px 6px; margin-left: 6px;
  font-size: 10px; line-height: 1; letter-spacing: 0.1em;
  color: var(--amber); border: 1px solid var(--amber-a12); border-radius: 2px;
  font-family: var(--font-mono);
}
.btn.is-locked, [data-intel-real].is-locked { opacity: 0.55; cursor: help; }
[data-intel-real].is-on { color: var(--teal); border-color: var(--line-accent); }

/* intel 面板 */
.intel-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.intel-head__act { display: flex; align-items: center; gap: 12px; }
.intel-badge {
  font-size: 11.5px; color: var(--ink-3);
  border: 1px solid var(--line); border-radius: 2px; padding: 3px 8px;
  letter-spacing: 0.06em; white-space: nowrap;
}
.intel-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 14px; }
.intel-box { background: var(--panel); border: 1px solid var(--line); border-radius: 4px; padding: 16px; }
.intel-box__head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-bottom: 12px; }
.intel-box__head b { font-size: 14px; color: var(--ink); }
.intel-box__head .intel-badge { font-size: 10.5px; }
.intel-box__body { display: grid; gap: 10px; }
.intel-row { display: flex; align-items: baseline; gap: 10px; font-size: 13.5px; }
.intel-row b.is-up { color: var(--red); }
.intel-row b.is-down { color: var(--teal); }
.intel-row b.is-flat { color: var(--ink-3); }
.intel-row__id { flex: none; min-width: 130px; color: var(--ink-3); font-size: 12px; }
.intel-row__note { color: var(--ink-2); }
.intel-ev { padding: 10px 12px; background: var(--panel-2); border: 1px solid var(--line); border-radius: 3px; }
.intel-ev__head { display: flex; align-items: center; gap: 10px; margin-bottom: 6px; }
.intel-ev__cat { font-size: 11.5px; color: var(--ev-cat, var(--ink-3)); border: 1px solid var(--line); border-radius: 2px; padding: 2px 7px; }
.intel-ev__date { font-size: 11.5px; color: var(--ink-4); }
.intel-ev__demo { font-size: 10.5px; color: var(--amber); border: 1px solid var(--amber-a12); border-radius: 2px; padding: 2px 6px; }
.intel-ev b { display: block; font-size: 13.5px; color: var(--ink); margin-bottom: 4px; }
.intel-ev p { margin: 0 0 6px; font-size: 13px; color: var(--ink-2); line-height: 1.7; }
.intel-ev__src { font-size: 11.5px; color: var(--ink-4); }
.intel-ins { padding: 10px 12px; background: var(--panel-2); border: 1px solid var(--line); border-radius: 3px; }
.intel-ins__tag { display: inline-block; font-size: 11px; letter-spacing: 0.1em; color: var(--teal); border: 1px solid var(--line-accent); border-radius: 2px; padding: 2px 7px; margin-bottom: 6px; }
.intel-ins p { margin: 0; font-size: 13px; color: var(--ink-2); line-height: 1.7; }

/* VIP 权益弹层 */
.vmodal {
  position: fixed; inset: 0; z-index: 300;
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(3px);
}
.vmodal__card {
  width: min(520px, 100%); max-height: 86vh; overflow: auto;
  padding: 28px 28px 24px;
  background: var(--panel); border: 1px solid var(--line-strong); border-radius: 6px;
  box-shadow: 0 24px 64px rgba(0, 0, 0, 0.5);
}
.vmodal__card h3 { font-size: 20px; color: var(--ink); }

/* 轻提示 */
.member-toast {
  position: fixed; left: 50%; bottom: 28px;
  transform: translate(-50%, 12px);
  z-index: 320; max-width: min(480px, calc(100vw - 32px));
  padding: 10px 18px; font-size: 13.5px;
  color: var(--ink); background: var(--panel-2);
  border: 1px solid var(--line-strong); border-radius: 3px;
  opacity: 0; pointer-events: none;
  transition: opacity 0.25s, transform 0.25s;
}
.member-toast.is-on { opacity: 1; transform: translate(-50%, 0); }

/* 徽章 / 收藏行 / 需求行 */
.badge {
  display: inline-block; padding: 2px 9px; font-size: 11.5px;
  letter-spacing: 0.08em; border-radius: 2px;
  border: 1px solid var(--line-strong); color: var(--ink-3); white-space: nowrap;
  font-family: var(--font-mono);
}
.badge--vip { color: var(--amber); border-color: var(--amber-a12); }
.badge--free { color: var(--ink-4); }
.badge--admin { color: var(--red); border-color: var(--red-a10); margin-left: 6px; }

.fav-list { display: grid; gap: 8px; }
.fav-row {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 12px; background: var(--panel-2);
  border: 1px solid var(--line); border-radius: 3px;
}
.fav-row__type { flex: none; font-size: 12px; color: var(--ink-4); }
.fav-row__name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: var(--font-mono); font-size: 12.5px; }
.fav-row__del {
  flex: none; width: 22px; height: 22px; border: 1px solid var(--line-strong);
  border-radius: 50%; color: var(--ink-3); background: var(--panel); line-height: 1; cursor: pointer;
}
.fav-row__del:hover { color: var(--red); border-color: var(--red-a10); }

.req-row { padding: 10px 12px; background: var(--panel-2); border: 1px solid var(--line); border-radius: 3px; }
.req-row + .req-row { margin-top: 8px; }
.req-row__head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.req-row__status { font-size: 12px; color: var(--teal); }
.req-row__date { font-size: 12px; color: var(--ink-4); margin-left: auto; font-family: var(--font-mono); }
.req-row__type { margin: 4px 0 0; font-size: 12.5px; color: var(--ink-4); }

.admin-acts { display: flex; align-items: center; gap: 8px; white-space: nowrap; }
.admin-acts .input, .admin-acts .select { padding: 5px 9px; font-size: 12.5px; }
.linklike { text-decoration: underline; }

@media (max-width: 620px) {
  .member-entry { height: 28px; padding: 0 9px; }
  .admin-acts { flex-wrap: wrap; }
}

/* --------------------------------------------------------------------------
   空状态 / 骨架屏 / 案例筛选 / 关注节点动态 (improvement-plan B3/B4/A3/A4)
   -------------------------------------------------------------------------- */
.empty-note {
  margin: 0; padding: 18px 16px;
  border: 1px dashed var(--line);
  color: var(--ink-3);
  font-size: 13px; line-height: 1.7;
}
.empty-note::before { content: "∅ "; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--ink-4); }

.intel-skel { display: flex; flex-direction: column; gap: 12px; padding: 6px 0; }
.intel-skel__bar {
  height: 12px; border-radius: 3px;
  background: var(--panel-2);
  animation: intel-skel-pulse 1.2s ease-in-out infinite;
}
@keyframes intel-skel-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }

.case-filter { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.case-filter__chips { display: flex; flex-wrap: wrap; gap: 8px; }
.case-chip {
  font: inherit; font-size: 12.5px; padding: 5px 12px;
  background: transparent; border: 1px solid var(--line);
  color: var(--ink-2); border-radius: 4px; cursor: pointer;
  transition: border-color .15s, color .15s, background .15s;
}
.case-chip:hover { border-color: var(--teal); color: var(--ink); }
.case-chip.is-on { background: var(--teal); border-color: var(--teal); color: #04211c; font-weight: 600; }
.case-filter__search { margin-left: auto; display: flex; align-items: center; gap: 8px; }
.case-filter__search .input { min-height: 0; padding: 6px 12px; width: 220px; }
.case-filter__stat { margin: 10px 0 0; font-size: 11.5px; color: var(--ink-4); }

.dyn-list { display: flex; flex-direction: column; }
.dyn-row {
  display: grid; grid-template-columns: 210px minmax(0, 1fr);
  gap: 4px 16px; padding: 12px 0; border-bottom: 1px solid var(--line);
}
.dyn-row:last-child { border-bottom: 0; }
.dyn-row__meta { grid-column: 1; font-size: 11.5px; color: var(--ink-4); align-self: baseline; }
.dyn-row b { grid-column: 2; font-size: 14px; line-height: 1.5; }
.dyn-row__detail { grid-column: 2; font-size: 13px; color: var(--ink-3); line-height: 1.6; }
@media (max-width: 720px) {
  .dyn-row { grid-template-columns: minmax(0, 1fr); }
  .dyn-row b, .dyn-row__detail { grid-column: 1; }
  .case-filter__search { margin-left: 0; width: 100%; }
  .case-filter__search .input { width: 100%; }
}

/* --------------------------------------------------------------------------
   节点详情页 (open-items 3.2 / gen-node-pages.py 生成)
   -------------------------------------------------------------------------- */
.node-kv { display: flex; align-items: baseline; gap: 14px; padding: 7px 0; border-bottom: 1px solid var(--line); font-size: 14px; margin: 0; }
.node-kv:last-of-type { border-bottom: 0; }
.node-kv .k { flex: 0 0 8.5em; color: var(--ink-3); font-size: 12.5px; }
.node-kv .v { min-width: 0; }
.node-ev { display: grid; gap: 4px; padding: 12px 0; border-bottom: 1px solid var(--line); }
.node-ev:last-child { border-bottom: 0; }
.node-ev__meta { font-size: 11.5px; color: var(--ink-4); }
.node-ev b { font-size: 14.5px; line-height: 1.5; }
.node-ev__d { font-size: 13px; color: var(--ink-3); line-height: 1.6; }
.node-ev__src { font-size: 11.5px; color: var(--ink-4); }
.node-panel { margin-top: 14px; }
.node-panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 20px 22px;
}
.node-panel .h3 { margin: 0 0 6px; }

/* 节点页分享弹层 */
.share-modal {
  position: fixed; inset: 0; z-index: 300;
  background: rgba(6, 12, 22, .62);
  display: flex; align-items: center; justify-content: center; padding: 20px;
}
.share-modal__card {
  background: var(--panel); border: 1px solid var(--line); border-radius: 11px;
  padding: 22px 24px; max-width: 480px; width: 100%; max-height: 90vh; overflow: auto;
}
.share-modal__card h3 { margin: 0 0 14px; font-size: 17px; }
.share-modal__card img { width: 100%; height: auto; border: 1px solid var(--line); border-radius: 6px; display: block; }
.share-modal__url { font-size: 12px; color: var(--ink-3); margin: 12px 0 0; word-break: break-all; }

/* 节点速查目录(链页 + chain-index) */
.node-dir__group { margin-bottom: 14px; }
.node-dir__k { margin: 0 0 8px; font-size: 11.5px; color: var(--ink-4); }
.node-dir__k b { color: var(--ink-2); }
.node-dir__chips { display: flex; flex-wrap: wrap; gap: 8px; }
.node-link {
  display: inline-block; padding: 5px 12px;
  border: 1px solid var(--line); border-radius: 4px;
  color: var(--ink-2); text-decoration: none; font-size: 13px;
  transition: border-color .15s, color .15s;
}
.node-link:hover { border-color: var(--teal); color: var(--ink); }
.node-link--strong { color: var(--ink); font-weight: 600; border-color: var(--line-strong); }
.node-dir__details { border-top: 1px solid var(--line); padding: 14px 0; }
.node-dir__details summary { cursor: pointer; }
.node-dir__details[open] summary { padding-bottom: 4px; }

/* 节点页视觉批(A1 定位条/层级色带 + A3 sparkline) */
.node-accent { display: inline-block; width: 18px; height: 4px; margin-right: 9px; vertical-align: 2px; }
.node-pos { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.node-pos__seg {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px; padding: 4px 10px;
  border: 1px solid var(--line); border-left: 3px solid var(--lc, var(--teal));
  color: var(--ink-3); border-radius: 3px;
}
.node-pos__seg.is-here {
  color: var(--ink); border-color: var(--teal);
  background: var(--teal-a14); font-weight: 600;
}
.node-pos__ar { color: var(--ink-4); font-size: 11px; }
.spark { color: var(--teal); flex: 0 0 auto; }
.node-spark { display: flex; align-items: center; gap: 10px; margin: 4px 0 10px; }
.node-spark__cap { font-size: 11px; color: var(--ink-4); }
.fut-row .spark--line { margin-left: auto; color: var(--ink-3); }
@media (prefers-reduced-motion: no-preference) {
  .spark, .node-pos__seg { transition: opacity .15s; }
}

/* 图谱外框:工程图纸角标(四角刻度线,不进画布内部,避免干扰关系线) */
.graph-canvas-frame {
  --tick: var(--teal);
  background-image:
    linear-gradient(var(--tick), var(--tick)), linear-gradient(var(--tick), var(--tick)),
    linear-gradient(var(--tick), var(--tick)), linear-gradient(var(--tick), var(--tick)),
    linear-gradient(var(--tick), var(--tick)), linear-gradient(var(--tick), var(--tick)),
    linear-gradient(var(--tick), var(--tick)), linear-gradient(var(--tick), var(--tick));
  background-repeat: no-repeat;
  background-size: 16px 2px, 2px 16px, 16px 2px, 2px 16px, 16px 2px, 2px 16px, 16px 2px, 2px 16px;
  background-position: left 10px top 10px, left 10px top 10px,
    right 10px top 10px, right 10px top 10px,
    left 10px bottom 10px, left 10px bottom 10px,
    right 10px bottom 10px, right 10px bottom 10px;
}

/* 图签 / 件号 / 尺寸标注(工程图纸语言) */
.titleblock {
  margin: 20px 0 0 auto; border-collapse: collapse;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 10.5px; color: var(--ink-2);
}
.titleblock th, .titleblock td { border: 1px solid var(--line); padding: 4px 10px; text-align: left; font-weight: 400; }
.titleblock th { color: var(--ink-4); background: var(--panel-2); white-space: nowrap; }
.titleblock td { white-space: nowrap; }

.dim-row { display: flex; align-items: center; gap: 14px; padding: 7px 0; border-bottom: 1px solid var(--line); }
.dim-row:last-of-type { border-bottom: 0; }
.dim-row .k { flex: 0 0 8.5em; color: var(--ink-3); font-size: 12.5px; }
.dim { position: relative; flex: 1; max-width: 300px; height: 18px; }
.dim::before, .dim::after {
  content: ""; position: absolute; top: 0; width: 1px; height: 100%;
  background: var(--line-strong);
}
.dim::before { left: 0; }
.dim::after { right: 0; }
.dim__track { position: absolute; left: 0; right: 0; top: 50%; height: 1px; background: var(--line); }
.dim__line { position: absolute; left: 0; top: 50%; height: 1.5px; width: var(--w); background: var(--teal); }
.dim__head {
  position: absolute; left: var(--w); top: 50%; transform: translateY(-50%);
  border-top: 4px solid transparent; border-bottom: 4px solid transparent;
  border-right: 6px solid var(--teal);
}
.dim__v {
  position: absolute; left: calc(var(--w) + 8px); top: 50%; transform: translateY(-50%);
  font-size: 11.5px; color: var(--ink); white-space: nowrap;
}

/* 示例印章 / 技术要求块(工程图纸语言第二批) */
.stamp {
  display: inline-block; transform: rotate(-3deg);
  border: 2px solid var(--red, #d94848); color: var(--red, #d94848);
  padding: 0 8px; font-size: 11px; font-weight: 700;
  letter-spacing: .25em; border-radius: 3px; opacity: .85; vertical-align: 2px;
}
.treq { border: 1px solid var(--line); border-left: 3px solid var(--line-strong); padding: 12px 16px; margin-top: 20px; }
.treq__h { margin: 0 0 6px; font-size: 11px; color: var(--ink-4); letter-spacing: .12em; }
.treq ol { margin: 0; padding-left: 18px; font-size: 12.5px; color: var(--ink-3); line-height: 1.9; }

/* 事件→诊断 CTA / 修订记录表(工程图纸语言) */
.node-ev__cta, .dyn-row__cta {
  color: var(--teal); text-decoration: none; font-size: 11px;
  margin-left: 10px; white-space: nowrap;
}
.node-ev__cta:hover, .dyn-row__cta:hover { text-decoration: underline; }
.rev-box { border-top: 1px solid var(--line); padding-top: 14px; }
.rev-box summary { cursor: pointer; color: var(--ink-3); font-size: 12px; }
.rev-table { width: 100%; border-collapse: collapse; margin-top: 12px; font-size: 12.5px; }
.rev-table th, .rev-table td { border: 1px solid var(--line); padding: 7px 12px; text-align: left; vertical-align: top; line-height: 1.6; }
.rev-table th { color: var(--ink-4); background: var(--panel-2); font-weight: 600; white-space: nowrap; }
.rev-table td:first-child, .rev-table td:nth-child(2) { color: var(--ink-3); white-space: nowrap; }

/* 关于我们:发展历程与公司信息暂时隐藏后,合作原则占满整幅,五条原则排两列。 */
.about-principles { max-width: 100%; }
.about-principles__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 20px;
}
@media (max-width: 760px) {
  .about-principles__grid { grid-template-columns: minmax(0, 1fr); }
}

/* 试运行声明条 —— 贴在 hero 上方，随页面上移（header 是 fixed，故放在 main 内）。
   克制处理：左侧一道 amber 细线做锚点，不加辉光，与图纸语言一致。 */
.notice-bar {
  display: flex;
  align-items: baseline;
  gap: 14px;
  padding-top: calc(var(--header-h) + 22px);
  padding-bottom: 22px;
}
.notice-bar__tag {
  flex: none;
  font-size: 11.5px;
  letter-spacing: 0.06em;
  color: var(--amber);
  background: var(--amber-a12);
  border: 1px solid rgba(255, 180, 84, 0.3);
  border-radius: var(--r-sm);
  padding: 3px 9px;
  white-space: nowrap;
}
.notice-bar__text {
  font-size: 14px;
  line-height: 1.7;
  color: var(--ink-3);
  padding-left: 14px;
  border-left: 2px solid var(--amber);
}
.notice-bar__en {
  display: block;
  margin-top: 3px;
  font-size: 11.5px;
  letter-spacing: 0.02em;
  color: var(--ink-4);
}
@media (max-width: 620px) {
  .notice-bar { flex-direction: column; gap: 8px; align-items: stretch; }
  .notice-bar__tag { align-self: flex-start; }
}

/* --------------------------------------------------------------------------
   聚氨酯耦合板（仅行业洞察页 hero）
   与首页「工艺窗口」同一槽位、同一套 .dash 仪表板语法。图由 chain-graph.js
   绘制 —— 那是 chain-puhe.html 用的同一个引擎，这里不重画任何线条，
   只保证画布尺寸与引擎一致、以及长中文标签能读。

   画布高度不能随意压：resize() 把 H 硬编码成 620/540/480 并按它跑布局，
   槽位比引擎矮就会把底部节点标签裁掉。改 resize() 会波及六个链页，所以
   这里就跟着引擎走，并用整板别处的精简把总高压到与首页那块同一量级。
   -------------------------------------------------------------------------- */
.dash--graph .dash__body { padding: 14px 15px 12px; gap: 11px; }
.dash--graph .chart--graph { padding: 10px 12px 8px; }

/* 垂直位置：首页那块图板顶几乎与 h1 顶齐平，视觉上就是"标题旁边挂一张图"。
   本页文案比首页短（453 vs 580），几何居中会把图板顶抬高 60px。
   但直接给图板 margin-top 会把网格行撑到「图板高 + margin」，
   居中余量被吃光、margin 实际等效于顶对齐，并不会真的把图板往下挪。
   正确做法是抬文案那一侧：给 .hero__copy 补上下边距，行高随之变化，
   图板在剩余空间里居中，落点就和首页一致。
   :has() 只命中「右栏挂着这块图板」的 hero，不影响首页与其他页面。 */
.dash--graph { margin-top: 0; }
.hero__grid:has(> .dash--graph) > .hero__copy { padding-bottom: 60px; }

/* 画布尺寸。
   高度跟着宿主走：chain-graph.js 的 resize() 优先读宿主的 CSS height，
   只有取不到才回退视口分档（620/540/480）。所以这里给多少就是多少。

   数值来自链页的真实比例 —— chain-puhe.html 是 869×620，宽高比 1.40。
   本板在 hero 右栏只有 483px 宽，要保持同样的扁长比例，高度就是
   483 ÷ 1.40 ≈ 345px。之前直接套用链页的 620px，等于在两倍窄的容器上
   保持同一高度，结果变成 0.78 的瘦高矩形。 */
.dash--graph .chart__scaler {
  position: relative;
  overflow: hidden;
  border-radius: 6px;
}
.dash--graph .chart__plot--graph {
  position: relative;
  width: 100%;
  height: 300px;
}
.dash--graph .chart__plot--graph canvas {
  display: block;
  width: 100%;
  height: 100%;
  touch-action: none;
  cursor: pointer;
}

/* 标题行现在要装「节点名 · N 条耦合 / N 节点」，中文比英文长，
   给它换行余量，不要 ellipsis 截成「聚氨酯硬…」 */
.dash--graph .chart__title {
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
  line-height: 1.35;
}
/* 图例两槽：左＝产业链层级（中文），右＝跳数 */
.dash--graph .chart__legend {
  flex: 0 0 auto;
  white-space: nowrap;
}
.dash--graph .dash__zone,
.dash--graph .status__zone { max-width: 46%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 状态条现在承载 role 整句，允许换行 */
.dash--graph .status__m { overflow-wrap: anywhere; }

@media (max-width: 1080px) {
  /* 单栏 hero，槽位变宽；同样按 1.40 的比例给高度 */
  .dash--graph .chart__plot--graph { height: 420px; }
}
@media (max-width: 720px) {
  /* 手机竖屏：容器约 360px 宽，1.40 比例对应约 257px，
     但那太扁读不清，这里放宽到 1.05 作为下限 */
  .dash--graph .chart__plot--graph { height: 340px; }
}
@media (max-width: 620px) {
  .dash--graph .dash__body { padding: 12px; gap: 10px; }
  .dash--graph .chart--graph { padding: 9px 10px 7px; }
}

/* --------------------------------------------------------------------------
   放大阶梯（仅技术转让页）
   阶梯线上的圆点与下方四列共用同一套 1/4 栅格（12.6 / 37.4 / 62.4 / 87.4%），
   所以图形和卡片始终对得上，不会因为容器宽度漂移。
   -------------------------------------------------------------------------- */
.ladder {
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: rgba(255, 255, 255, 0.02);
  padding: 24px 26px 20px;
}
.ladder__rungs { margin-bottom: 4px; }
.ladder__rungs svg { width: 100%; height: auto; display: block; overflow: visible; }
.ladder__base {
  stroke: var(--line);
  stroke-width: 1;
  stroke-dasharray: 3 5;
  fill: none;
}
/* 幽灵线始终画出完整阶梯：否则第一级时圆点像浮在空中，读不出「阶梯」 */
.ladder__ghost {
  stroke: var(--line);
  stroke-width: 1.5;
  fill: none;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.ladder__step {
  stroke: var(--teal);
  stroke-width: 2;
  fill: none;
  stroke-linejoin: round;
  stroke-linecap: round;
  transition: stroke-dashoffset 0.7s var(--ease);
}
.ladder__dots circle {
  fill: var(--line-strong);
  transition: fill 0.35s var(--ease-out), r 0.3s var(--ease-out);
}
.ladder__dots circle.is-on { fill: var(--teal); r: 7.5; }

.ladder__grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px;
  margin-top: 10px;
}
.ladder__rung {
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  padding: 14px 15px 15px;
  opacity: 0.5;
  transition: opacity 0.45s var(--ease-out), border-color 0.45s, background 0.45s;
}
.ladder__rung.is-on {
  opacity: 1;
  border-color: var(--line-accent);
  background: var(--teal-a08);
}
.ladder__no {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  color: var(--teal);
}
.ladder__rung h3 { margin: 6px 0 0; font-size: 15px; letter-spacing: -0.01em; }
.ladder__scale {
  margin-top: 3px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--ink-3);
}
.ladder__rung ul {
  margin: 11px 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.ladder__rung li {
  position: relative;
  padding-left: 13px;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--ink-2);
}
.ladder__rung li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 8px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--teal);
  opacity: 0.75;
}

.ladder__have {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 18px;
  border-top: 1px solid var(--line);
  padding-top: 14px;
}
.ladder__havek { font-size: 12.5px; color: var(--ink-3); white-space: nowrap; }
.ladder__havek b { color: var(--teal); font-weight: 600; }
.ladder__chips { display: flex; gap: 7px; flex-wrap: wrap; }
.chip {
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--ink-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 3px 10px;
  background: rgba(255, 255, 255, 0.03);
}
.chip--new { animation: chip-in 0.42s var(--ease-out) both; }
@keyframes chip-in {
  from { opacity: 0; transform: translateY(5px); }
  to   { opacity: 1; transform: none; }
}

@media (max-width: 900px) {
  .ladder__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 640px) {
  .ladder { padding: 18px 15px 16px; }
  .ladder__grid { grid-template-columns: minmax(0, 1fr); }
}

/* ==========================================================================
   15. 替代验证关卡漏斗（consulting.html 首屏右侧图板）
   --------------------------------------------------------------------------
   外壳 .dash / .mtiles / .chart / .status 都是全站已有组件，这里只画图内
   几何。尺寸与首页 hero 右栏那块工艺窗口图板一致（541×493），所以技术咨询
   页首与首页首屏是同一套版式，不引入第二套视觉语言。
   绘图区 480×214，随面板等比缩放。
   ========================================================================== */
.fn3 { min-width: 0; }
.fn3__svg { display: block; width: 100%; height: auto; }
.fn3__note {
  margin-top: 12px;
  color: var(--ink-3);
  font-size: 12px;
  line-height: 1.7;
}
.fn3__note b { color: var(--ink-2); }

/* 漏斗轮廓：淡填充 + 实边，剪影本身就是信息 */
.fn-funnel {
  fill: var(--teal-a08);
  stroke: var(--line-strong);
  stroke-width: 1;
}
.fn-tray {
  fill: none;
  stroke: var(--teal);
  stroke-opacity: .38;
  stroke-width: 1;
  stroke-dasharray: 4 4;
}

.fn-gate {
  stroke: var(--line-strong);
  stroke-width: 1;
  stroke-dasharray: 4 4;
  transition: stroke .4s ease, stroke-width .4s ease;
}
/* 介入后闸门打开：虚线转实线转青 */
.fn-gate.is-open {
  stroke: var(--teal);
  stroke-width: 1.6;
  stroke-dasharray: none;
}
.fn-jamband {
  fill: var(--amber);
  opacity: 0;
  transition: opacity .35s ease;
}
.fn-jamband.is-on { opacity: .2; }
.fn-jamtxt {
  fill: var(--amber);
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .06em;
  opacity: 0;
  transition: opacity .35s ease;
}
.fn-jamtxt.is-on { opacity: 1; }

/* 介入脉冲环 */
.fn-ring { fill: none; stroke: var(--teal); stroke-width: 1.4; pointer-events: none; }

/* 候选圆点：数点即数候选。外层 g 负责位移，内层 circle 负责颜色与状态，
   两层分开是为了让滞留抖动不跟位置打架。 */
.fn-u { transition: transform .72s cubic-bezier(.42, .02, .28, 1); }
.fn-dot {
  fill: var(--teal);
  opacity: 0;
  transition: fill .3s ease, opacity .3s ease;
}
.fn-u.is-in .fn-dot { opacity: 1; }

/* 滞留：变琥珀色并轻微抖动 —— 卡在放大窗口上出不去 */
.fn-u.is-jam .fn-dot {
  fill: var(--amber);
  animation: fnjam 1.5s ease-in-out infinite;
}
@keyframes fnjam {
  0%, 100% { transform: translate(0, 0); }
  50%      { transform: translate(.6px, -.6px); }
}

/* 出局：变红、留在原地、压到低透明度。透明度压得足够低，它只当底账，
   不与漏斗里还在推进的青色项抢视线；红点留着的理由见 consult-funnel.js 的 kill()。 */
.fn-u.is-out { transition-duration: .85s; }
.fn-u.is-out .fn-dot {
  fill: var(--red);
  opacity: .2;
  transition: fill .3s ease, opacity .6s ease;
}

/* 闸门左侧的出局计数 */
.fn-mark {
  fill: var(--red);
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* 右侧一行：关卡名 + 数字，别的一律不上图 */
.fn-lbl-name { fill: var(--ink-3); font-size: 10.5px; }
.fn-lbl-count {
  fill: var(--ink-2);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.fn-lbl-count.is-pool { fill: var(--ink-3); }
.fn-lbl-count.is-jam { fill: var(--amber); }

@media (prefers-reduced-motion: reduce) {
  .fn-u, .fn-dot, .fn-gate, .fn-jamband, .fn-jamtxt {
    transition: none !important;
    animation: none !important;
  }
  .fn-u.is-in .fn-dot { opacity: 1; }
}

/* ==========================================================================
   16. 替代测算可视化（solutions.html）
   --------------------------------------------------------------------------
   实现见 assets/js/subst-calc.js。同一组件挂两处：首屏右栏（自动演示）与
   #material-calc 的滑杆下方（拖动即见），共用同一份状态，因此这里只画图内
   几何与指标卡的栅格，外壳全部复用全站已有的 .dash / .mtiles / .chart / .status。
   ========================================================================== */
.mc__svg { display: block; width: 100%; height: auto; }
.mc__tiles { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }

/* 网格与刻度 */
.mc-grid { stroke: var(--line); stroke-width: 1; }
.mc-zero { stroke: var(--ink-4); stroke-width: 1; stroke-dasharray: 5 4; }
.mc-lab { fill: var(--ink-4); font-family: var(--font-mono); font-size: 10px; }
.mc-lab--zero { fill: var(--ink-3); font-weight: 700; }

/* 未回本区：零轴到曲线之间铺琥珀。候选更贵时它就是整条曲线下方那一片 */
.mc-lost { fill: color-mix(in srgb, var(--amber) 16%, transparent); }
.mc-path { fill: none; stroke: var(--teal); stroke-width: 2.2; stroke-linejoin: round; stroke-linecap: round; }
.mc-head { fill: var(--teal); }

/* 回本点 */
.mc-mark { stroke: var(--teal); stroke-opacity: .45; stroke-width: 1; stroke-dasharray: 3 3; }
.mc-mark-dot { fill: var(--panel); stroke: var(--teal); stroke-width: 2.2; }
.mc-mark-lab { fill: var(--teal); font-family: var(--font-mono); font-size: 10.5px; font-weight: 700; }

/* ---- 会员系统 P2/P3/P4（2026-10-29） ---- */
/* 页眉会员入口的未读红点 */
.member-entry { position: relative; }
.member-dot {
  position: absolute; top: -5px; right: -9px;
  min-width: 16px; height: 16px; padding: 0 4px;
  border-radius: 8px; background: var(--bad, #e5484d); color: #fff;
  font-size: 10px; font-style: normal; font-weight: 600;
  line-height: 16px; text-align: center;
}
/* 会员中心:站内通知 */
.msg-row { border-bottom: 1px solid var(--line, #e5e8ef); padding: 10px 0; cursor: default; }
.msg-row:last-child { border-bottom: 0; }
.msg-row__head { display: flex; justify-content: space-between; gap: 12px; align-items: baseline; }
.msg-row__body { margin: 4px 0 0; font-size: 13px; color: var(--muted, #6b7484); line-height: 1.6; white-space: pre-wrap; }
.msg-row--unread { cursor: pointer; }
.msg-row--unread .msg-row__head b::before {
  content: ""; display: inline-block; width: 7px; height: 7px;
  border-radius: 50%; background: var(--bad, #e5484d); margin-right: 7px;
}
/* 会员中心:需求处理进度与回复 */
.req-row__more { margin-top: 8px; }
.req-row__more summary { cursor: pointer; font-size: 12.5px; color: var(--muted, #6b7484); }
.req-row__reply { margin-top: 10px; padding: 10px 14px; background: var(--panel-2, rgba(90,201,255,.08)); border-radius: 8px; font-size: 13.5px; line-height: 1.7; }
.req-row__reply p { margin: 4px 0 0; }
.req-row__timeline { margin: 10px 0 0; padding-left: 18px; font-size: 12.5px; color: var(--muted, #6b7484); }
.req-row__timeline li { margin: 3px 0; }
/* 管理后台:老化行 / 停用行 */
.data tr.is-aging th, .data tr.is-aging td { background: rgba(255, 107, 107, .07); }
.data tr.is-disabled th, .data tr.is-disabled td { opacity: .55; }

/* ── 节点事实区块（研报库实测 + 产业链策展）─────────────────────────
   2026-11-02 新增。设计上把「语料实测」与「策展事实」在视觉上分开：
   fact-src 标签标出处，fact-chip 是可点的词条，fact-sub 是次级说明。 */
.fact-src {
  display: inline-block; margin-left: 8px; padding: 1px 7px; border-radius: 999px;
  font-size: 11px; font-weight: 500; letter-spacing: .02em; vertical-align: middle;
  color: var(--ink-3); background: var(--panel-2, rgba(90,201,255,.08));
  border: 1px solid var(--line);
}
.fact-chips { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 8px; }
.fact-chip {
  display: inline-flex; align-items: baseline; gap: 5px; padding: 4px 10px;
  border: 1px solid var(--line); border-radius: 999px; font-size: 13px;
  color: var(--ink); background: var(--panel-2, rgba(90,201,255,.06)); text-decoration: none;
}
a.fact-chip:hover { border-color: var(--accent, #5ac9ff); color: var(--accent, #5ac9ff); }
.fact-chip i { font-style: normal; font-size: 11.5px; color: var(--ink-3); }
.fact-sub { display: block; margin-top: 3px; font-size: 12.5px; color: var(--ink-3); }
.fact-issues li { color: var(--ink-2); }
